StableHLO هي عملية يتم تعيينها للعمليات عالية المستوى (HLO) في الجهاز التعلم (ML). ويعمل StableHLO كطبقة قابلة للنقل بين مختلف أطر عمل تعلُّم الآلة وبرامج تجميع تعلُّم الآلة: أُطر عمل تعلُّم الآلة التي تُنتج برامج StableHLO متوافقة مع محولات تعلُّم الآلة التي تستهلك برامج StableHLO
هدفنا هو تبسيط وتسريع تطوير تكنولوجيا تعلُّم الآلة من خلال إنشاء المزيد من إمكانية التشغيل التفاعلي بين أطر عمل تعلُّم الآلة (مثل TensorFlow وJAX PyTorch) ومحمولات تعلُّم الآلة (مثل XLA وIREE). نحو هذه النهاية، مواصفة للغة البرمجة StableHLO.
تتضمن هذه المواصفات ثلاثة أقسام رئيسية. أولاً، يصف قسم البرامج بنية برامج StableHLO. التي تتكوّن من دوال StableHLO التي تتكون نفسها من عمليات StableHLO. ضمن هذه البنية، يحدد قسم العمليات دلالات للعمليات الفردية. يوفّر قسم التنفيذ دلالات لكل تنفيذ هذه العمليات معًا ضمن البرنامج. أخيرًا، يناقش قسم التدوين الترميز المستخدَم خلال المواصفات.
لعرض مواصفات إصدار سابق من StableHLO، يُرجى فتح المستودع على إصدار محدد للاهتمام. على سبيل المثال، مواصفات الإصدار 0.19.0 من StableHLO. لعرض التغييرات التي حدثت عند كل تصادم بسيط للإصدار من StableHLO، يمكنك الرجوع إلى سجلّ الإصدار في VhloDialect.td
البرامج
Program ::= {Func}
تتألف برامج StableHLO من عدد عشوائي من دوال StableHLO.
في ما يلي مثال على برنامج يتضمّن الدالة @main
التي تتضمّن 3 إدخالات
(%image
و%weights
و%bias
) ومخرجًا واحدًا. نص الدالة
فيه 6 عمليات.
func.func @main(
%image: tensor<28x28xf32>,
%weights: tensor<784x10xf32>,
%bias: tensor<1x10xf32>
) -> tensor<1x10xf32> {
%0 = "stablehlo.reshape"(%image) : (tensor<28x28xf32>) -> tensor<1x784xf32>
%1 = "stablehlo.dot"(%0, %weights) : (tensor<1x784xf32>, tensor<784x10xf32>) -> tensor<1x10xf32>
%2 = "stablehlo.add"(%1, %bias) : (tensor<1x10xf32>, tensor<1x10xf32>) -> tensor<1x10xf32>
%3 = "stablehlo.constant"() {value = dense<0.0> : tensor<1x10xf32>} : () -> tensor<1x10xf32>
%4 = "stablehlo.maximum"(%2, %3) : (tensor<1x10xf32>, tensor<1x10xf32>) -> tensor<1x10xf32>
"func.return"(%4): (tensor<1x10xf32>) -> ()
}
الدوال
Func ::= 'func' '.' 'func' FuncId FuncInputs FuncOutputs '{' FuncBody '}'
FuncInputs ::= '(' [FuncInput {',' FuncInput}] `)`
FuncInput ::= ValueId ':' ValueType
FuncOutputs ::= ['->' FuncOutput, {',' FuncOutput}]
FuncOutput ::= ValueType
FuncBody ::= {Op}
تتضمن الدوال الثابتة (التي تُسمى أيضًا الدوال المُسمّاة) المعرف والمدخلات/المخرجات ونص. في المستقبل، نخطط وتقديم بيانات وصفية إضافية للدوال لتحقيق توافق أفضل باستخدام HLO (#425، #626، #740، #744.
المعرفات
FuncId ::= '@' letter {letter | digit}
ValueId ::= '%' digit {digit}
| '%' letter {letter | digit}
letter ::= 'a' | ... | 'z' | 'A' | ... | 'Z' | '_'
digit ::= '0' | ... | '9'
تتشابه معرّفات SttableHLO مع المعرّفات في العديد من البرامج. لغتين، مع خاصيتين: 1) جميع المعرفات لها sigil والتي التمييز بين الأنواع المختلفة للمعرفات، 2) يمكن أن تكون معرّفات القيم رقمية بالكامل لتبسيط إنشاء برامج StableHLO.
الأنواع
Type ::= ValueType | NonValueType
ValueType ::= TensorType | QuantizedTensorType | TokenType | TupleType
NonValueType ::= TensorElementType | QuantizedTensorElementType | FunctionType | StringType
يتم تصنيف أنواع الشاشة الثابتة إلى أنواع قيم (والتي تُسمى أيضًا. أنواع الفئة الأولى) التي تمثّل قيم StableHLO والأنواع غير القيم التي تصف عناصر البرنامج الأخرى. تشبه أنواع StableHLO الأنواع في والعديد من لغات البرمجة، مع الخصوصية الرئيسية في لغة StableHLO طبيعة خاصة بالنطاق والتي ينتج عنها بعض النتائج غير المعتادة (مثل الأنواع العددية ليست أنواع قيم).
TensorType ::= 'tensor' '<' Shape TensorElementType '>'
Shape ::= {DimensionSize 'x'}
DimensionSize ::= digit {digit} | '?'
تمثّل أنواع المستشعرات قوات التماس، أي الصفائف متعددة الأبعاد. لديهم
شكل ونوع عنصر، حيث يمثل الشكل قيمة غير سالبة أو
غير معروفة لأحجام السمات بالترتيب التصاعدي للبُعد المقابل
السمات (والتي تُعرف أيضًا باسم المحاور) مرقّمة من 0
إلى R-1
. تشير رسالة الأشكال البيانية
يُطلق على عدد السمات R
اسم الترتيب. على سبيل المثال، tensor<2x3xf32>
هو
نوع عنصر مترابط بالشكل 2x3
ونوع العنصر f32
. ولها بُعدان
(أو بعبارةٍ أخرى، محوران) - البعد 0 والبعد الأول - أحجام
2 و3. ترتيبه 2.
يمكن أن تكون الأشكال غير معروفة جزئيًا أو كليًا (ديناميكية)، على سبيل المثال tensor<?x2xf64>
غير معروف جزئيًا وtensor<?x?xf64>
غير معروفة على الإطلاق. ديناميكية
يتم تمثيل أحجام الأبعاد باستخدام ?
. لا يمكن للأشكال أن تكون غير مرتبة.
ونحن نخطط في المستقبل لاستكشاف توسيع أنواع موتّرات الأداء التي تتجاوز وأحجام الأبعاد وأنواع العناصر، على سبيل المثال، لتضمين تخطيطات (#629) والندرة (#1078)
QuantizedTensorType ::= 'tensor' '<' Shape QuantizedTensorElementType '>'
QuantizedTensorElementType ::= '!quant.uniform' '<'
QuantizationStorageType
['<' QuantizationStorageMin ':' QuantizationStorageMax '>']
':' QuantizationExpressedType
[':' QuantizationDimension]
',' QuantizationParameters '>'
QuantizationStorageType ::= IntegerType
QuantizationStorageMin ::= IntegerConstant
QuantizationStorageMax ::= IntegerConstant
QuantizationExpressedType ::= FloatType
QuantizationDimension ::= IntegerConstant
QuantizationParameters ::= QuantizationParameter
| '{' QuantizationParameter {',' QuantizationParameter} '}'
QuantizationParameter ::= QuantizationScale ':' QuantizationZeroPoint
QuantizationScale ::= FloatConstant
QuantizationZeroPoint ::= IntegerConstant
الاسم | النوع | القيود |
---|---|---|
storage_type |
نوع العدد الصحيح | (C1-C3)، (C8) |
storage_min |
ثابت العدد | (C1)، (C3)، (C7) |
storage_max |
ثابت العدد | (C2)، (C3)، (C7) |
expressed_type |
نوع النقطة العائمة | (C4) |
quantization_dimension |
ثابت عدد صحيح اختياري | (C10-C12) |
scales |
عدد متغيّرات الثوابت العائمة | (C4-C6)، (C9)، (C10)، (C13) |
zero_points |
عدد متغير لثوابت الأعداد الصحيحة | (C7-C9) |
تمثّل أنواع العناصر الكمية قيمًا أعدادًا صحيحة لـ نوع التخزين في
النطاق من storage_min
إلى storage_max
(شامل) الذي يتوافق مع
قيم النقطة العائمة لنوع تم التعبير عنه. بالنسبة إلى قيمة عدد صحيح i
،
يمكن حساب قيمة النقطة العائمة المقابلة f
على النحو التالي
f = (i - zero_point) * scale
، حيث تُسمى scale
وzero_point
مَعلمات تحديد الكمية. إنّ storage_min
وstorage_max
اختياريتان.
في القواعد النحوية، ولكن لها قيم افتراضية تبلغ min_value(storage_type)
max_value(storage_type)
على التوالي. تتمتع أنواع العناصر الكمية
القيود التالية:
- (ج1)
type(storage_min) = storage_type
. - (C2)
type(storage_max) = storage_type
. - (C3)
min_value(storage_type) <= storage_min < storage_max <= max_value(storage_type)
: - (C4)
type(scales...) = expressed_type
. - (C5)
0 < scales
. - (C6)
is_finite(scales...)
. - (C7)
storage_min <= zero_points <= storage_max
. - (C8)
type(zero_points...) = storage_type
. - (C9)
size(scales) = size(zero_points)
. - (C10) إذا كانت
is_empty(quantization_dimension)
، يتم تحصيلsize(scales) = 1
. - (C11)
0 <= quantization_dimension
.
في الوقت الحالي، QuantizationScale
هو ثابت النقطة العائمة، ولكن هناك
اهتمام كبير بالمقاييس القائمة على الأعداد الصحيحة، ممثلة بالمضاعفات
التبديلات. ونحن نخطّط لاستكشاف ذلك في المستقبل القريب.
(#1404)
هناك مناقشة مستمرة حول الدلالات المتعلقة باللغة QuantizationZeroPoint
،
بما في ذلك النوع والقيم وما إذا كان يمكن أن يكون هناك نوع واحد فقط أو
نقاط صفرية متعددة محتملة في نوع متنزس كمي. استنادًا إلى
نتائج هذه المناقشة، فقد تتغير المواصفات المتعلقة بالنقاط الصفرية
في المستقبل (#1405).
تتضمّن المناقشة الجارية الأخرى دلالات QuantizationStorageMin
وQuantizationStorageMax
لتحديد ما إذا كان ينبغي فرض أي قيود
مفروضة على هذه القيم وعلى قيم التوترات الكميّة
(#1406)
وأخيرًا، نخطط لاستكشاف كيفية تمثيل المقاييس غير المعروفة والصفر مماثلة للطريقة التي نخطط بها لاستكشاف تمثيل المجهول أحجام الأبعاد (#1407).
تمثل أنواع موتّرات الكم قوات التوتر التي تتضمّن عناصر كمية. هذه التي تشبه تمامًا نقاط التوتر المنتظمة، غير أن عناصرها على أنواع عناصر محددة الكمية بدلاً من أنواع العناصر العادية.
في مقادير التوتر الكمّي، يمكن أن يكون التحديد الكمي لكل متسابق، بمعنى الحصول على
واحد scale
وzero_point
لمرجع التوتر بالكامل أو يمكن أن يكون لكل محور،
بمعنى، وجود عدة scales
وzero_points
، زوج واحد لكل شريحة من
بُعد معين quantization_dimension
. بشكل رسمي، في تنسور t
مع التحديد الكمّي لكل محور، تتوفّر dim(t, quantization_dimension)
شريحة.
من quantization_dimension
: t[:, ..., 0, ..., :], t[:, ..., 1, ..., :]
،
إلخ. جميع العناصر في الشريحة i
تستخدم scales[i]
وzero_points[i]
معاملات الكمي الخاصة بها. تكون أنواع موتّرات الكمّية ما يلي:
القيود:
- للكمي حسب كل موتّر:
- ما مِن قيود إضافية.
- بالنسبة إلى الكمية حسب المحور:
- (C12)
quantization_dimension < rank(self)
. - (C13)
dim(self, quantization_dimension) = size(scales)
.
- (C12)
TokenType ::= 'token'
تمثّل أنواع الرموز المميّزة الرموز المميّزة، أي القيم غير الواضحة التي يتم إنتاجها واستهلاكها. من خلال بعض العمليات. تُستخدم الرموز المميّزة لفرض أمر تنفيذ على العمليات كما هو موضَّح في قسم التنفيذ.
TupleType ::= 'tuple' '<' TupleElementTypes '>'
TupleElementTypes ::= [ValueType {',' ValueType}]
تمثل أنواع الصفوف الصفوف، أي القوائم غير المتجانسة. الصفوف هي نظام قديم
الموجودة فقط للتوافق مع HLO. في HLO، الصفوف
لتمثيل المدخلات والمخرجات المتباينة. في StableHLO، تتنوع المدخلات
يتم دعم المخرجات محليًا، ولا يمكن استخدام الصفوف في StableHLO إلا من خلال
تمثل واجهة التطبيق الثنائية (HLO ABI) بشكل شامل حيث يمكن، على سبيل المثال، T
وtuple<T>
و
قد تختلف السمة tuple<tuple<T>>
اختلافًا جوهريًا استنادًا إلى
التنفيذ. نخطّط في المستقبل لإجراء تغييرات على واجهة التطبيق الثنائية (HLO ABI).
ما قد يسمح لنا بإزالة أنواع الصفوف من StableHLO
(#598)
TensorElementType ::= BooleanType | IntegerType | FloatType | ComplexType
BooleanType ::= 'i1'
IntegerType ::= SignedIntegerType | UnsignedIntegerType
SignedIntegerType ::= 'si2' | 'si4' | 'si8' | 'si16' | 'si32' | 'si64'
UnsignedIntegerType ::= 'ui2' | 'ui4' | 'ui8' | 'ui16' | 'ui32' | 'ui64'
FloatType ::= 'f8E4M3FN' | 'f8E5M2' | 'f8E4M3FNUZ' | 'f8E5M2FNUZ'
| 'f8E4M3B11FNUZ' | 'bf16' | 'f16' | 'f32' | 'f64'
TensorFloat32 ::= 'tf32'
ComplexType ::= 'complex' '<' ComplexElementType '>'
ComplexElementType ::= 'f32' | 'f64'
تمثّل أنواع العناصر عناصر أنواع أداة "المنسِّر". على عكس العديد من البرامج
اللغات، فهذه الأنواع ليست من الدرجة الأولى في StableHLO. هذا يعني أنّ
ولا يمكن لبرامج StableHLO أن تمثل قيمًا من هذه الأنواع بشكل مباشر (نتيجةً لذلك،
يكون من الاصطلاحي تمثيل القيم العددية من النوع T
باستخدام متوتر 0 الأبعاد
القيم من النوع tensor<T>
).
- يمثّل النوع المنطقي القيم المنطقية
true
وfalse
. - يمكن أن تكون أنواع الأعداد الصحيحة إما موقَّعة (
si
) أو غير موقَّعة (ui
) أحد عرض البتات المسموح به (2
أو4
أو8
أو16
أو32
أو64
). تمثل الأنواعsiN
الموقّعة قيم أعداد صحيحة من-2^(N-1)
إلى2^(N-1)-1
شاملة وغير موقعةuiN
تمثل قيم الأعداد الصحيحة من0
إلى2^N-1
بشكل شامل. - يمكن أن تكون أنواع النقاط العائمة أيًا مما يلي:
- النوعان
f8E4M3FN
وf8E5M2
المتوافقان مع الترميزانE4M3
وE5M2
للتنسيق FP8 الموضح في تنسيقات FP8 للتعلّم المتعمق - النوعان
f8E4M3FNUZ
وf8E5M2FNUZ
المتوافقان مع السمتَينE4M3
وE5M2
ترميزات تنسيقات FP8 الموضحة في تنسيقات رقمية 8 بت للشبكات العصبية العميقة - النوع
f8E4M3B11FNUZ
المقابل لترميزE4M3
لتنسيقات FP8. موصوفة في تدريب واستنتاج النقطة العائمة المختلطة (HFP8) للشبكات العصبية العميقة. - نوع
bf16
متوافق مع تنسيقbfloat16
الموضّح في. BFloat16: سر تحقيق الأداء العالي في وحدات معالجة الموتّرات في السحابة الإلكترونية - أنواع
f16
وf32
وf64
مناظرة على التواليbinary16
("نصف الدقة") وbinary32
("دقة واحدة") تنسيقاتbinary64
("الدقة المزدوجة") الموضّحة في معيار IEEE 754 - يتوافق النوع
tf32
مع تنسيق TensorFloat32. ولديها دعم محدود في StableHLO
- النوعان
- الأنواع المعقّدة تمثّل قيمًا معقدة تتضمّن جزءًا حقيقيًا.
وجزء خيالي من نوع العنصر نفسه. المجمّع المدعوم
النوعان هما
complex<f32>
(كلا الجزأين من النوعf32
) وcomplex<f64>
. (كلا الجزأين من النوعf64
).
FunctionType ::= '(' InputTypes ')' '->' '(' OutputTypes ')'
InputTypes ::= [ValueType {',' ValueType}]
OutputTypes ::= [ValueType {',' ValueType}]
تمثّل أنواع الدوال كلاً من الدوال المُسمّاة والمجهولة الهوية. لديهم
أنواع الإدخال (قائمة الأنواع على الجانب الأيسر من ->
) وأنواع الإخراج
(قائمة الأنواع على الجانب الأيسر من ->
). في العديد من البرامج
اللغات، تكون أنواع الدوال من الدرجة الأولى، ولكنها ليست في StableHLO.
StringType ::= 'string'
يمثل نوع السلسلة تسلسلات من وحدات البايت. على عكس العديد من البرامج فإن نوع السلسلة ليس من الفئة الأولى في StableHLO ويستخدم فقط تحديد بيانات التعريف الثابتة لعناصر البرنامج.
العمليات
تمثِّل العمليات الثابتة (التي تُسمى أيضًا العمليات) مجموعة مغلقة للعمليات رفيعة المستوى في نماذج التعلم الآلي. كما ناقشنا أعلاه، يتم استلهام بناء جملة StableHLO بشكل كبير من MLIR، والذي ليس بالضرورة أن يكون بديل مريح، ولكنه يمكن القول إنه الأنسب لهدف StableHLO المتمثل في توفير المزيد من إمكانية التشغيل التفاعلي بين أُطر عمل تعلُّم الآلة وبرامج تجميع تعلُّم الآلة.
Op ::= [OpOutputs] OpName OpInputs ':' OpSignature
OpName ::= '"' 'stablehlo' '.' OpMnemonic '"'
OpMnemonic ::= 'abs' | 'add' | ...
العمليات الثابتة (التي يُطلق عليها أيضًا العمليات) لها اسم
المدخلات/المخرجات والتوقيع. يتكون الاسم من البادئة stablehlo.
الذاكرة التي تحدد بشكل فريد إحدى العمليات المدعومة. انظر أدناه
قائمة شاملة بجميع العمليات المدعومة.
OpInputs ::= OpInputValues OpInputFuncs OpInputAttrs
OpInputValues ::= '(' [OpInputValue {',' OpInputValue}] ')'
OpInputValue ::= ValueId
OpInputFuncs ::= ['(' OpInputFunc {',' OpInputFunc} ')']
OpInputAttrs ::= ['{' OpInputAttr {',' OpInputAttr} '}']
OpOutputs ::= [OpOutput {',' OpOutput} '=']
OpOutput ::= ValueId
تستهلك العمليات الإدخالات وتُنتج المخرجات. يتم تصنيف الإدخالات إلى
قيم الإدخال (المحسوبة أثناء التنفيذ)، دوال الإدخال (المقدمة
بشكلٍ ثابت، لأن الدوال الثابتة HLO ليست قيمًا من الدرجة الأولى)
سمات الإدخال (يتم تقديمها أيضًا بشكل ثابت). نوع المدخلات والمخرجات
تعتمد العملية التي يتم استهلاكها وإنتاجها على ذاكرتها. على سبيل المثال، add
تستهلك هذه العملية قيمتي إدخال وينتج عنها قيمة واحدة للمخرج. وعند المقارنة،
تستهلك العملية select_and_scatter
3 قيم إدخال ووظيفتَي إدخال
3 سمات إدخال.
OpInputFunc ::= '{' Unused FuncInputs ':' FuncBody '}'
Unused ::= '^' digit {digit}
| '^' letter {letter | digit}
تُعد دوال الإدخال (والتي تُسمى أيضًا الدوال المجهولة) جزءًا مهمًا جدًا
تشبه الدوال المُسمّاة باستثناء: 1) ليس لها معرِّف (وبالتالي
الاسم "مجهول"، 2) أنها لا تعلن عن أنواع الإخراج (أنواع الناتج
يمكن استنتاجه من العملية return
في الدالة).
تتضمن بناء جملة دوال الإدخال جزءًا غير مستخدم حاليًا (انظر
Unused
أعلاه) متوفّر للتوافق مع MLIR. في MLIR،
فهناك مفهوم أكثر عمومية لمصطلح "المناطق" التي يمكن أن تتضمّن "محظورات" متعددة
العمليات مرتبطة معًا من خلال عمليات القفز. تحتوي هذه المجموعات على أرقام تعريف تتوافق مع
إلى إنتاج Unused
، حتى يمكن تمييزها عن بعضها البعض.
لا يحتوي StableHLO على عمليات الانتقال، لذا فإن الجزء المقابل من بناء جملة MLIR
غير مستخدم (ولكنه لا يزال موجودًا).
OpInputAttr ::= OpInputAttrName '=' OpInputAttrValue
OpInputAttrName ::= letter {letter | digit}
OpInputAttrValue ::= Constant
يحتوي سمات الإدخال على اسم وقيمة تمثّل إحدى السمات المتوافقة.
والثوابت. أنها الطريقة الأساسية لتحديد بيانات التعريف الثابتة للبرنامج
عناصر. على سبيل المثال، تستخدم العملية concatenate
السمة dimension
تحديد البُعد الذي يتم من خلاله تسلسل قيم الإدخال وبالمثل،
تستخدم العملية slice
سمات متعددة مثل start_indices
وlimit_indices
لتحديد الحدود المستخدمة لتقسيم قيمة الإدخال.
في الوقت الحالي، تحتوي برامج StableHLO المتوفّرة على الإنترنت على سمات والتي لم يتم وصفها في هذا المستند. في المستقبل، نخطط إما أن تمتص هذه السمات في بيئة StableHLO أو تمنعها من تظهر في برامج StableHLO في غضون ذلك، إليك قائمة بهذه :
layout
(#629).mhlo.frontend_attributes
(#628).mhlo.sharding
(#619).output_operand_aliases
(#740).- البيانات الوصفية للموقع الجغرافي (#594)
OpSignature ::= '(' [ValueType {',' ValueType}] ')' '->' '(' [ValueType {',' ValueType}] ')'
يتكون توقيع العمليات من أنواع جميع قيم الإدخال (قائمة الأنواع على
الجانب الأيسر لـ ->
) وأنواع جميع قيم الإخراج (قائمة
على الجانب الأيسر من ->
). وعلى وجه التحديد، تُعد أنواع المدخلات
متكررة، وأنواع الإخراج تكون متكررة دائمًا تقريبًا أيضًا (لأن
في معظم عمليات StableHLO، يمكن استنتاج أنواع الإخراج من الإدخالات). ومع ذلك،
يكون التوقيع جزءًا متعمدًا من بناء جملة StableHLO للتوافق مع MLIR.
فيما يلي مثال لعملية تقوية الذاكرة select_and_scatter
. يستهلك 3
قيم الإدخال (%operand
و%source
و%init_value
)، دالتا إدخال
و3 سمات إدخال (window_dimensions
وwindow_strides
وpadding
).
لاحظ كيف يتضمن توقيع العملية أنواع قيم الإدخال فقط
(ولكن ليس أنواع دوال الإدخال والسمات التي يتم توفيرها مضمّنة).
%result = "stablehlo.select_and_scatter"(%operand, %source, %init_value) ({
^bb0(%arg0: tensor<i32>, %arg1: tensor<i32>):
%0 = "stablehlo.compare"(%arg0, %arg1) {
comparison_direction = #stablehlo<comparison_direction GE>
} : (tensor<i32>, tensor<i32>) -> tensor<i1>
"stablehlo.return"(%0) : (tensor<i1>) -> ()
}, {
^bb0(%arg0: tensor<i32>, %arg1: tensor<i32>):
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i32>, tensor<i32>) -> tensor<i32>
"stablehlo.return"(%0) : (tensor<i32>) -> ()
}) {
window_dimensions = dense<[3, 1]> : tensor<2xi64>,
window_strides = dense<[2, 1]> : tensor<2xi64>,
padding = dense<[[0, 1], [0, 0]]> : tensor<2x2xi64>
} : (tensor<4x2xi32>, tensor<2x2xi32>, tensor<i32>) -> tensor<4x2xi32>
الثوابت
Constant ::= BooleanConstant
| IntegerConstant
| FloatConstant
| ComplexConstant
| TensorConstant
| QuantizedTensorConstant
| StringConstant
| EnumConstant
تضم الثوابت الثابتة HLO قيمة حرفية ونوع يمثلان معًا
قيمة StableHLO. وبشكلٍ عام، يُعد النوع جزءًا من الصيغة الثابتة، باستثناء
عندما يكون لا لبس فيه (على سبيل المثال، ثابت منطقي لا لبس فيه يكون من النوع i1
،
بينما يمكن أن يضم ثابت العدد الصحيح عدة أنواع محتملة).
BooleanConstant ::= BooleanLiteral
BooleanLiteral ::= 'true' | 'false'
تمثل الثوابت المنطقية القيمتين المنطقيتين true
وfalse
. منطقية
الثوابت من نوع i1
.
IntegerConstant ::= IntegerLiteral ':' IntegerType
IntegerLiteral ::= ['-' | '+'] DecimalDigits
| ['-' | '+'] '0x' HexadecimalDigits
DecimalDigits ::= decimalDigit {decimalDigit}
HexadecimalDigits ::= hexadecimalDigit {hexadecimalDigit}
decimalDigit ::= '0' | ... | '9'
hexadecimalDigit ::= decimalDigit | 'a' | ... | 'f' | 'A' | ... | 'F'
الثوابت لعدد صحيح هي قيم الأعداد الصحيحة من خلال السلاسل التي تستخدم الأعداد العشرية أو التدوين السداسي العشري. قواعد أخرى، مثل النظام الثنائي أو الثماني، تخضع الثوابت العددية للقيود التالية:
- (ج1)
is_wellformed(integer_literal, integer_type)
.
FloatConstant ::= FloatLiteral ':' FloatType
FloatLiteral ::= SignPart IntegerPart FractionalPart ScientificPart
| '0x' [HexadecimalDigits]
SignPart ::= ['-' | '+']
IntegerPart ::= DecimalDigits
FractionalPart ::= ['.' [DecimalDigits]]
ScientificPart ::= [('e' | 'E') ['-' | '+'] DecimalDigits]
تمثّل الثوابت العائمة قيم النقطة العائمة من خلال سلاسل تستخدم التدوين العشري أو العلمي. بالإضافة إلى ذلك، يمكن كتابة التدوين السداسي العشري يُستخدم لتحديد وحدات البت الأساسية مباشرةً بتنسيق النقطة العائمة والنوع المقابل. تنطبق القيود التالية على الثوابت العائمة:
- (C1) إذا تم استخدام تدوين غير سداسي عشري،
is_wellformed(float_literal, float_type)
- (C2) إذا تم استخدام تدوين سداسي عشري،
size(hexadecimal_digits) = num_bits(float_type) / 4
ComplexConstant ::= ComplexLiteral ':' ComplexType
ComplexLiteral ::= '(' RealPart ',' ImaginaryPart ')'
RealPart ::= FloatLiteral
ImaginaryPart ::= FloatLiteral
تمثل الثوابت المركّبة قيمًا مركّبة باستخدام قوائم لجزء حقيقي.
(يأتي أولاً) والجزء الخيالي (يأتي ثانيًا). على سبيل المثال:
يمثل (1.0, 0.0) : complex<f32>
1.0 + 0.0i
،
يمثل الحقل "(0.0, 1.0) : complex<f32>
" القيمة "0.0 + 1.0i
". الترتيب الذي
يتم تحديد تنفيذ هذه الأجزاء في الذاكرة. الثوابت المعقدة
للقيود التالية:
- (ج1)
is_wellformed(real_part, complex_element_type(complex_type))
. - (C2)
is_wellformed(imaginary_part, complex_element_type(complex_type))
.
TensorConstant ::= TensorLiteral ':' TensorType
TensorLiteral ::= 'dense' '<' (DenseLiteral | ElementLiteral) '>'
DenseLiteral ::= DenseDimension | DenseElements
DenseDimension ::= '[' [DenseLiteral {',' DenseLiteral}] ']'
DenseElements ::= [ElementLiteral {',' ElementLiteral}]
ElementLiteral ::= BooleanLiteral | IntegerLiteral | FloatLiteral | ComplexLiteral
تمثل ثوابت المستشعر قيم التوتر باستخدام قوائم متداخلة محددة عبر
تدوين نمباي. على سبيل المثال: dense<[[1, 2, 3], [4, 5, 6]]> : tensor<2x3xi32>
يمثل قيمة موتّر من خلال التعيين التالي من الفهارس إلى العناصر:
{0, 0} => 1
و{0, 1} => 2
و{0, 2} => 3
و{1, 0} => 4
و{1, 1} => 5
{1, 2} => 6
ثم ترتيب تخزين هذه العناصر في الذاكرة
التنفيذ. تحتوي ثوابت الموتّر على القيود التالية:
- (C1)
has_syntax(tensor_literal, element_type(tensor_type))
، حيث:has_syntax(element_literal: Syntax, element_type: Type) = is_wellformed(element_literal, type)
.has_syntax(tensor_literal: List, element_type: Type) = has_syntax(tensor_literal..., element_type)
.
- (C2)
has_shape(tensor_literal, shape(tensor_type))
، حيث:has_shape(element_literal: Syntax, []) = true
.has_shape(tensor_literal: List, shape: List) = size(tensor_literal) = shape[0] and has_shape(tensor_literal..., shape[1:])
.- وإلا،
false
.
QuantizedTensorConstant ::= QuantizedTensorLiteral ':' QuantizedTensorType
QuantizedTensorLiteral ::= 'dense' '<' (DenseLiteral | ElementLiteral) '>'
تمثّل ثوابت متنزّر الكميّة قيم متسّعة كميّة باستخدام القيم نفسها كثوابت متسقة، مع عناصر محددة كثوابت لثوابتها ونوع التخزين. هناك القيود التالية على ثوابت التينس الكميّة:
- (ج1)
has_syntax(quantized_tensor_literal, storage_type(quantized_tensor_type))
. - (C2)
has_shape(quantized_tensor_literal, shape(quantized_tensor_type))
.
StringConstant ::= StringLiteral
StringLiteral ::= '"' {stringCharacter | escapeSequence} '"'
stringCharacter ::= all ASCII characters except '\00', '\01', ... '\1f' and '"'
escapeSequence ::= '\' ('"' | '\' | 'n' | 't' | (hexadecimalDigit hexadecimalDigit))
تتكوّن الأحرف الحرفية للسلسلة من وحدات بايت يتم تحديدها باستخدام أحرف ASCII
وتسلسلات الهروب. فهي لا تتضمن أي ترميز، وبالتالي يمكن تفسير هذه
وحدات البايت محددة التنفيذ. تكون القيم الحرفية للسلسلة من النوع string
.
العمليات
abs
دلالات الألفاظ
تؤدي هذه العملية إلى إجراء عملية عضلات البطن من حيث العناصر على متوتر operand
وينتج عنها result
متنسور. حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى الأعداد الصحيحة الموقّعة: معامل العدد الصحيح.
- بالنسبة إلى الأعداد العشرية:
abs
من IEEE-754. - المعامل المركّب بالنسبة للأعداد المركّبة
- بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(abs, operand, type(result))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
موتّر عدد صحيح بعلامة أو نقطة عائمة أو نوع مركب أو مٍنسور كمي لكل متسابق | (C1-C2) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متسابق عدد صحيح بعلامة أو نوع النقطة العائمة أو متسابق كمي لكل متسابق | (C1-C2) |
القيود
- (ج1)
shape(result) = shape(operand)
. - (C2) يتم تعريف
baseline_element_type(result)
على النحو التالي:complex_element_type(element_type(operand))
إذاis_complex(operand)
.baseline_element_type(operand)
بخلاف ذلك.
أمثلة
// %operand: [-2, 0, 2]
%result = "stablehlo.abs"(%operand) : (tensor<3xi32>) -> tensor<3xi32>
// %result: [2, 0, 2]
إضافة
دلالات الألفاظ
لتنفيذ إضافة عاملين متوترين lhs
وrhs
حسب العناصر وينتج عن ذلك
متوتر result
حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى القيم المنطقية: منطقي OR.
- بالنسبة إلى الأعداد الصحيحة: إضافة عدد صحيح.
- بالنسبة إلى الأعداد العشرية:
addition
من IEEE-754. - بالنسبة للأعداد المركّبة: الإضافة المركّبة.
- بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(add, lhs, rhs, type(result))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
متوتر أو متنسّر كمي | (C1-C6) |
(I2) | rhs |
متوتر أو متنسّر كمي | (C1-C5)، (C7) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتر أو متنسّر كمي | (C1-C7) |
القيود
- إذا كانت العملية تستخدم موتّرات غير كَمية:
- (ج1)
type(lhs) = type(rhs) = type(result)
.
- (ج1)
- إذا كانت العملية تستخدم موتّرات كميّة:
- (C2)
is_quantized(lhs) and is_quantized(rhs) and is_quantized(result)
. - (C3)
storage_type(lhs) = storage_type(rhs) = storage_type(result)
: - (C4)
expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
. - (C5)
(is_per_axis_quantized(lhs) or is_per_axis_quantized(rhs)) = is_per_axis_quantized(result)
. - (C6) إذا كانت
is_per_axis_quantized(lhs)
، يتم عندهاquantization_dimension(lhs) = quantization_dimension(result)
. - (C7) إذا كانت
is_per_axis_quantized(rhs)
، يتم عندهاquantization_dimension(rhs) = quantization_dimension(result)
.
- (C2)
أمثلة
// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.add"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[6, 8], [10, 12]]
after_all
دلالات الألفاظ
يضمن تنفيذ العمليات التي تنتج عن inputs
قبل أي
العمليات التي تعتمد على result
. لا يؤدي تنفيذ هذه العملية إلى أي شيء،
فهي تهدف فقط إلى إنشاء تبعيات البيانات من result
إلى inputs
.
مدخلات
التصنيف | الاسم | النوع |
---|---|---|
(I1) | inputs |
العدد المتغير في token |
المُخرَجات
الاسم | النوع |
---|---|
result |
token |
أمثلة
// %input0: !stablehlo.token
// %input1: !stablehlo.token
%result = "stablehlo.after_all"(%input0, %input1) : (!stablehlo.token, !stablehlo.token) -> !stablehlo.token
all_gather
دلالات الألفاظ
في كل مجموعة عمليات ضمن شبكة العمليات StableHLO، يتم إنشاء تسلسل للقيم
من عوامل العشرات operands
من كل عملية على طول all_gather_dim
وينتج عن ذلك
results
متسابق.
تقسم هذه العملية شبكة عملية StableHLO إلى process_groups
وهي
على النحو التالي:
cross_replica(replica_groups)
إذا كانت القيمة هيchannel_id <= 0 and use_global_device_ids = false
.cross_replica_and_partition(replica_groups)
إذا كانت القيمة هيchannel_id > 0 and use_global_device_ids = false
.flattened_ids(replica_groups)
إذا كانت القيمة هيchannel_id > 0 and use_global_device_ids = true
.
بعد ذلك، ضمن كل process_group
:
operands...@receiver = [operand@sender for sender in process_group]
للجميعreceiver
فيprocess_group
.results...@process = concatenate(operands...@process, all_gather_dim)
للجميعprocess
فيprocess_group
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operands |
الأعداد المتباينة للمتسابقات أو المتسابقات الكميّة لكل متسابق | (C1)، (C6) |
(I2) | all_gather_dim |
ثابت من النوع si64 |
(C1)، (C6) |
(I3) | replica_groups |
ثابت التوتر الثنائي الأبعاد من النوع si64 |
(C2-C4) |
(I4) | channel_id |
ثابت من النوع si64 |
(C5) |
(I5) | use_global_device_ids |
ثابت من النوع i1 |
(C5) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
results |
الأعداد المتباينة للمتسابقات أو المتسابقات الكميّة لكل متسابق | (C6) |
القيود
- (ج1)
0 <= all_gather_dim < rank(operands...)
. - (C2)
is_unique(replica_groups)
. - (C3) يتم تعريف
size(replica_groups)
على النحو التالي:num_replicas
في حال استخدامcross_replica
.num_replicas
في حال استخدامcross_replica_and_partition
.num_processes
في حال استخدامflattened_ids
.
- (C4)
0 <= replica_groups < size(replica_groups)
. - (C5) إذا كانت
use_global_device_ids = true
، يتم عندهاchannel_id > 0
. - (C6)
type(results...) = type(operands...)
باستثناء:dim(results..., all_gather_dim) = dim(operands..., all_gather_dim) * dim(process_groups, 1)
.
أمثلة
// num_replicas: 2
// num_partitions: 1
// %operand0@(0, 0): [[1, 2], [3, 4]]
// %operand0@(1, 0): [[5, 6], [7, 8]]
// %operand1@(0, 0): [[11, 12], [13, 14]]
// %operand1@(1, 0): [[15, 16], [17, 18]]
%result:2 = "stablehlo.all_gather"(%operand0, %operand1) {
all_gather_dim = 1 : i64,
replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>,
// channel_id = 0
channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
// use_global_device_ids = false
} : (tensor<2x2xi64>, tensor<2x2xi64>) -> (tensor<2x4xi64>, tensor<2x4xi64>)
// %result0@(0, 0): [[1, 2, 5, 6], [3, 4, 7, 8]]
// %result0@(1, 0): [[1, 2, 5, 6], [3, 4, 7, 8]]
// %result1@(0, 0): [[11, 12, 15, 16], [13, 14, 17, 18]]
// %result1@(1, 0): [[11, 12, 15, 16], [13, 14, 17, 18]]
all_reduce
دلالات الألفاظ
ضمن كل مجموعة عمليات في شبكة عملية StableHLO، يطبق خفض
دالة computation
مع قيم مترابطات operands
من كل عملية
وتنتج results
موتّرات.
تقسم هذه العملية شبكة عملية StableHLO إلى process_groups
وهي
على النحو التالي:
cross_replica(replica_groups)
إذا كانت القيمة هيchannel_id <= 0 and use_global_device_ids = false
.cross_replica_and_partition(replica_groups)
إذا كانت القيمة هيchannel_id > 0 and use_global_device_ids = false
.flattened_ids(replica_groups)
إذا كانت القيمة هيchannel_id > 0 and use_global_device_ids = true
.
بعد ذلك، ضمن كل process_group
:
results...@process[result_index] = exec(schedule)
لبعض الشجرة الثنائيةschedule
حيث:exec(node)
=computation(exec(node.left), exec(node.right))
.exec(leaf)
=leaf.value
.
schedule
عبارة عن شجرة ثنائية محدّدة التنفيذ تكون ذات ترتيب قيمة الاجتياز هيto_destination_type(operands...@process_group...[result_index], type(func_inputs(computation)[0]))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operands |
الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق | (C5)، (C6) |
(I2) | replica_groups |
عدد متغير لثوابت متسابق أحادي البعد من النوع si64 |
(C1-C3) |
(I3) | channel_id |
ثابت من النوع si64 |
(C4) |
(I4) | use_global_device_ids |
ثابت من النوع i1 |
(C4) |
(I5) | computation |
دالة | (C5) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
results |
الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق | (C6-C7) |
القيود
- (ج1)
is_unique(replica_groups)
. - (C2) يتم تعريف
size(replica_groups)
على النحو التالي:num_replicas
في حال استخدامcross_replica
.num_replicas
في حال استخدامcross_replica_and_partition
.num_processes
في حال استخدامflattened_ids
.
- (C3)
0 <= replica_groups < size(replica_groups)
: - (C4) إذا كانت
use_global_device_ids = true
، يتم عندهاchannel_id > 0
. - (C5)
computation
من النوع(tensor<E>, tensor<E>) -> (tensor<E>)
حيث يكونis_promotable(element_type(operand), E)
- (C6)
shape(results...) = shape(operands...)
. - (C7)
element_type(results...) = E
.
أمثلة
// num_replicas: 2
// num_partitions: 1
// %operand0@(0, 0): [1, 2, 3, 4]
// %operand0@(1, 0): [5, 6, 7, 8]
// %operand1@(0, 0): [9, 10, 11, 12]
// %operand1@(1, 0): [13, 14, 15, 16]
%result:2 = "stablehlo.all_reduce"(%operand0, %operand0) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
"stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>,
// channel_id = 0
channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
// use_global_device_ids = false
} : (tensor<4xi64>, tensor<4xi64>) -> (tensor<4xi64>, tensor<4xi64>)
// %result0@(0, 0): [6, 8, 10, 12]
// %result0@(1, 0): [6, 8, 10, 12]
// %result1@(0, 0): [22, 24, 26, 28]
// %result1@(1, 0): [22, 24, 26, 28]
all_to_all
دلالات الألفاظ
داخل كل مجموعة عمليات في شبكة عملية StableHLO، تُقسم قيم
متسّعات operands
على طول split_dimension
إلى أجزاء، تفصل القسمة
يربط الأجزاء المتناثرة ببعضها البعض،
concat_dimension
وينتج results
متسابقًا.
تقسم هذه العملية شبكة عملية StableHLO إلى process_groups
وهي
على النحو التالي:
cross_replica(replica_groups)
إذاchannel_id <= 0
.cross_partition(replica_groups)
إذاchannel_id > 0
.
بعد ذلك، ضمن كل process_group
:
split_parts...@sender = split(operands...@sender, split_count, split_dimension)
لجميعsender
فيprocess_group
.- مكان
scattered_parts...@receiver = [split_parts...@sender[receiver_index] for sender in process_group]
receiver_index = process_group.index(receiver)
results...@process = concatenate(scattered_parts...@process, concat_dimension)
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operands |
الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق | (C1-C3)، (C9) |
(I2) | split_dimension |
ثابت من النوع si64 |
(C1)، (C2)، (C9) |
(I3) | concat_dimension |
ثابت من النوع si64 |
(C3)، (C9) |
(I4) | split_count |
ثابت من النوع si64 |
(C2)، (C4)، (C8)، (C9) |
(I5) | replica_groups |
ثابت التوتر الثنائي الأبعاد من النوع si64 |
(C5-C8) |
(I6) | channel_id |
ثابت من النوع si64 |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
results |
الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق | (C9) |
القيود
- (ج1)
0 <= split_dimension < rank(operands...)
. - (C2)
dim(operands..., split_dimension) % split_count = 0
. - (C3)
0 <= concat_dimension < rank(operands...)
: - (C4)
0 < split_count
. - (C5)
is_unique(replica_groups)
. - (C6) يتم تعريف
size(replica_groups)
على النحو التالي:num_replicas
في حال استخدامcross_replica
.num_partitions
في حال استخدامcross_partition
.
- (C7)
0 <= replica_groups < size(replica_groups)
. - (C8)
dim(replica_groups, 1) = split_count
. - (C9)
type(results...) = type(operands...)
باستثناء إذا كانتsplit_dimension != concat_dimension
:dim(results..., split_dimension) = dim(operands..., split_dimension) / split_count
.dim(results..., concat_dimension) = dim(operands..., concat_dimension) * split_count
.
أمثلة
// num_replicas: 2
// num_partitions: 1
// %operand1@(0, 0): [[1, 2, 3, 4],
// [5, 6, 7, 8]]
// %operand1@(1, 0): [[9, 10, 11, 12],
// [13, 14, 15, 16]]
// %operand2@(0, 0): [[17, 18, 19, 20],
// [21, 22, 23, 24]]
// %operand2@(1, 0): [[25, 26, 27, 28],
// [29, 30, 31, 32]]
%result:2 = "stablehlo.all_to_all"(%operand1, %operand2) {
split_dimension = 1 : i64,
concat_dimension = 0 : i64,
split_count = 2 : i64,
replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>
// channel_id = 0
} : (tensor<2x4xi64>, tensor<2x4xi64>) -> (tensor<4x2xi64>, tensor<4x2xi64>)
// %result#0@(0, 0): [[1, 2], [5, 6], [9, 10], [13, 14]]
// %result#0@(1, 0): [[3, 4], [7, 8], [11, 12], [15, 16]]
// %result#1@(0, 0): [[17, 18], [21, 22], [25, 26], [29, 30]]
// %result#1@(1, 0): [[19, 20], [23, 24], [27, 28], [31, 32]]
و
دلالات الألفاظ
تؤدي هذه العملية إلى إجراء AND من ناحية العناصر على مستوى العنصرين lhs
وrhs
وينتج عن ذلك result
.
متنسور. حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى القيم المنطقية: المنطقي AND.
- بالنسبة إلى الأعداد الصحيحة: استخدام AND على مستوى البت.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
متّصِل من نوع القيمة المنطقية أو العدد الصحيح | (C1) |
(I2) | rhs |
متّصِل من نوع القيمة المنطقية أو العدد الصحيح | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متّصِل من نوع القيمة المنطقية أو العدد الصحيح | (C1) |
القيود
- (ج1)
type(lhs) = type(rhs) = type(result)
.
أمثلة
// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.and"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[1, 2], [3, 0]]
atan2
دلالات الألفاظ
لتنفيذ عملية atan2 من العناصر في العناصر على lhs
وrhs
Tensor وينتج عن ذلك
متوتر result
حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى الأعداد العشرية:
atan2
من IEEE-754. - للأعداد المركّبة: مركّب Atan2.
- بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(atan2, lhs, rhs, type(result))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
(I2) | rhs |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
القيود
- (ج1)
baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)
.
أمثلة
// %lhs: [0.0, 1.0, -1.0]
// %rhs: [0.0, 0.0, 0.0]
%result = "stablehlo.atan2"(%lhs, %rhs) : (tensor<3xf64>, tensor<3xf64>) -> tensor<3xf64>
// %result: [0.0, 1.57079637, -1.57079637] // [0.0, pi/2, -pi/2]
batch_norm_grad
دلالات الألفاظ
احتساب تدرجات مدخلات متعددة لعملية الانتشار العكسي batch_norm_training
من grad_output
، وأنتج grad_operand
وgrad_scale
وgrad_offset
وأجهزة تنس. ويمكن التعبير عن هذه العملية بشكل أكثر رسمية بوصفها تحليلاً
عمليات StableHLO الحالية باستخدام بناء جملة Python على النحو التالي:
def compute_sum(operand, feature_index):
(sum,) = reduce(
inputs=[operand],
init_values=[constant(0, element_type(operand))],
dimensions=[i for i in range(rank(operand)) if i != feature_index],
body=lambda x, y: add(x, y))
return sum
def compute_mean(operand, feature_index):
sum = compute_sum(operand, feature_index)
divisor = constant(size(operand) / dim(operand, feature_index),
element_type(operand))
divisor_bcast = broadcast_in_dim(divisor, [], type(sum))
return divide(sum, divisor_bcast)
def batch_norm_grad(operand, scale, mean, variance, grad_output, epsilon, feature_index):
# Broadcast inputs to type(operand)
scale_bcast = broadcast_in_dim(scale, [feature_index], type(operand))
mean_bcast = broadcast_in_dim(mean, [feature_index], type(operand))
variance_bcast = broadcast_in_dim(variance, [feature_index], type(operand))
epsilon_bcast = broadcast_in_dim(constant(epsilon, element_type(operand)), [],
type(operand))
# Perform normalization using the provided `mean` and `variance`
# Intermediate values will be useful for computing gradients
centered_operand = subtract(operand, mean_bcast)
stddev = sqrt(add(variance_bcast, epsilon_bcast))
normalized_operand = divide(centered_operand, stddev)
# Use the implementation from batchnorm_expander.cc in XLA
# Temporary variables have exactly the same names as in the C++ code
elements_per_feature = broadcast_in_dim(
constant(divide(size(operand), dim(operand, feature_index)),
element_type(grad_output)),
[], type(operand))
i1 = multiply(grad_output, elements_per_feature)
i2 = broadcast_in_dim(
compute_sum(grad_output, feature_index), [feature_index], type(operand))
i3 = broadcast_in_dim(
compute_sum(multiply(grad_output, centered_operand), feature_index),
[feature_index], type(operand))
i4 = multiply(i3, centered_operand)
i5 = divide(i4, add(variance_bcast, epsilon_bcast))
i6 = subtract(subtract(i1, i2), i5)
grad_operand =
multiply(divide(divide(scale_bcast, stddev), elements_per_feature), i6)
grad_scale =
compute_sum(multiply(grad_output, normalized_operand), feature_index)
grad_offset = compute_sum(grad_output, feature_index)
return grad_operand, grad_scale, grad_offset
بالنسبة للأنواع الكَمية، تنفذ
dequantize_batch_norm_grad_or_training_quantize(lambda operand, scale, mean,
variance, grad_output: batch_norm_grad(operand, scale, mean, variance,
grad_output, epsilon, feature_index), operand, scale, mean, variance,
grad_output, type(grad_operand), type(grad_scale), type(feature_index))
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق | (C1-C3)، (C5) |
(I2) | scale |
متسّع أحادي البعد لنوع النقطة العائمة أو نوع كمي بالاستناد إلى كل متسابق | (C2)، (C4)، (C5) |
(I3) | mean |
متسّع أحادي البعد لنوع النقطة العائمة أو نوع كمي بالاستناد إلى كل متسابق | (C2)، (C4) |
(I4) | variance |
متسّع أحادي البعد لنوع النقطة العائمة أو نوع كمي بالاستناد إلى كل متسابق | (C2)، (C4) |
(I5) | grad_output |
متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق | (C2)، (C3) |
(I6) | epsilon |
ثابت من النوع f32 |
|
(I7) | feature_index |
ثابت من النوع si64 |
(C1)، (C5) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
grad_operand |
متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق | (C2)، (C3) |
grad_scale |
متسّع أحادي البعد لنوع النقطة العائمة أو نوع كمي بالاستناد إلى كل متسابق | (C2)، (C4) |
grad_offset |
متسّع أحادي البعد لنوع النقطة العائمة أو نوع كمي بالاستناد إلى كل متسابق | (C2)، (C4) |
القيود
- (ج1)
0 <= feature_index < rank(operand)
. - (C2)
operand
وscale
وmean
وvariance
وgrad_output
وgrad_operand
فيgrad_scale
وgrad_offset
نفس الحالةbaseline_element_type
. - (C3)
operand
وgrad_output
وgrad_operand
لها الشكل نفسه. - (C4)
scale
وmean
وvariance
وgrad_scale
وgrad_offset
لديهم نفس الشكل. - (C5)
size(scale) = dim(operand, feature_index)
.
أمثلة
// %operand: [
// [[1.0, 2.0], [3.0, 4.0]],
// [[3.0, 4.0], [1.0, 2.0]]
// ]
// %scale: [1.0, 1.0]
// %mean: [2.0, 3.0]
// %variance: [1.0, 1.0]
// %grad_output: [
// [[0.1, 0.1], [0.1, 0.1]],
// [[0.1, 0.1], [0.1, 0.1]]
// ]
%grad_operand, %grad_scale, %grad_offset =
"stablehlo.batch_norm_grad"(%operand, %scale, %mean, %variance, %grad_output) {
epsilon = 0.0 : f32,
feature_index = 2 : i64
} : (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>, tensor<2xf64>,
tensor<2x2x2xf64>) -> (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>)
// %grad_operand: [
// [[0.0, 0.0], [0.0, 0.0]],
// [[0.0, 0.0], [0.0, 0.0]]
// ]
// %grad_scale: [0.0, 0.0]
// %grad_offset: [0.4, 0.4]
batch_norm_inference
دلالات الألفاظ
تعمل هذه القيمة على تسوية متّجه operand
في جميع السمات باستثناء السمة
دالة feature_index
وينتج عنها متسابق result
. بشكل رسمي أكثر،
يمكن التعبير عن العملية كتحليل لعمليات StableHLO الحالية
باستخدام بناء جملة بايثون على النحو التالي:
def batch_norm_inference(operand, scale, offset, mean, variance, epsilon, feature_index):
# Broadcast inputs to shape(operand)
scale_bcast = broadcast_in_dim(scale, [feature_index], type(operand))
offset_bcast = broadcast_in_dim(offset, [feature_index], type(operand))
mean_bcast = broadcast_in_dim(mean, [feature_index], type(operand))
variance_bcast = broadcast_in_dim(variance, [feature_index], type(operand))
epsilon_bcast = broadcast_in_dim(constant(epsilon, element_type(operand)), [],
type(operand))
# Perform normalization using the provided `mean` and `variance` instead of
# computing them like `batch_norm_training` does.
centered_operand = subtract(operand, mean_bcast)
stddev = sqrt(add(variance_bcast, epsilon_bcast))
normalized_operand = divide(centered_operand, stddev)
return add(multiply(scale_bcast, normalized_operand), offset_bcast)
بالنسبة للأنواع الكَمية، تنفذ
dequantize_op_quantize(lambda operand, scale, offset, mean, variance:
batch_norm_inference(operand, scale, offset, mean, variance, epsilon,
feature_index), operand, scale, offset, mean, variance, type(result))
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق | (C1-C7) |
(I2) | scale |
متسّع أحادي البعد لنوع النقطة العائمة أو نوع كمي بالاستناد إلى كل متسابق | (C2)، (C3) |
(I3) | offset |
متسّع أحادي البعد لنوع النقطة العائمة أو نوع كمي بالاستناد إلى كل متسابق | (C2)، (C4) |
(I4) | mean |
متسّع أحادي البعد لنوع النقطة العائمة أو نوع كمي بالاستناد إلى كل متسابق | (C5) |
(I5) | variance |
متسّع أحادي البعد لنوع النقطة العائمة أو نوع كمي بالاستناد إلى كل متسابق | (C2)، (C6) |
(I6) | epsilon |
ثابت من النوع f32 |
|
(I7) | feature_index |
ثابت من النوع si64 |
(C1)، (C3-C6) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق | (C2)، (C7) |
القيود
- (ج1)
0 <= feature_index < rank(operand)
. - (C2)
operand
وscale
وoffset
وmean
وvariance
وresult
لديهمbaseline_element_type
نفسها. - (C3)
size(scale) = dim(operand, feature_index)
: - (C4)
size(offset) = dim(operand, feature_index)
. - (C5)
size(mean) = dim(operand, feature_index)
. - (C6)
size(variance) = dim(operand, feature_index)
. - (C7)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// %operand: [
// [[1.0, 2.0], [3.0, 4.0]],
// [[3.0, 4.0], [1.0, 2.0]]
// ]
// %scale: [1.0, 1.0]
// %offset: [1.0, 1.0]
// %mean: [2.0, 3.0]
// %variance: [1.0, 1.0]
%result = "stablehlo.batch_norm_inference"(%operand, %scale, %offset, %mean, %variance) {
epsilon = 0.0 : f32,
feature_index = 2 : i64
} : (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>, tensor<2xf64>, tensor<2xf64>) -> tensor<2x2x2xf64>
// %result: [
// [[0.0, 0.0], [2.0, 2.0]],
// [[2.0, 2.0], [0.0, 0.0]]
// ]
batch_norm_training
دلالات الألفاظ
احتساب المتوسط والتباين في جميع السمات باستثناء feature_index
ويعمل على تسوية مقياس operand
الذي ينتج output
، batch_mean
وbatch_var
متسابق. ويمكن التعبير عن هذه العملية بشكل رسمي
إلى عمليات StableHLO الحالية باستخدام بناء جملة Python
التالي:
def compute_mean(operand, feature_index):
(sum,) = reduce(
inputs=[operand],
init_values=[constant(0, element_type(operand))],
dimensions=[i for i in range(rank(operand)) if i != feature_index],
body=lambda x, y: add(x, y))
divisor = constant(size(operand) / dim(operand, feature_index),
element_type(operand))
divisor_bcast = broadcast_in_dim(divisor, [], type(sum))
return divide(sum, divisor_bcast)
def compute_variance(operand, feature_index):
mean = compute_mean(operand, feature_index)
mean_bcast = broadcast_in_dim(mean, [feature_index], type(operand))
centered_operand = subtract(operand, mean_bcast)
return compute_mean(mul(centered_operand, centered_operand), feature_index)
def batch_norm_training(operand, scale, offset, epsilon, feature_index):
mean = compute_mean(operand, feature_index)
variance = compute_variance(operand, feature_index)
return batch_norm_inference(operand, scale, offset, mean, variance, epsilon,
feature_index),
mean, variance
بالنسبة للأنواع الكَمية، تنفذ
dequantize_batch_norm_grad_or_training_quantize(lambda operand, scale, offset:
batch_norm_training(operand, scale, offset, epsilon, feature_index), operand,
scale, offset, type(output), type(batch_mean), type(batch_var))
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق | (C1) |
(I2) | scale |
مأخذ أحادي البعد للنقطة العائمة أو الكمّي بالمقدار نفسه | (C2)، (C3) |
(I3) | offset |
مأخذ أحادي البعد للنقطة العائمة أو الكمّي بالمقدار نفسه | (C2)، (C4) |
(I4) | epsilon |
ثابت من النوع f32 |
(C1)، (C3-C6) |
(I5) | feature_index |
ثابت من النوع si64 |
(C1)، (C3-C6) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
output |
متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق | (C7) |
batch_mean |
مأخذ أحادي البعد للنقطة العائمة أو الكمّي بالمقدار نفسه | (C2)، (C5) |
batch_var |
مأخذ أحادي البعد للنقطة العائمة أو الكمّي بالمقدار نفسه | (C2)، (C6) |
القيود
- (ج1)
0 <= feature_index < rank(operand)
. - (C2)
operand
وscale
وoffset
وbatch_mean
وbatch_var
وoutput
لديهم نفسbaseline_element_type
. - (C3)
size(scale) = dim(operand, feature_index)
: - (C4)
size(offset) = dim(operand, feature_index)
. - (C5)
size(batch_mean) = dim(operand, feature_index)
. - (C6)
size(batch_var) = dim(operand, feature_index)
. - (C7)
baseline_type(output) = baseline_type(operand)
.
أمثلة
// %operand: [
// [[1.0, 2.0], [3.0, 4.0]],
// [[3.0, 4.0], [1.0, 2.0]]
// ]
// %scale: [1.0, 1.0]
// %offset: [1.0, 1.0]
%output, %batch_mean, %batch_var = "stablehlo.batch_norm_training"(%operand, %scale, %offset) {
epsilon = 0.0 : f32,
feature_index = 2 : i64
} : (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>) ->
(tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>)
// %output: [
// [[0.0, 0.0], [2.0, 2.0]],
// [[2.0, 2.0], [0.0, 0.0]]
// ]
// %batch_mean: [2.0, 3.0]
// %batch_var: [1.0, 1.0]
bitcast_convert
دلالات الألفاظ
لإجراء عملية بث بت على المغناطيس operand
وينتج موتر result
حيث يُعاد تفسير بتات متوتر operand
بالكامل باستخدام
نوع متوتر result
.
بشكل رسمي، استنادًا إلى E = element_type(operand)
وE' = element_type(result)
،
وR = rank(operand)
:
- إذا كانت
num_bits(E') < num_bits(E)
،bits(result[i0, ..., iR-1, :]) = bits(operand[i0, ..., iR-1])
- إذا كانت
num_bits(E') > num_bits(E)
،bits(result[i0, ..., iR-2]) = bits(operand[i0, ..., iR-2, :])
- إذا كانت
num_bits(E') = num_bits(E)
،bits(result[i0, ..., iR-1]) = bits(operand[i0, ..., iR-1])
تعرض الدالة bits
تمثيلاً في الذاكرة لقيمة معيّنة وسلوكها
محدد التنفيذ لأن التمثيل الدقيق لدوال تنسور
محددة التنفيذ، والتمثيل الدقيق لأنواع العناصر
محددة التنفيذ أيضًا.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتر أو متنسّر كمي | (C1-C2) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتر أو متنسّر كمي | (C1-C2) |
القيود
- (C1) بالنظر إلى
E = is_quantized(operand) ? storage_type(operand) : element_type(operand)
وE' = is_quantized(result) ? storage_type(result) : element_type(result)
وR = rank(operand)
:- إذا كانت
num_bits(E') = num_bits(E)
،shape(result) = shape(operand)
. - إذا كانت
num_bits(E') < num_bits(E)
: rank(result) = R + 1
.dim(result, i) = dim(operand, i)
لكل0 <= i < R
dim(result, R) * num_bits(E') = num_bits(E)
.- إذا كانت
num_bits(E') > num_bits(E)
: rank(result) = R - 1
.dim(result, i) = dim(operand, i)
لكل0 <= i < R
dim(operand, R - 1) * num_bits(E) = num_bits(E')
.
- إذا كانت
- (C2) إذا كانت
is_complex(operand) or is_complex(result)
، إذًاis_complex(operand) and is_complex(result)
أمثلة
// %operand: 0x0123456789ABCDEF
%result = "stablehlo.bitcast_convert"(%operand) : (tensor<f64>) -> tensor<4xf16>
// %result: [0xCDEF, 0x89AB, 0x4567, 0x0123] // little-endian representation
broadcast_in_dim
دلالات الألفاظ
توسيع أبعاد و/أو ترتيب مُعدَّل الإدخال عن طريق تكرار البيانات
في موتّر operand
وينتج موتّر result
. بشكل أكثر رسمية،
result[result_index] = operand[operand_index]
أين يوجد جميع d
في
axes(operand)
:
operand_index[d] = 0
إذاdim(operand, d) = 1
.operand_index[d] = result_index[broadcast_dimensions[d]]
بخلاف ذلك.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتر أو متنسّر كمي | (C1-C2)، (C5-C6) |
(I2) | broadcast_dimensions |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C2-C6) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتر أو متنسّر كمي | (C1)، (C3)، (C5-C6) |
القيود
- (C1)
element_type(result)
يتم تقديمها من خلال:element_type(operand)
، إذا كانت!is_per_axis_quantized(operand)
.element_type(operand)
باستثناء أنّquantization_dimension(operand)
، وscales(operand)
، وzero_points(operand)
قد يختلفان عنquantization_dimension(result)
وscales(result)
وzero_points(result)
أو الرد.
- (C2)
size(broadcast_dimensions) = rank(operand)
. - (C3)
0 <= broadcast_dimensions < rank(result)
: - (C4)
is_unique(broadcast_dimensions)
. - (C5) لكل
d
فيaxes(operand)
:dim(operand, d) = 1
أوdim(operand, d) = dim(result, broadcast_dimensions[d])
.
- (C6) إذا كانت
is_per_axis_quantized(result)
:quantization_dimension(result) = broadcast_dimensions[quantization_dimension(operand)]
.- إذا كانت القيمة
dim(operand, quantization_dimension(operand)) = 1
،scales(result)[i] = scales(operand)[0] and zero_points(result)[i] = zero_points(operand)[0] for i in range(dim(result, quantization_dimension(result)))
أمثلة
// %operand: [
// [1, 2, 3]
// ]
%result = "stablehlo.broadcast_in_dim"(%operand) {
broadcast_dimensions = array<i64: 2, 1>
} : (tensor<1x3xi32>) -> tensor<2x3x2xi32>
// %result: [
// [
// [1, 1],
// [2, 2],
// [3, 3]
// ],
// [
// [1, 1],
// [2, 2],
// [3, 3]
// ]
// ]
حافظة
دلالات الألفاظ
الحصول على ناتج من تنفيذ دالة واحدة بالضبط من branches
استنادًا إلى قيمة index
. بشكل رسمي، result = selected_branch()
حيث:
selected_branch = branches[index]
إذا0 <= index < size(branches)
.selected_branch = branches[-1]
بخلاف ذلك.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | index |
متسابق أحادي الأبعاد من النوع si32 |
|
(I2) | branches |
عدد متباين من الدوال | (C1-C4) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
results |
الأعداد المتباينة من متساعات التوتر أو العشرات الكمية أو الرموز المميزة | (C4) |
القيود
- (ج1)
0 < size(branches)
. - (C2)
input_types(branches...) = []
. - (C3)
same(output_types(branches...))
: - (C4)
type(results...) = output_types(branches[0])
.
أمثلة
// %index: -1
// %result_branch0: [0, 0]
// %result_branch1: [1, 1]
%result0, %result1 = "stablehlo.case"(%index) ({
"stablehlo.return"(%result_branch0, %result_branch0) : (tensor<2xi64>, tensor<2xi64>) -> ()
}, {
"stablehlo.return"(%result_branch1, %result_branch1) : (tensor<2xi64>, tensor<2xi64>) -> ()
}) : (tensor<i32>) -> (tensor<2xi64>, tensor<2xi64>)
// %result0: [1, 1]
// %result1: [1, 1]
cbrt
دلالات الألفاظ
لتنفيذ عملية جذر تكعيبي حسب العناصر على موتّر operand
وينتج عنه
متوتر result
حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى الأعداد العشرية:
rootn(x, 3)
من IEEE-754. - بالنسبة للأعداد المركّبة: الجذر التكعيبي المركّب.
- بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(cbrt, operand, type(result))
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
القيود
- (ج1)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// %operand: [0.0, 1.0, 8.0, 27.0]
%result = "stablehlo.cbrt"(%operand) : (tensor<4xf64>) -> tensor<4xf64>
// %result: [0.0, 1.0, 2.0, 3.0]
ceil
دلالات الألفاظ
يؤدي هذا الإجراء إلى إنشاء تسلسل هرمي من ناحية العناصر في متسابق operand
وينتج متسّر result
.
تنفيذ عملية roundToIntegralTowardPositive
من IEEE-754
المواصفات. بالنسبة للأنواع الكَمية، تنفذ
dequantize_op_quantize(ceil, operand, type(result))
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق | (C1) |
القيود
- (ج1)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// %operand: [-0.8166, -0.2530, 0.2530, 0.8166, 2.0]
%result = "stablehlo.ceil"(%operand) : (tensor<5xf32>) -> tensor<5xf32>
// %result: [-0.0, -0.0, 1.0, 1.0, 2.0]
كولسكي
دلالات الألفاظ
لحساب تحليل كولسكي لدفعة من المصفوفات.
بشكل رسمي، لجميع i
في index_space(result)
،
وresult[i0, ..., iR-3, :, :]
عبارة عن انحلال كولسكي
بالمثل a[i0, ..., iR-3, :, :]
، في شكل أي من المثلث السفلي
(إذا كانت السمة lower
هي true
) أو مصفوفة مثلثية أعلى (إذا كانت السمة lower
هي false
).
قيم الناتج في المثلث المقابل، أي المثلث العلوي المتشدد أو
وفي المقابل، يتم تحديد التنفيذ.
إذا كان هناك i
حيث لا تكون مصفوفة الإدخال ذات قيمة موجب هيرميتية
مصفوفة، فسيكون السلوك غير محدد.
بالنسبة للأنواع الكَمية، تنفذ
dequantize_op_quantize(lambda operand: cholesky(operand, lower), a, type(result))
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | a |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1-C3) |
(I2) | lower |
ثابت التوتر الثنائي الأبعاد من النوع i1 |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
القيود
- (ج1)
baseline_type(a) = baseline_type(result)
. - (C2)
2 <= rank(a)
. - (C3)
dim(a, -2) = dim(a, -1)
:
أمثلة
// %a: [
// [1.0, 2.0, 3.0],
// [2.0, 20.0, 26.0],
// [3.0, 26.0, 70.0]
// ]
%result = "stablehlo.cholesky"(%a) {
lower = true
} : (tensor<3x3xf32>) -> tensor<3x3xf64>
// %result: [
// [1.0, 0.0, 0.0],
// [2.0, 4.0, 0.0],
// [3.0, 5.0, 6.0]
// ]
مشبك
دلالات الألفاظ
يربط كل عنصر من عناصر متّجه operand
بين الحد الأدنى والأقصى
وينتج متسابق result
. بشكل رسمي، result[result_index] =
minimum(maximum(operand[result_index], min_element), max_element)
،
حيث min_element = rank(min) = 0 ? min[] : min[result_index]
،
max_element = rank(max) = 0 ? max[] : max[result_index]
بالنسبة للأنواع الكَمية،
يؤدي استخدام dequantize_op_quantize(clamp, min, operand, max, type(result))
.
يتضمن فرض ترتيب على الأعداد المركّبة دلالات مدهشة، لذا نخطط في المستقبل لإلغاء دعم الأعداد المركّبة لهذه العملية (#560).
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | min |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1)، (C3) |
(I2) | operand |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1-C4) |
(I3) | max |
متوتّر أو مستنسر كمي لكلّ متسابق | (C2)، (C3) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتّر أو مستنسر كمي لكلّ متسابق | (C4) |
القيود
- (ج1)
rank(min) = 0 or shape(min) = shape(operand)
. - (C2)
rank(max) = 0 or shape(max) = shape(operand)
. - (C3)
baseline_element_type(min) = baseline_element_type(operand) = baseline_element_type(max)
: - (C4)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// %min: [5, 10, 15]
// %operand: [3, 13, 23]
// %max: [10, 15, 20]
%result = "stablehlo.clamp"(%min, %operand, %max) : (tensor<3xi32>, tensor<3xi32>, tensor<3xi32>) -> tensor<3xi32>
// %result: [5, 13, 20]
collective_broadcast
دلالات الألفاظ
ضمن كل مجموعة عمليات في شبكة عملية StableHLO، أرسل قيمة
معامل operand
من عملية المصدر إلى العمليات المستهدفة وينتج عنه
متوتر result
تقسم هذه العملية شبكة عملية StableHLO إلى process_groups
وهي
على النحو التالي:
cross_replica(replica_groups)
إذاchannel_id <= 0
.cross_partition(replica_groups)
إذاchannel_id > 0
.
بعد ذلك، يتم منح result@process
من خلال:
operand@process_groups[i, 0]
إذا كان هناكi
بحيث تكون العملية فيprocess_groups[i]
.broadcast_in_dim(constant(is_quantized(result) ? quantize(0, element_type(result)) : 0, element_type(result)), [], type(result))
وإلا.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتّر أو مستنسر كمي لكلّ متسابق | (C3) |
(I2) | replica_groups |
عدد متغير لثوابت متسابق أحادي البعد من النوع si64 |
(C1)، (C2) |
(I3) | channel_id |
ثابت من النوع si64 |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتّر أو مستنسر كمي لكلّ متسابق | (C3) |
القيود
- (ج1)
is_unique(replica_groups)
. - (C2)
0 <= replica_groups < N
حيث يتم تعريفN
على النحو التالي:num_replicas
في حال استخدامcross_replica
.num_partitions
في حال استخدامcross_partition
.
- (C3)
type(result) = type(operand)
:
أمثلة
// num_replicas: 4
// num_partitions: 1
// %operand@(0, 0): [[1, 2]]
// %operand@(1, 0): [[3, 4]]
// %operand@(2, 0): [[5, 6]]
// %operand@(3, 0): [[7, 8]]
%result = "stablehlo.collective_broadcast"(%operand) {
replica_groups = dense<[[2, 1]]> : tensor<1x2xi64>,
channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
} : (tensor1x2xi64>) -> tensor<1x2xi64>
// %result@(0, 0): [[0, 0]]
// %result@(1, 0): [[5, 6]]
// %result@(2, 0): [[5, 6]]
// %result@(3, 0): [[0, 0]]
collective_permute
دلالات الألفاظ
داخل كل مجموعة عمليات في شبكة عملية StableHLO، يرسل قيمة
سينتج عن شدة operand
من عملية المصدر إلى العملية المستهدفة وينتج عنه
متوتر result
تقسم هذه العملية شبكة عملية StableHLO إلى process_groups
وهي
على النحو التالي:
cross_replica(source_target_pairs)
إذاchannel_id <= 0
.cross_partition(source_target_pairs)
إذاchannel_id > 0
.
بعد ذلك، يتم منح result@process
من خلال:
operand@process_groups[i, 0]
، إذا كان هناكi
بحيثprocess_groups[i, 1] = process
broadcast_in_dim(constant(is_quantized(result) ? quantize(0, element_type(result)) : 0, element_type(result)), [], type(result))
وإلا.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتّر أو مستنسر كمي لكلّ متسابق | (C5) |
(I2) | source_target_pairs |
ثابت التوتر الثنائي الأبعاد من النوع si64 |
(C1-C4) |
(I3) | channel_id |
ثابت من النوع si64 |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1) |
القيود
- (ج1)
dim(source_target_pairs, 1) = 2
. - (C2)
is_unique(source_target_pairs[:, 0])
. - (C3)
is_unique(source_target_pairs[:, 1])
: - (C4)
0 <= source_target_pairs < N
، حيث يتم تعريفN
على أنه:num_replicas
في حال استخدامcross_replica
.num_partitions
في حال استخدامcross_partition
.
- (C5)
type(result) = type(operand)
.
أمثلة
// num_replicas: 3
// num_partitions: 1
// %operand@(0, 0): [[1, 2], [3, 4]]
// %operand@(1, 0): [[5, 6], [7, 8]]
// %operand@(2, 0): [[9, 10], [11, 12]]
%result = "stablehlo.collective_permute"(%operand) {
source_target_pairs = dense<[[0, 1], [1, 2]]> : tensor<2x2xi64>,
channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
} : (tensor<2x2xi64>) -> tensor<2x2xi64>
//
// %result@(0, 0): [[0, 0], [0, 0]]
// %result@(1, 0): [[1, 2], [3, 4]]
// %result@(2, 0): [[5, 6], [7, 8]]
مقارنة
دلالات الألفاظ
يجري مقارنة بين العناصر من حيث العناصر لـ lhs
وrhs
متوترَين وفقًا لما يلي:
comparison_direction
وcompare_type
، وينتج متسابق result
.
في ما يلي قيمتا comparison_direction
وcompare_type
:
الدلالة:
بالنسبة إلى أنواع العناصر المنطقية والعناصر الصحيحة:
EQ
:lhs = rhs
.NE
:lhs != rhs
.GE
:lhs >= rhs
.GT
:lhs > rhs
.LE
:lhs <= rhs
.LT
:lhs < rhs
.
بالنسبة إلى أنواع العناصر العائمة في compare_type = FLOAT
، يتم تنفيذ العملية
عمليات IEEE-754 التالية:
EQ
:compareQuietEqual
.NE
:compareQuietNotEqual
.GE
:compareQuietGreaterEqual
.GT
:compareQuietGreater
.LE
:compareQuietLessEqual
.LT
:compareQuietLess
.
وبالنسبة إلى أنواع العناصر العائمة باستخدام compare_type = TOTALORDER
،
تستخدم الجمع بين عمليات totalOrder
وcompareQuietEqual
من
معيار IEEE-754.
بالنسبة إلى أنواع العناصر المعقّدة، تكون المقارنة اللغوية لأزواج (real, imag)
هي
تم تنفيذه باستخدام comparison_direction
وcompare_type
المقدَّمتَين.
يتضمن فرض ترتيب على الأعداد المركّبة دلالات مدهشة،
لذا نخطط في المستقبل لإلغاء دعم الأعداد المركّبة
عندما تكون قيمة comparison_direction
هي GE
أو GT
أو LE
أو LT
(#560)
بالنسبة إلى الأنواع الكَمية. يؤدي استخدام dequantize_compare(lhs, rhs,
comparison_direction)
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1-C3) |
(I2) | rhs |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1-C2) |
(I3) | comparison_direction |
تعداد EQ وNE وGE وGT وLE وLT |
|
(I4) | compare_type |
تعداد FLOAT وTOTALORDER وSIGNED وUNSIGNED |
(C3) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متّصِل من النوع المنطقي | (C2) |
القيود
- (ج1)
baseline_element_type(lhs) = baseline_element_type(rhs)
. - (C2)
shape(lhs) = shape(rhs) = shape(result)
. - (C3) يتم تعريف
compare_type
على النحو التالي:SIGNED
إذاis_signed_integer(element_type(lhs))
.UNSIGNED
إذاis_unsigned_integer(element_type(lhs)) or is_boolean(element_type(lhs))
.FLOAT
أوTOTALORDER
إذاis_float(element_type(lhs))
.FLOAT
إذاis_complex(element_type(lhs))
.
أمثلة
// %lhs: [1.0, 3.0]
// %rhs: [1.1, 2.9]
%result = "stablehlo.compare"(%lhs, %rhs) {
comparison_direction = #stablehlo<comparison_direction LT>,
compare_type = #stablehlo<comparison_type FLOAT>
} : (tensor<2xf32>, tensor<2xf32>) -> tensor<2xi1>
// %result: [true, false]
معقد
دلالات الألفاظ
تُجري تحويلًا من ناحية العناصر إلى قيمة معقدة من زوج من القيم الحقيقية
القيم التخيّلية lhs
وrhs
، وينتج تينسور result
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
متوتر من النوع f32 أو f64 |
(C1-C3) |
(I2) | rhs |
متوتر من النوع f32 أو f64 |
(C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متّصِل من النوع المعقد | (C2)، (C3) |
القيود
- (ج1)
type(lhs) = type(rhs)
. - (C2)
shape(result) = shape(lhs)
. - (C3)
element_type(result)
من النوعcomplex<E>
حيثE = element_type(lhs)
أمثلة
// %lhs: [1.0, 3.0]
// %rhs: [2.0, 4.0]
%result = "stablehlo.complex"(%lhs, %rhs) : (tensor<2xf64>, tensor<2xf64>) -> tensor<2xcomplex<f64>>
// %result: [(1.0, 2.0), (3.0, 4.0)]
مُركّب
دلالات الألفاظ
وهي عملية تتألف من عمليات (يتم تكوينها) من عمليات StableHLO الأخرى،
استعِدّ لـ inputs
وcomposite_attributes
وينتج results
. تشير رسالة الأشكال البيانية
تطبّق السمة decomposition
دلالات العملية. تشير رسالة الأشكال البيانية
يمكن استبدال العملية composite
بتحليلها بدون تغيير البرنامج.
الدلالة. وفي الحالات التي لا يوفر فيها التحلل النموذج نفسه
علم الدلالات، يُفضَّل استخدام custom_call
.
يُستخدَم الحقل version
(القيمة التلقائية لـ 0
) للدلالة على عدم ظهور
تغيير الدلالة.
مدخلات
التصنيف | الاسم | النوع |
---|---|---|
(I1) | inputs |
العدد المتغير للقيم |
(I2) | name |
ثابت من النوع string |
(I3) | composite_attributes |
قاموس السمات |
(I4) | decomposition |
ثابت من النوع string |
(I5) | version |
ثابت من النوع si32 |
المُخرَجات
الاسم | النوع |
---|---|
results |
العدد المتغير للقيم |
القيود
- (C1)
is_namespaced_op_name(name)
- (C2)
is_defined_in_parent_scope(decomposition)
- (C3)
types(inputs...) == input_types(decomposition)
- (C4)
types(results...) == output_types(decomposition)
أمثلة
%results = "stablehlo.composite"(%input0, %input1) {
name = "my_namespace.my_op",
composite_attributes = {
my_attribute = "my_value"
},
decomposition = @my_op,
version = 1 : i32
} : (tensor<f32>, tensor<f32>) -> tensor<f32>
إنشاء تسلسل
دلالات الألفاظ
يؤدي إلى إنشاء تسلسل لـ inputs
في البُعد dimension
بنفس الترتيب المحدّد.
وينتج عن ذلك مترابط result
. بشكل أكثر رسمية،
result[i0, ..., id, ..., iR-1] = inputs[k][i0, ..., kd, ..., iR-1]
، حيث:
id = d0 + ... + dk-1 + kd
.d
يساويdimension
وd0
، ... هما حجمان للأبعادd
منinputs
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | inputs |
الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق | (C1-C6) |
(I2) | dimension |
ثابت من النوع si64 |
(C2)، (C4)، (C6) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتّر أو مستنسر كمي لكلّ متسابق | (C5-C6) |
القيود
- (ج1)
same(element_type(inputs...))
. - (C2)
same(shape(inputs...))
باستثناءdim(inputs..., dimension)
. - (C3)
0 < size(inputs)
: - (C4)
0 <= dimension < rank(inputs[0])
. - (C5)
element_type(result) = element_type(inputs[0])
. - (C6)
shape(result) = shape(inputs[0])
باستثناء:dim(result, dimension) = dim(inputs[0], dimension) + ...
.
أمثلة
// %input0: [[1, 2], [3, 4], [5, 6]]
// %input1: [[7, 8]]
%result = "stablehlo.concatenate"(%input0, %input1) {
dimension = 0 : i64
} : (tensor<3x2xi64>, tensor<1x2xi64>) -> tensor<4x2xi64>
// %result: [[1, 2], [3, 4], [5, 6], [7, 8]]
الثابت
دلالات الألفاظ
لإنتاج متوتر output
من value
ثابت.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | value |
الثابت | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
output |
متوتر أو متنسّر كمي | (C1) |
القيود
- (ج1)
type(value) = type(output)
.
أمثلة
%output = "stablehlo.constant"() {
value = dense<[[0.0, 1.0], [2.0, 3.0]]> : tensor<2x2xf32>
} : () -> tensor<2x2xf32>
// %output: [[0.0, 1.0], [2.0, 3.0]]
إجراء إحالة ناجحة
دلالات الألفاظ
تُجري عملية تحويل حسب العناصر من نوع عنصر إلى آخر على
ينسور operand
وينتج متسابق result
.
بالنسبة إلى الإحالات الناجحة boolean-to-any-supported-type، تكون القيمة false
هي
وتحويلها إلى صفر، وتحويل القيمة true
إلى واحد. بالنسبة
any-supported-type-to-boolean، يتم تحويل القيمة صفر إلى
يتم تحويل القيم false
والقيم غير الصفرية إلى true
. انظر أدناه لمعرفة كيف يمكنك تحقيق ذلك
تناسب الأنواع المعقدة.
بالنسبة إلى الإحالات الناجحة التي تتضمّن integer-to-integer وinteger-to-floating-point أو floating-point-to-floating-point، إذا كان من الممكن تحديد قيمة المصدر التي يتم تمثيلها في نوع الوجهة، فإن قيمة النتيجة هي تلك الدقيقة التمثيل المناسب. وبخلاف ذلك، سيتم تحديد السلوك لاحقًا. (#180)
بالنسبة إلى الإحالات الناجحة التي تتضمّن floating-point-to-integer، يكون الجزء الكسري هو تم اقتطاعه. إذا تعذّر تمثيل القيمة المقتطعة في نوع الوجهة، يتم تحديد السلوك لاحقًا (#180).
تتبع الإحالات الناجحة التي تشتمل على معقد إلى معقد سلوك الإحالات الناجحة floating-point-to-floating-point لتحويل الأجزاء الخيالية.
بالنسبة إلى الإحالات الناجحة complex-to-any-other-type وcomplex-to-any-other-type، يتم تجاهل القيمة التخيلية المصدر أو القيمة التخيلية للوجهة بأصفار، على التوالي. ويتبع تحويل الجزء الحقيقي إحالات ناجحة النقطة العائمة.
من حيث المبدأ، يمكن لهذه العملية التعبير عن إلغاء التحديد (تحويل من
المقوّمات الكميّة إلى موتّرات عادية)، الكمي (تحويل من منتظم)
المقوّسات إلى قياسات التوتر الكمّية) وإعادة الكمّية (التحويل بين الكميّة الكمية)
الأساسية)، ولكن في الوقت الحالي، خصصنا عمليات من أجل ذلك
uniform_dequantize
لحالة الاستخدام الأولى وuniform_quantize
لحالة الاستخدام
وحالات الاستخدام الثانية والثالثة. في المستقبل، قد يتم دمج هاتين العملتين
إلى convert
(#1576).
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متعدّد | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متعدّد | (C1) |
القيود
- (ج1)
shape(operand) = shape(result)
.
أمثلة
// %operand: [-1, 0, 1]
%result = "stablehlo.convert"(%operand) : (tensor<3xi64>) -> tensor<3xcomplex<f64>>
// %result: [(-1.0, 0.0), (0.0, 0.0), (1.0, 0.0)]
التفاف
دلالات الألفاظ
لحساب قيمة المنتجات النقطية بين نوافذ lhs
وشرائح rhs
، ويتم الحصول على
result
يوضّح المخطّط التالي طريقة حساب العناصر في result
من
lhs
وrhs
باستخدام مثال ملموس.
من الناحية الرسمية، ننصحك بإعادة صياغة الإدخالات من حيث lhs
.
ولتتمكّن من التعبير عن مهلة lhs
:
lhs_window_dimensions = lhs_shape(dim(lhs, input_batch_dimension), dim(rhs, kernel_spatial_dimensions), dim(lhs, input_feature_dimension))
.lhs_window_strides = lhs_shape(1, window_strides, 1)
.lhs_padding = lhs_shape([0, 0], padding, [0, 0])
.lhs_base_dilations = lhs_shape(1, lhs_dilation, 1)
.lhs_window_dilations = lhs_shape(1, rhs_dilation, 1)
.
تستخدم عملية إعادة الصياغة هذه الدوال المساعدة التالية:
lhs_shape(n, hw, c) = permute([n] + hw + [c], [input_batch_dimension] + input_spatial_dimensions + [input_feature_dimension])
.result_shape(n1, hw, c1) = permute([n1] + hw + [c1], [output_batch_dimension] + output_spatial_dimensions + [output_feature_dimension])
.permute([j0, j1, ..., jR-1], permutation) = [i0, i1, ..., iR-1]
حيثj[d] = i[permutation[d]]
.
إذا كان feature_group_count = 1
وbatch_group_count = 1
، يتم ذلك مع جميع
output_spatial_index
في index_space(dim(result, output_spatial_dimensions...))
،
result[result_shape(:, output_spatial_index, :)] = dot_product
حيث:
padding_value = constant(0, element_type(lhs))
.padded_lhs = pad(lhs, padding_value, lhs_padding[:, 0], lhs_padding[:, 1], lhs_base_dilations - 1)
.lhs_window_start = lhs_shape(0, output_spatial_index, 0) * lhs_window_strides
.lhs_window = slice(padded_lhs, lhs_window_start, lhs_window_start + lhs_window_dimensions, lhs_window_dilations)
.reversed_lhs_window = reverse(lhs_window, [input_spatial_dimensions[dim] for dim in range(size(window_reversal)) if window_reversal[dim] = true])
يبدو أنّ هذه الميزة غير مستخدَمة، لذا نخطّط لإزالتها في المستقبل. (#1181).dot_product = dot_general(reversed_lhs_window, rhs, lhs_batching_dimensions=[], lhs_contracting_dimensions=input_spatial_dimensions + [input_feature_dimension], rhs_batching_dimensions=[], rhs_contracting_dimensions=kernel_spatial_dimensions + [kernel_input_feature_dimension])
.
إذا كانت feature_group_count > 1
:
lhses = split(lhs, feature_group_count, input_feature_dimension)
.rhses = split(rhs, feature_group_count, kernel_output_feature_dimension)
.results... = convolution(lhses..., rhses..., ..., feature_group_count=1, ...)
.result = concatenate(results, output_feature_dimension)
.
إذا كانت batch_group_count > 1
:
lhses = split(lhs, batch_group_count, input_batch_dimension)
.rhses = split(rhs, batch_group_count, kernel_output_feature_dimension)
.results... = convolution(lhses..., rhses..., ..., batch_group_count=1, ...)
.result = concatenate(results, output_feature_dimension)
بالنسبة إلى الأنواع المحدَّدة الكمية، يتم تنفيذ dequantize_op_quantize(
lambda lhs, rhs: convolution(lhs, rhs, window_strides, padding,
lhs_dilation, rhs_dilation, window_reversal, input_batch_dimension,
input_feature_dimension, input_spatial_dimensions,
kernel_input_feature_dimension, kernel_output_feature_dimension,
kernel_spatial_dimensions, output_batch_dimension,
output_feature_dimension, output_spatial_dimensions,
feature_group_count, batch_group_count, precision_config), lhs, rhs,
type(result))
.
بالنسبة إلى الأنواع الكمية المختلطة، تحقّق قيمة hybrid_dequantize_then_op(
lambda lhs, rhs: convolution(lhs, rhs, window_strides, padding,
lhs_dilation, rhs_dilation, window_reversal, input_batch_dimension,
input_feature_dimension, input_spatial_dimensions,
kernel_input_feature_dimension, kernel_output_feature_dimension,
kernel_spatial_dimensions, output_batch_dimension,
output_feature_dimension, output_spatial_dimensions,
feature_group_count, batch_group_count, precision_config), lhs, rhs)
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1)، (C10-C11)، (C14) (C25)، (C27-C28)، (C31-C32)، (C34) |
(I2) | rhs |
متوتر أو متنسّر كمي | (C1)، (C14-C16)، (C25)، (C27-C29)، (C31-C34) |
(I3) | window_strides |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C2-C3)، (C25) |
(I4) | padding |
ثابت التوتر الثنائي الأبعاد من النوع si64 |
(C4)، (C25) |
(I5) | lhs_dilation |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C5-C6)، (C25) |
(I6) | rhs_dilation |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C7-C8)، (C25) |
(I7) | window_reversal |
ثابت التوتر ذو البعد الواحد من النوع i1 |
(C9) |
(I8) | input_batch_dimension |
ثابت من النوع si64 |
(C10)، (C13)، (C25) |
(I9) | input_feature_dimension |
ثابت من النوع si64 |
(C11)، (C13-C14) |
(I10) | input_spatial_dimensions |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C12)، (C13)، (C25) |
(I11) | kernel_input_feature_dimension |
ثابت من النوع si64 |
(C14)، (C18) |
(I12) | kernel_output_feature_dimension |
ثابت من النوع si64 |
(C15-C16)، (C18)، (C25)، (C29) |
(I13) | kernel_spatial_dimensions |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C17-C18)، (C25) |
(I14) | output_batch_dimension |
ثابت من النوع si64 |
(C20)، (C25) |
(I15) | output_feature_dimension |
ثابت من النوع si64 |
(C20)، (C25)، (C30) |
(I16) | output_spatial_dimensions |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C19-C20)، (C25) |
(I17) | feature_group_count |
ثابت من النوع si64 |
(C11)، (C14)، (C16)، (C21)، (C23) |
(I18) | batch_group_count |
ثابت من النوع si64 |
(C10)، (C15)، (C22)، (C23)، (C25) |
(I19) | precision_config |
اختلاف في عدد التعدادات للقيم DEFAULT وHIGH وHIGHEST |
(C24) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتر أو متنسّر كمي | (C25-C28)، (C30)، (C32-34) |
القيود
- (ج1)
N = rank(lhs) = rank(rhs)
. - (C2)
size(window_strides) = N - 2
. - (C3)
0 < window_strides
: - (C4)
shape(padding) = [N - 2, 2]
. - (C5)
size(lhs_dilation) = N - 2
. - (C6)
0 < lhs_dilation
. - (C7)
size(rhs_dilation) = N - 2
. - (C8)
0 < rhs_dilation
. - (C9)
size(window_reversal) = N - 2
. - (C10)
dim(lhs, input_batch_dimension) % batch_group_count = 0
. - (C11)
dim(lhs, input_feature_dimension) % feature_group_count = 0
. - (C12)
size(input_spatial_dimensions) = N - 2
. - (C13) بالنظر إلى
input_dimensions = [input_batch_dimension] + input_spatial_dimensions + [input_feature_dimension]
:is_unique(input_dimensions)
.0 <= input_dimensions < N
.
- (C14)
dim(rhs, kernel_input_feature_dimension) = dim(lhs, input_feature_dimension) / feature_group_count
. - (C15)
dim(rhs, kernel_output_feature_dimension) % batch_group_count = 0
. - (C16)
dim(rhs, kernel_output_feature_dimension) % feature_group_count = 0
. - (C17)
size(kernel_spatial_dimensions) = N - 2
. - (C18) نظرًا إلى
kernel_dimensions = kernel_spatial_dimensions + [kernel_input_feature_dimension] + [kernel_output_feature_dimension]
:is_unique(kernel_dimensions)
.0 <= kernel_dimensions < N
.
- (C19)
size(output_spatial_dimensions) = N - 2
. - (C20) بالنظر إلى
output_dimensions = [output_batch_dimension] + output_spatial_dimensions + [output_feature_dimension]
:is_unique(output_dimensions)
.0 <= output_dimensions < N
.
- (C21)
0 < feature_group_count
. - (C22)
0 < batch_group_count
. - (C23)
feature_group_count = 1 or batch_group_count = 1
. - (C24)
size(precision_config) = 2
. - (C25) يتم تعريف
dim(result, result_dim)
على النحو التالي:dim(lhs, input_batch_dimension) / batch_group_count
إذاresult_dim = output_batch_dimension
.dim(rhs, kernel_output_feature_dimension)
إذاresult_dim = output_feature_dimension
.num_windows
بخلاف ذلك، حيث:output_spatial_dimensions[spatial_dim] = result_dim
.lhs_dim = input_spatial_dimensions[spatial_dim]
.rhs_dim = kernel_spatial_dimensions[spatial_dim]
.dilated_input_shape[lhs_dim] = dim(lhs, lhs_dim) = 0 ? 0 : (dim(lhs, lhs_dim) - 1) * lhs_dilation[spatial_dim] + 1
.padded_input_shape[lhs_dim] = padding[spatial_dim, 0] + dilated_input_shape[lhs_dim] + padding[spatial_dim, 1]
.dilated_window_shape[lhs_dim] = dim(rhs, rhs_dim) = 0 ? 0 : (dim(rhs, rhs_dim) - 1) * rhs_dilation[spatial_dim] + 1
.is_empty_window[lhs_dim] = padded_input_shape[lhs_dim] = 0 || dilated_window_shape[lhs_dim] > padded_input_shape[lhs_dim]
.num_windows = is_empty_window[lhs_dim] ? 0 : floor((padded_input_shape[lhs_dim] - dilated_window_shape[lhs_dim]) / window_strides[spatial_dim]) + 1
.
- (C26)
rank(result) = N
. - إذا كانت العملية تستخدم موتّرات غير كَمية:
- (C27)
element_type(lhs) = element_type(rhs) = element_type(result)
.
- (C27)
- إذا كانت العملية تستخدم موتّرات كميّة:
- (C28)
is_quantized(lhs) = is_quantized(result) and is_quantized(rhs)
. - (C29) إذا كانت
is_per_axis_quantized(rhs)
: ثمquantization_dimension(rhs) = kernel_output_feature_dimension
. - (C30) إذا كانت
is_per_axis_quantized(result)
، إذًاquantization_dimension(result) = output_feature_dimension
- إذا كانت
is_quantized(lhs)
: - (C31)
storage_type(lhs) = storage_type(rhs)
. - (C32)
expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
. - (C33) إذا كانت
is_per_tensor_quantized(rhs)
، يتم عندها:is_per_tensor_quantized(result)
- إذا كانت
!is_quantized(lhs)
: - (C34)
element_type(lhs) = expressed_type(rhs) = element_type(result)
.
- (C28)
أمثلة
// %lhs: [[
// [
// [1], [2], [5], [6]
// ],
// [
// [3], [4], [7], [8]
// ],
// [
// [10], [11], [14], [15]
// ],
// [
// [12], [13], [16], [17]
// ]
// ]]
//
// %rhs: [
// [[[1]], [[1]], [[1]]],
// [[[1]], [[1]], [[1]]],
// [[[1]], [[1]], [[1]]]
// ]
%result = "stablehlo.convolution"(%lhs, %rhs) {
window_strides = array<i64: 4, 4>,
padding = dense<0> : tensor<2x2xi64>,
lhs_dilation = array<i64: 2, 2>,
rhs_dilation = array<i64: 1, 1>,
window_reversal = array<i1: false, false>,
// In the StableHLO dialect, dimension numbers are encoded via:
// `[<input dimensions>]x[<kernel dimensions>]->[output dimensions]`.
// "b" is batch dimension, "f" is feature dimension,
// "i" is input feature dimension, "o" is output feature dimension,
// "0/1/etc" are spatial dimensions.
dimension_numbers = #stablehlo.conv<[b, 0, 1, f]x[0, 1, i, o]->[b, 0, 1, f]>,
batch_group_count = 1 : i64,
feature_group_count = 1 : i64,
precision_config = [#stablehlo<precision DEFAULT>, #stablehlo<precision DEFAULT>]
} : (tensor<1x4x4x1xi64>, tensor<3x3x1x1xi64>) -> tensor<1x2x2x1xi64>
// %result: [[
// [[10], [26]],
// [[46], [62]]
// ]]
جيب التمام
دلالات الألفاظ
لتنفيذ عملية جيب التمام من حيث العناصر في موتر operand
وينتج عن ذلك
متوتر result
حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى الأعداد العشرية:
cos
من IEEE-754. - للأعداد المركّبة: جيب التمام المعقد.
- بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(cosine, operand, type(result))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
القيود
- (ج1)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// %operand: [
// [0.0, 1.57079632], // [0, pi/2]
// [3.14159265, 4.71238898] // [pi, 3pi/2]
// ]
%result = "stablehlo.cosine"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[1.0, 0.0], [-1.0, 0.0]]
count_leading_zeros
دلالات الألفاظ
تؤدي إلى إجراء العدد من حيث العناصر في عدد وحدات البت البادئة الصفرية في operand
.
متنسورة وينتج عنها متسابق result
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتر لنوع العدد الصحيح | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتر لنوع العدد الصحيح | (C1) |
القيود
- (ج1)
type(operand) = type(result)
.
أمثلة
// %operand: [[0, 1], [128, -1]]
%result = "stablehlo.count_leading_zeros"(%operand) : (tensor<2x2xi64>) -> tensor<2x2xi64>
// %result: [[64, 63], [56, 0]]
custom_call
دلالات الألفاظ
تتضمن عملية محددة للتنفيذ call_target_name
والتي
inputs
وcalled_computations
وينتج results
. has_side_effect
,
قد يتم استخدام backend_config
وapi_version
لتوفير خيارات إضافية
بيانات التعريف المحددة للتنفيذ.
في الوقت الحالي، تحتوي هذه العملية على مجموعة غير منظمة إلى حد ما من بيانات التعريف التي تعكس التطور العضوي لعملية نظيرتها في المحول البرمجي لـ XLA. نخطّط لتوحيد هذه البيانات الوصفية في المستقبل (#741)
مدخلات
التصنيف | الاسم | النوع |
---|---|---|
(I1) | inputs |
العدد المتغير للقيم |
(I2) | call_target_name |
ثابت من النوع string |
(I3) | has_side_effect |
ثابت من النوع i1 |
(I4) | backend_config |
ثابت من النوع string أو قاموس السمات |
(I5) | api_version |
ثابت من النوع si32 |
(I6) | called_computations |
العدد المتنوع للثوابت من النوع string |
المُخرَجات
الاسم | النوع |
---|---|
results |
العدد المتغير للقيم |
أمثلة
%results = "stablehlo.custom_call"(%input0) {
call_target_name = "foo",
has_side_effect = false,
backend_config = {bar = 42 : i32},
api_version = 4 : i32,
called_computations = [@foo]
} : (tensor<f64>) -> tensor<f64>
قسمة
دلالات الألفاظ
لإجراء عملية قسمة من العناصر المقابلة في الصفيفتين lhs
والقاسم rhs
لنقاط القوة
نحصل على متوتر result
. حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى الأعداد الصحيحة: قسمة الأعداد الصحيحة التي تنتج القسمة الجبرية مع أي تم تجاهل الجزء الجزئي.
- بالنسبة إلى الأعداد العشرية:
division
من IEEE-754. - بالنسبة إلى الأعداد المركّبة: القسمة المركّبة.
- بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(divide, lhs, rhs, type(result))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المتسابق الكمي لكل متسابق | (C1) |
(I2) | rhs |
موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المتسابق الكمي لكل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المنزِّع الكمي لكل متسابق | (C1) |
القيود
- (ج1)
baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)
.
أمثلة
// %lhs: [17.1, -17.1, 17.1, -17.1]
// %rhs: [3.0, 3.0, -3.0, -3.0]
%result = "stablehlo.divide"(%lhs, %rhs) : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
// %result: [5.66666651, -5.66666651, -5.66666651, 5.66666651]
dot_general
دلالات الألفاظ
لحساب قيمة المنتجات النقطية بين شرائح lhs
وشرائح rhs
، وينتج عن ذلك
متوتر result
بشكل رسمي، result[result_index] = dot_product
، حيث:
lhs_result_dimensions = [d for d in axes(lhs) and d not in lhs_batching_dimensions and d not in lhs_contracting_dimensions]
.rhs_result_dimensions = [d for d in axes(rhs) and d not in rhs_batching_dimensions and d not in rhs_contracting_dimensions]
.result_batching_index + result_lhs_index + result_rhs_index = result_index
حيثsize(result_batching_index) = size(lhs_batching_dimensions)
،size(result_lhs_index) = size(lhs_result_dimensions)
وsize(result_rhs_index) = size(rhs_result_dimensions)
transposed_lhs = transpose(lhs, lhs_batching_dimensions + lhs_result_dimensions + lhs_contracting_dimensions)
.transposed_lhs_slice = slice(transposed_lhs, result_batching_index + result_lhs_index + [:, ..., :])
.reshaped_lhs_slice = reshape(transposed_lhs_slice, dims(lhs, lhs_contracting_dimensions))
.transposed_rhs = transpose(rhs, rhs_batching_dimensions + rhs_result_dimensions + rhs_contracting_dimensions)
.transposed_rhs_slice = slice(transposed_rhs, result_batching_index + result_rhs_index + [:, ..., :])
.reshaped_rhs_slice = reshape(transposed_rhs_slice, dims(rhs, rhs_contracting_dimensions))
.dot_product = reduce( inputs=[multiply(reshaped_lhs_slice, reshaped_rhs_slice)], init_values=[constant(0, element_type(result))], dimensions=range(size(lhs_contracting_dimensions)), body=lambda x, y: add(x, y))
بالنسبة إلى الأنواع المحدَّدة الكمية، يتم تنفيذ dequantize_op_quantize(
lambda lhs, rhs: dot_general(lhs, rhs, lhs_batching_dimensions,
rhs_batching_dimensions, lhs_contracting_dimensions,
rhs_contracting_dimensions, precision_config), lhs, rhs, type(result))
.
بالنسبة إلى الأنواع الكمية المختلطة، تحقّق قيمة hybrid_dequantize_then_op(
lambda lhs, rhs: dot_general(lhs, rhs, lhs_batching_dimensions,
rhs_batching_dimensions, lhs_contracting_dimensions,
rhs_contracting_dimensions, precision_config), lhs, rhs)
.
يتحكّم precision_config
في الموازنة بين السرعة والدقة
العمليات الحسابية على الواجهات الخلفية للمسرِّع. يمكن أن يكون هذا أيًا مما يلي (في صفحة
فإن دلالات قيم التعداد هذه غير محدّدة بشكل كافٍ، ولكننا
تخطط لمعالجة هذا الأمر في
#755):
DEFAULT
: أسرع عملية حسابية، لكن التقريب الأقل دقة الرقم الأصلي.HIGH
: عملية حسابية أبطأ، لكنّها تقريبية أكثر دقة الرقم الأصلي.HIGHEST
: أبطأ عملية حسابية، ولكنها الأكثر دقة لتقريب الرقم الأصلي.
تحدّد السمة DotAlgorithm
السمات الرئيسية للخوارزمية المستخدَمة لتنفيذ
عملية النقطة، والتي تحدد أيضًا الدقة. إذا كانت تصنيف الخوارزمية
ضبط الحقل، يجب أن تكون قيمة precision_config
هي DEFAULT
. DotAlgorithms
ليس لها قيمة تلقائية، لأنّه يتم تنفيذ المَعلمات التلقائية
محددة. وبناءً على ذلك، يمكن ضبط جميع حقول خوارزمية النقاط على None
لتحديد
خوارزمية النقاط الفارغة التي ستستخدم القيمة precision_config
بدلاً من ذلك.
تتضمّن DotAlgorithm
حقول ما يلي:
lhs_precision_type
وrhs_precision_type
، والدقة التي تلاحظها LHS يتم تقريب RHS للعملية إلى. تكون أنواع الدقة مستقلّة عن أنواع التخزين للمدخلات والمخرجات.accumulation_type
الدقة المستخدمة في التراكم.lhs_component_count
وrhs_component_count
وnum_primitive_operations
عندما نقوم بخوارزمية تفكيك LHS و/أو RHS إلى عدة مكونات ويقوم بتنفيذ العديد من "الأساسيات" العمليات النقطية على تلك القيم - عادةً لمحاكاة دقة أعلى (على سبيل المثال الاستفادة من نوع بيانات bfloat16 للذكاء الاصطناعي لإجراء عمليات حسابية عالية الدقة: bf16_6x tf32_3x، إلخ). بالنسبة للخوارزميات التي لا تحتوي على أي تفكيك، فإن هذه القيم يجب ضبطها على1
.allow_imprecise_accumulation
لتحديد ما إذا كان التجميع بدقة أقل أم لا مسموح به لبعض الخطوات (مثلCUBLASLT_MATMUL_DESC_FAST_ACCUM
).
مثال على سمات DotAlgorithm
:
// Inputs are casted to tf32, and then accumulated in f32:
{lhs_precision_type = tf32,
rhs_precision_type = tf32,
accumulation_type = f32,
lhs_component_count = 1,
rhs_component_count = 1,
num_primitive_operations = 1,
allow_imprecise_accumulation = false}
// bf16_6x: each input is decomposed to 3 bf16 components, then 6 dot operations are done on those components, and the result is accumulated in f32.
{lhs_precision_type = bf16,
rhs_precision_type = bf16,
accumulation_type = f32,
lhs_component_count = 3,
rhs_component_count = 3,
num_primitive_operations = 6,
allow_imprecise_accumulation = false}
// Inputs are (casted to) f8e5m2, and we accumulate in f32, but for some steps we may accumulate in lower precision.
{lhs_precision_type = f8e5m2,
rhs_precision_type = f8e5m2,
accumulation_type = f32,
lhs_component_count = 1,
rhs_component_count = 1,
num_primitive_operations = 1,
allow_imprecise_accumulation = true}
والأمر متروك لعمليات التنفيذ لتحديد المجموعات المتوافقة. ضِمن بشكل عام، لا يمكن ضمان توافُق كل خوارزمية مع كل خوارزمية نوع مسرِّعة البيانات من قِبل مستهلك StableHLO. إذا لم تكن خوارزمية معينة دعمها، فينبغي رفع الخطأ بدلاً من الرجوع إلى البديل. سيوفر التحقق من StableHLO أفضل جهد للتحقق، لمنع الخوارزميات غير المعروفة أنّها متوافقة مع أي جهاز.
الاطّلاع على xla_data.proto > Algorithm
لبعض قيم الخوارزمية المتوافقة. تسجل التذكرة رقم 2483 الخطة لإنشاء
مستند مركزي على الخوارزميات المتوافقة من خلال الخلفية.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
متوتّر أو مستنسر كمي لكلّ متسابق | (C5-C6)، (C9-C10)، (C12-C14)، (C17-C18)، (C20) |
(I2) | rhs |
متوتر أو متنسّر كمي | (C7-C10)، (C12-C20) |
(I3) | lhs_batching_dimensions |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C1)، (C3)، (C5)، (C9)، (C12) |
(I4) | rhs_batching_dimensions |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C1)، (C4)، (C7)، (C9) |
(I5) | lhs_contracting_dimensions |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C2)، (C3)، (C6)، (C10) |
(I6) | rhs_contracting_dimensions |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C2)، (C4)، (C8)، (C10)، (C16) |
(I7) | precision_config |
اختلاف في عدد التعدادات للقيم DEFAULT وHIGH وHIGHEST |
(C11)، (C21) |
(I8) | lhs_precision_type |
FloatType أو TensorFloat32 | (C21) |
(I9) | rhs_precision_type |
FloatType أو TensorFloat32 | (C21) |
(I10) | accumulation_type |
FloatType أو TensorFloat32 | (C21) |
(I11) | lhs_component_count |
ثابت من النوع si32 |
(C21)، (C22) |
(I12) | rhs_component_count |
ثابت من النوع si32 |
(C21)، (C23) |
(I13) | num_primitive_operations |
ثابت من النوع si32 |
(C21)، (C24) |
(I14) | allow_imprecise_accumulation |
ثابت من النوع bool |
(C21) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتر أو متنسّر كمي | (C12)، (C14)، (C18-C20) |
القيود
- (ج1)
size(lhs_batching_dimensions) = size(rhs_batching_dimensions)
. - (C2)
size(lhs_contracting_dimensions) = size(rhs_contracting_dimensions)
. - (C3)
is_unique(lhs_batching_dimensions + lhs_contracting_dimensions)
: - (C4)
is_unique(rhs_batching_dimensions + rhs_contracting_dimensions)
. - (C5)
0 <= lhs_batching_dimensions < rank(lhs)
. - (C6)
0 <= lhs_contracting_dimensions < rank(lhs)
. - (C7)
0 <= rhs_batching_dimensions < rank(rhs)
. - (C8)
0 <= rhs_contracting_dimensions < rank(rhs)
. - (C9)
dim(lhs, lhs_batching_dimensions...) = dim(rhs, rhs_batching_dimensions...)
. - (C10)
dim(lhs, lhs_contracting_dimensions...) = dim(rhs, rhs_contracting_dimensions...)
. - (C11)
size(precision_config) = 2
. - (C12)
shape(result) = dim(lhs, lhs_batching_dimensions) + dim(lhs, lhs_result_dimensions) + dim(rhs, rhs_result_dimensions)
. - إذا كانت العملية تستخدم موتّرات غير كَمية:
- (C13)
element_type(lhs) = element_type(rhs)
.
- (C13)
- إذا كانت العملية تستخدم موتّرات كميّة:
- (C14)
is_quantized(lhs) = is_quantized(result) and is_quantized(rhs)
. - (C15)
zero_points(rhs) = 0
. - (C16) إذا كانت
is_per_axis_quantized(rhs)
، إذًاquantization_dimension(rhs)
ليس فيrhs_contracting_dimensions
. - إذا كانت
is_quantized(lhs)
: - (C17)
storage_type(lhs) = storage_type(rhs)
. - (C18)
expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
. - (C19) إذا كانت
is_per_tensor_quantized(rhs)
، يتم عندها:is_per_tensor_quantized(result)
- إذا كانت
!is_quantized(lhs)
: - (C20)
element_type(lhs) = expressed_type(rhs) = element_type(result)
.
- (C14)
- إذا كانت
!is_empty_algorithm(lhs_precision_type, rhs_precision_type, accumulation_type, lhs_component_count, rhs_component_count, num_primitive_operations allow_imprecise_accumulation)
:- (C21)
precision_config... = DEFAULT
. - (C22)
0 < lhs_component_count
. - (C23)
0 < rhs_component_count
. - (C24)
0 < num_primitive_operations
.
- (C21)
أمثلة
// %lhs: [
// [[1, 2],
// [3, 4]],
// [[5, 6],
// [7, 8]]
// ]
// %rhs: [
// [[1, 0],
// [0, 1]],
// [[1, 0],
// [0, 1]]
// ]
%result = "stablehlo.dot_general"(%lhs, %rhs) {
dot_dimension_numbers = #stablehlo.dot<
lhs_batching_dimensions = [0],
rhs_batching_dimensions = [0],
lhs_contracting_dimensions = [2],
rhs_contracting_dimensions = [1]
>,
precision_config = [#stablehlo<precision DEFAULT>, #stablehlo<precision DEFAULT>],
algorithm = #stablehlo.dot_algorithm<
lhs_precision_type = tf32,
rhs_precision_type = tf32,
accumulation_type = f32,
lhs_component_count = 1,
rhs_component_count = 1,
num_primitive_operations = 1,
allow_imprecise_accumulation = false
>
} : (tensor<2x2x2xi64>, tensor<2x2x2xi64>) -> tensor<2x2x2xi64>
// %result: [
// [[1, 2],
// [3, 4]],
// [[5, 6],
// [7, 8]]
// ]
dynamic_broadcast_in_dim
دلالات الألفاظ
هذه العملية مطابقة من الناحية الوظيفية
broadcast_in_dim
ولكن يتم تحديد شكل النتيجة ديناميكيًا عبر output_dimensions
.
تقبل العملية أيضًا السمتين الاختياريتين known_expanding_dimensions
وknown_non_expanding_dimensions
للتعبير عن المعرفة الثابتة حول السلوك المتوسع للأبعاد.
وفي حال عدم تحديد هذه السمة، من المفترض أن تكون جميع السمات قابلة للتوسيع.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتر أو متنسّر كمي | (C1-C2)، (C5-C6)، (C9) |
(I2) | output_dimensions |
متوتر ذو البعد الواحد لنوع العدد الصحيح | (C7) |
(I3) | broadcast_dimensions |
متسّع ثابت البعد الأحادي لنوع العدد الصحيح | (C2-C6) |
(I4) | known_expanding_dimensions |
متسّع ثابت البعد الأحادي لنوع العدد الصحيح | (C8-C9) |
(I5) | known_non_expanding_dimensions |
متسّع ثابت البعد الأحادي لنوع العدد الصحيح | (C8-C9) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتر أو متنسّر كمي | (C1)، (C3)، (C5-C7) |
القيود
- (C1)
element_type(result)
يتم تقديمها من خلال:element_type(operand)
، إذا كانت!is_per_axis_quantized(operand)
.element_type(operand)
باستثناء أنّquantization_dimension(operand)
، وscales(operand)
، وzero_points(operand)
قد يختلفان عنquantization_dimension(result)
وscales(result)
وzero_points(result)
أو الرد.
- (C2)
size(broadcast_dimensions) = rank(operand)
. - (C3)
0 <= broadcast_dimensions < rank(result)
: - (C4)
is_unique(broadcast_dimensions)
. - (C5) لكل
d
فيaxes(operand)
:dim(operand, d) = 1
أوdim(operand, d) = dim(result, broadcast_dimensions[d])
.
- (C6) إذا كانت
is_per_axis_quantized(result)
:quantization_dimension(result) = broadcast_dimensions[quantization_dimension(operand)]
.- إذا كانت القيمة
dim(operand, quantization_dimension(operand)) = 1
،scales(result)[i] = scales(operand)[0] and zero_points(result)[i] = zero_points(operand)[0] for i in range(dim(result, quantization_dimension(result)))
- (C7)
size(output_dimensions) = rank(result)
. - (C8)
is_unique(known_expanding_dimensions + known_non_expanding_dimensions)
. - (C9)
0 <= known_expanding_dimensions < rank(operand)
. - (C10)
0 <= known_non_expanding_dimensions < rank(operand)
.
أمثلة
// %operand: [
// [1, 2, 3]
// ]
%operand = stablehlo.constant dense<[[1, 2, 3]]> : tensor<1x3xi64>
%output_dimensions = stablehlo.constant dense<[2, 3, 2]> : tensor<3xi64>
%result = "stablehlo.dynamic_broadcast_in_dim"(%operand, %output_dimensions) {
broadcast_dimensions = array<i64: 2, 1>,
known_expanding_dimensions = array<i64: 0>,
known_non_expanding_dimensions = array<i64: 1>
} : (tensor<1x3xi64>, tensor<3xi64>) -> tensor<2x3x2xi64>
// %result: [
// [
// [1, 1],
// [2, 2],
// [3, 3]
// ],
// [
// [1, 1],
// [2, 2],
// [3, 3]
// ]
// ]
dynamic_conv
دلالات الألفاظ
هذه العملية مطابقة من الناحية الوظيفية
الالتفاف
هذه، ولكن يتم تحديد المساحة المتروكة ديناميكيًا عبر padding
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1)، (C10-C11)، (C14) (C25)، (C26-C27)، (C30-C31)، (C33) |
(I2) | rhs |
متوتر أو متنسّر كمي | (C1)، (C14-C16)، (C26-C28)، (C30-C33) |
(I3) | padding |
متين ثنائي الأبعاد لنوع العدد الصحيح | (C4) |
(I4) | window_strides |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C2-C3) |
(I5) | lhs_dilation |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C5-C6) |
(I6) | rhs_dilation |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C7-C8) |
(I7) | window_reversal |
ثابت التوتر ذو البعد الواحد من النوع i1 |
(C9) |
(I8) | input_batch_dimension |
ثابت من النوع si64 |
(C10)، (C13) |
(I9) | input_feature_dimension |
ثابت من النوع si64 |
(C11)، (C13-C14) |
(I10) | input_spatial_dimensions |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C12)، (C13) |
(I11) | kernel_input_feature_dimension |
ثابت من النوع si64 |
(C14)، (C18) |
(I12) | kernel_output_feature_dimension |
ثابت من النوع si64 |
(C15-C16)، (C18)، (C28) |
(I13) | kernel_spatial_dimensions |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C17-C18) |
(I14) | output_batch_dimension |
ثابت من النوع si64 |
(C20) |
(I15) | output_feature_dimension |
ثابت من النوع si64 |
(C20)، (C29) |
(I16) | output_spatial_dimensions |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C19-C20) |
(I17) | feature_group_count |
ثابت من النوع si64 |
(C11)، (C14)، (C16)، (C21)، (C23) |
(I18) | batch_group_count |
ثابت من النوع si64 |
(C10)، (C15)، (C22)، (C23) |
(I19) | precision_config |
اختلاف في عدد التعدادات للقيم DEFAULT وHIGH وHIGHEST |
(C24) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتر أو متنسّر كمي | (C25-C27)، (C29)، (C31-C33) |
القيود
- (ج1)
N = rank(lhs) = rank(rhs)
. - (C2)
size(window_strides) = N - 2
. - (C3)
0 < window_strides
: - (C4)
shape(padding) = [N - 2, 2]
. - (C5)
size(lhs_dilation) = N - 2
. - (C6)
0 < lhs_dilation
. - (C7)
size(rhs_dilation) = N - 2
. - (C8)
0 < rhs_dilation
. - (C9)
size(window_reversal) = N - 2
. - (C10)
dim(lhs, input_batch_dimension) % batch_group_count = 0
. - (C11)
dim(lhs, input_feature_dimension) % feature_group_count = 0
. - (C12)
size(input_spatial_dimensions) = N - 2
. - (C13) بالنظر إلى
input_dimensions = [input_batch_dimension] + input_spatial_dimensions + [input_feature_dimension]
:is_unique(input_dimensions)
.0 <= input_dimensions < N
.
- (C14)
dim(rhs, kernel_input_feature_dimension) = dim(lhs, input_feature_dimension) / feature_group_count
. - (C15)
dim(rhs, kernel_output_feature_dimension) % batch_group_count = 0
. - (C16)
dim(rhs, kernel_output_feature_dimension) % feature_group_count = 0
. - (C17)
size(kernel_spatial_dimensions) = N - 2
. - (C18) نظرًا إلى
kernel_dimensions = kernel_spatial_dimensions + [kernel_input_feature_dimension] + [kernel_output_feature_dimension]
:is_unique(kernel_dimensions)
.0 <= kernel_dimensions < N
.
- (C19)
size(output_spatial_dimensions) = N - 2
. - (C20) بالنظر إلى
output_dimensions = [output_batch_dimension] + output_spatial_dimensions + [output_feature_dimension]
:is_unique(output_dimensions)
.0 <= output_dimensions < N
.
- (C21)
0 < feature_group_count
. - (C22)
0 < batch_group_count
. - (C23)
feature_group_count = 1 or batch_group_count = 1
. - (C24)
size(precision_config) = 2
. - (C25) يتم تعريف
dim(result, result_dim)
على النحو التالي:dim(lhs, input_batch_dimension) / batch_group_count
إذاresult_dim = output_batch_dimension
.dim(rhs, kernel_output_feature_dimension)
إذاresult_dim = output_feature_dimension
.num_windows
بخلاف ذلك، حيث:output_spatial_dimensions[spatial_dim] = result_dim
.lhs_dim = input_spatial_dimensions[spatial_dim]
.rhs_dim = kernel_spatial_dimensions[spatial_dim]
.dilated_input_shape[lhs_dim] = dim(lhs, lhs_dim) = 0 ? 0 : (dim(lhs, lhs_dim) - 1) * lhs_dilation[spatial_dim] + 1
.padded_input_shape[lhs_dim] = padding[spatial_dim, 0] + dilated_input_shape[lhs_dim] + padding[spatial_dim, 1]
.dilated_window_shape[lhs_dim] = dim(rhs, rhs_dim) = 0 ? 0 : (dim(rhs, rhs_dim) - 1) * rhs_dilation[spatial_dim] + 1
.is_empty_window[lhs_dim] = padded_input_shape[lhs_dim] = 0 || dilated_window_shape[lhs_dim] > padded_input_shape[lhs_dim]
.num_windows = is_empty_window[lhs_dim] ? 0 : floor((padded_input_shape[lhs_dim] - dilated_window_shape[lhs_dim]) / window_strides[spatial_dim]) + 1
.
- (C26)
rank(result) = N
. - إذا كانت العملية تستخدم موتّرات غير كَمية:
- (C27)
element_type(lhs) = element_type(rhs) = element_type(result)
.
- (C27)
- إذا كانت العملية تستخدم موتّرات كميّة:
- (C28)
is_quantized(lhs) = is_quantized(result) and is_quantized(rhs)
. - (C29) إذا كانت
is_per_axis_quantized(rhs)
: ثمquantization_dimension(rhs) = kernel_output_feature_dimension
. - (C30) إذا كانت
is_per_axis_quantized(result)
، إذًاquantization_dimension(result) = output_feature_dimension
- إذا كانت
is_quantized(lhs)
: - (C31)
storage_type(lhs) = storage_type(rhs)
. - (C32)
expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
. - (C33) إذا كانت
is_per_tensor_quantized(rhs)
، يتم عندها:is_per_tensor_quantized(result)
- إذا كانت
!is_quantized(lhs)
: - (C34)
element_type(lhs) = expressed_type(rhs) = element_type(result)
.
- (C28)
أمثلة
// %lhs: [[
// [[1], [2], [5], [6]],
// [[3], [4], [7], [8]],
// [[10], [11], [14], [15]],
// [[12], [13], [16], [17]]
// ]]
//
// %rhs: [
// [[[1]], [[1]], [[1]]],
// [[[1]], [[1]], [[1]]],
// [[[1]], [[1]], [[1]]]
// ]
// %padding: [[1, 1],
// [1, 1]]
%result = "stablehlo.dynamic_conv"(%lhs, %rhs, %padding) {
window_strides = array<i64: 4, 4>,
lhs_dilation = array<i64: 2, 2>,
rhs_dilation = array<i64: 1, 1>,
window_reversal = array<i1: false, false>,
dimension_numbers = #stablehlo.conv<raw
input_batch_dimension = 0,
input_feature_dimension = 3,
input_spatial_dimensions = [0, 1],
kernel_input_feature_dimension = 2,
kernel_output_feature_dimension = 3,
kernel_spatial_dimensions = [0, 1],
output_batch_dimension = 0,
output_feature_dimension = 3,
output_spatial_dimensions = [1, 2]
>,
feature_group_count = 1 : i64,
batch_group_count = 1 : i64,
precision_config = [#stablehlo<precision DEFAULT>, #stablehlo<precision DEFAULT>]
} : (tensor<1x4x4x1xi64>, tensor<3x3x1x1xi64>, tensor<2x2xi64>) -> tensor<1x2x2x1xi64>
// %result: [[
// [[1], [5]],
// [[10], [14]]
// ]]
dynamic_gather
دلالات الألفاظ
هذه العملية مطابقة من الناحية الوظيفية
جمع
أو مع تحديد slice_sizes
ديناميكيًا كقيمة.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1)، (C7)، (C10-C12)، (C14) |
(I2) | start_indices |
متوتر لنوع العدد الصحيح | (C2)، (C3)، (C13) |
(I3) | slice_sizes |
متوتر ذو البعد الواحد لنوع العدد الصحيح | (C8)، (C11-C13) |
(I4) | offset_dims |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C1)، (C4-C5)، (C13) |
(I5) | collapsed_slice_dims |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C1)، (C6-C8)، (C13) |
(I6) | start_index_map |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C3)، (C9)، (C10) |
(I7) | index_vector_dim |
ثابت من النوع si64 |
(C2)، (C3)، (C13) |
(I8) | indices_are_sorted |
ثابت من النوع i1 |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتّر أو مستنسر كمي لكلّ متسابق | (C5)، (C13-C14) |
القيود
- (ج1)
rank(operand) = size(offset_dims) + size(collapsed_slice_dims)
. - (C2)
0 <= index_vector_dim <= rank(start_indices)
. - (C3)
size(start_index_map) = index_vector_dim < rank(start_indices) ? dim(start_indices, index_vector_dim) : 1
: - (C4)
is_unique(offset_dims) and is_sorted(offset_dims)
. - (C5)
0 <= offset_dims < rank(result)
. - (C6)
is_unique(collapsed_slice_dims) and is_sorted(collapsed_slice_dims)
. - (C7)
0 <= collapsed_slice_dims < rank(operand)
. - (C8)
slice_sizes[collapsed_slice_dims...] <= 1
. - (C9)
is_unique(start_index_map)
. - (C10)
0 <= start_index_map < rank(operand)
. - (C11)
size(slice_sizes) = rank(operand)
. - (C12)
0 <= slice_sizes <= shape(operand)
. - (C13)
shape(result) = combine(batch_dim_sizes, offset_dim_sizes)
حيث:batch_dim_sizes = shape(start_indices)
باستثناء أنّ حجم البُعد منstart_indices
بما يتوافق معindex_vector_dim
غير متضمنة.offset_dim_sizes = shape(slice_sizes)
باستثناء أنّ أحجام السمات فيslice_sizes
بما يتوافق معcollapsed_slice_dims
.- يضع
combine
batch_dim_sizes
في المحاور المقابلة لـbatch_dims
offset_dim_sizes
في المحاور المقابلة لـoffset_dims
.
- (C14)
element_type(operand) = element_type(result)
.
أمثلة
// %operand: [
// [[1, 2], [3, 4], [5, 6], [7, 8]],
// [[9, 10],[11, 12], [13, 14], [15, 16]],
// [[17, 18], [19, 20], [21, 22], [23, 24]]
// ]
// %start_indices: [
// [[0, 0], [1, 0], [2, 1]],
// [[0, 1], [1, 1], [0, 2]]
// ]
// %slize_sizes: [1, 2, 2]
%result = "stablehlo.dynamic_gather"(%operand, %start_indices, %slize_sizes) {
dimension_numbers = #stablehlo.gather<
offset_dims = [2, 3],
collapsed_slice_dims = [0],
start_index_map = [1, 0],
index_vector_dim = 2>,
indices_are_sorted = false
} : (tensor<3x4x2xi64>, tensor<2x3x2xi64>, tensor<3xi64>) -> tensor<2x3x2x2xi64>
// %result: [
// [
// [[1, 2], [3, 4]],
// [[3, 4], [5, 6]],
// [[13, 14], [15, 16]]
// ],
// [
// [[9, 10], [11, 12]],
// [[11, 12], [13, 14]],
// [[17, 18], [19, 20]]
// ]
// ]
dynamic_iota
دلالات الألفاظ
هذه العملية مطابقة من الناحية الوظيفية
يوتا
ولكن يتم تحديد شكل النتيجة ديناميكيًا عبر output_shape
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | output_shape |
متوتر ذو البعد الواحد لنوع العدد الصحيح | (C1)، (C2) |
(I2) | iota_dimension |
si64 |
(C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المنزِّع الكمي لكل متسابق | (C2) |
القيود
- (ج1)
0 <= iota_dimension < size(output_shape)
. - (C2)
rank(result) = size(output_shape)
.
أمثلة
%output_shape = stablehlo.constant dense<[4, 5]> : tensor<2xi64>
%result = "stablehlo.dynamic_iota"(%output_shape) {
iota_dimension = 0 : i64
} : (tensor<2xi64>) -> tensor<4x5xi64>
// %result: [
// [0, 0, 0, 0, 0],
// [1, 1, 1, 1, 1],
// [2, 2, 2, 2, 2],
// [3, 3, 3, 3, 3]
// ]
dynamic_pad
دلالات الألفاظ
هذه العملية مطابقة من الناحية الوظيفية
اللوحة
هذا، ولكن مع edge_padding_low
وedge_padding_high
وinterior_padding
المحددة ديناميكيًا كقيم.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1)، (C2)، (C4) |
(I2) | padding_value |
متسّع 0 بُعدي أو متنسورة كمّية بكل متسابق | (C1) |
(I3) | edge_padding_low |
متوتر ذو البعد الواحد لنوع العدد الصحيح | (C1)، (C4) |
(I4) | edge_padding_high |
متوتر ذو البعد الواحد لنوع العدد الصحيح | (C1)، (C4) |
(I5) | interior_padding |
متوتر ذو البعد الواحد لنوع العدد الصحيح | (C2-C4) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتّر أو مستنسر كمي لكلّ متسابق | (C3-C6) |
القيود
- (ج1)
element_type(operand) = element_type(padding_value) = element_type(result)
. - (C2)
size(edge_padding_low) = size(edge_padding_high) = size(interior_padding) = rank(operand)
. - (C3)
0 <= interior_padding
: - (C4)
shape(result) = shape(operand) + edge_padding_low + max(shape(operand) - 1, 0) * interior_padding + edge_padding_high
.
أمثلة
// %operand: [
// [1, 2, 3],
// [4, 5, 6]
// ]
// %padding_value: 0
// %edge_padding_low: [0, 1]
// %edge_padding_high: [2, 1]
// %interior_padding: [1, 2]
%result = "stablehlo.dynamic_pad"(%operand, %padding_value,
%edge_padding_low, %edge_padding_high, %interior_padding
) : (tensor<2x3xi64>, tensor<i64>, tensor<2xi64>, tensor<2xi64>, tensor<2xi64>) -> tensor<5x9xi64>
// %result: [
// [0, 1, 0, 0, 2, 0, 0, 3, 0],
// [0, 0, 0, 0, 0, 0, 0, 0, 0],
// [0, 4, 0, 0, 5, 0, 0, 6, 0],
// [0, 0, 0, 0, 0, 0, 0, 0, 0],
// [0, 0, 0, 0, 0, 0, 0, 0, 0]
// ]
dynamic_reshape
دلالات الألفاظ
هذه العملية مطابقة من الناحية الوظيفية
إعادة تشكيل
ولكن يتم تحديد شكل النتيجة ديناميكيًا عبر output_shape
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتر أو متنسّر كمي | (C1-C3) |
(I2) | output_shape |
متوتر ذو البعد الواحد لنوع العدد الصحيح | (C4) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتر أو متنسّر كمي | (C1-C4) |
القيود
- (C1)
element_type(result)
يتم تقديمها من خلال:element_type(operand)
، إذا كانت!is_per_axis_quantized(operand)
.element_type(operand)
باستثناء أنّquantization_dimension(operand)
قد تختلف السمةquantization_dimension(result)
في الحالات الأخرى.
- (C2)
size(operand) = size(result)
. - (C3) إذا كانت
is_per_axis_quantized(operand)
:reduce(dims(operand, [0, 1, ..., quantization_dimension(operand) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y) = reduce(dims(result, [0, 1, ..., quantization_dimension(result) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y)
.dim(operand, quantization_dimension(operand)) = dim(result, quantization_dimension(result))
.reduce(dims(operand, [quantization_dimension(operand) + 1, ..., rank(operand) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y) = reduce(dims(result, [quantization_dimension(result) + 1, ..., rank(result) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y)
.
- (C4)
size(output_shape) = rank(result)
.
أمثلة
// %operand: [[1, 2, 3], [4, 5, 6]]
// %output_shape: [3, 2]
%result = "stablehlo.dynamic_reshape"(%operand, %output_shape) : (tensor<2x3xi64>, tensor<2xi64>) -> tensor<3x2xi64>
// %result: [[1, 2], [3, 4], [5, 6]]
dynamic_slice
دلالات الألفاظ
لاستخراج شريحة من operand
باستخدام فهارس البدء المحسوبة ديناميكيًا
وينتج موتر result
. يحتوي start_indices
على مؤشرات البداية الخاصة بـ
الشريحة لكل بُعد خاضع للتعديل المحتمل، وslice_sizes
تحتوي على أحجام الشريحة لكل بُعد. بشكل أكثر رسمية،
result[result_index] = operand[operand_index]
حيث:
adjusted_start_indices = clamp(0, start_indices, shape(operand) - slice_sizes)
.operand_index = adjusted_start_indices + result_index
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1)، (C2)، (C4) |
(I2) | start_indices |
العدد المتنوع للعشرات ذوات الأبعاد الصفرية لنوع الأعداد الصحيحة | (C2)، (C3) |
(I3) | slice_sizes |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C2)، (C4)، (C5) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1)، (C5) |
القيود
- (ج1)
element_type(operand) = element_type(result)
. - (C2)
size(start_indices) = size(slice_sizes) = rank(operand)
. - (C3)
same(type(start_indices...))
: - (C4)
0 <= slice_sizes <= shape(operand)
. - (C5)
shape(result) = slice_sizes
.
أمثلة
// %operand: [
// [0, 0, 1, 1],
// [0, 0, 1, 1],
// [0, 0, 0, 0],
// [0, 0, 0, 0]
// ]
// %start_indices0: -1
// %start_indices1: 3
%result = "stablehlo.dynamic_slice"(%operand, %start_indices0, %start_indices1) {
slice_sizes = array<i64: 2, 2>
} : (tensor<4x4xi32>, tensor<i64>, tensor<i64>) -> tensor<2x2xi32>
// %result: [
// [1, 1],
// [1, 1]
// ]
dynamic_update_slice
دلالات الألفاظ
يتم إنشاء متسابق result
الذي يساوي سينسور operand
باستثناء
يتم تعديل الشريحة التي تبدأ من start_indices
بالقيم في update
.
وتعريف result[result_index]
من الناحية الرسمية على النحو التالي:
update[update_index]
إذا0 <= update_index < shape(update)
حيث:adjusted_start_indices = clamp(0, start_indices, shape(operand) - shape(update))
.update_index = result_index - adjusted_start_indices
.
operand[result_index]
بخلاف ذلك.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1-C4)، (C6) |
(I2) | update |
متوتّر أو مستنسر كمي لكلّ متسابق | (C2)، (C3)، (C6) |
(I3) | start_indices |
العدد المتنوع للعشرات ذوات الأبعاد الصفرية لنوع الأعداد الصحيحة | (C4)، (C5) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1) |
القيود
- (ج1)
type(operand) = type(result)
. - (C2)
element_type(update) = element_type(operand)
. - (C3)
rank(update) = rank(operand)
: - (C4)
size(start_indices) = rank(operand)
. - (C5)
same(type(start_indices...))
. - (C6)
0 <= shape(update) <= shape(operand)
.
أمثلة
// %operand: [
// [1, 1, 0, 0],
// [1, 1, 0, 0],
// [1, 1, 1, 1],
// [1, 1, 1, 1]
// ]
// %update: [
// [1, 1],
// [1, 1]
// ]
// %start_indices0: -1
// %start_indices1: 3
%result = "stablehlo.dynamic_update_slice"(%operand, %update, %start_indices0, %start_indices1)
: (tensor<4x4xi32>, tensor<2x2xi32>, tensor<i64>, tensor<i64>) -> tensor<4x4xi32>
// %result: [
// [1, 1, 1, 1],
// [1, 1, 1, 1],
// [1, 1, 1, 1],
// [1, 1, 1, 1]
// ]
دالات أسية
دلالات الألفاظ
لتنفيذ عملية أسّية من ناحية العناصر على موتر operand
وينتج عن ذلك
متوتر result
حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى الأعداد العشرية:
exp
من IEEE-754. - للأعداد المركّبة: أُس مركَّب.
- بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(exponential, operand, type(result))
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
القيود
- (ج1)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// %operand: [[0.0, 1.0], [2.0, 3.0]]
%result = "stablehlo.exponential"(%operand) : (tensor<2x2xf64>) -> tensor<2x2xf64>
// %result: [[1.0, 2.7182818284590451], [7.3890560989306504, 20.085536923187668]]
exponential_minus_one
دلالات الألفاظ
لتنفيذ أسّي العناصر من ناحية العناصر ناقص عملية واحدة على متسّع operand
نحصل على موتّر result
. حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى الأعداد العشرية:
expm1
من IEEE-754. - بالنسبة إلى الأعداد المركّبة: يتم استخدام الأس المركّب ناقص واحد.
- بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(exponential_minus_one, operand, type(result))
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
القيود
- (ج1)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// %operand: [0.0, 1.0]
%result = "stablehlo.exponential_minus_one"(%operand) : (tensor<2xf64>) -> tensor<2xf64>
// %result: [0.0, 1.71828187]
ضريبة القيمة المضافة
دلالات الألفاظ
تؤدي إلى تحويلات فورييه الأمامية والعكسية للتوصل إلى مفاهيم حقيقية ومعقدة المدخلات والمخرجات.
fft_type
هو واحد مما يلي:
FFT
: إعادة توجيه "واجهة سريعة معقّدة إلى معقّدة" (FFT)IFFT
: وقت الاستجابة السريع المعكوس والمعقد إلى المعقدRFFT
: إعادة توجيه وقت الاستجابة السريعة إذا كان واقعيًا إلى معقدIRFFT
: مقياس FFT غير حقيقي إلى معقّد (أي أنّه يعتبر معقّدًا وعريضًا حقيقيًا)
وبشكل أكثر رسمية، بناءً على الدالة fft
التي تستخدم موتّرات أحادية البعد
أنواع معقدة كمدخلات، ينتج عنها متسابقات أحادية البعد من نفس الأنواع
ويحسب تحويل فورييه المنفصل:
بالنسبة لـ fft_type = FFT
، يتم تعريف result
على أنه النتيجة النهائية لسلسلة من L
العمليات الحسابية حيث يكون L = size(fft_length)
. على سبيل المثال، بالنسبة إلى L = 3
:
result1[i0, ..., :] = fft(operand[i0, ..., :])
.result2[i0, ..., :, iR-1] = fft(result1[i0, ..., :, iR-1])
.result[i0, ..., :, iR-2, iR-1] = fft(result2[i0, ..., :, iR-2, iR-1])
.
علاوة على ذلك، ونظرًا لأن الدالة ifft
التي لها نوع التوقيع ذاته
تحسب معكوس fft
:
بالنسبة إلى fft_type = IFFT
، يتم تعريف result
على أنه عكس العمليات الحسابية
مقابل fft_type = FFT
. على سبيل المثال، بالنسبة إلى L = 3
:
result1[i0, ..., :, iR-2, iR-1] = ifft(operand[i0, ..., :, iR-2, iR-1])
.result2[i0, ..., :, iR-1] = ifft(result1[i0, ..., :, iR-1])
.result[i0, ..., :] = ifft(result2[i0, ..., :])
.
وعلاوة على ذلك، من خلال الدالة rfft
التي تستخدم العشرات الأحادية البعد
أنواع النقاط العائمة، ينتج عنها متسابقات أحادية البُعد للأنواع المعقدة
نفس دلالات النقطة العائمة وتعمل على النحو التالي:
- مكان
rfft(real_operand) = truncated_result
complex_operand... = (real_operand..., 0.0)
.complex_result = fft(complex_operand)
.truncated_result = complex_result[:(rank(complex_result) / 2 + 1)]
.
(عندما يتم حساب تحويل فورييه المنفصل للمعاملات الحقيقية، فإن أول
عناصر N/2 + 1
في النتيجة تحدد باقي النتيجة بوضوح،
وبالتالي يتم اقتطاع نتيجة rfft
لتجنب حساب العناصر المتكررة).
بالنسبة لـ fft_type = RFFT
، يتم تعريف result
على أنه النتيجة النهائية لسلسلة من L
العمليات الحسابية حيث يكون L = size(fft_length)
. على سبيل المثال، بالنسبة إلى L = 3
:
result1[i0, ..., :] = rfft(operand[i0, ..., :])
.result2[i0, ..., :, iR-1] = fft(result1[i0, ..., :, iR-1])
.result[i0, ..., :, iR-2, iR-1] = fft(result2[i0, ..., :, iR-2, iR-1])
.
وأخيرًا، ضع في الاعتبار الدالة irfft
التي لها نفس نوع التوقيع
تحسب معكوس rfft
:
بالنسبة إلى fft_type = IRFFT
، يتم تعريف result
على أنه عكس العمليات الحسابية
مقابل fft_type = RFFT
. على سبيل المثال، بالنسبة إلى L = 3
:
result1[i0, ..., :, iR-2, iR-1] = ifft(operand[i0, ..., :, iR-2, iR-1])
.result2[i0, ..., :, iR-1] = ifft(result1[i0, ..., :, iR-1])
.result[i0, ..., :] = irfft(result2[i0, ..., :])
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتر من النقطة العائمة أو نوع معقد | (C1)، (C2)، (C4)، (C5) |
(I2) | fft_type |
تعداد FFT وIFFT وRFFT وIRFFT |
(C2)، (C5) |
(I3) | fft_length |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C1)، (C3)، (C4) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتر من النقطة العائمة أو نوع معقد | (C2)، (C4)، (C5) |
القيود
- (ج1)
size(fft_length) <= rank(operand)
. - (C2) تختلف العلاقة بين نوعَي العناصر
operand
وresult
:- إذا كانت
fft_type = FFT
وelement_type(operand)
وelement_type(result)
لها نفس النوع المعقد. - إذا كانت
fft_type = IFFT
وelement_type(operand)
وelement_type(result)
لها نفس النوع المعقد. - إذا كان
fft_type = RFFT
، يكونelement_type(operand)
نوع نقطة عائمةelement_type(result)
هو نوع معقد من نفس النقطة العائمة الدلالة. - إذا كان
fft_type = IRFFT
،element_type(operand)
نوعًا معقدًاelement_type(result)
هو نوع نقطة عائمة لنفس النقطة العائمة الدلالة.
- إذا كانت
- (C3)
1 <= size(fft_length) <= 3
: - (C4) إذا كان بين
operand
وresult
، يكون هناك متسابقreal
نوع النقطة العائمة، ثمshape(real)[-size(fft_length):] = fft_length
. - (C5)
shape(result) = shape(operand)
باستثناء:- إذا كانت
fft_type = RFFT
،dim(result, -1) = dim(operand, -1) = 0 ? 0 : dim(operand, -1) / 2 + 1
- إذا كانت
fft_type = IRFFT
،dim(operand, -1) = dim(result, -1) = 0 ? 0 : dim(result, -1) / 2 + 1
- إذا كانت
أمثلة
// %operand: [(1.0, 0.0), (0.0, 0.0), (0.0, 0.0), (0.0, 0.0)]
%result = "stablehlo.fft"(%operand) {
fft_type = #stablehlo<fft_type FFT>,
fft_length = array<i64: 4>
} : (tensor<4xcomplex<f32>>) -> tensor<4xcomplex<f32>>
// %result: [(1.0, 0.0), (1.0, 0.0), (1.0, 0.0), (1.0, 0.0)]
floor
دلالات الألفاظ
يؤدي هذا الإجراء إلى تنفيذ دالة مناسبة من ناحية العناصر لمعرِف operand
وينتج موجِّه result
.
تنفيذ عملية roundToIntegralTowardNegative
من IEEE-754
المواصفات. بالنسبة للأنواع الكَمية، تنفذ
dequantize_op_quantize(floor, operand, type(result))
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق | (C1) |
القيود
- (ج1)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// %operand: [-0.8166, -0.2530, 0.2530, 0.8166, 2.0]
%result = "stablehlo.floor"(%operand) : (tensor<5xf32>) -> tensor<5xf32>
// %result: [-1.0, -1.0, 0.0, 0.0, 2.0]
جمع
دلالات الألفاظ
لجمع الشرائح من متسابق operand
من الإزاحة المحدّدة في start_indices
وينتج متسابق result
.
يوضّح المخطّط التالي كيفية ارتباط العناصر في result
بالعناصر في
operand
باستخدام مثال ملموس. ويختار الرسم البياني بعض الأمثلة result
.
المؤشرات ويشرح بالتفصيل مؤشرات operand
التي تتوافق معها.
بشكل رسمي، result[result_index] = operand[operand_index]
حيث:
batch_dims = [d for d in axes(result) and d not in offset_dims]
.batch_index = result_index[batch_dims...]
.- تعريف "
start_index
" على أنّه:start_indices[bi0, ..., :, ..., biN]
حيثbi
عبارة عن عناصر فردية في يتم إدراجbatch_index
و:
في فهرسindex_vector_dim
، إذاindex_vector_dim
<rank(start_indices)
[start_indices[batch_index]]
بخلاف ذلك.
- بالنسبة إلى
d_operand
فيaxes(operand)
،full_start_index[d_operand] = clamp(start_index[d_start], 0, dim(operand, d_operand) - slice_sizes[d_operand])
إذا كانت القيمة هيd_operand = start_index_map[d_start]
.full_start_index[d_operand] = 0
بخلاف ذلك.
- بالنسبة إلى
d_operand
فيaxes(operand)
،full_batching_index[d_operand] = batch_index[d_start - (d_start < index_vector_dim ? 0 : 1)]
إذا كانd_operand = operand_batching_dims[i_batching]
وd_start = start_indices_batching_dims[i_batching]
full_batching_index[d_operand] = 0
بخلاف ذلك.
offset_index = result_index[offset_dims...]
.full_offset_index = [oi0, ..., 0, ..., oiN]
حيث يكونoi
فرديًا العناصر فيoffset_index
، و0
يتم إدراجها في الفهارس منcollapsed_slice_dims
وoperand_batching_dims
.operand_index = full_start_index + full_batching_index + full_offset_index
إذا كانت indices_are_sorted
هي true
، يمكن لعملية التنفيذ أن تفترض أنّ
يتم ترتيب start_indices
حسب start_index_map
، وإلا
غير محدد. بشكل رسمي، لجميع i1 < i2
من indices(result)
،
full_start_index(i1) <= full_start_index(i2)
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1)، (C8)، (C11)، (C17)، (C19-C21)، (C23) |
(I2) | start_indices |
متوتر لنوع العدد الصحيح | (C2-C3)، (C14)، (C17)، (C22) |
(I3) | offset_dims |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C1)، (C4-C5)، (C22) |
(I4) | collapsed_slice_dims |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C1)، (C6-C9)، (C22) |
(I5) | operand_batching_dims |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C1)، (C6)، (C10-C12)، (C16-C18)، (C22) |
(I6) | start_indices_batching_dims |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C13-C17) |
(I7) | start_index_map |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C3)، (C18-C19) |
(I8) | index_vector_dim |
ثابت من النوع si64 |
(C2-C3)، (C15)، (C22) |
(I9) | slice_sizes |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C9)، (C12)، (C20-C22) |
(I10) | indices_are_sorted |
ثابت من النوع i1 |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتّر أو مستنسر كمي لكلّ متسابق | (C5)، (C22-C23) |
القيود
- (ج1)
rank(operand) = size(offset_dims) + size(collapsed_slice_dims) + size(operand_batching_dims)
. - (C2)
0 <= index_vector_dim <= rank(start_indices)
. - (C3)
size(start_index_map) = index_vector_dim < rank(start_indices) ? dim(start_indices, index_vector_dim) : 1
: - (C4)
is_unique(offset_dims) and is_sorted(offset_dims)
. - (C5)
0 <= offset_dims < rank(result)
. - (C6)
is_unique(concatenate(collapsed_slice_dims, operand_batching_dims))
- (C7)
is_sorted(collapsed_slice_dims)
. - (C8)
0 <= collapsed_slice_dims < rank(operand)
. - (C9)
slice_sizes[collapsed_slice_dims...] <= 1
. - (C10)
is_sorted(operand_batching_dims)
. - (C11)
0 <= operand_batching_dims < rank(operand)
. - (C12)
slice_sizes[operand_batching_dims...] <= 1
. - (C13)
is_unique(start_indices_batching_dims)
. - (C14)
0 <= start_indices_batching_dims < rank(start_indices)
. - (C15)
index_vector_dim not in start_indices_batching_dims
. - (C16)
size(operand_batching_dims) == size(start_indices_batching_dims)
. - (C17)
dim(operand, operand_batching_dims...) = dim(start_indices, start_indices_batching_dims...)
. - (C18)
is_unique(concatenate(start_index_map, operand_batching_dims))
. - (C19)
0 <= start_index_map < rank(operand)
. - (C20)
size(slice_sizes) = rank(operand)
. - (C21)
0 <= slice_sizes <= shape(operand)
. - (C22)
shape(result) = combine(batch_dim_sizes, offset_dim_sizes)
حيث:batch_dim_sizes = shape(start_indices)
باستثناء أنّ حجم البُعد منstart_indices
بما يتوافق معindex_vector_dim
غير متضمنة.offset_dim_sizes = slice_sizes
باستثناء أنّ أحجام السماتslice_sizes
المقابلة لـcollapsed_slice_dims
لا يتم تضمينoperand_batching_dims
.- يضع
combine
batch_dim_sizes
في المحاور المقابلة لـbatch_dims
offset_dim_sizes
في المحاور المقابلة لـoffset_dims
.
- (C23)
element_type(operand) = element_type(result)
.
أمثلة
// %operand: [
// [
// [[1, 2], [3, 4], [5, 6], [7, 8]],
// [[9, 10],[11, 12], [13, 14], [15, 16]],
// [[17, 18], [19, 20], [21, 22], [23, 24]]
// ],
// [
// [[25, 26], [27, 28], [29, 30], [31, 32]],
// [[33, 34], [35, 36], [37, 38], [39, 40]],
// [[41, 42], [43, 44], [45, 46], [47, 48]]
// ]
// ]
// %start_indices: [
// [
// [[0, 0], [1, 0], [2, 1]],
// [[0, 1], [1, 1], [0, 9]]
// ],
// [
// [[0, 0], [2, 1], [2, 2]],
// [[1, 2], [0, 1], [1, 0]]
// ]
// ]
%result = "stablehlo.gather"(%operand, %start_indices) {
dimension_numbers = #stablehlo.gather<
offset_dims = [3, 4],
collapsed_slice_dims = [1],
operand_batching_dims = [0],
start_indices_batching_dims = [1],
start_index_map = [2, 1],
index_vector_dim = 3>,
slice_sizes = array<i64: 1, 1, 2, 2>,
indices_are_sorted = false
} : (tensor<2x3x4x2xi32>, tensor<2x2x3x2xi64>) -> tensor<2x2x3x2x2xi32>
// %result: [
// [
// [
// [[1, 2], [3, 4]],
// [[3, 4], [5, 6]],
// [[13, 14], [15, 16]]
// ],
// [
// [[33, 34], [35, 36]],
// [[35, 36], [37, 38]],
// [[41, 42], [43, 44]]
// ]
// ],
// [
// [
// [[1, 2], [3, 4]],
// [[13, 14], [15, 16]],
// [[21, 22], [23, 24]]
// ],
// [
// [[43, 44], [45, 46]],
// [[33, 34], [35, 36]],
// [[27, 28], [29, 30]]
// ]
// ]
// ]
get_dimension_size
دلالات الألفاظ
لعرض حجم dimension
المحدّد لـ operand
. بشكل أكثر رسمية،
result = dim(operand, dimension)
بينما تتعلق دلالات الشكل فقط
المكون من النوع. يمكن أن يكون نوع العنصر أي شيء.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتر أو متنسّر كمي | (C1) |
(I2) | dimension |
ثابت من النوع si64 |
(C1) |
المُخرَجات
الاسم | النوع |
---|---|
result |
متسابق أحادي الأبعاد من النوع si32 |
القيود
- (ج1)
0 <= dimension < rank(operand)
.
أمثلة
// %operand: [[1, 2, 3], [4, 5, 6]]
%result = "stablehlo.get_dimension_size"(%operand) {
dimension = 1 : i64
} : (tensor<2x3xi64>) -> tensor<i32>
// %result: 3
get_tuple_element
دلالات الألفاظ
هي تعمل على استخراج العنصر في موضع index
في الصف operand
وينتج عنه
result
اسم "result = operand[index]
" رسميًا.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
صف | (C1)، (C2) |
(I2) | index |
ثابت من النوع si32 |
(C1)، (C2) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
أي نوع متوافق | (C2) |
القيود
- (ج1)
0 <= index < size(operand)
. - (C2)
type(result) = tuple_element_types(operand)[index]
.
أمثلة
// %operand: ([1.0, 2.0], (3))
index = 0 : i32
} : (tuple<tensor<2xf32>, tuple<tensor<i32>>>) -> tensor<2xf32>
// %result: [1.0, 2.0]
إذا
دلالات الألفاظ
الحصول على ناتج من تنفيذ دالة واحدة بالضبط من true_branch
أو
false_branch
استنادًا إلى قيمة pred
. اسم "result =
pred ? true_branch() : false_branch()
" رسميًا.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | pred |
متسابق أحادي الأبعاد من النوع i1 |
|
(I2) | true_branch |
دالة | (C1-C3) |
(I3) | false_branch |
دالة | (C1)، (C2) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
results |
الأعداد المتباينة من متساعات التوتر أو العشرات الكمية أو الرموز المميزة | (C3) |
القيود
- (ج1)
input_types(true_branch) = input_types(false_branch) = []
. - (C2)
output_types(true_branch) = output_types(false_branch)
. - (C3)
type(results...) = output_types(true_branch)
:
أمثلة
// %result_true_branch: 10
// %result_false_branch: 11
// %pred: true
%result = "stablehlo.if"(%pred) ({
"stablehlo.return"(%result_true_branch) : (tensor<i32>) -> ()
}, {
"stablehlo.return"(%result_false_branch) : (tensor<i32>) -> ()
}) : (tensor<i1>) -> tensor<i32>
// %result: 10
صورة
دلالات الألفاظ
يتم استخراج الجزء التخيلي، من ناحية العناصر، من operand
وينتج عنه
متوتر result
وبشكل رسمي، لكل عنصر x
:
imag(x) = is_complex(x) ? imaginary_part(x) :
constant(0, element_type(result))
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتر من النقطة العائمة أو نوع معقد | (C1)، (C2) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متّجه من نوع النقطة العائمة | (C1)، (C2) |
القيود
- (ج1)
shape(result) = shape(operand)
. - (C2) يتم تعريف
element_type(result)
على النحو التالي:complex_element_type(element_type(operand))
إذاis_complex(operand)
.element_type(operand)
بخلاف ذلك.
أمثلة
// %operand: [(1.0, 2.0), (3.0, 4.0)]
%result = "stablehlo.imag"(%operand) : (tensor<2xcomplex<f32>>) -> tensor<2xf32>
// %result: [2.0, 4.0]
إعلان ضمن الخلاصة
دلالات الألفاظ
تقرأ البيانات من الخلاصة الإعلانية وتُنتج results
.
يتم تحديد دلالات infeed_config
.
تتألف الدالة results
من قيم حمولة البيانات تأتي أولاً ورمزًا مميّزًا يأتي
الأخير. وفي المستقبل، نخطط لتقسيم الحمولة والرمز المميز إلى
المخرجات المنفصلة لتحسين الوضوح
(#670)
مدخلات
التصنيف | الاسم | النوع |
---|---|---|
(I1) | token |
token |
(I2) | infeed_config |
ثابت من النوع string |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
results |
الأعداد المتباينة من متساعات التوتر أو العشرات الكمية أو الرموز المميزة | (C1-C3) |
القيود
- (ج1)
0 < size(results)
. - (C2)
is_empty(result[:-1])
أوis_tensor(type(results[:-1]))
. - (C3)
is_token(type(results[-1]))
:
أمثلة
// %token: !stablehlo.token
// infeed_queue[0]: [[1, 2], [3, 4]]
// infeed_queue[1]: [[5, 6], [7, 8]]
%results0:2 = "stablehlo.infeed"(%token) {
infeed_config = ""
} : (!stablehlo.token) -> (tensor<2x2xi64>, !stablehlo.token)
// results0#0: [[1, 2], [3, 4]]
%results1:2 = "stablehlo.infeed"(%token) {
infeed_config = ""
} : (!stablehlo.token) -> (tensor<2x2xi64>, !stablehlo.token)
// results1#0: [[5, 6], [7, 8]]
يوتا
دلالات الألفاظ
ملء متوتر output
بقيم بترتيب متزايد بدءًا من الصفر
على طول البُعد iota_dimension
. بشكل أكثر رسمية،
output[output_index] = constant(is_quantized(output) ?
quantize(output_index[iota_dimension], element_type(output)) :
output_index[iota_dimension], element_type(output))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | iota_dimension |
si64 |
(C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
output |
موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المنزِّع الكمي لكل متسابق | (C1) |
القيود
- (ج1)
0 <= iota_dimension < rank(output)
.
أمثلة
%output = "stablehlo.iota"() {
iota_dimension = 0 : i64
} : () -> tensor<4x5xi32>
// %output: [
// [0, 0, 0, 0, 0],
// [1, 1, 1, 1, 1],
// [2, 2, 2, 2, 2],
// [3, 3, 3, 3, 3]
// ]
%output = "stablehlo.iota"() {
iota_dimension = 1 : i64
} : () -> tensor<4x5xi32>
// %output: [
// [0, 1, 2, 3, 4],
// [0, 1, 2, 3, 4],
// [0, 1, 2, 3, 4],
// [0, 1, 2, 3, 4]
// ]
is_finite
دلالات الألفاظ
تُجري هذا الإجراء التحقّق من العناصر الدقيقة إذا كانت القيمة في x
محدودة (أي أنّها ليست غير محدودة).
+Inf و-Inf وNaN) وينتج سينسور y
. لتنفيذ isFinite
وفقًا لمواصفات IEEE-754. بالنسبة للأنواع الكَمية، تكون النتيجة
دائمًا true
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | x |
متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
y |
متّصِل من النوع المنطقي | (C1) |
القيود
- (ج1)
shape(x) = shape(y)
.
أمثلة
// Logical values: -Inf, +Inf, NaN, ...
// %x: [0xFFF0000000000000, 0x7FF0000000000000, 0x7FF8000000000000, -10.0, -0.0, 0.0, 10.0]
%y = "stablehlo.is_finite"(%x) : (tensor<7xf64) -> tensor<7xi1>
// %y: [false, false, false, true, true, true, true]
log
دلالات الألفاظ
لتنفيذ عملية اللوغاريتم حسب العناصر على موتّر operand
وينتج عنه
متوتر result
حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى الأعداد العشرية:
log
من IEEE-754. - بالنسبة إلى الأعداد المركّبة: اللوغاريتم المركَّب.
- بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(log, operand, type(result))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
القيود
- (ج1)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// %operand: [[1.0, 2.0], [3.0, 4.0]]
%result = "stablehlo.log"(%operand) : (tensor<2x2xf64>) -> tensor<2x2xf64>
// %result: [[0.0, 0.69314718055994529], [1.0986122886681098, 1.3862943611198906]]
log_plus_one
دلالات الألفاظ
لتنفيذ لوغاريتم العناصر في العناصر بالإضافة إلى عملية واحدة على متين operand
نحصل على موتّر result
. حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى الأعداد العشرية:
logp1
من IEEE-754. - بالنسبة إلى الأعداد المركّبة: اللوغاريتم المركّب زائد واحد.
- بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(log_plus_one, operand, type(result))
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
القيود
- (ج1)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// %operand: [0.0, -0.999, 7.0, 6.38905621, 15.0]
%result = "stablehlo.log_plus_one"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// %result: [0.0, -6.90776825, 2.07944155, 2.0, 2.77258873]
الخدمات اللوجستية
دلالات الألفاظ
ينفذ عملية لوجستية بناءً على العناصر على متوتر operand
وينتج عنه
متوتر result
حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى الأعداد العشرية:
division(1, addition(1, exp(-x)))
من IEEE-754. - للأعداد المركّبة: لوجستية معقدة.
- بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(logistic, operand, type(result))
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
القيود
- (ج1)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// %operand: [[0.0, 1.0], [2.0, 3.0]]
%result = "stablehlo.logistic"(%operand) : (tensor<2x2xf64>) -> tensor<2x2xf64>
// %result: [[0.5, 0.73105858], [0.88079708, 0.95257413]]
خريطة
دلالات الألفاظ
يتم تطبيق دالة خريطة computation
على inputs
على طول dimensions
نحصل على متوتر result
.
اسم "result[result_index] = computation(inputs...[result_index])
" رسميًا.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | inputs |
الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق | (C1-C4) |
(I2) | dimensions |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C3) |
(I3) | computation |
دالة | (C4) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1)، (C4) |
القيود
- (ج1)
shape(inputs...) = shape(result)
. - (C2)
0 < size(inputs) = N
. - (C3)
dimensions = range(rank(inputs[0]))
: - (C4)
computation
النوع(tensor<E0>, ..., tensor<EN-1>) -> tensor<E'>
حيثEi = element_type(inputs[i])
وE' = element_type(result)
.
أمثلة
// %input0: [[0, 1], [2, 3]]
// %input1: [[4, 5], [6, 7]]
%result = "stablehlo.map"(%input0, %input1) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = stablehlo.multiply %arg0, %arg1 : tensor<i64>
stablehlo.return %0 : tensor<i64>
}) {
dimensions = array<i64: 0, 1>
} : (tensor<2x2xi64>, tensor<2x2xi64>) -> tensor<2x2xi64>
// %result: [[0, 5], [12, 21]]
أعلى قيمة
دلالات الألفاظ
لتنفيذ عملية الحد الأقصى من حيث العناصر على المستويَين lhs
وrhs
وينتج عن ذلك
متوتر result
حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى القيم المنطقية: منطقي OR.
- بالنسبة إلى الأعداد الصحيحة: الحد الأقصى لعدد صحيح.
- بالنسبة إلى الأعداد العشرية:
maximum
من IEEE-754. - بالنسبة إلى الأعداد المركّبة: الحد الأقصى للنصوص المعجمية لزوج
(real, imaginary)
. يتضمن فرض ترتيب على الأعداد المركّبة دلالات مدهشة، لذا نخطط في المستقبل لإلغاء دعم الأعداد المركّبة لهذه العملية (#560). - بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(maximum, lhs, rhs, type(result))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1) |
(I2) | rhs |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1) |
القيود
- (ج1)
baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)
.
أمثلة
// %lhs: [[1, 2], [7, 8]]
// %rhs: [[5, 6], [3, 4]]
%result = "stablehlo.maximum"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[5, 6], [7, 8]]
الحد الأدنى
دلالات الألفاظ
لتنفيذ عملية min من حيث العناصر على متسابقَي التوتر lhs
وrhs
وينتج عن ذلك
متوتر result
حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى القيم المنطقية: المنطقي AND.
- بالنسبة للأعداد الصحيحة: الحد الأدنى لعدد صحيح.
- بالنسبة إلى الأعداد العشرية:
minimum
من IEEE-754. - بالنسبة إلى الأعداد المركّبة: يجب استخدام الحد الأدنى للقيم اللغوية لزوج
(real, imaginary)
. يتضمن فرض ترتيب على الأعداد المركّبة دلالات مدهشة، لذا نخطط في المستقبل لإلغاء دعم الأعداد المركّبة لهذه العملية (#560). - بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(minimum, lhs, rhs, type(result))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1) |
(I2) | rhs |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1) |
القيود
- (ج1)
baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)
.
أمثلة
// %lhs: [[1, 2], [7, 8]]
// %rhs: [[5, 6], [3, 4]]
%result = "stablehlo.minimum"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[1, 2], [3, 4]]
ضرب
دلالات الألفاظ
لتنفيذ حاصل ضرب العناصر من ناحية العناصر لمتسرينَين lhs
وrhs
وينتج عن ذلك
متوتر result
حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى القيم المنطقية: المنطقي AND.
- بالنسبة إلى الأعداد الصحيحة: ضرب الأعداد الصحيحة.
- بالنسبة إلى الأعداد العشرية:
multiplication
من IEEE-754. - بالنسبة للأعداد المركّبة: الضرب المعقد.
- بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(multiply, lhs, rhs, type(result))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1) |
(I2) | rhs |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1) |
القيود
- (ج1)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.multiply"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[5, 12], [21, 32]]
نفي
دلالات الألفاظ
لتنفيذ عملية نفي تسلسلي حسب العناصر في متوتر operand
وينتج عن ذلك result
متنسور. حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى الأعداد الصحيحة الموقّعة: نفي العدد الصحيح.
- بالنسبة إلى الأعداد الصحيحة غير الموقَّعة: bitcast إلى عدد صحيح بعلامة، نفي عدد صحيح، Bitcast إلى عدد صحيح غير موقَّع.
- بالنسبة إلى الأعداد العشرية:
negate
من IEEE-754. - للأعداد المركّبة: النفي المركّب.
- بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(negate, operand, type(result))
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المنزِّع الكمي لكل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المنزِّع الكمي لكل متسابق | (C1) |
القيود
- (ج1)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// Negation operation with integer Tensors
// %operand: [0, -2]
%result = "stablehlo.negate"(%operand) : (tensor<2xi32>) -> tensor<2xi32>
// %result: [0, 2]
// Negation operation with with complex tensors
// %operand: (2.5, 0.0)
%result = "stablehlo.negate"(%operand) : (tensor<1xcomplex<f32>>) -> tensor<1xcomplex<f32>>
// %result: [-2.5, -0.0]
ليس
دلالات الألفاظ
تؤدي هذه الدالة إلى تنفيذ أمر NOT من العناصر المقابلة في عشرات operand
وينتج عنها متسابق result
.
حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى القيم المنطقية: منطقي NOT.
- بالنسبة إلى الأعداد الصحيحة: ليس بعكس البت.
الوسيطات
الاسم | النوع | القيود |
---|---|---|
operand |
متّصِل من نوع القيمة المنطقية أو العدد الصحيح | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متّصِل من نوع القيمة المنطقية أو العدد الصحيح | (C1) |
القيود
- (ج1)
type(operand) = type(result)
.
أمثلة
// Bitwise operation with with integer tensors
// %operand: [[1, 2], [3, 4]]
%result = "stablehlo.not"(%operand) : (tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[-2, -3], [-4, -5]]
// Bitwise operation with with boolean tensors
// %operand: [true, false]
%result = "stablehlo.not"(%operand) : (tensor<2xi1>) -> tensor<2xi1>
// %result: [false, true]
optimization_barrier
دلالات الألفاظ
يضمن تنفيذ العمليات التي تنتج عن operand
قبل أي
العمليات التي تعتمد على result
وتمنع تحويلات المحول البرمجي
من نقل العمليات عبر الحاجز. بخلاف ذلك، تكون العملية
هوية، أي result = operand
.
الوسيطات
الاسم | النوع | القيود |
---|---|---|
operand |
الأعداد المتباينة من متساعات التوتر أو المتسّعات المكمّلة لكل متسابق أو الرموز المميزة | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
الأعداد المتباينة من متساعات التوتر أو المتسّعات المكمّلة لكل متسابق أو الرموز المميزة | (C1) |
القيود
- (ج1)
type(operand...) = type(result...)
.
أمثلة
// %operand0: 0.0
// %operand1: 1.0
%result0, %result1 = "stablehlo.optimization_barrier"(%operand0, %operand1) : (tensor<f32>, tensor<f32>) -> (tensor<f32>, tensor<f32>)
// %result0: 0.0
// %result1: 1.0
أو
دلالات الألفاظ
تؤدي هذه العملية إلى تنفيذ OR من ناحية العناصر باستخدام عاملين متوترين lhs
وrhs
وينتج عن ذلك result
.
متنسور. حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى القيم المنطقية: منطقي OR.
- بالنسبة إلى الأعداد الصحيحة: استخدام OR على مستوى البت.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
متوتر العدد الصحيح أو النوع المنطقي | (C1) |
(I2) | rhs |
متوتر العدد الصحيح أو النوع المنطقي | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتر العدد الصحيح أو النوع المنطقي | (C1) |
القيود
- (ج1)
type(lhs) = type(rhs) = type(result)
.
أمثلة
// Bitwise operation with with integer tensors
// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.or"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[5, 6], [7, 12]]
// Logical operation with with boolean tensors
// %lhs: [[false, false], [true, true]]
// %rhs: [[false, true], [false, true]]
%result = "stablehlo.or"(%lhs, %rhs) : (tensor<2x2xi1>, tensor<2x2xi1>) -> tensor<2x2xi1>
// %result: [[false, true], [true, true]]
خلاصة خارج الخلاصة
دلالات الألفاظ
كتابة inputs
في الخلاصة الخارجية وينتج رمز result
مميزًا.
يتم تحديد دلالات outfeed_config
.
مدخلات
التصنيف | الاسم | النوع |
---|---|---|
(I1) | inputs |
الأعداد المتباينة للمتسللات أو العشرات الكمي |
(I2) | token |
token |
(I3) | outfeed_config |
ثابت من النوع string |
المُخرَجات
الاسم | النوع |
---|---|
result |
token |
أمثلة
%result = "stablehlo.outfeed"(%input0, %token) {
outfeed_config = ""
} : (tensor<2x2x2xi64>, !stablehlo.token) -> !stablehlo.token
لبادة
دلالات الألفاظ
توسيع operand
عن طريق المساحة المتروكة حول المتوتر وكذلك بين العناصر
لمخطَّط متعرِّض مع padding_value
المقدم.
edge_padding_low
وedge_padding_high
يحددان مقدار المساحة المتروكة التي تمت إضافتها
عند النقطة المنخفضة (بجوار المؤشر 0) والسعر النهائي (بجوار أعلى مؤشر)
كل بُعد على التوالي. يمكن أن يكون مقدار المساحة المتروكة سالبًا، حيث
القيمة المطلقة للمساحة المتروكة السالبة تشير إلى عدد العناصر المطلوب إزالتها
من البُعد المحدد.
interior_padding
يحدد مقدار المساحة المتروكة بين أي اثنين
العناصر في كل بُعد والتي قد لا تكون سالبة. تحدث المساحة المتروكة الداخلية
قبل المساحة المتروكة للحواف بحيث تؤدي المساحة المتروكة السالبة إلى إزالة العناصر من
المعامل المبطّن بالداخل.
وتعريف result[result_index]
من الناحية الرسمية على النحو التالي:
operand[operand_index]
إذاresult_index = edge_padding_low + operand_index * (interior_padding + 1)
padding_value
بخلاف ذلك.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1)، (C2)، (C4) |
(I2) | padding_value |
متسّع 0 بُعدي أو متنسورة كمّية بكل متسابق | (C1) |
(I3) | edge_padding_low |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C1)، (C4) |
(I4) | edge_padding_high |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C1)، (C4) |
(I5) | interior_padding |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C2-C4) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتّر أو مستنسر كمي لكلّ متسابق | (C3-C6) |
القيود
- (ج1)
element_type(operand) = element_type(padding_value) = element_type(result)
. - (C2)
size(edge_padding_low) = size(edge_padding_high) = size(interior_padding) = rank(operand)
. - (C3)
0 <= interior_padding
: - (C4)
shape(result) = shape(operand) + edge_padding_low + max(shape(operand) - 1, 0) * interior_padding + edge_padding_high
.
أمثلة
// %operand: [
// [1, 2, 3],
// [4, 5, 6]
// ]
// %padding_value: 0
%result = "stablehlo.pad"(%operand, %padding_value) {
edge_padding_low = array<i64: 0, 1>,
edge_padding_high = array<i64: 2, 1>,
interior_padding = array<i64: 1, 2>
} : (tensor<2x3xi32>, tensor<i32>) -> tensor<5x9xi32>
// %result: [
// [0, 1, 0, 0, 2, 0, 0, 3, 0],
// [0, 0, 0, 0, 0, 0, 0, 0, 0],
// [0, 4, 0, 0, 5, 0, 0, 6, 0],
// [0, 0, 0, 0, 0, 0, 0, 0, 0],
// [0, 0, 0, 0, 0, 0, 0, 0, 0]
// ]
partition_id
دلالات الألفاظ
عرض partition_id
من العملية الحالية
المُخرَجات
الاسم | النوع |
---|---|
result |
متسابق أحادي الأبعاد من النوع ui32 |
أمثلة
%result = "stablehlo.partition_id"() : () -> tensor<ui32>
بوبشن
دلالات الألفاظ
ينفذ العدد من حيث العناصر في عدد وحدات البت المحددة في متنور operand
وينتج موتر result
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتر لنوع العدد الصحيح | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتر لنوع العدد الصحيح | (C1) |
القيود
- (ج1)
type(operand) = type(result)
.
أمثلة
// %operand: [0, 1, 2, 127]
%result = "stablehlo.popcnt"(%operand) : (tensor<4xi64>) -> tensor<4xi64>
// %result: [0, 1, 1, 7]
الطاقة
دلالات الألفاظ
لتنفيذ الأس على العناصر حسب العناصر في متسابق lhs
باستخدام موتّر rhs
نحصل على متوتر result
. حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى الأعداد الصحيحة: أس الأعداد الصحيحة.
- بالنسبة إلى الأعداد العشرية:
pow
من IEEE-754. - للأعداد المركّبة: الأس المركَّب.
- بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(power, lhs, rhs, type(result))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المنزِّع الكمي لكل متسابق | (C1) |
(I2) | rhs |
موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المنزِّع الكمي لكل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المنزِّع الكمي لكل متسابق | (C1) |
القيود
- (ج1)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// %lhs: [-2.0, -0.0, -36.0, 5.0, 3.0, 10000.0]
// %rhs: [2.0, 2.0, 1.1, 2.0, -1.0, 10.0]
%result = "stablehlo.power"(%lhs, %rhs) : (tensor<6xf64>, tensor<6xf64>) -> tensor<6xf64>
// %result: [4.0, 0.0, -nan, 25.0, 0.333333343, inf]
حقيقي
دلالات الألفاظ
هي استخراج الجزء الحقيقي من العنصر operand
واستخراج result
متنسور. وبشكل رسمي، لكل عنصر x
:
real(x) = is_complex(x) ? real_part(x) : x
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتر من النقطة العائمة أو نوع معقد | (C1)، (C2) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متّجه من نوع النقطة العائمة | (C1)، (C2) |
القيود
- (ج1)
shape(result) = shape(operand)
. - (C2) يتم تعريف
element_type(result)
على النحو التالي:complex_element_type(element_type(operand))
إذاis_complex(operand)
.element_type(operand)
بخلاف ذلك.
أمثلة
// %operand: [(1.0, 2.0), (3.0, 4.0)]
%result = "stablehlo.real"(%operand) : (tensor<2xcomplex<f32>>) -> tensor<2xf32>
// %result: [1.0, 3.0]
تسجيل
دلالات الألفاظ
تتلقى البيانات من قناة تتضمن channel_id
وتُنتج results
.
إذا كانت قيمة is_host_transfer
هي true
، تنقل العملية البيانات من
المضيف. وإلا، سيتم نقل البيانات من جهاز آخر. يعني ذلك
التنفيذ. تكرر هذه العلامة المعلومات المقدمة في
channel_type
، لذلك نخطّط في المستقبل للاحتفاظ بواحدة فقط منها.
(#666).
تتألف الدالة results
من قيم حمولة البيانات تأتي أولاً ورمزًا مميّزًا يأتي
الأخير. وفي المستقبل، نخطط لتقسيم الحمولة والرمز المميز إلى
المخرجات المنفصلة لتحسين الوضوح
(#670)
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | token |
token |
(C4) |
(I2) | channel_id |
ثابت من النوع si64 |
|
(I3) | channel_type |
تعداد DEVICE_TO_DEVICE وHOST_TO_DEVICE |
(C1) |
(I4) | is_host_transfer |
ثابت من النوع i1 |
(C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
results |
الأعداد المتباينة من متساعات التوتر أو العشرات الكمية أو الرموز المميزة | (C2-C4) |
القيود
- (C1) يتم تعريف
channel_type
على النحو التالي:HOST_TO_DEVICE
إذاis_host_transfer = true
،DEVICE_TO_DEVICE
بخلاف ذلك.
- (C2)
0 < size(results)
. - (C3)
is_empty(result[:-1])
أوis_tensor(type(results[:-1]))
. - (C4)
is_token(type(results[-1]))
.
أمثلة
%results0, %results1 = "stablehlo.recv"(%token) {
channel_handle = #stablehlo.channel_handle<handle = 1, type = 3>,
is_host_transfer = true
} : (!stablehlo.token) -> (tensor<2x2xi64>, !stablehlo.token)
reduce
دلالات الألفاظ
يتم تطبيق دالة الاختزال body
على inputs
وinit_values
على طول
dimensions
وينتج results
موتّرًا.
يعتمد ترتيب التخفيضات على التنفيذ، ما يعني أنّ السمة body
يجب أن تشكل init_values
خطًا أحاديًا لضمان أن تُنتج العملية
النتائج نفسها لجميع المدخلات في جميع عمليات التنفيذ. ومع ذلك، فإن هذا الشرط
لا تشير إلى العديد من التخفيضات الشائعة. مثلاً: إضافة النقطة العائمة
لا تشكل body
وصفر لـ init_values
رقمًا واحدًا في الواقع لأن
إضافة النقطة العائمة غير ارتباطية.
بشكل رسمي، results...[j0, ..., jR-1] = reduce(input_slices_converted)
حيث:
input_slices = inputs...[j0, ..., :, ..., jR-1]
، حيث يتم إدراج:
فيdimensions
.input_slices_converted = to_destination_type(input_slices..., type(func_inputs(body)[:len(func_inputs(body))//2])...)
.init_values_converted = to_destination_type(init_values..., type(func_inputs(body)[len(func_inputs(body))//2:])...)
.reduce(input_slices_converted) = exec(schedule)
لبعض الشجرة الثنائيةschedule
حيث:exec(node) = body(exec(node.left), exec(node.right))
.exec(leaf) = leaf.value
.
schedule
عبارة عن شجرة ثنائية كاملة محددة التنفيذ وترتيبها يتكون الاجتياز مما يلي:input_slices_converted...[index]
قيمة لكلindex
بوصةindex_space(input_slices_converted)
بترتيب تصاعدي منindex
.- ويتخللها مقدار محدد من التنفيذ
init_values_converted
في المواضع المحددة للتنفيذ.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | inputs |
الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق | (C1-C4)، (C6)، (C7) |
(I2) | init_values |
عدد متغير من العشرات ذوات الأبعاد 0 أو مقدرات التوتر الكمية لكل متسابق | (C2)، (C3) |
(I3) | dimensions |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C4)، (C5)، (C7) |
(I4) | body |
دالة | (C6) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
results |
الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق | (C3)، (C7)، (C8) |
القيود
- (ج1)
same(shape(inputs...))
. - (C2)
element_type(inputs...) = element_type(init_values...)
. - (C3)
0 < size(inputs) = size(init_values) = size(results) = N
: - (C4)
0 <= dimensions < rank(inputs[0])
. - (C5)
is_unique(dimensions)
. - (C6) النوع
body
هو(tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ...,
مكانtensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>)
is_promotable(element_type(inputs[i]), Ei)
- (C7)
shape(results...) = shape(inputs...)
باستثناء أنّ السمة لم يتم تضمين مقاساتinputs...
المقابلة لـdimensions
. - (C8)
element_type(results[i]) = Ei
لكلi
في[0,N)
.
أمثلة
// %input = [[0, 1, 2, 3, 4, 5]]
// %init_value = 0
%result = "stablehlo.reduce"(%input, %init_value) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
"stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
dimensions = array<i64: 1>
} : (tensor<1x6xi64>, tensor<i64>) -> tensor<1xi64>
// %result = [15]
reduce_precision
دلالات الألفاظ
تُجري عملية تحويل operand
حسب العناصر إلى نوع نقطة عائمة آخر.
التي تستخدم exponent_bits
وmantissa_bits
وتعود إلى الأصل
نقطة عائمة وينتج عنها متسابق output
.
أكثر رسمية:
- يتم تعديل بتات المانتيسا للقيمة الأصلية لتقريب القيمة الأصلية
إلى أقرب قيمة قابلة للتمثيل بـ
mantissa_bits
باستخدامroundToIntegralTiesToEven
دلالات. - وإذا كانت
mantissa_bits
أصغر من عدد وحدات بتات المانتيسا القيمة الأصلية، يتم اقتطاع وحدات بت مانتسا إلىmantissa_bits
. - ومن ثم، إذا لم تتناسب وحدات بت الأس للنتيجة المتوسطة
النطاق المقدم من
exponent_bits
، تتجاوز النتيجة المتوسطة إلى لا نهاية باستخدام العلامة الأصلية أو التدفقات السفلية إلى صفر باستخدام العلامة الأصلية. - بالنسبة إلى الأنواع المحدَّدة الكمية، يتم تنفيذ
dequantize_op_quantize( lambda operand: reduce_precision(operand, exponent_bits, mantissa_bits), operand, type(result))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق | (C1) |
(I2) | exponent_bits |
ثابت من النوع si32 |
(C2) |
(I3) | mantissa_bits |
ثابت من النوع si32 |
(C3) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
output |
متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق | (C1) |
القيود
- (ج1)
baseline_type(operand) = baseline_type(output)
. - (C2)
1 <= exponent_bits
. - (C3)
0 <= mantissa_bits
:
أمثلة
// Logical values: +Inf, NaN, +Denormal, 0.0, 65519.0, 65520.0
// %operand: [0x7FF0000000000000, 0x7FFFFFFFFFFFFFFF, 0x0000000000000001, 0.0, 65519.0, 65520.0]
%output = "stablehlo.reduce_precision"(%operand) {
exponent_bits = 5 : i32,
mantissa_bits = 10 : i32
} : (tensor<6xf64>) -> tensor<6xf64>
// Logical values: +Inf, NaN, 0.0, 0.0, 65504.0, +Inf
// %output: [0x7FF0000000000000, 0x7FFFFFFFFFFFFFFF, 0.0, 0.0, 65504.0, 0x7FF0000000000000]
reduce_scatter
دلالات الألفاظ
داخل كل مجموعة عملية في شبكة المعالجة StableHLO، تُجري الاختزال
باستخدام computations
، على قيم متوتر operand
من كل عملية،
قسمة نتيجة الاختزال في scatter_dimension
إلى أجزاء، والنقاط المبعثرة
الأجزاء المقسّمة بين العمليّتين لإنتاج result
.
تقسم هذه العملية شبكة عملية StableHLO إلى process_groups
وهي
على النحو التالي:
cross_replica(replica_groups)
إذا كانت القيمة هيchannel_id <= 0 and use_global_device_ids = false
.cross_replica_and_partition(replica_groups)
إذا كانت القيمة هيchannel_id > 0 and use_global_device_ids = false
.flattened_ids(replica_groups)
إذا كانت القيمة هيchannel_id > 0 and use_global_device_ids = true
.
بعد ذلك، ضمن كل process_group
:
reduced_value = all_reduce(operand, replica_groups, channel_id, use_global_device_ids, computation)
.parts@sender = split(reduced_value@sender, dim(process_groups, 1), scatter_dimension)
.result@receiver = parts@sender[receiver_index]
لكلsender
بوصةprocess_group
، حيثreceiver_index = process_group.index(receiver)
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1)، (C2)، (C7)، (C8) |
(I2) | scatter_dimension |
ثابت من النوع si64 |
(C1)، (C2)، (C8) |
(I3) | replica_groups |
ثابت التوتر الثنائي الأبعاد من النوع si64 |
(C3-C5) |
(I4) | channel_id |
ثابت من النوع si64 |
(C6) |
(I5) | use_global_device_ids |
ثابت من النوع i1 |
(C6) |
(I6) | computation |
دالة | (C7) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتّر أو مستنسر كمي لكلّ متسابق | (C8-C9) |
القيود
- (ج1)
dim(operand, scatter_dimension) % dim(process_groups, 1) = 0
. - (C2)
0 <= scatter_dimension < rank(operand)
. - (C3)
is_unique(replica_groups)
: - (C4) يتم تعريف
size(replica_groups)
على النحو التالي:num_replicas
في حال استخدامcross_replica
.num_replicas
في حال استخدامcross_replica_and_partition
.num_processes
في حال استخدامflattened_ids
.
- (C5)
0 <= replica_groups < size(replica_groups)
. - (C6) إذا كانت
use_global_device_ids = true
، يتم عندهاchannel_id > 0
. - (C7)
computation
من النوع(tensor<E>, tensor<E>) -> (tensor<E>)
حيثis_promotable(element_type(operand), E)
- (C8)
shape(result) = shape(operand)
باستثناء:dim(result, scatter_dimension) = dim(operand, scatter_dimension) / dim(process_groups, 1)
.
- (C9)
element_type(result) = E
.
أمثلة
// num_replicas: 2
// num_partitions: 1
// %operand@(0, 0): [[1, 2, 3, 4],
// [5, 6, 7, 8]]
// %operand@(1, 0): [[9, 10, 11, 12],
// [13, 14, 15, 16]]
%result = "stablehlo.reduce_scatter"(%operand) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
"stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
scatter_dimension = 1 : i64,
replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>,
channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
} : (tensor<2x4xi64>) -> tensor<2x2xi64>
//
// %result@(0, 0): [[10, 12],
// [18, 20]]
// %result@(1, 0): [[14, 16],
// [22, 24]]
reduce_window
دلالات الألفاظ
يؤدي هذا الإجراء إلى تطبيق دالة التقليل body
على نافذتَي inputs
وinit_values
.
وتُنتج results
.
يوضّح المخطّط التالي طريقة حساب العناصر في results...
من
inputs...
باستخدام مثال ملموس.
بشكل أكثر رسمية،
results...[result_index] = reduce(windows, init_values, axes(inputs...), body)
(راجِع تقليل) حيث:
padded_inputs = pad(inputs..., init_values..., padding[:, 0], padding[:, 1], base_dilations - 1)
.window_start = result_index * window_strides
.window_end = window_start + (window_dimensions - 1) * window_dilations + 1
.windows = slice(padded_inputs..., window_start, window_end, window_dilations)
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | inputs |
الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق | (C1-C4)، (C6)، (C8)، (C10)، (C12)، (C13)، (C15) |
(I2) | init_values |
عدد متغير من العشرات ذوات الأبعاد 0 أو مقدرات التوتر الكمية لكل متسابق | (C1)، (C13) |
(I3) | window_dimensions |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C4)، (C5)، (C15) |
(I4) | window_strides |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C6)، (C7)، (C15) |
(I5) | base_dilations |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C8)، (C9)، (C15) |
(I6) | window_dilations |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C10)، (C11)، (C15) |
(I7) | padding |
ثابت التوتر الثنائي الأبعاد من النوع si64 |
(C12)، (C15) |
(I8) | body |
دالة | (C13) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
results |
الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق | (C1)، (C14-C16) |
القيود
- (ج1)
0 < size(inputs) = size(init_values) = size(results) = N
. - (C2)
same(shape(inputs...))
. - (C3)
element_type(inputs...) = element_type(init_values...)
: - (C4)
size(window_dimensions) = rank(inputs[0])
. - (C5)
0 < window_dimensions
. - (C6)
size(window_strides) = rank(inputs[0])
. - (C7)
0 < window_strides
. - (C8)
size(base_dilations) = rank(inputs[0])
. - (C9)
0 < base_dilations
. - (C10)
size(window_dilations) = rank(inputs[0])
. - (C11)
0 < window_dilations
. - (C12)
shape(padding) = [rank(inputs[0]), 2]
. - (C13) النوع
body
هو(tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ...,
. مكانtensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>)
is_promotable(element_type(inputs[i]), Ei)
- (C14)
same(shape(results...))
. - (C15)
shape(results[0]) = num_windows
حيث:dilated_input_shape = shape(inputs[0]) = 0 ? 0 : (shape(inputs[0]) - 1) * base_dilations + 1
.padded_input_shape = padding[:, 0] + dilated_input_shape + padding[:, 1]
.dilated_window_shape = (window_dimensions - 1) * window_dilations + 1
.is_empty_window = padded_input_shape = 0 || dilated_window_shape > padded_input_shape
.num_windows = is_empty_window ? 0 : floor((padded_input_shape - dilated_window_shape) / window_strides) + 1
.
- (C16)
element_type(results[i]) = Ei
لكلi
في[0,N)
.
أمثلة
// %input = [[1, 2], [3, 4], [5, 6]]
// %init_value = 0
%result = "stablehlo.reduce_window"(%input, %init_value) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
"stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
window_dimensions = array<i64: 2, 1>,
window_strides = array<i64: 4, 1>,
base_dilations = array<i64: 2, 1>,
window_dilations = array<i64: 3, 1>,
padding = dense<[[2, 1], [0, 0]]> : tensor<2x2xi64>
} : (tensor<3x2xi64>, tensor<i64>) -> tensor<2x2xi64>
// %result = [[0, 0], [3, 4]]
الباقي
دلالات الألفاظ
لتنفيذ باقي العناصر من حيث العناصر في معادلات المحصلة lhs
وقسمة القاسم rhs
نحصل على متوتر result
.
وبشكل أكثر رسمية، يتم أخذ علامة النتيجة من الربح،
تكون القيمة المطلقة للناتج دائمًا أقل من القيمة المطلقة للقاسم.
ويتم حساب الباقي على النحو التالي: lhs - d * rhs
، حيث يتم تحديد d
على النحو التالي:
- بالنسبة إلى الأعداد الصحيحة:
stablehlo.divide(lhs, rhs)
. - بالنسبة إلى الأعداد العشرية:
division(lhs, rhs)
من IEEE-754 مع سمة التقريبroundTowardZero
- بالنسبة إلى الأرقام المركّبة: يتم تحديدها لاحقًا. (#997)
- بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(remainder, lhs, rhs, type(result))
.
بالنسبة إلى أنواع العناصر العائمة، تتعارض هذه العملية مع
عملية remainder
تستند إلى مواصفات IEEE-754 حيث تكون d
قيمة متكاملة
الأقرب إلى القيمة الدقيقة لـ lhs/rhs
التي ترتبط بـ وحتى.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المتسابق الكمي لكل متسابق | (C1) |
(I2) | rhs |
موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المتسابق الكمي لكل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المتسابق الكمي لكل متسابق | (C1) |
القيود
- (ج1)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// %lhs: [17, -17, 17, -17]
// %rhs: [3, 3, -3, -3]
%result = "stablehlo.remainder"(%lhs, %rhs) : (tensor<4xi64>, tensor<4xi64>) -> tensor<4xi64>
// %result: [2, -2, 2, -2]
replica_id
دلالات الألفاظ
عرض replica_id
من العملية الحالية
المُخرَجات
الاسم | النوع |
---|---|
result |
متسابق أحادي الأبعاد من النوع ui32 |
أمثلة
%result = "stablehlo.replica_id"() : () -> tensor<ui32>
إعادة تشكيل
دلالات الألفاظ
يعيد تشكيل سينسور operand
إلى متسابق result
. من الناحية النظرية،
الحفاظ على نفس التمثيل المتعارف عليه ولكن من المحتمل
الشكل، على سبيل المثال من tensor<2x3xf32>
إلى tensor<3x2xf32>
أو tensor<6xf32>
.
بشكل رسمي، result[result_index] = operand[operand_index]
حيث
لهما result_index
وoperand_index
نفس الموضع في المعجم
ترتيب index_space(result)
وindex_space(operand)
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتر أو متنسّر كمي | (C1-C3) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتر أو متنسّر كمي | (C1-C3) |
القيود
- (C1)
element_type(result)
يتم تقديمها من خلال:element_type(operand)
، إذا كانت!is_per_axis_quantized(operand)
.element_type(operand)
باستثناء أنّquantization_dimension(operand)
قد تختلف السمةquantization_dimension(result)
في الحالات الأخرى.
- (C2)
size(operand) = size(result)
. - (C3) إذا كانت
is_per_axis_quantized(operand)
:reduce(dims(operand, [0, 1, ..., quantization_dimension(operand) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y) = reduce(dims(result, [0, 1, ..., quantization_dimension(result) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y)
.dim(operand, quantization_dimension(operand)) = dim(result, quantization_dimension(result))
.reduce(dims(operand, [quantization_dimension(operand) + 1, ..., rank(operand) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y) = reduce(dims(result, [quantization_dimension(result) + 1, ..., rank(result) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y)
.
أمثلة
// %operand: [[1, 2, 3], [4, 5, 6]]
%result = "stablehlo.reshape"(%operand) : (tensor<2x3xi32>) -> tensor<3x2xi32>
// %result: [[1, 2], [3, 4], [5, 6]]
إلغاء
دلالات الألفاظ
يعكس ترتيب العناصر في operand
على طول dimensions
المحدد
وينتج متسابق result
. بشكل أكثر رسمية،
result[result_index] = operand[operand_index]
حيث:
operand_index[d] = dim(result, d) - result_index[d] - 1
إذا كانت القيمة هيd
فيdimensions
.operand_index[d] = result_index[d]
بخلاف ذلك.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1)، (C3) |
(I2) | dimensions |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C2)، (C3) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1)، (C3) |
القيود
- (ج1)
type(operand) = type(result)
. - (C2)
is_unique(dimensions)
. - (C3)
0 <= dimensions < rank(result)
:
أمثلة
// %operand = [[1, 2], [3, 4], [5, 6]]
%result = "stablehlo.reverse"(%operand) {
dimensions = array<i64: 1>
} : (tensor<3x2xi32>) -> tensor<3x2xi32>
// %result: [[2, 1], [4, 3], [6, 5]]
رانغ
دلالات الألفاظ
تنشئ أرقامًا عشوائية باستخدام خوارزمية rng_distribution
وتُنتج
متسابق result
لشكل معين shape
.
إذا كانت rng_distribution = UNIFORM
، سيتم إنشاء أرقام عشوائية.
بعد التوزيع المنتظم على الفاصل الزمني [a, b)
. إذا كانت a >= b
،
يكون السلوك غير محدد.
إذا كانت rng_distribution = NORMAL
، سيتم إنشاء أرقام عشوائية.
بعد التوزيع الطبيعي، يكون المتوسط = a
والانحراف المعياري = b
.
إذا كانت b < 0
، سيكون السلوك غير محدَّد.
يتم تحديد الطريقة الدقيقة لإنشاء الأرقام العشوائية. بالنسبة على سبيل المثال، قد تكون حاسمة أو لا تكون حاسمة، وقد تستخدم أو لا حالة مخفية.
في المحادثات مع العديد من الأطراف المعنية، ظهرت هذه العملية بنفس قد تم إيقافها، لذا نخطط في المستقبل لاستكشاف إزالتها (#597)
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | a |
متين عشري الأبعاد للعدد الصحيح أو النوع المنطقي أو نوع النقطة العائمة | (C1)، (C2) |
(I2) | b |
متين عشري الأبعاد للعدد الصحيح أو النوع المنطقي أو نوع النقطة العائمة | (C1)، (C2) |
(I3) | shape |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C3) |
(I4) | rng_distribution |
تعداد UNIFORM وNORMAL |
(C2) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
مقياس العدد الصحيح أو المنطقي أو نوع النقطة العائمة | (C1-C3) |
القيود
- (ج1)
element_type(a) = element_type(b) = element_type(result)
. - (C2) إذا كانت
rng_distribution = NORMAL
، يتم عندهاis_float(a)
. - (C3)
shape(result) = shape
:
أمثلة
// %a = 0
// %b = 2
// %shape = [3, 3]
%result = "stablehlo.rng"(%a, %b, %shape) {
rng_distribution = #stablehlo<rng_distribution UNIFORM>
} : (tensor<i32>, tensor<i32>, tensor<2xi64>) -> tensor<3x3xi32>
// %result: [
// [1, 0, 1],
// [1, 1, 1],
// [0, 0, 0]
// ]
rng_bit_generator
دلالات الألفاظ
عرض output
مملوءة بوحدات بت عشوائية منتظمة وحالة إخراج معدَّلة
الدالة output_state
باستخدام خوارزمية إنشاء الأرقام الزائفة rng_algorithm
بحالة أولية initial_state
. يمكن ضمان أن يكون الناتج
الدالة الحاسمة للدالة initial_state
، ولكن ليس مضمونًا
حتميًا بين عمليات التنفيذ.
rng_algorithm
هو واحد مما يلي:
DEFAULT
: خوارزمية محددة للتنفيذ.THREE_FRY
: الصيغة المعرَّفة من قِبل التنفيذ لخوارزمية Threefry*PHILOX
: الصيغة المحددة للتنفيذ لخوارزمية Philox.*
* راجِع: Salmon et al. SC 2011. الأرقام العشوائية المتوازية: طريقة سهلة مثل 1، 2، 3.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | rng_algorithm |
تعداد DEFAULT وTHREE_FRY وPHILOX |
(C2) |
(I2) | initial_state |
متين أحادي البعد من النوع ui64 |
(C1)، (C2) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
output_state |
متين أحادي البعد من النوع ui64 |
(C1) |
output |
متّصِل من عدد صحيح أو نوع نقطة عائمة |
القيود
- (ج1)
type(initial_state) = type(output_state)
. - (C2) يتم تعريف
size(initial_state)
على النحو التالي:- محددة للتنفيذ إذا كانت
rng_algorithm = DEFAULT
. 2
إذاrng_algorithm = THREE_FRY
.2
أو3
إذاrng_algorithm = PHILOX
.
- محددة للتنفيذ إذا كانت
أمثلة
// %initial_state: [1, 2]
%output_state, %output = "stablehlo.rng_bit_generator"(%initial_state) {
rng_algorithm = #stablehlo<rng_algorithm THREE_FRY>
} : (tensor<2xui64>) -> (tensor<2xui64>, tensor<2x2xui64>)
// %output_state: [1, 6]
// %output: [
// [9236835810183407956, 16087790271692313299],
// [18212823393184779219, 2658481902456610144]
// ]
round_nearest_afz
دلالات الألفاظ
لإجراء تقريب من ناحية العناصر تجاه أقرب عدد صحيح، مما يؤدي إلى فصل الروابط
من الصفر، في متوتر operand
وينتج موتّر result
. عمليات التنفيذ
عملية roundToIntegralTiesToAway
من مواصفات IEEE-754. بالنسبة
محددة الكمية، ينفذ
dequantize_op_quantize(round_nearest_afz, operand, type(result))
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق | (C1) |
القيود
- (ج1)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// %operand = [-2.5, 0.4, 0.5, 0.6, 2.5]
%result = "stablehlo.round_nearest_afz"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// %result: [-3.0, 0.0, 1.0, 1.0, 3.0]
round_nearest_even
دلالات الألفاظ
لإجراء تقريب من ناحية العناصر تجاه أقرب عدد صحيح، مما يؤدي إلى قطع الروابط
تجاه العدد الصحيح الزوجي في موجِّه operand
وينتج عنه result
متنسور. تنفيذ عملية roundToIntegralTiesToEven
من IEEE-754
المواصفات. بالنسبة للأنواع الكَمية، تنفذ
dequantize_op_quantize(round_nearest_even, operand, type(result))
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق | (C1) |
القيود
- (ج1)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// %operand = [-2.5, 0.4, 0.5, 0.6, 2.5]
%result = "stablehlo.round_nearest_even"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// %result: [-2.0, 0.0, 0.0, 1.0, 2.0]
rsqrt
دلالات الألفاظ
لتنفيذ عملية جذر تربيعي تبادلي من حيث العناصر على متسابق operand
نحصل على موتّر result
. حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى الأعداد العشرية:
rSqrt
من IEEE-754. - بالنسبة للأعداد المركّبة: جذر مربع متبادلي مركّب.
- بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(rsqrt, operand, type(result))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
القيود
- (ج1)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// %operand: [[1.0, 4.0], [9.0, 25.0]]
%result = "stablehlo.rsqrt"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[1.0, 0.5], [0.33333343, 0.2]]
بعثرة
دلالات الألفاظ
يتم إنشاء results
متسابقًا تساوي inputs
متسابقًا باستثناء ذلك
يتم تعديل الشرائح المتعددة المحددة بواسطة scatter_indices
بالقيم
updates
باستخدام update_computation
.
يوضّح المخطّط التالي كيفية ارتباط العناصر في updates...
بالعناصر في
results...
باستخدام مثال ملموس. يختار المخطط بعض الأمثلة
يشير updates...
ويشرح بالتفصيل أي مؤشرات results...
يتجاوب مع.
بشكل رسمي، لجميع update_index
في index_space(updates[0])
:
update_scatter_dims = [d for d in axes(updates[0]) and d not in update_window_dims]
.update_scatter_index = update_index[update_scatter_dims...]
.- تعريف "
start_index
" على أنّه:scatter_indices[si0, ..., :, ..., siN]
حيث يكونsi
فرديًا العناصر فيupdate_scatter_index
و:
عند إدراج فهرسindex_vector_dim
، إذا كانتindex_vector_dim
<rank(scatter_indices)
[scatter_indices[update_scatter_index]]
بخلاف ذلك.
- بالنسبة إلى
d_input
فيaxes(inputs[0])
،full_start_index[d_input] = start_index[d_start]
إذاd_input = scatter_dims_to_operand_dims[d_start]
full_start_index[d_input] = 0
بخلاف ذلك.
- بالنسبة إلى
d_input
فيaxes(inputs[0])
،full_batching_index[d_input] = update_scatter_index[d_start - (d_start < index_vector_dim ? 0 : 1)]
إذا كانd_input = input_batching_dims[i_batching]
وd_start = scatter_indices_batching_dims[i_batching]
full_batching_index[d_input] = 0
بخلاف ذلك.
update_window_index = update_index[update_window_dims...]
.full_window_index = [wi0, ..., 0, ..., wiN]
حيث يكونwi
فرديًا العناصر فيupdate_window_index
، و0
يتم إدراجها في الفهارس منinserted_window_dims
وinput_batching_dims
.result_index = full_start_index + full_batching_index + full_window_index
.
بناءً على ذلك، results = exec(schedule, inputs)
، حيث:
schedule
هو تبديل محدد تنفيذًاindex_space(updates[0])
exec([update_index, ...], results) = exec([...], updated_results)
حيث:- في حال كان
result_index
ضمن حدودshape(results...)
updates_converted = to_destination_type( updates...[update_index], type(func_inputs(update_computation) [len(func_inputs(update_computation))//2:])... )
updated_values = update_computation(results...[result_index], updates_converted)
updated_results
هو نسخة منresults
معresults...[result_index]
. مضبوطة علىupdated_values...
- ويمكنك بدلاً من ذلك
updated_results = results
.
- في حال كان
exec([], results) = results
.
إذا كانت indices_are_sorted
هي true
، يمكن لعملية التنفيذ أن تفترض أنّ
يتم ترتيب scatter_indices
حسب scatter_dims_to_operand_dims
،
وإلا يكون السلوك غير محدد. بشكل رسمي، لجميع i1 < i2
من
indices(result)
، full_start_index(i1)
<= full_start_index(i2)
.
إذا كانت unique_indices
هي true
، يمكن لعملية التنفيذ أن تفترض أنّ كل
مؤشرات result_index
المتبعثرة إليها فريدة. إذا كانت السمة unique_indices
true
لكن المؤشرات المبعثرة غير فريدة عندئذ يكون السلوك
غير محددة.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | inputs |
الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق | (C1)، (C2)، (C4-C6)، (C11)، (C13)، (C18)، (C21)، (C23-C24) |
(I2) | scatter_indices |
متوتر لنوع العدد الصحيح | (C4)، (C15)، (C19)، (C22) |
(I3) | updates |
الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق | (C3-C6)، (C8) |
(I4) | update_window_dims |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C2)، (C4)، (C7-C8) |
(I5) | inserted_window_dims |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C2)، (C4)، (C9-C11) |
(I6) | input_batching_dims |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C2)، (C4)، (C9)، (C12-13)، (C17-18)، (C20) |
(I7) | scatter_indices_batching_dims |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C14-C18) |
(I8) | scatter_dims_to_operand_dims |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C19-C21) |
(I9) | index_vector_dim |
ثابت من النوع si64 |
(C4)، (C16)، (C19)، (C22) |
(I10) | indices_are_sorted |
ثابت من النوع i1 |
|
(I11) | unique_indices |
ثابت من النوع i1 |
|
(I12) | update_computation |
دالة | (C23) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
results |
الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق | (C24-C25) |
القيود
- (ج1)
same(shape(inputs...))
. - (C2) `rank(inputs[0]) = size(update_window_dims) + size(inserted_window_dims)
- size(input_batching_dims)`.
- (C3)
same(shape(updates...))
: - (C4)
shape(updates[0]) = combine(update_scatter_dim_sizes, update_window_dim_sizes)
حيث:update_scatter_dim_sizes = shape(scatter_indices)
باستثناء ذلك حجم البُعدscatter_indices
بما يتوافق مع لم يتم تضمينindex_vector_dim
.update_window_dim_sizes <= shape(inputs[0])
باستثناء ذلك أحجام السمات فيinputs[0]
بما يتوافق معinserted_window_dims
وinput_batching_dims
غير متضمنة.- يضع
combine
update_scatter_dim_sizes
في المحاور المقابلة لـupdate_scatter_dims
وupdate_window_dim_sizes
على المحورين المقابلين إلىupdate_window_dims
.
- (C5)
0 < size(inputs) = size(updates) = N
. - (C6)
element_type(updates...) = element_type(inputs...)
. - (C7)
is_unique(update_window_dims) and is_sorted(update_window_dims)
. - (C8)
0 <= update_window_dims < rank(updates[0])
. - (C9)
is_unique(concatenate(inserted_window_dims, input_batching_dims))
- (C10)
is_sorted(inserted_window_dims)
. - (C11)
0 <= inserted_window_dims < rank(inputs[0])
. - (C12)
is_sorted(input_batching_dims)
. - (C13)
0 <= input_batching_dims < rank(inputs[0]))
. - (C14)
is_unique(scatter_indices_batching_dims)
. - (C15)
0 <= scatter_indices_batching_dims < rank(scatter_indices)
. - (C16)
index_vector_dim not in scatter_indices_batching_dims
. - (C17)
size(input_batching_dims) == size(scatter_indices_batching_dims)
. - (C18)
dim(inputs[0], input_batching_dims...) = dim(scatter_indices, scatter_indices_batching_dims...)
. - (C19)
size(scatter_dims_to_operand_dims) = index_vector_dim < rank(scatter_indices) ? dim(scatter_indices, index_vector_dim) : 1
. - (C20)
is_unique(concatenate(scatter_dims_to_operand_dims, input_batching_dims))
. - (C21)
0 <= scatter_dims_to_operand_dims < rank(inputs[0])
. - (C22)
0 <= index_vector_dim <= rank(scatter_indices)
. - (C23)
update_computation
يحتوي على النوع(tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ..., tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>)
، حيثis_promotable(element_type(inputs[i]), Ei)
. - (C24)
shape(inputs...) = shape(results...)
. - (C25)
element_type(results[i]) = Ei
لكلi
في[0,N)
.
أمثلة
// %input: [
// [
// [[1, 2], [3, 4], [5, 6], [7, 8]],
// [[9, 10],[11, 12], [13, 14], [15, 16]],
// [[17, 18], [19, 20], [21, 22], [23, 24]]
// ],
// [
// [[25, 26], [27, 28], [29, 30], [31, 32]],
// [[33, 34], [35, 36], [37, 38], [39, 40]],
// [[41, 42], [43, 44], [45, 46], [47, 48]]
// ]
// ]
// %scatter_indices: [
// [
// [[0, 0], [1, 0], [2, 1]],
// [[0, 1], [1, 1], [0, 9]]
// ],
// [
// [[0, 0], [2, 1], [2, 2]],
// [[1, 2], [0, 1], [1, 0]]
// ]
// ]
// %update: [
// [
// [[1, 1], [1, 1], [1, 1]],
// [[1, 1], [1, 1], [1, 1]]
// ],
// [
// [[1, 1], [1, 1], [1, 1]],
// [[1, 1], [1, 1], [1, 1]]
// ]
// ]
%result = "stablehlo.scatter"(%input, %scatter_indices, %update) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
"stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
scatter_dimension_numbers = #stablehlo.scatter<
update_window_dims = [3, 4],
inserted_window_dims = [1],
input_batching_dims = [0],
scatter_indices_batching_dims = [1],
scatter_dims_to_operand_dims = [2, 1],
index_vector_dim = 3>,
indices_are_sorted = false,
unique_indices = false
} : (tensor<2x3x4x2xi64>, tensor<2x2x3x2xi64>, tensor<2x2x3x2x2xi64>) -> tensor<2x3x4x2xi64>
// %result: [
// [
// [[3, 4], [6, 7], [6, 7], [7, 8]],
// [[9, 10],[11, 12], [15, 16], [17, 18]],
// [[17, 18], [19, 20], [22, 23], [24, 25]]
// ],
// [
// [[25, 26], [28, 29], [30, 31], [31, 32]],
// [[35, 36], [38, 39], [38, 39], [39, 40]],
// [[41, 42], [44, 45], [46, 47], [47, 48]]
// ]
// ]
تحديد
دلالات الألفاظ
لإنشاء متسابق result
حيث يتم تحديد كل عنصر من on_true
أو
موتّر on_false
استنادًا إلى قيمة العنصر المتجاوب pred
.
رسميًا أكثر، result[result_index] = pred_element ? on_true[result_index] :
on_false[result_index]
، حيث pred_element = rank(pred) = 0 ? pred[] :
pred[result_index]
. بالنسبة للأنواع الكَمية، تنفذ
dequantize_select_quantize(pred, on_true, on_false, type(result))
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | pred |
متوتر من النوع i1 |
(C1) |
(I2) | on_true |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1-C2) |
(I3) | on_false |
متوتّر أو مستنسر كمي لكلّ متسابق | (C2) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتّر أو مستنسر كمي لكلّ متسابق | (C2) |
القيود
- (ج1)
rank(pred) = 0 or shape(pred) = shape(on_true)
. - (C2)
baseline_type(on_true) = baseline_type(on_false) = baseline_type(result)
.
أمثلة
// %pred: [[false, true], [true, false]]
// %on_true: [[1, 2], [3, 4]]
// %on_false: [[5, 6], [7, 8]]
%result = "stablehlo.select"(%pred, %on_true, %on_false) : (tensor<2x2xi1>, tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[5, 2], [3, 8]]
select_and_scatter
دلالات الألفاظ
مبعثر القيم من متوتر source
باستخدام scatter
بناءً على
ناتج reduce_window
لم متوتر input
باستخدام select
ونتج عنه
متوتر result
.
يوضّح المخطّط التالي طريقة حساب العناصر في result
من
operand
وsource
باستخدام مثال ملموس.
أكثر رسمية:
selected_values = reduce_window_without_init(...)
مع مصادر الإدخال التالية:inputs = [operand].
- يتم استخدام
window_dimensions
وwindow_strides
وpadding
كما هي. base_dilations = windows_dilations = 1
.- تعريف "
body
" على أنّه:
def body(arg0: tensor<E>, arg1: tensor<E>) -> tensor<E>: return select(arg0, arg1) ? arg0 : arg1;
أين يعمل
E = element_type(operand)
وreduce_window_without_init
تمامًا مثلreduce_window
، باستثناء أنschedule
للنوع الأساسي لا يشتملreduce
(راجِع تقليل) على قيم init. الوقت حاليًا غير محدد ماذا يحدث إذا لم تحتوي النافذة المقابلة على قيم (#731)result[result_index] = reduce([source_values], [init_value], [0], scatter)
حيث:source_values = [source[source_index] for source_index in source_indices]
.selected_index(source_index) = operand_index
إذاselected_values[source_index]
يتضمّن العنصرoperand
منoperand_index
.source_indices = [source_index for source_index in indices(source) if selected_index(source_index) = result_index]
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1-C4)، (C6)، (C8-C11) |
(I2) | source |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1)، (C2) |
(I3) | init_value |
متسّع 0 بُعدي أو متنسورة كمّية بكل متسابق | (C3) |
(I4) | window_dimensions |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C2)، (C4)، (C5) |
(I5) | window_strides |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C2)، (C6)، (C7) |
(I6) | padding |
ثابت التوتر الثنائي الأبعاد من النوع si64 |
(C2)، (C8) |
(I7) | select |
دالة | (C9) |
(I8) | scatter |
دالة | (C10) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتّر أو مستنسر كمي لكلّ متسابق | (C11-C12) |
القيود
- (ج1)
element_type(operand) = element_type(source)
. - (C2)
shape(source) = num_windows
حيث:padded_operand_shape = padding[:, 0] + shape(operand) + padding[:, 1]
.is_empty_window = padded_operand_shape = 0 || window_dimensions > padded_operand_shape
.num_windows = is_empty_window ? 0 : floor((padded_operand_shape - window_dimensions) / window_strides) + 1
.
- (C3)
element_type(init_value) = element_type(operand)
: - (C4)
size(window_dimensions) = rank(operand)
. - (C5)
0 < window_dimensions
. - (C6)
size(window_strides) = rank(operand)
. - (C7)
0 < window_strides
. - (C8)
shape(padding) = [rank(operand), 2]
. - (C9)
select
من النوع(tensor<E>, tensor<E>) -> tensor<i1>
حيث يكونE = element_type(operand)
- (C10)
scatter
من النوع(tensor<E>, tensor<E>) -> tensor<E>
حيث يكونis_promotable(element_type(operand), E)
- (C11)
shape(operand) = shape(result)
. - (C12)
element_type(result) = E
.
أمثلة
// %operand: [[1, 5], [2, 5], [3, 6], [4, 4]]
// %source: [[5, 6], [7, 8]]
// %init_value: 0
%result = "stablehlo.select_and_scatter"(%operand, %source, %init_value) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = "stablehlo.compare"(%arg0, %arg1) {
comparison_direction = #stablehlo<comparison_direction GE>
} : (tensor<i64>, tensor<i64>) -> tensor<i1>
"stablehlo.return"(%0) : (tensor<i1>) -> ()
}, {
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
"stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
window_dimensions = array<i64: 3, 1>,
window_strides = array<i64: 2, 1>,
padding = dense<[[0, 1], [0, 0]]> : tensor<2x2xi64>
} : (tensor<4x2xi64>, tensor<2x2xi64>, tensor<i64>) -> tensor<4x2xi64>
// %result: [[0, 0], [0, 0], [5, 14], [7, 0]]
إرسال
دلالات الألفاظ
إرسال inputs
إلى قناة channel_id
وإنشاء رمز مميّز result
إذا كانت قيمة is_host_transfer
هي true
، تنقل العملية البيانات إلى
المضيف. وإلا سيتم نقل البيانات إلى جهاز آخر. يعني ذلك
التنفيذ. تكرر هذه العلامة المعلومات المقدمة في
channel_type
، لذلك نخطّط في المستقبل للاحتفاظ بواحدة فقط منها.
(#666).
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | inputs |
الأعداد المتباينة للمتسللات أو العشرات الكمي | |
(I2) | token |
token |
|
(I3) | channel_id |
ثابت من النوع si64 |
|
(I4) | channel_type |
تعداد DEVICE_TO_DEVICE وDEVICE_TO_HOST |
(C1) |
(I5) | is_host_transfer |
ثابت من النوع i1 |
(C1) |
المُخرَجات
الاسم | النوع |
---|---|
result |
token |
القيود
- (C1) يتم تعريف
channel_type
على النحو التالي:DEVICE_TO_HOST
إذاis_host_transfer = true
،DEVICE_TO_DEVICE
بخلاف ذلك.
أمثلة
%result = "stablehlo.send"(%operand, %token) {
channel_handle = #stablehlo.channel_handle<handle = 1, type = 2>,
is_host_transfer = true
} : (tensor<2x2xi64>, !stablehlo.token) -> !stablehlo.token
shift_left
دلالات الألفاظ
لتنفيذ عملية التغيير الأيسر على مستوى العناصر في متسابق lhs
بمقدار rhs
البت وينتج متسابق result
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
متوتر لنوع العدد الصحيح | (C1) |
(I2) | rhs |
متوتر لنوع العدد الصحيح | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتر لنوع العدد الصحيح | (C1) |
القيود
- (ج1)
type(lhs) = type(rhs) = type(result)
.
أمثلة
// %lhs: [-1, 0, 1]
// %rhs: [1, 2, 3]
%result = "stablehlo.shift_left"(%lhs, %rhs): (tensor<3xi64>, tensor<3xi64>) -> tensor<3xi64>
// %result: [-2, 0, 8]
shift_right_arithmetic
دلالات الألفاظ
ينفذ عملية الانتقال الأيمن حسابيًا من حيث العناصر على موتر lhs
من خلال
عدد rhs
من البتات وينتج متسابق result
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
متوتر لنوع العدد الصحيح | (C1) |
(I2) | rhs |
متوتر لنوع العدد الصحيح | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتر لنوع العدد الصحيح | (C1) |
القيود
- (ج1)
type(lhs) = type(rhs) = type(result)
.
أمثلة
// %lhs: [-1, 0, 8]
// %rhs: [1, 2, 3]
%result = "stablehlo.shift_right_arithmetic"(%lhs, %rhs): (tensor<3xi64>, tensor<3xi64>) -> tensor<3xi64>
// %result: [-1, 0, 1]
shift_right_logical
دلالات الألفاظ
لتنفيذ عملية التحول الأيمن المنطقية من حيث العناصر على موتر lhs
بواسطة rhs
عدد وحدات البت وينتج موتّر result
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
متوتر لنوع العدد الصحيح | (C1) |
(I2) | rhs |
متوتر لنوع العدد الصحيح | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتر لنوع العدد الصحيح | (C1) |
القيود
- (ج1)
type(lhs) = type(rhs) = type(result)
.
أمثلة
// %lhs: [-1, 0, 8]
// %rhs: [1, 2, 3]
%result = "stablehlo.shift_right_logical"(%lhs, %rhs): (tensor<3xi64>, tensor<3xi64>) -> tensor<3xi64>
// %result: [9223372036854775807, 0, 1]
علامة
دلالات الألفاظ
لعرض علامة operand
من حيث الصياغة وينتج سينسور result
.
وبشكل أكثر رسمية، لكل عنصر x
، يمكن التعبير عن الدلالات باستخدام
بناء جملة بايثون على النحو التالي:
def sign(x):
if is_integer(x):
if compare(x, 0, LT, SIGNED): return -1
if compare(x, 0, EQ, SIGNED): return 0
return 1
elif is_float(x):
if is_nan(x): return NaN
if compare(x, -0.0, EQ, FLOAT): return -0.0
if compare(x, +0.0, EQ, FLOAT): return +0.0
if compare(x, 0.0, LT, FLOAT): return -1.0
return 1.0
elif is_complex(x):
if is_nan(real(x)) or is_nan(imag(x)): return (NaN, NaN)
if compare(x, (0.0, 0.0), EQ, FLOAT): return (0.0, 0.0)
return divide(x, convert(abs(x), type(x)))
بالنسبة للأنواع الكَمية، تنفذ
dequantize_op_quantize(sign, operand, type(result))
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
موتّر عدد صحيح بعلامة أو نقطة عائمة أو نوع مركب أو مٍنسور كمي لكل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
موتّر عدد صحيح بعلامة أو نقطة عائمة أو نوع مركب أو مٍنسور كمي لكل متسابق | (C1) |
القيود
- (ج1)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// Logical values: +NaN, -1.0, -0.0, +0.0, 1.0
// operand: [0x7FFFFFFFFFFFFFFF, -1.0, -0.0, 0.0, 1.0]
%result = "stablehlo.sign"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// Logical values: +NaN, -1.0, -0.0, +0.0, 1.0
// %result: [0x7FFFFFFFFFFFFFFF, -1.0, -0.0, 0.0, 1.0]
جيب الزاوية
دلالات الألفاظ
لتنفيذ عملية جيب الزاوية من ناحية العناصر على متسّع operand
وينتج عنه result
متنسور. حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى الأعداد العشرية:
sin
من IEEE-754. - بالنسبة إلى الأعداد المركّبة: جيب الزاوية المركّبة.
- بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(sine, operand, type(result))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
القيود
- (ج1)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// %operand: [
// [0.0, 1.57079632], // [0, pi/2]
// [3.14159265, 4.71238898] // [pi, 3pi/2]
// ]
%result = "stablehlo.sine"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[0.0, 1.0], [0.0, -1.0]]
slice
دلالات الألفاظ
لاستخراج شريحة من operand
باستخدام فهارس بدء محسوبة بشكلٍ ثابت
وينتج موتر result
. يحتوي start_indices
على مؤشرات البداية الخاصة بـ
الشريحة لكل بُعد، ويحتوي limit_indices
على فهارس النهاية
(حصريًا) للشريحة لكل بُعد، ويحتوي strides
على الخطوات
لكل سمة
بشكل رسمي، result[result_index] = operand[operand_index]
حيث
operand_index = start_indices + result_index * strides
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1-C3)، (C5) |
(I2) | start_indices |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C2)، (C3)، (C5) |
(I3) | limit_indices |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C2)، (C3)، (C5) |
(I4) | strides |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C2)، (C4) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتّر أو مستنسر كمي لكلّ متسابق | (C1)، (C5) |
القيود
- (ج1)
element_type(operand) = element_type(result)
. - (C2)
size(start_indices) = size(limit_indices) = size(strides) = rank(operand)
. - (C3)
0 <= start_indices <= limit_indices <= shape(operand)
: - (C4)
0 < strides
. - (C5)
shape(result) = ceil((limit_indices - start_indices) / strides)
.
أمثلة
// %operand: [
// [0, 0, 0, 0],
// [0, 0, 1, 1],
// [0, 0, 1, 1]
// ]
%result = "stablehlo.slice"(%operand) {
start_indices = array<i64: 1, 2>,
limit_indices = array<i64: 3, 4>,
strides = array<i64: 1, 1>
} : (tensor<3x4xi64>) -> tensor<2x2xi64>
// % result: [
// [1, 1],
// [1, 1]
// ]
ترتيب
دلالات الألفاظ
فرز الشرائح ذات البعد الواحد inputs
بجانب البُعد dimension
معًا،
وفقًا لـ comparator
، وتنتج results
.
وعلى عكس المدخلات المماثلة في العمليات الأخرى، تسمح الدالة dimension
بالقيم السالبة،
مع الدلالات الموضحة أدناه. قد لا يتم السماح بهذا الإجراء في المستقبل
لأسباب تتعلق بالاتساق
(#1377)
إذا كانت is_stable
صحيحة، فهذا يعني أن الترتيب ثابت، أي الترتيب النسبي
العناصر التي تعتبرها المقارن متساوية. للحافظة
عندما يكون هناك إدخال واحد، يعتبر العنصران e1
وe2
هما:
يساوي المُقارن إذا كان
comparator(e1, e2) = comparator(e2, e1) = false
اطّلِع على عملية الإعداد الرسمي أدناه.
حول كيفية تعميم ذلك على إدخالات متعددة.
بشكل رسمي، لجميع result_index
في index_space(results[0])
:
adjusted_dimension = dimension >= 0 ? dimension : rank(inputs[0]) + dimension
.result_slice = [ri0, ..., :, ..., riR-1]
حيث يكونriN
فرديًا العناصر فيresult_index
، وتم إدراج:
فيadjusted_dimension
.inputs_together = (inputs[0]..., ..., inputs[N-1]...)
.results_together[result_slice] = sort(inputs_together[result_slice], comparator_together)
.- حيث يقوم
sort
بترتيب شريحة أحادية البُعد بترتيب غير تنازلي متوقعًا أنcomparator_together
تعرضtrue
إذا كانت الوسيطة اليسرى أقل من الوسيطة الثانية اليمنى. def comparator_together(lhs_together, rhs_together): args = [] for (lhs_el, rhs_el) in zip(lhs_together, rhs_together): args.append(lhs_el) args.append(rhs_el) return comparator(*args)
(results[0]..., ..., results[N-1]...) = results_together
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | inputs |
الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق | (C1-C5) |
(I2) | dimension |
ثابت من النوع si64 |
(C4) |
(I3) | is_stable |
ثابت من النوع i1 |
|
(I4) | comparator |
دالة | (C5) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
results |
الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق | (C2)، (C3) |
القيود
- (ج1)
0 < size(inputs)
. - (C2)
type(inputs...) = type(results...)
. - (C3)
same(shape(inputs...) + shape(results...))
: - (C4)
-R <= dimension < R
، حيثR = rank(inputs[0])
. - (C5) النوع
comparator
(tensor<E1>, tensor<E1>, ..., tensor<EN-1>, tensor<EN-1>) -> tensor<i1>
, حيثEi = element_type(inputs[i])
.
أمثلة
// %input0 = [[1, 2, 3], [3, 2, 1]]
// %input1 = [[3, 2, 1], [1, 2, 3]]
%result0, %result1 = "stablehlo.sort"(%input0, %input1) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>, %arg2: tensor<i64>, %arg3: tensor<i64>):
%predicate = "stablehlo.compare"(%arg0, %arg1) {
comparison_direction = #stablehlo<comparison_direction GT>
} : (tensor<i64>, tensor<i64>) -> tensor<i1>
"stablehlo.return"(%predicate) : (tensor<i1>) -> ()
}) {
dimension = 0 : i64,
is_stable = true
} : (tensor<2x3xi64>, tensor<2x3xi64>) -> (tensor<2x3xi64>, tensor<2x3xi64>)
// %result0 = [[3, 2, 3], [1, 2, 1]]
// %result1 = [[1, 2, 1], [3, 2, 3]]
ربع السنة الحالي
دلالات الألفاظ
لتنفيذ عملية جذر تربيعي حسب العناصر على موتّر operand
وينتج عنه
متوتر result
حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى الأعداد العشرية:
squareRoot
من IEEE-754. - بالنسبة إلى الأعداد المركّبة: جذر تربيعي مركّب.
- بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(sqrt, operand, type(result))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
القيود
- (ج1)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// %operand: [[0.0, 1.0], [4.0, 9.0]]
%result = "stablehlo.sqrt"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[0.0, 1.0], [2.0, 3.0]]
طرح
دلالات الألفاظ
لتنفيذ عملية طرح على مستوى العناصر لاثنين من المتوترين lhs
وrhs
وينتج عن ذلك
متوتر result
حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى الأعداد الصحيحة: طرح الأعداد الصحيحة.
- بالنسبة إلى الأعداد العشرية:
subtraction
من IEEE-754. - بالنسبة إلى الأعداد المركّبة: الطرح المركَّب.
- بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(subtract, lhs, rhs, type(result))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المنزِّع الكمي لكل متسابق | (C1) |
(I2) | rhs |
موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المنزِّع الكمي لكل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المنزِّع الكمي لكل متسابق | (C1) |
القيود
- (ج1)
baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)
.
أمثلة
// %lhs: [[6, 8], [10, 12]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.subtract"(%lhs, %rhs) : (tensor<2x2xf32>, tensor<2x2xf32>) -> (tensor<2x2xf32>)
// %result: [[1, 2], [3, 4]]
tan
دلالات الألفاظ
لتنفيذ عملية ظل الزاوية من ناحية العناصر على متسّع operand
وينتج عنه
متوتر result
حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى الأعداد العشرية:
tan
من IEEE-754. - للأعداد المركّبة: المماس المعقد.
- بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(tan, operand, type(result))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
القيود
- (ج1)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// %operand: [
// [0.0, 1.57079632], // [0, pi/2]
// [3.14159265, 4.71238898] // [pi, 3pi/2]
// ]
%result = "stablehlo.tan"(%operand) : (tensor<2x2xf64>) -> tensor<2x2xf64>
// %result: [
// [0.0, 1.63312e+16],
// [0.0, 5.44375e+15]
// ]
تانه
دلالات الألفاظ
لتنفيذ عملية المماس الزائدي من حيث العناصر على متسابق operand
نحصل على موتّر result
. حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى الأعداد العشرية:
tanh
من IEEE-754. - بالنسبة إلى الأعداد المركّبة: المماس الزائدي المركّب.
- بالنسبة إلى الأنواع الكَمية:
dequantize_op_quantize(tanh, operand, type(result))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
القيود
- (ج1)
baseline_type(operand) = baseline_type(result)
.
أمثلة
// %operand: [-1.0, 0.0, 1.0]
%result = "stablehlo.tanh"(%operand) : (tensor<3xf32>) -> tensor<3xf32>
// %result: [-0.76159416, 0.0, 0.76159416]
تبديل الموقع
دلالات الألفاظ
لتنفيذ أبعاد مترابط operand
باستخدام permutation
وينتج عن ذلك
متوتر result
بشكل رسمي، result[result_index] = operand[operand_index]
حيث result_index[d] = operand_index[permutation[d]]
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتر أو متنسّر كمي | (C1-C4) |
(I2) | permutation |
ثابت التوتر ذو البعد الواحد من النوع si64 |
(C2-C4) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتر أو متنسّر كمي | (C1)، (C3-C4) |
القيود
- (C1)
element_type(result)
يتم تقديمها من خلال:element_type(operand)
، إذا كانت!is_per_axis_quantized(operand)
.element_type(operand)
باستثناء أنّquantization_dimension(operand)
قد تختلف السمةquantization_dimension(result)
في الحالات الأخرى.
- (C2)
permutation
هو تبديل لـrange(rank(operand))
. - (C3)
shape(result) = dim(operand, permutation...)
: - (C4) إذا كانت
is_per_axis_quantized(result)
، إذًاquantization_dimension(operand) = permutation(quantization_dimension(result))
أمثلة
// %operand: [
// [[1,2], [3,4], [5,6]],
// [[7,8], [9,10], [11,12]]
// ]
%result = "stablehlo.transpose"(%operand) {
permutation = array<i64: 2, 1, 0>
} : (tensor<2x3x2xi32>) -> tensor<2x3x2xi32>
// %result: [
// [[1,7], [3,9], [5,11]],
// [[2,8], [4,10], [6,12]]
// ]
triangular_solve
دلالات الألفاظ
حلّ مجموعات أنظمة المعادلات الخطية ذات المثلثات السفلية أو العليا مصفوفات المعاملات.
بشكل أكثر رسمية، بالنظر إلى a
وb
، يكون result[i0, ..., iR-3, :, :]
هو الحل
إلى op(a[i0, ..., iR-3, :, :]) * x = b[i0, ..., iR-3, :, :]
عندما يكون left_side
true
أو x * op(a[i0, ..., iR-3, :, :]) = b[i0, ..., iR-3, :, :]
عندما
قيمة left_side
هي false
، ما يؤدي إلى حل المتغير x
حيث يتم تحديد op(a)
.
بحلول transpose_a
، والذي يمكن أن يكون واحدًا مما يلي:
NO_TRANSPOSE
: يمكنك إجراء العملية باستخدامa
كما هي.TRANSPOSE
: إجراء عملية على تبديل موضعa
.ADJOINT
: إجراء عملية على التبديل المصاحب لـa
.
لا تتم قراءة بيانات الإدخال إلا من المثلث السفلي في a
، إذا كانت قيمة lower
true
أو
المثلث العلوي في a
، وإلا. يتم إرجاع بيانات الإخراج في نفس المثلث؛
والقيم في المثلث الآخر محددة التنفيذ.
إذا كانت unit_diagonal
صحيحة، فإن التنفيذ قد يفترض أن يكون القطر
تساوي عناصر a
1، وإلا يكون السلوك غير محدد.
بالنسبة للأنواع الكَمية، تنفذ
dequantize_op_quantize(lambda x, y: triangular_solve(x, y, left_side, lower,
unit_diagonal, transpose_a), a, b, type(result))
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | a |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1-C3) |
(I2) | b |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1-C4) |
(I3) | left_side |
ثابت من النوع i1 |
(C3) |
(I4) | lower |
ثابت من النوع i1 |
|
(I5) | unit_diagonal |
ثابت من النوع i1 |
|
(I6) | transpose_a |
تعداد NO_TRANSPOSE وTRANSPOSE وADJOINT |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق | (C1) |
القيود
- (ج1)
baseline_element_type(a) = baseline_element_type(b)
. - (C2)
2 <= rank(a) = rank(b) = R
. - (C3) يتم تعريف العلاقة بين
shape(a)
وshape(b)
على النحو التالي:shape(a)[:-3] = shape(b)[:-3]
.dim(a, -2) = dim(a, -1) = dim(b, left_side ? -2 : -1)
.
- (C4)
baseline_type(b) = baseline_type(result)
.
أمثلة
// %a = [
// [1.0, 0.0, 0.0],
// [2.0, 4.0, 0.0],
// [3.0, 5.0, 6.0]
// ]
// %b = [
// [2.0, 0.0, 0.0],
// [4.0, 8.0, 0.0],
// [6.0, 10.0, 12.0]
// ]
%result = "stablehlo.triangular_solve"(%a, %b) {
left_side = true,
lower = true,
unit_diagonal = false,
transpose_a = #stablehlo<transpose NO_TRANSPOSE>
} : (tensor<3x3xf32>, tensor<3x3xf32>) -> tensor<3x3xf32>
// %result: [
// [2.0, 0.0, 0.0],
// [0.0, 2.0, 0.0],
// [0.0, 0.0, 2.0]
// ]
صف
دلالات الألفاظ
تنتج صف result
من القيم val
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | val |
العدد المتغير للقيم | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
صف | (C1) |
القيود
- (C1) النوع
result
يحتوي على النوعtuple<E0, ..., EN-1>
حيثEi = type(val[i])
.
أمثلة
// %val0: [1.0, 2.0]
// %val1: (3)
%result = "stablehlo.tuple"(%val0, %val1) : (tensor<2xf32>, tuple<tensor<i32>>) -> tuple<tensor<2xf32>, tuple<tensor<i32>>>
// %result: ([1.0, 2.0], (3))
uniform_dequantize
دلالات الألفاظ
لإجراء تحويل من ناحية العناصر للمتنسور operand
الكمي إلى قيمة
موتر النقطة العائمة result
وفقًا لمعلمات القياس المحددة
حسب النوع operand
.
اسم "result = dequantize(operand)
" رسميًا.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متوتر كمي | (C1)، (C2) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متّجه من نوع النقطة العائمة | (C1)، (C2) |
القيود
- (ج1)
shape(operand) = shape(result)
. - (C2)
element_type(result) = expressed_type(operand)
.
أمثلة
// %operand: [10, 10]
%result = "stablehlo.uniform_dequantize"(%operand) : (tensor<2x!quant.uniform<i8:f32:0, {0.1:-30,0.5:-20}>>) -> tensor<2xf32>
// %result: [4.0, 15.0]
uniform_quantize
دلالات الألفاظ
لإجراء تحويل من ناحية العناصر لمتنس النقطة العائمة أو متنسورة الكمي
operand
إلى موصّل كمي result
حسب الكمّي
التي يتم تحديدها بواسطة النوع result
.
بشكل أكثر رسمية،
- إذا كانت
is_float(operand)
:result = quantize(operand, type(result))
.
- إذا كانت
is_quantized(operand)
:float_result = dequantize(operand)
.result = quantize(float_result, type(result))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متّجه النقطة العائمة أو النوع الكمي | (C1)، (C2) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متوتر كمي | (C1)، (C2) |
القيود
- (ج1)
shape(operand) = shape(result)
. - (C2)
expressed_type(result) = is_float(operand) ? element_type(operand) : expressed_type(operand)
.
أمثلة
// %operand: [4.0, 15.0]
%result = "stablehlo.uniform_quantize"(%operand) : (tensor<2xf32>) -> tensor<2x!quant.uniform<i8:f32:0, {0.1:-30,0.5:-20}>>
// %result: [10, 10]
// %operand: [10, 10]
%result = "stablehlo.uniform_quantize"(%operand) : (tensor<2x!quant.uniform<i8:f32:0, {0.1:-30,0.5:-20}>>) -> tensor<2x!quant.uniform<i8:f32:0, {0.1:-20,0.2:-30}>>
// %result: [20, 45]
بينما
دلالات الألفاظ
الحصول على ناتج تنفيذ الدالة body
0 مرة أو أكثر أثناء
مخرجات الدالة cond
true
. بشكل أكثر رسمية، يمكن التعبير عن الدلالات
باستخدام بناء جملة بايثون على النحو التالي:
internal_state = operand
while cond(*internal_state):
internal_state = body(*internal_state)
results = internal_state
يتم تحديد سلوك التكرار اللانهائي لاحقًا (#383)
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
الأعداد المتباينة من متساعات التوتر أو العشرات الكمية أو الرموز المميزة | (C1-C3) |
(I2) | cond |
دالة | (C1) |
(I3) | body |
دالة | (C2) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
results |
الأعداد المتباينة من متساعات التوتر أو العشرات الكمية أو الرموز المميزة | (C3) |
القيود
- (C1)
cond
من النوع(T0, ..., TN-1) -> tensor<i1>
، حيثTi = type(operand[i])
- (C2)
body
من النوع(T0, ..., TN-1) -> (T0, ..., TN-1)
، حيثTi = type(operand[i])
- (C3)
type(results...) = type(operand...)
:
أمثلة
// %init_i: 1
// %init_sum: 0
// %one: 1
// %ten: 10
%results0, %results1 = "stablehlo.while"(%init_i, %init_sum) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%cond = "stablehlo.compare"(%arg0, %ten) {
comparison_direction = #stablehlo<comparison_direction LT>
} : (tensor<i64>, tensor<i64>) -> tensor<i1>
stablehlo.return %cond : tensor<i1>
}, {
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%new_sum = stablehlo.add %arg1, %one : tensor<i64>
%new_i = stablehlo.add %arg0, %one : tensor<i64>
stablehlo.return %new_i, %new_sum : tensor<i64>, tensor<i64>
}) : (tensor<i64>, tensor<i64>) -> (tensor<i64>, tensor<i64>)
// %results0: 10
// %results1: 10
xor
دلالات الألفاظ
تؤدي هذه الإجراءات إلى تنفيذ XOR من ناحية العناصر باستخدام معاملين lhs
وrhs
وينتج عن ذلك result
.
متنسور. حسب نوع العنصر، يتم إجراء ما يلي:
- بالنسبة إلى القيم المنطقية: يستخدم XOR المنطقي.
- بالنسبة إلى الأعداد الصحيحة: XOR على مستوى البت.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
متّصِل من نوع القيمة المنطقية أو العدد الصحيح | (C1) |
(I2) | rhs |
متّصِل من نوع القيمة المنطقية أو العدد الصحيح | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متّصِل من نوع القيمة المنطقية أو العدد الصحيح | (C1) |
القيود
- (ج1)
type(lhs) = type(rhs) = type(result)
.
أمثلة
// Bitwise operation with with integer tensors
// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.xor"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[4, 4], [4, 12]]
// Logical operation with with boolean tensors
// %lhs: [[false, false], [true, true]]
// %rhs: [[false, true], [false, true]]
%result = "stablehlo.xor"(%lhs, %rhs) : (tensor<2x2xi1>, tensor<2x2xi1>) -> tensor<2x2xi1>
// %result: [[false, true], [true, false]]
التشغيل التفاعلي للّغات
وفي الوقت الحالي، تحتوي برامج StableHLO المتوفّرة في البرية على عمليات لم يتم تحديدها بواسطة StableHLO.
الوحدة، الوظيفة، الاتصال والعودة
يستخدم StableHLO عمليات MLIR الأولية لعمليات ModuleOp وFuncOp وCallOp ReturnOp. وقد تم إجراء ذلك لتحسين إمكانية التشغيل التفاعلي مع أجهزة MLIR الحالية، بطاقات مفيدة تستهدف FuncOp وModuleOp، والعديد من تجميع حول المشروعات تتوقع وجود هذه العمليات. تُعد ضمانات التوافق الكامل تطبيقها على هذه العمليات. إذا تغير أي شيء في أي وقت حول هذه العمليات في غير متوافقة (أي الإزالة)، ستتم إضافة مكافئات StableHLO للحفاظ على التوافق.
CHLO
تحتوي عملية CHLO على عمليات مستوى أعلى يتم تحليلها إلى StableHLO. ما مِن ضمانات توافق في الوقت الحالي مع CHLO. للتوافق أي ضمان، تصريح chlo-legalize-to-stablehlo قبل إنشاء التسلسل.
عمليات الأشكال
إنها حالة استخدام شائعة في المجتمع لاستخدام عمليات معينة من
لهجات MLIR في برامج StableHLO الديناميكية لإجراء عمليات حسابية للأشكال
وتشمل هذه العناوين اللهجة shape
بشكل أكثر شيوعًا.
العمليات مثل shape_of
أو num_elements
، لهجة tensor
عمليات مثل dim
أو from_elements
، والنوع index
المدمج.
Dynamism RFC > O2
أن ذلك خارج النطاق، إلا أن بعض التوافق مع أنواع index
لأغراض التشغيل التفاعلي. ليس هناك أي ضمانات للتوافق مع هذه
العمليات أو الأنواع. shape-legalize-to-stablehlo
يمكن استخدام البطاقة لتحويل هذه العمليات إلى عمليات StableHLO متوافقة بالكامل.
عمليات متوقّفة نهائيًا
هناك العديد من عمليات StableHLO التي تم اكتسابها من MHLO التي تم إيقافها وهي في طريقها للخروج من StableHLO. ستساعدك التفاصيل الكاملة حول هذه ويمكن العثور على عمليات الإزالة في StableHLO v1.0 Cleanup #2283. مشكلة أداة التتبُّع الخاصة بعمليات الإيقاف هذه هي #2340.
وتندرج هذه العمليات ضمن فئات قليلة:
- "ليس في HLO" فئة عمليات StableHLO - كانت في البداية جزءًا من
فرصة StableHLO ولكن تم اعتبارها غير مناسبة لاحقًا بشكل جيد:
"
broadcast
" و"create_token
" و"cross-replica-sum
" و"dot
" و"einsum
"torch_index_select
،unary_einsum
(رقم 3) - العمليات غير المستخدمة - ربما كانت هذه العمليات مفيدة في مرحلة ما، ولكن العمليات
كانت إما غير متطورة، أو كانت الأنابيب التي تستخدم هذه العمليات
إعادة الهيكلة لعدم طلبها بعد الآن. ويشمل ذلك
map
وtuple
(#598)get_tuple_element
أوrng
أوcomplex
مقارنات #560، والالتفافwindow_reversal
(#1181).
يمكن إزالة بعض هذه العمليات بسهولة حيث يمكن التعبير عنها باستخدام
العمليات الحالية (broadcast
، create_token
، cross-replica-sum
، dot
،
unary_einsum
) وستتم إزالتها بعد فترة التوافق الحالية.
البطاقات (6 أشهر). لا يزال البحث عن مجموعات أخرى مطلوب إزالتها (einsum
،
get_tuple_element
، map
، rng
torch_index_select
، tuple
، complex
والمقارنات، window_reversal
). في انتظار ملاحظات المنتدى،
ستتم إزالة هذه العمليات أو إضافتها إلى المواصفات بدعم كامل. حتى
هذه العمليات معروفة، وضمان توافقها لمدة 6 أشهر فقط.
التنفيذ
التنفيذ التسلسلي
يتم تنفيذ برنامج StableHLO من خلال تقديم قيم إدخال إلى الدالة main
وحساب قيم المخرجات. يتم حساب قيم مخرجات الدالة عن طريق
تنفيذ الرسم البياني للعمليات الجذر في عملية return
المقابلة.
يتم تحديد ترتيب التنفيذ طالما أنّه متوافق مع
تدفق البيانات، أي إذا تم تنفيذ العمليات قبل استخدامها. في StableHLO، يتم نقل جميع
ذلك أن العمليات ذات الآثار الجانبية تستهلك رمزًا مميزًا واحدًا وتنتج رمزًا مميزًا (يمكن أن تستهلك رموز مميزة
يتم مضاعفتها في رمز مميز واحد عبر after_all
)، لذا فإن ترتيب التنفيذ
والتأثيرات أيضًا مع تدفق البيانات. على سبيل المثال، في البرنامج أدناه
هناك أمران تنفيذيان محتملان: %0
← %1
← %2
← return
%1
← %0
← %2
← return
.
func.func @main() -> tensor<f64> {
%0 = stablehlo.constant dense<1.0> : tensor<f64>
%1 = stablehlo.constant dense<2.0> : tensor<f64>
%2 = stablehlo.add %0, %1 : tensor<f64>
return %2 : tensor<f64>
}
بشكل أكثر رسمية، تتمثل عملية SttableHLO في مجموعة مما يلي:
1) برنامج StableHLO، 2) حالات التشغيل (لم يتم تنفيذها بعد،
بالفعل)، و3) القيم المتوسطة التي تعمل عليها العملية.
تبدأ العملية بقيم مدخلات للدالة main
وتتقدم إلى
الرسم البياني للعمليات التي تعمل على تحديث حالات العملية والقيم المتوسطة
ينتهي بقيم المخرجات. يتم تحديد مرحلة إضافية من حيث الطابع الرسمي.
(#484)
التنفيذ الموازي
يمكن تنفيذ برامج StableHLO بالتوازي، ويتم تنظيمها في شبكة عمليات ثنائية الأبعاد
من num_replicas
بواسطة num_partitions
وكلاهما من النوع ui32
.
في شبكة عملية StableHLO، num_replicas * num_partitions
من StableHLO
يتم تنفيذ العمليات في نفس الوقت. ولكل عملية لها
process_id = (replica_id, partition_id)
، حيث
replica_id
في replica_ids = range(num_replicas)
و
partition_id
في partition_ids = range(num_partitions)
وكلاهما لهما
اكتب ui32
.
يُعرف حجم شبكة العملية ثابتًا لكل برنامج (في
فإننا نخطط لجعلها جزءًا صريحًا من برامج StableHLO
#650)، فضلاً عن الموضع
داخل شبكة العملية معروف بشكل ثابت لكل عملية. تحتوي كل عملية على
إلى موضعها داخل شبكة العملية عبر replica_id
partition_id
عمليات
داخل شبكة العمليات، يمكن أن تكون جميع البرامج متطابقة (في علامة البرنامج، البيانات المتعددة" النمط)، يمكن أن تكون مختلفة (في "برامج متعددة، البيانات المتعددة" ) أو شيء من هذا القبيل. نخطط في المستقبل لتقديم دعم لمصطلحات أخرى خاصة بتحديد برامج StableHLO المتوازية، بما في ذلك GSPMD (#619).
داخل شبكة العملية، تكون العمليات مستقلة في الغالب عن بعضها البعض - لكل منها حالات عملية منفصلة، وقيم إدخال/متوسط/إخراج منفصلة ويتم تنفيذ معظم العمليات بشكل منفصل بين العمليات، باستخدام باستثناء عدد صغير من العمليات الجماعية الموضحة أدناه.
بما أن تنفيذ معظم العمليات يتم فقط باستخدام قيم من نفس
الإشارة إلى هذه القيم بأسمائها عادةً لا لبس فيها.
ومع ذلك، عند وصف دلالات العمليات الجماعية، فهذا لا يكفي،
التي تؤدي إلى ظهور العلامة name@process_id
للإشارة إلى القيمة name
ضمن عملية معينة. (من هذا المنظور، يمكن اعتبار name
غير مؤهل)
يُعتبر اختصارًا لـ name@(replica_id(), partition_id())
).
يتم تحديد ترتيب التنفيذ في جميع العمليات باستثناء عملية مزامنة بفضل الاتصال من نقطة إلى نقطة والعمليات الجماعية كما هو موضح أدناه.
الاتصال من نقطة إلى نقطة
يمكن أن تتواصل عمليات StableHLO بعضها مع بعض من خلال
قنوات SttableHLO: يتم تمثيل القناة بمعرّف موجب من النوع
si64
ومن خلال العمليات المختلفة، يمكن إرسال القيم إلى القنوات
تتلقاها من القنوات.
إضافة مزيد من التفاصيل الرسمية، مثل مصدر معرّفات القنوات هذه، وكيف والعمليات التي تصبح فيها البرامج على دراية بها ونوع المزامنة قدموها، يتم تحديدها لاحقًا (#484)
اتصال البث
يمكن لكل عملية في StableHLO الوصول إلى واجهتي بث:
- الإعلان ضمن الخلاصة الذي يمكن القراءة منه
- الخلاصة التي يمكن الكتابة إليها.
على عكس القنوات، التي تُستخدم للتواصل بين العمليات وبالتالي من طرفيهما، يكون لكل من الخلاصة والخلاصات الخارجية عمليات التنفيذ النهائي.
إضافة مزيد من التفاصيل الرسمية، مثل كيف يؤثر اتصال البث على التنفيذ الترتيب ونوع المزامنة الذي يقدمه، يتم تحديده لاحقًا (#484)
العمليات الجماعية
هناك ست عمليات جماعية في StableHLO: all_gather
وall_reduce
،
all_to_all
وcollective_broadcast
وcollective_permute
reduce_scatter
تُقسِّم كل هذه العمليات العمليات في عملية StableHLO
إلى مجموعات عمليات ثابت هول (StableHLO) وتنفيذ عملية حسابية مشتركة داخل
كل مجموعة عمليات، بشكل مستقل عن مجموعات العمليات الأخرى.
ضمن كل مجموعة عمليات، قد تؤدي العمليات الجماعية إلى إجراء مزامنة حاجز. إضافة مزيد من التفاصيل الرسمية، مثل وأوضح متى بالضبط حدوث المزامنة، أي كيفية وصول العمليات بالضبط إلى هذا الحاجز، وما سيحدث إذا لم يحدث ذلك، سيتم تحديده لاحقًا (#484)
إذا كانت مجموعة العمليات تتضمن تواصلاً متعدد الأقسام، أي أن هناك
العمليات في مجموعة العمليات التي تختلف أرقام تعريف الأقسام بها، ثم يتم
من العملية الجماعية بحاجة إلى قناة، ويجب أن توفر العملية
موجب channel_id
من النوع si64
. الاتصال بين النُسخ المكررة لا يحتاج إلى
بشكل أفضل.
تكون العمليات الحسابية التي تجريها العمليات الجماعية خاصة بالعمليات الفردية وهي موضحة في أقسام العمليات الفردية أعلاه. ومع ذلك، فإن الإستراتيجيات التي يتم التي تنقسم إلى مجموعات عمليات، تتم مشاركتها بين هذه العمليات وهي موضحة في هذا القسم. بشكل رسمي، تدعم StableHLO باتباع الاستراتيجيات الأربع.
cross_replica
تحدث الاتصالات المتبادلة فقط داخل كل مجموعة عمليات. هذا النمط
تأخذ الإستراتيجية replica_groups
- قائمة بأرقام التعريف المتماثلة - وتحسب
منتج الديكارتي (replica_groups
) من إعداد partition_ids
. replica_groups
يجب أن يحتوي على عناصر فريدة وأن يشمل جميع replica_ids
. بشكل أكثر رسمية، باستخدام
بناء جملة Python:
def cross_replica(replica_groups: List[List[ReplicaId]]) -> List[List[ProcessId]]:
for replica_group in replica_groups:
for partition_id in partition_ids:
process_group = []
for replica_id in replica_group:
process_group.append((replica_id, partition_id))
yield process_group
على سبيل المثال، بالنسبة إلى replica_groups = [[0, 1], [2, 3]]
وnum_partitions = 2
،
سيُنتج cross_replica
[[(0, 0), (1, 0)], [(0, 1), (1, 1)], [(2, 0), (3, 0)], [(2, 1), (3, 1)]]
cross_partition
تحدث عمليات التواصل بين الأقسام فقط داخل كل مجموعة عمليات. هذا النمط
تستخدم الإستراتيجية partition_groups
- وهي قائمة بأرقام تعريف الأقسام - و
تحسب حاصل الضرب الديكارتي (partition_groups
) من خلال replica_ids
.
يجب أن يحتوي partition_groups
على عناصر فريدة وأن يشمل كل partition_ids
.
وبشكل رسمي، باستخدام بناء جملة بايثون:
def cross_partition(partition_groups: List[List[PartitionId]]) -> List[List[ProcessId]]:
for partition_group in partition_groups:
for replica_id in replica_ids:
process_group = []
for partition_id in partition_group:
process_group.append((replica_id, partition_id))
yield process_group
على سبيل المثال، بالنسبة إلى partition_groups = [[0, 1]]
وnum_replicas = 4
،
سيُنتج cross_partition
[[(0, 0), (0, 1)], [(1, 0), (1, 1)], [(2, 0), (2, 1)], [(3, 0), (3, 1)]]
cross_replica_and_partition
قد تحدث كل من الاتصالات المتبادلة والمشتركة بين الأقسام في كل
مجموعة العمليات. تستغرق هذه الاستراتيجية replica_groups
- وهي عبارة عن قائمة من قوائم
نُسخ طبق الأصل - وتحسب المنتجات الديكارتية لكل replica_group
حسب
partition_ids
يجب أن يحتوي replica_groups
على عناصر فريدة وأن يشمل كل العناصر
replica_ids
وبشكل رسمي، باستخدام بناء جملة بايثون:
def cross_replica_and_partition(replica_groups: List[List[ReplicaId]]) -> List[List[ProcessId]]:
for replica_group in replica_groups:
process_group = []
for partition_id in partition_ids:
for replica_id in replica_group:
process_group.append((replica_id, partition_id))
yield process_group
على سبيل المثال، بالنسبة إلى replica_groups = [[0, 1], [2, 3]]
وnum_partitions = 2
،
سيُنتج cross_replica_and_partition
[[(0, 0), (1, 0), (0, 1), (1, 1)], [(2, 0), (3, 0), (2, 1), (3, 1)]]
flattened_ids
تستغرق هذه الاستراتيجية flattened_id_groups
، وهي عبارة عن قائمة من القوائم "المُقسّمة".
أرقام تعريف العمليات في شكل replica_id * num_partitions + partition_id
وتحويلها إلى أرقام تعريف للعمليات. يجب أن يتضمّن flattened_id_groups
عناصر فريدة.
وتغطي جميع process_ids
. وبشكل رسمي، باستخدام بناء جملة بايثون:
def flattened_ids(flattened_id_groups: List[List[ui32]]) -> List[List[ProcessId]]:
for flattened_id_group in flattened_id_groups:
process_group = []
for flattened_id in flattened_id_group:
replica_id = flattened_id // num_partitions
partition_id = flattened_id % num_partitions
process_group.append((replica_id, partition_id))
yield process_group
على سبيل المثال، بالنسبة إلى flattened_id_groups = [[0, 1, 2, 3], [4, 5, 6, 7]]
،
num_replicas = 4
وnum_partitions = 2
، وflattened_ids
ينتج عنهما
[[(0, 0), (0, 1), (1, 0), (1, 1)], [(2, 0), (2, 1), (3, 0), (3, 1)]]
الدقة
وفي الوقت الحالي، لا تقدّم قناة StableHLO أي ضمانات بشأن الدقة الرقمية ولكن قد يتغير هذا في المستقبل (#1156)
دلالات تنفيذ العملية الكمية
قد يختلف التفسير للعمليات الكميّة لـ StableHLO حسب متطلبات الأجهزة وإمكاناتها. على سبيل المثال، قد تختار بعض الأجهزة تفسير العمليات الكميّة باستخدام "تحديد وتنفيذ النقطة العائمة" العملية، وأخيرًا تحديد الكميات" الاستراتيجية. ويمكن للآخرين تنفيذ العملية الحسابية باستخدام حساب الأعداد الصحيحة. وبالتالي، فإن تفسير ويتم تحديد عمليات StableHLO الكمية حصريًا من خلال التنفيذ. تفسير منهج الكم الهجين (#1575) يجب أن يستند إلى الدلالات على النحو الموصوف في المواصفات (عبر 1792).
الأخطاء
يتم التحقق من صحة برامج StableHLO من خلال مجموعة واسعة من القيود العمليات الفردية، التي تستبعد العديد من فئات الأخطاء قبل وقت التشغيل. ومع ذلك، تظل حالات الخطأ ممكنة، على سبيل المثال: من خلال فائض الأعداد الصحيحة، وعمليات الوصول إلى خارج الحدود، وما إلى ذلك، وما لم يتم ذكر ذلك صراحةً، محددة في طريقة التنفيذ، ولكن قد يتغير هذا في المستقبلية (#1157).
استثناءات النقاط العائمة
باستثناء هذه القاعدة، فإنّ استثناءات النقطة العائمة في برامج StableHLO
يكون لها سلوك محدد جيدًا. العمليات التي ينتج عنها استثناءات يحددها
معيار IEEE-754 (عملية غير صالحة، أو القسمة على صفر، أو التجاوز، أو التدفق السفلي، أو
الاستثناءات غير الدقيقة) تؤدي إلى نتائج افتراضية (كما هو موضح في المعيار)
مواصلة التنفيذ بدون رفع علامة الحالة المناسبة مشابه لـ
معالجة استثناء raiseNoFlag
من المعيار العادي استثناءات للحسابات غير العادية
العمليات الحسابية (مثل العمليات الحسابية المعقدة وبعض الدوال العليا)
التنفيذ.
عدم تطابق الأشكال
يتوافق StableHLO مع أدوات التوتر ذات الشكل الديناميكي. ومع ذلك، يجب أن تتفق الأشكال في وقت التشغيل، وإلا فسيكون السلوك غير محدد. لا تسمح قناة StableHLO بشكلٍ صريح توفير عملية يمكن من خلالها تأكيد وجود شكل معين للمتسق في وقت التشغيل. تقع مسؤولية إنشاء التعليمات البرمجية الصحيحة على عاتق المنتِج.
على سبيل المثال، البرنامج التالي صالح. ولكن في وقت التشغيل،
يجب أن تكون الأشكال الدقيقة لـ %arg0
و%arg1
متطابقة، وإلا
سلوك البرنامج غير محدد:
func.func @foo(%arg0: tensor<?xi32>, %arg1: tensor<?xi32>) -> tensor<?xi32> {
%0 = stablehlo.add %arg0, %arg1 : tensor<?xi32>
return %0 : tensor<?xi32>
}
الترميز
لوصف بناء الجملة، يستخدم هذا المستند صيغة ISO المعدَّلة الخاصة بـ EBNF.
(ISO/IEC 14977:1996,
ويكيبيديا)،
بتعديلين: 1) يتم تحديد القواعد باستخدام ::=
بدلاً من =
،
2) يتم التعبير عن التسلسل باستخدام التقارب بدلاً من ,
.
لوصف الدلالة (أي ضمن أقسام "الأنواع" و"الثابت" و"العمليات")، نستخدم صيغًا تستند إلى بناء جملة بايثون موسّعة مع للتعبير بإيجاز عن عمليات الصفيف كما هو موضح أدناه. هذا يسير بشكل جيد لمقتطفات صغيرة من الرموز، ولكن في بعض الحالات النادرة، عندما فإننا نستخدم بناء جملة فانيلا بايثون والذي يتم تقديمه دائمًا بشكل صريح.
الصيغ
لِنستكشف كيف تعمل الصيغ بناءً على مثال من dot_general
.
المواصفات. يبدو أحد قيود هذه العملية كما يلي:
dim(lhs, lhs_batching_dimensions...) = dim(rhs, rhs_batching_dimensions...)
تأتي الأسماء المستخدمة في هذه المعادلة من مصدرين: 1) الدوال العمومية،
بمعنى dim
، 2) تعريفات العضو لعنصر البرنامج ذي الصلة، أي
إدخالات lhs
وlhs_batching_dimensions
وrhs
وrhs_batching_dimensions
محدد في "الإدخالات" القسم الخاص بـ dot_general
.
وكما ذكرنا أعلاه، فإن بناء جملة هذه المعادلة يعتمد على لغة بايثون مع بعض بإضافات موجهة نحو الإيجاز. لفهم المعادلة، لنقم بتحويل إلى بناء جملة فانيلا بايثون.
أ) في هذه المعادلات، نستخدم =
لتمثيل التساوي، وبالتالي فإن الخطوة الأولى
نحو الحصول على بنية بايثون، يتم استبدال =
بـ ==
، كما يلي:
dim(lhs, lhs_batching_dimensions...) == dim(rhs, rhs_batching_dimensions...)
ب) تدعم هذه الصيغ أيضًا علامات الحذف (...
) التي تحول التعبيرات العددية
إلى تعبيرات تنسور. باختصار، تعني كلمة f(xs...)
تقريبًا "لكل من
العدد القياسي x
في المعامل xs
، نحسب العدد القياسي f(x)
ثم نرجع الكل
هذه النتائج العددية معًا كنتيجة تنسور". في بناء جملة فانيلا بايثون،
تتحول المعادلة المثالية إلى:
[dim(lhs, dim1) for dim1 in lhs_batching_dimensions] ==
[dim(rhs, dim2) for dim2 in rhs_batching_dimensions]
بفضل القطع الناقص، من الممكن غالبًا تجنب العمل على مستوى
المقاييس الفردية. ومع ذلك، في بعض الحالات الصعبة، لا يعتقد المستوى الأدنى
بناء الجملة كما هو الحال في صيغة start_indices[bi0, ..., :, ..., biN]
عن مواصفات gather
. في خدمة الإيجاز، لا نعني
وتقديم أسلوب رسمي محدد لترجمة مثل هذه الصيغة إلى فانيلا بايثون،
تأمل أن يظل مفهومًا بشكل حدسي على أساس كل حالة على حدة.
يُرجى إخبارنا إذا كانت بعض الصيغ المحددة تبدو غير شفافة، وسنحاول
وتحسينها.
ستلاحظ أيضًا أن المعادلات تستخدم القطع الناقص لتوسيع جميع أنواع القوائم، بما في ذلك الأثوان، قوائم متوترات (التي يمكن أن تنشأ مثلاً من المتغير وعدد متساعات التوتر)، إلخ. وهذا مكان آخر لا نوفر فيه القيمة الدقيقة الرسمية (على سبيل المثال، القوائم ليست جزءًا من نظام النوع StableHLO) و وبدلاً من ذلك تعتمد على سهولة الفهم.
ج) وسيلة الترميز النهائية الجديرة بالملاحظة التي نستخدمها ضمنية البث. وفي حين أن عملية StableHLO لا تتوافق مع البث الضمني، تفعله المعادلات، أيضًا في خدمة الإيجاز. باختصار، إذا كان هناك قياس يُستخدم في سياق يُتوقع فيه متسابق، يتم بث المقياس الشكل المتوقع.
إليك قيدًا آخر كي يتسنى لك متابعة مثال dot_general
:
0 <= lhs_batching_dimensions < rank(lhs)
كما هو محدّد في dot_general
المواصفة، فإن lhs_batching_dimensions
عبارة عن متسّع، إلا أن كلاً من 0
rank(lhs)
عبارة عن قيم قياسية. بعد تطبيق البث الضمني، ستتغير المعادلة
يصبح [0, ..., 0] <= lhs_batching_dimensions < [rank(lhs), ..., rank(lhs)]
.
عند تطبيق هذه الصيغة على عملية dot_general
معيّنة،
نقيّمه إلى موتر من القيم المنطقية. عند استخدام المعادلات كقيود، فإن
قيد القيد إذا تم تقييم المعادلة إلى true
أو إلى متوتر
تحتوي على true
من العناصر فقط.
الاسماء
في المعادلات، يتضمن النطاق المعجم: 1) الدوال العمومية، 2) تعريفات العضو،
3) التعريفات المحلية. في ما يلي قائمة الدوال العمومية. القائمة من تعريفات العناصر على عنصر البرنامج الذي يمثل الترميز تم التطبيق على:
- بالنسبة إلى العمليات، تتضمن تعريفات الأعضاء الأسماء التي تم تقديمها في "الإدخالات" أو "المخرجات" الأقسام.
- بالنسبة لكل شيء آخر، تتضمن تعريفات العضو الأجزاء الهيكلية
عنصر البرنامج، الذي يحمل اسم عنصري EBNF المقابل لهما. معظم
وقت ذلك، يتم الحصول على أسماء هذه الأجزاء الهيكلية عن طريق تحويل
أسماء الأحرف غير الطرفية إلى حالة الثعبان (مثال:
IntegerLiteral
=>integer_literal
)، ولكن في بعض الأحيان يتم اختصار الأسماء في العملية (مثلQuantizationStorageType
=>storage_type
) في هذه الحالة تكون الأسماء تم تقديمها بشكل صريح بشكل مشابه لـ "الإدخالات" / "المخرجات" الأقسام قيد التشغيل والمواصفات. - بالإضافة إلى ذلك، تتضمّن تعريفات الأعضاء دائمًا
self
للإشارة إلى عنصر البرنامج المقابل.
القيم
عندما يتم تقييم المعادلات، فإنها تعمل مع أنواع القيم التالية:
1) Value
(القيم الفعلية، مثل dense<[[1, 2], [3, 4]]> : tensor<2x2xi32>
؛
فإنهم يعرفون دائمًا أنواعها)،
2) Placeholder
(القيم المستقبلية، مثل lhs
أو rhs
أو result
؛ والقيم الفعلية لها
غير معروفة بعد، فهي تعرف أنواعها فقط)،
3) Type
(الأنواع على النحو المحدّد في قسم "الأنواع")،
4) Function
(دوال عمومية كما هو موضح في قسم "الدوال").
بناءً على السياق، قد تشير الأسماء إلى قيم مختلفة. المزيد
وعلى وجه التحديد، "الدلالات" للعمليات (وما يعادلها في برامج أخرى
) تحدد منطق بيئة التشغيل، لذلك تتوفر جميع الإدخالات على النحو التالي Value
.
في المقابل، "القيود" للعمليات (وما يعادلها) يحدد
"وقت التجميع" أي شيء يتم تنفيذه عادةً قبل بيئة التشغيل
لذلك تتوفر المدخلات الثابتة فقط مثل Value
والمدخلات الأخرى
يتوفّر فقط باسم Placeholder
.
الاسماء | في "Semantics" | في "القيود" |
---|---|---|
الدوال العمومية | Function |
Function |
الإدخالات المستمرة | Value |
Value |
الإدخالات غير الثابتة | Value |
Placeholder |
المُخرَجات | Value |
Placeholder |
التعريفات المحلية | تستند إلى التعريف | تستند إلى التعريف |
لنستعرض عملية transpose
كمثال:
%result = "stablehlo.transpose"(%operand) {
permutation = dense<[2, 1, 0]> : tensor<3xi64>
} : (tensor<2x3x2xi32>) -> tensor<2x3x2xi32>
بالنسبة إلى هذه العملية، تكون permutation
قيمة ثابتة، لذا فهي متاحة كـ Value
في كل من الدلالة والقيود. في المقابل، operand
وresult
هما
متوفر على شكل Value
في الدلالات ولكن فقط كـ Placeholder
في القيود.
الدوال
إنشاء الأنواع
لا توجد دوال يمكن استخدامها لإنشاء الأنواع. بدلاً من ذلك، نقوم مباشرة
نستخدم بناء جملة النوع لأنها عادةً ما تكون أكثر إيجازًا. مثلاً:
(tensor<E>, tensor<E>) -> (tensor<E>)
بدلاً من function_type(
[tensor_type([], E), tensor_type([], E)], [tensor_type([], E)])
الدوال على الأنواع
- يتم تعريف
element_type
على أنواع متسابقات وأنواع متسابقات الكميّة إرجاعTensorElementType
أوQuantizedTensorElementType
على التوالي منTensorType
أوQuantizedTensorType
المقابلة
def element_type(x: Value | Placeholder | Type):
if type(x) == TensorType:
return tensor_element_type(x)
if type(x) == QuantizedTensorType:
return quantized_tensor_element_type(x)
if type(x) is not Type:
return element_type(type(x))
"
is_per_axis_quantized(x: Value | Placeholder | Type) -> Value
" اختصار لصالحis_quantized(x) and quantization_dimension(x) is not None
.is_per_tensor_quantized(x: Value | Placeholder | Type) -> Value
هو الاختصار لـis_quantized(x) and quantization_dimension(x) is None
.يتحقق
is_promotable(x: Type, y: Type) -> bool
مما إذا كان يمكن ترقية النوعx
. لكتابةy
. عندما تكون قيمةx
وy
هيQuantizedTensorElementType
، يبدأ العرض الترويجي. يسري علىstorage_type
فقط. هذا الإصدار المحدّد من الإعلان الترويجي هو تُستخدم حاليًا في سياق حساب الاختزال (راجع RFC للاطّلاع على مزيد من التفاصيل
def is_promotable(x: Type, y: Type) -> Value:
is_same_type = (is_bool(x) and is_bool(y)) or
(is_integer(x) and is_integer(y)) or (is_float(x) and is_float(y)) or
(is_complex(x) and is_complex(y)) or
(is_quantized(x) and is_quantized(y) and expressed_type(x) = expressed_type(y))
if is_same_type == False:
return False
if is_integer(x) or is_float(x):
return bitwidth(x) <= bitwidth(y)
if is_complex(x):
return bitwidth(element_type(x)) <= bitwidth(element_type(y))
if is_quantized(x):
return bitwidth(storage_type(x)) <= bitwidth(storage_type(y))
return false
is_quantized(x: Value | Placeholder | Type) -> Value
هو اختصار لـis_quantized_tensor_element_type(x)
is_type_name(x: Value | Placeholder | Type) -> Value
متاحة للجميع الأنواع. على سبيل المثال، تعرض الدالةis_float(x)
القيمةtrue
إذا كانت قيمةx
هيFloatType
. إذا كانتx
قيمة أو عنصرًا نائبًا، فإن هذه الدالة هي اختصارis_type_name(type(x))
تعرض
max_value(x: Type) -> Value
الحد الأقصى لقيمةTensorElementType
إذا لم تكنx
هيTensorElementType
، سيتم عرضNone
.تعرض
min_value(x: Type) -> Value
أدنى قيمة ممكنة لـTensorElementType
إذا لم تكنx
هيTensorElementType
، سيتم عرضNone
.member_name(x: Value | Placeholder | Type) -> Any
متاح لجميع الأعضاء تعريفاتmember_name
بجميع أنواعها. على سبيل المثال:tensor_element_type(x)
تعرض الجزءTensorElementType
منTensorType
مقابل. إذا كانتx
قيمة أو عنصرًا نائبًا، فإن هذه الدالة هي اختصارmember_name(type(x))
إذا لم يكنx
من النوع الذي يضم العضو المناسب، أو قيمة أو عنصر نائب من هذا النوع، يؤدي إلى إرجاعNone
.تتحقّق الدالة
is_empty_algorithm(*args: Type)
من ضبط جميع حقول خوارزمية النقاط. إلىNone
. هذا الأمر مطلوب لأنّ خوارزميات النقاط قد تم تحديدها. على Google، لذا سيكون تحديد قيمة افتراضية غير صحيح.
إنشاء القيم
operation_name(*xs: Value | Type) -> Value
متاحة لجميع العمليات. على سبيل المثال، تأخذadd(lhs, rhs)
قيمتين للمتسابقlhs
وrhs
ناتج تقييم العمليةadd
مع هذه المدخلات. بالنسبة إلى بعض العمليات، مثلbroadcast_in_dim
، أنواع مخرجاتها هي: "تحميل"، أي أنه مطلوب لتقييم عملية. في هذه الحالة، لا يمكن هذه الأنواع كوسيطات.
الدوال على القيم
كل عوامل التشغيل والدوال في بايثون متوفرة. مثلاً: كلاهما اشتراك والتقسيم تتوفر التدوينات من بايثون لفهرستها إلى متسابقات التوتر الكمّي والصفوف.
تم تحديد
to_destination_type(x: Value, destination_type: Type) -> Value
في لعرض القيمة المحوّلةx
بناءً علىtype(x)
destination_type
على النحو التالي:
def to_destination_type(x: Value, destination_type: Type) -> Value:
if type(x) == destination_type:
return x
if is_quantized(destination_type):
if is_quantized(type(x)):
return quantize(x, destination_type)
assert is_float(type(x))
return quantize(x, destination_type)
if is_quantized(type(x)):
assert destination_type = expressed_type(type(x))
return dequantize(type(x))
return convert(x, destination_type)
كانت هناك مناقشة مبكرة حول دمج convert
وuniform_quantize
uniform_dequantize
العمليات (#1576).
بعد الدمج، لا نحتاج إلى الدالة أعلاه ويمكننا استخدام اسم العملية
مقابل convert
بدلاً من ذلك.
يتم تحديد
is_nan(x: Value) -> Value
باستخدام موتّرات ويكون الناتجtrue
إذا جميع عناصرx
هيNaN
أوfalse
بخلاف ذلك. إذا لم يكنx
متسابقًا، وإرجاعNone
.يتم تحديد
is_sorted(x: Value) -> Value
باستخدام موتّرات ويكون الناتجtrue
إذا يتم فرز عناصرx
بترتيب تصاعدي حسب الترتيب التصاعدي الترتيب المعجم لمؤشراتها أوfalse
غير ذلك. إذا لم يكنx
دالة Tenor، تعرضNone
.يتم تحديد
is_unique(x: Value) -> Value
باستخدام موتّرات وعرضtrue
إذا كانتx
. لا يحتوي على عناصر مكررة أوfalse
غير ذلك. إذا لم يكنx
متسابقًا، وإرجاعNone
.يتم تحديد
member_name(x: Value) -> Any
لجميع تعريفات الأعضاء.member_name
من جميع القيم. على سبيل المثال، تعرض الدالةreal_part(x)
السمةRealPart
جزء منComplexConstant
مقابل. إذا لم تكنx
قيمة تحتوي على العضو المناسب، يعرضNone
.يتم تحديد
same(x: Value) -> Value
باستخدام موتّرات ويكون الناتجtrue
إذا عناصرx
جميعها تساوي بعضها بعضًا أوfalse
في الحالات الأخرى. إذا كان المتغير على عناصر، تُحتسب على أنها "جميعها متساوية في بعضها البعض"، أي تُرجع الدالةtrue
. إذا لم يكنx
سينور، سيتم عرضNone
.تم تحديد
split(x: Value, num_results: Value, axis: Value) -> Value
في البيانات وعرضnum_results
شرائح منx
على طول المحورaxis
. إذا لم يكنx
هو tensor أوdim(x, axis) % num_results != 0
، سيتم عرضNone
.يتم تحديد
is_defined_in_parent_scope(x: Value) -> Value
في السلاسل وتعرضtrue
إذا كانتx
هي اسم الدالة المحددة في النطاق نفسه. باعتبارها الوظيفة الرئيسية للعملية ذات الصلة.يتم تحديد
is_namespaced_op_name(x: Value) -> Value
من خلال السلاسل والمرتجعات.true
إذا كانx
اسم عملية صالحًا، أي يتوافق مع الاسم العادي التالي التعبير:[a-zA-Z][a-zA-Z0-9_]*([.][a-zA-Z0-9_$]+)+
العمليات الحسابية للأشكال
axes(x: Value | Placeholder | Type) -> Value
هو اختصار لـrange(rank(x))
dim(x: Value | Placeholder | Type, axis: Value) -> Value
هو اختصار لـshape(x)[axis]
dims(x: Value | Placeholder | Type, axes: List) -> List
هو اختصار لـlist(map(lambda axis: dim(x, axis), axes))
يتم تحديد
index_space(x: Value | Placeholder | Type) -> Value
باستخدام متساعات التوتر. ويعرض فهارسsize(x)
لـTensorType
المقابل مرتبة حسب ترتيب معجمي تصاعدي، مثل[0, ..., 0]
،[0, ..., 1]
، ...،shape(x) - 1
إذا لم يكنx
نوع متسّع أو نوع متسّع كمي أو قيمة أو عرض عنصر نائب لأحد هذه الأنواع، بقيمةNone
.rank(x: Value | Placeholder | Type) -> Value
هو اختصار لـsize(shape(x))
يتم تعريف
shape(x: Value | Placeholder | Type) -> Value
في "الدوال على الأنواع" القسم من خلالmember_name
.size(x: Value | Placeholder | Type) -> Value
هو اختصار لـreduce(lambda x, y: x * y, shape(x))
عمليات احتساب الكمية
def baseline_element_type(x: Value | Placeholder | Type) -> Type
هو الاختصار لـelement_type(baseline_type(x))
.يتم تعريف
baseline_type
على أنواع متسابقات وأنواع متسابقات الكميّة إلى "خط أساس"، أي نوع بنفس الشكل ولكن مع تتم إعادة تعيين معلمات قياس نوع العنصر إلى القيم الافتراضية. هذا هو يستخدم كحيلة مفيدة للمقارنة بين أنواع متسابقات التوتر والكمية الكميّة بشكل موحد، وهو مطلوب كثيرًا. بالنسبة للأنواع الكَمية، يتيح ذلك لمقارنة الأنواع مع تجاهل مَعلمات الكمي، أيshape
،storage_type
وexpressed_type
وstorage_min
وstorage_max
يجب أن تتطابق السلسلةquantization_dimension
(للنوع المكمّل حسب المحور) بالكامل، ولكن قد يختلفscales
عنzero points
.
def baseline_type(x: Value | Placeholder | Type) -> Type:
if type(x) == TensorType:
return x
if type(x) == QuantizedTensorType:
element_type = quantized_tensor_element_type(x)
baseline_element_type = QuantizedTensorElementType(
storage_type = storage_type(element_type),
storage_min = storage_min(element_type),
storage_max = storage_max(element_type),
expressed_type = expressed_type(element_type),
quantization_dimension = quantization_dimension(element_type),
scales = [constant(1.0, expressed_type(element_type))] * dim(x, quantization_dimension(element_type)),
zero_points = [constant(0, storage_type(element_type))] * dim(x, quantization_dimension(element_type)))
return QuantizedTensorType(shape(x), baseline_element_type)
if type(x) is not Type:
return baseline_element_type(type(x))
- يتم تعريف
dequantize
على أنواع متسابقات التوتر الكَمية وتحويلها إلى أنواع موتر النقطة العائمة. يحدث ذلك من خلال تحويل العناصر الكمية التي تمثل القيم الصحيحة لنوع التخزين في قيم النقطة العائمة للنوع المعبّر عنه باستخدام النقطة الصفرية والمقياس المرتبطة بنوع العنصر الكمية.
def compute_zero_points(quantized_type, result_type):
if is_per_tensor_quantized(quantized_type):
return broadcast_in_dim(constant(zero_point(quantized_type), storage_type(quantized_type)), [], result_type)
if is_per_axis_quantized(quantized_type):
for i in index_space(result_type):
d = quantization_dimension(quantized_type)
zero_points[i] = zero_points(quantized_type)[i[d]]
return zero_points
def compute_scales(quantized_type, result_type):
if is_per_tensor_quantized(quantized_type):
return broadcast_in_dim(constant(scale(quantized_type), expressed_type(quantized_type)), [],
type(result_type))
if is_per_axis_quantized(quantized_type):
for i in index_space(result_type):
d = quantization_dimension(quantized_type)
scales[i] = scales(quantized_type)[i[d]]
return scales
def dequantize(x: Value) -> Value:
assert is_quantized(x)
x_storage = bitcast_convert(x, storage_type(x))
x_storage_sub = x_storage - compute_zero_points(type(x), type(x_storage))
x_expressed_sub = convert(x_storage_sub, expressed_type(x))
return x_expressed_sub * compute_scales(type(x), type(x_expressed_sub))
- يتم تعريف الدالة
quantize
على أنواع متسّع النقطة العائمة وتحويلها إلى أنواع متسابق العرض الكمّي. ويحدث ذلك من خلال تحويل قيم النقاط العائمة. للنوع المُعبَّر عنه إلى قيم الأعداد الصحيحة المقابلة لنوع التخزين باستخدام النقطة الصفرية والمقياس المرتبط بنوع العنصر الكمي.
def quantize(x: Value, result_type: Type) -> Value:
assert is_float(x) and is_quantized(result_type)
zero_points = compute_zero_points(result_type, TensorType(shape(x), storage_type(result_type)))
converted_zero_points = convert(zero_points, expressed_type(result_type))
converted_min = convert(storage_min(result_type), expressed_type(result_type))
converted_max = convert(storage_max(result_type), expressed_type(result_type))
x_scaled = x / compute_scales(result_type, type(x))
x_scaled_add_zp = x_scaled + converted_zero_points
x_clamped = clamp(converted_min, x_scaled_add_zp, converted_max)
x_rounded = round_nearest_even(x_clamped)
return convert(x_rounded, result_type)
- يستخدم
dequantize_op_quantize
لتحديد العمليات الحاسوبية للعناصر في للأعداد الكميّة. فهو يحدد كمية العناصر، أي يحول العناصر الكميّة إلى عناصر ثم تقوم بإجراء عملية، ثم تحدد الكميات، أي تحويل النتائج إلى أنواع التخزين الخاصة بها. في الوقت الحالي، لا يمكن لهذه الدالة يصلح لكمية كل متسابق. جارِ العمل على عملية جمع الكمية لكل محور (#1574)
def dequantize_op_quantize(op, *inputs_and_output_type):
inputs = inputs_and_output_type[:-1]
output_type = inputs_and_output_type[-1]
float_inputs = map(dequantize, inputs)
float_result = op(*float_inputs)
return quantize(float_result, output_type)
def dequantize_batch_norm_grad_or_training_quantize(op, *inputs_and_output_types):
inputs = inputs_and_output_type[:-3]
float_inputs = map(dequantize, inputs)
float_results = op(*float_inputs)
return map(quantize, float_results, inputs_and_output_type[-3:])
def dequantize_compare(lhs, rhs, comparison_direction):
float_lhs = dequantize(lhs)
float_rhs = dequantize(rhs)
return compare(float_lhs, float_rhs, comparison_direction, FLOAT)
def dequantize_select_quantize(pred, on_true, on_false, output_type):
float_on_true = dequantize(on_true)
float_on_false = dequantize(on_false)
float_result = select(pred, float_on_true, float_on_false)
return quantize(float_result, output_type)
- يُستخدم
hybrid_dequantize_then_op
لتحديد الكمية بالوزن فقط عملية مختلطة تقبل lhs في النقطة العائمة والدالة rh بأنواع محددة. أُنشأها جون هنتر، الذي كان متخصصًا تحدد كمية المدخلات الكميّة إلى أنواعها المعبَّر عنها وتجري عمليات حسابية عدد عشري. نوع العنصر المتغير lhs tensor والنوع المعبر عنه rhs الكميّة يكون متناسورًا متماثلاً.
def hybrid_dequantize_then_op(op, lhs, rhs):
assert(is_float(lhs) and is_quantized(rhs) and element_type(lhs) == expressed_type(rhs))
return op(lhs, dequantize(rhs))
عمليات احتساب الشبكة
cross_partition(replica_groups: Value) -> Value
عرض "cross_replica" أعلاه.cross_replica(replica_groups: Value) -> Value
عرض "cross_replica" أعلاه.cross_replica_and_partition(replica_groups: Value) -> Value
يمكنك الاطّلاع على "cross_replica_and_partition" أعلاه.flattened_ids(replica_groups: Value) -> Value
الاطّلاع على "flattened_ids" أعلاه.
الديناميكية
يمكن أن تحتوي قيم StableHLO على أحجام سمات ديناميكية، مثل: tensor<?xi64>
ومع ذلك، لا يمكن أن تحتوي قيم StableHLO على عدد ديناميكي من السمات (بدون ترتيب).
الديناميكية، على سبيل المثال tensor<*xi64>
). يُسمَح للمعاملين والنتائج باستخدام العناصر الديناميكية
وأحجام الأبعاد، حتى إذا كانت هناك قيود على الأحجام. ستكون القيود
بشكل ثابت إن أمكن، وإلا سيتم تأجيلها إلى وقت التشغيل
إلى حدوث سلوك غير محدد. اطّلِع على الأمثلة أدناه.
عدم تطابُق الأشكال للعمليات الأحادية العناصر
ضع في اعتبارك برنامج الألعاب التالي:
func.func @foo(%arg0: tensor<?xf64>) {
%0 = stablehlo.abs %arg0 : (tensor<?xf64>) -> tensor<2xf64>
return
}
وهذا البرنامج أمر غير عادي، لأنه ليس من الشائع معرفة شكل
النتيجة وليس شكل المدخلات. على الرغم من ذلك، تعتبر هذه دالة StableHLO صالحة
البرنامج. لا يمكن التحقّق بشكل ثابت من عملية abs
في هذه الحالة.
لأن الشكل الدقيق للمعامل غير معروف. ومع ذلك، فإن الأشكال
متوافقة بالتأكيد، ويمكن التحقّق من ذلك بشكل ثابت: قد يتبين أنّ ?
على 2
في وقت التشغيل، ولن تكون هناك أي مشكلة. في المقابل، بإمكان "?
"
يتضح أيضًا أنه عدد صحيح آخر، وفي هذه الحالة يكون السلوك غير محدد.
تجدر الإشارة إلى أنّه إذا كان حجم البُعد ديناميكيًا في النتيجة، لا يمكن سلوك غير محدد. في الواقع، ليس هناك "متوقع" لذلك لا يمكن أن يكون هناك غير متطابق.
عدم تطابق الأشكال للعمليات الثنائية العناصر
ضع في اعتبارك برنامج الألعاب التالي:
func.func @foo(%arg0: tensor<?xf64>, %arg1: tensor<?xf64>) {
%0 = stablehlo.add %arg0, %arg0 : (tensor<?xf64>, tensor<?xf64>) -> tensor<?xf64>
return
}
عندما يتعلق الأمر بالعمليات الثنائية العناصر، تمثل أشكال المدخلات يجب أن تتوافق النتيجة في وقت التشغيل. في وقت التجميع، يجب أن تكون الأبعاد الثابتة متساوية، وإلا فإنها تحتاج فقط إلى أن تكون متوافقة. إذا كانت أي سمة ديناميكية في المُدخلات، قد تكون هناك حاجة إلى بيانات غير محدّدة سلوكًا في وقت التشغيل، لأنّ الحجم الديناميكي قد لا يتطابق مع الحجم الحجم في المعامل الآخر (سواء كان ثابتًا أو ديناميكيًا). إذا كانت جميع المدخلات ثابتة، فما إذا كانت النتيجة ديناميكية أم لا: سيتم التحقّق من السمات المعروفة بشكلٍ ثابت، ولن يتم التحقّق من السمات الديناميكية لفرض أي قيود.
عدم تطابق الأشكال للعمليات التي تتخذ شكل مخرجاتها كمعامل
ضع في اعتبارك برنامج الألعاب التالي:
func.func @foo(%arg0: tensor<2xi32>) {
%0 = stablehlo.dynamic_iota %arg0, dim = 0 : (tensor<2xi32>) -> tensor<3x4xi64>
return
}
يجب أن تتطابق القيم في معامل الشكل في وقت التشغيل مع شكل النتيجة،
وإلا يكون السلوك غير محدد. أي أنّه يجب أن يتضمّن %arg0
في وقت التشغيل
بقيمة dense<[3, 4]> : tensor<2xi32>
. وإذا كان معامل الشكل ثابتًا، فإن هذا
يمكن التحقق منها بشكل ثابت. وإذا كان شكل النتيجة ديناميكيًا بالكامل، فعندئذ يكون هناك
لا يمكن أن يكون عدم التطابق.