مواصفات StableHLO

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

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

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

البرامج

Program ::= {Func}

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

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

الدوال

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

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

المعرّفات

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

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

الأنواع

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

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

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

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

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

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

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

  • (C1) num_bits(storage_type) < num_bits(expressed_type).
  • (C2) type(storage_min) = storage_type.
  • (C3) type(storage_max) = storage_type.
  • (C4) min_value(storage_type) <= storage_min < storage_max <= max_value(storage_type).
  • (C5) type(scales...) = expressed_type.
  • (C6) 0 < scales.
  • (C7) is_finite(scales...).
  • (C8) storage_min <= zero_points <= storage_max.
  • (C9) type(zero_points...) = storage_type.
  • (C10) size(scales) = size(zero_points).
  • (C11) إذا كانت is_empty(quantization_dimension)، تكون size(scales) = 1.
  • (C12) 0 <= quantization_dimension.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

StringType ::= 'string'

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

العمليات

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

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

تتضمَّن عمليات SttableHLO (التي تُسمى أيضًا ops) اسمًا ومدخلات/مخرجات وتوقيعًا. يتكوّن الاسم من البادئة stablehlo. وmnemonic تحدد بشكل فريد إحدى العمليات المتوافقة. انظر أدناه للحصول على قائمة شاملة بجميع العمليات المدعومة.

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

  • builtin.module وfunc.func وfunc.call وfunc.return (رقم 425).
  • عمليات chlo (#602).
  • فئة "ليست في HLO" من عمليات StableHLO - كانت في البداية جزءًا من عملية StableHLO ولكن تم اعتبارها لاحقًا غير مناسبة: broadcast، create_token، cross-replica-sum، dot، einsum، torch_index_select، unary_einsum (#3).
  • فئة "Dynamism" من عمليات StableHLO - تم تحديدها منذ البداية من MHLO، لكننا لم نحددها بعد: compute_reshape_shape، cstr_reshapable، dynamic_broadcast_in_dim، dynamic_conv، dynamic_gather، dynamic_iota، dynamic_pad، dynamic_reshape، real_dynamic_slice، set_dimension_size (#8).
  • العمليات الحسابية للأشكال، بما في ذلك عمليات arith وshape وtensor (#8).
OpInputs        ::= OpInputValues OpInputFuncs OpInputAttrs
OpInputValues   ::= '(' [OpInputValue {',' OpInputValue}] ')'
OpInputValue    ::= ValueId
OpInputFuncs    ::= ['(' OpInputFunc {',' OpInputFunc} ')']
OpInputAttrs    ::= ['{' OpInputAttr {',' OpInputAttr} '}']
OpOutputs       ::= [OpOutput {',' OpOutput} '=']
OpOutput        ::= ValueId

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

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

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

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

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

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

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

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

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

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

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

الثوابت

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

العمليات

abs

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

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

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

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

إضافة

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

تنفِّذ إضافة عناصر متكافئة lhs وrhs في كل عنصر وينتج عنها result متعدّد. بناءً على نوع العنصر، يتم تنفيذ ما يلي:

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(lhs) = baseline_type(rhs) = baseline_type(result).

أمثلة

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

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

after_all

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

يضمن تنفيذ العمليات التي تنتج عن inputs قبل أي عمليات تعتمد على result. ليس هناك أي تأثير لتنفيذ هذه العملية، بل الهدف الوحيد هو إنشاء تبعيات للبيانات من result إلى inputs.

مدخلات

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

المُخرَجات

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

أمثلة

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

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

all_gather

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

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

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

  • cross_replica(replica_groups) إذا channel_id <= 0 and use_global_device_ids = false.
  • cross_replica_and_partition(replica_groups) إذا channel_id > 0 and use_global_device_ids = false.
  • flattened_ids(replica_groups) إذا channel_id > 0 and use_global_device_ids = true.

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

  • operands@receiver = [operand@sender for sender in process_group] مقابل كل receiver في process_group.
  • result@process = concatenate(operands@process, all_gather_dim) مقابل كل process في process_group.

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

all_reduce

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

ضمن كل مجموعة عمليات في شبكة عمليات StableHLO، يتم تطبيق دالة الاختزال computation على قيم متدرج operand من كل عملية وينتج عن ذلك دالة result.

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

  • cross_replica(replica_groups) إذا channel_id <= 0 and use_global_device_ids = false.
  • cross_replica_and_partition(replica_groups) إذا channel_id > 0 and use_global_device_ids = false.
  • flattened_ids(replica_groups) إذا channel_id > 0 and use_global_device_ids = true.

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

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

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

// num_replicas: 2
// num_partitions: 1
// %operand@(0, 0): [1, 2, 3, 4]
// %operand@(1, 0): [5, 6, 7, 8]
%result = "stablehlo.all_reduce"(%operand) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
    "stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
  replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>,
  channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
} : (tensor<i64>) -> tensor<i64>
// %result@(0, 0): [6, 8, 10, 12]
// %result@(1, 0): [6, 8, 10, 12]

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

all_to_all

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

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

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

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

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

  • split_parts@sender = split(operand@sender, split_count, split_dimension) لكل sender في process_group.
  • scattered_parts@receiver = [split_parts@sender[receiver_index] for sender in process_group] حيث receiver_index = process_group.index(receiver).
  • result@process = concatenate(scattered_parts@process, concat_dimension).

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

// num_replicas: 2
// num_partitions: 1
// %operand@(0, 0): [[1, 2, 3, 4],
//                   [5, 6, 7, 8]]
// %operand@(1, 0): [[9, 10, 11, 12],
//                   [13, 14, 15, 16]]
%result = "stablehlo.all_to_all"(%operand) {
  split_dimension = 1 : i64,
  concat_dimension = 0 : i64,
  split_count = 2 : i64,
  replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>
} : (tensor<2x4xi64>) -> tensor<4x2xi64>
// %result@(0, 0): [[1, 2],
//                  [5, 6],
//                  [9, 10],
//                  [13, 14]]
// %result@(1, 0): [[3, 4],
//                  [7, 8],
//                  [11, 12],
//                  [15, 16]]

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

و

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

ينفذ الإجراء AND في عناصر مترابطة لاثنين من معاملَي الشد lhs وrhs وينتج عن result موتر. بناءً على نوع العنصر، يتم تنفيذ ما يلي:

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) type(lhs) = type(rhs) = type(result).

أمثلة

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

atan2

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

تُجري عملية atan2 على مستوى العناصر على مستوى lhs وrhs وتُنتج result متعدّد. بناءً على نوع العنصر، يتم تنفيذ ما يلي:

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(lhs) = baseline_type(rhs) = baseline_type(result).

أمثلة

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

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

batch_norm_grad

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

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

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

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

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

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

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

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

  return grad_operand, grad_scale, grad_offset

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

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

batch_norm_inference

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

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

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

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

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

مدخلات

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

المُخرَجات

الاسم النوع القيود
result متعدّد من نوع النقطة العائمة أو متعدّد كميّ لكل موقد (C2), (C7)

القيود

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

أمثلة

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

batch_norm_training

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

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

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

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

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

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

مدخلات

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

المُخرَجات

الاسم النوع القيود
output متعدّد من نوع النقطة العائمة أو متعدّد كميّ لكل موقد (C7)
batch_mean موتر أحادي البُعد للنقطة العائمة أو لكل موصّل كمّي (C2), (C5)
batch_var موتر أحادي البُعد للنقطة العائمة أو لكل موصّل كمّي (C2), (C6)

القيود

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

أمثلة

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

bitcast_convert

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

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

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

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

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

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

broadcast_in_dim

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

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

  • operand_index[d] = 0 إذا dim(operand, d) = 1.
  • أو operand_index[d] = result_index[broadcast_dimensions[d]].

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

حافظة

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

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

  • selected_branch = branches[index] إذا 0 <= index < size(branches).
  • أو selected_branch = branches[-1].

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

نظام CBRT

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

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(operand) = baseline_type(result).

أمثلة

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

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

ceil

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(operand) = baseline_type(result).

أمثلة

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

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

أزرق سماوي

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

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

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

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

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

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

مشبك

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

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

إنّ فرض ترتيب الأعداد المركّبة يتضمن دلالات منطقية مفاجئة، ولذلك نخطط في المستقبل لإزالة إتاحة استخدام الأرقام المركّبة لهذه العملية (#560).

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

collective_broadcast

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

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

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

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

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

  • operand@process_groups[i, 0] إذا كان هناك عنصر i بهذه الطريقة تكون العملية في process_groups[i].
  • broadcast_in_dim(constant(0, element_type(result)), [], type(result)) بطريقة أخرى.

مدخلات

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

المُخرَجات

الاسم النوع القيود
result متّجه متّجه للأسفل (C3)

القيود

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

أمثلة

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

collective_permute

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

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

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

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

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

  • operand@process_groups[i, 0]، في حال توفُّر عنصر i مثل process_groups[i, 1] = process.
  • broadcast_in_dim(constant(is_quantized(result) ? quantize(0, element_type(result)) : 0, element_type(result)), [], type(result)) بطريقة أخرى.

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

مقارنة

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

تُجري مقارنة من حيث العناصر بين معاملَي lhs وrhs وفقًا لـ comparison_direction وcompare_type، وينتج عن ذلك متغيّر result.

تتضمن قيمتي comparison_direction وcompare_type دلالات الألفاظ التالية:

لأنواع العناصر المنطقية والأعداد الصحيحة:

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

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

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

بالنسبة إلى أنواع عناصر النقطة العائمة مع compare_type = TOTALORDER، تستخدم العملية مزيجًا من العمليات totalOrder وcompareQuietEqual من IEEE-754. يبدو أن هذه الميزة لم يتم استخدامها، ولذلك نخطط لإزالتها في المستقبل (#584).

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

بالنسبة إلى الأنواع الكمية، ينفّذ دالة dequantize_compare(lhs, rhs, comparison_direction).

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

معقد

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

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

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

concatenate

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

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

  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)

القيود

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

أمثلة

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

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

الثابت

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

لإنشاء عارض output من قيمة value ثابتة.

مدخلات

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

المُخرَجات

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

القيود

  • (C1) type(value) = type(output).

أمثلة

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

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

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

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

تنفِّذ عملية تحويل العناصر من نوع عنصر إلى آخر على الموتر operand وينتج عنها متعدّد result.

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

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

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

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

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) shape(operand) = shape(result).

أمثلة

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

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

التفاف

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

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

بشكل أكثر رسمية، ننصحك بإعادة صياغة المدخلات وفقًا لـ lhs لتتمكن من التعبير عن نوافذ lhs:

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

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

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

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

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

إذا كان feature_group_count > 1:

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

إذا كان batch_group_count > 1:

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

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

مدخلات

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

المُخرَجات

الاسم النوع القيود
result متعدّد أو متدرج كمي (C25-C28), (C30-C31), (C33)

القيود

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

أمثلة

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

جيب التمام

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

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(operand) = baseline_type(result).

أمثلة

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

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

count_leading_zeros

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

ينفِّذ عددًا حسب العناصر لعدد وحدات البت البادئة صفر في المتسلسل operand وينتج عنها متعدّد result.

مدخلات

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

المُخرَجات

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

القيود

  • (C1) type(operand) = type(result).

أمثلة

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

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

custom_call

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

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

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

مدخلات

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

المُخرَجات

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

أمثلة

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

قسمة

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

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(lhs) = baseline_type(rhs) = baseline_type(result).

أمثلة

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

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

dot_general

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

تحسب المنتجات النقطية بين شرائح lhs وشرائح rhs وينتج عنها result متعدّد.

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

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

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

يحدد هذا فقط الدلالة الدلالية لتحديد كم المتسلسل. إن عملية القياس حسب المحور هي قيد التنفيذ (#1574). ويمكننا أيضًا في المستقبل إتاحة استخدام طريقة القياس المختلطة (#1575).

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

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

مدخلات

التصنيف الاسم النوع القيود
(I1) lhs متعدّد أو متعدّد كميّ لكل موقد (C5-C6), (C9-C10), (C12-C16)
(I2) rhs متعدّد أو متعدّد كميّ لكل موقد (C7-C10), (C12)
(I3) lhs_batching_dimensions ثابت الموتّر الأحادي الأبعاد من النوع si64 (C1)، (C3)، (C5)، (C9)، (C12)
(I4) rhs_batching_dimensions ثابت الموتّر الأحادي الأبعاد من النوع si64 (C1)، (C4)، (C7)، (C9)
(I5) lhs_contracting_dimensions ثابت الموتّر الأحادي الأبعاد من النوع si64 (C2), (C3), (C6), (C10)
(I6) rhs_contracting_dimensions ثابت الموتّر الأحادي الأبعاد من النوع si64 (C2), (C4), (C8), (C10)
(I7) precision_config عدد متغيّر لتعدادات DEFAULT وHIGH وHIGHEST (C11)

المُخرَجات

الاسم النوع القيود
result متعدّد أو متعدّد كميّ لكل موقد (C12), (C14), (C16)

القيود

  • (C1) size(lhs_batching_dimensions) = size(rhs_batching_dimensions).
  • (C2) size(lhs_contracting_dimensions) = size(rhs_contracting_dimensions).
  • (C3) is_unique(lhs_batching_dimensions + lhs_contracting_dimensions).
  • (C4) is_unique(rhs_batching_dimensions + rhs_contracting_dimensions).
  • (C5) 0 <= lhs_batching_dimensions < rank(lhs).
  • (C6) 0 <= lhs_contracting_dimensions < rank(lhs).
  • (C7) 0 <= rhs_batching_dimensions < rank(rhs).
  • (C8) 0 <= rhs_contracting_dimensions < rank(rhs).
  • (C9) dim(lhs, lhs_batching_dimensions...) = dim(rhs, rhs_batching_dimensions...).
  • (C10) dim(lhs, lhs_contracting_dimensions...) = dim(rhs, rhs_contracting_dimensions...).
  • (C11) size(precision_config) = 2.
  • (C12) shape(result) = dim(lhs, lhs_batching_dimensions) + dim(lhs, lhs_result_dimensions) + dim(rhs, rhs_result_dimensions).
  • إذا كانت العملية تستخدم متوترات غير كميّة:
    • (C13) element_type(lhs) = element_type(rhs).
  • إذا كانت العملية تستخدم متوترات كمّية:
    • (C14) is_quantized(lhs) and is_quantized(rhs) and is_quantized(result).
    • (C15) storage_type(lhs) = storage_type(rhs).
    • (C16) expressed_type(lhs) = expressed_type(rhs) = expressed_type(result).
    • (C17) zero_points(rhs) = 0.

أمثلة

// %lhs: [
//        [[1, 2],
//         [3, 4]],
//        [[5, 6],
//         [7, 8]]
//       ]
// %rhs: [
//        [[1, 0],
//         [0, 1]],
//        [[1, 0],
//         [0, 1]]
//       ]
%result = "stablehlo.dot_general"(%lhs, %rhs) {
  dot_dimension_numbers = #stablehlo.dot<
    lhs_batching_dimensions = [0],
    rhs_batching_dimensions = [0],
    lhs_contracting_dimensions = [2],
    rhs_contracting_dimensions = [1]
  >,
  precision_config = [#stablehlo<precision DEFAULT>, #stablehlo<precision DEFAULT>]
} : (tensor<2x2x2xi64>, tensor<2x2x2xi64>) -> tensor<2x2x2xi64>
// %result: [
//           [[1, 2],
//            [3, 4]],
//           [[5, 6],
//            [7, 8]]
//          ]

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

dynamic_slice

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

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

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

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

dynamic_update_slice

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

للحصول على مستطيل result يساوي المثلث operand باستثناء أنه يتم تعديل الشريحة التي تبدأ بـ start_indices بالقيم في update. بشكل أكثر رسمية، يتم تعريف result[result_index] على النحو التالي:

  • update[update_index] إذا كانت 0 <= update_index < shape(update)، أين:
    • adjusted_start_indices = clamp(0, start_indices, shape(operand) - shape(update)).
    • update_index = result_index - adjusted_start_indices.
  • أو operand[result_index].

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

دالات أسية

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

تؤدي هذه الدالة عملية أسية في كل العناصر على معامل operand وينتج عنها متعدّد result. بناءً على نوع العنصر، يتم تنفيذ ما يلي:

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(operand) = baseline_type(result).

أمثلة

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

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

exponential_minus_one

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

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(operand) = baseline_type(result).

أمثلة

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

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

fft

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

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

fft_type هو أحد الخيارات التالية:

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

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

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

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

بالإضافة إلى ذلك، باستخدام الدالة ifft التي لها نوع التوقيع نفسه وتحتسب معكوس fft:

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

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

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

  • المكان الذي تتوفّر فيه ميزة "rfft(real_operand) = truncated_result"
  • complex_operand... = (real_operand..., 0.0).
  • complex_result = fft(complex_operand).
  • truncated_result = complex_result[:(rank(complex_result) / 2 + 1)].

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

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

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

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

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

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

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

floor

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(operand) = baseline_type(result).

أمثلة

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

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

جمع

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

تجمع الشرائح من متعدّد operand من الإزاحة المحدَّدة في start_indices وينتج عنها متعدّد result

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

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

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

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

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

get_dimension_size

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

لعرض حجم dimension المحدد من operand. بشكل أكثر رسمية، "result = dim(operand, dimension)".

مدخلات

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

المُخرَجات

الاسم النوع
result متوتر 0 أبعاد من النوع si32

القيود

  • (C1) 0 <= dimension < rank(operand).

أمثلة

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

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

get_tuple_element

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

لاستخراج العنصر في موضع index بالصف operand وإنشاء result. بشكل أكثر رسمية، result = operand[index].

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

if

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) input_types(true_branch) = input_types(false_branch) = [].
  • (C2) output_types(true_branch) = output_types(false_branch).
  • (C3) type(results...) = output_types(true_branch).

أمثلة

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

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

تخيل

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) shape(result) = shape(operand).
  • (C2) يتم تعريف element_type(result) على النحو التالي:
    • complex_element_type(element_type(operand)) إذا is_complex(operand).
    • أو element_type(operand).

أمثلة

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

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

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

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

تقرأ البيانات من الخلاصة وتنشئ results.

يتم تحديد دلالات infeed_config للتنفيذ.

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

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

يوتا

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

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) 0 <= iota_dimension < rank(output).

أمثلة

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

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

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

is_finite

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) shape(x) = shape(y).

أمثلة

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

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

log

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

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(operand) = baseline_type(result).

أمثلة

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

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

log_plus_one

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

تؤدي هذه الدالة لوغاريتم العناصر في كل عنصر مع عملية واحدة على موتر operand وتنشئ متعدّد result. بناءً على نوع العنصر، يتم تنفيذ ما يلي:

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(operand) = baseline_type(result).

أمثلة

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

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

لوجستي

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

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(operand) = baseline_type(result).

أمثلة

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

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

خريطة

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

تطبِّق دالة الخريطة computation على inputs على طول dimensions وتُنشئ دالة متعدّد result.

بشكل أكثر رسمية، result[result_index] = computation(inputs...[result_index]). تجدر الإشارة إلى أنّ dimensions غير مستخدَمة حاليًا ومن المحتمل أن تتم إزالتها في المستقبل (#487).

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

أعلى قيمة

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

تُجري عمليات الحدّ الأقصى من حيث العناصر على الموترتَين lhs وrhs وتنتج result متعدّد. بناءً على نوع العنصر، يتم تنفيذ ما يلي:

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(lhs) = baseline_type(rhs) = baseline_type(result).

أمثلة

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

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

أقل قيمة

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

تُجري عمليات دقيقة من حيث أداء العناصر على الموترين lhs وrhs وتنتج result متبدّل. بناءً على نوع العنصر، يتم تنفيذ ما يلي:

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(lhs) = baseline_type(rhs) = baseline_type(result).

أمثلة

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

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

ضرب

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

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(operand) = baseline_type(result).

أمثلة

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

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

ينفي

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

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(operand) = baseline_type(result).

أمثلة

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

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

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

ليس

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

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

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

الوسيطات

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

المُخرَجات

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

القيود

  • (C1) type(operand) = type(result).

أمثلة

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

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

optimization_barrier

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

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

الوسيطات

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

المُخرَجات

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

القيود

  • (C1) type(operand...) = type(result...).

أمثلة

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

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

أو

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

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) type(lhs) = type(rhs) = type(result).

أمثلة

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

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

خلاصة خارجية

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

كتابة inputs في الخلاصة الخارجية وإنشاء رمز مميّز result

يتم تحديد دلالات outfeed_config للتنفيذ.

مدخلات

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

المُخرَجات

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

أمثلة

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

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

وسادة

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

لتوسيع operand من خلال المساحة المتروكة حول الموتر وكذلك بين عناصر الموتر باستخدام padding_value المحددة.

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

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

بشكل أكثر رسمية، يتم تعريف result[result_index] على النحو التالي:

  • operand[operand_index] إذا result_index = edge_padding_low + operand_index * (interior_padding + 1).
  • أو padding_value.

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

partition_id

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

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

المُخرَجات

الاسم النوع
result متوتر 0 أبعاد من النوع ui32

أمثلة

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

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

الترويج

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

تحسب العناصر حسب عدد العناصر في عدد وحدات البت المعيّنة في الموتر operand وينتج عنها متعدّد result.

مدخلات

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

المُخرَجات

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

القيود

  • (C1) type(operand) = type(result).

أمثلة

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

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

الطاقة

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

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(operand) = baseline_type(result).

أمثلة

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

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

الريال

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) shape(result) = shape(operand).
  • (C2) يتم تعريف element_type(result) على النحو التالي:
    • complex_element_type(element_type(operand)) إذا is_complex(operand).
    • أو element_type(operand).

أمثلة

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

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

recv

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

تلقّي البيانات من قناة مرتبطة بـ channel_id وينتج عنها results.

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

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

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

reduce

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

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

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

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

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

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

reduce_precision

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

تُجري إحالة ناجحة من حيث العناصر لـ operand إلى نوع نقطة عائمة آخر يستخدم exponent_bits وmantissa_bits والعودة إلى نوع النقطة العائمة الأصلي، وينتج عن ذلك متعدّد output.

بشكل أكثر رسمية:

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

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

reduce_scatter

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

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

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

  • cross_replica(replica_groups) إذا channel_id <= 0 and use_global_device_ids = false.
  • cross_replica_and_partition(replica_groups) إذا channel_id > 0 and use_global_device_ids = false.
  • flattened_ids(replica_groups) إذا channel_id > 0 and use_global_device_ids = true.

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

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

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

reduce_window

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

تطبِّق دالة الاختزال body على نوافذ inputs وinit_values وتنتج results.

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

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

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

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

الباقي

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

لتنفيذ باقي العناصر بالنسبة إلى المقسّم lhs والقاسم rhs وينتج عن ذلك المثلث result.

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

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(operand) = baseline_type(result).

أمثلة

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

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

replica_id

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

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

المُخرَجات

الاسم النوع
result متوتر 0 أبعاد من النوع ui32

أمثلة

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

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

إعادة تشكيل

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

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

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

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

إلغاء

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

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

  • operand_index[d] = dim(result, d) - result_index[d] - 1 إذا d في dimensions.
  • أو operand_index[d] = result_index[d].

مدخلات

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

المُخرَجات

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

القيود

  • (C1) type(operand) = type(result).
  • (C2) is_unique(dimensions).
  • (C3) 0 <= dimensions < rank(result).

أمثلة

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

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

rng

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

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

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

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

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

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

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

rng_bit_generator

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

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

rng_algorithm هو أحد الخيارات التالية:

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

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

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

round_nearest_afz

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(operand) = baseline_type(result).

أمثلة

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

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

round_nearest_even

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(operand) = baseline_type(result).

أمثلة

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

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

rsqrt

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

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(operand) = baseline_type(result).

أمثلة

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

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

scatter

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

إنتاج results من الأوتار التي تساوي inputs باستثناء أن العديد من الشرائح التي تم تحديدها بواسطة scatter_indices يتم تعديلها بالقيم updates باستخدام update_computation

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

بشكل أكثر رسمية، لجميع update_index في index_space(updates[0]):

  • update_scatter_dims = [d for d in axes(updates[0]) and d not in update_window_dims].
  • update_scatter_index = update_index[update_scatter_dims...].
  • تم تعريف السمة start_index على أنّها:
    • scatter_indices[si0, ..., :, ..., siN] حيث تكون si عناصر فردية في update_scatter_index و: في فهرس index_vector_dim، إذا كانت index_vector_dim < rank(scatter_indices).
    • أو [scatter_indices[update_scatter_index]].
  • بالنسبة إلى d_input في axes(inputs[0])،
    • full_start_index[d_input] = start_index[d_start] إذا d_input = scatter_dims_to_operand_dims[d_start].
    • أو full_start_index[d_input] = 0.
  • update_window_index = update_index[update_window_dims...].
  • full_window_index = [wi0, ..., 0, ..., wiN] حيث تكون wi عناصر فردية في update_window_index، ويتم إدراج 0 في فهارس من inserted_window_dims.
  • result_index = full_start_index + full_window_index.

بناءً على ذلك، results = exec(schedule, inputs)، حيث:

  • schedule هي تبديل محدد لتنفيذ index_space(updates[0]).
  • exec([update_index, ...], results) = exec([...], updated_results) حيث:
    • إذا كان result_index داخل حدود shape(results...)
    • updates_converted = to_destination_type( updates...[update_index], type(func_inputs(update_computation) [len(func_inputs(update_computation))//2:])... )
    • updated_values = update_computation(results...[result_index], updates_converted)
    • updated_results هو نسخة من results مع ضبط results...[result_index] على updated_values....
    • ويمكنك بدلاً من ذلك
    • updated_results = results.
  • exec([], results) = results.

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

إذا كانت قيمة unique_indices هي true، يمكن أن تفترض عملية التنفيذ أنّ جميع الفهارس result_index المتفرقة فريدة. إذا كانت قيمة السمة unique_indices هي true، ولكن الفهارس المتفرقة غير فريدة، سيكون السلوك غير محدّد.

مدخلات

التصنيف الاسم النوع القيود
(I1) inputs العدد المتباين للمتوترات أو الموترات الكمّية لكل مفرد (C1), (C2), (C4-C6), (C10), (C13), (C15-C16)
(I2) scatter_indices متعدّد نوع العدد الصحيح (C4), (C11), (C14)
(I3) updates العدد المتباين للمتوترات أو الموترات الكمّية لكل مفرد (C3-C6), (C8)
(I4) update_window_dims ثابت الموتّر الأحادي الأبعاد من النوع si64 (C2)، (C4)، (C7)، (C8)
(I5) inserted_window_dims ثابت الموتّر الأحادي الأبعاد من النوع si64 (C2)، (C4)، (C9)، (C10)
(I6) scatter_dims_to_operand_dims ثابت الموتّر الأحادي الأبعاد من النوع si64 (C11-C13)
(I7) index_vector_dim ثابت من النوع si64 (C4), (C11), (C14)
(I8) indices_are_sorted ثابت من النوع i1
(I9) unique_indices ثابت من النوع i1
(I10) update_computation function (C15)

المُخرَجات

الاسم النوع القيود
results العدد المتباين للمتوترات أو الموترات الكمّية لكل مفرد (C15-C17)

القيود

  • (C1) same(shape(inputs...)).
  • (C2) rank(inputs[0]) = size(update_window_dims) + size(inserted_window_dims).
  • (C3) same(shape(updates...)).
  • (C4) shape(updates[0]) = combine(update_scatter_dim_sizes, update_window_dim_sizes) أين:
    • update_scatter_dim_sizes = shape(scatter_indices) باستثناء أنه لا يتم تضمين حجم البُعد scatter_indices المتوافق مع index_vector_dim.
    • update_window_dim_sizes <= shape(inputs[0]) باستثناء أنه لا يتم تضمين أحجام الأبعاد في inputs[0] المقابلة لـ inserted_window_dims.
    • combine يضع update_scatter_dim_sizes على المحورين المقابلين لـ update_scatter_dims وupdate_window_dim_sizes في المحاور المقابلين لـ update_window_dims.
  • (C5) 0 < size(inputs) = size(updates) = N.
  • (C6) element_type(updates...) = element_type(inputs...).
  • (C7) is_unique(update_window_dims) and is_sorted(update_window_dims).
  • (C8) 0 <= update_window_dims < rank(updates[0]).
  • (C9) is_unique(inserted_window_dims) and is_sorted(update_window_dims).
  • (C10) 0 <= inserted_window_dims < rank(inputs[0]).
  • (C11) size(scatter_dims_to_operand_dims) = index_vector_dim < rank(scatter_indices) ? dim(scatter_indices, index_vector_dim) : 1.
  • (C12) is_unique(scatter_dims_to_operand_dims).
  • (C13) 0 <= scatter_dims_to_operand_dims < rank(inputs[0]).
  • (C14) 0 <= index_vector_dim <= rank(scatter_indices).
  • (C15) update_computation من النوع (tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ..., tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>)، حيث is_promotable(element_type(inputs[i]), Ei).
  • (C16) shape(inputs...) = shape(results...).
  • (C17) element_type(results[i]) = Ei لكل i في [0,N).

أمثلة

// %input: [
//          [[1, 2], [3, 4], [5, 6], [7, 8]],
//          [[9, 10], [11, 12], [13, 14], [15, 16]],
//          [[17, 18], [19, 20], [21, 22], [23, 24]]
//         ]
// %scatter_indices: [[[0, 2], [1, 0], [2, 1]], [[0, 1], [1, 0], [0, 9]]]
// %update: [
//           [[[1, 1], [1, 1]], [[1, 1], [1, 1]], [[1, 1], [1, 1]]],
//           [[[1, 1], [1, 1]], [[1, 1], [1, 1]], [[1, 1], [1, 1]]]
//          ]
%result = "stablehlo.scatter"(%input, %scatter_indices, %update) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
    "stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
  scatter_dimension_numbers = #stablehlo.scatter<
    update_window_dims = [2, 3],
    inserted_window_dims = [0],
    scatter_dims_to_operand_dims = [1, 0],
    index_vector_dim = 2>,
  indices_are_sorted = false,
  unique_indices = false
} : (tensor<3x4x2xi64>, tensor<2x3x2xi64>, tensor<2x3x2x2xi64>) -> tensor<3x4x2xi64>
// %result: [
//           [[1, 2], [5, 6], [7, 8], [7, 8]],
//           [[10, 11], [12, 13], [14, 15], [16, 17]],
//           [[18, 19], [20, 21], [21, 22], [23, 24]]
//          ]

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

اختيار

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

لعرض متدرج result حيث يتم اختيار كل عنصر من on_true أو on_false بناءً على قيمة العنصر المقابل وهو pred. بشكل أكثر رسمية، result[result_index] = pred_element ? on_true[result_index] : on_false[result_index]، حيث pred_element = rank(pred) = 0 ? pred[] : pred[result_index]. بالنسبة إلى الأنواع الكمية، ينفّذ dequantize_select_quantize(pred, on_true, on_false, type(result)).

مدخلات

التصنيف الاسم النوع القيود
(I1) pred متعدّد من النوع i1 (C1)
(I2) on_true متعدّد أو متعدّد كميّ لكل موقد (C1-C2)
(I3) on_false متعدّد أو متعدّد كميّ لكل موقد (C2)

المُخرَجات

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

القيود

  • (C1) rank(pred) = 0 or shape(pred) = shape(on_true).
  • (C2) baseline_type(on_true) = baseline_type(on_false) = baseline_type(result).

أمثلة

// %pred: [[false, true], [true, false]]
// %on_true: [[1, 2], [3, 4]]
// %on_false: [[5, 6], [7, 8]]
%result = "stablehlo.select"(%pred, %on_true, %on_false) : (tensor<2x2xi1>, tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[5, 2], [3, 8]]

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

select_and_scatter

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

مبعثرة القيم من متدرج source باستخدام scatter بناءً على ناتج reduce_window من المثلث input باستخدام select وينتج عن الموتر result.

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

بشكل أكثر رسمية:

  • selected_values = reduce_window_without_init(...) مع الإدخالَين التاليَين:

    • `inputs = [Operand].
    • تُستخدم window_dimensions وwindow_strides وpadding كما هي.
    • base_dilations = windows_dilations = 1.
    • تم تحديد body على أنّه:
    def body(arg0: tensor<E>, arg1: tensor<E>) -> tensor<E>:
      return select(arg0, arg1) ? arg0 : arg1;
    

    حيث تعمل E = element_type(operand) وreduce_window_without_init تمامًا مثل reduce_window، باستثناء أنّ schedule في العنصر الأساسي reduce (راجِع تقليل) لا تتضمّن قيم init. ومن غير المحدّد حاليًا ما يحدث إذا كانت النافذة المقابلة لا تحتوي على قيم (#731).

  • result[result_index] = reduce([source_values], [init_value], [0], scatter) حيث:

    • source_values = [source[source_index] for source_index in source_indices].
    • selected_index(source_index) = operand_index إذا كان selected_values[source_index] يتضمّن العنصر operand من operand_index.
    • source_indices = [source_index for source_index in indices(source) if selected_index(source_index) = result_index].

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متعدّد أو متعدّد كميّ لكل موقد (C1-C4), (C6), (C8-C11)
(I2) source متعدّد أو متعدّد كميّ لكل موقد (C1)، (C2)
(I3) init_value متعدّد أبعاد صفري أو متعدّد كمي لكل موصّل (C3)
(I4) window_dimensions ثابت الموتّر الأحادي الأبعاد من النوع si64 (C2)، (C4)، (C5)
(I5) window_strides ثابت الموتّر الأحادي الأبعاد من النوع si64 (C2), (C6), (C7)
(I6) padding ثابت الموتر ثنائي الأبعاد من النوع si64 (C2), (C8)
(I7) select function (C9)
(I8) scatter function (C10)

المُخرَجات

الاسم النوع القيود
result متعدّد أو متعدّد كميّ لكل موقد (C11-C12)

القيود

  • (C1) element_type(operand) = element_type(source).
  • (C2) shape(source) = num_windows أين:
    • padded_operand_shape = padding[:, 0] + shape(operand) + padding[:, 1].
    • is_empty_window = padded_operand_shape = 0 || window_dimensions > padded_operand_shape.
    • num_windows = is_empty_window ? 0 : floor((padded_operand_shape - window_dimensions) / window_strides) + 1.
  • (C3) element_type(init_value) = element_type(operand).
  • (C4) size(window_dimensions) = rank(operand).
  • (C5) 0 < window_dimensions.
  • (C6) size(window_strides) = rank(operand).
  • (C7) 0 < window_strides.
  • (C8) shape(padding) = [rank(operand), 2].
  • (C9) select من النوع (tensor<E>, tensor<E>) -> tensor<i1> حيث E = element_type(operand).
  • (C10) scatter من النوع (tensor<E>, tensor<E>) -> tensor<E> حيث is_promotable(element_type(operand), E).
  • (C11) shape(operand) = shape(result).
  • (C12) element_type(result) = E.

أمثلة

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

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

إرسال

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

لإرسال inputs إلى قناة channel_id وإنشاء رمز result

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

مدخلات

التصنيف الاسم النوع القيود
(I1) inputs العدد المتباين للمتوترات أو الموترات الكمّية
(I2) token token
(I3) channel_id ثابت من النوع si64
(I4) channel_type تعداد DEVICE_TO_DEVICE وDEVICE_TO_HOST (C1)
(I5) is_host_transfer ثابت من النوع i1 (C1)

المُخرَجات

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

القيود

  • (C1) يتم تعريف channel_type على النحو التالي:
    • DEVICE_TO_HOST إذا is_host_transfer = true،
    • أو DEVICE_TO_DEVICE.

أمثلة

%result = "stablehlo.send"(%operand, %token) {
  channel_handle = #stablehlo.channel_handle<handle = 1, type = 2>,
  is_host_transfer = true
} : (tensor<2x2xi64>, !stablehlo.token) -> !stablehlo.token

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

shift_left

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) type(lhs) = type(rhs) = type(result).

أمثلة

// %lhs: [-1, 0, 1]
// %rhs: [1, 2, 3]
%result = "stablehlo.shift_left"(%lhs, %rhs): (tensor<3xi64>, tensor<3xi64>) -> tensor<3xi64>
// %result: [-2, 0, 8]

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

shift_right_arithmetic

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) type(lhs) = type(rhs) = type(result).

أمثلة

// %lhs: [-1, 0, 8]
// %rhs: [1, 2, 3]
%result = "stablehlo.shift_right_arithmetic"(%lhs, %rhs): (tensor<3xi64>, tensor<3xi64>) -> tensor<3xi64>
// %result: [-1, 0, 1]

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

shift_right_logical

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

تؤدي عملية إزاحة يمين منطقيًا في العناصر على مستوى العناصر على الموتر lhs بمقدار rhs من وحدات البت وينتج عن المخطَّط result.

مدخلات

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

المُخرَجات

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

القيود

  • (C1) type(lhs) = type(rhs) = type(result).

أمثلة

// %lhs: [-1, 0, 8]
// %rhs: [1, 2, 3]
%result = "stablehlo.shift_right_logical"(%lhs, %rhs): (tensor<3xi64>, tensor<3xi64>) -> tensor<3xi64>
// %result: [9223372036854775807, 0, 1]

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

علامة

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

تعرض علامة operand من حيث قيمة العناصر وتنتج عن مربّع result. بشكل أكثر رسمية، لكل عنصر x، يمكن التعبير عن دلالات الألفاظ باستخدام بناء جملة بايثون على النحو التالي:

def sign(x):
  if is_integer(x):
    if compare(x, 0, LT, SIGNED): return -1
    if compare(x, 0, EQ, SIGNED): return 0
    return 1
  elif is_float(x):
    if is_nan(x): return NaN
    if compare(x, -0.0, EQ, FLOAT): return -0.0
    if compare(x, +0.0, EQ, FLOAT): return +0.0
    if compare(x, 0.0, LT, FLOAT): return -1.0
    return 1.0
  elif is_complex(x):
    if is_nan(real(x)) or is_nan(imag(x)): return (NaN, NaN)
    if compare(x, (0.0, 0.0), EQ, FLOAT): return (0.0, 0.0)
    return divide(x, convert(abs(x), type(x)))

بالنسبة إلى الأنواع الكمية، ينفّذ dequantize_op_quantize(sign, operand, type(result)).

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(operand) = baseline_type(result).

أمثلة

// Logical values: +NaN, -1.0, -0.0, +0.0, 1.0
// operand: [0x7FFFFFFFFFFFFFFF, -1.0, -0.0, 0.0, 1.0]
%result = "stablehlo.sign"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// Logical values: +NaN, -1.0, -0.0, +0.0, 1.0
// %result: [0x7FFFFFFFFFFFFFFF, -1.0, -0.0, 0.0, 1.0]

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

جيب الزاوية

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

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(operand) = baseline_type(result).

أمثلة

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

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

slice

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

لاستخراج شريحة من operand باستخدام فهارس بداية محسوبة بشكلٍ ثابت وإنتاج متعدّد result تحتوي start_indices على فهارس البداية للشريحة لكل بُعد، وتحتوي limit_indices على فهارس النهاية (حصرية) للشريحة لكل بُعد، وتحتوي strides على الخطوات لكل بُعد.

بشكل أكثر رسمية، result[result_index] = operand[operand_index] حيث operand_index = start_indices + result_index * strides.

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متعدّد أو متعدّد كميّ لكل موقد (C1-C3), (C5)
(I2) start_indices ثابت الموتّر الأحادي الأبعاد من النوع si64 (C2), (C3), (C5)
(I3) limit_indices ثابت الموتّر الأحادي الأبعاد من النوع si64 (C2), (C3), (C5)
(I4) strides ثابت الموتّر الأحادي الأبعاد من النوع si64 (C2), (C4)

المُخرَجات

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

القيود

  • (C1) element_type(operand) = element_type(result).
  • (C2) size(start_indices) = size(limit_indices) = size(strides) = rank(operand).
  • (C3) 0 <= start_indices <= limit_indices <= shape(operand).
  • (C4) 0 < strides.
  • (C5) shape(result) = ceil((limit_indices - start_indices) / strides).

أمثلة

// %operand: [
//            [0, 0, 0, 0],
//            [0, 0, 1, 1],
//            [0, 0, 1, 1]
//           ]
%result = "stablehlo.slice"(%operand) {
  start_indices = dense<[1, 2]> : tensor<2xi64>,
  limit_indices = dense<[3, 4]> : tensor<2xi64>,
  strides = dense<1> : tensor<2xi64>
} : (tensor<3x4xi64>) -> tensor<2x2xi64>
// % result: [
//            [1, 1],
//            [1, 1]
//           ]

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

ترتيب

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

لترتيب شرائح inputs ذات البُعد الواحد على طول البُعد dimension معًا، وفقًا لـ comparator وينتج عنها results.

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

إذا كانت القيمة is_stable صحيحة، يكون الترتيب مستقرًا، أي يتم الحفاظ على الترتيب النسبي للعناصر التي تُعتبر تساويًا في المقارِن. في حال توفّر إدخال واحد، سيتم اعتبار العنصرَين e1 وe2 متساويَين في قيمة المقارِن فقط في حال استخدام comparator(e1, e2) = comparator(e2, e1) = false. انظر إلى الصياغة أدناه لمعرفة كيفية تعميم هذا على المدخلات المتعددة.

بشكل أكثر رسمية، لجميع result_index في index_space(results[0]):

  • adjusted_dimension = dimension >= 0 ? dimension : rank(inputs[0]) + dimension.
  • result_slice = [ri0, ..., :, ..., riR-1] حيث تكون riN عناصر فردية في result_index و: في adjusted_dimension.
  • inputs_together = (inputs[0]..., ..., inputs[N-1]...).
  • results_together[result_slice] = sort(inputs_together[result_slice], comparator_together).
  • حيث يرتب sort شريحة أحادية البعد بترتيب غير تنازلي متوقعًا أن يعرض comparator_together true إذا كانت الوسيطة الموجودة على الجانب الأيسر أقل من الوسيطة الثانية اليمنى.
  • def comparator_together(lhs_together, rhs_together):
      args = []
      for (lhs_el, rhs_el) in zip(lhs_together, rhs_together):
        args.append(lhs_el)
        args.append(rhs_el)
      return comparator(*args)
    
  • (results[0]..., ..., results[N-1]...) = results_together.

مدخلات

التصنيف الاسم النوع القيود
(I1) inputs العدد المتباين للمتوترات أو الموترات الكمّية لكل مفرد (C1-C5)
(I2) dimension ثابت من النوع si64 (C4)
(I3) is_stable ثابت من النوع i1
(I4) comparator function (C5)

المُخرَجات

الاسم النوع القيود
results العدد المتباين للمتوترات أو الموترات الكمّية لكل مفرد (C2), (C3)

القيود

  • (C1) 0 < size(inputs).
  • (C2) type(inputs...) = type(results...).
  • (C3) same(shape(inputs...) + shape(results...)).
  • (C4) -R <= dimension < R، حيث تم R = rank(inputs[0]).
  • (C5) comparator من النوع (tensor<E1>, tensor<E1>, ..., tensor<EN-1>, tensor<EN-1>) -> tensor<i1>، حيث Ei = element_type(inputs[i]).

أمثلة

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

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

sqrt

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

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(operand) = baseline_type(result).

أمثلة

// %operand: [[0.0, 1.0], [4.0, 9.0]]
%result = "stablehlo.sqrt"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[0.0, 1.0], [2.0, 3.0]]

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

طرح

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

لتنفيذ عملية طرح عناصر متكافئة lhs وrhs بشكل حاسم العناصر وينتج عن result متحد. بناءً على نوع العنصر، يتم تنفيذ ما يلي:

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(lhs) = baseline_type(rhs) = baseline_type(result).

أمثلة

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

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

تانه

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

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

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) baseline_type(operand) = baseline_type(result).

أمثلة

// %operand: [-1.0, 0.0, 1.0]
%result = "stablehlo.tanh"(%operand) : (tensor<3xf32>) -> tensor<3xf32>
// %result: [-0.76159416, 0.0, 0.76159416]

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

تبديل الموضع

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

تعديل أبعاد المتوتر operand باستخدام permutation وينتج عنه result متعدّد. بشكل أكثر رسمية، result[result_index] = operand[operand_index] حيث result_index[d] = operand_index[permutation[d]].

مدخلات

التصنيف الاسم النوع القيود
(I1) operand متعدّد أو متدرج كمي (C1-C4)
(I2) permutation ثابت الموتّر الأحادي الأبعاد من النوع si64 (C2-C4)

المُخرَجات

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

القيود

  • (C1) يتم تقديم element_type(result) من خلال:
    • element_type(operand)، إذا كانت !is_per_axis_quantized(operand).
    • element_type(operand) إلا أنّ quantization_dimension(operand) وquantization_dimension(result) قد تختلفان، بخلاف ذلك.
  • (C2) permutation هو تبديل range(rank(operand)).
  • (C3) shape(result) = dim(operand, permutation...).
  • (C4) إذا كانت is_per_axis_quantized(result)، عندها quantization_dimension(operand) = permutation(quantization_dimension(result)).

أمثلة

// %operand: [
//            [[1,2], [3,4], [5,6]],
//            [[7,8], [9,10], [11,12]]
//           ]
%result = "stablehlo.transpose"(%operand) {
  permutation = dense<[2, 1, 0]> : tensor<3xi64>
} : (tensor<2x3x2xi32>) -> tensor<2x3x2xi32>
// %result: [
//           [[1,7], [3,9], [5,11]],
//           [[2,8], [4,10], [6,12]]
//          ]

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

triangular_solve

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

تعمل على حل مجموعات أنظمة المعادلات الخطية ذات المصفوفات المثلثية السفلية أو العلوية.

بشكل أكثر رسمية، بالنسبة إلى a وb، يكون result[i0, ..., iR-3, :, :] هو الحل op(a[i0, ..., iR-3, :, :]) * x = b[i0, ..., iR-3, :, :] عندما تكون left_side true أو x * op(a[i0, ..., iR-3, :, :]) = b[i0, ..., iR-3, :, :] عندما تكون left_side هي false، وهو حل للمتغير x حيث يتم تحديد op(a) بواسطة transpose_a، والذي يمكن أن يكون واحدًا مما يلي:

  • NO_TRANSPOSE: تنفيذ العملية باستخدام a كما هي
  • TRANSPOSE: تنفيذ عملية على تبديل موضع a
  • ADJOINT: تنفيذ عملية على تبديل موضع a

تتم قراءة بيانات الإدخال فقط من المثلث السفلي لـ a، إذا كان lower هو true أو المثلث العلوي لـ a، وإلا. يتم إرجاع بيانات الناتج في نفس المثلث؛ القيم في المثلث الآخر يتم تحديدها بالتنفيذ.

إذا كانت قيمة السمة unit_diagonal صحيحة، يمكن أن تفترض عملية التنفيذ أنّ العناصر القطرية لـ a تساوي 1، وإلا يكون السلوك غير محدّد.

بالنسبة إلى الأنواع الكمية، ينفّذ dequantize_op_quantize(lambda x, y: triangular_solve(x, y, left_side, lower, unit_diagonal, transpose_a), a, b, type(result)).

مدخلات

التصنيف الاسم النوع القيود
(I1) a متعدّد من نوع النقطة العائمة أو المعقد أو متعدّد كميّ لكل موقد (C1-C3)
(I2) b متعدّد من نوع النقطة العائمة أو المعقد أو متعدّد كميّ لكل موقد (C1-C4)
(I3) left_side ثابت من النوع i1 (C3)
(I4) lower ثابت من النوع i1
(I5) unit_diagonal ثابت من النوع i1
(I6) transpose_a تعداد NO_TRANSPOSE وTRANSPOSE وADJOINT

المُخرَجات

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

القيود

  • (C1) baseline_element_type(a) = baseline_element_type(b).
  • (C2) 2 <= rank(a) = rank(b) = R.
  • (C3) يتم تعريف العلاقة بين shape(a) وshape(b) على النحو التالي:
    • shape(a)[:-3] = shape(b)[:-3].
    • dim(a, -2) = dim(a, -1) = dim(b, left_side ? -2 : -1).
  • (C4) baseline_type(b) = baseline_type(result).

أمثلة

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

tuple

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

لعرض صف result من القيم val.

مدخلات

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

المُخرَجات

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

القيود

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

أمثلة

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

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

uniform_dequantize

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

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

بشكل أكثر رسمية، result = dequantize(operand).

مدخلات

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

المُخرَجات

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

القيود

  • (C1) shape(operand) = shape(result).
  • (C2) element_type(result) = expressed_type(operand).

أمثلة

// %operand: [10, 10]
%result = "stablehlo.uniform_dequantize"(%operand) : (tensor<2x!quant.uniform<i8:f32:0, {0.1:-30,0.5:-20}>>) -> tensor<2xf32>
// %result: [4.0, 15.0]

uniform_quantize

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

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

بشكل أكثر رسمية،

  • في حال كان is_float(operand):
    • result = quantize(operand, type(result)).
  • في حال كان is_quantized(operand):
    • float_result = dequantize(operand).
    • result = quantize(float_result, type(result)).

مدخلات

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

المُخرَجات

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

القيود

  • (C1) shape(operand) = shape(result).
  • (C2) expressed_type(result) = is_float(operand) ? element_type(operand) : expressed_type(operand).

أمثلة

// %operand: [4.0, 15.0]
%result = "stablehlo.uniform_quantize"(%operand) : (tensor<2xf32>) -> tensor<2x!quant.uniform<i8:f32:0, {0.1:-30,0.5:-20}>>
// %result: [10, 10]

// %operand: [10, 10]
%result = "stablehlo.uniform_quantize"(%operand) : (tensor<2x!quant.uniform<i8:f32:0, {0.1:-30,0.5:-20}>>) -> tensor<2x!quant.uniform<i8:f32:0, {0.1:-20,0.2:-30}>>
// %result: [20, 45]

فيما

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

لعرض الناتج من تنفيذ دالة body 0 أو أكثر بينما تنتج الدالة cond true. بشكل أكثر رسمية، يمكن التعبير عن الدلالات باستخدام بناء جملة بايثون على النحو التالي:

internal_state = operand
while cond(*internal_state):
  internal_state = body(*internal_state)
results = internal_state

يتم تحديد سلوك التكرار اللانهائي لاحقًا (#383).

مدخلات

التصنيف الاسم النوع القيود
(I1) operand العدد المتباين من الموتّرات، أو الموتدّات الكمية أو الرموز المميّزة (C1-C3)
(I2) cond function (C1)
(I3) body function (C2)

المُخرَجات

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

القيود

  • (C1) cond من النوع (T0, ..., TN-1) -> tensor<i1>، حيث Ti = type(operand[i]).
  • (C2) body من النوع (T0, ..., TN-1) -> (T0, ..., TN-1)، حيث Ti = type(operand[i]).
  • (C3) type(results...) = type(operand...).

أمثلة

// %init_i: 1
// %init_sum: 0
// %one: 1
// %ten: 10
%results0, %results1 = "stablehlo.while"(%init_i, %init_sum) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %cond = "stablehlo.compare"(%arg0, %ten) {
      comparison_direction = #stablehlo<comparison_direction LT>
    } : (tensor<i64>, tensor<i64>) -> tensor<i1>
    stablehlo.return %cond : tensor<i1>
  }, {
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %new_sum = stablehlo.add %arg1, %one : tensor<i64>
    %new_i = stablehlo.add %arg0, %one : tensor<i64>
    stablehlo.return %new_i, %new_sum : tensor<i64>, tensor<i64>
}) : (tensor<i64>, tensor<i64>) -> (tensor<i64>, tensor<i64>)
// %results0: 10
// %results1: 10

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

سور

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

تؤدي هذه الدالة XOR على مستوى العناصر في معاملين متّجهين lhs وrhs وينتج عنها متعدّد result. بناءً على نوع العنصر، يتم تنفيذ ما يلي:

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

مدخلات

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

المُخرَجات

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

القيود

  • (C1) type(lhs) = type(rhs) = type(result).

أمثلة

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

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

التنفيذ

التنفيذ التسلسلي

يتم تنفيذ برنامج StableHLO من خلال توفير قيم الإدخال لدالة main وحوسبة قيم المخرجات. يتم حساب قيم مخرجات الدالة من خلال تنفيذ الرسم البياني للعمليات الجذر في عملية return المقابلة.

يتم تحديد ترتيب التنفيذ طالما أنه متوافق مع تدفق البيانات، أي إذا تم تنفيذ العمليات قبل استخداماتها. في StableHLO، تستهلك جميع عمليات الأثر الجانبي رمزًا مميزًا واحدًا وتنتج رمزًا مميزًا واحدًا (يمكن مضاعفة الرموز المميزة المتعددة في رمز مميز واحد عبر after_all)، بحيث يتوافق ترتيب تنفيذ الآثار الجانبية أيضًا مع تدفق البيانات. ترتيبات التنفيذ المحتملة لنموذج البرنامج أعلاه هي %0%1%2%3%4return أو %3%0%1%2%4return.

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

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

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

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

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

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

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

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

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

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

يمكن لعمليات StableHLO التواصل مع بعضها البعض من خلال قنواتStableHLO. يتم تمثيل القناة بمعرّف موجب من النوع si64. من خلال عمليات مختلفة، من الممكن إرسال قيم إلى القنوات وتلقّيها من القنوات.

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

اتصال البث

يمكن لكل عملية من عمليات StableHLO الوصول إلى واجهتي بث:

  • إضافة خلاصة يمكن القراءة منها:
  • Outfeed الذي يمكن الكتابة إليه.

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

يتم تحديد مزيد من إضفاء الطابع الرسمي، مثل كيفية تأثير اتصال البث في ترتيب التنفيذ ونوع المزامنة التي تتم من خلال ذلك، (رقم 484).

العمليات الجماعية

تتوفر ست عمليات جماعية في StableHLO وهي: all_gather وall_reduce وall_to_all وcollective_broadcast وcollective_permute وreduce_scatter. تؤدي جميع العمليات هذه إلى تقسيم العمليات في شبكة عملية StableHLO إلى مجموعات عمليات StableHLO وتنفيذ عملية حسابية مشتركة ضمن كل مجموعة عمليات بشكل مستقل عن المجموعات الأخرى.

ضمن كل مجموعة عمليات، قد تمثل العمليات الجماعية حاجزًا للمزامنة. يتم تحديد موعد إضافي لإجراء مزيد من التفاصيل، مثل توضيح وقت حدوث هذه المزامنة بالضبط، وكيفية وصول العمليات إلى هذا الحاجز، وما يحدث إذا لم يحدث ذلك، بعد ذلك. (رقم 484).

إذا كانت مجموعة العمليات تتضمّن اتصالًا من عدة أقسام، أي أنّ هناك عمليات مختلفة ضمن مجموعة العمليات التي تختلف أرقام تعريف الأقسام الخاصة بها، يحتاج تنفيذ العملية الجماعية إلى قناة، ويجب أن توفّر العملية الجماعية سمة channel_id إيجابية من النوع si64. لا يحتاج التواصل عبر التكرار إلى قنوات.

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

cross_replica

تحدث فقط الاتصالات المتكررة داخل كل مجموعة عملية. تأخذ هذه الاستراتيجية replica_groups - قائمة من قوائم المعرفات المتماثلة - وتحسب منتجًا الديكارتي لـ replica_groups بواسطة partition_ids. يجب أن يحتوي replica_groups على عناصر فريدة وأن يغطي جميع replica_ids. بشكل أكثر رسمية، باستخدام بناء جملة بايثون:

def cross_replica(replica_groups: List[List[ReplicaId]]) -> List[List[ProcessId]]:
  for replica_group in replica_groups:
    for partition_id in partition_ids:
      process_group = []
      for replica_id in replica_group:
        process_group.append((replica_id, partition_id))
      yield process_group

على سبيل المثال، بالنسبة إلى replica_groups = [[0, 1], [2, 3]] وnum_partitions = 2، سينتج عن cross_replica [[(0, 0), (1, 0)], [(0, 1), (1, 1)], [(2, 0), (3, 0)], [(2, 1), (3, 1)]].

cross_partition

تحدث فقط الاتصالات بين الأقسام داخل كل مجموعة عملية. تأخذ هذه الاستراتيجية partition_groups، وهي قائمة من قوائم أرقام تعريف الأقسام، وتحتسب ناتج الديكارتي لـ partition_groups حسب replica_ids. يجب أن يحتوي partition_groups على عناصر فريدة وأن يغطي جميع partition_ids. بشكل أكثر رسمية، باستخدام بناء جملة بايثون:

def cross_partition(partition_groups: List[List[PartitionId]]) -> List[List[ProcessId]]:
  for partition_group in partition_groups:
    for replica_id in replica_ids:
      process_group = []
      for partition_id in partition_group:
        process_group.append((replica_id, partition_id))
      yield process_group

على سبيل المثال، بالنسبة إلى partition_groups = [[0, 1]] وnum_replicas = 4، سينتج عن cross_partition [[(0, 0), (0, 1)], [(1, 0), (1, 1)], [(2, 0), (2, 1)], [(3, 0), (3, 1)]].

cross_replica_and_partition

قد تحدث كل من الاتصالات عبر النسخ المتماثل والتقسيم بين الأقسام داخل كل مجموعة عمليات. تستخدم هذه الاستراتيجية replica_groups، وهي قائمة بمعرّفات النُسخ المتماثلة، وتحسب المنتجات الديكارتية لكل replica_group حسب partition_ids. يجب أن يحتوي replica_groups على عناصر فريدة وأن يغطي جميع replica_ids. بشكل أكثر رسمية، باستخدام بناء جملة بايثون:

def cross_replica_and_partition(replica_groups: List[List[ReplicaId]]) -> List[List[ProcessId]]:
  for replica_group in replica_groups:
    process_group = []
    for partition_id in partition_ids:
      for replica_id in replica_group:
        process_group.append((replica_id, partition_id))
    yield process_group

على سبيل المثال، بالنسبة إلى replica_groups = [[0, 1], [2, 3]] وnum_partitions = 2، سينتج عن cross_replica_and_partition [[(0, 0), (1, 0), (0, 1), (1, 1)], [(2, 0), (3, 0), (2, 1), (3, 1)]].

flattened_ids

تستخدم هذه الاستراتيجية flattened_id_groups، وهي قائمة من قوائم أرقام تعريف العمليات "المنظّمة" على شكل replica_id * num_partitions + partition_id، وتحولها إلى أرقام تعريف عمليات. يجب أن يحتوي flattened_id_groups على عناصر فريدة وأن يغطي process_ids بالكامل. بشكل أكثر رسمية، باستخدام بناء جملة بايثون:

def flattened_ids(flattened_id_groups: List[List[ui32]]) -> List[List[ProcessId]]:
  for flattened_id_group in flattened_id_groups:
    process_group = []
    for flattened_id in flattened_id_group:
      replica_id = flattened_id // num_partitions
      partition_id = flattened_id % num_partitions
      process_group.append((replica_id, partition_id))
    yield process_group

على سبيل المثال، لـ flattened_id_groups = [[0, 1, 2, 3], [4, 5, 6, 7]] وnum_replicas = 4 وnum_partitions = 2، ستعرض flattened_ids القيمة [[(0, 0), (0, 1), (1, 0), (1, 1)], [(2, 0), (2, 1), (3, 0), (3, 1)]].

الدقة

في الوقت الحالي، لا يوفر StableHLO ضمانات حول الدقة الرقمية، ولكن هذا قد يتغير في المستقبل (#1156).

الأخطاء

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

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

الترميز

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

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

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

الصيغ

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

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

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

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

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

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

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

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

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

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

الأسماء

في المعادلات، يتضمن النطاق المعجمي: 1) الدوال العمومية، 2) تعريفات الأعضاء،

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

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

القيم

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

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

الأسماء في "الدلالات" في "القيود"
الدوال العامة Function Function
الإدخالات المستمرة Value Value
الإدخالات غير الثابتة Value Placeholder
المُخرَجات Value Placeholder
التعريفات المحلية يعتمد على التعريف يعتمد على التعريف

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

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

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

الدوال

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

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

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

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

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

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

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

  if is_same_type == False:
    return False

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

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

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

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

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

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

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

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

إنشاء القيم

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

الدالة على القيم

  • تتوفر جميع عوامل تشغيل بايثون ودواله. على سبيل المثال، يتوفر كل من الترميزات الاشتراك والتقسيم من بايثون للفهرسة إلى معاملين أو موترات كَمية وصفوف.

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

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

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

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

  return convert(x, destination_type)

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

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

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

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

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

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

  • يتم تحديد split(x: Value, num_results: Value, axis: Value) -> Value على الموترات وتعرض num_results شرائح من x على طول المحور axis. إذا لم يكن x متعدّدًا أو dim(x, axis) % num_results != 0، سيتم عرض None.

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

  • axes(x: Value | Placeholder | Type) -> Value هو اختصار لـ range(rank(x)).

  • dim(x: Value | Placeholder | Type, axis: Value) -> Value هو اختصار لـ shape(x)[axis].

  • dims(x: Value | Placeholder | Type, axes: List) -> List هو اختصار لـ list(map(lambda axis: dim(x, axis), axes)).

  • تُحدَّد index_space(x: Value | Placeholder | Type) -> Value على الموترات وتعرض مؤشرات size(x) لـ TensorType المقابل مرتَّبة بترتيب تصاعدي، أي [0, ..., 0]، [0, ..., 1]، ...،shape(x) - 1. إذا لم يكن x من نوع متعدّد المتغيّرات أو نوع متعدّد كميّ أو قيمة أو عنصرًا نائبًا لأحد هذه الأنواع، سيتم عرض None.

  • rank(x: Value | Placeholder | Type) -> Value هو اختصار لـ size(shape(x)).

  • يتم تحديد shape(x: Value | Placeholder | Type) -> Value في قسم "الدوالّ على الأنواع" من خلال member_name.

  • size(x: Value | Placeholder | Type) -> Value هو اختصار لـ reduce(lambda x, y: x * y, shape(x)).

عمليات تحديد الكمية

  • def baseline_element_type(x: Value | Placeholder | Type) -> Type هو اختصار لـ element_type(baseline_type(x)).

  • يتمّ تعريف baseline_type على أنواع المتوتر وأنواع المتسلسل الكمية وتحوّلها إلى "خط أساسي"، بمعنى نوع له الشكل نفسه ولكن مع إعادة ضبط معلمات الكمية لنوع العنصر إلى القيم التلقائية. ويُستخدم هذا كحيلة سهلة للمقارنة بين أنواع المتوتر وأنواع المتحدِّر الكمّي بشكل منتظم، وهو أمر مطلوب في كثير من الأحيان. بالنسبة إلى الأنواع الكمية، يتيح ذلك إمكانية مقارنة الأنواع التي تجتاز مَعلمات القياس، أي أنّ shape وstorage_type وexpressed_type وstorage_min وstorage_max وquantization_dimension (للنوع المحدّد كميًا لكل محور) يجب أن تتطابق جميعها، ولكن قد تختلف scales وzero points.

def baseline_type(x: Value | Placeholder | Type) -> Type:
  if type(x) == TensorType:
    return x
  if type(x) == QuantizedTensorType:
    element_type = quantized_tensor_element_type(x)
    baseline_element_type = QuantizedTensorElementType(
      storage_type = storage_type(element_type),
      storage_min = storage_min(element_type),
      storage_max = storage_max(element_type),
      expressed_type = expressed_type(element_type),
      quantization_dimension = quantization_dimension(element_type),
      scales = [constant(1.0, expressed_type(element_type))] * dim(x, quantization_dimension(element_type)),
      zero_points = [constant(0, storage_type(element_type))] * dim(x, quantization_dimension(element_type)))
    return QuantizedTensorType(shape(x), baseline_element_type)
  if type(x) is not Type:
    return baseline_element_type(type(x))
  • تُحدَّد السمة dequantize على أنواع الموجات الكمية وتحولها إلى أنواع متسلسلة عائمة. ويحدث ذلك من خلال تحويل العناصر الكمية التي تمثل قيم الأعداد الصحيحة لنوع التخزين إلى قيم النقطة العائمة المقابلة للنوع الذي تم التعبير عنه باستخدام النقطة الصفرية والمقياس المرتبط بنوع العنصر المحدد.
def compute_zero_points(quantized_type, result_type):
  if is_per_tensor_quantized(quantized_type):
    return broadcast_in_dim(constant(zero_point(quantized_type), storage_type(quantized_type)), [], result_type)
  if is_per_axis_quantized(quantized_type):
    for i in index_space(result_type):
      d = quantization_dimension(quantized_type)
      zero_points[i] = zero_points(quantized_type)[i[d]]
    return zero_points

def compute_scales(quantized_type, result_type):
  if is_per_tensor_quantized(quantized_type):
    return broadcast_in_dim(constant(scale(quantized_type), expressed_type(quantized_type)), [],
            type(result_type))
  if is_per_axis_quantized(quantized_type):
    for i in index_space(result_type):
      d = quantization_dimension(quantized_type)
      scales[i] = scales(quantized_type)[i[d]]
    return scales

def dequantize(x: Value) -> Value:
  assert is_quantized(x)
  x_storage = bitcast_convert(x, storage_type(x))
  x_storage_sub = x_storage - compute_zero_points(type(x), type(x_storage))
  x_expressed_sub = convert(x_storage_sub, expressed_type(x))
  return x_expressed_sub * compute_scales(type(x), type(x_expressed_sub))
  • يتمّ تعريف quantize على أنواع متحد النقطة العائمة وتحوّلها إلى أنواع متسلسلة كمية. يحدث ذلك من خلال تحويل قيم النقطة العائمة للنوع الذي تم التعبير عنه إلى قيم أعداد صحيحة مقابلة لنوع التخزين باستخدام النقطة الصفرية والمقياس المرتبط بنوع العنصر المحدد.
def quantize(x: Value, type: Type) -> Value:
  assert is_float(x) and is_quantized(type)
  x_expressed_rounded = round_nearest_even(x / compute_scales(type, type(x)))
  x_storage_rounded = convert(x_expressed_rounded, storage_type(type))
  x_storage_add = x_storage_rounded + compute_zero_points(type, type(x_storage_rounded))
  x_storage = clamp(storage_min(type), x_storage_add, storage_max(type))
  return bitcast_convert(x_storage, type)
  • تُستخدم الدالة dequantize_op_quantize لتحديد العمليات الحسابية للعناصر على المصفوفات الكمّية. فهي تفصِل العناصر الكمية، أي تحويل العناصر الكمية إلى أنواع معبرة عنها، ثم تُجري عملية، وبعد ذلك تحدد الكميات، أي أنها تعيد النتائج إلى أنواع التخزين. في الوقت الحالي، تعمل هذه الدالة فقط مع تحديد الكم لكل متسلسل. جارٍ العمل على تحديد الكمية لكل محور (#1574).
def dequantize_op_quantize(op, *inputs_and_output_type):
  inputs = inputs_and_output_type[:-1]
  output_type = inputs_and_output_type[-1]

  float_inputs = map(dequantize, inputs)
  float_result = op(*float_inputs)
  return quantize(float_result, output_type)

def dequantize_batch_norm_grad_or_training_quantize(op, *inputs_and_output_types):
  inputs = inputs_and_output_type[:-3]
  float_inputs = map(dequantize, inputs)
  float_results = op(*float_inputs)
  return map(quantize, float_results, inputs_and_output_type[-3:])

def dequantize_compare(lhs, rhs, comparison_direction):
  float_lhs = dequantize(lhs)
  float_rhs = dequantize(rhs)
  return compare(float_lhs, float_rhs, comparison_direction, FLOAT)

def dequantize_select_quantize(pred, on_true, on_false, output_type):
  float_on_true = dequantize(on_true)
  float_on_false = dequantize(on_false)
  float_result = select(pred, float_on_true, float_on_false)
  return quantize(float_result, output_type)

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

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

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

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

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