הגדרת FSDP (Fully Sharded Data Parallel) לאימון

אימון של מודלים גדולים נתקע בזיכרון ומאט את כל הפרויקט. אנו מגדירים אימון מפוצל מקצה לקצה: בוחרים מצבים, מסירים מגבלות זיכרון ומעבירים לצוות קונפיגורציות ונהלים מוכנים. התוצאה — אימון יציב וצפוי ללא כתיבת קוד מחדש מאפס.

תחומי פיתוח AI

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1365
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • עיצוב לוגו לחברת B2B Advance
    עיצוב לוגו לחברת B2B Advance
    776
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח לוגו חברת AIDER
    פיתוח לוגו חברת AIDER
    1022
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113

FSDP PyTorch: מדוע אימון של מודל גדול נתקע בזיכרון

אימון של מודל גדול לא נתקע במספר הפרמטרים כשלעצמו, אלא במה שכל מאיץ חייב להחזיק אצלו. מצב המודל המלא — משקלים, גרדיאנטים ומצב האופטימייזר — משוכפל בכל התקן באימון מבוזר. מצב האופטימייזר כבד פי כמה מהמשקלים עצמם: עבור כל פרמטר נשמרות כמה כמויות מצטברות.

ברגע שהנפח הכולל מפסיק להיכנס לזיכרון של המאיץ, האימון או נופל עם שגיאת הקצאה, או שמתחילה חסכנות כפויה: מקטינים את גודל הבאץ', מפעילים צבירת גרדיאנטים, מפצלים שכבות ידנית. כל צעד כזה הוא פשרה: יותר זיכרון פנוי, אבל זמן הצעד גדל, וחלק מההתקנים מתבטלים בהמתנה.

FSDP PyTorch מטפל בכך באמצעות שרדינג של מצב המודל: משקלים, גרדיאנטים ומצב האופטימייזר מתפצלים בין ההתקנים במקום להישמר במלואם בכל אחד. לפני חישוב של שכבה הפרמטרים שלה נאספים על המאיצים הנדרשים, ואחר כך משוחררים שוב, בעוד שמצב האופטימייזר נשאר מפוצל באופן קבוע.

בדיוק שם משתחרר רוב הזיכרון, ואימון של מודלים גדולים מפסיק להיות תלוי בשאלה אם המודל נכנס כולו למאיץ אחד.

נפרק כיצד זה נסגר בפועל: אילו מצבי שרדינג לבחור, כיצד להגדיר קבוצות התקנים והיכן לרוב מתבזבזת הביצועים.

מה נותן השרדינג של מצב המודל והאופטימייזר

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

ב-PyTorch FSDP זה מופעל באמצעות מצב שרדינג, ומכאן התוצאה תלויה באופן שבו מוגדרים ההחלפה ונקודות הביקורת.

נבדוק סעיף-סעיף מה משתנה באופן מדיד.

  • גודל הבאץ'. הזיכרון שהתפנה מוקדש לאקטיבציות, ולכן גודל הבאץ' הגלובלי גדל בלי להחליף חומרה. באץ' גדול יותר נותן גרדיאנט חלק יותר ומאפשר להעלות את קצב הלמידה בלי לאבד התכנסות.
  • זמן צעד האימון. החלפת הגרדיאנטים מוסתרת על ידי החישובים, ולכן הצעד מתארך לאט בהרבה מקצב גידול נפח הנתונים. זמן האימון הכולל מתקצר פי כמה, ולא באחוזים.
  • עמידות לתקלות. המצב המשורד נאסף לנקודת ביקורת בלי שכפול, ולכן קריסה של תהליך בודד אינה משמעה אובדן ההתקדמות. נעלם סוג התקלות הקשור לחריגת זיכרון בהתקן אחד.
  • זמן ההתאוששות. הפעלה מנקודת הביקורת האחרונה אורכת דקות: המצב עולה באותו פיצול, והאימון ממשיך מאותו צעד.

כדאי לבדוק זאת על פרופיל העומס שלכם — בארכיטקטורות שונות צוואר הבקבוק נע בין זיכרון האופטימייזר, האקטיבציות ורשת ההחלפה. אנחנו מבצעים מדידות לפני ואחרי, מתעדים את גודל הבאץ', זמן הצעד וזמן ההתאוששות, ורק אז מחשיבים את המצב כמוגדר.

השוואה בין מצבי השרדינג ומגבלותיהם

