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

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

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

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 מערך או צמד לא ריק של מערכים, כדי לצמצם בין רפליקות
computation XlaComputation חישוב ההפחתה
replica_groups של הווקטורים של int64 קבוצות שביניהן מתבצעות ההפחתה
channel_id int64 (אופציונלי) מזהה ערוץ אופציונלי לתקשורת בין מודולים
  • כשה-operand הוא צמד של מערכים, פעולת הצמצום מתבצעת בכל רכיב ב-tuple.
  • 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] בשני הרפליקות. אם הקלט הוא קפל, גם הפלט יהיה גמיש.

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

AllToAll

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

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

  1. שלב הפיזור. בכל ליבה, אופרנד מחולק למספר split_count של בלוקים לאורך split_dimensions, והבלוקים מפוזרים לכל הליבות, למשל הבלוק ה-ith נשלח לליבה של ה-ith.
  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. בכל ליבה, האופרנד מחולק לארבעה חלקים לאורך מימד 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 מייצגים ערכי רגעים במאפיינים של אצווה ומרחבי.

סוג הפלט מורכב מ-tuple של שלוש נקודות אחיזה:

פלט סוג סמנטיקה
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 רכיבים עם w ו-h כגודל של מימדים מרחביים (בהנחה ש-operand הוא מערך 4 ממדי):

  • מחשבת את ממוצע האצווה \(\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, היא מבצעת פעולת ביטcast ברמת הרכיב מצורת נתונים לצורת יעד. גודל הקלט והפלט צריך להתאים: למשל, רכיבי s32 הופכים לאלמנטים f32 דרך תרחיש ביטcast, ואלמנט s32 אחד יהפוך לארבעה אלמנטים של s8. Bitcast מיושם כהעברה (cast) ברמה נמוכה, כך שמכונות עם ייצוגים שונים של נקודה צפה (floating-point) יניבו תוצאות שונות.

BitcastConvertType(operand, new_element_type)

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

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

אסור שיהיו אלמנטים של מקור ויעד.

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

הוראת HLO של BitcastConvert תומכת במקרים שבהם גודל סוג רכיב הפלט T' לא שווה לגודל של רכיב הקלט T. מאחר שהפעולה כולה היא בעצם ביטcast ולא משנה את הבייטים שבבסיס שלה, הצורה של רכיב הפלט צריכה להשתנות. לגבי 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 XlaOp שנ' N ארגומנטים מסוג שרירותי

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

צ'ולסקי

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

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

Cholesky(a, lower)

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

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

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

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

אם הערך של 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:

  • לכל שני זוגות לא יכול להיות אותו מזהה רפליקה של יעד, ואסור להם להיות אותו מזהה של עותק מקור.
  • אם מזהה של רפליקה הוא לא יעד באף צמד, אז הפלט ברפליקציה הזו הוא tensor שמורכב מ-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 XlaComputations מסוג \(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.

המרה (קונבולוציה)

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

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

ConvWithGeneralPadding (קובולוציה)

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

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

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

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

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

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

  • output-z: המימד z של הפלט.
  • input-z: גודל המאפיין הזה כפול feature_group_count צריך להיות זהה לגודל של המאפיין z ביחידות h.
  • 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 מוצבים באופן מרומז בין כל אחד מהערכים של המאפיין הזה, וכך מגדילים את המערך. החורים ממולאים בערך ללא תפעול, כלומר אפסים.

הרחבות של rhs נקראת גם 'קונבולוציה מטורגטת'. למידע נוסף ראו tf.nn.atrous_conv2d. הרחבה של לולאות נקראת גם 'קונוולוציה טרנספוזיציה'. פרטים נוספים זמינים במאמר 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-th משמשות יחד כדי לחשב את feature_group_count לשילובים נפרדים רבים. התוצאות של ההתפתחויות האלה משורשרות יחד במאפיין תכונת הפלט.

כדי לבצע קונבולציה של עומק, הארגומנט 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, המשמעות היא שמאפיין קבוצת הפלט צריך להיות בגודל input batch / batch_group_count. הערך batch_group_count חייב להיות מחלק בגודל תכונת הפלט.

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

  • batch: גודל המאפיין הזה כפול batch_group_count צריך להיות שווה לגודל של המאפיין batch ביחידות h.
  • 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 קומבוציות נפרדות עם מסנן שונה לכל אחת מהן.

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

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

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

המרה כמו 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);

לדוגמה, אם משתמשים ב-CustomCall באופן הבא:

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];
  // ...
}

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

נקודה

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

Dot(lhs, rhs)

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

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

