StableHLO Özelliği

StableHLO, makine öğrenimi (ML) modellerinde üst düzey işlemler (HLO) için bir işlem kümesidir. StableHLO, farklı ML çerçeveleri ve ML derleyicileri arasında 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 (ör. TensorFlow, JAX ve PyTorch) ile makine öğrenimi derleyicileri (ör. XLA ve IREE) arasında daha fazla birlikte çalışabilirlik sağlayarak makine öğrenimi geliştirmeyi basitleştirmek ve hızlandırmaktır. Bu amaçla, bu belgede StableHLO programlama dili için bir spesifikasyon sağlanmaktadır.

Bu spesifikasyon üç ana bölümden oluşur. İlk olarak, Programlar bölümünde, StableHLO işlevlerinden oluşan StableHLO programlarının yapısı açıklanmaktadır. StableHLO işlevleri de StableHLO işlemlerinden oluşur. Bu yapı içinde, Ops bölümünde tek tek işlemlerin semantiği belirtilir. Yürütme bölümü, bir programda birlikte yürütülen tüm bu işlemlerin semantiğini sağlar. Son olarak, Notasyon bölümünde, spesifikasyon genelinde kullanılan notasyon ele alınır.

StableHLO'nun önceki bir sürümündeki spesifikasyonu görüntülemek için ilgilendiğiniz etiketli sürümde depoyu açın. Örneğin, StableHLO v0.19.0 Spec. StableHLO'nun her küçük sürüm artışında meydana gelen 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şi (%image, %weights ve %bias) ve 1 çıkışı olan @main işlevini içeren bir örnek program verilmiştir. İşlevin gövdesinde 6 işlem var.

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ıya, girişlere/çıkışlara ve gövdeye sahiptir. Gelecekte, HLO ile daha iyi uyumluluk sağlamak için işlevlere ek meta veriler eklemeyi 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 farklıdır: 1) Tüm tanımlayıcılar, farklı tanımlayıcı türlerini ayıran işaretlere sahiptir. 2) StableHLO programlarının oluşturulmasını kolaylaştırmak için değer tanımlayıcıları tamamen sayısal olabilir.

Türler

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

StableHLO türleri, StableHLO değerlerini temsil eden değer türleri (birinci sınıf türleri olarak da adlandırılır) ve diğer program öğelerini açıklayan değer dışı türler olarak sınıflandırılır. StableHLO türleri, birçok programlama dilindeki türlere benzer.Ancak StableHLO'nun alana özgü yapısı nedeniyle bazı sıra dışı sonuçlar (ör. skaler türler değer türleri değildir) ortaya çıkar.

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

Tensor türleri, tensörleri (yani çok boyutlu diziler) temsil eder. Bunlar bir şekle ve bir öğe türüne sahiptir. Şekil, karşılık gelen boyutların (eksenler olarak da adlandırılır) artan sırasındaki negatif olmayan veya bilinmeyen boyutları temsil eder. Boyutlar, 0 ile R-1 arasında numaralandırılır. Boyut sayısı R sıra olarak adlandırılır. Örneğin, tensor<2x3xf32>, 2x3 şekline ve f32 öğe türüne sahip bir tensör türüdür. Boyutları 2 ve 3 olan iki boyuta (veya başka bir deyişle iki eksene) sahiptir: 0. boyut ve 1. boyut. Sıralaması 2'dir.

Şekiller kısmen veya tamamen bilinmeyebilir (dinamik). Örneğin, tensor<?x2xf64> kısmen bilinirken tensor<?x?xf64> tamamen bilinmez. Dinamik boyutlar ? kullanılarak gösterilir. Şekillerin derecelendirmesi kaldırılamaz.

Gelecekte, tensör türlerini boyut boyutları ve öğe türlerinin ötesine taşıyarak düzenler (#629) ve seyrekliği (#1078) de içerecek şekilde genişletmeyi 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 değişken sayıda kayan nokta sabiti (C4-C6), (C9), (C10), (C13)
zero_points değişken sayıda tam sayı sabiti (C7-C9)

Kuantize edilmiş öğe türleri, depolama türünün storage_min ile storage_max (dahil) arasındaki aralıkta bulunan ve ifade edilmiş türün kayan nokta değerlerine karşılık gelen tam sayı değerlerini temsil eder. 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, nicelendirme parametreleri olarak adlandırılır. storage_min ve storage_max, dilbilgisinde isteğe bağlıdır ancak sırasıyla min_value(storage_type) ve max_value(storage_type) varsayılan değerlerine sahiptir. Kuantize edilmiş öğ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 sabittir ancak çarpanlar ve kaydırmalarla gösterilen tam sayı tabanlı ölçeklere büyük ilgi duyulmaktadır. Bu konuyu yakın gelecekte ele almayı planlıyoruz (#1404).

QuantizationZeroPoint semantiğiyle ilgili devam eden bir tartışma var. Bu tartışma, türü, değerleri ve nicelenmiş tensör türünde yalnızca bir veya birden fazla sıfır noktası olup olamayacağını içeriyor. Bu tartışmanın sonuçlarına göre, sıfır puanla ilgili spesifikasyon gelecekte değişebilir (#1405).

Devam eden bir diğer tartışma ise bu değerlere ve nicelenmiş tensörlerin değerlerine herhangi bir kısıtlama getirilip getirilmeyeceğini belirlemek için QuantizationStorageMin ve QuantizationStorageMax semantiğini içeriyor (#1406).

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

Kuantize edilmiş tensör türleri, kuantize edilmiş öğeler içeren tensörleri temsil eder. Bu tensörler, öğelerinin normal öğe türleri yerine nicelenmiş öğe türlerine sahip olması dışında normal tensörlerle tamamen aynıdır.

Kuantize edilmiş tensörlerde kuantizasyon tensör başına olabilir. Bu durumda, tensörün tamamı için bir scale ve zero_point bulunur. Kuantizasyon eksen başına da olabilir. Bu durumda, belirli bir boyutun quantization_dimension her dilimi için bir çift olmak üzere birden fazla scales ve zero_points bulunur. Daha resmi bir ifadeyle, eksen başına nicemleme içeren bir tensörde t, quantization_dimension'nin dim(t, quantization_dimension) dilimi vardır: t[:, ..., 0, ..., :], t[:, ..., 1, ..., :] vb. i. dilimdeki tüm öğeler, nicemleme parametreleri olarak scales[i] ve zero_points[i] kullanır. Kuantize edilmiş tensör türleri aşağıdaki kısıtlamalara sahiptir:

  • Tensör başına nicemleme için:
    • Ek kısıtlama yoktur.
  • Eksen başına nicemleme 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 oluşturulan ve kullanılan opak değerler) 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}]

Arabellek türleri, arabellekleri temsil eder. Örneğin, XLA'da arabellekler, tutarlı depolama alanına sahip çok boyutlu dizilerdir. Tensor türlerine benzer şekilde, arabellek türlerinin de şekli ve öğe türü vardır. Şekil, 0 ile R-1 arasında numaralandırılmış, karşılık gelen boyutların (eksenler olarak da adlandırılır) artan sırasındaki negatif olmayan veya bilinmeyen boyutları temsil eder. Boyut sayısı R sıra olarak adlandırılır. Örneğin, memref<2x3xf32>, şekli 2x3 ve öğe türü f32 olan bir arabellek türüdür. Boyutları 2 ve 3 olan iki boyutu (veya başka bir deyişle iki ekseni) vardır: 0. boyut ve 1. boyut. Sıralaması 2'dir.

Arabellekler, custom_call ile CreateBuffer veya Pin kullanılarak ayrılabilir ve custom_call ile Unpin kullanılarak serbest bırakılabilir. Yalnızca custom_call işlemleri arabelleklerdeki içeriği okuyabilir ve yazabilir. Daha fazla ayrıntı için custom_call sayfasına bakın.

Demet türleri, demetleri (yani heterojen listeleri) temsil eder. Demetler, yalnızca HLO ile uyumluluk için kullanılan eski bir özelliktir. HLO'da, değişken sayıda giriş ve çıkışı temsil etmek için demetler kullanılır. StableHLO'da değişken sayıda giriş ve çıkış yerel olarak desteklenir.StableHLO'da demetlerin 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 değişiklikler yapmayı planlıyoruz. Bu değişiklikler, StableHLO'dan demet türlerini kaldırmamıza olanak tanıyabilir (#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 nedenle, StableHLO programları bu türlerin değerlerini doğrudan temsil edemez (sonuç olarak, T türündeki skaler değerleri tensor<T> türündeki 0 boyutlu tensör değerleriyle temsil etmek yaygın bir uygulamadır).

  • Boole türü, Boole değerleri true ve false'ü temsil eder.
  • Tam sayı türleri işaretli (si) veya işaretsiz (ui) olabilir ve desteklenen bit genişliklerinden birine (2, 4, 8, 16, 32 veya 64) sahip olabilir. İşaretli siN türleri, -2^(N-1) ile 2^(N-1)-1 arasındaki tam sayı değerlerini (bu değerler dahil) temsil eder. İşaretsiz uiN türleri ise 0 ile 2^N-1 arasındaki tam sayı değerlerini (bu değerler dahil) temsil eder.
  • Kayan nokta türleri aşağıdakilerden biri olabilir:
  • Karmaşık türler, aynı öğe türüne ait bir reel kısım ve bir sanal kısım içeren 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).
FunctionType ::= '(' InputTypes ')' '->' '(' OutputTypes ')'
InputTypes ::= [ValueType {',' ValueType}]
OutputTypes ::= [ValueType {',' ValueType}]

İşlev türleri, hem adlandırılmış hem de anonim işlevleri temsil eder. Giriş türleri (-> simgesinin sol tarafındaki türlerin listesi) ve çıkış türleri (-> simgesinin sağ tarafındaki türlerin listesi) vardır. Birçok programlama dilinde işlev türleri birinci sınıf olsa da StableHLO'da birinci sınıf değildir.

StringType ::= 'string'

Dize türü, bayt dizilerini temsil eder. Birçok programlama dilinin aksine, StableHLO'da dize türü 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 adlandırılır) makine öğrenimi modellerindeki üst düzey işlemlerin kapalı bir kümesini temsil eder. Yukarıda bahsedildiği gibi, StableHLO söz dizimi büyük ölçüde MLIR'den esinlenmiştir. Bu, en ergonomik alternatif olmasa da StableHLO'nun makine öğrenimi çerçeveleri ve makine öğrenimi derleyicileri arasında daha fazla birlikte çalışabilirlik oluşturma hedefi için muhtemelen en uygun seçenektir.

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

StableHLO işlemleri (işlemler olarak da adlandırılır) bir ada, girişlere/çıkışlara ve imzaya sahiptir. Ad, stablehlo. önekinden ve desteklenen işlemlerden birini benzersiz şekilde tanımlayan bir anımsatıcıdan oluşur. Desteklenen tüm işlemlerin kapsamlı listesi için aşağıya bakın.

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

İşlemler girdileri tüketir ve çıktılar üretir. 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ığından statik olarak sağlanır) ve giriş özellikleri (ayrıca statik olarak sağlanır) şeklinde sınıflandırılır. Bir işlemin kullandığı ve ürettiği giriş ve çıkış türü, işlemin anımsatıcı koduna bağlıdır. Örneğin, add işlemi 2 giriş değeri kullanır ve 1 çıkış değeri üretir. Buna kıyasla, 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 adlandırılır) adlandırılmış işlevlere çok benzer. Ancak: 1) Tanımlayıcıları yoktur (bu nedenle "anonim" olarak adlandırılırlar). 2) Çıkış türlerini bildirmezler (çıkış türleri, işlevdeki return işleminden çıkarılır).

Giriş işlevlerinin söz diziminde, MLIR ile uyumluluk için şu anda kullanılmayan bir bölüm bulunur (yukarıdaki Unused üretim bölümüne bakın). MLIR'de, atlama işlemleriyle birbirine bağlanmış birden fazla işlem "bloğu" içerebilen daha genel bir "bölgeler" kavramı vardır. Bu blokların, Unused üretimle eşleşen kimlikleri vardır. Böylece bloklar birbirinden ayırt edilebilir. StableHLO'da atlama işlemleri olmadığından MLIR söz diziminin ilgili kısmı kullanılmaz (ancak yine de oradadır).

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

Giriş özelliklerinin adı ve desteklenen sabitlerden biri olan değeri vardır. Bunlar, 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 üzere start_indices ve limit_indices gibi birden fazla özellik kullanır.

Şu anda, gerçek hayattaki StableHLO programları bazen bu belgede açıklanmayan özellikler içerir. Gelecekte bu özellikleri StableHLO işlem kümesine dahil etmeyi veya StableHLO programlarında görünmelerini yasaklamayı planlıyoruz. Bu süre zarfında, 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ürlerin listesi) ve tüm çıkış değerlerinin türlerinden (->'nin sağ tarafındaki türlerin listesi) oluşur. Giriş türleri kesinlikle gereksizdir ve çıkış türleri de neredeyse her zaman gereksizdir (çünkü çoğu StableHLO işlemi için çıkış türleri girişlerden çıkarılabilir). Bununla birlikte, op signature, MLIR ile uyumluluk için StableHLO söz diziminin bir parçasıdır.

Aşağıda, anımsatıcısı select_and_scatter 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) kullanır. İşlemin imzasının yalnızca giriş değerlerinin türlerini (ancak satır içi olarak sağlanan giriş işlevlerinin ve özelliklerinin türlerini değil) içerdiğine dikkat edin.

%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 değere ve türe sahiptir. Genellikle tür, sabit söz diziminin bir parçasıdır.Ancak türün net olduğu durumlarda (ör. bir boolean sabiti net bir şekilde i1 türündedir, ancak bir tam sayı sabiti birden fazla olası türe sahip olabilir) bu durum geçerli değildir.

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

Boole sabitleri, true ve false Boole değerlerini temsil eder. Boole sabitlerinin türü i1'dır.

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

Tamsayı sabitleri, ondalık veya onaltılık gösterim kullanan dizeler aracılığıyla tamsayı 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, ilgili türün kayan nokta biçimindeki temel bitleri doğrudan belirtmek için kullanılabilir. Kayan nokta sabitleri 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 (önce gelir) ve sanal kısım (ikinci gelir) listelerini kullanarak karmaşık değerleri temsil eder. Örneğin, (1.0, 0.0) : complex<f32>, 1.0 + 0.0i'yi, (0.0, 1.0) : complex<f32> ise 0.0 + 1.0i'ü temsil eder. Bu parçaların bellekte depolanma sırası uygulamaya bağlıdır. Karmaşık sabitler aşağıdaki kısıtlamalara tabidir:

  • (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österimiyle belirtilen iç içe geçmiş listeler kullanılarak tensör değerlerini temsil eder. Örneğin, dense<[[1, 2, 3], [4, 5, 6]]> : tensor<2x3xi32>, dizinlerden öğelere aşağıdaki eşlemeyi içeren 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 daha sonra bellekte depolanma sırası uygulamaya bağlıdır. Tensor 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) '>'

Kuantize edilmiş tensör sabitleri, tensör sabitleriyle aynı gösterimi kullanarak kuantize edilmiş tensör değerlerini temsil eder. Öğeler, depolama türlerinin sabitleri olarak belirtilir. Kuantize edilmiş tensö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 değişmezleri, ASCII karakterleri ve kaçış dizileri kullanılarak belirtilen baytlardan oluşur. Kodlamadan bağımsız oldukları için bu baytların yorumlanması uygulamaya göre tanımlanır. Dize değişmezleri string türündedir.

İşlemler

abs

