פרק 4 מתוך 5

לאמן בחינם: Unsloth על Colab ו-Kaggle עד מודל שרץ ב-Ollama

בפרק הזה מפסיקים לדבר על fine-tuning כאפשרות ומבצעים אותו בפועל. המטרה אינה לבנות סביבת מחקר מושלמת, אלא להגיע ל-run ראשון שעובד ב-$0, להבין איפה הוא יכול להישבר, לשמור checkpoints, ואז להפוך את ה-adapter למודל מקומי שאפשר להריץ ב-Ollama בלי endpoint בתשלום.

מה יהיה לך בסוף הפרק

מטרות למידה

לפני שמתחילים

הפרויקט שלך

בפרק 3 בנית dataset נקי במבנה chat template נכון, עם דוגמאות seed וסינון בסיסי. בפרק הזה תשתמש/י ב-dataset הזה כדי לאמן LoRA/QLoRA חינמי, לשמור checkpoints, ולייצא מודל שרץ מקומית. בפרק 5 תשתמש/י במודל הזה כדי לבצע הערכה, preference tuning וקפסטון שמוכיח שיפור מול ה-base.

מילון מושגים לפרק

Termתרגוםהגדרה קצרה
SFTTrainerמאמן SFTמחלקת אימון של Hugging Face TRL שמריצה supervised fine-tuning על dataset של דוגמאות.
Smoke testבדיקת עשןריצה זעירה על מעט דוגמאות שמוודאת שהצנרת עובדת לפני ששורפים GPU על run מלא.
Checkpointנקודת שמירהתמונת מצב של האימון: weights, optimizer, scheduler ו-step, שאפשר להמשיך ממנה אחרי עצירה.
Mergeמיזוגאיחוד ה-LoRA adapter לתוך base model כדי לקבל מודל שלם שניתן לייצא או להריץ.
GGUFפורמט GGUFפורמט מודל מקומי שמשמש את llama.cpp, Ollama ו-LM Studio לריצה יעילה על מחשב אישי.
Modelfileקובץ מודלקובץ הוראות של Ollama שמגדיר FROM, adapter, template ופרמטרים ליצירת מודל מקומי.
Gradient accumulationצבירת גרדיאנטיםטכניקה שמדמה batch גדול בעזרת כמה צעדים קטנים, בלי להחזיק batch גדול ב-VRAM בבת אחת.
OOMכשל זיכרוןOut of Memory: ה-GPU לא מצליח להחזיק את המודל, ה-batch או ה-context ומפסיק את הריצה.
בינוני12 דקותחינםאסטרטגיה

למה הפרק הזה מתחיל ב-run קטן ולא ב-run מושלם

הנטייה הטבעית אחרי פרק 3 היא לקחת את כל ה-dataset, לפתוח notebook, ללחוץ Run all, ולחכות לתוצאה. זה מובן: עבדת על הדוגמאות, בדקת chat template, אולי אפילו בנית synthetic data עם Claude, ועכשיו יש רצון לראות מודל שמתנהג אחרת. אבל free GPU אינו מקום טוב להוכיח אופטימיות. הוא מקום טוב להוכיח שהצנרת עובדת. ההבדל הזה חשוב יותר מכל hyperparameter בפרק הזה.

Smoke test הוא ריצה קטנה בכוונה. לא ריצה גרועה, לא קיצור דרך עצלן, אלא ניסוי שמטרתו לענות על ארבע שאלות בסיסיות: האם ה-GPU באמת זמין, האם ה-dataset נטען, האם ה-chat template לא משבש את הדוגמאות, והאם האימון מתקדם מספיק כדי ליצור checkpoint או adapter שאפשר לבדוק. אם אחת מהשאלות האלה נכשלת, עדיף לגלות את זה אחרי 20 דוגמאות וחמש דקות, לא אחרי שעתיים ומגבלת session שכבר נשרפה.

בפרקים הקודמים חזרנו שוב ושוב על הבחנה אחת: fine-tuning משנה התנהגות, לא מחליף חשיבה. אותו דבר נכון לאימון עצמו. אימון טוב אינו מתחיל בשאלה "איך אני מפיק את המודל הכי חזק?". הוא מתחיל בשאלה "מהו הניסוי הקטן ביותר שמוכיח שה-stack שלי תקין?". כשאתה עובד עם Colab free או Kaggle free, הניסוי הקטן ביותר הוא כלי הישרדות. הוא מגן עליך מ-OOM, מ-template mismatch, מ-column name לא נכון, מ-runtime CPU בלבד, ומ-run שמסתיים רגע לפני checkpoint.

בפרק הזה נשתמש ב-Unsloth, ספריית fine-tuning פתוחה שמספקת notebooks מוכנים ומאיצה LoRA/QLoRA. לפי baseline המחקר של הקורס ולפי תיעוד TRL, Unsloth משתלב עם ה-stack של Hugging Face ומקטין משמעותית שימוש ב-VRAM ביחס למסלול vanilla של PEFT ו-TRL. זו הסיבה שהוא מתאים ללומד שרוצה לאמן בחינם: הוא לא מבקש ממך לבנות trainer, tokenizer, collator ו-quantization מאפס. הוא נותן notebook קרוב למוכן, ואתה מחליף בו את המודל, הנתונים, והפרמטרים הרלוונטיים למשימה שלך.

המשימה שניקח כדוגמה לאורך הפרק היא מודל קטן שעונה בסגנון מותג עברי. אפשר להחליף אותה במודל Q&A פנימי, assistant לכתיבת קוד בסגנון אישי, או מודל שמחזיר JSON schema עקבי. מה שחשוב הוא שהמשימה תהיה צרה. אם המודל צריך להיות גם מומחה משפטי, גם קופירייטר, גם מחולל SQL, וגם יועץ מכירות, ה-run הראשון שלך יתפזר. בפרק הזה אנחנו רוצים הצלחה קטנה, מדידה, שניתן להריץ עד הסוף.

כדי להישאר מעשיים, נגדיר הצלחה לפני שנכתוב שורת קוד. הצלחה בפרק הזה היא לא loss נמוך באופן קסום. הצלחה היא notebook שעבר smoke test, ריצה מלאה שהגיעה לפחות ל-checkpoint אחד, adapter שמוציא פלט שונה מה-base על שתי דוגמאות held-out, ו-Ollama model מקומי שאפשר להריץ מהטרמינל. אם ארבעת הדברים האלה קיימים, יש לך pipeline. את שיפור האיכות העמוק נמדוד בפרק הבא.

עשה עכשיו 4 דקות

בחר/י 20 דוגמאות מתוך ה-dataset של פרק 3 ושמור/י אותן כקובץ קטן בשם train_smoke.jsonl. הדוגמאות צריכות לכלול לפחות שלושה סוגי בקשות שונים, לא רק וריאציות על אותו prompt.

טעות נפוצה: להתחיל run מלא לפני smoke test

זה מפתה כי כבר הכנת dataset, והתחושה היא שכל בדיקה נוספת מעכבת אותך. בפועל, run מלא הוא הדרך היקרה ביותר לגלות שהעמודה נקראת messages במקום conversations, שה-template לא מתאים, או שה-runtime בכלל רץ על CPU. במקום זה, הרץ/י קודם 20 דוגמאות, בדוק/י שה-loss זז, ודגום/י פלט אחד לפני שמרחיבים.

Dataset JSONL מפרק 3 Unsloth notebook Adapter LoRA/QLoRA Ollama מודל מקומי checkpoints מצילים session merge לפני GGUF

הדיאגרמה הזו היא כל הפרק במשפט אחד: dataset נקי נכנס ל-notebook, ה-notebook מאמן adapter, checkpoint מגן על הזמן שלך, merge הופך את ה-adapter למודל שלם או לייבוא מסודר, ו-Ollama נותן לך inference מקומי ב-$0. כל פעם שתסתבך בפרטים, תחזור/י למסלול הזה. אם שלב אחד לא ברור, לא ממשיכים לשלב הבא.

בינוני15 דקותחינםאסטרטגיה

בחירת זירת אימון: Colab, Kaggle או לדחות את הריצה