בחירת המצב נקבעת לפי שני גדלים: כמה זיכרון מתפנה בכל מאיץ ומהי העלות של החלפת גרדיאנטים ופרמטרים. שרדינג מלא מפצל גם פרמטרים, גם גרדיאנטים וגם מצבי אופטימייזר — הרווח בזיכרון הוא המרבי, אבל גם ההעברות הן הרבות ביותר.

קבוצות פרמטרים מאפשרות להוציא באופן נקודתי שכבות בודדות מהשרדינג — אמבדינגים, שכבות נרמול, הראש הפלט — כאשר הפיצול שלהן מייצר יותר החלפות מאשר חיסכון. להלן שלושה מצבים והגבולות שמעבר להם כל אחד מפסיד.

מצב מתי מתאים מה אינו יודע
שרדינג מלא המודל אינו נכנס למאיץ אחד: מתחלקים הפרמטרים, הגרדיאנטים ומצבי האופטימייזר ההחלפה בכל צעד היא מרבית; בחיבור בין-התקני חלש המאיצים מתבטלים בהמתנה
שרדינג היברידי מספר צמתים: בתוך הצומת התעלה מהירה, בין הצמתים איטית יותר דורש חלוקה של העולם לקבוצות בכפולה של מספר המאיצים בצומת; בחלוקה שגויה הרווח אובד
נקודתי, רק גרדיאנטים המודל נכנס לזיכרון, אבל נדרש מרווח לאקטיבציות ולכוונון עדין הפרמטרים ומצבי האופטימייזר נשארים משוכפלים — החיסכון בזיכרון נמוך בהרבה

את המצב מקבעים לפי מדידות, ולא לפי תיאור: בוחנים את חלק הזמן בהחלפה ואת ניצול הזיכרון בגודל הבאץ' העובד. ב-PyTorch מעבר בין מצבים הוא החלפה של הגדרות ה-wrapper, ואין צורך לשכתב את המודל עצמו.

כיצד מתבצעת ההטמעה: מהאודיט ועד למסירה לצוות

אימון של מודל גדול נתקע בזיכרון של מאיץ אחד, ולכן את מצב המודל והאופטימייזר מפזרים על כמה מאיצים. במעבר הזה צפות שגיאות הגדרה: אי-התאמה בין מצבי הדיוק, העברות מיותרות בין ההתקנים, סטייה בהתכנסות לעומת ההרצה הקודמת. את ההטמעה מובילים בצעדים קצרים, שכל אחד מהם מאומת במדידה.

  1. אודיט של הגדרות האימון. מפרקים את המתכון הנוכחי: גודל הבאץ' והפיצול שלו, מצב הדיוק, הרכב השכבות, מתזמן קצב הלמידה. מתעדים קו בסיס — זמן הצעד, צריכת הזיכרון, עקומת ההתכנסות בהרצה קצרה.

  2. תוכנית שרדינג. מחליטים מה לפזר בין ההתקנים: פרמטרים, גרדיאנטים, מצב האופטימייזר, ומה להשאיר משוכפל. קובעים אילו בלוקים לעטוף בשלמותם כדי לא לשלם על החלפות מיותרות.

  3. הגדרת FSDP. מרכיבים הגדרה לתוכנית הנבחרת: מדיניות העטיפה, סדר בניית הפרמטרים מחדש, צבירת גרדיאנטים. בודקים שההרצה משוחזרת על אותו מספר התקנים.

  4. בדיקת התכנסות על המשימה האמיתית. משווים לקו הבסיס לפי צעדים, ולא רק לפי המדד הסופי: סטייה בהתחלה מצביעה על דיוק או על סדר ההחלפה. מתקנים עד ליציאה להרצה מלאה.

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

  6. מסירה לצוות. מוסרים הגדרות, תרשים שרדינג, נוהל הפעלה וניתוח תקלות, ומבצעים הרצה משותפת על הסטנד שלכם. מכאן והלאה המהנדסים משנים את המתכון בעצמם.

