close menu

איך CHATGPT רץ כל כך מהר?!

למה כשאני מריץ את המודל הקטן והמעפן שלי זה לוקח רבע שעה.
אבל איכשהו ChatGPT מחזיר תשובה תוך שניה וחצי?!

עם כל 175 מיליארד הפרמטרים שלו!

מדריך: איך מריצים מודלי ענק?

די נו. מה הטריק?
די ברור שהמודלים של OpenAI מוחזקים בזכרון כל הזמן והמשימות נכנסות אליהם בתורים כלשהם כשאנחנו שולחים בקשות דביליות לזמזם מכתב אהבה באסמבלי כיאילו הוא נכתב על ידי אדם שמעולם לא ראה מחשב.

התורים גם מסבירים למה יש הבדל בזמני הפרדיקציה של GPT-3 אם משתמשים בהיפרפרמטרים לא סטנדרטים. נסו ותראו.

ללא כל קשר לתור המשימות, המודל עדיין פשוט עובד מהר מידי.

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

קוונטיזציה

ישנן בגדול שתי גישות עיקריות לקוונטיזציה היום:
קוונטיזציה לאחר האימון: מודל מאומן תחילה ולאחר ממירים את המשקולות להיות מטיפוס שונה (בדרך כלל Precision נמוך יותר).
אימון מודע לקוונטיזציה (Quantization-Aware Training): אימון מודע לקוונטיזציה מדמה את התנהגות המודל בPrecision נמוך בהרצה קדימה בעוד שבמעבר אחורה המודל נשאר זהה. הטריק הזה גורם לשגיאת קוונטיזציה כלשהי להגיע אל האופטימייזר ומכאן שהאופטימיזר מנסה לצמצם אותה בזמן עדכון המשקולות. זה הופך את הפרמטרים של המודל לעמידים יותר לקוונטיזציה והופך את תהליך הקוונטיזציה לאחר האימון להרבה יותר יציב.
איך טרנספורמרים עובדים? – ערכים חריגים באקטיבציות
קוונטיזציה פשוטה של טרנספורמרים לאחר האימון מובילה לירידה משמעותית בביצועים בעיקר בכלל טווח הערכים הרב של אקטיבציות המודל.
בשנים האחרונות שוחררו מספר מחקרים [1] שהבחינו בערכים חריגים המתפתחים בתוך המודל המאומן בזמן ההפעלה
למשל: לקלט ולפלט של שכבת הFFN יש טווחים שונים מאוד בגלל שבטנזור הפלט מופיעים לפעמים ערכים חריגים. אם נקוונטט את הטזנזורים: נהרוס את אותם ערכים חריגים.
ולכן ככל שנגדיל את המודל עוד ועוד (למיליארדי פרמטרים) הערכים החריגים יתחילו להופיע יותר ויותר בכל שכבות המודל, מה שגורם לכישלון יותר חזק של הקוונטיזציה. מחקר מאד מעניין בתחום [2] צפה בתופעה כזו עבור דגמי OPT הגדולים מ-6.7B פרמטרים. למודלים גדולים יותר בעלי יותר שכבות ערכים חריגים קיצוניים ולהם יש יש השפעה משמעותית על ביצועי המודל כולו. במספרים: ערכים חריגים עלו יכולים להגיע גם לפי 100 מהערכים האחרים.
קוונטיזציה לאחר אימון:
הדרך הפשוטה ביותר לפתרון בעית הערכים החריגים היא לבצע קוונטיזציה בכמה Precision שונים: דיוק שונה למשקולות ולאקטיבציות.
אחד המאמרים החלוצים בנושא [3] הניח שמשקלי המודל בכל שכבה מתפלגים גאוסית ולכן בחר לזהות ערכים חריגים על ידי השוואת ממוצע וסטיית תקן בכל שכבה. ערכים חריגים נשארים כמו שהם בעוד שערכים אחרים מפוצלים לBins והסטנטרואידים של הBins רק הם נשמרים.
בהתבסס תצפית זו (רק שכבות אקטיבציה מסוימות (למשל residuals לאחר FFN) גורמים לירידה גדולה בביצועים) מאמרי המשך [4] ביצעו קוונטיזציה בכמה רמות דיוק שונות: קוונטיזציה של Float16 על האקטיבציות ו8-ביט על על כל השאר.
מאמר הדגל: ()LLM.int8:

המאמר הוא זה שנכנס לכל המודלים בHuggingface

לפני כמה חודשים..

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

..שוחרר מאמר מוצלח מאד על קוונטיזציה שפתח את הדלת להפעלת קוונטיזציה על כל מודל שרק תרצו. המאמר: ()LLM.int8 [הלינק למטה לכל המאמרים: [5]]
הרעיון הולך ככה: מכיוון שכפל מטריצות מכיל תוצאת מכפלות רבות בלתי תלויות בין וקטורי שורה ועמודה, אנו יכולים להפעיל קוונטיזציה בלתי תלויה לכל מכפלה פנימית: כל שורה ועמודה עוברים Scale ורק לאחר מכן מומרים ל-INT8.
האקטיבציות החריגות (למשל, גדולות פי 20 מערכים אחרים במודל) נשארות ב-Float16 אבל הן מייצגות רק חלק זעיר מהמשקולות במודל ולכן לא מוסיפות הרבה לצריכת הזכרון הכוללת של המודל.
קוונטיזציה עדינה
סתם לקחת משקולות ולשנות להן את הtype לא מוביל לתוצאות מי יודע מה, דרכים איכותיות יותר לבצע קווניטיזציה מבוססות על שיטות שמחלקות את הטנזורים לחלקים שונים ומפעילות על כל אחד מהחלקים פעולות אחרות.
מכיוון שלא כל הערכים במודל מגיעים בטווחים שווים (ולכן להם גם חשיבות שונה), פותחו מספר שיטות שונות לביצוע קוונטיזציה לחלקים שונים במודל בצורה שונה:
למשל Q-BERT הוא מודל בו ביצעו קוונטיזציה ברמת ראשי האטנשן השונים כשכל ראש היה ישות נפרדת ולאחר מכאן בוצעה קוונטיזציה מלאה מבוססת הסיאן לכולם יחד.
עוד רעיון בנושא הוא קוונטיזציה פר קבוצת אמבדינגס (Per-embedding group), הרעיון בשיטה הוא שערכים חריגים מופיעים רק בחלק מהממדים ולכן לפני ביצוע הקוונטיזציה ממיינים את מימדי האמבדינגס לקבוצות לפי ערכיהם ואז מבצעים קוונטיזציה בתוך כל אחת מהקבוצות בצורה שהכי מתאימה לאותם הערכים.
קוונטיזציה עם מידע מסדר שני
במאמר של Q-BERT פיתחו את השיטהHessian AWare Quantization עבור הקוונטיזציה שלה ברמת דיוק מעורבת. הרעיון הוא שפרמטרים בעלי ערך עצמי גבוה במטריצת ההסיאן רגישים יותר לקוונטיזציה ולכן דורשים דיוק גבוה יותר. כך בעצם גם אפשר לזהות חריגים.
שיטה נוספת היא GPTQ – מתייחסת למטריצת המשקולות כאוסף של וקטורי שורות ומפעילה קוונטיזציה על כל שורה בנפרד. בנוסף: GPTQ מפעילה קוונטיזציה על משקולות נוספות שנבחרות Greedy כדי למזער את שגיאת הקוונטיזציה.
אימון מודע קוונטיזציה (Quantization-aware training)
אימון מודע קוונטיזציה ממזג את פעולת הקוונטיזציה לתוך תהליך האימון. הוא לומד את משקולות המודל בייצוג Precision נמוך ישירות ומוביל לביצועים טובים יותר אבל במחיר קטן של עוד חישובים.
הגישה הפשוטה ביותר היא לאמן Fine Tuning את המודל לאחר קוונטיזציה על סט אימון זהה או סט אימון שמייצג את סט האימון עליו בוצע האימון הראשוני. מטרת האימון יכולה להיות זהה לזו של אימון מקדים (למשל NLL/MLM באימון מודלי שפה כללים) או ספציפית למשימה אחרת שאכפת לנו ממנה.
דיסטילציה למודל בPrecision נמוך:
גישה נוספת לבצע קוונטיזציה היא להשתמש במודל בדיוק הגבוה כמורה ובמודל בדיוק הנמוך כתלמיד, ולאחר מכן לאמן את המודל בעל הדיוק הנמוך עם לוס דיסטילציה. בדרך כלל בדיסטילציה אין צורך להשתמש בכל סט אימון המקורי, המטרה היא לאמן את התלמיד להיות כמו המורה. מספיק להפעיל את המודל על דאטהסט "מספיק מייצג" על מנת לדעת איך מתנהג עליו. לדוגמה: הדאטהסט המפורסם של ויקיפדיה יכול להיות בחירה טובה טובה אבל אפילו טוקנים אקראיים יכולים להביא את מודל התלמיד לביצועים לא רעים בכלל. ישנן כל מיני שיטות וטריקים כדי לעשות את התהליך הזה כמה שיותר מדויק, אחת מהן [6] היא למשל לעבור שכבה שכבה ולבצע דיסטיליציה לשכבות אחת אחת מהמורה אל התלמיד.