לפני שפותחים notebook צריך לבחור איפה לרוץ. זו לא בחירה אסתטית. זו החלטה על VRAM, אמינות GPU, מגבלת session, ואיך תתאושש/י אם session נגמר באמצע. Colab free נוח מאוד לניסויים קצרים, אבל הוא לא מבטיח GPU בכל שעה. Kaggle בדרך כלל צפוי יותר מבחינת GPU assignment, ומתועד עם quota שבועי סביב 30 שעות או לפעמים יותר לפי ביקוש ומשאבים, אבל גם שם יש session ceiling. לכן השאלה אינה "איזה שירות טוב יותר", אלא "איזה שירות מתאים ל-run המסוים שלי היום".

אם המודל שלך הוא 1B עד 4B, Colab free לרוב מספיק ל-smoke test ול-run קצר. אם אתה מאמן 7B או 8B ב-QLoRA על dataset לא גדול, Colab יכול להספיק אבל צריך להשאיר מרווח. אם אתה מתקרב ל-13B, Kaggle T4x2 הוא הבחירה ההגיונית יותר, כי שני T4 נותנים מרחב עבודה משמעותי יותר. אם אתה מנסה 14B ומעלה על free tier, ההחלטה המקצועית היא לא להתחכם אלא להקטין מודל או לדחות עד שיש compute מתאים. אין גבורה ב-OOM.

המספרים עצמם רגישים לזמן. Colab משנה מדיניות, Kaggle משנה availability, ו-Unsloth מוסיף notebooks חדשים. אבל העיקרון יציב: GPU חינמי הוא משאב זמני, לא תשתית production. אל תבנה/י עליו run שאין לו checkpoints. אל תכנן/י אימון שצריך לשרוד לילה שלם בלי שמירה. אל תניח/י ש-session שנפתח עם GPU יישאר נגיש אם המחשב נרדם. כל ההחלטות בפרק הזה מכבדות את העובדה הזו.

מצבבחירה מומלצתלמהמה לבדוק לפני Run all
מודל 1B-4B, dataset קטןColab freeמהיר לפתיחה, מספיק ל-smoke test ול-run ראשוןשה-runtime באמת GPU ולא CPU
מודל 7B-8B, QLoRAColab או Kaggleאפשרי על T4, אבל Kaggle צפוי יותר ל-run ארוךש-VRAM פנוי וש-max_seq_length לא גדול מדי
מודל 13B או dataset גדולKaggle T4x2יותר מרחב VRAM, אך session עדיין מוגבלcheckpoint מוקדם והעתקה ל-storage קבוע
מודל 14B+להקטין מודל או לשלם computefree GPU לא המקום להילחם במגבלה הזולא להתחיל לפני שמחשבים VRAM מחדש

הבחירה בין Colab ל-Kaggle קשורה גם להרגל העבודה שלך. Colab מרגיש חלק יותר למי שכבר עובד ב-Google Drive. Kaggle מרגיש טכני יותר בהתחלה, אבל נוח לשמור notebooks, datasets ו-outputs כגרסאות. אם אתה לומד לבד, ההמלצה שלי היא לפתוח את שניהם פעם אחת, להריץ תא GPU קטן, ואז לבחור לפי run. לא להפוך את זה לזהות. היום Colab, מחר Kaggle. המודל לא יודע איפה הוא התאמן; הוא יודע אם הנתונים והפרמטרים היו נכונים.

מסגרת החלטה: איפה לאמן היום?

עשה עכשיו 3 דקות

פתח/י את טבלת ה-VRAM מפרק 2, כתוב/י את שם המודל שאתה רוצה לאמן, ולידו סמן/י אחת משלוש אפשרויות: Colab, Kaggle, או "להקטין מודל". הוסף/י משפט אחד שמסביר את הבחירה.

בישראל, עוד שיקול קטן אבל אמיתי הוא זמן. הרבה פרילנסרים ומפתחים עובדים בערב. בשעות עומס, Colab free יכול להיות פחות צפוי. Kaggle עשוי להיות נוח יותר לריצה מתוכננת כי אפשר לשמור notebook ו-dataset בצורה מסודרת. מצד שני, אם אתה עובד עם Google Drive וה-dataset כבר שם, Colab חוסך friction. זו הסיבה שהפרק לא מכתיר מנצח. הוא נותן לך תהליך בחירה.

טעות נפוצה: להניח ש-Colab free תמיד נתן GPU

לפעמים runtime נפתח על CPU, וכל תא אימון נראה כאילו הוא פשוט תקוע. לפני כל התקנה ולפני טעינת מודל, הרץ/י בדיקת GPU. אם אין GPU, עצור/י. אל תתקין/י חבילות, אל תעלה/י dataset, ואל תתחיל/י train. החלפה מוקדמת ל-Kaggle זולה יותר משעה של בלבול.

בינוני18 דקותחינםהקמה

פתיחת notebook של Unsloth בלי לבנות stack מאפס

הכוח של Unsloth בפרק הזה הוא לא רק speedup. הכוח הוא שה-notebooks שלו כבר מחברים הרבה חלקים שקשה לחבר נכון בפעם הראשונה: טעינת מודל, 4-bit quantization, הגדרת LoRA, dataset formatting, trainer, inference קצר, ושמירה. אם תנסה/י לבנות את כל זה מאפס, תלמד/י הרבה, אבל זה לא יעד הפרק. יעד הפרק הוא להגיע למודל עובד בחינם. לכן מתחילים מ-notebook קיים.

פתח/י את עמוד notebooks של Unsloth ובחר/י notebook לפי משפחת המודל, לא לפי השם הכי מרשים. אם dataset שלך בעברית ובאנגלית, Qwen, Gemma או Llama קטן יכולים להיות בחירה סבירה, אבל אל תבחר/י מודל רק כי הוא חדש. שאל/י: האם יש notebook מוכן? האם הוא נכנס ב-VRAM? האם הוא מתאים ל-chat template שלי? האם יש community examples? מודל בינוני עם notebook ברור עדיף על מודל נוצץ שה-notebook שלו דורש שינוי עמוק.

אחרי פתיחת notebook, אל תרוץ/י קדימה. קודם בדוק/י runtime. ב-Colab בחר/י GPU דרך Runtime settings. ב-Kaggle בחר/י Accelerator. אחר כך הרץ/י תא שמדפיס את שם ה-GPU. אם התא נכשל, זו לא בעיית fine-tuning אלא בעיית סביבה. אם הוא מחזיר T4 או P100, המשך/י. אם הוא מחזיר CPU או כלום, עצור/י. הפרק הזה מלמד אותך לשמור GPU, לא לבזבז אותו.

!nvidia-smi

import torch
print(torch.cuda.is_available())
print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'CPU only')

התא הבא שאתה מחפש הוא תא התקנה. Notebooks של Unsloth משתנים, ולכן לא כדאי לשנן פקודת pip אחת. השתמש/י במה שה-notebook נותן באותו יום. מה שחשוב הוא להבין מה קורה: מתקינים unsloth, transformers, datasets, accelerate, peft, trl ולעיתים bitsandbytes או xformers. אם תא התקנה נכשל, קרא/י את השגיאה לפני שמריצים שוב. חצי מהבעיות ב-notebooks הן dependency conflicts שנפתרות על ידי Restart runtime אחרי התקנה.

השלב הבא הוא dataset path. בפרק 3 בנית JSONL. עכשיו צריך להעלות אותו. ב-Colab אפשר להעלות קובץ זמני, לחבר Drive, או להוריד מ-Hugging Face Dataset פרטי. ב-Kaggle עדיף ליצור Dataset קטן או להעלות דרך sidebar. למתחיל, הדרך הכי פשוטה היא קובץ קטן בתוך notebook ל-smoke test וקובץ מלא ב-storage קבוע ל-run האמיתי. אל תתחיל/י מהריצה המלאה עם קובץ שנעלם כש-session נסגר.

תרגיל 1: בדיקת זירה ו-run זעיר על 20 דוגמאות 20 דקות

  1. בחר/י מודל קטן שמתאים למשימה שלך: 1B עד 4B לריצה ראשונה, או 7B רק אם חישבת VRAM ויש GPU מתאים.
  2. פתח/י Unsloth notebook מאותה משפחת מודל, למשל Qwen, Gemma או Llama, ושמור/י עותק אישי.
  3. בחר/י GPU ב-runtime והריץ/י nvidia-smi. אם אין GPU, עצור/י ועבור/י זירה.
  4. העלה/י את train_smoke.jsonl עם 20 דוגמאות מפרק 3.
  5. שנה/י רק את dataset path ואת שם המודל אם צריך. אל תשנה/י עדיין את כל הפרמטרים.
  6. הרץ/י preprocessing ותא אימון קצר. המטרה היא שה-run יתחיל, יציג loss, ויסיים בלי OOM.
  7. שמור/י צילום מסך או העתק טקסט של GPU, מספר דוגמאות, loss ראשון ו-loss אחרון.

