סמנטיקה של פעולה

בהמשך מתואר הסמנטיקה של הפעולות שמוגדרות בממשק XlaBuilder. בדרך כלל, הפעולות האלה ממופות אחד לאחד לפעולות שמוגדרות בממשק ה-RPC ב-xla_data.proto.

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

AfterAll

מידע נוסף זמין במאמר XlaBuilder::AfterAll.

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

AfterAll(operands)

ארגומנטים סוג סמנטיקה
operands XlaOp מספר משתנה של אסימונים

AllGather

מידע נוסף זמין במאמר XlaBuilder::AllGather.

מבצעת שרשור בין רפליקציות.

AllGather(operand, all_gather_dim, shard_count, replica_group_ids, channel_id)

ארגומנטים סוג סמנטיקה
operand XlaOp מערך לשרשור בין עותקים
all_gather_dim int64 מאפיין שרשור
replica_groups וקטור של וקטורים של int64 הקבוצות שבין
channel_id אופציונלי int64 מזהה ערוץ אופציונלי לתקשורת בין מודולים
  • replica_groups הוא רשימה של קבוצות רפליקות שביניהן מתבצע שרשור (מזהה הרפליקציה של הרפליקה הנוכחית אפשר לאחזר באמצעות ReplicaId). סדר הרפליקות בכל קבוצה קובע את הסדר שבו ערכי הקלט שלהן נמצאים בתוצאה. השדה replica_groups חייב להיות ריק (במקרה כזה כל הרפליקות שייכות לקבוצה אחת, בסדר מ-0 עד N - 1), או להכיל את אותו מספר רכיבים כמו מספר הרפליקות. לדוגמה, replica_groups = {0, 2}, {1, 3} מבצע שרשור בין הרפליקות 0 ל-2, לבין 1 ו-3.
  • shard_count הוא הגודל של כל קבוצת עותקים. אנחנו זקוקים לזה במקרים שבהם הערכים של replica_groups ריקים.
  • השדה channel_id משמש לתקשורת בין מודולים: רק פעולות all-gather עם אותו channel_id יכולות לתקשר זו עם זו.

צורת הפלט היא צורת הקלט, כאשר all_gather_dim גדולה פי shard_count. לדוגמה, אם יש שתי רפליקות והאופרטנד הוא [1.0, 2.5] ו-[3.0, 5.25], בהתאמה, בשתי הרפליקות, ערך הפלט של הפעולה הזו, כאשר all_gather_dim הוא 0, יהיה [1.0, 2.5, 3.0, 5.25] בשתי הרפליקות.

AllReduce

למידע נוסף, ראו XlaBuilder::AllReduce.

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

AllReduce(operand, computation, replica_group_ids, channel_id)

ארגומנטים סוג סמנטיקה
operand XlaOp מערך או קבוצת מערכי tupliות לא ריקה שרוצים לצמצם בין הרפליקות
computation XlaComputation חישוב ההנחה
replica_groups וקטור של וקטורים של int64 הקבוצות שביניהן מתבצעות ההנחות
channel_id אופציונלי int64 מזהה ערוץ אופציונלי לתקשורת בין מודולים
  • כש-operand הוא קבוצה של מערכי משנה, הפעולה all-reduce מתבצעת בכל אלמנט של הקבוצה.
  • replica_groups היא רשימה של קבוצות של רפליקות שביניהן מתבצעת ההפחתה (אפשר לאחזר את מזהה הרפליקה של הרפליקה הנוכחית באמצעות ReplicaId). replica_groups חייבת להיות ריקה (במקרה כזה, כל הרפליקות שייכות לקבוצה אחת) או להכיל את אותו מספר רכיבים כמו מספר הרפליקות. לדוגמה, replica_groups = {0, 2}, {1, 3} מבצע צמצום בין הרפליקות 0 ל-2, לבין 1 ו-3.
  • channel_id משמש לתקשורת בין מודולים: רק פעולות all-reduce עם אותו channel_id יכולות לתקשר זו עם זו.

צורת הפלט זהה לצורת הקלט. לדוגמה, אם יש שתי רפליקות והאופרנד מכיל את הערכים [1.0, 2.5] ו-[3.0, 5.25] בשתי הרפליקות, ערך הפלט מהפעולה הזו ומחישוב הסיכום יהיה [4.0, 7.75] בשתי הרפליקות. אם הקלט הוא tuple, גם הפלט הוא tuple.

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

AllToAll

למידע נוסף, ראו XlaBuilder::AllToAll.

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

  1. שלב הפיזור. בכל ליבה, המשתנה מפוצל למספר הבלוקים split_count לאורך split_dimensions, והבלוקים מפוזרים לכל הליבות, למשל, הבלוק ה-i נשלח לליבה ה-i.
  2. שלב האיסוף. כל ליבה מקשרת את הבלוקים שהתקבלו לאורך הערך של concat_dimension.

אפשר להגדיר את הליבות המשתתפות באופן הבא:

  • replica_groups: כל ReplicaGroup מכילה רשימה של מזהי רפליקציות שמשתתפים בחישוב (אפשר לאחזר את מזהה הרפליקציה של הרפליקציה הנוכחית באמצעות ReplicaId). המערכת תחיל את AllToAll בתוך תת-קבוצות לפי הסדר שצוין. לדוגמה, הערך replica_groups = { {1,2,3}, {4,5,0} } מציין ש-AllToAll יחול על הרפליקות {1, 2, 3}, ובשלב האיסוף, והבלוקים שהתקבלו יקושרו באותו הסדר של 1, 2, 3. לאחר מכן, המערכת תחיל את AllToAll אחר ברפליקות 4, 5 ו-0, וסדר השרשור הוא גם 4, 5, 0. אם השדה replica_groups ריק, כל הרפליקות שייכות לקבוצה אחת, לפי סדר הקונקטנוציה שלהן.

דרישות מוקדמות:

  • גודל המאפיין של האופרנד ב-split_dimension מתחלק ב-split_count.
  • צורת האופרנד היא לא חצאית.

AllToAll(operand, split_dimension, concat_dimension, split_count, replica_groups)

ארגומנטים סוג סמנטיקה
operand XlaOp מערך קלט ממדי של n
split_dimension int64 ערך במרווח [0, n) שמציין את המאפיין שבו מתבצע הפיצול של הפועל
concat_dimension int64 ערך במרווח [0, n) שמציין את המאפיין שלצידו מחוברים הבלוקים של הפיצול
split_count int64 מספר הליבות שמשתתפות בפעולה הזו. אם השדה replica_groups ריק, הערך צריך להיות מספר הרפליקות. אחרת, הערך צריך להיות שווה למספר הרפליקות בכל קבוצה.
replica_groups וקטור ReplicaGroup כל קבוצה מכילה רשימה של מזהי רפליקות.

למטה מוצגת דוגמה של Alltoall.

XlaBuilder b("alltoall");
auto x = Parameter(&b, 0, ShapeUtil::MakeShape(F32, {4, 16}), "x");
AllToAll(x, /*split_dimension=*/1, /*concat_dimension=*/0, /*split_count=*/4);

בדוגמה הזו, יש 4 ליבות שמשתתפות ב-Alltoall. בכל ליבה, המשתנה מחולק ל-4 חלקים לפי המאפיין 0, כך שכל חלק הוא מסוג f32‏[4,4]. 4 החלקים מפוזרים לכל הליבות. לאחר מכן, כל ליבה מקשרת את החלקים שהתקבלו לפי המאפיין 1, בסדר של הליבה 0-4. לכן הפלט בכל ליבה הוא בפורמט f32[16,4].

BatchNormGrad

תיאור מפורט של האלגוריתם מופיע גם ב-XlaBuilder::BatchNormGrad ובמאמר המקורי על נירמול בכמות גדולה.

מחשבת הדרגתיות של נורמה באצווה.

BatchNormGrad(operand, scale, mean, variance, grad_output, epsilon, feature_index)

ארגומנטים סוג סמנטיקה
operand XlaOp מערך ממדי של n לנרמול (x)
scale XlaOp מערך מימדי אחד (\(\gamma\))
mean XlaOp מערך חד-מימדי (\(\mu\))
variance XlaOp מערך מימדי אחד (\(\sigma^2\))
grad_output XlaOp שלבים שהועברו אל BatchNormTraining (\(\nabla y\))
epsilon float ערך אפסילון (\(\epsilon\))
feature_index int64 אינדקס למאפיין נבחר ב-operand

לכל מאפיין במאפיין התכונה (feature_index הוא האינדקס של המאפיין במאפיין ב-operand), הפעולה מחשבת את ההדרגתיות ביחס ל-operand, ל-offset ול-scale בכל שאר המאפיינים. feature_index חייב להיות אינדקס חוקי למאפיין התכונה ב-operand.

שלושת הגרדיאנטים מוגדרים לפי הנוסחאות הבאות (בהנחה שמשתמשים במערך 4-מימדי בתור operand, עם אינדקס של מאפיין המאפיין l, גודל האצווה m וגדלים מרחביים w ו-h):

\[ \begin{split} c_l&= \frac{1}{mwh}\sum_{i=1}^m\sum_{j=1}^w\sum_{k=1}^h \left( \nabla y_{ijkl} \frac{x_{ijkl} - \mu_l}{\sigma^2_l+\epsilon} \right) \\\\ d_l&= \frac{1}{mwh}\sum_{i=1}^m\sum_{j=1}^w\sum_{k=1}^h \nabla y_{ijkl} \\\\ \nabla x_{ijkl} &= \frac{\gamma_{l} }{\sqrt{\sigma^2_{l}+\epsilon} } \left( \nabla y_{ijkl} - d_l - c_l (x_{ijkl} - \mu_{l}) \right) \\\\ \nabla \gamma_l &= \sum_{i=1}^m\sum_{j=1}^w\sum_{k=1}^h \left( \nabla y_{ijkl} \frac{x_{ijkl} - \mu_l}{\sqrt{\sigma^2_{l}+\epsilon} } \right) \\\\\ \nabla \beta_l &= \sum_{i=1}^m\sum_{j=1}^w\sum_{k=1}^h \nabla y_{ijkl} \end{split} \]

ערכי הקלט mean ו-variance מייצגים ערכי רגעים לפי אצווה וממדים מרחביים.

סוג הפלט הוא קבוצה של שלושה כינויים:

פלט סוג סמנטיקה
grad_operand XlaOp שיפוע ביחס לקלט operand‏ ($\nabla x$)
grad_scale XlaOp שיפוע ביחס לקלט scale ($\nabla \gamma$)
grad_offset XlaOp שיפוע ביחס לקלט offset‏($\nabla \beta$)

BatchNormInference

תיאור מפורט של האלגוריתם זמין גם במאמרים XlaBuilder::BatchNormInference והמאמר המקורי בנושא נורמליזציה באצווה.

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

BatchNormInference(operand, scale, offset, mean, variance, epsilon, feature_index)

ארגומנטים סוג סמנטיקה
operand XlaOp מערך ממדי של n לנרמול
scale XlaOp מערך מימדי אחד
offset XlaOp מערך מימדי אחד
mean XlaOp מערך מימדי אחד
variance XlaOp מערך מימדי אחד
epsilon float ערך אפסילון
feature_index int64 אינדקס למאפיין נבחר ב-operand

לכל מאפיין במאפיין המאפיין (feature_index הוא האינדקס של מאפיין המאפיין ב-operand), הפעולה מחשבת את הממוצע והשונות בכל המאפיינים האחרים, ומשתמשת בממוצע ובשונות כדי לנרמל כל רכיב ב-operand. הערך של feature_index חייב להיות אינדקס חוקי למאפיין המאפיין ב-operand.

BatchNormInference היא שוות-ערך לקריאה ל-BatchNormTraining בלי לחשב את mean ו-variance לכל קבוצה. במקום זאת, המערכת משתמשת בערכים המשוערים mean ו-variance. המטרה של הפעולה הזו היא לצמצם את זמן האחזור בתהליך ההסקה, ולכן השם שלה הוא BatchNormInference.

הפלט הוא מערך n-ממדי ומנורמל, שיש לו צורה זהה לזו של הקלט operand.

BatchNormTraining

למידע מפורט של האלגוריתם, ראו XlaBuilder::BatchNormTraining ו-the original batch normalization paper.

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

BatchNormTraining(operand, scale, offset, epsilon, feature_index)

ארגומנטים סוג סמנטיקה
operand XlaOp מערך n-מימדי לצורך נירמול (x)
scale XlaOp מערך מימדי אחד (\(\gamma\))
offset XlaOp מערך חד-מימדי (\(\beta\))
epsilon float ערך אפסילון (\(\epsilon\))
feature_index int64 אינדקס למאפיין התכונה ב-operand

לכל מאפיין במאפיין המאפיין (feature_index הוא האינדקס של מאפיין המאפיין ב-operand), הפעולה מחשבת את הממוצע והשונות בכל המאפיינים האחרים, ומשתמשת בממוצע ובשונות כדי לנרמל כל רכיב ב-operand. הערך של feature_index חייב להיות אינדקס חוקי למאפיין המאפיין ב-operand.

האלגוריתם פועל באופן הבא לכל קבוצה ב-operand \(x\) שמכילה m רכיבי m עם w ו-h כגודל של ממדים מרחביים (בהנחה ש-operand הוא מערך דו-ממדי):

  • חישוב הממוצע של הקבוצה \(\mu_l\) לכל מאפיין l במאפיין המאפיין: \(\mu_l=\frac{1}{mwh}\sum_{i=1}^m\sum_{j=1}^w\sum_{k=1}^h x_{ijkl}\)

  • חישוב השונות באצווה \(\sigma^2_l\): $\sigma^2l=\frac{1}{mwh}\sum{i=1}^m\sum{j=1}^w\sum{k=1}^h (x_{ijkl} - \mu_l)^2$

  • נרמול, שינוי גודל ושינויים: \(y_{ijkl}=\frac{\gamma_l(x_{ijkl}-\mu_l)}{\sqrt[2]{\sigma^2_l+\epsilon} }+\beta_l\)

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

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

פלט סוג סמנטיקה
output XlaOp מערך n-ממדי באותה צורה כמו הקלט operand‏ (y)
batch_mean XlaOp מערך מימדי אחד (\(\mu\))
batch_var XlaOp מערך מימדי אחד (\(\sigma^2\))

הערכים batch_mean ו-batch_var הם רגעים שמחושבים במאפיינים של האצווה והמרחב באמצעות הנוסחאות שלמעלה.

BitcastConvertType

מידע נוסף זמין במאמר XlaBuilder::BitcastConvertType.

