הסבר מפורט על SparseCore למודלים גדולים של הטמעה (LEM)

‫SparseCore הוא מעבד מיוחד עם ארכיטקטורת tiled שנועד להאצת עומסי עבודה שכוללים גישה לא סדירה ודלילה לזיכרון וחישובים, במיוחד במערכי נתונים גדולים שמאוחסנים בזיכרון עם רוחב פס גבוה (HBM). הוא מצטיין במשימות כמו חיפושי הטמעה, אבל היכולות שלו כוללות גם האצה של מגוון עומסי עבודה דינמיים ודלילים אחרים.

1. מבוא ל-SparseCore

מאפיינים אדריכליים מרכזיים:

  • ארכיטקטורה מבוססת-משבצות: כוללת משבצות מחשוב מרובות (כל משבצת היא יחידת Dataflow מלאה עם זיכרון מקומי ויחידת עיבוד משלה), שמאפשרות עיבוד מקביל.
  • ביצוע דינמי: תמיכה מובנית בגישה לזיכרון ובזרימת בקרה שתלויה בנתונים, שחשובה לנתונים דלילים.
  • עיבוד וקטורי: נעשה שימוש במשימות וקטוריות קטנות (8 או 16 אלמנטים, בהתאם לגרסת החומרה) לחישוב יעיל.
  • שליטה מרכזית: רכיב SparseCore אחד של רצף פעולות מתזמן משימות בכל האריחים, כדי להבטיח פעולות מסונכרנות.
  • תמיכה בסיכום נתונים: כולל פעולות מיוחדות בין נתיבים שמועילות למשימות כמו מיון, סינון וסכומי קידומות.
  • היררכיית זיכרון: שימוש אסטרטגי ב-HBM לאחסון מערכי נתונים גדולים ובזיכרון מקומי של לוח טיוטה (SPMEM) לאחסון נתונים שניגשים אליהם לעיתים קרובות, מה שמפחית באופן משמעותי את זמן האחזור של HBM.

מפרטים בקצרה:

מאפיין TPU v4 TPU v5p Trillium
SparseCores/Chip 4 4 2
Tiles/SparseCore 16 16 16
SIMD Width 8 8 ‎8 (F32) 16 (BF16)
קיבולת HBM ‫‎32 GiB ‫96 GiB ‫‎32 GiB

2. עיבוד מקדים של מארח SparseCore

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

  • טרנספורמציה של נתונים:
    • מחילים את הטרנספורמציות הנדרשות על נתוני הקלט הגולמיים.
    • ניהול טרנספורמציות של מזהים, וזה חשוב במיוחד כשמדובר בהערמה של מאפיינים או טבלאות.
    • להמיר את נתוני הקלט לפורמט הדליל של הקואורדינטות (COO), שמפורט בקטע הבא.
    • חלוקת הנתונים למחיצות כדי להפיץ אותם בצורה יעילה בין ליבות SparseCore השונות שזמינות בשבב.
  • אימות מגבלות:
    • חשוב לוודא שהמאפיינים של נתוני הקלט (למשל, מספר המזהים) תואמים למגבלות התפעוליות המוגדרות מראש של SparseCore, כמו max_ids_per_partition ו-max_unique_ids_per_partition.
    • אם נתוני הקלט חורגים מהמגבלות האלה, שכבת העיבוד המקדים של המארח יכולה לנסות לפלח את הנתונים לקבוצות קטנות יותר שמתאימות למגבלות.
  • העברת נתונים:
    • הנתונים המעובדים והמאומתים מועתקים ביעילות לזיכרון ברוחב פס גבוה (HBM) של TPU, כך שהם מוכנים להרצה של SparseCore.

הסבר על סידור טבלאות זו על גבי זו:

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

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

היתרון העיקרי של סידור טבלאות בערימה הוא יצירת גודל אצווה אפקטיבי גדול יותר לפעולות בטבלאות האלה. כך מצטמצם העומס החישובי, והשיטה יכולה להסתיר ביעילות את השהיות של תקשורת בין-שבבית (ICI). כדי לקבל ביצועים אופטימליים, מומלץ להשתמש במספר מתון של טבלאות מוערמות (בדרך כלל בטווח של 5 עד 100).

3. המרת טנסורים ל-COO

לפני ש-SparseCore מעבד את הנתונים, בדרך כלל הוא ממיר אותם לפורמט של טנזור דליל מסוג Coordinate ‏ (COO). פורמט COO הוא דרך לייצג מטריצות דלילות בצורה יעילה, בדרך כלל באמצעות שלושה מערכים:

  • row_ids: מערך שמכיל את אינדקס השורה של כל רכיב שאינו אפס. בהקשר של עיבוד אצווה, זה בדרך כלל מתאים למאפיין 'אצווה'.
  • col_ids: מערך שמכיל את אינדקס העמודה של כל רכיב שאינו אפס. במקרה של הטמעות, אלה לרוב ערכי התכונה או המזהה.
  • values (אופציונלי): מערך שמכיל את הערכים בפועל של הרכיבים שאינם אפס בקואורדינטות התואמות (row, col). בחישובים של מגבלות (שנרחיב עליהם בהמשך) שקשורים לספירת מזהים, לרוב לא נלקחים בחשבון הערכים האלה (הרווחים).

דוגמה להמחשה:

נניח שיש מטריצה דלילה של קלט שמייצגת קבוצות של מזהים:

[
    [id_A],                 // Sample 0
    [id_A, id_B, id_C],     // Sample 1
    [id_B, id_B, id_D],     // Sample 2 (note duplicate id_B)
]

אחרי ההמרה לפורמט COO (ואולי אחרי הסרת כפילויות של מזהים באותו מדגם):

row_ids = [0, 1, 1, 1, 2, 2]
col_ids = [id_A, id_A, id_B, id_C, id_B, id_D]

ההמרה הזו היא בסיסית לאופן שבו SparseCore מעבד ומפיץ עבודה. הערכים col_ids חשובים במיוחד לקביעה של המחיצה הספציפית של SparseCore שאליה שייך מזהה, וכך מאפשרים לבצע חלוקה יעילה למקטעים וחיפוש יעיל.

4. ‫SparsecoreConfig: ה-API ברמה הגבוהה