תוצר צפוי: Notebook שמוכיח שהסביבה, ה-GPU, ה-dataset וה-trainer עובדים יחד על 20 דוגמאות.

אם התרגיל הזה נכשל, אל תתקן/י עשרה דברים יחד. אם אין GPU, זו בעיית platform. אם dataset לא נטען, זו בעיית path או format. אם יש OOM ב-20 דוגמאות, זה model או max sequence length. אם loss הוא nan, זו בדרך כלל בעיית dtype, data corruption, או learning rate חריג. תן/י לכל כשל שם. שם טוב מקצר debug.

עשה עכשיו 4 דקות

בתוך ה-notebook שלך, צור/י תא בשם Environment proof שמדפיס GPU, גרסת Python, מספר דוגמאות ב-smoke dataset, ושם המודל. התא הזה יהיה ההוכחה הראשונה בתיקיית evidence שלך.

שימו לב למילה "הוכחה". כשאתה עובד לבד קל להחליק על הצלחות חלקיות. "ה-notebook נפתח" זו לא הוכחה. "ה-GPU פעיל, dataset נטען, trainer התחיל, loss ירד, ונוצר output directory" זו הוכחה. הפרק הזה בונה הרגל עבודה שמונע סיפורי הצלחה דמיוניים.

בינוני18 דקותחינםכלי

טעינת המודל והגדרת LoRA בצורה שלא מפוצצת VRAM

טעינת מודל היא המקום שבו הרבה runs נשברים עוד לפני אימון. בפרק 2 למדת למה QLoRA מכניס מודלים גדולים יותר ל-VRAM קטן: ה-base נטען ב-4-bit, וה-adapters נשארים בדיוק גבוה יותר. ב-Unsloth זה בדרך כלל מופיע כ-load_in_4bit או הגדרה דומה בתוך התא שטוען את המודל. אל תבטל/י אותה מתוך תחושה ש-16-bit יהיה "איכותי יותר". על T4 חינמי, איכות שלא נכנסת ל-VRAM היא לא איכות.

הגדרת LoRA מתחילה ב-rank. בפרק 2 הגדרנו כלל פשוט: r=8 למשימת style או brand voice, r=16 עד 32 למשימת skill learning צרה, r=64 ומעלה רק כשיש סיבה חזקה ומספיק VRAM. בפרק הזה ניישם את זה באופן שמרני. אם אתה מאמן מודל שיודע לכתוב בסגנון מותג עברי, r=8 או r=16 מספיקים לריצה ראשונה. אם אתה מאמן reasoning מקצועי או code style מורכב, אפשר לשקול r=32. לא מתחילים מ-r=64 כי זה נשמע רציני.

lora_alpha הוא עוד פרמטר שנראה מסתורי אבל אפשר להתחיל איתו פשוט. בהרבה notebooks תראה alpha שהוא פי שניים מה-rank, למשל r=16 ו-alpha=32. זו לא תורה מסיני, אבל זו נקודת פתיחה סבירה. מה שחשוב יותר הוא לא לערבב עשרה ניסויים בבת אחת. אם הריצה הראשונה עובדת, שמור/י אותה. רק אחר כך משנים rank או alpha ומשווים.

target_modules אומר לאילו שכבות של המודל להוסיף adapters. Notebooks של Unsloth בדרך כלל נותנים רשימה טובה למשפחת המודל. מתחילים לא צריכים לנחש רשימה חדשה. אם אתה משתמש ב-Qwen notebook על Qwen model, שמור/י על הרשימה. אם אתה משנה משפחה, ודא שה-notebook מתאים למשפחה. שינוי לא נכון של target modules יכול להוביל לאימון שלא באמת משפיע או לאימון שנכשל בטעינה.

# דוגמת מבנה, לא להעתיק בלי להתאים ל-notebook הנוכחי
model = FastLanguageModel.get_peft_model(
    model,
    r = 16,
    lora_alpha = 32,
    lora_dropout = 0,
    target_modules = ['q_proj', 'k_proj', 'v_proj', 'o_proj', 'gate_proj', 'up_proj', 'down_proj'],
    use_gradient_checkpointing = 'unsloth'
)

הדבר החשוב בדוגמה אינו התחביר המדויק אלא המחשבה. r נמוך יחסית, alpha הגיוני, dropout אפס או קטן לפי notebook, target modules מוכרים, ו-gradient checkpointing כדי לחסוך זיכרון. אם ה-notebook שלך משתמש בשמות אחרים, אל תכריח/י אותו להתאים לדוגמה. שמור/י על העיקרון: להקטין VRAM בלי לפגוע בצנרת.

עשה עכשיו 3 דקות

בחר/י rank אחד לריצה הראשונה וכתוב/י לידו סיבה. למשל: "r=16 כי המשימה היא brand voice עם מעט schema, ואני מעדיף/ה למנוע forgetting בריצה הראשונה".

אם קיבלת OOM בזמן טעינת המודל, אל תתחיל/י בלהוריד batch size; עוד לא הגעת לאימון. קודם בדוק/י שהמודל נטען ב-4-bit, שאין context ענק שמוגדר מראש, ושלא בחרת model variant גדול מדי. אחר כך הקטן/י מודל. אם OOM מופיע בזמן train, אז batch size, gradient accumulation, max_seq_length ו-packing נכנסים למשחק.

שימו לב: לא כל 7B שווה לכל 7B

שמות מודלים דומים יכולים להסתיר הבדלים ב-context, tokenizer, architecture ותמיכת notebook. אל תבחר/י מודל רק לפי מספר הפרמטרים. בדוק/י שיש notebook מתאים, שה-chat template ברור, ושיש לך סיבה לבחור דווקא אותו. אם המטרה היא ללמוד pipeline, מודל קטן ויציב עדיף.

בינוני25 דקותחינםתרגול

SFTTrainer: הפרמטרים הקטנים שמחליטים אם הריצה מסיימת

SFTTrainer הוא המקום שבו dataset הופך לאימון. TRL תומך ב-conversational datasets עם messages, ב-prompt-completion datasets, באימון adapters דרך PEFT, ב-resume from checkpoint, ובאפשרויות כמו packing או assistant_only_loss. אבל למתחיל בפרק הזה יש כלל: לא מפעילים כל אפשרות כי היא קיימת. מפעילים את המינימום שמייצר run יציב, ואז מוסיפים רק כאשר יש סיבה.

הפרמטר הראשון הוא per_device_train_batch_size. על T4 חינמי, ערך 2 הוא נקודת פתיחה שמרנית. ערך 1 בטוח יותר אך איטי יותר. ערך 4 יכול לעבוד במודלים קטנים אבל לא כדאי להתחיל ממנו אם אתה עדיין לא יודע איפה גבול ה-VRAM. במקום batch גדול, נשתמש ב-gradient accumulation. אם batch size הוא 2 ו-gradient_accumulation_steps הוא 4, ה-effective batch הוא בערך 8, אבל ה-GPU לא מחזיק שמונה דוגמאות מלאות בבת אחת.

הפרמטר השני הוא max_seq_length. זה הפרמטר שרבים מזלזלים בו, והוא יכול להכפיל שימוש בזיכרון. אם בפרק 3 רוב הדוגמאות שלך הן 400 עד 800 tokens, אל תגדיר/י 4096 רק כי זה נשמע נדיב. הגדרה של 1024 או 2048 יכולה להספיק. אם יש דוגמאות ארוכות, שקול/י לקצר אותן או לפצל. מודל קטן שמתאמן על דוגמאות מדויקות עדיף על מודל שנופל כי ניסית להכניס כל מסמך שלם ל-context.

הפרמטר השלישי הוא learning_rate. ב-adapter training מקובל להתחיל גבוה יותר מאימון full, ובסילבוס הקורס קבענו סביב 2e-4 כנקודת פתיחה ל-T4 חינמי. זה לא מספר קדוש. אם loss מתפוצץ או נעשה nan, מורידים. אם loss לא זז בכלל, לא מעלים מיד; קודם בודקים שה-labels נכונים, שהassistant tokens נלמדים, ושאין בעיית template. Learning rate הוא כפתור כיוון, לא פתרון קסם ל-data שבור.