Anlam Bilimi

operand tensöründe öğe bazında mutlak değer işlemi gerçekleştirir ve result tensörünü üretir. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • İşaretli tam sayılar için: tam sayı modülü.
  • Kayan nokta sayıları için: IEEE-754'ten abs.
  • Karmaşık sayılar için: karmaşık modül.
  • Kuantize edilmiş 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 tensör ya da tensör başına nicemlenmiş tensör (C1-C2)

Çıkışlar

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

Sınırlamalar

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

Örnekler

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

 Diğer örnekler

add

Anlam Bilimi

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

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

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs Tensor veya nicelenmiş tensor (C1-C6)
(I2) rhs Tensor veya nicelenmiş tensor (C1-C5), (C7)

Çıkışlar

Ad Tür Sınırlamalar
result Tensor veya nicelenmiş tensor (C1-C7)

Sınırlamalar

  • İşlemde nicelendirilmemiş tensörler kullanılıyorsa:
    • (C1) type(lhs) = type(rhs) = type(result).
  • İşlemde nicel tensorlar 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 Bilimi

inputs üreten işlemlerin, result öğesine bağlı olan 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 kullanılır.

Girişler

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

Çı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 tablosundaki her işlem grubunda, her işlemden gelen operands tensörlerinin değerlerini all_gather_dim boyunca birleştirir ve results tensörleri oluşturur.

İşlem, StableHLO işlem ızgarasını process_groups olarak böler. Bu değer aşağıdaki şekilde tanımlanır:

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

Ardından, her bir process_group içinde:

  • process_group içindeki tüm receiver için operands...@receiver = [operand@sender for sender in process_group].
  • process_group içindeki 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 tensör veya tensör başına nicemlenmiş tensörler (C1), (C6)
(I2) all_gather_dim si64 türünde sabit (C1), (C6)
(I3) replica_groups si64 türünde 2 boyutlu tensör sabiti (C2-C4)
(I4) channel_id si64 türünde sabit (C5)
(I5) use_global_device_ids i1 türünde sabit (C5)

Çıkışlar

Ad Tür Sınırlamalar
results değişken sayıda tensör veya tensör başına nicemlenmiş tensö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 tablosundaki her işlem grubunda, her işlemden gelen operands tensörlerinin değerlerine bir indirgeme işlevi computation uygular ve results tensörleri üretir.

İşlem, StableHLO işlem ızgarasını process_groups olarak böler. Bu değer aşağıdaki şekilde tanımlanır:

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

Ardından, her bir process_group içinde:

  • results...@process[result_index] = exec(schedule) bazı ikili ağaçlar için schedule. Burada:
    • exec(node) = computation(exec(node.left), exec(node.right)).
    • exec(leaf) = leaf.value.
  • schedule, sıralı geçişi to_destination_type(operands...@process_group...[result_index], type(func_inputs(computation)[0])) olan, uygulamaya göre tanımlanmış bir ikili ağaçtır.

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
results değişken sayıda tensör veya tensör başına nicemlenmiş tensö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, (tensor<E>, tensor<E>) -> (tensor<E>) türünde. Burada is_promotable(element_type(operand), E).
  • (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 tensörlerinin 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 tensörleri oluşturur. İşlem, StableHLO işlem ızgarasını process_groups olarak böler. Bu değer aşağıdaki şekilde tanımlanır:

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

Ardından, her bir process_group içinde:

  • split_parts...@sender = split(operands...@sender, split_count, split_dimension) process_group içindeki tüm sender için.
  • scattered_parts...@receiver = [split_parts...@sender[receiver_index] for sender in process_group] where 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 tensör veya tensör başına nicemlenmiş tensörler (C1-C3), (C9)
(I2) split_dimension si64 türünde sabit (C1), (C2), (C9)
(I3) concat_dimension si64 türünde sabit (C3), (C9)
(I4) split_count si64 türünde sabit (C2), (C4), (C8), (C9)
(I5) replica_groups si64 türünde 2 boyutlu tensör sabiti (C5-C8)
(I6) channel_id si64 türünde sabit

Çıkışlar

Ad Tür Sınırlamalar
results değişken sayıda tensör veya tensör başına nicemlenmiş tensö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) type(results...) = type(operands...), split_dimension != concat_dimension koşulu hariç:
    • 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

lhs ve rhs tensörlerinin öğe bazında VE işlemini gerçekleştirir ve result tensörü 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: bit düzeyinde VE.

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result Boole veya tam sayı türünde tensö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 result tensörü oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

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

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result kayan noktalı veya karmaşık türde tensör ya da tensör başına nicemlenmiş tensö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

batch_norm_training'nın grad_output'den geri yayılım yapan çeşitli girişlerinin gradyanlarını hesaplar ve grad_operand, grad_scale ve grad_offset tensörlerini üretir. Daha resmi bir şekilde ifade etmek gerekirse bu işlem, Python söz dizimi kullanılarak mevcut StableHLO işlemlerine ayrıştırma olarak 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

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

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
grad_operand Kayan nokta türünde tensör veya tensör başına nicelenmiş tensör (C2), (C3)
grad_scale Kayan nokta veya tensör başına nicemlenmiş türde 1 boyutlu tensör (C2), (C4)
grad_offset Kayan nokta veya tensör başına nicemlenmiş türde 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'a sahiptir.
  • (C3) operand, grad_output ve grad_operand aynı şekle sahip.
  • (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 Bilimi

operand tensörünü, feature_index boyutu hariç tüm boyutlarda normalleştirir ve result tensörü üretir. Daha resmi bir şekilde, bu işlem Python söz dizimi kullanılarak mevcut StableHLO işlemlerine ayrıştırma olarak 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)

Kuantize edilmiş 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ünde tensör veya tensör başına nicelenmiş tensör (C1-C7)
(I2) scale Kayan nokta veya tensör başına nicemlenmiş türde 1 boyutlu tensör (C2), (C3)
(I3) offset Kayan nokta veya tensör başına nicemlenmiş türde 1 boyutlu tensör (C2), (C4)
(I4) mean Kayan nokta veya tensör başına nicemlenmiş türde 1 boyutlu tensör (C5)
(I5) variance Kayan nokta veya tensör başına nicemlenmiş türde 1 boyutlu tensör (C2), (C6)
(I6) epsilon f32 türünde sabit
(I7) feature_index si64 türünde sabit (C1), (C3-C6)

Çıkışlar