גיזום – Pruning

מטרת הגיזום היא להקטין את גודל המודל על ידי מחיקה של משקולות או חיבורים חסרי חשיבות תוך כדי שמירה על ביצועי המודל עד כמה שניתן.
שיטות גיזום מודרניות בדרך כלל מנסות לשמור על כפל מטריצות צפופות שחלק מהערכים בהן הם אפסים. כדי להנות מהאצות אופטימיזצית החומרה המודרנית בדרך כלל גם מנסים לשמור עליהם בדפוס מסוים בתוך המטריצה.
על מנת להנות מכל העולמות (גם מהירות וגם ביצועים) שיטות גיזום מודרניות בדרך כלל פועלות בצורה הבאה:
  • אימון רשת עד התכנסות
  • גיזום משקולות הרשת והקטנתה
  • אופציונלי: אימון נוסף של הרשת הקטנה על מנת לשחזר את ביצועי הרשת הגדולה.
איך גוזמים בכלל?
גיזום לפי גודל היא שיטת הגיזום הפשוטה ביותר – משקולות עם הערכים המוחלטים הקטנים ביותר: נמחקות. זה עובד, זה קל וזה מגיע לביצועים די טובים (ואפילו זהים לשיטות מסובכות יותר).
עוד שיטות גיזום למשל מציעות לבצע גיזום בזמן האימון [7] כך שהרשת הולכת וקטנה לאורך האימון. באותה העבודה נמצא שרשתות שנגזמות בצורה כזו מגיעות לביצועים גבוהים יותר מאשר רשתות שנגזמות לאחר האימון. הרעיון הכללי הוא שכל כמה צעדים (היפרפרמטר) המשקולות בעלות הערכים המוחלטים הקטנים ביותר מאופסות בזמן האימון.
שיפור של שיטה זו הוא גיזום איטרטיבי [8]: הרעיון פשוט: נחזור על שלב 2 (לגזום) ושלב 3 (אימון מחדש) מספר פעמים בלולאה: התהליך חוזר על עצמו עד שמגיעים לגודל המודל הרצוי.
טריק שמשפר ביצועי גיזום:
במאמר מ2020 [9] הכותבים גילו שלאחר גיזום משקולות, ניתן לקבל ביצועים טובים יותר על ידי "חזרה אחורה" של המשקולות שלא נגזמו לערכים בשלב מוקדם יותר באימון.

עידוד דלילות בזמן האימון

דרכים לעודד דלילות משקולות בזמן האימון:
היה נחמד אם היה לנו איזה טריק כך שעוד כשנאמן את הרשת נוכל לדחוף אותה להיות כמה שיותר דלילה (ואז נוכל לגזום אותה).
ישנן שתי גישות עיקריות על מנת לעודד דלילות במשקולות המודל המאומן:
  • עידוד דלילות המשקולות עצמן בזמן האימון
  • עידד ברמת שכבות המודל (Mixture Of Experts)