הפרמטר הרביעי הוא epochs. לרוב המשימות בפרק הזה 1 עד 3 epochs מספיקים. Dataset קטן מדי עם יותר מדי epochs מוביל ל-overfitting: המודל מחקה את דוגמאות האימון אבל נכשל על קלט חדש. Dataset גדול יותר יכול להצדיק יותר צעדים, אבל בפרק הזה אין סיבה להתחיל מ-10 epochs. אנחנו רוצים run שמסיים, לא מודל שמתרגל לזכור.

פרמטרנקודת פתיחה ל-T4מתי לשנותסיכון אם מגזימים
batch_size2להוריד ל-1 אם יש OOM בזמן trainOOM או train איטי מדי
gradient_accumulation4להעלות אם רוצים effective batch גדול בלי VRAM נוסףאימון איטי יותר לכל optimizer step
learning_rate2e-4להוריד אם loss לא יציבnan loss או forgetting מהיר
epochs1-3להוסיף רק אם held-out לא משתפר וה-loss עדיין יורדoverfitting ומודל שמדקלם
max_seq_length1024 או 2048להעלות רק אם הדוגמאות באמת ארוכותVRAM גבוה ו-truncation שקט
save_steps250-500להקטין ב-dataset קטן או session קצריותר קבצים, אבל פחות סיכון לאבד ריצה

מסגרת החלטה: אם הריצה לא יציבה, איזה פרמטר נוגעים קודם?

תרגיל 2: קונפיגורציית SFTTrainer בטוחה ל-T4 25 דקות

  1. פתח/י את התפלגות אורכי הדוגמאות מפרק 3. אם אין לך, דגום/י 20 שורות וספור/י בערך את אורך ה-prompt והתשובה.
  2. בחר/י max_seq_length: 1024 לדוגמאות קצרות, 2048 לדוגמאות בינוניות, ורק אז 4096 אם באמת חייבים.
  3. הגדר/י batch_size=2 ו-gradient_accumulation=4. אם ה-notebook כבר הגדיר ערכים אחרים, כתוב/י למה אתה משנה או לא משנה.
  4. הגדר/י learning_rate סביב 2e-4 לריצה ראשונה של adapter. אל תבצע/י tuning לפני שיש baseline.
  5. בחר/י 1 עד 3 epochs לפי גודל dataset: 1 ל-smoke או dataset קטן מאוד, 2-3 ל-run מלא ראשוני.
  6. הגדר/י output_dir בשם שכולל תאריך, מודל ו-rank, למשל runs/qwen2b-brand-r16-2026-06-01.
  7. הגדר/י logging_steps ו-save_steps כך שתראה/י loss מוקדם ותקבל/י checkpoint לפני סוף session.

תוצר צפוי: טבלת hyperparameters עם ערכים ונימוקים. אם מישהו אחר קורא אותה, הוא מבין למה בחרת כל ערך.

עשה עכשיו 4 דקות

העתק/י את טבלת הפרמטרים למחברת שלך ומלא/י רק שלושה שדות: max_seq_length, epochs ו-output_dir. אם אינך יודע/ת מה לבחור, בחר/י את הערך השמרני יותר.

ב-notebooks עדכניים של TRL, חלק מהשמות וה-defaults יכולים להשתנות. לכן בפרק הזה אנחנו מתייחסים לתצורה כעקרון ולא כחוזה API. אם SFTConfig שלך מצפה ל-max_length במקום max_seq_length, או אם Unsloth notebook עוטף חלק מהפרמטרים בפונקציה משלו, אל תילחם/י בו. מפה את העיקרון לשם הנוכחי: אורך sequence, batch, accumulation, rate, epochs, שמירה. זו המיומנות שתישאר גם כששם הפרמטר משתנה.

בינוני28 דקותחינםתרגול

הרצת smoke test ואז אימון מלא עם checkpoints

עכשיו מגיע רגע ה-train, אבל גם כאן לא לוחצים Run all בעיניים עצומות. מתחילים ב-smoke test, מסתכלים על loss, מוודאים שה-output directory נוצר, ורק אז מרחיבים. ב-smoke test, לא אכפת לנו שהמודל יהיה טוב. אכפת לנו שהמסלול עובד. אם ה-loss יורד קצת, אין nan, אין OOM, ויש checkpoint או adapter שמור, אפשר לעבור לריצה מלאה.

הדבר הראשון שמסתכלים עליו הוא לא loss מוחלט אלא התנהגות. Loss שמתחיל גבוה ויורד מעט הוא סימן חיים. Loss שהוא nan הוא סימן לעצור. Loss שלא משתנה בכלל יכול להיות data labels לא נכונים, template שמלמד את המודל לחזות גם prompt במקום assistant, או dataset שבו כל התשובות כמעט זהות. אל תפרש/י כל מספר כתוצאה איכותית. בשלב הזה loss הוא מערכת עשן: הוא אומר אם יש אש, לא אם הבית יפה.

בריצה המלאה, checkpoints הם הביטוח שלך. Kaggle יכול להגביל session, Colab יכול להתנתק, הדפדפן יכול להירדם, וה-runtime storage יכול להיעלם. checkpoint כל 500 steps הוא נקודת פתיחה טובה, אבל אם dataset קטן או session קצר, אפשר לשמור מוקדם יותר. כן, זה יוצר יותר קבצים. זה עדיף על run שמגיע ל-80% ונעלם.

תכנון checkpoint כולל גם איפה הוא נשמר. output_dir בתוך runtime זמני אינו מספיק אם session יכול להימחק. ב-Colab, העתק/י ל-Google Drive בסוף כל checkpoint משמעותי או השתמש/י ב-output_dir בתוך mounted Drive אם זה לא מאט מדי. ב-Kaggle, שמור/י outputs וגרסאות notebook, או ארוז/י checkpoint כקובץ שניתן להורדה. אל תחכה/י לסוף כדי לחשוב על זה. סוף session הוא רגע גרוע להיזכר בגיבוי.

# דוגמת כיוון עקרונית בתוך TrainingArguments או SFTConfig
per_device_train_batch_size = 2
gradient_accumulation_steps = 4
learning_rate = 2e-4
num_train_epochs = 2
logging_steps = 10
save_steps = 500
output_dir = 'runs/qwen2b-brand-r16'

כדי להוכיח שאתה יכול להתאושש, אל תחכה/י לקריסה אמיתית. אחרי checkpoint ראשון, עצור/י ריצה קטנה בכוונה או הרץ/י תא שמדגים resume_from_checkpoint. זה מרגיש מיותר עד הפעם הראשונה שבה session נופל. מי שבדק חידוש מראש חוזר לעבוד. מי שלא בדק, מתחיל לחפש בפאניקה אם checkpoint כולל optimizer state או רק adapter weights.

תרגיל 3: אימון מלא עם checkpoint וחידוש מדומה 30 דקות

  1. החלף/י את train_smoke.jsonl ב-dataset המלא, או בתת-קבוצה של 200 דוגמאות אם זה ה-run הראשון שלך.
  2. ודא/י output_dir יציב ושמו כולל מודל, rank ותאריך. שם ברור חוסך טעויות merge בהמשך.
  3. הגדר/י save_steps כך ש-checkpoint ראשון ייווצר מוקדם יחסית, לפני שתגיע/י לסיכון session.
  4. הרץ/י train עד checkpoint ראשון. צפה/י ב-loss ובשימוש VRAM.
  5. עצור/י או שכפל/י את ה-notebook cell כדי לדמות חידוש. אל תמחק/י את checkpoint.
  6. הרץ/י train עם resume_from_checkpoint שמצביע ל-checkpoint. ודא/י שהוא ממשיך מאותו step ולא מתחיל מאפס.
  7. העתק/י לתיקיית evidence את שם checkpoint, step, loss לפני עצירה ו-loss אחרי חידוש.

תוצר צפוי: תיקיית checkpoint שממנה אפשר לחדש run ותיעוד קצר שמוכיח שהחידוש עובד.

עשה עכשיו 4 דקות