הגדרות, תרשימים ונוהלים שהלקוח מקבל

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

  • הגדרות הפעלה — פרמטרים של האימון ושל פיצול המודל במערכת לניהול גרסאות: שינויים עוברים אישור ולא נערכים ישירות על השרת, ולכן כל הרצה ניתנת לשחזור.
  • תרשימי שרדינג — כיצד FSDP ב-PyTorch מפזר פרמטרים ומצבי אופטימייזר בין ההתקנים וכמה זיכרון הוא שומר, בתוספת חישוב עבור המודל שלכם ומספר הצמתים.
  • מדיניות גישה — מי רשאי להפעיל אימון, לשנות הגדרות ולהוציא משקלים; התפקידים מופרדים, והגישה לנתונים ולארטיפקטים היא מינימלית הכרחית.
  • נוהל התאוששות — תדירות נקודות הביקורת, תקופת השמירה וסדר ההפעלה מחדש מהנקודה האחרונה שנשמרה לאחר תקלת צומת.
  • תיעוד — פריסה מאפס, תיאור ההגדרות והספים שבהם האימון מתדרדר, ניתוח של שגיאות אופייניות.
  • נראות — עקומות הפסד ותפוקה לפי צעדים: מיד רואים אם האימון נתקע בנתונים, ברשת או במאיץ.

בסך הכול זה אינו אוסף סקריפטים, אלא תהליך בר-שחזור: אפשר למסור אותו לצוות אחר או לחזור אליו כעבור שנה בלי ארכיאולוגיה.

מקרה בוחן: אימון של מודל גדול הפסיק להיתקע בזיכרון

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

מה היה לפני

מדידת בסיס על המשימה האמיתית: צעד אימון ארך כ-3.8 שניות, 6 הרצות מתוך 10 הגיעו בהצלחה לנקודת הביקורת, והשאר נפלו בגלל זיכרון. במהלך שבוע עבודה הצטברו 12–14 תקלות כאלה, חלק מהמאיצים התבטלו, וחידוש אחרי תקלה דרש הרכבה ידנית של המצב. הגדלת הבאץ', שהייתה משפרת את ההתכנסות, הייתה בלתי אפשרית עקרונית.

מה שינו

האימון הועבר ל-FSDP ב-PyTorch — פרמטרים, גרדיאנטים ומצבי אופטימייזר משורדים בין ההתקנים, ולכן העתקה מלאה של המודל אינה חייבת עוד לשכון בזיכרון של מאיץ אחד.

בנוסף הפעילו חישוב מחדש של אקטיבציות במעבר קדימה, איזנו את גדלי הבאץ' בין הצמתים והעבירו את שמירת נקודות הביקורת לצורה משורדת — המצב נאסף רק בעת החידוש.

מה נהיה

זמן צעד האימון הצטמצם ל-2.1 שניות, שיעור ההרצות המוצלחות עלה ל-10 מתוך 10, וכבר חודש אין נפילות בגלל זיכרון. הצלחנו להכפיל את גודל הבאץ' — ההתכנסות נעשתה חלקה יותר, והחזרה לנקודת הביקורת הקודמת אורכת דקות במקום הרכבה ידנית. אנחנו מודדים מדדים כאלה בכל פרויקט: הם מראים אם הגדרת הפיזור השתלמה.

במה שונה FSDP PyTorch מאימון מבוזר רגיל?

מקביליות נתונים קלאסית מחזיקה העתקה מלאה של המודל בכל מאיץ: התהליכים לוקחים חלקים שונים של הבאץ', מחשבים גרדיאנטים ומסנכרנים אותם לפני צעד האופטימייזר. כל עוד המשקלים, מצבי האופטימייזר והאקטיבציות נכנסים לזיכרון של התקן אחד, הסכמה מתקננת כמעט ליניארית. ברגע שהמודל גדל, ההעתקות מפסיקות להיכנס במלואן — והוספת התקנים כבר לא עוזרת.

מקביליות מודל פותרת את הבעיה אחרת: שכבות או בלוקים נחתכים בין ההתקנים, וכל אחד מחזיק רק את חלקו במשקלים. המחיר — פיצול ידני, איזון עומסים והעברות מתמידות של אקטיבציות בין השלבים. גישה כזו מרחיבה את נפח המודל, אבל עוברת בקושי בין ארכיטקטורות ודורשת דיבוג נפרד לכל אחת.

FSDP PyTorch תופס עמדת ביניים. פרמטרים, גרדיאנטים ומצבי אופטימייזר משורדים על פני כל תהליכי הקבוצה: לפני החישוב השכבה נאספת במלואה, ואחריו משוחררת.

בכל מאיץ חי באופן קבוע רק חלק ממצב המודל, ולא העתקה מלאה, ובמקביל לולאת האימון נשארת מוכרת — עוטפים את המודולים, ומכאן העבודה ממשיכה כמו עם מודל רגיל.