Ad Tür Sınırlamalar
result Kayan nokta türünde tensör veya tensör başına nicelenmiş 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'ye 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 tensörünü normalleştirerek output, batch_mean ve batch_var tensörlerini oluşturur. Daha resmi bir şekilde ifade etmek gerekirse bu işlem, 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

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

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
output Kayan nokta türünde tensör veya tensör başına nicelenmiş tensör (C7)
batch_mean Kayan nokta veya tensör başına kuantize edilmiş 1 boyutlu tensör (C2), (C5)
batch_var Kayan nokta veya tensör başına kuantize edilmiş 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'ye sahip.
  • (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 bit yayınlama işlemi gerçekleştirir ve result tensörü oluşturur. Bu tensörde, operand tensörünün tamamındaki bitler result tensörünün türü kullanılarak yeniden yorumlanır.

Daha resmi bir ifadeyle, E = element_type(operand), E' = element_type(result) ve R = rank(operand) verildiğinde:

  • 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 bellek içi gösterimini döndürür ve tensörlerin tam gösterimi uygulamaya bağlı olduğundan ve öğe türlerinin tam gösterimi de uygulamaya bağlı olduğundan davranışı uygulamaya bağlıdır.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand Tensor veya nicelenmiş tensor (C1-C2)

Çıkışlar

Ad Tür Sınırlamalar
result Tensor veya nicelenmiş tensor (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) değerleri verildiğinde:
    • num_bits(E') = num_bits(E) ise shape(result) = shape(operand).
    • Eğer num_bits(E') < num_bits(E):
    • rank(result) = R + 1.
    • dim(result, i) = dim(operand, i) tüm 0 <= i < R için.
    • dim(result, R) * num_bits(E') = num_bits(E).
    • Eğer num_bits(E') > num_bits(E):
    • rank(result) = R - 1.
    • dim(result, i) = dim(operand, i) tüm 0 <= i < R için.
    • 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 bilimi

broadcast_in_dim

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

  • operand_index[d] = 0 ise dim(operand, d) = 1.
  • Aksi takdirde operand_index[d] = result_index[broadcast_dimensions[d]].

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand Tensor veya nicelenmiş tensor (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 Tensor veya nicelenmiş tensor (C1), (C3), (C5-C6)

Sınırlamalar

  • (C1) element_type(result) tarafından verilir:
    • !is_per_axis_quantized(operand) ise element_type(operand).
    • element_type(operand) hariç olmak üzere quantization_dimension(operand), scales(operand) ve zero_points(operand), quantization_dimension(result), scales(result) ve zero_points(result)'den farklı olabilir. Aksi takdirde, sırasıyla.
  • (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

branches içindeki işlevlerden tam olarak birini index değerine bağlı olarak çalıştırıp çıkışı üretir. Daha resmi bir şekilde ifade etmek gerekirse, result = selected_branch() burada:

  • selected_branch = branches[index] ise 0 <= index < size(branches).
  • Aksi takdirde selected_branch = branches[-1].

Girişler

Şirket Ad Tür Sınırlamalar
(I1) index si32 türünde 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 sayıda tensör, nicelenmiş tensör veya jeton (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ünde öğe bazında küp kökü işlemi gerçekleştirir ve result tensörü oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

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

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result kayan noktalı veya karmaşık türde tensör ya da tensör başına nicemlenmiş tensö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 tensörünün öğe bazında tavanını alır ve result tensörü oluşturur. IEEE-754 spesifikasyonundaki roundToIntegralTowardPositive işlemini uygular. Kuantize edilmiş 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ünde tensör veya tensör başına nicelenmiş tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result Kayan nokta türünde tensör veya tensör başına nicelenmiş 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 bilimi

Bir grup matrisin Cholesky ayrıştırması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 Cholesky ayrışımıdır ve alt üçgen (lower, true ise) veya üst üçgen (lower, false ise) matris biçimindedir. Karşı üçgendeki çıkış değerleri (sırasıyla kesin üst üçgen veya kesin alt üçgen) uygulamaya göre tanımlanır.

Giriş matrisinin Hermitian pozitif tanımlı matris olmadığı i varsa davranış tanımlanmamıştır.

Kuantize edilmiş türler için dequantize_op_quantize(lambda operand: cholesky(operand, lower), a, type(result)) işlemini gerçekleştirir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) a kayan noktalı veya karmaşık türde tensör ya da tensör başına nicemlenmiş tensör (C1-C3)
(I2) lower i1 türünde sabit

Çıkışlar

Ad Tür Sınırlamalar
result kayan noktalı veya karmaşık türde tensör ya da tensör başına nicemlenmiş tensö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]
//          ]

sıkıştırma

Anlam Bilimi

operand tensörünün her öğesini minimum ve maksimum değer arasında sıkıştırır ve result tensörü 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]. Kuantize edilmiş türler için dequantize_op_quantize(clamp, min, operand, max, type(result)) işlemi yapılır.

Karmaşık sayılara sıralama uygulamak şaşırtıcı bir anlambilim içerir. Bu nedenle, gelecekte bu işlem için karmaşık sayı 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 kuantize edilmiş tensör (C1), (C3)
(I2) operand tensör veya tensör başına kuantize edilmiş tensör (C1-C4)
(I3) max tensör veya tensör başına kuantize edilmiş tensör (C2), (C3)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına kuantize edilmiş 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 tablosundaki her işlem grubunda, kaynak işlemden hedef işlemlere operand tensörünün değerini gönderin ve result tensörü oluşturun.

İşlem, StableHLO işlem ızgarasını process_groups olarak böler. Bu değer aşağıdaki şekilde tanımlanır:

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

Daha sonra result@process şu şekilde verilir:

  • operand@process_groups[i, 0] varsa süreç i içinde yer alır.process_groups[i]
  • 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 kuantize edilmiş tensör (C3)
(I2) replica_groups si64 türünde 1 boyutlu tensör sabitlerinin değişken sayıda (C1), (C2)
(I3) channel_id si64 türünde sabit

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına kuantize edilmiş 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, kaynak işlemden hedef işleme operand tensörünün değerini gönderir ve result tensörü oluşturur.

İşlem, StableHLO işlem ızgarasını process_groups olarak böler. Bu değer aşağıdaki şekilde tanımlanır:

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

Daha sonra result@process şu şekilde verilir:

  • operand@process_groups[i, 0], process_groups[i, 1] = process olacak şekilde 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 tensör veya tensör başına kuantize edilmiş tensör (C5)
(I2) source_target_pairs si64 türünde 2 boyutlu tensör sabiti (C1-C4)
(I3) channel_id si64 türünde sabit

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına kuantize edilmiş 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 tensörlerini comparison_direction ve compare_type'ye göre öğe bazında karşılaştırır ve result tensörü oluşturur.

comparison_direction ve compare_type değerleri aşağıdaki anlamsal özelliklere 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 ile kayan nokta öğesi türleri için işlem, aşağıdaki IEEE-754 işlemlerini uygular:

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

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

Karmaşık öğe türlerinde, sağlanan comparison_direction ve compare_type kullanılarak (real, imag) çiftlerinin sözlük sırasına göre karşılaştırması yapılır. Karmaşık sayılara sıralama uygulamak şaşırtıcı bir semantiğe yol açar. Bu nedenle, gelecekte comparison_direction değeri GE, GT, LE veya LT olduğunda karmaşık sayı desteğini kaldırmayı planlıyoruz (#560).

Kuantize edilmiş 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 tensör veya tensör başına kuantize edilmiş tensör (C1-C3)
(I2) rhs tensör veya tensör başına kuantize edilmiş tensör (C1-C2)
(I3) comparison_direction EQ, NE, GE, GT, LE ve LT numaralandırması
(I4) compare_type FLOAT, TOTALORDER, SIGNED ve UNSIGNED numaralandırması (C3)

Çıkışlar

Ad Tür Sınırlamalar
result Boole türünde 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:
    • SIGNED ise is_signed_integer(element_type(lhs)).
    • UNSIGNED ise is_unsigned_integer(element_type(lhs)) or is_boolean(element_type(lhs)).
    • FLOAT veya TOTALORDER ise is_float(element_type(lhs)).
    • FLOAT ise is_complex(element_type(lhs)).

Ö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 Bilimi

Gerçek ve hayali değerler çifti olan lhs ve rhs değerlerinden karmaşık bir değere öğe bazında dönüştürme işlemi gerçekleştirir ve result tensörünü oluşturur.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs f32 veya f64 türünde tensör (C1-C3)
(I2) rhs f32 veya f64 türünde 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ğu durumlarda complex<E> türündedir.

Ö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

Diğer StableHLO işlemlerinden oluşan bir işlemi kapsar. inputs ve composite_attributes değerlerini alır ve results değerini üretir. İşlemin anlamı, decomposition özelliğiyle uygulanır. composite işlemi, program semantiğini değiştirmeden ayrıştırılmış haliyle değiştirilebilir. Ayrıştırmanın satır içine yerleştirilmesi aynı işlem semantiğini sağlamadığı durumlarda custom_call kullanmayı tercih edin.

version alanı (varsayılan olarak 0) bir bileşenin semantiğinin ne zaman değiştiğini belirtmek için kullanılır.

Girişler

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

Çıkışlar

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

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ştir

Anlam Bilimi

Verilen bağımsız değişkenlerle aynı sırada inputs boyutunda dimension boyutunu birleştirir ve result tensörü oluşturur. Daha resmi bir şekilde ifade etmek gerekirse, result[i0, ..., id, ..., iR-1] = inputs[k][i0, ..., kd, ..., iR-1], burada:

  1. id = d0 + ... + dk-1 + kd.
  2. d, dimension değerine eşittir ve d0, ... inputs öğesinin d. boyutunun 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 nicemlenmiş tensörler (C1-C6)
(I2) dimension si64 türünde sabit (C2), (C4), (C6)

Çıkışlar

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

Sınırlamalar

  • (C1) same(element_type(inputs...)).
  • (C2) same(shape(inputs...)) hariç dim(inputs..., dimension).
  • (C3) 0 < size(inputs).
  • (C4) 0 <= dimension < rank(inputs[0]).
  • (C5) element_type(result) = element_type(inputs[0]).
  • (C6) shape(result) = shape(inputs[0]) şu durumlar hariç:
    • 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 Bilimi

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 Tensor veya nicelenmiş tensor (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 Bilimi

operand tensöründe bir öğe türünden diğerine öğe bazında dönüştürme işlemi gerçekleştirir ve result tensörü oluşturur.

boolean-to-any-supported-type (Boolean'dan desteklenen herhangi bir türe) dönüşümlerinde false değeri sıfıra, true değeri ise bire dönüştürülür. any-supported-type-to-boolean dönüşümlerinde sıfır değeri false, sıfır olmayan değerler ise true olarak dönüştürülür. Karmaşık türlerde bu işlemin nasıl çalıştığını öğrenmek için aşağıya bakın.

Tam sayıdan tam sayıya, tam sayıdan kayan noktalı sayıya veya kayan noktalı sayıdan kayan noktalı sayıya dönüşümlerde kaynak değer hedef türde tam olarak gösterilebiliyorsa sonuç değeri bu tam gösterimdir. Aksi takdirde davranış henüz belli değil (#180).

floating-point-to-integer dönüştürme işlemlerinde kesirli kısım kesilir. Kısaltılmış değer hedef türde gösterilemiyorsa davranış belirlenir (TBD) (#180).

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

Karmaşıktan diğer tüm türlere ve diğer tüm türlerden karmaşığa dönüşümlerde kaynak hayali değer yok sayılır veya hedef hayali değer sıfırlanır. Gerçek bölümün dönüştürülmesi, kayan nokta dönüştürmelerini izler.

Bu işlem, prensip olarak nicelikten arındırma (nicelikli tensörlerden normal tensörlere dönüştürme), niceliklendirme (normal tensörlerden nicelikli tensörlere dönüştürme) ve yeniden niceliklendirme (nicelikli tensörler arasında dönüştürme) işlemlerini ifade edebilir. Ancak şu anda bu işlemler için özel işlemlerimiz var: uniform_dequantize ilk kullanım alanı için, uniform_quantize ise ikinci ve üçüncü kullanım alanları için. Gelecekte bu iki işlem convert (#1576) içinde birleştirilebilir.

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 üretir. Aşağıdaki şemada, result içindeki öğelerin lhs ve rhs değerlerinden nasıl hesaplandığı somut bir örnekle gösterilmektedir.

konvolüsyon

Daha resmi bir şekilde, lhs zaman aralıklarını ifade edebilmek için girişlerin lhs cinsinden aşağıdaki gibi 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] / 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 olur. Burada:

  • 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 özellik kullanılmıyor gibi görünüyor. Bu nedenle, gelecekte 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]).

Eğer feature_group_count > 1:

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

Eğer batch_group_count > 1:

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

Kuantize edilmiş 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 nicelenmiş 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 tensör veya tensör başına kuantize edilmiş tensör (C1), (C10-C11), (C14) (C25), (C27-C28), (C31-C32), (C34)
(I2) rhs Tensor veya nicelenmiş tensor (C1), (C14-C16), (C25), (C27-C29), (C31-C34)
(I3) window_strides si64 türünde 1 boyutlu tensör sabiti (C2-C3), (C25)
(I4) padding si64 türünde 2 boyutlu tensör sabiti (C4), (C25)
(I5) lhs_dilation si64 türünde 1 boyutlu tensör sabiti (C5-C6), (C25)
(I6) rhs_dilation si64 türünde 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ünde sabit (C10), (C13), (C25)
(I9) input_feature_dimension si64 türünde sabit (C11), (C13-C14)
(I10) input_spatial_dimensions si64 türünde 1 boyutlu tensör sabiti (C12), (C13), (C25)
(I11) kernel_input_feature_dimension si64 türünde sabit (C14), (C18)
(I12) kernel_output_feature_dimension si64 türünde sabit (C15-C16), (C18), (C25), (C29)
(I13) kernel_spatial_dimensions si64 türünde 1 boyutlu tensör sabiti (C17-C18), (C25)
(I14) output_batch_dimension si64 türünde sabit (C20), (C25)
(I15) output_feature_dimension si64 türünde sabit (C20), (C25), (C30)
(I16) output_spatial_dimensions si64 türünde 1 boyutlu tensör sabiti (C19-C20), (C25)
(I17) feature_group_count si64 türünde sabit (C11), (C14), (C16), (C21), (C23)
(I18) batch_group_count si64 türünde sabit (C10), (C15), (C22), (C23), (C25)
(I19) precision_config DEFAULT, HIGH ve HIGHEST değerlerinin değişken sayıda enum'ı (C24)

Çıkışlar

Ad Tür Sınırlamalar
result Tensor veya nicelenmiş tensor (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] verildi:
    • 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] verildi:
    • is_unique(kernel_dimensions).
    • 0 <= kernel_dimensions < N.
  • (C19) size(output_spatial_dimensions) = N - 2.
  • (C20) Verilen output_dimensions = [output_batch_dimension] + output_spatial_dimensions + [output_feature_dimension]:
    • is_unique(output_dimensions).
    • 0 <= output_dimensions < N.
  • (C21) 0 < feature_group_count.
  • (C22) 0 < batch_group_count.
  • (C23) feature_group_count = 1 or batch_group_count = 1.
  • (C24) size(precision_config) = 2.
  • (C25) dim(result, result_dim) şu şekilde tanımlanır:
    • dim(lhs, input_batch_dimension) / batch_group_count ise result_dim = output_batch_dimension.
    • dim(rhs, kernel_output_feature_dimension) ise result_dim = output_feature_dimension.
    • Aksi takdirde num_windows, şu durumlarda:
    • 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 nicelendirilmemiş tensörler kullanılıyorsa:
    • (C27) element_type(lhs) = element_type(rhs) = element_type(result).
  • İşlemde nicel tensorlar 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) Eğer 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ünde öğe bazında kosinüs işlemi gerçekleştirir ve result tensörü oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

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

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result kayan noktalı veya karmaşık türde tensör ya da tensör başına nicemlenmiş tensö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 tensordaki baştaki sıfır bitlerinin sayısını öğe bazında hesaplar ve result tensörü oluşturur.

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result tam sayı türünde 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

call_target_name ile tanımlanan, inputs ve called_computations alan ve results üreten bir işlemi kapsar. has_side_effect, backend_config ve api_version, ek uygulama tanımlı meta veriler sağlamak için kullanılabilir.

Şu anda bu işlem, XLA derleyicisindeki benzer işlemin 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 sayıda değer
(I2) call_target_name string türünde sabit
(I3) has_side_effect i1 türünde sabit
(I4) backend_config string türünde sabit veya özellik sözlüğü
(I5) api_version si32 türünde sabit
(I6) called_computations string türünde değişken sayıda sabit
(I7) output_operand_aliases Çıkışlarda ve işlenenlerde diğer adlandırma yapılan kısımları belirtin.

Çıkışlar

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

(XLA GPU Desteği) Özel custom_call hedefleri

buffer türleriyle ilgili üç özel call_target_name vardır: CreateBuffer başlatılmamış bir buffer oluşturur, Pin başlatılmış bir buffer oluşturur ve Unpin bir buffer'nin yerini kaldırıp buffer'nin içeriğini döndürür.

%uninitialized_buffer = "stablehlo.custom_call"() {
  call_target_name = "CreateBuffer",
  api_version = 4 : i32,
} : () -> memref<4xf64>

%initialized_buffer = "stablehlo.custom_call"(%init_value) {
  call_target_name = "Pin",
  api_version = 4 : i32,
} : (tensor<4xf64>) -> memref<4xf64>

%dealloc_buffer = "stablehlo.custom_call"(%initialized_buffer) {
  call_target_name = "Unpin",
  api_version = 4 : i32,
} : (memref<4xf64>) -> tensor<4xf64>

Takma ad

Bazı custom_call işlemleri, çıkışlarda bir bölümün ve işlenenlerde bir bölümün aynı belleği paylaşmasını gerektirebilir. Bu durum, output_operand_aliases ile ifade edilebilir. Bir takma ad çifti gösterimi, çıkış kısmını temsil eden çıkış demeti dizinlerinin bir listesinden ve işlenen kısmını temsil eden işlenen demeti dizinlerinin bir listesiyle birlikte bir operand_index'ten oluşur. İlgili tür bir tuple türü değilse çıkış veya işlenen demeti dizinlerinin listesi boştur ve rastgele iç içe yerleştirilmiş bir demet türü için rastgele uzun olabilir. Bu, XLA takma ad gösterimine benzer.

Bir takma ad çiftindeki çıkış kısmı ve giriş kısmı aynı türde olmalıdır. CreateBuffer, Pin ve Unpin'a yapılan çağrı olmayan özel çağrı işlemleri için buffer işleneni en fazla bir takma ad çiftinde görünebilir ve buffer çıkışı bir takma ad çiftinde görünmelidir.

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

%updated_buffer = "stablehlo.custom_call"(%buffer) {
  call_target_name = "Update",
  api_version = 4 : i32,
  output_operand_aliases = [
    #stablehlo.output_operand_alias<output_tuple_indices = [],
      operand_index = 0,
      operand_tuple_indices = []>]
} : (memref<4xf64>) -> memref<4xf64>

bölü

Anlam bilimi

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

  • Tam sayılar için: Kesir kısmı atılarak cebirsel bölümü üreten tam sayı bölme.
  • Kayan nokta sayıları için: IEEE-754'ten division.
  • Karmaşık sayılar için: karmaşık bölme.
  • Kuantize edilmiş 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ürde tensör ya da tensör başına nicemlenmiş tensör (C1)
(I2) rhs Tam sayı, kayan nokta veya karmaşık türde tensör ya da tensör başına nicemlenmiş tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result Tam sayı, kayan nokta veya karmaşık türde tensör ya da tensör başına nicelenmiş 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 dilimleri ile rhs dilimleri arasındaki iç çarpımları hesaplar ve result tensörü oluşturur.

Daha resmi bir ifadeyle 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)).

Kuantize edilmiş 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 nicelenmiş 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ız ile doğruluk arasındaki dengeyi kontrol eder. Bu, aşağıdakilerden biri olabilir (Şu anda bu enum değerlerinin semantiği yeterince belirtilmemiştir ancak #755 numaralı sorunda bu konuyu ele almayı planlıyoruz):

  • DEFAULT: En hızlı hesaplama ancak orijinal sayıya en az doğru yaklaşım.
  • HIGH: Daha yavaş hesaplama ancak orijinal sayıya daha doğru yaklaşım.
  • HIGHEST: En yavaş hesaplama ancak orijinal sayıya en yakın tahmin.

DotAlgorithm, nokta işlemini uygulamak için kullanılan algoritmanın temel özelliklerini tanımlar. Bu özellikler, hassasiyeti de tanımlar. Algoritma özelliği alanları ayarlanırsa precision_config, DEFAULT olmalıdır. DotAlgorithms Varsayılan parametreler uygulamaya göre tanımlandığından varsayılan bir değere sahip değildir. Bu nedenle, tüm nokta algoritması alanları, boş bir nokta algoritması belirtmek için None olarak ayarlanabilir. Bu durumda, precision_config değeri kullanılır.

DotAlgorithm alanları şunlardır:

  • lhs_precision_type ve rhs_precision_type, işlemin sol ve sağ tarafının yuvarlandığı duyarlılıklar. Kesinlik türleri, girişlerin ve çıkışın depolama türlerinden bağımsızdır.
  • accumulation_type Birikim 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 uyguladığımızda geçerlidir. Bu genellikle daha yüksek bir hassasiyeti taklit etmek için yapılır (ör. 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.
  • allow_imprecise_accumulation, bazı adımlarda (ör. CUBLASLT_MATMUL_DESC_FAST_ACCUM) daha düşük hassasiyette birikime izin verilip verilmeyeceğini belirtmek için kullanılır.

Ö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 destekleneceğine uygulamalar karar verir. Genel olarak, StableHLO tüketicisi tarafından her hızlandırıcı türünde her algoritmanın destekleneceği garanti edilmez. Belirli bir algoritma desteklenmiyorsa alternatif bir algoritma kullanılmak yerine hata verilmelidir. StableHLO doğrulaması, herhangi bir donanımda desteklendiği bilinmeyen algoritmaları engelleyerek en iyi çaba doğrulaması sağlar.

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 algoritmalarla ilgili merkezi bir doküman oluşturma planını içerir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs tensör veya tensör başına kuantize edilmiş tensör (C5-C6), (C9-C10), (C12-C14), (C17-C18), (C20)
(I2) rhs Tensor veya nicelenmiş tensor (C7-C10), (C12-C20)
(I3) lhs_batching_dimensions si64 türünde 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ünde 1 boyutlu tensör sabiti (C2), (C4), (C8), (C10), (C16)
(I7) precision_config DEFAULT, HIGH ve HIGHEST değerlerinin 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ünde sabit (C21), (C22)
(I12) rhs_component_count si32 türünde sabit (C21), (C23)
(I13) num_primitive_operations si32 türünde sabit (C21), (C24)
(I14) allow_imprecise_accumulation bool türünde sabit (C21)

Çıkışlar

Ad Tür Sınırlamalar
result Tensor veya nicelenmiş tensor (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 nicelendirilmemiş tensörler kullanılıyorsa:
    • (C13) element_type(lhs) = element_type(rhs).
  • İşlemde nicel tensorlar 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ğil.
    • Eğer is_quantized(lhs):
    • (C17) storage_type(lhs) = storage_type(rhs).
    • (C18) expressed_type(lhs) = expressed_type(rhs) = expressed_type(result).
    • (C19) Eğer is_per_tensor_quantized(rhs) ise is_per_tensor_quantized(result).
    • Eğer !is_quantized(lhs):
    • (C20) element_type(lhs) = expressed_type(rhs) = element_type(result).
  • !is_empty_algorithm(lhs_precision_type, rhs_precision_type, accumulation_type, lhs_component_count, rhs_component_count, num_primitive_operations allow_imprecise_accumulation) 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, işlevsel olarak broadcast_in_dim işlemine eşdeğerdir ancak sonuç şekli output_dimensions aracılığıyla dinamik olarak belirtilir.

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

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand Tensor veya nicelenmiş tensor (C1-C2), (C5-C6), (C9)
(I2) output_dimensions Tam sayı türünde 1 boyutlu tensö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ünde 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 Tensor veya nicelenmiş tensor (C1), (C3), (C5-C7)

Sınırlamalar

  • (C1) element_type(result) tarafından verilir:
    • !is_per_axis_quantized(operand) ise element_type(operand).
    • element_type(operand) hariç olmak üzere quantization_dimension(operand), scales(operand) ve zero_points(operand), quantization_dimension(result), scales(result) ve zero_points(result)'den farklı olabilir. Aksi takdirde, sırasıyla.
  • (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 convolution op ile aynıdır ancak dolgu, padding aracılığıyla dinamik olarak belirtilir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs tensör veya tensör başına kuantize edilmiş tensör (C1), (C10-C11), (C14) (C25), (C26-C27), (C30-C31), (C33)
(I2) rhs Tensor veya nicelenmiş tensor (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ünde 1 boyutlu tensör sabiti (C2-C3)
(I5) lhs_dilation si64 türünde 1 boyutlu tensör sabiti (C5-C6)
(I6) rhs_dilation si64 türünde 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ünde sabit (C10), (C13)
(I9) input_feature_dimension si64 türünde 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ünde sabit (C14), (C18)
(I12) kernel_output_feature_dimension si64 türünde sabit (C15-C16), (C18), (C28)
(I13) kernel_spatial_dimensions si64 türünde 1 boyutlu tensör sabiti (C17-C18)
(I14) output_batch_dimension si64 türünde sabit (C20)
(I15) output_feature_dimension si64 türünde sabit (C20), (C29)
(I16) output_spatial_dimensions si64 türünde 1 boyutlu tensör sabiti (C19-C20)
(I17) feature_group_count si64 türünde sabit (C11), (C14), (C16), (C21), (C23)
(I18) batch_group_count si64 türünde sabit (C10), (C15), (C22), (C23)
(I19) precision_config DEFAULT, HIGH ve HIGHEST değerlerinin değişken sayıda enum'ı (C24)

Çıkışlar

Ad Tür Sınırlamalar
result Tensor veya nicelenmiş tensor (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] verildi:
    • 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] verildi:
    • is_unique(kernel_dimensions).
    • 0 <= kernel_dimensions < N.
  • (C19) size(output_spatial_dimensions) = N - 2.
  • (C20) Verilen output_dimensions = [output_batch_dimension] + output_spatial_dimensions + [output_feature_dimension]:
    • is_unique(output_dimensions).
    • 0 <= output_dimensions < N.
  • (C21) 0 < feature_group_count.
  • (C22) 0 < batch_group_count.
  • (C23) feature_group_count = 1 or batch_group_count = 1.
  • (C24) size(precision_config) = 2.
  • (C25) dim(result, result_dim) şu şekilde tanımlanır:
    • dim(lhs, input_batch_dimension) / batch_group_count ise result_dim = output_batch_dimension.
    • dim(rhs, kernel_output_feature_dimension) ise result_dim = output_feature_dimension.
    • Aksi takdirde num_windows, şu durumlarda:
    • 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 nicelendirilmemiş tensörler kullanılıyorsa:
    • (C27) element_type(lhs) = element_type(rhs) = element_type(result).
  • İşlemde nicel tensorlar 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) Eğer 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ğerinin dinamik olarak belirtildiği gather işlemine işlevsel olarak eşdeğerdir.

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına kuantize edilmiş tensör (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) where:
    • batch_dim_sizes = shape(start_indices) hariç. index_vector_dim ile eşleşen start_indices boyutunun boyutu dahil değildir.
    • offset_dim_sizes = shape(slice_sizes), collapsed_slice_dims ile eşleşen slice_sizes boyutları hariç.
    • combine, batch_dim_sizes değerini batch_dims değerine karşılık gelen eksenlere, offset_dim_sizes değerini ise offset_dims değerine 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 bilimi

Bu işlem, işlevsel olarak iota op ile aynıdır 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ünde 1 boyutlu tensö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 tensör ya da tensör başına nicelenmiş 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şlemine eşdeğerdir 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 kuantize edilmiş tensör (C1), (C2), (C4)
(I2) padding_value 0 boyutlu tensör veya tensör başına nicelenmiş tensör (C1)
(I3) edge_padding_low Tam sayı türünde 1 boyutlu tensö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ünde 1 boyutlu tensör (C2-C4)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına kuantize edilmiş 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 Bilimi

Bu işlem, işlevsel olarak reshape işlemine eşdeğerdir ancak sonuç şekli output_shape aracılığıyla dinamik olarak belirtilir.

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result Tensor veya nicelenmiş tensor (C1-C4)

Sınırlamalar

  • (C1) element_type(result) tarafından verilir:
    • !is_per_axis_quantized(operand) ise element_type(operand).
    • element_type(operand) dışında 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 Bilimi

Dinamik olarak hesaplanan başlangıç dizinlerini kullanarak operand öğesinden bir dilim çıkarır ve result tensörü oluşturur. start_indices, olası ayarlamaya tabi her boyut için dilimin başlangıç dizinlerini, slice_sizes ise her boyut için dilimin boyutlarını içerir. Daha resmi bir dille ifade etmek gerekirse, 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 kuantize edilmiş tensör (C1), (C2), (C4)
(I2) start_indices 0 boyutlu tam sayı türünde tensörlerin değişken sayısı (C2), (C3)
(I3) slice_sizes si64 türünde 1 boyutlu tensör sabiti (C2), (C4), (C5)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına kuantize edilmiş tensör (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

result tensörünü oluşturur. Bu tensör, start_indices ile başlayan dilimin update değerleriyle güncellenmesi dışında operand tensörüne eşittir. Daha resmi bir şekilde result[result_index] şu şekilde tanımlanır:

  • update[update_index] ise 0 <= update_index < shape(update) burada:
    • 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 tensör veya tensör başına kuantize edilmiş tensör (C1-C4), (C6)
(I2) update tensör veya tensör başına kuantize edilmiş tensör (C2), (C3), (C6)
(I3) start_indices 0 boyutlu tam sayı türünde 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 kuantize edilmiş 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 tensöründe öğe bazında üstel işlem gerçekleştirir ve result tensörü oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

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

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result kayan noktalı veya karmaşık türde tensör ya da tensör başına nicemlenmiş tensö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 tensöründe öğe bazında üstel eksi bir işlemi gerçekleştirir ve result tensörü oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • Kayan nokta sayıları için: IEEE-754'ten expm1.
  • Karmaşık sayılar için: karmaşık üstel eksi bir.
  • Kuantize edilmiş 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 noktalı veya karmaşık türde tensör ya da tensör başına nicemlenmiş tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result kayan noktalı veya karmaşık türde tensör ya da tensör başına nicemlenmiş tensö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/çıkışlar için ileri ve ters Fourier dönüşümlerini gerçekleştirir.

fft_type aşağıdakilerden biri olmalıdır:

  • FFT: Karmaşık-karmaşık FFT'yi iletme.
  • IFFT: Ters karmaşık-karmaşık FFT.
  • RFFT: Gerçekten karmaşık FFT'yi iletme.
  • IRFFT: Gerçekten karmaşığa ters FFT (yani karmaşık alır, gerçek döndürür).

Daha resmi bir ifadeyle, giriş olarak karmaşık türlerdeki 1 boyutlu tensörleri alan, çıkış olarak aynı türlerdeki 1 boyutlu tensörleri üreten ve ayrık Fourier dönüşümünü hesaplayan fft fonksiyonu verildiğinde:

fft_type = FFT için result, L = size(fft_length) olduğu 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ürlerinin 1 boyutlu tensörlerini alır, aynı kayan nokta semantiğinin karmaşık türlerinin 1 boyutlu tensörlerini üretir 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)].

(Ayrık Fourier dönüşümü gerçek işlenenler için hesaplandığında, sonucun ilk N/2 + 1 öğesi, sonucun geri kalanını net bir şekilde tanımlar. Bu nedenle, gereksiz öğelerin hesaplanmasını önlemek için rfft sonucu kesilir.)

fft_type = RFFT için result, L = size(fft_length) olduğu 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 imzasına sahip olan ve rfft işlevinin tersini hesaplayan irfft işlevini göz önünde bulundurun:

fft_type = IRFFT için result, fft_type = RFFT 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, ..., :] = 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 numaralandırması (C2), (C5)
(I3) fft_length si64 türünde 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 ve result öğe türleri arasındaki ilişki değişir:
    • 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), kayan nokta türü ve element_type(result), aynı kayan nokta semantiğine sahip karmaşık bir türdür.
    • fft_type = IRFFT ise element_type(operand) karmaşık bir türdür ve element_type(result), aynı kayan nokta semantiğine sahip bir kayan nokta türüdür.
  • (C3) 1 <= size(fft_length) <= 3.
  • (C4) operand ve result arasında kayan nokta türünde bir tensör real varsa shape(real)[-size(fft_length):] = fft_length.
  • (C5) shape(result) = shape(operand) hariç:
    • 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)]

taban

Anlam bilimi

operand tensörünün öğe bazında tabanını alır ve result tensörü üretir. IEEE-754 spesifikasyonundaki roundToIntegralTowardNegative işlemini uygular. Kuantize edilmiş türler için dequantize_op_quantize(floor, operand, type(result)) işlemini gerçekleştirir.

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result Kayan nokta türünde tensör veya tensör başına nicelenmiş 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

toplama

Anlam bilimi

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

Aşağıdaki şemada, result içindeki öğelerin operand içindeki öğelerle nasıl eşlendiği somut bir örnekle gösterilmektedir. Diyagramda birkaç örnek result indeks seçilerek hangi operand indekslere karşılık geldikleri ayrıntılı olarak açıklanmaktadır.

toplama

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 dizinine eklenir.
    • Aksi takdirde [start_indices[batch_index]].
  • 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]) if d_operand = start_index_map[d_start].
    • 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)] if d_operand = operand_batching_dims[i_batching] ve d_start = start_indices_batching_dims[i_batching].
    • Aksi takdirde full_batching_index[d_operand] = 0.
  • 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 indekslere eklenir.
  • operand_index = full_start_index + full_batching_index + full_offset_index.

