בהמשך מתוארת הסמנטיקה של הפעולות המוגדרות בממשק 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 היא פעולה קולקטיבית ששולחת נתונים מכל הליבות לכל הליבות. התהליך כולל שני שלבים:
- שלב הפיזור. בכל ליבה, אופרנד מחולק למספר
split_count
של בלוקים לאורךsplit_dimensions
, והבלוקים מפוזרים לכל הליבות, למשל הבלוק ה-ith נשלח לליבה של ה-ith. - שלב האיסוף. כל ליבה משרשרת את הבלוקים שהתקבלו לאורך
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
מחושבים באופן הבא:
אם
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
] אחרת).אם
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
מחושב באופן הבא:
הפונקציה
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
.יוצרים אינדקס התחלה,
S
in
, לתוךoperand
באמצעותS
על ידי פיזורS
באמצעותstart_index_map
. ליתר דיוק:S
in
[start_index_map
[k
]] =S
[k
] אםk
<start_index_map.size
.S
in
[_
] =0
אחרת.
יוצרים אינדקס
O
in
בתוךoperand
על ידי פיזור האינדקסים לפי מאפייני ההיסט ב-Out
לפי הקבוצהcollapsed_slice_dims
. ליתר דיוק:O
in
[remapped_offset_dims
(k
)] =Out
[offset_dims
[k
]] אםk
<offset_dims.size
(remapped_offset_dims
מוגדר למטה).O
in
[_
] =0
אחרת.
In
הואO
in
+S
in
, כאשר + הוא תוספת הרכיבים.
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
הוא {0
←1
,
1
←3
, 2
←4
, 3
←5
}.
אם המדיניות 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
,O
0
,O
1
], אינדקס בצורת הפלט, וממפה אותו לרכיב במערך הקלט באופן הבא:
תחילה נבחר וקטור (X
,Y
) ממערך האינדקסים של האיסוף באמצעות G
.
הרכיב במערך הפלט באינדקס
[G
,O
0
,O
1
] הוא הרכיב במערך הקלט באינדקס [X
+O
0
,Y
+O
1
].
הערך slice_sizes
הוא [8,6]
, שקובע את הטווח של O0
ו-O1
, והוא קובע את גבולות הקטע.
פעולת האיסוף הזו פועלת כפרוסה דינמית באצווה עם G
בתור המאפיין של אצווה.
אינדקסי האיסוף יכולים להיות רב-ממדיים. לדוגמה, גרסה כללית יותר של הדוגמה שלמעלה עם מערך "gather indices" בצורה [4,5,2]
, תתרגם אינדקסים באופן הבא:
שוב, הוא פועל כפלח דינמי של אצווה G
0
ו-G
1
בתור מאפייני האצווה. גודל הפרוסה הוא עדיין [8,6]
.
פעולת האיסוף ב-XA מכלילת את הסמנטיקה הלא-רשמית שתיארנו למעלה בדרכים הבאות:
אנחנו יכולים להגדיר אילו מאפיינים בצורת הפלט יהיו מאפייני ההיסט (מאפיינים שמכילים
O
0
,O
1
בדוגמה האחרונה). הממדים של אצווה הפלט (מאפיינים שמכיליםG
0
,G
1
בדוגמה האחרונה) מוגדרים כמאפייני הפלט שאינם מתקזזים.מספר המאפיינים של היסט הפלט שמופיעים במפורש בצורת הפלט עשוי להיות קטן מדירוג הקלט. למאפיינים ה "חסרים" האלה, שמצוינים במפורש כ-
collapsed_slice_dims
, צריך להיות גודל פרוסה של1
. גודל הפרוסות שלהם הוא1
, ולכן האינדקס החוקי היחיד עבורן הוא0
, והסרת החילוק שלהן לא גורמת לחוסר בהירות.יכול להיות שהפרוסה שחולפה מהמערך 'מדדי איסוף' ((
X
,Y
) בדוגמה האחרונה) תכלול פחות רכיבים מדירוג מערך הקלט, ומיפוי מפורש קובע איך להרחיב את האינדקס כך שיהיה זהה לדירוג של הקלט.
כדוגמה אחרונה, אנחנו משתמשים בסעיפים (2) ו-(3) כדי ליישם את tf.gather_nd
:
G
0
ו-G
1
משמשים לפילוח האינדקס ההתחלתי
ממערך האינדקסים, כרגיל, אלא שהאינדקס ההתחלתי כולל רק אלמנט אחד, X
. באופן דומה, יש רק אינדקס קיזוז פלט אחד עם הערך O
0
. 0
G
G
G
G
1
1
GatherIndices
tf.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
:
rng_default
: אלגוריתם ספציפי לקצה עורפי עם דרישות צורה ספציפיות לקצה העורפי.rng_three_fry
: אלגוריתם PRNG של ThreeFry שמבוסס על מונה. הצורהinitial_state
היאu64[2]
עם ערכים שרירותיים. Salmon et al. SC 2011. מספרים אקראיים מקבילים: קלים כמו 1, 2, 3.rng_philox
: האלגוריתם Philox יוצר מספרים אקראיים במקביל. הצורהinitial_state
היאu64[3]
עם ערכים שרירותיים. Salmon et al. SC 2011. מספרים אקראיים מקבילים: קלים כמו 1, 2, 3.
פיזור
פעולת הפיזור של 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
המתאים שאליו צריך להחיל את העדכון הזה מחושב באופן הבא:
- הפונקציה
G
= {U
[k
] עבורk
ב-update_scatter_dims
}. אפשר להשתמש ב-G
כדי לחפש וקטור אינדקסS
במערךscatter_indices
, כך ש-S
[i
] =scatter_indices
[שילוב(G
,i
)] כאשר שילוב(A, b) יוסיף את b במיקומיםindex_vector_dim
ל-A. - אפשר ליצור אינדקס
S
in
בתוךoperand
באמצעותS
על ידי פיזורS
באמצעות המפהscatter_dims_to_operand_dims
. בצורה יותר רשמית:S
in
[scatter_dims_to_operand_dims
[k
]] =S
[k
] אםk
<scatter_dims_to_operand_dims.size
.S
in
[_
] =0
אחרת.
- כדי ליצור אינדקס
W
in
לכל מערךoperands
, מפזרים את האינדקסים ב-update_window_dims
ב-U
לפיinserted_window_dims
. בצורה יותר רשמית:W
in
[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
הוא {0
←1
,1
←3
,2
←4
,3
←5
}).W
in
[_
] =0
אחרת.
I
הואW
in
+S
in
, כאשר + הוא תוספת הרכיבים.
לסיכום, אפשר להגדיר את פעולת הפיזור באופן הבא.
- מאתחלים את
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
מוחלת בכל אינדקס שנבחר במערך הפלט. נדרשים שני פרמטרים סקלריים:
- הערך הנוכחי באינדקס שנבחר במערך הפלט
- ערך הפיזור מ-
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};
}