מכאן גם הקריטריון למתי ליישם: מודל קטן ובינוני — מקביליות נתונים, פחות החלפות ודיבוג פשוט יותר; מודל שאינו נכנס לזיכרון של מאיץ אחד גם עם צבירת גרדיאנטים — שרדינג של המצב. עבור רשתות עמוקות במיוחד יש היגיון בשילוב: FSDP בתוך הצומת, מקביליות נתונים בין הצמתים.

ההבדל בין הגישות מצטמצם לשאלה אחת — מה מרחיבים: את התפוקה של ההעתקות, את נפח המצב, או את שניהם בבת אחת.

ספקות טכניים לפני הפעלת אימון משורד

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

FSDP ב-PyTorch אינו דורש לשכתב את הארכיטקטורה: הוא מתחבר באמצעות מדיניות עטיפה מעל המודולים, בעוד האופטימייזר ולולאת האימון נשארים במקום. בנפרד אנחנו בודקים את דרישות החומרה: הגבול של ההרחבה הוא לרוב ההחלפה בין הצמתים, ולא נפח הזיכרון בהתקן.

האם FSDP יתאים למודל שלנו?

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

מה לעשות עם נקודות הביקורת המצטברות?

הקבצים הישנים נשארים תקפים: מפרקים אותם לפי שכבות ומרכיבים לפורמט משורד בסקריפט נפרד, והמרה הפוכה מאפשרת חזרה להרצה לא מפוצלת. הבדיקה — השוואת פלט המודל לפני ואחרי ההמרה על צעד אחד.

האם החיבורים בין הצמתים יספיקו ומה לעשות עם דיוק מעורב?

מודדים את חלק הזמן בהחלפה בין הצמתים: אם הוא גדל, מגדילים את גודל השרד ומצמצמים את מספר הסנכרונים. דיוק מעורב מופעל ברמת העטיפות; הסיכון בחישוב מחדש של הנרמול מוסר על ידי המרת טיפוסים בגבולות הבלוקים והרצה קצרה.

נדון במשימה: מה להבהיר לפני תחילת העבודה

ככל שהנתונים הראשוניים על המשימה קונקרטיים יותר, כך יש פחות הנחות באומדן. אין לנו צורך בגישה לפרודקשן בשלב הזה — די בתשובות לשאלות שלהלן כדי להבין את היקף העבודה והסיכונים.

  • לולאת האימון הנוכחית: על מה היא רצה כעת, אילו צווארי בקבוק כבר נראים — מחסור בזיכרון בהתקן, בטלה של מאיצים, הפסקות ארוכות בשמירת המצב.
  • גודל המודל והרכב הזיכרון: כמה פרמטרים, אילו שכבות הן הכבדות ביותר, ומה בדיוק לא נכנס — משקלים, גרדיאנטים, מצבי אופטימייזר או אקטיבציות ביניים.
  • הגדרות החומרה: מספר המאיצים, כיצד הם מחוברים זה לזה, תפוקת תעלת התקשורת — מכך תלוי בחירת תרשים השרדינג והאם הוא ישתלם.
  • תרשים הפריסה: מה מפזרים בין ההתקנים, אילו בלוקים משאירים בשלמותם בכל אחד, והאם נדרשת בנייה מחדש בשינוי מספר הצמתים.
  • עבודה עם צ'קפוינטים: באיזו צורה שומרים את המצב, האם נדרש חידוש האימון מאותה נקודה לאחר תקלה וכמה מהר הוא צריך לקרות.
  • תרחיש תקלה: מה נחשב סביר — אובדן צעד, הפעלה מחדש מנקודת הביקורת האחרונה, התאוששות על מספר קטן יותר של התקנים.
  • קריטריוני קבלה: לפי אילו מדדים שופטים את התוצאה — זמן הצעד, האצה עם גידול מספר ההתקנים, התכנסות והאיכות הסופית של המודל.

מכאן אנחנו חוזרים עם אומדן ותוכנית: היקף העבודה, לוחות זמנים, הרכב הצוות ונקודות בקרה. עבור FSDP ב-PyTorch אנחנו מציעים כסעיף נפרד הרצת פיילוט על המודל שלכם ועל קטע נתונים אמיתי — היא מראה את ההאצה בפועל ומסירה שאלות של תאימות לפני תחילת העבודה העיקרית.

תארו את המשימה כפי שהיא — בטיוטה, בלי הכנה. את שאלות ההבהרה נשאל בעצמנו, ואת לוחות הזמנים וגבולות האחריות נתעד לפני ההתחלה.