indices_are_sorted, true ise uygulama, start_indices değerlerinin start_index_map'ye göre sıralandığını varsayabilir. Aksi takdirde davranış tanımlanmamıştır. Daha resmi bir ifadeyle, indices(result) ile i1 < i2 arasındaki tüm full_start_index(i1) <= full_start_index(i2) için geçerlidir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand tensör veya tensör başına kuantize edilmiş tensör (C1), (C8), (C11), (C17), (C19-C21), (C23)
(I2) start_indices tam sayı türünde tensör (C2-C3), (C14), (C17), (C22)
(I3) offset_dims si64 türünde 1 boyutlu tensör sabiti (C1), (C4-C5), (C22)
(I4) collapsed_slice_dims si64 türünde 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ünde 1 boyutlu tensör sabiti (C13-C17)
(I7) start_index_map si64 türünde 1 boyutlu tensör sabiti (C3), (C18-C19)
(I8) index_vector_dim si64 türünde sabit (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ünde sabit

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına kuantize edilmiş 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) hariç. index_vector_dim ile eşleşen start_indices boyutunun boyutu dahil değildir.
    • offset_dim_sizes = slice_sizes hariç olmak üzere, collapsed_slice_dims ve operand_batching_dims ile ilişkili slice_sizes içindeki boyutlar dahil değildir.
    • combine, batch_dim_sizes değerini batch_dims değerine karşılık gelen eksenlere, offset_dim_sizes değerini ise offset_dims değerine 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

Belirtilen dimension değerinin operand boyutunu üretir. Daha resmi bir şekilde, result = dim(operand, dimension). Semantik 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 Tensor veya nicelenmiş tensor (C1)
(I2) dimension si64 türünde sabit (C1)

Çıkışlar

Ad Tür
result si32 türünde 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 demetinin index konumundaki öğeyi çıkarır ve result oluşturur. 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ünde sabit (C1), (C2)

Çıkışlar

Ad Tür Sınırlamalar
result herhangi bir değer (C2)

Sınırlamalar

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

Örnekler

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

 Diğer örnekler

koşul:

Anlam bilimi

true_branch veya false_branch işlevlerinden tam olarak birini pred değerine bağlı olarak çalıştırıp çıkışı üretir. Daha resmi bir ifadeyle result = pred ? true_branch() : false_branch().

Girişler

Şirket Ad Tür Sınırlamalar
(I1) pred i1 türünde 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 tensör, nicelenmiş tensö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

Sanal kısmı operand öğesinden öğe bazında çıkarır ve result tensörü oluşturur. Daha resmi bir ifadeyle, her x öğesi için: 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ünde tensör (C1), (C2)

Sınırlamalar

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

Ö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

infeed

Anlam Bilimi

Feed içi reklamdan verileri okur ve results oluşturur.

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

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

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
results değişken sayıda tensör, nicelenmiş tensö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 Bilimi

output tensörünü, iota_dimension boyutu boyunca sıfırdan başlayarak artan sırada değerlerle doldurur. Daha resmi bir dille 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 tensör ya da tensör başına nicelenmiş 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 içindeki değerin sonlu (yani +Inf, -Inf veya NaN olmayan) olup olmadığını öğe bazında kontrol eder ve y tensörü oluşturur. IEEE-754 spesifikasyonundaki isFinite işlemini uygular. Kuantize edilmiş türler için sonuç her zaman true olur.

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
y Boole türünde 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 bilimi

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

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

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result kayan noktalı veya karmaşık türde tensör ya da tensör başına nicemlenmiş tensö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 Bilimi

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

  • Kayan nokta sayıları için: IEEE-754'ten logp1.
  • Karmaşık sayılar için: complex(log(hypot(real(x) + 1, imag(x))), atan2(imag(x), real(x) + 1))
  • Kuantize edilmiş 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 noktalı veya karmaşık türde tensör ya da tensör başına nicemlenmiş tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result kayan noktalı veya karmaşık türde tensör ya da tensör başına nicemlenmiş tensö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

lojistik

Anlam Bilimi

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

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

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result kayan noktalı veya karmaşık türde tensör ya da tensör başına nicemlenmiş tensö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

computation harita işlevini dimensions boyunca inputs öğesine uygular ve result tensörünü oluşturur.

