مواصفات StableHLO

StableHLO هي عملية يتم تعيينها للعمليات عالية المستوى (HLO) في الجهاز التعلم (ML). ويعمل StableHLO كطبقة قابلة للنقل بين مختلف أطر عمل تعلُّم الآلة وبرامج تجميع تعلُّم الآلة: أُطر عمل تعلُّم الآلة التي تُنتج برامج StableHLO متوافقة مع محولات تعلُّم الآلة التي تستهلك برامج StableHLO

هدفنا هو تبسيط وتسريع تطوير تكنولوجيا تعلُّم الآلة من خلال إنشاء المزيد من إمكانية التشغيل التفاعلي بين أطر عمل تعلُّم الآلة (مثل TensorFlow وJAX PyTorch) ومحمولات تعلُّم الآلة (مثل XLA وIREE). نحو هذه النهاية، مواصفة للغة البرمجة StableHLO.

تتضمن هذه المواصفات ثلاثة أقسام رئيسية. أولاً، يصف قسم البرامج بنية برامج StableHLO. التي تتكوّن من دوال StableHLO التي تتكون نفسها من عمليات StableHLO. ضمن هذه البنية، يحدد قسم العمليات دلالات للعمليات الفردية. يوفّر قسم التنفيذ دلالات لكل تنفيذ هذه العمليات معًا ضمن البرنامج. أخيرًا، يناقش قسم التدوين الترميز المستخدَم خلال المواصفات.

لعرض مواصفات إصدار سابق من StableHLO، يُرجى فتح المستودع على إصدار محدد للاهتمام. على سبيل المثال، مواصفات الإصدار 0.19.0 من StableHLO. لعرض التغييرات التي حدثت عند كل تصادم بسيط للإصدار من StableHLO، يمكنك الرجوع إلى سجلّ الإصدار في VhloDialect.td

البرامج

Program ::= {Func}

تتألف برامج StableHLO من عدد عشوائي من دوال StableHLO. في ما يلي مثال على برنامج يتضمّن الدالة @main التي تتضمّن 3 إدخالات (%image و%weights و%bias) ومخرجًا واحدًا. نص الدالة فيه 6 عمليات.

func.func @main(
  %image: tensor<28x28xf32>,
  %weights: tensor<784x10xf32>,
  %bias: tensor<1x10xf32>
) -> tensor<1x10xf32> {
  %0 = "stablehlo.reshape"(%image) : (tensor<28x28xf32>) -> tensor<1x784xf32>
  %1 = "stablehlo.dot"(%0, %weights) : (tensor<1x784xf32>, tensor<784x10xf32>) -> tensor<1x10xf32>
  %2 = "stablehlo.add"(%1, %bias) : (tensor<1x10xf32>, tensor<1x10xf32>) -> tensor<1x10xf32>
  %3 = "stablehlo.constant"() {value = dense<0.0> : tensor<1x10xf32>} : () -> tensor<1x10xf32>
  %4 = "stablehlo.maximum"(%2, %3) : (tensor<1x10xf32>, tensor<1x10xf32>) -> tensor<1x10xf32>
  "func.return"(%4): (tensor<1x10xf32>) -> ()
}

الدوال

Func        ::= 'func' '.' 'func' FuncId FuncInputs FuncOutputs '{' FuncBody '}'
FuncInputs  ::= '(' [FuncInput {',' FuncInput}] `)`
FuncInput   ::= ValueId ':' ValueType
FuncOutputs ::= ['->' FuncOutput, {',' FuncOutput}]
FuncOutput  ::= ValueType
FuncBody    ::= {Op}

تتضمن الدوال الثابتة (التي تُسمى أيضًا الدوال المُسمّاة) المعرف والمدخلات/المخرجات ونص. في المستقبل، نخطط وتقديم بيانات وصفية إضافية للدوال لتحقيق توافق أفضل باستخدام HLO (#425، #626، #740، #744.

المعرفات

FuncId  ::= '@' letter {letter | digit}
ValueId ::= '%' digit {digit}
          | '%' letter {letter | digit}
letter  ::= 'a' | ... | 'z' | 'A' | ... | 'Z' | '_'
digit   ::= '0' | ... | '9'

تتشابه معرّفات SttableHLO مع المعرّفات في العديد من البرامج. لغتين، مع خاصيتين: 1) جميع المعرفات لها sigil والتي التمييز بين الأنواع المختلفة للمعرفات، 2) يمكن أن تكون معرّفات القيم رقمية بالكامل لتبسيط إنشاء برامج StableHLO.

الأنواع

Type         ::= ValueType | NonValueType
ValueType    ::= TensorType | QuantizedTensorType | TokenType | TupleType
NonValueType ::= TensorElementType | QuantizedTensorElementType | FunctionType | StringType

يتم تصنيف أنواع الشاشة الثابتة إلى أنواع قيم (والتي تُسمى أيضًا. أنواع الفئة الأولى) التي تمثّل قيم StableHLO والأنواع غير القيم التي تصف عناصر البرنامج الأخرى. تشبه أنواع StableHLO الأنواع في والعديد من لغات البرمجة، مع الخصوصية الرئيسية في لغة StableHLO طبيعة خاصة بالنطاق والتي ينتج عنها بعض النتائج غير المعتادة (مثل الأنواع العددية ليست أنواع قيم).

TensorType ::= 'tensor' '<' Shape TensorElementType '>'
Shape ::= {DimensionSize 'x'}
DimensionSize ::= digit {digit} | '?'

تمثّل أنواع المستشعرات قوات التماس، أي الصفائف متعددة الأبعاد. لديهم شكل ونوع عنصر، حيث يمثل الشكل قيمة غير سالبة أو غير معروفة لأحجام السمات بالترتيب التصاعدي للبُعد المقابل السمات (والتي تُعرف أيضًا باسم المحاور) مرقّمة من 0 إلى R-1. تشير رسالة الأشكال البيانية يُطلق على عدد السمات R اسم الترتيب. على سبيل المثال، tensor<2x3xf32> هو نوع عنصر مترابط بالشكل 2x3 ونوع العنصر f32. ولها بُعدان (أو بعبارةٍ أخرى، محوران) - البعد 0 والبعد الأول - أحجام 2 و3. ترتيبه 2.

يمكن أن تكون الأشكال غير معروفة جزئيًا أو كليًا (ديناميكية)، على سبيل المثال tensor<?x2xf64> غير معروف جزئيًا وtensor<?x?xf64> غير معروفة على الإطلاق. ديناميكية يتم تمثيل أحجام الأبعاد باستخدام ?. لا يمكن للأشكال أن تكون غير مرتبة.