האצה חומרתית: N:M Sparsity באמצעות גיזום
חומרה מודרנית תומכת בדלילות N:M כל N מתוך M רכיבים עוקבים הם אפסים. לדוגמה, ה Nvidia A100 מכיל בתוך ה GPU חומרתית תמיכה ב האצת דלילות 2:4.
כדי לעודד דלילות ברשת, אנבידיה הציעו [10] לאמן את הרשת, לאחר מכן לבצע גיזום ליחס המתאים בו נקבל את ההאצה החומרתית ואז לאמן שוב את המשקולות הגזומות של הרשת. כך נקבל רשת קטנה וחזקה מאד שנהנית מהאצה חומרתית משמעותית ברמת החומרה.
אפשר לדחוף את הרעיון הזה אפילו יותר רחוק: אם נשחלף עמודות במטריצה וגם נדאג לשחלף שורות ועמודות במטירצות אחרי ברשת בצורה המתאימה נקבל שתוצאת כפל המטריצות תשאר אותו הדבר. במאמר משנה שעברה [11] חקרו את הנושא לעומק והצליחו להגיע להאצה משמעותית בביצועים באמצעות הטריק הזה.
באותו המאמר גם הציעו שיטה Greedy למציאת השחלוף האופטימלי שיביא להאצה הגדולה ביותר בביצעי המודל.
גזירה באימון המעודד דלילות:
במאמר מהשנה שעברה [12] הציעו שיפור לאלגוריתם האימון תחת קוונטיזציה כך שהאימון יכיל גם גיזום לפי ערך מוחלט ודלילות הגדלה לאורך האימון. הרעיון הוא שכלל העדכון כך שיכיל Masking שנעודד אותו לא להשתנות "יותר מידי" (היפרפרמטר) בזמן האימון ולאורך האימון נשנה את מידת ההשפעה של האימון על הפמטרים אותם החלטנו לגזום בשלב כלשהו בזמן האימון. אלגוריתם הלמידה תחת קוונטיזציה הוא Straight-Through Estimator ושיפור האלגוריתם נקרא Sparse-refined STE – לאלו שרוצים להמשיך לחפש ולקרוא.
שיטה נוספת [13] נקראת Top-KAST ומטרתה היא לשמר דלילות לאורך כל האימון גם במעבר קדימה וגם במעבר אחורה ברשת.
הרעיון פשוט מאד:
  • בהרצה קדימה: נבחר את הTop K פרמטרים בעלי הערך העצמי הגבוה ביותר ורק אותם נעדכן
  • בהרצה אחורה: נעדכן רק את הTop K פרמטרים בעלי הערך העצמי הגבוה ביותר.
כך אנו דוחפים את הרשת לדלילות לאורך האימון.
כמות הפרמטרים לעדכון באימון (כמה K פרמטרים מתוך כל הפרמטרים) הוא פרמטר המשתנה לאורך האימון כך שבתחילת האימון לרשת מותר להשתמש בכל הפרמטרים שלה ולאורך האימון אנו מדללים אותה יותר ויותר.
וכדי למנוע מצב של פידבק בו פרמטרים גדולים רק גדלים יותר ויותר כשכל השאר איתם מקבלים הזדמנות, מאמנים את הרשת עם רגולריזצית Weight Decay כך שלגרדיאנטים יש דחיפה להתפצל על כמה שיותר משקולות בתוך הרשת ולחקור כמה שיותר פרמטרים לעדכון הרשת.
הטרנספורמר הדליל – Sparsified Transformer
במאמר משנה שעברה [13] שינו הכותבים חלקים ספציפיים ברשת ובכך הצילו להגיע להאצה של פי 37 (!!) בביצועי הרשת תוך פגיעה מזערית בביצועים:
שכבת FFN דלילה: כל שכבת FFN חלשה מכילה 2 MLP ו-ReLU אחד ביניהן (שימו לב, אין אף ReLU בטרנספורמרים מודרנים) מכיוון ש-ReLU גורם להרבה אפסים, נוצרים הרבה אפסים באופן טבעי באקטיבציות המודל דפוס הדלילות הוא דינמי ושונה עבור כל טוקן.
הטריק הגדול הוא הוספה של שכבת Controller הבוחרת מתוך מטריצת הFNN אילו שורות יש לטעון לזכרון בכפל המטריצות הבא. היא עושה זו על ידי שימוש בGumbel-softmax כך היא יכולה להכיל סופטמקס ולגזור אותו בתוך הרשת בזמן האימון. [14]
שכבת אטנשן דלילה: בשכבת האטנשן המימד מחולק לכמה מודולים שונים בזמן החישוב, הרעיון המרכזי אותו ננצל הוא שנוסיף שכבת מכפלה נלמדת שתלמד לבחור בשבילנו באילו ערכים נשתמש בזמן חישוב האטנשן. לאחר הפעלת שכבה זו מעבירים את תוצאת חישוב הכפלה דרך שכבת קונבולוציה דו מימדית המורידה את מימד הפמרמטרים אפילו יותר כך שכשמופעלת שכבת האטנשן עצמה עליה לפעול על כמות פרמטרים קטנה במיוחד ביחס להפעלה המלאה.