Daha resmi bir ifadeyle result[result_index] = computation(inputs...[result_index]).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) inputs değişken sayıda tensör veya tensör başına nicemlenmiş tensö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 tensör veya tensör başına kuantize edilmiş tensör (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 Bilimi

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

  • Boole değerleri için: mantıksal VEYA.
  • Tam sayılar için: maksimum tam sayı.
  • Kayan nokta sayıları için: IEEE-754'ten maximum.
  • Karmaşık sayılar için: (real, imaginary) çifti için sözlükbilimsel maksimum. Karmaşık sayılara sıralama uygulamak şaşırtıcı bir anlambilim içerir. Bu nedenle, gelecekte bu işlem için karmaşık sayı desteğini kaldırmayı planlıyoruz (#560).
  • Kuantize edilmiş türler için:
    • dequantize_op_quantize(maximum, lhs, rhs, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs tensör veya tensör başına kuantize edilmiş tensör (C1)
(I2) rhs tensör veya tensör başına kuantize edilmiş tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına kuantize edilmiş 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 bilimi

lhs ve rhs tensörlerinde öğe bazında minimum işlemi gerçekleştirir ve result tensörü 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 nokta sayıları için: IEEE-754'ten minimum.
  • Karmaşık sayılar için: (real, imaginary) çiftinin sözlükbilimsel minimum değeri. Karmaşık sayılara sıralama uygulamak şaşırtıcı bir anlambilim içerir. Bu nedenle, gelecekte bu işlem için karmaşık sayı desteğini kaldırmayı planlıyoruz (#560).
  • Kuantize edilmiş türler için:
    • dequantize_op_quantize(minimum, lhs, rhs, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs tensör veya tensör başına kuantize edilmiş tensör (C1)
(I2) rhs tensör veya tensör başına kuantize edilmiş tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına kuantize edilmiş 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 bilimi

İki tensörün (lhs ve rhs) öğe bazında çarpımını gerçekleştirir ve result tensörü 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: tam sayı çarpımı.
  • Kayan nokta sayıları için: IEEE-754'ten multiplication.
  • Karmaşık sayılar için: karmaşık çarpma.
  • Kuantize edilmiş türler için:
    • dequantize_op_quantize(multiply, lhs, rhs, type(result)).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs tensör veya tensör başına kuantize edilmiş tensör (C1)
(I2) rhs tensör veya tensör başına kuantize edilmiş tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına kuantize edilmiş 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 tensörünün öğe bazında olumsuzlamasını yapar ve result tensörü oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • İşaretli tam sayılar için: tam sayı olumsuzlaması.
  • İşaretsiz tam sayılar için: bitcast to signed integer, integer negation, bitcast back to unsigned integer.
  • Kayan nokta sayıları için: IEEE-754'ten negate.
  • Karmaşık sayılar için: karmaşık olumsuzlama.
  • Kuantize edilmiş 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 tensör ya da tensör başına nicelenmiş tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result Tam sayı, kayan nokta veya karmaşık türde tensör ya da tensör başına nicelenmiş 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 Bilimi

operand tensörünün öğe bazında NOT işlemini gerçekleştirir ve result tensörünü üretir. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • Boole değerleri için: Mantıksal DEĞİL.
  • Tam sayılar için: bit düzeyinde DEĞİL.

Bağımsız değişkenler

Ad Tür Sınırlamalar
operand Boole veya tam sayı türünde tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result Boole veya tam sayı türünde tensö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 Bilimi

operand üreten işlemlerin, result öğesine bağlı olan işlemlerden önce yürütülmesini sağlar ve derleyici dönüşümlerinin işlemleri bariyerin ötesine taşımasını engeller. Bunun dışında işlem, kimliktir (ör. result = operand).

Bağımsız değişkenler

Ad Tür Sınırlamalar
operand değişken sayıda tensör, tensör başına nicemlenmiş tensörler veya jetonlar (C1)

Çıkışlar

Ad Tür Sınırlamalar
result değişken sayıda tensör, tensör başına nicemlenmiş tensörler veya jetonlar (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 tensörlerinin öğe bazında OR işlemini gerçekleştirir ve result tensörü oluşturur. Öğ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ı VEYA.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) lhs Tam sayı veya Boole türünde tensör (C1)
(I2) rhs Tam sayı veya Boole türünde tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result Tam sayı veya Boole türünde tensö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

outfeed

Anlam Bilimi

Feed'e inputs yazar ve result jetonu oluşturur.

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

Girişler

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

Çı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

Tensörün etrafını ve tensörün öğeleri arasını verilen padding_value ile doldurarak operand değerini genişletir.

edge_padding_low ve edge_padding_high, her bir boyutun düşük uç kısmına (0 dizininin yanında) ve yüksek uç kısmına (en yüksek dizinin yanında) eklenen dolgu miktarını belirtir. Dolgu miktarı negatif olabilir. Negatif dolgunun mutlak değeri, belirtilen boyuttan kaldırılacak öğe sayısını gösterir.

interior_padding, her boyutta herhangi iki öğe arasına eklenen ve negatif olmaması gereken dolgu miktarını belirtir. İç dolgu, kenar dolgusundan önce gerçekleşir. Bu nedenle, negatif kenar dolgusu, iç dolgulu işlenenden öğeleri kaldırır.

Daha resmi bir şekilde 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 kuantize edilmiş tensör (C1), (C2), (C4)
(I2) padding_value 0 boyutlu tensör veya tensör başına nicelenmiş tensör (C1)
(I3) edge_padding_low si64 türünde 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ünde 1 boyutlu tensör sabiti (C2-C4)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına kuantize edilmiş 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 Bilimi

Geçerli işlemin partition_id değerini üretir.

Çıkışlar

Ad Tür
result ui32 türünde 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ı öğe bazında hesaplar ve result tensörü oluşturur.

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result tam sayı türünde 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 tensörünün rhs tensörüyle öğe bazında üs alma işlemini gerçekleştirir ve result tensörü oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • Tam sayılar için: tam sayı üs alma.
  • Kayan nokta sayıları için: IEEE-754'ten pow.
  • Karmaşık sayılar için: karmaşık üs alma.
  • Kuantize edilmiş 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 tensör ya da tensör başına nicelenmiş tensör (C1)
(I2) rhs Tam sayı, kayan nokta veya karmaşık türde tensör ya da tensör başına nicelenmiş tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result Tam sayı, kayan nokta veya karmaşık türde tensör ya da tensör başına nicelenmiş 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 çıkarır ve result tensörü oluşturur. Daha resmi bir ifadeyle, her x öğesi için: 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ünde tensör (C1), (C2)

Sınırlamalar

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

Ö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 değeri true ise işlem, verileri ana makineden aktarır. Aksi takdirde, source_target_pairs değerlerine göre başka bir cihazdan veri aktarır. Bu işaret, channel_type bölümünde verilen bilgileri tekrar ediyor. Bu nedenle, gelecekte bu iki işaretten yalnızca birini tutmayı planlıyoruz (#666). is_host_transfer = false ve source_target_pairs değeri None veya boş ise davranış tanımlanmamış olarak kabul edilir.

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

Girişler

Şirket Ad Tür Sınırlamalar
(I1) token token
(I2) channel_id si64 türünde sabit
(I3) channel_type DEVICE_TO_DEVICE ve DEVICE_TO_HOST numaralandırması (C5)
(I4) is_host_transfer i1 türünde sabit (C5-C6)
(I5) source_target_pairs si64 türünde 2 boyutlu tensör sabiti (C1-C4), (C6)

Çıkışlar

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

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) channel_type şu şekilde tanımlanır:
    • is_host_transfer = true ise DEVICE_TO_HOST,
    • Aksi takdirde DEVICE_TO_DEVICE.

Örnekler

%results0, %results1 = "stablehlo.recv"(%token) {
  channel_handle = #stablehlo.channel_handle<handle = 0, type = 1>,
  is_host_transfer = false,
  source_target_pairs = dense<[[0, 1], [1, 2]]> : tensor<2x2xi64>
} : (!stablehlo.token) -> (tensor<2x2xi64>, !stablehlo.token)

 Diğer örnekler

reduce

Anlam Bilimi

body azaltma işlevini inputs ve init_values üzerinde dimensions boyunca uygular ve results tensörleri üretir.

İndirgeme sırası uygulamaya bağlı olarak tanımlanır. Bu nedenle, işlemin tüm uygulamalarda tüm girişler için aynı sonuçları ürettiğini garanti etmek amacıyla body ve init_values bir monoit oluşturmalıdır. Ancak bu koşul, 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 birleşme özelliği 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], : öğelerinin dimensions konumuna yerleştirildiği yerdir.
  • input_slices_converted = to_destination_type(input_slices..., type(func_inputs(body)[:len(func_inputs(body))//2])...).
  • init_values_converted = to_destination_type(init_values..., type(func_inputs(body)[len(func_inputs(body))//2:])...).
  • reduce(input_slices_converted) = exec(schedule) bazı ikili ağaçlar için schedule. Burada:
    • exec(node) = body(exec(node.left), exec(node.right)).
    • exec(leaf) = leaf.value.
  • schedule, sıralı geçişi aşağıdakilerden oluşan, uygulamaya bağlı olarak tanımlanan tam bir ikili ağaçtır:
    • input_slices_converted...[index] değerleri, index'nin artan sözlük sıralamasında index_space(input_slices_converted) içindeki tüm index için.
    • Uygulamaya özel konumlarda, uygulamaya özel miktarda init_values_converted ile serpiştirilmiş.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) inputs değişken sayıda tensör veya tensör başına nicemlenmiş tensörler (C1-C4), (C6), (C7)
(I2) init_values 0 boyutlu tensörlerin veya tensör başına nicemlenmiş tensörlerin değişken sayısı (C2), (C3)
(I3) dimensions si64 türünde 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 tensör veya tensör başına nicemlenmiş tensö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ünde tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>) ve is_promotable(element_type(inputs[i]), Ei).
  • (C7) shape(results...) = shape(inputs...) dimensions ile eşleşen inputs... boyutları hariç.
  • (C8) element_type(results[i]) = Ei for all i in [0,N).

Ö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 bilimi

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

Daha resmi bir dille ifade etmek gerekirse:

  • Orijinal değerin mantis bitleri, orijinal değeri roundToIntegralTiesToEven semantiği kullanılarak mantissa_bits ile gösterilebilen en yakın değere yuvarlamak için güncellenir.
  • Ardından, mantissa_bits, orijinal değerin mantis bitlerinin sayısından küçükse mantis bitleri mantissa_bits'ya kısaltılır.
  • Ardından, ara sonucun üs bitleri exponent_bits tarafından sağlanan aralığa sığmıyorsa ara sonuç, orijinal işaret kullanılarak sonsuza taşar veya orijinal işaret kullanılarak sıfıra taşar.
  • Kuantize edilmiş türler için dequantize_op_quantize( lambda operand: reduce_precision(operand, exponent_bits, mantissa_bits), operand, type(result)) işlemini gerçekleştirir.

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
output Kayan nokta türünde tensör veya tensör başına nicelenmiş 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şlemin operand tensörünün değerleri üzerinde computations kullanılarak azaltma işlemi gerçekleştirilir, azaltma sonucu scatter_dimension boyunca parçalara bölünür ve bölünmüş parçalar, result'ü oluşturmak için işlemler arasında dağıtılır.

İşlem, StableHLO işlem ızgarasını process_groups olarak böler. Bu değer aşağıdaki şekilde tanımlanır:

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

Ardından, her bir 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 içindeki tüm sender için result@receiver = parts@sender[receiver_index], burada receiver_index = process_group.index(receiver).

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına kuantize edilmiş tensör (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, (tensor<E>, tensor<E>) -> (tensor<E>) türünde. Burada is_promotable(element_type(operand), E).
  • (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

body azaltma işlevini inputs ve init_values pencerelerine uygular ve results oluşturur.

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

reduce_window

Daha resmi bir şekilde, results...[result_index] = reduce(windows, init_values, axes(inputs...), body) (bkz. reduce) burada:

  • 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 nicemlenmiş tensörler (C1-C4), (C6), (C8), (C10), (C12), (C13), (C15)
(I2) init_values 0 boyutlu tensörlerin veya tensör başına nicemlenmiş 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ünde 1 boyutlu tensör sabiti (C6), (C7), (C15)
(I5) base_dilations si64 türünde 1 boyutlu tensör sabiti (C8), (C9), (C15)
(I6) window_dilations si64 türünde 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 tensör veya tensör başına nicemlenmiş tensö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ünde 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) bölgesindeki 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

Bölünen lhs ve bölen rhs tensörlerinin öğe bazında kalanını hesaplar ve result tensörünü oluşturur.

Daha resmi bir ifadeyle, sonucun işareti bölenden alınır ve sonucun mutlak değeri her zaman bölenin mutlak değerinden küçüktür. Kalan kısım lhs - d * rhs olarak hesaplanır. Burada d şu şekilde verilir:

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

Kayan nokta öğe türleri için bu işlem, remainder işleminin aksine, d değerinin lhs/rhs değerinin tam değerine en yakın tam sayı değeri olduğu IEEE-754 spesifikasyonundaki remainder işlemiyle çelişir.

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result Tam sayı, kayan nokta veya karmaşık türde tensör ya da tensör başına nicemlenmiş tensö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

Geçerli işlemin replica_id değerini üretir.

Çıkışlar

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

Örnekler

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

 Diğer örnekler

yeniden şekillendirme

Anlam Bilimi

operand tensörünü result tensörüne yeniden şekillendirir. Kavramsal olarak, aynı standart gösterimi korumak ancak şekli (ör. tensor<2x3xf32> yerine tensor<3x2xf32> veya tensor<6xf32>) değiştirmek anlamına gelir.

Daha resmi bir ifadeyle, result[result_index] = operand[operand_index] burada result_index ve operand_index, index_space(result) ve index_space(operand)'nin sözlük sırasındaki aynı konuma sahiptir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand Tensor veya nicelenmiş tensor (C1-C3)

Çıkışlar

Ad Tür Sınırlamalar
result Tensor veya nicelenmiş tensor (C1-C3)

Sınırlamalar

  • (C1) element_type(result) tarafından verilir:
    • !is_per_axis_quantized(operand) ise element_type(operand).
    • element_type(operand) dışında 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

ters

Anlam Bilimi

operand içindeki öğelerin sırasını belirtilen dimensions boyunca tersine çevirir ve result tensörü oluşturur. Daha resmi bir dille ifade etmek gerekirse, result[result_index] = operand[operand_index] burada:

  • operand_index[d] = dim(result, d) - result_index[d] - 1 dimensions konumunda d ise.
  • Aksi takdirde operand_index[d] = result_index[d].

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına kuantize edilmiş tensör (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 Bilimi

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

rng_distribution = UNIFORM ise rastgele sayılar, [a, b) aralığında tekdüze dağılıma göre oluşturulur. a >= b ise davranış tanımlanmamıştır.

rng_distribution = NORMAL ise rastgele sayılar, ortalaması a ve standart sapması b olan normal dağılıma göre oluşturulur. b < 0 ise davranış tanımlanmamıştır.

Rastgele sayıların tam olarak nasıl oluşturulduğu, uygulamaya bağlıdır. Örneğin, bu işlevler deterministik olabilir veya olmayabilir ve gizli durum kullanabilir veya kullanmayabilir.

Birçok paydaşla yapılan görüşmelerde bu işlemin etkili bir şekilde kullanımdan kaldırıldığı belirtildi. Bu nedenle, gelecekte bu işlemi kaldırmayı planlıyoruz (#597).

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result Tam sayı, Boole veya kayan nokta türünde tensö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, sözde rastgele sayı oluşturucu algoritması rng_algorithm kullanılarak tekdüze rastgele bitlerle doldurulmuş bir output ve güncellenmiş bir çıkış durumu output_state döndürür. Çıkışın initial_state ile deterministik bir işlev olduğu garanti edilir ancak uygulamalar arasında deterministik olduğu garanti edilmez.

rng_algorithm aşağıdakilerden biri olmalıdır:

  • DEFAULT: Uygulamaya göre tanımlanmış algoritma.
  • THREE_FRY: Üçlü şifreleme algoritmasının uygulamaya göre tanımlanmış varyantı.*
  • PHILOX: Philox algoritmasının uygulamaya göre tanımlanmış varyantı.*

* Bkz: Salmon et al. 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 enum'ı (C2)
(I2) initial_state ui64 türünde 1 boyutlu tensör (C1), (C2)

Çıkışlar

Ad Tür Sınırlamalar
output_state ui64 türünde 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 ise uygulamaya bağlıdır.
    • 2 ise rng_algorithm = THREE_FRY.
    • 2 veya 3 ise rng_algorithm = PHILOX.

Ö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, bağları sıfırdan uzaklaştırarak en yakın tam sayıya doğru öğe bazında yuvarlama işlemi gerçekleştirir ve result tensörü oluşturur. IEEE-754 spesifikasyonundaki roundToIntegralTiesToAway işlemini uygular. Kuantize edilmiş türler için dequantize_op_quantize(round_nearest_afz, operand, type(result)) işlemi yapılır.

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result Kayan nokta türünde tensör veya tensör başına nicelenmiş 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 bilimi

operand tensöründe, bağları çift tam sayıya doğru bozarak en yakın tam sayıya doğru öğe bazında yuvarlama işlemi gerçekleştirir ve result tensörü üretir. IEEE-754 spesifikasyonundaki roundToIntegralTiesToEven işlemini uygular. Kuantize edilmiş 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ünde tensör veya tensör başına nicelenmiş tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result Kayan nokta türünde tensör veya tensör başına nicelenmiş 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 bilimi

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

  • Kayan nokta sayıları için: IEEE-754'ten rSqrt.
  • Karmaşık sayılar için: karmaşık karşılıklı karekök.
  • Kuantize edilmiş türler için: dequantize_op_quantize(rsqrt, operand, type(result)).

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result kayan noktalı veya karmaşık türde tensör ya da tensör başına nicemlenmiş tensö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ğıtmak

Anlam bilimi

results tensörleri üretir. Bu tensörler, inputs tensörlerine eşittir ancak scatter_indices ile belirtilen birkaç dilim, update_computation kullanılarak updates değerleriyle güncellenir.

Aşağıdaki şemada, updates... içindeki öğelerin results... içindeki öğelerle nasıl eşlendiği somut bir örnekle gösterilmektedir. Diyagramda birkaç örnek updates... endeksi seçilip bunların hangi results... endekslerine karşılık geldiği ayrıntılı olarak açıklanmaktadır.

dağıtmak

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.
  • 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)] if d_input = input_batching_dims[i_batching] ve d_start = scatter_indices_batching_dims[i_batching].
    • Aksi takdirde full_batching_index[d_input] = 0.
  • 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 indekslere eklenir.
  • result_index = full_start_index + full_batching_index + full_window_index.

Bu durumda results = exec(schedule, inputs), burada:

  • schedule, index_space(updates[0])'nin uygulamaya bağlı 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] değeri updated_values... olarak ayarlanmış results öğesinin bir kopyasıdır.
    • Aksi halde
    • updated_results = results.
  • exec([], results) = results.

indices_are_sorted, true ise uygulama, scatter_indices öğelerinin scatter_dims_to_operand_dims'e göre sıralandığını varsayabilir. Aksi takdirde davranış tanımlanmamıştır. Daha resmi bir ifadeyle, indices(result)'den 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ımlanmamıştır.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) inputs değişken sayıda tensör veya tensör başına nicemlenmiş tensörler (C1), (C2), (C4-C6), (C11), (C13), (C18), (C21), (C23-C24)
(I2) scatter_indices tam sayı türünde tensör (C4), (C15), (C19), (C22)
(I3) updates değişken sayıda tensör veya tensör başına nicemlenmiş tensörler (C3-C6), (C8)
(I4) update_window_dims si64 türünde 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ünde 1 boyutlu tensör sabiti (C2), (C4), (C9), (C12-13), (C17-18), (C20)
(I7) scatter_indices_batching_dims si64 türünde 1 boyutlu tensör sabiti (C14-C18)
(I8) scatter_dims_to_operand_dims si64 türünde 1 boyutlu tensör sabiti (C19-C21)
(I9) index_vector_dim si64 türünde sabit (C4), (C16), (C19), (C22)
(I10) indices_are_sorted i1 türünde sabit
(I11) unique_indices i1 türünde 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 nicemlenmiş tensörler (C24-C25)

Sınırlamalar

  • (C1) same(shape(inputs...)).
  • (C2) rank(inputs[0]) = size(update_window_dims) + size(inserted_window_dims) + size(input_batching_dims).
  • (C3) same(shape(updates...)).
  • (C4) shape(updates[0]) = combine(update_scatter_dim_sizes, update_window_dim_sizes) burada:
    • update_scatter_dim_sizes = shape(scatter_indices) hariç olmak üzere, index_vector_dim ile ilişkili scatter_indices boyutunun boyutu dahil değildir.
    • update_window_dim_sizes <= shape(inputs[0]) hariç olmak üzere inserted_window_dims ve input_batching_dims ile ilişkili inputs[0] içindeki boyutlar dahil değildir.
    • combine, update_scatter_dim_sizes öğesini update_scatter_dims ve update_window_dim_sizes öğesini update_window_dims eksenlerine 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, (tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ..., tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>) türünde, burada is_promotable(element_type(inputs[i]), Ei).
  • (C24) shape(inputs...) = shape(results...).
  • (C25) element_type(results[i]) = Ei, [0,N) içindeki tüm i için.

Ö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]]]
//           ],
//           [
//            [[[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 öğenin, result veya on_false tensöründen pred tensörünün karşılık gelen öğesinin değerine göre seçildiği bir result tensörü üretir.on_true Daha resmi bir ifadeyle, result[result_index] = pred_element ? on_true[result_index] : on_false[result_index], burada pred_element = rank(pred) = 0 ? pred[] : pred[result_index]. Kuantize edilmiş türler için dequantize_select_quantize(pred, on_true, on_false, type(result)) işlemini gerçekleştirir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) pred i1 türünde tensör (C1)
(I2) on_true tensör veya tensör başına kuantize edilmiş tensör (C1-C2)
(I3) on_false tensör veya tensör başına kuantize edilmiş tensör (C2)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına kuantize edilmiş tensör (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

source tensöründeki değerleri, scatter kullanarak reduce_window sonucuna göre input tensöründen select kullanarak dağıtır ve result tensörü oluşturur.

Aşağıdaki şemada, result içindeki öğelerin operand ve source değerlerinden nasıl hesaplandığı somut bir örnekle gösterilmektedir.

select_and_scatter

Daha resmi bir dille ifade etmek gerekirse:

  • 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, reduce_window ile aynı şekilde çalışır. Tek fark, temel reduce'in schedule'sının (bkz. reduce) başlangıç değerlerini içermemesidir. İ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_index(source_index) = operand_index ise selected_values[source_index], operand_index kaynağından operand öğesini içerir.
    • 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 tensör veya tensör başına kuantize edilmiş tensör (C1-C4), (C6), (C8-C11)
(I2) source tensör veya tensör başına kuantize edilmiş tensör (C1), (C2)
(I3) init_value 0 boyutlu tensör veya tensör başına nicelenmiş tensör (C3)
(I4) window_dimensions si64 türünde 1 boyutlu tensör sabiti (C2), (C4), (C5)
(I5) window_strides si64 türünde 1 boyutlu tensör sabiti (C2), (C6), (C7)
(I6) padding si64 türünde 2 boyutlu tensör sabiti (C2), (C8)
(I7) select işlev (C9)
(I8) scatter işlev (C10)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına kuantize edilmiş tensör (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, (tensor<E>, tensor<E>) -> tensor<i1> türünde. Burada E = element_type(operand).
  • (C10) scatter, (tensor<E>, tensor<E>) -> tensor<E> türünde. Burada is_promotable(element_type(operand), E).
  • (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

inputs adlı kullanıcıyı channel_id adlı kanala gönderir. Girişler, source_target_pairs tarafından belirtilen sırayla diğer cihazlara gönderilir. İşlem bir result jetonu oluşturur.

is_host_transfer değeri true ise işlem, verileri ana makineye aktarır. Aksi takdirde, source_target_pairs değerlerine göre verileri başka bir cihaza aktarır. Bu işaret, channel_type bölümünde verilen bilgileri tekrar ediyor. Bu nedenle, gelecekte bu iki işaretten yalnızca birini tutmayı planlıyoruz (#666). is_host_transfer = false ve source_target_pairs değeri None veya boş ise davranış tanımlanmamış olarak kabul edilir.

Girişler

Şirket Ad Tür Sınırlamalar
(I1) inputs değişken sayıda tensör veya nicelenmiş tensör
(I2) token token
(I3) channel_id si64 türünde sabit
(I4) channel_type DEVICE_TO_DEVICE ve DEVICE_TO_HOST numaralandırması (C5)
(I5) is_host_transfer i1 türünde sabit (C5-C6)
(I6) source_target_pairs si64 türünde 2 boyutlu tensör sabiti (C1-C4), (C6)

Çıkışlar

Ad Tür
result token

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) channel_type şu şekilde tanımlanır:
    • is_host_transfer = true ise DEVICE_TO_HOST,
    • Aksi takdirde DEVICE_TO_DEVICE.

Örnekler

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

 Diğer örnekler

shift_left

Anlam Bilimi

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

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result tam sayı türünde 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ğa kaydırma işlemi gerçekleştirir ve result tensörü oluşturur.

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result tam sayı türünde 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ğa kaydırma işlemi gerçekleştirir ve result tensörü oluşturur.

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result tam sayı türünde 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 öğe bazında döndürür ve result tensörü oluşturur. Daha resmi bir ifadeyle, her x öğesi için semantik, Python söz dizimi kullanılarak şu şekilde 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)))

Kuantize edilmiş türler için dequantize_op_quantize(sign, operand, type(result)) işlemini gerçekleştirir.

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result işaretli tam sayı, kayan nokta veya karmaşık türde tensör ya da tensör başına nicemlenmiş 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 Bilimi

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

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

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result kayan noktalı veya karmaşık türde tensör ya da tensör başına nicemlenmiş tensö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 result tensörü oluşturur. 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ımları içerir.

Daha resmi bir ifadeyle, result[result_index] = operand[operand_index] burada 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 kuantize edilmiş 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ünde 1 boyutlu tensör sabiti (C2), (C3), (C5)
(I4) strides si64 türünde 1 boyutlu tensör sabiti (C2), (C4)

Çıkışlar

Ad Tür Sınırlamalar
result tensör veya tensör başına kuantize edilmiş tensör (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 bilimi

inputs öğesinin 1 boyutlu dilimlerini dimension boyutu boyunca comparator değerine göre birlikte sıralar ve results değerini üretir.

Diğer işlemlerdeki benzer girişlerin aksine, dimension negatif değerlere izin verir ve anlamları aşağıda açıklanmıştır. Gelecekte tutarlılık nedeniyle bu durum engellenebilir (#1377).

is_stable doğruysa sıralama sabittir. Yani karşılaştırıcı tarafından eşit kabul edilen öğelerin göreli sırası korunur. Tek bir girişin olduğu durumda, iki öğe e1 ve e2 yalnızca comparator(e1, e2) = comparator(e2, e1) = false ise karşılaştırıcı tarafından eşit kabul edilir. Bunun birden fazla girişe nasıl genellendiğini öğrenmek için aşağıdaki resmîleştirme bölümüne 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], riN, result_index içindeki bağımsız öğelerdir ve :, adjusted_dimension konumuna 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 artmayan düzende sıralar. comparator_together, sol taraftaki bağımsız değişken sağ taraftaki ikinci bağımsız değişkenden küçükse true değerini 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 tensör veya tensör başına nicemlenmiş tensörler (C1-C5)
(I2) dimension si64 türünde sabit (C4)
(I3) is_stable i1 türünde sabit
(I4) comparator işlev (C5)

Çıkışlar

Ad Tür Sınırlamalar
results değişken sayıda tensör veya tensör başına nicemlenmiş tensö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 türünde (tensor<E1>, tensor<E1>, ..., tensor<EN-1>, tensor<EN-1>) -> tensor<i1>, where 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 tensöründe öğe bazında karekök işlemi gerçekleştirir ve result tensörünü üretir. Öğe türüne bağlı olarak aşağıdakileri yapar:

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

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result kayan noktalı veya karmaşık türde tensör ya da tensör başına nicemlenmiş tensö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

lhs ve rhs olmak üzere iki tensörün öğe bazında çıkarılmasını gerçekleştirir ve result tensörü oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

  • Tam sayılar için: tam sayı çıkarma.
  • Kayan nokta sayıları için: IEEE-754'ten subtraction.
  • Karmaşık sayılar için: karmaşık çıkarma.
  • Kuantize edilmiş 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 tensör ya da tensör başına nicelenmiş tensör (C1)
(I2) rhs Tam sayı, kayan nokta veya karmaşık türde tensör ya da tensör başına nicelenmiş tensör (C1)

Çıkışlar

Ad Tür Sınırlamalar
result Tam sayı, kayan nokta veya karmaşık türde tensör ya da tensör başına nicelenmiş 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 bilimi

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

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

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result kayan noktalı veya karmaşık türde tensör ya da tensör başına nicemlenmiş tensö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ünde öğe bazında hiperbolik tanjant işlemi gerçekleştirir ve result tensörü oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:

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

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result kayan noktalı veya karmaşık türde tensör ya da tensör başına nicemlenmiş tensö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 etmek

Anlam bilimi

operand tensörünün boyutlarını permutation kullanarak değiştirir 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 Tensor veya nicelenmiş tensor (C1-C4)
(I2) permutation si64 türünde 1 boyutlu tensör sabiti (C2-C4)

Çıkışlar

Ad Tür Sınırlamalar
result Tensor veya nicelenmiş tensor (C1), (C3-C4)

Sınırlamalar

  • (C1) element_type(result) tarafından verilir:
    • !is_per_axis_quantized(operand) ise element_type(operand).
    • element_type(operand) dışında quantization_dimension(operand) ve quantization_dimension(result) farklı olabilir.
  • (C2) permutation, range(rank(operand)) öğesinin 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ı matrisleriyle doğrusal denklem sistemlerini toplu olarak çözer.

Daha resmi bir ifadeyle, a ve b verildiğinde result[i0, ..., iR-3, :, :], left_side true olduğunda op(a[i0, ..., iR-3, :, :]) * x = b[i0, ..., iR-3, :, :]'ün, left_side false olduğunda ise x * op(a[i0, ..., iR-3, :, :]) = b[i0, ..., iR-3, :, :]'ın çözümüdür. Burada op(a), transpose_a tarafından belirlenen x değişkeni için çözüm yapılır. transpose_a aşağıdakilerden biri olabilir:

  • NO_TRANSPOSE: a'yi olduğu gibi kullanarak işlemi gerçekleştirin.
  • TRANSPOSE: a öğesinin transpozesi üzerinde işlem gerçekleştirin.
  • ADJOINT: a'nin eşlenik transpozesi üzerinde işlem gerçekleştirir.

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

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

Kuantize edilmiş 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 noktalı veya karmaşık türde tensör ya da tensör başına nicemlenmiş tensör (C1-C3)
(I2) b kayan noktalı veya karmaşık türde tensör ya da tensör başına nicemlenmiş tensör (C1-C4)
(I3) left_side i1 türünde sabit (C3)
(I4) lower i1 türünde sabit
(I5) unit_diagonal i1 türünde sabit
(I6) transpose_a NO_TRANSPOSE, TRANSPOSE ve ADJOINT enum'ı

Çıkışlar

Ad Tür Sınırlamalar
result kayan noktalı veya karmaşık türde tensör ya da tensör başına nicemlenmiş tensö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 şu şekilde 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 result demeti oluşturur.

Girişler

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

Çıkışlar

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

Sınırlamalar

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

Örnekler

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

 Diğer örnekler

uniform_dequantize

Anlam bilimi

operand türü tarafından tanımlanan nicemleme parametrelerine göre, nicemlenmiş tensör operand öğe bazında dönüştürülerek kayan noktalı tensör result oluşturulur.

Daha resmi bir ifadeyle result = dequantize(operand).

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result kayan nokta türünde 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 Bilimi

operand türü tarafından tanımlanan nicelendirme parametrelerine göre, kayan noktalı tensörün veya nicelendirilmiş tensörün result nicelendirilmiş tensöre öğe bazında dönüştürülmesini gerçekleştirir.result

Daha resmi bir dille ifade etmek gerekirse,

  • 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 nicelenmiş türde tensör (C1), (C2)

Çıkışlar

Ad Tür Sınırlamalar
result nicelendirilmiş 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]

sırasında

Anlam Bilimi

body işlevi cond işlevi true çıkışını verirken 0 veya daha fazla kez yürütülerek çıkış üretir. Daha resmi bir şekilde, semantikler Python söz dizimi kullanılarak 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ışı henüz belli değil (#383).

Girişler

Şirket Ad Tür Sınırlamalar
(I1) operand değişken sayıda değer (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 değer (C3)

Sınırlamalar

  • (C1) cond, (T0, ..., TN-1) -> tensor<i1> türündedir. Burada Ti = type(operand[i]).
  • (C2) body, (T0, ..., TN-1) -> (T0, ..., TN-1) türündedir. Burada Ti = type(operand[i]).
  • (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

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

  • Boole değerleri için: mantıksal XOR.
  • Tam sayılar için: bit düzeyinde XOR.

Girişler

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

Çıkışlar

Ad Tür Sınırlamalar
result Boole veya tam sayı türünde tensö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

Dialect Interop

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

Modül, İşlev, Çağrı ve Döndürme

StableHLO, ModuleOp, FuncOp, CallOp ve ReturnOp için yukarı akış MLIR işlemlerini kullanır. Bu, mevcut MLIR mekanizmasıyla daha iyi birlikte çalışabilmek için yapıldı. Çünkü birçok yararlı geçiş, FuncOp ve ModuleOp'u hedefleyerek yazılıyor ve birçok derleme işlem hattı, bu işlemleri bekliyor. Bu işlemler için tam uyumluluk garantileri uygulanır. Bu işlemlerle ilgili olarak uyumsuz bir şekilde (ör. kaldırma) herhangi bir değişiklik olursa uyumluluğu korumak için StableHLO eşdeğerleri eklenir.

CHLO

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

Şekil İşlemleri

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

Dynamism RFC > O2 bunları kapsam dışı olarak belirtir ancak birlikte çalışabilirlik amacıyla index türleri için bir miktar destek sağlanır. Bu işlemler veya türler için uyumluluk garantisi verilmez. shape-legalize-to-stablehlo geçişi, bu işlemleri tam olarak desteklenen StableHLO işlemlerine dönüştürmek için kullanılabilir.

Desteği sonlandırılan işlemler

MHLO'dan devralınan ve StableHLO'da kullanımdan kaldırılma sürecinde olan çeşitli StableHLO işlemleri vardır. Bu kaldırma işlemleriyle ilgili tüm ayrıntıları StableHLO v1.0 Cleanup #2283 başlıklı makalede bulabilirsiniz. Bu desteğin sonlandırılmasıyla ilgili takip sorunu #2340'tır.

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

  • StableHLO işlemlerinin "HLO'da değil" kategorisi: Başlangıçta StableHLO işlem kümesinin bir parçası olan bu işlemler, daha sonra bu kümeye uygun olmadığına karar verilerek kümeye dahil edilmemiştir: broadcast, create_token, cross-replica-sum, dot, einsum, torch_index_select, unary_einsum (#3).
  • Kullanılmayan işlemler: Bu işlemler bir noktada faydalı olmuş olabilir ancak işlemler ya yeterince geliştirilmemiştir ya da bu işlemleri kullanan işlem hatları, artık bu işlemleri gerektirmeyecek şekilde yeniden düzenlenmiştir. Buna map, tuple (#598), get_tuple_element, rng, complex karşılaştırmaları #560, ve konvolüsyon window_reversal (#1181) dahildir.

Bu işlemlerden bazıları mevcut işlemler (broadcast, create_token, cross-replica-sum, dot, unary_einsum) kullanılarak ifade edilebildiğinden kolayca kaldırılabilir ve mevcut uyumluluk penceresi (6 ay) geçtikten sonra kaldırılacaktır. Diğerlerinin kaldırılması için ise araştırmalar devam ediyor (einsum, get_tuple_element, map, rng torch_index_select, tuple, complex karşılaştırmalar, window_reversal). Topluluk geri bildirimlerine bağlı olarak bu işlemler kaldırılacak veya tam destekle spesifikasyona eklenecek. Bu işlemlerin geleceği bilinene kadar yalnızca 6 aylık uyumluluk garantisi verilir.

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, ilgili return işleminde köklenen işlemlerin grafiği yürütülerek hesaplanır.

Yürütme sırası, veri akışıyla uyumlu olduğu sürece (ör. işlemler kullanımlarından önce yürütülürse) uygulamaya göre tanımlanır. StableHLO'da, yan etkili tüm işlemler bir jeton tüketir ve bir jeton üretir (birden fazla jeton after_all aracılığıyla tek bir jeton hâline getirilebilir). Bu nedenle, yan etkilerin yürütme sırası da veri akışıyla uyumludur. Örneğin, aşağıdaki programda iki olası yürütme sırası 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 aşağıdakilerin bir kombinasyonudur: 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şlevinin giriş değerleriyle başlar, işlem durumlarını ve ara değerleri güncelleyen işlemlerin grafiğiyle devam eder ve çıkış değerleriyle sona erer. Daha fazla resmileştirme henüz belli değil (#484).

Paralel yürütme

StableHLO programları paralel olarak yürütülebilir ve her ikisi de ui32 türünde olan num_replicas x num_partitions boyutlarında 2 boyutlu bir işlem ızgarası şeklinde düzenlenebilir.

StableHLO işlem ızgarasında, StableHLO işlemlerinin num_replicas * num_partitions'si aynı anda yürütülüyor. Her işlemin benzersiz bir process_id = (replica_id, partition_id) değeri vardır. Burada replica_ids = range(num_replicas) içindeki replica_id ve partition_ids = range(num_partitions) içindeki partition_id değerlerinin her ikisi de ui32 türündedir.

Süreç ızgarasının boyutu her program için statik olarak bilinir (gelecekte, bunu StableHLO programlarının açık bir parçası yapmayı planlıyoruz #650) ve süreç ızgarasındaki konum her süreç 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ç tablosunda programlar aynı (tek program, çoklu veri stilinde), farklı (çoklu program, çoklu veri stilinde) veya ikisinin arasında bir şekilde olabilir. Gelecekte, GSPMD (#619) dahil olmak üzere paralel StableHLO programlarını tanımlamanın diğer deyimleri için destek sunmayı planlıyoruz.

İşlem tablosunda, işlemler çoğunlukla birbirinden bağımsızdır. Ayrı işlem durumları, ayrı giriş/ara/çıkış değerleri vardır ve aşağıda açıklanan az sayıda toplu işlem dışında işlemlerin çoğu ayrı ayrı yürütülür.

İşlemlerin çoğunun yürütülmesinde yalnızca aynı süreçteki değerler kullanıldığından bu değerlere adlarıyla başvurmak genellikle net bir şekilde anlaşılır. Ancak toplu işlemlerin semantiğini açıklarken bu yeterli değildir ve belirli bir süreçteki name değerini ifade etmek 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.)

Süreçler arasındaki yürütme sırası, aşağıda açıklandığı gibi noktadan noktaya iletişim ve toplu işlemlerin getirdiği senkronizasyon dışında uygulamaya göre tanımlanır.

Noktadan noktaya iletişim

StableHLO işlemleri, StableHLO kanalları aracılığıyla birbirleriyle iletişim kurabilir. Kanal, si64 türünde pozitif bir kimlikle temsil edilir. Çeşitli işlemler aracılığıyla kanallara değer göndermek ve kanallardan değer almak mümkündür.

Bu kanal kimliklerinin nereden geldiği, süreç programlarının bunları nasıl öğrendiği ve ne tür bir senkronizasyonun kullanıldığı gibi daha fazla resmileştirme, belirlenecektir (TBD) (#484).

Akış iletişimi

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

  • Okunabilen feed içi reklamlar
  • Yazılabilir bir outfeed.

Süreçler arasında iletişim kurmak için kullanılan ve bu nedenle her iki ucunda da süreçler bulunan kanalların aksine, beslemelerde ve çıkış beslemelerinde diğer uç uygulama tanımlıdır.

Daha fazla resmileştirme (ör. akış iletişimi, yürütme sırasını nasıl etkiler ve ne tür bir senkronizasyon getirir?) henüz belirlenmemiştir (#484).

Toplu işlemler

StableHLO'da altı toplu işlem vardır: all_gather, all_reduce, all_to_all, collective_broadcast, collective_permute ve reduce_scatter. Bu işlemlerin tümü, StableHLO işlem ızgarasındaki işlemleri StableHLO işlem gruplarına böler 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 grubu içinde toplu işlemler bir senkronizasyon engeli oluşturabilir. Daha fazla resmileştirme (ör. bu senkronizasyonun tam olarak ne zaman gerçekleştiği, süreçlerin tam olarak nasıl bu bariyerle karşılaştığı ve karşılaşmadıkları takdirde ne olacağı hakkında ayrıntılı bilgi verilmesi) belirlenecektir (#484).

İşlem grubu, bölüm içi iletişimi 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ünde pozitif bir channel_id sağlamalıdır. Kopyalar arası iletişim için kanallar gerekmez.

Toplu işlemler tarafından gerçekleştirilen hesaplamalar, tek tek işlemler için geçerlidir ve yukarıdaki tek tek işlem bölümlerinde açıklanmıştır. Ancak, işlem tablosunun işlem gruplarına ayrıldığı stratejiler bu işlemler arasında paylaşılır ve bu bölümde açıklanır. Daha resmi olarak, StableHLO aşağıdaki dört stratejiyi destekler.

cross_replica

Her işlem grubunda yalnızca kopyalar arası iletişim gerçekleşir. Bu strateji, replica_groups (kopya kimliklerinin listelerinin listesi) alır ve replica_groups ile partition_ids'nin Kartezyen çarpımını hesaplar. replica_groups benzersiz öğeler içermeli ve tüm replica_ids'leri kapsamalıdır. Daha resmi bir şekilde, 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)]] sonucunu verir.

cross_partition

Her işlem grubunda yalnızca bölümler arası iletişim gerçekleşir. Bu strateji, partition_groups (bölüm kimliklerinin listelerinin listesi) alır ve partition_groups ile replica_ids'nin Kartezyen çarpımını hesaplar. partition_groups, benzersiz öğeler içermeli ve tüm partition_ids'leri kapsamalıdır. Daha resmi bir şekilde, 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)]] sonucunu verir.

cross_replica_and_partition

Her işlem grubunda hem kopyalar arası hem de bölümler arası iletişim gerçekleşebilir. Bu strateji, replica_groups (kopya kimliklerinin listelerinin listesi) alır ve her replica_group'nin Kartezyen çarpımlarını partition_ids ile hesaplar. replica_groups, benzersiz öğeler içermeli ve tüm replica_ids'leri 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)]] sonucunu verir.

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 öğeler içermeli ve tüm process_ids'leri 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)]] sonucunu verir.

Doğruluk

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

Kuantize edilmiş işlemin yürütme semantiği

Kuantize edilmiş StableHLO işlemlerinin yorumlanması, donanım gereksinimlerine ve özelliklerine bağlı olarak değişebilir. Örneğin, bazı donanımlar, "dequantize, perform floating-point operation, and finally quantize" (niceliksizleştir, kayan nokta işlemi gerçekleştir ve son olarak nicelleştir) stratejisini kullanarak nicelleştirilmiş işlemleri yorumlamayı tercih edebilir. Diğerleri ise tüm hesaplamayı tam sayı aritmetiğiyle yapabilir. Bu nedenle, nicelenmiş StableHLO işlemlerinin yorumlanması yalnızca belirli bir uygulamaya göre belirlenir. Karma nicelendirme (#1575) yorumu, spesifikasyonda (1792 aracılığıyla) belirtilen semantiğine göre yapılmalıdır.

Hatalar

StableHLO programları, tek tek işlemler için kapsamlı bir kısıtlama grubu aracılığıyla doğrulanır. Bu sayede, çalışma zamanından önce birçok hata sınıfı ortadan kaldırılır. Ancak, tamsayı taşmaları, sınırların dışında erişimler vb. aracılığıyla hata koşulları yine de mümkündür. Açıkça belirtilmediği sürece, tüm bu hatalar uygulamaya bağlı davranışa neden olur ancak bu durum gelecekte değişebilir (#1157).

Kayan nokta istisnaları

Bu kuralın istisnası olarak, StableHLO programlarındaki kayan nokta istisnalarının iyi tanımlanmış bir davranışı vardır. IEEE-754 standardı tarafından tanımlanan istisnalarla (geçersiz işlem, sıfıra bölme, taşma, yetersizlik veya kesin olmayan istisnalar) sonuçlanan işlemler, varsayılan sonuçlar (standartta tanımlandığı gibi) üretir ve ilgili durum işaretini yükseltmeden yürütmeye devam eder. Bu durum, standarttaki raiseNoFlag istisna işleme ile benzerdir. Standart olmayan işlemlerle (ör. karmaşık aritmetik ve belirli aşkın fonksiyonlar) ilgili istisnalar, uygulamaya göre tanımlanır.

Şekil uyuşmazlıkları

StableHLO, dinamik şekilli tensörleri destekler. Ancak şekiller çalışma zamanında eşleşmelidir. Aksi takdirde davranış tanımlanmamış olur. StableHLO, bir tensörün çalışma zamanında belirli bir şekle sahip olduğunu onaylayabilecek bir işlem sağlamaz. Doğru kod oluşturmak yapımcının sorumluluğundadır.

Özel bir örnek olarak, aşağıdaki program geçerlidir. 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 belgede, söz dizimini açıklamak için EBNF söz diziminin değiştirilmiş ISO sürümü (ISO/IEC 14977:1996, Wikipedia) kullanılmaktadır. Bu sürümde iki değişiklik yapılmıştır: 1) Kurallar = yerine ::= kullanılarak tanımlanır.

2) Birleştirme, , yerine yan yana getirme kullanılarak ifade edilir.

Semantiği açıklamak için (ör. "Türler", "Sabitler" ve "İşlemler" bölümlerinde) Python söz dizimine dayalı ve dizi işlemlerini aşağıda açıklandığı gibi kısa ve öz bir şekilde ifade etme desteğiyle genişletilmiş formüller kullanıyoruz. Bu yöntem, küçük kod snippet'leri için uygundur. Ancak nadir durumlarda daha büyük kod snippet'leri gerektiğinde her zaman açıkça belirtilen standart Python söz dizimini kullanırız.

Formüller

Formüllerin işleyiş şeklini dot_generalspesifikasyonundaki bir örneğe göre inceleyelim. 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'ın "Girişler" bölümünde tanımlanan lhs, lhs_batching_dimensions, rhs ve rhs_batching_dimensions girişleri).

Yukarıda belirtildiği gibi, bu formülün söz dizimi Python tabanlıdır ve bazı kısa ve öz uzantılar içerir. Formülü anlamak için onu standart Python söz dizimine dönüştürelim.

A) Bu formüllerde eşitliği göstermek için = kullanıyoruz. Bu nedenle, Python söz dizimini elde etmeye yönelik ilk adım, = yerine == yazmaktır. Bu işlem şu şekilde yapılır: 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 üç nokta (...) işaretini destekler. Kısaca f(xs...), "xs tensöründeki her bir x skaler değeri için bir f(x) skaler değeri hesapla ve ardından tüm bu skaler sonuçları birlikte bir tensör sonucu olarak döndür" anlamına gelir. Örnek formülümüz, vanilla Python söz diziminde şu şekilde görünür: [dim(lhs, dim1) for dim1 in lhs_batching_dimensions] == [dim(rhs, dim2) for dim2 in rhs_batching_dimensions].

Üç nokta sayesinde genellikle tek tek ölçekler düzeyinde çalışmaktan kaçınmak mümkündür. Ancak bazı zor durumlarda, gather spesifikasyonundaki start_indices[bi0, ..., :, ..., biN] formülünde olduğu gibi daha düşük düzeyde yarı resmi söz dizimi kullanılabilir. Kısa ve öz olması için bu tür söz dizimlerini standart Python'a çevirme konusunda tam bir biçimsel yöntem sunmuyoruz. Bu söz dizimlerinin, her bir durumda sezgisel olarak anlaşılacağını umuyoruz. Belirli formüllerin opak göründüğünü düşünüyorsanız lütfen bize bildirin. Bu formülleri iyileştirmeye çalışacağız.

Ayrıca, tensörler ve tensör listeleri (ör. değişken sayıda tensörden oluşabilir) gibi her türlü listeyi genişletmek için formüllerde üç nokta kullanıldığını da fark edeceksiniz. Bu, tam bir biçimlendirme sağlamadığımız (ör. listeler StableHLO tür sisteminin bir parçası bile değildir) ve bunun yerine sezgisel anlaşılabilirliğe güvendiğimiz başka bir alandır.

C) Kullandığımız son önemli notasyon aracı, örtülü yayınlamadır. StableHLO işlem kümesi örtülü yayın yapmayı desteklemese de formüller, kısa ve öz olması için bunu destekler. Özetle, bir skalerin tensörün beklendiği bir bağlamda kullanılması durumunda skaler, beklenen şekle yayınlanır.

dot_general örneğine devam etmek için başka bir kısıtlama ekleyelim: 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ülü yayın uygulandı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 boole tensörüne dönüşür. Formüller kısıtlama olarak kullanıldığında, formül true olarak veya yalnızca true öğeleri içeren bir tensör olarak değerlendirilirse kısıtlama geçerli olur.

Adlar

Formüllerde sözcüksel kapsam şunları içerir: 1) genel işlevler, 2) üye tanımları,