כתוב/י בתא Markdown ב-notebook: "אם session נופל, אני מחדש/ת מ: ..." והדבק/י את הנתיב המדויק ל-checkpoint האחרון. זה נשמע קטן, אבל בזמן תקלה זה חוסך חיפוש.

טעות נפוצה: לפגוש session limit בלי checkpoint

ה-quota השבועי אינו מבטיח ש-run יחיד ישרוד עד הסוף. session יכול להיגמר גם כשיש עוד שעות שבועיות. לכן checkpoint הוא חלק מהאימון, לא תוספת. שמור/י מוקדם, שמור/י בשם ברור, והעתק/י החוצה לפני שאתה סוגר/ת את הדפדפן.

אם run מלא נמשך יותר מדי, אל תסיק/י מיד שהמחשב חלש. בדוק/י האם packing כבוי ויש הרבה padding, האם max_seq_length גדול מדי, האם dataset כולל תשובות ארוכות שלא לצורך, והאם logging או saving תכופים מדי. מצד שני, אל תפעיל/י packing לפני שאתה מבין/ה איך הוא משנה רצפים. Packing יכול לשפר יעילות, אבל אם ה-template או labels לא נכונים, הוא גם מקשה על debug. בפרק הזה, clarity לפני cleverness.

בינוני18 דקותחינםניתוח

בדיקת adapter לפני merge: לא מחכים ל-Ollama כדי לגלות שהמודל נשבר

אחרי אימון יש רגע מסוכן: הכול נראה הצלחה כי notebook סיים. אבל סיום train אינו הוכחת איכות. לפני merge, לפני GGUF, לפני Ollama, צריך לבדוק adapter בתוך אותה סביבת Python. זה המקום שבו הכי קל להשוות base מול adapter, כי יש לך tokenizer, model ו-helper functions זמינים. אם adapter כבר כאן מוציא פלט מקושקש, אין סיבה להתקדם ל-GGUF. Conversion לא מתקן אימון שבור.

קח/י שתי דוגמאות held-out מפרק 3. Held-out פירושו שהן לא היו באימון. אחת צריכה להיות דוגמה רגילה שמייצגת את המשימה, והשנייה צריכה להיות דוגמה קצת קשה: prompt ארוך יותר, Hebrew-English mix, או דרישת format. הרץ/י את אותו prompt על base ועל adapter. אל תחפש/י מושלמות. חפש/י שינוי בכיוון הנכון: סגנון מותג עקבי יותר, JSON נקי יותר, פחות הסברים מיותרים, או תשובה שמתאימה להנחיות.

חשוב לתעד גם כישלון. אם adapter גרוע מה-base, זה מידע טוב. אולי dataset קטן מדי, אולי epochs נמוכים מדי, אולי template mismatch, אולי rank לא מתאים, אולי הדוגמאות הסינתטיות דומות מדי זו לזו. אם תדלג/י ישר ל-Ollama, יהיה קשה לדעת אם הבעיה באימון או ב-export. בדיקה מוקדמת שומרת על עץ ה-debug פשוט.

עשה עכשיו 5 דקות

בחר/י שתי דוגמאות held-out והריץ/י אותן על base ועל adapter. שמור/י ארבעה פלטים בתיקיית evidence: base רגיל, adapter רגיל, base קשה, adapter קשה.

הבדיקה הזו מחברת את פרק 4 לפרק 5. בפרק הבא נבנה הערכה מסודרת יותר, אבל כבר עכשיו צריך לראות שהמודל לא נשבר. אם הפלט של adapter עדיין לא טוב אבל הוא בכיוון נכון, אפשר להמשיך ל-export ולסמן שהאיכות תטופל בהערכה. אם הפלט מקושקש, חוזר על tokens, מתעלם מהשפה, או לא עוצר, עוצרים. זו בדרך כלל בעיית template או EOS, לא בעיית Ollama.

דוגמה מייצגת: בדיקה מהירה ל-brand voice

Prompt held-out: "כתוב פתיח קצר למייל לקוחות על פיצ'ר חדש, בטון ישיר ולא מכירתי". ה-base נותן פתיח כללי, מנומס וארוך. ה-adapter אמור לתת פתיח קצר, עם אותו rhythm שהכנסת בדוגמאות, בלי משפטי "אנחנו שמחים להכריז" אם זה לא סגנון המותג. אם ההבדל קטן אבל ברור, יש סימן שהאימון תפס. אם שניהם זהים כמעט לגמרי, ייתכן שה-rank נמוך מדי, ה-epochs נמוכים מדי, או שה-dataset לא מייצג מספיק.

מתקדם32 דקותחינםתרגול

Merge, GGUF ו-Ollama: להפוך אימון בענן למודל מקומי

עכשיו הופכים את תוצר האימון למשהו שאפשר להריץ מחוץ ל-notebook. כאן יש שתי דרכים לגיטימיות. הדרך הראשונה היא merge: מאחדים את ה-LoRA adapter לתוך base model, שומרים מודל מלא, ממירים ל-GGUF, ואז מייבאים ל-Ollama. הדרך השנייה היא adapter import: Ollama תומך ב-Modelfile עם FROM של base ו-ADAPTER שמצביע על adapter מתאים. למרות שהדרך השנייה נוחה במקרים מסוימים, הדרך הראשונה היא ברירת המחדל לפרק הזה כי היא מפיקה artifact אחד ברור ונייד יותר.

הכלל שאסור לשכוח: adapter אינו base model. Adapter מכיל שינוי קטן יחסית. הוא לא עומד לבד. אם תנסה/י להמיר אותו כאילו הוא מודל מלא, התוצאה עלולה להיראות כאילו הצליחה אבל להתנהג בצורה שבורה. לכן לפני כל פעולה כתוב/י שלושה נתונים: שם base model המדויק, נתיב adapter, ונתיב output של merged model. אם אחד מהם לא ברור, עוצרים.

ב-PEFT תראה לעיתים model.merge_and_unload. ב-Unsloth תראה helper methods כמו save_pretrained_merged או merge_to_bf16, תלוי גרסה ו-notebook. אל תתעקש/י על שם פונקציה מהפרק אם ה-notebook העדכני נותן תא export אחר. העיקרון הוא אותו עיקרון: לייצר תיקייה שמכילה משקלים ממוזגים, tokenizer וקונפיגורציה מספקת להמשך המרה או import.

# דוגמה עקרונית בלבד: השתמש/י בתא export העדכני של notebook Unsloth
merged_dir = 'merged_model'
model.save_pretrained_merged(merged_dir, tokenizer, save_method = 'merged_16bit')
tokenizer.save_pretrained(merged_dir)

אחרי שיש merged model, עוברים ל-GGUF אם רוצים קובץ שמתאים ל-llama.cpp ול-Ollama. llama.cpp כולל convert_hf_to_gguf.py, ובתיעוד העדכני שלו מופיעים גם כלים ל-GGUF adapters. בפרק הזה נשתמש במסלול הפשוט: ממירים מודל ממוזג. אם אתה עובד בתוך Colab או Kaggle, ייתכן שתצטרך clone של llama.cpp והתקנת requirements. אם Unsloth notebook כבר נותן export ל-GGUF או Ollama, השתמש/י בו. זה עדיף מכתיבה ידנית של converter.

# דוגמה עקרונית מחוץ ל-notebook או בתא shell
git clone https://github.com/ggml-org/llama.cpp
python llama.cpp/convert_hf_to_gguf.py merged_model --outfile my-brand-model-f16.gguf

בשלב הזה אפשר להחליט אם quantization מתבצע ב-llama.cpp, ב-Ollama create, או בכלי אחר. למודל קטן אפשר להתחיל מ-F16 אם המחשב המקומי מחזיק. לרוב המשתמשים, q4_K_M הוא איזון טוב בין גודל לאיכות. אבל אל תעשה/י quantization לפני בדיקת adapter. אם הפלט שבור, quantization רק תסתיר את מקור הבעיה.

מסגרת החלטה: איזה מסלול יצוא לבחור?

Modelfile בסיסי ל-GGUF יכול להיות קצר מאוד. אם ה-GGUF כבר כולל chat template נכון, אפשר להתחיל רק מ-FROM. אם צריך template, מוסיפים אותו בזהירות. אל תכניס/י template שלא תואם את המודל. Template לא נכון אחרי export יכול לגרום לאותם סימפטומים כמו template לא נכון באימון: פלט מוזר, תגובות שלא נגמרות, או role markers שמופיעים בטקסט.