רשתות מומחים – Mixture Of Experts

הרעיון הוא כזה: נקצה בעצמנו מראש חלקים שונים ברשת שיתמחו בתת משימות שונות ומשונות לפי איך שנרצה ואז נוכל בזמן האימון לטעון את אותם החלקים בהתאם למה שנרצה (או שנוכל "לתת" לרשת יכולות על ידי כך שנוסיף חלקים שונים לרשת בזמן ההפעלה)
שימוש בטריק זה על מנת להאיץ את ביצועי הרשת הוא שמכיוון שכל חלק ברשת צריך רק כמה "מומחים" ולא את כולם, נוכל ללמד שכבה מיוחד התדע לבחור בזמן ריצה אילו מומחים לטעון ובכך פעולת החישוב תקטן במיוחד.
עם ארכיטקטורה זו רק חלק מהפרמטריםמנוצלים בזמן ההפעלה ולכן נחסכים הרבה מאד חישובים בזמן הפעלת המודל. ניתן גם להתאים את הקיבולת של כל תת רשת עם היפרפרמטר וכמות תת הרשתות המופעלות לכל טוקן וטוקן כך שהרעיון כולו מאפשר שליטה גדולה על הרשת.
שיפור אסטרטגית הניתוב בMoE
לשכבת MoE נוספת בדרך כלל שכבת ניתוב המקצה תת קבוצות של מומחים לכל סוג טוקן ברשת.
שיפור לשיטה זו V-MoE מגיע במאמר הטרנספורמר לתמונות V-MoE [15] המוסיף שכבות MoE לתוך ViT (Vision Transformer). בצורה זו הם שמרו על ביצועי הSOTA אבל השתמשו רק בחצי מכוח החישוב הנדרש על מנת להשתמש ברשת.
מכיוון שלכל מומחה יש יכולת מוגבלת מבחינת כמות הטוקנים אותה הוא יכול להכיל נוצר מצב שבשלבים מסוימים ברשת חלק מהטוקנים נזרקים החוצה ללא חישוב, ישנן עבודות המדברות על סדר חשיבות הטוקנים ברשת אבל בגדול זאת בעיה. כדי למנוע חיסרון זה במאמר של V-MoE נכנס שיפור בו המומחים מקבלים ניקוד חשיבות הנקבע על פי כמות הניתובים המגיעים לאותו המומחה מהטוקנים השונים, גישה זו מבטיחה שהטוקנים החשובים ביותר יקבלו חישוב בסבירות הגבוהה ביותר ובכך חוסך את בעית האינפורמציה החסרה.
הטריק הזה עובד הרבה יותר מאשר ניתוב קלאסי ומביא את ביצועי רשתות המומחים לביצועים זהים לרשתות הצפופות (תוך חסכון משמעותי בכוח החישוב).
עוד יתרון מגניב של השיטה כשהיא פועלת על תמונות הוא שניקוד החשיבות מראה לנו על איזו איזורים בתמונה הרשת מסתכלת בכל שכבה (כי הטוקנים מגיעים מיקומים קבועים) במאמר הבחינו ששכבות מוקדמות הן כלליות יותר, בעוד שכבות מאוחרות יותר יכולות להיות מיוחדות עבור מחלקות תמונה ספציפיות.
מומחים לצרכי משימה ספציפית:
בעוד עבודה מהשנה שעברה [16] השתמשו ברשתו תמומחים הלוקחות בחשבון את המידע על המשימה אותה יש לפתור ומנתבות חלקים ברשת למומחים שונים ברמת המשימה ולא ברמת הטוקן.
למשל במאמר הראו את הדוגמה הפשוטה של תרגום בין שפות כשיש מומחים המבינים בשפות ספציפיות ורק בהם נעשה השימוש בזמן האימון כשהמודל נחשף לשפה ספציפית.
יתרון של שיטה זו ברור: ניתוב ברמת הטוקן הוא דינמי והחלטת הניתוב עבור כל טוקן מתקבלת בזמן החישוב. לפיכך, בזמן הפעלת הרשת עדיין על השרת לטעון מראש את כל המומחים. לשם השוואה, ניתוב ברמת המשימה הוא סטטי בהינתן משימה קבועה, כך ששרת ההפעלה של הרשת עבור משימה ספציפית צריך רק לטעון מראש רק מומחים לאותה המשימה (למשל, תרגום אנגלית-עברית: אם יש מומחים ש"יודעים" עברית ומומחים ש"יודעים" אנגלית אז אין סיבה שנטען מומחים ש"יודעים" צרפתית אם זו לא המשימה שלנו). לפי הניסוים שלהם, בדאטהסט שהם בדקו בו עם הרשתות שהם בדקו איתן הביצועים ברמת המשימה זהים לביצועים ברמת הטוקן.
מבנה רשת מומחים:
בעבודה שפורסמה השנה..