ونحن نخطط في المستقبل لاستكشاف توسيع أنواع موتّرات الأداء التي تتجاوز وأحجام الأبعاد وأنواع العناصر، على سبيل المثال، لتضمين تخطيطات (#629) والندرة (#1078)

QuantizedTensorType ::= 'tensor' '<' Shape QuantizedTensorElementType '>'
QuantizedTensorElementType ::= '!quant.uniform' '<'
                  QuantizationStorageType
                  ['<' QuantizationStorageMin ':' QuantizationStorageMax '>']
                  ':' QuantizationExpressedType
                  [':' QuantizationDimension]
                  ',' QuantizationParameters '>'
QuantizationStorageType ::= IntegerType
QuantizationStorageMin ::= IntegerConstant
QuantizationStorageMax ::= IntegerConstant
QuantizationExpressedType ::= FloatType
QuantizationDimension ::= IntegerConstant
QuantizationParameters ::= QuantizationParameter
                         | '{' QuantizationParameter {',' QuantizationParameter} '}'
QuantizationParameter ::= QuantizationScale ':' QuantizationZeroPoint
QuantizationScale ::= FloatConstant
QuantizationZeroPoint ::= IntegerConstant
الاسم النوع القيود
storage_type نوع العدد الصحيح (C1-C3)، (C8)
storage_min ثابت العدد (C1)، (C3)، (C7)
storage_max ثابت العدد (C2)، (C3)، (C7)
expressed_type نوع النقطة العائمة (C4)
quantization_dimension ثابت عدد صحيح اختياري (C10-C12)
scales عدد متغيّرات الثوابت العائمة (C4-C6)، (C9)، (C10)، (C13)
zero_points عدد متغير لثوابت الأعداد الصحيحة (C7-C9)

تمثّل أنواع العناصر الكمية قيمًا أعدادًا صحيحة لـ نوع التخزين في النطاق من storage_min إلى storage_max (شامل) الذي يتوافق مع قيم النقطة العائمة لنوع تم التعبير عنه. بالنسبة إلى قيمة عدد صحيح i، يمكن حساب قيمة النقطة العائمة المقابلة f على النحو التالي f = (i - zero_point) * scale، حيث تُسمى scale وzero_point مَعلمات تحديد الكمية. إنّ storage_min وstorage_max اختياريتان. في القواعد النحوية، ولكن لها قيم افتراضية تبلغ min_value(storage_type) max_value(storage_type) على التوالي. تتمتع أنواع العناصر الكمية القيود التالية:

  • (ج1) type(storage_min) = storage_type.
  • (C2) type(storage_max) = storage_type.
  • (C3) min_value(storage_type) <= storage_min < storage_max <= max_value(storage_type):
  • (C4) type(scales...) = expressed_type.
  • (C5) 0 < scales.
  • (C6) is_finite(scales...).
  • (C7) storage_min <= zero_points <= storage_max.
  • (C8) type(zero_points...) = storage_type.
  • (C9) size(scales) = size(zero_points).
  • (C10) إذا كانت is_empty(quantization_dimension)، يتم تحصيل size(scales) = 1.
  • (C11) 0 <= quantization_dimension.

في الوقت الحالي، QuantizationScale هو ثابت النقطة العائمة، ولكن هناك اهتمام كبير بالمقاييس القائمة على الأعداد الصحيحة، ممثلة بالمضاعفات التبديلات. ونحن نخطّط لاستكشاف ذلك في المستقبل القريب. (#1404)

هناك مناقشة مستمرة حول الدلالات المتعلقة باللغة QuantizationZeroPoint، بما في ذلك النوع والقيم وما إذا كان يمكن أن يكون هناك نوع واحد فقط أو نقاط صفرية متعددة محتملة في نوع متنزس كمي. استنادًا إلى نتائج هذه المناقشة، فقد تتغير المواصفات المتعلقة بالنقاط الصفرية في المستقبل (#1405).

تتضمّن المناقشة الجارية الأخرى دلالات QuantizationStorageMin وQuantizationStorageMax لتحديد ما إذا كان ينبغي فرض أي قيود مفروضة على هذه القيم وعلى قيم التوترات الكميّة (#1406)

وأخيرًا، نخطط لاستكشاف كيفية تمثيل المقاييس غير المعروفة والصفر مماثلة للطريقة التي نخطط بها لاستكشاف تمثيل المجهول أحجام الأبعاد (#1407).

تمثل أنواع موتّرات الكم قوات التوتر التي تتضمّن عناصر كمية. هذه التي تشبه تمامًا نقاط التوتر المنتظمة، غير أن عناصرها على أنواع عناصر محددة الكمية بدلاً من أنواع العناصر العادية.

في مقادير التوتر الكمّي، يمكن أن يكون التحديد الكمي لكل متسابق، بمعنى الحصول على واحد scale وzero_point لمرجع التوتر بالكامل أو يمكن أن يكون لكل محور، بمعنى، وجود عدة scales وzero_points، زوج واحد لكل شريحة من بُعد معين quantization_dimension. بشكل رسمي، في تنسور t مع التحديد الكمّي لكل محور، تتوفّر dim(t, quantization_dimension) شريحة. من quantization_dimension: t[:, ..., 0, ..., :], t[:, ..., 1, ..., :]، إلخ. جميع العناصر في الشريحة iتستخدم scales[i] وzero_points[i] معاملات الكمي الخاصة بها. تكون أنواع موتّرات الكمّية ما يلي: القيود:

  • للكمي حسب كل موتّر:
    • ما مِن قيود إضافية.
  • بالنسبة إلى الكمية حسب المحور:
    • (C12) quantization_dimension < rank(self).
    • (C13) dim(self, quantization_dimension) = size(scales).
TokenType ::= 'token'

تمثّل أنواع الرموز المميّزة الرموز المميّزة، أي القيم غير الواضحة التي يتم إنتاجها واستهلاكها. من خلال بعض العمليات. تُستخدم الرموز المميّزة لفرض أمر تنفيذ على العمليات كما هو موضَّح في قسم التنفيذ.

TupleType ::= 'tuple' '<' TupleElementTypes '>'
TupleElementTypes ::= [ValueType {',' ValueType}]

تمثل أنواع الصفوف الصفوف، أي القوائم غير المتجانسة. الصفوف هي نظام قديم الموجودة فقط للتوافق مع HLO. في HLO، الصفوف لتمثيل المدخلات والمخرجات المتباينة. في StableHLO، تتنوع المدخلات يتم دعم المخرجات محليًا، ولا يمكن استخدام الصفوف في StableHLO إلا من خلال تمثل واجهة التطبيق الثنائية (HLO ABI) بشكل شامل حيث يمكن، على سبيل المثال، T وtuple<T> و قد تختلف السمة tuple<tuple<T>> اختلافًا جوهريًا استنادًا إلى التنفيذ. نخطّط في المستقبل لإجراء تغييرات على واجهة التطبيق الثنائية (HLO ABI). ما قد يسمح لنا بإزالة أنواع الصفوف من StableHLO (#598)

TensorElementType ::= BooleanType | IntegerType | FloatType | ComplexType
BooleanType ::= 'i1'
IntegerType ::= SignedIntegerType | UnsignedIntegerType
SignedIntegerType ::= 'si2' | 'si4' | 'si8' | 'si16' | 'si32' | 'si64'
UnsignedIntegerType ::= 'ui2' | 'ui4' | 'ui8' | 'ui16' | 'ui32' | 'ui64'
FloatType ::= 'f8E4M3FN' | 'f8E5M2' | 'f8E4M3FNUZ' | 'f8E5M2FNUZ'
            | 'f8E4M3B11FNUZ' | 'bf16' | 'f16' | 'f32' | 'f64'
TensorFloat32 ::= 'tf32'
ComplexType ::= 'complex' '<' ComplexElementType '>'
ComplexElementType ::= 'f32' | 'f64'

تمثّل أنواع العناصر عناصر أنواع أداة "المنسِّر". على عكس العديد من البرامج اللغات، فهذه الأنواع ليست من الدرجة الأولى في StableHLO. هذا يعني أنّ ولا يمكن لبرامج StableHLO أن تمثل قيمًا من هذه الأنواع بشكل مباشر (نتيجةً لذلك، يكون من الاصطلاحي تمثيل القيم العددية من النوع T باستخدام متوتر 0 الأبعاد القيم من النوع tensor<T>).

FunctionType ::= '(' InputTypes ')' '->' '(' OutputTypes ')'
InputTypes ::= [ValueType {',' ValueType}]
OutputTypes ::= [ValueType {',' ValueType}]

تمثّل أنواع الدوال كلاً من الدوال المُسمّاة والمجهولة الهوية. لديهم أنواع الإدخال (قائمة الأنواع على الجانب الأيسر من ->) وأنواع الإخراج (قائمة الأنواع على الجانب الأيسر من ->). في العديد من البرامج اللغات، تكون أنواع الدوال من الدرجة الأولى، ولكنها ليست في StableHLO.

StringType ::= 'string'

يمثل نوع السلسلة تسلسلات من وحدات البايت. على عكس العديد من البرامج فإن نوع السلسلة ليس من الفئة الأولى في StableHLO ويستخدم فقط تحديد بيانات التعريف الثابتة لعناصر البرنامج.

العمليات

تمثِّل العمليات الثابتة (التي تُسمى أيضًا العمليات) مجموعة مغلقة للعمليات رفيعة المستوى في نماذج التعلم الآلي. كما ناقشنا أعلاه، يتم استلهام بناء جملة StableHLO بشكل كبير من MLIR، والذي ليس بالضرورة أن يكون بديل مريح، ولكنه يمكن القول إنه الأنسب لهدف StableHLO المتمثل في توفير المزيد من إمكانية التشغيل التفاعلي بين أُطر عمل تعلُّم الآلة وبرامج تجميع تعلُّم الآلة.

Op            ::= [OpOutputs] OpName OpInputs ':' OpSignature
OpName        ::= '"' 'stablehlo' '.' OpMnemonic '"'
OpMnemonic    ::= 'abs' | 'add' | ...

العمليات الثابتة (التي يُطلق عليها أيضًا العمليات) لها اسم المدخلات/المخرجات والتوقيع. يتكون الاسم من البادئة stablehlo. الذاكرة التي تحدد بشكل فريد إحدى العمليات المدعومة. انظر أدناه قائمة شاملة بجميع العمليات المدعومة.

OpInputs        ::= OpInputValues OpInputFuncs OpInputAttrs
OpInputValues   ::= '(' [OpInputValue {',' OpInputValue}] ')'
OpInputValue    ::= ValueId
OpInputFuncs    ::= ['(' OpInputFunc {',' OpInputFunc} ')']
OpInputAttrs    ::= ['{' OpInputAttr {',' OpInputAttr} '}']
OpOutputs       ::= [OpOutput {',' OpOutput} '=']
OpOutput        ::= ValueId

تستهلك العمليات الإدخالات وتُنتج المخرجات. يتم تصنيف الإدخالات إلى قيم الإدخال (المحسوبة أثناء التنفيذ)، دوال الإدخال (المقدمة بشكلٍ ثابت، لأن الدوال الثابتة HLO ليست قيمًا من الدرجة الأولى) سمات الإدخال (يتم تقديمها أيضًا بشكل ثابت). نوع المدخلات والمخرجات تعتمد العملية التي يتم استهلاكها وإنتاجها على ذاكرتها. على سبيل المثال، add تستهلك هذه العملية قيمتي إدخال وينتج عنها قيمة واحدة للمخرج. وعند المقارنة، تستهلك العملية select_and_scatter 3 قيم إدخال ووظيفتَي إدخال 3 سمات إدخال.

OpInputFunc ::= '{' Unused FuncInputs ':' FuncBody '}'
Unused      ::= '^' digit {digit}
              | '^' letter {letter | digit}

تُعد دوال الإدخال (والتي تُسمى أيضًا الدوال المجهولة) جزءًا مهمًا جدًا تشبه الدوال المُسمّاة باستثناء: 1) ليس لها معرِّف (وبالتالي الاسم "مجهول"، 2) أنها لا تعلن عن أنواع الإخراج (أنواع الناتج يمكن استنتاجه من العملية return في الدالة).

تتضمن بناء جملة دوال الإدخال جزءًا غير مستخدم حاليًا (انظر Unused أعلاه) متوفّر للتوافق مع MLIR. في MLIR، فهناك مفهوم أكثر عمومية لمصطلح "المناطق" التي يمكن أن تتضمّن "محظورات" متعددة العمليات مرتبطة معًا من خلال عمليات القفز. تحتوي هذه المجموعات على أرقام تعريف تتوافق مع إلى إنتاج Unused، حتى يمكن تمييزها عن بعضها البعض. لا يحتوي StableHLO على عمليات الانتقال، لذا فإن الجزء المقابل من بناء جملة MLIR غير مستخدم (ولكنه لا يزال موجودًا).

OpInputAttr      ::= OpInputAttrName '=' OpInputAttrValue
OpInputAttrName  ::= letter {letter | digit}
OpInputAttrValue ::= Constant

يحتوي سمات الإدخال على اسم وقيمة تمثّل إحدى السمات المتوافقة. والثوابت. أنها الطريقة الأساسية لتحديد بيانات التعريف الثابتة للبرنامج عناصر. على سبيل المثال، تستخدم العملية concatenate السمة dimension تحديد البُعد الذي يتم من خلاله تسلسل قيم الإدخال وبالمثل، تستخدم العملية slice سمات متعددة مثل start_indices وlimit_indices لتحديد الحدود المستخدمة لتقسيم قيمة الإدخال.

في الوقت الحالي، تحتوي برامج StableHLO المتوفّرة على الإنترنت على سمات والتي لم يتم وصفها في هذا المستند. في المستقبل، نخطط إما أن تمتص هذه السمات في بيئة StableHLO أو تمنعها من تظهر في برامج StableHLO في غضون ذلك، إليك قائمة بهذه :

  • layout (#629).
  • mhlo.frontend_attributes (#628).
  • mhlo.sharding (#619).
  • output_operand_aliases (#740).
  • البيانات الوصفية للموقع الجغرافي (#594)
OpSignature ::= '(' [ValueType {',' ValueType}] ')' '->' '(' [ValueType {',' ValueType}] ')'

يتكون توقيع العمليات من أنواع جميع قيم الإدخال (قائمة الأنواع على الجانب الأيسر لـ ->) وأنواع جميع قيم الإخراج (قائمة على الجانب الأيسر من ->). وعلى وجه التحديد، تُعد أنواع المدخلات متكررة، وأنواع الإخراج تكون متكررة دائمًا تقريبًا أيضًا (لأن في معظم عمليات StableHLO، يمكن استنتاج أنواع الإخراج من الإدخالات). ومع ذلك، يكون التوقيع جزءًا متعمدًا من بناء جملة StableHLO للتوافق مع MLIR.

فيما يلي مثال لعملية تقوية الذاكرة select_and_scatter. يستهلك 3 قيم الإدخال (%operand و%source و%init_value)، دالتا إدخال و3 سمات إدخال (window_dimensions وwindow_strides وpadding). لاحظ كيف يتضمن توقيع العملية أنواع قيم الإدخال فقط (ولكن ليس أنواع دوال الإدخال والسمات التي يتم توفيرها مضمّنة).

%result = "stablehlo.select_and_scatter"(%operand, %source, %init_value) ({
  ^bb0(%arg0: tensor<i32>, %arg1: tensor<i32>):
    %0 = "stablehlo.compare"(%arg0, %arg1) {
      comparison_direction = #stablehlo<comparison_direction GE>
    } : (tensor<i32>, tensor<i32>) -> tensor<i1>
    "stablehlo.return"(%0) : (tensor<i1>) -> ()
}, {
  ^bb0(%arg0: tensor<i32>, %arg1: tensor<i32>):
    %0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i32>, tensor<i32>) -> tensor<i32>
    "stablehlo.return"(%0) : (tensor<i32>) -> ()
}) {
  window_dimensions = dense<[3, 1]> : tensor<2xi64>,
  window_strides = dense<[2, 1]> : tensor<2xi64>,
  padding = dense<[[0, 1], [0, 0]]> : tensor<2x2xi64>
} : (tensor<4x2xi32>, tensor<2x2xi32>, tensor<i32>) -> tensor<4x2xi32>

الثوابت

Constant ::= BooleanConstant
           | IntegerConstant
           | FloatConstant
           | ComplexConstant
           | TensorConstant
           | QuantizedTensorConstant
           | StringConstant
           | EnumConstant

تضم الثوابت الثابتة HLO قيمة حرفية ونوع يمثلان معًا قيمة StableHLO. وبشكلٍ عام، يُعد النوع جزءًا من الصيغة الثابتة، باستثناء عندما يكون لا لبس فيه (على سبيل المثال، ثابت منطقي لا لبس فيه يكون من النوع i1، بينما يمكن أن يضم ثابت العدد الصحيح عدة أنواع محتملة).

BooleanConstant ::= BooleanLiteral
BooleanLiteral  ::= 'true' | 'false'

تمثل الثوابت المنطقية القيمتين المنطقيتين true وfalse. منطقية الثوابت من نوع i1.

IntegerConstant   ::= IntegerLiteral ':' IntegerType
IntegerLiteral    ::= ['-' | '+'] DecimalDigits
                    | ['-' | '+'] '0x' HexadecimalDigits
DecimalDigits     ::= decimalDigit {decimalDigit}
HexadecimalDigits ::= hexadecimalDigit {hexadecimalDigit}
decimalDigit      ::= '0' | ... | '9'
hexadecimalDigit  ::= decimalDigit | 'a' | ... | 'f' | 'A' | ... | 'F'

الثوابت لعدد صحيح هي قيم الأعداد الصحيحة من خلال السلاسل التي تستخدم الأعداد العشرية أو التدوين السداسي العشري. قواعد أخرى، مثل النظام الثنائي أو الثماني، تخضع الثوابت العددية للقيود التالية:

  • (ج1) is_wellformed(integer_literal, integer_type).
FloatConstant  ::= FloatLiteral ':' FloatType
FloatLiteral   ::= SignPart IntegerPart FractionalPart ScientificPart
                 | '0x' [HexadecimalDigits]
SignPart       ::= ['-' | '+']
IntegerPart    ::= DecimalDigits
FractionalPart ::= ['.' [DecimalDigits]]
ScientificPart ::= [('e' | 'E') ['-' | '+'] DecimalDigits]

تمثّل الثوابت العائمة قيم النقطة العائمة من خلال سلاسل تستخدم التدوين العشري أو العلمي. بالإضافة إلى ذلك، يمكن كتابة التدوين السداسي العشري يُستخدم لتحديد وحدات البت الأساسية مباشرةً بتنسيق النقطة العائمة والنوع المقابل. تنطبق القيود التالية على الثوابت العائمة:

  • (C1) إذا تم استخدام تدوين غير سداسي عشري، is_wellformed(float_literal, float_type)
  • (C2) إذا تم استخدام تدوين سداسي عشري، size(hexadecimal_digits) = num_bits(float_type) / 4
ComplexConstant ::= ComplexLiteral ':' ComplexType
ComplexLiteral  ::= '(' RealPart ',' ImaginaryPart ')'
RealPart        ::= FloatLiteral
ImaginaryPart   ::= FloatLiteral

تمثل الثوابت المركّبة قيمًا مركّبة باستخدام قوائم لجزء حقيقي. (يأتي أولاً) والجزء الخيالي (يأتي ثانيًا). على سبيل المثال: يمثل (1.0, 0.0) : complex<f32> 1.0 + 0.0i، يمثل الحقل "(0.0, 1.0) : complex<f32>" القيمة "0.0 + 1.0i". الترتيب الذي يتم تحديد تنفيذ هذه الأجزاء في الذاكرة. الثوابت المعقدة للقيود التالية:

  • (ج1) is_wellformed(real_part, complex_element_type(complex_type)).
  • (C2) is_wellformed(imaginary_part, complex_element_type(complex_type)).
TensorConstant ::= TensorLiteral ':' TensorType
TensorLiteral  ::= 'dense' '<' (DenseLiteral | ElementLiteral) '>'
DenseLiteral   ::= DenseDimension | DenseElements
DenseDimension ::= '[' [DenseLiteral {',' DenseLiteral}] ']'
DenseElements  ::= [ElementLiteral {',' ElementLiteral}]
ElementLiteral ::= BooleanLiteral | IntegerLiteral | FloatLiteral | ComplexLiteral

تمثل ثوابت المستشعر قيم التوتر باستخدام قوائم متداخلة محددة عبر تدوين نمباي. على سبيل المثال: dense<[[1, 2, 3], [4, 5, 6]]> : tensor<2x3xi32> يمثل قيمة موتّر من خلال التعيين التالي من الفهارس إلى العناصر: {0, 0} => 1 و{0, 1} => 2 و{0, 2} => 3 و{1, 0} => 4 و{1, 1} => 5 {1, 2} => 6 ثم ترتيب تخزين هذه العناصر في الذاكرة التنفيذ. تحتوي ثوابت الموتّر على القيود التالية:

  • (C1) has_syntax(tensor_literal, element_type(tensor_type))، حيث:
    • has_syntax(element_literal: Syntax, element_type: Type) = is_wellformed(element_literal, type).
    • has_syntax(tensor_literal: List, element_type: Type) = has_syntax(tensor_literal..., element_type).
  • (C2) has_shape(tensor_literal, shape(tensor_type))، حيث:
    • has_shape(element_literal: Syntax, []) = true.
    • has_shape(tensor_literal: List, shape: List) = size(tensor_literal) = shape[0] and has_shape(tensor_literal..., shape[1:]).
    • وإلا، false.
QuantizedTensorConstant ::= QuantizedTensorLiteral ':' QuantizedTensorType
QuantizedTensorLiteral  ::= 'dense' '<' (DenseLiteral | ElementLiteral) '>'

تمثّل ثوابت متنزّر الكميّة قيم متسّعة كميّة باستخدام القيم نفسها كثوابت متسقة، مع عناصر محددة كثوابت لثوابتها ونوع التخزين. هناك القيود التالية على ثوابت التينس الكميّة:

  • (ج1) has_syntax(quantized_tensor_literal, storage_type(quantized_tensor_type)).
  • (C2) has_shape(quantized_tensor_literal, shape(quantized_tensor_type)).
StringConstant  ::= StringLiteral
StringLiteral   ::= '"' {stringCharacter | escapeSequence} '"'
stringCharacter ::= all ASCII characters except '\00', '\01', ... '\1f' and '"'
escapeSequence  ::= '\' ('"' | '\' | 'n' | 't' | (hexadecimalDigit hexadecimalDigit))

تتكوّن الأحرف الحرفية للسلسلة من وحدات بايت يتم تحديدها باستخدام أحرف ASCII وتسلسلات الهروب. فهي لا تتضمن أي ترميز، وبالتالي يمكن تفسير هذه وحدات البايت محددة التنفيذ. تكون القيم الحرفية للسلسلة من النوع string.

العمليات

abs

دلالات الألفاظ

تؤدي هذه العملية إلى إجراء عملية عضلات البطن من حيث العناصر على متوتر operand وينتج عنها result متنسور. حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى الأعداد الصحيحة الموقّعة: معامل العدد الصحيح.
  • بالنسبة إلى الأعداد العشرية: abs من IEEE-754.
  • المعامل المركّب بالنسبة للأعداد المركّبة
  • بالنسبة إلى الأنواع الكَمية: dequantize_op_quantize(abs, operand, type(result)).

مدخلات

التصنيف الاسم النوع القيود
(I1) operand موتّر عدد صحيح بعلامة أو نقطة عائمة أو نوع مركب أو مٍنسور كمي لكل متسابق (C1-C2)

المُخرَجات

الاسم النوع القيود
result متسابق عدد صحيح بعلامة أو نوع النقطة العائمة أو متسابق كمي لكل متسابق (C1-C2)

القيود

  • (ج1) shape(result) = shape(operand).
  • (C2) يتم تعريف baseline_element_type(result) على النحو التالي:
    • complex_element_type(element_type(operand)) إذا is_complex(operand).
    • baseline_element_type(operand) بخلاف ذلك.

أمثلة

// %operand: [-2, 0, 2]
%result = "stablehlo.abs"(%operand) : (tensor<3xi32>) -> tensor<3xi32>
// %result: [2, 0, 2]

مزيد من الأمثلة

إضافة

دلالات الألفاظ

لتنفيذ إضافة عاملين متوترين lhs وrhs حسب العناصر وينتج عن ذلك متوتر result حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى القيم المنطقية: منطقي OR.
  • بالنسبة إلى الأعداد الصحيحة: إضافة عدد صحيح.
  • بالنسبة إلى الأعداد العشرية: addition من IEEE-754.
  • بالنسبة للأعداد المركّبة: الإضافة المركّبة.
  • بالنسبة إلى الأنواع الكَمية: dequantize_op_quantize(add, lhs, rhs, type(result)).

مدخلات

التصنيف الاسم النوع القيود
(I1) lhs متوتر أو متنسّر كمي (C1-C6)
(I2) rhs متوتر أو متنسّر كمي (C1-C5)، (C7)

المُخرَجات

الاسم النوع القيود
result متوتر أو متنسّر كمي (C1-C7)

القيود

  • إذا كانت العملية تستخدم موتّرات غير كَمية:
    • (ج1) type(lhs) = type(rhs) = type(result).
  • إذا كانت العملية تستخدم موتّرات كميّة:
    • (C2) is_quantized(lhs) and is_quantized(rhs) and is_quantized(result).
    • (C3) storage_type(lhs) = storage_type(rhs) = storage_type(result):
    • (C4) expressed_type(lhs) = expressed_type(rhs) = expressed_type(result).
    • (C5) (is_per_axis_quantized(lhs) or is_per_axis_quantized(rhs)) = is_per_axis_quantized(result).
    • (C6) إذا كانت is_per_axis_quantized(lhs)، يتم عندها quantization_dimension(lhs) = quantization_dimension(result).
    • (C7) إذا كانت is_per_axis_quantized(rhs)، يتم عندها quantization_dimension(rhs) = quantization_dimension(result).

أمثلة

// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.add"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[6, 8], [10, 12]]

مزيد من الأمثلة

after_all

دلالات الألفاظ

يضمن تنفيذ العمليات التي تنتج عن inputs قبل أي العمليات التي تعتمد على result. لا يؤدي تنفيذ هذه العملية إلى أي شيء، فهي تهدف فقط إلى إنشاء تبعيات البيانات من result إلى inputs.

مدخلات

التصنيف الاسم النوع
(I1) inputs العدد المتغير في token

المُخرَجات

الاسم النوع
result token

أمثلة

// %input0: !stablehlo.token
// %input1: !stablehlo.token
%result = "stablehlo.after_all"(%input0, %input1) : (!stablehlo.token, !stablehlo.token) -> !stablehlo.token

مزيد من الأمثلة

all_gather

دلالات الألفاظ

في كل مجموعة عمليات ضمن شبكة العمليات StableHLO، يتم إنشاء تسلسل للقيم من عوامل العشرات operands من كل عملية على طول all_gather_dim وينتج عن ذلك results متسابق.

تقسم هذه العملية شبكة عملية StableHLO إلى process_groups وهي على النحو التالي:

  • cross_replica(replica_groups) إذا كانت القيمة هي channel_id <= 0 and use_global_device_ids = false.
  • cross_replica_and_partition(replica_groups) إذا كانت القيمة هي channel_id > 0 and use_global_device_ids = false.
  • flattened_ids(replica_groups) إذا كانت القيمة هي channel_id > 0 and use_global_device_ids = true.

بعد ذلك، ضمن كل process_group:

  • operands...@receiver = [operand@sender for sender in process_group] للجميع receiver في process_group.
  • results...@process = concatenate(operands...@process, all_gather_dim) للجميع process في process_group.

مدخلات

التصنيف الاسم النوع القيود
(I1) operands الأعداد المتباينة للمتسابقات أو المتسابقات الكميّة لكل متسابق (C1)، (C6)
(I2) all_gather_dim ثابت من النوع si64 (C1)، (C6)
(I3) replica_groups ثابت التوتر الثنائي الأبعاد من النوع si64 (C2-C4)
(I4) channel_id ثابت من النوع si64 (C5)
(I5) use_global_device_ids ثابت من النوع i1 (C5)

المُخرَجات

الاسم النوع القيود
results الأعداد المتباينة للمتسابقات أو المتسابقات الكميّة لكل متسابق (C6)

القيود

  • (ج1) 0 <= all_gather_dim < rank(operands...).
  • (C2) is_unique(replica_groups).
  • (C3) يتم تعريف size(replica_groups) على النحو التالي:
    • num_replicas في حال استخدام cross_replica.
    • num_replicas في حال استخدام cross_replica_and_partition.
    • num_processes في حال استخدام flattened_ids.
  • (C4) 0 <= replica_groups < size(replica_groups).
  • (C5) إذا كانت use_global_device_ids = true، يتم عندها channel_id > 0.
  • (C6) type(results...) = type(operands...) باستثناء:
    • dim(results..., all_gather_dim) = dim(operands..., all_gather_dim) * dim(process_groups, 1).

أمثلة

// num_replicas: 2
// num_partitions: 1
// %operand0@(0, 0): [[1, 2], [3, 4]]
// %operand0@(1, 0): [[5, 6], [7, 8]]
// %operand1@(0, 0): [[11, 12], [13, 14]]
// %operand1@(1, 0): [[15, 16], [17, 18]]
%result:2 = "stablehlo.all_gather"(%operand0, %operand1) {
  all_gather_dim = 1 : i64,
  replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>,
  // channel_id = 0
  channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
  // use_global_device_ids = false
} : (tensor<2x2xi64>, tensor<2x2xi64>) -> (tensor<2x4xi64>, tensor<2x4xi64>)
// %result0@(0, 0): [[1, 2, 5, 6], [3, 4, 7, 8]]
// %result0@(1, 0): [[1, 2, 5, 6], [3, 4, 7, 8]]
// %result1@(0, 0): [[11, 12, 15, 16], [13, 14, 17, 18]]
// %result1@(1, 0): [[11, 12, 15, 16], [13, 14, 17, 18]]

مزيد من الأمثلة

all_reduce

دلالات الألفاظ

ضمن كل مجموعة عمليات في شبكة عملية StableHLO، يطبق خفض دالة computation مع قيم مترابطات operands من كل عملية وتنتج results موتّرات.

تقسم هذه العملية شبكة عملية StableHLO إلى process_groups وهي على النحو التالي:

  • cross_replica(replica_groups) إذا كانت القيمة هي channel_id <= 0 and use_global_device_ids = false.
  • cross_replica_and_partition(replica_groups) إذا كانت القيمة هي channel_id > 0 and use_global_device_ids = false.
  • flattened_ids(replica_groups) إذا كانت القيمة هي channel_id > 0 and use_global_device_ids = true.

بعد ذلك، ضمن كل process_group:

  • results...@process[result_index] = exec(schedule) لبعض الشجرة الثنائية schedule حيث:
    • exec(node) = computation(exec(node.left), exec(node.right)).
    • exec(leaf) = leaf.value.
  • schedule عبارة عن شجرة ثنائية محدّدة التنفيذ تكون ذات ترتيب قيمة الاجتياز هي to_destination_type(operands...@process_group...[result_index], type(func_inputs(computation)[0])).

مدخلات

التصنيف الاسم النوع القيود
(I1) operands الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق (C5)، (C6)
(I2) replica_groups عدد متغير لثوابت متسابق أحادي البعد من النوع si64 (C1-C3)
(I3) channel_id ثابت من النوع si64 (C4)
(I4) use_global_device_ids ثابت من النوع i1 (C4)
(I5) computation دالة (C5)

المُخرَجات

الاسم النوع القيود
results الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق (C6-C7)

القيود

  • (ج1) is_unique(replica_groups).
  • (C2) يتم تعريف size(replica_groups) على النحو التالي:
    • num_replicas في حال استخدام cross_replica.
    • num_replicas في حال استخدام cross_replica_and_partition.
    • num_processes في حال استخدام flattened_ids.
  • (C3) 0 <= replica_groups < size(replica_groups):
  • (C4) إذا كانت use_global_device_ids = true، يتم عندها channel_id > 0.
  • (C5) computation من النوع (tensor<E>, tensor<E>) -> (tensor<E>) حيث يكون is_promotable(element_type(operand), E)
  • (C6) shape(results...) = shape(operands...).
  • (C7) element_type(results...) = E.

أمثلة

// num_replicas: 2
// num_partitions: 1
// %operand0@(0, 0): [1, 2, 3, 4]
// %operand0@(1, 0): [5, 6, 7, 8]
// %operand1@(0, 0): [9, 10, 11, 12]
// %operand1@(1, 0): [13, 14, 15, 16]
%result:2 = "stablehlo.all_reduce"(%operand0, %operand0) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
    "stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
  replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>,
  // channel_id = 0
  channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
  // use_global_device_ids = false
} : (tensor<4xi64>, tensor<4xi64>) -> (tensor<4xi64>, tensor<4xi64>)
// %result0@(0, 0): [6, 8, 10, 12]
// %result0@(1, 0): [6, 8, 10, 12]
// %result1@(0, 0): [22, 24, 26, 28]
// %result1@(1, 0): [22, 24, 26, 28]

مزيد من الأمثلة

all_to_all

دلالات الألفاظ

all_to_all

داخل كل مجموعة عمليات في شبكة عملية StableHLO، تُقسم قيم متسّعات operands على طول split_dimension إلى أجزاء، تفصل القسمة يربط الأجزاء المتناثرة ببعضها البعض، concat_dimension وينتج results متسابقًا. تقسم هذه العملية شبكة عملية StableHLO إلى process_groups وهي على النحو التالي:

  • cross_replica(replica_groups) إذا channel_id <= 0.
  • cross_partition(replica_groups) إذا channel_id > 0.

بعد ذلك، ضمن كل process_group:

  • split_parts...@sender = split(operands...@sender, split_count, split_dimension) لجميع sender في process_group.
  • مكان scattered_parts...@receiver = [split_parts...@sender[receiver_index] for sender in process_group] receiver_index = process_group.index(receiver)
  • results...@process = concatenate(scattered_parts...@process, concat_dimension).

مدخلات

التصنيف الاسم النوع القيود
(I1) operands الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق (C1-C3)، (C9)
(I2) split_dimension ثابت من النوع si64 (C1)، (C2)، (C9)
(I3) concat_dimension ثابت من النوع si64 (C3)، (C9)
(I4) split_count ثابت من النوع si64 (C2)، (C4)، (C8)، (C9)
(I5) replica_groups ثابت التوتر الثنائي الأبعاد من النوع si64 (C5-C8)
(I6) channel_id ثابت من النوع si64

المُخرَجات

الاسم النوع القيود
results الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق (C9)

القيود

  • (ج1) 0 <= split_dimension < rank(operands...).
  • (C2) dim(operands..., split_dimension) % split_count = 0.
  • (C3) 0 <= concat_dimension < rank(operands...):
  • (C4) 0 < split_count.
  • (C5) is_unique(replica_groups).
  • (C6) يتم تعريف size(replica_groups) على النحو التالي:
    • num_replicas في حال استخدام cross_replica.
    • num_partitions في حال استخدام cross_partition.
  • (C7) 0 <= replica_groups < size(replica_groups).
  • (C8) dim(replica_groups, 1) = split_count.
  • (C9) type(results...) = type(operands...) باستثناء إذا كانت split_dimension != concat_dimension:
    • dim(results..., split_dimension) = dim(operands..., split_dimension) / split_count.
    • dim(results..., concat_dimension) = dim(operands..., concat_dimension) * split_count.

أمثلة

// num_replicas: 2
// num_partitions: 1
// %operand1@(0, 0): [[1, 2, 3, 4],
//                    [5, 6, 7, 8]]
// %operand1@(1, 0): [[9, 10, 11, 12],
//                    [13, 14, 15, 16]]
// %operand2@(0, 0): [[17, 18, 19, 20],
//                    [21, 22, 23, 24]]
// %operand2@(1, 0): [[25, 26, 27, 28],
//                    [29, 30, 31, 32]]
%result:2 = "stablehlo.all_to_all"(%operand1, %operand2) {
  split_dimension = 1 : i64,
  concat_dimension = 0 : i64,
  split_count = 2 : i64,
  replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>
  // channel_id = 0
} : (tensor<2x4xi64>, tensor<2x4xi64>) -> (tensor<4x2xi64>, tensor<4x2xi64>)
// %result#0@(0, 0): [[1, 2], [5, 6], [9, 10], [13, 14]]
// %result#0@(1, 0): [[3, 4], [7, 8], [11, 12], [15, 16]]
// %result#1@(0, 0): [[17, 18], [21, 22], [25, 26], [29, 30]]
// %result#1@(1, 0): [[19, 20], [23, 24], [27, 28], [31, 32]]

مزيد من الأمثلة

و

دلالات الألفاظ

تؤدي هذه العملية إلى إجراء AND من ناحية العناصر على مستوى العنصرين lhs وrhs وينتج عن ذلك result. متنسور. حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى القيم المنطقية: المنطقي AND.
  • بالنسبة إلى الأعداد الصحيحة: استخدام AND على مستوى البت.

مدخلات

التصنيف الاسم النوع القيود
(I1) lhs متّصِل من نوع القيمة المنطقية أو العدد الصحيح (C1)
(I2) rhs متّصِل من نوع القيمة المنطقية أو العدد الصحيح (C1)

المُخرَجات

الاسم النوع القيود
result متّصِل من نوع القيمة المنطقية أو العدد الصحيح (C1)

القيود

  • (ج1) type(lhs) = type(rhs) = type(result).

أمثلة

// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.and"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[1, 2], [3, 0]]

مزيد من الأمثلة

atan2

دلالات الألفاظ

لتنفيذ عملية atan2 من العناصر في العناصر على lhs وrhs Tensor وينتج عن ذلك متوتر result حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى الأعداد العشرية: atan2 من IEEE-754.
  • للأعداد المركّبة: مركّب Atan2.
  • بالنسبة إلى الأنواع الكَمية: dequantize_op_quantize(atan2, lhs, rhs, type(result)).

مدخلات

التصنيف الاسم النوع القيود
(I1) lhs مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)
(I2) rhs مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

القيود

  • (ج1) baseline_type(lhs) = baseline_type(rhs) = baseline_type(result).

أمثلة

// %lhs: [0.0, 1.0, -1.0]
// %rhs: [0.0, 0.0, 0.0]
%result = "stablehlo.atan2"(%lhs, %rhs) : (tensor<3xf64>, tensor<3xf64>) -> tensor<3xf64>
// %result: [0.0, 1.57079637, -1.57079637] // [0.0, pi/2, -pi/2]

مزيد من الأمثلة

batch_norm_grad

دلالات الألفاظ

احتساب تدرجات مدخلات متعددة لعملية الانتشار العكسي batch_norm_training من grad_output، وأنتج grad_operand وgrad_scale وgrad_offset وأجهزة تنس. ويمكن التعبير عن هذه العملية بشكل أكثر رسمية بوصفها تحليلاً عمليات StableHLO الحالية باستخدام بناء جملة Python على النحو التالي:

def compute_sum(operand, feature_index):
  (sum,) = reduce(
      inputs=[operand],
      init_values=[constant(0, element_type(operand))],
      dimensions=[i for i in range(rank(operand)) if i != feature_index],
      body=lambda x, y: add(x, y))
  return sum

def compute_mean(operand, feature_index):
  sum = compute_sum(operand, feature_index)
  divisor = constant(size(operand) / dim(operand, feature_index),
                     element_type(operand))
  divisor_bcast = broadcast_in_dim(divisor, [], type(sum))
  return divide(sum, divisor_bcast)

def batch_norm_grad(operand, scale, mean, variance, grad_output, epsilon, feature_index):
  # Broadcast inputs to type(operand)
  scale_bcast = broadcast_in_dim(scale, [feature_index], type(operand))
  mean_bcast = broadcast_in_dim(mean, [feature_index], type(operand))
  variance_bcast = broadcast_in_dim(variance, [feature_index], type(operand))
  epsilon_bcast = broadcast_in_dim(constant(epsilon, element_type(operand)), [],
                                   type(operand))

  # Perform normalization using the provided `mean` and `variance`
  # Intermediate values will be useful for computing gradients
  centered_operand = subtract(operand, mean_bcast)
  stddev = sqrt(add(variance_bcast, epsilon_bcast))
  normalized_operand = divide(centered_operand, stddev)

  # Use the implementation from batchnorm_expander.cc in XLA
  # Temporary variables have exactly the same names as in the C++ code
  elements_per_feature = broadcast_in_dim(
      constant(divide(size(operand), dim(operand, feature_index)),
               element_type(grad_output)),
      [], type(operand))
  i1 = multiply(grad_output, elements_per_feature)
  i2 = broadcast_in_dim(
      compute_sum(grad_output, feature_index), [feature_index], type(operand))
  i3 = broadcast_in_dim(
      compute_sum(multiply(grad_output, centered_operand), feature_index),
      [feature_index], type(operand))
  i4 = multiply(i3, centered_operand)
  i5 = divide(i4, add(variance_bcast, epsilon_bcast))
  i6 = subtract(subtract(i1, i2), i5)

  grad_operand =
      multiply(divide(divide(scale_bcast, stddev), elements_per_feature), i6)
  grad_scale =
      compute_sum(multiply(grad_output, normalized_operand), feature_index)
  grad_offset = compute_sum(grad_output, feature_index)

  return grad_operand, grad_scale, grad_offset

بالنسبة للأنواع الكَمية، تنفذ dequantize_batch_norm_grad_or_training_quantize(lambda operand, scale, mean, variance, grad_output: batch_norm_grad(operand, scale, mean, variance, grad_output, epsilon, feature_index), operand, scale, mean, variance, grad_output, type(grad_operand), type(grad_scale), type(feature_index))

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق (C1-C3)، (C5)
(I2) scale متسّع أحادي البعد لنوع النقطة العائمة أو نوع كمي بالاستناد إلى كل متسابق (C2)، (C4)، (C5)
(I3) mean متسّع أحادي البعد لنوع النقطة العائمة أو نوع كمي بالاستناد إلى كل متسابق (C2)، (C4)
(I4) variance متسّع أحادي البعد لنوع النقطة العائمة أو نوع كمي بالاستناد إلى كل متسابق (C2)، (C4)
(I5) grad_output متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق (C2)، (C3)
(I6) epsilon ثابت من النوع f32
(I7) feature_index ثابت من النوع si64 (C1)، (C5)

المُخرَجات

الاسم النوع القيود
grad_operand متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق (C2)، (C3)
grad_scale متسّع أحادي البعد لنوع النقطة العائمة أو نوع كمي بالاستناد إلى كل متسابق (C2)، (C4)
grad_offset متسّع أحادي البعد لنوع النقطة العائمة أو نوع كمي بالاستناد إلى كل متسابق (C2)، (C4)

القيود

  • (ج1) 0 <= feature_index < rank(operand).
  • (C2) operand وscale وmean وvariance وgrad_output وgrad_operand في grad_scale وgrad_offset نفس الحالة baseline_element_type.
  • (C3) operand وgrad_output وgrad_operand لها الشكل نفسه.
  • (C4) scale وmean وvariance وgrad_scale وgrad_offset لديهم نفس الشكل.
  • (C5) size(scale) = dim(operand, feature_index).

أمثلة

// %operand: [
//            [[1.0, 2.0], [3.0, 4.0]],
//            [[3.0, 4.0], [1.0, 2.0]]
//           ]
// %scale: [1.0, 1.0]
// %mean: [2.0, 3.0]
// %variance: [1.0, 1.0]
// %grad_output: [
//                [[0.1, 0.1], [0.1, 0.1]],
//                [[0.1, 0.1], [0.1, 0.1]]
//               ]
%grad_operand, %grad_scale, %grad_offset =
"stablehlo.batch_norm_grad"(%operand, %scale, %mean, %variance, %grad_output) {
  epsilon = 0.0 : f32,
  feature_index = 2 : i64
} : (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>, tensor<2xf64>,
     tensor<2x2x2xf64>) -> (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>)
// %grad_operand: [
//                 [[0.0, 0.0], [0.0, 0.0]],
//                 [[0.0, 0.0], [0.0, 0.0]]
//                ]
// %grad_scale:  [0.0, 0.0]
// %grad_offset: [0.4, 0.4]

batch_norm_inference

دلالات الألفاظ

تعمل هذه القيمة على تسوية متّجه operand في جميع السمات باستثناء السمة دالة feature_index وينتج عنها متسابق result. بشكل رسمي أكثر، يمكن التعبير عن العملية كتحليل لعمليات StableHLO الحالية باستخدام بناء جملة بايثون على النحو التالي:

def batch_norm_inference(operand, scale, offset, mean, variance, epsilon, feature_index):
  # Broadcast inputs to shape(operand)
  scale_bcast = broadcast_in_dim(scale, [feature_index], type(operand))
  offset_bcast = broadcast_in_dim(offset, [feature_index], type(operand))
  mean_bcast = broadcast_in_dim(mean, [feature_index], type(operand))
  variance_bcast = broadcast_in_dim(variance, [feature_index], type(operand))
  epsilon_bcast = broadcast_in_dim(constant(epsilon, element_type(operand)), [],
                                   type(operand))

  # Perform normalization using the provided `mean` and `variance` instead of
  # computing them like `batch_norm_training` does.
  centered_operand = subtract(operand, mean_bcast)
  stddev = sqrt(add(variance_bcast, epsilon_bcast))
  normalized_operand = divide(centered_operand, stddev)
  return add(multiply(scale_bcast, normalized_operand), offset_bcast)

بالنسبة للأنواع الكَمية، تنفذ dequantize_op_quantize(lambda operand, scale, offset, mean, variance: batch_norm_inference(operand, scale, offset, mean, variance, epsilon, feature_index), operand, scale, offset, mean, variance, type(result))

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق (C1-C7)
(I2) scale متسّع أحادي البعد لنوع النقطة العائمة أو نوع كمي بالاستناد إلى كل متسابق (C2)، (C3)
(I3) offset متسّع أحادي البعد لنوع النقطة العائمة أو نوع كمي بالاستناد إلى كل متسابق (C2)، (C4)
(I4) mean متسّع أحادي البعد لنوع النقطة العائمة أو نوع كمي بالاستناد إلى كل متسابق (C5)
(I5) variance متسّع أحادي البعد لنوع النقطة العائمة أو نوع كمي بالاستناد إلى كل متسابق (C2)، (C6)
(I6) epsilon ثابت من النوع f32
(I7) feature_index ثابت من النوع si64 (C1)، (C3-C6)

المُخرَجات

الاسم النوع القيود
result متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق (C2)، (C7)

القيود

  • (ج1) 0 <= feature_index < rank(operand).
  • (C2) operand وscale وoffset وmean وvariance وresult لديهم baseline_element_type نفسها.
  • (C3) size(scale) = dim(operand, feature_index):
  • (C4) size(offset) = dim(operand, feature_index).
  • (C5) size(mean) = dim(operand, feature_index).
  • (C6) size(variance) = dim(operand, feature_index).
  • (C7) baseline_type(operand) = baseline_type(result).

أمثلة

// %operand: [
//            [[1.0, 2.0], [3.0, 4.0]],
//            [[3.0, 4.0], [1.0, 2.0]]
//           ]
// %scale: [1.0, 1.0]
// %offset: [1.0, 1.0]
// %mean: [2.0, 3.0]
// %variance: [1.0, 1.0]
%result = "stablehlo.batch_norm_inference"(%operand, %scale, %offset, %mean, %variance) {
  epsilon = 0.0 : f32,
  feature_index = 2 : i64
} : (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>, tensor<2xf64>, tensor<2xf64>) -> tensor<2x2x2xf64>
// %result: [
//           [[0.0, 0.0], [2.0, 2.0]],
//           [[2.0, 2.0], [0.0, 0.0]]
//          ]

batch_norm_training

دلالات الألفاظ

احتساب المتوسط والتباين في جميع السمات باستثناء feature_index ويعمل على تسوية مقياس operand الذي ينتج output، batch_mean وbatch_var متسابق. ويمكن التعبير عن هذه العملية بشكل رسمي إلى عمليات StableHLO الحالية باستخدام بناء جملة Python التالي:

def compute_mean(operand, feature_index):
  (sum,) = reduce(
      inputs=[operand],
      init_values=[constant(0, element_type(operand))],
      dimensions=[i for i in range(rank(operand)) if i != feature_index],
      body=lambda x, y: add(x, y))
  divisor = constant(size(operand) / dim(operand, feature_index),
                     element_type(operand))
  divisor_bcast = broadcast_in_dim(divisor, [], type(sum))
  return divide(sum, divisor_bcast)

def compute_variance(operand, feature_index):
  mean = compute_mean(operand, feature_index)
  mean_bcast = broadcast_in_dim(mean, [feature_index], type(operand))
  centered_operand = subtract(operand, mean_bcast)
  return compute_mean(mul(centered_operand, centered_operand), feature_index)

def batch_norm_training(operand, scale, offset, epsilon, feature_index):
  mean = compute_mean(operand, feature_index)
  variance = compute_variance(operand, feature_index)
  return batch_norm_inference(operand, scale, offset, mean, variance, epsilon,
                              feature_index),
         mean, variance

بالنسبة للأنواع الكَمية، تنفذ dequantize_batch_norm_grad_or_training_quantize(lambda operand, scale, offset: batch_norm_training(operand, scale, offset, epsilon, feature_index), operand, scale, offset, type(output), type(batch_mean), type(batch_var))

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق (C1)
(I2) scale مأخذ أحادي البعد للنقطة العائمة أو الكمّي بالمقدار نفسه (C2)، (C3)
(I3) offset مأخذ أحادي البعد للنقطة العائمة أو الكمّي بالمقدار نفسه (C2)، (C4)
(I4) epsilon ثابت من النوع f32 (C1)، (C3-C6)
(I5) feature_index ثابت من النوع si64 (C1)، (C3-C6)

المُخرَجات

الاسم النوع القيود
output متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق (C7)
batch_mean مأخذ أحادي البعد للنقطة العائمة أو الكمّي بالمقدار نفسه (C2)، (C5)
batch_var مأخذ أحادي البعد للنقطة العائمة أو الكمّي بالمقدار نفسه (C2)، (C6)

القيود

  • (ج1) 0 <= feature_index < rank(operand).
  • (C2) operand وscale وoffset وbatch_mean وbatch_var وoutput لديهم نفس baseline_element_type.
  • (C3) size(scale) = dim(operand, feature_index):
  • (C4) size(offset) = dim(operand, feature_index).
  • (C5) size(batch_mean) = dim(operand, feature_index).
  • (C6) size(batch_var) = dim(operand, feature_index).
  • (C7) baseline_type(output) = baseline_type(operand).

أمثلة

// %operand: [
//            [[1.0, 2.0], [3.0, 4.0]],
//            [[3.0, 4.0], [1.0, 2.0]]
//           ]
// %scale: [1.0, 1.0]
// %offset: [1.0, 1.0]
%output, %batch_mean, %batch_var = "stablehlo.batch_norm_training"(%operand, %scale, %offset) {
  epsilon = 0.0 : f32,
  feature_index = 2 : i64
} : (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>) ->
    (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>)
// %output: [
//           [[0.0, 0.0], [2.0, 2.0]],
//           [[2.0, 2.0], [0.0, 0.0]]
//          ]
// %batch_mean: [2.0, 3.0]
// %batch_var: [1.0, 1.0]

bitcast_convert

دلالات الألفاظ

لإجراء عملية بث بت على المغناطيس operand وينتج موتر result حيث يُعاد تفسير بتات متوتر operand بالكامل باستخدام نوع متوتر result.

بشكل رسمي، استنادًا إلى E = element_type(operand) وE' = element_type(result)، وR = rank(operand):

  • إذا كانت num_bits(E') < num_bits(E)، bits(result[i0, ..., iR-1, :]) = bits(operand[i0, ..., iR-1])
  • إذا كانت num_bits(E') > num_bits(E)، bits(result[i0, ..., iR-2]) = bits(operand[i0, ..., iR-2, :])
  • إذا كانت num_bits(E') = num_bits(E)، bits(result[i0, ..., iR-1]) = bits(operand[i0, ..., iR-1])

تعرض الدالة bits تمثيلاً في الذاكرة لقيمة معيّنة وسلوكها محدد التنفيذ لأن التمثيل الدقيق لدوال تنسور محددة التنفيذ، والتمثيل الدقيق لأنواع العناصر محددة التنفيذ أيضًا.

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتر أو متنسّر كمي (C1-C2)

المُخرَجات

الاسم النوع القيود
result متوتر أو متنسّر كمي (C1-C2)

القيود

  • (C1) بالنظر إلى E = is_quantized(operand) ? storage_type(operand) : element_type(operand) وE' = is_quantized(result) ? storage_type(result) : element_type(result) وR = rank(operand):
    • إذا كانت num_bits(E') = num_bits(E)، shape(result) = shape(operand).
    • إذا كانت num_bits(E') < num_bits(E):
    • rank(result) = R + 1.
    • dim(result, i) = dim(operand, i) لكل 0 <= i < R
    • dim(result, R) * num_bits(E') = num_bits(E).
    • إذا كانت num_bits(E') > num_bits(E):
    • rank(result) = R - 1.
    • dim(result, i) = dim(operand, i) لكل 0 <= i < R
    • dim(operand, R - 1) * num_bits(E) = num_bits(E').
  • (C2) إذا كانت is_complex(operand) or is_complex(result)، إذًا is_complex(operand) and is_complex(result)

أمثلة

// %operand: 0x0123456789ABCDEF
%result = "stablehlo.bitcast_convert"(%operand) : (tensor<f64>) -> tensor<4xf16>
// %result: [0xCDEF, 0x89AB, 0x4567, 0x0123] // little-endian representation

مزيد من الأمثلة

broadcast_in_dim

دلالات الألفاظ

توسيع أبعاد و/أو ترتيب مُعدَّل الإدخال عن طريق تكرار البيانات في موتّر operand وينتج موتّر result. بشكل أكثر رسمية، result[result_index] = operand[operand_index] أين يوجد جميع d في axes(operand):

  • operand_index[d] = 0 إذا dim(operand, d) = 1.
  • operand_index[d] = result_index[broadcast_dimensions[d]] بخلاف ذلك.

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتر أو متنسّر كمي (C1-C2)، (C5-C6)
(I2) broadcast_dimensions ثابت التوتر ذو البعد الواحد من النوع si64 (C2-C6)

المُخرَجات

الاسم النوع القيود
result متوتر أو متنسّر كمي (C1)، (C3)، (C5-C6)

القيود

  • (C1) element_type(result) يتم تقديمها من خلال:
    • element_type(operand)، إذا كانت !is_per_axis_quantized(operand).
    • element_type(operand) باستثناء أنّ quantization_dimension(operand)، وscales(operand)، وzero_points(operand) قد يختلفان عن quantization_dimension(result) وscales(result) وzero_points(result) أو الرد.
  • (C2) size(broadcast_dimensions) = rank(operand).
  • (C3) 0 <= broadcast_dimensions < rank(result):
  • (C4) is_unique(broadcast_dimensions).
  • (C5) لكل d في axes(operand):
    • dim(operand, d) = 1 أو
    • dim(operand, d) = dim(result, broadcast_dimensions[d]).
  • (C6) إذا كانت is_per_axis_quantized(result):
    • quantization_dimension(result) = broadcast_dimensions[quantization_dimension(operand)].
    • إذا كانت القيمة dim(operand, quantization_dimension(operand)) = 1، scales(result)[i] = scales(operand)[0] and zero_points(result)[i] = zero_points(operand)[0] for i in range(dim(result, quantization_dimension(result)))

أمثلة

// %operand: [
//            [1, 2, 3]
//           ]
%result = "stablehlo.broadcast_in_dim"(%operand) {
  broadcast_dimensions = array<i64: 2, 1>
} : (tensor<1x3xi32>) -> tensor<2x3x2xi32>
// %result: [
//            [
//             [1, 1],
//             [2, 2],
//             [3, 3]
//            ],
//            [
//             [1, 1],
//             [2, 2],
//             [3, 3]
//            ]
//          ]

مزيد من الأمثلة

حافظة

دلالات الألفاظ

الحصول على ناتج من تنفيذ دالة واحدة بالضبط من branches استنادًا إلى قيمة index. بشكل رسمي، result = selected_branch() حيث:

  • selected_branch = branches[index] إذا 0 <= index < size(branches).
  • selected_branch = branches[-1] بخلاف ذلك.

مدخلات

التصنيف الاسم النوع القيود
(I1) index متسابق أحادي الأبعاد من النوع si32
(I2) branches عدد متباين من الدوال (C1-C4)

المُخرَجات

الاسم النوع القيود
results الأعداد المتباينة من متساعات التوتر أو العشرات الكمية أو الرموز المميزة (C4)

القيود

  • (ج1) 0 < size(branches).
  • (C2) input_types(branches...) = [].
  • (C3) same(output_types(branches...)):
  • (C4) type(results...) = output_types(branches[0]).

أمثلة

// %index: -1
// %result_branch0: [0, 0]
// %result_branch1: [1, 1]
%result0, %result1 = "stablehlo.case"(%index) ({
  "stablehlo.return"(%result_branch0, %result_branch0) : (tensor<2xi64>, tensor<2xi64>) -> ()
}, {
  "stablehlo.return"(%result_branch1, %result_branch1) : (tensor<2xi64>, tensor<2xi64>) -> ()
}) : (tensor<i32>) -> (tensor<2xi64>, tensor<2xi64>)
// %result0: [1, 1]
// %result1: [1, 1]

مزيد من الأمثلة

cbrt

دلالات الألفاظ

لتنفيذ عملية جذر تكعيبي حسب العناصر على موتّر operand وينتج عنه متوتر result حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى الأعداد العشرية: rootn(x, 3) من IEEE-754.
  • بالنسبة للأعداد المركّبة: الجذر التكعيبي المركّب.
  • بالنسبة إلى الأنواع الكَمية: dequantize_op_quantize(cbrt, operand, type(result))

مدخلات

التصنيف الاسم النوع القيود
(I1) operand مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(result).

أمثلة

// %operand: [0.0, 1.0, 8.0, 27.0]
%result = "stablehlo.cbrt"(%operand) : (tensor<4xf64>) -> tensor<4xf64>
// %result: [0.0, 1.0, 2.0, 3.0]

مزيد من الأمثلة

ceil

دلالات الألفاظ

يؤدي هذا الإجراء إلى إنشاء تسلسل هرمي من ناحية العناصر في متسابق operand وينتج متسّر result. تنفيذ عملية roundToIntegralTowardPositive من IEEE-754 المواصفات. بالنسبة للأنواع الكَمية، تنفذ dequantize_op_quantize(ceil, operand, type(result))

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(result).

أمثلة

// %operand: [-0.8166, -0.2530, 0.2530, 0.8166, 2.0]
%result = "stablehlo.ceil"(%operand) : (tensor<5xf32>) -> tensor<5xf32>
// %result: [-0.0, -0.0, 1.0, 1.0, 2.0]

مزيد من الأمثلة

كولسكي

دلالات الألفاظ

لحساب تحليل كولسكي لدفعة من المصفوفات.

بشكل رسمي، لجميع i في index_space(result)، وresult[i0, ..., iR-3, :, :] عبارة عن انحلال كولسكي بالمثل a[i0, ..., iR-3, :, :]، في شكل أي من المثلث السفلي (إذا كانت السمة lower هي true) أو مصفوفة مثلثية أعلى (إذا كانت السمة lower هي false). قيم الناتج في المثلث المقابل، أي المثلث العلوي المتشدد أو وفي المقابل، يتم تحديد التنفيذ.

إذا كان هناك i حيث لا تكون مصفوفة الإدخال ذات قيمة موجب هيرميتية مصفوفة، فسيكون السلوك غير محدد.

بالنسبة للأنواع الكَمية، تنفذ dequantize_op_quantize(lambda operand: cholesky(operand, lower), a, type(result))

مدخلات

التصنيف الاسم النوع القيود
(I1) a مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1-C3)
(I2) lower ثابت التوتر الثنائي الأبعاد من النوع i1

المُخرَجات

الاسم النوع القيود
result مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

القيود

  • (ج1) baseline_type(a) = baseline_type(result).
  • (C2) 2 <= rank(a).
  • (C3) dim(a, -2) = dim(a, -1):

أمثلة

// %a: [
//      [1.0, 2.0, 3.0],
//      [2.0, 20.0, 26.0],
//      [3.0, 26.0, 70.0]
//     ]
%result = "stablehlo.cholesky"(%a) {
  lower = true
} : (tensor<3x3xf32>) -> tensor<3x3xf64>
// %result: [
//           [1.0, 0.0, 0.0],
//           [2.0, 4.0, 0.0],
//           [3.0, 5.0, 6.0]
//          ]

مشبك

دلالات الألفاظ

يربط كل عنصر من عناصر متّجه operand بين الحد الأدنى والأقصى وينتج متسابق result. بشكل رسمي، result[result_index] = minimum(maximum(operand[result_index], min_element), max_element)، حيث min_element = rank(min) = 0 ? min[] : min[result_index]، max_element = rank(max) = 0 ? max[] : max[result_index] بالنسبة للأنواع الكَمية، يؤدي استخدام dequantize_op_quantize(clamp, min, operand, max, type(result)).

يتضمن فرض ترتيب على الأعداد المركّبة دلالات مدهشة، لذا نخطط في المستقبل لإلغاء دعم الأعداد المركّبة لهذه العملية (#560).

مدخلات

التصنيف الاسم النوع القيود
(I1) min متوتّر أو مستنسر كمي لكلّ متسابق (C1)، (C3)
(I2) operand متوتّر أو مستنسر كمي لكلّ متسابق (C1-C4)
(I3) max متوتّر أو مستنسر كمي لكلّ متسابق (C2)، (C3)

المُخرَجات

الاسم النوع القيود
result متوتّر أو مستنسر كمي لكلّ متسابق (C4)

القيود

  • (ج1) rank(min) = 0 or shape(min) = shape(operand).
  • (C2) rank(max) = 0 or shape(max) = shape(operand).
  • (C3) baseline_element_type(min) = baseline_element_type(operand) = baseline_element_type(max):
  • (C4) baseline_type(operand) = baseline_type(result).

أمثلة

// %min: [5, 10, 15]
// %operand: [3, 13, 23]
// %max: [10, 15, 20]
%result = "stablehlo.clamp"(%min, %operand, %max) : (tensor<3xi32>, tensor<3xi32>, tensor<3xi32>) -> tensor<3xi32>
// %result: [5, 13, 20]

مزيد من الأمثلة

collective_broadcast

دلالات الألفاظ

ضمن كل مجموعة عمليات في شبكة عملية StableHLO، أرسل قيمة معامل operand من عملية المصدر إلى العمليات المستهدفة وينتج عنه متوتر result

تقسم هذه العملية شبكة عملية StableHLO إلى process_groups وهي على النحو التالي:

  • cross_replica(replica_groups) إذا channel_id <= 0.
  • cross_partition(replica_groups) إذا channel_id > 0.

بعد ذلك، يتم منح result@process من خلال:

  • operand@process_groups[i, 0] إذا كان هناك i بحيث تكون العملية في process_groups[i].
  • broadcast_in_dim(constant(is_quantized(result) ? quantize(0, element_type(result)) : 0, element_type(result)), [], type(result)) وإلا.

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتّر أو مستنسر كمي لكلّ متسابق (C3)
(I2) replica_groups عدد متغير لثوابت متسابق أحادي البعد من النوع si64 (C1)، (C2)
(I3) channel_id ثابت من النوع si64

المُخرَجات

الاسم النوع القيود
result متوتّر أو مستنسر كمي لكلّ متسابق (C3)

القيود

  • (ج1) is_unique(replica_groups).
  • (C2) 0 <= replica_groups < N حيث يتم تعريف N على النحو التالي:
    • num_replicas في حال استخدام cross_replica.
    • num_partitions في حال استخدام cross_partition.
  • (C3) type(result) = type(operand):

أمثلة

// num_replicas: 4
// num_partitions: 1
// %operand@(0, 0): [[1, 2]]
// %operand@(1, 0): [[3, 4]]
// %operand@(2, 0): [[5, 6]]
// %operand@(3, 0): [[7, 8]]
%result = "stablehlo.collective_broadcast"(%operand) {
  replica_groups = dense<[[2, 1]]> : tensor<1x2xi64>,
  channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
} : (tensor1x2xi64>) -> tensor<1x2xi64>
// %result@(0, 0): [[0, 0]]
// %result@(1, 0): [[5, 6]]
// %result@(2, 0): [[5, 6]]
// %result@(3, 0): [[0, 0]]

collective_permute

دلالات الألفاظ

داخل كل مجموعة عمليات في شبكة عملية StableHLO، يرسل قيمة سينتج عن شدة operand من عملية المصدر إلى العملية المستهدفة وينتج عنه متوتر result

تقسم هذه العملية شبكة عملية StableHLO إلى process_groups وهي على النحو التالي:

  • cross_replica(source_target_pairs) إذا channel_id <= 0.
  • cross_partition(source_target_pairs) إذا channel_id > 0.

بعد ذلك، يتم منح result@process من خلال:

  • operand@process_groups[i, 0]، إذا كان هناك i بحيث process_groups[i, 1] = process
  • broadcast_in_dim(constant(is_quantized(result) ? quantize(0, element_type(result)) : 0, element_type(result)), [], type(result)) وإلا.

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتّر أو مستنسر كمي لكلّ متسابق (C5)
(I2) source_target_pairs ثابت التوتر الثنائي الأبعاد من النوع si64 (C1-C4)
(I3) channel_id ثابت من النوع si64

المُخرَجات

الاسم النوع القيود
result متوتّر أو مستنسر كمي لكلّ متسابق (C1)

القيود

  • (ج1) dim(source_target_pairs, 1) = 2.
  • (C2) is_unique(source_target_pairs[:, 0]).
  • (C3) is_unique(source_target_pairs[:, 1]):
  • (C4) 0 <= source_target_pairs < N، حيث يتم تعريف N على أنه:
    • num_replicas في حال استخدام cross_replica.
    • num_partitions في حال استخدام cross_partition.
  • (C5) type(result) = type(operand).

أمثلة

// num_replicas: 3
// num_partitions: 1
// %operand@(0, 0): [[1, 2], [3, 4]]
// %operand@(1, 0): [[5, 6], [7, 8]]
// %operand@(2, 0): [[9, 10], [11, 12]]
%result = "stablehlo.collective_permute"(%operand) {
  source_target_pairs = dense<[[0, 1], [1, 2]]> : tensor<2x2xi64>,
  channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
} : (tensor<2x2xi64>) -> tensor<2x2xi64>
//
// %result@(0, 0): [[0, 0], [0, 0]]
// %result@(1, 0): [[1, 2], [3, 4]]
// %result@(2, 0): [[5, 6], [7, 8]]

مزيد من الأمثلة

مقارنة

دلالات الألفاظ

يجري مقارنة بين العناصر من حيث العناصر لـ lhs وrhs متوترَين وفقًا لما يلي: comparison_direction وcompare_type، وينتج متسابق result.

في ما يلي قيمتا comparison_direction وcompare_type: الدلالة:

بالنسبة إلى أنواع العناصر المنطقية والعناصر الصحيحة:

  • EQ: lhs = rhs.
  • NE: lhs != rhs.
  • GE: lhs >= rhs.
  • GT: lhs > rhs.
  • LE: lhs <= rhs.
  • LT: lhs < rhs.

بالنسبة إلى أنواع العناصر العائمة في compare_type = FLOAT، يتم تنفيذ العملية عمليات IEEE-754 التالية:

  • EQ: compareQuietEqual.
  • NE: compareQuietNotEqual.
  • GE: compareQuietGreaterEqual.
  • GT: compareQuietGreater.
  • LE: compareQuietLessEqual.
  • LT: compareQuietLess.

وبالنسبة إلى أنواع العناصر العائمة باستخدام compare_type = TOTALORDER، تستخدم الجمع بين عمليات totalOrder وcompareQuietEqual من معيار IEEE-754.

بالنسبة إلى أنواع العناصر المعقّدة، تكون المقارنة اللغوية لأزواج (real, imag) هي تم تنفيذه باستخدام comparison_direction وcompare_type المقدَّمتَين. يتضمن فرض ترتيب على الأعداد المركّبة دلالات مدهشة، لذا نخطط في المستقبل لإلغاء دعم الأعداد المركّبة عندما تكون قيمة comparison_direction هي GE أو GT أو LE أو LT (#560)

بالنسبة إلى الأنواع الكَمية. يؤدي استخدام dequantize_compare(lhs, rhs, comparison_direction).

مدخلات

التصنيف الاسم النوع القيود
(I1) lhs متوتّر أو مستنسر كمي لكلّ متسابق (C1-C3)
(I2) rhs متوتّر أو مستنسر كمي لكلّ متسابق (C1-C2)
(I3) comparison_direction تعداد EQ وNE وGE وGT وLE وLT
(I4) compare_type تعداد FLOAT وTOTALORDER وSIGNED وUNSIGNED (C3)

المُخرَجات

الاسم النوع القيود
result متّصِل من النوع المنطقي (C2)

القيود

  • (ج1) baseline_element_type(lhs) = baseline_element_type(rhs).
  • (C2) shape(lhs) = shape(rhs) = shape(result).
  • (C3) يتم تعريف compare_type على النحو التالي:
    • SIGNED إذا is_signed_integer(element_type(lhs)).
    • UNSIGNED إذا is_unsigned_integer(element_type(lhs)) or is_boolean(element_type(lhs)).
    • FLOAT أو TOTALORDER إذا is_float(element_type(lhs)).
    • FLOAT إذا is_complex(element_type(lhs)).

أمثلة

// %lhs: [1.0, 3.0]
// %rhs: [1.1, 2.9]
%result = "stablehlo.compare"(%lhs, %rhs) {
  comparison_direction = #stablehlo<comparison_direction LT>,
  compare_type = #stablehlo<comparison_type FLOAT>
} : (tensor<2xf32>, tensor<2xf32>) -> tensor<2xi1>
// %result: [true, false]

مزيد من الأمثلة

معقد

دلالات الألفاظ

تُجري تحويلًا من ناحية العناصر إلى قيمة معقدة من زوج من القيم الحقيقية القيم التخيّلية lhs وrhs، وينتج تينسور result.

مدخلات

التصنيف الاسم النوع القيود
(I1) lhs متوتر من النوع f32 أو f64 (C1-C3)
(I2) rhs متوتر من النوع f32 أو f64 (C1)

المُخرَجات

الاسم النوع القيود
result متّصِل من النوع المعقد (C2)، (C3)

القيود

  • (ج1) type(lhs) = type(rhs).
  • (C2) shape(result) = shape(lhs).
  • (C3) element_type(result) من النوع complex<E> حيث E = element_type(lhs)

أمثلة

// %lhs: [1.0, 3.0]
// %rhs: [2.0, 4.0]
%result = "stablehlo.complex"(%lhs, %rhs) : (tensor<2xf64>, tensor<2xf64>) -> tensor<2xcomplex<f64>>
// %result: [(1.0, 2.0), (3.0, 4.0)]

مزيد من الأمثلة

مُركّب

دلالات الألفاظ

وهي عملية تتألف من عمليات (يتم تكوينها) من عمليات StableHLO الأخرى، استعِدّ لـ inputs وcomposite_attributes وينتج results. تشير رسالة الأشكال البيانية تطبّق السمة decomposition دلالات العملية. تشير رسالة الأشكال البيانية يمكن استبدال العملية composite بتحليلها بدون تغيير البرنامج. الدلالة. وفي الحالات التي لا يوفر فيها التحلل النموذج نفسه علم الدلالات، يُفضَّل استخدام custom_call.

يُستخدَم الحقل version (القيمة التلقائية لـ 0) للدلالة على عدم ظهور تغيير الدلالة.

مدخلات

التصنيف الاسم النوع
(I1) inputs العدد المتغير للقيم
(I2) name ثابت من النوع string
(I3) composite_attributes قاموس السمات
(I4) decomposition ثابت من النوع string
(I5) version ثابت من النوع si32

المُخرَجات

الاسم النوع
results العدد المتغير للقيم

القيود

  • (C1) is_namespaced_op_name(name)
  • (C2) is_defined_in_parent_scope(decomposition)
  • (C3) types(inputs...) == input_types(decomposition)
  • (C4) types(results...) == output_types(decomposition)

أمثلة

%results = "stablehlo.composite"(%input0, %input1) {
  name = "my_namespace.my_op",
  composite_attributes = {
    my_attribute = "my_value"
  },
  decomposition = @my_op,
  version = 1 : i32
} : (tensor<f32>, tensor<f32>) -> tensor<f32>

مزيد من الأمثلة

إنشاء تسلسل

دلالات الألفاظ

يؤدي إلى إنشاء تسلسل لـ inputs في البُعد dimension بنفس الترتيب المحدّد. وينتج عن ذلك مترابط result. بشكل أكثر رسمية، result[i0, ..., id, ..., iR-1] = inputs[k][i0, ..., kd, ..., iR-1]، حيث:

  1. id = d0 + ... + dk-1 + kd.
  2. d يساوي dimension وd0، ... هما حجمان للأبعاد d من inputs.

مدخلات

التصنيف الاسم النوع القيود
(I1) inputs الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق (C1-C6)
(I2) dimension ثابت من النوع si64 (C2)، (C4)، (C6)

المُخرَجات

الاسم النوع القيود
result متوتّر أو مستنسر كمي لكلّ متسابق (C5-C6)

القيود

  • (ج1) same(element_type(inputs...)).
  • (C2) same(shape(inputs...)) باستثناء dim(inputs..., dimension).
  • (C3) 0 < size(inputs):
  • (C4) 0 <= dimension < rank(inputs[0]).
  • (C5) element_type(result) = element_type(inputs[0]).
  • (C6) shape(result) = shape(inputs[0]) باستثناء:
    • dim(result, dimension) = dim(inputs[0], dimension) + ....

أمثلة

// %input0: [[1, 2], [3, 4], [5, 6]]
// %input1: [[7, 8]]
%result = "stablehlo.concatenate"(%input0, %input1) {
  dimension = 0 : i64
} : (tensor<3x2xi64>, tensor<1x2xi64>) -> tensor<4x2xi64>
// %result: [[1, 2], [3, 4], [5, 6], [7, 8]]

مزيد من الأمثلة

الثابت

دلالات الألفاظ

لإنتاج متوتر output من value ثابت.

مدخلات

التصنيف الاسم النوع القيود
(I1) value الثابت (C1)

المُخرَجات

الاسم النوع القيود
output متوتر أو متنسّر كمي (C1)

القيود

  • (ج1) type(value) = type(output).

أمثلة

%output = "stablehlo.constant"() {
  value = dense<[[0.0, 1.0], [2.0, 3.0]]> : tensor<2x2xf32>
} : () -> tensor<2x2xf32>
// %output: [[0.0, 1.0], [2.0, 3.0]]

مزيد من الأمثلة

إجراء إحالة ناجحة

دلالات الألفاظ

تُجري عملية تحويل حسب العناصر من نوع عنصر إلى آخر على ينسور operand وينتج متسابق result.

بالنسبة إلى الإحالات الناجحة boolean-to-any-supported-type، تكون القيمة false هي وتحويلها إلى صفر، وتحويل القيمة true إلى واحد. بالنسبة any-supported-type-to-boolean، يتم تحويل القيمة صفر إلى يتم تحويل القيم false والقيم غير الصفرية إلى true. انظر أدناه لمعرفة كيف يمكنك تحقيق ذلك تناسب الأنواع المعقدة.

بالنسبة إلى الإحالات الناجحة التي تتضمّن integer-to-integer وinteger-to-floating-point أو floating-point-to-floating-point، إذا كان من الممكن تحديد قيمة المصدر التي يتم تمثيلها في نوع الوجهة، فإن قيمة النتيجة هي تلك الدقيقة التمثيل المناسب. وبخلاف ذلك، سيتم تحديد السلوك لاحقًا. (#180)

بالنسبة إلى الإحالات الناجحة التي تتضمّن floating-point-to-integer، يكون الجزء الكسري هو تم اقتطاعه. إذا تعذّر تمثيل القيمة المقتطعة في نوع الوجهة، يتم تحديد السلوك لاحقًا (#180).

تتبع الإحالات الناجحة التي تشتمل على معقد إلى معقد سلوك الإحالات الناجحة floating-point-to-floating-point لتحويل الأجزاء الخيالية.

بالنسبة إلى الإحالات الناجحة complex-to-any-other-type وcomplex-to-any-other-type، يتم تجاهل القيمة التخيلية المصدر أو القيمة التخيلية للوجهة بأصفار، على التوالي. ويتبع تحويل الجزء الحقيقي إحالات ناجحة النقطة العائمة.

من حيث المبدأ، يمكن لهذه العملية التعبير عن إلغاء التحديد (تحويل من المقوّمات الكميّة إلى موتّرات عادية)، الكمي (تحويل من منتظم) المقوّسات إلى قياسات التوتر الكمّية) وإعادة الكمّية (التحويل بين الكميّة الكمية) الأساسية)، ولكن في الوقت الحالي، خصصنا عمليات من أجل ذلك uniform_dequantize لحالة الاستخدام الأولى وuniform_quantize لحالة الاستخدام وحالات الاستخدام الثانية والثالثة. في المستقبل، قد يتم دمج هاتين العملتين إلى convert (#1576).

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متعدّد (C1)

المُخرَجات

الاسم النوع القيود
result متعدّد (C1)

القيود

  • (ج1) shape(operand) = shape(result).

أمثلة

// %operand: [-1, 0, 1]
%result = "stablehlo.convert"(%operand) : (tensor<3xi64>) -> tensor<3xcomplex<f64>>
// %result: [(-1.0, 0.0), (0.0, 0.0), (1.0, 0.0)]

مزيد من الأمثلة

التفاف

دلالات الألفاظ

لحساب قيمة المنتجات النقطية بين نوافذ lhs وشرائح rhs، ويتم الحصول على result يوضّح المخطّط التالي طريقة حساب العناصر في result من lhs وrhs باستخدام مثال ملموس.

التفاف

من الناحية الرسمية، ننصحك بإعادة صياغة الإدخالات من حيث lhs. ولتتمكّن من التعبير عن مهلة lhs:

  • lhs_window_dimensions = lhs_shape(dim(lhs, input_batch_dimension), dim(rhs, kernel_spatial_dimensions), dim(lhs, input_feature_dimension)).
  • lhs_window_strides = lhs_shape(1, window_strides, 1).
  • lhs_padding = lhs_shape([0, 0], padding, [0, 0]).
  • lhs_base_dilations = lhs_shape(1, lhs_dilation, 1).
  • lhs_window_dilations = lhs_shape(1, rhs_dilation, 1).

تستخدم عملية إعادة الصياغة هذه الدوال المساعدة التالية:

  • lhs_shape(n, hw, c) = permute([n] + hw + [c], [input_batch_dimension] + input_spatial_dimensions + [input_feature_dimension]).
  • result_shape(n1, hw, c1) = permute([n1] + hw + [c1], [output_batch_dimension] + output_spatial_dimensions + [output_feature_dimension]).
  • permute([j0, j1, ..., jR-1], permutation) = [i0, i1, ..., iR-1] حيث j[d] = i[permutation[d]].

إذا كان feature_group_count = 1 وbatch_group_count = 1، يتم ذلك مع جميع output_spatial_index في index_space(dim(result, output_spatial_dimensions...))، result[result_shape(:, output_spatial_index, :)] = dot_product حيث:

  • padding_value = constant(0, element_type(lhs)).
  • padded_lhs = pad(lhs, padding_value, lhs_padding[:, 0], lhs_padding[:, 1], lhs_base_dilations - 1).
  • lhs_window_start = lhs_shape(0, output_spatial_index, 0) * lhs_window_strides.
  • lhs_window = slice(padded_lhs, lhs_window_start, lhs_window_start + lhs_window_dimensions, lhs_window_dilations).
  • reversed_lhs_window = reverse(lhs_window, [input_spatial_dimensions[dim] for dim in range(size(window_reversal)) if window_reversal[dim] = true]) يبدو أنّ هذه الميزة غير مستخدَمة، لذا نخطّط لإزالتها في المستقبل. (#1181).
  • dot_product = dot_general(reversed_lhs_window, rhs, lhs_batching_dimensions=[], lhs_contracting_dimensions=input_spatial_dimensions + [input_feature_dimension], rhs_batching_dimensions=[], rhs_contracting_dimensions=kernel_spatial_dimensions + [kernel_input_feature_dimension]).

إذا كانت feature_group_count > 1:

  • lhses = split(lhs, feature_group_count, input_feature_dimension).
  • rhses = split(rhs, feature_group_count, kernel_output_feature_dimension).
  • results... = convolution(lhses..., rhses..., ..., feature_group_count=1, ...).
  • result = concatenate(results, output_feature_dimension).

إذا كانت batch_group_count > 1:

  • lhses = split(lhs, batch_group_count, input_batch_dimension).
  • rhses = split(rhs, batch_group_count, kernel_output_feature_dimension).
  • results... = convolution(lhses..., rhses..., ..., batch_group_count=1, ...).
  • result = concatenate(results, output_feature_dimension)

بالنسبة إلى الأنواع المحدَّدة الكمية، يتم تنفيذ dequantize_op_quantize( lambda lhs, rhs: convolution(lhs, rhs, window_strides, padding, lhs_dilation, rhs_dilation, window_reversal, input_batch_dimension, input_feature_dimension, input_spatial_dimensions, kernel_input_feature_dimension, kernel_output_feature_dimension, kernel_spatial_dimensions, output_batch_dimension, output_feature_dimension, output_spatial_dimensions, feature_group_count, batch_group_count, precision_config), lhs, rhs, type(result)).

بالنسبة إلى الأنواع الكمية المختلطة، تحقّق قيمة hybrid_dequantize_then_op( lambda lhs, rhs: convolution(lhs, rhs, window_strides, padding, lhs_dilation, rhs_dilation, window_reversal, input_batch_dimension, input_feature_dimension, input_spatial_dimensions, kernel_input_feature_dimension, kernel_output_feature_dimension, kernel_spatial_dimensions, output_batch_dimension, output_feature_dimension, output_spatial_dimensions, feature_group_count, batch_group_count, precision_config), lhs, rhs).

مدخلات

التصنيف الاسم النوع القيود
(I1) lhs متوتّر أو مستنسر كمي لكلّ متسابق (C1)، (C10-C11)، (C14) (C25)، (C27-C28)، (C31-C32)، (C34)
(I2) rhs متوتر أو متنسّر كمي (C1)، (C14-C16)، (C25)، (C27-C29)، (C31-C34)
(I3) window_strides ثابت التوتر ذو البعد الواحد من النوع si64 (C2-C3)، (C25)
(I4) padding ثابت التوتر الثنائي الأبعاد من النوع si64 (C4)، (C25)
(I5) lhs_dilation ثابت التوتر ذو البعد الواحد من النوع si64 (C5-C6)، (C25)
(I6) rhs_dilation ثابت التوتر ذو البعد الواحد من النوع si64 (C7-C8)، (C25)
(I7) window_reversal ثابت التوتر ذو البعد الواحد من النوع i1 (C9)
(I8) input_batch_dimension ثابت من النوع si64 (C10)، (C13)، (C25)
(I9) input_feature_dimension ثابت من النوع si64 (C11)، (C13-C14)
(I10) input_spatial_dimensions ثابت التوتر ذو البعد الواحد من النوع si64 (C12)، (C13)، (C25)
(I11) kernel_input_feature_dimension ثابت من النوع si64 (C14)، (C18)
(I12) kernel_output_feature_dimension ثابت من النوع si64 (C15-C16)، (C18)، (C25)، (C29)
(I13) kernel_spatial_dimensions ثابت التوتر ذو البعد الواحد من النوع si64 (C17-C18)، (C25)
(I14) output_batch_dimension ثابت من النوع si64 (C20)، (C25)
(I15) output_feature_dimension ثابت من النوع si64 (C20)، (C25)، (C30)
(I16) output_spatial_dimensions ثابت التوتر ذو البعد الواحد من النوع si64 (C19-C20)، (C25)
(I17) feature_group_count ثابت من النوع si64 (C11)، (C14)، (C16)، (C21)، (C23)
(I18) batch_group_count ثابت من النوع si64 (C10)، (C15)، (C22)، (C23)، (C25)
(I19) precision_config اختلاف في عدد التعدادات للقيم DEFAULT وHIGH وHIGHEST (C24)

المُخرَجات

الاسم النوع القيود
result متوتر أو متنسّر كمي (C25-C28)، (C30)، (C32-34)

القيود

  • (ج1) N = rank(lhs) = rank(rhs).
  • (C2) size(window_strides) = N - 2.
  • (C3) 0 < window_strides:
  • (C4) shape(padding) = [N - 2, 2].
  • (C5) size(lhs_dilation) = N - 2.
  • (C6) 0 < lhs_dilation.
  • (C7) size(rhs_dilation) = N - 2.
  • (C8) 0 < rhs_dilation.
  • (C9) size(window_reversal) = N - 2.
  • (C10) dim(lhs, input_batch_dimension) % batch_group_count = 0.
  • (C11) dim(lhs, input_feature_dimension) % feature_group_count = 0.
  • (C12) size(input_spatial_dimensions) = N - 2.
  • (C13) بالنظر إلى input_dimensions = [input_batch_dimension] + input_spatial_dimensions + [input_feature_dimension]:
    • is_unique(input_dimensions).
    • 0 <= input_dimensions < N.
  • (C14) dim(rhs, kernel_input_feature_dimension) = dim(lhs, input_feature_dimension) / feature_group_count.
  • (C15) dim(rhs, kernel_output_feature_dimension) % batch_group_count = 0.
  • (C16) dim(rhs, kernel_output_feature_dimension) % feature_group_count = 0.
  • (C17) size(kernel_spatial_dimensions) = N - 2.
  • (C18) نظرًا إلى kernel_dimensions = kernel_spatial_dimensions + [kernel_input_feature_dimension] + [kernel_output_feature_dimension]:
    • is_unique(kernel_dimensions).
    • 0 <= kernel_dimensions < N.
  • (C19) size(output_spatial_dimensions) = N - 2.
  • (C20) بالنظر إلى output_dimensions = [output_batch_dimension] + output_spatial_dimensions + [output_feature_dimension]:
    • is_unique(output_dimensions).
    • 0 <= output_dimensions < N.
  • (C21) 0 < feature_group_count.
  • (C22) 0 < batch_group_count.
  • (C23) feature_group_count = 1 or batch_group_count = 1.
  • (C24) size(precision_config) = 2.
  • (C25) يتم تعريف dim(result, result_dim) على النحو التالي:
    • dim(lhs, input_batch_dimension) / batch_group_count إذا result_dim = output_batch_dimension.
    • dim(rhs, kernel_output_feature_dimension) إذا result_dim = output_feature_dimension.
    • num_windows بخلاف ذلك، حيث:
    • output_spatial_dimensions[spatial_dim] = result_dim.
    • lhs_dim = input_spatial_dimensions[spatial_dim].
    • rhs_dim = kernel_spatial_dimensions[spatial_dim].
    • dilated_input_shape[lhs_dim] = dim(lhs, lhs_dim) = 0 ? 0 : (dim(lhs, lhs_dim) - 1) * lhs_dilation[spatial_dim] + 1.
    • padded_input_shape[lhs_dim] = padding[spatial_dim, 0] + dilated_input_shape[lhs_dim] + padding[spatial_dim, 1].
    • dilated_window_shape[lhs_dim] = dim(rhs, rhs_dim) = 0 ? 0 : (dim(rhs, rhs_dim) - 1) * rhs_dilation[spatial_dim] + 1.
    • is_empty_window[lhs_dim] = padded_input_shape[lhs_dim] = 0 || dilated_window_shape[lhs_dim] > padded_input_shape[lhs_dim].
    • num_windows = is_empty_window[lhs_dim] ? 0 : floor((padded_input_shape[lhs_dim] - dilated_window_shape[lhs_dim]) / window_strides[spatial_dim]) + 1.
  • (C26) rank(result) = N.
  • إذا كانت العملية تستخدم موتّرات غير كَمية:
    • (C27) element_type(lhs) = element_type(rhs) = element_type(result).
  • إذا كانت العملية تستخدم موتّرات كميّة:
    • (C28) is_quantized(lhs) = is_quantized(result) and is_quantized(rhs).
    • (C29) إذا كانت is_per_axis_quantized(rhs): ثم quantization_dimension(rhs) = kernel_output_feature_dimension.
    • (C30) إذا كانت is_per_axis_quantized(result)، إذًا quantization_dimension(result) = output_feature_dimension
    • إذا كانت is_quantized(lhs):
    • (C31) storage_type(lhs) = storage_type(rhs).
    • (C32) expressed_type(lhs) = expressed_type(rhs) = expressed_type(result).
    • (C33) إذا كانت is_per_tensor_quantized(rhs)، يتم عندها: is_per_tensor_quantized(result)
    • إذا كانت !is_quantized(lhs):
    • (C34) element_type(lhs) = expressed_type(rhs) = element_type(result).

أمثلة

// %lhs: [[
//        [
//          [1], [2], [5], [6]
//        ],
//        [
//          [3], [4], [7], [8]
//        ],
//        [
//          [10], [11], [14], [15]
//        ],
//        [
//          [12], [13], [16], [17]
//        ]
//      ]]
//
// %rhs: [
//        [[[1]], [[1]], [[1]]],
//        [[[1]], [[1]], [[1]]],
//        [[[1]], [[1]], [[1]]]
//       ]
%result = "stablehlo.convolution"(%lhs, %rhs) {
  window_strides = array<i64: 4, 4>,
  padding = dense<0> : tensor<2x2xi64>,
  lhs_dilation = array<i64: 2, 2>,
  rhs_dilation = array<i64: 1, 1>,
  window_reversal = array<i1: false, false>,
  // In the StableHLO dialect, dimension numbers are encoded via:
  // `[<input dimensions>]x[<kernel dimensions>]->[output dimensions]`.
  // "b" is batch dimension, "f" is feature dimension,
  // "i" is input feature dimension, "o" is output feature dimension,
  // "0/1/etc" are spatial dimensions.
  dimension_numbers = #stablehlo.conv<[b, 0, 1, f]x[0, 1, i, o]->[b, 0, 1, f]>,
  batch_group_count = 1 : i64,
  feature_group_count = 1 : i64,
  precision_config = [#stablehlo<precision DEFAULT>, #stablehlo<precision DEFAULT>]
} : (tensor<1x4x4x1xi64>, tensor<3x3x1x1xi64>) -> tensor<1x2x2x1xi64>
// %result: [[
//            [[10], [26]],
//            [[46], [62]]
//          ]]

مزيد من الأمثلة

جيب التمام

دلالات الألفاظ

لتنفيذ عملية جيب التمام من حيث العناصر في موتر operand وينتج عن ذلك متوتر result حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى الأعداد العشرية: cos من IEEE-754.
  • للأعداد المركّبة: جيب التمام المعقد.
  • بالنسبة إلى الأنواع الكَمية: dequantize_op_quantize(cosine, operand, type(result)).

مدخلات

التصنيف الاسم النوع القيود
(I1) operand مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(result).

أمثلة

// %operand: [
//            [0.0, 1.57079632],       // [0, pi/2]
//            [3.14159265, 4.71238898] // [pi, 3pi/2]
//           ]
%result = "stablehlo.cosine"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[1.0, 0.0], [-1.0, 0.0]]

مزيد من الأمثلة

count_leading_zeros

دلالات الألفاظ

تؤدي إلى إجراء العدد من حيث العناصر في عدد وحدات البت البادئة الصفرية في operand. متنسورة وينتج عنها متسابق result.

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتر لنوع العدد الصحيح (C1)

المُخرَجات

الاسم النوع القيود
result متوتر لنوع العدد الصحيح (C1)

القيود

  • (ج1) type(operand) = type(result).

أمثلة

// %operand: [[0, 1], [128, -1]]
%result = "stablehlo.count_leading_zeros"(%operand) : (tensor<2x2xi64>) -> tensor<2x2xi64>
// %result: [[64, 63], [56, 0]]

مزيد من الأمثلة

custom_call

دلالات الألفاظ

تتضمن عملية محددة للتنفيذ call_target_name والتي inputs وcalled_computations وينتج results. has_side_effect, قد يتم استخدام backend_config وapi_version لتوفير خيارات إضافية بيانات التعريف المحددة للتنفيذ.

في الوقت الحالي، تحتوي هذه العملية على مجموعة غير منظمة إلى حد ما من بيانات التعريف التي تعكس التطور العضوي لعملية نظيرتها في المحول البرمجي لـ XLA. نخطّط لتوحيد هذه البيانات الوصفية في المستقبل (#741)

مدخلات

التصنيف الاسم النوع
(I1) inputs العدد المتغير للقيم
(I2) call_target_name ثابت من النوع string
(I3) has_side_effect ثابت من النوع i1
(I4) backend_config ثابت من النوع string أو قاموس السمات
(I5) api_version ثابت من النوع si32
(I6) called_computations العدد المتنوع للثوابت من النوع string

المُخرَجات

الاسم النوع
results العدد المتغير للقيم

أمثلة

%results = "stablehlo.custom_call"(%input0) {
  call_target_name = "foo",
  has_side_effect = false,
  backend_config = {bar = 42 : i32},
  api_version = 4 : i32,
  called_computations = [@foo]
} : (tensor<f64>) -> tensor<f64>

قسمة

دلالات الألفاظ

لإجراء عملية قسمة من العناصر المقابلة في الصفيفتين lhs والقاسم rhs لنقاط القوة نحصل على متوتر result. حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى الأعداد الصحيحة: قسمة الأعداد الصحيحة التي تنتج القسمة الجبرية مع أي تم تجاهل الجزء الجزئي.
  • بالنسبة إلى الأعداد العشرية: division من IEEE-754.
  • بالنسبة إلى الأعداد المركّبة: القسمة المركّبة.
  • بالنسبة إلى الأنواع الكَمية:
    • dequantize_op_quantize(divide, lhs, rhs, type(result)).

مدخلات

التصنيف الاسم النوع القيود
(I1) lhs موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المتسابق الكمي لكل متسابق (C1)
(I2) rhs موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المتسابق الكمي لكل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المنزِّع الكمي لكل متسابق (C1)

القيود

  • (ج1) baseline_type(lhs) = baseline_type(rhs) = baseline_type(result).

أمثلة

// %lhs: [17.1, -17.1, 17.1, -17.1]
// %rhs: [3.0, 3.0, -3.0, -3.0]
%result = "stablehlo.divide"(%lhs, %rhs) : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
// %result: [5.66666651, -5.66666651, -5.66666651, 5.66666651]

مزيد من الأمثلة

dot_general

دلالات الألفاظ

لحساب قيمة المنتجات النقطية بين شرائح lhs وشرائح rhs، وينتج عن ذلك متوتر result

بشكل رسمي، result[result_index] = dot_product، حيث:

  • lhs_result_dimensions = [d for d in axes(lhs) and d not in lhs_batching_dimensions and d not in lhs_contracting_dimensions].
  • rhs_result_dimensions = [d for d in axes(rhs) and d not in rhs_batching_dimensions and d not in rhs_contracting_dimensions].
  • result_batching_index + result_lhs_index + result_rhs_index = result_index حيث size(result_batching_index) = size(lhs_batching_dimensions)، size(result_lhs_index) = size(lhs_result_dimensions) و size(result_rhs_index) = size(rhs_result_dimensions)
  • transposed_lhs = transpose(lhs, lhs_batching_dimensions + lhs_result_dimensions + lhs_contracting_dimensions).
  • transposed_lhs_slice = slice(transposed_lhs, result_batching_index + result_lhs_index + [:, ..., :]).
  • reshaped_lhs_slice = reshape(transposed_lhs_slice, dims(lhs, lhs_contracting_dimensions)).
  • transposed_rhs = transpose(rhs, rhs_batching_dimensions + rhs_result_dimensions + rhs_contracting_dimensions).
  • transposed_rhs_slice = slice(transposed_rhs, result_batching_index + result_rhs_index + [:, ..., :]).
  • reshaped_rhs_slice = reshape(transposed_rhs_slice, dims(rhs, rhs_contracting_dimensions)).
  • dot_product = reduce( inputs=[multiply(reshaped_lhs_slice, reshaped_rhs_slice)], init_values=[constant(0, element_type(result))], dimensions=range(size(lhs_contracting_dimensions)), body=lambda x, y: add(x, y))

بالنسبة إلى الأنواع المحدَّدة الكمية، يتم تنفيذ dequantize_op_quantize( lambda lhs, rhs: dot_general(lhs, rhs, lhs_batching_dimensions, rhs_batching_dimensions, lhs_contracting_dimensions, rhs_contracting_dimensions, precision_config), lhs, rhs, type(result)).

بالنسبة إلى الأنواع الكمية المختلطة، تحقّق قيمة hybrid_dequantize_then_op( lambda lhs, rhs: dot_general(lhs, rhs, lhs_batching_dimensions, rhs_batching_dimensions, lhs_contracting_dimensions, rhs_contracting_dimensions, precision_config), lhs, rhs).

يتحكّم precision_config في الموازنة بين السرعة والدقة العمليات الحسابية على الواجهات الخلفية للمسرِّع. يمكن أن يكون هذا أيًا مما يلي (في صفحة فإن دلالات قيم التعداد هذه غير محدّدة بشكل كافٍ، ولكننا تخطط لمعالجة هذا الأمر في #755):

  • DEFAULT: أسرع عملية حسابية، لكن التقريب الأقل دقة الرقم الأصلي.
  • HIGH: عملية حسابية أبطأ، لكنّها تقريبية أكثر دقة الرقم الأصلي.
  • HIGHEST: أبطأ عملية حسابية، ولكنها الأكثر دقة لتقريب الرقم الأصلي.

تحدّد السمة DotAlgorithm السمات الرئيسية للخوارزمية المستخدَمة لتنفيذ عملية النقطة، والتي تحدد أيضًا الدقة. إذا كانت تصنيف الخوارزمية ضبط الحقل، يجب أن تكون قيمة precision_config هي DEFAULT. DotAlgorithms ليس لها قيمة تلقائية، لأنّه يتم تنفيذ المَعلمات التلقائية محددة. وبناءً على ذلك، يمكن ضبط جميع حقول خوارزمية النقاط على None لتحديد خوارزمية النقاط الفارغة التي ستستخدم القيمة precision_config بدلاً من ذلك.

تتضمّن DotAlgorithm حقول ما يلي:

  • lhs_precision_type وrhs_precision_type، والدقة التي تلاحظها LHS يتم تقريب RHS للعملية إلى. تكون أنواع الدقة مستقلّة عن أنواع التخزين للمدخلات والمخرجات.
  • accumulation_type الدقة المستخدمة في التراكم.
  • lhs_component_count وrhs_component_count وnum_primitive_operations عندما نقوم بخوارزمية تفكيك LHS و/أو RHS إلى عدة مكونات ويقوم بتنفيذ العديد من "الأساسيات" العمليات النقطية على تلك القيم - عادةً لمحاكاة دقة أعلى (على سبيل المثال الاستفادة من نوع بيانات bfloat16 للذكاء الاصطناعي لإجراء عمليات حسابية عالية الدقة: bf16_6x tf32_3x، إلخ). بالنسبة للخوارزميات التي لا تحتوي على أي تفكيك، فإن هذه القيم يجب ضبطها على 1.
  • allow_imprecise_accumulation لتحديد ما إذا كان التجميع بدقة أقل أم لا مسموح به لبعض الخطوات (مثل CUBLASLT_MATMUL_DESC_FAST_ACCUM).

مثال على سمات DotAlgorithm:

// Inputs are casted to tf32, and then accumulated in f32:
{lhs_precision_type = tf32,
 rhs_precision_type = tf32,
 accumulation_type = f32,
 lhs_component_count = 1,
 rhs_component_count = 1,
 num_primitive_operations = 1,
 allow_imprecise_accumulation = false}


// bf16_6x: each input is decomposed to 3 bf16 components, then 6 dot operations are done on those components, and the result is accumulated in f32.
{lhs_precision_type = bf16,
 rhs_precision_type = bf16,
 accumulation_type = f32,
 lhs_component_count = 3,
 rhs_component_count = 3,
 num_primitive_operations = 6,
 allow_imprecise_accumulation = false}


// Inputs are (casted to) f8e5m2, and we accumulate in f32, but for some steps we may accumulate in lower precision.
{lhs_precision_type = f8e5m2,
 rhs_precision_type = f8e5m2,
 accumulation_type = f32,
 lhs_component_count = 1,
 rhs_component_count = 1,
 num_primitive_operations = 1,
 allow_imprecise_accumulation = true}

والأمر متروك لعمليات التنفيذ لتحديد المجموعات المتوافقة. ضِمن بشكل عام، لا يمكن ضمان توافُق كل خوارزمية مع كل خوارزمية نوع مسرِّعة البيانات من قِبل مستهلك StableHLO. إذا لم تكن خوارزمية معينة دعمها، فينبغي رفع الخطأ بدلاً من الرجوع إلى البديل. سيوفر التحقق من StableHLO أفضل جهد للتحقق، لمنع الخوارزميات غير المعروفة أنّها متوافقة مع أي جهاز.

الاطّلاع على xla_data.proto > Algorithm لبعض قيم الخوارزمية المتوافقة. تسجل التذكرة رقم 2483 الخطة لإنشاء مستند مركزي على الخوارزميات المتوافقة من خلال الخلفية.

مدخلات

التصنيف الاسم النوع القيود
(I1) lhs متوتّر أو مستنسر كمي لكلّ متسابق (C5-C6)، (C9-C10)، (C12-C14)، (C17-C18)، (C20)
(I2) rhs متوتر أو متنسّر كمي (C7-C10)، (C12-C20)
(I3) lhs_batching_dimensions ثابت التوتر ذو البعد الواحد من النوع si64 (C1)، (C3)، (C5)، (C9)، (C12)
(I4) rhs_batching_dimensions ثابت التوتر ذو البعد الواحد من النوع si64 (C1)، (C4)، (C7)، (C9)
(I5) lhs_contracting_dimensions ثابت التوتر ذو البعد الواحد من النوع si64 (C2)، (C3)، (C6)، (C10)
(I6) rhs_contracting_dimensions ثابت التوتر ذو البعد الواحد من النوع si64 (C2)، (C4)، (C8)، (C10)، (C16)
(I7) precision_config اختلاف في عدد التعدادات للقيم DEFAULT وHIGH وHIGHEST (C11)، (C21)
(I8) lhs_precision_type FloatType أو TensorFloat32 (C21)
(I9) rhs_precision_type FloatType أو TensorFloat32 (C21)
(I10) accumulation_type FloatType أو TensorFloat32 (C21)
(I11) lhs_component_count ثابت من النوع si32 (C21)، (C22)
(I12) rhs_component_count ثابت من النوع si32 (C21)، (C23)
(I13) num_primitive_operations ثابت من النوع si32 (C21)، (C24)
(I14) allow_imprecise_accumulation ثابت من النوع bool (C21)

المُخرَجات

الاسم النوع القيود
result متوتر أو متنسّر كمي (C12)، (C14)، (C18-C20)

القيود

  • (ج1) size(lhs_batching_dimensions) = size(rhs_batching_dimensions).
  • (C2) size(lhs_contracting_dimensions) = size(rhs_contracting_dimensions).
  • (C3) is_unique(lhs_batching_dimensions + lhs_contracting_dimensions):
  • (C4) is_unique(rhs_batching_dimensions + rhs_contracting_dimensions).
  • (C5) 0 <= lhs_batching_dimensions < rank(lhs).
  • (C6) 0 <= lhs_contracting_dimensions < rank(lhs).
  • (C7) 0 <= rhs_batching_dimensions < rank(rhs).
  • (C8) 0 <= rhs_contracting_dimensions < rank(rhs).
  • (C9) dim(lhs, lhs_batching_dimensions...) = dim(rhs, rhs_batching_dimensions...).
  • (C10) dim(lhs, lhs_contracting_dimensions...) = dim(rhs, rhs_contracting_dimensions...).
  • (C11) size(precision_config) = 2.
  • (C12) shape(result) = dim(lhs, lhs_batching_dimensions) + dim(lhs, lhs_result_dimensions) + dim(rhs, rhs_result_dimensions).
  • إذا كانت العملية تستخدم موتّرات غير كَمية:
    • (C13) element_type(lhs) = element_type(rhs).
  • إذا كانت العملية تستخدم موتّرات كميّة:
    • (C14) is_quantized(lhs) = is_quantized(result) and is_quantized(rhs).
    • (C15) zero_points(rhs) = 0.
    • (C16) إذا كانت is_per_axis_quantized(rhs)، إذًا quantization_dimension(rhs) ليس في rhs_contracting_dimensions.
    • إذا كانت is_quantized(lhs):
    • (C17) storage_type(lhs) = storage_type(rhs).
    • (C18) expressed_type(lhs) = expressed_type(rhs) = expressed_type(result).
    • (C19) إذا كانت is_per_tensor_quantized(rhs)، يتم عندها: is_per_tensor_quantized(result)
    • إذا كانت !is_quantized(lhs):
    • (C20) element_type(lhs) = expressed_type(rhs) = element_type(result).
  • إذا كانت !is_empty_algorithm(lhs_precision_type, rhs_precision_type, accumulation_type, lhs_component_count, rhs_component_count, num_primitive_operations allow_imprecise_accumulation):
    • (C21) precision_config... = DEFAULT.
    • (C22) 0 < lhs_component_count.
    • (C23) 0 < rhs_component_count.
    • (C24) 0 < num_primitive_operations.

أمثلة

// %lhs: [
//        [[1, 2],
//         [3, 4]],
//        [[5, 6],
//         [7, 8]]
//       ]
// %rhs: [
//        [[1, 0],
//         [0, 1]],
//        [[1, 0],
//         [0, 1]]
//       ]
%result = "stablehlo.dot_general"(%lhs, %rhs) {
  dot_dimension_numbers = #stablehlo.dot<
    lhs_batching_dimensions = [0],
    rhs_batching_dimensions = [0],
    lhs_contracting_dimensions = [2],
    rhs_contracting_dimensions = [1]
  >,
  precision_config = [#stablehlo<precision DEFAULT>, #stablehlo<precision DEFAULT>],
  algorithm = #stablehlo.dot_algorithm<
    lhs_precision_type = tf32,
    rhs_precision_type = tf32,
    accumulation_type = f32,
    lhs_component_count = 1,
    rhs_component_count = 1,
    num_primitive_operations = 1,
    allow_imprecise_accumulation = false
  >
} : (tensor<2x2x2xi64>, tensor<2x2x2xi64>) -> tensor<2x2x2xi64>
// %result: [
//           [[1, 2],
//            [3, 4]],
//           [[5, 6],
//            [7, 8]]
//          ]

مزيد من الأمثلة

dynamic_broadcast_in_dim

دلالات الألفاظ

هذه العملية مطابقة من الناحية الوظيفية broadcast_in_dim ولكن يتم تحديد شكل النتيجة ديناميكيًا عبر output_dimensions.

تقبل العملية أيضًا السمتين الاختياريتين known_expanding_dimensions وknown_non_expanding_dimensions للتعبير عن المعرفة الثابتة حول السلوك المتوسع للأبعاد. وفي حال عدم تحديد هذه السمة، من المفترض أن تكون جميع السمات قابلة للتوسيع.

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتر أو متنسّر كمي (C1-C2)، (C5-C6)، (C9)
(I2) output_dimensions متوتر ذو البعد الواحد لنوع العدد الصحيح (C7)
(I3) broadcast_dimensions متسّع ثابت البعد الأحادي لنوع العدد الصحيح (C2-C6)
(I4) known_expanding_dimensions متسّع ثابت البعد الأحادي لنوع العدد الصحيح (C8-C9)
(I5) known_non_expanding_dimensions متسّع ثابت البعد الأحادي لنوع العدد الصحيح (C8-C9)

المُخرَجات

الاسم النوع القيود
result متوتر أو متنسّر كمي (C1)، (C3)، (C5-C7)

القيود

  • (C1) element_type(result) يتم تقديمها من خلال:
    • element_type(operand)، إذا كانت !is_per_axis_quantized(operand).
    • element_type(operand) باستثناء أنّ quantization_dimension(operand)، وscales(operand)، وzero_points(operand) قد يختلفان عن quantization_dimension(result) وscales(result) وzero_points(result) أو الرد.
  • (C2) size(broadcast_dimensions) = rank(operand).
  • (C3) 0 <= broadcast_dimensions < rank(result):
  • (C4) is_unique(broadcast_dimensions).
  • (C5) لكل d في axes(operand):
    • dim(operand, d) = 1 أو
    • dim(operand, d) = dim(result, broadcast_dimensions[d]).
  • (C6) إذا كانت is_per_axis_quantized(result):
    • quantization_dimension(result) = broadcast_dimensions[quantization_dimension(operand)].
    • إذا كانت القيمة dim(operand, quantization_dimension(operand)) = 1، scales(result)[i] = scales(operand)[0] and zero_points(result)[i] = zero_points(operand)[0] for i in range(dim(result, quantization_dimension(result)))
  • (C7) size(output_dimensions) = rank(result).
  • (C8) is_unique(known_expanding_dimensions + known_non_expanding_dimensions).
  • (C9) 0 <= known_expanding_dimensions < rank(operand).
  • (C10) 0 <= known_non_expanding_dimensions < rank(operand).

أمثلة

// %operand: [
//            [1, 2, 3]
//           ]
%operand = stablehlo.constant dense<[[1, 2, 3]]> : tensor<1x3xi64>
%output_dimensions = stablehlo.constant dense<[2, 3, 2]> : tensor<3xi64>
%result = "stablehlo.dynamic_broadcast_in_dim"(%operand, %output_dimensions) {
  broadcast_dimensions = array<i64: 2, 1>,
  known_expanding_dimensions = array<i64: 0>,
  known_non_expanding_dimensions = array<i64: 1>
} : (tensor<1x3xi64>, tensor<3xi64>) -> tensor<2x3x2xi64>
// %result: [
//            [
//             [1, 1],
//             [2, 2],
//             [3, 3]
//            ],
//            [
//             [1, 1],
//             [2, 2],
//             [3, 3]
//            ]
//          ]

مزيد من الأمثلة

dynamic_conv

دلالات الألفاظ

هذه العملية مطابقة من الناحية الوظيفية الالتفاف هذه، ولكن يتم تحديد المساحة المتروكة ديناميكيًا عبر padding.

مدخلات

التصنيف الاسم النوع القيود
(I1) lhs متوتّر أو مستنسر كمي لكلّ متسابق (C1)، (C10-C11)، (C14) (C25)، (C26-C27)، (C30-C31)، (C33)
(I2) rhs متوتر أو متنسّر كمي (C1)، (C14-C16)، (C26-C28)، (C30-C33)
(I3) padding متين ثنائي الأبعاد لنوع العدد الصحيح (C4)
(I4) window_strides ثابت التوتر ذو البعد الواحد من النوع si64 (C2-C3)
(I5) lhs_dilation ثابت التوتر ذو البعد الواحد من النوع si64 (C5-C6)
(I6) rhs_dilation ثابت التوتر ذو البعد الواحد من النوع si64 (C7-C8)
(I7) window_reversal ثابت التوتر ذو البعد الواحد من النوع i1 (C9)
(I8) input_batch_dimension ثابت من النوع si64 (C10)، (C13)
(I9) input_feature_dimension ثابت من النوع si64 (C11)، (C13-C14)
(I10) input_spatial_dimensions ثابت التوتر ذو البعد الواحد من النوع si64 (C12)، (C13)
(I11) kernel_input_feature_dimension ثابت من النوع si64 (C14)، (C18)
(I12) kernel_output_feature_dimension ثابت من النوع si64 (C15-C16)، (C18)، (C28)
(I13) kernel_spatial_dimensions ثابت التوتر ذو البعد الواحد من النوع si64 (C17-C18)
(I14) output_batch_dimension ثابت من النوع si64 (C20)
(I15) output_feature_dimension ثابت من النوع si64 (C20)، (C29)
(I16) output_spatial_dimensions ثابت التوتر ذو البعد الواحد من النوع si64 (C19-C20)
(I17) feature_group_count ثابت من النوع si64 (C11)، (C14)، (C16)، (C21)، (C23)
(I18) batch_group_count ثابت من النوع si64 (C10)، (C15)، (C22)، (C23)
(I19) precision_config اختلاف في عدد التعدادات للقيم DEFAULT وHIGH وHIGHEST (C24)

المُخرَجات

الاسم النوع القيود
result متوتر أو متنسّر كمي (C25-C27)، (C29)، (C31-C33)

القيود

  • (ج1) N = rank(lhs) = rank(rhs).
  • (C2) size(window_strides) = N - 2.
  • (C3) 0 < window_strides:
  • (C4) shape(padding) = [N - 2, 2].
  • (C5) size(lhs_dilation) = N - 2.
  • (C6) 0 < lhs_dilation.
  • (C7) size(rhs_dilation) = N - 2.
  • (C8) 0 < rhs_dilation.
  • (C9) size(window_reversal) = N - 2.
  • (C10) dim(lhs, input_batch_dimension) % batch_group_count = 0.
  • (C11) dim(lhs, input_feature_dimension) % feature_group_count = 0.
  • (C12) size(input_spatial_dimensions) = N - 2.
  • (C13) بالنظر إلى input_dimensions = [input_batch_dimension] + input_spatial_dimensions + [input_feature_dimension]:
    • is_unique(input_dimensions).
    • 0 <= input_dimensions < N.
  • (C14) dim(rhs, kernel_input_feature_dimension) = dim(lhs, input_feature_dimension) / feature_group_count.
  • (C15) dim(rhs, kernel_output_feature_dimension) % batch_group_count = 0.
  • (C16) dim(rhs, kernel_output_feature_dimension) % feature_group_count = 0.
  • (C17) size(kernel_spatial_dimensions) = N - 2.
  • (C18) نظرًا إلى kernel_dimensions = kernel_spatial_dimensions + [kernel_input_feature_dimension] + [kernel_output_feature_dimension]:
    • is_unique(kernel_dimensions).
    • 0 <= kernel_dimensions < N.
  • (C19) size(output_spatial_dimensions) = N - 2.
  • (C20) بالنظر إلى output_dimensions = [output_batch_dimension] + output_spatial_dimensions + [output_feature_dimension]:
    • is_unique(output_dimensions).
    • 0 <= output_dimensions < N.
  • (C21) 0 < feature_group_count.
  • (C22) 0 < batch_group_count.
  • (C23) feature_group_count = 1 or batch_group_count = 1.
  • (C24) size(precision_config) = 2.
  • (C25) يتم تعريف dim(result, result_dim) على النحو التالي:
    • dim(lhs, input_batch_dimension) / batch_group_count إذا result_dim = output_batch_dimension.
    • dim(rhs, kernel_output_feature_dimension) إذا result_dim = output_feature_dimension.
    • num_windows بخلاف ذلك، حيث:
    • output_spatial_dimensions[spatial_dim] = result_dim.
    • lhs_dim = input_spatial_dimensions[spatial_dim].
    • rhs_dim = kernel_spatial_dimensions[spatial_dim].
    • dilated_input_shape[lhs_dim] = dim(lhs, lhs_dim) = 0 ? 0 : (dim(lhs, lhs_dim) - 1) * lhs_dilation[spatial_dim] + 1.
    • padded_input_shape[lhs_dim] = padding[spatial_dim, 0] + dilated_input_shape[lhs_dim] + padding[spatial_dim, 1].
    • dilated_window_shape[lhs_dim] = dim(rhs, rhs_dim) = 0 ? 0 : (dim(rhs, rhs_dim) - 1) * rhs_dilation[spatial_dim] + 1.
    • is_empty_window[lhs_dim] = padded_input_shape[lhs_dim] = 0 || dilated_window_shape[lhs_dim] > padded_input_shape[lhs_dim].
    • num_windows = is_empty_window[lhs_dim] ? 0 : floor((padded_input_shape[lhs_dim] - dilated_window_shape[lhs_dim]) / window_strides[spatial_dim]) + 1.
  • (C26) rank(result) = N.
  • إذا كانت العملية تستخدم موتّرات غير كَمية:
    • (C27) element_type(lhs) = element_type(rhs) = element_type(result).
  • إذا كانت العملية تستخدم موتّرات كميّة:
    • (C28) is_quantized(lhs) = is_quantized(result) and is_quantized(rhs).
    • (C29) إذا كانت is_per_axis_quantized(rhs): ثم quantization_dimension(rhs) = kernel_output_feature_dimension.
    • (C30) إذا كانت is_per_axis_quantized(result)، إذًا quantization_dimension(result) = output_feature_dimension
    • إذا كانت is_quantized(lhs):
    • (C31) storage_type(lhs) = storage_type(rhs).
    • (C32) expressed_type(lhs) = expressed_type(rhs) = expressed_type(result).
    • (C33) إذا كانت is_per_tensor_quantized(rhs)، يتم عندها: is_per_tensor_quantized(result)
    • إذا كانت !is_quantized(lhs):
    • (C34) element_type(lhs) = expressed_type(rhs) = element_type(result).

أمثلة

// %lhs: [[
//        [[1], [2], [5], [6]],
//        [[3], [4], [7], [8]],
//        [[10], [11], [14], [15]],
//        [[12], [13], [16], [17]]
//      ]]
//
// %rhs: [
//         [[[1]], [[1]], [[1]]],
//         [[[1]], [[1]], [[1]]],
//         [[[1]], [[1]], [[1]]]
//        ]
// %padding: [[1, 1],
//            [1, 1]]
%result = "stablehlo.dynamic_conv"(%lhs, %rhs, %padding) {
  window_strides = array<i64: 4, 4>,
  lhs_dilation = array<i64: 2, 2>,
  rhs_dilation = array<i64: 1, 1>,
  window_reversal = array<i1: false, false>,
  dimension_numbers = #stablehlo.conv<raw
    input_batch_dimension = 0,
    input_feature_dimension = 3,
    input_spatial_dimensions = [0, 1],
    kernel_input_feature_dimension = 2,
    kernel_output_feature_dimension = 3,
    kernel_spatial_dimensions = [0, 1],
    output_batch_dimension = 0,
    output_feature_dimension = 3,
    output_spatial_dimensions = [1, 2]
  >,
  feature_group_count = 1 : i64,
  batch_group_count = 1 : i64,
  precision_config = [#stablehlo<precision DEFAULT>, #stablehlo<precision DEFAULT>]
} : (tensor<1x4x4x1xi64>, tensor<3x3x1x1xi64>, tensor<2x2xi64>) -> tensor<1x2x2x1xi64>
// %result: [[
//            [[1], [5]],
//            [[10], [14]]
//          ]]

مزيد من الأمثلة

dynamic_gather

دلالات الألفاظ

هذه العملية مطابقة من الناحية الوظيفية جمع أو مع تحديد slice_sizes ديناميكيًا كقيمة.

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتّر أو مستنسر كمي لكلّ متسابق (C1)، (C7)، (C10-C12)، (C14)
(I2) start_indices متوتر لنوع العدد الصحيح (C2)، (C3)، (C13)
(I3) slice_sizes متوتر ذو البعد الواحد لنوع العدد الصحيح (C8)، (C11-C13)
(I4) offset_dims ثابت التوتر ذو البعد الواحد من النوع si64 (C1)، (C4-C5)، (C13)
(I5) collapsed_slice_dims ثابت التوتر ذو البعد الواحد من النوع si64 (C1)، (C6-C8)، (C13)
(I6) start_index_map ثابت التوتر ذو البعد الواحد من النوع si64 (C3)، (C9)، (C10)
(I7) index_vector_dim ثابت من النوع si64 (C2)، (C3)، (C13)
(I8) indices_are_sorted ثابت من النوع i1

المُخرَجات

الاسم النوع القيود
result متوتّر أو مستنسر كمي لكلّ متسابق (C5)، (C13-C14)

القيود

  • (ج1) rank(operand) = size(offset_dims) + size(collapsed_slice_dims).
  • (C2) 0 <= index_vector_dim <= rank(start_indices).
  • (C3) size(start_index_map) = index_vector_dim < rank(start_indices) ? dim(start_indices, index_vector_dim) : 1:
  • (C4) is_unique(offset_dims) and is_sorted(offset_dims).
  • (C5) 0 <= offset_dims < rank(result).
  • (C6) is_unique(collapsed_slice_dims) and is_sorted(collapsed_slice_dims).
  • (C7) 0 <= collapsed_slice_dims < rank(operand).
  • (C8) slice_sizes[collapsed_slice_dims...] <= 1.
  • (C9) is_unique(start_index_map).
  • (C10) 0 <= start_index_map < rank(operand).
  • (C11) size(slice_sizes) = rank(operand).
  • (C12) 0 <= slice_sizes <= shape(operand).
  • (C13) shape(result) = combine(batch_dim_sizes, offset_dim_sizes) حيث:
    • batch_dim_sizes = shape(start_indices) باستثناء أنّ حجم البُعد من start_indices بما يتوافق مع index_vector_dim غير متضمنة.
    • offset_dim_sizes = shape(slice_sizes) باستثناء أنّ أحجام السمات في slice_sizes بما يتوافق مع collapsed_slice_dims.
    • يضع combine batch_dim_sizes في المحاور المقابلة لـ batch_dims offset_dim_sizes في المحاور المقابلة لـ offset_dims.
  • (C14) element_type(operand) = element_type(result).

أمثلة

// %operand: [
//            [[1, 2], [3, 4], [5, 6], [7, 8]],
//            [[9, 10],[11, 12], [13, 14], [15, 16]],
//            [[17, 18], [19, 20], [21, 22], [23, 24]]
//           ]
// %start_indices: [
//                  [[0, 0], [1, 0], [2, 1]],
//                  [[0, 1], [1, 1], [0, 2]]
//                 ]
// %slize_sizes: [1, 2, 2]
%result = "stablehlo.dynamic_gather"(%operand, %start_indices, %slize_sizes) {
  dimension_numbers = #stablehlo.gather<
    offset_dims = [2, 3],
    collapsed_slice_dims = [0],
    start_index_map = [1, 0],
    index_vector_dim = 2>,
  indices_are_sorted = false
} : (tensor<3x4x2xi64>, tensor<2x3x2xi64>, tensor<3xi64>) -> tensor<2x3x2x2xi64>
// %result: [
//            [
//              [[1, 2], [3, 4]],
//              [[3, 4], [5, 6]],
//              [[13, 14], [15, 16]]
//            ],
//            [
//              [[9, 10], [11, 12]],
//              [[11, 12], [13, 14]],
//              [[17, 18], [19, 20]]
//            ]
//          ]

مزيد من الأمثلة

dynamic_iota

دلالات الألفاظ

هذه العملية مطابقة من الناحية الوظيفية يوتا ولكن يتم تحديد شكل النتيجة ديناميكيًا عبر output_shape.

مدخلات

التصنيف الاسم النوع القيود
(I1) output_shape متوتر ذو البعد الواحد لنوع العدد الصحيح (C1)، (C2)
(I2) iota_dimension si64 (C1)

المُخرَجات

الاسم النوع القيود
result موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المنزِّع الكمي لكل متسابق (C2)

القيود

  • (ج1) 0 <= iota_dimension < size(output_shape).
  • (C2) rank(result) = size(output_shape).

أمثلة

%output_shape = stablehlo.constant dense<[4, 5]> : tensor<2xi64>
%result = "stablehlo.dynamic_iota"(%output_shape) {
  iota_dimension = 0 : i64
} : (tensor<2xi64>) -> tensor<4x5xi64>
// %result: [
//           [0, 0, 0, 0, 0],
//           [1, 1, 1, 1, 1],
//           [2, 2, 2, 2, 2],
//           [3, 3, 3, 3, 3]
//          ]

مزيد من الأمثلة

dynamic_pad

دلالات الألفاظ

هذه العملية مطابقة من الناحية الوظيفية اللوحة هذا، ولكن مع edge_padding_low وedge_padding_high وinterior_padding المحددة ديناميكيًا كقيم.

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتّر أو مستنسر كمي لكلّ متسابق (C1)، (C2)، (C4)
(I2) padding_value متسّع 0 بُعدي أو متنسورة كمّية بكل متسابق (C1)
(I3) edge_padding_low متوتر ذو البعد الواحد لنوع العدد الصحيح (C1)، (C4)
(I4) edge_padding_high متوتر ذو البعد الواحد لنوع العدد الصحيح (C1)، (C4)
(I5) interior_padding متوتر ذو البعد الواحد لنوع العدد الصحيح (C2-C4)

المُخرَجات

الاسم النوع القيود
result متوتّر أو مستنسر كمي لكلّ متسابق (C3-C6)

القيود

  • (ج1) element_type(operand) = element_type(padding_value) = element_type(result).
  • (C2) size(edge_padding_low) = size(edge_padding_high) = size(interior_padding) = rank(operand).
  • (C3) 0 <= interior_padding:
  • (C4) shape(result) = shape(operand) + edge_padding_low + max(shape(operand) - 1, 0) * interior_padding + edge_padding_high.

أمثلة

// %operand: [
//            [1, 2, 3],
//            [4, 5, 6]
//           ]
// %padding_value: 0
// %edge_padding_low: [0, 1]
// %edge_padding_high: [2, 1]
// %interior_padding: [1, 2]
%result = "stablehlo.dynamic_pad"(%operand, %padding_value,
  %edge_padding_low, %edge_padding_high, %interior_padding
) : (tensor<2x3xi64>, tensor<i64>, tensor<2xi64>, tensor<2xi64>, tensor<2xi64>) -> tensor<5x9xi64>
// %result: [
//           [0, 1, 0, 0, 2, 0, 0, 3, 0],
//           [0, 0, 0, 0, 0, 0, 0, 0, 0],
//           [0, 4, 0, 0, 5, 0, 0, 6, 0],
//           [0, 0, 0, 0, 0, 0, 0, 0, 0],
//           [0, 0, 0, 0, 0, 0, 0, 0, 0]
//          ]

مزيد من الأمثلة

dynamic_reshape

دلالات الألفاظ

هذه العملية مطابقة من الناحية الوظيفية إعادة تشكيل ولكن يتم تحديد شكل النتيجة ديناميكيًا عبر output_shape.

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتر أو متنسّر كمي (C1-C3)
(I2) output_shape متوتر ذو البعد الواحد لنوع العدد الصحيح (C4)

المُخرَجات

الاسم النوع القيود
result متوتر أو متنسّر كمي (C1-C4)

القيود

  • (C1) element_type(result) يتم تقديمها من خلال:
    • element_type(operand)، إذا كانت !is_per_axis_quantized(operand).
    • element_type(operand) باستثناء أنّ quantization_dimension(operand) قد تختلف السمة quantization_dimension(result) في الحالات الأخرى.
  • (C2) size(operand) = size(result).
  • (C3) إذا كانت is_per_axis_quantized(operand):
    • reduce(dims(operand, [0, 1, ..., quantization_dimension(operand) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y) = reduce(dims(result, [0, 1, ..., quantization_dimension(result) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y).
    • dim(operand, quantization_dimension(operand)) = dim(result, quantization_dimension(result)).
    • reduce(dims(operand, [quantization_dimension(operand) + 1, ..., rank(operand) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y) = reduce(dims(result, [quantization_dimension(result) + 1, ..., rank(result) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y).
  • (C4) size(output_shape) = rank(result).

أمثلة

// %operand: [[1, 2, 3], [4, 5, 6]]
// %output_shape: [3, 2]
%result = "stablehlo.dynamic_reshape"(%operand, %output_shape) : (tensor<2x3xi64>, tensor<2xi64>) -> tensor<3x2xi64>
// %result: [[1, 2], [3, 4], [5, 6]]

مزيد من الأمثلة

dynamic_slice

دلالات الألفاظ

لاستخراج شريحة من operand باستخدام فهارس البدء المحسوبة ديناميكيًا وينتج موتر result. يحتوي start_indices على مؤشرات البداية الخاصة بـ الشريحة لكل بُعد خاضع للتعديل المحتمل، وslice_sizes تحتوي على أحجام الشريحة لكل بُعد. بشكل أكثر رسمية، result[result_index] = operand[operand_index] حيث:

  • adjusted_start_indices = clamp(0, start_indices, shape(operand) - slice_sizes).
  • operand_index = adjusted_start_indices + result_index.

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتّر أو مستنسر كمي لكلّ متسابق (C1)، (C2)، (C4)
(I2) start_indices العدد المتنوع للعشرات ذوات الأبعاد الصفرية لنوع الأعداد الصحيحة (C2)، (C3)
(I3) slice_sizes ثابت التوتر ذو البعد الواحد من النوع si64 (C2)، (C4)، (C5)

المُخرَجات

الاسم النوع القيود
result متوتّر أو مستنسر كمي لكلّ متسابق (C1)، (C5)

القيود

  • (ج1) element_type(operand) = element_type(result).
  • (C2) size(start_indices) = size(slice_sizes) = rank(operand).
  • (C3) same(type(start_indices...)):
  • (C4) 0 <= slice_sizes <= shape(operand).
  • (C5) shape(result) = slice_sizes.

أمثلة

// %operand: [
//            [0, 0, 1, 1],
//            [0, 0, 1, 1],
//            [0, 0, 0, 0],
//            [0, 0, 0, 0]
//           ]
// %start_indices0: -1
// %start_indices1: 3
%result = "stablehlo.dynamic_slice"(%operand, %start_indices0, %start_indices1) {
  slice_sizes = array<i64: 2, 2>
} : (tensor<4x4xi32>, tensor<i64>, tensor<i64>) -> tensor<2x2xi32>
// %result: [
//           [1, 1],
//           [1, 1]
//          ]

مزيد من الأمثلة

dynamic_update_slice

دلالات الألفاظ

يتم إنشاء متسابق result الذي يساوي سينسور operand باستثناء يتم تعديل الشريحة التي تبدأ من start_indices بالقيم في update. وتعريف result[result_index] من الناحية الرسمية على النحو التالي:

  • update[update_index] إذا 0 <= update_index < shape(update) حيث:
    • adjusted_start_indices = clamp(0, start_indices, shape(operand) - shape(update)).
    • update_index = result_index - adjusted_start_indices.
  • operand[result_index] بخلاف ذلك.

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتّر أو مستنسر كمي لكلّ متسابق (C1-C4)، (C6)
(I2) update متوتّر أو مستنسر كمي لكلّ متسابق (C2)، (C3)، (C6)
(I3) start_indices العدد المتنوع للعشرات ذوات الأبعاد الصفرية لنوع الأعداد الصحيحة (C4)، (C5)

المُخرَجات

الاسم النوع القيود
result متوتّر أو مستنسر كمي لكلّ متسابق (C1)

القيود

  • (ج1) type(operand) = type(result).
  • (C2) element_type(update) = element_type(operand).
  • (C3) rank(update) = rank(operand):
  • (C4) size(start_indices) = rank(operand).
  • (C5) same(type(start_indices...)).
  • (C6) 0 <= shape(update) <= shape(operand).

أمثلة

// %operand: [
//            [1, 1, 0, 0],
//            [1, 1, 0, 0],
//            [1, 1, 1, 1],
//            [1, 1, 1, 1]
//           ]
// %update: [
//           [1, 1],
//           [1, 1]
//          ]
// %start_indices0: -1
// %start_indices1: 3
%result = "stablehlo.dynamic_update_slice"(%operand, %update, %start_indices0, %start_indices1)
  : (tensor<4x4xi32>, tensor<2x2xi32>, tensor<i64>, tensor<i64>) -> tensor<4x4xi32>
// %result: [
//           [1, 1, 1, 1],
//           [1, 1, 1, 1],
//           [1, 1, 1, 1],
//           [1, 1, 1, 1]
//          ]

مزيد من الأمثلة

دالات أسية

دلالات الألفاظ

لتنفيذ عملية أسّية من ناحية العناصر على موتر operand وينتج عن ذلك متوتر result حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى الأعداد العشرية: exp من IEEE-754.
  • للأعداد المركّبة: أُس مركَّب.
  • بالنسبة إلى الأنواع الكَمية: dequantize_op_quantize(exponential, operand, type(result))

مدخلات

التصنيف الاسم النوع القيود
(I1) operand مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(result).

أمثلة

// %operand: [[0.0, 1.0], [2.0, 3.0]]
%result = "stablehlo.exponential"(%operand) : (tensor<2x2xf64>) -> tensor<2x2xf64>
// %result: [[1.0, 2.7182818284590451], [7.3890560989306504, 20.085536923187668]]

مزيد من الأمثلة

exponential_minus_one

دلالات الألفاظ

لتنفيذ أسّي العناصر من ناحية العناصر ناقص عملية واحدة على متسّع operand نحصل على موتّر result. حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى الأعداد العشرية: expm1 من IEEE-754.
  • بالنسبة إلى الأعداد المركّبة: يتم استخدام الأس المركّب ناقص واحد.
  • بالنسبة إلى الأنواع الكَمية: dequantize_op_quantize(exponential_minus_one, operand, type(result))

مدخلات

التصنيف الاسم النوع القيود
(I1) operand مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(result).

أمثلة

// %operand: [0.0, 1.0]
%result = "stablehlo.exponential_minus_one"(%operand) : (tensor<2xf64>) -> tensor<2xf64>
// %result: [0.0, 1.71828187]

مزيد من الأمثلة

ضريبة القيمة المضافة

دلالات الألفاظ

تؤدي إلى تحويلات فورييه الأمامية والعكسية للتوصل إلى مفاهيم حقيقية ومعقدة المدخلات والمخرجات.

fft_type هو واحد مما يلي:

  • FFT: إعادة توجيه "واجهة سريعة معقّدة إلى معقّدة" (FFT)
  • IFFT: وقت الاستجابة السريع المعكوس والمعقد إلى المعقد
  • RFFT: إعادة توجيه وقت الاستجابة السريعة إذا كان واقعيًا إلى معقد
  • IRFFT: مقياس FFT غير حقيقي إلى معقّد (أي أنّه يعتبر معقّدًا وعريضًا حقيقيًا)

وبشكل أكثر رسمية، بناءً على الدالة fft التي تستخدم موتّرات أحادية البعد أنواع معقدة كمدخلات، ينتج عنها متسابقات أحادية البعد من نفس الأنواع ويحسب تحويل فورييه المنفصل:

بالنسبة لـ fft_type = FFT، يتم تعريف result على أنه النتيجة النهائية لسلسلة من L العمليات الحسابية حيث يكون L = size(fft_length). على سبيل المثال، بالنسبة إلى L = 3:

  • result1[i0, ..., :] = fft(operand[i0, ..., :]).
  • result2[i0, ..., :, iR-1] = fft(result1[i0, ..., :, iR-1]).
  • result[i0, ..., :, iR-2, iR-1] = fft(result2[i0, ..., :, iR-2, iR-1]).

علاوة على ذلك، ونظرًا لأن الدالة ifft التي لها نوع التوقيع ذاته تحسب معكوس fft:

بالنسبة إلى fft_type = IFFT، يتم تعريف result على أنه عكس العمليات الحسابية مقابل fft_type = FFT. على سبيل المثال، بالنسبة إلى L = 3:

  • result1[i0, ..., :, iR-2, iR-1] = ifft(operand[i0, ..., :, iR-2, iR-1]).
  • result2[i0, ..., :, iR-1] = ifft(result1[i0, ..., :, iR-1]).
  • result[i0, ..., :] = ifft(result2[i0, ..., :]).

وعلاوة على ذلك، من خلال الدالة rfft التي تستخدم العشرات الأحادية البعد أنواع النقاط العائمة، ينتج عنها متسابقات أحادية البُعد للأنواع المعقدة نفس دلالات النقطة العائمة وتعمل على النحو التالي:

  • مكان rfft(real_operand) = truncated_result
  • complex_operand... = (real_operand..., 0.0).
  • complex_result = fft(complex_operand).
  • truncated_result = complex_result[:(rank(complex_result) / 2 + 1)].

(عندما يتم حساب تحويل فورييه المنفصل للمعاملات الحقيقية، فإن أول عناصر N/2 + 1 في النتيجة تحدد باقي النتيجة بوضوح، وبالتالي يتم اقتطاع نتيجة rfft لتجنب حساب العناصر المتكررة).

بالنسبة لـ fft_type = RFFT، يتم تعريف result على أنه النتيجة النهائية لسلسلة من L العمليات الحسابية حيث يكون L = size(fft_length). على سبيل المثال، بالنسبة إلى L = 3:

  • result1[i0, ..., :] = rfft(operand[i0, ..., :]).
  • result2[i0, ..., :, iR-1] = fft(result1[i0, ..., :, iR-1]).
  • result[i0, ..., :, iR-2, iR-1] = fft(result2[i0, ..., :, iR-2, iR-1]).

وأخيرًا، ضع في الاعتبار الدالة irfft التي لها نفس نوع التوقيع تحسب معكوس rfft:

بالنسبة إلى fft_type = IRFFT، يتم تعريف result على أنه عكس العمليات الحسابية مقابل fft_type = RFFT. على سبيل المثال، بالنسبة إلى L = 3:

  • result1[i0, ..., :, iR-2, iR-1] = ifft(operand[i0, ..., :, iR-2, iR-1]).
  • result2[i0, ..., :, iR-1] = ifft(result1[i0, ..., :, iR-1]).
  • result[i0, ..., :] = irfft(result2[i0, ..., :]).

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتر من النقطة العائمة أو نوع معقد (C1)، (C2)، (C4)، (C5)
(I2) fft_type تعداد FFT وIFFT وRFFT وIRFFT (C2)، (C5)
(I3) fft_length ثابت التوتر ذو البعد الواحد من النوع si64 (C1)، (C3)، (C4)

المُخرَجات

الاسم النوع القيود
result متوتر من النقطة العائمة أو نوع معقد (C2)، (C4)، (C5)

القيود

  • (ج1) size(fft_length) <= rank(operand).
  • (C2) تختلف العلاقة بين نوعَي العناصر operand وresult:
    • إذا كانت fft_type = FFT وelement_type(operand) وelement_type(result) لها نفس النوع المعقد.
    • إذا كانت fft_type = IFFT وelement_type(operand) وelement_type(result) لها نفس النوع المعقد.
    • إذا كان fft_type = RFFT، يكون element_type(operand) نوع نقطة عائمة element_type(result) هو نوع معقد من نفس النقطة العائمة الدلالة.
    • إذا كان fft_type = IRFFT، element_type(operand) نوعًا معقدًا element_type(result) هو نوع نقطة عائمة لنفس النقطة العائمة الدلالة.
  • (C3) 1 <= size(fft_length) <= 3:
  • (C4) إذا كان بين operand وresult، يكون هناك متسابق real نوع النقطة العائمة، ثم shape(real)[-size(fft_length):] = fft_length.
  • (C5) shape(result) = shape(operand) باستثناء:
    • إذا كانت fft_type = RFFT، dim(result, -1) = dim(operand, -1) = 0 ? 0 : dim(operand, -1) / 2 + 1
    • إذا كانت fft_type = IRFFT، dim(operand, -1) = dim(result, -1) = 0 ? 0 : dim(result, -1) / 2 + 1

أمثلة

// %operand: [(1.0, 0.0), (0.0, 0.0), (0.0, 0.0), (0.0, 0.0)]
%result = "stablehlo.fft"(%operand) {
  fft_type = #stablehlo<fft_type FFT>,
  fft_length = array<i64: 4>
} : (tensor<4xcomplex<f32>>) -> tensor<4xcomplex<f32>>
// %result: [(1.0, 0.0), (1.0, 0.0), (1.0, 0.0), (1.0, 0.0)]

floor

دلالات الألفاظ

يؤدي هذا الإجراء إلى تنفيذ دالة مناسبة من ناحية العناصر لمعرِف operand وينتج موجِّه result. تنفيذ عملية roundToIntegralTowardNegative من IEEE-754 المواصفات. بالنسبة للأنواع الكَمية، تنفذ dequantize_op_quantize(floor, operand, type(result))

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(result).

أمثلة

// %operand: [-0.8166, -0.2530, 0.2530, 0.8166, 2.0]
%result = "stablehlo.floor"(%operand) : (tensor<5xf32>) -> tensor<5xf32>
// %result: [-1.0, -1.0, 0.0, 0.0, 2.0]

مزيد من الأمثلة

جمع

دلالات الألفاظ

لجمع الشرائح من متسابق operand من الإزاحة المحدّدة في start_indices وينتج متسابق result.

يوضّح المخطّط التالي كيفية ارتباط العناصر في result بالعناصر في operand باستخدام مثال ملموس. ويختار الرسم البياني بعض الأمثلة result. المؤشرات ويشرح بالتفصيل مؤشرات operand التي تتوافق معها.

جمع

بشكل رسمي، result[result_index] = operand[operand_index] حيث:

  • batch_dims = [d for d in axes(result) and d not in offset_dims].
  • batch_index = result_index[batch_dims...].
  • تعريف "start_index" على أنّه:
    • start_indices[bi0, ..., :, ..., biN] حيث bi عبارة عن عناصر فردية في يتم إدراج batch_index و: في فهرس index_vector_dim، إذا index_vector_dim < rank(start_indices)
    • [start_indices[batch_index]] بخلاف ذلك.
  • بالنسبة إلى d_operand في axes(operand)،
    • full_start_index[d_operand] = clamp(start_index[d_start], 0, dim(operand, d_operand) - slice_sizes[d_operand]) إذا كانت القيمة هي d_operand = start_index_map[d_start].
    • full_start_index[d_operand] = 0 بخلاف ذلك.
  • بالنسبة إلى d_operand في axes(operand)،
    • full_batching_index[d_operand] = batch_index[d_start - (d_start < index_vector_dim ? 0 : 1)] إذا كان d_operand = operand_batching_dims[i_batching] و d_start = start_indices_batching_dims[i_batching]
    • full_batching_index[d_operand] = 0 بخلاف ذلك.
  • offset_index = result_index[offset_dims...].
  • full_offset_index = [oi0, ..., 0, ..., oiN] حيث يكون oi فرديًا العناصر في offset_index، و0 يتم إدراجها في الفهارس من collapsed_slice_dims وoperand_batching_dims.
  • operand_index = full_start_index + full_batching_index + full_offset_index

إذا كانت indices_are_sorted هي true، يمكن لعملية التنفيذ أن تفترض أنّ يتم ترتيب start_indices حسب start_index_map، وإلا غير محدد. بشكل رسمي، لجميع i1 < i2 من indices(result)، full_start_index(i1) <= full_start_index(i2)

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتّر أو مستنسر كمي لكلّ متسابق (C1)، (C8)، (C11)، (C17)، (C19-C21)، (C23)
(I2) start_indices متوتر لنوع العدد الصحيح (C2-C3)، (C14)، (C17)، (C22)
(I3) offset_dims ثابت التوتر ذو البعد الواحد من النوع si64 (C1)، (C4-C5)، (C22)
(I4) collapsed_slice_dims ثابت التوتر ذو البعد الواحد من النوع si64 (C1)، (C6-C9)، (C22)
(I5) operand_batching_dims ثابت التوتر ذو البعد الواحد من النوع si64 (C1)، (C6)، (C10-C12)، (C16-C18)، (C22)
(I6) start_indices_batching_dims ثابت التوتر ذو البعد الواحد من النوع si64 (C13-C17)
(I7) start_index_map ثابت التوتر ذو البعد الواحد من النوع si64 (C3)، (C18-C19)
(I8) index_vector_dim ثابت من النوع si64 (C2-C3)، (C15)، (C22)
(I9) slice_sizes ثابت التوتر ذو البعد الواحد من النوع si64 (C9)، (C12)، (C20-C22)
(I10) indices_are_sorted ثابت من النوع i1

المُخرَجات

الاسم النوع القيود
result متوتّر أو مستنسر كمي لكلّ متسابق (C5)، (C22-C23)

القيود

  • (ج1) rank(operand) = size(offset_dims) + size(collapsed_slice_dims) + size(operand_batching_dims).
  • (C2) 0 <= index_vector_dim <= rank(start_indices).
  • (C3) size(start_index_map) = index_vector_dim < rank(start_indices) ? dim(start_indices, index_vector_dim) : 1:
  • (C4) is_unique(offset_dims) and is_sorted(offset_dims).
  • (C5) 0 <= offset_dims < rank(result).
  • (C6) is_unique(concatenate(collapsed_slice_dims, operand_batching_dims))
  • (C7) is_sorted(collapsed_slice_dims).
  • (C8) 0 <= collapsed_slice_dims < rank(operand).
  • (C9) slice_sizes[collapsed_slice_dims...] <= 1.
  • (C10) is_sorted(operand_batching_dims).
  • (C11) 0 <= operand_batching_dims < rank(operand).
  • (C12) slice_sizes[operand_batching_dims...] <= 1.
  • (C13) is_unique(start_indices_batching_dims).
  • (C14) 0 <= start_indices_batching_dims < rank(start_indices).
  • (C15) index_vector_dim not in start_indices_batching_dims.
  • (C16) size(operand_batching_dims) == size(start_indices_batching_dims).
  • (C17) dim(operand, operand_batching_dims...) = dim(start_indices, start_indices_batching_dims...).
  • (C18) is_unique(concatenate(start_index_map, operand_batching_dims)).
  • (C19) 0 <= start_index_map < rank(operand).
  • (C20) size(slice_sizes) = rank(operand).
  • (C21) 0 <= slice_sizes <= shape(operand).
  • (C22) shape(result) = combine(batch_dim_sizes, offset_dim_sizes) حيث:
    • batch_dim_sizes = shape(start_indices) باستثناء أنّ حجم البُعد من start_indices بما يتوافق مع index_vector_dim غير متضمنة.
    • offset_dim_sizes = slice_sizes باستثناء أنّ أحجام السمات slice_sizes المقابلة لـ collapsed_slice_dims لا يتم تضمين operand_batching_dims.
    • يضع combine batch_dim_sizes في المحاور المقابلة لـ batch_dims offset_dim_sizes في المحاور المقابلة لـ offset_dims.
  • (C23) element_type(operand) = element_type(result).

أمثلة

// %operand: [
//            [
//             [[1, 2], [3, 4], [5, 6], [7, 8]],
//             [[9, 10],[11, 12], [13, 14], [15, 16]],
//             [[17, 18], [19, 20], [21, 22], [23, 24]]
//            ],
//            [
//             [[25, 26], [27, 28], [29, 30], [31, 32]],
//             [[33, 34], [35, 36], [37, 38], [39, 40]],
//             [[41, 42], [43, 44], [45, 46], [47, 48]]
//            ]
//           ]
// %start_indices: [
//                  [
//                   [[0, 0], [1, 0], [2, 1]],
//                   [[0, 1], [1, 1], [0, 9]]
//                  ],
//                  [
//                   [[0, 0], [2, 1], [2, 2]],
//                   [[1, 2], [0, 1], [1, 0]]
//                  ]
//                 ]
%result = "stablehlo.gather"(%operand, %start_indices) {
  dimension_numbers = #stablehlo.gather<
    offset_dims = [3, 4],
    collapsed_slice_dims = [1],
    operand_batching_dims = [0],
    start_indices_batching_dims = [1],
    start_index_map = [2, 1],
    index_vector_dim = 3>,
  slice_sizes = array<i64: 1, 1, 2, 2>,
  indices_are_sorted = false
} : (tensor<2x3x4x2xi32>, tensor<2x2x3x2xi64>) -> tensor<2x2x3x2x2xi32>
// %result: [
//           [
//            [
//             [[1, 2], [3, 4]],
//             [[3, 4], [5, 6]],
//             [[13, 14], [15, 16]]
//            ],
//            [
//             [[33, 34], [35, 36]],
//             [[35, 36], [37, 38]],
//             [[41, 42], [43, 44]]
//            ]
//           ],
//           [
//            [
//             [[1, 2], [3, 4]],
//             [[13, 14], [15, 16]],
//             [[21, 22], [23, 24]]
//            ],
//            [
//             [[43, 44], [45, 46]],
//             [[33, 34], [35, 36]],
//             [[27, 28], [29, 30]]
//            ]
//           ]
//          ]

مزيد من الأمثلة

get_dimension_size

دلالات الألفاظ

لعرض حجم dimension المحدّد لـ operand. بشكل أكثر رسمية، result = dim(operand, dimension) بينما تتعلق دلالات الشكل فقط المكون من النوع. يمكن أن يكون نوع العنصر أي شيء.

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتر أو متنسّر كمي (C1)
(I2) dimension ثابت من النوع si64 (C1)

المُخرَجات

الاسم النوع
result متسابق أحادي الأبعاد من النوع si32

القيود

  • (ج1) 0 <= dimension < rank(operand).

أمثلة

// %operand: [[1, 2, 3], [4, 5, 6]]
%result = "stablehlo.get_dimension_size"(%operand) {
  dimension = 1 : i64
} : (tensor<2x3xi64>) -> tensor<i32>
// %result: 3

مزيد من الأمثلة

get_tuple_element

دلالات الألفاظ

هي تعمل على استخراج العنصر في موضع index في الصف operand وينتج عنه result اسم "result = operand[index]" رسميًا.

مدخلات

التصنيف الاسم النوع القيود
(I1) operand صف (C1)، (C2)
(I2) index ثابت من النوع si32 (C1)، (C2)

المُخرَجات

الاسم النوع القيود
result أي نوع متوافق (C2)

القيود

  • (ج1) 0 <= index < size(operand).
  • (C2) type(result) = tuple_element_types(operand)[index].

أمثلة

// %operand: ([1.0, 2.0], (3))
  index = 0 : i32
} : (tuple<tensor<2xf32>, tuple<tensor<i32>>>) -> tensor<2xf32>
// %result: [1.0, 2.0]

مزيد من الأمثلة

إذا

دلالات الألفاظ

الحصول على ناتج من تنفيذ دالة واحدة بالضبط من true_branch أو false_branch استنادًا إلى قيمة pred. اسم "result = pred ? true_branch() : false_branch()" رسميًا.

مدخلات

التصنيف الاسم النوع القيود
(I1) pred متسابق أحادي الأبعاد من النوع i1
(I2) true_branch دالة (C1-C3)
(I3) false_branch دالة (C1)، (C2)

المُخرَجات

الاسم النوع القيود
results الأعداد المتباينة من متساعات التوتر أو العشرات الكمية أو الرموز المميزة (C3)

القيود

  • (ج1) input_types(true_branch) = input_types(false_branch) = [].
  • (C2) output_types(true_branch) = output_types(false_branch).
  • (C3) type(results...) = output_types(true_branch):

أمثلة

// %result_true_branch: 10
// %result_false_branch: 11
// %pred: true
%result = "stablehlo.if"(%pred) ({
  "stablehlo.return"(%result_true_branch) : (tensor<i32>) -> ()
}, {
  "stablehlo.return"(%result_false_branch) : (tensor<i32>) -> ()
}) : (tensor<i1>) -> tensor<i32>
// %result: 10

مزيد من الأمثلة

صورة

دلالات الألفاظ

يتم استخراج الجزء التخيلي، من ناحية العناصر، من operand وينتج عنه متوتر result وبشكل رسمي، لكل عنصر x: imag(x) = is_complex(x) ? imaginary_part(x) : constant(0, element_type(result))

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتر من النقطة العائمة أو نوع معقد (C1)، (C2)

المُخرَجات

الاسم النوع القيود
result متّجه من نوع النقطة العائمة (C1)، (C2)

القيود

  • (ج1) shape(result) = shape(operand).
  • (C2) يتم تعريف element_type(result) على النحو التالي:
    • complex_element_type(element_type(operand)) إذا is_complex(operand).
    • element_type(operand) بخلاف ذلك.

أمثلة

// %operand: [(1.0, 2.0), (3.0, 4.0)]
%result = "stablehlo.imag"(%operand) : (tensor<2xcomplex<f32>>) -> tensor<2xf32>
// %result: [2.0, 4.0]

مزيد من الأمثلة

إعلان ضمن الخلاصة

دلالات الألفاظ

تقرأ البيانات من الخلاصة الإعلانية وتُنتج results.

يتم تحديد دلالات infeed_config.

تتألف الدالة results من قيم حمولة البيانات تأتي أولاً ورمزًا مميّزًا يأتي الأخير. وفي المستقبل، نخطط لتقسيم الحمولة والرمز المميز إلى المخرجات المنفصلة لتحسين الوضوح (#670)

مدخلات

التصنيف الاسم النوع
(I1) token token
(I2) infeed_config ثابت من النوع string

المُخرَجات

الاسم النوع القيود
results الأعداد المتباينة من متساعات التوتر أو العشرات الكمية أو الرموز المميزة (C1-C3)

القيود

  • (ج1) 0 < size(results).
  • (C2) is_empty(result[:-1]) أو is_tensor(type(results[:-1])).
  • (C3) is_token(type(results[-1])):

أمثلة

// %token: !stablehlo.token
// infeed_queue[0]: [[1, 2], [3, 4]]
// infeed_queue[1]: [[5, 6], [7, 8]]
%results0:2 = "stablehlo.infeed"(%token) {
  infeed_config = ""
} : (!stablehlo.token) -> (tensor<2x2xi64>, !stablehlo.token)
// results0#0: [[1, 2], [3, 4]]
%results1:2 = "stablehlo.infeed"(%token) {
  infeed_config = ""
} : (!stablehlo.token) -> (tensor<2x2xi64>, !stablehlo.token)
// results1#0: [[5, 6], [7, 8]]

مزيد من الأمثلة

يوتا

دلالات الألفاظ

ملء متوتر output بقيم بترتيب متزايد بدءًا من الصفر على طول البُعد iota_dimension. بشكل أكثر رسمية،

output[output_index] = constant(is_quantized(output) ? quantize(output_index[iota_dimension], element_type(output)) : output_index[iota_dimension], element_type(output)).

مدخلات

التصنيف الاسم النوع القيود
(I1) iota_dimension si64 (C1)

المُخرَجات

الاسم النوع القيود
output موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المنزِّع الكمي لكل متسابق (C1)

القيود

  • (ج1) 0 <= iota_dimension < rank(output).

أمثلة

%output = "stablehlo.iota"() {
  iota_dimension = 0 : i64
} : () -> tensor<4x5xi32>
// %output: [
//           [0, 0, 0, 0, 0],
//           [1, 1, 1, 1, 1],
//           [2, 2, 2, 2, 2],
//           [3, 3, 3, 3, 3]
//          ]

%output = "stablehlo.iota"() {
  iota_dimension = 1 : i64
} : () -> tensor<4x5xi32>
// %output: [
//           [0, 1, 2, 3, 4],
//           [0, 1, 2, 3, 4],
//           [0, 1, 2, 3, 4],
//           [0, 1, 2, 3, 4]
//          ]

مزيد من الأمثلة

is_finite

دلالات الألفاظ

تُجري هذا الإجراء التحقّق من العناصر الدقيقة إذا كانت القيمة في x محدودة (أي أنّها ليست غير محدودة). +Inf و-Inf وNaN) وينتج سينسور y. لتنفيذ isFinite وفقًا لمواصفات IEEE-754. بالنسبة للأنواع الكَمية، تكون النتيجة دائمًا true.

مدخلات

التصنيف الاسم النوع القيود
(I1) x متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق (C1)

المُخرَجات

الاسم النوع القيود
y متّصِل من النوع المنطقي (C1)

القيود

  • (ج1) shape(x) = shape(y).

أمثلة

// Logical values: -Inf, +Inf, NaN, ...
// %x: [0xFFF0000000000000, 0x7FF0000000000000, 0x7FF8000000000000, -10.0, -0.0, 0.0, 10.0]
%y = "stablehlo.is_finite"(%x) : (tensor<7xf64) -> tensor<7xi1>
// %y: [false, false, false, true, true, true, true]

مزيد من الأمثلة

log

دلالات الألفاظ

لتنفيذ عملية اللوغاريتم حسب العناصر على موتّر operand وينتج عنه متوتر result حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى الأعداد العشرية: log من IEEE-754.
  • بالنسبة إلى الأعداد المركّبة: اللوغاريتم المركَّب.
  • بالنسبة إلى الأنواع الكَمية: dequantize_op_quantize(log, operand, type(result)).

مدخلات

التصنيف الاسم النوع القيود
(I1) operand مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(result).

أمثلة

// %operand: [[1.0, 2.0], [3.0, 4.0]]
%result = "stablehlo.log"(%operand) : (tensor<2x2xf64>) -> tensor<2x2xf64>
// %result: [[0.0, 0.69314718055994529], [1.0986122886681098, 1.3862943611198906]]

مزيد من الأمثلة

log_plus_one

دلالات الألفاظ

لتنفيذ لوغاريتم العناصر في العناصر بالإضافة إلى عملية واحدة على متين operand نحصل على موتّر result. حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى الأعداد العشرية: logp1 من IEEE-754.
  • بالنسبة إلى الأعداد المركّبة: اللوغاريتم المركّب زائد واحد.
  • بالنسبة إلى الأنواع الكَمية: dequantize_op_quantize(log_plus_one, operand, type(result))

مدخلات

التصنيف الاسم النوع القيود
(I1) operand مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(result).

أمثلة

// %operand: [0.0, -0.999, 7.0, 6.38905621, 15.0]
%result = "stablehlo.log_plus_one"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// %result: [0.0, -6.90776825, 2.07944155, 2.0, 2.77258873]

مزيد من الأمثلة

الخدمات اللوجستية

دلالات الألفاظ

ينفذ عملية لوجستية بناءً على العناصر على متوتر operand وينتج عنه متوتر result حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى الأعداد العشرية: division(1, addition(1, exp(-x))) من IEEE-754.
  • للأعداد المركّبة: لوجستية معقدة.
  • بالنسبة إلى الأنواع الكَمية: dequantize_op_quantize(logistic, operand, type(result))

مدخلات

التصنيف الاسم النوع القيود
(I1) operand مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(result).

أمثلة

// %operand: [[0.0, 1.0], [2.0, 3.0]]
%result = "stablehlo.logistic"(%operand) : (tensor<2x2xf64>) -> tensor<2x2xf64>
// %result: [[0.5, 0.73105858], [0.88079708, 0.95257413]]

مزيد من الأمثلة

خريطة

دلالات الألفاظ

يتم تطبيق دالة خريطة computation على inputs على طول dimensions نحصل على متوتر result.

اسم "result[result_index] = computation(inputs...[result_index])" رسميًا.

مدخلات

التصنيف الاسم النوع القيود
(I1) inputs الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق (C1-C4)
(I2) dimensions ثابت التوتر ذو البعد الواحد من النوع si64 (C3)
(I3) computation دالة (C4)

المُخرَجات

الاسم النوع القيود
result متوتّر أو مستنسر كمي لكلّ متسابق (C1)، (C4)

القيود

  • (ج1) shape(inputs...) = shape(result).
  • (C2) 0 < size(inputs) = N.
  • (C3) dimensions = range(rank(inputs[0])):
  • (C4) computation النوع (tensor<E0>, ..., tensor<EN-1>) -> tensor<E'> حيث Ei = element_type(inputs[i]) وE' = element_type(result).

أمثلة

// %input0: [[0, 1], [2, 3]]
// %input1: [[4, 5], [6, 7]]
%result = "stablehlo.map"(%input0, %input1) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %0 = stablehlo.multiply %arg0, %arg1 : tensor<i64>
    stablehlo.return %0 : tensor<i64>
}) {
  dimensions = array<i64: 0, 1>
} : (tensor<2x2xi64>, tensor<2x2xi64>) -> tensor<2x2xi64>
// %result: [[0, 5], [12, 21]]

مزيد من الأمثلة

أعلى قيمة

دلالات الألفاظ

لتنفيذ عملية الحد الأقصى من حيث العناصر على المستويَين lhs وrhs وينتج عن ذلك متوتر result حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى القيم المنطقية: منطقي OR.
  • بالنسبة إلى الأعداد الصحيحة: الحد الأقصى لعدد صحيح.
  • بالنسبة إلى الأعداد العشرية: maximum من IEEE-754.
  • بالنسبة إلى الأعداد المركّبة: الحد الأقصى للنصوص المعجمية لزوج (real, imaginary). يتضمن فرض ترتيب على الأعداد المركّبة دلالات مدهشة، لذا نخطط في المستقبل لإلغاء دعم الأعداد المركّبة لهذه العملية (#560).
  • بالنسبة إلى الأنواع الكَمية:
    • dequantize_op_quantize(maximum, lhs, rhs, type(result)).

مدخلات

التصنيف الاسم النوع القيود
(I1) lhs متوتّر أو مستنسر كمي لكلّ متسابق (C1)
(I2) rhs متوتّر أو مستنسر كمي لكلّ متسابق (C1)

المُخرَجات

الاسم النوع القيود
result متوتّر أو مستنسر كمي لكلّ متسابق (C1)

القيود

  • (ج1) baseline_type(lhs) = baseline_type(rhs) = baseline_type(result).

أمثلة

// %lhs: [[1, 2], [7, 8]]
// %rhs: [[5, 6], [3, 4]]
%result = "stablehlo.maximum"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[5, 6], [7, 8]]

مزيد من الأمثلة

الحد الأدنى

دلالات الألفاظ

لتنفيذ عملية min من حيث العناصر على متسابقَي التوتر lhs وrhs وينتج عن ذلك متوتر result حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى القيم المنطقية: المنطقي AND.
  • بالنسبة للأعداد الصحيحة: الحد الأدنى لعدد صحيح.
  • بالنسبة إلى الأعداد العشرية: minimum من IEEE-754.
  • بالنسبة إلى الأعداد المركّبة: يجب استخدام الحد الأدنى للقيم اللغوية لزوج (real, imaginary). يتضمن فرض ترتيب على الأعداد المركّبة دلالات مدهشة، لذا نخطط في المستقبل لإلغاء دعم الأعداد المركّبة لهذه العملية (#560).
  • بالنسبة إلى الأنواع الكَمية:
    • dequantize_op_quantize(minimum, lhs, rhs, type(result)).

مدخلات

التصنيف الاسم النوع القيود
(I1) lhs متوتّر أو مستنسر كمي لكلّ متسابق (C1)
(I2) rhs متوتّر أو مستنسر كمي لكلّ متسابق (C1)

المُخرَجات

الاسم النوع القيود
result متوتّر أو مستنسر كمي لكلّ متسابق (C1)

القيود

  • (ج1) baseline_type(lhs) = baseline_type(rhs) = baseline_type(result).

أمثلة

// %lhs: [[1, 2], [7, 8]]
// %rhs: [[5, 6], [3, 4]]
%result = "stablehlo.minimum"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[1, 2], [3, 4]]

مزيد من الأمثلة

ضرب

دلالات الألفاظ

لتنفيذ حاصل ضرب العناصر من ناحية العناصر لمتسرينَين lhs وrhs وينتج عن ذلك متوتر result حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى القيم المنطقية: المنطقي AND.
  • بالنسبة إلى الأعداد الصحيحة: ضرب الأعداد الصحيحة.
  • بالنسبة إلى الأعداد العشرية: multiplication من IEEE-754.
  • بالنسبة للأعداد المركّبة: الضرب المعقد.
  • بالنسبة إلى الأنواع الكَمية:
    • dequantize_op_quantize(multiply, lhs, rhs, type(result)).

مدخلات

التصنيف الاسم النوع القيود
(I1) lhs متوتّر أو مستنسر كمي لكلّ متسابق (C1)
(I2) rhs متوتّر أو مستنسر كمي لكلّ متسابق (C1)

المُخرَجات

الاسم النوع القيود
result متوتّر أو مستنسر كمي لكلّ متسابق (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(result).

أمثلة

// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.multiply"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[5, 12], [21, 32]]

مزيد من الأمثلة

نفي

دلالات الألفاظ

لتنفيذ عملية نفي تسلسلي حسب العناصر في متوتر operand وينتج عن ذلك result متنسور. حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى الأعداد الصحيحة الموقّعة: نفي العدد الصحيح.
  • بالنسبة إلى الأعداد الصحيحة غير الموقَّعة: bitcast إلى عدد صحيح بعلامة، نفي عدد صحيح، Bitcast إلى عدد صحيح غير موقَّع.
  • بالنسبة إلى الأعداد العشرية: negate من IEEE-754.
  • للأعداد المركّبة: النفي المركّب.
  • بالنسبة إلى الأنواع الكَمية: dequantize_op_quantize(negate, operand, type(result))

مدخلات

التصنيف الاسم النوع القيود
(I1) operand موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المنزِّع الكمي لكل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المنزِّع الكمي لكل متسابق (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(result).

أمثلة

// Negation operation with integer Tensors
// %operand: [0, -2]
%result = "stablehlo.negate"(%operand) : (tensor<2xi32>) -> tensor<2xi32>
// %result: [0, 2]

// Negation operation with with complex tensors
// %operand: (2.5, 0.0)
%result = "stablehlo.negate"(%operand) : (tensor<1xcomplex<f32>>) -> tensor<1xcomplex<f32>>
// %result: [-2.5, -0.0]

مزيد من الأمثلة

ليس

دلالات الألفاظ

تؤدي هذه الدالة إلى تنفيذ أمر NOT من العناصر المقابلة في عشرات operand وينتج عنها متسابق result. حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى القيم المنطقية: منطقي NOT.
  • بالنسبة إلى الأعداد الصحيحة: ليس بعكس البت.

الوسيطات

الاسم النوع القيود
operand متّصِل من نوع القيمة المنطقية أو العدد الصحيح (C1)

المُخرَجات

الاسم النوع القيود
result متّصِل من نوع القيمة المنطقية أو العدد الصحيح (C1)

القيود

  • (ج1) type(operand) = type(result).

أمثلة

// Bitwise operation with with integer tensors
// %operand: [[1, 2], [3, 4]]
%result = "stablehlo.not"(%operand) : (tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[-2, -3], [-4, -5]]

// Bitwise operation with with boolean tensors
// %operand: [true, false]
%result = "stablehlo.not"(%operand) : (tensor<2xi1>) -> tensor<2xi1>
// %result: [false, true]

مزيد من الأمثلة

optimization_barrier

دلالات الألفاظ

يضمن تنفيذ العمليات التي تنتج عن operand قبل أي العمليات التي تعتمد على result وتمنع تحويلات المحول البرمجي من نقل العمليات عبر الحاجز. بخلاف ذلك، تكون العملية هوية، أي result = operand.

الوسيطات

الاسم النوع القيود
operand الأعداد المتباينة من متساعات التوتر أو المتسّعات المكمّلة لكل متسابق أو الرموز المميزة (C1)

المُخرَجات

الاسم النوع القيود
result الأعداد المتباينة من متساعات التوتر أو المتسّعات المكمّلة لكل متسابق أو الرموز المميزة (C1)

القيود

  • (ج1) type(operand...) = type(result...).

أمثلة

// %operand0: 0.0
// %operand1: 1.0
%result0, %result1 = "stablehlo.optimization_barrier"(%operand0, %operand1) : (tensor<f32>, tensor<f32>) -> (tensor<f32>, tensor<f32>)
// %result0: 0.0
// %result1: 1.0

مزيد من الأمثلة

أو

دلالات الألفاظ

تؤدي هذه العملية إلى تنفيذ OR من ناحية العناصر باستخدام عاملين متوترين lhs وrhs وينتج عن ذلك result. متنسور. حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى القيم المنطقية: منطقي OR.
  • بالنسبة إلى الأعداد الصحيحة: استخدام OR على مستوى البت.

مدخلات

التصنيف الاسم النوع القيود
(I1) lhs متوتر العدد الصحيح أو النوع المنطقي (C1)
(I2) rhs متوتر العدد الصحيح أو النوع المنطقي (C1)

المُخرَجات

الاسم النوع القيود
result متوتر العدد الصحيح أو النوع المنطقي (C1)

القيود

  • (ج1) type(lhs) = type(rhs) = type(result).

أمثلة

// Bitwise operation with with integer tensors
// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.or"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[5, 6], [7, 12]]

// Logical operation with with boolean tensors
// %lhs: [[false, false], [true, true]]
// %rhs: [[false, true], [false, true]]
%result = "stablehlo.or"(%lhs, %rhs) : (tensor<2x2xi1>, tensor<2x2xi1>) -> tensor<2x2xi1>
// %result: [[false, true], [true, true]]

مزيد من الأمثلة

خلاصة خارج الخلاصة

دلالات الألفاظ

كتابة inputs في الخلاصة الخارجية وينتج رمز result مميزًا.

يتم تحديد دلالات outfeed_config.

مدخلات

التصنيف الاسم النوع
(I1) inputs الأعداد المتباينة للمتسللات أو العشرات الكمي
(I2) token token
(I3) outfeed_config ثابت من النوع string

المُخرَجات

الاسم النوع
result token

أمثلة

%result = "stablehlo.outfeed"(%input0, %token) {
  outfeed_config = ""
} : (tensor<2x2x2xi64>, !stablehlo.token) -> !stablehlo.token

مزيد من الأمثلة

لبادة

دلالات الألفاظ

توسيع operand عن طريق المساحة المتروكة حول المتوتر وكذلك بين العناصر لمخطَّط متعرِّض مع padding_value المقدم.

edge_padding_low وedge_padding_high يحددان مقدار المساحة المتروكة التي تمت إضافتها عند النقطة المنخفضة (بجوار المؤشر 0) والسعر النهائي (بجوار أعلى مؤشر) كل بُعد على التوالي. يمكن أن يكون مقدار المساحة المتروكة سالبًا، حيث القيمة المطلقة للمساحة المتروكة السالبة تشير إلى عدد العناصر المطلوب إزالتها من البُعد المحدد.

interior_padding يحدد مقدار المساحة المتروكة بين أي اثنين العناصر في كل بُعد والتي قد لا تكون سالبة. تحدث المساحة المتروكة الداخلية قبل المساحة المتروكة للحواف بحيث تؤدي المساحة المتروكة السالبة إلى إزالة العناصر من المعامل المبطّن بالداخل.

وتعريف result[result_index] من الناحية الرسمية على النحو التالي:

  • operand[operand_index] إذا result_index = edge_padding_low + operand_index * (interior_padding + 1)
  • padding_value بخلاف ذلك.

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتّر أو مستنسر كمي لكلّ متسابق (C1)، (C2)، (C4)
(I2) padding_value متسّع 0 بُعدي أو متنسورة كمّية بكل متسابق (C1)
(I3) edge_padding_low ثابت التوتر ذو البعد الواحد من النوع si64 (C1)، (C4)
(I4) edge_padding_high ثابت التوتر ذو البعد الواحد من النوع si64 (C1)، (C4)
(I5) interior_padding ثابت التوتر ذو البعد الواحد من النوع si64 (C2-C4)

المُخرَجات

الاسم النوع القيود
result متوتّر أو مستنسر كمي لكلّ متسابق (C3-C6)

القيود

  • (ج1) element_type(operand) = element_type(padding_value) = element_type(result).
  • (C2) size(edge_padding_low) = size(edge_padding_high) = size(interior_padding) = rank(operand).
  • (C3) 0 <= interior_padding:
  • (C4) shape(result) = shape(operand) + edge_padding_low + max(shape(operand) - 1, 0) * interior_padding + edge_padding_high.

أمثلة

// %operand: [
//            [1, 2, 3],
//            [4, 5, 6]
//           ]
// %padding_value: 0
%result = "stablehlo.pad"(%operand, %padding_value) {
  edge_padding_low = array<i64: 0, 1>,
  edge_padding_high = array<i64: 2, 1>,
  interior_padding = array<i64: 1, 2>
} : (tensor<2x3xi32>, tensor<i32>) -> tensor<5x9xi32>
// %result: [
//           [0, 1, 0, 0, 2, 0, 0, 3, 0],
//           [0, 0, 0, 0, 0, 0, 0, 0, 0],
//           [0, 4, 0, 0, 5, 0, 0, 6, 0],
//           [0, 0, 0, 0, 0, 0, 0, 0, 0],
//           [0, 0, 0, 0, 0, 0, 0, 0, 0]
//          ]

مزيد من الأمثلة

partition_id

دلالات الألفاظ

عرض partition_id من العملية الحالية

المُخرَجات

الاسم النوع
result متسابق أحادي الأبعاد من النوع ui32

أمثلة

%result = "stablehlo.partition_id"() : () -> tensor<ui32>

مزيد من الأمثلة

بوبشن

دلالات الألفاظ

ينفذ العدد من حيث العناصر في عدد وحدات البت المحددة في متنور operand وينتج موتر result.

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتر لنوع العدد الصحيح (C1)

المُخرَجات

الاسم النوع القيود
result متوتر لنوع العدد الصحيح (C1)

القيود

  • (ج1) type(operand) = type(result).

أمثلة

// %operand: [0, 1, 2, 127]
%result = "stablehlo.popcnt"(%operand) : (tensor<4xi64>) -> tensor<4xi64>
// %result: [0, 1, 1, 7]

مزيد من الأمثلة

الطاقة

دلالات الألفاظ

لتنفيذ الأس على العناصر حسب العناصر في متسابق lhs باستخدام موتّر rhs نحصل على متوتر result. حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى الأعداد الصحيحة: أس الأعداد الصحيحة.
  • بالنسبة إلى الأعداد العشرية: pow من IEEE-754.
  • للأعداد المركّبة: الأس المركَّب.
  • بالنسبة إلى الأنواع الكَمية: dequantize_op_quantize(power, lhs, rhs, type(result)).

مدخلات

التصنيف الاسم النوع القيود
(I1) lhs موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المنزِّع الكمي لكل متسابق (C1)
(I2) rhs موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المنزِّع الكمي لكل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المنزِّع الكمي لكل متسابق (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(result).

أمثلة

// %lhs: [-2.0, -0.0, -36.0, 5.0, 3.0, 10000.0]
// %rhs: [2.0, 2.0, 1.1, 2.0, -1.0, 10.0]
%result = "stablehlo.power"(%lhs, %rhs) : (tensor<6xf64>, tensor<6xf64>) -> tensor<6xf64>
// %result: [4.0, 0.0, -nan, 25.0, 0.333333343, inf]

مزيد من الأمثلة

حقيقي

دلالات الألفاظ

هي استخراج الجزء الحقيقي من العنصر operand واستخراج result متنسور. وبشكل رسمي، لكل عنصر x: real(x) = is_complex(x) ? real_part(x) : x

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتر من النقطة العائمة أو نوع معقد (C1)، (C2)

المُخرَجات

الاسم النوع القيود
result متّجه من نوع النقطة العائمة (C1)، (C2)

القيود

  • (ج1) shape(result) = shape(operand).
  • (C2) يتم تعريف element_type(result) على النحو التالي:
    • complex_element_type(element_type(operand)) إذا is_complex(operand).
    • element_type(operand) بخلاف ذلك.

أمثلة

// %operand: [(1.0, 2.0), (3.0, 4.0)]
%result = "stablehlo.real"(%operand) : (tensor<2xcomplex<f32>>) -> tensor<2xf32>
// %result: [1.0, 3.0]

مزيد من الأمثلة

تسجيل

دلالات الألفاظ

تتلقى البيانات من قناة تتضمن channel_id وتُنتج results.

إذا كانت قيمة is_host_transfer هي true، تنقل العملية البيانات من المضيف. وإلا، سيتم نقل البيانات من جهاز آخر. يعني ذلك التنفيذ. تكرر هذه العلامة المعلومات المقدمة في channel_type، لذلك نخطّط في المستقبل للاحتفاظ بواحدة فقط منها. (#666).

تتألف الدالة results من قيم حمولة البيانات تأتي أولاً ورمزًا مميّزًا يأتي الأخير. وفي المستقبل، نخطط لتقسيم الحمولة والرمز المميز إلى المخرجات المنفصلة لتحسين الوضوح (#670)

مدخلات

التصنيف الاسم النوع القيود
(I1) token token (C4)
(I2) channel_id ثابت من النوع si64
(I3) channel_type تعداد DEVICE_TO_DEVICE وHOST_TO_DEVICE (C1)
(I4) is_host_transfer ثابت من النوع i1 (C1)

المُخرَجات

الاسم النوع القيود
results الأعداد المتباينة من متساعات التوتر أو العشرات الكمية أو الرموز المميزة (C2-C4)

القيود

  • (C1) يتم تعريف channel_type على النحو التالي:
    • HOST_TO_DEVICE إذا is_host_transfer = true،
    • DEVICE_TO_DEVICE بخلاف ذلك.
  • (C2) 0 < size(results).
  • (C3) is_empty(result[:-1]) أو is_tensor(type(results[:-1])).
  • (C4) is_token(type(results[-1])).

أمثلة

%results0, %results1 = "stablehlo.recv"(%token) {
  channel_handle = #stablehlo.channel_handle<handle = 1, type = 3>,
  is_host_transfer = true
} : (!stablehlo.token) -> (tensor<2x2xi64>, !stablehlo.token)

مزيد من الأمثلة

reduce

دلالات الألفاظ

يتم تطبيق دالة الاختزال body على inputs وinit_values على طول dimensions وينتج results موتّرًا.

يعتمد ترتيب التخفيضات على التنفيذ، ما يعني أنّ السمة body يجب أن تشكل init_values خطًا أحاديًا لضمان أن تُنتج العملية النتائج نفسها لجميع المدخلات في جميع عمليات التنفيذ. ومع ذلك، فإن هذا الشرط لا تشير إلى العديد من التخفيضات الشائعة. مثلاً: إضافة النقطة العائمة لا تشكل body وصفر لـ init_values رقمًا واحدًا في الواقع لأن إضافة النقطة العائمة غير ارتباطية.

بشكل رسمي، results...[j0, ..., jR-1] = reduce(input_slices_converted) حيث:

  • input_slices = inputs...[j0, ..., :, ..., jR-1]، حيث يتم إدراج : في dimensions.
  • input_slices_converted = to_destination_type(input_slices..., type(func_inputs(body)[:len(func_inputs(body))//2])...).
  • init_values_converted = to_destination_type(init_values..., type(func_inputs(body)[len(func_inputs(body))//2:])...).
  • reduce(input_slices_converted) = exec(schedule) لبعض الشجرة الثنائية schedule حيث:
    • exec(node) = body(exec(node.left), exec(node.right)).
    • exec(leaf) = leaf.value.
  • schedule عبارة عن شجرة ثنائية كاملة محددة التنفيذ وترتيبها يتكون الاجتياز مما يلي:
    • input_slices_converted...[index] قيمة لكل index بوصة index_space(input_slices_converted) بترتيب تصاعدي من index.
    • ويتخللها مقدار محدد من التنفيذ init_values_converted في المواضع المحددة للتنفيذ.

مدخلات

التصنيف الاسم النوع القيود
(I1) inputs الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق (C1-C4)، (C6)، (C7)
(I2) init_values عدد متغير من العشرات ذوات الأبعاد 0 أو مقدرات التوتر الكمية لكل متسابق (C2)، (C3)
(I3) dimensions ثابت التوتر ذو البعد الواحد من النوع si64 (C4)، (C5)، (C7)
(I4) body دالة (C6)

المُخرَجات

الاسم النوع القيود
results الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق (C3)، (C7)، (C8)

القيود

  • (ج1) same(shape(inputs...)).
  • (C2) element_type(inputs...) = element_type(init_values...).
  • (C3) 0 < size(inputs) = size(init_values) = size(results) = N:
  • (C4) 0 <= dimensions < rank(inputs[0]).
  • (C5) is_unique(dimensions).
  • (C6) النوع body هو (tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ..., مكان tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>) is_promotable(element_type(inputs[i]), Ei)
  • (C7) shape(results...) = shape(inputs...) باستثناء أنّ السمة لم يتم تضمين مقاسات inputs... المقابلة لـ dimensions.
  • (C8) element_type(results[i]) = Ei لكل i في [0,N).

أمثلة

// %input = [[0, 1, 2, 3, 4, 5]]
// %init_value = 0
%result = "stablehlo.reduce"(%input, %init_value) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
    "stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
  dimensions = array<i64: 1>
} : (tensor<1x6xi64>, tensor<i64>) -> tensor<1xi64>
// %result = [15]

مزيد من الأمثلة

reduce_precision

دلالات الألفاظ

تُجري عملية تحويل operand حسب العناصر إلى نوع نقطة عائمة آخر. التي تستخدم exponent_bits وmantissa_bits وتعود إلى الأصل نقطة عائمة وينتج عنها متسابق output.

أكثر رسمية:

  • يتم تعديل بتات المانتيسا للقيمة الأصلية لتقريب القيمة الأصلية إلى أقرب قيمة قابلة للتمثيل بـ mantissa_bits باستخدام roundToIntegralTiesToEven دلالات.
  • وإذا كانت mantissa_bits أصغر من عدد وحدات بتات المانتيسا القيمة الأصلية، يتم اقتطاع وحدات بت مانتسا إلى mantissa_bits.
  • ومن ثم، إذا لم تتناسب وحدات بت الأس للنتيجة المتوسطة النطاق المقدم من exponent_bits، تتجاوز النتيجة المتوسطة إلى لا نهاية باستخدام العلامة الأصلية أو التدفقات السفلية إلى صفر باستخدام العلامة الأصلية.
  • بالنسبة إلى الأنواع المحدَّدة الكمية، يتم تنفيذ dequantize_op_quantize( lambda operand: reduce_precision(operand, exponent_bits, mantissa_bits), operand, type(result)).

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق (C1)
(I2) exponent_bits ثابت من النوع si32 (C2)
(I3) mantissa_bits ثابت من النوع si32 (C3)

المُخرَجات

الاسم النوع القيود
output متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(output).
  • (C2) 1 <= exponent_bits.
  • (C3) 0 <= mantissa_bits:

أمثلة

// Logical values: +Inf, NaN, +Denormal, 0.0, 65519.0, 65520.0
// %operand: [0x7FF0000000000000, 0x7FFFFFFFFFFFFFFF, 0x0000000000000001, 0.0, 65519.0, 65520.0]
%output = "stablehlo.reduce_precision"(%operand) {
  exponent_bits = 5 : i32,
  mantissa_bits = 10 : i32
} : (tensor<6xf64>) -> tensor<6xf64>
// Logical values: +Inf, NaN, 0.0, 0.0, 65504.0, +Inf
// %output: [0x7FF0000000000000, 0x7FFFFFFFFFFFFFFF, 0.0, 0.0, 65504.0, 0x7FF0000000000000]

مزيد من الأمثلة

reduce_scatter

دلالات الألفاظ

reduce_scatter

داخل كل مجموعة عملية في شبكة المعالجة StableHLO، تُجري الاختزال باستخدام computations، على قيم متوتر operand من كل عملية، قسمة نتيجة الاختزال في scatter_dimension إلى أجزاء، والنقاط المبعثرة الأجزاء المقسّمة بين العمليّتين لإنتاج result.

تقسم هذه العملية شبكة عملية StableHLO إلى process_groups وهي على النحو التالي:

  • cross_replica(replica_groups) إذا كانت القيمة هي channel_id <= 0 and use_global_device_ids = false.
  • cross_replica_and_partition(replica_groups) إذا كانت القيمة هي channel_id > 0 and use_global_device_ids = false.
  • flattened_ids(replica_groups) إذا كانت القيمة هي channel_id > 0 and use_global_device_ids = true.

بعد ذلك، ضمن كل process_group:

  • reduced_value = all_reduce(operand, replica_groups, channel_id, use_global_device_ids, computation).
  • parts@sender = split(reduced_value@sender, dim(process_groups, 1), scatter_dimension).
  • result@receiver = parts@sender[receiver_index] لكل sender بوصة process_group، حيث receiver_index = process_group.index(receiver).

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتّر أو مستنسر كمي لكلّ متسابق (C1)، (C2)، (C7)، (C8)
(I2) scatter_dimension ثابت من النوع si64 (C1)، (C2)، (C8)
(I3) replica_groups ثابت التوتر الثنائي الأبعاد من النوع si64 (C3-C5)
(I4) channel_id ثابت من النوع si64 (C6)
(I5) use_global_device_ids ثابت من النوع i1 (C6)
(I6) computation دالة (C7)

المُخرَجات

الاسم النوع القيود
result متوتّر أو مستنسر كمي لكلّ متسابق (C8-C9)

القيود

  • (ج1) dim(operand, scatter_dimension) % dim(process_groups, 1) = 0.
  • (C2) 0 <= scatter_dimension < rank(operand).
  • (C3) is_unique(replica_groups):
  • (C4) يتم تعريف size(replica_groups) على النحو التالي:
    • num_replicas في حال استخدام cross_replica.
    • num_replicas في حال استخدام cross_replica_and_partition.
    • num_processes في حال استخدام flattened_ids.
  • (C5) 0 <= replica_groups < size(replica_groups).
  • (C6) إذا كانت use_global_device_ids = true، يتم عندها channel_id > 0.
  • (C7) computation من النوع (tensor<E>, tensor<E>) -> (tensor<E>) حيث is_promotable(element_type(operand), E)
  • (C8) shape(result) = shape(operand) باستثناء:
    • dim(result, scatter_dimension) = dim(operand, scatter_dimension) / dim(process_groups, 1).
  • (C9) element_type(result) = E.

أمثلة

// num_replicas: 2
// num_partitions: 1
// %operand@(0, 0): [[1, 2, 3, 4],
//                   [5, 6, 7, 8]]
// %operand@(1, 0): [[9, 10, 11, 12],
//                   [13, 14, 15, 16]]
%result = "stablehlo.reduce_scatter"(%operand) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
  %0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
  "stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
  scatter_dimension = 1 : i64,
  replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>,
  channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
} : (tensor<2x4xi64>) -> tensor<2x2xi64>
//
// %result@(0, 0): [[10, 12],
//                  [18, 20]]
// %result@(1, 0): [[14, 16],
//                  [22, 24]]

مزيد من الأمثلة

reduce_window

دلالات الألفاظ

يؤدي هذا الإجراء إلى تطبيق دالة التقليل body على نافذتَي inputs وinit_values. وتُنتج results.

يوضّح المخطّط التالي طريقة حساب العناصر في results... من inputs... باستخدام مثال ملموس.

reduce_window

بشكل أكثر رسمية، results...[result_index] = reduce(windows, init_values, axes(inputs...), body) (راجِع تقليل) حيث:

  • padded_inputs = pad(inputs..., init_values..., padding[:, 0], padding[:, 1], base_dilations - 1).
  • window_start = result_index * window_strides.
  • window_end = window_start + (window_dimensions - 1) * window_dilations + 1.
  • windows = slice(padded_inputs..., window_start, window_end, window_dilations).

مدخلات

التصنيف الاسم النوع القيود
(I1) inputs الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق (C1-C4)، (C6)، (C8)، (C10)، (C12)، (C13)، (C15)
(I2) init_values عدد متغير من العشرات ذوات الأبعاد 0 أو مقدرات التوتر الكمية لكل متسابق (C1)، (C13)
(I3) window_dimensions ثابت التوتر ذو البعد الواحد من النوع si64 (C4)، (C5)، (C15)
(I4) window_strides ثابت التوتر ذو البعد الواحد من النوع si64 (C6)، (C7)، (C15)
(I5) base_dilations ثابت التوتر ذو البعد الواحد من النوع si64 (C8)، (C9)، (C15)
(I6) window_dilations ثابت التوتر ذو البعد الواحد من النوع si64 (C10)، (C11)، (C15)
(I7) padding ثابت التوتر الثنائي الأبعاد من النوع si64 (C12)، (C15)
(I8) body دالة (C13)

المُخرَجات

الاسم النوع القيود
results الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق (C1)، (C14-C16)

القيود

  • (ج1) 0 < size(inputs) = size(init_values) = size(results) = N.
  • (C2) same(shape(inputs...)).
  • (C3) element_type(inputs...) = element_type(init_values...):
  • (C4) size(window_dimensions) = rank(inputs[0]).
  • (C5) 0 < window_dimensions.
  • (C6) size(window_strides) = rank(inputs[0]).
  • (C7) 0 < window_strides.
  • (C8) size(base_dilations) = rank(inputs[0]).
  • (C9) 0 < base_dilations.
  • (C10) size(window_dilations) = rank(inputs[0]).
  • (C11) 0 < window_dilations.
  • (C12) shape(padding) = [rank(inputs[0]), 2].
  • (C13) النوع body هو (tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ...,. مكان tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>) is_promotable(element_type(inputs[i]), Ei)
  • (C14) same(shape(results...)).
  • (C15) shape(results[0]) = num_windows حيث:
    • dilated_input_shape = shape(inputs[0]) = 0 ? 0 : (shape(inputs[0]) - 1) * base_dilations + 1.
    • padded_input_shape = padding[:, 0] + dilated_input_shape + padding[:, 1].
    • dilated_window_shape = (window_dimensions - 1) * window_dilations + 1.
    • is_empty_window = padded_input_shape = 0 || dilated_window_shape > padded_input_shape.
    • num_windows = is_empty_window ? 0 : floor((padded_input_shape - dilated_window_shape) / window_strides) + 1.
  • (C16) element_type(results[i]) = Ei لكل i في [0,N).

أمثلة

// %input = [[1, 2], [3, 4], [5, 6]]
// %init_value = 0
%result = "stablehlo.reduce_window"(%input, %init_value) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
    "stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
  window_dimensions = array<i64: 2, 1>,
  window_strides = array<i64: 4, 1>,
  base_dilations = array<i64: 2, 1>,
  window_dilations = array<i64: 3, 1>,
  padding = dense<[[2, 1], [0, 0]]> : tensor<2x2xi64>
} : (tensor<3x2xi64>, tensor<i64>) -> tensor<2x2xi64>
// %result = [[0, 0], [3, 4]]

مزيد من الأمثلة

الباقي

دلالات الألفاظ

لتنفيذ باقي العناصر من حيث العناصر في معادلات المحصلة lhs وقسمة القاسم rhs نحصل على متوتر result.

وبشكل أكثر رسمية، يتم أخذ علامة النتيجة من الربح، تكون القيمة المطلقة للناتج دائمًا أقل من القيمة المطلقة للقاسم. ويتم حساب الباقي على النحو التالي: lhs - d * rhs، حيث يتم تحديد d على النحو التالي:

  • بالنسبة إلى الأعداد الصحيحة: stablehlo.divide(lhs, rhs).
  • بالنسبة إلى الأعداد العشرية: division(lhs, rhs) من IEEE-754 مع سمة التقريب roundTowardZero
  • بالنسبة إلى الأرقام المركّبة: يتم تحديدها لاحقًا. (#997)
  • بالنسبة إلى الأنواع الكَمية:
    • dequantize_op_quantize(remainder, lhs, rhs, type(result)).

بالنسبة إلى أنواع العناصر العائمة، تتعارض هذه العملية مع عملية remainder تستند إلى مواصفات IEEE-754 حيث تكون d قيمة متكاملة الأقرب إلى القيمة الدقيقة لـ lhs/rhs التي ترتبط بـ وحتى.

مدخلات

التصنيف الاسم النوع القيود
(I1) lhs موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المتسابق الكمي لكل متسابق (C1)
(I2) rhs موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المتسابق الكمي لكل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المتسابق الكمي لكل متسابق (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(result).

أمثلة

// %lhs: [17, -17, 17, -17]
// %rhs: [3, 3, -3, -3]
%result = "stablehlo.remainder"(%lhs, %rhs) : (tensor<4xi64>, tensor<4xi64>) -> tensor<4xi64>
// %result: [2, -2, 2, -2]

مزيد من الأمثلة

replica_id

دلالات الألفاظ

عرض replica_id من العملية الحالية

المُخرَجات

الاسم النوع
result متسابق أحادي الأبعاد من النوع ui32

أمثلة

%result = "stablehlo.replica_id"() : () -> tensor<ui32>

مزيد من الأمثلة

إعادة تشكيل

دلالات الألفاظ

يعيد تشكيل سينسور operand إلى متسابق result. من الناحية النظرية، الحفاظ على نفس التمثيل المتعارف عليه ولكن من المحتمل الشكل، على سبيل المثال من tensor<2x3xf32> إلى tensor<3x2xf32> أو tensor<6xf32>.

بشكل رسمي، result[result_index] = operand[operand_index] حيث لهما result_index وoperand_index نفس الموضع في المعجم ترتيب index_space(result) وindex_space(operand).

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتر أو متنسّر كمي (C1-C3)

المُخرَجات

الاسم النوع القيود
result متوتر أو متنسّر كمي (C1-C3)

القيود

  • (C1) element_type(result) يتم تقديمها من خلال:
    • element_type(operand)، إذا كانت !is_per_axis_quantized(operand).
    • element_type(operand) باستثناء أنّ quantization_dimension(operand) قد تختلف السمة quantization_dimension(result) في الحالات الأخرى.
  • (C2) size(operand) = size(result).
  • (C3) إذا كانت is_per_axis_quantized(operand):
    • reduce(dims(operand, [0, 1, ..., quantization_dimension(operand) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y) = reduce(dims(result, [0, 1, ..., quantization_dimension(result) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y).
    • dim(operand, quantization_dimension(operand)) = dim(result, quantization_dimension(result)).
    • reduce(dims(operand, [quantization_dimension(operand) + 1, ..., rank(operand) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y) = reduce(dims(result, [quantization_dimension(result) + 1, ..., rank(result) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y).

أمثلة

// %operand: [[1, 2, 3], [4, 5, 6]]
%result = "stablehlo.reshape"(%operand) : (tensor<2x3xi32>) -> tensor<3x2xi32>
// %result: [[1, 2], [3, 4], [5, 6]]

مزيد من الأمثلة

إلغاء

دلالات الألفاظ

يعكس ترتيب العناصر في operand على طول dimensions المحدد وينتج متسابق result. بشكل أكثر رسمية، result[result_index] = operand[operand_index] حيث:

  • operand_index[d] = dim(result, d) - result_index[d] - 1 إذا كانت القيمة هي d في dimensions.
  • operand_index[d] = result_index[d] بخلاف ذلك.

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتّر أو مستنسر كمي لكلّ متسابق (C1)، (C3)
(I2) dimensions ثابت التوتر ذو البعد الواحد من النوع si64 (C2)، (C3)

المُخرَجات

الاسم النوع القيود
result متوتّر أو مستنسر كمي لكلّ متسابق (C1)، (C3)

القيود

  • (ج1) type(operand) = type(result).
  • (C2) is_unique(dimensions).
  • (C3) 0 <= dimensions < rank(result):

أمثلة

// %operand = [[1, 2], [3, 4], [5, 6]]
%result = "stablehlo.reverse"(%operand) {
  dimensions = array<i64: 1>
} : (tensor<3x2xi32>) -> tensor<3x2xi32>
// %result: [[2, 1], [4, 3], [6, 5]]

مزيد من الأمثلة

رانغ

دلالات الألفاظ

تنشئ أرقامًا عشوائية باستخدام خوارزمية rng_distribution وتُنتج متسابق result لشكل معين shape.

إذا كانت rng_distribution = UNIFORM، سيتم إنشاء أرقام عشوائية. بعد التوزيع المنتظم على الفاصل الزمني [a, b). إذا كانت a >= b، يكون السلوك غير محدد.

إذا كانت rng_distribution = NORMAL، سيتم إنشاء أرقام عشوائية. بعد التوزيع الطبيعي، يكون المتوسط = a والانحراف المعياري = b. إذا كانت b < 0، سيكون السلوك غير محدَّد.

يتم تحديد الطريقة الدقيقة لإنشاء الأرقام العشوائية. بالنسبة على سبيل المثال، قد تكون حاسمة أو لا تكون حاسمة، وقد تستخدم أو لا حالة مخفية.

في المحادثات مع العديد من الأطراف المعنية، ظهرت هذه العملية بنفس قد تم إيقافها، لذا نخطط في المستقبل لاستكشاف إزالتها (#597)

مدخلات

التصنيف الاسم النوع القيود
(I1) a متين عشري الأبعاد للعدد الصحيح أو النوع المنطقي أو نوع النقطة العائمة (C1)، (C2)
(I2) b متين عشري الأبعاد للعدد الصحيح أو النوع المنطقي أو نوع النقطة العائمة (C1)، (C2)
(I3) shape ثابت التوتر ذو البعد الواحد من النوع si64 (C3)
(I4) rng_distribution تعداد UNIFORM وNORMAL (C2)

المُخرَجات

الاسم النوع القيود
result مقياس العدد الصحيح أو المنطقي أو نوع النقطة العائمة (C1-C3)

القيود

  • (ج1) element_type(a) = element_type(b) = element_type(result).
  • (C2) إذا كانت rng_distribution = NORMAL، يتم عندها is_float(a).
  • (C3) shape(result) = shape:

أمثلة

// %a = 0
// %b = 2
// %shape = [3, 3]
%result = "stablehlo.rng"(%a, %b, %shape) {
  rng_distribution = #stablehlo<rng_distribution UNIFORM>
} : (tensor<i32>, tensor<i32>, tensor<2xi64>) -> tensor<3x3xi32>
// %result: [
//           [1, 0, 1],
//           [1, 1, 1],
//           [0, 0, 0]
//          ]

rng_bit_generator

دلالات الألفاظ

عرض output مملوءة بوحدات بت عشوائية منتظمة وحالة إخراج معدَّلة الدالة output_state باستخدام خوارزمية إنشاء الأرقام الزائفة rng_algorithm بحالة أولية initial_state. يمكن ضمان أن يكون الناتج الدالة الحاسمة للدالة initial_state، ولكن ليس مضمونًا حتميًا بين عمليات التنفيذ.

rng_algorithm هو واحد مما يلي:

  • DEFAULT: خوارزمية محددة للتنفيذ.
  • THREE_FRY: الصيغة المعرَّفة من قِبل التنفيذ لخوارزمية Threefry*
  • PHILOX: الصيغة المحددة للتنفيذ لخوارزمية Philox.*

* راجِع: Salmon et al. SC 2011. الأرقام العشوائية المتوازية: طريقة سهلة مثل 1، 2، 3.

مدخلات

التصنيف الاسم النوع القيود
(I1) rng_algorithm تعداد DEFAULT وTHREE_FRY وPHILOX (C2)
(I2) initial_state متين أحادي البعد من النوع ui64 (C1)، (C2)

المُخرَجات

الاسم النوع القيود
output_state متين أحادي البعد من النوع ui64 (C1)
output متّصِل من عدد صحيح أو نوع نقطة عائمة

القيود

  • (ج1) type(initial_state) = type(output_state).
  • (C2) يتم تعريف size(initial_state) على النحو التالي:
    • محددة للتنفيذ إذا كانت rng_algorithm = DEFAULT.
    • 2 إذا rng_algorithm = THREE_FRY.
    • 2 أو 3 إذا rng_algorithm = PHILOX.

أمثلة

// %initial_state: [1, 2]
%output_state, %output = "stablehlo.rng_bit_generator"(%initial_state) {
  rng_algorithm = #stablehlo<rng_algorithm THREE_FRY>
} : (tensor<2xui64>) -> (tensor<2xui64>, tensor<2x2xui64>)
// %output_state: [1, 6]
// %output: [
//           [9236835810183407956, 16087790271692313299],
//           [18212823393184779219, 2658481902456610144]
//          ]

round_nearest_afz

دلالات الألفاظ

لإجراء تقريب من ناحية العناصر تجاه أقرب عدد صحيح، مما يؤدي إلى فصل الروابط من الصفر، في متوتر operand وينتج موتّر result. عمليات التنفيذ عملية roundToIntegralTiesToAway من مواصفات IEEE-754. بالنسبة محددة الكمية، ينفذ dequantize_op_quantize(round_nearest_afz, operand, type(result))

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(result).

أمثلة

// %operand = [-2.5, 0.4, 0.5, 0.6, 2.5]
%result = "stablehlo.round_nearest_afz"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// %result: [-3.0, 0.0, 1.0, 1.0, 3.0]

مزيد من الأمثلة

round_nearest_even

دلالات الألفاظ

لإجراء تقريب من ناحية العناصر تجاه أقرب عدد صحيح، مما يؤدي إلى قطع الروابط تجاه العدد الصحيح الزوجي في موجِّه operand وينتج عنه result متنسور. تنفيذ عملية roundToIntegralTiesToEven من IEEE-754 المواصفات. بالنسبة للأنواع الكَمية، تنفذ dequantize_op_quantize(round_nearest_even, operand, type(result))

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result متّصِل من نوع النقطة العائمة أو متوتر كمي حسب كل متسابق (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(result).

أمثلة

// %operand = [-2.5, 0.4, 0.5, 0.6, 2.5]
%result = "stablehlo.round_nearest_even"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// %result: [-2.0, 0.0, 0.0, 1.0, 2.0]

مزيد من الأمثلة

rsqrt

دلالات الألفاظ

لتنفيذ عملية جذر تربيعي تبادلي من حيث العناصر على متسابق operand نحصل على موتّر result. حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى الأعداد العشرية: rSqrt من IEEE-754.
  • بالنسبة للأعداد المركّبة: جذر مربع متبادلي مركّب.
  • بالنسبة إلى الأنواع الكَمية: dequantize_op_quantize(rsqrt, operand, type(result)).

مدخلات

التصنيف الاسم النوع القيود
(I1) operand مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(result).

أمثلة

// %operand: [[1.0, 4.0], [9.0, 25.0]]
%result = "stablehlo.rsqrt"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[1.0, 0.5], [0.33333343, 0.2]]

مزيد من الأمثلة

بعثرة

دلالات الألفاظ

يتم إنشاء results متسابقًا تساوي inputs متسابقًا باستثناء ذلك يتم تعديل الشرائح المتعددة المحددة بواسطة scatter_indices بالقيم updates باستخدام update_computation.

يوضّح المخطّط التالي كيفية ارتباط العناصر في updates... بالعناصر في results... باستخدام مثال ملموس. يختار المخطط بعض الأمثلة يشير updates... ويشرح بالتفصيل أي مؤشرات results... يتجاوب مع.

بعثرة

بشكل رسمي، لجميع update_index في index_space(updates[0]):

  • update_scatter_dims = [d for d in axes(updates[0]) and d not in update_window_dims].
  • update_scatter_index = update_index[update_scatter_dims...].
  • تعريف "start_index" على أنّه:
    • scatter_indices[si0, ..., :, ..., siN] حيث يكون si فرديًا العناصر في update_scatter_index و: عند إدراج فهرس index_vector_dim، إذا كانت index_vector_dim < rank(scatter_indices)
    • [scatter_indices[update_scatter_index]] بخلاف ذلك.
  • بالنسبة إلى d_input في axes(inputs[0])،
    • full_start_index[d_input] = start_index[d_start] إذا d_input = scatter_dims_to_operand_dims[d_start]
    • full_start_index[d_input] = 0 بخلاف ذلك.
  • بالنسبة إلى d_input في axes(inputs[0])،
    • full_batching_index[d_input] = update_scatter_index[d_start - (d_start < index_vector_dim ? 0 : 1)] إذا كان d_input = input_batching_dims[i_batching] و d_start = scatter_indices_batching_dims[i_batching]
    • full_batching_index[d_input] = 0 بخلاف ذلك.
  • update_window_index = update_index[update_window_dims...].
  • full_window_index = [wi0, ..., 0, ..., wiN] حيث يكون wi فرديًا العناصر في update_window_index، و0 يتم إدراجها في الفهارس من inserted_window_dims وinput_batching_dims.
  • result_index = full_start_index + full_batching_index + full_window_index.

بناءً على ذلك، results = exec(schedule, inputs)، حيث:

  • schedule هو تبديل محدد تنفيذًا index_space(updates[0])
  • exec([update_index, ...], results) = exec([...], updated_results) حيث:
    • في حال كان result_index ضمن حدود shape(results...)
    • updates_converted = to_destination_type( updates...[update_index], type(func_inputs(update_computation) [len(func_inputs(update_computation))//2:])... )
    • updated_values = update_computation(results...[result_index], updates_converted)
    • updated_results هو نسخة من results مع results...[result_index]. مضبوطة على updated_values...
    • ويمكنك بدلاً من ذلك
    • updated_results = results.
  • exec([], results) = results.

إذا كانت indices_are_sorted هي true، يمكن لعملية التنفيذ أن تفترض أنّ يتم ترتيب scatter_indices حسب scatter_dims_to_operand_dims، وإلا يكون السلوك غير محدد. بشكل رسمي، لجميع i1 < i2 من indices(result)، full_start_index(i1) <= full_start_index(i2).

إذا كانت unique_indices هي true، يمكن لعملية التنفيذ أن تفترض أنّ كل مؤشرات result_index المتبعثرة إليها فريدة. إذا كانت السمة unique_indices true لكن المؤشرات المبعثرة غير فريدة عندئذ يكون السلوك غير محددة.

مدخلات

التصنيف الاسم النوع القيود
(I1) inputs الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق (C1)، (C2)، (C4-C6)، (C11)، (C13)، (C18)، (C21)، (C23-C24)
(I2) scatter_indices متوتر لنوع العدد الصحيح (C4)، (C15)، (C19)، (C22)
(I3) updates الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق (C3-C6)، (C8)
(I4) update_window_dims ثابت التوتر ذو البعد الواحد من النوع si64 (C2)، (C4)، (C7-C8)
(I5) inserted_window_dims ثابت التوتر ذو البعد الواحد من النوع si64 (C2)، (C4)، (C9-C11)
(I6) input_batching_dims ثابت التوتر ذو البعد الواحد من النوع si64 (C2)، (C4)، (C9)، (C12-13)، (C17-18)، (C20)
(I7) scatter_indices_batching_dims ثابت التوتر ذو البعد الواحد من النوع si64 (C14-C18)
(I8) scatter_dims_to_operand_dims ثابت التوتر ذو البعد الواحد من النوع si64 (C19-C21)
(I9) index_vector_dim ثابت من النوع si64 (C4)، (C16)، (C19)، (C22)
(I10) indices_are_sorted ثابت من النوع i1
(I11) unique_indices ثابت من النوع i1
(I12) update_computation دالة (C23)

المُخرَجات

الاسم النوع القيود
results الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق (C24-C25)

القيود

  • (ج1) same(shape(inputs...)).
  • (C2) `rank(inputs[0]) = size(update_window_dims) + size(inserted_window_dims)
    • size(input_batching_dims)`.
  • (C3) same(shape(updates...)):
  • (C4) shape(updates[0]) = combine(update_scatter_dim_sizes, update_window_dim_sizes) حيث:
    • update_scatter_dim_sizes = shape(scatter_indices) باستثناء ذلك حجم البُعد scatter_indices بما يتوافق مع لم يتم تضمين index_vector_dim.
    • update_window_dim_sizes <= shape(inputs[0]) باستثناء ذلك أحجام السمات في inputs[0] بما يتوافق مع inserted_window_dims وinput_batching_dims غير متضمنة.
    • يضع combine update_scatter_dim_sizes في المحاور المقابلة لـ update_scatter_dims وupdate_window_dim_sizes على المحورين المقابلين إلى update_window_dims.
  • (C5) 0 < size(inputs) = size(updates) = N.
  • (C6) element_type(updates...) = element_type(inputs...).
  • (C7) is_unique(update_window_dims) and is_sorted(update_window_dims).
  • (C8) 0 <= update_window_dims < rank(updates[0]).
  • (C9) is_unique(concatenate(inserted_window_dims, input_batching_dims))
  • (C10) is_sorted(inserted_window_dims).
  • (C11) 0 <= inserted_window_dims < rank(inputs[0]).
  • (C12) is_sorted(input_batching_dims).
  • (C13) 0 <= input_batching_dims < rank(inputs[0])).
  • (C14) is_unique(scatter_indices_batching_dims).
  • (C15) 0 <= scatter_indices_batching_dims < rank(scatter_indices).
  • (C16) index_vector_dim not in scatter_indices_batching_dims.
  • (C17) size(input_batching_dims) == size(scatter_indices_batching_dims).
  • (C18) dim(inputs[0], input_batching_dims...) = dim(scatter_indices, scatter_indices_batching_dims...).
  • (C19) size(scatter_dims_to_operand_dims) = index_vector_dim < rank(scatter_indices) ? dim(scatter_indices, index_vector_dim) : 1.
  • (C20) is_unique(concatenate(scatter_dims_to_operand_dims, input_batching_dims)).
  • (C21) 0 <= scatter_dims_to_operand_dims < rank(inputs[0]).
  • (C22) 0 <= index_vector_dim <= rank(scatter_indices).
  • (C23) update_computation يحتوي على النوع (tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ..., tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>)، حيث is_promotable(element_type(inputs[i]), Ei).
  • (C24) shape(inputs...) = shape(results...).
  • (C25) element_type(results[i]) = Ei لكل i في [0,N).

أمثلة

// %input: [
//          [
//           [[1, 2], [3, 4], [5, 6], [7, 8]],
//           [[9, 10],[11, 12], [13, 14], [15, 16]],
//           [[17, 18], [19, 20], [21, 22], [23, 24]]
//          ],
//          [
//           [[25, 26], [27, 28], [29, 30], [31, 32]],
//           [[33, 34], [35, 36], [37, 38], [39, 40]],
//           [[41, 42], [43, 44], [45, 46], [47, 48]]
//          ]
//         ]
// %scatter_indices: [
//                    [
//                     [[0, 0], [1, 0], [2, 1]],
//                     [[0, 1], [1, 1], [0, 9]]
//                    ],
//                    [
//                     [[0, 0], [2, 1], [2, 2]],
//                     [[1, 2], [0, 1], [1, 0]]
//                    ]
//                   ]
// %update: [
//           [
//            [[1, 1], [1, 1], [1, 1]],
//            [[1, 1], [1, 1], [1, 1]]
//           ],
//           [
//            [[1, 1], [1, 1], [1, 1]],
//            [[1, 1], [1, 1], [1, 1]]
//           ]
//          ]
%result = "stablehlo.scatter"(%input, %scatter_indices, %update) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
    "stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
  scatter_dimension_numbers = #stablehlo.scatter<
    update_window_dims = [3, 4],
    inserted_window_dims = [1],
    input_batching_dims = [0],
    scatter_indices_batching_dims = [1],
    scatter_dims_to_operand_dims = [2, 1],
    index_vector_dim = 3>,
  indices_are_sorted = false,
  unique_indices = false
} : (tensor<2x3x4x2xi64>, tensor<2x2x3x2xi64>, tensor<2x2x3x2x2xi64>) -> tensor<2x3x4x2xi64>
// %result: [
//           [
//            [[3, 4], [6, 7], [6, 7], [7, 8]],
//            [[9, 10],[11, 12], [15, 16], [17, 18]],
//            [[17, 18], [19, 20], [22, 23], [24, 25]]
//           ],
//           [
//            [[25, 26], [28, 29], [30, 31], [31, 32]],
//            [[35, 36], [38, 39], [38, 39], [39, 40]],
//            [[41, 42], [44, 45], [46, 47], [47, 48]]
//           ]
//          ]

مزيد من الأمثلة

تحديد

دلالات الألفاظ

لإنشاء متسابق result حيث يتم تحديد كل عنصر من on_true أو موتّر on_false استنادًا إلى قيمة العنصر المتجاوب pred. رسميًا أكثر، result[result_index] = pred_element ? on_true[result_index] : on_false[result_index]، حيث pred_element = rank(pred) = 0 ? pred[] : pred[result_index]. بالنسبة للأنواع الكَمية، تنفذ dequantize_select_quantize(pred, on_true, on_false, type(result))

مدخلات

التصنيف الاسم النوع القيود
(I1) pred متوتر من النوع i1 (C1)
(I2) on_true متوتّر أو مستنسر كمي لكلّ متسابق (C1-C2)
(I3) on_false متوتّر أو مستنسر كمي لكلّ متسابق (C2)

المُخرَجات

الاسم النوع القيود
result متوتّر أو مستنسر كمي لكلّ متسابق (C2)

القيود

  • (ج1) rank(pred) = 0 or shape(pred) = shape(on_true).
  • (C2) baseline_type(on_true) = baseline_type(on_false) = baseline_type(result).

أمثلة

// %pred: [[false, true], [true, false]]
// %on_true: [[1, 2], [3, 4]]
// %on_false: [[5, 6], [7, 8]]
%result = "stablehlo.select"(%pred, %on_true, %on_false) : (tensor<2x2xi1>, tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[5, 2], [3, 8]]

مزيد من الأمثلة

select_and_scatter

دلالات الألفاظ

مبعثر القيم من متوتر source باستخدام scatter بناءً على ناتج reduce_window لم متوتر input باستخدام select ونتج عنه متوتر result.

يوضّح المخطّط التالي طريقة حساب العناصر في result من operand وsource باستخدام مثال ملموس.

select_and_scatter

أكثر رسمية:

  • selected_values = reduce_window_without_init(...) مع مصادر الإدخال التالية:

    • inputs = [operand].
    • يتم استخدام window_dimensions وwindow_strides وpadding كما هي.
    • base_dilations = windows_dilations = 1.
    • تعريف "body" على أنّه:
    def body(arg0: tensor<E>, arg1: tensor<E>) -> tensor<E>:
      return select(arg0, arg1) ? arg0 : arg1;
    

    أين يعمل E = element_type(operand) وreduce_window_without_init تمامًا مثل reduce_window، باستثناء أن schedule للنوع الأساسي لا يشتمل reduce (راجِع تقليل) على قيم init. الوقت حاليًا غير محدد ماذا يحدث إذا لم تحتوي النافذة المقابلة على قيم (#731)

  • result[result_index] = reduce([source_values], [init_value], [0], scatter) حيث:

    • source_values = [source[source_index] for source_index in source_indices].
    • selected_index(source_index) = operand_index إذا selected_values[source_index] يتضمّن العنصر operand من operand_index.
    • source_indices = [source_index for source_index in indices(source) if selected_index(source_index) = result_index].

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتّر أو مستنسر كمي لكلّ متسابق (C1-C4)، (C6)، (C8-C11)
(I2) source متوتّر أو مستنسر كمي لكلّ متسابق (C1)، (C2)
(I3) init_value متسّع 0 بُعدي أو متنسورة كمّية بكل متسابق (C3)
(I4) window_dimensions ثابت التوتر ذو البعد الواحد من النوع si64 (C2)، (C4)، (C5)
(I5) window_strides ثابت التوتر ذو البعد الواحد من النوع si64 (C2)، (C6)، (C7)
(I6) padding ثابت التوتر الثنائي الأبعاد من النوع si64 (C2)، (C8)
(I7) select دالة (C9)
(I8) scatter دالة (C10)

المُخرَجات

الاسم النوع القيود
result متوتّر أو مستنسر كمي لكلّ متسابق (C11-C12)

القيود

  • (ج1) element_type(operand) = element_type(source).
  • (C2) shape(source) = num_windows حيث:
    • padded_operand_shape = padding[:, 0] + shape(operand) + padding[:, 1].
    • is_empty_window = padded_operand_shape = 0 || window_dimensions > padded_operand_shape.
    • num_windows = is_empty_window ? 0 : floor((padded_operand_shape - window_dimensions) / window_strides) + 1.
  • (C3) element_type(init_value) = element_type(operand):
  • (C4) size(window_dimensions) = rank(operand).
  • (C5) 0 < window_dimensions.
  • (C6) size(window_strides) = rank(operand).
  • (C7) 0 < window_strides.
  • (C8) shape(padding) = [rank(operand), 2].
  • (C9) select من النوع (tensor<E>, tensor<E>) -> tensor<i1> حيث يكون E = element_type(operand)
  • (C10) scatter من النوع (tensor<E>, tensor<E>) -> tensor<E> حيث يكون is_promotable(element_type(operand), E)
  • (C11) shape(operand) = shape(result).
  • (C12) element_type(result) = E.

أمثلة

// %operand: [[1, 5], [2, 5], [3, 6], [4, 4]]
// %source: [[5, 6], [7, 8]]
// %init_value: 0
%result = "stablehlo.select_and_scatter"(%operand, %source, %init_value) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %0 = "stablehlo.compare"(%arg0, %arg1) {
      comparison_direction = #stablehlo<comparison_direction GE>
    } : (tensor<i64>, tensor<i64>) -> tensor<i1>
    "stablehlo.return"(%0) : (tensor<i1>) -> ()
}, {
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
    "stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
  window_dimensions = array<i64: 3, 1>,
  window_strides = array<i64: 2, 1>,
  padding = dense<[[0, 1], [0, 0]]> : tensor<2x2xi64>
} : (tensor<4x2xi64>, tensor<2x2xi64>, tensor<i64>) -> tensor<4x2xi64>
// %result: [[0, 0], [0, 0], [5, 14], [7, 0]]

مزيد من الأمثلة

إرسال

دلالات الألفاظ

إرسال inputs إلى قناة channel_id وإنشاء رمز مميّز result

إذا كانت قيمة is_host_transfer هي true، تنقل العملية البيانات إلى المضيف. وإلا سيتم نقل البيانات إلى جهاز آخر. يعني ذلك التنفيذ. تكرر هذه العلامة المعلومات المقدمة في channel_type، لذلك نخطّط في المستقبل للاحتفاظ بواحدة فقط منها. (#666).

مدخلات

التصنيف الاسم النوع القيود
(I1) inputs الأعداد المتباينة للمتسللات أو العشرات الكمي
(I2) token token
(I3) channel_id ثابت من النوع si64
(I4) channel_type تعداد DEVICE_TO_DEVICE وDEVICE_TO_HOST (C1)
(I5) is_host_transfer ثابت من النوع i1 (C1)

المُخرَجات

الاسم النوع
result token

القيود

  • (C1) يتم تعريف channel_type على النحو التالي:
    • DEVICE_TO_HOST إذا is_host_transfer = true،
    • DEVICE_TO_DEVICE بخلاف ذلك.

أمثلة

%result = "stablehlo.send"(%operand, %token) {
  channel_handle = #stablehlo.channel_handle<handle = 1, type = 2>,
  is_host_transfer = true
} : (tensor<2x2xi64>, !stablehlo.token) -> !stablehlo.token

مزيد من الأمثلة

shift_left

دلالات الألفاظ

لتنفيذ عملية التغيير الأيسر على مستوى العناصر في متسابق lhs بمقدار rhs البت وينتج متسابق result.

مدخلات

التصنيف الاسم النوع القيود
(I1) lhs متوتر لنوع العدد الصحيح (C1)
(I2) rhs متوتر لنوع العدد الصحيح (C1)

المُخرَجات

الاسم النوع القيود
result متوتر لنوع العدد الصحيح (C1)

القيود

  • (ج1) type(lhs) = type(rhs) = type(result).

أمثلة

// %lhs: [-1, 0, 1]
// %rhs: [1, 2, 3]
%result = "stablehlo.shift_left"(%lhs, %rhs): (tensor<3xi64>, tensor<3xi64>) -> tensor<3xi64>
// %result: [-2, 0, 8]

مزيد من الأمثلة

shift_right_arithmetic

دلالات الألفاظ

ينفذ عملية الانتقال الأيمن حسابيًا من حيث العناصر على موتر lhs من خلال عدد rhs من البتات وينتج متسابق result.

مدخلات

التصنيف الاسم النوع القيود
(I1) lhs متوتر لنوع العدد الصحيح (C1)
(I2) rhs متوتر لنوع العدد الصحيح (C1)

المُخرَجات

الاسم النوع القيود
result متوتر لنوع العدد الصحيح (C1)

القيود

  • (ج1) type(lhs) = type(rhs) = type(result).

أمثلة

// %lhs: [-1, 0, 8]
// %rhs: [1, 2, 3]
%result = "stablehlo.shift_right_arithmetic"(%lhs, %rhs): (tensor<3xi64>, tensor<3xi64>) -> tensor<3xi64>
// %result: [-1, 0, 1]

مزيد من الأمثلة

shift_right_logical

دلالات الألفاظ

لتنفيذ عملية التحول الأيمن المنطقية من حيث العناصر على موتر lhs بواسطة rhs عدد وحدات البت وينتج موتّر result.

مدخلات

التصنيف الاسم النوع القيود
(I1) lhs متوتر لنوع العدد الصحيح (C1)
(I2) rhs متوتر لنوع العدد الصحيح (C1)

المُخرَجات

الاسم النوع القيود
result متوتر لنوع العدد الصحيح (C1)

القيود

  • (ج1) type(lhs) = type(rhs) = type(result).

أمثلة

// %lhs: [-1, 0, 8]
// %rhs: [1, 2, 3]
%result = "stablehlo.shift_right_logical"(%lhs, %rhs): (tensor<3xi64>, tensor<3xi64>) -> tensor<3xi64>
// %result: [9223372036854775807, 0, 1]

مزيد من الأمثلة

علامة

دلالات الألفاظ

لعرض علامة operand من حيث الصياغة وينتج سينسور result. وبشكل أكثر رسمية، لكل عنصر x، يمكن التعبير عن الدلالات باستخدام بناء جملة بايثون على النحو التالي:

def sign(x):
  if is_integer(x):
    if compare(x, 0, LT, SIGNED): return -1
    if compare(x, 0, EQ, SIGNED): return 0
    return 1
  elif is_float(x):
    if is_nan(x): return NaN
    if compare(x, -0.0, EQ, FLOAT): return -0.0
    if compare(x, +0.0, EQ, FLOAT): return +0.0
    if compare(x, 0.0, LT, FLOAT): return -1.0
    return 1.0
  elif is_complex(x):
    if is_nan(real(x)) or is_nan(imag(x)): return (NaN, NaN)
    if compare(x, (0.0, 0.0), EQ, FLOAT): return (0.0, 0.0)
    return divide(x, convert(abs(x), type(x)))

بالنسبة للأنواع الكَمية، تنفذ dequantize_op_quantize(sign, operand, type(result))

مدخلات

التصنيف الاسم النوع القيود
(I1) operand موتّر عدد صحيح بعلامة أو نقطة عائمة أو نوع مركب أو مٍنسور كمي لكل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result موتّر عدد صحيح بعلامة أو نقطة عائمة أو نوع مركب أو مٍنسور كمي لكل متسابق (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(result).

أمثلة

// Logical values: +NaN, -1.0, -0.0, +0.0, 1.0
// operand: [0x7FFFFFFFFFFFFFFF, -1.0, -0.0, 0.0, 1.0]
%result = "stablehlo.sign"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// Logical values: +NaN, -1.0, -0.0, +0.0, 1.0
// %result: [0x7FFFFFFFFFFFFFFF, -1.0, -0.0, 0.0, 1.0]

مزيد من الأمثلة

جيب الزاوية

دلالات الألفاظ

لتنفيذ عملية جيب الزاوية من ناحية العناصر على متسّع operand وينتج عنه result متنسور. حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى الأعداد العشرية: sin من IEEE-754.
  • بالنسبة إلى الأعداد المركّبة: جيب الزاوية المركّبة.
  • بالنسبة إلى الأنواع الكَمية: dequantize_op_quantize(sine, operand, type(result)).

مدخلات

التصنيف الاسم النوع القيود
(I1) operand مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(result).

أمثلة

// %operand: [
//            [0.0, 1.57079632],       // [0, pi/2]
//            [3.14159265, 4.71238898] // [pi, 3pi/2]
//           ]
%result = "stablehlo.sine"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[0.0, 1.0], [0.0, -1.0]]

مزيد من الأمثلة

slice

دلالات الألفاظ

لاستخراج شريحة من operand باستخدام فهارس بدء محسوبة بشكلٍ ثابت وينتج موتر result. يحتوي start_indices على مؤشرات البداية الخاصة بـ الشريحة لكل بُعد، ويحتوي limit_indices على فهارس النهاية (حصريًا) للشريحة لكل بُعد، ويحتوي strides على الخطوات لكل سمة

بشكل رسمي، result[result_index] = operand[operand_index] حيث operand_index = start_indices + result_index * strides

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتّر أو مستنسر كمي لكلّ متسابق (C1-C3)، (C5)
(I2) start_indices ثابت التوتر ذو البعد الواحد من النوع si64 (C2)، (C3)، (C5)
(I3) limit_indices ثابت التوتر ذو البعد الواحد من النوع si64 (C2)، (C3)، (C5)
(I4) strides ثابت التوتر ذو البعد الواحد من النوع si64 (C2)، (C4)

المُخرَجات

الاسم النوع القيود
result متوتّر أو مستنسر كمي لكلّ متسابق (C1)، (C5)

القيود

  • (ج1) element_type(operand) = element_type(result).
  • (C2) size(start_indices) = size(limit_indices) = size(strides) = rank(operand).
  • (C3) 0 <= start_indices <= limit_indices <= shape(operand):
  • (C4) 0 < strides.
  • (C5) shape(result) = ceil((limit_indices - start_indices) / strides).

أمثلة

// %operand: [
//            [0, 0, 0, 0],
//            [0, 0, 1, 1],
//            [0, 0, 1, 1]
//           ]
%result = "stablehlo.slice"(%operand) {
  start_indices = array<i64: 1, 2>,
  limit_indices = array<i64: 3, 4>,
  strides = array<i64: 1, 1>
} : (tensor<3x4xi64>) -> tensor<2x2xi64>
// % result: [
//            [1, 1],
//            [1, 1]
//           ]

مزيد من الأمثلة

ترتيب

دلالات الألفاظ

فرز الشرائح ذات البعد الواحد inputs بجانب البُعد dimension معًا، وفقًا لـ comparator، وتنتج results.

وعلى عكس المدخلات المماثلة في العمليات الأخرى، تسمح الدالة dimension بالقيم السالبة، مع الدلالات الموضحة أدناه. قد لا يتم السماح بهذا الإجراء في المستقبل لأسباب تتعلق بالاتساق (#1377)

إذا كانت is_stable صحيحة، فهذا يعني أن الترتيب ثابت، أي الترتيب النسبي العناصر التي تعتبرها المقارن متساوية. للحافظة عندما يكون هناك إدخال واحد، يعتبر العنصران e1 وe2 هما: يساوي المُقارن إذا كان comparator(e1, e2) = comparator(e2, e1) = false اطّلِع على عملية الإعداد الرسمي أدناه. حول كيفية تعميم ذلك على إدخالات متعددة.

بشكل رسمي، لجميع result_index في index_space(results[0]):

  • adjusted_dimension = dimension >= 0 ? dimension : rank(inputs[0]) + dimension.
  • result_slice = [ri0, ..., :, ..., riR-1] حيث يكون riN فرديًا العناصر في result_index، وتم إدراج : في adjusted_dimension.
  • inputs_together = (inputs[0]..., ..., inputs[N-1]...).
  • results_together[result_slice] = sort(inputs_together[result_slice], comparator_together).
  • حيث يقوم sort بترتيب شريحة أحادية البُعد بترتيب غير تنازلي متوقعًا أن comparator_together تعرض true إذا كانت الوسيطة اليسرى أقل من الوسيطة الثانية اليمنى.
  • def comparator_together(lhs_together, rhs_together):
      args = []
      for (lhs_el, rhs_el) in zip(lhs_together, rhs_together):
        args.append(lhs_el)
        args.append(rhs_el)
      return comparator(*args)
    
  • (results[0]..., ..., results[N-1]...) = results_together.

مدخلات

التصنيف الاسم النوع القيود
(I1) inputs الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق (C1-C5)
(I2) dimension ثابت من النوع si64 (C4)
(I3) is_stable ثابت من النوع i1
(I4) comparator دالة (C5)

المُخرَجات

الاسم النوع القيود
results الأعداد المتباينة للأتسلس أو المتسّعات الكميّة لكل متسابق (C2)، (C3)

القيود

  • (ج1) 0 < size(inputs).
  • (C2) type(inputs...) = type(results...).
  • (C3) same(shape(inputs...) + shape(results...)):
  • (C4) -R <= dimension < R، حيث R = rank(inputs[0]).
  • (C5) النوع comparator (tensor<E1>, tensor<E1>, ..., tensor<EN-1>, tensor<EN-1>) -> tensor<i1>, حيث Ei = element_type(inputs[i]).

أمثلة

// %input0 = [[1, 2, 3], [3, 2, 1]]
// %input1 = [[3, 2, 1], [1, 2, 3]]
%result0, %result1 = "stablehlo.sort"(%input0, %input1) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>, %arg2: tensor<i64>, %arg3: tensor<i64>):
    %predicate = "stablehlo.compare"(%arg0, %arg1) {
      comparison_direction = #stablehlo<comparison_direction GT>
    } : (tensor<i64>, tensor<i64>) -> tensor<i1>
    "stablehlo.return"(%predicate) : (tensor<i1>) -> ()
}) {
  dimension = 0 : i64,
  is_stable = true
} : (tensor<2x3xi64>, tensor<2x3xi64>) -> (tensor<2x3xi64>, tensor<2x3xi64>)
// %result0 = [[3, 2, 3], [1, 2, 1]]
// %result1 = [[1, 2, 1], [3, 2, 3]]

مزيد من الأمثلة

ربع السنة الحالي

دلالات الألفاظ

لتنفيذ عملية جذر تربيعي حسب العناصر على موتّر operand وينتج عنه متوتر result حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى الأعداد العشرية: squareRoot من IEEE-754.
  • بالنسبة إلى الأعداد المركّبة: جذر تربيعي مركّب.
  • بالنسبة إلى الأنواع الكَمية: dequantize_op_quantize(sqrt, operand, type(result)).

مدخلات

التصنيف الاسم النوع القيود
(I1) operand مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(result).

أمثلة

// %operand: [[0.0, 1.0], [4.0, 9.0]]
%result = "stablehlo.sqrt"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[0.0, 1.0], [2.0, 3.0]]

مزيد من الأمثلة

طرح

دلالات الألفاظ

لتنفيذ عملية طرح على مستوى العناصر لاثنين من المتوترين lhs وrhs وينتج عن ذلك متوتر result حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى الأعداد الصحيحة: طرح الأعداد الصحيحة.
  • بالنسبة إلى الأعداد العشرية: subtraction من IEEE-754.
  • بالنسبة إلى الأعداد المركّبة: الطرح المركَّب.
  • بالنسبة إلى الأنواع الكَمية:
    • dequantize_op_quantize(subtract, lhs, rhs, type(result)).

مدخلات

التصنيف الاسم النوع القيود
(I1) lhs موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المنزِّع الكمي لكل متسابق (C1)
(I2) rhs موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المنزِّع الكمي لكل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result موتّر العدد الصحيح أو النقطة العائمة أو النوع المركّب أو المنزِّع الكمي لكل متسابق (C1)

القيود

  • (ج1) baseline_type(lhs) = baseline_type(rhs) = baseline_type(result).

أمثلة

// %lhs: [[6, 8], [10, 12]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.subtract"(%lhs, %rhs) : (tensor<2x2xf32>, tensor<2x2xf32>) -> (tensor<2x2xf32>)
// %result: [[1, 2], [3, 4]]

مزيد من الأمثلة

tan

دلالات الألفاظ

لتنفيذ عملية ظل الزاوية من ناحية العناصر على متسّع operand وينتج عنه متوتر result حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى الأعداد العشرية: tan من IEEE-754.
  • للأعداد المركّبة: المماس المعقد.
  • بالنسبة إلى الأنواع الكَمية: dequantize_op_quantize(tan, operand, type(result)).

مدخلات

التصنيف الاسم النوع القيود
(I1) operand مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(result).

أمثلة

// %operand: [
//            [0.0, 1.57079632],       // [0, pi/2]
//            [3.14159265, 4.71238898] // [pi, 3pi/2]
//           ]
%result = "stablehlo.tan"(%operand) : (tensor<2x2xf64>) -> tensor<2x2xf64>
// %result: [
//           [0.0, 1.63312e+16],
//           [0.0, 5.44375e+15]
//          ]

مزيد من الأمثلة

تانه

دلالات الألفاظ

لتنفيذ عملية المماس الزائدي من حيث العناصر على متسابق operand نحصل على موتّر result. حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى الأعداد العشرية: tanh من IEEE-754.
  • بالنسبة إلى الأعداد المركّبة: المماس الزائدي المركّب.
  • بالنسبة إلى الأنواع الكَمية:
    • dequantize_op_quantize(tanh, operand, type(result)).

مدخلات

التصنيف الاسم النوع القيود
(I1) operand مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

المُخرَجات

الاسم النوع القيود
result مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(result).

أمثلة

// %operand: [-1.0, 0.0, 1.0]
%result = "stablehlo.tanh"(%operand) : (tensor<3xf32>) -> tensor<3xf32>
// %result: [-0.76159416, 0.0, 0.76159416]

مزيد من الأمثلة

تبديل الموقع

دلالات الألفاظ

لتنفيذ أبعاد مترابط operand باستخدام permutation وينتج عن ذلك متوتر result بشكل رسمي، result[result_index] = operand[operand_index] حيث result_index[d] = operand_index[permutation[d]].

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتر أو متنسّر كمي (C1-C4)
(I2) permutation ثابت التوتر ذو البعد الواحد من النوع si64 (C2-C4)

المُخرَجات

الاسم النوع القيود
result متوتر أو متنسّر كمي (C1)، (C3-C4)

القيود

  • (C1) element_type(result) يتم تقديمها من خلال:
    • element_type(operand)، إذا كانت !is_per_axis_quantized(operand).
    • element_type(operand) باستثناء أنّ quantization_dimension(operand) قد تختلف السمة quantization_dimension(result) في الحالات الأخرى.
  • (C2) permutation هو تبديل لـ range(rank(operand)).
  • (C3) shape(result) = dim(operand, permutation...):
  • (C4) إذا كانت is_per_axis_quantized(result)، إذًا quantization_dimension(operand) = permutation(quantization_dimension(result))

أمثلة

// %operand: [
//            [[1,2], [3,4], [5,6]],
//            [[7,8], [9,10], [11,12]]
//           ]
%result = "stablehlo.transpose"(%operand) {
  permutation = array<i64: 2, 1, 0>
} : (tensor<2x3x2xi32>) -> tensor<2x3x2xi32>
// %result: [
//           [[1,7], [3,9], [5,11]],
//           [[2,8], [4,10], [6,12]]
//          ]

مزيد من الأمثلة

triangular_solve

دلالات الألفاظ

حلّ مجموعات أنظمة المعادلات الخطية ذات المثلثات السفلية أو العليا مصفوفات المعاملات.

بشكل أكثر رسمية، بالنظر إلى a وb، يكون result[i0, ..., iR-3, :, :] هو الحل إلى op(a[i0, ..., iR-3, :, :]) * x = b[i0, ..., iR-3, :, :] عندما يكون left_side true أو x * op(a[i0, ..., iR-3, :, :]) = b[i0, ..., iR-3, :, :] عندما قيمة left_side هي false، ما يؤدي إلى حل المتغير x حيث يتم تحديد op(a). بحلول transpose_a، والذي يمكن أن يكون واحدًا مما يلي:

  • NO_TRANSPOSE: يمكنك إجراء العملية باستخدام a كما هي.
  • TRANSPOSE: إجراء عملية على تبديل موضع a.
  • ADJOINT: إجراء عملية على التبديل المصاحب لـ a.

لا تتم قراءة بيانات الإدخال إلا من المثلث السفلي في a، إذا كانت قيمة lower true أو المثلث العلوي في a، وإلا. يتم إرجاع بيانات الإخراج في نفس المثلث؛ والقيم في المثلث الآخر محددة التنفيذ.

إذا كانت unit_diagonal صحيحة، فإن التنفيذ قد يفترض أن يكون القطر تساوي عناصر a 1، وإلا يكون السلوك غير محدد.

بالنسبة للأنواع الكَمية، تنفذ dequantize_op_quantize(lambda x, y: triangular_solve(x, y, left_side, lower, unit_diagonal, transpose_a), a, b, type(result))

مدخلات

التصنيف الاسم النوع القيود
(I1) a مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1-C3)
(I2) b مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1-C4)
(I3) left_side ثابت من النوع i1 (C3)
(I4) lower ثابت من النوع i1
(I5) unit_diagonal ثابت من النوع i1
(I6) transpose_a تعداد NO_TRANSPOSE وTRANSPOSE وADJOINT

المُخرَجات

الاسم النوع القيود
result مأخذ النقطة العائمة أو النوع المركّب أو المتسّع الكمّي حسب كل متسابق (C1)

القيود

  • (ج1) baseline_element_type(a) = baseline_element_type(b).
  • (C2) 2 <= rank(a) = rank(b) = R.
  • (C3) يتم تعريف العلاقة بين shape(a) وshape(b) على النحو التالي:
    • shape(a)[:-3] = shape(b)[:-3].
    • dim(a, -2) = dim(a, -1) = dim(b, left_side ? -2 : -1).
  • (C4) baseline_type(b) = baseline_type(result).

أمثلة

// %a = [
//       [1.0, 0.0, 0.0],
//       [2.0, 4.0, 0.0],
//       [3.0, 5.0, 6.0]
//      ]
// %b = [
//       [2.0, 0.0, 0.0],
//       [4.0, 8.0, 0.0],
//       [6.0, 10.0, 12.0]
//      ]
%result = "stablehlo.triangular_solve"(%a, %b) {
  left_side = true,
  lower = true,
  unit_diagonal = false,
  transpose_a = #stablehlo<transpose NO_TRANSPOSE>
} : (tensor<3x3xf32>, tensor<3x3xf32>) -> tensor<3x3xf32>
// %result: [
//           [2.0, 0.0, 0.0],
//           [0.0, 2.0, 0.0],
//           [0.0, 0.0, 2.0]
//          ]

صف

دلالات الألفاظ

تنتج صف result من القيم val.

مدخلات

التصنيف الاسم النوع القيود
(I1) val العدد المتغير للقيم (C1)

المُخرَجات

الاسم النوع القيود
result صف (C1)

القيود

  • (C1) النوع result يحتوي على النوع tuple<E0, ..., EN-1> حيث Ei = type(val[i]).

أمثلة

// %val0: [1.0, 2.0]
// %val1: (3)
%result = "stablehlo.tuple"(%val0, %val1) : (tensor<2xf32>, tuple<tensor<i32>>) -> tuple<tensor<2xf32>, tuple<tensor<i32>>>
// %result: ([1.0, 2.0], (3))

مزيد من الأمثلة

uniform_dequantize

دلالات الألفاظ

لإجراء تحويل من ناحية العناصر للمتنسور operand الكمي إلى قيمة موتر النقطة العائمة result وفقًا لمعلمات القياس المحددة حسب النوع operand.

اسم "result = dequantize(operand)" رسميًا.

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متوتر كمي (C1)، (C2)

المُخرَجات

الاسم النوع القيود
result متّجه من نوع النقطة العائمة (C1)، (C2)

القيود

  • (ج1) shape(operand) = shape(result).
  • (C2) element_type(result) = expressed_type(operand).

أمثلة

// %operand: [10, 10]
%result = "stablehlo.uniform_dequantize"(%operand) : (tensor<2x!quant.uniform<i8:f32:0, {0.1:-30,0.5:-20}>>) -> tensor<2xf32>
// %result: [4.0, 15.0]

uniform_quantize

دلالات الألفاظ

لإجراء تحويل من ناحية العناصر لمتنس النقطة العائمة أو متنسورة الكمي operand إلى موصّل كمي result حسب الكمّي التي يتم تحديدها بواسطة النوع result.

بشكل أكثر رسمية،

  • إذا كانت is_float(operand):
    • result = quantize(operand, type(result)).
  • إذا كانت is_quantized(operand):
    • float_result = dequantize(operand).
    • result = quantize(float_result, type(result)).

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متّجه النقطة العائمة أو النوع الكمي (C1)، (C2)

المُخرَجات

الاسم النوع القيود
result متوتر كمي (C1)، (C2)

القيود

  • (ج1) shape(operand) = shape(result).
  • (C2) expressed_type(result) = is_float(operand) ? element_type(operand) : expressed_type(operand).

أمثلة

// %operand: [4.0, 15.0]
%result = "stablehlo.uniform_quantize"(%operand) : (tensor<2xf32>) -> tensor<2x!quant.uniform<i8:f32:0, {0.1:-30,0.5:-20}>>
// %result: [10, 10]

// %operand: [10, 10]
%result = "stablehlo.uniform_quantize"(%operand) : (tensor<2x!quant.uniform<i8:f32:0, {0.1:-30,0.5:-20}>>) -> tensor<2x!quant.uniform<i8:f32:0, {0.1:-20,0.2:-30}>>
// %result: [20, 45]

بينما

دلالات الألفاظ

الحصول على ناتج تنفيذ الدالة body 0 مرة أو أكثر أثناء مخرجات الدالة cond true. بشكل أكثر رسمية، يمكن التعبير عن الدلالات باستخدام بناء جملة بايثون على النحو التالي:

internal_state = operand
while cond(*internal_state):
  internal_state = body(*internal_state)
results = internal_state

يتم تحديد سلوك التكرار اللانهائي لاحقًا (#383)

مدخلات

التصنيف الاسم النوع القيود
(I1) operand الأعداد المتباينة من متساعات التوتر أو العشرات الكمية أو الرموز المميزة (C1-C3)
(I2) cond دالة (C1)
(I3) body دالة (C2)

المُخرَجات

الاسم النوع القيود
results الأعداد المتباينة من متساعات التوتر أو العشرات الكمية أو الرموز المميزة (C3)

القيود

  • (C1) cond من النوع (T0, ..., TN-1) -> tensor<i1>، حيث Ti = type(operand[i])
  • (C2) body من النوع (T0, ..., TN-1) -> (T0, ..., TN-1)، حيث Ti = type(operand[i])
  • (C3) type(results...) = type(operand...):

أمثلة

// %init_i: 1
// %init_sum: 0
// %one: 1
// %ten: 10
%results0, %results1 = "stablehlo.while"(%init_i, %init_sum) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %cond = "stablehlo.compare"(%arg0, %ten) {
      comparison_direction = #stablehlo<comparison_direction LT>
    } : (tensor<i64>, tensor<i64>) -> tensor<i1>
    stablehlo.return %cond : tensor<i1>
  }, {
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %new_sum = stablehlo.add %arg1, %one : tensor<i64>
    %new_i = stablehlo.add %arg0, %one : tensor<i64>
    stablehlo.return %new_i, %new_sum : tensor<i64>, tensor<i64>
}) : (tensor<i64>, tensor<i64>) -> (tensor<i64>, tensor<i64>)
// %results0: 10
// %results1: 10

مزيد من الأمثلة

xor

دلالات الألفاظ

تؤدي هذه الإجراءات إلى تنفيذ XOR من ناحية العناصر باستخدام معاملين lhs وrhs وينتج عن ذلك result. متنسور. حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى القيم المنطقية: يستخدم XOR المنطقي.
  • بالنسبة إلى الأعداد الصحيحة: XOR على مستوى البت.

مدخلات

التصنيف الاسم النوع القيود
(I1) lhs متّصِل من نوع القيمة المنطقية أو العدد الصحيح (C1)
(I2) rhs متّصِل من نوع القيمة المنطقية أو العدد الصحيح (C1)

المُخرَجات

الاسم النوع القيود
result متّصِل من نوع القيمة المنطقية أو العدد الصحيح (C1)

القيود

  • (ج1) type(lhs) = type(rhs) = type(result).

أمثلة

// Bitwise operation with with integer tensors
// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.xor"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[4, 4], [4, 12]]

// Logical operation with with boolean tensors
// %lhs: [[false, false], [true, true]]
// %rhs: [[false, true], [false, true]]
%result = "stablehlo.xor"(%lhs, %rhs) : (tensor<2x2xi1>, tensor<2x2xi1>) -> tensor<2x2xi1>
// %result: [[false, true], [true, false]]

مزيد من الأمثلة

التشغيل التفاعلي للّغات

وفي الوقت الحالي، تحتوي برامج StableHLO المتوفّرة في البرية على عمليات لم يتم تحديدها بواسطة StableHLO.

الوحدة، الوظيفة، الاتصال والعودة

يستخدم StableHLO عمليات MLIR الأولية لعمليات ModuleOp وFuncOp وCallOp ReturnOp. وقد تم إجراء ذلك لتحسين إمكانية التشغيل التفاعلي مع أجهزة MLIR الحالية، بطاقات مفيدة تستهدف FuncOp وModuleOp، والعديد من تجميع حول المشروعات تتوقع وجود هذه العمليات. تُعد ضمانات التوافق الكامل تطبيقها على هذه العمليات. إذا تغير أي شيء في أي وقت حول هذه العمليات في غير متوافقة (أي الإزالة)، ستتم إضافة مكافئات StableHLO للحفاظ على التوافق.

CHLO

تحتوي عملية CHLO على عمليات مستوى أعلى يتم تحليلها إلى StableHLO. ما مِن ضمانات توافق في الوقت الحالي مع CHLO. للتوافق أي ضمان، تصريح chlo-legalize-to-stablehlo قبل إنشاء التسلسل.

عمليات الأشكال

إنها حالة استخدام شائعة في المجتمع لاستخدام عمليات معينة من لهجات MLIR في برامج StableHLO الديناميكية لإجراء عمليات حسابية للأشكال وتشمل هذه العناوين اللهجة shape بشكل أكثر شيوعًا. العمليات مثل shape_of أو num_elements، لهجة tensor عمليات مثل dim أو from_elements، والنوع index المدمج.

Dynamism RFC > O2 أن ذلك خارج النطاق، إلا أن بعض التوافق مع أنواع index لأغراض التشغيل التفاعلي. ليس هناك أي ضمانات للتوافق مع هذه العمليات أو الأنواع. shape-legalize-to-stablehlo يمكن استخدام البطاقة لتحويل هذه العمليات إلى عمليات StableHLO متوافقة بالكامل.

عمليات متوقّفة نهائيًا

هناك العديد من عمليات StableHLO التي تم اكتسابها من MHLO التي تم إيقافها وهي في طريقها للخروج من StableHLO. ستساعدك التفاصيل الكاملة حول هذه ويمكن العثور على عمليات الإزالة في StableHLO v1.0 Cleanup #2283. مشكلة أداة التتبُّع الخاصة بعمليات الإيقاف هذه هي #2340.

وتندرج هذه العمليات ضمن فئات قليلة:

  • "ليس في HLO" فئة عمليات StableHLO - كانت في البداية جزءًا من فرصة StableHLO ولكن تم اعتبارها غير مناسبة لاحقًا بشكل جيد: "broadcast" و"create_token" و"cross-replica-sum" و"dot" و"einsum" torch_index_select، unary_einsum (رقم 3)
  • العمليات غير المستخدمة - ربما كانت هذه العمليات مفيدة في مرحلة ما، ولكن العمليات كانت إما غير متطورة، أو كانت الأنابيب التي تستخدم هذه العمليات إعادة الهيكلة لعدم طلبها بعد الآن. ويشمل ذلك map وtuple (#598) get_tuple_element أو rng أو complex مقارنات #560، والالتفاف window_reversal (#1181).

يمكن إزالة بعض هذه العمليات بسهولة حيث يمكن التعبير عنها باستخدام العمليات الحالية (broadcast، create_token، cross-replica-sum، dot، unary_einsum) وستتم إزالتها بعد فترة التوافق الحالية. البطاقات (6 أشهر). لا يزال البحث عن مجموعات أخرى مطلوب إزالتها (einsum، get_tuple_element، map، rng torch_index_select، tuple، complex والمقارنات، window_reversal). في انتظار ملاحظات المنتدى، ستتم إزالة هذه العمليات أو إضافتها إلى المواصفات بدعم كامل. حتى هذه العمليات معروفة، وضمان توافقها لمدة 6 أشهر فقط.

التنفيذ

التنفيذ التسلسلي

يتم تنفيذ برنامج StableHLO من خلال تقديم قيم إدخال إلى الدالة main وحساب قيم المخرجات. يتم حساب قيم مخرجات الدالة عن طريق تنفيذ الرسم البياني للعمليات الجذر في عملية return المقابلة.

يتم تحديد ترتيب التنفيذ طالما أنّه متوافق مع تدفق البيانات، أي إذا تم تنفيذ العمليات قبل استخدامها. في StableHLO، يتم نقل جميع ذلك أن العمليات ذات الآثار الجانبية تستهلك رمزًا مميزًا واحدًا وتنتج رمزًا مميزًا (يمكن أن تستهلك رموز مميزة يتم مضاعفتها في رمز مميز واحد عبر after_all)، لذا فإن ترتيب التنفيذ والتأثيرات أيضًا مع تدفق البيانات. على سبيل المثال، في البرنامج أدناه هناك أمران تنفيذيان محتملان: %0%1%2return %1%0%2return.

func.func @main() -> tensor<f64> {
  %0 = stablehlo.constant dense<1.0> : tensor<f64>
  %1 = stablehlo.constant dense<2.0> : tensor<f64>
  %2 = stablehlo.add %0, %1 : tensor<f64>
  return %2 : tensor<f64>
}

بشكل أكثر رسمية، تتمثل عملية SttableHLO في مجموعة مما يلي: 1) برنامج StableHLO، 2) حالات التشغيل (لم يتم تنفيذها بعد، بالفعل)، و3) القيم المتوسطة التي تعمل عليها العملية. تبدأ العملية بقيم مدخلات للدالة main وتتقدم إلى الرسم البياني للعمليات التي تعمل على تحديث حالات العملية والقيم المتوسطة ينتهي بقيم المخرجات. يتم تحديد مرحلة إضافية من حيث الطابع الرسمي. (#484)

التنفيذ الموازي

يمكن تنفيذ برامج StableHLO بالتوازي، ويتم تنظيمها في شبكة عمليات ثنائية الأبعاد من num_replicas بواسطة num_partitions وكلاهما من النوع ui32.

في شبكة عملية StableHLO، num_replicas * num_partitions من StableHLO يتم تنفيذ العمليات في نفس الوقت. ولكل عملية لها process_id = (replica_id, partition_id)، حيث replica_id في replica_ids = range(num_replicas) و partition_id في partition_ids = range(num_partitions) وكلاهما لهما اكتب ui32.

يُعرف حجم شبكة العملية ثابتًا لكل برنامج (في فإننا نخطط لجعلها جزءًا صريحًا من برامج StableHLO #650)، فضلاً عن الموضع داخل شبكة العملية معروف بشكل ثابت لكل عملية. تحتوي كل عملية على إلى موضعها داخل شبكة العملية عبر replica_id partition_id عمليات

داخل شبكة العمليات، يمكن أن تكون جميع البرامج متطابقة (في علامة البرنامج، البيانات المتعددة" النمط)، يمكن أن تكون مختلفة (في "برامج متعددة، البيانات المتعددة" ) أو شيء من هذا القبيل. نخطط في المستقبل لتقديم دعم لمصطلحات أخرى خاصة بتحديد برامج StableHLO المتوازية، بما في ذلك GSPMD (#619).

داخل شبكة العملية، تكون العمليات مستقلة في الغالب عن بعضها البعض - لكل منها حالات عملية منفصلة، وقيم إدخال/متوسط/إخراج منفصلة ويتم تنفيذ معظم العمليات بشكل منفصل بين العمليات، باستخدام باستثناء عدد صغير من العمليات الجماعية الموضحة أدناه.

بما أن تنفيذ معظم العمليات يتم فقط باستخدام قيم من نفس الإشارة إلى هذه القيم بأسمائها عادةً لا لبس فيها. ومع ذلك، عند وصف دلالات العمليات الجماعية، فهذا لا يكفي، التي تؤدي إلى ظهور العلامة name@process_id للإشارة إلى القيمة name ضمن عملية معينة. (من هذا المنظور، يمكن اعتبار name غير مؤهل) يُعتبر اختصارًا لـ name@(replica_id(), partition_id())).

يتم تحديد ترتيب التنفيذ في جميع العمليات باستثناء عملية مزامنة بفضل الاتصال من نقطة إلى نقطة والعمليات الجماعية كما هو موضح أدناه.

الاتصال من نقطة إلى نقطة

يمكن أن تتواصل عمليات StableHLO بعضها مع بعض من خلال قنوات SttableHLO: يتم تمثيل القناة بمعرّف موجب من النوع si64 ومن خلال العمليات المختلفة، يمكن إرسال القيم إلى القنوات تتلقاها من القنوات.

إضافة مزيد من التفاصيل الرسمية، مثل مصدر معرّفات القنوات هذه، وكيف والعمليات التي تصبح فيها البرامج على دراية بها ونوع المزامنة قدموها، يتم تحديدها لاحقًا (#484)

اتصال البث

يمكن لكل عملية في StableHLO الوصول إلى واجهتي بث:

  • الإعلان ضمن الخلاصة الذي يمكن القراءة منه
  • الخلاصة التي يمكن الكتابة إليها.

على عكس القنوات، التي تُستخدم للتواصل بين العمليات وبالتالي من طرفيهما، يكون لكل من الخلاصة والخلاصات الخارجية عمليات التنفيذ النهائي.

إضافة مزيد من التفاصيل الرسمية، مثل كيف يؤثر اتصال البث على التنفيذ الترتيب ونوع المزامنة الذي يقدمه، يتم تحديده لاحقًا (#484)

العمليات الجماعية

هناك ست عمليات جماعية في StableHLO: all_gather وall_reduce، all_to_all وcollective_broadcast وcollective_permute reduce_scatter تُقسِّم كل هذه العمليات العمليات في عملية StableHLO إلى مجموعات عمليات ثابت هول (StableHLO) وتنفيذ عملية حسابية مشتركة داخل كل مجموعة عمليات، بشكل مستقل عن مجموعات العمليات الأخرى.

ضمن كل مجموعة عمليات، قد تؤدي العمليات الجماعية إلى إجراء مزامنة حاجز. إضافة مزيد من التفاصيل الرسمية، مثل وأوضح متى بالضبط حدوث المزامنة، أي كيفية وصول العمليات بالضبط إلى هذا الحاجز، وما سيحدث إذا لم يحدث ذلك، سيتم تحديده لاحقًا (#484)

إذا كانت مجموعة العمليات تتضمن تواصلاً متعدد الأقسام، أي أن هناك العمليات في مجموعة العمليات التي تختلف أرقام تعريف الأقسام بها، ثم يتم من العملية الجماعية بحاجة إلى قناة، ويجب أن توفر العملية موجب channel_id من النوع si64. الاتصال بين النُسخ المكررة لا يحتاج إلى بشكل أفضل.

تكون العمليات الحسابية التي تجريها العمليات الجماعية خاصة بالعمليات الفردية وهي موضحة في أقسام العمليات الفردية أعلاه. ومع ذلك، فإن الإستراتيجيات التي يتم التي تنقسم إلى مجموعات عمليات، تتم مشاركتها بين هذه العمليات وهي موضحة في هذا القسم. بشكل رسمي، تدعم StableHLO باتباع الاستراتيجيات الأربع.

cross_replica

تحدث الاتصالات المتبادلة فقط داخل كل مجموعة عمليات. هذا النمط تأخذ الإستراتيجية replica_groups - قائمة بأرقام التعريف المتماثلة - وتحسب منتج الديكارتي (replica_groups) من إعداد partition_ids. replica_groups يجب أن يحتوي على عناصر فريدة وأن يشمل جميع replica_ids. بشكل أكثر رسمية، باستخدام بناء جملة Python:

def cross_replica(replica_groups: List[List[ReplicaId]]) -> List[List[ProcessId]]:
  for replica_group in replica_groups:
    for partition_id in partition_ids:
      process_group = []
      for replica_id in replica_group:
        process_group.append((replica_id, partition_id))
      yield process_group

على سبيل المثال، بالنسبة إلى replica_groups = [[0, 1], [2, 3]] وnum_partitions = 2، سيُنتج cross_replica [[(0, 0), (1, 0)], [(0, 1), (1, 1)], [(2, 0), (3, 0)], [(2, 1), (3, 1)]]

cross_partition

تحدث عمليات التواصل بين الأقسام فقط داخل كل مجموعة عمليات. هذا النمط تستخدم الإستراتيجية partition_groups - وهي قائمة بأرقام تعريف الأقسام - و تحسب حاصل الضرب الديكارتي (partition_groups) من خلال replica_ids. يجب أن يحتوي partition_groups على عناصر فريدة وأن يشمل كل partition_ids. وبشكل رسمي، باستخدام بناء جملة بايثون:

def cross_partition(partition_groups: List[List[PartitionId]]) -> List[List[ProcessId]]:
  for partition_group in partition_groups:
    for replica_id in replica_ids:
      process_group = []
      for partition_id in partition_group:
        process_group.append((replica_id, partition_id))
      yield process_group

على سبيل المثال، بالنسبة إلى partition_groups = [[0, 1]] وnum_replicas = 4، سيُنتج cross_partition [[(0, 0), (0, 1)], [(1, 0), (1, 1)], [(2, 0), (2, 1)], [(3, 0), (3, 1)]]

cross_replica_and_partition

قد تحدث كل من الاتصالات المتبادلة والمشتركة بين الأقسام في كل مجموعة العمليات. تستغرق هذه الاستراتيجية replica_groups - وهي عبارة عن قائمة من قوائم نُسخ طبق الأصل - وتحسب المنتجات الديكارتية لكل replica_group حسب partition_ids يجب أن يحتوي replica_groups على عناصر فريدة وأن يشمل كل العناصر replica_ids وبشكل رسمي، باستخدام بناء جملة بايثون:

def cross_replica_and_partition(replica_groups: List[List[ReplicaId]]) -> List[List[ProcessId]]:
  for replica_group in replica_groups:
    process_group = []
    for partition_id in partition_ids:
      for replica_id in replica_group:
        process_group.append((replica_id, partition_id))
    yield process_group

على سبيل المثال، بالنسبة إلى replica_groups = [[0, 1], [2, 3]] وnum_partitions = 2، سيُنتج cross_replica_and_partition [[(0, 0), (1, 0), (0, 1), (1, 1)], [(2, 0), (3, 0), (2, 1), (3, 1)]]

flattened_ids

تستغرق هذه الاستراتيجية flattened_id_groups، وهي عبارة عن قائمة من القوائم "المُقسّمة". أرقام تعريف العمليات في شكل replica_id * num_partitions + partition_id وتحويلها إلى أرقام تعريف للعمليات. يجب أن يتضمّن flattened_id_groups عناصر فريدة. وتغطي جميع process_ids. وبشكل رسمي، باستخدام بناء جملة بايثون:

def flattened_ids(flattened_id_groups: List[List[ui32]]) -> List[List[ProcessId]]:
  for flattened_id_group in flattened_id_groups:
    process_group = []
    for flattened_id in flattened_id_group:
      replica_id = flattened_id // num_partitions
      partition_id = flattened_id % num_partitions
      process_group.append((replica_id, partition_id))
    yield process_group

على سبيل المثال، بالنسبة إلى flattened_id_groups = [[0, 1, 2, 3], [4, 5, 6, 7]]، num_replicas = 4 وnum_partitions = 2، وflattened_ids ينتج عنهما [[(0, 0), (0, 1), (1, 0), (1, 1)], [(2, 0), (2, 1), (3, 0), (3, 1)]]

الدقة

وفي الوقت الحالي، لا تقدّم قناة StableHLO أي ضمانات بشأن الدقة الرقمية ولكن قد يتغير هذا في المستقبل (#1156)

دلالات تنفيذ العملية الكمية

قد يختلف التفسير للعمليات الكميّة لـ StableHLO حسب متطلبات الأجهزة وإمكاناتها. على سبيل المثال، قد تختار بعض الأجهزة تفسير العمليات الكميّة باستخدام "تحديد وتنفيذ النقطة العائمة" العملية، وأخيرًا تحديد الكميات" الاستراتيجية. ويمكن للآخرين تنفيذ العملية الحسابية باستخدام حساب الأعداد الصحيحة. وبالتالي، فإن تفسير ويتم تحديد عمليات StableHLO الكمية حصريًا من خلال التنفيذ. تفسير منهج الكم الهجين (#1575) يجب أن يستند إلى الدلالات على النحو الموصوف في المواصفات (عبر 1792).

الأخطاء

يتم التحقق من صحة برامج StableHLO من خلال مجموعة واسعة من القيود العمليات الفردية، التي تستبعد العديد من فئات الأخطاء قبل وقت التشغيل. ومع ذلك، تظل حالات الخطأ ممكنة، على سبيل المثال: من خلال فائض الأعداد الصحيحة، وعمليات الوصول إلى خارج الحدود، وما إلى ذلك، وما لم يتم ذكر ذلك صراحةً، محددة في طريقة التنفيذ، ولكن قد يتغير هذا في المستقبلية (#1157).

استثناءات النقاط العائمة

باستثناء هذه القاعدة، فإنّ استثناءات النقطة العائمة في برامج StableHLO يكون لها سلوك محدد جيدًا. العمليات التي ينتج عنها استثناءات يحددها معيار IEEE-754 (عملية غير صالحة، أو القسمة على صفر، أو التجاوز، أو التدفق السفلي، أو الاستثناءات غير الدقيقة) تؤدي إلى نتائج افتراضية (كما هو موضح في المعيار) مواصلة التنفيذ بدون رفع علامة الحالة المناسبة مشابه لـ معالجة استثناء raiseNoFlag من المعيار العادي استثناءات للحسابات غير العادية العمليات الحسابية (مثل العمليات الحسابية المعقدة وبعض الدوال العليا) التنفيذ.

عدم تطابق الأشكال

يتوافق StableHLO مع أدوات التوتر ذات الشكل الديناميكي. ومع ذلك، يجب أن تتفق الأشكال في وقت التشغيل، وإلا فسيكون السلوك غير محدد. لا تسمح قناة StableHLO بشكلٍ صريح توفير عملية يمكن من خلالها تأكيد وجود شكل معين للمتسق في وقت التشغيل. تقع مسؤولية إنشاء التعليمات البرمجية الصحيحة على عاتق المنتِج.

على سبيل المثال، البرنامج التالي صالح. ولكن في وقت التشغيل، يجب أن تكون الأشكال الدقيقة لـ %arg0 و%arg1 متطابقة، وإلا سلوك البرنامج غير محدد:

func.func @foo(%arg0: tensor<?xi32>, %arg1: tensor<?xi32>) -> tensor<?xi32> {
    %0 = stablehlo.add %arg0, %arg1 : tensor<?xi32>
    return %0 : tensor<?xi32>
}

الترميز

لوصف بناء الجملة، يستخدم هذا المستند صيغة ISO المعدَّلة الخاصة بـ EBNF. (ISO/IEC 14977:1996, ويكيبيديا)، بتعديلين: 1) يتم تحديد القواعد باستخدام ::= بدلاً من =،

2) يتم التعبير عن التسلسل باستخدام التقارب بدلاً من ,.

لوصف الدلالة (أي ضمن أقسام "الأنواع" و"الثابت" و"العمليات")، نستخدم صيغًا تستند إلى بناء جملة بايثون موسّعة مع للتعبير بإيجاز عن عمليات الصفيف كما هو موضح أدناه. هذا يسير بشكل جيد لمقتطفات صغيرة من الرموز، ولكن في بعض الحالات النادرة، عندما فإننا نستخدم بناء جملة فانيلا بايثون والذي يتم تقديمه دائمًا بشكل صريح.

الصيغ

لِنستكشف كيف تعمل الصيغ بناءً على مثال من dot_general. المواصفات. يبدو أحد قيود هذه العملية كما يلي: dim(lhs, lhs_batching_dimensions...) = dim(rhs, rhs_batching_dimensions...)

تأتي الأسماء المستخدمة في هذه المعادلة من مصدرين: 1) الدوال العمومية، بمعنى dim، 2) تعريفات العضو لعنصر البرنامج ذي الصلة، أي إدخالات lhs وlhs_batching_dimensions وrhs وrhs_batching_dimensions محدد في "الإدخالات" القسم الخاص بـ dot_general.

وكما ذكرنا أعلاه، فإن بناء جملة هذه المعادلة يعتمد على لغة بايثون مع بعض بإضافات موجهة نحو الإيجاز. لفهم المعادلة، لنقم بتحويل إلى بناء جملة فانيلا بايثون.

أ) في هذه المعادلات، نستخدم = لتمثيل التساوي، وبالتالي فإن الخطوة الأولى نحو الحصول على بنية بايثون، يتم استبدال = بـ ==، كما يلي: dim(lhs, lhs_batching_dimensions...) == dim(rhs, rhs_batching_dimensions...)

ب) تدعم هذه الصيغ أيضًا علامات الحذف (...) التي تحول التعبيرات العددية إلى تعبيرات تنسور. باختصار، تعني كلمة f(xs...) تقريبًا "لكل من العدد القياسي x في المعامل xs، نحسب العدد القياسي f(x) ثم نرجع الكل هذه النتائج العددية معًا كنتيجة تنسور". في بناء جملة فانيلا بايثون، تتحول المعادلة المثالية إلى: [dim(lhs, dim1) for dim1 in lhs_batching_dimensions] == [dim(rhs, dim2) for dim2 in rhs_batching_dimensions]

بفضل القطع الناقص، من الممكن غالبًا تجنب العمل على مستوى المقاييس الفردية. ومع ذلك، في بعض الحالات الصعبة، لا يعتقد المستوى الأدنى بناء الجملة كما هو الحال في صيغة start_indices[bi0, ..., :, ..., biN] عن مواصفات gather. في خدمة الإيجاز، لا نعني وتقديم أسلوب رسمي محدد لترجمة مثل هذه الصيغة إلى فانيلا بايثون، تأمل أن يظل مفهومًا بشكل حدسي على أساس كل حالة على حدة. يُرجى إخبارنا إذا كانت بعض الصيغ المحددة تبدو غير شفافة، وسنحاول وتحسينها.

ستلاحظ أيضًا أن المعادلات تستخدم القطع الناقص لتوسيع جميع أنواع القوائم، بما في ذلك الأثوان، قوائم متوترات (التي يمكن أن تنشأ مثلاً من المتغير وعدد متساعات التوتر)، إلخ. وهذا مكان آخر لا نوفر فيه القيمة الدقيقة الرسمية (على سبيل المثال، القوائم ليست جزءًا من نظام النوع StableHLO) و وبدلاً من ذلك تعتمد على سهولة الفهم.

ج) وسيلة الترميز النهائية الجديرة بالملاحظة التي نستخدمها ضمنية البث. وفي حين أن عملية StableHLO لا تتوافق مع البث الضمني، تفعله المعادلات، أيضًا في خدمة الإيجاز. باختصار، إذا كان هناك قياس يُستخدم في سياق يُتوقع فيه متسابق، يتم بث المقياس الشكل المتوقع.

إليك قيدًا آخر كي يتسنى لك متابعة مثال dot_general: 0 <= lhs_batching_dimensions < rank(lhs) كما هو محدّد في dot_general المواصفة، فإن lhs_batching_dimensions عبارة عن متسّع، إلا أن كلاً من 0 rank(lhs) عبارة عن قيم قياسية. بعد تطبيق البث الضمني، ستتغير المعادلة يصبح [0, ..., 0] <= lhs_batching_dimensions < [rank(lhs), ..., rank(lhs)].

عند تطبيق هذه الصيغة على عملية dot_general معيّنة، نقيّمه إلى موتر من القيم المنطقية. عند استخدام المعادلات كقيود، فإن قيد القيد إذا تم تقييم المعادلة إلى true أو إلى متوتر تحتوي على true من العناصر فقط.

الاسماء

في المعادلات، يتضمن النطاق المعجم: 1) الدوال العمومية، 2) تعريفات العضو،

3) التعريفات المحلية. في ما يلي قائمة الدوال العمومية. القائمة من تعريفات العناصر على عنصر البرنامج الذي يمثل الترميز تم التطبيق على:

  • بالنسبة إلى العمليات، تتضمن تعريفات الأعضاء الأسماء التي تم تقديمها في "الإدخالات" أو "المخرجات" الأقسام.
  • بالنسبة لكل شيء آخر، تتضمن تعريفات العضو الأجزاء الهيكلية عنصر البرنامج، الذي يحمل اسم عنصري EBNF المقابل لهما. معظم وقت ذلك، يتم الحصول على أسماء هذه الأجزاء الهيكلية عن طريق تحويل أسماء الأحرف غير الطرفية إلى حالة الثعبان (مثال: IntegerLiteral => integer_literal)، ولكن في بعض الأحيان يتم اختصار الأسماء في العملية (مثل QuantizationStorageType => storage_type) في هذه الحالة تكون الأسماء تم تقديمها بشكل صريح بشكل مشابه لـ "الإدخالات" / "المخرجات" الأقسام قيد التشغيل والمواصفات.
  • بالإضافة إلى ذلك، تتضمّن تعريفات الأعضاء دائمًا self للإشارة إلى عنصر البرنامج المقابل.

القيم

عندما يتم تقييم المعادلات، فإنها تعمل مع أنواع القيم التالية: 1) Value (القيم الفعلية، مثل dense<[[1, 2], [3, 4]]> : tensor<2x2xi32>؛ فإنهم يعرفون دائمًا أنواعها)، 2) Placeholder (القيم المستقبلية، مثل lhs أو rhs أو result؛ والقيم الفعلية لها غير معروفة بعد، فهي تعرف أنواعها فقط)، 3) Type (الأنواع على النحو المحدّد في قسم "الأنواع")، 4) Function (دوال عمومية كما هو موضح في قسم "الدوال").

بناءً على السياق، قد تشير الأسماء إلى قيم مختلفة. المزيد وعلى وجه التحديد، "الدلالات" للعمليات (وما يعادلها في برامج أخرى ) تحدد منطق بيئة التشغيل، لذلك تتوفر جميع الإدخالات على النحو التالي Value. في المقابل، "القيود" للعمليات (وما يعادلها) يحدد "وقت التجميع" أي شيء يتم تنفيذه عادةً قبل بيئة التشغيل لذلك تتوفر المدخلات الثابتة فقط مثل Value والمدخلات الأخرى يتوفّر فقط باسم Placeholder.

الاسماء في "Semantics" في "القيود"
الدوال العمومية Function Function
الإدخالات المستمرة Value Value
الإدخالات غير الثابتة Value Placeholder
المُخرَجات Value Placeholder
التعريفات المحلية تستند إلى التعريف تستند إلى التعريف

لنستعرض عملية transpose كمثال:

%result = "stablehlo.transpose"(%operand) {
  permutation = dense<[2, 1, 0]> : tensor<3xi64>
} : (tensor<2x3x2xi32>) -> tensor<2x3x2xi32>

بالنسبة إلى هذه العملية، تكون permutation قيمة ثابتة، لذا فهي متاحة كـ Value في كل من الدلالة والقيود. في المقابل، operand وresult هما متوفر على شكل Value في الدلالات ولكن فقط كـ Placeholder في القيود.

الدوال

إنشاء الأنواع

لا توجد دوال يمكن استخدامها لإنشاء الأنواع. بدلاً من ذلك، نقوم مباشرة نستخدم بناء جملة النوع لأنها عادةً ما تكون أكثر إيجازًا. مثلاً: (tensor<E>, tensor<E>) -> (tensor<E>) بدلاً من function_type( [tensor_type([], E), tensor_type([], E)], [tensor_type([], E)])

الدوال على الأنواع

  • يتم تعريف element_type على أنواع متسابقات وأنواع متسابقات الكميّة إرجاع TensorElementType أو QuantizedTensorElementType على التوالي من TensorType أو QuantizedTensorType المقابلة
def element_type(x: Value | Placeholder | Type):
 if type(x) == TensorType:
    return tensor_element_type(x)
  if type(x) == QuantizedTensorType:
    return quantized_tensor_element_type(x)
  if type(x) is not Type:
    return element_type(type(x))
  • "is_per_axis_quantized(x: Value | Placeholder | Type) -> Value" اختصار لصالح is_quantized(x) and quantization_dimension(x) is not None.

  • is_per_tensor_quantized(x: Value | Placeholder | Type) -> Value هو الاختصار لـ is_quantized(x) and quantization_dimension(x) is None.

  • يتحقق is_promotable(x: Type, y: Type) -> bool مما إذا كان يمكن ترقية النوع x. لكتابة y. عندما تكون قيمة x وy هي QuantizedTensorElementType، يبدأ العرض الترويجي. يسري على storage_type فقط. هذا الإصدار المحدّد من الإعلان الترويجي هو تُستخدم حاليًا في سياق حساب الاختزال (راجع RFC للاطّلاع على مزيد من التفاصيل

def is_promotable(x: Type, y: Type) -> Value:
  is_same_type = (is_bool(x) and is_bool(y)) or
    (is_integer(x) and is_integer(y)) or (is_float(x) and is_float(y)) or
    (is_complex(x) and is_complex(y)) or
    (is_quantized(x) and is_quantized(y) and expressed_type(x) = expressed_type(y))

  if is_same_type == False:
    return False

  if is_integer(x) or is_float(x):
    return bitwidth(x) <= bitwidth(y)

  if is_complex(x):
    return bitwidth(element_type(x)) <= bitwidth(element_type(y))

  if is_quantized(x):
    return bitwidth(storage_type(x)) <= bitwidth(storage_type(y))

  return false
  • is_quantized(x: Value | Placeholder | Type) -> Value هو اختصار لـ is_quantized_tensor_element_type(x)

  • is_type_name(x: Value | Placeholder | Type) -> Value متاحة للجميع الأنواع. على سبيل المثال، تعرض الدالة is_float(x) القيمة true إذا كانت قيمة x هي FloatType. إذا كانت x قيمة أو عنصرًا نائبًا، فإن هذه الدالة هي اختصار is_type_name(type(x))

  • تعرض max_value(x: Type) -> Value الحد الأقصى لقيمة TensorElementType إذا لم تكن x هي TensorElementType، سيتم عرض None.

  • تعرض min_value(x: Type) -> Value أدنى قيمة ممكنة لـ TensorElementType إذا لم تكن x هي TensorElementType، سيتم عرض None.

  • member_name(x: Value | Placeholder | Type) -> Any متاح لجميع الأعضاء تعريفات member_name بجميع أنواعها. على سبيل المثال: tensor_element_type(x) تعرض الجزء TensorElementType من TensorType مقابل. إذا كانت x قيمة أو عنصرًا نائبًا، فإن هذه الدالة هي اختصار member_name(type(x)) إذا لم يكن x من النوع الذي يضم العضو المناسب، أو قيمة أو عنصر نائب من هذا النوع، يؤدي إلى إرجاع None.

  • تتحقّق الدالة is_empty_algorithm(*args: Type) من ضبط جميع حقول خوارزمية النقاط. إلى None. هذا الأمر مطلوب لأنّ خوارزميات النقاط قد تم تحديدها. على Google، لذا سيكون تحديد قيمة افتراضية غير صحيح.

إنشاء القيم

  • operation_name(*xs: Value | Type) -> Value متاحة لجميع العمليات. على سبيل المثال، تأخذ add(lhs, rhs) قيمتين للمتسابق lhs وrhs ناتج تقييم العملية add مع هذه المدخلات. بالنسبة إلى بعض العمليات، مثل broadcast_in_dim، أنواع مخرجاتها هي: "تحميل"، أي أنه مطلوب لتقييم عملية. في هذه الحالة، لا يمكن هذه الأنواع كوسيطات.

الدوال على القيم

  • كل عوامل التشغيل والدوال في بايثون متوفرة. مثلاً: كلاهما اشتراك والتقسيم تتوفر التدوينات من بايثون لفهرستها إلى متسابقات التوتر الكمّي والصفوف.

  • تم تحديد to_destination_type(x: Value, destination_type: Type) -> Value في لعرض القيمة المحوّلة x بناءً على type(x) destination_type على النحو التالي:

def to_destination_type(x: Value, destination_type: Type) -> Value:
  if type(x) == destination_type:
    return x

  if is_quantized(destination_type):
    if is_quantized(type(x)):
      return quantize(x, destination_type)
    assert is_float(type(x))
    return quantize(x, destination_type)

  if is_quantized(type(x)):
    assert destination_type = expressed_type(type(x))
    return dequantize(type(x))

  return convert(x, destination_type)

كانت هناك مناقشة مبكرة حول دمج convert وuniform_quantize uniform_dequantize العمليات (#1576). بعد الدمج، لا نحتاج إلى الدالة أعلاه ويمكننا استخدام اسم العملية مقابل convert بدلاً من ذلك.

  • يتم تحديد is_nan(x: Value) -> Value باستخدام موتّرات ويكون الناتج true إذا جميع عناصر x هي NaN أو false بخلاف ذلك. إذا لم يكن x متسابقًا، وإرجاع None.

  • يتم تحديد is_sorted(x: Value) -> Value باستخدام موتّرات ويكون الناتج true إذا يتم فرز عناصر x بترتيب تصاعدي حسب الترتيب التصاعدي الترتيب المعجم لمؤشراتها أو false غير ذلك. إذا لم يكن x دالة Tenor، تعرض None.

  • يتم تحديد is_unique(x: Value) -> Value باستخدام موتّرات وعرض true إذا كانت x. لا يحتوي على عناصر مكررة أو false غير ذلك. إذا لم يكن x متسابقًا، وإرجاع None.

  • يتم تحديد member_name(x: Value) -> Any لجميع تعريفات الأعضاء. member_name من جميع القيم. على سبيل المثال، تعرض الدالة real_part(x) السمة RealPart جزء من ComplexConstant مقابل. إذا لم تكن x قيمة تحتوي على العضو المناسب، يعرض None.

  • يتم تحديد same(x: Value) -> Value باستخدام موتّرات ويكون الناتج true إذا عناصر x جميعها تساوي بعضها بعضًا أو false في الحالات الأخرى. إذا كان المتغير على عناصر، تُحتسب على أنها "جميعها متساوية في بعضها البعض"، أي تُرجع الدالة true. إذا لم يكن x سينور، سيتم عرض None.

  • تم تحديد split(x: Value, num_results: Value, axis: Value) -> Value في البيانات وعرض num_results شرائح من x على طول المحور axis. إذا لم يكن x هو tensor أو dim(x, axis) % num_results != 0، سيتم عرض None.

  • يتم تحديد is_defined_in_parent_scope(x: Value) -> Value في السلاسل وتعرض true إذا كانت x هي اسم الدالة المحددة في النطاق نفسه. باعتبارها الوظيفة الرئيسية للعملية ذات الصلة.

  • يتم تحديد is_namespaced_op_name(x: Value) -> Value من خلال السلاسل والمرتجعات. true إذا كان x اسم عملية صالحًا، أي يتوافق مع الاسم العادي التالي التعبير: [a-zA-Z][a-zA-Z0-9_]*([.][a-zA-Z0-9_$]+)+

العمليات الحسابية للأشكال

  • axes(x: Value | Placeholder | Type) -> Value هو اختصار لـ range(rank(x))

  • dim(x: Value | Placeholder | Type, axis: Value) -> Value هو اختصار لـ shape(x)[axis]

  • dims(x: Value | Placeholder | Type, axes: List) -> List هو اختصار لـ list(map(lambda axis: dim(x, axis), axes))

  • يتم تحديد index_space(x: Value | Placeholder | Type) -> Value باستخدام متساعات التوتر. ويعرض فهارس size(x) لـ TensorType المقابل مرتبة حسب ترتيب معجمي تصاعدي، مثل [0, ..., 0]، [0, ..., 1]، ...، shape(x) - 1 إذا لم يكن x نوع متسّع أو نوع متسّع كمي أو قيمة أو عرض عنصر نائب لأحد هذه الأنواع، بقيمة None.

  • rank(x: Value | Placeholder | Type) -> Value هو اختصار لـ size(shape(x))

  • يتم تعريف shape(x: Value | Placeholder | Type) -> Value في "الدوال على الأنواع" القسم من خلال member_name.

  • size(x: Value | Placeholder | Type) -> Value هو اختصار لـ reduce(lambda x, y: x * y, shape(x))

عمليات احتساب الكمية

  • def baseline_element_type(x: Value | Placeholder | Type) -> Type هو الاختصار لـ element_type(baseline_type(x)).

  • يتم تعريف baseline_type على أنواع متسابقات وأنواع متسابقات الكميّة إلى "خط أساس"، أي نوع بنفس الشكل ولكن مع تتم إعادة تعيين معلمات قياس نوع العنصر إلى القيم الافتراضية. هذا هو يستخدم كحيلة مفيدة للمقارنة بين أنواع متسابقات التوتر والكمية الكميّة بشكل موحد، وهو مطلوب كثيرًا. بالنسبة للأنواع الكَمية، يتيح ذلك لمقارنة الأنواع مع تجاهل مَعلمات الكمي، أي shape، storage_type وexpressed_type وstorage_min وstorage_max يجب أن تتطابق السلسلة quantization_dimension (للنوع المكمّل حسب المحور) بالكامل، ولكن قد يختلف scales عن zero points.

def baseline_type(x: Value | Placeholder | Type) -> Type:
  if type(x) == TensorType:
    return x
  if type(x) == QuantizedTensorType:
    element_type = quantized_tensor_element_type(x)
    baseline_element_type = QuantizedTensorElementType(
      storage_type = storage_type(element_type),
      storage_min = storage_min(element_type),
      storage_max = storage_max(element_type),
      expressed_type = expressed_type(element_type),
      quantization_dimension = quantization_dimension(element_type),
      scales = [constant(1.0, expressed_type(element_type))] * dim(x, quantization_dimension(element_type)),
      zero_points = [constant(0, storage_type(element_type))] * dim(x, quantization_dimension(element_type)))
    return QuantizedTensorType(shape(x), baseline_element_type)
  if type(x) is not Type:
    return baseline_element_type(type(x))
  • يتم تعريف dequantize على أنواع متسابقات التوتر الكَمية وتحويلها إلى أنواع موتر النقطة العائمة. يحدث ذلك من خلال تحويل العناصر الكمية التي تمثل القيم الصحيحة لنوع التخزين في قيم النقطة العائمة للنوع المعبّر عنه باستخدام النقطة الصفرية والمقياس المرتبطة بنوع العنصر الكمية.
def compute_zero_points(quantized_type, result_type):
  if is_per_tensor_quantized(quantized_type):
    return broadcast_in_dim(constant(zero_point(quantized_type), storage_type(quantized_type)), [], result_type)
  if is_per_axis_quantized(quantized_type):
    for i in index_space(result_type):
      d = quantization_dimension(quantized_type)
      zero_points[i] = zero_points(quantized_type)[i[d]]
    return zero_points

def compute_scales(quantized_type, result_type):
  if is_per_tensor_quantized(quantized_type):
    return broadcast_in_dim(constant(scale(quantized_type), expressed_type(quantized_type)), [],
            type(result_type))
  if is_per_axis_quantized(quantized_type):
    for i in index_space(result_type):
      d = quantization_dimension(quantized_type)
      scales[i] = scales(quantized_type)[i[d]]
    return scales

def dequantize(x: Value) -> Value:
  assert is_quantized(x)
  x_storage = bitcast_convert(x, storage_type(x))
  x_storage_sub = x_storage - compute_zero_points(type(x), type(x_storage))
  x_expressed_sub = convert(x_storage_sub, expressed_type(x))
  return x_expressed_sub * compute_scales(type(x), type(x_expressed_sub))
  • يتم تعريف الدالة quantize على أنواع متسّع النقطة العائمة وتحويلها إلى أنواع متسابق العرض الكمّي. ويحدث ذلك من خلال تحويل قيم النقاط العائمة. للنوع المُعبَّر عنه إلى قيم الأعداد الصحيحة المقابلة لنوع التخزين باستخدام النقطة الصفرية والمقياس المرتبط بنوع العنصر الكمي.
def quantize(x: Value, result_type: Type) -> Value:
  assert is_float(x) and is_quantized(result_type)
  zero_points = compute_zero_points(result_type, TensorType(shape(x), storage_type(result_type)))
  converted_zero_points = convert(zero_points, expressed_type(result_type))
  converted_min = convert(storage_min(result_type), expressed_type(result_type))
  converted_max = convert(storage_max(result_type), expressed_type(result_type))

  x_scaled = x / compute_scales(result_type, type(x))
  x_scaled_add_zp = x_scaled + converted_zero_points
  x_clamped = clamp(converted_min, x_scaled_add_zp, converted_max)
  x_rounded = round_nearest_even(x_clamped)
  return convert(x_rounded, result_type)
  • يستخدم dequantize_op_quantize لتحديد العمليات الحاسوبية للعناصر في للأعداد الكميّة. فهو يحدد كمية العناصر، أي يحول العناصر الكميّة إلى عناصر ثم تقوم بإجراء عملية، ثم تحدد الكميات، أي تحويل النتائج إلى أنواع التخزين الخاصة بها. في الوقت الحالي، لا يمكن لهذه الدالة يصلح لكمية كل متسابق. جارِ العمل على عملية جمع الكمية لكل محور (#1574)
def dequantize_op_quantize(op, *inputs_and_output_type):
  inputs = inputs_and_output_type[:-1]
  output_type = inputs_and_output_type[-1]

  float_inputs = map(dequantize, inputs)
  float_result = op(*float_inputs)
  return quantize(float_result, output_type)

def dequantize_batch_norm_grad_or_training_quantize(op, *inputs_and_output_types):
  inputs = inputs_and_output_type[:-3]
  float_inputs = map(dequantize, inputs)
  float_results = op(*float_inputs)
  return map(quantize, float_results, inputs_and_output_type[-3:])

def dequantize_compare(lhs, rhs, comparison_direction):
  float_lhs = dequantize(lhs)
  float_rhs = dequantize(rhs)
  return compare(float_lhs, float_rhs, comparison_direction, FLOAT)

def dequantize_select_quantize(pred, on_true, on_false, output_type):
  float_on_true = dequantize(on_true)
  float_on_false = dequantize(on_false)
  float_result = select(pred, float_on_true, float_on_false)
  return quantize(float_result, output_type)
  • يُستخدم hybrid_dequantize_then_op لتحديد الكمية بالوزن فقط عملية مختلطة تقبل lhs في النقطة العائمة والدالة rh بأنواع محددة. أُنشأها جون هنتر، الذي كان متخصصًا تحدد كمية المدخلات الكميّة إلى أنواعها المعبَّر عنها وتجري عمليات حسابية عدد عشري. نوع العنصر المتغير lhs tensor والنوع المعبر عنه rhs الكميّة يكون متناسورًا متماثلاً.
def hybrid_dequantize_then_op(op, lhs, rhs):
  assert(is_float(lhs) and is_quantized(rhs) and element_type(lhs) == expressed_type(rhs))
  return op(lhs, dequantize(rhs))

عمليات احتساب الشبكة

  • cross_partition(replica_groups: Value) -> Value عرض "cross_replica" أعلاه.

  • cross_replica(replica_groups: Value) -> Value عرض "cross_replica" أعلاه.

  • cross_replica_and_partition(replica_groups: Value) -> Value يمكنك الاطّلاع على &quot;cross_replica_and_partition&quot; أعلاه.

  • flattened_ids(replica_groups: Value) -> Value الاطّلاع على "flattened_ids" أعلاه.

الديناميكية

يمكن أن تحتوي قيم StableHLO على أحجام سمات ديناميكية، مثل: tensor<?xi64> ومع ذلك، لا يمكن أن تحتوي قيم StableHLO على عدد ديناميكي من السمات (بدون ترتيب). الديناميكية، على سبيل المثال tensor<*xi64>). يُسمَح للمعاملين والنتائج باستخدام العناصر الديناميكية وأحجام الأبعاد، حتى إذا كانت هناك قيود على الأحجام. ستكون القيود بشكل ثابت إن أمكن، وإلا سيتم تأجيلها إلى وقت التشغيل إلى حدوث سلوك غير محدد. اطّلِع على الأمثلة أدناه.

عدم تطابُق الأشكال للعمليات الأحادية العناصر

ضع في اعتبارك برنامج الألعاب التالي:

func.func @foo(%arg0: tensor<?xf64>) {
  %0 = stablehlo.abs %arg0 : (tensor<?xf64>) -> tensor<2xf64>
  return
}

وهذا البرنامج أمر غير عادي، لأنه ليس من الشائع معرفة شكل النتيجة وليس شكل المدخلات. على الرغم من ذلك، تعتبر هذه دالة StableHLO صالحة البرنامج. لا يمكن التحقّق بشكل ثابت من عملية abs في هذه الحالة. لأن الشكل الدقيق للمعامل غير معروف. ومع ذلك، فإن الأشكال متوافقة بالتأكيد، ويمكن التحقّق من ذلك بشكل ثابت: قد يتبين أنّ ? على 2 في وقت التشغيل، ولن تكون هناك أي مشكلة. في المقابل، بإمكان "?" يتضح أيضًا أنه عدد صحيح آخر، وفي هذه الحالة يكون السلوك غير محدد.

تجدر الإشارة إلى أنّه إذا كان حجم البُعد ديناميكيًا في النتيجة، لا يمكن سلوك غير محدد. في الواقع، ليس هناك "متوقع" لذلك لا يمكن أن يكون هناك غير متطابق.

عدم تطابق الأشكال للعمليات الثنائية العناصر

ضع في اعتبارك برنامج الألعاب التالي:

func.func @foo(%arg0: tensor<?xf64>, %arg1: tensor<?xf64>) {
  %0 = stablehlo.add %arg0, %arg0 : (tensor<?xf64>, tensor<?xf64>) -> tensor<?xf64>
  return
}

عندما يتعلق الأمر بالعمليات الثنائية العناصر، تمثل أشكال المدخلات يجب أن تتوافق النتيجة في وقت التشغيل. في وقت التجميع، يجب أن تكون الأبعاد الثابتة متساوية، وإلا فإنها تحتاج فقط إلى أن تكون متوافقة. إذا كانت أي سمة ديناميكية في المُدخلات، قد تكون هناك حاجة إلى بيانات غير محدّدة سلوكًا في وقت التشغيل، لأنّ الحجم الديناميكي قد لا يتطابق مع الحجم الحجم في المعامل الآخر (سواء كان ثابتًا أو ديناميكيًا). إذا كانت جميع المدخلات ثابتة، فما إذا كانت النتيجة ديناميكية أم لا: سيتم التحقّق من السمات المعروفة بشكلٍ ثابت، ولن يتم التحقّق من السمات الديناميكية لفرض أي قيود.

عدم تطابق الأشكال للعمليات التي تتخذ شكل مخرجاتها كمعامل

ضع في اعتبارك برنامج الألعاب التالي:

func.func @foo(%arg0: tensor<2xi32>) {
  %0 = stablehlo.dynamic_iota %arg0, dim = 0 : (tensor<2xi32>) -> tensor<3x4xi64>
  return
}

يجب أن تتطابق القيم في معامل الشكل في وقت التشغيل مع شكل النتيجة، وإلا يكون السلوك غير محدد. أي أنّه يجب أن يتضمّن %arg0 في وقت التشغيل بقيمة dense<[3, 4]> : tensor<2xi32>. وإذا كان معامل الشكل ثابتًا، فإن هذا يمكن التحقق منها بشكل ثابت. وإذا كان شكل النتيجة ديناميكيًا بالكامل، فعندئذ يكون هناك لا يمكن أن يكون عدم التطابق.