FROM ./my-brand-model-q4_K_M.gguf
PARAMETER temperature 0.7
PARAMETER top_p 0.9

SYSTEM אתה assistant קצר, ישיר, בעברית טבעית, לפי סגנון המותג שאומן.
ollama create brand-helper -f Modelfile
ollama run brand-helper

אם בחרת adapter import במקום GGUF merged, ה-Modelfile יכלול FROM של base ו-ADAPTER. כאן הסיכון הוא base mismatch. אם אימנת על גרסה אחת של Qwen וה-Ollama base הוא גרסה אחרת, תקבל תוצאות לא צפויות. לכן adapter import מתאים יותר למי שיודע לשלוט בדיוק ב-base. למתחיל, merge-to-GGUF מפחית דרגות חופש.

שתי דרכים ל-Ollama מסלול בטוח למתחיל merge -> GGUF -> FROM file מסלול גמיש FROM base + ADAPTER artifact אחד קל להעביר ולתעד דורש base זהה טעות קטנה, פלט מוזר

תרגיל 4: Merge, יצירת Modelfile והרצה ב-Ollama 30 דקות

  1. הרץ/י שתי דוגמאות held-out על adapter בתוך notebook ושמור/י את הפלטים.
  2. כתוב/י בתא Markdown את שם base model המדויק, נתיב adapter ונתיב merged output.
  3. בצע/י merge בעזרת תא export של Unsloth או PEFT, ושמור/י תיקיית merged_model.
  4. המר/י את merged_model ל-GGUF בעזרת תא export קיים או convert_hf_to_gguf.py.
  5. צור/י Modelfile עם FROM לקובץ GGUF ו-system קצר שמתאים למשימה.
  6. הרץ/י ollama create ואז ollama run. אם המודל לא נטען, בדוק/י נתיב, שם קובץ וגודל קובץ.
  7. השווה/י prompt אחד מול base ואחד מול המודל החדש, ושמור/י את ההבדלים בתיקיית evidence.

תוצר צפוי: מודל Ollama מקומי שעולה מהטרמינל ומפיק פלט שמראה שינוי התנהגותי ביחס ל-base.

עשה עכשיו 3 דקות

לפני merge או adapter import, כתוב/י שלושה נתונים: base המדויק, adapter path, output path. אם אינך יודע/ת אחד מהם, עצור/י עד שהוא ברור.

טעות נפוצה: להמיר adapter לא ממוזג כאילו הוא מודל מלא

Adapter נראה כמו תיקיית מודל כי יש בו config וקבצים, אבל הוא אינו מכיל את כל משקלי ה-base. אם ממירים אותו לא נכון, אפשר לקבל artifact שנראה תקין אך מתנהג רע. בצע/י merge ל-base לפני GGUF, או השתמש/י ב-ADAPTER עם base זהה בדיוק.

בינוני20 דקותחינםניתוח

מה עושים כשזה נופל: OOM, timeout, פלט מקושקש ו-chat template mismatch

Fine-tuning חינמי כמעט תמיד כולל תקלה אחת לפחות. זה לא סימן שאתה לא מתאים לזה. זה סימן שאתה עובד עם הרבה שכבות: GPU זמני, CUDA, PyTorch, tokenizer, dataset, trainer, adapter, export ו-runtime מקומי. המיומנות היא לא להימנע מכל תקלה. המיומנות היא לזהות באיזה שכבה התקלה נמצאת.

OOM בזמן טעינת מודל שונה מ-OOM בזמן אימון. טעינה שנכשלת אומרת בדרך כלל שהמודל גדול מדי, 4-bit לא פעיל, או שיש variant לא מתאים. אימון שנכשל אומר שאורך הרצף, batch size או activations גדולים מדי. לכן לא פותרים את שניהם באותה דרך. אם טעינה נופלת, הקטן/י מודל או ודא/י quantization. אם אימון נופל, הורד/י max_seq_length או batch size, והפעל/י gradient checkpointing אם notebook תומך.

Timeout הוא תקלה אחרת. הוא לא אומר שהמודל גרוע, אלא שהתכנון לא כיבד session. הפתרון הוא checkpoint מוקדם, resume מתורגל, והקטנת run. אם run אחד לא נכנס ב-session, מחלקים אותו. אם dataset גדול מדי, מתחילים בתת-קבוצה איכותית. אם epochs רבים מדי, מקצרים ומודדים. אל תנסה/י לנצח את השעון בעזרת תקווה.

פלט מקושקש הוא הכשל שהכי מפחיד מתחילים, כי הכל נראה כאילו הצליח עד הרגע שבו המודל מדבר שטויות. ברוב המקרים, החשוד הראשון הוא chat template mismatch. אם אימנת בפורמט messages אבל inference משתמש בתבנית אחרת, המודל לא רואה את אותה שפה מבנית. חשוד שני הוא EOS או stop token. חשוד שלישי הוא dataset עם artifacts, למשל תשובות שמכילות role markers לא עקביים. רק אחרי שבדקת את אלה, בדוק/י rank, learning rate ו-epochs.

סימפטוםחשוד ראשוןפעולה ראשונהלא לעשות
OOM בטעינת מודלמודל גדול או 4-bit כבויודא load_in_4bit או בחר מודל קטן יותרלהעלות gradient accumulation
OOM בזמן trainsequence או batch גדוליםהורד max_seq_length או batch_sizeלהחליף dataset בלי לבדוק VRAM
run נקטעsession limitחדש מ-checkpoint ותכנן save_steps מוקדםלהתחיל מאפס בלי לבדוק checkpoint
פלט עם role markerschat template mismatchהשווה template באימון וב-inferenceלהאשים quantization מיד
מודל מדקלם דוגמאותoverfittingפחות epochs, יותר גיוון, held-out בדיקהלהוסיף עוד epochs

עשה עכשיו 4 דקות

כתוב/י לעצמך שלוש שורות חירום: אם OOM אז..., אם timeout אז..., אם פלט מקושקש אז.... בזמן תקלה עובדים לפי השורות האלה ולא לפי לחץ.

סולם Debug: מתקנים מהשכבה החיצונית פנימה 1. סביבה: GPU, CUDA, runtime, storage 2. טעינת מודל: 4-bit, גודל מודל, VRAM פנוי 3. Dataset: columns, JSONL, chat template 4. Trainer: batch, seq length, lr, checkpoints 5. Export: merge, GGUF, Modelfile, template

הסולם הזה מונע תיקונים אקראיים. אם GPU לא זמין, אין טעם לשנות learning rate. אם dataset לא נטען, אין טעם לשנות rank. אם adapter טוב ב-notebook אבל גרוע ב-Ollama, הבעיה כנראה ב-export, template או quantization, לא באימון. Debug טוב הוא לא מהיר כי אתה מנחש מהר. הוא מהיר כי אתה מצמצם את המרחב.

מתחיל12 דקותחינםאסטרטגיה

השגרה החדשה שלך אחרי שיש מודל שרץ

אם הגעת ל-Ollama model שרץ, עשית את החלק שרוב המדריכים משאירים מעורפל. אבל מודל שרץ אינו סוף העבודה. עכשיו צריך לשמור את מה שלמדת, כדי שה-run הבא יהיה טוב יותר ולא רק חוזר על אותם ניסויים. השגרה בפרק הזה מצטרפת לשגרה מפרק 3: שם בדקת dataset; כאן אתה בודק training run ו-export.

הדרך הפשוטה לשמור למידה היא לנהל run log, יומן ריצה קצר. לא צריך מערכת ניסויים כבדה. מספיק קובץ Markdown או גיליון פשוט עם עמודות קבועות: תאריך, platform, GPU, base model, dataset version, מספר דוגמאות, rank, alpha, max sequence length, batch size, gradient accumulation, epochs, save steps, זמן ריצה, checkpoint אחרון, status, ושתי הערות איכות. אם אתה עובד מול לקוח ישראלי, הוסף גם שורת context: האם זה מודל לסגנון מותג, תמיכה בעברית, קוד, או schema. אחרי שלושה runs, היומן הזה הופך ממסמך משעמם למפה. אתה רואה שלא כל כישלון הוא חדש; חלקם חוזרים באותה צורה.