אני מתייחס ל2022 כהשנה כי בRolling Window של שנה אחורה: עדיין "השנה".

..הוצעה ארכיטקטורה מיוחדת המשלבת מומחים ברשת [17] – לכל טוקן בנוסף למעבר דרך המומחים המוקצים לו מוקצה גםMLP המשותף לכל המומחים ובנוסף מניסוים בשיטה עולה שמומחים בשכבות מאוחרות יותר תורמים יותר ברשת, כמות המומחים משתנה בין השכבות כך שבשכבות מאוחרות יותר ברשת יש יותר מומחים. המאמר מומש בספריית DeepSpeed במקביליות מרובה.
הרצה מקבילית במספר מכונות:
אפשר לטעון רשתות מומחים למספר מכונות במקביל אבל כשמספר הGPUs גדל גם מספר המומחים בכל GPU יורד ואז מתחילו להווצר בעיות צוואר בקבוק בתקשורת בין המכונות. תקשורת בין מומחים על פני מספר GPUs בכמה מכונות שונות מסתמכות על ממשקי NCCL שאינם נהנים מהמהירות הגבוהה של ממשקי GPUs באותה המכונה כמו NVLink, HDR InfiniBand. מכיוון שככל שמגדילים את כמות היחידות בתוך השכבות, עולה הצורך לפצל שכבות ספציפיות לכמה מכונות ומכשירים בעית התקשורת הולכת ונהפכת לקשה יותר ויותר ובקנה מידה גדול מתקבלת הרבה תקשורת של "כל המכונות לכל המכונות" המשאירה את המכונות בנצילות נמוכה מאד.
ישנם מגוון שיפורים על מנת לבנות רשתות מומחים המתאימות מראש לעבודה מקבילית כך שעלות התקשורת תהיה זולה ומהירה כמה שיותר.

ספריית DeepSpeed

בספריה הפופולרית להרצת רשתות ענקיות DeepSpeed [18] יושם אלגוריתם היררכי לצורך תקשורת הכל-להכל, האלגוריתם מבוסס-עץ, המפעיל תקשורת תוך-GPU באותה המכונה בין כולם לכולם ורק אחרי כן תקשורת GPU בין מכונות לכל המכונות. שינוי קטן זה מכפיל (!!!) את ביצועי הרצת מודלי ענק בכל שהוא מקטין משמעותית את תנועת התקשורת: כל GPU צריך לחכות קטן משמעותית מכיוון שהתקשורת מתבצעת קודם כל בתוך המכונה ורק החלקים המחייבים תקשורת בין המכונות נשלחים על גבי הרשת.
מעקב אחר כמות הדגימות המשתמשות בכל מומחה באופן דינמי
מאמר נוסף מהשנה האחרונה [19] מתאים את המשאבים החישוביים ביחס לעומקי העבודה על כל מומחה.הוא מרכיב גרף חישוב ומקצה מחדש משאבים רק בעת הצורך לכל מומחה. הוא עושה זאת על ידי מדידת כמות הדגימות המוקצות לכל מומחה ומתאים את קיבולת העבודה של המומחים באופן דינמי על מנת להפחית את דרישות הזיכרון וזמן הריצה. בהתבסס על ניסוים, נראה שהקצאות העומס על כל מומחה מתכנסות בשלב מוקדם בזמן האימון ולכן נוסף לאלגוריתם גם זכרון נקבע להיות קבוע לאחר התכנסות זו ובכך חוסך גם את רשת הניתוב.

