StableHLO هي عملية يتم تعيينها للعمليات عالية المستوى (HLO) في نماذج تعلُم الآلة (ML). يعمل نظام StableHLO كطبقة قابلة للنقل بين إطارات عمل تعلُّم الآلة المختلفة وبرامج تجميع تعلُّم الآلة: إطارات عمل تعلُّم الآلة التي تُنتج برامج StableHLO متوافقة مع برامج التجميع الآلي لتعلُّم الآلة التي تستهلك برامج StableHLO.
يكمن هدفنا في تبسيط عملية تطوير تعلُّم الآلة وتسريعها من خلال إنشاء المزيد من التشغيل التفاعلي بين إطارات عمل تعلُّم الآلة المختلفة (مثل TensorFlow وJAX وPyTorch) وبرامج التجميع من حيث تعلُّم الآلة (مثل XLA وIREE). لتحقيق هذه الغاية، توفر هذه الوثيقة مواصفات للغة البرمجة StableHLO.
تحتوي هذه المواصفات على ثلاثة أقسام رئيسية. أولاً، يصف قسم البرامج بنية برامج StableHLO التي تتكوّن من دوال StableHLO التي تتكون في حد ذاتها من عمليات StableHLO. وفي هذه البنية، يحدّد قسم العمليات دلالات العمليات الفردية. يوفر قسم التنفيذ دلالات الألفاظ لكل العمليات التي يتم تنفيذها معًا في البرنامج. أخيرًا، يناقش قسم الملاحظة الترميز المستخدَم خلال المواصفات.
البرامج
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}
تحتوي دوالStableHLO (التي يُطلق عليها أيضًا الدوال المُسمّاة) على معرّف ومدخلات/مخرجات ونص. نخطط في المستقبل لتقديم بيانات وصفية إضافية للدوال لتحقيق توافق أفضل مع HLO (#425، #626، #740، #744).
المعرّفات
FuncId ::= '@' letter {letter | digit}
ValueId ::= '%' digit {digit}
| '%' letter {letter | digit}
letter ::= 'a' | ... | 'z' | 'A' | ... | 'Z' | '_'
digit ::= '0' | ... | '9'
تتشابه معرّفات StableHLO مع المعرّفات في العديد من لغات البرمجة، وتتميّز بخاصيتين: 1) تحتوي جميع المعرّفات على سمات تميز الأنواع المختلفة من المعرّفات، 2) يمكن أن تكون معرّفات القيم رقمية تمامًا لتبسيط إنشاء برامج StableHLO.
الأنواع
Type ::= ValueType | NonValueType
ValueType ::= TensorType | QuantizedTensorType | TokenType | TupleType
NonValueType ::= TensorElementType | QuantizedTensorElementType | FunctionType | StringType
يتم تصنيف أنواع StableHLO إلى أنواع قيم (والتي تُعرف أيضًا باسم أنواع من الدرجة الأولى) التي تمثل قيم StableHLO والأنواع غير ذات القيمة التي تصف عناصر البرنامج الأخرى. تتشابه أنواع StableHLO مع الأنواع في العديد من لغات البرمجة، وخاصيتها الرئيسية هي طبيعة StableHLO الخاصة بالنطاق والتي تؤدي إلى بعض النتائج غير المعتادة (على سبيل المثال، الأنواع القياسية ليست أنواع قيم).
TensorType ::= 'tensor' '<' Shape TensorElementType '>'
Shape ::= {DimensionSize 'x'}
DimensionSize ::= digit {digit}
تمثّل أنواع المستشعر المصفوفات، أي الصفائف متعددة الأبعاد. وتتضمن هذه الأشكال شكل ونوع عنصر، حيث يمثل الشكل أحجام أبعاد غير سالبة بترتيب تصاعدي للأبعاد المقابلة (والتي تُعرف أيضًا باسم المحاور) والمرقمة من 0
إلى R-1
. يُطلق على عدد السمات R
اسم الترتيب. على سبيل المثال، tensor<2x3xf32>
هو نوع متدرج
يحتوي على الشكل 2x3
ونوع العنصر f32
. وله أبعادان (أو محوران) - البعد "الصفر" والبعد الأول - الحجمان هما 2 و3. مرتبة 2.
يحدِّد ذلك دعم الأشكال الثابتة التي تكون فيها أحجام الأبعاد معروفة بشكل ثابت. ونخطّط أيضًا في المستقبل لإتاحة الأشكال الديناميكية التي تكون فيها أحجام الأبعاد غير معروفة جزئيًا أو كليًا (رقم 8). علاوة على ذلك، نخطط لاستكشاف توسيع أنواع المترابط بما يتجاوز أحجام الأبعاد وأنواع العناصر، مثل تضمين التنسيقات (#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-C4), (C9) |
storage_min |
ثابت العدد الصحيح | (C2)، (C4)، (C8) |
storage_max |
ثابت العدد الصحيح | (C3), (C4), (C8) |
expressed_type |
نوع النقطة العائمة | (C1)، (C5) |
quantization_dimension |
ثابت العدد الصحيح الاختياري | (C11-C13) |
scales |
عدد متباين لثابت النقطة العائمة | (C5-C7), (C10), (C11), (C13) |
zero_points |
عدد متغير لثوابت الأعداد الصحيحة | (C8-C10) |
تمثّل أنواع العناصر الكمية قيمًا صحيحة لنوع التخزين في النطاق الذي يتراوح من 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)
على التوالي. تخضع أنواع العناصر الكمية
للقيود التالية:
- (C1)
num_bits(storage_type) < num_bits(expressed_type)
. - (C2)
type(storage_min) = storage_type
. - (C3)
type(storage_max) = storage_type
. - (C4)
min_value(storage_type) <= storage_min < storage_max <= max_value(storage_type)
. - (C5)
type(scales...) = expressed_type
. - (C6)
0 < scales
. - (C7)
is_finite(scales...)
. - (C8)
storage_min <= zero_points <= storage_max
. - (C9)
type(zero_points...) = storage_type
. - (C10)
size(scales) = size(zero_points)
. - (C11) إذا كانت
is_empty(quantization_dimension)
، تكونsize(scales) = 1
. - (C12)
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 ::= 'si4' | 'si8' | 'si16' | 'si32' | 'si64'
UnsignedIntegerType ::= 'ui4' | 'ui8' | 'ui16' | 'ui32' | 'ui64'
FloatType ::= 'f8E4M3FN' | 'f8E5M2' | 'f8E4M3FNUZ' | 'f8E5M2FNUZ'
| 'f8E4M3B11FNUZ' | 'bf16' | 'f16' | 'f32' | 'f64'
ComplexType ::= 'complex' '<' ComplexElementType '>'
ComplexElementType ::= 'f32' | 'f64'
تمثّل أنواع العناصر عناصر من أنواع متبدّلة. على عكس العديد من لغات البرمجة،
هذه الأنواع ليست من الدرجة الأولى في StableHLO. وهذا يعني أنّ برامج SttableHLO لا يمكنها تمثيل قيم هذه الأنواع بشكل مباشر (وبالتالي، يُعدّ تمثيل القيم العددية من النوع T
بقيم متعدّد الأبعاد 0 من النوع tensor<T>
طريقة اصطلاحية).
- يمثل النوع المنطقي القيم المنطقية
true
وfalse
. - يمكن أن تكون أنواع الأعداد الصحيحة موقّعة (
si
) أو غير موقَّعة (ui
) وأن يكون لها أحد عرض البت المتوافق (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 الموضّحة في تدريب واستنتاج النقطة العائمة الهجينة 8 بت (HFP8) للشبكات العصبية العميقة.bf16
يتوافق مع تنسيقbfloat16
الموضّح في BFloat16: السر في تحقيق أداء عالٍ في وحدات معالجة الموتّرات في Cloud.- يتوافق النوعان
f16
وf32
وf64
مع التنسيقينbinary16
("نصف الدقة") وbinary32
("دقة فردية") وbinary64
("دقة مزدوجة") على التوالي في معيار IEEE 754.
- يتطابق نوعَا
- تمثل الأنواع المركّبة قيمًا معقدة تتضمن جزءًا حقيقيًا وجزءًا خياليًا من نوع العنصر نفسه. الأنواع المركّبة المتوافقة هي
complex<f32>
(كلا الجزأين من النوعf32
) وcomplex<f64>
(كلا الجزأين من النوعf64
).
FunctionType ::= '(' InputTypes ')' '->' '(' OutputTypes ')'
InputTypes ::= [ValueType {',' ValueType}]
OutputTypes ::= [ValueType {',' ValueType}]
تمثّل أنواع الدوال كلاً من الدوال المُسمّاة والدوال المجهولة الهوية. وتشتمل على أنواع الإدخالات (قائمة الأنواع على يسار ->
) وأنواع المخرجات
(قائمة الأنواع على الجانب الأيسر من ->
). في العديد من لغات البرمجة، تكون أنواع الدوال من الدرجة الأولى، ولكنها ليست ثابتة في دالة StableHLO.
StringType ::= 'string'
يمثل نوع السلسلة تسلسلات من وحدات البايت. على عكس العديد من لغات البرمجة، لا يكون نوع السلسلة هو الفئة الأولى في StableHLO ولا يُستخدم إلا لتحديد بيانات التعريف الثابتة لعناصر البرنامج.
العمليات
تمثّل عمليات SttableHLO (التي تُعرف أيضًا باسم ops) مجموعة مغلقة من العمليات عالية المستوى في نماذج تعلُّم الآلة. كما ناقشنا أعلاه، تستند بنية StableHLO بشكل كبير إلى تقنية MLIR، والتي لا تُعد بالضرورة البديل الأكثر توفيرًا من حيث الراحة، ولكنها يمكن القول إنَّها الأنسب لهدف StableHLO المتمثل في إنشاء المزيد من إمكانية التشغيل التفاعلي بين إطارات عمل تقنية تعلُّم الآلة وبرامج تجميع تعلُّم الآلة.
Op ::= [OpOutputs] OpName OpInputs ':' OpSignature
OpName ::= '"' 'stablehlo' '.' OpMnemonic '"'
OpMnemonic ::= 'abs' | 'add' | ...
تتضمَّن عمليات SttableHLO (التي تُسمى أيضًا ops) اسمًا
ومدخلات/مخرجات وتوقيعًا. يتكوّن الاسم من البادئة stablehlo.
وmnemonic تحدد بشكل فريد إحدى العمليات المتوافقة. انظر أدناه للحصول على
قائمة شاملة بجميع العمليات المدعومة.
في الوقت الحالي، تحتوي برامج StableHLO في البرية على عمليات غير مذكورة في هذا المستند أحيانًا. نخطط في المستقبل إما لاستيعاب هذه العمليات في عملية StableHLO أو منع ظهورها في برامج StableHLO. في الوقت الحالي، في ما يلي قائمة بهذه العمليات:
builtin.module
وfunc.func
وfunc.call
وfunc.return
(رقم 425).- عمليات
chlo
(#602). - فئة "ليست في HLO" من عمليات StableHLO - كانت في البداية جزءًا من عملية StableHLO ولكن تم اعتبارها لاحقًا غير مناسبة:
broadcast
،create_token
،cross-replica-sum
،dot
،einsum
،torch_index_select
،unary_einsum
(#3). - فئة "Dynamism" من عمليات StableHLO - تم تحديدها منذ البداية من MHLO، لكننا لم نحددها بعد:
compute_reshape_shape
،cstr_reshapable
،dynamic_broadcast_in_dim
،dynamic_conv
،dynamic_gather
،dynamic_iota
،dynamic_pad
،dynamic_reshape
،real_dynamic_slice
،set_dimension_size
(#8). - العمليات الحسابية للأشكال، بما في ذلك عمليات
arith
وshape
وtensor
(#8).
OpInputs ::= OpInputValues OpInputFuncs OpInputAttrs
OpInputValues ::= '(' [OpInputValue {',' OpInputValue}] ')'
OpInputValue ::= ValueId
OpInputFuncs ::= ['(' OpInputFunc {',' OpInputFunc} ')']
OpInputAttrs ::= ['{' OpInputAttr {',' OpInputAttr} '}']
OpOutputs ::= [OpOutput {',' OpOutput} '=']
OpOutput ::= ValueId
تستهلك العمليات المدخلات وتنتج الناتجات. يتم تصنيف الإدخالات إلى
قيم الإدخال (يتم حسابها أثناء التنفيذ)، ودوال الإدخال (يتم توفيرها
بشكل ثابت، لأن دوال StableHLO ليست قيمًا من الدرجة الأولى)
وسمات الإدخال (يتم توفيرها أيضًا بشكل ثابت). يعتمد نوع المدخلات والمخرجات التي يتم
استهلاكها وإنتاجها بواسطة العملية على عملية الاستدعاء. على سبيل المثال، تستهلك عملية 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}] ')'
يتكوّن توقيع Op من أنواع جميع قيم الإدخال (قائمة الأنواع على الجانب الأيسر من ->
) وأنواع جميع قيم الإخراج (قائمة
أنواع الإخراج على الجانب الأيمن من ->
). بعبارة أخرى، تكون أنواع الإدخالات
متكررة، وأن أنواع الإخراج تكون متكررة في أغلب الأحيان أيضًا (لأنّه يمكن استنتاج أنواع الإخراج على معظم عمليات
SableHLO من المدخلات). ومع ذلك، فإنّ توقيع العملية هو عمدًا جزءًا من بنية 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
ثابت StableHLO لها نوع حرفي ونوع يمثلان معًا قيمة 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'
تمثل ثوابت الأعداد الصحيحة قيم الأعداد الصحيحة من خلال السلاسل التي تستخدم الترميز العشري أو السداسي العشري. ولا يمكن استخدام القواعد الأخرى، مثل الثنائية أو الثماني. تنطبق القيود التالية على ثوابت الأعداد الصحيحة:
- (C1)
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
. يتم تحديد الترتيب الذي يتم به تخزين هذه
الأجزاء في الذاكرة بعد ذلك. الثوابت المعقدة لها
القيود التالية:
- (C1)
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
تمثل ثوابت Tensor قيم الموتر باستخدام القوائم المتداخلة المحددة باستخدام ترميز NumPy. على سبيل المثال، تمثِّل 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) '>'
تمثل ثوابت المتسلسل الكمية قيم المتحد الكمية باستخدام نفس طريقة الترميز مثل ثوابت المتسلسل، مع عناصر محددة كثوابت من نوع التخزين. تنطبق الثوابت الكمّية على القيود التالية:
- (C1)
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) |
القيود
- (C1)
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) |
(I2) | rhs |
متعدّد أو متعدّد كميّ لكل موقد | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متعدّد أو متعدّد كميّ لكل موقد | (C1) |
القيود
- (C1)
baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)
.
أمثلة
// %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، تعمل على إنشاء تسلسل لقيم
الموتر operand
من كل عملية على طول all_gather_dim
وينتج عنها
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
:
operands@receiver = [operand@sender for sender in process_group]
مقابل كلreceiver
فيprocess_group
.result@process = concatenate(operands@process, all_gather_dim)
مقابل كلprocess
فيprocess_group
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متعدّد أو متعدّد كميّ لكل موقد | (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) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متعدّد أو متعدّد كميّ لكل موقد | (C6) |
القيود
- (C1)
0 <= all_gather_dim < rank(operand)
. - (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(result) = type(operand)
باستثناء:dim(result, all_gather_dim) = dim(operand, all_gather_dim) * dim(process_groups, 1)
.
أمثلة
// num_replicas: 2
// num_partitions: 1
// %operand@(0, 0): [[1, 2], [3, 4]]
// %operand@(1, 0): [[5, 6], [7, 8]]
%result = "stablehlo.all_gather"(%operand) {
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<2x4xi64>
// %result@(0, 0): [[1, 2, 5, 6], [3, 4, 7, 8]]
// %result@(1, 0): [[1, 2, 5, 6], [3, 4, 7, 8]]
all_reduce
دلالات الألفاظ
ضمن كل مجموعة عمليات في شبكة عمليات StableHLO، يتم تطبيق دالة الاختزال computation
على قيم متدرج operand
من كل عملية وينتج عن ذلك دالة 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
:
result@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) | operand |
متعدّد أو متعدّد كميّ لكل موقد | (C5), (C6) |
(I2) | replica_groups |
عدد متغير لثوابت الموتّر أحادية البُعد من النوع si64 |
(C1-C3) |
(I3) | channel_id |
ثابت من النوع si64 |
(C4) |
(I4) | use_global_device_ids |
ثابت من النوع i1 |
(C4) |
(I5) | computation |
function | (C5) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متعدّد أو متعدّد كميّ لكل موقد | (C6-C7) |
القيود
- (C1)
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(result) = shape(operand)
. - (C7)
element_type(result) = E
.
أمثلة
// num_replicas: 2
// num_partitions: 1
// %operand@(0, 0): [1, 2, 3, 4]
// %operand@(1, 0): [5, 6, 7, 8]
%result = "stablehlo.all_reduce"(%operand) ({
^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_handle = #stablehlo.channel_handle<handle = 0, type = 0>
} : (tensor<i64>) -> tensor<i64>
// %result@(0, 0): [6, 8, 10, 12]
// %result@(1, 0): [6, 8, 10, 12]
all_to_all
دلالات الألفاظ
في كل مجموعة عمليات في شبكة عمليات StableHLO، تقسّم قيم
الموتر operand
على طول split_dimension
إلى أجزاء، ويعمل على توزيع الأجزاء
المقسمة بين العمليتين، وإنشاء تسلسل للأجزاء المبعثرة على طول
concat_dimension
وإنشاء متوتر result
.
تقسّم العملية شبكة عملية StableHLO إلى process_groups
والتي يتم تحديدها على النحو التالي:
cross_replica(replica_groups)
إذاchannel_id <= 0
.cross_partition(replica_groups)
إذاchannel_id > 0
.
بعد ذلك، ضمن كل process_group
:
split_parts@sender = split(operand@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)
.result@process = concatenate(scattered_parts@process, concat_dimension)
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متعدّد أو متعدّد كميّ لكل موقد | (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 |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متعدّد أو متعدّد كميّ لكل موقد | (C9) |
القيود
- (C1)
0 <= split_dimension < rank(operand)
. - (C2)
dim(operand, split_dimension) % split_count = 0
. - (C3)
0 <= concat_dimension < rank(operand)
. - (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(result) = type(operand)
باستثناء:dim(result, split_dimension) = dim(operand, split_dimension) / split_count
.dim(result, concat_dimension) = dim(operand, concat_dimension) * split_count
.
أمثلة
// 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.all_to_all"(%operand) {
split_dimension = 1 : i64,
concat_dimension = 0 : i64,
split_count = 2 : i64,
replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>
} : (tensor<2x4xi64>) -> tensor<4x2xi64>
// %result@(0, 0): [[1, 2],
// [5, 6],
// [9, 10],
// [13, 14]]
// %result@(1, 0): [[3, 4],
// [7, 8],
// [11, 12],
// [15, 16]]
و
دلالات الألفاظ
ينفذ الإجراء AND في عناصر مترابطة لاثنين من معاملَي الشد lhs
وrhs
وينتج عن
result
موتر. بناءً على نوع العنصر، يتم تنفيذ ما يلي:
- للقيم المنطقية: المنطقي AND.
- بالنسبة إلى الأعداد الصحيحة: استخدام البت باستخدام AND.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
متعدّد النوع المنطقي أو العدد الصحيح | (C1) |
(I2) | rhs |
متعدّد النوع المنطقي أو العدد الصحيح | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متعدّد النوع المنطقي أو العدد الصحيح | (C1) |
القيود
- (C1)
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
وتُنتج
result
متعدّد. بناءً على نوع العنصر، يتم تنفيذ ما يلي:
- للأعداد العشرية:
atan2
من IEEE-754. - للأعداد المعقدة: مركّب atan2.
- بالنسبة إلى الأنواع الكمية:
dequantize_op_quantize(atan2, lhs, rhs, type(result))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
متعدّد من نوع النقطة العائمة أو المعقد أو متعدّد كميّ لكل موقد | (C1) |
(I2) | rhs |
متعدّد من نوع النقطة العائمة أو المعقد أو متعدّد كميّ لكل موقد | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متعدّد من نوع النقطة العائمة أو المعقد أو متعدّد كميّ لكل موقد | (C1) |
القيود
- (C1)
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 الحالية باستخدام بناء جملة بايثون على النحو التالي:
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) |
القيود
- (C1)
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) |
القيود
- (C1)
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 الحالية باستخدام بناء جملة بايثون على النحو التالي:
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) |
القيود
- (C1)
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 |
متوتر 0 أبعاد من النوع si32 |
|
(I2) | branches |
عدد الدوال المختلفة | (C1-C4) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
results |
العدد المتباين من الموتّرات، أو الموتدّات الكمية أو الرموز المميّزة | (C4) |
القيود
- (C1)
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) |
القيود
- (C1)
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) |
القيود
- (C1)
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]
أزرق سماوي
دلالات الألفاظ
لحساب تحلل Cهولسكي لدفعة من المصفوفات.
بشكل أكثر رسمية، بالنسبة إلى 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) |
القيود
- (C1)
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) |
القيود
- (C1)
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(0, element_type(result)), [], type(result))
بطريقة أخرى.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متّجه متّجه للأسفل | (C3) |
(I2) | replica_groups |
عدد متغير لثوابت الموتّر أحادية البُعد من النوع si64 |
(C1)، (C2) |
(I3) | channel_id |
ثابت من النوع si64 |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متّجه متّجه للأسفل | (C3) |
القيود
- (C1)
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) |
القيود
- (C1)
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. يبدو أن هذه الميزة لم يتم استخدامها، ولذلك نخطط لإزالتها في المستقبل (#584).
بالنسبة إلى أنواع العناصر المعقّدة، يتم إجراء مقارنة معجمية لأزواج (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) |
القيود
- (C1)
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) |
القيود
- (C1)
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)]
concatenate
دلالات الألفاظ
تربط 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) |
القيود
- (C1)
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) |
القيود
- (C1)
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
. انظر أدناه لمعرفة كيفية عمل
هذا مع الأنواع المعقدة.
بالنسبة إلى الإحالات الناجحة التي تتضمّن عدد صحيح إلى عدد صحيح أو عدد صحيح إلى نقطة عددية أو نقطة عائمة إلى نقطة عائمة، إذا كان من الممكن تمثيل قيمة المصدر بدقة في نوع الوجهة، تكون قيمة النتيجة هي ذلك التمثيل الدقيق. وبخلاف ذلك، يتم تحديد السلوك لاحقًا (#180).
بالنسبة إلى الإحالات الناجحة التي تتضمّن floating-point-to-integer، يتم اقتطاع الجزء الجزئي. إذا تعذّر تمثيل القيمة المقتطعة في نوع الوجهة، يكون السلوك لاحقًا (#180).
والتحويل الذي يتضمّن مكون مركّب إلى معقد يتّبع السلوك نفسه لإحالات ناجحة النقطة العائمة إلى نقطة عائمة لتحويل أجزاء حقيقية وتخيلية.
بالنسبة إلى الإحالات الناجحة من النوع complex-to-any-other-type والإحالات الناجحة من نوع complex-to-any-other-type، يتم تجاهل القيمة التخيلية للمصدر أو تصبح القيمة التخيلية للوجهة صفرًا، على التوالي. يتبع تحويل الجزء الحقيقي تحويلات النقطة العائمة.
من حيث المبدأ، يمكن أن تعبّر هذه العملية عن فك الكميات (التحويل من
المتوترات الكمية إلى متحدتات عادية)، وتحديد الكمية (التحويل من دوال متعددة
عادية إلى عارضات كمية) وإعادة قياس الكم (التحويل بين متوترات كمية)، ولكن في الوقت الحالي لدينا عمليات مخصصة لذلك -
uniform_dequantize
لحالة الاستخدام الأولى وuniform_quantize
لحالات الاستخدام الثانية والثالثة. في المستقبل، قد يتم دمج هاتين العمليتين في convert
(#1576).
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متّجه متّجه للأسفل | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متّجه متّجه للأسفل | (C1) |
القيود
- (C1)
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))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
متعدّد أو متعدّد كميّ لكل موقد | (C1), (C10-C11), (C14) (C25), (C27-C30) |
(I2) | rhs |
متعدّد أو متدرج كمي | (C1), (C14-C16), (C25), (C27-C32) |
(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), (C32) |
(I13) | kernel_spatial_dimensions |
ثابت الموتّر الأحادي الأبعاد من النوع si64 |
(C17-C18), (C25) |
(I14) | output_batch_dimension |
ثابت من النوع si64 |
(C20), (C25) |
(I15) | output_feature_dimension |
ثابت من النوع si64 |
(C20), (C25), (C33) |
(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-C31), (C33) |
القيود
- (C1)
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_tensor(lhs) and is_quantized_tensor(rhs) and is_quantized_tensor(result)
. - (C29)
storage_type(lhs) = storage_type(rhs)
. - (C30)
expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
. - (C31) إذا كانت
is_per_tensor_quantized(rhs)
، عندهاis_per_tensor_quantized(result)
. - (C32) إذا كانت
is_per_axis_quantized(rhs)
، عندهاquantization_dimension(rhs) = kernel_output_feature_dimension
. - (C33) إذا كانت
is_per_axis_quantized(result)
، عندهاquantization_dimension(result) = output_feature_dimension
.
- (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 = dense<4> : tensor<2xi64>,
padding = dense<0> : tensor<2x2xi64>,
lhs_dilation = dense<2> : tensor<2xi64>,
rhs_dilation = dense<1> : tensor<2xi64>,
window_reversal = dense<false> : tensor<2xi1>,
// 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]>,
feature_group_count = 1 : i64,
batch_group_count = 1 : i64,
precision_config = [#stablehlo<precision DEFAULT>, #stablehlo<precision DEFAULT>]
} : (tensor<1x4x4x1xi32>, tensor<3x3x1x1xi32>) -> tensor<1x2x2x1xi32>
// %result: [[
// [[10], [26]],
// [[46], [62]]
// ]]
جيب التمام
دلالات الألفاظ
تنفِّذ عملية جيب التمام في العناصر المقابلة على مستوى العناصر في الموتر operand
وتنشئ متعدّد result
. بناءً على نوع العنصر، يتم تنفيذ ما يلي:
- للأعداد العشرية:
cos
من IEEE-754. - بالنسبة إلى الأعداد المركّبة: جيب التمام المركّب.
- بالنسبة إلى الأنواع الكمية:
dequantize_op_quantize(cosine, operand, type(result))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متعدّد من نوع النقطة العائمة أو المعقد أو متعدّد كميّ لكل موقد | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متعدّد من نوع النقطة العائمة أو المعقد أو متعدّد كميّ لكل موقد | (C1) |
القيود
- (C1)
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) |
القيود
- (C1)
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",
api_version = 1 : 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) |
القيود
- (C1)
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))
.
يحدد هذا فقط الدلالة الدلالية لتحديد كم المتسلسل. إن عملية القياس حسب المحور هي قيد التنفيذ (#1574). ويمكننا أيضًا في المستقبل إتاحة استخدام طريقة القياس المختلطة (#1575).
يتحكم precision_config
في المفاضلة بين السرعة والدقة لعمليات
الحسابية على خلفيات مسرِّع الأعمال. يمكن أن يكون ذلك واحدًا مما يلي (في الوقت الحالي، لم يتم تحديد دلالات قيم التعداد هذه بشكل كافٍ، ولكننا نخطط لمعالجة ذلك في
#755):
DEFAULT
: أسرع عملية حسابية، ولكن التقريب الأقل دقةً للرقم الأصليHIGH
: عملية حسابية أبطأ، ولكن تقريب أكثر دقة للرقم الأصليHIGHEST
: أقصر عملية حسابية، ولكنها أكثر دقة تقديرية للرقم الأصلي.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
متعدّد أو متعدّد كميّ لكل موقد | (C5-C6), (C9-C10), (C12-C16) |
(I2) | rhs |
متعدّد أو متعدّد كميّ لكل موقد | (C7-C10), (C12) |
(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) |
(I7) | precision_config |
عدد متغيّر لتعدادات DEFAULT وHIGH وHIGHEST |
(C11) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متعدّد أو متعدّد كميّ لكل موقد | (C12), (C14), (C16) |
القيود
- (C1)
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) and is_quantized(rhs) and is_quantized(result)
. - (C15)
storage_type(lhs) = storage_type(rhs)
. - (C16)
expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
. - (C17)
zero_points(rhs) = 0
.
- (C14)
أمثلة
// %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>]
} : (tensor<2x2x2xi64>, tensor<2x2x2xi64>) -> tensor<2x2x2xi64>
// %result: [
// [[1, 2],
// [3, 4]],
// [[5, 6],
// [7, 8]]
// ]
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 |
عدد متغير لأمتارات 0 بعد الأبعاد لنوع صحيح | (C2), (C3) |
(I3) | slice_sizes |
ثابت الموتّر الأحادي الأبعاد من النوع si64 |
(C2)، (C4)، (C5) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متعدّد أو متعدّد كميّ لكل موقد | (C1)، (C5) |
القيود
- (C1)
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 = dense<[2, 2]> : tensor<2xi64>
} : (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 |
عدد متغير لأمتارات 0 بعد الأبعاد لنوع صحيح | (C4), (C5) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متعدّد أو متعدّد كميّ لكل موقد | (C1) |
القيود
- (C1)
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) |
القيود
- (C1)
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) |
القيود
- (C1)
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
دلالات الألفاظ
يُجري عمليات تحويل فورييه للأمام والعكس للمدخلات/المخرجات الحقيقية والمعقدة.
fft_type
هو أحد الخيارات التالية:
FFT
: إعادة توجيه FFT من المعقد إلى المعقد.IFFT
: دالة FFT العكسية المركّبة إلى المركّبةRFFT
: عملية إعادة توجيه فعلية مع رموز FFTIRFFT
: دالة FFT معكوسة حقيقية (بمعنى أنها تأخذ معقدًا، تؤدي إلى إرجاع حقيقي)
بشكل أكثر رسمية، نظرًا لأن الدالة fft
التي تستخدم متحدتات البُعد الواحد من الأنواع المركّبة كمدخلات، تُنتج متعدّدات أبعاد واحدة من نفس أنواع الخرج وتحسب تحويل فورييه المنفصل:
بالنسبة إلى fft_type = FFT
، يتم تعريف result
على أنه النتيجة النهائية لسلسلة من العمليات الحسابية حيث يتم تحديد 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 = 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) |
القيود
- (C1)
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 = dense<4> : tensor<1xi64>
} : (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) |
القيود
- (C1)
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
.
offset_index = result_index[offset_dims...]
.full_offset_index = [oi0, ..., 0, ..., oiN]
حيث تكونoi
عناصر فردية فيoffset_index
، ويتم إدراج0
في فهارس منcollapsed_slice_dims
.operand_index = full_start_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), (C7), (C10-C12), (C14) |
(I2) | start_indices |
متعدّد نوع العدد الصحيح | (C2), (C3), (C13) |
(I3) | offset_dims |
ثابت الموتّر الأحادي الأبعاد من النوع si64 |
(C1), (C4-C5), (C13) |
(I4) | collapsed_slice_dims |
ثابت الموتّر الأحادي الأبعاد من النوع si64 |
(C1), (C6-C8), (C13) |
(I5) | start_index_map |
ثابت الموتّر الأحادي الأبعاد من النوع si64 |
(C3), (C9), (C10) |
(I6) | index_vector_dim |
ثابت من النوع si64 |
(C2), (C3), (C13) |
(I7) | slice_sizes |
ثابت الموتّر الأحادي الأبعاد من النوع si64 |
(C8), (C11-C13) |
(I8) | indices_are_sorted |
ثابت من النوع i1 |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متعدّد أو متعدّد كميّ لكل موقد | (C5), (C13-C14) |
القيود
- (C1)
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]]
// ]
%result = "stablehlo.gather"(%operand, %start_indices) {
dimension_numbers = #stablehlo.gather<
offset_dims = [2, 3],
collapsed_slice_dims = [0],
start_index_map = [1, 0],
index_vector_dim = 2>,
slice_sizes = dense<[1, 2, 2]> : tensor<3xi64>,
indices_are_sorted = false
} : (tensor<3x4x2xi32>, tensor<2x3x2xi64>) -> tensor<2x3x2x2xi32>
// %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]]
// ]
// ]
get_dimension_size
دلالات الألفاظ
لعرض حجم dimension
المحدد من operand
. بشكل أكثر رسمية،
"result = dim(operand, dimension)
".
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متّجه متّجه للأسفل | (C1) |
(I2) | dimension |
ثابت من النوع si64 |
(C1) |
المُخرَجات
الاسم | النوع |
---|---|
result |
متوتر 0 أبعاد من النوع si32 |
القيود
- (C1)
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 |
tuple | (C1)، (C2) |
(I2) | index |
ثابت من النوع si32 |
(C1)، (C2) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
أي نوع متوافق | (C2) |
القيود
- (C1)
0 <= index < size(operand)
. - (C2)
type(result) = tuple_element_types(operand)[index]
.
أمثلة
// %operand: ([1.0, 2.0], (3))
%result = "stablehlo.get_tuple_element"(%operand) {
index = 0 : i32
} : (tuple<tensor<2xf32>, tuple<tensor<i32>>>) -> tensor<2xf32>
// %result: [1.0, 2.0]
if
دلالات الألفاظ
لعرض الناتج من تنفيذ دالة واحدة من true_branch
أو false_branch
استنادًا إلى قيمة pred
. بشكل أكثر رسمية، result =
pred ? true_branch() : false_branch()
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | pred |
متوتر 0 أبعاد من النوع i1 |
|
(I2) | true_branch |
function | (C1-C3) |
(I3) | false_branch |
function | (C1)، (C2) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
results |
العدد المتباين من الموتّرات، أو الموتدّات الكمية أو الرموز المميّزة | (C3) |
القيود
- (C1)
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) |
القيود
- (C1)
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) |
القيود
- (C1)
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[result_index] = constant(is_quantized(output) ?
quantize(result_index[iota_dimension], element_type(output)) :
result_index[iota_dimension], element_type(output))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | iota_dimension |
si64 |
(C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
output |
متعدّد عدد صحيح أو نقطة عائمة أو من نوع مركّب أو متعدّد كميّ لكل موقد | (C1) |
القيود
- (C1)
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) |
القيود
- (C1)
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) |
القيود
- (C1)
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) |
القيود
- (C1)
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) |
القيود
- (C1)
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])
.
تجدر الإشارة إلى أنّ dimensions
غير مستخدَمة حاليًا ومن المحتمل أن تتم إزالتها في المستقبل (#487).
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | inputs |
العدد المتباين للمتوترات أو الموترات الكمّية لكل مفرد | (C1-C4) |
(I2) | dimensions |
ثابت الموتّر الأحادي الأبعاد من النوع si64 |
(C3) |
(I3) | computation |
function | (C4) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متعدّد أو متعدّد كميّ لكل موقد | (C1)، (C4) |
القيود
- (C1)
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 = dense<[0, 1]> : tensor<2xi64>
} : (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) |
القيود
- (C1)
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]]
أقل قيمة
دلالات الألفاظ
تُجري عمليات دقيقة من حيث أداء العناصر على الموترين 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) |
القيود
- (C1)
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) |
القيود
- (C1)
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) |
القيود
- (C1)
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) |
القيود
- (C1)
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) |
القيود
- (C1)
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) |
القيود
- (C1)
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"(%inputs0, %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 |
متعدّد أبعاد صفري أو متعدّد كمي لكل موصّل | (C1) |
(I3) | edge_padding_low |
ثابت الموتّر الأحادي الأبعاد من النوع si64 |
(C1)، (C4) |
(I4) | edge_padding_high |
ثابت الموتّر الأحادي الأبعاد من النوع si64 |
(C1)، (C4) |
(I5) | interior_padding |
ثابت الموتّر الأحادي الأبعاد من النوع si64 |
(C2-C4) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متعدّد أو متعدّد كميّ لكل موقد | (C3-C6) |
القيود
- (C1)
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 = dense<[0, 1]> : tensor<2xi64>,
edge_padding_high = dense<[2, 1]> : tensor<2xi64>,
interior_padding = dense<[1, 2]> : tensor<2xi64>
} : (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 |
متوتر 0 أبعاد من النوع ui32 |
أمثلة
%result = "stablehlo.partition_id"() : () -> tensor<ui32>
الترويج
دلالات الألفاظ
تحسب العناصر حسب عدد العناصر في عدد وحدات البت المعيّنة في الموتر operand
وينتج عنها متعدّد result
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متعدّد نوع العدد الصحيح | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متعدّد نوع العدد الصحيح | (C1) |
القيود
- (C1)
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) |
القيود
- (C1)
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) |
القيود
- (C1)
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]
recv
دلالات الألفاظ
تلقّي البيانات من قناة مرتبطة بـ 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 |
العدد المتغير للمتوردات صفرية الأبعاد أو المتحدات الكمية لكل مولد | (C2), (C3) |
(I3) | dimensions |
ثابت الموتّر الأحادي الأبعاد من النوع si64 |
(C4), (C5), (C7) |
(I4) | body |
function | (C6) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
results |
العدد المتباين للمتوترات أو الموترات الكمّية لكل مفرد | (C3), (C7), (C8) |
القيود
- (C1)
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 = dense<1> : tensor<1xi64>
} : (tensor<1x6xi64>, tensor<i64>) -> tensor<1xi64>
// %result = [15]
reduce_precision
دلالات الألفاظ
تُجري إحالة ناجحة من حيث العناصر لـ operand
إلى نوع نقطة عائمة آخر يستخدم exponent_bits
وmantissa_bits
والعودة إلى نوع النقطة العائمة الأصلي، وينتج عن ذلك متعدّد output
.
بشكل أكثر رسمية:
- يتم تعديل بتات القيمة الأصلية لتقريب القيمة الأصلية إلى أقرب قيمة يمكن تمثيلها باستخدام
mantissa_bits
باستخدام دلالاتroundToIntegralTiesToEven
. - وبعد ذلك، إذا كانت
mantissa_bits
أصغر من عدد وحدات بت mantisa للقيمة الأصلية، سيتم اقتطاع وحدات بت mantisa إلى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) |
القيود
- (C1)
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 |
function | (C7) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متعدّد أو متعدّد كميّ لكل موقد | (C8-C9) |
القيود
- (C1)
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 |
العدد المتغير للمتوردات صفرية الأبعاد أو المتحدات الكمية لكل مولد | (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 |
function | (C13) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
results |
العدد المتباين للمتوترات أو الموترات الكمّية لكل مفرد | (C1), (C14-C16) |
القيود
- (C1)
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 = dense<[2, 1]> : tensor<2xi64>,
window_strides = dense<[4, 1]> : tensor<2xi64>,
base_dilations = dense<[2, 1]> : tensor<2xi64>,
window_dilations = dense<[3, 1]> : tensor<2xi64>,
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) |
القيود
- (C1)
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 |
متوتر 0 أبعاد من النوع 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) |
القيود
- (C1)
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 = dense<1> : tensor<1xi64>
} : (tensor<3x2xi32>) -> tensor<3x2xi32>
// %result: [[2, 1], [4, 3], [6, 5]]
rng
دلالات الألفاظ
تنشئ هذه الدالة أرقامًا عشوائية باستخدام خوارزمية 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) |
القيود
- (C1)
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 |
متعدّد العدد الصحيح أو نوع النقطة العائمة |
القيود
- (C1)
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) |
القيود
- (C1)
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) |
القيود
- (C1)
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) |
القيود
- (C1)
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]]
scatter
دلالات الألفاظ
إنتاج 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
.
update_window_index = update_index[update_window_dims...]
.full_window_index = [wi0, ..., 0, ..., wiN]
حيث تكونwi
عناصر فردية فيupdate_window_index
، ويتم إدراج0
في فهارس منinserted_window_dims
.result_index = full_start_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), (C10), (C13), (C15-C16) |
(I2) | scatter_indices |
متعدّد نوع العدد الصحيح | (C4), (C11), (C14) |
(I3) | updates |
العدد المتباين للمتوترات أو الموترات الكمّية لكل مفرد | (C3-C6), (C8) |
(I4) | update_window_dims |
ثابت الموتّر الأحادي الأبعاد من النوع si64 |
(C2)، (C4)، (C7)، (C8) |
(I5) | inserted_window_dims |
ثابت الموتّر الأحادي الأبعاد من النوع si64 |
(C2)، (C4)، (C9)، (C10) |
(I6) | scatter_dims_to_operand_dims |
ثابت الموتّر الأحادي الأبعاد من النوع si64 |
(C11-C13) |
(I7) | index_vector_dim |
ثابت من النوع si64 |
(C4), (C11), (C14) |
(I8) | indices_are_sorted |
ثابت من النوع i1 |
|
(I9) | unique_indices |
ثابت من النوع i1 |
|
(I10) | update_computation |
function | (C15) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
results |
العدد المتباين للمتوترات أو الموترات الكمّية لكل مفرد | (C15-C17) |
القيود
- (C1)
same(shape(inputs...))
. - (C2)
rank(inputs[0]) = size(update_window_dims) + size(inserted_window_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
.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(inserted_window_dims) and is_sorted(update_window_dims)
. - (C10)
0 <= inserted_window_dims < rank(inputs[0])
. - (C11)
size(scatter_dims_to_operand_dims) = index_vector_dim < rank(scatter_indices) ? dim(scatter_indices, index_vector_dim) : 1
. - (C12)
is_unique(scatter_dims_to_operand_dims)
. - (C13)
0 <= scatter_dims_to_operand_dims < rank(inputs[0])
. - (C14)
0 <= index_vector_dim <= rank(scatter_indices)
. - (C15)
update_computation
من النوع(tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ..., tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>)
، حيثis_promotable(element_type(inputs[i]), Ei)
. - (C16)
shape(inputs...) = shape(results...)
. - (C17)
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]]
// ]
// %scatter_indices: [[[0, 2], [1, 0], [2, 1]], [[0, 1], [1, 0], [0, 9]]]
// %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 = [2, 3],
inserted_window_dims = [0],
scatter_dims_to_operand_dims = [1, 0],
index_vector_dim = 2>,
indices_are_sorted = false,
unique_indices = false
} : (tensor<3x4x2xi64>, tensor<2x3x2xi64>, tensor<2x3x2x2xi64>) -> tensor<3x4x2xi64>
// %result: [
// [[1, 2], [5, 6], [7, 8], [7, 8]],
// [[10, 11], [12, 13], [14, 15], [16, 17]],
// [[18, 19], [20, 21], [21, 22], [23, 24]]
// ]
اختيار
دلالات الألفاظ
لعرض متدرج 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) |
القيود
- (C1)
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 |
متعدّد أبعاد صفري أو متعدّد كمي لكل موصّل | (C3) |
(I4) | window_dimensions |
ثابت الموتّر الأحادي الأبعاد من النوع si64 |
(C2)، (C4)، (C5) |
(I5) | window_strides |
ثابت الموتّر الأحادي الأبعاد من النوع si64 |
(C2), (C6), (C7) |
(I6) | padding |
ثابت الموتر ثنائي الأبعاد من النوع si64 |
(C2), (C8) |
(I7) | select |
function | (C9) |
(I8) | scatter |
function | (C10) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متعدّد أو متعدّد كميّ لكل موقد | (C11-C12) |
القيود
- (C1)
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 = dense<[3, 1]> : tensor<2xi64>,
window_strides = dense<[2, 1]> : tensor<2xi64>,
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) |
القيود
- (C1)
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) |
القيود
- (C1)
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) |
القيود
- (C1)
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) |
القيود
- (C1)
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) |
القيود
- (C1)
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) |
القيود
- (C1)
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 = dense<[1, 2]> : tensor<2xi64>,
limit_indices = dense<[3, 4]> : tensor<2xi64>,
strides = dense<1> : tensor<2xi64>
} : (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 |
function | (C5) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
results |
العدد المتباين للمتوترات أو الموترات الكمّية لكل مفرد | (C2), (C3) |
القيود
- (C1)
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]]
sqrt
دلالات الألفاظ
تنفِّذ عملية جذر تربيعي في العناصر على مستوى العناصر على الموتر operand
وتنشئ متعدّد result
. بناءً على نوع العنصر، يتم تنفيذ ما يلي:
- للأعداد العشرية:
squareRoot
من IEEE-754. - بالنسبة إلى الأعداد المركّبة: جذر تربيعي مركّب.
- بالنسبة إلى الأنواع الكمية:
dequantize_op_quantize(sqrt, operand, type(result))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متعدّد من نوع النقطة العائمة أو المعقد أو متعدّد كميّ لكل موقد | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متعدّد من نوع النقطة العائمة أو المعقد أو متعدّد كميّ لكل موقد | (C1) |
القيود
- (C1)
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) |
القيود
- (C1)
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]]
تانه
دلالات الألفاظ
تنفّذ عملية تماس زائدية في العناصر المقابلة مع المماس operand
وتنتج دالة result
. بناءً على نوع العنصر، يتم تنفيذ ما يلي:
- للأعداد العشرية:
tanh
من IEEE-754. - بالنسبة إلى الأعداد المركّبة: المماس الزائدي المعقد.
- بالنسبة إلى الأنواع الكمية:
dequantize_op_quantize(tanh, operand, type(result))
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | operand |
متعدّد من نوع النقطة العائمة أو المعقد أو متعدّد كميّ لكل موقد | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متعدّد من نوع النقطة العائمة أو المعقد أو متعدّد كميّ لكل موقد | (C1) |
القيود
- (C1)
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 = dense<[2, 1, 0]> : tensor<3xi64>
} : (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) |
القيود
- (C1)
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]
// ]
tuple
دلالات الألفاظ
لعرض صف result
من القيم val
.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | val |
عدد القيم المتغير | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
tuple | (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) |
القيود
- (C1)
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) |
القيود
- (C1)
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 |
function | (C1) |
(I3) | body |
function | (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 على مستوى العناصر في معاملين متّجهين lhs
وrhs
وينتج عنها متعدّد result
. بناءً على نوع العنصر، يتم تنفيذ ما يلي:
- للقيم المنطقية: XOR المنطقي.
- للأعداد الصحيحة: XOR على مستوى البت.
مدخلات
التصنيف | الاسم | النوع | القيود |
---|---|---|---|
(I1) | lhs |
متعدّد النوع المنطقي أو العدد الصحيح | (C1) |
(I2) | rhs |
متعدّد النوع المنطقي أو العدد الصحيح | (C1) |
المُخرَجات
الاسم | النوع | القيود |
---|---|---|
result |
متعدّد النوع المنطقي أو العدد الصحيح | (C1) |
القيود
- (C1)
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 من خلال توفير قيم الإدخال لدالة main
وحوسبة قيم المخرجات. يتم حساب قيم مخرجات الدالة من خلال تنفيذ
الرسم البياني للعمليات الجذر في عملية return
المقابلة.
يتم تحديد ترتيب التنفيذ طالما أنه متوافق مع تدفق البيانات، أي إذا تم تنفيذ العمليات قبل استخداماتها. في StableHLO، تستهلك جميع عمليات الأثر الجانبي رمزًا مميزًا واحدًا وتنتج رمزًا مميزًا واحدًا (يمكن مضاعفة الرموز المميزة المتعددة في رمز مميز واحد عبر after_all
)، بحيث يتوافق ترتيب تنفيذ الآثار الجانبية أيضًا مع تدفق البيانات. ترتيبات التنفيذ المحتملة لنموذج
البرنامج أعلاه هي %0
← %1
← %2
← %3
← %4
← return
أو %3
← %0
←
%1
← %2
← %4
← return
.
بشكل أكثر رسمية، تكون عملية StableHLO مزيجًا من ما يلي:
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 التواصل مع بعضها البعض من خلال قنواتStableHLO. يتم تمثيل القناة بمعرّف موجب من النوع
si64
. من خلال عمليات مختلفة، من الممكن إرسال قيم إلى القنوات وتلقّيها من القنوات.
مزيد من إضفاء الطابع الرسمي، على سبيل المثال، من أين تأتي معرّفات القنوات هذه، وكيف تتعرّف البرامج على العمليات، ونوع المزامنة التي بدأها المستخدمون، يتم تحديدها لاحقًا (#484).
اتصال البث
يمكن لكل عملية من عمليات StableHLO الوصول إلى واجهتي بث:
- إضافة خلاصة يمكن القراءة منها:
- Outfeed الذي يمكن الكتابة إليه.
وعلى عكس القنوات التي تُستخدم للتواصل بين العمليات ومن ثمَّ تحتوي على عمليات من طرفيها، يكون لكل من الخلاصات والخلاصات الخارجية تحديدًا آخر فيهما.
يتم تحديد مزيد من إضفاء الطابع الرسمي، مثل كيفية تأثير اتصال البث في ترتيب التنفيذ ونوع المزامنة التي تتم من خلال ذلك، (رقم 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
. بشكل أكثر رسمية، باستخدام
بناء جملة بايثون:
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 من خلال مجموعة واسعة من القيود للعمليات الفردية، والتي تستبعد العديد من فئات الأخطاء قبل وقت التشغيل. مع ذلك، لا تزال حالات الخطأ ممكنة، على سبيل المثال من خلال فائض الأعداد الصحيحة، وعمليات الوصول خارج الحدود، وما إلى ذلك. تؤدي جميع هذه الأخطاء، ما لم يتم ذكرها صراحةً، إلى سلوك محدّد بالتنفيذ، ولكن هذا الأمر قد يتغيّر في المستقبل (#1157).
واستثناءً لهذه القاعدة، فإنّ استثناءات النقطة العائمة في برامج StableHLO لها سلوك محدّد جيدًا. إنّ العمليات التي تنتج عن استثناءات محدّدة وفقًا لمعيار IEEE-754 (عملية غير صالحة أو قسمة بصفر أو تجاوز السعة أو التدفق الداخلي أو استثناءات غير محددة) تنتج نتائج تلقائية (على النحو المحدّد في المعيار) وتستمر في التنفيذ بدون رفع علامة الحالة المقابلة، على غرار معالجة استثناء raiseNoFlag
من المعيار. يتم تحديد استثناءات للعمليات غير القياسية (على سبيل المثال، العمليات الحسابية المعقدة وبعض الوظائف الفائقة).
الترميز
لوصف البنية، يستخدم هذا المستند صيغة ISO المعدَّلة لبنية EBNF (ISO/IEC 14977:1996،
ويكيبيديا)،
مع تعديلين: 1) يتم تحديد القواعد باستخدام ::=
بدلاً من =
،
2) يتم التعبير عن الترابط باستخدام التقارب بدلاً من ,
.
لوصف دلالات الألفاظ (أي ضمن أقسام "الأنواع" و"الثوابت" و "العمليات")، نستخدم المعادلات التي تستند إلى بناء جملة بايثون مع دعم للتعبير بإيجاز عن عمليات الصفيفة كما هو موضح أدناه. يعمل ذلك بشكل جيد مع مقتطفات الرمز الصغيرة، ولكن في حالات نادرة عندما تكون هناك حاجة إلى مقتطفات أكبر من التعليمات البرمجية، نستخدم بنية vanilla Python التي يتم تقديمها بشكل صريح دائمًا.
الصيغ
دعنا نستكشف كيفية عمل المعادلات بناءً على مثال من
مواصفات 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)
رقمية ثم عرض كل هذه النتائج القياسية معًا كنتيجة متعدّد". في بناء جملة vanilla Python،
يتحوّل مثال المعادلة إلى:
[dim(lhs, dim1) for dim1 in lhs_batching_dimensions] ==
[dim(rhs, dim2) for dim2 in rhs_batching_dimensions]
.
بفضل القطع الناقص، من الممكن غالبًا تجنب العمل على مستوى الكميات القياسية الفردية. مع ذلك، في بعض الحالات الصعبة، يمكن استخدام البنية شبه غير الرسمية ذات المستوى الأدنى كما هو الحال في معادلة start_indices[bi0, ..., :, ..., biN]
من مواصفات gather
. في خدمة الإيجاز، لا نقدم لغة رسمية دقيقة لترجمة بناء الجملة هذا إلى vanilla Python، على أمل أن يظل مفهومًا بشكل حدسي على أساس كل حالة على حدة.
يرجى إخبارنا إذا كانت بعض المعادلات المحددة تبدو مبهمة، وسنحاول
تحسينها.
ستلاحظ أيضًا أن المعادلات تستخدم القطع الناقص لتوسيع جميع أنواع القوائم، بما في ذلك المتمدرات، وقوائم المتوترات (والتي فعلى سبيل المثال يمكن أن تنشأ من عدد متباين من وحدات شدية)، وما إلى ذلك. وهذا مجال آخر لا نوفر فيه أسلوبًا رسميًا دقيقًا (على سبيل المثال، القوائم ليست حتى جزءًا من نظام 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
.
الأسماء | في "الدلالات" | في "القيود" |
---|---|---|
الدوال العامة | 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
.
إنشاء القيم
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
متحدًا، يتم عرض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
متعدّدًا أوdim(x, axis) % num_results != 0
، سيتم عرضNone
.
العمليات الحسابية للأشكال
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, type: Type) -> Value:
assert is_float(x) and is_quantized(type)
x_expressed_rounded = round_nearest_even(x / compute_scales(type, type(x)))
x_storage_rounded = convert(x_expressed_rounded, storage_type(type))
x_storage_add = x_storage_rounded + compute_zero_points(type, type(x_storage_rounded))
x_storage = clamp(storage_min(type), x_storage_add, storage_max(type))
return bitcast_convert(x_storage, 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)
العمليات الحسابية على الشبكة
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" أعلاه.