3) yerel tanımlar. Genel işlevlerin listesini aşağıda bulabilirsiniz. Öğe tanımları listesi, notasyonun uygulandığı program öğesine bağlıdır:

  • İşlemler için üye tanımları, "Girişler" ve "Çıkışlar" bölümlerinde belirtilen adları içerir.
  • Diğer her şey için üye tanımları, program öğesinin yapısal kısımlarını içerir ve ilgili EBNF olmayan terimlere göre adlandırılır. Çoğu zaman bu yapısal parçaların adları, terminal olmayanların adları yılan biçimli büyük/küçük harf biçimine dönüştürülerek elde edilir (ör.IntegerLiteral => integer_literal). Ancak bazen adlar bu süreçte kısaltılır (ör.QuantizationStorageType => storage_type). Bu durumda adlar, işlem spesifikasyonlarındaki "Girişler" ve "Çıkışlar" bölümlerine benzer şekilde açıkça belirtilir.
  • Ayrıca, üye tanımları her zaman self içerir. Bu işaret, ilgili program öğesini ifade eder.

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 atıfta bulunabilir. Daha spesifik olarak, işlemler için "Semantik" bölümü (ve diğer program öğeleri için eşdeğerleri) çalışma zamanı mantığını tanımlar. Bu nedenle, tüm girişler Value olarak kullanılabilir. Bunun aksine, işlemler (ve eşdeğerleri) için "Kısıtlamalar" bölümünde "derleme zamanı" mantığı tanımlanır.Yani genellikle çalışma zamanından önce yürütülen bir şeydir. Bu nedenle, yalnızca sabit girişler Value olarak kullanılabilir ve diğer girişler yalnızca Placeholder olarak kullanılabilir.