אופטימיזציה לארכיטקטורת הרשת

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

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

  • חלוק רצפי קלט לבלוקים בגודל קבוע
  • במאמר של Image Transformer משתמשים בתשומת לב מקומית [20]
  • הטרנספורמר הדליל – Sparse Transformer משתמש בדפוסי אטנשן עם Stride [21]
  • הטרנספורמר הארוך: Longformer משתמש בחלונות אטנשן עם Dialation rate [22]
  • הרחבת אטנשן קיים לאטנשן לינארי גלובלי דליל: Linear Global Sparse גורם לשכבות אטנשן של מודלים מאומנים מראש להיות חזקות במיוחד ברצפים ארוכים (גרסת רוברטה של אטנשן זה ניצחה תחרות בקאגל) [23]
אטנשן מקומי:

מאפשר הסתכלות מקומית על איזורים ספציפים בקלט:

  • בטרנספורמר הדליל משולב אטנשן מקומי עם Stride
  • בטרנספורמר Axial במקום להפעיל אטנשן על כל הרצף מפעילים כמה שכבות אטנשן במימד נוסף [24]
  • במודל BigBird יש כמה סוגי אטנשן: אטנשן גלובלי, אטנשן רנדומלי ואטנשן עם Sliding window [25]

המודל מגיע לביצועים לא מי יודע מה בדרך כלל, ממליץ על Longformer כאלטרנטיבה שעובדת מצוין! – אבל תבדקו על הדאטה שלכם ואל תקשיבו לי

ללמוד את תבנית האטנשן:
  • במודל Reformer מבצעים קלאסטרינג לטוקנים לפי דמיון hash-based ובכך לומדים את תבנית האטנשן [26]
  • במודל Routing Transformer מבצעים קלאסטרינג לפי K-Means ובכך לומדים את תבנית האטנשן [27]
  • במודל Sparse Sinkhorn Attention לומדים למיין בלוקים בקלט לפי חשיבות [28]
שימוש במשקולות ויצוגים כמה פעמים במודל:
  • במודל Transformer XL משתמשים בקלט ארוך בו משתמשים שוב ושוב באותו יצוג נסתר באיזורים שונים בקלט [29]
  • במודל Universal Transformer משלבים אטנשן עם שכבות RNN המשתמשות כמובן באותו היצוג כמה פעמים [30]

הקונספט הזה גם ניצח תחרות בקאגל

  • במודל Compressive Transformer משתמשים בתור בלוקי זכרון בחשיבות משתנה כך שכשזכרון נכנס אל התור הוא דוחף ל"דחיסה" את הזכרון הקודם שהיה בתור ושניהם משתמשים באותו יצוג נסתר [31]
אטנשן גלובלי:
  • במאמר Set Transformer השתמשו בזכרון צד היכול להיות נגיש לכל טוקן באותו הזמן [32]
  • במאמר Extended Transformer Construction השתמשו בטרנספורמר הדליל והוסיפו לו זכרון ואטנשן גלובלי [33]
  • במאמר של Longformer השתמשו באטנשן גלובלי ובאטנשן עם Dialation שמגדיל את הReceptive Field ככל שמעמיקים ברשת. [34]
אטנשן אדפטיבי:
  • במאמר של Adaptive Attention לימדו את המודל מתי להפסיק מוקדם את חישוב האטנשן לכל טוקן [36]
  • במאמר של Universal Transformer השתמשו בRNN בתוך המודל שיש לו ACT (החלטה נלמדת בזמן החישוב מתי להפסיק את פעולת הRNN) [37]
  • במאמר של Depth Adaptive Transformer לימדו את המודל להפסיק את החישוב לאחר מספר שכבות ספציפי [38]
אופטימיזציות ארכיטקטורה לצורך חסכון בצריכת זכרון:
  • במאמר של Linformer השתמשו בהטלה לאטנשן למימד נמוך יותר בתוך שכבת האטנשן ובכך חסכו משמעותית בביצועים [35]