יומן כזה חשוב במיוחד כי free GPU מייצר תנאים משתנים. Run שרץ ב-Colab ביום ראשון בערב לא בהכרח ירוץ באותו אופן ביום שלישי בבוקר. Kaggle יכול לתת לך סביבת GPU טובה, אבל session אחר יתחיל עם package cache נקי. אם אין יומן, אתה זוכר רק את התחושה: "הפעם זה היה איטי", "הפעם זה כמעט עבד". אם יש יומן, אתה יודע: max_seq_length היה 2048 במקום 1024, ה-dataset גדל מ-200 ל-850 דוגמאות, save_steps היה מאוחר מדי, או שבחרת rank אחר. Engineering טוב מתחיל בזיכרון חיצוני.

ליד יומן הריצה כדאי ליצור model card קטן, גם אם המודל נשאר רק אצלך. Model card אינו מסמך שיווקי. הוא תעודת זהות: מה המודל אמור לעשות, על איזה base הוא אומן, איזה dataset version שימש, מה לא היה באימון, אילו מגבלות ידועות יש, ואיזה prompts נבדקו. אם אתה מוכר שירות ללקוח, model card מגן עליך משתי בעיות. הראשונה היא הבטחת יתר: הלקוח חושב שהמודל יודע כל דבר שקשור לעסק. השנייה היא שכחה: חודש אחר כך אף אחד לא זוכר אם המודל אומן על פניות שירות, פוסטים, או מסמכי FAQ.

דוגמה מייצגת: Model card קצר למודל סגנון מותג

שם: heb-brand-helper-qwen2b-r16. מטרה: לכתוב טיוטות קצרות בעברית בסגנון ישיר של מותג B2B קטן. Base: Qwen small instruct variant לפי notebook של Unsloth. Dataset: 420 דוגמאות, מתוכן 300 ידניות/ערוכות ו-120 synthetic שעברו סינון. לא באימון: מידע עובדתי עדכני על מוצרים, מחירים, מלאי או מדיניות משפטית. בדיקות: 20 held-out prompts, השוואה מול base, בדיקה ידנית של טון, אורך, ושמירה על עברית טבעית. מגבלות: המודל יכול להמציא פרטי מוצר אם prompt מבקש עובדות שלא נמצאות בו; לשימוש עם RAG או prompt מפורש כשצריך ידע דינמי.

ה-model card עוזר גם בפרק הבא, כשנמדוד שיפור מול base. בלי תיאור משימה ברור, evaluation הופך לטעם אישי. אתה אומר "זה נשמע טוב יותר", אבל לא יודע ביחס למה. עם model card, אפשר לשאול: האם המודל עושה את המשימה שהוגדרה? האם הוא קצר יותר? האם הוא שומר על schema? האם הוא נמנע מביטויים שלא רצינו? האם הוא נכשל בקטגוריות שלא היו ב-dataset? זו הדרך להפוך תחושה למדידה.

עוד חלק מהשגרה הוא ניהול גרסאות ל-dataset. בפרק 3 כבר דיברנו על סינון, deduplication ו-teacher artifacts. אחרי אימון ראשון, אל תערוך/י את אותו קובץ במקום. צור/י גרסה חדשה: dataset-v1.jsonl, dataset-v2.jsonl, או תיקייה עם תאריך. הסיבה פשוטה: אם run v2 גרוע יותר מ-v1, אתה צריך לדעת מה השתנה. אולי הוספת יותר מדי דוגמאות synthetic. אולי סיננת החוצה דוגמאות קשות. אולי הכנסת דוגמאות עם סגנון אחר. בלי גרסאות, אי אפשר לחזור אחורה.

אם הדוגמאות שלך מכילות מידע של לקוחות, יש גם שיקול פרטיות. אימון חינמי ב-Colab או Kaggle עדיין מריץ קוד בסביבה עננית. אל תעלה/י נתוני לקוח רגישים בלי הרשאה, ואל תכניס/י פרטים אישיים שלא דרושים למשימה. עבור מודל brand voice, בדרך כלל לא צריך שמות לקוחות, מספרי טלפון, כתובות או נתוני עסקאות. אפשר להחליף אותם במבנים מייצגים: "לקוח A", "מוצר B", "תאריך C". Fine-tuning לומד דפוסים; הוא לא צריך לזכור פרטים פרטיים כדי ללמוד טון.

במקרים שבהם חייבים לעבוד עם מידע רגיש, המסלול החינמי בענן אולי לא מתאים. זו אינה כישלון של הקורס; זו החלטת סיכון. אפשר לאמן מקומית אם יש GPU מתאים, להשתמש בסביבה עננית פרטית בתשלום, או לבנות RAG שלא מכניס את הידע לאימון. ההחלטה הזו חוזרת לעקרון מפרק 1: fine-tuning אינו המקום להזריק ידע דינמי או רגיש רק כי הוא נראה נוח. אם הנתונים צריכים להישאר פרטיים או להתעדכן כל שבוע, אולי RAG או prompt עם context הוא פתרון נכון יותר.

שגרה טובה כוללת גם cleanup. אחרי כמה ניסויים, תיקיות output מתנפחות: checkpoints, merged models, GGUF בכמה quantizations, notebooks משוכפלים, וקבצי evidence. מחיקה אקראית מסוכנת, אבל אי-מחיקה יוצרת בלגן שמוביל לטעויות. פעם בשבוע, שמור/י שלושה דברים מכל run חשוב: config, checkpoint או adapter סופי, ו-evidence. אם run נכשל ואין בו ערך לימודי, שמור/י רק הערת כשל קצרה ומחק/י artifacts כבדים. דיסק מלא הוא לא רק בעיית מקום; הוא מקור לבלבול.

כדאי גם להפריד בין artifact ללמידה. Artifact הוא הקובץ שמריצים: GGUF, adapter, Modelfile. למידה היא ההבנה למה הוא יצא כמו שיצא: dataset, config, platform, logs, השוואות. הרבה מתחילים שומרים רק את artifact ואז לא יודעים לשחזר אותו. אחרים שומרים רק notebook ואז לא יודעים איזה קובץ GGUF הוא האחרון. שמור/י את שניהם, אבל בשם שמספר סיפור. לדוגמה: qwen2b-brand-r16-ds420-e2-q4km. זה לא שם יפה, אבל הוא שימושי.

לבסוף, קבע/י כלל לעצמך: לא משנים יותר ממשתנה אחד בריצה הבאה. אם בריצה הראשונה השתמשת r=16, 2 epochs ו-dataset של 420 דוגמאות, ובריצה השנייה שינית ל-r=32, 3 epochs, dataset של 900 דוגמאות ו-max_seq_length 2048, לא תדע מה גרם לשיפור או להידרדרות. Free GPU דוחף אותנו לרצות לנצל כל session עד הסוף, אבל ניסוי שמערבב הכול מלמד מעט. עדיף run קטן שמבודד משתנה אחד מאשר run גדול שמייצר תחושה של פעילות.

המשמעת הזו היא ההבדל בין "הצלחתי להריץ tutorial" לבין "אני יודע/ת לאמן מודל קטן באופן חוזר". Tutorial מסתיים כשהפקודה עובדת. Workflow מקצועי מתחיל שם. יש לך dataset גרסאי, config מתועד, checkpoints, adapter test, export, Ollama run, evidence, model card ויומן. עכשיו אפשר לשפר. עכשיו אפשר להסביר ללקוח או לעצמך מה קרה. עכשיו אפשר לעבור לפרק 5 ולמדוד.

כדי שהשגרה הזו לא תישאר רעיון יפה, כדאי ליצור מבנה תיקיות קבוע לכל run. לדוגמה: data, config, checkpoints, adapter, merged, gguf, ollama, evidence ו-notes. התיקייה data מכילה קישור או עותק של dataset version, לא קובץ מסתורי בשם final.jsonl. התיקייה config מכילה את ערכי האימון בפורמט קריא. checkpoints כוללת רק נקודות שמירה שחשובות לשחזור, לא כל קובץ זמני. adapter הוא התוצר לפני merge. merged הוא המודל הממוזג. gguf הוא קובץ הריצה המקומית. ollama כולל Modelfile. evidence כולל prompts ופלטים. notes כולל החלטות וכשלים. מבנה כזה נראה טכני, אבל הוא מפחית מאוד את הסיכוי להשתמש בטעות ב-adapter מ-run אחר או ב-GGUF ישן.