ממשקי API להטמעה שספציפיים למסגרת:

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

  • disable_table_stacking: bool = False
    • הסבר: הדגל הזה קובע אם יופעל סידור אוטומטי של טבלאות. אם לא מפעילים את הסידור האוטומטי, יכול להיות שהמסגרת לא תסדר את הטבלאות, מה שעלול להוביל לירידה בביצועים בגלל תקורה מוגברת ויכולת מופחתת להסתיר את זמן האחזור של Inter-Chip Interconnect ‏ (ICI).
    • ברירת מחדל: False (כלומר, בדרך כלל מופעלת ברירת המחדל של סידור הטבלאות זו מעל זו, במקומות שבהם המסגרת תומכת בכך).
  • max_ids_per_chip_per_sample: int = 64
    • הסבר: הפרמטר הזה קובע מגבלה עליונה גלובלית על המספר הכולל של מזהי הטמעה ששבב יחיד יכול לעבד מדגימה אחת באצווה של הקלט, אחרי צבירה בכל הטבלאות. זהו מנגנון לניהול משאבים ברמת השבב, לפני שמתחשבים במגבלות מפורטות יותר ברמת הטבלה או המחיצה. התאמה מדויקת של הערך הזה תלויה בדרך כלל במאפיינים ספציפיים של המודל ובקיבולת הכוללת של המערכת.
    • ברירת מחדל: 64.
  • max_ids_per_table: Optional[Dict[str, int]] = None
    • הסבר: הפרמטר הזה מציין את המספר המקסימלי של מזהי הטמעה (שיכולים לכלול כפילויות) שאפשר לעבד עבור כל טבלה לוגית, תוך התחשבות בכל המחיצות שלה בכל SparseCores. המגבלה הזו רחבה יותר מהמגבלה max_ids_per_partition. אם טבלה T מחולקת ל-P מחיצות, המגבלה הזו חלה על סכום המזהים שמופנים לכל המחיצות. בדרך כלל השגיאה הזו קשורה לmax_ids_per_partition_per_sample ולגודל הכולל של הקבוצה.
    • הגדרה: בדרך כלל מוגדר באמצעות קובץ הגבלות (לדוגמה, באמצעות הדגל xla_sparse_core_max_ids_file), שבו מוגדר max_ids_per_partition. המושג הזה ברמת הטבלה הוא שיטה להגדרת המגבלות האלה ברמת המחיצה (max_ids ו-max_uniques).
    • ברירת מחדל: None (יכול להיות שהערך יוסק ממגבלות לכל מחיצה או מהגדרות אחרות אם הוא לא צוין במפורש).
  • max_unique_ids_per_table: Optional[Dict[str, int]] = None
    • הסבר: דומה ל-max_ids_per_table, אבל הפרמטר הזה מציין את המספר המקסימלי של מזהים ייחודיים לכל טבלה לוגית. ההגדרה הזו קריטית להתאמת הגודל של מאגרי הנתונים הזמניים במכשיר שמשמשים לעיבוד של מזהים ייחודיים ולפעולות וקטוריות שמתבצעות לאחר מכן.
    • הגדרה: מוגדרת בדרך כלל בקובץ מגבלות או נגזרת מ-max_unique_ids_per_partition_per_sample.
    • ברירת מחדל: None.
  • allow_id_dropping: bool = False
    • הסבר: דגל בוליאני שקובע אם להשמיט מזהים כשמספר המזהים שמופיעים בנתוני הקלט (המגבלות שנצפו) חורג מהמגבלות שהוגדרו במהלך ההידור (לדוגמה, max_ids_per_partition).
      • אם True: מזהים שיגרמו לחריגה מהמגבלות יושמטו ללא הודעה. בדרך כלל, מזהים במחיצה מעובדים בסדר ממוין, וכל מזהה שיגרום לספירה הפעילה לחרוג מהמגבלה של המיני-אצווה המיועדת שלו ייפסל. הפעולה הזו מאפשרת לתוכנית להמשיך לפעול, אבל היא עלולה להשפיע לרעה על דיוק המודל.
      • אם False: מופעלת שגיאה, והתהליך כנראה יסתיים אם המגבלות שנצפו חורגות מהמגבלות שקומפלו. הגישה הזו מבטיחה שכל הנתונים יעברו עיבוד, אבל היא מחייבת להגדיר את המגבלות בצורה שמרנית יותר.
    • ברירת מחדל: False (גורם לשגיאה בגלל חריגה ולא להשמטה שקטה של נתונים).
  • initialize_tables_on_host: bool = True

    • הסבר: הפלאג הזה קובע אם טבלאות ההטמעה מאותחלות במעבד המארח לפני שהן מועברות לזיכרון ברוחב פס גבוה (HBM) של ה-TPU. הנוהל המקובל הוא לאתחל את הטבלאות במארח. הגדרה של True תהיה בהתאם למוסכמה הזו. אם הערך היה False, המשמעות הייתה מנגנון הפעלה במכשיר, שיכולות להיות לו השלכות שונות על הביצועים או דרישות מוקדמות ספציפיות להפעלה.
  • enable_fast_table_initialization: bool = False

    • הסבר: מאתחלת את הטבלאות ישירות ב-TPU. הפעולה הזו יכולה לעזור לקצר את זמני ההפעלה של המודל.

5. שיפור הביצועים באמצעות צינורות