רשימת המאמרים שהוזכרו בפוסט:
[1]: על ערכים חריגים באקטיבציות ברט: https://arxiv.org/abs/2109.12948
[2]: מחקר מעניין על הערכים החריגים באקטיבציות טרנספורמרים: https://arxiv.org/abs/2208.07339
[3]: מאמר חלוץ בנושא קוונטיזציה של טרנספורמרים: https://arxiv.org/abs/2005.03842
[4]: מאמר המשך על קוונטיצית טרנספורמרים בכמה רמות דיוק שונות: https://arxiv.org/abs/2109.12948
[5]: מאמר הדגל בנושא קוונטיזציה (כל כך מוצלח שנכנס לHuggingface) כאן: https://arxiv.org/abs/2208.07339
[6]: דיסטילציה שכבה אחרי שכבה: https://arxiv.org/abs/2206.01861
[7]: גיזום בזמן האימון: https://arxiv.org/abs/1710.01878
[8]: גיזום איטרטיבי: https://arxiv.org/abs/2003.02389
[9]: טריק לשיפור ביצועי הגיזום: https://arxiv.org/abs/2003.02389
[10]: תמיכה חומרתית ברשתות דלילות: https://images.nvidia.com/…/nvidia-ampere-architecture…
[11]: שחלוף שורות ועמודות במטריצת המודל: https://proceedings.neurips.cc/…/6e8404c3b93a9527c8db24…
[12]: אימון מעודד דלילות ברשת: https://arxiv.org/abs/2102.04010
[13]: הטרנספורמר הדליל: https://arxiv.org/abs/2111.12763
[13]: שימור דלילות לאורך כל האימון: https://arxiv.org/abs/2106.03517
[14]: טריק הסופטמקס באמצע הרשת בזמן האימון: https://arxiv.org/abs/1611.01144
[15]: שיפור לאסטרטגית הניתוב: https://arxiv.org/abs/2106.05974
[16]: רשתות מומחים למשימות ספציפיות: https://arxiv.org/abs/2110.03742
[17]: ארכיטקטורת רשת מומחים: https://arxiv.org/abs/2201.05596
[18]: ספריית DeepSpeed הפופולרית להרצת רשתות ענק: https://arxiv.org/abs/2201.05596
[19]: מעקב דינמי אחר העומסים לכל מומחה ברשת: https://arxiv.org/abs/2205.01848
[20]: המאמר של Image Transformer כאן: https://lilianweng.github.io/…/2020-04-07-the…/…
[21]: האטנשן הדליל כאן: https://lilianweng.github.io/…/2020-04-07-the…/…
[22]: הטרנספורמר הארוך: https://arxiv.org/abs/2004.05150
[23]: אטנשן לינארי גלובלי דליל: https://arxiv.org/abs/2210.15497
[24]: אטנשן במימד נוסף: https://arxiv.org/abs/1912.12180
[25]: המודל BigBird כאן: https://arxiv.org/abs/2007.14062
[27]: המודל Routing Transformer כאן: https://arxiv.org/abs/2003.05997
[28]: המודל Sparse Sinkhorn Attention כאן https://arxiv.org/pdf/2002.11296.pdf
[29]: המודל Transformer XL כאן: https://lilianweng.github.io/…/2020-04-07-the…/…
[30]: המודל Universal Transformer כאן: https://lilianweng.github.io/…/2020-04-07-the…/…
[31]: המאמר Compressive Transformer כאן: https://arxiv.org/abs/1911.05507
[32]: המאמר של Set Transformer כאן: https://arxiv.org/abs/1810.00825
[33]: המאמר של Extended Transformer Constructuion כאן: https://aclanthology.org/2020.emnlp-main.19/
[34]: המאמר של Longformer כאן: https://arxiv.org/abs/2004/05150
[35]: המאמר של Linformer כאן: https://arxiv.org/abs/2006.04768
[36]: המאמר של Adaptive Attention כאן: https://lilianweng.github.io/…/2020-04-07-the…/…
[37]: המאמר של Universal Transformer כאן: https://lilianweng.github.io/…/2020-04-07-the…/…
[38]: המאמר של Depth-adaptive Transformer כאן: https://arxiv.org/abs/1910.10073
בלוגפוסט מצוין על הנושא עליו התבססתי רבות במהלך סקירה זו: https://lilianweng.github.io/…/2023-01-10-inference…/
עוד בנושא: