مواصفات StableHLO

‫StableHLO هي مجموعة عمليات للعمليات العالية المستوى (HLO) في نماذج تعلُّم الآلة (ML). تعمل StableHLO كطبقة لنقل البرامج بين مختلف إطارات عمل تعلُّم الآلة وبرامج التحويل الخاصة به: إنّ إطارات عمل تعلُّم الآلة التي تُنشئ برامج StableHLO تكون متوافقة مع برامج التحويل الخاصة بتعلُّم الآلة التي تستخدِم برامج StableHLO.

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

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

للاطّلاع على المواصفات من إصدار سابق من StableHLO، افتح المستودع في الإصدار الذي يحمل علامة من الاهتمام. على سبيل المثال، مواصفات StableHLO v0.19.0. لعرض التغييرات التي حدثت في كل إصدار ثانوي من 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}

تحتوي وظائف StableHLO (المعروفة أيضًا باسم الدوال المُسمّاة) على معرّف وعناصر إدخال/إخراج ونص. في المستقبل، نخطّط لطرح بيانات وصفية إضافية للوظائف من أجل تحقيق توافق أفضل مع 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 الأنواع في العديد من لغات البرمجة، حيث تتمثّل الخصوصية الرئيسية في طبيعة 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 ::= IntegerLiteral
QuantizationStorageMax ::= IntegerLiteral
QuantizationExpressedType ::= FloatType
QuantizationDimension ::= IntegerLiteral
QuantizationParameters ::= QuantizationParameter
                         | '{' QuantizationParameter {',' QuantizationParameter} '}'
QuantizationParameter ::= QuantizationScale [':' QuantizationZeroPoint]
QuantizationScale ::= FloatLiteral
QuantizationZeroPoint ::= IntegerLiteral
الاسم النوع القيود
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.
  • (ج2) type(storage_max) = storage_type.
  • (ج3) min_value(storage_type) <= storage_min < storage_max <= max_value(storage_type).
  • (C4) type(scales...) = expressed_type.
  • (ج5) 0 < scales.
  • (C6) is_finite(scales...).
  • (ج7) storage_min <= zero_points <= storage_max.
  • (C8) type(zero_points...) = storage_type.
  • (ج9) 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 هو تمثيل ABI لـ HLO بشكل شامل، حيث قد يختلف 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 ::= 'f4E2M1FN' | 'f6E2M3FN' | 'f6E3M2FN' | 'f8E3M4' | 'f8E4M3'
            | 'f8E4M3FN' | 'f8E4M3FNUZ' | 'f8E4M3B11FNUZ' | 'f8E5M2'
            | 'f8E5M2FNUZ' | 'f8E8M0FNU' | 'bf16' | 'f16' | 'f32' | 'f64'
TensorFloat32 ::= 'tf32'
ComplexType ::= 'complex' '<' ComplexElementType '>'
ComplexElementType ::= 'f32' | 'f64'

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

  • يمثّل النوع المنطقي القيم المنطقية true وfalse.
  • يمكن أن تكون أنواع الأعداد الصحيحة إما ذات علامة (si) أو بدون علامة (ui) وأن يكون لها أحد مساحات البتات المتوافقة (2 أو 4 أو 8 أو 16 أو 32 أو 64). تمثّل أنواع siN ذات العلامة قيمًا صحيحة من -2^(N-1) إلى 2^(N-1)-1 شاملة، وتمثّل أنواع uiN بدون علامة قيمًا صحيحة من 0 إلى 2^N-1 شاملة.
  • يمكن أن تكون أنواع النقاط العائمة أيًا مما يلي:
  • تمثّل الأنواع المعقدة القيم المعقدة التي تحتوي على جزء حقيقي وجزء تخيلي من نوع العنصر نفسه. الأنواع المركّبة المسموح بها هي complex<f32> (كلا الجزأين من النوع f32) وcomplex<f64> (كلا الجزأين من النوع f64).
FunctionType ::= '(' InputTypes ')' '->' '(' OutputTypes ')'
InputTypes ::= [ValueType {',' ValueType}]
OutputTypes ::= [ValueType {',' ValueType}]

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

StringType ::= 'string'

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

العمليات

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

الثوابت

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

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

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

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

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

تمثِّل الثوابت الصحيحة القيم الصحيحة من خلال سلاسل تستخدم الترميز العشري أو السداسي العشري. ولا يمكن استخدام القواعد الأخرى، مثل النظام الثنائي أو الثماني. تنطبق القيود التالية على الثوابت الصحيحة:

  • (ج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]

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

  • (ج1) في حال استخدام ترميز غير سداسي عشري، 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)).
  • (ج2) 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

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

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

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

  • (ج1) has_syntax(quantized_tensor_literal, storage_type(quantized_tensor_type)).
  • (ج2) 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. بناءً على نوع العنصر، نفِّذ ما يلي:

  • بالنسبة إلى القيم المنطقية: "أو" منطقي
  • بالنسبة للأعداد الصحيحة: إضافة عدد صحيح.
  • بالنسبة إلى الأعداد العشرية العائمة: 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).
  • إذا كانت العملية تستخدم مصفوفات كمية:
    • (ج2) is_quantized(lhs) and is_quantized(rhs) and is_quantized(result).
    • (ج3) storage_type(lhs) = storage_type(rhs) = storage_type(result).
    • (C4) expressed_type(lhs) = expressed_type(rhs) = expressed_type(result).
    • (ج5) (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...).
  • (ج2) 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).
  • (ج5) إذا كان 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
  • (ج3) 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.
  • (ج3) 0 <= concat_dimension < rank(operands...).
  • (C4) 0 < split_count.
  • (ج5) is_unique(replica_groups).
  • (C6) يتم تعريف size(replica_groups) على النحو التالي:
    • num_replicas في حال استخدام cross_replica.
    • num_partitions في حال استخدام cross_partition.
  • (ج7) 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]]

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

و

الدلالات

تُنفِّذ عملية "و" بين مصفوفتَي lhs وrhs على مستوى العنصر الواحد، وتُنشئ مصفوفة result . بناءً على نوع العنصر، نفِّذ ما يلي:

  • بالنسبة إلى القيم المنطقية: "الواو المنطقي"
  • بالنسبة إلى الأعداد الصحيحة: استخدام 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، وتُنشئ مصفوفة 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 backpropagating من 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 لها الشكل نفسه.
  • (ج5) 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 الحالية باستخدام بنية جملة Python على النحو التالي:

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).
  • (ج2) تحتوي operand وscale وoffset وmean وvariance وresult على baseline_element_type نفسه.
  • (ج3) size(scale) = dim(operand, feature_index).
  • (C4) size(offset) = dim(operand, feature_index).
  • (ج5) size(mean) = dim(operand, feature_index).
  • (C6) size(variance) = dim(operand, feature_index).
  • (ج7) 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 نفسها.
  • (ج3) size(scale) = dim(operand, feature_index).
  • (C4) size(offset) = dim(operand, feature_index).
  • (ج5) size(batch_mean) = dim(operand, feature_index).
  • (C6) size(batch_var) = dim(operand, feature_index).
  • (ج7) 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)

القيود

  • (ج1) بالنظر إلى 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). بخلاف ذلك.
  • (ج2) size(broadcast_dimensions) = rank(operand).
  • (ج3) 0 <= broadcast_dimensions < rank(result).
  • (C4) is_unique(broadcast_dimensions).
  • (ج5) بالنسبة إلى جميع 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).
  • (ج2) 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]

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

cholesky

الدلالات

تحسب هذه الدالة عملية تقسيم Cholesky لمجموعة من المصفوفات.

وبشكل أكثر رسمًا، بالنسبة إلى جميع 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 ثابت مصفوفة لاتّجاه 0 من النوع i1

النواتج

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

القيود

  • (ج1) baseline_type(a) = baseline_type(result).
  • (ج2) 2 <= rank(a).
  • (ج3) 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).
  • (ج2) rank(max) = 0 or shape(max) = shape(operand).
  • (ج3) 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
  • (ج3) 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.
  • (ج2) is_unique(source_target_pairs[:, 0]).
  • (ج3) 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، يستخدم op مزيجًا من عمليتَي 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 enum من EQ وNE وGE وGT وLE وLT
(I4) compare_type enum من FLOAT وTOTALORDER وSIGNED وUNSIGNED (C3)

النواتج

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

القيود

  • (ج1) baseline_element_type(lhs) = baseline_element_type(rhs).
  • (ج2) 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).
  • (ج2) 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 بتحليلها بدون تغيير دلالات البرنامج. في الحالات التي لا يوفّر فيها تضمين عملية التقسيم معنى op نفسه، يُفضّل استخدام 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)
  • (ج2) is_defined_in_parent_scope(decomposition)
  • (C3) types(inputs...) == input_types(decomposition)
  • (ج4) 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).
  • (ج3) 0 < size(inputs).
  • (C4) 0 <= dimension < rank(inputs[0]).
  • (ج5) 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. اطّلِع أدناه على كيفية عمل ذلك مع الأنواع المعقّدة.

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

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

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

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

من حيث المبدأ، يمكن أن تعبِّر هذه العملية عن التحليل الكمي (التحويل من عشرات الكميات إلى عشرات الكميات العادية) والقياس الكمي (التحويل من موتّرات عادية إلى موتّرات كَمية) وإعادة الكمي (التحويل بين العشرات الكمي)، ولكننا لدينا في الوقت الحالي عمليات مخصّصة لذلك - 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.
  • (ج3) 0 < window_strides.
  • (C4) shape(padding) = [N - 2, 2].
  • (ج5) size(lhs_dilation) = N - 2.
  • (C6) 0 < lhs_dilation.
  • (ج7) size(rhs_dilation) = N - 2.
  • (ج8) 0 < rhs_dilation.
  • (ج9) 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]]

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

عدد_الأصفار_الأولية

الدلالات

تُجري عملية احتساب عدد الوحدات الثنائية الصفرية الأولى في مصفوفة 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 لتوفير بيانات وصفية إضافية تحدّدها عملية التنفيذ.

في الوقت الحالي، تحتوي هذه العملية على مجموعة غير منظمة إلى حدٍ كبير من البيانات الوصفية التي تعكس التطور العضوي لعملية المعالجة المقابلة لها في compiler (المجمّع) 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، هما دقتَا التقريب اللتان يتم تقريب التعبيرَين "الأيمن" و"الأيسر" للعملية إليهما. تكون أنواع الدقة مستقلّة عن أنواع التخزين للمدخلات والمخرجات.
  • accumulation_type الدقة المستخدَمة في التجميع
  • تنطبق lhs_component_count وrhs_component_count وnum_primitive_operations عندما نستخدم خوارزمية تُحلِّل الجانب الأيمن و/أو الجانب الأيسر إلى مكونات متعدّدة وتُجري عمليات ضرب "بدائية" متعدّدة على تلك القيم، وذلك عادةً لمحاكاة دقة أعلى (مثل الاستفادة من نوع بيانات الذكاء الاصطناعي 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).
  • (ج3) is_unique(lhs_batching_dimensions + lhs_contracting_dimensions).
  • (C4) is_unique(rhs_batching_dimensions + rhs_contracting_dimensions).
  • (ج5) 0 <= lhs_batching_dimensions < rank(lhs).
  • (C6) 0 <= lhs_contracting_dimensions < rank(lhs).
  • (ج7) 0 <= rhs_batching_dimensions < rank(rhs).
  • (C8) 0 <= rhs_contracting_dimensions < rank(rhs).
  • (ج9) 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_nonexpanding_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_nonexpanding_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). بخلاف ذلك.
  • (ج2) size(broadcast_dimensions) = rank(operand).
  • (ج3) 0 <= broadcast_dimensions < rank(result).
  • (C4) is_unique(broadcast_dimensions).
  • (ج5) بالنسبة إلى جميع 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))).
  • (ج7) size(output_dimensions) = rank(result).
  • (ج8) is_unique(known_expanding_dimensions + known_nonexpanding_dimensions).
  • (C9) 0 <= known_expanding_dimensions < rank(operand).
  • (C10) 0 <= known_nonexpanding_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_nonexpanding_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

الدلالات

هذه العملية متطابقة من الناحية الوظيفية مع عملية التفاف op، ولكن يتم تحديد الحشو ديناميكيًا من خلال 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.
  • (ج3) 0 < window_strides.
  • (C4) shape(padding) = [N - 2, 2].
  • (ج5) size(lhs_dilation) = N - 2.
  • (C6) 0 < lhs_dilation.
  • (ج7) size(rhs_dilation) = N - 2.
  • (ج8) 0 < rhs_dilation.
  • (ج9) 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

الدلالات

هذه العملية متطابقة من الناحية الوظيفية مع gather op، مع تحديد 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).
  • (ج2) 0 <= index_vector_dim <= rank(start_indices).
  • (ج3) 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).
  • (ج5) 0 <= offset_dims < rank(result).
  • (C6) is_unique(collapsed_slice_dims) and is_sorted(collapsed_slice_dims).
  • (C7) 0 <= collapsed_slice_dims < rank(operand).
  • (ج8) slice_sizes[collapsed_slice_dims...] <= 1.
  • (ج9) 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

الدلالات

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

مدخلات

التصنيف الاسم النوع القيود
(I1) output_shape مصفوفة لاتّجاه واحد من النوع الصحيح (C1)، (C2)
(I2) iota_dimension si64 (C1)

النواتج

الاسم النوع القيود
result مصفوفة من النوع الصحيح أو الكسور العشرية أو المركّب أو مصفوفة مُشفَّرة لكل مصفوفة (C2)

القيود

  • (ج1) 0 <= iota_dimension < size(output_shape).
  • (ج2) 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

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

هذه العملية متطابقة من الناحية الوظيفية مع دالة pad op، ولكن مع تحديد 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).
  • (ج2) size(edge_padding_low) = size(edge_padding_high) = size(interior_padding) = rank(operand).
  • (ج3) 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

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

هذه العملية متطابقة من الناحية الوظيفية مع عملية 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) قد تختلف عن الأخرى.
  • (ج2) size(operand) = size(result).
  • (ج3) إذا كان 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 عدد متغير من مصفوفات 0 الأبعاد من النوع الصحيح (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).
  • (ج3) 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 عدد متغير من مصفوفات 0 الأبعاد من النوع الصحيح (C4)، (C5)

النواتج

الاسم النوع القيود
result متّجه متعدّد الأبعاد أو متّجه متعدّد الأبعاد مُشفَّر على مستوى كل متّجه (C1)

القيود

  • (ج1) type(operand) = type(result).
  • (ج2) element_type(update) = element_type(operand).
  • (C3) rank(update) = rank(operand):
  • (C4) size(start_indices) = rank(operand).
  • (ج5) 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

الدلالات

تُجري تحويلات فورييه المباشرة والعكسية للعمليات الإدخال/الإخراج الحقيقية والمعقدة.

fft_type هو أحد العناصر التالية:

  • FFT: تحويل فورييه المباشر من إشارة معقدة إلى إشارة معقدة
  • IFFT: تحويل فورييه العكسي المعقد إلى المعقد
  • RFFT: تحويل فورييه المباشر من القيم الحقيقية إلى القيم المعقدة
  • IRFFT: تحويل فورييه العكسي من القيم الحقيقية إلى القيم المركبة (أي يأخذ قيمًا مركبة ويعرض قيمًا حقيقية).

بشكل أكثر رسمية، تأخذ الدالة 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 enum من FFT وIFFT وRFFT وIRFFT (C2)، (C5)
(I3) fft_length ثابت التوتر ذو البعد الواحد من النوع si64 (C1)، و(C3)، و(C4)

النواتج

الاسم النوع القيود
result مصفوفة من النوع النقطة العائمة أو النوع المركّب (C2)، (C4)، (C5)

القيود

  • (ج1) size(fft_length) <= rank(operand).
  • (ج2) تختلف العلاقة بين نوعَي العنصرَين 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) هو نوع نقطة عائمة من نفس دلالات النقطة العائمة.
  • (ج3) 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)]

الطابق

الدلالات

تُجري هذه الدالة عملية تقريب للأعلى للعنصر في مصفوفة 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 عناصر individual في 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).
  • (ج2) 0 <= index_vector_dim <= rank(start_indices).
  • (ج3) 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).
  • (ج5) 0 <= offset_dims < rank(result).
  • (C6) is_unique(concatenate(collapsed_slice_dims, operand_batching_dims))
  • (ج7) is_sorted(collapsed_slice_dims).
  • (ج8) 0 <= collapsed_slice_dims < rank(operand).
  • (ج9) 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 tuple (C1)، (C2)
(I2) index ثابت من النوع si32 (C1)، (C2)

النواتج

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

القيود

  • (ج1) 0 <= index < size(operand).
  • (ج2) 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) = [].
  • (ج2) output_types(true_branch) = output_types(false_branch).
  • (ج3) 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

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

imag

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

تستخرج هذه الدالة الجزء التخيُّلي من 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])).
  • (ج3) 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]]

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

iota

الدلالات

تملأ هذه الدالة مصفوفة 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.
  • (ج3) 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. حسب نوع العنصر، يتم إجراء ما يلي:

  • بالنسبة إلى القيم المنطقية: "أو" منطقي
  • بالنسبة إلى الأعداد الصحيحة: الحد الأقصى للعدد الصحيح
  • بالنسبة إلى الأعداد العشرية العائمة: 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]]

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

الحد الأدنى

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

تُنفِّذ عملية الحد الأدنى لكل عنصر على مصفوفتَي lhs وrhs وتُنشئ مصفوفة result. بناءً على نوع العنصر، نفِّذ ما يلي:

  • بالنسبة إلى القيم المنطقية: "الواو المنطقي"
  • بالنسبة إلى الأعداد الصحيحة: الحد الأدنى لطول العدد الصحيح
  • بالنسبة إلى الأعداد العشرية العائمة: 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. بناءً على نوع العنصر، نفِّذ ما يلي:

  • بالنسبة إلى القيم المنطقية: "الواو المنطقي"
  • بالنسبة إلى الأعداد الصحيحة: ضرب الأعداد الصحيحة
  • بالنسبة إلى الأعداد العشرية العائمة: 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. بناءً على نوع العنصر، نفِّذ ما يلي:

  • بالنسبة إلى الأعداد الصحيحة الموجبة أو السالبة: نفي الأعداد الصحيحة
  • بالنسبة إلى الأعداد الصحيحة غير المزوّدة بعلامة: تحويل ثنائي إلى عدد صحيح مزوّد بعلامة، نفي عدد صحيح، تحويل ثنائي مجددًا إلى عدد صحيح غير مزوّد بعلامة
  • بالنسبة إلى الأعداد العشرية العائمة: 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. بناءً على نوع العنصر، نفِّذ ما يلي:

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

الوسيطات

الاسم النوع القيود
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 على مستوى البت.

مدخلات

التصنيف الاسم النوع القيود
(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).
  • (ج2) size(edge_padding_low) = size(edge_padding_high) = size(interior_padding) = rank(operand).
  • (ج3) 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>

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

popcnt

الدلالات

تُجري عملية احتساب عدد وحدات البت التي تم ضبطها في مصفوفة 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]

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

recv

الدلالات

تتلقّى البيانات من قناة تحتوي على channel_id وتُنشئ results.

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

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

مدخلات

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

النواتج

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

القيود

  • يتم تعريف (C1) channel_type على النحو التالي:
    • HOST_TO_DEVICE إذا is_host_transfer = true،
    • DEVICE_TO_DEVICE بخلاف ذلك.
  • (ج2) 0 < size(results).
  • (ج3) 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...)).
  • (ج2) element_type(inputs...) = element_type(init_values...).
  • (ج3) 0 < size(inputs) = size(init_values) = size(results) = N.
  • (C4) 0 <= dimensions < rank(inputs[0]).
  • (ج5) 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).
  • (ج7) 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 (ج3)

النواتج

الاسم النوع القيود
output مصفوفة من النوع العشري أو مصفوفة مُشفَّرة لكل مصفوفة (C1)

القيود

  • (ج1) baseline_type(operand) = baseline_type(output).
  • (C2) 1 <= exponent_bits.
  • (ج3) 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.
  • (ج2) 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
  • (ج5) 0 <= replica_groups < size(replica_groups).
  • (ج6) إذا كان 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).
  • (ج9) 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...)).
  • (ج3) element_type(inputs...) = element_type(init_values...).
  • (C4) size(window_dimensions) = rank(inputs[0]).
  • (ج5) 0 < window_dimensions.
  • (C6) size(window_strides) = rank(inputs[0]).
  • (ج7) 0 < window_strides.
  • (C8) size(base_dilations) = rank(inputs[0]).
  • (ج9) 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) قد تختلف عن الأخرى.
  • (ج2) size(operand) = size(result).
  • (ج3) إذا كان 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).
  • (ج2) is_unique(dimensions).
  • (ج3) 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 (ج3)
(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).
  • (ج3) 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. أرقام عشوائية متوازية: خطوات سهلة وبسيطة.

مدخلات

التصنيف الاسم النوع القيود
(I1) rng_algorithm enum من 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 عناصر individual في 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 عناصر individual في 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)`.
  • (ج3) 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.
  • (ج5) 0 < size(inputs) = size(updates) = N.
  • (C6) element_type(updates...) = element_type(inputs...).
  • (ج7) 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).
  • (ج2) 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 (راجِع reduce) لا يتضمّن قيم الإعداد. لم يتم تحديد حاليًا ما يحدث في حال عدم توفّر قيم في النافذة المقابلة (#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 أو مصفوفة متّجهية مُشفَّرة لكلّ متّجه (ج3)
(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.
  • (ج3) element_type(init_value) = element_type(operand).
  • (C4) size(window_dimensions) = rank(operand).
  • (ج5) 0 < window_dimensions.
  • (C6) size(window_strides) = rank(operand).
  • (C7) 0 < window_strides.
  • (ج8) 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، يمكن التعبير عن الدلالات باستخدام بنية Python على النحو التالي:

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.
  • (ج5) 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 عناصر individual في 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).
  • (ج2) type(inputs...) = type(results...).
  • (ج3) same(shape(inputs...) + shape(results...)).
  • (C4) -R <= dimension < R، حيث R = rank(inputs[0]).
  • (C5) comparator من النوع (tensor<E1>, tensor<E1>, ..., tensor<EN-1>, tensor<EN-1>) -> tensor<i1>، حيث Ei = element_type(inputs[i]).

أمثلة

// %input0 = [[1, 2, 3], [3, 2, 1]]
// %input1 = [[3, 2, 1], [1, 2, 3]]
%result0, %result1 = "stablehlo.sort"(%input0, %input1) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>, %arg2: tensor<i64>, %arg3: tensor<i64>):
    %predicate = "stablehlo.compare"(%arg0, %arg1) {
      comparison_direction = #stablehlo<comparison_direction GT>
    } : (tensor<i64>, tensor<i64>) -> tensor<i1>
    "stablehlo.return"(%predicate) : (tensor<i1>) -> ()
}) {
  dimension = 0 : i64,
  is_stable = true
} : (tensor<2x3xi64>, tensor<2x3xi64>) -> (tensor<2x3xi64>, tensor<2x3xi64>)
// %result0 = [[3, 2, 3], [1, 2, 1]]
// %result1 = [[1, 2, 1], [3, 2, 3]]

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

sqrt

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

تُجري عملية الجذر التربيعي لكل عنصر في مصفوفة operand وتُنشئ مصفوفة result. بناءً على نوع العنصر، نفِّذ ما يلي:

  • بالنسبة إلى الأعداد العشرية العائمة: squareRoot من IEEE-754
  • بالنسبة إلى الأعداد المركّبة: جذر تربيعي مركّب.
  • بالنسبة إلى الأنواع التي تم تحويلها إلى قيم عددية: dequantize_op_quantize(sqrt, operand, type(result)).

مدخلات

التصنيف الاسم النوع القيود
(I1) operand مصفوفة متّجه من النوع الكسري أو المركّب أو مصفوفة متّجه مُشفَّرة لكل متّجه (C1)

النواتج

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

القيود

  • (ج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]
//          ]

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

tanh

الدلالات

تُنفِّذ عملية ظلّ زائدي للزاوية على عنصر مصفوفة 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) قد يختلفان، بخلاف ذلك.
  • (ج2) permutation هو تبديل range(rank(operand)).
  • (ج3) 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 (ج3)
(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).
  • (ج2) 2 <= rank(a) = rank(b) = R.
  • (ج3) يتم تعريف العلاقة بين shape(a) وshape(b) على النحو التالي:
    • shape(a)[:-3] = shape(b)[:-3].
    • dim(a, -2) = dim(a, -1) = dim(b, left_side ? -2 : -1).
  • (C4) baseline_type(b) = baseline_type(result).

أمثلة

// %a = [
//       [1.0, 0.0, 0.0],
//       [2.0, 4.0, 0.0],
//       [3.0, 5.0, 6.0]
//      ]
// %b = [
//       [2.0, 0.0, 0.0],
//       [4.0, 8.0, 0.0],
//       [6.0, 10.0, 12.0]
//      ]
%result = "stablehlo.triangular_solve"(%a, %b) {
  left_side = true,
  lower = true,
  unit_diagonal = false,
  transpose_a = #stablehlo<transpose NO_TRANSPOSE>
} : (tensor<3x3xf32>, tensor<3x3xf32>) -> tensor<3x3xf32>
// %result: [
//           [2.0, 0.0, 0.0],
//           [0.0, 2.0, 0.0],
//           [0.0, 0.0, 2.0]
//          ]

tuple

الدلالات

تنتج صف result من القيم val.

مدخلات

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

النواتج

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

القيود

  • (C1) النوع result يحتوي على النوع tuple<E0, ..., EN-1> حيث Ei = type(val[i]).

أمثلة

// %val0: [1.0, 2.0]
// %val1: (3)
%result = "stablehlo.tuple"(%val0, %val1) : (tensor<2xf32>, tuple<tensor<i32>>) -> tuple<tensor<2xf32>, tuple<tensor<i32>>>
// %result: ([1.0, 2.0], (3))

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

uniform_dequantize

الدلالات

تُجري عملية تحويل عنصرية لمجموعة السلاسل التسلسلية المحوَّلة إلى كثافة operand إلى مجموعة سلاسل تسلسلية result ذات نقطة عائمة وفقًا لمَعلمات التكثيف التي يحدّدها نوع operand.

اسم "result = dequantize(operand)" رسميًا.

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متّجه مُكمّر (C1)، (C2)

النواتج

الاسم النوع القيود
result مصفوفة من النوع النقطة العائمة (C1)، (C2)

القيود

  • (ج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).
  • (ج2) 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]).
  • (ج3) 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 المضمّن.

يشير بروتوكول 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>
}

بشكل أكثر رسمية، عملية StableHLO هي تركيبة من: 1) برنامج StableHLO، و2) حالات العمليات (لم يتم تنفيذها بعد، تم تنفيذها)، و3) القيم الوسيطة التي تعمل عليها العملية. تبدأ العملية بقيم الإدخال في الدالة main، وتنتقل إلى الرسم البياني لعمليات تعديل حالات العمليات والقيم الوسيطة، ثم تنتهي بقيم الإخراج. سيتم تحديد مزيد من الإجراءات الرسمية لاحقًا (#484).

التنفيذ المتوازي

يمكن تنفيذ برامج StableHLO بالتوازي، ويتم تنظيمها في شبكة عملية ثنائية الأبعاد من num_replicas بواسطة num_partitions وكلاهما من النوع ui32.

في شبكة عمليات StableHLO، يتم تنفيذ num_replicas * num_partitions من عمليات StableHLO في الوقت نفسه. لكل عملية process_id = (replica_id, partition_id) فريد، حيث replica_id في replica_ids = range(num_replicas) و partition_id في partition_ids = range(num_partitions) اللذان يملكان النوع ui32.

إنّ حجم شبكة العمليات معروف بشكل ثابت لكل برنامج (في المستقبل، نخطّط لجعله جزءًا صريحًا من برامج StableHLO #650)، كما أنّ الموضع داخل شبكة العمليات معروف بشكلٍ ثابت لكل عملية. يمكن لكل عملية الوصول إلى موقعها ضمن شبكة العمليات من خلال عمليتَي replica_id و partition_id.

ضمن شبكة العمليات، يمكن أن تكون البرامج متطابقة (باستخدام النمط "برنامج واحد، بيانات متعدّدة") أو مختلفة (باستخدام النمط "برامج متعدّدة، بيانات متعدّدة") أو ما بينهما. ونخطط في المستقبل لتقديم الدعم للمصطلحات الأخرى المتعلقة بتحديد برامج StableHLO الموازية، بما في ذلك GSPMD (#619).

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

بالنظر إلى تنفيذ معظم العمليات فقط باستخدام قيم من نفس العملية، يكون من الواضح عادةً الإشارة إلى هذه القيم من خلال أسمائها. ومع ذلك، لا يكفي وصف دلالات العمليات الجماعية، ما يؤدي إلى ظهور الرمز name@process_id للإشارة إلى القيمة name ضمن عملية معيّنة. (من هذه الناحية، يمكن استخدام name غير المؤهَّلة كاختصار لـ name@(replica_id(), partition_id())).

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

الاتصال من نقطة إلى نقطة

يمكن أن تتواصل عمليات StableHLO بعضها مع بعض من خلال قنوات 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. بشكل أكثر رسمية، باستخدام بنية Python:

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. بشكل أكثر رسمية، باستخدام بنية Python:

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. بشكل أكثر رسمية، باستخدام بنية Python:

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>
}

الرمز الموسيقي

لوصف البنية، يستخدم هذا المستند بنية EBNF المعدَّلة وفقًا لمعيار ISO (ISO/IEC 14977:1996، Wikipedia)، مع إجراء تعديلَين: 1) يتم تعريف القواعد باستخدام ::= بدلاً من =،

2) يتم التعبير عن التسلسل باستخدام الترادف بدلاً من ,.

لوصف الدلالات (أي ضمن أقسام "الأنواع" و"الثوابت" و"العمليات")، نستخدم صِيَغًا تستند إلى بنية بايثون الموسّعة مع إتاحة التعبير بدقة عن عمليات الصفيف كما هو موضّح أدناه. يفيد ذلك في التعامل مع مقتطفات الرمز البرمجي الصغيرة، ولكن في بعض الحالات النادرة التي نحتاج فيها إلى مقتطفات أكبر من التعليمات البرمجية، نستخدم بناء جملة vanilla Python الذي يتم تقديمه دائمًا بشكل صريح.

الصيغ

لنستكشف كيف تعمل المعادلات بناءً على مثال من مواصفات dot_general. يبدو أحد قيود هذه العملية على النحو التالي: dim(lhs, lhs_batching_dimensions...) = dim(rhs, rhs_batching_dimensions...).

تأتي الأسماء المستخدَمة في هذه الصيغة من مصدرَين: 1) الدوالّ الشاملة، أي dim، 2) تعريفات الأعضاء لعنصر البرنامج المقابل، أي مدخلات lhs وlhs_batching_dimensions وrhs وrhs_batching_dimensions المحدَّدة في قسم "المدخلات" ضمن dot_general.

كما ذكرنا أعلاه، تستند بنية هذه الصيغة إلى Python مع بعض الإضافات الموجّهة إلى الإيجاز. لفهم الصيغة، لنبدِّلها إلى بنية Python الأساسية.

(أ) في هذه الصِيَغ، نستخدم = لتمثيل المساواة، لذا فإنّ الخطوة الأولى نحو الحصول على بنية Python هي استبدال = بـ ==، على النحو التالي: dim(lhs, lhs_batching_dimensions...) == dim(rhs, rhs_batching_dimensions...).

ب) تتيح هذه الصِيَغ أيضًا استخدام الأقواس البيضاوية (...) التي تحوّل التعبيرات السلاسلِية إلى تعبيرات مصفوفات. باختصار، تعني f(xs...) تقريبًا "لكل مقدار скалري x في مصفوفة xs، احتسِب مقدارًا скалريًا f(x) ثم أعِد كل هذه القيم السكالرية معًا كنتيجة مصفوفة". في بنية Python العادية، تتحول صيغة المثال إلى: [dim(lhs, dim1) for dim1 in lhs_batching_dimensions] == [dim(rhs, dim2) for dim2 in rhs_batching_dimensions].

بفضل الأقواس البيضاوية، غالبًا ما يكون من الممكن تجنُّب العمل على مستوى المقاييس الفردية. ومع ذلك، في بعض الحالات الصعبة، قد يتم استخدام نحو شبه غير رسمي من المستوى الأدنى، مثل صيغة start_indices[bi0, ..., :, ..., biN] من مواصفة gather. من أجل الإيجاز، لا نقدّم أسلوبًا رسميًا دقيقًا لترجمة هذه البنية إلى لغة Python الأساسية، على أمل أن يظلّ من السهل فهمها بشكل حدسي على أساس كل حالة على حدة. يُرجى إعلامنا إذا كانت بعض الصِيَغ المحدّدة تبدو غير شفافة، وسنحاول تحسينها.

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

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

لمواصلة مثال dot_general، إليك قيد آخر: 0 <= lhs_batching_dimensions < rank(lhs). وفقًا لتعريف dot_general المواصفات، lhs_batching_dimensions هو مصفوفة، ولكن كلاً من 0 و rank(lhs) هما متّجهان. بعد تطبيق البث الضمني، سيصبح[0, ..., 0] <= lhs_batching_dimensions < [rank(lhs), ..., rank(lhs)] هو [0, ..., 0] <= lhs_batching_dimensions < [rank(lhs), ..., rank(lhs)].

عند تطبيق هذه الصيغة على عملية dot_general معيّنة، سيتم تقييم هذه الصيغة إلى متسابق من القيم المنطقية. عند استخدام الصِيَغ كقيود، يتم تطبيق القيد إذا كانت القيمة الناتجة عن تقييم الصيغة هي true أو مصفوفة تصعيد تتضمّن true عنصرًا فقط.

الاسماء

في الصِيَغ، يتضمّن النطاق المعجمي ما يلي: 1) الدوالّ العامة، 2) تعريفات الأعضاء.

3) التعريفات المحلية. في ما يلي قائمة الدوال العمومية. تعتمد قائمة تعريفات العناصر على عنصر البرنامج الذي يتم تطبيق الرمز عليه:

  • بالنسبة للعمليات، تتضمن تعريفات الأعضاء الأسماء التي تم تقديمها في قسمي "الإدخالات" و"المخرجات".
  • بالنسبة إلى كل العناصر الأخرى، تتضمّن تعريفات العناصر أجزاءً هيكلية من عنصر البرنامج، ويتم تسميتها باسم العناصر غير النهائية في بنية EBNF المقابلة. في معظم الأحيان، يتم الحصول على أسماء هذه الأجزاء الهيكلية من خلال تحويل أسماء العناصر غير الطرفية إلى تنسيق Snake Case (مثل IntegerLiteral => integer_literal)، ولكن في بعض الأحيان يتم اختصار الأسماء أثناء العملية (مثل QuantizationStorageType => storage_type)، وفي هذه الحالة يتم إدخال الأسماء بشكل صريح على غرار أقسام "المدخلات" / "المخرجات" في مواصفات العملية.
  • بالإضافة إلى ذلك، تتضمّن تعريفات الأعضاء دائمًا self للإشارة إلى عنصر البرنامج المقابل.

القيم

عند تقييم الصِيَغ، تعمل مع الأنواع التالية من القيم: 1) Value (القيم الفعلية، مثل dense<[[1, 2], [3, 4]]> : tensor<2x2xi32>، وتكون أنواعها معروفة دائمًا)، 2) Placeholder (القيم المستقبلية، مثل lhs أو rhs أو result، وتكون قيمها الفعلية غير معروفة بعد، وتكون أنواعها فقط معروفة)، 3) Type (الأنواع على النحو المحدّد في قسم "الأنواع")، 4) Function (الدوالّ الشاملة على النحو المحدّد في قسم "الدوالّ").

استنادًا إلى السياق، قد تشير الأسماء إلى قيم مختلفة. على نحوٍ أدق، يحدّد قسم "الدلالات" للعمليات (والعناصر المشابهة لعناصر البرنامج الأخرى) منطق وقت التشغيل، وبالتالي تتوفّر جميع المدخلات على هيئة Value. في المقابل، يحدّد قسم "القيود" الخاص بالعمليات (والمكافئات) منطق "وقت التجميع"، أي إجراء يتم تنفيذه عادةً قبل وقت التشغيل، لذلك لا تتوفّر سوى الإدخالات الثابتة مثل Value ولا تتوفّر مصادر الإدخال الأخرى إلا بتنسيق Placeholder.

الاسماء في "الدلالات" في "القيود"
الدوالّ العامة Function Function
الإدخالات الثابتة Value Value
الإدخالات غير الثابتة Value Placeholder
النواتج Value Placeholder
التعريفات المحلية يعتمد ذلك على التعريف يعتمد ذلك على التعريف

لنلقِ نظرة على مثال على عملية transpose:

%result = "stablehlo.transpose"(%operand) {
  permutation = dense<[2, 1, 0]> : tensor<3xi64>
} : (tensor<2x3x2xi32>) -> tensor<2x3x2xi32>

بالنسبة إلى هذه العملية، تكون permutation قيمة ثابتة، لذا فهي متاحة كـ Value في كل من الدلالات والقيود. في المقابل، يتوفرoperand وresult كValue في الدلالات، ولكن كPlaceholder فقط في القيود.

الدوال

إنشاء الأنواع

لا تتوفّر دوال يمكن استخدامها لإنشاء أنواع. بدلاً من ذلك، نستخدم مباشرةً بنية النوع لأنّها عادةً ما تكون أكثر إيجازًا. على سبيل المثال، (tensor<E>, tensor<E>) -> (tensor<E>) بدلاً من function_type( [tensor_type([], E), tensor_type([], E)], [tensor_type([], E)]).

الدوالّ على الأنواع

  • يتم تعريف element_type على أنواع مصفوفات السلاسل الزمنية وأنواع مصفوفات السلاسل الزمنية المقيَّدة ويؤدي إلى عرض جزء TensorElementType أو QuantizedTensorElementType من TensorType أو QuantizedTensorType المطابقَين على التوالي.
def element_type(x: Value | Placeholder | Type):
 if type(x) == TensorType:
    return tensor_element_type(x)
  if type(x) == QuantizedTensorType:
    return quantized_tensor_element_type(x)
  if type(x) is not Type:
    return element_type(type(x))
  • is_per_axis_quantized(x: Value | Placeholder | Type) -> Value هو اختصار لـ is_quantized(x) and quantization_dimension(x) is not None.

  • is_per_tensor_quantized(x: Value | Placeholder | Type) -> Value هو اختصار لـ is_quantized(x) and quantization_dimension(x) is None.

  • يتحقّق is_promotable(x: Type, y: Type) -> bool ممّا إذا كان يمكن ترقية النوع x إلى النوع y. عندما تكون قيمة x وy هي QuantizedTensorElementType، لا يسري العرض الترويجي إلا على storage_type. يُستخدم هذا الإصدار المحدّد من العرض الترويجي حاليًا في سياق احتساب التقليل (يمكنك مراجعة RFC للاطّلاع على مزيد من التفاصيل).

def is_promotable(x: Type, y: Type) -> Value:
  is_same_type = (is_bool(x) and is_bool(y)) or
    (is_integer(x) and is_integer(y)) or (is_float(x) and is_float(y)) or
    (is_complex(x) and is_complex(y)) or
    (is_quantized(x) and is_quantized(y) and expressed_type(x) = expressed_type(y))

  if is_same_type == False:
    return False

  if is_integer(x) or is_float(x):
    return bitwidth(x) <= bitwidth(y)

  if is_complex(x):
    return bitwidth(element_type(x)) <= bitwidth(element_type(y))

  if is_quantized(x):
    return bitwidth(storage_type(x)) <= bitwidth(storage_type(y))

  return false
  • is_quantized(x: Value | Placeholder | Type) -> Value هو اختصار لعبارة is_quantized_tensor_element_type(x).

  • is_type_name(x: Value | Placeholder | Type) -> Value. متوفّرة لجميع الأنواع. على سبيل المثال، تعرِض is_float(x) القيمة true إذا كانت x هي FloatType. إذا كان x قيمة أو عنصر نائب، تكون هذه الدالة اختصارًا لمحاولة is_type_name(type(x)).

  • تعرِض max_value(x: Type) -> Value الحد الأقصى لقيمة TensorElementType. إذا لم تكن x TensorElementType، يتم عرض None.

  • تعرِض الدالة min_value(x: Type) -> Value الحد الأدنى للقيمة الممكنة لسمة TensorElementType. إذا لم تكن x TensorElementType، يتم عرض None.

  • member_name(x: Value | Placeholder | Type) -> Any. متاحة لجميع تعريفات الأعضاء member_name من جميع الأنواع. على سبيل المثال، تعرض tensor_element_type(x) الجزء TensorElementType من TensorType المطابق. إذا كان x قيمة أو عنصر نائب، تكون هذه الدالة اختصارًا لمحاولة member_name(type(x)). إذا لم يكن x نوعًا يتضمّن عنصرًا مناسبًا، أو قيمة أو عنصرًا نائبًا من هذا النوع، يتم عرض None.

  • يتحقق is_empty_algorithm(*args: Type) مما إذا تم ضبط جميع حقول خوارزمية النقاط على None. ويُعدّ ذلك ضروريًا لأنّ خوارزميات النقاط لها سلوكيات تلقائية محدّدة التنفيذ، لذا سيكون تحديد قيمة تلقائية غير صحيح.

إنشاء القيم

  • operation_name(*xs: Value | Type) -> Value: متاح لجميع العمليات. على سبيل المثال، تأخذ add(lhs, rhs) قيمتين للمتساع lhs وrhs وتعرض ناتج تقييم عملية add بهذه المدخلات. في بعض العمليات، مثل broadcast_in_dim، تكون أنواع نتائجها "قابلة للحمل"، أي أنّها مطلوبة لتقييم عملية. في هذه الحالة، تأخذ الدالة هذه الأنواع كوسيطات.

الدوالّ على القيم

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

  • يتمّ تعريف to_destination_type(x: Value, destination_type: Type) -> Value على كثافات تشكلت من tensors، وتُعرِض القيمة المحوَّلة لـ x استنادًا إلى type(x) و destination_type على النحو التالي:

def to_destination_type(x: Value, destination_type: Type) -> Value:
  if type(x) == destination_type:
    return x

  if is_quantized(destination_type):
    if is_quantized(type(x)):
      return quantize(x, destination_type)
    assert is_float(type(x))
    return quantize(x, destination_type)

  if is_quantized(type(x)):
    assert destination_type = expressed_type(type(x))
    return dequantize(type(x))

  return convert(x, destination_type)

هناك مناقشة مبكّرة حول دمج عمليات convert وuniform_quantize و uniform_dequantize (#1576). بعد الدمج، لا نحتاج إلى الدالة أعلاه ويمكننا استخدام اسم العملية لـ convert بدلاً من ذلك.

  • يتم تعريف is_nan(x: Value) -> Value على مصفوفات متجاوبة وتعرض true إذا كانت جميع عناصر x هي NaN أو false بخلاف ذلك. إذا لم يكن x أداة تنس، يتم عرض None.

  • يتم تحديد is_sorted(x: Value) -> Value في قيم التوتر وعرض true إذا كانت عناصر x مرتّبة تصاعديًا بالنسبة إلى الترتيب الهيكلي التصاعدي لمؤشراتها أو false بطريقة أخرى. إذا لم يكن x ملفًا مكثّفًا، يتم عرض None.

  • يتم تعريف is_unique(x: Value) -> Value على مصفوفات متجاوبة وتعرض القيمة true إذا لم تكن x تحتوي على عناصر مكرّرة أو false في حال عدم استيفاء هذا الشرط. إذا لم تكن x مصفوفة كثيفة، يتم عرض None.

  • يتم تعريف member_name(x: Value) -> Any لجميع تعريفات الأعضاء member_name لجميع القيم. على سبيل المثال، تعرض real_part(x) الجزء RealPart من ComplexConstant المطابق. إذا لم تكن x قيمة تحتوي على عضو مناسب، يتم عرض None.

  • يتم تعريف same(x: Value) -> Value على مصفوفات متجاوبة وتُرجع true إذا كانت عناصر x متساوية مع بعضها البعض أو false في الحالات الأخرى. إذا لم يكُن هناك عناصر في Tensor، يُحتسب ذلك على أنّه "جميعها متساوية بعضها مع بعض"، أي أنّ الدالة تعرض true. إذا لم تكن x مصفوفة تانسور، يتم عرض None.

  • يتم تعريف split(x: Value, num_results: Value, axis: Value) -> Value على المتجهات وتُعرِض num_results شرائح من x على طول المحور axis. إذا لم يكن x مصفوفة تانسور أو 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 في النقطة العائمة وrhs في الأنواع التي تم تقليلها كميًا. يحدد المدخلات الكميّة في أنواعها المعب عنها ويجري الحساب في عدد عائم. يجب أن يكون نوع العنصر float lhs tensor والنوع الموضح لنسور rhs الكمّي متطابقًا.
def hybrid_dequantize_then_op(op, lhs, rhs):
  assert(is_float(lhs) and is_quantized(rhs) and element_type(lhs) == expressed_type(rhs))
  return op(lhs, dequantize(rhs))

عمليات حسابية في الشبكة

  • cross_partition(replica_groups: Value) -> Value. اطّلِع على القسم "cross_replica" أعلاه.

  • cross_replica(replica_groups: Value) -> Value. اطّلِع على القسم "cross_replica" أعلاه.

  • cross_replica_and_partition(replica_groups: Value) -> Value. اطّلِع على القسم "cross_replica_and_partition" أعلاه.

  • flattened_ids(replica_groups: Value) -> Value. راجِع القسم "flattened_ids" أعلاه.

الديناميكية

يمكن أن تحتوي قيم StableHLO على أحجام سمات ديناميكية، مثل tensor<?xi64>. ومع ذلك، لا يمكن أن تحتوي قيم StableHLO على عدد ديناميكي من السمات (ديناميكية غير مصنّفة، مثل tensor<*xi64>). يُسمح للمُعامِلات والنتائج باستخدام أحجام سمات ديناميكية، حتى إذا كانت هناك قيود على الأحجام. سيتم التحقّق من القيود بشكل ثابت إن أمكن، وإلا سيتم تأجيلها إلى وقت التشغيل، وسيؤدي عدم المطابقة إلى سلوك غير محدّد. يمكنك الاطّلاع على الأمثلة أدناه.

عدم تطابق الشكل للعمليات الأحادية العنصر

فكِّر في البرنامج التالي:

func.func @foo(%arg0: tensor<?xf64>) {
  %0 = stablehlo.abs %arg0 : (tensor<?xf64>) -> tensor<2xf64>
  return
}

هذا البرنامج غير معتاد، لأنه ليس من الشائع معرفة شكل النتيجة ولكن ليس شكل المدخلات. ومع ذلك، يعد هذا برنامج StableHLO صالحًا. لا يمكن التحقّق من عملية abs بشكلٍ ثابت في هذا البرنامج، لأنّ الشكل الدقيق للمَعلمة غير معروف. مع ذلك، تتوافق الأشكال بالتأكيد، ويمكن التحقّق من ذلك بشكل ثابت: قد يتبين أنّ ? هو 2 في وقت التشغيل، ولن تكون هناك أي مشكلة. ومع ذلك، يمكن أن يتحول ? أيضًا إلى عدد صحيح آخر، وفي هذه الحالة يكون السلوك غير محدّد.

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

عدم تطابق الشكل للعمليات الثنائية على مستوى العنصر

ضع في اعتبارك برنامج الألعاب التالي:

func.func @foo(%arg0: tensor<?xf64>, %arg1: tensor<?xf64>) {
  %0 = stablehlo.add %arg0, %arg0 : (tensor<?xf64>, tensor<?xf64>) -> tensor<?xf64>
  return
}

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

عدم تطابق الشكل للعمليات التي تأخذ شكل الإخراج كمعامل

فكِّر في البرنامج التالي:

func.func @foo(%arg0: tensor<2xi32>) {
  %0 = stablehlo.dynamic_iota %arg0, dim = 0 : (tensor<2xi32>) -> tensor<3x4xi64>
  return
}

يجب أن تتطابق القيم في معامل الشكل في وقت التشغيل مع شكل النتيجة، وإلا يكون السلوك غير محدد. وهذا يعني أنّه في وقت التشغيل، يجب أن تكون قيمة %arg0 هي dense<[3, 4]> : tensor<2xi32>. إذا كان معامل الشكل ثابتًا، يمكن التحقق من ذلك بشكل ثابت. إذا كان شكل النتيجة ديناميكيًا بالكامل، لن يكون هناك عدم تطابق.