פייפליינינג (Pipelining) היא טכניקה לאופטימיזציה של הביצועים שמאפשרת ביצוע בו-זמני של פעולות ב-TensorCore ‏(TC) וב-SparseCore ‏(SC). חפיפה בין החישובים האלה יכולה לשפר באופן משמעותי את התפוקה הכוללת.

  • מנגנון: בשלב אימון רגיל שכולל חיפושים של הטמעות דלילות (מטופלים על ידי SC) וחישובים של שכבות צפופות (מטופלים על ידי TC), צינורות מאפשרים ל-SC לעבוד על החלק שלו בשלב i (לדוגמה, העברה קדימה או אחורה) בזמן ש-TC מעבד במקביל חלק אחר של אותו שלב i, או אפילו חלקים של שלבים סמוכים כמו i-1 או i+1.
  • השפעה על גרדיאנטים: יכול להיות שה-SparseCore יפעל על גרדיאנטים 'ישנים'. לדוגמה, יכול להיות שהגרדיאנטים שמחושבים במהלך שלב i של backpropagation לא יעודכנו באופן מלא ולא יהיו גלויים ל-SC עד לשלב i+2.
  • הפשרה בין ביצועים לבין נתונים מספריים: הביצוע החופף הזה יכול להוביל לשיפורים משמעותיים במהירות, ואולי אפילו לשיפור של עד פי 2 בזמן השלב של המכשיר. עם זאת, השינויים הקלים בערכים המספריים (embedding_weights) שנובעים מהשימוש בגרדיאנטים לא עדכניים עשויים להשפיע על התנהגות ההתכנסות של המודל או על רמת הדיוק הסופית שהושגה. המידה שבה הפשרה הזו מקובלת תלויה מאוד במודל, ולעתים קרובות נדרש אימות אמפירי.
  • דגל בקרה: אפשר לשלוט ב-Pipelining באמצעות tf_xla_disable_full_embedding_pipelining. הגדרת הדגל הזה ל-true משביתה את הצינור המלא (חישוב חופף של TensorCore ו-SparseCore), ואילו הגדרת הדגל הזה ל-false (או אם הסמנטיקה של הדגל מרמזת על הפעלה כשהערך הוא false) מפעילה אותו.

זרימת צינורות עיבוד נתונים מושגית:

  • ללא צינורות (זרימה רציפה פשוטה):

    Loop: SC/F_i -> TC/F_i -> TC/B_i -> SC/B_i

  • עם צינורות (תהליך חופף פשוט):

    Time ->
    Step i:   SC/F_i | TC/F_i | TC/B_i | SC/B_i
    Step i+1:          SC/F_i+1| TC/F_i+1| TC/B_i+1| SC/B_i+1
    

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

6. התפקיד של XLA

‫XLA (Accelerated Linear Algebra) הוא קומפיילר ספציפי לדומיין שמתרגם גרפים חישוביים ברמה גבוהה, בדרך כלל ממסגרות כמו TensorFlow, לקוד מכונה שעבר אופטימיזציה גבוהה ומותאם ל-TPU. הפעולה הזו כוללת יצירה של הוראות לפעולות שמיועדות ל-SparseCore.

פונקציות מרכזיות בהקשר של SparseCore:

  • קומפילציה של פעולות דלילות: XLA אחראי לקומפילציה של פעולות חיפוש של הטמעה (כמו SparseDenseMatmulOp) וחישובים דלילים אחרים לתוכניות SparseCore ברמה נמוכה שניתנות להרצה.
  • שילוב של מגבלות: המערכת משתמשת במגבלות התפעוליות שהוגדרו (לדוגמה, max_ids_per_partition, max_unique_ids_per_partition, שלרוב מסופקות באמצעות קובץ מגבלות שצוין על ידי פלאגים כמו xla_sparse_core_max_ids_file) כדי לקבוע באופן סטטי את הגדלים של מאגרי הזיכרון במכשיר ולהקצות אותם, במיוחד בתוך SPMEM.
  • אופטימיזציות מטורגטות: XLA מבצעת חבילה של אופטימיזציות שנועדו במיוחד לארכיטקטורת SparseCore. האופטימיזציות האלה יכולות לכלול תזמון הוראות, שינויים בפריסת הזיכרון ומיזוג פעולות כדי למקסם את היעילות.
  • שליטה באמצעות דגלים: היבטים רבים של התנהגות SparseCore, פרמטרים של כוונון ושיטות אופטימיזציה נחשפים ונשלטים באמצעות דגלי XLA (לדוגמה, xla_sparse_core_estimate_max_ids להערכת מגבלות או xla_sc_detect_nan לניפוי באגים).

סטטוס קוד פתוח:

ההטמעה של Sparsecore היא כרגע פנימית ומוצגת באמצעות libtpu.so.

דיווח על שגיאות וניתוח ביצועים:

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

7. איך המגבלות מתורגמות לטבלאות ב-SparseCore

ב-SparseCore, 'מגבלות' הן פרמטרים בסיסיים להגדרה שמתייחסים בעיקר לשתי הגדרות לכל מחיצה בכל טבלה שמפוצלת (מופצת) בין ה-SparseCore הזמינים:

  • max_ids_per_partition: ההגדרה הזו מגדירה את המספר המקסימלי של מזהים כוללים (כולל כפילויות) שכל SparseCore צפוי לשלוח למחיצה ספציפית בטבלה נתונה, או לעבד אותם עבורה, במסגרת שלב חישובי יחיד.
  • max_unique_ids_per_partition: הערך הזה מגדיר את המספר המקסימלי של מזהים ייחודיים שכל SparseCore צפוי לשלוח או לעבד עבור

