שידור

במסמך הזה מתוארת הסמנטיקה של שידור ב-XLA.

מהו שידור?

שידור (broadcasting) הוא תהליך שבו משנים את הצורה של מערכים שונים לצורה תואמת כדי לבצע פעולות אריתמטיות. הטרמינולוגיה נלקחה משידור (broadcasting) ב-NumPy.

יכול להיות שיהיה צורך בשידור כדי לבצע פעולות בין מערכים רב-ממדיים בדרגות שונות, או בין מערכים רב-ממדיים עם צורות שונות אבל תואמות. נניח שיש לנו את הפעולה X+v כאשר X היא מטריצה (מערך עם 2 ממדים) ו-v הוא וקטור (מערך עם ממד אחד). כדי לבצע חיבור של כל רכיב בנפרד, XLA צריך לבצע שידור (broadcast) של הווקטור v למספר הממדים של המטריצה X, על ידי שכפול של v מספר מסוים של פעמים. האורך של הווקטור צריך להיות זהה לפחות לאחד מהממדים של המטריצה.

לדוגמה:

|1 2 3| + |7 8 9|
|4 5 6|

המידות של המטריצה הן (2,3), והמידות של הווקטור הן (3). הווקטור מועבר בשידור על ידי שכפול שלו על פני שורות כדי לקבל:

|1 2 3| + |7 8 9| = |8  10 12|
|4 5 6|   |7 8 9|   |11 13 15|

ב-NumPy, הפעולה הזו נקראת broadcasting.

עקרונות

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

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

שידור של מערך עם פחות ממדים למערך עם יותר ממדים

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

|1 2 3| + 7 = |8  9  10|
|4 5 6|       |11 12 13|

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

נחזור לדוגמה הקודמת. במקום להוסיף סקלר למטריצה (2,3), מוסיפים וקטור עם מימד (3) למטריצה עם מימדים (2,3). הפעולה הזו לא חוקית אם לא מציינים שידור. כדי לבקש נכון חיבור של מטריצה לווקטור, צריך לציין שהמימד של השידור הוא (1), כלומר המימד של הווקטור תואם למימד 1 של המטריצה. ב-2D, אם מימד 0 מייצג שורות ומימד 1 מייצג עמודות, המשמעות היא שכל רכיב של הווקטור הופך לעמודה בגודל שמתאים למספר השורות במטריצה:

|7 8 9| ==> |7 8 9|
            |7 8 9|

דוגמה מורכבת יותר: הוספה של וקטור עם 3 רכיבים (ממד (3)) למטריצה בגודל 3x3 (ממדים (3,3)). יש שתי דרכים לשידור בדוגמה הזו:

‫(1) אפשר להשתמש במאפיין שידור של 1. כל אלמנט וקטורי הופך לעמודה, והווקטור משוכפל לכל שורה במטריצה.

|7 8 9| ==> |7 8 9|
            |7 8 9|
            |7 8 9|

‫(2) אפשר להשתמש במאפיין שידור עם ערך 0. כל רכיב וקטור הופך לשורה, והווקטור משוכפל לכל עמודה במטריצה.

 |7| ==> |7 7 7|
 |8|     |8 8 8|
 |9|     |9 9 9|

המימדים של השידור יכולים להיות טאפל שמתאר איך צורה עם פחות מימדים משודרת לצורה עם יותר מימדים. לדוגמה, אם יש תיבה באורך 2, ברוחב 3 ובגובה 4 ומטריצה בגודל 3x4, טופל שידור (1,2) אומר התאמה של המטריצה למימדים 1 ו-2 של התיבה.

השידור מהסוג הזה משמש בפעולות הבינאריות ב-XlaBuilder, אם ניתן הארגומנט broadcast_dimensions. לדוגמה, אפשר לעיין ב-XlaBuilder::Add. בקוד המקור של XLA, סוג השידור הזה נקרא לפעמים שידור InDim.

הגדרה פורמלית

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

          MxNxPxQ