Adlar "Semantik" bölümünde "Kısıtlamalar" 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ıma bağlıdır Tanıma bağlıdır

Şimdi bir örnek transpose işlemi inceleyelim:

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

Bu işlemde permutation sabittir. Bu nedenle, hem semantikte hem de kısıtlamalarda Value olarak kullanılabilir. Buna karşılık, operand ve result, semantikte Value olarak, kısıtlamalarda ise yalnızca Placeholder olarak kullanılabilir.

İşlevler

Türlerin yapısı

Tür oluşturmak için kullanılabilecek işlev yok. Bunun yerine, genellikle daha kısa olduğu için doğrudan tür söz dizimini kullanırız. Örneğin, function_type( [tensor_type([], E), tensor_type([], E)], [tensor_type([], E)]) yerine (tensor<E>, tensor<E>) -> (tensor<E>).

Türler üzerindeki işlevler

  • element_type, tensör türlerinde ve nicelenmiş tensör türlerinde tanımlanır ve sırasıyla ilgili TensorType veya QuantizedTensorType'nin TensorElementType veya 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 bir 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 için geçerli olur. Promosyonun bu sürümü şu anda indirim 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, is_float(x), x bir FloatType ise 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, TensorElementType değilse None değerini döndürür.

  • min_value(x: Type) -> Value, TensorElementType için mümkün olan en düşük değeri döndürür. x, TensorElementType değilse None değerini döndürür.

  • member_name(x: Value | Placeholder | Type) -> Any. Tüm üye tanımları member_name için kullanılabilir. Örneğin, tensor_element_type(x), ilgili 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 üyeye sahip bir tür değilse veya bu türden bir değer ya da yer tutucu değilse None değerini döndürür.

  • is_empty_algorithm(*args: Type), tüm nokta algoritması alanlarının None olarak ayarlanıp ayarlanmadığını kontrol eder. Nokta algoritmaları, uygulamaya bağlı varsayılan davranışlara sahip olduğundan varsayılan bir değer belirtmek yanlış olur. Bu nedenle bu alan gereklidir.