תרגום לפריסת טבלה פיזית ועיבוד:

  • אסטרטגיית חלוקת הטבלה: טבלאות של הטמעה הן בדרך כלל 'חלוקה מודולרית' בין כל ליבות SparseCore במערכת. כלומר, כל SparseCore אחראי על קבוצת משנה נפרדת של אוצר המילים (שורות) בכל טבלה. בדרך כלל, מזהה j יוקצה ל-SparseCore_k על סמך נוסחה כמו k = j % num_total_sparse_cores.
  • הגדרה של 'מחיצה': בהקשר הזה, 'מחיצה' מתייחסת לפלח הספציפי של טבלת הטמעה שחיפושים בה מטופלים על ידי SparseCore יחיד.
  • הקצאת מאגר SPMEM: המגבלות האלה משמשות את מהדר XLA כדי להקצות מאגרים ולשנות את הגודל שלהם באופן סטטי בזיכרון הזמני במכשיר (SPMEM). גודל המאגרים מותאם כך שניתן יהיה לטעון ל-SPMEM את כל הנתונים הנדרשים שקשורים למזהים של מחיצה מסוימת (עד למגבלות שצוינו max_ids ו-max_unique_ids) לצורך עיבוד. זה חשוב במיוחד לחישובים שלא מתבצעים ברמת הרכיב, כמו צמצום מזהים כפולים במחיצה (לדוגמה, כשיוצרים ייצוג של שורה דלילה דחוסה (CSR)), שבהם מערך הנתונים הרלוונטי כולו של המזהים של המחיצה צריך להיות זמין בקלות בזיכרון מהיר.
  • מגבלות משוקללות לעומת מגבלות שנצפו:

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

    1. אוסף הקלט (לדוגמה, SparseTensor דו-ממדי בצורה [BatchSize, MaxSequenceLength]) מפולג בהתחלה בין ליבות SparseCore הזמינות. לדוגמה, אם ליבת TensorCore משויכת ל-2 ליבות SparseCore, כל ליבת SparseCore עשויה לקבל קבוצת משנה (sub-batch) בצורה [BatchSize/2, MaxSequenceLength].
    2. אחר כך, קבוצת המשנה הזו מומרת לפורמט COO, ומתקבלים row_ids ו-col_ids.
    3. מערכת Analytics מסירה מזהים כפולים באותו מדגם (כלומר, רשומות עם אותו row_id ואותו col_id).
    4. לכל מזהה ייחודי שנותר col_id (בתוך מדגם), מערכת SparseCore שאחראית למזהה הזה נקבעת באמצעות כלל החלוקה לשברים של mod: ‏ target_sc_id = col_id % num_total_sparse_cores.
    5. המערכת שומרת על ספירה של המספר הכולל של המזהים (ids_per_sparse_core[target_sc_id]++) ושל מספר המזהים הייחודיים (unique_ids_per_sparse_core[target_sc_id]++, אחרי שמוודאים שהם ייחודיים לtarget_sc_id הספציפי), שמיועדים לכל target_sc_id.
    6. הערך max_ids_per_partition של הטבלה T1 מוגדר ל-max(ids_per_sparse_core_array).
    7. באופן דומה, הערך של max_unique_ids_per_partition בטבלה T1 מוגדר ל-max(unique_ids_per_sparse_core_array).
    8. אם טבלה T1 היא רכיב של טבלה מוערמת, יכול להיות שיוחלו על התפלגויות המזהים טרנספורמציות נוספות כמו סיבובים או הזזות, לפני סיכום הנתונים הסטטיסטיים מכל הטבלאות שמרכיבות אותה. כך אפשר לאזן את העומס בין השבבים.

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

8. איך כל SparseCore מתקשר

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

  • חלוקת מודולו וניתוב משתמע:
    • טבלאות ההטמעה מחולקות באמצעות mod-sharding בין כל ליבות SparseCore במערכת.
    • כשהמארח מספק קבוצה של נתוני קלט (שעוברים עיבוד מראש לפורמט COO, כולל col_ids), הערך col_id משמש לקביעה איזה SparseCore אחראי למזהה הספציפי הזה: target_sc_id = col_id % num_total_sparse_cores.
    • כל SparseCore מקבל ומעבד רק את קבוצת המשנה של המזהים שממופים למחיצות אוצר המילים שהוקצו לו. שלב העיבוד המקדים של המארח הוא חיוני להכנת הנתונים באופן כזה שכל SparseCore יוכל לזהות בקלות את המזהים הרלוונטיים שלו ולפעול עליהם.
  • חלוקת הנתונים לפי מארח:
    • הלוגיקה של העיבוד המקדים במארח מחלקת את אצווה הקלט הכוללת ומפיצה את החלקים הרלוונטיים של row_ids ושל col_ids (יחד עם תכונות או משקלים משויכים, אם רלוונטי) לזיכרון (HBM) שאליו יש גישה ישירה לכל SparseCore, או ל-HBM משותף שממנו יאחזרו ה-SparseCore את הנתונים הנדרשים.
  • עיבוד Intra-SparseCore:
    • אחרי ש-SparseCore מקבל את קבוצת המזהים המיועדת שלו עבור מחיצה מסוימת בטבלה, הוא מבצע פעולות כמו ביטול כפילויות של המזהים האלה ואיסוף וקטורי ההטמעה התואמים. אלה בעיקר חישובים מקומיים שמופעלים בתוך המשבצות של SparseCore עצמו, ונעשה בהם שימוש ב-SPMEM המקומי שלו.
  • תקשורת בין ליבות SparseCore (העברה מכל ליבה לכל ליבה):
    • אחרי שלב העיבוד הראשוני (כמו חיפושי הטמעה), יכול להיות שייעשה שימוש בדפוס תקשורת 'כולם לכולם' כדי לשלב או להפיץ מחדש תוצאות בין SparseCores (לדוגמה, לפני הזנת הפעלות לשכבת TensorCore שמצפה לקלט שתואם לכל מיקומי הדגימה המקוריים). הנתון הזה חיוני לשחזור של קבוצת ההפעלות המלאה אם אצווה הקלט המקורית חולקה לעיבוד מקביל.
  • תקשורת עם TensorCores:
    • ליבות SparseCore מתקשרות עם ליבות TensorCore כדי לשלוח הפעלות של הטמעה (במהלך ההעברה קדימה) ולקבל גרדיאנטים (במהלך ההעברה אחורה). האינטראקציה הזו מתבצעת על ידי התוכנית שעברה קומפילציה של XLA, ולרוב היא כוללת HBM כמאגר ביניים. השיטה של צינורות (שדיברנו עליה קודם) משפיעה מאוד על התזמון והסנכרון של התקשורת בין SC ל-TC.

בעיקרון, ה'חלוקה' הראשונית של המזהים ל-SparseCore המתאים מתבצעת בעיקר על ידי תוכנית ה-sharding ושלבי העיבוד המקדים של המארח. התקשורת הבאה כוללת את SparseCores שפועלים על הנתונים המקומיים שלהם, ואחריה יכולות להיות פעולות תקשורת קולקטיביות כמו all-to-all אם צריך להחליף נתונים באופן גלובלי או לסדר אותם מחדש בין SparseCores לפני עיבוד נוסף על ידי TensorCores.

9. ניהול זיכרון ב-SparseCore

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

  • זיכרון Scratchpad‏ (SPMEM):
    • Nature: זיכרון SRAM מקומי קטן יחסית, אבל מהיר מאוד, שזמין באופן בלעדי לכל SparseCore. חשוב לציין ש-SPMEM הוא לא מטמון. השימוש בו מנוהל ומתואם באופן מפורש על ידי מהדר ה-XLA.
    • מטרה: SPMEM משמש ל "העברת נתונים באופן אופורטוניסטי". הנתונים האלה כוללים קלט, פלט ותוצאות ביניים שנדרשים לחישובים שוטפים של ציון האיכות. העברת נתונים לאזור זמני ב-SPMEM מפחיתה באופן משמעותי את זמן האחזור הגבוה שקשור בדרך כלל לגישה ל-HBM.
    • גודל: כמו שצוין בקטע בנושא 'מגבלות', המאגרים של SPMEM הם בגודל קבוע בזמן ההידור. הגודל הזה מבוסס על פרמטרים כמו max_ids_per_partition ו-max_unique_ids_per_partition. ההקצאה הסטטית הזו מבטיחה שכל הנתונים שדרושים למזהים של מחיצה מסוימת בטבלה (עד למגבלות שהוגדרו) יוכלו להיכנס ל-SPMEM, לכל פעולה שמתבצעת במחיצה (למשל, צמצום CSR).
    • אופטימיזציות של קומפיילר: קומפיילר XLA משלב אופטימיזציות מתוחכמות כדי לקבוע בדיוק כמה נתונים, ואילו רכיבי נתונים ספציפיים, צריך להעביר ל-SPMEM כדי להסתיר ביעילות את זמן האחזור של HBM ולמקסם את הביצועים.
    • מגבלת הקצאה דינמית: קומפיילר SparseCore לא תומך כרגע בהקצאה דינמית של זיכרון זמני. הדבר מדגיש את החשיבות הקריטית של הגדרת גודל קבוע באמצעות הגדרה מדוקדקת של מגבלות.
  • זיכרון עם רוחב פס גבוה (HBM):
    • Nature: משאב זיכרון גדול ומשותף שנגיש לכל ליבות ה-SparseCore, ליבות ה-TensorCore ומערכת המארח. טבלאות ההטמעה הראשיות מאוחסנות ב-HBM.
    • שימוש ב-Stack: פעולות של SparseCore דורשות לעיתים קרובות אחסון זמני ב-HBM של תוצאות ביניים שלא נכנסות ל-SPMEM המוגבל או שצריך להעביר אותן בין שלבים גדולים יותר של צינור עיבוד הנתונים. אפשר להעריך את השימוש במערך HBM במהלך מעברים קדימה ואחורה באופן הבא:
      • העברת נתונים קדימה במחסנית HBM (טבלה יחידה) ≈ (2 * feature_width + 1) * max_unique_nz_per_row * logical_replica_count * 4 בייט
      • העברה לאחור של ערימת HBM (טבלה יחידה) ≈ 3 * feature_width * max_unique_nz_per_row * logical_replica_count * 4 בייט
    • שימוש בערימה (heap): HBM גם מאפשרת שימוש בערימה, שמנוהלת על ידי המארח. ה-heap מאחסן נתונים כמו משקלים של שכבות צפופות, קבועים שמשמשים את המודל ונתוני קלט שנשלפו מראש. השימוש ב-Heap נוטה לגדול עם מספר השלבים שבהם המארח מבצע אחזור מראש של נתונים (נשלט על ידי הדגל maximum_parallel_iterations). אמנם אחזור מראש של נתונים יכול לשפר את הביצועים על ידי חפיפה בין העברות משרת למכשיר לבין חישובים במכשיר, אבל הוא גם צורך יותר HBM.
    • סריאליזציה לאופטימיזציה של HBM: הדגל xla_sc_num_serialized_tables_to_optimize_hbm מספק מנגנון לשליטה במספר הטבלאות שהנתונים שלהן נשמרים 'פעילים' בזיכרון של מחסנית HBM בכל זמן נתון. הגדלת המספר הזה גורמת למעשה לעיבוד סדרתי של יותר טבלאות, מה שיכול להפחית את השימוש המקסימלי ב-HBM, אבל עלול לפגוע בביצועים בגלל הפחתה של העיבוד המקביל.
  • זיכרון וקטורי (VMEM):
    • זיכרון VMEM הוא זיכרון מקומי זמני שמשמש אך ורק את ה-TC (TensorCore). אמנם VMEM לא מנוהל ישירות על ידי SparseCore, אבל הוא חלק בלתי נפרד ממערכת הזיכרון שאיתה SparseCore מתקשר, בעיקר דרך TensorCore.

אסטרטגיה כוללת לניהול זיכרון:

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

10. צווארי בקבוק בביצועים ובזיכרון

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