קלט פלט סמנטיקה
וקטור [n] dot וקטור [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 int64 חוזר מספרי מאפיינים חוזיים של lhs
rhs_contracting_dimensions int64 חוזר מספרי מאפיינים חוזיים של rhs
lhs_batch_dimensions int64 חוזר מספרי מאפיינים של lhs אצווה
rhs_batch_dimensions 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 צריך להיות אותו גודל מימדים.

דוגמה למספרים באצווה (בגודל 2x2, מטריצות 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] Bundle matmul
[b0, b1, m, k] dot [b0, b1, k, n] [b0, b1, m, n] Bundle matmul

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

DynamicSlice

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

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

DynamicSlice(operand, start_indices, size_indices)

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

מחושבים המדדים של הפלחים האפקטיביים על ידי החלת הטרנספורמציה הבאה על כל אינדקס 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 או שווה לו.

מחושבים המדדים של הפלחים האפקטיביים על ידי החלת הטרנספורמציה הבאה על כל אינדקס 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)

כאשר Op הוא אחד מהערכים Add (תוספת), Sub (הפחתה), Mul (כפל), Div (חילוק), Rem (שארית), Max (מקסימלי), Min (מינימום), LogicalAnd (לוגי AND) או LogicalOr (לוגי OR).

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

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

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

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

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

Op(lhs, rhs, broadcast_dimensions)

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

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

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

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

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

Op(lhs, rhs)

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

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

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

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

Op(lhs, rhs, broadcast_dimensions)

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

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

פונקציות אונריות ברמת האלמנט

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

Abs(operand) תוספות רכיבים x -> |x|.

Ceil(operand) קיבול x -> ⌈x⌉ ברמת הרכיב.

Cos(operand) קוסינוס x -> cos(x) ברמת הרכיב.

Exp(operand) מעריכיות טבעית של רכיבים x -> e^x.

Floor(operand) קומה x -> ⌊x⌋ ברמת הרכיב.

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

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

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

LogicalNot(operand) לוגיקת הרכיב ולא x -> !(x).

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

PopulationCount(operand) מחשבת את מספר הביטים שנקבע בכל רכיב של operand.

Neg(operand) שלילה ברמת הרכיב x -> -x.

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

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.

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

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

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

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

RoundNearestEven(operand) עיגול חלקי אלמנט, קשר לזוג הקרוב ביותר.

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

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

Fft

הפעולה XLA FFT מטמיעה את הטרנספורמציות הקדמיות וההפוכות של פורייה בקלט/פלט אמיתיים ומורכבים. יש תמיכה באובייקטים רב-ממדיים של עד 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] הוא ערך שאינו אפס, ללא החלק הצמוד של האות שהשתנה מעבר לתדר Nyquist.
IRFFT פונקציית ה-FFT ההופכת מאמת למורכבות (כלומר, הפונקציה מחזירה את הערך 'מורכב' או 'ממש'). צורת הציר הפנימי ביותר מורחבת ל-fft_length[-1] אם fft_length[-1] הוא ערך שאינו אפס. המסיקה מהאות שהשתנה מעבר לתדירות ה-Nyquist היא הצירוף ההפוך של הערכים 1 ל-fft_length[-1] // 2 + 1.

FFT רב-ממדי

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

פרטי ההטמעה

ה-CPU FFT מגובה על ידי TensorFFT של Eigen. ב-GPU FFT נעשה שימוש ב-cuFFT.

איסוף

פעולת ה-LA אוספת כמה פרוסות (כל פרוסה עם קיזוז זמן ריצה שונה שעשוי להיות שונה) של מערך קלט.

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

למידע נוסף, ראו 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] עבור k ב-batch_dims }. אפשר להשתמש ב-G כדי לחתוך וקטור S כך ש-S[i] = start_indices[שילוב(G, i)] כאשר שילוב(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 על ידי פיזור האינדקסים לפי מאפייני ההיסט ב-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.rank) לאינדקס מתחיל 'מלא' לתוך operand.

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

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

  • אנחנו משתמשים במידות ההיסט ב-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].

לאחר מכן ניתן להציג את ההתנהגות של פעולת האיסוף כטרנספורמציה של אינדקס שלוקחת את [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].

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

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

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

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

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

G0 ו-G1 משמשים לפילוח האינדקס ההתחלתי ממערך האינדקסים, כרגיל, אלא שהאינדקס ההתחלתי כולל רק אלמנט אחד, X. באופן דומה, יש רק אינדקס קיזוז פלט אחד עם הערך O0. 0GGGG11GatherIndicestf.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) שמציין את המאפיין.

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

פעולות הפחתה ב-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.

בגוף הפיד

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

Infeed(shape)

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

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

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

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

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

Iota

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

Iota(shape, iota_dimension)

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

ארגומנטים סוג סמנטיקה
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 XlaOp שנ' 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 למערך דו-ממדי.

הקלטה

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

Recv(shape, channel_handle)

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

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

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

Recv(const Shape& shape, int64 channel_id)