בדומה ל-tf.bitcast ב-TensorFlow, מבצעת פעולת bitcast לפי רכיב מצורף (element-wise) מצורת נתונים לצורת יעד. גודל הקלט והפלט חייב להיות זהה: לדוגמה, רכיבי s32 הופכים לרכיבי f32 באמצעות תוכנית bitcast, ורכיב s32 אחד הופך לארבעה רכיבי s8. ה-bitcast מיושם כ-cast ברמה נמוכה, כך שמכונות עם ייצוגים שונים של נקודות צפות יניבו תוצאות שונות.

BitcastConvertType(operand, new_element_type)

ארגומנטים סוג סמנטיקה
operand XlaOp מערך מסוג T עם מאפייני גודל D
new_element_type PrimitiveType סוג U

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

סוגי הרכיבים של המקור והיעד לא יכולים להיות זוגות.

המרה של Bitcast לסוג פרימיטיבי ברוחב שונה

הוראה BitcastConvert של HLO תומכת במקרה שבו הגודל של סוג רכיב הפלט T' לא שווה לגודל של רכיב הקלט T. מכיוון שהפעולה כולה היא בעצם bitcast ולא משתנה את הבייטים הבסיסיים, הצורה של רכיב הפלט צריכה להשתנות. עבור B = sizeof(T), B' = sizeof(T'), יש שני מקרים אפשריים.

קודם כול, כשהערך הוא B > B', צורת הפלט מקבלת ממד חדש, משני הצדדים, בגודל B/B'. לדוגמה:

  f16[10,2]{1,0} %output = f16[10,2]{1,0} bitcast-convert(f32[10]{0} %input)

הכלל נשאר זהה למשתנים סקלריים יעילים:

  f16[2]{0} %output = f16[2]{0} bitcast-convert(f32[] %input)

לחלופין, עבור B' > B ההוראה דורשת שהמאפיין הלוגי האחרון של צורת הקלט יהיה שווה ל-B'/B, והמאפיין הזה מושמט במהלך ההמרה:

  f32[10]{0} %output = f32[10]{0} bitcast-convert(f16[10,2]{1,0} %input)

חשוב לשים לב שהמרות בין רוחבי סיביות שונים לא מבוצעות באופן מהותי.

להודיע לכולם

מידע נוסף זמין במאמר XlaBuilder::Broadcast.

הוספת מאפיינים למערך על ידי שכפול הנתונים במערך.

Broadcast(operand, broadcast_sizes)

ארגומנטים סוג סמנטיקה
operand XlaOp המערך לשכפול
broadcast_sizes ArraySlice<int64> הגדלים של המאפיינים החדשים

המימדים החדשים נוספו בצד שמאל, כלומר אם ל-broadcast_sizes יש את הערכים {a0, ..., aN} ולצורה האופרנדית יש מידות {b0, ..., bM}, לצורת הפלט יש מידות של {a0, ..., aN, b0, ..., bM}.

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

output[i0, ..., iN, j0, ..., jM] = operand[j0, ..., jM]

לדוגמה, אם operand הוא f32 סקלר עם הערך 2.0f, ו-broadcast_sizes הוא {2, 3}, התוצאה תהיה מערך עם צורה f32[2, 3] וכל הערכים בתוצאה יהיו 2.0f.

BroadcastInDim

למידע נוסף, ראו XlaBuilder::BroadcastInDim.

הרחבת הגודל והדירוג של מערך על ידי שכפול הנתונים במערך.

BroadcastInDim(operand, out_dim_size, broadcast_dimensions)

ארגומנטים סוג סמנטיקה
operand XlaOp המערך שרוצים לשכפל
out_dim_size ArraySlice<int64> הגדלים של המאפיינים של צורת היעד
broadcast_dimensions ArraySlice<int64> המאפיין בצורת היעד שאליו מתאים כל מאפיין בצורת המשתנה

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

הערך של operand מופץ לצורה שמתוארת על ידי out_dim_size. הפונקציה broadcast_dimensions ממפה את המאפיינים של operand למאפיינים של צורת היעד, כלומר המאפיין ה-i של המשתנה המבצע ממופה למאפיין ה-broadcast_dimension[i] של צורת הפלט. המידות של operand צריכות להיות בגודל 1 או להיות באותו גודל כמו המאפיין בפלט שאליו הם ממופים. שאר המאפיינים יתמלאו במאפיינים בגודל 1. לאחר מכן, השידור של המאפיינים המנוונים מתבצע לאורך המאפיינים המנוונים האלה כדי להגיע לצורת הפלט. הסמנטיקה מתוארת בפירוט בדף השידור.

התקשרות

למידע נוסף, ראו XlaBuilder::Call.

מפעילה חישוב עם הארגומנטים הנתונים.

Call(computation, args...)

ארגומנטים סוג סמנטיקה
computation XlaComputation חישוב מסוג T_0, T_1, ..., T_{N-1} -> S עם N פרמטרים מסוג שרירותי
args רצף של N XlaOps N ארגומנטים מסוג שרירותי

ה-arity והסוגים של args חייבים להתאים לפרמטרים של computation. מותר שלא יהיה args.

Cholesky

למידע נוסף, ראו XlaBuilder::Cholesky.

הפונקציה מחשבת את הניתוח של Cholesky של קבוצה של מטריצות סימטריות (הרמיטיות) חיוביות מוגדרות.

Cholesky(a, lower)

ארגומנטים סוג סמנטיקה
a XlaOp מערך מסוג מספר מרוכב או מספר צף, בעל דרגה גדולה מ-2.
lower bool אם להשתמש במשולש העליון או התחתון של a.

אם lower הוא true, הפונקציה מחשבת מטריצות משולש תחתון l כך ש-‎$a = l . l^T$. אם lower הוא false, מחשב מטריצות משושות עליונות u כך ש\(a = u^T . u\).

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

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

אם a הוא לא ערך חיובי סימטרי (הרמיטיה), התוצאה מוגדרת מראש לפי תהליך ההטמעה.

קליפ

למידע נוסף, ראו XlaBuilder::Clamp.

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

Clamp(min, operand, max)

ארגומנטים סוג סמנטיקה
min XlaOp מערך מסוג T
operand XlaOp מערך מסוג T
max XlaOp מערך מסוג T

הפונקציה מקבלת אופרנד וערכים מינימלי ומקסימלי, ומחזירה את האופרנד אם הוא נמצא בטווח שבין הערך המינימלי לערך המקסימלי. אחרת, הפונקציה מחזירה את הערך המינימלי אם האופרנד נמוך מהטווח הזה, או את הערך המקסימלי אם האופרנד גבוה מהטווח הזה. כלומר, clamp(a, x, b) = min(max(a, x), b).

כל שלוש המערכות צריכות להיות באותו צורה. לחלופין, כצורה מוגבלת של שידור, min ו/או max יכולים להיות סקלר מסוג T.

דוגמה עם סקלר min ו-max:

let operand: s32[3] = {-1, 5, 9};
let min: s32 = 0;
let max: s32 = 6;
==>
Clamp(min, operand, max) = s32[3]{0, 5, 6};

כיווץ

אפשר לעיין גם במאמר XlaBuilder::Collapse ובפעולה tf.reshape.

צמצום המימדים של מערך למימד אחד.

Collapse(operand, dimensions)

ארגומנטים סוג סמנטיקה
operand XlaOp מערך מסוג T
dimensions וקטור int64 קבוצת משנה עוקבת בסדר של המאפיינים של T.

כיווץ מחליף את קבוצת המשנה הנתונה של מאפייני האופרנד במאפיין יחיד. ארגומנטים מסוג קלט הם מערך שרירותי מסוג T והוא וקטור קבוע-זמן הידור של אינדקסי מאפיינים. האינדקסים של המאפיינים חייבים להיות בסדר אלפביתי (מספרים מהנמוך לגבוה), קבוצת משנה רציפה של מאפייני T. לדוגמה, {0, 1, 2}, {0, 1} או {1, 2} הן קבוצות מאפיינים חוקיות, אבל {1, 0} או {0, 2} לא. הם מוחלפים במאפיין חדש יחיד, באותו מיקום ברצף המאפיינים שבו הם מוחלפים, כאשר גודל המאפיין החדש שווה למכפלה של גדלי המאפיינים המקוריים. מספר המאפיין הנמוך ביותר ב-dimensions הוא המאפיין המשתנה האיטי ביותר (החשוב ביותר) בתוך ערימת הלולאות שמצמצמת את המאפיינים האלה, ומספר המאפיין הגבוה ביותר הוא המאפיין המשתנה המהיר ביותר (החשוב פחות). אם אתם צריכים סדר קריאה כללי יותר של התכונה 'קיבוץ', תוכלו לעיין באופרטור tf.reshape.

לדוגמה, נניח ש-v הוא מערך של 24 רכיבים:

let v = f32[4x2x3] { { {10, 11, 12},  {15, 16, 17} },
{ {20, 21, 22},  {25, 26, 27} },
{ {30, 31, 32},  {35, 36, 37} },
{ {40, 41, 42},  {45, 46, 47} } };

// Collapse to a single dimension, leaving one dimension.
let v012 = Collapse(v, {0,1,2});
then v012 == f32[24] {10, 11, 12, 15, 16, 17,
20, 21, 22, 25, 26, 27,
30, 31, 32, 35, 36, 37,
40, 41, 42, 45, 46, 47};

// Collapse the two lower dimensions, leaving two dimensions.
let v01 = Collapse(v, {0,1});
then v01 == f32[4x6] { {10, 11, 12, 15, 16, 17},
{20, 21, 22, 25, 26, 27},
{30, 31, 32, 35, 36, 37},
{40, 41, 42, 45, 46, 47} };

// Collapse the two higher dimensions, leaving two dimensions.
let v12 = Collapse(v, {1,2});
then v12 == f32[8x3] { {10, 11, 12},
{15, 16, 17},
{20, 21, 22},
{25, 26, 27},
{30, 31, 32},
{35, 36, 37},
{40, 41, 42},
{45, 46, 47} };

CollectivePermute

מידע נוסף זמין במאמר XlaBuilder::CollectivePermute.

CollectivePermute היא פעולה קולקטיבית ששולחת ומקבלים רפליקות בין נתונים.

CollectivePermute(operand, source_target_pairs)

ארגומנטים סוג סמנטיקה
operand XlaOp מערך קלט n-ממדי
source_target_pairs וקטור <int64, int64> רשימה של זוגות (source_replica_id, target_replica_id). לכל צמד, המשתנה נשלח מהרפליקה של המקור לרפליקה של היעד.

חשוב לשים לב שההגבלות הבאות חלות על source_target_pair:

  • לכל שני זוגות לא יכול להיות אותו מזהה של רפליקת יעד, וגם לא אותו מזהה של רפליקת מקור.
  • אם מזהה עותק הוא לא יעד באף צמד, הפלט ברפליקציות הזה הוא טנזור שכולל 0(ים) עם צורה זהה לקלט.

שרשור

מידע נוסף זמין במאמר XlaBuilder::ConcatInDim.

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

Concatenate(operands..., dimension)

ארגומנטים סוג סמנטיקה
operands רצף של N XlaOp N מערכי T עם המאפיינים [L0, L1, ...]. נדרש N >= 1.
dimension int64 ערך במרווח [0, N) שמציין את המאפיין שיש לחבר בין operands.

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

דוגמה במאפיין אחד:

Concat({ {2, 3}, {4, 5}, {6, 7} }, 0)
>>> {2, 3, 4, 5, 6, 7}

דוגמה לדו-ממדית:

let a = {
{1, 2},
{3, 4},
{5, 6},
};
let b = {
{7, 8},
};
Concat({a, b}, 0)
>>> {
{1, 2},
{3, 4},
{5, 6},
{7, 8},
}

דיאגרמה:

משפטי תנאי

מידע נוסף זמין במאמר XlaBuilder::Conditional.

Conditional(pred, true_operand, true_computation, false_operand, false_computation)

ארגומנטים סוג סמנטיקה
pred XlaOp סקלר מסוג PRED
true_operand XlaOp ארגומנט מסוג \(T_0\)
true_computation XlaComputation XlaComputation מסוג \(T_0 \to S\)
false_operand XlaOp ארגומנט מסוג \(T_1\)
false_computation XlaComputation XlaComputation מסוג \(T_1 \to S\)

הפונקציה מפעילה את true_computation אם הערך של pred הוא true, את false_computation אם הערך של pred הוא false ומחזירה את התוצאה.

הפונקציה true_computation חייבת לקבל ארגומנט יחיד מסוג \(T_0\) , והיא תופעל באמצעות true_operand, שגם הוא חייב להיות מאותו סוג. הפונקציה false_computation חייבת לקבל ארגומנט יחיד מסוג \(T_1\) , והיא תופעל באמצעות false_operand, שגם הוא חייב להיות מאותו סוג. הסוג של הערך המוחזר של true_computation ושל false_computation חייב להיות זהה.

הערה: רק אחד מהמאפיינים true_computation ו-false_computation יבוצע, בהתאם לערך של pred.

Conditional(branch_index, branch_computations, branch_operands)

ארגומנטים סוג סמנטיקה
branch_index XlaOp סקלר מסוג S32
branch_computations רצף של N XlaComputation Xlaחישובים מסוג \(T_0 \to S , T_1 \to S , ..., T_{N-1} \to S\)
branch_operands רצף של N XlaOp ארגומנטים מסוג \(T_0 , T_1 , ..., T_{N-1}\)

הפונקציה מפעילה את branch_computations[branch_index] ומחזירה את התוצאה. אם branch_index הוא S32 שהוא < 0 או >= N, אז branch_computations[N-1] מופעל כענף ברירת המחדל.

כל branch_computations[b] חייב לקבל ארגומנט יחיד מסוג \(T_b\) , והוא יופעל באמצעות branch_operands[b] שחייב להיות מאותו סוג. סוג הערך המוחזר של כל branch_computations[b] חייב להיות זהה.

שימו לב שרק אחד מהשדות branch_computations יופעל, בהתאם לערך של branch_index.

Conv (convolution)

מידע נוסף זמין במאמר XlaBuilder::Conv.

כמו ConvWithGeneralPadding, אבל המילוי מצוין בקיצור כ-SAME או כ-VALID. בדילול SAME, הקלט (lhs) מתמלא באפסים כדי שהפלט יהיה באותו צורה כמו הקלט, בלי להביא בחשבון את ה-striding. משמעות האפשרות VALID padding היא פשוט ללא תוספת.

ConvWithGeneralPadding (עיבוד נתונים באמצעות convolve)

למידע נוסף, ראו XlaBuilder::ConvWithGeneralPadding.

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

ארגומנטים סוג סמנטיקה
lhs XlaOp דירוג n+2 מערך קלט
rhs XlaOp מערך של משקלים של גרעיני חזקה n+2
window_strides ArraySlice<int64> מערך n-ממדי של צעדים של ליבה
padding ArraySlice< pair<int64,int64>> מערך n-d של מרווח פנימי (נמוך, גבוה)
lhs_dilation ArraySlice<int64> מערך של גורם הרחבה של n-d lhs
rhs_dilation ArraySlice<int64> מערך גורם הרחבה n-d rhs
feature_group_count int64 מספר הקבוצות של התכונות
batch_group_count int64 מספר הקבוצות באצווה

נניח ש-n הוא מספר המימדים המרחביים. הארגומנט lhs הוא מערך דירוג n+2 שמתאר את אזור הבסיס. זה נקרא הקלט, למרות שגם ה-rhs הוא קלט. ברשת נוירונים, אלה הפעלות הקלט. המאפיינים n+2 הם, לפי הסדר הזה:

  • batch: כל קואורדינטה במאפיין הזה מייצגת קלט עצמאי שעבורו מתבצעת הקונבולוציה.
  • z/depth/features: לכל מיקום (x,y) באזור הבסיס משויך וקטור שמשויך למאפיין הזה.
  • spatial_dims: מתאר את המאפיינים המרחביים n שמגדירים את אזור הבסיס שבו החלון נע.

הארגומנט rhs הוא מערך בעל דרגה n+2 שמתאר את המסנן/הגרעין/החלון הקוונטי. המאפיינים הם, לפי הסדר הזה:

  • output-z: המאפיין z של הפלט.
  • input-z: הגודל של המימד הזה כפול feature_group_count צריך להיות שווה לגודל של המימד z ביחידות מידה שלמות.
  • spatial_dims: תיאור המימדים המרחביים של n שמגדירים את חלון ה-n-d שנע על פני אזור הבסיס.

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

הארגומנט padding מציין את הכמות של אפס מרווחים שצריך להחיל על אזור הבסיס. כמות המרווח הפנימי יכולה להיות שלילית – הערך המוחלט של המרווח הפנימי מציין את מספר הרכיבים שיש להסיר מהמאפיין שצוין לפני ביצוע הקונבולוציה. padding[0] מציין את המילוי למאפיין y ו-padding[1] מציין את המילוי למאפיין x. לכל זוג יש את המרווח הפנימי הנמוך בתור הרכיב הראשון, ואת המרווח הפנימי הגבוה בתור הרכיב השני. המרווח הפנימי הנמוך מוחל בכיוון האינדקסים הנמוכים יותר, והמרווח הפנימי הגבוה מוחל בכיוון האינדקסים הגבוהים יותר. לדוגמה, אם הערך של padding[1] הוא (2,3), תתבצע הוספת 2 אפסים בצד ימין ו-3 אפסים בצד שמאל במאפיין המרחבי השני. השימוש במילוי שווה ערך להוספת אותם ערכי אפס לקלט (lhs) לפני ביצוע ההתמרה.

הארגומנטים lhs_dilation ו-rhs_dilation מציינים את גורם ההרחבה שיש להחיל על Hs ו-rhs, בהתאמה, בכל מימד מרחבי. אם גורם ההרחבה במימד מרחבי הוא d, אז חורי d-1 מוצבים במרומז בין כל אחד מהפריטים במימד הזה וכך מגדילים את המערך. החורים מלאים בערך מסוג no-op, שמשמעותו קונבולציה היא אפסים.

הרחבה של הצד הימני של המשוואה נקראת גם 'קונבולוציה אטרוסית'. למידע נוסף, ראו tf.nn.atrous_conv2d. הרחבה של ה-lhs נקראת גם טרנספוזיציה של convolve. פרטים נוספים זמינים במאמר tf.nn.conv2d_transpose.

אפשר להשתמש בארגומנט feature_group_count (ערך ברירת המחדל הוא 1) כדי לבצע עיבוד נתונים קבוצתי. הערך feature_group_count צריך להיות מחלק של מאפיין הקלט ושל מאפיין הפלט. אם הערך של feature_group_count גדול מ-1, המשמעות היא שקונספטואלית, מאפייני הקלט והפלט ומאפייני הפלט של rhs מחולקים באופן שווה למספר רב של קבוצות feature_group_count, כאשר כל קבוצה מורכבת מרצף משנה רציף של מאפיינים. המאפיין של מאפיין הקלט rhs צריך להיות שווה למאפיין של מאפיין הקלט lhs חלקי feature_group_count (כך שהוא כבר בגודל של קבוצה של מאפייני קלט). הקבוצות ה-i משמשות יחד כדי לחשב את feature_group_count עבור עיבודים מרובים של convolve. התוצאות של ההתחברות הזו מחוברות זו לזו במאפיין הפלט.

עבור convolveion לעומק, הארגומנט feature_group_count יוגדר למאפיין של מאפיין הקלט, והמסנן ישתנה מ-[filter_height, filter_width, in_channels, channel_multiplier] ל-[filter_height, filter_width, 1, in_channels * channel_multiplier]. לפרטים נוספים: tf.nn.depthwise_conv2d.

אפשר להשתמש בארגומנט batch_group_count (ערך ברירת המחדל 1) למסננים מקובצים במהלך ההפצה לאחור. batch_group_count צריך להיות המחלק של הגודל של המימד lhs (קלט). אם הערך של batch_group_count גדול מ-1, המשמעות היא שהמאפיין batch של הפלט צריך להיות בגודל input batch / batch_group_count. הערך של batch_group_count חייב להיות מחלק של גודל המאפיינים של הפלט.

לצורת הפלט יש את המידות האלו, בסדר הזה:

  • batch: הגודל של המימד הזה כפול batch_group_count צריך להיות שווה לגודל של המימד batch בשניות.
  • z: באותו גודל כמו output-z בליבה (rhs).
  • spatial_dims: ערך אחד לכל מיקום תקין של החלון הקוונטי.

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

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

כדי לתאר את הפעולה של קונבולציה, נבחן קונבולציה דו-מימדית ונבחר כמה קואורדינטות קבועות batch,‏ z,‏ y,‏ x בפלט. במקרה כזה, הערך של (y,x) הוא המיקום של פינה של החלון בתוך אזור הבסיס (למשל, הפינה הימנית העליונה, בהתאם לאופן שבו מפרשים את המימדים המרחביים). עכשיו יש לנו חלון דו-מימדי, שנלקח מאזור הבסיס, שבו כל נקודה דו-מימדית משויכת לוקטור חד-מימדי, כך שאנחנו מקבלים תיבה תלת-מימדית. מהליבה המורכבת, מכיוון תיקנו את קואורדינטת הפלט z, יש לנו גם תיבה תלת ממדית. לשתי התיבות יש אותם מאפיינים, כך שאפשר לחשב את הסכום של המכפלות של הרכיבים בין שתי התיבות (בדומה למכפלה סקלרית). זהו ערך הפלט.

הערה: אם הערך של output-z הוא, למשל, 5, כל מיקום של החלון יוצר 5 ערכים בפלט במאפיין z של הפלט. הערכים האלו שונים בחלק מהליבה המסוכנת שבה משתמשים – יש תיבת ערכים תלת-ממדית נפרדת לכל קואורדינטה output-z. אפשר לחשוב על זה בתור 5 convolve נפרד עם מסנן שונה לכל אחד מהם.

הנה קוד מדומה לקונבולוציה דו-ממדית עם מרווח פנימי וצעדות:

for (b, oz, oy, ox) {  // output coordinates
  value = 0;
  for (iz, ky, kx) {  // kernel coordinates and input z
    iy = oy*stride_y + ky - pad_low_y;
    ix = ox*stride_x + kx - pad_low_x;
    if ((iy, ix) inside the base area considered without padding) {
      value += input(b, iz, iy, ix) * kernel(oz, iz, ky, kx);
    }
  }
  output(b, oz, oy, ox) = value;
}

ConvertElementType

מידע נוסף זמין במאמר XlaBuilder::ConvertElementType.

בדומה ל-static_cast לפי רכיב ב-C++, מבצע פעולת המרה לפי רכיב מתבנית נתונים לתבנית יעד. המאפיינים חייבים להיות זהים, וההמרה צריכה להיות מורכבת מהרכיבים. למשל, רכיבי s32 הופכים לרכיבי f32 באמצעות שגרת המרה של s32 ל-f32.

ConvertElementType(operand, new_element_type)

ארגומנטים סוג סמנטיקה
operand XlaOp מערך מסוג T עם מאפייני גודל D
new_element_type PrimitiveType סוג U

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

המרה כמו T=s32 ל-U=f32 תבצע נירמול של שגרת המרות מסוג 'מספר ציפה', למשל 'מסביב לשווי'.

let a: s32[3] = {0, 1, 2};
let b: f32[3] = convert(a, f32);
then b == f32[3]{0.0, 1.0, 2.0}

CrossReplicaSum

ביצוע AllReduce עם חישוב סכום.

CustomCall

למידע נוסף, ראו XlaBuilder::CustomCall.

קריאה לפונקציה שהמשתמש סיפק בתוך חישוב.

CustomCall(target_name, args..., shape)

ארגומנטים סוג סמנטיקה
target_name string שם הפונקציה. תופעל הוראה של קריאה שמטרגטת את שם הסמל הזה.
args רצף של N XlaOp שנ' N ארגומנטים מסוג שרירותי, שיועברו לפונקציה.
shape Shape צורת הפלט של הפונקציה

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

extern "C" void target_name(void* out, void** in);

לדוגמה, אם משתמשים בהתאמה אישית לשיחה:

let x = f32[2] {1,2};
let y = f32[2x3] { {10, 20, 30}, {40, 50, 60} };

CustomCall("myfunc", {x, y}, f32[3x3])

דוגמה להטמעה של myfunc:

extern "C" void myfunc(void* out, void** in) {
  float (&x)[2] = *static_cast<float(*)[2]>(in[0]);
  float (&y)[2][3] = *static_cast<float(*)[2][3]>(in[1]);
  EXPECT_EQ(1, x[0]);
  EXPECT_EQ(2, x[1]);
  EXPECT_EQ(10, y[0][0]);
  EXPECT_EQ(20, y[0][1]);
  EXPECT_EQ(30, y[0][2]);
  EXPECT_EQ(40, y[1][0]);
  EXPECT_EQ(50, y[1][1]);
  EXPECT_EQ(60, y[1][2]);
  float (&z)[3][3] = *static_cast<float(*)[3][3]>(out);
  z[0][0] = x[1] + y[1][0];
  // ...
}

אסור שפונקציה שהמשתמש מספק תהיה עם תופעות לוואי, וההפעלה שלה צריכה להיות חזקה (idempotent).

נקודה

מידע נוסף זמין במאמר XlaBuilder::Dot.

Dot(lhs, rhs)

ארגומנטים סוג סמנטיקה
lhs XlaOp מערך מסוג T
rhs XlaOp מערך מסוג T

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

קלט פלט סמנטיקה
vector [n] dot vector [n] סקלר מכפלה סקלרית של וקטורים
מטריצה [m x k] dot וקטור [k] וקטור [m] כפל של מטריצה וקטורית
מטריצה [m x k] dot מטריצה [k x n] מטריצת [m x n] כפל מטריצות

הפעולה מבצעת סכום של מוצרים במאפיין השני של lhs (או במאפיין הראשון אם הדירוג שלו הוא 1) ובמאפיין הראשון של rhs. אלה המאפיינים 'בהסכם'. המאפיינים המקוצרים של lhs ו-rhs חייבים להיות באותו גודל. בפועל, אפשר להשתמש בו כדי לבצע מכפלות נקודה בין וקטורים, מכפלות של וקטורים/מטריצות או מכפלות של מטריצות/מטריצות.

DotGeneral

למידע נוסף, ראו XlaBuilder::DotGeneral.

DotGeneral(lhs, rhs, dimension_numbers)

ארגומנטים סוג סמנטיקה
lhs XlaOp מערך מסוג T
rhs XlaOp מערך מסוג T
dimension_numbers DotDimensionNumbers מספרי ממדים מקוצרים ובאצווה

דומה ל-Dot, אבל מאפשר לציין מספרי מימדים חוזיים ובאצווה גם ל-lhs וגם ל-rhs.

שדות DotdimensionNumbers סוג סמנטיקה
lhs_contracting_dimensions repeated int64 lhs מספרי מאפיינים מתכווצים
rhs_contracting_dimensions repeated int64 rhs מספרי המאפיינים של הקבלן
lhs_batch_dimensions repeated int64 lhs מספרי מימדים באצווה
rhs_batch_dimensions repeated int64 rhs מספרי מימדים באצווה

הפונקציה DotGeneral מבצעת את סכום המכפלות של המאפיינים המצטמצמים שצוינו ב-dimension_numbers.

מספרי המידות המשויכים מ-lhs ומ-rhs לא צריכים להיות זהים, אבל המידות שלהם צריכות להיות זהות.

דוגמה עם מספרי מאפיינים של צדדים חותמים:

lhs = { {1.0, 2.0, 3.0},
{4.0, 5.0, 6.0} }

rhs = { {1.0, 1.0, 1.0},
{2.0, 2.0, 2.0} }

DotDimensionNumbers dnums;
dnums.add_lhs_contracting_dimensions(1);
dnums.add_rhs_contracting_dimensions(1);

DotGeneral(lhs, rhs, dnums) -> { {6.0, 12.0},
{15.0, 30.0} }

למספרי המאפיינים המשויכים של האצווה מהשדות lhs ו-rhs צריכים להיות אותם גדלים של מאפיינים.

דוגמה למספרים באצווה (מטריצות בגודל אצווה 2, 2x2):

lhs = { { {1.0, 2.0},
{3.0, 4.0} },
{ {5.0, 6.0},
{7.0, 8.0} } }

rhs = { { {1.0, 0.0},
{0.0, 1.0} },
{ {1.0, 0.0},
{0.0, 1.0} } }

DotDimensionNumbers dnums;
dnums.add_lhs_contracting_dimensions(2);
dnums.add_rhs_contracting_dimensions(1);
dnums.add_lhs_batch_dimensions(0);
dnums.add_rhs_batch_dimensions(0);

DotGeneral(lhs, rhs, dnums) -> { { {1.0, 2.0},
{3.0, 4.0} },
{ {5.0, 6.0},
{7.0, 8.0} } }
קלט פלט סמנטיקה
[b0, m, k] dot [b0, k, n] [b0, m, n] batch matmul
[b0, b1, m, k] dot [b0, b1, k, n] [b0, b1, m, n] batch matmul

לכן, מספר המאפיין שנוצר מתחיל במאפיין האצווה, ואז במאפיין lhs ללא חוזה/ללא אצווה, ולבסוף במאפיין rhs ללא חוזה/ללא אצווה.

DynamicSlice

מידע נוסף זמין במאמר XlaBuilder::DynamicSlice.

DynamicSlice מחלץ מערך משנה ממערך הקלט ב-start_indices הדינמי. הגודל של הפלחים בכל מאפיין מועבר ב-size_indices, שמציין את נקודת הסיום של מרווחים בלעדיים של פלחים בכל מאפיין:‏ [start, start + size). הצורה של start_indices חייבת להיות rank == 1, עם גודל מאפיין שווה לדרגה של operand.

DynamicSlice(operand, start_indices, size_indices)

ארגומנטים סוג סמנטיקה
operand XlaOp מערך N-מימדי מסוג T
start_indices רצף של N XlaOp רשימה של N מספרים שלמים סקלריים שמכילים את האינדקסים ההתחלתיים של הפלח לכל מאפיין. הערך חייב להיות גדול מ-0 או שווה ל-0.
size_indices ArraySlice<int64> רשימה של N מספרים שלמים שמכילה את גודל הפרוסת לכל מאפיין. כל ערך חייב להיות גדול מאפס, והערך start + size חייב להיות קטן או שווה לגודל המאפיין כדי למנוע גלישת מודולים לפי גודל המאפיין.

כדי לחשב את אינדקסי הפלחים היעילים, מחילים את הטרנספורמציה הבאה על כל אינדקס i ב-[1, N) לפני ביצוע הפלחים:

start_indices[i] = clamp(start_indices[i], 0, operand.dimension_size[i] - size_indices[i])

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

דוגמה חד-ממדית:

let a = {0.0, 1.0, 2.0, 3.0, 4.0}
let s = {2}

DynamicSlice(a, s, {2}) produces:
{2.0, 3.0}

דוגמה דו-ממדית:

let b =
{ {0.0,  1.0,  2.0},
{3.0,  4.0,  5.0},
{6.0,  7.0,  8.0},
{9.0, 10.0, 11.0} }
let s = {2, 1}

DynamicSlice(b, s, {2, 2}) produces:
{ { 7.0,  8.0},
{10.0, 11.0} }

DynamicUpdateSlice

למידע נוסף, ראו XlaBuilder::DynamicUpdateSlice.

הפונקציה DynamicUpdateSlice יוצרת תוצאה שהיא הערך של מערך הקלט operand, עם פלחים של update שמחליפים את start_indices. הצורה של update קובעת את הצורה של מערך המשנה של התוצאה שמתעדכן. הצורה של start_indices חייבת להיות בדירוג == 1, וגודל המימד שווה לדירוג של operand.

DynamicUpdateSlice(operand, update, start_indices)

ארגומנטים סוג סמנטיקה
operand XlaOp מערך ממדי של N מסוג T
update XlaOp מערך ממדי של N מסוג T שמכיל את עדכון הפלח. כל מימד של צורת עדכון חייב להיות גדול מאפס, ו'התחלה + עדכון' חייב להיות קטן מגודל האופרנד של כל מימד או שווה לו, כדי להימנע מיצירת מדדי עדכון מחוץ לתחום.
start_indices רצף של N XlaOp רשימה של N מספרים שלמים סקלריים שמכילים את האינדקסים ההתחלתיים של הפלח לכל מאפיין. הערך חייב להיות גדול מ-0 או שווה ל-0.

מדדי הפרוסות האפקטיביים מחושבים על ידי החלת הטרנספורמציה הבאה על כל אינדקס i ב-[1, N) לפני ביצוע הפרוסות:

start_indices[i] = clamp(start_indices[i], 0, operand.dimension_size[i] - update.dimension_size[i])

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

דוגמה חד-ממדית:

let a = {0.0, 1.0, 2.0, 3.0, 4.0}
let u = {5.0, 6.0}
let s = {2}

DynamicUpdateSlice(a, u, s) produces:
{0.0, 1.0, 5.0, 6.0, 4.0}

דוגמה דו-ממדית:

let b =
{ {0.0,  1.0,  2.0},
{3.0,  4.0,  5.0},
{6.0,  7.0,  8.0},
{9.0, 10.0, 11.0} }
let u =
{ {12.0,  13.0},
{14.0,  15.0},
{16.0,  17.0} }

let s = {1, 1}

DynamicUpdateSlice(b, u, s) produces:
{ {0.0,  1.0,  2.0},
{3.0, 12.0, 13.0},
{6.0, 14.0, 15.0},
{9.0, 16.0, 17.0} }

פעולות אריתמטיות בינאריות לפי רכיבים

מידע נוסף זמין במאמר XlaBuilder::Add.

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

Op(lhs, rhs)

OpAddSubMulDivPowRemMaxMinAndOrXorShiftLeftShiftRightArithmeticShiftRightLogicalAtan2Complex

ארגומנטים סוג סמנטיקה
lhs XlaOp אופרנד בצד ימין: מערך מסוג T
rhs XlaOp אופרנד בצד שמאל: מערך מסוג T

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

כש-Op הוא Rem, סימן התוצאה נלקח מהמחלק, והערך המוחלט של התוצאה תמיד קטן מהערך המוחלט של המחלק.

אם מתרחש חריגה ממכסת המספרים שלמים בחילוק (חילוק/שארית עם סימן או ללא סימן באפס, או חילוק/שארית עם סימן של INT_SMIN ב--1), מתקבל ערך שמוגדר על ידי ההטמעה.

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

Op(lhs, rhs, broadcast_dimensions)

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

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

פעולות השוואה ברמת הרכיב

למידע נוסף, ראו XlaBuilder::Eq.

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

Op(lhs, rhs)

כאשר Op הוא אחד מהערכים Eq (שווה ל-), Ne (לא שווה ל-), Ge (גדול או שווה ל-), Gt (גדול מ-), Le (פחות או שווה מ-), Lt (פחות מ-). קבוצה נוספת של אופרטורים, EqTotalOrder,‏ NeTotalOrder,‏ GeTotalOrder,‏ GtTotalOrder,‏ LeTotalOrder ו-LtTotalOrder, מספקת את אותן פונקציות, מלבד תמיכה נוספת בסדר מלא על מספרי נקודה צפה, על ידי אכיפה של -NaN < -Inf < -Finite < -0 < +0 < +Finite < +Inf < +NaN.

ארגומנטים סוג סמנטיקה
lhs XlaOp אופרנד בצד ימין: מערך מסוג T
rhs XlaOp אופרנד בצד שמאל: מערך מסוג T

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

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

Op(lhs, rhs, broadcast_dimensions)

כאשר הערך של Op זהה לערך שלמעלה. צריך להשתמש בגרסה הזו של הפעולה לפעולות השוואה בין מערכי משנה (arrays) של דרגות שונות (למשל, הוספת מטריצה לוקטור).

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

פונקציות יוניאריות לפי רכיב

ב-XlaBuilder יש תמיכה בפונקציות אונריות ברמת הרכיבים הבאות:

Abs(operand) אבסולוטיות x -> |x|.

Cbrt(operand) פעולת שורש מעוקבים ברמת הרכיב x -> cbrt(x).

Ceil(operand) x -> ⌈x⌉ – חלוקת הסכום של כל הרכיבים ב-1.

Clz(operand) ספירה של אפסים מובילים ברמת הרכיב.

Cos(operand) קוסינוס של רכיבים x -> cos(x).

Erf(operand) פונקציית שגיאה מבוססת-רכיב x -> erf(x) כאשר

\(\text{erf}(x) = \frac{2}{\sqrt{\pi} }\int_0^x e^{-t^2} \, dt\).

Exp(operand) מעריכי טבעי ברמת הרכיב x -> e^x.

Expm1(operand) מעריכיות טבעית ברמת הרכיב פחות x -> e^x - 1 אחת.

Floor(operand) x -> ⌊x⌋ – רצפה של כל רכיב.

Imag(operand) החלק המדומה של צורה מורכבת (או ממשית) לפי אלמנט. x -> imag(x). אם האופרנד הוא מסוג נקודה צפה, הפונקציה מחזירה 0.

IsFinite(operand) הפונקציה בודקת אם כל אלמנט ב-operand הוא סופי, כלומר, שהוא לא אינסוף חיובי או שלילי, והוא לא NaN. הפונקציה מחזירה מערך של ערכים מסוג PRED באותו צורה של הקלט, שבו כל רכיב הוא true אם ורק אם רכיב הקלט התואם הוא סופי.

Log(operand) לוגריתם טבעי מבחינת רכיבים x -> ln(x).

Log1p(operand) לוגריתם טבעי שהוזז לפי רכיבים x -> ln(1+x).

Logistic(operand) חישוב פונקציה לוגיסטית לפי רכיבים x -> logistic(x).

Neg(operand) ביטול של רכיבים x -> -x.

Not(operand) 'לא' לוגית לפי רכיבים x -> !(x).

PopulationCount(operand) חישוב מספר הסיביות שמוגדרים בכל רכיב של operand.

Real(operand) החלק האמיתי מבחינת הרכיבים מתוך צורה מורכבת (או אמיתית). x -> real(x). אם האופרנד הוא סוג נקודה צפה (floating-point), מחזירה את אותו ערך.

Round(operand) עיגול לפי אלמנט, במקרה של שוויון עיגול הרחק מהאפס.

RoundNearestEven(operand) עיגול לפי רכיבים, בחיבור לזוגי הקרוב ביותר.

Rsqrt(operand) הפונקציה ההדדית ברמת הרכיב של פעולת שורש ריבועית x -> 1.0 / sqrt(x).

Sign(operand) פעולת סימן ברמת הרכיב x -> sgn(x) כאשר

\[\text{sgn}(x) = \begin{cases} -1 & x < 0\\ -0 & x = -0\\ NaN & x = NaN\\ +0 & x = +0\\ 1 & x > 0 \end{cases}\]

באמצעות אופרטור ההשוואה של סוג הרכיב operand.

Sin(operand) סינוס של רכיבים x -> sin(x).

Sqrt(operand) פעולת שורש ריבועית מבחינת רכיב x -> sqrt(x).

Tan(operand) טנגנס מבחינת רכיבים x -> tan(x).

Tanh(operand) טנגנס היפרבולי לפי רכיבים x -> tanh(x).

ארגומנטים סוג סמנטיקה
operand XlaOp האופרנד לפונקציה

הפונקציה מוחלת על כל רכיב במערך operand, וכתוצאה מכך נוצרת מערך עם אותה הצורה. מותר ל-operand להיות סקלר (דרגה 0).

Fft

פעולת ה-FFT של XLA מיישמת את טרנספורמציית פורייה הישירה והפונקציה ההפוכה שלה לקלטים/פלטות אמיתיים ומרוכבים. יש תמיכה ב-FFTs מרובי-מימדים ב-3 צירים לכל היותר.

מידע נוסף זמין במאמר XlaBuilder::Fft.

ארגומנטים סוג סמנטיקה
operand XlaOp המערך שאנחנו ממירים בעזרת פורייה.
fft_type FftType פרטים נוספים מופיעים בטבלה שבהמשך.
fft_length ArraySlice<int64> אורכי דומיין הזמן של הצירים שעוברים טרנספורמציה. השינוי הזה נדרש במיוחד כדי ש-IRFFT יתאים את הגודל של הציר הפנימי ביותר, כי ל-RFFT(fft_length=[16]) יש צורת פלט זהה לזו של RFFT(fft_length=[17]).
FftType סמנטיקה
FFT FFT קדימה ממרוכב למרוכב. הצורה לא משתנה.
IFFT המרה מרוכבת מרוכבת למורכבת (FFT), הצורה לא השתנתה.
RFFT FFT קדימה ממרחב ממשי למרוכב. הצורה של הציר הפנימי ביותר מצטמצמת ל-fft_length[-1] // 2 + 1 אם fft_length[-1] הוא ערך שאינו אפס, והחלק המנוגד (conjugate) ההפוך של האות המומר מעבר לתדר Nyquist מושמט.
IRFFT המרה מ-Real-to-complex ל-FFT (כלומר היא לוקחת מורכבת, מחזירה TRUE). הצורה של הציר הפנימי ביותר מורחבת ל-fft_length[-1] אם fft_length[-1] הוא ערך שאינו אפס, ומסקנת את החלק של האות המומר מעבר לתדר Nyquist מהערך הקונגרונטי ההפוך של הרשומות מ-1 ל-fft_length[-1] // 2 + 1.

FFT רב-מימדי

אם מציינים יותר מ-fft_length אחד, הפעולה הזו זהה להפעלת מפל של פעולות FFT בכל אחד מהצירים הפנימיים ביותר. שימו לב שבמקרים של המרה מ-real ל-complex ומ-complex ל-real, טרנספורמציית הציר הפנימי ביותר מתבצעת (למעשה) קודם (RFFT, אחרונה ב-IRFFT), ולכן הציר הפנימי ביותר הוא זה שמשתנה. לאחר מכן, טרנספורמציות ציר אחרות יהיו מסוג complex->complex.

פרטי ההטמעה

ה-FFT במעבד (CPU) נתמך על ידי TensorFFT של Eigen. GPU FFT משתמש ב-cuFFT.

איסוף

פעולת האיסוף של XLA מחברת כמה פרוסות (כל פרוסה יכולה להיות במרווח זמן שונה בסביבת זמן הריצה) של מערך קלט.

סמנטיקה כללית

מידע נוסף זמין במאמר XlaBuilder::Gather. תיאור אינטואיטיבי יותר זמין בקטע 'תיאור לא רשמי' שבהמשך.

gather(operand, start_indices, offset_dims, collapsed_slice_dims, slice_sizes, start_index_map)

ארגומנטים סוג סמנטיקה
operand XlaOp המערך שממנו אנחנו אוספים.
start_indices XlaOp מערך שמכיל את האינדקסים ההתחלתיים של הפרוסות שאנחנו אוספים.
index_vector_dim int64 המאפיין ב-start_indices ש'מכיל' את המדדים ההתחלתיים. תיאור מפורט מופיע בהמשך.
offset_dims ArraySlice<int64> קבוצת המאפיינים בפורמט הפלט שמשוייכים למערך שנחתך מהאופרטור.
slice_sizes ArraySlice<int64> slice_sizes[i] הוא הגבולות של הפרוסה במאפיין i.
collapsed_slice_dims ArraySlice<int64> קבוצת המאפיינים בכל פרוסה שמכווצת. המאפיינים האלה חייבים להיות בגודל 1.
start_index_map ArraySlice<int64> מפה שמתארת איך למפות אינדקסים ב-start_indices לאינדקסים חוקיים באופרטנד.
indices_are_sorted bool האם מובטח שהמדדים ימוינו על ידי מבצע הקריאה החוזרת.

לנוחיותכם, אנחנו מוסיפים תוויות למאפיינים במערך הפלט שלא נמצאים ב-offset_dims כ-batch_dims.

הפלט הוא מערך בדרגה batch_dims.size + offset_dims.size.

הערך operand.rank חייב להיות שווה לסכום של offset_dims.size ו-collapsed_slice_dims.size. בנוסף, הערך של slice_sizes.size חייב להיות שווה ל-operand.rank.

אם index_vector_dim שווה ל-start_indices.rank, אנחנו מתייחסים ל-start_indices כאל מאפיין עם מאפיין 1 בסופו (כלומר, אם start_indices היה בצורה [6,7] ו-index_vector_dim הוא 2, אנחנו מתייחסים ל-start_indices כאל [6,7,1]).

הגבולות של מערך הפלט לאורך המאפיין i יחושבו כך:

  1. אם הערך i נמצא ב-batch_dims (כלומר, הוא שווה ל-batch_dims[k] עבור k מסוים), בוחרים את גבולות המאפיין התואמים מתוך start_indices.shape, ודילוגים על index_vector_dim (כלומר, בוחרים ב-start_indices.shape.dims[k] אם k < index_vector_dim וב-start_indices.shape.dims[k+1] במקרים אחרים).

  2. אם i נמצא ב-offset_dims (כלומר שווה ל-offset_dims[k] בשביל חלק מ-k), אנחנו בוחרים את הגבול המתאים מתוך slice_sizes אחרי collapsed_slice_dims (כלומר, אנחנו בוחרים את adjusted_slice_sizes[k] כאשר adjusted_slice_sizes הוא slice_sizes לאחר הסרת הגבולות באינדקסים collapsed_slice_dims).

באופן רשמי, אינדקס המשתנה In שתואם לאינדקס פלט Out נתון מחושב באופן הבא:

  1. מגדירים את G = { Out[k] for k in batch_dims }. משתמשים ב-G כדי לחתוך את הווקטור S כך ש-S[i] = start_indices[Combine(G, i)] כאשר Combine(A, b) מוסיף את b למיקום index_vector_dim ב-A. שימו לב שזה מוגדר היטב גם אם G ריק: אם G ריק, S = start_indices.

  2. יוצרים אינדקס התחלה, Sin, ב-operand באמצעות S, על ידי פיזור S באמצעות start_index_map. באופן מדויק יותר:

    1. Sin[start_index_map[k]] = S[k] אם k < start_index_map.size.

    2. Sin[_] = 0 אחרת.

  3. יוצרים אינדקס Oin ב-operand על ידי פיזור האינדקסים במאפייני ה-offset ב-Out בהתאם לקבוצה collapsed_slice_dims. באופן מדויק יותר:

    1. Oin[remapped_offset_dims(k)] = Out[offset_dims[k]] אם k < offset_dims.size (remapped_offset_dims מוגדר בהמשך).

    2. Oin[_] = 0 אחרת.

  4. In הוא Oin + Sin, כאשר + הוא חיבור של רכיבים.

remapped_offset_dims היא פונקציה מונוטונית עם הדומיין [0, offset_dims.size) והטווח [0, operand.rank) \ collapsed_slice_dims. למשל, אם offset_dims.size הוא 4,‏ operand.rank הוא 6 ו-collapsed_slice_dims הוא {0, 2}, אז remapped_offset_dims הוא {01,‏ 13,‏ 24,‏ 35}.

אם המדיניות indices_are_sorted מוגדרת כ-True, XLA יכול להניח שהערכים start_indices ממוינים (בסדר עולה, אחרי פיזור הערכים לפי start_index_map) לפי המשתמש. אם זה לא המצב, הסמנטיקה מוגדרת בהטמעה.

תיאור לא רשמי ודוגמאות

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

  • אנחנו משתמשים במאפייני האצווה ב-Out כדי לחפש אינדקס התחלה מ-start_indices.

  • אנחנו משתמשים ב-start_index_map כדי למפות ל-operand את האינדקס ההתחלתי (שגודלו עשוי להיות קטן מ-operand.rank) לאינדקס התחלתי 'מלא'.

  • אנחנו יוצרים פרוסה דינמית בגודל slice_sizes באמצעות אינדקס ההתחלה המלא.

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

  • אנחנו משתמשים במידות ההיסט ב-Out כדי להוסיף לאינדקס את הפלח הזה כדי לקבל את רכיב הקלט, E, שתואם לאינדקס הפלט Out.

בכל הדוגמאות הבאות מגדירים את index_vector_dim כ-start_indices.rank עד 1. ערכים מעניינים יותר של index_vector_dim לא משנים את הפעולה באופן מהותי, אבל הם הופכים את הייצוג החזותי למסורבל יותר.

כדי להבין איך כל הרכיבים האלה משתלבים, נבחן דוגמה לאיסוף של 5 פרוסות בצורת [8,6] ממערך [16,11]. המיקום של פרוסה במערך [16,11] יכול להיות מיוצג בווקטור אינדקס בצורה S64[2], כך שאפשר לייצג את הקבוצה של 5 המיקומים כמערך S64[5,2].

לאחר מכן, אפשר לתאר את ההתנהגות של פעולת ה-gather כטרנספורמציה של אינדקס שמקבלת את הערכים [G,O0,O1], אינדקס בפורמט הפלט, וממפה אותו לרכיב במערך הקלט באופן הבא:

קודם אנחנו בוחרים וקטור (X,Y) ממערך האינדקסים שאוספים באמצעות G. הרכיב במערך הפלט באינדקס [G,O0,O1] הוא הרכיב במערך הקלט באינדקס [X+O0,Y+O1].

הערך של slice_sizes הוא [8,6], שמחליט על הטווח של O0 ושל O1, והם קובעים את גבולות הפרוסה.

פעולת האיסוף הזו משמשת כפרוסה דינמית באצווה עם G בתור המאפיין באצווה.

אינדקסי האיסוף יכולים להיות מרובת-ממדיים. לדוגמה, גרסה כללית יותר של הדוגמה שלמעלה, שמשתמשת במערך 'gather indices' בפורמט [4,5,2], תתרגם את המדדים כך:

שוב, הפונקציה הזו פועלת כפלח דינמי של קבוצה G0 ו-G1 כמאפייני הקבוצה. גודל הפלח הוא עדיין [8,6].

פעולת ה-gather ב-XLA מבצעת הכללה של הסמנטיקה הבלתי רשמית שמפורטת למעלה בדרכים הבאות:

  1. אנחנו יכולים להגדיר אילו מאפיינים בצורת הפלט הם מאפייני ההיסט (מאפיינים שמכילים את O0, O1 בדוגמה האחרונה). מאפייני האצווה של הפלט (מאפיינים שמכילים את הערכים G0 ו-G1 בדוגמה האחרונה) מוגדרים כמאפייני הפלט שאינם מאפייני הזזה.

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

  3. לפרוסת הנתונים שחולצה מהמערך Gather Indices‏ ((X, Y) בדוגמה האחרונה) יכולים להיות פחות רכיבים מאשר הדירוג של מערך הקלט, ומיפוי מפורש קובע איך צריך להרחיב את האינדקס כדי שיהיה לו אותו דירוג כמו הקלט.

בדוגמה האחרונה, אנחנו משתמשים ב-(2) וב-(3) כדי להטמיע את tf.gather_nd:

G0 ו-G1 משמשים לחיתוך אינדקס התחלה ממערך אינדקסי האיסוף, כמו תמיד, אלא שהאינדקס ההתחלתי מכיל רק רכיב אחד, X. באופן דומה, יש רק אינדקס אחד של היסט פלט עם הערך O0. כך כבר משתמשים כאינדקסים למערך הקלט של מערך הקלט. השדות האלה הורחבו כך קיימים כאינדקס כאינדקס למערך הקלט של מערך הקלט. הם מורחבים. כך ההוראות המורחבות כאי ההוראות שאינדקס למערך הקלט במערך הקלט. הן מפורטות בהתאם ל- [O [שניהם { Gather_מא הזו מיפוי מיפוי (start_index_map (start_index_map ב ב תיאור רשמי) ו-[[ ב-(start_index_map ב[הפי תיאור מפורט) ו- ל- [במיפוי ל- [ מתוך [ב [ מתוך [. [ מתוך ה היא תיאור ה היא [אינדקס במערך הקלט של מערך הקלט?] הם הורחבו בהתאם ל- [ O0 { מא ה- { מא ה- המטרה לremapped_offset_dimsXX00000000OOGGGG11GatherIndicestf.gather_nd

slice_sizes במקרה הזה הוא [1,11]. באופן אינטואיטיבי, פירוש הדבר הוא שכל אינדקס אינדקס X במערך האיסוף של האינדקסים בוחר שורה שלמה, והתוצאה היא שרשור כל השורות האלה.

GetDimensionSize

למידע נוסף, ראו XlaBuilder::GetDimensionSize.

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

GetDimensionSize(operand, dimension)

ארגומנטים סוג סמנטיקה
operand XlaOp מערך קלט ממדי של n
dimension int64 ערך בטווח [0, n) שקובע את המאפיין

SetDimensionSize

מידע נוסף זמין במאמר XlaBuilder::SetDimensionSize.

מגדיר את הגודל הדינמי של המאפיין הנתון של XlaOp. האופרנד חייב להיות בצורת מערך.

SetDimensionSize(operand, size, dimension)

ארגומנטים סוג סמנטיקה
operand XlaOp מערך קלט ממדי של n.
size XlaOp int32 שמייצג את הגודל הדינמי בסביבת זמן הריצה.
dimension int64 ערך בטווח [0, n) שמציין את המאפיין.

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

פעולות של הפחתת מידע ב-downstream יתעלמו מערכים מרווחים.

let v: f32[10] = f32[10]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
let five: s32 = 5;
let six: s32 = 6;

// Setting dynamic dimension size doesn't change the upper bound of the static
// shape.
let padded_v_five: f32[10] = set_dimension_size(v, five, /*dimension=*/0);
let padded_v_six: f32[10] = set_dimension_size(v, six, /*dimension=*/0);

// sum == 1 + 2 + 3 + 4 + 5
let sum:f32[] = reduce_sum(padded_v_five);
// product == 1 * 2 * 3 * 4 * 5
let product:f32[] = reduce_product(padded_v_five);

// Changing padding size will yield different result.
// sum == 1 + 2 + 3 + 4 + 5 + 6
let sum:f32[] = reduce_sum(padded_v_six);

GetTupleElement

למידע נוסף, ראו XlaBuilder::GetTupleElement.

הוספת אינדקסים לקבוצת ערכים (tuple) עם ערך קבוע בזמן הידור.

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

זה דומה ל-std::get<int N>(t) ב-C++. באופן קונספטואלי:

let v: f32[10] = f32[10]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
let s: s32 = 5;
let t: (f32[10], s32) = tuple(v, s);
let element_1: s32 = gettupleelement(t, 1);  // Inferred shape matches s32.

מידע נוסף זמין במאמר tf.tuple.

Infeed

מידע נוסף זמין במאמר XlaBuilder::Infeed.

Infeed(shape)

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

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

result1 = while (condition, init = init_value) {
  Infeed(shape)
}

result2 = while (condition, init = result1) {
  Infeed(shape)
}

אין תמיכה בצורות של צמדי ערכים (tuple) בתצוגת עץ. אם תבצעו פעולה על טופל (tuple) ריק, פעולת ה-Infeed תהיה למעשה פעולה ללא תוצאה (no-op) והיא תמשיך בלי לקרוא נתונים מה-Infeed של המכשיר.

Iota

למידע נוסף, ראו XlaBuilder::Iota.

Iota(shape, iota_dimension)

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

ארגומנטים סוג סמנטיקה
shape Shape צורת המערך שנוצרה על ידי Iota()
iota_dimension int64 המאפיין שבו רוצים להגדיל את הערך.

לדוגמה, הפקודה Iota(s32[4, 8], 0) תחזיר

  [[0, 0, 0, 0, 0, 0, 0, 0 ],
   [1, 1, 1, 1, 1, 1, 1, 1 ],
   [2, 2, 2, 2, 2, 2, 2, 2 ],
   [3, 3, 3, 3, 3, 3, 3, 3 ]]

אפשרות החזרה במחיר Iota(s32[4, 8], 1)

  [[0, 1, 2, 3, 4, 5, 6, 7 ],
   [0, 1, 2, 3, 4, 5, 6, 7 ],
   [0, 1, 2, 3, 4, 5, 6, 7 ],
   [0, 1, 2, 3, 4, 5, 6, 7 ]]

מפה

למידע נוסף, ראו XlaBuilder::Map.

Map(operands..., computation)

ארגומנטים סוג סמנטיקה
operands רצף של N XlaOps N מערכים מסוגים T0..T{N-1}
computation XlaComputation חישוב מסוג T_0, T_1, .., T_{N + M -1} -> S עם N פרמטרים מסוג T ו-M מסוג שרירותי
dimensions מערך int64 מערך של מאפייני מפה

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

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

לדוגמה: Map(op1, op2, op3, computation, par1) ממפה את elem_out <- computation(elem1, elem2, elem3, par1) בכל אינדקס (רב-מימדי) במערכי הקלט כדי ליצור את מערך הפלט.

OptimizationBarrier

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

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

משטח מונע החלקה

מידע נוסף זמין במאמר XlaBuilder::Pad.

Pad(operand, padding_value, padding_config)

ארגומנטים סוג סמנטיקה
operand XlaOp מערך מסוג T
padding_value XlaOp סקלר מסוג T כדי למלא את המילוי שנוסף
padding_config PaddingConfig כמות המרווח הפנימי בשני הקצוות (נמוך, גבוה) ובין הרכיבים של כל מאפיין

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

PaddingConfig הוא שדה חוזר של PaddingConfigDimension, שמכיל שלושה שדות לכל מאפיין: edge_padding_low, edge_padding_high ו-interior_padding.

edge_padding_low ו-edge_padding_high מציינים את כמות המילוי שנוספה בקצוות הנמוכים (לצד המדד 0) ובקצוות הגבוהים (לצד המדד הגבוה ביותר) של כל מאפיין, בהתאמה. כמות המרווח הפנימי בקצוות יכולה להיות שלילית – הערך המוחלט של המרווח הפנימי השלילי מציין את מספר הרכיבים שצריך להסיר מהמאפיין שצוין.

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

הפעולה הזו היא פעולה ללא תוצאה (no-op) אם כל זוגות המרווחים בקצוות הם (0, 0) וכל ערכי המרווחים הפנימיים הם 0. האיור הבא מציג דוגמאות לערכי edge_padding ו-interior_padding שונים עבור מערך דו-ממדי.

Recv

מידע נוסף זמין במאמר XlaBuilder::Recv.

Recv(shape, channel_handle)

ארגומנטים סוג סמנטיקה
shape Shape את הצורה של הנתונים לקבל
channel_handle ChannelHandle מזהה ייחודי לכל צמד שליחה/אישור

מקבל נתונים בפורמט הנתונים הנתון מהוראה Send במחשוב אחר שמשתמש באותו כינוי ערוץ. הפונקציה מחזירה XlaOp עבור הנתונים שהתקבלו.

ה-API של הלקוח בפעולה Recv מייצג תקשורת סנכרונית. עם זאת, ההוראה מחולקת באופן פנימי ל-2 הוראות HLO (Recv ו-RecvDone) כדי לאפשר העברות נתונים אסינכרוניות. מידע נוסף זמין במאמרים HloInstruction::CreateRecv ו-HloInstruction::CreateRecvDone.

Recv(const Shape& shape, int64 channel_id)

הקצאת המשאבים הנדרשים לקבלת נתונים מהוראה Send עם אותו channel_id. הפונקציה מחזירה הקשר של המשאבים שהוקצו, שמשמש את ההוראה הבאה של RecvDone כדי להמתין להשלמת העברת הנתונים. ההקשר הוא שלל {receive buffer (shape), requestidentifier (U32)}, ואפשר להשתמש בו רק בהוראה RecvDone.

RecvDone(HloInstruction context)

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

הקטנה

מידע נוסף זמין במאמר XlaBuilder::Reduce.

החלת פונקציית הפחתה על מערך אחד או יותר במקביל.

Reduce(operands..., init_values..., computation, dimensions)

ארגומנטים סוג סמנטיקה
operands רצף של N XlaOp N מערכים מסוגים T_0, ..., T_{N-1}.
init_values רצף של N XlaOp N סקלריים מסוגים T_0, ..., T_{N-1}.
computation XlaComputation חישוב מסוג T_0, ..., T_{N-1}, T_0, ..., T_{N-1} -> Collate(T_0, ..., T_{N-1}).
dimensions מערך int64 מערך לא מסודר של מימדים להקטנה.

כאשר:

  • הערך של N חייב להיות גדול מ-1 או שווה לו.
  • החישוב צריך להיות אסוציאטיבי "בערך" (ראו בהמשך).
  • לכל מערכי הקלט צריכים להיות אותם מאפיינים.
  • כל הערכים הראשוניים צריכים ליצור זהות ב-computation.
  • אם הערך שלו הוא N = 1, הערך של Collate(T) הוא T.
  • אם הערך שלו הוא N > 1, Collate(T_0, ..., T_{N-1}) הוא שילוב של N רכיבים מסוג T.

הפעולה הזו מפחיתה מימד אחד או יותר של כל מערך קלט למשתני סקלאר. הדירוג של כל מערך מוחזר הוא rank(operand) - len(dimensions). הפלט של הפעולה הוא Collate(Q_0, ..., Q_N), כאשר Q_i הוא מערך מסוג T_i, שהמאפיינים שלו מתוארים בהמשך.

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

דוגמאות

כשמפחיתים מימד אחד במערך חד-ממדי יחיד עם הערכים [10, 11, 12, 13], עם פונקציית ההפחתה f (ה היא computation), ניתן לחשב את הערך הזה באופן הבא:

f(10, f(11, f(12, f(init_value, 13)))

אבל יש גם עוד הרבה אפשרויות אחרות, למשל

f(init_value, f(f(10, f(init_value, 11)), f(f(init_value, 12), f(init_value, 13))))

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

result_shape <- remove all dims in dimensions from operand_shape

# Iterate over all elements in result_shape. The number of r's here is equal
# to the rank of the result
for r0 in range(result_shape[0]), r1 in range(result_shape[1]), ...:
  # Initialize this result element
  result[r0, r1...] <- 0

  # Iterate over all the reduction dimensions
  for d0 in range(dimensions[0]), d1 in range(dimensions[1]), ...:
    # Increment the result element with the value of the operand's element.
    # The index of the operand's element is constructed from all ri's and di's
    # in the right order (by construction ri's and di's together index over the
    # whole operand shape).
    result[r0, r1...] += operand[ri... di]

דוגמה לצמצום מערך דו-מימדי (מטריצה). לדוגמה, למבנה יש דרגה 2, מאפיין 0 בגודל 2 ומאפיין 1 בגודל 3:

תוצאות של צמצום מימדים 0 או 1 עם פונקציית "add":

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

דוגמה מורכבת יותר היא מערך תלת-ממדי. הדירוג שלו הוא 3, המאפיין 0 הוא בגודל 4, המאפיין 1 הוא בגודל 2 והמאפיין 2 הוא בגודל 3. כדי לפשט את הדברים, הערכים 1 עד 6 מוכפלים במאפיין 0.

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

|  4   8  12 |
| 16  20  24 |

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

| 6  15 |
| 6  15 |
| 6  15 |
| 6  15 |

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

אפשר גם לצמצם כמה מאפיינים. על ידי חיסור המאפיינים 0 ו-1 נוצר המערך הדו-ממדי [20, 28, 36].

הקטנת המערך התלת-ממדי על כל המאפיינים שלו יוצרת את הערך 84 הסקלר.

פונקציית Reduce עם מספר פרמטרים

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

  • הרצת ערך מוקטן של האופרנד הראשון
  • ...
  • הרצת ערך מוקטן של אופרנד N'
  • ערך קלט לאופרנד הראשון
  • ...
  • ערך הקלט של האופרנד ה-N

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

f: (Float, Int, Float, Int) -> Float, Int
f(max, argmax, value, index):
  if value >= max:
    return (value, index)
  else:
    return (max, argmax)

למערכי קלט מסוג 1-D V = Float[N], K = Int[N] ולערכי אתחול I_V = Float, I_K = Int, התוצאה של f_(N-1) של צמצום במאפיין הקלט היחיד מקבילה לאפליקציה הרקורסיבית הבאה:

f_0 = f(I_V, I_K, V_0, K_0)
f_1 = f(f_0.first, f_0.second, V_1, K_1)
...
f_(N-1) = f(f_(N-2).first, f_(N-2).second, V_(N-1), K_(N-1))

החלת הפחתה זו על מערך של ערכים ועל מערך של אינדקסים רציפים (כלומר iota) תבצע איטרציה משותפת על המערכים ותחזיר קבוצת ערכים (tuple) שמכילה את הערך המקסימלי ואת האינדקס התואם.

ReducePrecision

למידע נוסף, ראו XlaBuilder::ReducePrecision.

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

ReducePrecision(operand, mantissa_bits, exponent_bits)

ארגומנטים סוג סמנטיקה
operand XlaOp מערך של נקודה צפה מסוג T.
exponent_bits int32 מספר הביטים של המעריך בפורמט עם דיוק נמוך יותר
mantissa_bits int32 מספר ביטים של מנטיסה בפורמט ברמת דיוק נמוכה

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

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

ReduceScatter

למידע נוסף, ראו XlaBuilder::ReduceScatter.

ReduceScatter היא פעולה קולקטיבית שמבצעת ביעילות AllReduce, ואז מפזרת את התוצאה על ידי פיצולה ל-shard_count בלוקים לאורך scatter_dimension, והרפליקה i בקבוצת הרפליקות מקבלת את הפלח ith.

ReduceScatter(operand, computation, scatter_dim, shard_count, replica_group_ids, channel_id)

ארגומנטים סוג סמנטיקה
operand XlaOp מערך או קבוצת מערכי tupliות לא ריקה שצריך לצמצם בין הרפליקות.
computation XlaComputation חישוב ההנחה
scatter_dimension int64 מאפיין לפיזור.
shard_count int64 מספר הבלוקטים לפצל scatter_dimension
replica_groups וקטור של וקטורים של int64 הקבוצות שביניהן מתבצעות הפחתות
channel_id int64 אופציונלי מזהה ערוץ אופציונלי לתקשורת בין מודולים
  • כש-operand הוא המספר של מערכים, הפיזור של ההפחתה מתבצע על כל רכיב של הצירוף.
  • replica_groups הוא רשימה של קבוצות רפליקות שביניהן מבוצע ההפחתה (מזהה הרפליקציה של הרפליקה הנוכחית אפשר לאחזר באמצעות ReplicaId). סדר הרפליקות בכל קבוצה קובע את הסדר שבו תפוצל התוצאה של ההפחתה הכוללת. השדה replica_groups חייב להיות ריק (במקרה כזה כל הרפליקות שייכות לקבוצה אחת) או להכיל את אותו מספר רכיבים כמו מספר הרפליקות. אם יש יותר מקבוצת רפליקות אחת, כולן חייבות להיות באותו גודל. לדוגמה, replica_groups = {0, 2}, {1, 3} מבצע צמצום בין הרפליקות 0 ו-2, לבין 1 ו-3, ואז מפזר את התוצאה.
  • shard_count הוא הגודל של כל קבוצת רפליקות. אנחנו זקוקים לזה במקרים שבהם הערכים של replica_groups ריקים. אם השדה replica_groups לא ריק, הערך של shard_count חייב להיות שווה לגודל של כל קבוצת רפליקות.
  • השדה channel_id משמש לתקשורת בין מודולים: רק פעולות reduce-scatter עם אותו channel_id יכולות לתקשר זו עם זו.

צורת הפלט היא צורת הקלט, כאשר scatter_dimension קטנה פי shard_count. לדוגמה, אם יש שתי רפליקות והאופרנד הוא [1.0, 2.25] ו-[3.0, 5.25], בהתאמה, בשתי הרפליקות, ערך הפלט של הפעולה הזו, כאשר scatter_dim הוא 0, יהיה [4.0] ברפליקה הראשונה ו-[7.5] ברפליקה השנייה.

ReduceWindow

למידע נוסף, ראו XlaBuilder::ReduceWindow.

הפונקציה מחילה פונקציית הפחתה על כל הרכיבים בכל חלון של רצף של N מערכים מרובי-ממדים, ויוצרת מערך יחיד או קבוצה של N מערכים מרובי-ממדים כפלט. לכל מערך פלט יש אותו מספר רכיבים כמו מספר המיקומים החוקיים של החלון. אפשר לבטא שכבת צבירה בתור ReduceWindow. בדומה ל-Reduce, הערך של computation שהוחל תמיד מועבר ל-init_values בצד ימין.

ReduceWindow(operands..., init_values..., computation, window_dimensions, window_strides, padding)

ארגומנטים סוג סמנטיקה
operands N XlaOps רצף של N מערכים רב-ממדיים מהסוגים T_0,..., T_{N-1}, שכל אחד מהם מייצג את אזור הבסיס שעליו החלון ממוקם.
init_values N XlaOps N הערכים ההתחלתיים של הפחתה, אחד לכל אחד מ-N המשתנים. אפשר לקרוא פרטים נוספים בקטע צמצום.
computation XlaComputation פונקציית הפחתה מסוג T_0, ..., T_{N-1}, T_0, ..., T_{N-1} -> Collate(T_0, ..., T_{N-1}), שמיושמת על רכיבים בכל חלון של כל האופרנדים של הקלט.
window_dimensions ArraySlice<int64> מערך של מספרים שלמים לערכי מאפייני החלון
window_strides ArraySlice<int64> מערך מספרים שלמים לערכים של צעדים בחלון הזמן
base_dilations ArraySlice<int64> מערך מספרים שלמים לערכים של הרחבה בסיסית
window_dilations ArraySlice<int64> מערך של מספרים שלמים לערכים של הרחבת חלון
padding Padding סוג המילוי של החלון (Padding::kSame, שמוסיף מילוי כדי שהצורה של הפלט תהיה זהה לזו של הקלט אם הצעידה היא 1, או Padding::kValid, שלא משתמש במילוי ו"עוצר" את החלון ברגע שהוא כבר לא מתאים)

כאשר:

  • N צריך להיות שווה ל-1 או גדול מ-1.
  • לכל מערכי הקלט צריכים להיות אותם מאפיינים.
  • אם הערך שלו הוא N = 1, הערך של Collate(T) הוא T.
  • אם הערך שלו הוא N > 1, Collate(T_0, ..., T_{N-1}) הוא שילוב של N רכיבים מסוג (T0,...T{N-1}).

בקוד ובאיור שבהמשך מוצגת דוגמה לשימוש ב-ReduceWindow. הקלט הוא מטריקס בגודל [4x6], וגם window_dimensions וגם window_stride_dimensions הם בגודל [2x3].

// Create a computation for the reduction (maximum).
XlaComputation max;
{
  XlaBuilder builder(client_, "max");
  auto y = builder.Parameter(0, ShapeUtil::MakeShape(F32, {}), "y");
  auto x = builder.Parameter(1, ShapeUtil::MakeShape(F32, {}), "x");
  builder.Max(y, x);
  max = builder.Build().value();
}

// Create a ReduceWindow computation with the max reduction computation.
XlaBuilder builder(client_, "reduce_window_2x3");
auto shape = ShapeUtil::MakeShape(F32, {4, 6});
auto input = builder.Parameter(0, shape, "input");
builder.ReduceWindow(
    input,
    /*init_val=*/builder.ConstantLiteral(LiteralUtil::MinValue(F32)),
    *max,
    /*window_dimensions=*/{2, 3},
    /*window_stride_dimensions=*/{2, 3},
    Padding::kValid);

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

בדוגמה של מרווח פנימי לא טריווי, אפשר להשתמש במחשוב למינימום חלונות (הערך הראשוני הוא MAX_FLOAT) עם המאפיין 3 ולצעוד 2 מעל מערך הקלט [10000, 1000, 100, 10, 1]. הפונקציה kValid מחשבת מינימומים בשני חלונות תקפים: [10000, 1000, 100] ו-[100, 10, 1], וכתוצאה מכך מתקבל הפלט [100, 1]. הפונקציה kSame מוסיפה תחילה לאלמנטים של המערך כדי שהצורה אחרי reduce-window תהיה זהה לכניסה של צעד אחד, על ידי הוספת רכיבים ראשוניים משני הצדדים, ומקבלת את [MAX_VALUE, 10000, 1000, 100, 10, 1, MAX_VALUE]. הפעלת reduce-window על המערך המרופד פועלת על שלושה חלונות: [MAX_VALUE, 10000, 1000],‏ [1000, 100, 10] ו-[10, 1, MAX_VALUE], ומניבה את הערך [1000, 10, 1].

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

ReplicaId

למידע נוסף, ראו XlaBuilder::ReplicaId.

מחזירה את המזהה הייחודי (סקלר U32) של הרפליקה.

ReplicaId()

המזהה הייחודי של כל עותק הוא מספר שלם ללא סימן במרווח [0, N), כאשר N הוא מספר העותקים. מאחר שכל הרפליקות מריצות את אותה תוכנית, קריאה ל-ReplicaId() בתוכנית תחזיר ערך שונה בכל רפליקה.

שינוי העיצוב

אפשר לעיין גם במאמר XlaBuilder::Reshape ובפעולה Collapse.

שינוי הצורה של המאפיינים של מערך להגדרה חדשה.

Reshape(operand, new_sizes) Reshape(operand, dimensions, new_sizes)

ארגומנטים סוג סמנטיקה
operand XlaOp מערך מסוג T
dimensions וקטור int64 הסדר שבו המאפיינים מקופלים
new_sizes וקטור int64 הווקטור של מימדים חדשים

באופן קונספטואלי, הפונקציה reshape קודם משטחת מערך וקובעת לו וקטור דו-מימדי של ערכים של נתונים, ולאחר מכן משייפת את הווקטור הזה לצורה חדשה. ארגומנטים של קלט הם מערך שרירותי מסוג T, וקטור קבוע-זמן הידור של אינדקסי מאפיינים וכן וקטור קבוע-זמן הידור של גודלי מימדים לתוצאה. אם מציינים ערכים בעורך dimension, הם חייבים להיות תמורה של כל המאפיינים של T. ערך ברירת המחדל אם לא מציינים ערכים הוא {0, ..., rank - 1}. הסדר של המאפיינים ב-dimensions הוא מהמאפיין שמשתנה לאט ביותר (החשוב ביותר) למאפיין שמשתנה במהירות הרבה ביותר (החשוב פחות) בתוך ערימת הלולאות שמצמצמת את מערך הקלט למאפיין יחיד. הווקטור new_sizes קובע את הגודל של מערך הפלט. הערך באינדקס 0 ב-new_sizes הוא הגודל של המאפיין 0, הערך באינדקס 1 הוא הגודל של המאפיין 1 וכן הלאה. המכפלה של המאפיינים של new_size חייבת להיות שווה למכפלה של גדלי המאפיינים של המשתנה. כשמפיחים את המערך המכווץ למערך רב-מימדי שמוגדר על ידי new_sizes, המאפיינים ב-new_sizes ממוינים מהשינויים האיטיים ביותר (העיקריים ביותר) ועד לשינויים המהירים ביותר (המשניים ביותר).

לדוגמה, נניח ש-v הוא מערך של 24 רכיבים:

let v = f32[4x2x3] { { {10, 11, 12}, {15, 16, 17} },
                    { {20, 21, 22}, {25, 26, 27} },
                    { {30, 31, 32}, {35, 36, 37} },
                    { {40, 41, 42}, {45, 46, 47} } };

In-order collapse:
let v012_24 = Reshape(v, {0,1,2}, {24});
then v012_24 == f32[24] {10, 11, 12, 15, 16, 17, 20, 21, 22, 25, 26, 27,
                         30, 31, 32, 35, 36, 37, 40, 41, 42, 45, 46, 47};

let v012_83 = Reshape(v, {0,1,2}, {8,3});
then v012_83 == f32[8x3] { {10, 11, 12}, {15, 16, 17},
                          {20, 21, 22}, {25, 26, 27},
                          {30, 31, 32}, {35, 36, 37},
                          {40, 41, 42}, {45, 46, 47} };

Out-of-order collapse:
let v021_24 = Reshape(v, {1,2,0}, {24});
then v012_24 == f32[24]  {10, 20, 30, 40, 11, 21, 31, 41, 12, 22, 32, 42,
                          15, 25, 35, 45, 16, 26, 36, 46, 17, 27, 37, 47};

let v021_83 = Reshape(v, {1,2,0}, {8,3});
then v021_83 == f32[8x3] { {10, 20, 30}, {40, 11, 21},
                          {31, 41, 12}, {22, 32, 42},
                          {15, 25, 35}, {45, 16, 26},
                          {36, 46, 17}, {27, 37, 47} };


let v021_262 = Reshape(v, {1,2,0}, {2,6,2});
then v021_262 == f32[2x6x2] { { {10, 20}, {30, 40},
                              {11, 21}, {31, 41},
                              {12, 22}, {32, 42} },
                             { {15, 25}, {35, 45},
                              {16, 26}, {36, 46},
                              {17, 27}, {37, 47} } };

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

Reshape(f32[1x1] { {5} }, {0,1}, {}) == 5;
Reshape(5, {}, {1,1}) == f32[1x1] { {5} };

Rev (הפוך)

למידע נוסף, ראו XlaBuilder::Rev.

Rev(operand, dimensions)

ארגומנטים סוג סמנטיקה
operand XlaOp מערך מסוג T
dimensions ArraySlice<int64> המאפיינים שרוצים להפוך

הפונקציה הופכת את הסדר של הרכיבים במערך operand לפי הערך שצוין ב-dimensions, ויוצרת מערך פלט באותו צורה. כל רכיב במערך האופרנד באינדקס רב-מימדי מאוחסן במערך הפלט באינדקס שהומר. כדי לבצע את הטרנספורמציה של המדד המימדי, הופכים את המדד בכל מאפיין שרוצים להפוך (כלומר, אם מאפיין בגודל N הוא אחד מהמאפיינים שרוצים להפוך, המדד שלו i הופך ל-N - 1 - i).

שימוש אחד בפעולה Rev הוא להפוך את מערך משקל הקונבולוציה לאורך שני מאפייני החלונות במהלך חישוב ההדרגתי ברשתות נוירונים.

RngNormal

למידע נוסף, ראו XlaBuilder::RngNormal.

יצירת פלט בצורה נתונה באמצעות מספרים אקראיים שנוצרו בהתאם להתפלגות הנורמלית \(N(\mu, \sigma)\) . לפרמטרים \(\mu\) ו- \(\sigma\)ולצורה של הפלט צריכים להיות סוג אלמנט של נקודה צפה (floating-point). בנוסף, הערכים של הפרמטרים צריכים להיות סקלריים.

RngNormal(mu, sigma, shape)

ארגומנטים סוג סמנטיקה
mu XlaOp סקלר מסוג T שקובע את הממוצע של המספרים שנוצרו
sigma XlaOp סקלר מסוג T שקובע את סטיית התקן של ה-generated
shape Shape צורת הפלט מסוג T

RngUniform

מידע נוסף זמין במאמר XlaBuilder::RngUniform.

הפונקציה בונה פלט של צורה נתונה עם מספרים אקראיים שנוצרים בעקבות ההתפלגות האחידה על פני הרווח \([a,b)\). הסוגים של הפרמטרים ורכיבי הפלט צריכים להיות בוליאניים, שלמים או של נקודות צפות, והם צריכים להיות עקביים. בשלב הזה, הקצוות העורפיים של המעבד (CPU) וה-GPU תומכים רק ב-F64, ב-F32, ב-F16, ב-BF16, ב-S64, ב-U64, ב-S32 וב-U32. בנוסף, הערכים של הפרמטרים צריכים להיות סקלריים. אם \(b <= a\) התוצאה מוגדרת על ידי ההטמעה.

RngUniform(a, b, shape)

ארגומנטים סוג סמנטיקה
a XlaOp סקלר מסוג T שקובע את הגבול התחתון של מרווח
b XlaOp סקלר מסוג T שקובע את הגבול העליון של מרווח
shape Shape צורת פלט מסוג T

RngBitGenerator

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

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

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

RngBitGenerator(algorithm, key, shape)

ארגומנטים סוג סמנטיקה
algorithm RandomAlgorithm אלגוריתם ה-PRNG שבו יש להשתמש.
initial_state XlaOp המצב הראשוני של אלגוריתם ה-PRNG.
shape Shape צורת הפלט של הנתונים שנוצרו.

הערכים הזמינים עבור algorithm:

פיזור

פעולת הפיזור של XLA יוצרת רצף של תוצאות שהן הערכים של מערך הקלט operands, עם כמה פרוסות (באינדקסים שצוינו על ידי scatter_indices) שמתעדכנות ברצף הערכים ב-updates באמצעות update_computation.

מידע נוסף זמין במאמר XlaBuilder::Scatter.

scatter(operands..., scatter_indices, updates..., update_computation, index_vector_dim, update_window_dims, inserted_window_dims, scatter_dims_to_operand_dims)

ארגומנטים סוג סמנטיקה
operands רצף של N XlaOp N מערכי מסוגים T_0, ..., T_N שלפיהם יתבצע פיזור.
scatter_indices XlaOp המערך שמכיל את האינדקסים ההתחלתיים של הפרוסות שצריך לפזר אליהן.
updates רצף של N XlaOp N מערכים מסוגים T_0, ..., T_N. updates[i] מכיל את הערכים שצריך להשתמש בהם כדי לבצע פיזור operands[i].
update_computation XlaComputation החישוב שישמש לשילוב הערכים הקיימים במערך הקלט והעדכונים במהלך הפיצול. החישוב הזה צריך להיות מסוג T_0, ..., T_N, T_0, ..., T_N -> Collate(T_0, ..., T_N).
index_vector_dim int64 המאפיין ב-scatter_indices שמכיל את האינדקסים ההתחלתיים.
update_window_dims ArraySlice<int64> קבוצת המאפיינים בצורה updates שהם מאפייני חלון.
inserted_window_dims ArraySlice<int64> קבוצת מאפייני החלון שיש להוסיף לצורה updates.
scatter_dims_to_operand_dims ArraySlice<int64> מפת מאפיינים מהאינדקסים של הפיזור למרחב של אינדקס המשתנים. המערך הזה מפורש כמיפוי של i אל scatter_dims_to_operand_dims[i]. הוא צריך להיות אחד לאחד ושלם.
indices_are_sorted bool האם יש ערובה שהאינדקסים ימוינו על ידי מבצע הקריאה החוזרת.
unique_indices bool האם המפנה מבטיח שהאינדקסים יהיו ייחודיים.

כאשר:

  • N צריך להיות שווה ל-1 או גדול מ-1.
  • operands[0], …, operands[N-1] חייבים להיות בעלי אותם מאפיינים.
  • המאפיינים updates[0], ..., updates[N-1] צריכים להיות זהים.
  • אם הערך שלו הוא N = 1, הערך של Collate(T) הוא T.
  • אם הערך שלו הוא N > 1, Collate(T_0, ..., T_N) הוא צירוף של N רכיבים מסוג T.

אם הערך של index_vector_dim שווה ל-scatter_indices.rank, אנחנו מתייחסים ל-scatter_indices כאל מאפיין 1 עם תו אחריו.

אנחנו מגדירים את update_scatter_dims מסוג ArraySlice<int64> כקבוצת המאפיינים בצורה updates שלא נמצאת ב-update_window_dims, בסדר עולה.

הארגומנטים של scatter צריכים לעמוד באילוצים הבאים:

  • כל מערך updates חייב להיות בעל דרגה update_window_dims.size + scatter_indices.rank - 1.

  • גבולות המאפיין i בכל מערך updates חייבים להתאים לתנאים הבאים:

    • אם i נמצא בפונקציה update_window_dims (כלומר שווה ל-update_window_dims[k] בשביל חלק מהשדות k), הגבול של המאפיין i ב-updates לא יחרוג מהגבול התואם של operand אחרי חישוב הערך inserted_window_dims (כלומר adjusted_window_bounds[k], כאשר adjusted_window_bounds מכיל את הגבולות של operand עם גבולות באינדקסים inserted_window_dims).
    • אם הערך i נמצא ב-update_scatter_dims (כלומר, הוא שווה ל-update_scatter_dims[k] עבור ערך כלשהו של k), אז הגבול של המאפיין i ב-updates חייב להיות שווה לגבול התואם של scatter_indices, תוך דילוג על index_vector_dim (כלומר, scatter_indices.shape.dims[k], אם k < index_vector_dim, ו-scatter_indices.shape.dims[k+1] במקרים אחרים).
  • update_window_dims חייב להיות בסדר עולה, ללא מספרי מאפיינים חוזרים ולהיות בטווח [0, updates.rank).

  • inserted_window_dims חייב להיות בסדר עולה, בלי מספרי מאפיינים חוזרים, ובטווח [0, operand.rank).

  • operand.rank חייב להיות שווה לסכום של update_window_dims.size ו-inserted_window_dims.size.

  • scatter_dims_to_operand_dims.size חייב להיות שווה ל-scatter_indices.shape.dims[index_vector_dim] והערכים שלו חייבים להיות בטווח [0, operand.rank).

לכל אינדקס נתון U בכל מערך updates, האינדקס המתאים I במערך operands המתאים שעליו צריך להחיל את העדכון הזה:

  1. מגדירים את G = { U[k] for k in update_scatter_dims }. משתמשים ב-G כדי לחפש וקטור אינדקס S במערך scatter_indices כך ש-S[i] = scatter_indices[Combine(G, i)] כאשר Combine(A, b) מוסיף את b למיקומים index_vector_dim ב-A.
  2. יוצרים אינדקס Sin ב-operand באמצעות S, על ידי פיזור של S באמצעות המפה scatter_dims_to_operand_dims. באופן רשמי יותר:
    1. Sin[scatter_dims_to_operand_dims[k]] = S[k] אם k < scatter_dims_to_operand_dims.size.
    2. Sin[_] = 0 אחרת.
  3. יוצרים אינדקס Win לכל מערך operands על ידי פיזור המדדים ב-update_window_dims ב-U לפי inserted_window_dims. באופן רשמי יותר:
    1. Win[window_dims_to_operand_dims(k)] = U[k] אם k הוא ב-update_window_dims, כאשר window_dims_to_operand_dims היא הפונקציה המונוטונית עם הדומיין [0, update_window_dims.size) והטווח [0, operand.rank) \ inserted_window_dims. (לדוגמה, אם update_window_dims.size הוא 4, operand.rank הוא 6 ו-inserted_window_dims הוא {0, 2}, אז window_dims_to_operand_dims הוא {01, 13, 24, 35}).
    2. Win[_] = 0 אחרת.
  4. I הוא Win + Sin, כאשר + הוא חיבור של רכיבים.

לסיכום, אפשר להגדיר את פעולת הפזורה באופן הבא.

  • מאתחלים את output עם operands, כלומר לכל האינדקסים J, לכל האינדקסים O במערך operands[J]:
    output[J][O] = operands[J][O]
  • לכל אינדקס U במערך updates[J] ולאינדקס התואם O במערך operand[J], אם O הוא אינדקס חוקי עבור output:
    (output[0][O], ..., output[N-1][O]) =update_computation(output[0][O], ..., ,output[N-1][O],updates[0][U], ...,updates[N-1][U])

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

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

אם הערך של indices_are_sorted מוגדר כ-True, המערכת של XLA יכולה להניח שהמשתמש ממיין את scatter_indices (במספר עולה, אחרי פיזור הערכים שלו לפי scatter_dims_to_operand_dims). אם זה לא המצב, הסמנטיקה מוגדרת כהטמעה.

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

באופן לא מובן, אפשר לראות את אופציית הפיזור כהופכי של פעולת האיסוף, כלומר

לתיאור מפורט ולדוגמאות לא רשמיות, עיינו בקטע 'תיאור בלתי רשמי' ב-Gather.

בחירה

מידע נוסף זמין במאמר XlaBuilder::Select.

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

Select(pred, on_true, on_false)

ארגומנטים סוג סמנטיקה
pred XlaOp מערך מסוג PRED
on_true XlaOp מערך מסוג T
on_false XlaOp מערך מסוג T

המערך on_true והמערך on_false חייבים להיות באותו צורה. זהו גם הצורה של מערך הפלט. למערך pred צריכה להיות אותה מימדיות כמו של on_true ו-on_false, עם סוג הרכיב PRED.

לכל רכיב P של pred, הרכיב התואם של מערך הפלט נלקח מ-on_true אם הערך של P הוא true, ומ-on_false אם הערך של P הוא false. כצורה מוגבלת של שידור, הערך של pred יכול להיות סקלאר מסוג PRED. במקרה כזה, מערך הפלט נלקח כולו מ-on_true אם הערך של pred הוא true, ומ-on_false אם הערך של pred הוא false.

דוגמה עם pred שאינו סקלר:

let pred: PRED[4] = {true, false, false, true};
let v1: s32[4] = {1, 2, 3, 4};
let v2: s32[4] = {100, 200, 300, 400};
==>
Select(pred, v1, v2) = s32[4]{1, 200, 300, 4};

דוגמה עם סקלר pred:

let pred: PRED = true;
let v1: s32[4] = {1, 2, 3, 4};
let v2: s32[4] = {100, 200, 300, 400};
==>
Select(pred, v1, v2) = s32[4]{1, 2, 3, 4};

יש תמיכה בבחירות בין צמדי מידע. למטרה הזו, צמדי מפתחות נחשבים לסוגי סקלר. אם on_true ו-on_false הן קבוצות (שצריכות להיות באותו צורה), אז pred צריכה להיות סקלר מסוג PRED.

SelectAndScatter

למידע נוסף, ראו XlaBuilder::SelectAndScatter.

אפשר להתייחס לפעולה הזו כפעולה מורכבת שמחשבת קודם את ReduceWindow במערך operand כדי לבחור רכיב מכל חלון, ואז מפזרת את מערך source למערכי האינדקסים של הרכיבים שנבחרו כדי ליצור מערך פלט באותו צורה כמו מערך המשתנה. הפונקציה select הבינארית משמשת לבחירת רכיב מכל חלון על ידי החלה שלו על כל חלון, ונקראת באמצעות המאפיין שווקטור האינדקס של הפרמטר הראשון קטן מבחינה לקסיקוגרפית מהווקטור האינדקס של הפרמטר השני. הפונקציה select מחזירה את הערך true אם הפרמטר הראשון נבחר, ומחזירה את הערך false אם הפרמטר השני נבחר. הפונקציה חייבת להיות טרנזיטיבית (כלומר, אם select(a, b) ו-select(b, c) הם true, אז select(a, c) הוא גם true) כדי שהאלמנט שנבחר לא יהיה תלוי בסדר האלמנטים שעברתם בחלון נתון.

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

  1. הערך הנוכחי במדד שנבחר במערך הפלט
  2. ערך הפיזור מ-source שחלה על האינדקס שנבחר

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

מערך הפלט הוא באותו צורה כמו מערך operand, וערך המערך source חייב להיות באותו צורה כמו התוצאה של החלת הפעולה ReduceWindow על מערך operand. אפשר להשתמש ב-SelectAndScatter כדי להעביר חזרה (backpropagate) את ערכי המדרון של שכבת אגירה ברשת עצבית.

SelectAndScatter(operand, select, window_dimensions, window_strides, padding, source, init_value, scatter)

ארגומנטים סוג סמנטיקה
operand XlaOp מערך מסוג T שעליו החלונות מחליקים
select XlaComputation חישוב בינארי מסוג T, T -> PRED, שיחול על כל הרכיבים בכל חלון. הפונקציה מחזירה את הערך true אם נבחר הפרמטר הראשון, ומחזירה את הערך false אם נבחר הפרמטר השני
window_dimensions ArraySlice<int64> מערך של מספרים שלמים לערכי מאפייני החלון
window_strides ArraySlice<int64> מערך מספרים שלמים לערכים של צעדים בחלון הזמן
padding Padding סוג המרווח הפנימי לחלון (ריפוד::kSame או מרווח פנימי::kValid)
source XlaOp מערך מסוג T עם הערכים לפיזור
init_value XlaOp ערך סקלרי מסוג T עבור הערך הראשוני של מערך הפלט
scatter XlaComputation חישוב בינארי מסוג T, T -> T, כדי להחיל כל רכיב מקור של פיזור על רכיב היעד שלו

האיור הבא מציג דוגמאות לשימוש ב-SelectAndScatter, כשהפונקציה select מחשבת את הערך המקסימלי בין הפרמטרים שלה. שימו לב שכאשר יש חפיפה בין החלונות, כמו באיור (2) שבהמשך, אינדקס של המערך operand עשוי להיבחר מספר פעמים על ידי חלונות שונים. בתרשים, האלמנט עם הערך 9 נבחר על ידי שני החלונות העליונים (כחול ואדום), ופונקציית החיבור הבינארי scatter יוצרת את אלמנט הפלט עם הערך 8 (2 + 6).

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

שליחה

מידע נוסף זמין במאמר XlaBuilder::Send.

Send(operand, channel_handle)

ארגומנטים סוג סמנטיקה
operand XlaOp הנתונים לשליחה (מערך מסוג T)
channel_handle ChannelHandle מזהה ייחודי לכל צמד שליחה/אישור

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

בדומה לפעולה Recv, ה-API של הלקוח ב-Send מייצג תקשורת סנכרונית, והוא מפורק באופן פנימי לשתי הוראות HLO (Send ו-SendDone) כדי לאפשר העברות אסינכרוניות של נתונים. מידע נוסף זמין במאמרים HloInstruction::CreateSend ו-HloInstruction::CreateSendDone.

Send(HloInstruction operand, int64 channel_id)

הפקודה מפעילה העברה אסינכררונית של המשתנה למשאבים שהוקצו על ידי ההוראה Recv עם אותו מזהה ערוץ. הפונקציה מחזירה הקשר, שמשמש את ההוראה הבאה מסוג SendDone כדי להמתין להשלמת העברת הנתונים. ההקשר הוא צירוף של {operand (shape), request id (U32)}, וניתן להשתמש בו רק בהוראה SendDone.

SendDone(HloInstruction context)

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

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

סדר הביצוע של 4 ההוראות לכל ערוץ (Recv, RecvDone, Send, SendDone) הוא כפי שמפורט בהמשך.

  • Recv מתרחש לפני Send
  • Send מתרחש לפני RecvDone
  • Recv מתרחש לפני RecvDone
  • Send מתרחש לפני SendDone

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

תבנית של תוכן דינמי

למידע נוסף, ראו XlaBuilder::Slice.

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

Slice(operand, start_indices, limit_indices, strides)

ארגומנטים סוג סמנטיקה
operand XlaOp מערך N-מימדי מסוג T
start_indices ArraySlice<int64> רשימה של N מספרים שלמים שמכילה את אינדקסי ההתחלה של הפלחים בכל מאפיין. הערכים חייבים להיות גדולים מ-0 או שווים לו.
limit_indices ArraySlice<int64> רשימה של N מספרים שלמים שמכילה את אינדקסי הסיום (לא כולל) של הפלחים לכל מאפיין. כל ערך צריך להיות שווה לערך start_indices המתאים של המאפיין או גדול ממנו, וקטן מגודל המאפיין או שווה לו.
strides ArraySlice<int64> רשימה של N מספרים שלמים שמחליטים על צעד הקלט של הפלחים. הפלח בוחר כל רכיב strides[d] במאפיין d.

דוגמה במאפיין אחד:

let a = {0.0, 1.0, 2.0, 3.0, 4.0}
Slice(a, {2}, {4}) produces:
  {2.0, 3.0}

דוגמה דו-ממדית:

let b =
 { {0.0,  1.0,  2.0},
   {3.0,  4.0,  5.0},
   {6.0,  7.0,  8.0},
   {9.0, 10.0, 11.0} }

Slice(b, {2, 1}, {4, 3}) produces:
  { { 7.0,  8.0},
    {10.0, 11.0} }

מיון

מידע נוסף זמין במאמר XlaBuilder::Sort.

Sort(operands, comparator, dimension, is_stable)

ארגומנטים סוג סמנטיקה
operands ArraySlice<XlaOp> האופרנדים למיון.
comparator XlaComputation החישוב של המשווא להשוואה שבו צריך להשתמש.
dimension int64 המאפיין שלפיהם יתבצע המיון.
is_stable bool האם כדאי להשתמש במיון יציב.

אם צוין רק אופרטנד אחד:

  • אם המשתנה המבצע הוא טינסור מסדר 1 (מערך), התוצאה היא מערך ממוין. אם רוצים למיין את המערך בסדר עולה, כלי ההשוואה צריך לבצע השוואה של 'פחות מ-'. באופן רשמי, אחרי שהמערך ממוין, הוא שומר את כל מיקומי האינדקס i, j עם i < j של comparator(value[i], value[j]) = comparator(value[j], value[i]) = false או comparator(value[i], value[j]) = true.

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

אם מציינים אופרטורים של n > 1:

  • כל האופרנדים מסוג n חייבים להיות טנזורים עם אותם מימדים. סוגי הרכיבים של הטנסורים עשויים להיות שונים.

  • כל המשתנים המבצעיים ממוינים יחד, ולא בנפרד. באופן עקרוני, לאופרנדים מתייחסים כאל צינור. כשבודקים אם צריך להחליף את הרכיבים של כל אופרנד במיקומי האינדקס i ו-j, מתבצעת קריאה למבצע ההשוואה עם 2 * n פרמטרים סקלריים, כאשר הפרמטר 2 * k תואם לערך במיקום i מהאופרטור k-th, והפרמטר 2 * k + 1 תואם לערך במיקום j מהאופרטור k-th. בדרך כלל, כלי ההשוואה ישווה את הפרמטרים 2 * k ו-2 * k + 1 זה לזה, ואולי ישתמש בצמדי פרמטרים אחרים בתור מפרי שוויון.

  • התוצאה היא קבוצת ערכים (tuple) שמכילה את אופרטנדים בסדר ממוין (לפי המאפיין שצוין, כפי שמתואר למעלה). המשתנה i-th של הטופל תואם למשתנה i-th של Sort.

לדוגמה, אם יש שלושה אופרטנדים operand0 = [3, 1],‏ operand1 = [42, 50] ו-operand2 = [-3.0, 1.1], והמתבצע משווה רק את הערכים של operand0 עם פחות מ-, הפלט של המיון הוא הטופל ([1, 3], [50, 42], [1.1, -3.0]).

אם הערך של is_stable מוגדר כ-true, אפשר להבטיח שהמיון יהיה יציב. כלומר, אם יש אלמנטים שנחשבים זהים על ידי המבצע, הסדר היחסי של הערכים הזהים נשמר. שני אלמנטים e1 ו-e2 שווים רק אם comparator(e1, e2) = comparator(e2, e1) = false. כברירת מחדל, הערך של is_stable מוגדר כ-false.

טרנספוזיציה

אפשר לעיין גם בפעולה tf.reshape.

Transpose(operand)

ארגומנטים סוג סמנטיקה
operand XlaOp המשתנה שרוצים לבצע לו טרנספוזיציה.
permutation ArraySlice<int64> איך להשתיק את המאפיינים.

הפונקציה מבצעת תמורה של המאפיינים של המשתנה לפי התמורה שצוינה, כך ש-∀ i . 0 ≤ i < rank ⇒ input_dimensions[permutation[i]] = output_dimensions[i].

הפונקציה הזו זהה לפונקציה Reshape(operand, permutation, Permute(permutation, operand.shape.dimensions)).

TriangularSolve

למידע נוסף, ראו XlaBuilder::TriangularSolve.

פתרון מערכות של משוואות ליניאריות עם מטריצות של ערכים טריגונומטרים עליונים או תחתונים באמצעות החלפה קדימה או אחורה. באמצעות שידור (broadcasting) לפי המאפיינים המובילים, התכנית הזו פותרת אחת ממערכות המטריצות op(a) * x = b או x * op(a) = b עבור המשתנה x, בהתאם ל-a ו-b, כאשר op(a) הוא op(a) = a, או op(a) = Transpose(a), או op(a) = Conj(Transpose(a)).

TriangularSolve(a, b, left_side, lower, unit_diagonal, transpose_a)

ארגומנטים סוג סמנטיקה
a XlaOp מערך דירוג > 2 מסוג מרוכב או מסוג נקודה צפה (floating-point) עם הצורה [..., M, M].
b XlaOp מערך דירוג > 2 מאותו סוג עם הצורה [..., M, K] אם left_side נכון, [..., K, M] אחרת.
left_side bool מציין אם לפתור מערכת בצורה op(a) * x = b (true) או x * op(a) = b (false).
lower bool האם להשתמש במשולש העליון או התחתון של a.
unit_diagonal bool אם true, ההנחה היא שהרכיבים האלכסוןים של a הם 1 ואין גישה אליהם.
transpose_a Transpose אם להשתמש ב-a כפי שהוא, לבצע בו טרנספוזיציה או לבצע טרנספוזיציה של הקונגרואנט שלו.

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

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

Tuple

מידע נוסף זמין במאמר XlaBuilder::Tuple.

קבוצת ערכים (tuple) שמכילה מספר משתנה של מזהים של נתונים, לכל אחד מהם יש צורה משלו.

הדבר מקביל ל-std::tuple ב-C++. מבחינה רעיונית:

let v: f32[10] = f32[10]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
let s: s32 = 5;
let t: (f32[10], s32) = tuple(v, s);

אפשר לפרק צמדי-ערכי-מפתח (ולגשת אליהם) באמצעות הפעולה GetTupleElement.

אף שהפונקציה

מידע נוסף זמין במאמר XlaBuilder::While.

While(condition, body, init)

ארגומנטים סוג סמנטיקה
condition XlaComputation XlaComputation מסוג T -> PRED שמגדיר את תנאי הסיום של הלוופ.
body XlaComputation XlaComputation מסוג T -> T שמגדיר את גוף הלולאה.
init T הערך הראשוני של הפרמטר של condition ו-body.

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

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

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

אחד התרחיש לדוגמה העיקרי של הצומת While הוא להטמיע ביצוע חוזר של אימון ברשתות נוירונים. בהמשך מוצג קוד מדומה פשוט עם תרשים שמייצג את החישוב. הקוד מופיע ב-while_test.cc. הסוג T בדוגמה הזו הוא Tuple שמורכב מ-int32 למספר החזרות ומ-vector[10] למצטבר. במשך 1,000 חזרות, הלולאה ממשיכה להוסיף וקטור קבוע למצטבר.

// Pseudocode for the computation.
init = {0, zero_vector[10]} // Tuple of int32 and float[10].
result = init;
while (result(0) < 1000) {
  iteration = result(0) + 1;
  new_vector = result(1) + constant_vector[10];
  result = {iteration, new_vector};
}