צווארי בקבוק נפוצים בביצועים:

  • צוואר בקבוק במארח:
    • בעיה: יכול להיות שהמעבד המארח לא יצליח לבצע עיבוד מקדים של הנתונים ולהזין אותם ל-TPU במהירות מספקת, מה שיוביל לניצול חלקי של SparseCores ו-TensorCores. זוהי הגבלה נפוצה על הביצועים.
    • הפחתת הסיכון: עוקבים אחרי ניצול המעבד של המארח ומדדים של צינורות קלט. מבצעים אופטימיזציה של טעינת נתונים בצד המארח ושל שגרות עיבוד מקדים (אפשר לעיין בטיפים להמרת נתונים ב-COO). משנים את הערך של הדגל maximum_parallel_iterations כדי לשפר את הטעינה מראש של הנתונים.
  • סנכרון לא אופטימלי של TC/SC (חוסר צינורות):
    • בעיה: אם צינורות הנתונים בין TensorCore ו-SparseCore מושבתים או לא פועלים ביעילות, ייתכן שיחידה אחת תבזבז זמן רב בהמתנה ליחידה השנייה, וכך תפחית את התפוקה הכוללת של המערכת.
    • הפחתת הסיכון: מוודאים שהפעלת צינורות מופעלת (לדוגמה, tf_xla_disable_full_embedding_pipelining = false או מקבילה).
  • צווארי בקבוק שנובעים ממגבלות:
    • Issue:
      • המגבלות נמוכות מדי: יכולות להפעיל חלוקה מוגזמת של קבוצות קטנות (פיצול של קבוצות קלט למספר רב של קבוצות משנה קטנות יותר כדי לעמוד במגבלות המחמירות). הגישה הזו שומרת על הדיוק, אבל כל אצווה קטנה מוסיפה תקורה מסוימת לעיבוד, ויכול להיות שהיא תאט את הביצוע הכולל. אם allow_id_dropping מוגדר כ-True, מגבלות נמוכות מדי עלולות גם לגרום להשמטת מזהים, מה שמשפיע על דיוק המודל.
      • המגבלות גבוהות מדי (אבל עדיין מתאימות): מגבלות גבוהות מאוד עשויות למנוע את השימוש במיני-אצווה, אבל הן עלולות להגדיל את העומס על SPMEM שלא לצורך אם מאפייני הנתונים בפועל לא מתקרבים לערכי השיא האלה. הן גם עלולות לגרום לשימוש גדול יותר במצבור HBM ממה שנדרש.
      • כשלים בהידור: אם המגבלות שהוגדרו דורשות יותר SPMEM או HBM stack מהזיכרון הפיזי הזמין, ההידור ייכשל.
    • הפחתת הסיכון: מוודאים שהמגבלות מוגדרות בצורה נכונה.
  • הטיה בחלוקת הנתונים:
    • בעיה: אם מחיצות מסוימות של SparseCore מקבלות באופן עקבי מספר גדול באופן לא פרופורציונלי של מזהים בהשוואה למחיצות אחרות (מה שמצביע על חלוקת מזהים לא טובה), מחיצות SparseCore עמוסות מדי יהפכו לצווארי בקבוק בביצועים.
    • הפחתת הסיכון: ערבוב מזהים במהלך תהליך יצירת המיני-אצווה יכול לעזור להפחית את הסיכון הזה בטבלאות מוערמות, במיוחד בטבלאות משתמשים 'פעילים'. כדאי לנתח בקפידה את התפלגויות המזהים כדי להגדיר מגבלות מתאימות ומאוזנות לכל טבלה.
  • בעיות בהצגת טבלאות זו על גבי זו:
    • Issue:
      • מספר הטבלאות שמוערמות קטן מדי: יכול להיות שהמספר לא מספיק כדי להסתיר ביעילות את זמן האחזור של ICI או כדי לצמצם באופן מספק את תקורה העיבוד.
      • יותר מדי טבלאות מוערמות: יכול להיות שייווצרו טבלאות לוגיות גדולות מאוד שיהיה קשה לנהל אותן או שהן יחרגו ממגבלות המשאבים הזמינים.
    • הפחתת הסיכון:
      • חשוב לוודא שיש מספר אופטימלי של טבלאות לסידור בערימה. הנחיה כללית היא להשתמש ב-5 עד 100 טבלאות לסידור בערימה.
  • Inefficient numerics/quantization:
    • בעיה: שימוש בדיוק מלא של FP32 כשפורמטים עם דיוק נמוך יותר כמו BF16 או מספרים שלמים שעברו קוונטיזציה יספיקו (ויאפשרו חישוב מהיר יותר) עלול להוביל לצוואר בקבוק בביצועים.
    • הפחתת הסיכון: כדאי לבדוק אפשרויות עם דיוק נמוך יותר. עם זאת, חשוב לזכור שלקוונטיזציה עצמה יש תקורה מסוימת, ויכול להיות שיהיה צורך לכוונן בקפידה את פרמטרים הקוונטיזציה כדי לשמור על דיוק המודל.
  • HBM bandwidth saturation:
    • הבעיה: תנועת נתונים מוגזמת אל HBM וממנו, שיכולה להיגרם מרוחבי תכונות קטנים מאוד (שמובילים לתקורה גבוהה של ריפוד), מדפוסי גישה לא יעילים לזיכרון או ממספר גדול במיוחד של חיפושים, יכולה להביא לניצול מלא של רוחב הפס הזמין של HBM.
    • הפחתת הסיכון: הגדלת מספר ה-TPU יכולה לעזור ברוחב הפס של HBM.

צווארי בקבוק נפוצים בזיכרון:

  • SPMEM overflow (compilation failure):
    • הבעיה: אם הערכים של max_ids_per_partition ו-max_unique_ids_per_partition גבוהים מדי, יכול להיות שהקומפיילר של XLA לא יוכל להקצות מספיק SPMEM, וכתוצאה מכך יופיעו שגיאות קומפילציה כמו: "Fixed size allocations (...) do not fit in TileSpmem (...)". בנוסף, אם המונח (sample_count * feature_width) / kNumTiles (כאשר kNumTiles הוא מספר המשבצות לכל SC) גדול מדי בשביל אזור ההמתנה לאיסוף אופרנדים ב-SPMEM של המשבצת, יכולות להתרחש שגיאות כמו "Gather operand too large...".
    • הפחתת הסיכון: הקטנת גודל האצווה או הגדלת מספר השבבים שמשמשים לעיבוד.
  • HBM stack overflow (runtime or compilation):
    • הבעיה: אם השילוב של feature_width,‏ max_unique_nz_per_row ו-logical_replica_count מוביל לדרישות זיכרון של HBM Stack שחורגות מה-HBM הזמין, יכולות להתרחש שגיאות של חוסר זיכרון (OOM) בזמן ריצה או במהלך קומפילציה.
    • הפחתת הסיכון: כדאי לשנות את הערך של xla_sc_num_serialized_tables_to_optimize_hbm flag כדי להפחית את השימוש ב-HBM stack על ידי סדרת העיבוד של הטבלאות (בדרך כלל זה בא על חשבון הביצועים).
  • HBM heap exhaustion:
    • בעיה: נגרמת בעיקר בגלל משקלים גדולים מאוד של שכבות צפופות, מספר רב של קבועים שמאוחסנים בזיכרון או אחזור מראש אגרסיבי מדי של נתוני קלט (ערך גבוה של maximum_parallel_iterations).
    • הפחתת הסיכון: מעקב אחר השימוש בערימה באמצעות כלים כמו XProf Memory Viewer.
  • Padding overhead:
    • בעיה: הטמעת טבלאות מרופדת כך שתהיה מיושרת ל-32B (שווה ערך ל-8 ערכים מסוג float) במאפיין התכונה. כתוצאה מכך, רוחבי תכונות קטנים (למשל, 1 float) גורמים לתקורה משמעותית של ריפוד (למשל, 7/8 משטח המאגר שהוקצה הוא ריפוד), מה שמוביל לבזבוז של HBM. גם מאפיין אוצר המילים של הטבלאות מרופד כך שיהיה כפולה של מספר ליבות SparseCore במערכת. עם זאת, ההשפעה הזו בדרך כלל זניחה בטבלאות עם גודל אוצר מילים גבוה מספיק.

גורמים כלליים שמשפיעים על הביצועים ועל הזיכרון:

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

