StableHLO Özelliği

StableHLO, makine öğrenimi (ML) modellerindeki üst düzey işlemler (HLO) için bir işlem grubudur. StableHLO, farklı ML çerçeveleri ve ML derleyicileri arasında bir taşınabilirlik katmanı olarak çalışır: StableHLO programları üreten ML çerçeveleri, StableHLO programlarını kullanan ML derleyicileriyle uyumludur.

Amacımız, çeşitli makine öğrenimi çerçeveleri (TensorFlow, JAX ve PyTorch gibi) ile makine öğrenimi derleyicileri (XLA ve IREE gibi) arasında daha fazla birlikte çalışabilirlik sağlayarak makine öğrenimi geliştirme sürecini basitleştirmek ve hızlandırmak. Bu amaçla, bu belgede StableHLO programlama dili için bir spesifikasyon sunulmaktadır.

Bu spesifikasyon üç ana bölümden oluşur. İlk olarak Programlar bölümünde, kendileri StableHLO işlemlerinden oluşan StableHLO işlevlerinden oluşan StableHLO programlarının yapısı açıklanmaktadır. Bu yapıda İşlemler bölümü, ayrı işlemlerin anlamlarını belirtir. Yürütme bölümü, bir programda birlikte yürütülen tüm bu işlemler için anlam sağlar. Son olarak Notasyon bölümünde, spesifikasyon boyunca kullanılan notasyon ele alınmaktadır.

StableHLO'nun önceki bir sürümüne ait spesifikasyonu görüntülemek için ilgili etiketlenmiş sürümde deposu açın. Örneğin, StableHLO v0.19.0 Spesifikasyonu. StableHLO'nun her küçük sürüm yükseltmesinde gerçekleşen değişiklikleri görüntülemek için VhloDialect.td'deki sürüm günlüğüne bakın.

Programlar

Program ::= {Func}

StableHLO programları, rastgele sayıda StableHLO işlevinden oluşur. Aşağıda, 3 giriş (%image, %weights ve %bias) ve 1 çıkışa sahip bir @main işlevi içeren örnek bir program verilmiştir. İşlevin gövdesinde 6 işlem vardır.

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

İşlevler

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

StableHLO işlevleri (adlandırılmış işlevler olarak da bilinir), bir tanımlayıcı, giriş/çıkış ve bir gövdeye sahiptir. Gelecekte, HLO ile daha iyi uyumluluk elde etmek için işlevler için ek meta veriler sunmayı planlıyoruz (#425, #626, #740, #744).

Tanımlayıcılar

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

StableHLO tanımlayıcıları, birçok programlama dilindeki tanımlayıcılara benzer, ancak iki özelliği vardır: 1) tüm tanımlayıcıların farklı tanımlayıcı türlerini ayırt eden eş değerleri vardır, 2) değer tanımlayıcıları StableHLO programlarının oluşturulmasını basitleştirmek için tamamen sayısal olabilir.

Türler

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

StableHLO türleri, StableHLO değerlerini temsil eden değer türleri (birinci sınıf türler olarak da bilinir) ve diğer program öğelerini tanımlayan değer olmayan türler olarak kategorize edilir. StableHLO türleri, birçok programlama dilindeki türlere benzer. Temel özelliği, bazı sıra dışı sonuçlara yol açan StableHLO'nun alana özgü yapısıdır (ör. skaler türler değer türleri değildir).

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

Tenör türleri, tenörleri (yani çok boyutlu dizileri) temsil eder. Bu öğelerin bir şekli ve öğe türü vardır. Şekle, 0 ile R-1 arasında numaralandırılan ve ilgili boyutların (eksenler olarak da bilinir) artan sırasına göre negatif olmayan veya bilinmeyen boyut boyutlarını temsil eder. Boyut sayısı R'e sıralama adı verilir. Örneğin tensor<2x3xf32>, 2x3 şekline ve f32 öğe türüne sahip bir tensör türüdür. 0. boyut ve 1. boyut olmak üzere iki boyutu (veya başka bir deyişle iki ekseni) vardır. Bu boyutların boyutları 2 ve 3'tür. Sıralaması 2.

Şekiller kısmen veya tamamen bilinmeyen (dinamik) olabilir. Örneğin, tensor<?x2xf64> kısmen bilinmiyor, tensor<?x?xf64> tamamen bilinmiyor. Dinamik boyut boyutları, ? kullanılarak gösterilir. Şekillerin sıralaması geri alınamaz.

Gelecekte, tensör türlerini boyut boyutlarının ve öğe türlerinin ötesine genişleterek, örneğin düzenler (#629) ve seyreklik (#1078) eklemeyi planlıyoruz.

QuantizedTensorType ::= 'tensor' '<' Shape QuantizedTensorElementType '>'
QuantizedTensorElementType ::= '!quant.uniform' '<'
                  QuantizationStorageType
                  ['<' QuantizationStorageMin ':' QuantizationStorageMax '>']
                  ':' QuantizationExpressedType
                  [':' QuantizationDimension]
                  ',' QuantizationParameters '>'
QuantizationStorageType ::= IntegerType
QuantizationStorageMin ::= IntegerLiteral
QuantizationStorageMax ::= IntegerLiteral
QuantizationExpressedType ::= FloatType
QuantizationDimension ::= IntegerLiteral
QuantizationParameters ::= QuantizationParameter
                         | '{' QuantizationParameter {',' QuantizationParameter} '}'
QuantizationParameter ::= QuantizationScale [':' QuantizationZeroPoint]
QuantizationScale ::= FloatLiteral
QuantizationZeroPoint ::= IntegerLiteral
Ad Tür Sınırlamalar
storage_type tam sayı türü (C1-C3), (C8)
storage_min tam sayı sabiti (C1), (C3), (C7)
storage_max tam sayı sabiti (C2), (C3), (C7)
expressed_type kayan nokta türü (C4)
quantization_dimension isteğe bağlı tam sayı sabiti (C10-C12)
scales kayan nokta sabitlerinin değişken sayısı (C4-C6), (C9), (C10), (C13)
zero_points tam sayı sabitlerinin değişken sayısı (C7-C9)

Kantitatif öğe türleri, storage_min ile storage_max arasındaki (dahil) aralıkta bir depolama türü tam sayı değerlerini temsil eder. Bu değerler, ifade edilen tür kayan nokta değerlerine karşılık gelir. Belirli bir tam sayı değeri i için karşılık gelen kayan nokta değeri (f), f = (i - zero_point) * scale olarak hesaplanabilir. Burada scale ve zero_point değerine nicelleştirme parametreleri denir. storage_min ve storage_max dil bilgisinde isteğe bağlıdır ancak sırasıyla min_value(storage_type) ve max_value(storage_type) varsayılan değerlerine sahiptir. Ölçülmüş öğe türleri aşağıdaki kısıtlamalara sahiptir:

  • (C1) type(storage_min) = storage_type.
  • (C2) type(storage_max) = storage_type.
  • (C3) min_value(storage_type) <= storage_min < storage_max <= max_value(storage_type).
  • (C4) type(scales...) = expressed_type.
  • (C5) 0 < scales.
  • (C6) is_finite(scales...).
  • (C7) storage_min <= zero_points <= storage_max.
  • (C8) type(zero_points...) = storage_type
  • (C9) size(scales) = size(zero_points).
  • (C10) is_empty(quantization_dimension) ise size(scales) = 1.
  • (C11) 0 <= quantization_dimension.

Şu anda QuantizationScale kayan noktalı bir sabit olsa da çarpanlar ve kaydırmalarla temsil edilen tam sayıya dayalı ölçeklere yönelik güçlü bir ilgi var. Bu özelliği yakın gelecekte araştırmayı planlıyoruz (#1404).

Tür, değerler ve kesikli bir tensör türünde yalnızca bir veya birden fazla sıfır noktası bulunup bulunamayacağı da dahil olmak üzere QuantizationZeroPoint'ün semantiği hakkında devam eden bir tartışma var. Bu tartışmanın sonuçlarına göre, sıfır noktayla ilgili spesifikasyon gelecekte değişebilir (#1405).

Devam eden bir diğer tartışma, bu değerlere ve kesikli tenzorların değerlerine herhangi bir kısıtlama uygulanıp uygulanmayacağını belirlemek için QuantizationStorageMin ve QuantizationStorageMax'nin semantiğiyle ilgilidir (#1406).

Son olarak, bilinmeyen boyut boyutlarını (#1407) temsil etmeyi planladığımız gibi, bilinmeyen ölçekleri ve sıfır noktaları temsil etmeyi de planlıyoruz.

Kantitatifleştirilmiş tenör türleri, kantitatifleştirilmiş öğelere sahip tenörleri temsil eder. Bu tensörler, öğelerinin normal öğe türleri yerine kesikli öğe türlerine sahip olması dışında normal tensörlerle tamamen aynıdır.

Kesirli tensörlerde kesirli sayım tensör başına olabilir. Bu durumda, tensörün tamamı için bir scale ve zero_point bulunur. Kesirli sayım eksen başına da olabilir. Bu durumda, belirli bir boyut quantization_dimension'nin dilimi başına bir çift olmak üzere birden fazla scales ve zero_points bulunur. Daha resmi bir ifadeyle, eksen başına kesme işlemi uygulanmış bir t tensörde quantization_dimension'nin dim(t, quantization_dimension) dilimi vardır: t[:, ..., 0, ..., :], t[:, ..., 1, ..., :] vb. i. dilimdeki tüm öğeler, kesme parametreleri olarak scales[i] ve zero_points[i] kullanır. Ölçülmüş tenör türleri aşağıdaki kısıtlamalara sahiptir:

  • Tensör başına kesme için:
    • Ek kısıtlama yoktur.
  • Eksen başına kesme için:
    • (C12) quantization_dimension < rank(self)
    • (C13) dim(self, quantization_dimension) = size(scales).
TokenType ::= 'token'

Jeton türleri, jetonları (yani bazı işlemler tarafından üretilen ve tüketilen opak değerleri) temsil eder. Jetonlar, Yürütme bölümünde açıklandığı gibi işlemlere yürütme sırası uygulamak için kullanılır.

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

Tuple türleri, grupları (heterojen listeler) temsil eder. Tuplar, yalnızca HLO ile uyumluluk için mevcut olan eski bir özelliktir. HLO'da, değişken sayıda giriş ve çıkışı temsil etmek için kümeler kullanılır. StableHLO'da değişken girişler ve çıkışlar doğal olarak desteklenir. StableHLO'da tupların tek kullanımı, HLO ABI'yi kapsamlı bir şekilde temsil etmektir. Örneğin, T, tuple<T> ve tuple<tuple<T>> belirli bir uygulamaya bağlı olarak önemli ölçüde farklı olabilir. Gelecekte, HLO ABI'de StableHLO'dan tuple türlerini kaldırmamıza olanak tanıyabilecek değişiklikler yapmayı planlıyoruz (#598).

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

Öğe türleri, tensör türlerinin öğelerini temsil eder. Birçok programlama dilinin aksine, bu türler StableHLO'da birinci sınıf değildir. Bu, StableHLO programlarının bu türlerin değerlerini doğrudan temsil edemeyeceği anlamına gelir (sonuç olarak, T türündeki skaler değerleri tensor<T> türündeki 0 boyutlu tenör değerleriyle temsil etmek idiomatiktir).

  • Boole türü, true ve false boole değerlerini temsil eder.
  • Tam sayı türleri, imzalı (si) veya imzasız (ui) olabilir ve desteklenen bit genişliklerinden birine (2, 4, 8, 16, 32 veya 64) sahip olabilir. İmzalı siN türleri, -2^(N-1) ile 2^(N-1)-1 dahil arasındaki tam sayı değerlerini, imzasız uiN türleri ise 0 ile 2^N-1 dahil arasındaki tam sayı değerlerini temsil eder.
  • Kayan nokta türleri aşağıdakilerden biri olabilir:
  • Karmaşık türler, aynı öğe türünde reel bir bölüme ve sanal bir bölüme sahip karmaşık değerleri temsil eder. Desteklenen karmaşık türler complex<f32> (her iki bölüm de f32 türündedir) ve complex<f64> (her iki bölüm de f64 türündedir) türleridir.
FunctionType ::= '(' InputTypes ')' '->' '(' OutputTypes ')'
InputTypes ::= [ValueType {',' ValueType}]
OutputTypes ::= [ValueType {',' ValueType}]

İşlev türleri hem adlandırılmış hem de anonim işlevleri temsil eder. Bunlar giriş türlerine (->'ün sol tarafındaki tür listesi) ve çıkış türlerine (->'ün sağ tarafındaki tür listesi) sahiptir. Birçok programlama dilinde işlev türleri birinci sınıftır ancak StableHLO'da değildir.

StringType ::= 'string'

Dize türü, bayt dizilerini temsil eder. Birçok programlama dilinin aksine, dize türü StableHLO'da birinci sınıf değildir ve yalnızca program öğeleri için statik meta verileri belirtmek amacıyla kullanılır.

İşlemler

StableHLO işlemleri (işlemler olarak da bilinir), makine öğrenimi modellerindeki kapalı bir üst düzey işlem grubunu temsil eder. Yukarıda da belirtildiği gibi, StableHLO söz dizimi büyük ölçüde MLIR'den esinlenmiştir. MLIR her zaman en ergonomik alternatif olmasa da StableHLO'nun ML çerçeveleri ile ML derleyicileri arasında daha fazla birlikte çalışabilirlik oluşturma hedefine en uygun seçenektir.

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

StableHLO işlemleri (işlemler olarak da bilinir) bir ada, giriş/çıkışa ve imzaya sahiptir. Ad, stablehlo. ön eki ve desteklenen işlemlerden birini benzersiz şekilde tanımlayan bir hatırlatıcıdan oluşur. Desteklenen tüm işlemlerin kapsamlı bir listesini aşağıda bulabilirsiniz.

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

İşlemler girişler tüketir ve çıktılar oluşturur. Girişler, giriş değerleri (yürütme sırasında hesaplanır), giriş işlevleri (StableHLO'da işlevler birinci sınıf değerler olmadığı için statik olarak sağlanır) ve giriş özellikleri (ayrıca statik olarak sağlanır) olarak sınıflandırılır. Bir işlem tarafından tüketilen ve üretilen giriş ve çıkışların türü, o işlemin anımsatıcısına bağlıdır. Örneğin, add op 2 giriş değeri tüketir ve 1 çıkış değeri oluşturur. Buna karşılık, select_and_scatter işlemi 3 giriş değeri, 2 giriş işlevi ve 3 giriş özelliği kullanır.

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

Giriş işlevleri (anonim işlevler olarak da bilinir), adlandırılmış işlevlere çok benzer. Bununla birlikte, aşağıdakiler dışında adlandırılmış işlevlere benzerler: 1) Tanımlayıcıları yoktur (bu nedenle "anonim" adı kullanılır), 2) Çıkış türlerini belirtmezler (Çıkış türleri, işlev içindeki return op'sinden anlaşılır).

Giriş işlevlerinin söz dizimi, şu anda kullanılmayan bir kısmı (yukarıdaki Unused üretimine bakın) içeriyor. Bu parça MLIR ile uyumludur. MLIR&#39;de, atlama işlemleri aracılığıyla birbirine bağlı birden fazla işlem &quot;bloğu&quot; içerebilen daha genel bir &quot;bölge&quot; kavramı vardır. Bu blokların, birbirinden ayırt edilebilmesi için Unused üretimine karşılık gelen kimlikleri vardır. StableHLO'da atlama işlemleri olmadığından MLIR söz dizesinin ilgili kısmı kullanılmaz (ancak yine de mevcuttur).

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

Giriş özelliklerinin bir adı ve desteklenen sabit değerlerinden biri olan bir değeri vardır. Program öğeleri için statik meta verileri belirtmenin birincil yoludur. Örneğin, concatenate işlemi, giriş değerlerinin birleştirildiği boyutu belirtmek için dimension özelliğini kullanır. Benzer şekilde, slice işlemi, giriş değerini dilimlemek için kullanılan sınırları belirtmek için start_indices ve limit_indices gibi birden fazla özellik kullanır.

Şu anda kullanımdaki StableHLO programları bazen bu dokümanda açıklanmayan özellikler içeriyor. Gelecekte bu özellikleri StableHLO işletim sistemine dahil etmeyi veya StableHLO programlarında görünmelerini yasaklamayı planlıyoruz. Bu sırada, bu özelliklerin listesini aşağıda bulabilirsiniz:

  • layout (#629).
  • mhlo.frontend_attributes (#628).
  • mhlo.sharding (#619).
  • output_operand_aliases (#740).
  • Konum meta verileri (#594).
OpSignature ::= '(' [ValueType {',' ValueType}] ')' '->' '(' [ValueType {',' ValueType}] ')'

İşlem imzası, tüm giriş değerlerinin türlerinden (->'nin sol tarafındaki tür listesi) ve tüm çıkış değerlerinin türlerinden (->'nin sağ tarafındaki tür listesi) oluşur. Giriş türleri ve çıkış türleri genellikle gereksizdir (çünkü çoğu StableHLO işleminde çıkış türleri girişlerden çıkarılabilir). Yine de op türü, MLIR ile uyumluluk için StableHLO söz dizesinin bir parçası olarak bilinçli olarak tasarlanmıştır.

Aşağıda, select_and_scatter kısaltması olan bir örnek işlem verilmiştir. 3 giriş değeri (%operand, %source ve %init_value), 2 giriş işlevi ve 3 giriş özelliği (window_dimensions, window_strides ve padding) tüketir. İşlemin imzasının yalnızca giriş değerlerinin türlerini içerdiğini (ancak satır içi olarak sağlanan giriş işlevlerinin ve özelliklerin türlerini içermediğini) unutmayın.

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

Sabitler

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

StableHLO sabitleri, birlikte bir StableHLO değerini temsil eden bir değişmez ve bir türe sahiptir. Türü, açık olmadığı durumlar hariç (ör. doğru/yanlış sabitinin türü açıkça i1 iken tam sayı sabitinin birden fazla olası türü olabilir) genellikle sabit söz dizesinin bir parçasıdır.

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

Boole sabitleri, true ve false boole değerlerini temsil eder. Boole sabitleri i1 türüne sahiptir.

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

Tam sayı sabitleri, ondalık veya onaltılık gösterim kullanan dizeler aracılığıyla tam sayı değerlerini temsil eder. Diğer tabanlar (ör. ikili veya sekizlik) desteklenmez. Tam sayı sabitleri aşağıdaki kısıtlamalara sahiptir:

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

Kayan nokta sabitleri, ondalık veya bilimsel gösterim kullanan dizeler aracılığıyla kayan nokta değerlerini temsil eder. Ayrıca, onaltılık gösterim, temel bitleri ilgili türün kayan nokta biçiminde doğrudan belirtmek için de kullanılabilir. Kayan noktalı sabitler aşağıdaki kısıtlamalara sahiptir:

  • (C1) Onaltılık olmayan gösterim kullanılıyorsa is_wellformed(float_literal, float_type).
  • (C2) Onaltılık gösterim kullanılıyorsa size(hexadecimal_digits) = num_bits(float_type) / 4.
ComplexConstant ::= ComplexLiteral ':' ComplexType
ComplexLiteral  ::= '(' RealPart ',' ImaginaryPart ')'
RealPart        ::= FloatLiteral
ImaginaryPart   ::= FloatLiteral

Karmaşık sabitler, gerçek kısım (ilk sırada gelir) ve sanal kısım (ikinci sırada gelir) listelerini kullanarak karmaşık değerleri temsil eder. Örneğin, (1.0, 0.0) : complex<f32>, 1.0 + 0.0i'u, (0.0, 1.0) : complex<f32> ise 0.0 + 1.0i'ı temsil eder. Bu parçaların bellekte depolanma sırası, uygulamaya göre belirlenir. Karmaşık sabitler aşağıdaki kısıtlamalara sahiptir:

  • (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 sabitleri, NumPy gösterimi ile belirtilen iç içe geçmiş listeleri kullanan tensör değerlerini temsil eder. Örneğin dense<[[1, 2, 3], [4, 5, 6]]> : tensor<2x3xi32>, dizinlerden öğelere yapılan aşağıdaki eşlemeyle bir tensör değerini temsil eder: {0, 0} => 1, {0, 1} => 2, {0, 2} => 3, {1, 0} => 4, {1, 1} => 5,{1, 2} => 6. Bu öğelerin bellekte depolanma sırası, uygulamaya göre belirlenir. Tensör sabitleri aşağıdaki kısıtlamalara sahiptir:

  • (C1) has_syntax(tensor_literal, element_type(tensor_type)). Burada:
    • 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)), burada:
    • 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:]).
    • aksi takdirde false.
QuantizedTensorConstant ::= QuantizedTensorLiteral ':' QuantizedTensorType
QuantizedTensorLiteral  ::= 'dense' '<' (DenseLiteral | ElementLiteral) '>'

Nicelleştirilmiş tensör sabitleri, tensör sabitleriyle aynı gösterimi kullanan nicelenmiş tensör değerlerini temsil eder ve öğeler, depolama türlerinin sabitleri olarak belirtilir. Ölçülmüş tenör sabitleri aşağıdaki kısıtlamalara sahiptir:

  • (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))

Dize sabit değerleri, ASCII karakterleri ve kaçış dizileri kullanılarak belirtilen baytlardan oluşur. Kodlamaya duyarlı değildirler. Bu nedenle, bu baytların yorumlanması uygulamaya göre belirlenir. Dize değişmezleri string türüne sahiptir.

İşlemler

abs

Anlam

operand tensörü üzerinde öğe düzeyinde abs işlemi gerçekleştirir ve result tensörü üretir. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • İmzalı tam sayılar için: tamsayı modülü.
  • Kayan reklamlar için: IEEE-754'ten abs.
  • Karmaşık sayılar için: karmaşık modül.
  • Miktarlanmış türler için: dequantize_op_quantize(abs, operand, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand işaretli tam sayı, kayan nokta veya karmaşık türde veya tensör başına kesirli tensör (C1-C2)

Çıkışlar

Ad Tür Sınırlamalar
result işaretli tam sayı veya kayan nokta türündeki veya tensör başına kesirli tensör (C1-C2)

Sınırlamalar

  • (C1) shape(result) = shape(operand).
  • (C2) baseline_element_type(result) şu şekilde tanımlanır:
    • is_complex(operand) ise complex_element_type(element_type(operand)).
    • Aksi takdirde baseline_element_type(operand) değerini alır.

Örnekler

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

Diğer Örnekler

add

Anlam bilimi

İki tensör lhs ve rhs'ün öğe bazında toplama işlemini gerçekleştirir ve result tensörü oluşturur. Öğe türüne bağlı olarak aşağıdakiler gerçekleşir:

  • Boole değerleri için: mantıksal VEYA.
  • Tam sayılar için: tamsayı toplama.
  • Kayan noktalı sayılar için: IEEE-754'ten addition.
  • Karmaşık sayılar için: karmaşık toplama.
  • Kesirli türler için: dequantize_op_quantize(add, lhs, rhs, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs tenzor veya kesirli tenzor (C1-C6)
(I2) rhs tenzor veya kesirli tenzor (C1-C5), (C7)

Çıkışlar

Ad Tür Sınırlamalar
result tenzor veya kesirli tenzor (C1-C7)

Sınırlamalar

  • İşlemde kesirli olmayan tenzorlar kullanılıyorsa:
    • (C1) type(lhs) = type(rhs) = type(result).
  • İşlemde kesirli tenzorlar kullanılıyorsa:
    • (C2) is_quantized(lhs) and is_quantized(rhs) and is_quantized(result).
    • (C3) storage_type(lhs) = storage_type(rhs) = storage_type(result).
    • (C4) expressed_type(lhs) = expressed_type(rhs) = expressed_type(result).
    • (C5) (is_per_axis_quantized(lhs) or is_per_axis_quantized(rhs)) = is_per_axis_quantized(result).
    • (C6) is_per_axis_quantized(lhs) ise quantization_dimension(lhs) = quantization_dimension(result).
    • (C7) is_per_axis_quantized(rhs) ise quantization_dimension(rhs) = quantization_dimension(result).

Örnekler

// %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]]

 Diğer Örnekler

after_all

Anlam

inputs değerini üreten işlemlerin, result değerine bağlı tüm işlemlerden önce yürütülmesini sağlar. Bu işlemin yürütülmesi hiçbir şey yapmaz. Yalnızca result ile inputs arasında veri bağımlılıkları oluşturmak için vardır.

Girişler

Şirket Ad Tür
(I1) inputs token değişken sayısı

Çıkışlar

Ad Tür
result token

Örnekler

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

 Diğer Örnekler

all_gather

Anlam bilimi

StableHLO işlem ızgarasındaki her işlem grubunda, all_gather_dim boyunca her işlemden alınan operands tenzorlarının değerlerini birleştirir ve results tenzorları oluşturur.

İşlem, StableHLO işlem ızgarasını aşağıdaki gibi tanımlanan process_groups olarak böler:

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

Ardından her bir process_group içinde:

  • process_group adlı kuruluş biriminde tüm receiver için operands...@receiver = [operand@sender for sender in process_group].
  • process_group kapsamındaki tüm process için results...@process = concatenate(operands...@process, all_gather_dim).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operands değişken sayıda tenör veya tenör başına kesikli tenörler (C1), (C6)
(I2) all_gather_dim si64 türünün sabiti (C1), (C6)
(I3) replica_groups si64 türündeki 2 boyutlu tensör sabit (C2-C4)
(I4) channel_id si64 türünün sabiti (C5)
(I5) use_global_device_ids i1 türünün sabiti (C5)

Çıkışlar

Ad Tür Sınırlamalar
results değişken sayıda tenör veya tenör başına kesikli tenörler (C6)

Sınırlamalar

  • (C1) 0 <= all_gather_dim < rank(operands...).
  • (C2) is_unique(replica_groups).
  • (C3) size(replica_groups) şu şekilde tanımlanır:
    • cross_replica kullanılıyorsa num_replicas.
    • cross_replica_and_partition kullanılıyorsa num_replicas.
    • flattened_ids kullanılıyorsa num_processes.
  • (C4) 0 <= replica_groups < size(replica_groups)
  • (C5) use_global_device_ids = true ise channel_id > 0.
  • (C6) type(results...) = type(operands...) hariç:
    • dim(results..., all_gather_dim) = dim(operands..., all_gather_dim) * dim(process_groups, 1).

Örnekler

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

 Diğer Örnekler

all_reduce

Anlam bilimi

StableHLO işlem ızgarasındaki her işlem grubunda, her işlemdeki operands tenörlerinin değerlerine bir azaltma işlevi computation uygular ve results tenörü oluşturur.

İşlem, StableHLO süreç ızgarasını şu şekilde tanımlanan process_groups şeklinde ayırır:

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

Ardından her bir process_group içinde:

  • results...@process[result_index] = exec(schedule) için bazı ikili ağaç schedule şöyledir:
    • exec(node) = computation(exec(node.left), exec(node.right)).
    • exec(leaf) = leaf.value.
  • schedule, sıralı traversal'ı to_destination_type(operands...@process_group...[result_index], type(func_inputs(computation)[0])) olan, uygulama tanımlı bir ikili ağaçtır.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operands değişken sayıda tenör veya tenör başına kesikli tenörler (C5), (C6)
(I2) replica_groups si64 türündeki 1 boyutlu tensör sabitlerinin değişken sayısı (C1-C3)
(I3) channel_id si64 türündeki sabit (C4)
(I4) use_global_device_ids i1 türünün sabiti (C4)
(I5) computation işlev (C5)

Çıkışlar

Ad Tür Sınırlamalar
results değişken sayıda tenör veya tenör başına kesikli tenörler (C6-C7)

Sınırlamalar

  • (C1) is_unique(replica_groups).
  • (C2) size(replica_groups) şu şekilde tanımlanır:
    • cross_replica kullanılıyorsa num_replicas.
    • cross_replica_and_partition kullanılıyorsa num_replicas.
    • flattened_ids kullanılıyorsa num_processes.
  • (C3) 0 <= replica_groups < size(replica_groups).
  • (C4) use_global_device_ids = true ise channel_id > 0.
  • (C5) computation, is_promotable(element_type(operand), E) olduğunda (tensor<E>, tensor<E>) -> (tensor<E>) türüne sahiptir.
  • (C6) shape(results...) = shape(operands...).
  • (C7) element_type(results...) = E.

Örnekler

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

Diğer Örnekler

all_to_all

Anlam bilimi

all_to_all

StableHLO işlem ızgarasındaki her işlem grubunda, operands tenzorlarının değerlerini split_dimension boyunca parçalara ayırır, ayrılan parçaları işlemler arasında dağıtır, dağıtılan parçaları concat_dimension boyunca birleştirir ve results tenzorları oluşturur. İşlem, StableHLO işlem ızgarasını aşağıdaki gibi tanımlanan process_groups olarak böler:

  • channel_id <= 0 ise cross_replica(replica_groups).
  • channel_id > 0 ise cross_partition(replica_groups).

Daha sonra, her process_group içinde:

  • process_group adlı kuruluş biriminde tüm sender için split_parts...@sender = split(operands...@sender, split_count, split_dimension)
  • scattered_parts...@receiver = [split_parts...@sender[receiver_index] for sender in process_group] burada receiver_index = process_group.index(receiver).
  • results...@process = concatenate(scattered_parts...@process, concat_dimension).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operands değişken sayıda tenör veya tenör başına kesikli tenörler (C1-C3), (C9)
(I2) split_dimension si64 türündeki sabit (C1), (C2), (C9)
(I3) concat_dimension si64 türündeki sabit (C3), (C9)
(I4) split_count si64 türündeki sabit (C2), (C4), (C8), (C9)
(I5) replica_groups si64 türündeki 2 boyutlu tensör sabit (C5-C8)
(I6) channel_id si64 türünün sabiti

Çıkışlar

Ad Tür Sınırlamalar
results değişken sayıda tenör veya tenör başına kesikli tenörler (C9)

Sınırlamalar

  • (C1) 0 <= split_dimension < rank(operands...).
  • (C2) dim(operands..., split_dimension) % split_count = 0.
  • (C3) 0 <= concat_dimension < rank(operands...).
  • (C4) 0 < split_count.
  • (C5) is_unique(replica_groups)
  • (C6) size(replica_groups) şu şekilde tanımlanır:
    • cross_replica kullanılıyorsa num_replicas.
    • cross_partition kullanılıyorsa num_partitions.
  • (C7) 0 <= replica_groups < size(replica_groups).
  • (C8) dim(replica_groups, 1) = split_count.
  • (C9) split_dimension != concat_dimension ise type(results...) = type(operands...) dışında:
    • dim(results..., split_dimension) = dim(operands..., split_dimension) / split_count.
    • dim(results..., concat_dimension) = dim(operands..., concat_dimension) * split_count.

Örnekler

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

 Diğer Örnekler

ve

Anlam bilimi

İki lhs ve rhs tenörünün öğe bazında VE işlemini gerçekleştirir ve bir result tenörü oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • Boolelar için: mantıksal VE.
  • Tam sayılar için: bit tabanlı VE.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs boole veya tam sayı türündeki tenör (C1)
(I2) rhs boole veya tam sayı türündeki tensor (C1)

Çıkışlar

Ad Tür Sınırlamalar
result boole veya tam sayı türündeki tenör (C1)

Sınırlamalar

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

Örnekler

// %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]]

 Diğer Örnekler

atan2

Anlam bilimi

lhs ve rhs tensöründe öğe bazında atan2 işlemi gerçekleştirir ve bir result tensörü oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • Kayan reklamlar için: IEEE-754'ten atan2.
  • Karmaşık sayılar için: karmaşık atan2.
  • Kesirli türler için: dequantize_op_quantize(atan2, lhs, rhs, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)
(I2) rhs kayan nokta veya karmaşık tür ya da tensör başına miktarlandırılmış tensör tensörü (C1)

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Sınırlamalar

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

Örnekler

// %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]

 Diğer Örnekler

batch_norm_grad

Anlam bilimi

grad_output'dan geri yayılan batch_norm_training girişlerinin gradyanlarını hesaplar ve grad_operand, grad_scale ve grad_offset tensörlerini oluşturur. Daha resmi bir ifadeyle bu işlem, Python söz dizimi kullanılarak mevcut StableHLO işlemlerine aşağıdaki şekilde ayrılarak ifade edilebilir:

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

Miktarı ölçülmüş türlerde, 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)) gerçekleştirir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand Kayan nokta türündeki veya tensör başına kesirli tensör (C1-C3); (C5)
(I2) scale Kayan nokta veya tensör başına kesirli cinsinden 1 boyutlu tensör (C2), (C4), (C5)
(I3) mean Kayan nokta veya tensör başına kesirli cinsinden 1 boyutlu tensör (C2), (C4)
(I4) variance Kayan nokta veya tensör başına miktarlandırılmış türde 1 boyutlu tensör (C2), (C4)
(I5) grad_output Kayan nokta türündeki veya tensör başına kesirli tensör (C2), (C3)
(I6) epsilon f32 türündeki sabit
(I7) feature_index si64 türündeki sabit (C1), (C5)

Çıkışlar

Ad Tür Sınırlamalar
grad_operand Kayan nokta türündeki veya tensör başına kesirli tensör (C2), (C3)
grad_scale Kayan nokta veya tensör başına miktarlandırılmış türde 1 boyutlu tensör (C2), (C4)
grad_offset Kayan nokta veya tensör başına kesirli cinsinden 1 boyutlu tensör (C2), (C4)

Sınırlamalar

  • (C1) 0 <= feature_index < rank(operand).
  • (C2) operand, scale, mean, variance, grad_output, grad_operand, grad_scale ve grad_offset aynı baseline_element_type değerine sahiptir.
  • (C3) operand, grad_output ve grad_operand aynı şekle sahiptir.
  • (C4) scale, mean, variance, grad_scale ve grad_offset aynı şekle sahiptir.
  • (C5) size(scale) = dim(operand, feature_index)

Örnekler

// %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

Anlam

operand tensörünü feature_index boyutu hariç tüm boyutlarda normalize eder ve bir result tensörü oluşturur. Daha resmi bir ifadeyle bu işlem, Python söz dizimini kullanarak mevcut StableHLO işlemlerinin bir ayrışımı olarak şu şekilde ifade edilebilir:

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)

Miktarı belirlenmiş türler için 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)) işlemini gerçekleştirir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand Kayan nokta türündeki veya tensör başına kesirli tensör (C1-C7)
(I2) scale Kayan nokta veya tensör başına kesirli cinsinden 1 boyutlu tensör (C2), (C3)
(I3) offset Kayan nokta veya tensör başına kesirli cinsinden 1 boyutlu tensör (C2), (C4)
(I4) mean Kayan nokta veya tensör başına kesirli cinsinden 1 boyutlu tensör (C5)
(I5) variance Kayan nokta veya tensör başına miktarlandırılmış türde 1 boyutlu tensör (C2), (C6)
(I6) epsilon f32 türündeki sabit
(I7) feature_index si64 türünün sabiti (C1), (C3-C6)

Çıkışlar

Ad Tür Sınırlamalar
result Kayan nokta türündeki veya tensör başına kesirli tensör (C2), (C7)

Sınırlamalar

  • (C1) 0 <= feature_index < rank(operand).
  • (C2) operand, scale, offset, mean, variance ve result aynı baseline_element_type değerine sahiptir.
  • (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).

Örnekler

// %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

Anlam bilimi

feature_index boyutu hariç tüm boyutlarda ortalama ve varyansı hesaplar ve operand tenzorunu normalleştirerek output, batch_mean ve batch_var tenzorlarını oluşturur. Daha resmi bir ifadeyle, bu işlem aşağıdaki gibi Python söz dizimi kullanılarak mevcut StableHLO işlemlerine ayrıştırma olarak ifade edilebilir:

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

Miktarı ölçülmüş türlerde, 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)) gerçekleştirir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand Kayan nokta türündeki veya tensör başına kesirli tensör (C1)
(I2) scale Kayan nokta veya tensör başına kesirli 1 boyutlu tensör (C2), (C3)
(I3) offset Kayan nokta veya tensör başına miktarlandırılmış 1 boyutlu tensör (C2), (C4)
(I4) epsilon f32 türünün sabiti (C1), (C3-C6)
(I5) feature_index si64 türündeki sabit (C1), (C3-C6)

Çıkışlar

Ad Tür Sınırlamalar
output Kayan nokta türündeki veya tensör başına kesirli tensör (C7)
batch_mean Kayan nokta veya tensör başına kesirli 1 boyutlu tensör (C2), (C5)
batch_var Kayan nokta veya tensör başına kesirli 1 boyutlu tensör (C2), (C6)

Sınırlamalar

  • (C1) 0 <= feature_index < rank(operand).
  • (C2) operand, scale, offset, batch_mean, batch_var ve output aynı baseline_element_type değerine sahiptir.
  • (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).

Örnekler

// %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

Anlam bilimi

operand tensöründe bir bit yayınlama işlemi gerçekleştirir ve operand tenörünün tümünün bitlerinin result tenörünün türü kullanılarak yeniden yorumlandığı bir result tensörü oluşturur.

Daha resmi bir ifadeyle, E = element_type(operand), E' = element_type(result) ve R = rank(operand) için:

  • num_bits(E') < num_bits(E) ise bits(result[i0, ..., iR-1, :]) = bits(operand[i0, ..., iR-1]).
  • num_bits(E') > num_bits(E) ise bits(result[i0, ..., iR-2]) = bits(operand[i0, ..., iR-2, :]).
  • num_bits(E') = num_bits(E) ise bits(result[i0, ..., iR-1]) = bits(operand[i0, ..., iR-1]).

bits, belirli bir değerin bellekteki temsilini döndürür. Tensörlerin tam temsilinin uygulama tanımlı olması ve öğe türlerinin tam temsilinin de uygulama tanımlı olması nedeniyle bu davranışı uygulama tanımlıdır.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tenzor veya kesirli tenzor (C1-C2)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya nicel tensör (C1-C2)

Sınırlamalar

  • (C1) E = is_quantized(operand) ? storage_type(operand) : element_type(operand), E' = is_quantized(result) ? storage_type(result) : element_type(result) ve R = rank(operand) çerçevesinde:
    • num_bits(E') = num_bits(E) ise shape(result) = shape(operand).
    • num_bits(E') < num_bits(E) ise:
    • rank(result) = R + 1.
    • dim(result, i) = dim(operand, i) için 0 <= i < R.
    • dim(result, R) * num_bits(E') = num_bits(E).
    • num_bits(E') > num_bits(E) ise:
    • rank(result) = R - 1.
    • dim(result, i) = dim(operand, i) için 0 <= i < R.
    • dim(operand, R - 1) * num_bits(E) = num_bits(E').
  • (C2) is_complex(operand) or is_complex(result) ise is_complex(operand) and is_complex(result).

Örnekler

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

 Diğer Örnekler

broadcast_in_dim

Anlam

operand tenzorundaki verileri kopyalayarak bir giriş tenzorunun boyutlarını ve/veya rütbesini genişletir ve bir result tenzoru oluşturur. Daha resmi bir ifadeyle, axes(operand) içindeki tüm d için result[result_index] = operand[operand_index]:

  • dim(operand, d) = 1 ise operand_index[d] = 0.
  • Aksi takdirde operand_index[d] = result_index[broadcast_dimensions[d]] değerini alır.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tenzor veya kesirli tenzor (C1-C2), (C5-C6)
(I2) broadcast_dimensions si64 türünde 1 boyutlu tensör sabiti (C2-C6)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya nicel tensör (C1), (C3), (C5-C6)

Sınırlamalar

  • (C1) element_type(result) şu şekilde hesaplanır:
    • !is_per_axis_quantized(operand) ise element_type(operand).
    • element_type(operand), ancak quantization_dimension(operand), scales(operand) ve zero_points(operand) sırasıyla quantization_dimension(result), scales(result) ve zero_points(result)'den farklı olabilir.
  • (C2) size(broadcast_dimensions) = rank(operand).
  • (C3) 0 <= broadcast_dimensions < rank(result).
  • (C4) is_unique(broadcast_dimensions).
  • (C5) axes(operand) içindeki tüm d için:
    • dim(operand, d) = 1 veya
    • dim(operand, d) = dim(result, broadcast_dimensions[d]).
  • (C6) is_per_axis_quantized(result) ise:
    • quantization_dimension(result) = broadcast_dimensions[quantization_dimension(operand)].
    • dim(operand, quantization_dimension(operand)) = 1 ise scales(result)[i] = scales(operand)[0] and zero_points(result)[i] = zero_points(operand)[0] for i in range(dim(result, quantization_dimension(result))).

Örnekler

// %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]
//            ]
//          ]

 Diğer Örnekler

kılıf

Anlam bilimi

index değerine bağlı olarak branches içinden tam olarak bir işlevin yürütülmesiyle elde edilen çıktıyı oluşturur. Daha resmi bir ifadeyle, result = selected_branch() burada:

  • 0 <= index < size(branches) ise selected_branch = branches[index].
  • Aksi takdirde selected_branch = branches[-1] değerini alır.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) index si32 türündeki 0 boyutlu tensör
(I2) branches değişken sayıda işlev (C1-C4)

Çıkışlar

Ad Tür Sınırlamalar
results değişken tensör, nicel tensör veya jeton sayısı (C4)

Sınırlamalar

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

Örnekler

// %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]

 Diğer Örnekler

cbrt

Anlam bilimi

operand tensörü üzerinde öğe tabanlı kübik kök işlemi gerçekleştirir ve result tensörü üretir. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • Kayan noktalı sayılar için: IEEE-754'ten rootn(x, 3).
  • Karmaşık sayılar için: karmaşık küp kökü.
  • Kesirli türler için: dequantize_op_quantize(cbrt, operand, type(result))

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Sınırlamalar

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

Örnekler

// %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]

 Diğer Örnekler

ceil

Anlam bilimi

operand tenzorunun öğe bazında üst sınırını gerçekleştirir ve bir result tenzoru oluşturur. IEEE-754 spesifikasyonundaki roundToIntegralTowardPositive işlemini uygular. Miktarı belirlenmiş türler için dequantize_op_quantize(ceil, operand, type(result)) işlemini gerçekleştirir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand Kayan nokta türündeki veya tensör başına kesirli tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta türünde veya tensör başına miktarlandırılmış tensörün tensörü (C1)

Sınırlamalar

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

Örnekler

// %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]

 Diğer Örnekler

cholesky

Anlam

Bir dizi matrisin Cholesky ayrışmasını hesaplar.

Daha resmi bir ifadeyle, index_space(result) içindeki tüm i için result[i0, ..., iR-3, :, :], a[i0, ..., iR-3, :, :]'ın alt üçgen (lower true ise) veya üst üçgen (lower false ise) matris biçiminde Cholesky ayrışımıdır. Karşıt üçgendeki çıkış değerleri (ör. katı üst üçgen veya buna karşılık gelen katı alt üçgen) uygulama tanımlıdır.

Girdi matrisinin Hermitian pozitif tanımlı bir matrisi olmadığı i varsa davranış tanımsızdır.

Miktarı ölçülmüş türlerde, dequantize_op_quantize(lambda operand: cholesky(operand, lower), a, type(result)) gerçekleştirir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) a kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1-C3)
(I2) lower i1 türündeki 0 boyutlu tensör sabit

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Sınırlamalar

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

Örnekler

// %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]
//          ]

kelepçe

Anlam bilimi

operand tenzorunun her bir öğesini minimum ve maksimum değer arasında sıkıştırır ve bir result tenzoru oluşturur. Daha resmi bir ifadeyle, result[result_index] = minimum(maximum(operand[result_index], min_element), max_element), burada min_element = rank(min) = 0 ? min[] : min[result_index], max_element = rank(max) = 0 ? max[] : max[result_index]. Nicel türlerde dequantize_op_quantize(clamp, min, operand, max, type(result)) olarak performans gösterir.

Karmaşık sayılara sıralama uygulamak şaşırtıcı anlamlar içerir. Bu nedenle, gelecekte bu işlem için karmaşık sayılar desteğini kaldırmayı planlıyoruz (#560).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) min tensör veya tensör başına miktarlandırılmış tensör (C1), (C3)
(I2) operand tensor veya tensor başına kesikli tensor (C1-C4)
(I3) max tensor veya tensor başına kesikli tensor (C2), (C3)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına miktarlandırılmış tensör (C4)

Sınırlamalar

  • (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).

Örnekler

// %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]

 Diğer Örnekler

collective_broadcast

Anlam bilimi

StableHLO işlem ızgarasındaki her işlem grubunda, operand tenzorunun değerini kaynak işlemden hedef işlemlere gönderin ve bir result tenzoru oluşturun.

İşlem, StableHLO işlem ızgarasını aşağıdaki gibi tanımlanan process_groups olarak böler:

  • channel_id <= 0 ise cross_replica(replica_groups).
  • channel_id > 0 ise cross_partition(replica_groups).

Ardından result@process şu şekilde hesaplanır:

  • operand@process_groups[i, 0], işlem process_groups[i] içinde olduğunda i varsa.
  • broadcast_in_dim(constant(is_quantized(result) ? quantize(0, element_type(result)) : 0, element_type(result)), [], type(result)) aksi takdirde.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tensör veya tensör başına miktarlandırılmış tensör (C3)
(I2) replica_groups si64 türündeki 1 boyutlu tensör sabitlerinin değişken sayısı (C1), (C2)
(I3) channel_id si64 türündeki sabit

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına miktarlandırılmış tensör (C3)

Sınırlamalar

  • (C1) is_unique(replica_groups).
  • (C2) 0 <= replica_groups < N; burada N şu şekilde tanımlanır:
    • cross_replica kullanılıyorsa num_replicas.
    • cross_partition kullanılıyorsa num_partitions.
  • (C3) type(result) = type(operand).

Örnekler

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

Anlam bilimi

StableHLO işlem ızgarasındaki her işlem grubunda, operand tensörü değeri kaynak işlemden hedef işleme gönderilir ve bir result tensörü üretir.

İşlem, StableHLO işlem ızgarasını aşağıdaki gibi tanımlanan process_groups olarak böler:

  • channel_id <= 0 ise cross_replica(source_target_pairs).
  • channel_id > 0 ise cross_partition(source_target_pairs).

Ardından result@process şu şekilde hesaplanır:

  • operand@process_groups[i, 0] (process_groups[i, 1] = process gibi bir i varsa).
  • broadcast_in_dim(constant(is_quantized(result) ? quantize(0, element_type(result)) : 0, element_type(result)), [], type(result)) aksi takdirde.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tensor veya tensor başına kesikli tensor (C5)
(I2) source_target_pairs si64 türünde 2 boyutlu tensör sabiti (C1-C4)
(I3) channel_id si64 türündeki sabit

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına miktarlandırılmış tensör (C1)

Sınırlamalar

  • (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. Burada N şu şekilde tanımlanır:
    • cross_replica kullanılıyorsa num_replicas.
    • cross_partition kullanılıyorsa num_partitions.
  • (C5) type(result) = type(operand).

Örnekler

// 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]]

 Diğer Örnekler

karşılaştır

Anlam bilimi

lhs ve rhs tenörlerinin comparison_direction ve compare_type'e göre öğe bazında karşılaştırmasını yapar ve bir result tenörü oluşturur.

comparison_direction ve compare_type değerleri şu anlamlara sahiptir:

Boole ve tam sayı öğe türleri için:

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

compare_type = FLOAT içeren kayan nokta öğe türleri için op, aşağıdaki IEEE-754 işlemlerini uygular:

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

compare_type = TOTALORDER içeren kayan noktalı öğe türleri için op, IEEE-754'teki totalOrder ve compareQuietEqual işlemlerinin bir kombinasyonunu kullanır.

Karmaşık öğe türleri için, sağlanan comparison_direction ve compare_type kullanılarak (real, imag) çiftlerinin alfabetik karşılaştırması yapılır. Karmaşık sayılara sıralama uygulamak şaşırtıcı anlamlar içerir. Bu nedenle, gelecekte comparison_direction GE, GT, LE veya LT olduğunda karmaşık sayı desteğini kaldırmayı planlıyoruz (#560).

Kesirli türler için dequantize_compare(lhs, rhs, comparison_direction) işlemini gerçekleştirir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs tensor veya tensor başına kesikli tensor (C1-C3)
(I2) rhs tensor veya tensor başına kesikli tensor (C1-C2)
(I3) comparison_direction EQ, NE, GE, GT, LE ve LT değerlerini içeren bir enum
(I4) compare_type FLOAT, TOTALORDER, SIGNED ve UNSIGNED değerlerini içeren bir enum (C3)

Çıkışlar

Ad Tür Sınırlamalar
result boole türündeki tensör (C2)

Sınırlamalar

  • (C1) baseline_element_type(lhs) = baseline_element_type(rhs).
  • (C2) shape(lhs) = shape(rhs) = shape(result).
  • (C3) compare_type şu şekilde tanımlanır:
    • is_signed_integer(element_type(lhs)) ise SIGNED.
    • is_unsigned_integer(element_type(lhs)) or is_boolean(element_type(lhs)) ise UNSIGNED.
    • is_float(element_type(lhs)) ise FLOAT veya TOTALORDER.
    • is_complex(element_type(lhs)) ise FLOAT.

Örnekler

// %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]

 Diğer Örnekler

karmaşık

Anlam

Gerçek ve sanal değerlerden (lhs ve rhs) oluşan iki değerden karmaşık bir değere öğe düzeyinde dönüştürme gerçekleştirir ve bir result tensörü üretir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs f32 veya f64 türündeki tensör (C1-C3)
(I2) rhs f32 veya f64 türündeki tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result karmaşık türde tensör (C2), (C3)

Sınırlamalar

  • (C1) type(lhs) = type(rhs).
  • (C2) shape(result) = shape(lhs).
  • (C3) element_type(result), E = element_type(lhs) olduğunda complex<E> türünde.

Örnekler

// %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)]

 Diğer Örnekler

birleşik

Anlam bilimi

inputs ve composite_attributes'yi alıp results üreterek diğer StableHLO işlemlerinden oluşan bir işlemi kapsar. Op'nin semantikleri decomposition özelliği tarafından uygulanır. composite işlemi, program semantiklerini değiştirmeden ayrıştırmasıyla değiştirilebilir. Ayrıştırmanın satır içi olarak yerleştirilmesinin aynı işlem semantiğini sağlamadığı durumlarda custom_call kullanmayı tercih edin.

version alanı (varsayılan olarak 0 değerine ayarlanır), bileşenin anlamının ne zaman değiştiğini belirtmek için kullanılır.

Girişler

Şirket Ad Tür
(I1) inputs değişken değer sayısı
(I2) name string türündeki sabit
(I3) composite_attributes özellik sözlüğü
(I4) decomposition string türündeki sabit
(I5) version si32 türünün sabiti

Çıkışlar

Ad Tür
results değişken değer sayısı

Sınırlamalar

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

Örnekler

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

 Diğer Örnekler

birleştirmek

Anlam

inputs öğesini, belirtilen bağımsız değişkenlerle aynı sırada dimension boyutu boyunca birleştirir ve bir result tensörü oluşturur. Daha resmi bir ifadeyle, result[i0, ..., id, ..., iR-1] = inputs[k][i0, ..., kd, ..., iR-1], burada:

  1. id = d0 + ... + dk-1 + kd.
  2. d, dimension değerine eşit ve d0, ... inputs öğesinin d. boyut boyutlarıdır.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) inputs değişken sayıda tensör veya tensör başına miktarlandırılmış tensör (C1-C6)
(I2) dimension si64 türündeki sabit (C2), (C4), (C6)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına miktarlandırılmış tensör (C5-C6)

Sınırlamalar

  • (C1) same(element_type(inputs...)).
  • (C2) dim(inputs..., dimension) hariç same(shape(inputs...)).
  • (C3) 0 < size(inputs).
  • (C4) 0 <= dimension < rank(inputs[0]).
  • (C5) element_type(result) = element_type(inputs[0]).
  • (C6) Aşağıdakiler hariç shape(result) = shape(inputs[0]):
    • dim(result, dimension) = dim(inputs[0], dimension) + ....

Örnekler

// %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]]

 Diğer Örnekler

sabit

Anlam

Sabit bir value değerinden output tensörü oluşturur.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) value sabit (C1)

Çıkışlar

Ad Tür Sınırlamalar
output tenzor veya kesirli tenzor (C1)

Sınırlamalar

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

Örnekler

%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]]

 Diğer Örnekler

Dönüşüm gerçekleştirme

Anlam

operand tenzorunda bir öğe türünden diğerine öğe bazında dönüşüm gerçekleştirir ve bir result tenzoru oluşturur.

boolean-to-any-supported-type dönüşümleri için false değeri sıfıra ve true değeri bire dönüştürülür. any-supported-type-to-boolean dönüşümleri için sıfır değeri false değerine, sıfır olmayan değerler ise true değerine dönüştürülür. Bunun karmaşık türler için nasıl çalıştığını aşağıda görebilirsiniz.

Tam sayı ile tam sayı, tam sayı ile kayan nokta veya kayan nokta ile kayan nokta dönüşümleri söz konusu olduğunda, kaynak değer hedef türünde tam olarak temsil edilebiliyorsa sonuç değeri bu tam temsildir. Aksi takdirde davranış henüz belirlenmemiştir (#180).

floating-point-to-integer dönüşümleri içeren dönüşümlerde kesirli kısım kısaltılır. Kısaltılmış değer hedef türünde temsil edilemiyorsa davranış TBD olur (#180).

Karmaşıktan karmaşığa dönüşüm, gerçek ve sanal kısımları dönüştürmek için kayan noktadan kayan noktaya dönüşümlerin aynı davranışını izler.

Karmaşıktan başka bir türe ve başka bir türden karmaşığa dönüşümlerde sırasıyla kaynak karmaşık değer yok sayılır veya hedef karmaşık değer sıfırlanır. Gerçek kısmın dönüştürülmesi, kayan nokta dönüşümlerini izler.

Bu işlem, prensipte kesirli sayılaştırmayı (kesirli sayılaştırılmış tenzorlardan normal tenzorlara dönüşüm), kesirli sayılaştırmayı (normal tenzorlardan kesirli sayılaştırılmış tenzorlara dönüşüm) ve yeniden kesirli sayılaştırmayı (kesirli sayılaştırılmış tenzorlar arasında dönüşüm) ifade edebilir ancak şu anda bunun için özel işlemlerimiz var: ilk kullanım alanı için uniform_dequantize ve ikinci ve üçüncü kullanım alanları için uniform_quantize. Gelecekte bu iki işlem convert ile birleştirilebilir (#1576).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand Tensor (C1)

Çıkışlar

Ad Tür Sınırlamalar
result Tensor (C1)

Sınırlamalar

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

Örnekler

// %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)]

 Diğer Örnekler

konvolüsyon

Anlam bilimi

lhs pencereleri ile rhs dilimleri arasındaki iç çarpımları hesaplar ve result değerini döndürür. Aşağıdaki şemada, result öğelerinin lhs ve rhs'den nasıl hesaplandığı somut bir örnekle gösterilmektedir.

konvolüsyon

Daha resmi bir ifadeyle, lhs pencerelerini ifade edebilmek için girişlerin lhs açısından aşağıdaki şekilde yeniden çerçevelendiğini düşünün:

  • 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).

Bu yeniden çerçeveleme işleminde aşağıdaki yardımcı işlevler kullanılır:

  • 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] burada j[d] = i[permutation[d]].

feature_group_count = 1 ve batch_group_count = 1 ise index_space(dim(result, output_spatial_dimensions...)) içindeki tüm output_spatial_index için 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]). Bu özelliğin kullanılmadığı anlaşılıyor. Bu nedenle, ileride bu özelliği kaldırmayı planlıyoruz (#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 ise:

  • 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 ise:

  • 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).

Miktarı belirlenmiş türler için 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)) işlemini gerçekleştirir.

Karma kesirli türler için hybrid_dequantize_then_op( lambda lhs, rhs: convolution(lhs, rhs, window_strides, padding, lhs_dilation, rhs_dilation, window_reversal, input_batch_dimension, input_feature_dimension, input_spatial_dimensions, kernel_input_feature_dimension, kernel_output_feature_dimension, kernel_spatial_dimensions, output_batch_dimension, output_feature_dimension, output_spatial_dimensions, feature_group_count, batch_group_count, precision_config), lhs, rhs) işlemini gerçekleştirir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs tensor veya tensor başına kesikli tensor (C1), (C10-C11), (C14) (C25), (C27-C28), (C31-C32), (C34)
(I2) rhs tenzor veya kesirli tenzor (C1), (C14-C16), (C25), (C27-C29), (C31-C34)
(I3) window_strides si64 türündeki 1 boyutlu tensör sabiti (C2-C3), (C25)
(I4) padding si64 türündeki 2 boyutlu tensör sabit (C4), (C25)
(I5) lhs_dilation si64 türündeki 1 boyutlu tensör sabiti (C5-C6), (C25)
(I6) rhs_dilation si64 türündeki 1 boyutlu tensör sabiti (C7-C8), (C25)
(I7) window_reversal i1 türünde 1 boyutlu tensör sabiti (C9)
(I8) input_batch_dimension si64 türündeki sabit (C10), (C13), (C25)
(I9) input_feature_dimension si64 türündeki sabit (C11), (C13-C14)
(I10) input_spatial_dimensions si64 türündeki 1 boyutlu tensör sabiti (C12), (C13), (C25)
(I11) kernel_input_feature_dimension si64 türündeki sabit (C14), (C18)
(I12) kernel_output_feature_dimension si64 türündeki sabit (C15-C16), (C18), (C25), (C29)
(I13) kernel_spatial_dimensions si64 türündeki 1 boyutlu tensör sabiti (C17-C18), (C25)
(I14) output_batch_dimension si64 türündeki sabit (C20), (C25)
(I15) output_feature_dimension si64 türündeki sabit (C20), (C25), (C30)
(I16) output_spatial_dimensions si64 türündeki 1 boyutlu tensör sabiti (C19-C20), (C25)
(I17) feature_group_count si64 türündeki sabit (C11), (C14), (C16), (C21), (C23)
(I18) batch_group_count si64 türündeki sabit (C10), (C15), (C22), (C23), (C25)
(I19) precision_config DEFAULT, HIGH ve HIGHEST türetilmiş türleri için değişken sayıda enum (C24)

Çıkışlar

Ad Tür Sınırlamalar
result tenzor veya kesirli tenzor (C25-C28), (C30), (C32-34)

Sınırlamalar

  • (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] ile ilgili:
    • 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] ile ilgili:
    • 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] verildiğinde:
    • 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) şu şekilde tanımlanır:
    • result_dim = output_batch_dimension ise dim(lhs, input_batch_dimension) / batch_group_count.
    • result_dim = output_feature_dimension ise dim(rhs, kernel_output_feature_dimension).
    • num_windows aksi takdirde:
    • 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.
  • İşlemde miktarlandırılmamış tensörler kullanılıyorsa:
    • (C27) element_type(lhs) = element_type(rhs) = element_type(result).
  • İşlemde kesirli tenzorlar kullanılıyorsa:
    • (C28) is_quantized(lhs) = is_quantized(result) and is_quantized(rhs).
    • (C29) is_per_axis_quantized(rhs) ise quantization_dimension(rhs) = kernel_output_feature_dimension.
    • (C30) is_per_axis_quantized(result) ise quantization_dimension(result) = output_feature_dimension.
    • Eğer is_quantized(lhs):
    • (C31) storage_type(lhs) = storage_type(rhs).
    • (C32) expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
    • (C33) is_per_tensor_quantized(rhs) ise is_per_tensor_quantized(result).
    • Eğer !is_quantized(lhs):
    • (C34) element_type(lhs) = expressed_type(rhs) = element_type(result).

Örnekler

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

 Diğer Örnekler

kosinüs

Anlam bilimi

operand tensörü üzerinde element düzeyinde kosinüs işlemi gerçekleştirir ve result tensörü üretir. Öğe türüne bağlı olarak aşağıdakiler gerçekleşir:

  • Kayan noktalı sayılar için: IEEE-754'ten cos.
  • Karmaşık sayılar için: karmaşık kosinüs.
  • Kesirli türler için: dequantize_op_quantize(cosine, operand, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Sınırlamalar

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

Örnekler

// %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]]

 Diğer Örnekler

count_leading_zeros

Anlam bilimi

operand tenzorundaki baştaki sıfır bitlerinin sayısını öğe bazında sayar ve bir result tenzoru oluşturur.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tam sayı türündeki tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result tam sayı türündeki tensör (C1)

Sınırlamalar

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

Örnekler

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

 Diğer Örnekler

custom_call

Anlam bilimi

inputs ve called_computations değerini alıp results değerini döndüren uygulama tanımlı bir işlem call_target_name'ü kapsar. has_side_effect, backend_config ve api_version, uygulama tanımlı ek meta veriler sağlamak için kullanılabilir.

Şu anda bu işlem, XLA derleyicideki eşdeğer işleminin organik gelişimini yansıtan, oldukça düzensiz bir meta veri koleksiyonu içeriyor. Gelecekte bu meta verileri birleştirmeyi planlıyoruz (#741).

Girişler

Şirket Ad Tür
(I1) inputs değişken değer sayısı
(I2) call_target_name string türündeki sabit
(I3) has_side_effect i1 türündeki sabit
(I4) backend_config string türündeki sabit veya özellik sözlüğü
(I5) api_version si32 türündeki sabit
(I6) called_computations string türündeki değişken sayıda sabit

Çıkışlar

Ad Tür
results değişken değer sayısı

Örnekler

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

bölü

Anlam bilimi

Pay lhs ve bölen rhs tenörlerinin öğe bazında bölünmesini gerçekleştirir ve bir result tenörü oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • Tam sayılar için: kesirli parçalar çıkarılarak cebirsel bölümü oluşturan tam sayı bölme.
  • Kayan noktalı sayılar için: IEEE-754'ten division.
  • Karmaşık sayılar için: karmaşık bölme.
  • Kesirli türler için:
    • dequantize_op_quantize(divide, lhs, rhs, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs tam sayı, kayan nokta veya karmaşık tür ya da tensör başına miktarlandırılmış tensör tensörü (C1)
(I2) rhs tam sayı, kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result Tam sayı, kayan nokta veya karmaşık türde bir tensör ya da tensör başına kesirli tensör (C1)

Sınırlamalar

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

Örnekler

// %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]

 Diğer Örnekler

dot_general

Anlam bilimi

lhs dilimlerinin rhs dilimleriyle iç çarpımlarını hesaplar ve bir result tensörü oluşturur.

Daha resmi olarak, result[result_index] = dot_product, burada:

  • 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 Burada size(result_batching_index) = size(lhs_batching_dimensions), size(result_lhs_index) = size(lhs_result_dimensions) ve 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)).

Miktarı belirlenmiş türler için 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)) işlemini gerçekleştirir.

Karma kesirli türler için hybrid_dequantize_then_op( lambda lhs, rhs: dot_general(lhs, rhs, lhs_batching_dimensions, rhs_batching_dimensions, lhs_contracting_dimensions, rhs_contracting_dimensions, precision_config), lhs, rhs) işlemini gerçekleştirir.

precision_config, hızlandırıcı arka uçlarındaki hesaplamalar için hız ile doğruluk arasındaki dengeyi kontrol eder. Bu, aşağıdakilerden biri olabilir (şu anda bu enum değerlerinin semantikleri yeterince belirtilmemiştir ancak bu sorunu #755 ile çözmeyi planlıyoruz):

  • DEFAULT: En hızlı hesaplamadır, ancak orijinal sayıya en az doğru tahmindir.
  • HIGH: Daha yavaş hesaplama, ancak orijinal sayıya daha yakın bir yaklaşım.
  • HIGHEST: En yavaş hesaplama yöntemidir ancak orijinal sayıya en yakın yaklaşık değerdir.

DotAlgorithm, nokta işlemini uygulamak için kullanılan ve hassasiyeti de tanımlayan algoritmanın ana özelliklerini tanımlar. Algoritma özellik alanları ayarlanmışsa precision_config, DEFAULT olmalıdır. DotAlgorithms öğesinin varsayılan bir değeri yoktur. Çünkü varsayılan parametreler uygulama tarafından tanımlanmıştır. Dolayısıyla tüm nokta algoritması alanları, boş bir nokta algoritması belirtmek için None olarak ayarlanabilir. Bu algoritma, bunun yerine precision_config değerini kullanır.

DotAlgorithm alanları şunları içerir:

  • lhs_precision_type ve rhs_precision_type, işlemin sol ve sağ tarafının yuvarlandığı hassasiyettir. Hassasiyet türleri, giriş ve çıkışın depolama türlerinden bağımsızdır.
  • accumulation_type Toplama için kullanılan hassasiyet.
  • lhs_component_count, rhs_component_count ve num_primitive_operations, sol taraf ve/veya sağ tarafı birden fazla bileşene ayıran ve bu değerler üzerinde birden fazla "ilkel" nokta işlemi yapan bir algoritma uygularken geçerlidir. Bu işlemler genellikle daha yüksek bir hassasiyeti taklit etmek için yapılır (ör. Daha Yüksek Hassasiyetli Hesaplamalar İçin bfloat16 Yapay Zeka Veri Türü'nden Yararlanma: bf16_6x tf32_3x vb.). Ayrıştırma içermeyen algoritmalar için bu değerler 1 olarak ayarlanmalıdır.
  • Bazı adımlarda (ör. CUBLASLT_MATMUL_DESC_FAST_ACCUM) daha düşük hassasiyette veri toplamaya izin verilip verilmediğini belirtmek için allow_imprecise_accumulation kullanın.

Örnek DotAlgorithm özellikleri:

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


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


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

Hangi kombinasyonların desteklendiğine karar vermek uygulamalara bağlıdır. Genel olarak, StableHLO tüketicisi tarafından her algoritmanın her hızlandırıcı türünde desteklendiği garanti edilmez. Belirli bir algoritma desteklenmiyorsa alternatife geçmek yerine bir hata oluşturulmalıdır. StableHLO doğrulaması, herhangi bir donanımda desteklenmediği bilinen algoritmaların kullanılmasını önleyerek en iyi doğrulama yöntemini sunar.

Desteklenen bazı algoritma değerleri için xla_data.proto > Algorithm bölümüne bakın. 2483 numaralı destek kaydı, arka uç tarafından desteklenen algoritmalar hakkında merkezi bir doküman oluşturma planını içerir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs tensor veya tensor başına kesikli tensor (C5-C6), (C9-C10), (C12-C14), (C17-C18), (C20)
(I2) rhs tenzor veya kesirli tenzor (C7-C10), (C12-C20)
(I3) lhs_batching_dimensions si64 türündeki 1 boyutlu tensör sabiti (C1), (C3), (C5), (C9), (C12)
(I4) rhs_batching_dimensions si64 türünde 1 boyutlu tensör sabiti (C1), (C4), (C7), (C9)
(I5) lhs_contracting_dimensions si64 türünde 1 boyutlu tensör sabiti (C2), (C3), (C6), (C10)
(I6) rhs_contracting_dimensions si64 türündeki 1 boyutlu tensör sabiti (C2), (C4), (C8), (C10), (C16)
(I7) precision_config DEFAULT, HIGH ve HIGHEST türetilmiş türleri için değişken sayıda enum (C11), (C21)
(I8) lhs_precision_type floatType veya Tensorfloat32 (C21)
(I9) rhs_precision_type FloatType veya TensorFloat32 (C21)
(I10) accumulation_type FloatType veya TensorFloat32 (C21)
(I11) lhs_component_count si32 türünün sabiti (C21), (C22)
(I12) rhs_component_count si32 türünün sabiti (C21), (C23)
(I13) num_primitive_operations si32 türündeki sabit (C21), (C24)
(I14) allow_imprecise_accumulation bool türündeki sabit (C21)

Çıkışlar

Ad Tür Sınırlamalar
result tenzor veya kesirli tenzor (C12), (C14), (C18-C20)

Sınırlamalar

  • (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).
  • İşlemde miktarlandırılmamış tensörler kullanılıyorsa:
    • (C13) element_type(lhs) = element_type(rhs)
  • İşlemde nicel tensörler kullanılıyorsa:
    • (C14) is_quantized(lhs) = is_quantized(result) and is_quantized(rhs).
    • (C15) zero_points(rhs) = 0.
    • (C16) is_per_axis_quantized(rhs) ise quantization_dimension(rhs) rhs_contracting_dimensions içinde değildir.
    • is_quantized(lhs) ise:
    • (C17) storage_type(lhs) = storage_type(rhs).
    • (C18) expressed_type(lhs) = expressed_type(rhs) = expressed_type(result).
    • (C19) is_per_tensor_quantized(rhs) ise is_per_tensor_quantized(result).
    • !is_quantized(lhs) ise:
    • (C20) element_type(lhs) = expressed_type(rhs) = element_type(result).
  • !is_empty_algorithm(lhs_precision_type, rhs_precision_type, accumulation_type, lhs_component_count, rhs_component_count, num_primitive_operations allow_imprecise_accumulation) ise:
    • (C21) precision_config... = DEFAULT
    • (C22) 0 < lhs_component_count.
    • (C23) 0 < rhs_component_count.
    • (C24) 0 < num_primitive_operations.

Örnekler

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

 Diğer Örnekler

dynamic_broadcast_in_dim

Anlam bilimi

Bu işlem, broadcast_in_dim çalışma biçimiyle işlevsel olarak aynıdır ancak sonuç şekli output_dimensions aracılığıyla dinamik olarak belirtilir.

İşlemde, boyutların genişleme davranışı hakkındaki statik bilgileri ifade etmek için isteğe bağlı known_expanding_dimensions, known_nonexpanding_dimensions özellikleri de kabul edilir. Belirtilmezse tüm boyutların genişleyebileceği varsayılır.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tenzor veya kesirli tenzor (C1-C2), (C5-C6), (C9)
(I2) output_dimensions Tam sayı türündeki 1 boyutlu tenör (C7)
(I3) broadcast_dimensions Tam sayı türünde 1 boyutlu sabit tensör (C2-C6)
(I4) known_expanding_dimensions Tam sayı türündeki 1 boyutlu sabit tensör (C8-C9)
(I5) known_nonexpanding_dimensions Tam sayı türünde 1 boyutlu sabit tensör (C8-C9)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya nicel tensör (C1), (C3), (C5-C7)

Sınırlamalar

  • (C1) element_type(result) şu şekilde hesaplanır:
    • !is_per_axis_quantized(operand) ise element_type(operand).
    • element_type(operand), ancak quantization_dimension(operand), scales(operand) ve zero_points(operand) sırasıyla quantization_dimension(result), scales(result) ve zero_points(result)'den farklı olabilir.
  • (C2) size(broadcast_dimensions) = rank(operand).
  • (C3) 0 <= broadcast_dimensions < rank(result).
  • (C4) is_unique(broadcast_dimensions).
  • (C5) axes(operand) içindeki tüm d için:
    • dim(operand, d) = 1 veya
    • dim(operand, d) = dim(result, broadcast_dimensions[d]).
  • (C6) is_per_axis_quantized(result) ise:
    • quantization_dimension(result) = broadcast_dimensions[quantization_dimension(operand)].
    • dim(operand, quantization_dimension(operand)) = 1 ise scales(result)[i] = scales(operand)[0] and zero_points(result)[i] = zero_points(operand)[0] for i in range(dim(result, quantization_dimension(result))).
  • (C7) size(output_dimensions) = rank(result).
  • (C8) is_unique(known_expanding_dimensions + known_nonexpanding_dimensions).
  • (C9) 0 <= known_expanding_dimensions < rank(operand).
  • (C10) 0 <= known_nonexpanding_dimensions < rank(operand)

Örnekler

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

 Diğer Örnekler

dynamic_conv

Anlam bilimi

Bu işlem işlevsel olarak toplama işleviyle aynıdır ancak dolgu, padding aracılığıyla dinamik olarak belirtilir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs tensor veya tensor başına kesikli tensor (C1), (C10-C11), (C14) (C25), (C26-C27), (C30-C31), (C33)
(I2) rhs tensör veya nicel tensör (C1), (C14-C16), (C26-C28), (C30-C33)
(I3) padding Tam sayı türünde 2 boyutlu tensör (C4)
(I4) window_strides si64 türündeki 1 boyutlu tensör sabiti (C2-C3)
(I5) lhs_dilation si64 türündeki 1 boyutlu tensör sabiti (C5-C6)
(I6) rhs_dilation si64 türündeki 1 boyutlu tensör sabiti (C7-C8)
(I7) window_reversal i1 türünde 1 boyutlu tensör sabiti (C9)
(I8) input_batch_dimension si64 türündeki sabit (C10), (C13)
(I9) input_feature_dimension si64 türündeki sabit (C11), (C13-C14)
(I10) input_spatial_dimensions si64 türünde 1 boyutlu tensör sabiti (C12), (C13)
(I11) kernel_input_feature_dimension si64 türündeki sabit (C14), (C18)
(I12) kernel_output_feature_dimension si64 türündeki sabit (C15-C16), (C18), (C28)
(I13) kernel_spatial_dimensions si64 türündeki 1 boyutlu tensör sabiti (C17-C18)
(I14) output_batch_dimension si64 türünün sabiti (C20)
(I15) output_feature_dimension si64 türünün sabiti (C20), (C29)
(I16) output_spatial_dimensions si64 türünde 1 boyutlu tensör sabiti (C19-C20)
(I17) feature_group_count si64 türündeki sabit (C11), (C14), (C16), (C21), (C23)
(I18) batch_group_count si64 türündeki sabit (C10), (C15), (C22), (C23)
(I19) precision_config DEFAULT, HIGH ve HIGHEST türetilmiş türleri için değişken sayıda enum (C24)

Çıkışlar

Ad Tür Sınırlamalar
result tenzor veya kesirli tenzor (C25-C27), (C29), (C31-C33)

Sınırlamalar

  • (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] ile ilgili:
    • 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] ile ilgili:
    • 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] verildiğinde:
    • 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) şu şekilde tanımlanır:
    • result_dim = output_batch_dimension ise dim(lhs, input_batch_dimension) / batch_group_count.
    • result_dim = output_feature_dimension ise dim(rhs, kernel_output_feature_dimension).
    • num_windows aksi takdirde:
    • 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.
  • İşlemde miktarlandırılmamış tensörler kullanılıyorsa:
    • (C27) element_type(lhs) = element_type(rhs) = element_type(result).
  • İşlemde kesirli tenzorlar kullanılıyorsa:
    • (C28) is_quantized(lhs) = is_quantized(result) and is_quantized(rhs).
    • (C29) is_per_axis_quantized(rhs) ise quantization_dimension(rhs) = kernel_output_feature_dimension.
    • (C30) is_per_axis_quantized(result) ise quantization_dimension(result) = output_feature_dimension.
    • Eğer is_quantized(lhs):
    • (C31) storage_type(lhs) = storage_type(rhs).
    • (C32) expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
    • (C33) is_per_tensor_quantized(rhs) ise is_per_tensor_quantized(result).
    • Eğer !is_quantized(lhs):
    • (C34) element_type(lhs) = expressed_type(rhs) = element_type(result).

Örnekler

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

Diğer Örnekler

dynamic_gather

Anlam bilimi

Bu işlem, slice_sizes değeri dinamik olarak belirtildiğinde işlevsel olarak gather işlevine eşittir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tensor veya tensor başına kesikli tensor (C1), (C7), (C10-C12), (C14)
(I2) start_indices tam sayı türündeki tensör (C2), (C3), (C13)
(I3) slice_sizes Tam sayı türündeki 1 boyutlu tenör (C8), (C11-C13)
(I4) offset_dims si64 türündeki 1 boyutlu tensör sabiti (C1); (C4-C5); (C13)
(I5) collapsed_slice_dims si64 türündeki 1 boyutlu tensör sabiti (C1), (C6-C8), (C13)
(I6) start_index_map si64 türündeki 1 boyutlu tensör sabiti (C3), (C9), (C10)
(I7) index_vector_dim si64 türündeki sabit (C2), (C3), (C13)
(I8) indices_are_sorted i1 türünün sabiti

Çıkışlar

Ad Tür Sınırlamalar
result tensor veya tensor başına kesikli tensor (C5), (C13-C14)

Sınırlamalar

  • (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) burada:
    • batch_dim_sizes = shape(start_indices) dışında index_vector_dim'e karşılık gelen start_indices boyut boyutu dahil edilmemiştir.
    • offset_dim_sizes = shape(slice_sizes) dışında, slice_sizes ürününde collapsed_slice_dims'a karşılık gelen boyut boyutları dahil edilmemiştir.
    • combine, batch_dim_sizes öğesini offset_dims öğesine karşılık gelen eksenlere batch_dims ve offset_dim_sizes karşılık gelen eksenlere yerleştirir.
  • (C14) element_type(operand) = element_type(result).

Örnekler

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

Diğer Örnekler

dynamic_iota

Anlam

Bu işlem işlevsel olarak iota işlevine benzer ancak sonuç şekli output_shape aracılığıyla dinamik olarak belirtilir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) output_shape Tam sayı türündeki 1 boyutlu tenör (C1), (C2)
(I2) iota_dimension si64 (C1)

Çıkışlar

Ad Tür Sınırlamalar
result Tam sayı, kayan nokta veya karmaşık türde bir tensör ya da tensör başına kesirli tensör (C2)

Sınırlamalar

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

Örnekler

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

 Diğer Örnekler

dynamic_pad

Anlam bilimi

Bu işlem işlevsel olarak pad işlevine benzer ancak edge_padding_low, edge_padding_high ve interior_padding değerleri dinamik olarak belirtilir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tensör veya tensör başına miktarlandırılmış tensör (C1), (C2), (C4)
(I2) padding_value 0 boyutlu tensör veya tensör başına miktarlandırılmış tensör (C1)
(I3) edge_padding_low Tam sayı türündeki 1 boyutlu tenör (C1), (C4)
(I4) edge_padding_high Tam sayı türünde 1 boyutlu tensör (C1), (C4)
(I5) interior_padding Tam sayı türündeki 1 boyutlu tenör (C2-C4)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına miktarlandırılmış tensör (C3-C6)

Sınırlamalar

  • (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.

Örnekler

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

 Diğer Örnekler

dynamic_reshape

Anlam

Bu işlem işlevsel olarak reshape işleviyle aynıdır ancak sonuç şekli output_shape aracılığıyla dinamik olarak belirtilir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tenzor veya kesirli tenzor (C1-C3)
(I2) output_shape Tam sayı türünde 1 boyutlu tensör (C4)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya nicel tensör (C1-C4)

Sınırlamalar

  • (C1) element_type(result) şu şekilde hesaplanır:
    • !is_per_axis_quantized(operand) ise element_type(operand).
    • element_type(operand), ancak quantization_dimension(operand) ve quantization_dimension(result) farklı olabilir.
  • (C2) size(operand) = size(result).
  • (C3) is_per_axis_quantized(operand) ise:
    • reduce(dims(operand, [0, 1, ..., quantization_dimension(operand) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y) = reduce(dims(result, [0, 1, ..., quantization_dimension(result) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y).
    • dim(operand, quantization_dimension(operand)) = dim(result, quantization_dimension(result)).
    • reduce(dims(operand, [quantization_dimension(operand) + 1, ..., rank(operand) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y) = reduce(dims(result, [quantization_dimension(result) + 1, ..., rank(result) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y).
  • (C4) size(output_shape) = rank(result).

Örnekler

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

Diğer Örnekler

dynamic_slice

Anlam

Dinamik olarak hesaplanan başlangıç dizinlerini kullanarak operand'ten bir dilim çıkarır ve result tensörü oluşturur. start_indices, olası düzenlemeye tabi her boyut için dilimin başlangıç dizinlerini içerir ve slice_sizes, her boyuta ait dilimin boyutlarını içerir. Daha resmi bir ifadeyle, result[result_index] = operand[operand_index] burada:

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

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tensör veya tensör başına miktarlandırılmış tensör (C1), (C2), (C4)
(I2) start_indices tam sayı türündeki 0 boyutlu tensörlerin değişken sayısı (C2), (C3)
(I3) slice_sizes si64 türündeki 1 boyutlu tensör sabiti (C2), (C4), (C5)

Çıkışlar

Ad Tür Sınırlamalar
result tensor veya tensor başına kesikli tensor (C1), (C5)

Sınırlamalar

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

Örnekler

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

 Diğer Örnekler

dynamic_update_slice

Anlam bilimi

start_indices ile başlayan dilim update içindeki değerlerle güncellenmesi dışında, operand tensörüne eşit bir result tensörü oluşturur. Daha resmi bir şekilde result[result_index] şu şekilde tanımlanır:

  • 0 <= update_index < shape(update) ise update[update_index]:
    • adjusted_start_indices = clamp(0, start_indices, shape(operand) - shape(update)).
    • update_index = result_index - adjusted_start_indices.
  • Aksi takdirde operand[result_index].

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tensor veya tensor başına kesikli tensor (C1-C4); (C6)
(I2) update tensor veya tensor başına kesikli tensor (C2), (C3), (C6)
(I3) start_indices tam sayı türündeki 0 boyutlu tensörlerin değişken sayısı (C4), (C5)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına miktarlandırılmış tensör (C1)

Sınırlamalar

  • (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).

Örnekler

// %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]
//          ]

 Diğer Örnekler

üstel

Anlam bilimi

operand tenzorunda öğe bazında üstel işlem gerçekleştirir ve bir result tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • Kayan reklamlar için: IEEE-754'ten exp.
  • Karmaşık sayılar için: karmaşık üs.
  • Kesirli türler için: dequantize_op_quantize(exponential, operand, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Sınırlamalar

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

Örnekler

// %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]]

 Diğer Örnekler

exponential_minus_one

Anlam bilimi

operand tenzorunda öğe bazında üstel eksi bir işlemi gerçekleştirir ve bir result tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • Kayan noktalı sayılar için: IEEE-754'ten expm1.
  • Karmaşık sayılar için: karmaşık üssün bir eksi değeri.
  • Kesirli türler için: dequantize_op_quantize(exponential_minus_one, operand, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Sınırlamalar

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

Örnekler

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

 Diğer Örnekler

fft

Anlam bilimi

Gerçek ve karmaşık girişler/çıktılar için ileri ve ters Fourier dönüşümlerini gerçekleştirir.

fft_type aşağıdakilerden biridir:

  • FFT: Karmaşıktan karmaşığa ileri FFT.
  • IFFT: Karmaşıktan karmaşığa ters FFT.
  • RFFT: Gerçekten karmaşık FFT'ye yönlendirme.
  • IRFFT: Ters gerçeğe dayalı FFT (ör. karmaşık alır, gerçek sonucu döndürür).

Daha resmi bir ifadeyle, karmaşık türlerde 1 boyutlu tenzorları giriş olarak alan, çıkış olarak aynı türde 1 boyutlu tenzorlar üreten ve ayrık Fourier dönüşümünü hesaplayan fft işlevi verildiğinde:

fft_type = FFT için result, L = size(fft_length) olan bir dizi L hesaplamasının nihai sonucu olarak tanımlanır. Örneğin, L = 3 için:

  • 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]).

Ayrıca, aynı tür imzasına sahip olan ve fft işlevinin tersini hesaplayan ifft işlevi verildiğinde:

fft_type = IFFT için result, fft_type = FFT hesaplamalarının tersi olarak tanımlanır. Örneğin, L = 3 için:

  • 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, ..., :]).

Ayrıca, rfft işlevi, kayan nokta türünde 1 boyutlu tenzorlar alır, aynı kayan nokta semantiğine sahip karmaşık türde 1 boyutlu tenzorlar oluşturur ve aşağıdaki gibi çalışır:

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

(Dijital Fourier dönüşümü gerçek operatörler için hesaplandığında, sonucun ilk N/2 + 1 öğeleri sonucun geri kalanını açıkça tanımlar. Bu nedenle, rfft sonucu gereksiz öğelerin hesaplanmasını önlemek için kısaltılır.)

fft_type = RFFT için result, L = size(fft_length) olan bir dizi L hesaplamasının nihai sonucu olarak tanımlanır. Örneğin, L = 3 için:

  • 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]).

Son olarak, aynı tür imzaya sahip olan ve rfft işlevinin tersini hesaplayan irfft işlevine göz atalım:

fft_type = IRFFT için result, fft_type = RFFT için hesaplamaların tersi olarak tanımlanır. Örneğin, L = 3 için:

  • 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, ..., :]).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand kayan nokta veya karmaşık türde tensör (C1), (C2), (C4), (C5)
(I2) fft_type FFT, IFFT, RFFT ve IRFFT sıralaması (C2), (C5)
(I3) fft_length si64 türündeki 1 boyutlu tensör sabiti (C1), (C3), (C4)

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta veya karmaşık türde tensör (C2), (C4), (C5)

Sınırlamalar

  • (C1) size(fft_length) <= rank(operand).
  • (C2) operand ile result öğe türleri arasındaki ilişki değişiklik gösterir:
    • fft_type = FFT, element_type(operand) ve element_type(result) aynı karmaşık türe sahipse.
    • fft_type = IFFT, element_type(operand) ve element_type(result) aynı karmaşık türe sahipse.
    • fft_type = RFFT ise element_type(operand) bir kayan nokta türü, element_type(result) ise aynı kayan nokta semantiğinin karmaşık bir türüdür.
    • fft_type = IRFFT ise element_type(operand) karmaşık bir türse ve element_type(result) aynı kayan nokta anlamına sahip bir kayan nokta türüdür.
  • (C3) 1 <= size(fft_length) <= 3.
  • (C4) operand ve result arasında kayan nokta türüne sahip bir real tensörü varsa shape(real)[-size(fft_length):] = fft_length.
  • (C5) Şunlar hariç shape(result) = shape(operand):
    • fft_type = RFFT ise dim(result, -1) = dim(operand, -1) = 0 ? 0 : dim(operand, -1) / 2 + 1.
    • fft_type = IRFFT ise dim(operand, -1) = dim(result, -1) = 0 ? 0 : dim(result, -1) / 2 + 1.

Örnekler

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

kat

Anlam bilimi

Element tabanlı tabanda operand tensörü gerçekleştirir ve bir result tensörü üretir. IEEE-754 spesifikasyonundaki roundToIntegralTowardNegative işlemini uygular. Miktarı ölçülmüş türlerde, dequantize_op_quantize(floor, operand, type(result)) gerçekleştirir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand Kayan nokta türündeki veya tensör başına kesirli tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta türünde veya tensör başına miktarlandırılmış tensörün tensörü (C1)

Sınırlamalar

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

Örnekler

// %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]

 Diğer Örnekler

topla

Anlam

start_indices içinde belirtilen ofsetlerden operand tensöründen dilimleri toplar ve bir result tensörü üretir.

Aşağıdaki şemada, result öğelerinin operand öğeleriyle nasıl eşlendiği somut bir örnekle gösterilmektedir. Diyagramda birkaç örnek result dizin seçilir ve bunların hangi operand dizinlerine karşılık geldiği ayrıntılı olarak açıklanır.

topla

Daha resmi bir ifadeyle, result[result_index] = operand[operand_index] burada:

  • batch_dims = [d for d in axes(result) and d not in offset_dims].
  • batch_index = result_index[batch_dims...].
  • start_index şu şekilde tanımlanır:
    • start_indices[bi0, ..., :, ..., biN]; burada bi, batch_index içindeki bağımsız öğelerdir ve index_vector_dim < rank(start_indices) ise :, index_vector_dim dizine yerleştirilir.
    • Aksi takdirde [start_indices[batch_index]] değerini alır.
  • axes(operand) içinde d_operand için
    • 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] ise.
    • Aksi takdirde full_start_index[d_operand] = 0.
  • axes(operand) içinde d_operand için
    • full_batching_index[d_operand] = batch_index[d_start - (d_start < index_vector_dim ? 0 : 1)] d_operand = operand_batching_dims[i_batching] ve d_start = start_indices_batching_dims[i_batching] ise.
    • Aksi takdirde full_batching_index[d_operand] = 0 değerini alır.
  • offset_index = result_index[offset_dims...].
  • full_offset_index = [oi0, ..., 0, ..., oiN]; burada oi, offset_index içindeki bağımsız öğelerdir ve 0, collapsed_slice_dims ile operand_batching_dims arasındaki dizinlere eklenir.
  • operand_index = full_start_index + full_batching_index + full_offset_index.

indices_are_sorted değeri true ise uygulama, start_indices değerinin start_index_map öğesine göre sıralandığını varsayabilir. Aksi takdirde davranış tanımsızdır. Daha resmî bir şekilde ifade etmek gerekirse indices(result), full_start_index(i1) <= full_start_index(i2) tarafından sağlanan tüm i1 < i2 için.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tensor veya tensor başına kesikli tensor (C1), (C8), (C11), (C17), (C19-C21), (C23)
(I2) start_indices tam sayı türündeki tensör (C2-C3), (C14), (C17), (C22)
(I3) offset_dims si64 türündeki 1 boyutlu tensör sabiti (C1), (C4-C5), (C22)
(I4) collapsed_slice_dims si64 türündeki 1 boyutlu tensör sabiti (C1), (C6-C9), (C22)
(I5) operand_batching_dims si64 türünde 1 boyutlu tensör sabiti (C1), (C6), (C10-C12), (C16-C18), (C22)
(I6) start_indices_batching_dims si64 türündeki 1 boyutlu tensör sabiti (C13-C17)
(I7) start_index_map si64 türündeki 1 boyutlu tensör sabiti (C3), (C18-C19)
(I8) index_vector_dim si64 türünün sabiti (C2-C3), (C15), (C22)
(I9) slice_sizes si64 türünde 1 boyutlu tensör sabiti (C9), (C12), (C20-C22)
(I10) indices_are_sorted i1 türündeki sabit

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına miktarlandırılmış tensör (C5), (C22-C23)

Sınırlamalar

  • (C1) rank(operand) = size(offset_dims) + size(collapsed_slice_dims) + size(operand_batching_dims).
  • (C2) 0 <= index_vector_dim <= rank(start_indices).
  • (C3) size(start_index_map) = index_vector_dim < rank(start_indices) ? dim(start_indices, index_vector_dim) : 1.
  • (C4) is_unique(offset_dims) and is_sorted(offset_dims).
  • (C5) 0 <= offset_dims < rank(result).
  • (C6) is_unique(concatenate(collapsed_slice_dims, operand_batching_dims))
  • (C7) is_sorted(collapsed_slice_dims).
  • (C8) 0 <= collapsed_slice_dims < rank(operand)
  • (C9) slice_sizes[collapsed_slice_dims...] <= 1.
  • (C10) is_sorted(operand_batching_dims).
  • (C11) 0 <= operand_batching_dims < rank(operand).
  • (C12) slice_sizes[operand_batching_dims...] <= 1.
  • (C13) is_unique(start_indices_batching_dims).
  • (C14) 0 <= start_indices_batching_dims < rank(start_indices)
  • (C15) index_vector_dim not in start_indices_batching_dims.
  • (C16) size(operand_batching_dims) == size(start_indices_batching_dims).
  • (C17) dim(operand, operand_batching_dims...) = dim(start_indices, start_indices_batching_dims...).
  • (C18) is_unique(concatenate(start_index_map, operand_batching_dims)).
  • (C19) 0 <= start_index_map < rank(operand).
  • (C20) size(slice_sizes) = rank(operand).
  • (C21) 0 <= slice_sizes <= shape(operand).
  • (C22) shape(result) = combine(batch_dim_sizes, offset_dim_sizes); burada:
    • batch_dim_sizes = shape(start_indices), ancak index_vector_dim'ye karşılık gelen start_indices boyutu dahil değildir.
    • offset_dim_sizes = slice_sizes, ancak slice_sizes'daki collapsed_slice_dims ve operand_batching_dims'a karşılık gelen boyut boyutları dahil edilmez.
    • combine, batch_dim_sizes öğesini offset_dims öğesine karşılık gelen eksenlere batch_dims ve offset_dim_sizes karşılık gelen eksenlere yerleştirir.
  • (C23) element_type(operand) = element_type(result).

Örnekler

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

 Diğer Örnekler

get_dimension_size

Anlam bilimi

operand öğesinin belirtilen dimension boyutunu döndürür. Daha resmi ifade etmek gerekirse, result = dim(operand, dimension). Anlambilim, yalnızca türün şekil bileşeniyle ilgilidir. Öğe türü herhangi bir şey olabilir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tenzor veya kesirli tenzor (C1)
(I2) dimension si64 türünün sabiti (C1)

Çıkışlar

Ad Tür
result si32 türündeki 0 boyutlu tensör

Sınırlamalar

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

Örnekler

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

 Diğer Örnekler

get_tuple_element

Anlam bilimi

operand unsurunun index konumundaki öğeyi çıkarır ve bir result üretir. Daha resmi bir ifadeyle result = operand[index].

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tuple (C1), (C2)
(I2) index si32 türünün sabiti (C1), (C2)

Çıkışlar

Ad Tür Sınırlamalar
result Desteklenen tüm türler (C2)

Sınırlamalar

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

Örnekler

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

Diğer Örnekler

koşul:

Anlam bilimi

pred değerine bağlı olarak true_branch veya false_branch'ten tam olarak bir işlevin yürütülmesiyle elde edilen çıktıyı oluşturur. Daha resmi bir ifadeyle result = pred ? true_branch() : false_branch().

Girişler

Şirket Ad Tür Sınırlamalar
(I1) pred i1 türündeki 0 boyutlu tensör
(I2) true_branch işlev (C1-C3)
(I3) false_branch işlev (C1), (C2)

Çıkışlar

Ad Tür Sınırlamalar
results değişken sayıda tenör, kesirli tenör veya jeton (C3)

Sınırlamalar

  • (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).

Örnekler

// %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

 Diğer Örnekler

imag

Anlam bilimi

operand öğesinden sanal kısmı öğe bazında çıkarır ve bir result tensörü oluşturur. Daha resmi olarak, her öğe için x: imag(x) = is_complex(x) ? imaginary_part(x) : constant(0, element_type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand kayan nokta veya karmaşık türde tensör (C1), (C2)

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta türündeki tensör (C1), (C2)

Sınırlamalar

  • (C1) shape(result) = shape(operand).
  • (C2) element_type(result) şu şekilde tanımlanır:
    • is_complex(operand) ise complex_element_type(element_type(operand)).
    • Aksi takdirde element_type(operand) değerini alır.

Örnekler

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

 Diğer Örnekler

feed

Anlam bilimi

Giriş feed'inden verileri okur ve results oluşturur.

infeed_config semantiği uygulamaya göre tanımlanır.

results, önce gelen yük değerleri ve en son gelen bir jetondan oluşur. Gelecekte, netliği artırmak için yükü ve jetonu iki ayrı çıkışa ayırmayı planlıyoruz (#670).

Girişler

Şirket Ad Tür
(I1) token token
(I2) infeed_config string türündeki sabit

Çıkışlar

Ad Tür Sınırlamalar
results değişken sayıda tenör, kesirli tenör veya jeton (C1-C3)

Sınırlamalar

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

Örnekler

// %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]]

Diğer Örnekler

iota

Anlam

Bir output tensörünü, iota_dimension boyutu boyunca sıfırdan başlayarak artan düzende değerlerle doldurur. Daha resmi ifade etmek gerekirse

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

Girişler

Şirket Ad Tür Sınırlamalar
(I1) iota_dimension si64 (C1)

Çıkışlar

Ad Tür Sınırlamalar
output Tam sayı, kayan nokta veya karmaşık türde bir tensör ya da tensör başına kesirli tensör (C1)

Sınırlamalar

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

Örnekler

%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]
//          ]

 Diğer Örnekler

is_finite

Anlam bilimi

x'teki değerin sonlu olup olmadığını (yani +Inf, -Inf veya NaN olup olmadığını) öğe bazında kontrol eder ve bir y tensörü oluşturur. IEEE-754 spesifikasyonundaki isFinite işlemini uygular. Miktarı ölçülmüş türler için sonuç her zaman true olur.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) x Kayan nokta türündeki veya tensör başına kesirli tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
y boole türündeki tensör (C1)

Sınırlamalar

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

Örnekler

// 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]

Diğer Örnekler

log

Anlam

operand tenzorunda öğe bazında logaritma işlemi gerçekleştirir ve bir result tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • Kayan noktalı sayılar için: IEEE-754'ten log.
  • Karmaşık sayılar için: karmaşık logaritma.
  • Kesirli türler için: dequantize_op_quantize(log, operand, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Sınırlamalar

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

Örnekler

// %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]]

 Diğer Örnekler

log_plus_one

Anlam

operand tenzorunda öğe bazında logaritma artı bir işlemi gerçekleştirir ve bir result tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • Kayan reklamlar için: IEEE-754'ten logp1.
  • Karmaşık sayılar için: karmaşık logaritma artı bir.
  • Kesirli türler için: dequantize_op_quantize(log_plus_one, operand, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Sınırlamalar

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

Örnekler

// %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]

Diğer Örnekler

mantıksal

Anlam bilimi

operand tenzorunda öğe bazında mantıksal işlem gerçekleştirir ve bir result tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakiler gerçekleşir:

  • Kayan noktalı sayılar için: IEEE-754'ten division(1, addition(1, exp(-x))).
  • Karmaşık sayılar için: karmaşık mantıksal.
  • Kesirli türler için: dequantize_op_quantize(logistic, operand, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Sınırlamalar

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

Örnekler

// %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]]

 Diğer Örnekler

harita

Anlam bilimi

dimensions boyunca computation harita işlevini inputs'e uygular ve bir result tensörü oluşturur.

Daha resmi olarak, result[result_index] = computation(inputs...[result_index]).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) inputs değişken sayıda tenör veya tenör başına kesikli tenörler (C1-C4)
(I2) dimensions si64 türünde 1 boyutlu tensör sabiti (C3)
(I3) computation işlev (C4)

Çıkışlar

Ad Tür Sınırlamalar
result tensor veya tensor başına kesikli tensor (C1), (C4)

Sınırlamalar

  • (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'> türündedir (Ei = element_type(inputs[i]) ve E' = element_type(result)).

Örnekler

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

Diğer Örnekler

maksimum

Anlam

lhs ve rhs tenzorları üzerinde öğe bazında maksimum işlemi gerçekleştirir ve bir result tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • Boolelar için: mantıksal VEYA.
  • Tam sayılar için: tam sayı maksimumu.
  • Kayan reklamlar için: IEEE-754'ten maximum.
  • Karmaşık sayılar için: (real, imaginary) çifti için alfabetik sıraya göre maksimum değer. Karmaşık sayılara sıralama uygulamak şaşırtıcı anlamlar içerir. Bu nedenle, gelecekte bu işlem için karmaşık sayılar desteğini kaldırmayı planlıyoruz (#560).
  • Kesirli türler için:
    • dequantize_op_quantize(maximum, lhs, rhs, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs tensor veya tensor başına kesikli tensor (C1)
(I2) rhs tensor veya tensor başına kesikli tensor (C1)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına miktarlandırılmış tensör (C1)

Sınırlamalar

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

Örnekler

// %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]]

Diğer Örnekler

minimum

Anlam

lhs ve rhs tenzorları üzerinde öğe bazında minimum işlemi gerçekleştirir ve bir result tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • Boole değerleri için: mantıksal VE.
  • Tam sayılar için: minimum tam sayı.
  • Kayan noktalı sayılar için: IEEE-754'ten minimum.
  • Karmaşık sayılar için: (real, imaginary) çifti için alfabetik minimum. Karmaşık sayılara sıralama uygulamak şaşırtıcı anlamlar içerir. Bu nedenle, gelecekte bu işlem için karmaşık sayı desteğini kaldırmayı planlıyoruz (#560).
  • Kesirli türler için:
    • dequantize_op_quantize(minimum, lhs, rhs, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs tensor veya tensor başına kesikli tensor (C1)
(I2) rhs tensor veya tensor başına kesikli tensor (C1)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına miktarlandırılmış tensör (C1)

Sınırlamalar

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

Örnekler

// %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]]

 Diğer Örnekler

Çarpma

Anlam

İki tensör lhs ve rhs'ün öğe bazında çarpımını gerçekleştirir ve bir result tensörü oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • Boolelar için: mantıksal VE.
  • Tam sayılar için: tam sayı çarpımı.
  • Kayan noktalı sayılar için: IEEE-754'ten multiplication.
  • Karmaşık sayılar için: karmaşık çarpma.
  • Kesirli türler için:
    • dequantize_op_quantize(multiply, lhs, rhs, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs tensor veya tensor başına kesikli tensor (C1)
(I2) rhs tensor veya tensor başına kesikli tensor (C1)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına miktarlandırılmış tensör (C1)

Sınırlamalar

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

Örnekler

// %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]]

Diğer Örnekler

işareti değiştir

Anlam bilimi

operand tenzorunun öğe bazında olumsuzlamasını gerçekleştirir ve bir result tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • İşaretli tam sayılar için: Tam sayı olumsuzlama.
  • İşaretsiz tam sayılar için: işaretli tam sayıya bitcast, tam sayı reddi, işaretsiz tam sayıya geri bitcast.
  • Kayan noktalı sayılar için: IEEE-754'ten negate.
  • Karmaşık sayılar için: karmaşık reddi.
  • Kesirli türler için: dequantize_op_quantize(negate, operand, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand Tam sayı, kayan nokta veya karmaşık türde bir tensör ya da tensör başına kesirli tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result Tam sayı, kayan nokta veya karmaşık türde bir tensör ya da tensör başına kesirli tensör (C1)

Sınırlamalar

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

Örnekler

// 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]

Diğer Örnekler

değil

Anlam

operand tensörünün öğe bazında DEĞİL işlemini gerçekleştirir ve bir result tensörü oluşturur. Öğe türüne bağlı olarak aşağıdakiler gerçekleşir:

  • Boolelar için: mantıksal DEĞİL.
  • Tam sayılar için: bit tabanlı DEĞİL.

Bağımsız değişkenler

Ad Tür Sınırlamalar
operand boole veya tam sayı türündeki tenör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result boole veya tam sayı türündeki tenör (C1)

Sınırlamalar

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

Örnekler

// 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]

 Diğer Örnekler

optimization_barrier

Anlam

operand değerini üreten işlemlerin, result değerine bağlı tüm işlemlerden önce yürütülmesini sağlar ve derleyici dönüşümlerinin işlemleri engellemeye çalışmasını önler. Bunun dışında işlem bir kimliktir (ör. result = operand).

Bağımsız değişkenler

Ad Tür Sınırlamalar
operand değişken tensör, tensör başına nicel tensör veya jeton sayısı (C1)

Çıkışlar

Ad Tür Sınırlamalar
result değişken tensör, tensör başına nicel tensör veya jeton sayısı (C1)

Sınırlamalar

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

Örnekler

// %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

 Diğer Örnekler

veya

Anlam bilimi

lhs ve rhs iki tensörü için öğe düzeyinde VEYA gerçekleştirir ve bir result tensörü üretir. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • Boolelar için: mantıksal VEYA.
  • Tam sayılar için: bit tabanlı VEYA.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs tam sayı veya boole türündeki tenör (C1)
(I2) rhs tam sayı veya boole türündeki tenör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result tam sayı veya boole türündeki tenör (C1)

Sınırlamalar

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

Örnekler

// 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]]

 Diğer Örnekler

çıkış feed'i

Anlam

Çıkış feed'ine inputs yazar ve bir result jetonu oluşturur.

outfeed_config semantiği uygulamaya göre tanımlanır.

Girişler

Şirket Ad Tür
(I1) inputs değişken sayıda tensör veya kesirli tensör
(I2) token token
(I3) outfeed_config string türünün sabiti

Çıkışlar

Ad Tür
result token

Örnekler

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

 Diğer Örnekler

ped

Anlam bilimi

operand değerini, tensörün çevresindeki ve verilen padding_value değerine sahip tensör öğeleri arasındaki dolguyla genişletir.

edge_padding_low ve edge_padding_high, sırasıyla her boyutun alt ucunda (0 dizininin yanında) ve üst ucunda (en yüksek dizinin yanında) eklenen dolgu miktarını belirtir. Dolgu miktarı negatif olabilir. Burada, negatif dolgunun mutlak değeri belirtilen boyuttan kaldırılacak öğe sayısını gösterir.

interior_padding, her boyuttaki herhangi iki öğe arasına eklenen dolgu miktarını belirtir ve negatif olmayabilir. İç dolgu, kenar dolgu işleminden önce gerçekleşir. Böylece negatif kenar dolgu, iç dolgulu operatörden öğeleri kaldırır.

Daha resmi olarak, result[result_index] şu şekilde tanımlanır:

  • operand[operand_index] ise result_index = edge_padding_low + operand_index * (interior_padding + 1).
  • Aksi takdirde padding_value.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tensör veya tensör başına miktarlandırılmış tensör (C1), (C2), (C4)
(I2) padding_value 0 boyutlu tensör veya tensör başına miktarlandırılmış tensör (C1)
(I3) edge_padding_low si64 türündeki 1 boyutlu tensör sabiti (C1), (C4)
(I4) edge_padding_high si64 türünde 1 boyutlu tensör sabiti (C1), (C4)
(I5) interior_padding si64 türündeki 1 boyutlu tensör sabiti (C2-C4)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına miktarlandırılmış tensör (C3-C6)

Sınırlamalar

  • (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.

Örnekler

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

 Diğer Örnekler

partition_id

Anlam

Mevcut işlemin partition_id'ünü oluşturur.

Çıkışlar

Ad Tür
result ui32 türündeki 0 boyutlu tensör

Örnekler

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

 Diğer Örnekler

popcnt

Anlam bilimi

operand tensöründe ayarlanan bit sayısının öğe bazında sayımını yapar ve bir result tensörü üretir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tam sayı türündeki tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result tam sayı türündeki tensör (C1)

Sınırlamalar

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

Örnekler

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

 Diğer Örnekler

güç

Anlam bilimi

lhs tenzorunun rhs tenzoruyla öğe bazında üssünü alır ve bir result tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • Tam sayılar için: tam sayı üss alma.
  • Kayan reklamlar için: IEEE-754'ten pow.
  • Karmaşık sayılar için: karmaşık üs alma.
  • Miktarlanmış türler için: dequantize_op_quantize(power, lhs, rhs, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs Tam sayı, kayan nokta veya karmaşık türde bir tensör ya da tensör başına kesirli tensör (C1)
(I2) rhs Tam sayı, kayan nokta veya karmaşık türde bir tensör ya da tensör başına kesirli tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result Tam sayı, kayan nokta veya karmaşık türde bir tensör ya da tensör başına kesirli tensör (C1)

Sınırlamalar

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

Örnekler

// %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]

Diğer Örnekler

gerçek

Anlam bilimi

operand öğesinden gerçek kısmı öğe bazında ayıklayıp bir result tensörü oluşturur. Daha resmi olarak, her öğe için x: real(x) = is_complex(x) ? real_part(x) : x.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand kayan nokta veya karmaşık türde tensör (C1), (C2)

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta türündeki tensör (C1), (C2)

Sınırlamalar

  • (C1) shape(result) = shape(operand).
  • (C2) element_type(result) şu şekilde tanımlanır:
    • is_complex(operand) ise complex_element_type(element_type(operand)).
    • Aksi takdirde element_type(operand) değerini alır.

Örnekler

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

 Diğer Örnekler

recv

Anlam bilimi

channel_id içeren bir kanaldan veri alır ve results oluşturur.

is_host_transfer true ise işlem, verileri ana makineden aktarır. Aksi takdirde, başka bir cihazdan veri aktarır. Yani uygulamaya bağlıdır. Bu işaret, channel_type içinde sağlanan bilgileri yinelediği için gelecekte bunlardan yalnızca birini tutmayı planlıyoruz (#666).

results, önce gelen yük değerleri ve en son gelen bir jetondan oluşur. Gelecekte yükü ve jetonu iki ayrı çıkışa bölerek daha anlaşılır hale getirmeyi planlıyoruz (#670).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) token token (C4)
(I2) channel_id si64 türündeki sabit
(I3) channel_type DEVICE_TO_DEVICE ve HOST_TO_DEVICE türetilmiş liste (C1)
(I4) is_host_transfer i1 türündeki sabit (C1)

Çıkışlar

Ad Tür Sınırlamalar
results değişken sayıda tenör, kesirli tenör veya jeton (C2-C4)

Sınırlamalar

  • (C1) channel_type şu şekilde tanımlanır:
    • is_host_transfer = true ise HOST_TO_DEVICE,
    • Aksi takdirde DEVICE_TO_DEVICE değerini alır.
  • (C2) 0 < size(results).
  • (C3) is_empty(result[:-1]) veya is_tensor(type(results[:-1])).
  • (C4) is_token(type(results[-1])).

Örnekler

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

 Diğer Örnekler

reduce

Anlam bilimi

dimensions boyunca inputs ve init_values'ye bir azaltma işlevi body uygular ve results tenzorları oluşturur.

İndirimlerin sırası uygulama tanımlıdır. Diğer bir deyişle, işlemin tüm uygulamalarda tüm girişler için aynı sonuçları vermesini garanti etmek üzere body ve init_values bir monoid oluşturmalıdır. Ancak bu durum, birçok popüler indirim için geçerli değildir. Örneğin, body için kayan nokta toplama ve init_values için sıfır, kayan nokta toplama ilişkili olmadığından aslında bir monoid oluşturmaz.

Daha resmi bir ifadeyle, results...[j0, ..., jR-1] = reduce(input_slices_converted) burada:

  • input_slices = inputs...[j0, ..., :, ..., jR-1], : dimensions yerine eklenir.
  • 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:])...).
  • Bazı ikili ağaç türleri için reduce(input_slices_converted) = exec(schedule) schedule burada:
    • exec(node) = body(exec(node.left), exec(node.right)).
    • exec(leaf) = leaf.value.
  • schedule, sıralı traversal'ı aşağıdakilerden oluşan, uygulama tanımlı bir tam ikili ağaçtır:
    • index değerleri, index_space(input_slices_converted)'deki tüm index için index'ün artan sözlük sıralamasına göre.input_slices_converted...[index]
    • Uygulamada tanımlanan konumlarda uygulamada tanımlanan miktarda init_values_converted ile birlikte kullanılır.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) inputs değişken sayıda tenör veya tenör başına kesikli tenörler (C1-C4), (C6), (C7)
(I2) init_values 0 boyutlu tensörlerin veya tensör başına miktarlandırılmış tensörlerin değişken sayısı (C2), (C3)
(I3) dimensions si64 türündeki 1 boyutlu tensör sabiti (C4), (C5), (C7)
(I4) body işlev (C6)

Çıkışlar

Ad Tür Sınırlamalar
results değişken sayıda tenör veya tenör başına kesikli tenörler (C3), (C7), (C8)

Sınırlamalar

  • (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>, ..., türündedirtensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>) ve is_promotable(element_type(inputs[i]), Ei).
  • (C7) dimensions'ye karşılık gelen inputs... boyutlarının dahil edilmemesi dışında shape(results...) = shape(inputs...).
  • (C8) [0,N) içindeki tüm i için element_type(results[i]) = Ei.

Örnekler

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

 Diğer Örnekler

reduce_precision

Anlam

operand öğesini, exponent_bits ve mantissa_bits kullanan başka bir kayan nokta türüne ve orijinal kayan nokta türüne geri dönüştürür ve bir output tenzoru oluşturur.

Daha resmi bir dille:

  • Orijinal değerin mantisa bitleri, orijinal değeri roundToIntegralTiesToEven semantiği kullanılarak mantissa_bits ile temsil edilebilen en yakın değere yuvarlayacak şekilde güncellenir.
  • Daha sonra, mantissa_bits, orijinal değerin mantis bit sayısından küçükse mantissa bitleri mantissa_bits olacak şekilde kısaltılır.
  • Ardından, ara sonucun üssünün bitleri exponent_bits tarafından sağlanan aralığa sığmazsa ara sonuç, orijinal işareti kullanarak sonsuzluk değerine taşma veya orijinal işareti kullanarak sıfır değerine alt taşma yapar.
  • Miktarı ölçülmüş türlerde, dequantize_op_quantize( lambda operand: reduce_precision(operand, exponent_bits, mantissa_bits), operand, type(result)) gerçekleştirir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand Kayan nokta türündeki veya tensör başına kesirli tensör (C1)
(I2) exponent_bits si32 türünün sabiti (C2)
(I3) mantissa_bits si32 türünün sabiti (C3)

Çıkışlar

Ad Tür Sınırlamalar
output kayan nokta türünde veya tensör başına miktarlandırılmış tensörün tensörü (C1)

Sınırlamalar

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

Örnekler

// 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]

 Diğer Örnekler

reduce_scatter

Anlam bilimi

reduce_scatter

StableHLO işlem ızgarasındaki her işlem grubunda, her işlemden gelen operand tensörünün değerleri üzerinde computations kullanarak azaltma işlemi gerçekleştirir, azaltma sonucunu scatter_dimension boyunca parçalara ayırır ve result oluşturmak için bölünmüş parçaları işlemler arasında dağıtır.

İşlem, StableHLO süreç ızgarasını şu şekilde tanımlanan process_groups şeklinde ayırır:

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

Daha sonra, her process_group içinde:

  • 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).
  • process_group'de receiver_index = process_group.index(receiver) olan tüm sender için result@receiver = parts@sender[receiver_index].

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tensor veya tensor başına kesikli tensor (C1), (C2), (C7), (C8)
(I2) scatter_dimension si64 türündeki sabit (C1), (C2), (C8)
(I3) replica_groups si64 türündeki 2 boyutlu tensör sabit (C3-C5)
(I4) channel_id si64 türündeki sabit (C6)
(I5) use_global_device_ids i1 türündeki sabit (C6)
(I6) computation işlev (C7)

Çıkışlar

Ad Tür Sınırlamalar
result tensor veya tensor başına kesikli tensor (C8-C9)

Sınırlamalar

  • (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) şu şekilde tanımlanır:
    • cross_replica kullanılıyorsa num_replicas.
    • cross_replica_and_partition kullanılıyorsa num_replicas.
    • flattened_ids kullanılıyorsa num_processes.
  • (C5) 0 <= replica_groups < size(replica_groups)
  • (C6) use_global_device_ids = true ise channel_id > 0.
  • (C7) computation, is_promotable(element_type(operand), E) olduğunda (tensor<E>, tensor<E>) -> (tensor<E>) türüne sahiptir.
  • (C8) shape(result) = shape(operand) hariç:
    • dim(result, scatter_dimension) = dim(operand, scatter_dimension) / dim(process_groups, 1).
  • (C9) element_type(result) = E.

Örnekler

// 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]]

 Diğer Örnekler

reduce_window

Anlam bilimi

inputs ve init_values pencerelerine bir azaltma işlevi body uygular ve results değerini döndürür.

Aşağıdaki şemada, somut bir örnek kullanılarak results... içindeki öğelerin inputs... parametresinden nasıl hesaplandığı gösterilmektedir.

reduce_window

Daha resmi bir şekilde, results...[result_index] = reduce(windows, init_values, axes(inputs...), body) (reduce işlevine bakın) şu geçerlidir:

  • 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).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) inputs değişken sayıda tensör veya tensör başına miktarlandırılmış tensör (C1-C4), (C6), (C8), (C10), (C12), (C13), (C15)
(I2) init_values 0 boyutlu tensörlerin veya tensör başına kesikli tensörlerin değişken sayısı (C1), (C13)
(I3) window_dimensions si64 türünde 1 boyutlu tensör sabiti (C4), (C5), (C15)
(I4) window_strides si64 türündeki 1 boyutlu tensör sabiti (C6), (C7), (C15)
(I5) base_dilations si64 türündeki 1 boyutlu tensör sabiti (C8), (C9), (C15)
(I6) window_dilations si64 türündeki 1 boyutlu tensör sabiti (C10), (C11), (C15)
(I7) padding si64 türünde 2 boyutlu tensör sabiti (C12), (C15)
(I8) body işlev (C13)

Çıkışlar

Ad Tür Sınırlamalar
results değişken sayıda tenör veya tenör başına kesikli tenörler (C1), (C14-C16)

Sınırlamalar

  • (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>, ..., türündedir tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>) ve is_promotable(element_type(inputs[i]), Ei).
  • (C14) same(shape(results...))
  • (C15) shape(results[0]) = num_windows burada:
    • 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) [0,N) kapsamındaki tüm i için element_type(results[i]) = Ei.

Örnekler

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

Diğer Örnekler

kalan

Anlam bilimi

lhs bölen ve bölen rhs tensörlerinin öğe bazında geri kalanını gerçekleştirir ve bir result tensörü oluşturur.

Daha resmi bir ifadeyle, sonucun işareti paydan alınır ve sonucun mutlak değeri her zaman bölenin mutlak değerinden azdır. Kalan değer lhs - d * rhs olarak hesaplanır. Burada d değeri şu şekilde bulunur:

  • Tam sayılar için: stablehlo.divide(lhs, rhs).
  • Kayan reklamlar için: IEEE-754'ten, yuvarlama özelliğiyle division(lhs, rhs) roundTowardZero.
  • Karmaşık sayılar için: TBD (#997).
  • Kesirli türler için:
    • dequantize_op_quantize(remainder, lhs, rhs, type(result)).

Kayan nokta öğe türlerinde bu işlem, IEEE-754 spesifikasyonundaki remainder işleminin tersidir. Burada d, eşit ile bağlantılı olan lhs/rhs tam değerine en yakın integral değerdir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs tam sayı, kayan nokta veya karmaşık tür ya da tensör başına miktarlandırılmış tensör tensörü (C1)
(I2) rhs tam sayı, kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result tam sayı, kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Sınırlamalar

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

Örnekler

// %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]

Diğer Örnekler

replica_id

Anlam bilimi

Mevcut işlemin replica_id'ünü oluşturur.

Çıkışlar

Ad Tür
result ui32 türündeki 0 boyutlu tensör

Örnekler

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

 Diğer Örnekler

yeniden şekillendirme

Anlam bilimi

operand tenörünü result tenörüne yeniden şekillendirir. Kavramsal olarak bu, aynı standart gösterimin korunması ancak şeklin potansiyel olarak değiştirilmesi (ör. tensor<2x3xf32> yerine tensor<3x2xf32> veya tensor<6xf32>) anlamına gelir.

Daha resmi bir ifadeyle, result_index ve operand_index'nin index_space(result) ve index_space(operand)'in alfabetik sıralamasında aynı konuma sahip olduğu result[result_index] = operand[operand_index].

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tenzor veya kesirli tenzor (C1-C3)

Çıkışlar

Ad Tür Sınırlamalar
result tenzor veya kesirli tenzor (C1-C3)

Sınırlamalar

  • (C1) element_type(result) şu şekilde hesaplanır:
    • !is_per_axis_quantized(operand) ise element_type(operand).
    • element_type(operand), ancak quantization_dimension(operand) ve quantization_dimension(result) farklı olabilir.
  • (C2) size(operand) = size(result).
  • (C3) is_per_axis_quantized(operand) ise:
    • 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).

Örnekler

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

 Diğer Örnekler

geri al

Anlam bilimi

Belirtilen dimensions boyunca operand'teki öğelerin sırasını tersine çevirir ve bir result tensörü oluşturur. Daha resmi bir ifadeyle, result[result_index] = operand[operand_index] burada:

  • dimensions konumunda d ise operand_index[d] = dim(result, d) - result_index[d] - 1
  • Aksi takdirde operand_index[d] = result_index[d] değerini alır.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tensör veya tensör başına miktarlandırılmış tensör (C1), (C3)
(I2) dimensions si64 türündeki 1 boyutlu tensör sabiti (C2), (C3)

Çıkışlar

Ad Tür Sınırlamalar
result tensor veya tensor başına kesikli tensor (C1), (C3)

Sınırlamalar

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

Örnekler

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

 Diğer Örnekler

rng

Anlam

rng_distribution algoritmasını kullanarak rastgele sayılar oluşturur ve belirli bir shape şeklindeki result tensörünü üretir.

rng_distribution = UNIFORM ise [a, b) aralığı üzerindeki tek tip dağılım uygulanarak rastgele sayılar oluşturulur. a >= b ise davranış tanımlanmamıştır.

rng_distribution = NORMAL ise rastgele sayılar, ortalama = a ve standart sapma = b olan normal dağılımı izleyerek oluşturulur. b < 0 ise davranış tanımlanmamıştır.

Rastgele sayıların tam olarak nasıl oluşturulduğu, uygulama tarafından tanımlanır. Örneğin, bu modeller deterministik olabilir veya olmayabilir ve gizli durum kullanabilir veya kullanmayabilir.

Pek çok paydaşla yaptığımız görüşmelerde bu operasyon, oldukça etkili bir şekilde kullanımdan kaldırıldı. Bu nedenle gelecekte bu seçeneği kaldırmayı planlıyoruz (#597).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) a Tam sayı, boole veya kayan nokta türündeki 0 boyutlu tensör (C1), (C2)
(I2) b Tam sayı, boole veya kayan nokta türündeki 0 boyutlu tensör (C1), (C2)
(I3) shape si64 türünde 1 boyutlu tensör sabiti (C3)
(I4) rng_distribution UNIFORM ve NORMAL türetilmiş liste (C2)

Çıkışlar

Ad Tür Sınırlamalar
result tam sayı, boole veya kayan nokta türündeki tenör (C1-C3)

Sınırlamalar

  • (C1) element_type(a) = element_type(b) = element_type(result).
  • (C2) rng_distribution = NORMAL ise is_float(a).
  • (C3) shape(result) = shape.

Örnekler

// %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

Anlam bilimi

Başlangıç durumu initial_state verildiğinde, rng_algorithm sözde rastgele sayı oluşturucu algoritmasını kullanarak tekdüze rastgele bitlerle dolu bir output ve güncellenmiş bir çıkış durumu output_state döndürür. Sonucun initial_state öğesinin deterministik işlevi olacağı garanti edilir ancak uygulamalar arasında deterministik olacağı garanti edilmez.

rng_algorithm aşağıdakilerden biridir:

  • DEFAULT: Uygulama tanımlı algoritma.
  • THREE_FRY: Threefry algoritmasının uygulama tanımlı varyantı.*
  • PHILOX: Philox algoritmasının uygulama tanımlı varyantı.*

* Bkz. Salmon ve diğerleri SC 2011. Paralel rastgele sayılar: 1, 2, 3 kadar kolay.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) rng_algorithm DEFAULT, THREE_FRY ve PHILOX değerlerini içeren bir enum (C2)
(I2) initial_state ui64 türündeki 1 boyutlu tensör (C1), (C2)

Çıkışlar

Ad Tür Sınırlamalar
output_state ui64 türündeki 1 boyutlu tensör (C1)
output tam sayı veya kayan nokta türünde tensör

Sınırlamalar

  • (C1) type(initial_state) = type(output_state).
  • (C2) size(initial_state) şu şekilde tanımlanır:
    • rng_algorithm = DEFAULT durumunda uygulama tanımlanır.
    • rng_algorithm = THREE_FRY ise 2.
    • rng_algorithm = PHILOX ise 2 veya 3.

Örnekler

// %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

Anlam bilimi

operand tensöründe, sıfırdan farklı olan eşit değerleri sıfırdan farklı bir değere atayarak öğe bazında en yakın tam sayıya yuvarlama işlemi gerçekleştirir ve bir result tensörü oluşturur. IEEE-754 spesifikasyonundaki roundToIntegralTiesToAway işlemini uygular. Kesirli türler için dequantize_op_quantize(round_nearest_afz, operand, type(result)) işlemini gerçekleştirir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand Kayan nokta türündeki veya tensör başına kesirli tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta türünde veya tensör başına miktarlandırılmış tensörün tensörü (C1)

Sınırlamalar

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

Örnekler

// %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]

 Diğer Örnekler

round_nearest_even

Anlam

operand tenzorunda, en yakın tam sayıya doğru öğe bazında yuvarlama yapar ve eşitlik durumunda çift sayıya doğru yuvarlama yapar. Ardından result tenzoru oluşturur. IEEE-754 spesifikasyonundaki roundToIntegralTiesToEven işlemini uygular. Miktarı belirlenmiş türler için dequantize_op_quantize(round_nearest_even, operand, type(result)) işlemini gerçekleştirir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand Kayan nokta türündeki veya tensör başına kesirli tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta türünde veya tensör başına miktarlandırılmış tensörün tensörü (C1)

Sınırlamalar

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

Örnekler

// %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]

 Diğer Örnekler

rsqrt

Anlam

operand tensörü üzerinde element düzeyinde ters karekök işlemi gerçekleştirir ve bir result tensörü üretir. Öğe türüne bağlı olarak aşağıdakiler gerçekleşir:

  • Kayan reklamlar için: IEEE-754'ten rSqrt.
  • Karmaşık sayılar için: karmaşık ters karekökü.
  • Kesirli türler için: dequantize_op_quantize(rsqrt, operand, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Sınırlamalar

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

Örnekler

// %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]]

 Diğer Örnekler

dağılım

Anlam bilimi

scatter_indices tarafından belirtilen birkaç dilimin update_computation kullanılarak updates değerleriyle güncellenmesi dışında inputs tenörlerine eşit results tenörleri oluşturur.

Aşağıdaki şemada, updates... öğelerinin results... öğeleriyle nasıl eşlendiği somut bir örnekle gösterilmektedir. Diyagramda birkaç örnek updates... dizini seçilir ve bu dizinlerin hangi results... dizinlerine karşılık geldiği ayrıntılı olarak açıklanır.

dağılım

Daha resmi bir ifadeyle, index_space(updates[0]) içindeki tüm update_index için:

  • 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 şu şekilde tanımlanır:
    • scatter_indices[si0, ..., :, ..., siN]; burada si, update_scatter_index içindeki bağımsız öğelerdir ve :, index_vector_dim < rank(scatter_indices) ise index_vector_dim dizinine eklenir.
    • Aksi takdirde [scatter_indices[update_scatter_index]].
  • axes(inputs[0]) içinde d_input için
    • full_start_index[d_input] = start_index[d_start] ise d_input = scatter_dims_to_operand_dims[d_start].
    • Aksi takdirde full_start_index[d_input] = 0 değerini alır.
  • axes(inputs[0]) içinde d_input için
    • full_batching_index[d_input] = update_scatter_index[d_start - (d_start < index_vector_dim ? 0 : 1)] d_input = input_batching_dims[i_batching] ve d_start = scatter_indices_batching_dims[i_batching] ise.
    • Aksi takdirde full_batching_index[d_input] = 0 değerini alır.
  • update_window_index = update_index[update_window_dims...].
  • full_window_index = [wi0, ..., 0, ..., wiN]; burada wi, update_window_index içindeki bağımsız öğelerdir ve 0, inserted_window_dims ile input_batching_dims arasındaki dizinlere eklenir.
  • result_index = full_start_index + full_batching_index + full_window_index.

Bu durumda results = exec(schedule, inputs), şu şekilde tanımlanır:

  • schedule, index_space(updates[0]) öğesinin uygulama tanımlı bir permütasyonudur.
  • exec([update_index, ...], results) = exec([...], updated_results) where:
    • result_index, shape(results...) için sınırların içindeyse
    • 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...[result_index] updated_values... olarak ayarlanmış results'un bir kopyasıdır.
    • Aksi halde
    • updated_results = results.
  • exec([], results) = results.

indices_are_sorted değeri true ise uygulama, scatter_indices öğesinin scatter_dims_to_operand_dims ile göreceli olarak sıralandığını varsayabilir. Aksi takdirde davranış tanımlanmamış olur. Daha resmi bir ifadeyle, indices(result) kaynağından gelen tüm i1 < i2 için full_start_index(i1) <= full_start_index(i2).

unique_indices true ise uygulama, dağıtılan tüm result_index dizinlerinin benzersiz olduğunu varsayabilir. unique_indices değeri true ise ancak dağıtılan dizinler benzersiz değilse davranış tanımsızdır.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) inputs değişken sayıda tenör veya tenör başına kesikli tenörler (C1), (C2), (C4-C6), (C11), (C13), (C18), (C21), (C23-C24)
(I2) scatter_indices tam sayı türündeki tensör (C4), (C15), (C19), (C22)
(I3) updates değişken sayıda tensör veya tensör başına miktarlandırılmış tensör (C3-C6), (C8)
(I4) update_window_dims si64 türündeki 1 boyutlu tensör sabiti (C2), (C4), (C7-C8)
(I5) inserted_window_dims si64 türünde 1 boyutlu tensör sabiti (C2), (C4), (C9-C11)
(I6) input_batching_dims si64 türündeki 1 boyutlu tensör sabiti (C2), (C4), (C9), (C12-13), (C17-18), (C20)
(I7) scatter_indices_batching_dims si64 türündeki 1 boyutlu tensör sabiti (C14-C18)
(I8) scatter_dims_to_operand_dims si64 türündeki 1 boyutlu tensör sabiti (C19-C21)
(I9) index_vector_dim si64 türündeki sabit (C4), (C16), (C19), (C22)
(I10) indices_are_sorted i1 türündeki sabit
(I11) unique_indices i1 türündeki sabit
(I12) update_computation işlev (C23)

Çıkışlar

Ad Tür Sınırlamalar
results değişken sayıda tensör veya tensör başına miktarlandırılmış tensör (C24-C25)

Sınırlamalar

  • (C1) same(shape(inputs...)).
  • (C2) `rank(inputs[0]) = boyut(update_window_dims) + boyut(inserted_window_dims)
    • size(input_batching_dims)`.
  • (C3) same(shape(updates...)).
  • (C4) shape(updates[0]) = combine(update_scatter_dim_sizes, update_window_dim_sizes); burada:
    • update_scatter_dim_sizes = shape(scatter_indices) dışında index_vector_dim'e karşılık gelen scatter_indices boyut boyutu dahil edilmemiştir.
    • update_window_dim_sizes <= shape(inputs[0]), ancak inputs[0]'daki inserted_window_dims ve input_batching_dims'a karşılık gelen boyut boyutları dahil edilmez.
    • combine, update_scatter_dim_sizes öğesini update_window_dims öğesine karşılık gelen eksenlere update_scatter_dims ve update_window_dim_sizes karşılık gelen eksenlere yerleştirir.
  • (C5) 0 < size(inputs) = size(updates) = N
  • (C6) element_type(updates...) = element_type(inputs...).
  • (C7) is_unique(update_window_dims) and is_sorted(update_window_dims).
  • (C8) 0 <= update_window_dims < rank(updates[0])
  • (C9) is_unique(concatenate(inserted_window_dims, input_batching_dims))
  • (C10) is_sorted(inserted_window_dims).
  • (C11) 0 <= inserted_window_dims < rank(inputs[0]).
  • (C12) is_sorted(input_batching_dims).
  • (C13) 0 <= input_batching_dims < rank(inputs[0]))
  • (C14) is_unique(scatter_indices_batching_dims).
  • (C15) 0 <= scatter_indices_batching_dims < rank(scatter_indices).
  • (C16) index_vector_dim not in scatter_indices_batching_dims.
  • (C17) size(input_batching_dims) == size(scatter_indices_batching_dims)
  • (C18) dim(inputs[0], input_batching_dims...) = dim(scatter_indices, scatter_indices_batching_dims...).
  • (C19) size(scatter_dims_to_operand_dims) = index_vector_dim < rank(scatter_indices) ? dim(scatter_indices, index_vector_dim) : 1.
  • (C20) is_unique(concatenate(scatter_dims_to_operand_dims, input_batching_dims)).
  • (C21) 0 <= scatter_dims_to_operand_dims < rank(inputs[0]).
  • (C22) 0 <= index_vector_dim <= rank(scatter_indices).
  • (C23) update_computation, is_promotable(element_type(inputs[i]), Ei) olduğunda (tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ..., tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>) türündedir.
  • (C24) shape(inputs...) = shape(results...).
  • (C25) [0,N) içindeki tüm i için element_type(results[i]) = Ei.

Örnekler

// %input: [
//          [
//           [[1, 2], [3, 4], [5, 6], [7, 8]],
//           [[9, 10],[11, 12], [13, 14], [15, 16]],
//           [[17, 18], [19, 20], [21, 22], [23, 24]]
//          ],
//          [
//           [[25, 26], [27, 28], [29, 30], [31, 32]],
//           [[33, 34], [35, 36], [37, 38], [39, 40]],
//           [[41, 42], [43, 44], [45, 46], [47, 48]]
//          ]
//         ]
// %scatter_indices: [
//                    [
//                     [[0, 0], [1, 0], [2, 1]],
//                     [[0, 1], [1, 1], [0, 9]]
//                    ],
//                    [
//                     [[0, 0], [2, 1], [2, 2]],
//                     [[1, 2], [0, 1], [1, 0]]
//                    ]
//                   ]
// %update: [
//           [
//            [[1, 1], [1, 1], [1, 1]],
//            [[1, 1], [1, 1], [1, 1]]
//           ],
//           [
//            [[1, 1], [1, 1], [1, 1]],
//            [[1, 1], [1, 1], [1, 1]]
//           ]
//          ]
%result = "stablehlo.scatter"(%input, %scatter_indices, %update) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
    "stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
  scatter_dimension_numbers = #stablehlo.scatter<
    update_window_dims = [3, 4],
    inserted_window_dims = [1],
    input_batching_dims = [0],
    scatter_indices_batching_dims = [1],
    scatter_dims_to_operand_dims = [2, 1],
    index_vector_dim = 3>,
  indices_are_sorted = false,
  unique_indices = false
} : (tensor<2x3x4x2xi64>, tensor<2x2x3x2xi64>, tensor<2x2x3x2x2xi64>) -> tensor<2x3x4x2xi64>
// %result: [
//           [
//            [[3, 4], [6, 7], [6, 7], [7, 8]],
//            [[9, 10],[11, 12], [15, 16], [17, 18]],
//            [[17, 18], [19, 20], [22, 23], [24, 25]]
//           ],
//           [
//            [[25, 26], [28, 29], [30, 31], [31, 32]],
//            [[35, 36], [38, 39], [38, 39], [39, 40]],
//            [[41, 42], [44, 45], [46, 47], [47, 48]]
//           ]
//          ]

 Diğer Örnekler

seç

Anlam bilimi

Her bir öğenin pred'daki ilgili öğenin değerine göre on_true veya on_false tenzorundan seçildiği bir result tenzoru oluşturur. Daha resmi olarak, result[result_index] = pred_element ? on_true[result_index] : on_false[result_index] (pred_element = rank(pred) = 0 ? pred[] : pred[result_index]). Miktarı ölçülmüş türlerde, dequantize_select_quantize(pred, on_true, on_false, type(result)) gerçekleştirir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) pred i1 türündeki tensör (C1)
(I2) on_true tensor veya tensor başına kesikli tensor (C1-C2)
(I3) on_false tensör veya tensör başına miktarlandırılmış tensör (C2)

Çıkışlar

Ad Tür Sınırlamalar
result tensor veya tensor başına kesikli tensor (C2)

Sınırlamalar

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

Örnekler

// %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]]

 Diğer Örnekler

select_and_scatter

Anlam bilimi

select kullanarak input tensöründen reduce_window sonucuna göre scatter kullanarak source tensöründen gelen değerleri dağıtır ve bir result tensörü üretir.

Aşağıdaki şemada, result öğelerinin operand ve source'den nasıl hesaplandığı somut bir örnekle gösterilmektedir.

select_and_scatter

Daha resmi bir dille:

  • selected_values = reduce_window_without_init(...) aşağıdaki girişlerle:

    • inputs = [operand].
    • window_dimensions, window_strides ve padding, olduğu gibi kullanılır.
    • base_dilations = windows_dilations = 1.
    • body şu şekilde tanımlanır:
    def body(arg0: tensor<E>, arg1: tensor<E>) -> tensor<E>:
      return select(arg0, arg1) ? arg0 : arg1;
    

    Burada E = element_type(operand) ve reduce_window_without_init, temel reduce'in schedule (reduce bölümüne bakın) özelliğinin ilk değer içermemesi dışında reduce_window gibi çalışır. İlgili pencerede değer yoksa ne olacağı şu anda belirtilmemiştir (#731).

  • result[result_index] = reduce([source_values], [init_value], [0], scatter) Burada:

    • source_values = [source[source_index] for source_index in source_indices].
    • selected_values[source_index], operand_index kaynağından operand öğesine sahipse selected_index(source_index) = operand_index.
    • source_indices = [source_index for source_index in indices(source) if selected_index(source_index) = result_index].

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tensor veya tensor başına kesikli tensor (C1-C4), (C6), (C8-C11)
(I2) source tensör veya tensör başına miktarlandırılmış tensör (C1), (C2)
(I3) init_value 0 boyutlu tensör veya tensör başına miktarlandırılmış tensör (C3)
(I4) window_dimensions si64 türündeki 1 boyutlu tensör sabiti (C2), (C4), (C5)
(I5) window_strides si64 türündeki 1 boyutlu tensör sabiti (C2), (C6), (C7)
(I6) padding si64 türündeki 2 boyutlu tensör sabit (C2), (C8)
(I7) select işlev (C9)
(I8) scatter işlev (C10)

Çıkışlar

Ad Tür Sınırlamalar
result tensor veya tensor başına kesikli tensor (C11-C12)

Sınırlamalar

  • (C1) element_type(operand) = element_type(source).
  • (C2) shape(source) = num_windows burada:
    • 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, E = element_type(operand) olduğunda (tensor<E>, tensor<E>) -> tensor<i1> türüne sahiptir.
  • (C10) scatter, is_promotable(element_type(operand), E) olduğunda (tensor<E>, tensor<E>) -> tensor<E> türüne sahiptir.
  • (C11) shape(operand) = shape(result).
  • (C12) element_type(result) = E

Örnekler

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

 Diğer Örnekler

gönder

Anlam bilimi

channel_id kanalına inputs gönderir ve result jetonu oluşturur.

is_host_transfer true ise işlem, verileri ana makineye aktarır. Aksi takdirde veriler başka bir cihaza aktarılır. Bunun anlamı, uygulama tanımlıdır. Bu işaret, channel_type alanında sağlanan bilgileri kopyalar. Bu nedenle, gelecekte bunlardan yalnızca birini (#666) kullanmayı planlıyoruz.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) inputs değişken sayıda tensör veya kesirli tensör
(I2) token token
(I3) channel_id si64 türünün sabiti
(I4) channel_type DEVICE_TO_DEVICE ve DEVICE_TO_HOST türetilmiş liste (C1)
(I5) is_host_transfer i1 türündeki sabit (C1)

Çıkışlar

Ad Tür
result token

Sınırlamalar

  • (C1) channel_type şu şekilde tanımlanır:
    • is_host_transfer = true ise DEVICE_TO_HOST,
    • Aksi takdirde DEVICE_TO_DEVICE değerini alır.

Örnekler

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

 Diğer Örnekler

shift_left

Anlam

lhs tensörü üzerinde rhs bit sayısı kadar öğe düzeyinde sol kayma işlemi gerçekleştirir ve bir result tensörü üretir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs tam sayı türündeki tensör (C1)
(I2) rhs tam sayı türündeki tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result tam sayı türündeki tensör (C1)

Sınırlamalar

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

Örnekler

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

Diğer Örnekler

shift_right_arithmetic

Anlam bilimi

lhs tensöründe rhs bit sayısı kadar öğe bazında aritmetik sağ kaydırma işlemi gerçekleştirir ve bir result tensörü oluşturur.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs tam sayı türündeki tensör (C1)
(I2) rhs tam sayı türündeki tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result tam sayı türündeki tensör (C1)

Sınırlamalar

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

Örnekler

// %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]

 Diğer Örnekler

shift_right_logical

Anlam bilimi

lhs tensöründe rhs bit sayısı kadar öğe bazında mantıksal sağ kaydırma işlemi gerçekleştirir ve bir result tensörü oluşturur.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs tam sayı türündeki tensör (C1)
(I2) rhs tam sayı türündeki tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result tam sayı türündeki tensör (C1)

Sınırlamalar

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

Örnekler

// %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]

Diğer Örnekler

işaret

Anlam bilimi

operand öğesinin işaretini döndürür ve bir result tensörü oluşturur. Daha resmi bir şekilde, her x öğesi için anlamlar Python söz dizimi kullanılarak aşağıdaki gibi ifade edilebilir:

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

Miktarı ölçülmüş türlerde, dequantize_op_quantize(sign, operand, type(result)) gerçekleştirir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand işaretli tam sayı, kayan nokta veya karmaşık tür ya da tensör başına miktarlandırılmış tensörün tensörü (C1)

Çıkışlar

Ad Tür Sınırlamalar
result işaretli tam sayı, kayan nokta veya karmaşık türde veya tensör başına kesirli tensör (C1)

Sınırlamalar

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

Örnekler

// 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]

Diğer Örnekler

sinüs

Anlam

operand tenzorunda öğe bazında sinüs işlemi gerçekleştirir ve bir result tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • Kayan noktalı sayılar için: IEEE-754'ten sin.
  • Karmaşık sayılar için: karmaşık sinüs.
  • Kesirli türler için: dequantize_op_quantize(sine, operand, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Sınırlamalar

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

Örnekler

// %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]]

 Diğer Örnekler

slice

Anlam bilimi

Statik olarak hesaplanmış başlangıç dizinlerini kullanarak operand öğesinden bir dilim çıkarır ve bir result tensörü üretir. start_indices, her boyut için dilimin başlangıç dizinlerini, limit_indices her boyut için dilimin bitiş dizinlerini (hariç) ve strides her boyut için adımlara sahiptir.

Daha resmi bir ifadeyle, result[result_index] = operand[operand_index] where operand_index = start_indices + result_index * strides.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tensör veya tensör başına miktarlandırılmış tensör (C1-C3); (C5)
(I2) start_indices si64 türünde 1 boyutlu tensör sabiti (C2), (C3), (C5)
(I3) limit_indices si64 türündeki 1 boyutlu tensör sabiti (C2), (C3), (C5)
(I4) strides si64 türündeki 1 boyutlu tensör sabiti (C2), (C4)

Çıkışlar

Ad Tür Sınırlamalar
result tensor veya tensor başına kesikli tensor (C1), (C5)

Sınırlamalar

  • (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).

Örnekler

// %operand: [
//            [0, 0, 0, 0],
//            [0, 0, 1, 1],
//            [0, 0, 1, 1]
//           ]
%result = "stablehlo.slice"(%operand) {
  start_indices = array<i64: 1, 2>,
  limit_indices = array<i64: 3, 4>,
  strides = array<i64: 1, 1>
} : (tensor<3x4xi64>) -> tensor<2x2xi64>
// % result: [
//            [1, 1],
//            [1, 1]
//           ]

 Diğer Örnekler

sıralama

Anlam

inputs'ün 1 boyutlu dilimlerini dimension boyutu boyunca birlikte, bir comparator'ye göre sıralar ve results oluşturur.

Diğer işlemlerdeki benzer girişlerin aksine dimension, aşağıda açıklanan semantikle birlikte negatif değerlere izin verir. Gelecekte tutarlılık nedeniyle buna izin verilmeyebilir (#1377).

is_stable doğruysa sıralama kararlıdır. Yani karşılaştırıcı tarafından eşit kabul edilen öğelerin göreceli sırası korunur. Tek bir girişin olduğu durumda, iki öğe e1 ve e2, karşılaştırıcı tarafından comparator(e1, e2) = comparator(e2, e1) = false ise ve yalnızca bu durumda eşit olarak kabul edilir. Bunun birden çok girdiye nasıl genelleştiğini öğrenmek için aşağıdaki resmileştirmeye bakın.

Daha resmi bir ifadeyle, index_space(results[0]) içindeki tüm result_index için:

  • adjusted_dimension = dimension >= 0 ? dimension : rank(inputs[0]) + dimension.
  • result_slice = [ri0, ..., :, ..., riR-1]; burada riN, result_index'deki bağımsız öğelerdir ve :, adjusted_dimension'e eklenir.
  • inputs_together = (inputs[0]..., ..., inputs[N-1]...).
  • results_together[result_slice] = sort(inputs_together[result_slice], comparator_together).
  • Burada sort, 1 boyutlu bir dilimi azalan olmayan düzende sıralar. comparator_together, sol taraftaki bağımsız değişken sağ taraftaki ikinci bağımsız değişkenden azsa true döndürür.
  • 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.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) inputs değişken sayıda tenör veya tenör başına kesikli tenörler (C1-C5)
(I2) dimension si64 türündeki sabit (C4)
(I3) is_stable i1 türündeki sabit
(I4) comparator işlev (C5)

Çıkışlar

Ad Tür Sınırlamalar
results değişken sayıda tenör veya tenör başına kesikli tenörler (C2), (C3)

Sınırlamalar

  • (C1) 0 < size(inputs).
  • (C2) type(inputs...) = type(results...).
  • (C3) same(shape(inputs...) + shape(results...)).
  • (C4) -R <= dimension < R, burada R = rank(inputs[0]).
  • (C5) comparator, (tensor<E1>, tensor<E1>, ..., tensor<EN-1>, tensor<EN-1>) -> tensor<i1> türünde (Ei = element_type(inputs[i])).

Örnekler

// %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]]

 Diğer Örnekler

sqrt

Anlam bilimi

operand tenzorunda öğe bazında karekök işlemi gerçekleştirir ve result tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • Kayan noktalı sayılar için: IEEE-754'ten squareRoot.
  • Karmaşık sayılar için: karmaşık karekökü.
  • Kesirli türler için: dequantize_op_quantize(sqrt, operand, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Sınırlamalar

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

Örnekler

// %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]]

 Diğer Örnekler

çıkarma

Anlam bilimi

İki tenzor lhs ve rhs'un öğe bazında çıkarımını gerçekleştirir ve bir result tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • Tam sayılar için: tam sayı çıkarma.
  • Kayan noktalı sayılar için: IEEE-754'ten subtraction.
  • Karmaşık sayılar için: karmaşık çıkarma.
  • Kesirli türler için:
    • dequantize_op_quantize(subtract, lhs, rhs, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs Tam sayı, kayan nokta veya karmaşık türde bir tensör ya da tensör başına kesirli tensör (C1)
(I2) rhs Tam sayı, kayan nokta veya karmaşık türde bir tensör ya da tensör başına kesirli tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result Tam sayı, kayan nokta veya karmaşık türde bir tensör ya da tensör başına kesirli tensör (C1)

Sınırlamalar

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

Örnekler

// %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]]

 Diğer Örnekler

tan

Anlam

operand tensöründe öğe bazında tanjant işlemi gerçekleştirir ve bir result tensörü oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • Kayan noktalı sayılar için: IEEE-754'ten tan.
  • Karmaşık sayılar için: karmaşık tanjant.
  • Kesirli türler için: dequantize_op_quantize(tan, operand, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Sınırlamalar

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

Örnekler

// %operand: [
//            [0.0, 1.57079632],       // [0, pi/2]
//            [3.14159265, 4.71238898] // [pi, 3pi/2]
//           ]
%result = "stablehlo.tan"(%operand) : (tensor<2x2xf64>) -> tensor<2x2xf64>
// %result: [
//           [0.0, 1.63312e+16],
//           [0.0, 5.44375e+15]
//          ]

 Diğer Örnekler

tanh

Anlam bilimi

operand tensörü üzerinde element düzeyinde hiperbolik tanjant işlemi gerçekleştirir ve result tensörü üretir. Öğe türüne bağlı olarak aşağıdakiler gerçekleşir:

  • Kayan noktalı sayılar için: IEEE-754'ten tanh.
  • Karmaşık sayılar için: karmaşık hiperbolik tanjant.
  • Miktarlanmış türler için:
    • dequantize_op_quantize(tanh, operand, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Sınırlamalar

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

Örnekler

// %operand: [-1.0, 0.0, 1.0]
%result = "stablehlo.tanh"(%operand) : (tensor<3xf32>) -> tensor<3xf32>
// %result: [-0.76159416, 0.0, 0.76159416]

Diğer Örnekler

transpoze

Anlam bilimi

permutation kullanarak operand tensörünün boyutlarını korur ve result tensörü üretir. Daha resmi bir ifadeyle, result[result_index] = operand[operand_index] burada result_index[d] = operand_index[permutation[d]].

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tenzor veya kesirli tenzor (C1-C4)
(I2) permutation si64 türündeki 1 boyutlu tensör sabiti (C2-C4)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya nicel tensör (C1), (C3-C4)

Sınırlamalar

  • (C1) element_type(result) şu şekilde hesaplanır:
    • !is_per_axis_quantized(operand) ise element_type(operand).
    • element_type(operand), ancak quantization_dimension(operand) ve quantization_dimension(result) farklı olabilir.
  • (C2) permutation, range(rank(operand))'un bir permütasyonudur.
  • (C3) shape(result) = dim(operand, permutation...).
  • (C4) is_per_axis_quantized(result) ise quantization_dimension(operand) = permutation(quantization_dimension(result)).

Örnekler

// %operand: [
//            [[1,2], [3,4], [5,6]],
//            [[7,8], [9,10], [11,12]]
//           ]
%result = "stablehlo.transpose"(%operand) {
  permutation = array<i64: 2, 1, 0>
} : (tensor<2x3x2xi32>) -> tensor<2x3x2xi32>
// %result: [
//           [[1,7], [3,9], [5,11]],
//           [[2,8], [4,10], [6,12]]
//          ]

Diğer Örnekler

triangular_solve

Anlam bilimi

Alt veya üst üçgen katsayı matrislerine sahip doğrusal denklem sistemleri gruplarını çözer.

Daha resmi olmak gerekirse a ve b için result[i0, ..., iR-3, :, :], left_side true olduğunda x * op(a[i0, ..., iR-3, :, :]) = b[i0, ..., iR-3, :, :] veya left_side false olduğunda op(a[i0, ..., iR-3, :, :]) * x = b[i0, ..., iR-3, :, :] için çözümdür. op(a), transpose_a ile belirlendiği x değişkenini bulur. Bu değişken aşağıdakilerden biri olabilir:

  • NO_TRANSPOSE: a'u olduğu gibi kullanarak işlemi gerçekleştirin.
  • TRANSPOSE: İşlemi a'un transpozesiyle gerçekleştirin.
  • ADJOINT: İşlemi a'un eşlenik transpozu üzerinde gerçekleştirir.

Giriş verileri, lower true ise yalnızca a'ün alt üçgeninden, aksi takdirde a'ün üst üçgeninden okunur. Çıkış verileri aynı üçgende döndürülür; diğer üçgendeki değerler uygulama tanımlıdır.

unit_diagonal doğruysa uygulama, a'un köşegen öğelerinin 1'e eşit olduğunu varsayabilir. Aksi takdirde davranış tanımlanmaz.

Miktarı belirlenmiş türler için dequantize_op_quantize(lambda x, y: triangular_solve(x, y, left_side, lower, unit_diagonal, transpose_a), a, b, type(result)) işlemini gerçekleştirir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) a kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1-C3)
(I2) b kayan nokta veya karmaşık tür ya da tensör başına miktarlandırılmış tensör tensörü (C1-C4)
(I3) left_side i1 türündeki sabit (C3)
(I4) lower i1 türündeki sabit
(I5) unit_diagonal i1 türünün sabiti
(I6) transpose_a NO_TRANSPOSE, TRANSPOSE ve ADJOINT değerlerini içeren bir enum

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör (C1)

Sınırlamalar

  • (C1) baseline_element_type(a) = baseline_element_type(b).
  • (C2) 2 <= rank(a) = rank(b) = R.
  • (C3) shape(a) ile shape(b) arasındaki ilişki aşağıdaki gibi tanımlanır:
    • 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).

Örnekler

// %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

Anlam bilimi

val değerlerinden bir result tuple oluşturur.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) val değişken değer sayısı (C1)

Çıkışlar

Ad Tür Sınırlamalar
result tuple (C1)

Sınırlamalar

  • (C1) result, Ei = type(val[i]) olduğunda tuple<E0, ..., EN-1> türüne sahiptir.

Örnekler

// %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))

 Diğer Örnekler

uniform_dequantize

Anlam

operand türü tarafından tanımlanan niceleme parametrelerine göre, miktarlandırılmış operand tensörü result ile kayan nokta tensörüne öğe düzeyinde dönüştürme yapar.

Daha resmi bir ifadeyle result = dequantize(operand).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand nicel tensör (C1), (C2)

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta türündeki tensör (C1), (C2)

Sınırlamalar

  • (C1) shape(operand) = shape(result).
  • (C2) element_type(result) = expressed_type(operand).

Örnekler

// %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

Anlam

result türü tarafından tanımlanan kesme noktaları parametrelerine göre, kayan noktalı tenzor veya kesikli tenzor operand'ü kesikli tenzor result'a öğe bazında dönüştürür.

Daha resmi bir dille,

  • is_float(operand) ise:
    • result = quantize(operand, type(result)).
  • is_quantized(operand) ise:
    • float_result = dequantize(operand).
    • result = quantize(float_result, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand kayan nokta veya kesirli türde bir tenör (C1), (C2)

Çıkışlar

Ad Tür Sınırlamalar
result kesirli tensör (C1), (C2)

Sınırlamalar

  • (C1) shape(operand) = shape(result).
  • (C2) expressed_type(result) = is_float(operand) ? element_type(operand) : expressed_type(operand).

Örnekler

// %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]

iken

Anlam

cond işlevi true çıktısını verirken body işlevinin yürütülmesinden elde edilen çıktıyı 0 veya daha fazla kez üretir. Daha resmi bir şekilde, semantikler Python söz dizimini kullanarak aşağıdaki gibi ifade edilebilir:

internal_state = operand
while cond(*internal_state):
  internal_state = body(*internal_state)
results = internal_state

Sonsuz döngünün davranışı TBD'dir (#383).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand değişken sayıda tenör, kesirli tenör veya jeton (C1-C3)
(I2) cond işlev (C1)
(I3) body işlev (C2)

Çıkışlar

Ad Tür Sınırlamalar
results değişken sayıda tenör, kesirli tenör veya jeton (C3)

Sınırlamalar

  • (C1) cond, Ti = type(operand[i]) olduğunda (T0, ..., TN-1) -> tensor<i1> türündedir.
  • (C2) body, Ti = type(operand[i]) olduğunda (T0, ..., TN-1) -> (T0, ..., TN-1) türündedir.
  • (C3) type(results...) = type(operand...).

Örnekler

// %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

 Diğer Örnekler

xor

Anlam bilimi

İki lhs ve rhs tensörü için öğe tabanlı XOR gerçekleştirir ve bir result tensörü üretir. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • Boole değerleri için: mantıksal VEYA.
  • Tam sayılar için: bit tabanlı XOR.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs boole veya tam sayı türündeki tenör (C1)
(I2) rhs boole veya tam sayı türündeki tensor (C1)

Çıkışlar

Ad Tür Sınırlamalar
result boole veya tam sayı türündeki tenör (C1)

Sınırlamalar

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

Örnekler

// 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]]

 Diğer Örnekler

Lehçe birlikte çalışabilirliği

Şu anda kullanımdaki StableHLO programları bazen StableHLO tarafından tanımlanmayan işlemler içeriyor.

Modül, İşlev, Arama ve İade

StableHLO, ModuleOp, FuncOp, CallOp ve ReturnOp için yayın öncesi MLIR işlemlerini kullanır. FuncOp ve ModuleOp'u hedefleyen birçok faydalı geçiş yazıldığından ve birçok derleme ardışık düzeninde bu işlemlerin mevcut olması beklendiğinden bu, mevcut MLIR makineleriyle daha iyi birlikte çalışmak için yapıldı. Bu işlemlere tam uyumluluk garantileri uygulanır. Bu işlemlerle ilgili uyumlu olmayan bir değişiklik (ör. kaldırma) olursa uyumluluğu korumak için StableHLO eşdeğerleri eklenir.

CHLO

CHLO opset'i, StableHLO'ya ayrıştırılan daha yüksek düzey işlemler içerir. Şu anda CHLO için uyumluluk garantisi yoktur. Uyumluluk garantileri için serileştirmeden önce chlo-legalize-to-stablehlo geçişi kullanılmalıdır.

Şekil İşlemleri

Şekil hesaplamaları yapmak için dinamik StableHLO programlarında temel MLIR lehçelerinden belirli işlemleri kullanmak, toplulukta yaygın bir kullanım alanıdır. Bunlar arasında en çok shape_of veya num_elements gibi shape lehçesi işlemleri, dim veya from_elements gibi tensor lehçesi işlemleri ve yerleşik index türü bulunur.

Dinamik RFC > O2, bunları kapsam dışında olarak belirtir ancak birlikte çalışabilirlik amacıyla index türleri için bazı destekler dahil edilmiştir. Bu işlemler veya türler için uyumluluk garantisi yoktur. shape-legalize-to-stablehlo ardışık düzeni, bu işlemleri tam olarak desteklenen StableHLO işlemlerine dönüştürmek için kullanılabilir.

Kullanımdan Kaldırılan İşlemler

MHLO'dan devralınan ve desteği sonlandırılan, StableHLO'dan kullanımdan kaldırılmakta olan çeşitli StableHLO işlemleri vardır. Bu kaldırma işlemleriyle ilgili tüm ayrıntıları StableHLO v1.0 Cleanup #2283'te bulabilirsiniz. Bu desteğin sonlandırılmasıyla ilgili takip numarası #2340'dır.

Bu işlemler birkaç kategoriye ayrılır:

  • StableHLO operasyonlarının "HLO" kategorisinde değil. Bunlar başlangıçta StableHLO işletim sisteminin bir parçasıydı ancak daha sonra uygun olmadığı belirlendi: broadcast, create_token, cross-replica-sum, dot, einsum, torch_index_select, unary_einsum (#3).
  • Kullanılmayan işlemler: Bu işlemler bir noktada faydalı olabilir ancak işlemler yeterince geliştirilmemiş veya bu işlemleri kullanan ardışık düzenler artık bunları gerektirmeyecek şekilde yeniden düzenlenmiştir. Buna map, tuple (#598), get_tuple_element, rng, complex karşılaştırmaları #560 ve window_reversal (#1181) convolve işlevi dahildir.

Mevcut işlemler (broadcast, create_token, cross-replica-sum, dot, unary_einsum) kullanılarak ifade edilebildikleri için bu işlemlerin bazıları kolayca kaldırılabilir ve mevcut uyumluluk aralığı (6 ay) geçtikten sonra kaldırılır. Diğerleri, kaldırılma olasılığı açısından incelenmeye devam ediyor (einsum, get_tuple_element, map, rng torch_index_select, tuple, complex karşılaştırmaları, window_reversal). Topluluk geri bildirimleri doğrultusunda bu işlemler kaldırılır veya tam destekli olarak spesifikasyona eklenir. Bu operasyonların gelecekleri öğrenilene kadar yalnızca 6 aylık uyumluluk garanti edilir.

Yürütme

Sıralı yürütme

StableHLO programı, main işlevine giriş değerleri sağlanarak ve çıkış değerleri hesaplanarak yürütülür. Bir işlevin çıkış değerleri, karşılık gelen return işlemindeki kök işlemleri grafiğini yürütülerek hesaplanır.

Veri akışıyla uyumlu olduğu sürece (ör. işlemler kullanımlarından önce yürütülüyorsa) yürütme sırası uygulama tarafından tanımlanır. StableHLO'da, yan etki oluşturan tüm işlemler bir jeton tüketir ve bir jeton üretir (after_all aracılığıyla birden fazla jeton tek bir jetonda birleştirilebilir). Bu nedenle, yan etkilerin yürütme sırası da veri akışıyla uyumludur. Örneğin, aşağıdaki programda olası iki yürütme siparişi vardır: %0%1%2return ve %1%0%2return.

func.func @main() -> tensor<f64> {
  %0 = stablehlo.constant dense<1.0> : tensor<f64>
  %1 = stablehlo.constant dense<2.0> : tensor<f64>
  %2 = stablehlo.add %0, %1 : tensor<f64>
  return %2 : tensor<f64>
}

Daha resmi bir ifadeyle, StableHLO süreci şunların bir birleşimidir: 1) StableHLO programı, 2) işlem durumları (henüz yürütülmedi, zaten yürütüldü) ve 3) sürecin üzerinde çalıştığı ara değerler. İşlem, main işlevine ait giriş değerleriyle başlar, işlem durumlarını ve ara değerleri güncelleyen işlemler grafiğinde ilerler ve çıkış değerleriyle sona erer. Daha fazla resmileştirme henüz belirlenmedi (#484).

Paralel yürütme

StableHLO programları paralel olarak yürütülebilir ve her ikisi de ui32 türüne sahip olan num_replicas x num_partitions boyutunda bir 2D işlem ızgarasına düzenlenebilir.

StableHLO işlem ızgarasındaki num_replicas * num_partitions StableHLO işlemi aynı anda yürütülüyor. Her sürecin benzersiz bir process_id = (replica_id, partition_id) değeri vardır. replica_ids = range(num_replicas) içindeki replica_id ve partition_ids = range(num_partitions) içindeki partition_id, ui32 türüne sahiptir.

İşlem ızgarasının boyutu her program için statik olarak bilinir (İleride bunu StableHLO programlarının #650 açık bir parçası haline getirmeyi planlıyoruz) ve işlem ızgarasındaki konum her işlem için statik olarak bilinir. Her işlem, replica_id ve partition_id işlemleri aracılığıyla işlem ızgarasındaki konumuna erişebilir.

Süreç çizelgesinde programların tümü aynı ("Tek Program, Birden Çok Veri" stilinde), tümü farklı ("Çoklu Program, Birden Çok Veri" stilinde) veya ikisi arasında bir seçenek olabilir. Gelecekte, GSPMD (#619) dahil olmak üzere paralel StableHLO programlarını tanımlamayla ilgili diğer deyimler için de destek sunmayı planlıyoruz.

Süreç ızgarasında, süreçler büyük ölçüde birbirinden bağımsızdır. Ayrı çalışma durumları vardır, ayrı giriş/ara/çıktı değerleri bulunur ve işlemlerin çoğu, aşağıda açıklanan az sayıda toplu işlem hariç olmak üzere, süreçler arasında ayrı ayrı yürütülür.

İşlemlerin çoğunun yürütülmesinde yalnızca aynı işlemdeki değerler kullanıldığı için bu değerlere adlarıyla başvurmak genellikle net bir ifadedir. Ancak toplu işlemlerin anlamını açıklarken bu yeterli değildir ve belirli bir işlemdeki name değerini belirtmek için name@process_id gösterimi kullanılır. (Bu açıdan, niteliksiz name, name@(replica_id(), partition_id()) için kısaltma olarak görülebilir.)

Aşağıda açıklandığı gibi, noktadan noktaya iletişim ve toplu işlemlerin sağladığı senkronizasyon hariç olmak üzere, süreçler genelindeki yürütme sırası uygulama tanımlıdır.

Bire bir iletişim

StableHLO süreçleri, StableHLO kanalları üzerinden birbirleriyle iletişim kurabilir. Kanallar, si64 türündeki pozitif bir kimlikle temsil edilir. Çeşitli işlemler aracılığıyla, kanallara değer göndermek ve bunları kanallardan almak mümkündür.

Bu kanal kimliklerinin nereden geldiği, programların bu kimlikleri nasıl bildiği ve bu kimliklerle nasıl bir senkronizasyon sağlandığı gibi konularla ilgili daha fazla bilgi daha sonra paylaşılacaktır (#484).

Akış iletişimi

Her StableHLO işlemi iki akış arayüzüne erişebilir:

  • Okunabilen feed.
  • Yazılabilen outfeed.

İşlemler arasında iletişim kurmak için kullanılan ve bu nedenle her iki ucunda da işlem bulunan kanalların aksine, feed'lerin diğer ucu uygulama tarafından tanımlanır.

Daha ayrıntılı hale getirme, ör. iletişim akışının yürütme sırasını nasıl etkilediği ve bunun ne tür bir senkronizasyonu başlattığı henüz belli değildir (#484).

Toplu işlemler

StableHLO'da altı adet ortak işlem vardır: all_gather, all_reduce, all_to_all, collective_broadcast, collective_permute ve reduce_scatter. Tüm bu işlemler, StableHLO işlem ızgarasındaki işlemleri StableHLO işlem gruplarına ayırır ve her işlem grubunda diğer işlem gruplarından bağımsız olarak ortak bir hesaplama yürütür.

Her işlem grubunda toplu işlemler bir senkronizasyon engeli oluşturabilir. Bu senkronizasyonun tam olarak ne zaman gerçekleştiği, işlemlerin bu engele tam olarak nasıl ulaştığı ve ulaşmaması durumunda ne olduğu gibi konuların daha ayrıntılı olarak açıklanması henüz belirlenmedi (#484).

İşlem grubu, bölümler arası iletişim içeriyorsa (ör. işlem grubunda bölüm kimlikleri farklı olan işlemler varsa) toplu işlemin yürütülmesi için bir kanal gerekir ve toplu işlem, si64 türündeki pozitif bir channel_id sağlamalıdır. Çapraz kopya iletişimde kanallara ihtiyaç yoktur.

Toplu işlemler tarafından gerçekleştirilen hesaplamalar, bireysel işlemlere özgüdür ve yukarıdaki bireysel işlem bölümlerinde açıklanmaktadır. Ancak işlem ızgarasının işlem gruplarına ayrıldığı stratejiler bu operasyonlar arasında paylaşılır ve bu bölümde açıklanır. Daha resmi bir ifadeyle, StableHLO aşağıdaki dört stratejiyi destekler.

cross_replica

Her bir işlem grubunda yalnızca kopyalar arası iletişim gerçekleşir. Bu stratejide, replica_groups (replika kimlik listelerinden) oluşan bir liste ve partition_ids ile replica_groups öğesinin Kartezyen ürünü hesaplanır. replica_groups, benzersiz öğelere sahip olmalı ve tüm replica_ids öğelerini kapsamalıdır. Daha resmi olarak, Python söz dizimini kullanarak:

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

Örneğin, replica_groups = [[0, 1], [2, 3]] ve num_partitions = 2 için cross_replica, [[(0, 0), (1, 0)], [(0, 1), (1, 1)], [(2, 0), (3, 0)], [(2, 1), (3, 1)]] değerini döndürür.

cross_partition

Her bir işlem grubunda yalnızca bölümler arası iletişim gerçekleşir. Bu strateji, bölüm kimliklerinin listelerinin listesi olan partition_groups'yi alır ve partition_groups ile replica_ids'nin Kartezyen çarpımını hesaplar. partition_groups benzersiz öğelere sahip olmalı ve tüm partition_ids öğelerini kapsamalıdır. Daha resmi bir ifadeyle, Python söz dizimini kullanarak:

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

Örneğin, partition_groups = [[0, 1]] ve num_replicas = 4 için cross_partition, [[(0, 0), (0, 1)], [(1, 0), (1, 1)], [(2, 0), (2, 1)], [(3, 0), (3, 1)]] üretir.

cross_replica_and_partition

Her süreç grubu içinde hem çapraz replikalı hem de bölümler arası iletişimler gerçekleşebilir. Bu strateji, kopya kimliklerinin listelerinin listesi olan replica_groups'yi alır ve her replica_group için partition_ids'ye göre Kartezyen çarpımlarını hesaplar. replica_groups benzersiz öğelere sahip olmalı ve tüm replica_ids öğelerini kapsamalıdır. Daha resmi bir şekilde, Python söz dizimini kullanarak:

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

Örneğin, replica_groups = [[0, 1], [2, 3]] ve num_partitions = 2 için cross_replica_and_partition, [[(0, 0), (1, 0), (0, 1), (1, 1)], [(2, 0), (3, 0), (2, 1), (3, 1)]] değerini döndürür.

flattened_ids

Bu strateji, flattened_id_groups'ü (replica_id * num_partitions + partition_id biçiminde "düzleştirilmiş" işlem kimliklerinin listelerinin listesi) alır ve bunları işlem kimliklerine dönüştürür. flattened_id_groups, benzersiz öğelere sahip olmalı ve tüm process_ids öğelerini kapsamalıdır. Daha resmi bir şekilde, Python söz dizimini kullanarak:

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

Örneğin, flattened_id_groups = [[0, 1, 2, 3], [4, 5, 6, 7]], num_replicas = 4 ve num_partitions = 2 için flattened_ids, [[(0, 0), (0, 1), (1, 0), (1, 1)], [(2, 0), (2, 1), (3, 0), (3, 1)]] değerini döndürür.

Doğruluk

StableHLO şu anda sayısal doğruluk konusunda garanti vermez ancak bu durum gelecekte değişebilir (#1156).

Ölçülen işlemin yürütme anlamı

Ölçülen StableHLO işlemlerinin yorumlanması, donanım gereksinimlerine ve özelliklerine bağlı olarak değişiklik gösterebilir. Örneğin, bazı donanımlar "küme çözme, kayan nokta işlemi gerçekleştirme ve son olarak küme oluşturma" stratejisini kullanarak kesirli işlemleri yorumlayabilir. Diğerleri ise hesaplamanın tamamını tam sayı aritmetiğiyle gerçekleştirebilir. Sonuç olarak, kesirli StableHLO işlemlerinin yorumlanması yalnızca belirli uygulamaya göre belirlenir. Karma örneklemenin (#1575) yorumu, spesifikasyonda (1792 aracılığıyla) belirtilen semantiklerine dayalı olmalıdır.

Hatalar

StableHLO programları, her bir işlem için kapsamlı bir kısıtlama grubu aracılığıyla doğrulanır. Bu kısıtlama grubu, çalışma zamanından önce birçok hata sınıfını ortadan kaldırır. Bununla birlikte, hata koşulları (ör.tam sayı taşmaları, sınır dışı erişimler vb. aracılığıyla) yine de mümkündür. Açıkça belirtilmediği sürece tüm bu hatalar uygulama tanımlı davranışla sonuçlanır, ancak bu durum ileride değişebilir (#1157).

Kayan nokta istisnaları

Bu kuralın istisnası olarak, StableHLO programlarındaki kayan nokta istisnaları iyi tanımlanmış bir davranışa sahiptir. IEEE-754 standardı tarafından tanımlanan istisnalarla sonuçlanan işlemler (geçersiz işlem, sıfıra bölme, taşma, eksik taşma veya yanlış istisnalar), varsayılan sonuçları (standartta tanımlandığı şekilde) üretir ve ilgili durum işaretini kaldırmadan yürütmeye devam eder. Bu, standarttaki raiseNoFlag istisna işleme özelliğine benzer. Standart olmayan işlemler (ör. karmaşık aritmetik ve belirli aşkın işlevler) için istisnalar uygulamaya göre tanımlanır.

Şekil uyuşmazlıkları

StableHLO, dinamik olarak şekillendirilmiş tenzorları destekler. Ancak şekillerin çalışma zamanında eşleşmesi gerekir. Aksi takdirde davranış tanımlanmaz. StableHLO, bir tensörün çalışma zamanında belirli bir şekle sahip olduğunu doğrulayabilecek bir işlem açıkça sağlamaz. Doğru kodu oluşturma sorumluluğu yapımcıya aittir.

Somut bir örnek vermek gerekirse aşağıdaki programın geçerliliği vardır. Ancak, çalışma zamanında %arg0 ve %arg1 öğelerinin tam şekilleri aynı olmalıdır. Aksi takdirde, programın davranışı tanımlanmamış olur:

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

Notasyon

Bu dokümanda, EBNF söz dizimini açıklamak için EBNF söz dizisinin değiştirilmiş ISO versiyonu (ISO/IEC 14977:1996, Wikipedia) kullanılmaktadır. Bu versiyonda iki değişiklik yapılmıştır: 1) Kurallar = yerine ::= kullanılarak tanımlanır.

2) dize birleştirme işlemi , yerine yan yana ekleme kullanılarak ifade edilir.

Anlamı (yani "Türler", "Sabitler" ve "İşlemler" bölümlerinde) açıklamak için aşağıda açıklandığı gibi dizi işlemlerini kısa ve öz şekilde ifade etme desteğiyle genişletilmiş Python söz dizimine dayalı formüller kullanırız. Bu yöntem küçük kod snippet'leri için iyi çalışır ancak daha büyük kod snippet'lerinin gerekli olduğu nadir durumlarda her zaman açıkça tanıtılan standart Python söz dizimini kullanırız.

Formüller

dot_general spesifikasyonundan alınan bir örneğe dayanarak formüllerin nasıl çalıştığını keşfedelim. Bu işlemle ilgili kısıtlamalardan biri aşağıdaki gibidir: dim(lhs, lhs_batching_dimensions...) = dim(rhs, rhs_batching_dimensions...).

Bu formülde kullanılan adlar iki kaynaktan gelir: 1) genel işlevler (ör. dim), 2) ilgili program öğesinin üye tanımları (ör. dot_general'in "Girişler" bölümünde tanımlanan lhs, lhs_batching_dimensions, rhs ve rhs_batching_dimensions girişleri).

Yukarıda da belirtildiği gibi, bu formülün söz dizimi Python tabanlı olup bazı kısaltmalara sahiptir. Formülü anlamak için bunu standart Python söz dizimine dönüştürelim.

C: Bu formüllerde eşitliği temsil etmek için = kullanıyoruz. Dolayısıyla Python söz dizimini elde etmeye yönelik ilk adım, ='yi aşağıdaki gibi == ile değiştirmektir: dim(lhs, lhs_batching_dimensions...) == dim(rhs, rhs_batching_dimensions...).

B) Ayrıca bu formüller, skaler ifadeleri tensör ifadelerine dönüştüren elipsleri (...) destekler. Özetlemek gerekirse f(xs...), kabaca "xs tensörindeki her skaler x için bir skaler f(x) hesaplayıp tüm bu skaler sonuçları birlikte bir tensör sonucu olarak döndürme" anlamına gelir. Basit Python söz diziminde, örnek formülümüzün şekli şu şekilde değişir: [dim(lhs, dim1) for dim1 in lhs_batching_dimensions] == [dim(rhs, dim2) for dim2 in rhs_batching_dimensions].

Elipsler sayesinde bağımsız skaler düzeyinde çalışmaktan genellikle kaçınmak mümkündür. Ancak bazı karmaşık durumlarda, gather spesifikasyonundaki start_indices[bi0, ..., :, ..., biN] formülünde olduğu gibi alt düzey yarı resmi söz dizimi kullanılabilir. Özlülük sağlamak amacıyla, bu tür söz dizimlerini standart Python'a çevirmek için tam bir biçimsellik sağlamayız. Bununla birlikte, her duruma göre sezgisel olarak anlaşılabilir olmasını umuyoruz. Belirli formüllerin anlaşılır olmadığını düşünüyorsanız lütfen bize bildirin. Bu formüller üzerinde iyileştirme yapmaya çalışacağız.

Ayrıca, formüllerin; tensörler, tensör listeleri (ör. değişken sayıda tensörden oluşabilir) vb. dahil olmak üzere her türlü listeyi genişletmek için elips kullandığını fark edeceksiniz. Bu, tam bir biçimcilik sağlamadığımız (ör. listeler StableHLO tür sisteminin bile bir parçası değildir) ve bunun yerine sezgisel anlaşılabilirliğe güvendiğimiz başka bir alandır.

C) Kullandığımız son kayda değer gösterim aracı, örtük yayındır. StableHLO opset'i, örtülü yayını desteklemezken formüller bunu destekler ve ayrıca kısalık sağlar. Özetlemek gerekirse, bir skaler, bir tensörün beklendiği bir bağlamda kullanılırsa skaler, beklenen şekle yayınlanır.

dot_general örneğine devam etmek için başka bir kısıtlama daha verelim: 0 <= lhs_batching_dimensions < rank(lhs). dot_general spesifikasyonunda tanımlandığı gibi, lhs_batching_dimensions bir tensördür ancak hem 0 hem de rank(lhs) skalerdir. Örtük yayını uyguladıktan sonra formül [0, ..., 0] <= lhs_batching_dimensions < [rank(lhs), ..., rank(lhs)] olur.

Bu formül, belirli bir dot_general işlemine uygulandığında doğru/yanlış değerleri içeren bir tensör olarak değerlendirilir. Formüller kısıtlama olarak kullanıldığında, formül true veya yalnızca true öğesi olan bir tensör olarak değerlendirilirse kısıtlama geçerli olur.

Adlar

Formüllerde sözlüksel kapsam şunları içerir: 1) genel işlevler, 2) üye tanımları,

3) yerel tanımlar. Genel işlevlerin listesi aşağıda verilmiştir. Öğe tanımlarının listesi, gösterimin uygulandığı program öğesine bağlıdır:

  • İşlemler için üye tanımları, "Girişler" ve "Çıkışlar" bölümlerinde tanıtılan adları içerir.
  • Diğer tüm üye tanımları, program öğesinin yapısal parçalarını içerir ve ilgili EBNF sonlu olmayan öğelerinin adından türetilir. Çoğu zaman bu yapısal parçaların adları, terminal olmayan öğelerin adlarının yılan büyük/küçük harf düzenineIntegerLiteralinteger_literalQuantizationStorageTypestorage_type
  • Ayrıca, üye tanımları her zaman ilgili program öğesine atıfta bulunmak için self içerir.

Değerler

Formüller değerlendirilirken aşağıdaki değer türleriyle çalışır: 1) Value (gerçek değerler, ör. dense<[[1, 2], [3, 4]]> : tensor<2x2xi32>; türleri her zaman bilinir), 2) Placeholder (gelecekteki değerler, ör. lhs, rhs veya result; gerçek değerleri henüz bilinmez, yalnızca türleri bilinir), 3) Type ("Türler" bölümünde tanımlandığı şekilde türler), 4) Function ("İşlevler" bölümünde tanımlandığı şekilde genel işlevler).

Bağlama bağlı olarak adlar farklı değerlere işaret edebilir. Daha ayrıntılı belirtmek gerekirse, işlemler (ve diğer program öğelerinin eşdeğerleri) için "Anlamsal" bölümü, çalışma zamanı mantığını tanımlar. Bu nedenle, tüm girişler Value olarak kullanılabilir. Buna karşılık, işlemler (ve eşdeğerleri) için "Kısıtlar" bölümü, "derleme zamanı" mantığını (yani genellikle çalışma zamanından önce yürütülen bir şey) tanımlar. Bu nedenle, yalnızca sabit girişler Value olarak kullanılabilir ve diğer girişler yalnızca Placeholder olarak kullanılabilir.

Adlar "Anlambilim" bölümünde "Kısıtlar" bölümünde
Genel işlevler Function Function
Sabit girişler Value Value
Sabit olmayan girişler Value Placeholder
Çıkışlar Value Placeholder
Yerel tanımlar Tanımlamaya bağlıdır Tanımlamaya bağlıdır

Bir örnek transpose işlemini inceleyelim:

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

Bu işlemde permutation sabit olduğundan hem semantikte hem de kısıtlamalarda Value olarak kullanılabilir. Buna karşılık, operand ve result, anlamsal olarak bir Value olarak ancak kısıtlamalarda yalnızca Placeholder olarak kullanılabilir.

İşlevler

Tür oluşturma

Tür oluşturmak için kullanılabilecek işlev yoktur. Bunun yerine, genellikle daha kısa olduğu için doğrudan tür söz dizimini kullanırız. Ör. function_type( [tensor_type([], E), tensor_type([], E)], [tensor_type([], E)]) yerine (tensor<E>, tensor<E>) -> (tensor<E>).

Türlerde işlevler

  • element_type, tenör türlerinde ve kesirli tenör türlerinde tanımlanır ve sırasıyla ilgili TensorType veya QuantizedTensorType öğesinin TensorElementType ya da QuantizedTensorElementType bölümünü döndürür.
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 için bir kısayoldur.

  • is_per_tensor_quantized(x: Value | Placeholder | Type) -> Value, is_quantized(x) and quantization_dimension(x) is None için kısayoldur.

  • is_promotable(x: Type, y: Type) -> bool, x türünün y türüne yükseltilip yükseltilemeyeceğini kontrol eder. x ve y QuantizedTensorElementType olduğunda promosyon yalnızca storage_type'e uygulanır. Promosyonun bu sürümü şu anda azaltma hesaplaması bağlamında kullanılmaktadır (daha fazla bilgi için RFC'ye bakın).

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) için bir kısayoldur.

  • is_type_name(x: Value | Placeholder | Type) -> Value. Tüm türlerde kullanılabilir. Örneğin, x bir FloatType ise is_float(x), true değerini döndürür. x bir değer veya yer tutucuysa bu işlev, is_type_name(type(x)) için bir kısayoldur.

  • max_value(x: Type) -> Value, bir TensorElementType değerinin maksimum değerini döndürür. x bir TensorElementType değilse None döndürülür.

  • min_value(x: Type) -> Value, TensorElementType için mümkün olan en düşük değeri döndürür. x bir TensorElementType değilse None döndürülür.

  • member_name(x: Value | Placeholder | Type) -> Any. Tüm türlerdeki tüm üye tanımları member_name için kullanılabilir. Örneğin tensor_element_type(x), karşılık gelen TensorType öğesinin TensorElementType bölümünü döndürür. x bir değer veya yer tutucuysa bu işlev, member_name(type(x)) için bir kısayoldur. x, uygun bir üyesi olan bir tür değilse veya bu türde bir değer ya da yer tutucu değilse None döndürülür.

  • is_empty_algorithm(*args: Type), tüm nokta algoritması alanlarının None olarak ayarlanıp ayarlanmadığını kontrol eder. Nokta algoritmalarının uygulamada tanımlanmış varsayılan davranışları olduğundan bu gereklidir. Bu nedenle, varsayılan bir değer belirtmek yanlış olur.

Değerlerin oluşturulması

  • operation_name(*xs: Value | Type) -> Value. Tüm işlemler için kullanılabilir. Örneğin, add(lhs, rhs) iki tenör değeri lhs ve rhs alır ve add işleminin bu girişlerle değerlendirilmesinin sonucunu döndürür. Bazı işlemler (ör. broadcast_in_dim) için çıkış türleri "yük taşıyıcı"dır, yani bir işlemin değerlendirilmesi için gereklidir. Bu durumda işlev, bu türleri bağımsız değişken olarak alır.

Değerler üzerinde işlevler

  • Python'un tüm operatörleri ve işlevleri kullanılabilir. Örneğin Python'daki abonelik ve dilimleme gösterimleri, tensörlere, miktarlandırılmış tensörlere ve tuple'lara dizine eklenebilir.

  • to_destination_type(x: Value, destination_type: Type) -> Value, tensörlerde tanımlanır ve x değerinin dönüştürülmüş değerini type(x) ve destination_type'a göre aşağıdaki gibi döndürür:

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 ve uniform_dequantize işlemlerinin birleştirilmesi hakkında erken bir tartışma var (#1576). Birleştirme işleminden sonra yukarıdaki işleve ihtiyacımız kalmaz ve bunun yerine convert için işlem adını kullanabiliriz.

  • is_nan(x: Value) -> Value, tensörlerde tanımlanır ve x öğesinin tüm öğeleri NaN veya aksi takdirde false ise true değerini döndürür. x bir tensör değilse None değerini döndürür.

  • is_sorted(x: Value) -> Value, tensörlerde tanımlanır ve x öğeleri dizinlerinin artan alfabetik sırasına göre artan düzende sıralanmışsa true döndürür, aksi takdirde false döndürür. x bir tensör değilse None döndürülür.

  • is_unique(x: Value) -> Value, tensörlerde tanımlanır ve x'de kopya öğe yoksa true, aksi takdirde false döndürür. x bir tensör değilse None döndürülür.

  • member_name(x: Value) -> Any, tüm değerlerin tüm üye tanımları için tanımlanır. member_name Örneğin, real_part(x), ilgili ComplexConstant öğesinin RealPart bölümünü döndürür. x, uygun bir üyesi olan bir değer değilse None döndürülür.

  • same(x: Value) -> Value, tensörlerde tanımlanır ve x öğelerinin tümü birbirine eşitse true, aksi takdirde false döndürür. Tensör öğe içermiyorsa "tümü birbirine eşit" olarak kabul edilir. Yani işlev true döndürür. x bir tensör değilse None döndürülür.

  • split(x: Value, num_results: Value, axis: Value) -> Value, tensörlerde tanımlanır ve axis ekseni boyunca x'nin num_results dilimlerini döndürür. x bir tensör veya dim(x, axis) % num_results != 0 değilse None döndürülür.

  • is_defined_in_parent_scope(x: Value) -> Value dizelerde tanımlanır ve x, ilgili işlemin üst işleviyle aynı kapsamda tanımlanan bir işlevin adıysa true döndürür.

  • is_namespaced_op_name(x: Value) -> Value, dizelerde tanımlanır ve x geçerli bir işlem adıysa (yani aşağıdaki normal ifadeye uyarsa) true döndürür: [a-zA-Z][a-zA-Z0-9_]*([.][a-zA-Z0-9_$]+)+

Şekil hesaplamaları

  • axes(x: Value | Placeholder | Type) -> Value, range(rank(x)) için bir kısayoldur.

  • dim(x: Value | Placeholder | Type, axis: Value) -> Value, shape(x)[axis] için bir kısayoldur.

  • dims(x: Value | Placeholder | Type, axes: List) -> List, list(map(lambda axis: dim(x, axis), axes)) için bir kısayoldur.

  • index_space(x: Value | Placeholder | Type) -> Value, tensörlerde tanımlanır ve karşılık gelen TensorType için [0, ..., 0], [0, ..., 1], ..., shape(x) - 1 şeklinde artan alfabetik sırayla dizilmiş size(x) dizinleri döndürür. x bir tensör türü, kesirli tensör türü, değer veya bu türlerden birinin yer tutucusu değilse None döndürülür.

  • rank(x: Value | Placeholder | Type) -> Value, size(shape(x)) için bir kısayoldur.

  • shape(x: Value | Placeholder | Type) -> Value, member_name aracılığıyla "Türlerdeki işlevler" bölümünde tanımlanır.

  • size(x: Value | Placeholder | Type) -> Value, reduce(lambda x, y: x * y, shape(x)) için bir kısayoldur.

Kesirli sayı hesaplamaları

  • def baseline_element_type(x: Value | Placeholder | Type) -> Type, element_type(baseline_type(x)) için kısayoldur.

  • baseline_type, tenör türleri ve kesirli tenör türleri üzerinde tanımlanır ve bunları bir "temel çizgiye", yani aynı şekle sahip ancak öğe türünün kesirli parametreleri varsayılan değerlere sıfırlanmış bir türe dönüştürür. Bu, oldukça sık ihtiyaç duyulan tensör ve nicel tensör türlerini eşit şekilde karşılaştırmak için kullanışlı bir yöntem olarak kullanılır. Bu, kesirli türler için kesirli parametreler göz ardı edilerek türlerin karşılaştırılmasını sağlar. Yani shape, storage_type, expressed_type, storage_min, storage_max ve quantization_dimension (eksen başına kesirli tür için) değerlerinin tümü eşleşmelidir ancak scales ve zero points farklı olabilir.

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, kesirli vektör türlerinde tanımlanır ve bunları kayan nokta vektör türlerine dönüştürür. Bu işlem, depolama alanı türünün tam sayı değerlerini temsil eden kesikli öğeleri, kesikli öğe türüyle ilişkili sıfır noktası ve ölçek kullanılarak ifade edilen türün karşılık gelen kayan nokta değerlerine dönüştürerek gerçekleştirilir.
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, kayan noktalı tenör türlerinde tanımlanır ve bunları kesirli tenör türlerine dönüştürür. Bu işlem, miktarlandırılmış öğe türüyle ilişkili sıfır noktası ve ölçeği kullanılarak ifade edilen türdeki kayan nokta değerlerinin depolama türünün karşılık gelen tam sayı değerlerine dönüştürülmesiyle gerçekleşir.
def quantize(x: Value, result_type: Type) -> Value:
  assert is_float(x) and is_quantized(result_type)
  zero_points = compute_zero_points(result_type, TensorType(shape(x), storage_type(result_type)))
  converted_zero_points = convert(zero_points, expressed_type(result_type))
  converted_min = convert(storage_min(result_type), expressed_type(result_type))
  converted_max = convert(storage_max(result_type), expressed_type(result_type))

  x_scaled = x / compute_scales(result_type, type(x))
  x_scaled_add_zp = x_scaled + converted_zero_points
  x_clamped = clamp(converted_min, x_scaled_add_zp, converted_max)
  x_rounded = round_nearest_even(x_clamped)
  return convert(x_rounded, result_type)
  • dequantize_op_quantize, kesikli tenzorlarda öğe bazında hesaplamaları belirtmek için kullanılır. Önce nicelleştirmeyi kaldırır (yani nicelleştirilmiş öğeleri ifade edilen türlerine dönüştürür), ardından bir işlem gerçekleştirir ve daha sonra nicelleştirme yapar (yani sonuçları tekrar depolama türlerine dönüştürür). Bu işlev şu anda yalnızca tensör başına kesme işlemi için kullanılabilir. Eksen başına kesme işlemi üzerinde çalışılıyor (#1574).
def dequantize_op_quantize(op, *inputs_and_output_type):
  inputs = inputs_and_output_type[:-1]
  output_type = inputs_and_output_type[-1]

  float_inputs = map(dequantize, inputs)
  float_result = op(*float_inputs)
  return quantize(float_result, output_type)

def dequantize_batch_norm_grad_or_training_quantize(op, *inputs_and_output_types):
  inputs = inputs_and_output_type[:-3]
  float_inputs = map(dequantize, inputs)
  float_results = op(*float_inputs)
  return map(quantize, float_results, inputs_and_output_type[-3:])

def dequantize_compare(lhs, rhs, comparison_direction):
  float_lhs = dequantize(lhs)
  float_rhs = dequantize(rhs)
  return compare(float_lhs, float_rhs, comparison_direction, FLOAT)

def dequantize_select_quantize(pred, on_true, on_false, output_type):
  float_on_true = dequantize(on_true)
  float_on_false = dequantize(on_false)
  float_result = select(pred, float_on_true, float_on_false)
  return quantize(float_result, output_type)
  • hybrid_dequantize_then_op, kayan noktalı olarak lh ve miktarlandırılmış türlerde rh'leri kabul eden karma işlem için yalnızca ağırlıkla ilgili miktarlandırmayı belirtmek amacıyla kullanılır. Ölçülmüş girişleri ifade edilen türlerine göre dequantize eder ve hesaplamayı float olarak gerçekleştirir. Kayan lhs tensörünün öğe türü ve ifade edilen nicel rhs tensörü türü aynı olmalıdır.
def hybrid_dequantize_then_op(op, lhs, rhs):
  assert(is_float(lhs) and is_quantized(rhs) and element_type(lhs) == expressed_type(rhs))
  return op(lhs, dequantize(rhs))

Izgara hesaplamaları

  • cross_partition(replica_groups: Value) -> Value. Yukarıdaki "cross_replica" bölümüne bakın.

  • cross_replica(replica_groups: Value) -> Value. Yukarıdaki "cross_replica" bölümüne bakın.

  • cross_replica_and_partition(replica_groups: Value) -> Value. Yukarıdaki "cross_replica_and_partition" bölümüne bakın.

  • flattened_ids(replica_groups: Value) -> Value. Yukarıdaki "flattened_ids" bölümüne bakın.

Dinamizm

StableHLO değerleri dinamik boyut boyutlarına sahip olabilir (ör. tensor<?xi64>). Ancak StableHLO değerleri dinamik sayıda boyuta sahip olamaz (sıralanmamış dinamizm, ör. tensor<*xi64>). Operan ve sonuçlarda, boyutlar üzerinde kısıtlamalar olsa bile dinamik boyut boyutlarının kullanılmasına izin verilir. Kısıtlamalar, mümkünse statik olarak doğrulanır. Aksi takdirde, çalışma zamanına ertelenirler ve uyuşmazlıklar tanımlanmamış davranışa yol açar. Örnekler için aşağıya bakın.

Bir öğeyle ilgili tek adımlı işlemler için şekil uyuşmazlıkları

Aşağıdaki oyuncak programı düşünün:

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

Sonucun şeklinin bilinmesi yaygın olmasa da girdinin şekli bilinmediği için böyle bir program olağan dışıdır. Yine de bu geçerli bir StableHLO programıdır. Operanın tam şekli bilinmediği için bu programdaki abs işlemini statik olarak doğrulamak mümkün değildir. Ancak şekiller kesinlikle uyumludur ve bu durum statik olarak kontrol edilebilir: ?, çalışma zamanında 2 olabilir ve herhangi bir sorun yaşanmaz. Ancak ? başka bir tam sayı da olabilir. Bu durumda davranış tanımlanmaz.

Sonuçta bir boyut boyutu dinamikse tanımlanmamış davranış olmayacağını unutmayın. "Beklenen" boyut olmadığından eşleşme sorunu olamaz.

İkili öğe bazında işlemler için şekil uyuşmazlıkları

Aşağıdaki oyuncak programı düşünün:

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

İkili öğe bazında işlemlerde, girişlerin ve sonucun şekilleri çalışma zamanında aynı olmalıdır. Statik boyutlar derleme zamanında eşit olmalıdır. Aksi takdirde yalnızca uyumlu olmaları gerekir. Girişlerde herhangi bir boyut dinamikse dinamik boyut, diğer operatördeki (statik veya dinamik) ilgili boyutla eşleşmeyebileceğinden çalışma zamanında tanımlanmamış bir davranış olabilir. Tüm girişler statikse sonucun dinamik olup olmadığı önemli değildir: Statik olarak bilinen boyutlar statik olarak kontrol edilir ve dinamik boyutlar herhangi bir kısıtlama getirmez.

Çıktı şeklini işlenen olarak alan işlemler için şekil uyuşmazlıkları

Aşağıdaki oyuncak programı düşünün:

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

Çalışma zamanında şekil operatöründe bulunan değerler, sonucun şekliyle eşleşmelidir. Aksi takdirde davranış tanımlanmaz. Yani, çalışma zamanında %arg0 değerinin dense<[3, 4]> : tensor<2xi32> olması gerekir. Şekil operanı sabitse bu durum statik olarak doğrulanabilir. Sonuç şekli tamamen dinamikse bir uyumsuzluk oluşamaz.