dim 3:          T
dim 2:        T
dim 1:      T
dim 0:    T

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

כדי להתאים מטריצת TxV למערך MxNxPxQ, משתמשים בזוג מימדים של שידור:

          MxNxPxQ
dim 2,3:      T V
dim 1,2:    T V
dim 0,3:  T     V
etc...

הסדר של המימדים בטופל של השידור צריך להיות הסדר שבו המימדים של המערך עם מספר המימדים הנמוך יותר צפויים להתאים למימדים של המערך עם מספר המימדים הגבוה יותר. האלמנט הראשון בטופל מציין איזה מאפיין במערך הרב-ממדי צריך להיות זהה למאפיין 0 במערך הדו-ממדי. האלמנט השני בטופל מציין איזה מאפיין במערך הרב-ממדי צריך להיות זהה למאפיין 1 במערך הדו-ממדי, וכן הלאה. הסדר של מאפייני השידור חייב להיות בסדר עולה. לדוגמה, בדוגמה הקודמת, אסור להתאים את V ל-N ואת T ל-P. אסור גם להתאים את V ל-P ול-N.

שידור של מערכים עם מימדים דומים ומימדים מנוונים

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

  • הם שווים, או
  • אחד מהם הוא 1 (ממד "מנוון")

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

דוגמאות:

  1. ‫(2,1) ו-‫ (2,3) משדרים ל-‫ (2,3).
  2. ‫(1,2,5) ו- (7,2,5) משדרים אל (7,2,5).
  3. ‫(7,2,5) ו- (7,1,5) משדרים אל (7,2,5).
  4. ‫(7,2,5) ו-‫ (7,2,6) לא תואמים ואי אפשר לשדר אותם.

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

הרכב השידור

אפשר לבצע גם שידור של מערך עם פחות ממדים למערך עם יותר ממדים וגם שידור באמצעות ממדים מנווונים באותה פעולה בינארית. לדוגמה, אפשר לחבר וקטור בגודל 4 ומטריצה בגודל 1x2 באמצעות שידור של מימדים עם ערך (0):

|1 2 3 4| + [5 6]    // [5 6] is a 1x2 matrix, not a vector.

קודם הווקטור משודר עד ל-2 מימדים (מטריצה) באמצעות broadcast dimensions. הערך הבודד (0) במאפייני השידור מציין שהמאפיין אפס של הווקטור תואם למאפיין אפס של המטריצה. הפונקציה הזו יוצרת מטריצה בגודל 4xM, כאשר הערך M נבחר כך שיתאים לגודל המאפיין התואם במערך 1x2. לכן, נוצרת מטריצה בגודל 4x2:

|1 1| + [5 6]
|2 2|
|3 3|
|4 4|

לאחר מכן, 'שידור של מאפיין מנוון' משדר את מאפיין האפס של מטריצת 1x2 כדי להתאים לגודל המאפיין התואם בצד שמאל:

|1 1| + |5 6|     |6  7|
|2 2| + |5 6|  =  |7  8|
|3 3| + |5 6|     |8  9|
|4 4| + |5 6|     |9 10|

דוגמה מורכבת יותר היא מטריצה בגודל 1x2 שנוספת למערך בגודל 4x3x1 באמצעות מימדי שידור של (1, 2). קודם כל, המטריצה 1x2 משודרת עד 3 מאפיינים באמצעות מאפייני השידור כדי ליצור מערך ביניים Mx1x2 שבו גודל המאפיין M נקבע לפי גודל האופרנד הגדול יותר (המערך 4x3x1) ויוצר מערך ביניים 4x1x2. האות M נמצאת במאפיין 0 (המאפיין הכי שמאלי) כי המאפיינים 1 ו-2 ממופים למאפיינים של מטריצת 1x2 המקורית, כמו המאפיינים של השידור (1, 2). אפשר להוסיף את מערך הביניים הזה למטריצה 4x3x1 באמצעות שידור של ממדים מנוונים כדי ליצור מערך 4x3x2 כתוצאה.