הפונקציה משייכת את המשאבים הדרושים כדי לקבל נתונים מהוראה של Send עם אותו ערך channel_id. מחזירה הקשר למשאבים שהוקצו, ומשמשת להוראה הבאה של RecvDone כדי להמתין לסיום העברת הנתונים. ההקשר הוא שילוב של {קבלת מאגר נתונים (shape), מזהה בקשה (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, שהמאפיינים שלהם מתוארים בהמשך.

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

דוגמאות

כשמצמצמים מאפיין אחד במערך חד-ממדי יחיד עם הערכים [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":

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

הנה דוגמה מורכבת יותר למערך תלת-ממדי. הדירוג שלה הוא 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.

הפחתה וראיאדית

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

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

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

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

עבור מערכי קלט חד-ממדיים 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), תבצע איטרציה משותפת על המערכים ותחזיר משולש שמכיל את הערך המקסימלי ואת האינדקס התואם.

ReducePrecision

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

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

ReducePrecision(operand, mantissa_bits, exponent_bits)

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

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

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

ReduceScatter

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

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

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

ארגומנטים סוג סמנטיקה
operand XlaOp מערך או צמד לא ריק של מערכים לצמצום ברפליקות.
computation XlaComputation חישוב ההפחתה
scatter_dimension int64 מידה לפיזור.
shard_count int64 מספר הבלוקים לפיצול scatter_dimension
replica_groups הווקטורים של int64 קבוצות שמביניהן מבוצעות ההפחתה
channel_id int64 (אופציונלי) מזהה ערוץ אופציונלי לתקשורת בין מודולים
  • כשה-operand הוא צמד של מערכים, הפחתת הפיזור מתבצעת על כל רכיב ב-tuple.
  • 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 סוג המרווח הפנימי של החלון (Pאימות::kSame, שמחפש את אותה צורת פלט כמו קלט אם הפס הוא 1, או Padding::kValid, שאינו משתמש במרווח פנימי ו "מעצור" את החלון לאחר שהוא כבר לא מתאים)

כאשר:

  • N חייב להיות גדול מ-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. האיור הבא ממחיש את השימוש בשני ערכי שלבים שונים. המרווח מוחל על כל מימד של הקלט, והחישובים זהים לאלו שהקלט הגיע עם המאפיינים שהתקבלו אחרי המרווח.

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

באופן עקרוני, תחילה מעצבים מערך מחדש כדי להפוך מערך לווקטור חד-ממדי של ערכי נתונים, ולאחר מכן מצמצם את הווקטור לצורה חדשה. הארגומנטים של הקלט הם מערך שרירותי מסוג 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 יכול להפוך מערך של רכיב יחיד לסקלרי, ולהפך. לדוגמה,

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 שמציין סטיית תקן של
shape Shape צורת פלט מסוג T

RngUniform

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

הפונקציה יוצרת פלט של צורה נתונה עם מספרים אקראיים שנוצרים בהתאם להתפלגות האחידה על פני המרווח \([a,b)\). הפרמטרים וסוג רכיב הפלט צריכים להיות מסוג בוליאני, סוג אינטגרל או סוגי נקודה צפה (floating-point), והסוגים צריכים להיות עקביים. הקצוות העורפיים של המעבד (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

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

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

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

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 או שווה לו.
  • 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, בסדר עולה.

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

  • כל מערך 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] עבור k ב-update_scatter_dims }. אפשר להשתמש ב-G כדי לחפש וקטור אינדקס S במערך scatter_indices, כך ש-S[i] = scatter_indices[שילוב(G, i)] כאשר שילוב(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 יכול להניח שstart_indices ממוינים (בסדר start_index_map עולה) על ידי המשתמש. אם הם לא זהים, אז הסמנטיקה של ההטמעה מוגדרת.

אם המדיניות 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 כדי לבצע העתקה לאחור של ערכי ההדרגתיות של שכבת מאגר ברשת נוירונים.

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 סוג המרווח הפנימי של החלון (Padding::kSame או Padding::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, הפעולה של Client API של Send מייצגת תקשורת סינכרונית, ומפרקת באופן פנימי לשתי הוראות ל-HLO (Send ו-SendDone) כדי לאפשר העברות נתונים אסינכרוניות. למידע נוסף, ראו HloInstruction::CreateSend ו-HloInstruction::CreateSendDone.

Send(HloInstruction operand, int64 channel_id)

הפעלת העברה אסינכרונית של האופרנד למשאבים שהוקצו על ידי ההוראה Recv עם אותו מזהה ערוץ. מחזירה הקשר, שמשמש בהוראה הבאה של SendDone להמתין לסיום העברת הנתונים. ההקשר הוא שילוב של {operand (shape), מזהה בקשה (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.

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

אם סופקו אופרנדים n > 1:

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

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

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

לדוגמה, במקרה שיש שלושה אופרנדים 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.

פתרון מערכות של משוואות ליניאריות עם מטריצות של משולש תחתון או משולש עליון, באמצעות החלפה קדימה או אחורה. שידור לאורך מאפיינים מובילים, התרחיש הזה פותר את אחת ממערכות המטריצה 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 צריכות להיות זהות.

טופל

למידע נוסף, ראו XlaBuilder::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);

ניתן לבנות את ה-tuples באמצעות הפעולה GetTupleElement.

אף שהפונקציה

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

While(condition, body, init)

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

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

  • צומת 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};
}