11. ניתוח של פרופיל SparseCore

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

  1. קבלת נתוני מעקב:
    • כדאי להשתמש בכלי פרופיל כמו XProf כדי לתעד מעקב מפורט אחר הביצוע בזמן שהמודל מתאמן או מריץ הסקה. המעקב הזה יספק ציר זמן של פעולות שמתרחשות במארח, ב-TensorCores וב-SparseCores.
  2. בודקים את הכלי Trace Viewer (לדוגמה, ב-XProf או ב-TensorBoard):
    • פעילות המארח: בדיקה מדוקדקת של פעילות המארח. האם יש פערים משמעותיים בפעילות של TPU? פערים כאלה עשויים להצביע על כך שהמארח הוא צוואר בקבוק, ולא מצליח להעביר את הנתונים מספיק מהר. ניתוח הביצועים של צינור עיבוד הנתונים של הקלט.
    • פעילות של TensorCore ‏ (TC) ו-SparseCore ‏ (SC):
      • בודקים את ציר הזמן של ההפעלה גם של TC וגם של SC. האם הם פועלים במקביל, מה שמצביע על צינור עיבוד נתונים יעיל? או שיש תקופות ארוכות שבהן יחידה אחת לא פעילה ומחכה ליחידה השנייה?
      • לזהות את הפעולות שצורכות הכי הרבה זמן (הפעולות שפועלות הכי הרבה זמן) גם ב-SC וגם ב-TC.
      • פלט של מעקב ויזואלי (לרוב מוצגים בלוקים צבעוניים שמייצגים פעולות שונות לאורך זמן, כמו TPU:0 SparseCore 1 (pid 1005)) הוא בעל ערך רב לזיהוי ויזואלי של פעולות דומיננטיות ותקופות של חוסר פעילות.
    • ניתוח משך הזמן של השלב: אפשר לראות את משך הזמן הכולל של השלב ולהבין איך הוא מתחלק בין עיבוד המארח, חישוב ה-SC וחישוב ה-TC.
  3. ניתוח זיכרון (XProf Memory Viewer):
    • שימוש בערימה (heap): אפשר להשתמש בכלים כמו הכרטיסייה Memory Viewer (צפייה בזיכרון) ב-XProf כדי לבדוק את השימוש בערימה ב-HBM. הבדיקה הזו יכולה לעזור לקבוע אם משקלים גדולים של מודלים, קבועים או אחזור מוקדם אגרסיבי מדי של קלט צורכים כמות מוגזמת של HBM. הפעלת דגלים כמו --vmodule=best_fit_allocator=1 עשויה לספק יומנים של שימוש בערמת זיכרון בשיא.
    • שימוש במחסנית (עקיף): פרופיל ישיר של מחסנית HBM יכול להיות מורכב, אבל אם נתקלתם בשגיאות של חוסר זיכרון (Out-Of-Memory) והשימוש ב-heap נראה סביר, יכול להיות שהמחסנית של HBM מלאה (לרוב בגלל מגבלות גדולות מדי או רוחב תכונות). הנוסחאות שמופיעות במאמר הזה יכולות לעזור לכם להעריך את השימוש ב-HBM.
  4. חיפוש דפוסים ספציפיים:
    • מיני-batching: אם המגבלות נחצות לעיתים קרובות, יכול להיות שתראו הוכחות למיני-batching בנתוני המעקב (לדוגמה, מספר גבוה יותר של פעולות SC קטנות מהצפוי לגודל ה-batch הגלובלי). לרוב אפשר להסיק את זה מיומנים או ממעקב אחר מספר הקריאות של פעולות מסוימות.
    • השמטה של מזהים: אם השמטה של מזהים מופעלת ומתרחשת, יומני המערכת עשויים לספק אינדיקציות לכך. זה גם יהיה סימן ברור לכך שהמגבלות שהוגדרו מגבילות מדי את נתוני הקלט.
    • זמני קומפילציה: זמני קומפילציה מחדש ארוכים, במיוחד אם האפשרות 'אופטימיזציה מבוססת-משוב' (FDO) מופעלת והמערכת משנה את המגבלות לעיתים קרובות, יכולים להוסיף תקורה משמעותית לזמן האימון הכולל.
  5. התאמה לדגלים ולהגדרות:
    • צריך לקשר בין ההתנהגות שנצפתה בפרופיל לבין הגדרות SparseCore (הגדרות בקובצי הגבלות, דגלי XLA). לדוגמה, אם הערך של xla_sc_num_serialized_tables_to_optimize_hbm מוגדר כערך גבוה, יכול להיות שתצפו לביצועים איטיים יותר של SC אבל לצריכה נמוכה יותר של HBM stack.
  6. תהליך איטרטיבי:
    • יצירת פרופיל היא לרוב תהליך של שיפור חוזר. מבצעים שינוי ספציפי (למשל, התאמה של מגבלה, הפעלה או השבתה של תכונה), מצלמים פרופיל חדש ואז משווים אותו לפרופיל הקודם כדי לראות את ההשפעה של השינוי.

12. דגלים כלליים לניפוי באגים

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

  • בדיקות של מזהים (מחוץ לטווח):
    • דגל: xla_sparse_core_enable_id_bound_check = true
    • מטרה: מאפשרת לבצע בדיקות במערכת המארחת כדי לזהות אם מזהים של הטמעה בנתוני הקלט חורגים מטווח אוצר המילים התקף שהוגדר לטבלת הטמעה נתונה. כך אפשר לזהות בעיות שקשורות לנתוני קלט שגויים או פגומים.
  • בודק NaN:
    • דגל: xla_sc_detect_nan = true
    • מטרה: מאפשרת לזהות ערכי NaN (לא מספר) בנתונים של נקודות צפות שעוברים עיבוד ב-SparseCore. אם ערך NaN מזוהה בקלט או בפלט של מעברים שונים של קומפילציה, הדגל הזה יגרום להצגת שגיאה. בדרך כלל השגיאות האלה כוללות מידע על המקום שבו נתקלתם ב-NaN.
  • בודק גבולות (גישה לזיכרון):
    • דגל: xla_sc_assert_level=bounds
    • מטרה: הדגל הזה מפעיל כלי בסגנון ASAN ‏ (AddressSanitizer) שכותב מחדש הוראות לגישה לזיכרון (כמו טעינות/אחסונים של VMEM ופעולות DMA) כדי לכלול בדיקות דינמיות. הבדיקות האלה מאמתות אם הגישה לזיכרון היא במסגרת הגבולות שהוקצו לאזור הזיכרון של היעד.
    • התנהגות: אם המערכת מזהה גישה לזיכרון מחוץ לגבולות, הביצוע ייכשל.
    • זהירות: יכול להיות שהכלי הזה יפיק תוצאות חיוביות שגויות, למשל בגלל דפוסי גישה מורכבים עם צעדים קבועים שלא מובנים באופן מלא על ידי הכלי. השינוי הזה מתבצע בשלב מאוחר בתהליך ההידור של ה-backend.
  • בודק מאגרים (פגיעה בזיכרון):
    • דגלים:
      • xla_tpu_buffer_contents_sanitizer_config='cores_to_sanitize: [TC, SC_SCS, SC_TILE], sanitizer_mode: LOCAL_ONLY'
      • xla_tpu_verify_launch_id_across_cores=true
    • מטרה: הדגלים האלה עוזרים לוודא שמאגרי הזיכרון לא ניזוקים או נמחקים בטעות על ידי פעולות לא קשורות. הכלי Buffer Sanitizer בודק את התוכן של מאגרי נתונים זמניים כדי לוודא שהם לא משתנים באופן לא צפוי.