runs/
  qwen2b-brand-r16-ds420-2026-06-01/
    data/
    config/
    checkpoints/
    adapter/
    merged/
    gguf/
    ollama/
    evidence/
    notes/

בתיקיית evidence אל תשמור/י רק את הפלט שאתה אוהב. שמור/י שלושה סוגי ראיות: הצלחה ברורה, כישלון ברור, ומקרה גבולי. הצלחה ברורה מראה למה ה-run היה שווה. כישלון ברור מראה מה צריך לתקן. מקרה גבולי מלמד אותך איפה המודל לא יציב. אם אתה עובד על מודל סגנון מותג, הצלחה יכולה להיות פתיח קצר שנשמע כמו המותג; כישלון יכול להיות טון מכירתי מדי; מקרה גבולי יכול להיות תשובה טובה בעברית אבל ארוכה מדי. בפרק 5, הראיות האלה יהפכו ל-held-out evaluation set מסודר יותר.

כשמשווים base מול fine-tuned model, אל תסתכל/י רק על איזו תשובה "יפה". כתוב/י קריטריונים לפני ההשוואה. למשל: אורך עד 80 מילים, בלי פתיח גנרי, שומר על עברית טבעית, מחזיר שלושה bullets, לא מוסיף עובדות שלא הופיעו ב-prompt, ושומר על call to action אחד. עכשיו ההשוואה פחות רגשית. אם המודל המאומן קצר יותר אבל ממציא עובדות, הוא לא ניצח. אם הוא שומר schema אבל הטון עדיין גנרי, הוא השתפר חלקית. אם הוא טוב רק על prompts שדומים מאוד ל-training data, יש חשד overfitting.

מומלץ להריץ גם prompt שלילי אחד: בקשה שהמודל לא אמור לפתור טוב יותר אחרי fine-tuning. לדוגמה, אם אימנת brand voice, בקש/י שאלה עובדתית על מחירי מוצר שלא היו ב-dataset. המודל לא אמור להפוך למאגר ידע. אם הוא ממציא בביטחון, זו תזכורת שהאימון שינה התנהגות ולא הוסיף מערכת אמת. בדיקה שלילית מגינה עליך מפירוש מוגזם של הצלחה. היא גם עוזרת להסביר ללקוח למה עדיין צריך RAG, prompt context או בדיקה אנושית במקומות מסוימים.

עוד הרגל קטן: שמור/י את פקודת ollama run ואת prompt הבדיקה בדיוק כפי שהרצת אותם. הרבה בעיות נראות כמו בעיות מודל אבל הן בעצם שונות ב-prompt. אם ב-notebook השתמשת ב-system מסוים וב-Ollama השתמשת ב-system אחר, ההשוואה לא נקייה. אם ב-base השתמשת בטמפרטורה 0.2 ובמודל המאומן 0.9, ההשוואה לא נקייה. בפרק הזה לא צריך evaluation מחקרי, אבל צריך הוגנות בסיסית. אותו prompt, אותם פרמטרים, ואז מסתכלים על ההבדל.

לסיום, תן/י לכל run verdict קצר: keep, retry, discard או archive. keep אומר שהמודל שימושי מספיק להמשך הערכה. retry אומר שהכיוון נכון אבל צריך שינוי אחד מוגדר, למשל max_seq_length קצר יותר או dataset מגוון יותר. discard אומר שה-run לא תרם ואין סיבה לשמור artifacts כבדים. archive אומר שה-run לא הכי טוב אבל יש בו לקח שכדאי לשמור. ההחלטה הזו סוגרת את הלולאה. בלי verdict, כל run נשאר פתוח בראש. עם verdict, אתה בונה רצף ניסויים שמתקדם.

יש עוד פרט קטן שמציל שעות: אל תקרא/י למודל המקומי בשם כללי כמו my-model. ב-Ollama, שם כזה יישכח מהר מאוד. השתמש/י בשם שמכיל משפחה, משימה וגרסה, למשל brand-helper-qwen2b-r16-v1. אם יצרת quantization אחר, הוסף/י q4 או q8 לשם. אם זה מודל ללקוח, אל תכניס/י לשם מידע רגיש, אבל כן שמור/י mapping פנימי. שם טוב מאפשר להריץ שתי גרסאות זו מול זו, למחוק גרסה גרועה בלי פחד, ולכתוב בפרק 5 evaluation שמצביע למודל הנכון. Reproducibility אינו מתחיל במאמר מחקר; הוא מתחיל בשם שאפשר להבין שבוע אחרי.

אותו עיקרון חל על prompts הבדיקה. שמור/י אותם כקובץ קטן ולא רק בזיכרון או בהיסטוריית הטרמינל. אם prompt השתנה בין ריצה לריצה, גם ההשוואה השתנתה. קובץ prompts קבוע מאפשר לך לבדוק מהר אם שינוי dataset באמת שיפר את המודל או רק פגש דוגמה נוחה יותר.

ככל שהשמות, הקבצים והבדיקות עקביים יותר, כך הריצה הבאה מתחילה מעבודה ולא מחפירה בארכיון.

לפני שמסמנים את הפרק כסגור, כתוב/י גם הערת סיכון קצרה: מה עדיין לא נבדק. אולי האימון רץ רק על 50 דוגמאות, אולי לא בדקת עברית מעורבת באנגלית, אולי ההמרה ל-GGUF עבדה אבל לא נבדקה על prompt ארוך, ואולי ה-adapter טוב רק על משימה אחת צרה. הערת סיכון אינה מורידה מערך העבודה; היא הופכת אותה למקצועית. בפרק 5 ההערה הזאת תהפוך לרשימת בדיקות הערכה, ולכן עדיף לכתוב אותה כשה-run עדיין טרי בראש ולא שבוע אחרי.

שגרת עבודה מומלצת

תדירותפעולותתוצר
יומי, בזמן ניסויבדיקת GPU לפני train; שמירת loss ו-step; בדיקת שתי דוגמאות held-out אחרי runRun log קצר ועדכני
שבועיהשוואת adapter מול base על 5 prompts; ניקוי checkpoints ישנים; עדכון טבלת hyperparametersטבלת ניסויים שמראה מה עבד
חודשיבדיקת freshness ל-Unsloth notebooks, TRL API, Kaggle/Colab limits ו-Ollama import syntaxרשימת שינויים לפני הריצה הבאה

אם אתם עושים רק דבר אחד מהפרק הזה 5 דקות

הריצו smoke test של 20 דוגמאות ושמרו checkpoint ראשון לפני כל run מלא. הפעולה הזו לבדה תחסוך יותר זמן מכל כיוון hyperparameters מוקדם.

בדקו את עצמכם

  1. למה smoke test על 20 דוגמאות טוב יותר מריצה מלאה ראשונה? (רמז: אילו כשלים הוא חושף מוקדם?)
  2. איך gradient accumulation עוזר ל-T4 חינמי בלי להגדיל batch פיזי? (רמז: effective batch מול VRAM)
  3. למה adapter לא ממוזג אינו שקול למודל מלא? (רמז: איפה נמצאים משקלי ה-base?)
  4. איך תזהה/י אם בעיית פלט מקושקש מגיעה מ-chat template ולא מ-quantization? (רמז: בדיקה בתוך notebook לפני export)
  5. למה session quota ו-session ceiling אינם אותו דבר? (רמז: כמה זמן run יחיד יכול להחזיק)

אם ענית נכון על ארבע מתוך חמש, יש לך את המודל המנטלי הדרוש להריץ אימון חינמי בלי להמר על session.

סיכום הפרק

בפרק הזה הפכת dataset מוכן לאימון אמיתי: בחרת זירת GPU חינמית, פתחת notebook של Unsloth, הגדרת LoRA ו-SFTTrainer בצורה שמכבדת T4, שמרת checkpoints, בדקת adapter לפני export, והבאת את המודל ל-Ollama. הרעיון המרכזי אינו ש-Unsloth עושה קסם, אלא ש-run קטן, שמור ומדיד מנצח run גדול שמבוסס על תקווה. מעכשיו יש לך pipeline חינמי שאפשר לשפר, למדוד ולחזור עליו. בפרק הבא נעבור ל-preference tuning, image LoRAs, hosted alternatives והערכה מסודרת שמוכיחה האם המודל באמת טוב יותר מה-base.

Checklist לסיום