Değerlerin oluşturulması

  • operation_name(*xs: Value | Type) -> Value. Tüm işlemler için kullanılabilir. Örneğin, add(lhs, rhs) iki tensör değeri (lhs ve rhs) alır ve add işleminin bu girişlerle değerlendirilmesinin sonucunu döndürür. Bazı işlemlerin (ör. broadcast_in_dim) çıkış türleri, bir işlemi değerlendirmek için gerekli olan "yük taşıyıcı" türlerdir. Bu durumda işlev, bağımsız değişken olarak bu türleri alır.

Değerler üzerindeki işlevler

  • Python'ın tüm operatörleri ve işlevleri kullanılabilir. Örneğin, Python'daki abonelik ve dilimleme gösterimleri, tensörler, nicelenmiş tensörler ve demetlerde dizin oluşturmak için kullanılabilir.

  • to_destination_type(x: Value, destination_type: Type) -> Value, tensörlerde tanımlanır ve x değerini type(x) ve destination_type'ye göre aşağıdaki şekilde dönüştürülmüş olarak 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ştirilmesiyle ilgili erken aşamada bir tartışma var (#1576). Birleştirme işleminden sonra yukarıdaki işlev gerekli değildir ve convert için işlem adı kullanılabilir.

  • is_nan(x: Value) -> Value, tensörlerde tanımlanır ve x öğelerinin tümü NaN ise true, aksi takdirde false 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örler üzerinde tanımlanır ve x öğeleri, dizinlerinin artan sözcüksel sırasına göre artan düzende sıralanmışsa true, aksi takdirde false değerini döndürür. x bir tensör değilse None değerini döndürür.

  • is_unique(x: Value) -> Value, tensörlerde tanımlanır ve x öğesinde yinelenen öğe yoksa true, aksi takdirde false değerini döndürür. x bir tensör değilse None değerini döndürür.

  • member_name(x: Value) -> Any, tüm değerlerin tüm üye tanımları member_name için tanımlanır. Örneğin, real_part(x), ilgili ComplexConstant öğesinin RealPart bölümünü döndürür. x, uygun bir üyeye sahip olmayan bir değerse None değerini döndürür.

  • same(x: Value) -> Value, tensörler üzerinde tanımlanır ve x öğeleri birbirine eşitse true, aksi takdirde false değerini döndürür. Tensörde öğe yoksa bu durum "hepsi birbirine eşit" olarak kabul edilir. Yani işlev true değerini döndürür. x tensör değilse None değerini döndürür.

  • split(x: Value, num_results: Value, axis: Value) -> Value, tensörler üzerinde tanımlanır ve axis ekseni boyunca x'nin num_results dilimini döndürür. x bir tensör veya dim(x, axis) % num_results != 0 değilse None değerini döndürü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 değerini 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 şu normal ifadeye uyuyorsa) true değerini 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 size(x) dizinlerini döndürür.Bu dizinler, artan sözlükbilimsel düzende sıralanır (ör. [0, ..., 0], [0, ..., 1], ..., shape(x) - 1). x bir tensör türü, nicelenmiş tensör türü veya bu türlerden birinin değeri ya da yer tutucusu değilse None değerini döndürür.

  • rank(x: Value | Placeholder | Type) -> Value, size(shape(x)) için bir kısayoldur.

  • shape(x: Value | Placeholder | Type) -> Value, "Türler üzerinde işlevler" bölümünde member_name aracılığıyla tanımlanır.

  • size(x: Value | Placeholder | Type) -> Value, reduce(lambda x, y: x * y, shape(x)) için bir kısayoldur.

Kuantizasyon hesaplamaları

  • def baseline_element_type(x: Value | Placeholder | Type) -> Type, element_type(baseline_type(x)) için bir kısayoldur.

  • baseline_type, tensör türlerinde ve nicemlenmiş tensör türlerinde tanımlanır ve bunları "temel çizgi"ye dönüştürür. Diğer bir deyişle, aynı şekle sahip ancak öğe türünün nicemleme parametreleri varsayılan değerlere sıfırlanmış bir türe dönüştürür. Bu, hem tensör hem de nicemlenmiş tensör türlerini tek tipte karşılaştırmak için kullanışlı bir yöntemdir ve bu karşılaştırma oldukça sık gerekir. Kuantize edilmiş türler için bu, kuantizasyon parametrelerini (ör. shape, storage_type, expressed_type, storage_min, storage_max ve quantization_dimension) yoksayarak türleri karşılaştırmayı sağlar. Eksen başına kuantize edilmiş tür için bunların 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, nicelenmiş tensör türlerinde tanımlanır ve bunları kayan noktalı tensör türlerine dönüştürür. Bu işlem, depolama türünün tamsayı değerlerini temsil eden nicelendirilmiş öğelerin, nicelendirilmiş öğ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ürülmesiyle gerçekleşir.
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ı tensör türlerinde tanımlanır ve bunları nicelendirilmiş tensör türlerine dönüştürür. Bu işlem, ifade edilen türdeki kayan nokta değerlerinin, nicelendirilmiş öğe türüyle ilişkili sıfır noktası ve ölçek kullanılarak 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, nicelendirilmiş tensörlerde öğe bazında hesaplamaları belirtmek için kullanılır. Bu operatör, nicelendirilmiş öğeleri ifade edilen türlerine dönüştürür (yani nicelendirmeyi kaldırır), ardından bir işlem gerçekleştirir ve sonuçları depolama türlerine geri dönüştürür (yani nicelendirir). Bu işlev şu anda yalnızca tensör başına nicemleme için kullanılabilir. Eksen başına nicemleme üzerinde çalışılmaktadır (#1574).
def dequantize_op_quantize(op, *inputs_and_output_type):
  inputs = inputs_and_output_type[:-1]
  output_type = inputs_and_output_type[-1]

  float_inputs = map(dequantize, inputs)
  float_result = op(*float_inputs)
  return quantize(float_result, output_type)

def dequantize_batch_norm_grad_or_training_quantize(op, *inputs_and_output_types):
  inputs = inputs_and_output_type[:-3]
  float_inputs = map(dequantize, inputs)
  float_results = op(*float_inputs)
  return map(quantize, float_results, inputs_and_output_type[-3:])

def dequantize_compare(lhs, rhs, comparison_direction):
  float_lhs = dequantize(lhs)
  float_rhs = dequantize(rhs)
  return compare(float_lhs, float_rhs, comparison_direction, FLOAT)

def dequantize_select_quantize(pred, on_true, on_false, output_type):
  float_on_true = dequantize(on_true)
  float_on_false = dequantize(on_false)
  float_result = select(pred, float_on_true, float_on_false)
  return quantize(float_result, output_type)
  • hybrid_dequantize_then_op, lhs'yi kayan noktalı ve rhs'yi nicelendirilmiş türlerde kabul eden karma işlem için yalnızca ağırlık nicelendirmesini belirtmek üzere kullanılır. Kuantize edilmiş girişlerin kuantizasyonunu kaldırarak bunları ifade edilen türlerine dönüştürür ve kayan nokta biçiminde hesaplama yapar. Float lhs tensörünün öğe türü ve nicelenmiş rhs tensörünün ifade edilen 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 boyutlara sahip olabilir (ör. tensor<?xi64>). Ancak StableHLO değerleri dinamik sayıda boyuta sahip olamaz (sıralanmamış dinamizm, ör. tensor<*xi64>). Boyutlarla ilgili kısıtlamalar olsa bile işlenenler ve sonuçlar dinamik boyut boyutlarını kullanabilir. Kısıtlamalar mümkünse statik olarak doğrulanır. Aksi takdirde, çalışma zamanına ertelenir ve uyuşmazlıklar tanımsız davranışa neden olur. Örnekler için aşağıya bakın.

Tekli öğe bazında işlemler için şekil uyuşmazlıkları

Aşağıdaki oyuncak programını inceleyin:

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

Sonucun şeklinin bilinip girişin şeklinin bilinmemesi yaygın bir durum olmadığından bu tür bir program alışılmadık bir durumdur. Bununla birlikte, bu geçerli bir StableHLO programıdır. İşlenenin tam şekli bilinmediği için bu programda abs işlemini statik olarak doğrulamak mümkün değildir. Ancak şekiller kesinlikle uyumludur ve bu statik olarak kontrol edilebilir: ?, çalışma zamanında 2 olarak ortaya çıkabilir ve sorun olmaz. Ancak ? başka bir tam sayı da olabilir. Bu durumda davranış tanımlanmamıştır.

Sonuçta bir boyutun boyutu dinamikse tanımlanmamış davranış olamayacağını unutmayın. Gerçekten de "beklenen" bir boyut olmadığı için uyuşmazlık söz konusu olamaz.

İkili öğe bazında işlemler için şekil uyuşmazlıkları

Aşağıdaki oyuncak programını inceleyin:

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şlemler söz konusu olduğunda, girişlerin ve sonucun şekilleri çalışma zamanında aynı olmalıdır. Derleme zamanında statik boyutlar eşit olmalıdır. Aksi takdirde yalnızca uyumlu olmaları gerekir. Girişlerde herhangi bir boyut dinamikse çalışma zamanında tanımlanmamış davranışlar olabilir. Bunun nedeni, dinamik boyutun diğer işlenendeki (statik veya dinamik) ilgili boyuta uymamasıdır. Tüm girişler statikse sonucun dinamik olup olmaması önemli değildir: Statik olarak bilinen boyutlar statik olarak kontrol edilir ve dinamik boyutlar herhangi bir kısıtlama getirmez.

Çıkış şeklini işlenen olarak alan işlemler için şekil uyuşmazlıkları

Aşağıdaki oyuncak programını inceleyin:

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

Çalışma zamanında şekil işlenenindeki değerler, sonucun şekliyle eşleşmelidir. Aksi takdirde davranış tanımlanmamış olur. Yani, çalışma zamanında %arg0, dense<[3, 4]> : tensor<2xi32> değerine sahip olmalıdır. Şekil işleneni sabitse bu durum statik olarak doğrulanabilir. Sonuç şekli tamamen dinamikse uyuşmazlık olamaz.