13. תמיכה בקוונטיזציה

הפונקציה SparseDenseMatmulOp של SparseCore מיועדת לתמוך בפעולות על טבלאות הטמעה באמצעות סוגי נתונים של מספרים שלמים (integer) ושל נקודה צפה (floating-point) של 32 ביט (FP32). בדרך כלל, אימון המודל מתבצע באמצעות דיוק FP32 לטבלאות של הטמעה, אבל אפשר להחיל כימות אחרי האימון (PTQ). ‫PTQ מאפשר שימוש בסוגי נתונים עם דיוק נמוך יותר (כמו מספרים שלמים של 8 ביט) לצורך הסקה, מה שיכול להוביל לשיפור בביצועים ולצמצום השימוש בזיכרון.

קוונטיזציה מדומה:

אפשר להגדיר את SparseDenseMatmulOp לביצוע 'קוונטיזציה מדומה'. במצב הפעולה הזה, וקטורי ההטמעה עוברים קודם קוונטיזציה לדיוק נמוך יותר, ואז דה-קוונטיזציה בחזרה לדיוק גבוה יותר (לדוגמה, FP32) לפני שמשתמשים בהם בחישובים הבאים. הטכניקה הזו מאפשרת לאמן מודלים תוך התחשבות בהשפעות של רעשי קוונטיזציה. אימון עם כימות מדומה יכול לשפר את הדיוק של המודל הסופי כשהוא עובר כימות מלא לצורך הסקת מסקנות.

מאפייני ההגדרה של SparseDenseMatmulOp (לכימות):

  • quantization_config_num_buckets = 256
    • במאפיין הזה מציינים את מספר הדליים או הרמות הנפרדים שבהם יבוצע קוונטיזציה של מספר נקודה צפה בן 32 ביט. לדוגמה, כשמבצעים קוונטיזציה למספרים שלמים של 8 ביט, בדרך כלל מציינים 2^8 =256 דליים.
  • quantization_config_low = -X.X
    • במאפיין הזה מגדירים את הערך המינימלי של נקודה צפה בטווח הכימות. כל ערך קלט שנמוך מהערך המינימלי שצוין יעבור חיתוך לערך המינימלי הזה במהלך הכימות.
  • quantization_config_high = Y.Y
    • במאפיין הזה מגדירים את הערך המקסימלי של נקודה צפה בטווח הכימות. כל ערכי קלט שגבוהים מהמקסימום שצוין ייחתכו לערך המקסימלי הזה במהלך הכימות.

אינטראקציה מספרית וצינורית:

ההתנהגות המספרית של המודל יכולה להשתנות בהתאם להפעלה של צינורות בין TensorCore ל-SparseCore. אם צינור העיבוד פעיל, יכול להיות שהשיפועים שעוברים עיבוד על ידי SparseCore יהיו "ישנים" (מאיטרציה קודמת). הפעולה הזו יכולה להשפיע על תהליך הכימות, ועלולה להשפיע על הדינמיקה של אימון המודל או על הדיוק הסופי שלו.

14. תכונות חדשות ושיפורים מהזמן האחרון

הסביבה העסקית של SparseCore נתונה לפיתוח ולשיפור מתמשכים.

תוכנית:

  • חלוקה למיני-אצווה לפי מימד הדגימה:
    • התכונה הזו מתוכננת כתוספת ליכולות הקיימות של חלוקת נתונים לקבוצות קטנות לפי מימד אוצר המילים.
    • היא תאפשר חלוקה נוספת של נתוני ההטמעה לאורך מאפיין הדגימה. הפתרון הוא להוסיף לולאות במכשיר שיכולות לסנן ולעבד חיפושים מקבוצת משנה של דוגמאות בכל פעם. תכונה כזו יכולה להיות שימושית לניהול מספרים גדולים מאוד של מזהי דגימות או לשיפור איזון העומסים בין יחידות העיבוד.
  • שיפור התמיכה בהטמעה עם פחות מ-8 מספרים שלמים בכל שורה (רוחבי תכונות קטנים):
    • בדרך כלל, העיצוב הנוכחי משתמש בריווח משמעותי להטמעת רוחבי תכונות שהם פחות מ-8 מספרים ממשיים (שמתאימים ל-32 בייטים). הריווח הזה עלול לגרום לבזבוז של HBM ולניצול חלקי של משאבי מחשוב. בעתיד נבצע שיפורים כדי לצמצם את חוסר היעילות הזה בטבלאות עם מאפיינים קטנים.

שיפורים אחרונים:

  • Staging of gather operands in HBM:
    • האופטימיזציה הזו עוזרת להפחית את העומס על הזיכרון המשותף של ה-scratchpad (SPMEM) בכך שהיא מאפשרת לאחסן חלק מהקלט או הפלט של פעולות איסוף ב-HBM הגדול יותר.
  • ירידה בשימוש בזיכרון המחסנית:
    • הטמענו שיפורים כדי לצמצם את צריכת הזיכרון של מחסנית HBM במהלך פעולות SparseCore, באופן שלא ישפיע לרעה על הביצועים הכוללים או על קצב העברת הנתונים.

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