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)isesize(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).
- (C12)
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
truevefalse'ü temsil eder. - Tam sayı türleri işaretli (
si) veya işaretsiz (ui) olabilir ve desteklenen bit genişliklerinden birine (2,4,8,16,32veya64) sahip olabilir. İşaretlisiNtürleri,-2^(N-1)ile2^(N-1)-1arasındaki tam sayı değerlerini (bu değerler dahil) temsil eder. İşaretsizuiNtürleri ise0ile2^N-1arasındaki tam sayı değerlerini (bu değerler dahil) temsil eder. - Kayan nokta türleri aşağıdakilerden biri olabilir:
f8E3M4,f8E4M3vef8E5M2, IEEE-754 kurallarına uygun 8 bitlik kayan nokta sayılarıdır.f8E4M3FNvef8E5M2türleri, FP8 Formats for Deep Learning (Derin Öğrenme için FP8 Biçimleri) başlıklı makalede açıklanan FP8 biçiminin sırasıylaE4M3veE5M2kodlamalarına karşılık gelir.f8E4M3FNUZvef8E5M2FNUZtürleri, 8-bit Numerical Formats for Deep Neural Networks (Derin Sinir Ağları İçin 8 Bit Sayısal Biçimler) başlıklı makalede açıklanan FP8 biçimlerininE4M3veE5M2kodlamalarına karşılık gelir.f8E4M3B11FNUZtürü,E4M3kodlamasına karşılık gelir. FP8 biçimlerinin kodlaması, Derin Sinir Ağları İçin Hibrit 8 Bit Kayan Noktalı (HFP8) Eğitim ve Çıkarım başlıklı makalede açıklanmıştır.bf16, BFloat16: The secret to high performance on Cloud TPUs (BFloat16: Cloud TPU'larda yüksek performansın sırrı) başlıklı makalede açıklananbfloat16biçimine karşılık gelen tür.f16,f32vef64türleri sırasıylabinary16("yarım duyarlıklı"),binary32("tek duyarlıklı") vebinary64("çift duyarlıklı") biçimlerine karşılık gelir. Bu biçimler IEEE 754 standardında açıklanmıştır.tf32türü, TensorFloat32 biçimine karşılık gelir ve StableHLO'da sınırlı destek sunar.- OCP Microscaling Formats Specification'da açıklanan
f4E2M1FN,f6E2M3FN,f6E3M2FNvef8E8M0FNUMX (mikro ölçeklendirme) türleri.
- 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 def32türündedir) vecomplex<f64>(her iki bölüm def64tü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))iseis_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]
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).
- (C1)
- İş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)isequantization_dimension(lhs) = quantization_dimension(result). - (C7)
is_per_axis_quantized(rhs)isequantization_dimension(rhs) = quantization_dimension(result).
- (C2)
Ö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]]
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
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)ifchannel_id <= 0 and use_global_device_ids = false.cross_replica_and_partition(replica_groups)ifchannel_id > 0 and use_global_device_ids = false.flattened_ids(replica_groups)ifchannel_id > 0 and use_global_device_ids = true.
Ardından, her bir process_group içinde:
process_groupiçindeki tümreceiveriçinoperands...@receiver = [operand@sender for sender in process_group].process_groupiçindeki tümprocessiçinresults...@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_replicakullanılıyorsanum_replicascross_replica_and_partitionkullanılıyorsanum_replicasflattened_idskullanılıyorsanum_processes
- (C4)
0 <= replica_groups < size(replica_groups). - (C5)
use_global_device_ids = trueisechannel_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]]
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)ifchannel_id <= 0 and use_global_device_ids = false.cross_replica_and_partition(replica_groups)ifchannel_id > 0 and use_global_device_ids = false.flattened_ids(replica_groups)ifchannel_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çinschedule. Burada:exec(node)=computation(exec(node.left), exec(node.right)).exec(leaf)=leaf.value.
schedule, sıralı geçişito_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_replicakullanılıyorsanum_replicascross_replica_and_partitionkullanılıyorsanum_replicasflattened_idskullanılıyorsanum_processes
- (C3)
0 <= replica_groups < size(replica_groups). - (C4)
use_global_device_ids = trueisechannel_id > 0. - (C5)
computation,(tensor<E>, tensor<E>) -> (tensor<E>)türünde. Buradais_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]
all_to_all
Anlam Bilimi
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)isechannel_id <= 0.cross_partition(replica_groups)isechannel_id > 0.
Ardından, her bir process_group içinde:
split_parts...@sender = split(operands...@sender, split_count, split_dimension)process_groupiçindeki tümsenderiçin.scattered_parts...@receiver = [split_parts...@sender[receiver_index] for sender in process_group]wherereceiver_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_replicakullanılıyorsanum_replicascross_partitionkullanılıyorsanum_partitions
- (C7)
0 <= replica_groups < size(replica_groups). - (C8)
dim(replica_groups, 1) = split_count. - (C9)
type(results...) = type(operands...),split_dimension != concat_dimensionkoş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]]
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]]
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]
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_scalevegrad_offsetaynıbaseline_element_type'a sahiptir. - (C3)
operand,grad_outputvegrad_operandaynı şekle sahip. - (C4)
scale,mean,variance,grad_scalevegrad_offsetaynı ş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,varianceveresultaynı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_varveoutputaynı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)veR = rank(operand)değerleri verildiğinde:num_bits(E') = num_bits(E)iseshape(result) = shape(operand).- Eğer
num_bits(E') < num_bits(E): rank(result) = R + 1.dim(result, i) = dim(operand, i)tüm0 <= i < Riç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üm0 <= i < Riçin.dim(operand, R - 1) * num_bits(E) = num_bits(E').
- (C2)
is_complex(operand) or is_complex(result)iseis_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
broadcast_in_dim
Anlam bilimi
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] = 0isedim(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)iseelement_type(operand).element_type(operand)hariç olmak üzerequantization_dimension(operand),scales(operand)vezero_points(operand),quantization_dimension(result),scales(result)vezero_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ümdiçin:dim(operand, d) = 1veyadim(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)) = 1isescales(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]
// ]
// ]
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]ise0 <= 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]
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]
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]
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]
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)isechannel_id <= 0.cross_partition(replica_groups)isechannel_id > 0.
Daha sonra result@process şu şekilde verilir:
operand@process_groups[i, 0]varsa süreçiiç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 < NburadaNşu şekilde tanımlanır:cross_replicakullanılıyorsanum_replicascross_partitionkullanılıyorsanum_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)isechannel_id <= 0.cross_partition(source_target_pairs)isechannel_id > 0.
Daha sonra result@process şu şekilde verilir:
operand@process_groups[i, 0],process_groups[i, 1] = processolacak şekilde birivarsa.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, buradaNşu şekilde tanımlanır:cross_replicakullanılıyorsanum_replicascross_partitionkullanılıyorsanum_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]]
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:SIGNEDiseis_signed_integer(element_type(lhs)).UNSIGNEDiseis_unsigned_integer(element_type(lhs)) or is_boolean(element_type(lhs)).FLOATveyaTOTALORDERiseis_float(element_type(lhs)).FLOATiseis_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]
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 durumlardacomplex<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)]
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>
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:
id = d0 + ... + dk-1 + kd.d,dimensiondeğerine eşittir ved0, ...inputsöğesinind. 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]]
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]]
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)]
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.
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_countiseresult_dim = output_batch_dimension.dim(rhs, kernel_output_feature_dimension)iseresult_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).
- (C27)
- İşlemde nicel tensorlar kullanılıyorsa:
- (C28)
is_quantized(lhs) = is_quantized(result) and is_quantized(rhs). - (C29)
is_per_axis_quantized(rhs)isequantization_dimension(rhs) = kernel_output_feature_dimension. - (C30)
is_per_axis_quantized(result)isequantization_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)iseis_per_tensor_quantized(result). - Eğer
!is_quantized(lhs): - (C34)
element_type(lhs) = expressed_type(rhs) = element_type(result).
- (C28)
Ö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]]
// ]]
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]]
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]]
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]
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_indexburadasize(result_batching_index) = size(lhs_batching_dimensions),size(result_lhs_index) = size(lhs_result_dimensions)vesize(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_typeverhs_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_typeBirikim için kullanılan hassasiyet.lhs_component_count,rhs_component_countvenum_primitive_operationssol 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ğerler1olarak 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).
- (C13)
- İş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)isequantization_dimension(rhs),rhs_contracting_dimensionsiç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)iseis_per_tensor_quantized(result). - Eğer
!is_quantized(lhs): - (C20)
element_type(lhs) = expressed_type(rhs) = element_type(result).
- (C14)
!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.
- (C21)
Ö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]]
// ]
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)iseelement_type(operand).element_type(operand)hariç olmak üzerequantization_dimension(operand),scales(operand)vezero_points(operand),quantization_dimension(result),scales(result)vezero_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ümdiçin:dim(operand, d) = 1veyadim(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)) = 1isescales(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]
// ]
// ]
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_countiseresult_dim = output_batch_dimension.dim(rhs, kernel_output_feature_dimension)iseresult_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).
- (C27)
- İşlemde nicel tensorlar kullanılıyorsa:
- (C28)
is_quantized(lhs) = is_quantized(result) and is_quantized(rhs). - (C29)
is_per_axis_quantized(rhs)isequantization_dimension(rhs) = kernel_output_feature_dimension. - (C30)
is_per_axis_quantized(result)isequantization_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)iseis_per_tensor_quantized(result). - Eğer
!is_quantized(lhs): - (C34)
element_type(lhs) = expressed_type(rhs) = element_type(result).
- (C28)
Ö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]]
// ]]
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_dimile eşleşenstart_indicesboyutunun boyutu dahil değildir.offset_dim_sizes = shape(slice_sizes),collapsed_slice_dimsile eşleşenslice_sizesboyutları hariç.combine,batch_dim_sizesdeğerinibatch_dimsdeğerine karşılık gelen eksenlere,offset_dim_sizesdeğerini iseoffset_dimsdeğ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]]
// ]
// ]
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]
// ]
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]
// ]
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)iseelement_type(operand).element_type(operand)dışındaquantization_dimension(operand)vequantization_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]]
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]
// ]
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]ise0 <= 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]
// ]
ü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]]
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]
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_resultneredecomplex_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)
operandveresultöğe türleri arasındaki ilişki değişir:fft_type = FFT,element_type(operand)veelement_type(result)aynı karmaşık türe sahipse.fft_type = IFFT,element_type(operand)veelement_type(result)aynı karmaşık türe sahipse.fft_type = RFFTiseelement_type(operand), kayan nokta türü veelement_type(result), aynı kayan nokta semantiğine sahip karmaşık bir türdür.fft_type = IRFFTiseelement_type(operand)karmaşık bir türdür veelement_type(result), aynı kayan nokta semantiğine sahip bir kayan nokta türüdür.
- (C3)
1 <= size(fft_length) <= 3. - (C4)
operandveresultarasında kayan nokta türünde bir tensörrealvarsashape(real)[-size(fft_length):] = fft_length. - (C5)
shape(result) = shape(operand)hariç:fft_type = RFFTise:dim(result, -1) = dim(operand, -1) = 0 ? 0 : dim(operand, -1) / 2 + 1.fft_type = IRFFTise: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]
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.
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]. Buradabi,batch_indexiçindeki bağımsız öğelerdir veindex_vector_dim<rank(start_indices)ise:,index_vector_dimdizinine eklenir.- Aksi takdirde
[start_indices[batch_index]].
axes(operand)içinded_operandiçin,full_start_index[d_operand] = clamp(start_index[d_start], 0, dim(operand, d_operand) - slice_sizes[d_operand])ifd_operand = start_index_map[d_start].- Aksi takdirde
full_start_index[d_operand] = 0.
axes(operand)içinded_operandiçin,full_batching_index[d_operand] = batch_index[d_start - (d_start < index_vector_dim ? 0 : 1)]ifd_operand = operand_batching_dims[i_batching]ved_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]. Buradaoi,offset_indexiçindeki bağımsız öğelerdir ve0,collapsed_slice_dimsileoperand_batching_dimsarası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_dimile eşleşenstart_indicesboyutunun boyutu dahil değildir.offset_dim_sizes = slice_sizeshariç olmak üzere,collapsed_slice_dimsveoperand_batching_dimsile ilişkilislice_sizesiçindeki boyutlar dahil değildir.combine,batch_dim_sizesdeğerinibatch_dimsdeğerine karşılık gelen eksenlere,offset_dim_sizesdeğerini iseoffset_dimsdeğ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]]
// ]
// ]
// ]
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
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]
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
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))iseis_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]
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])veyais_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]]
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]
// ]
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]
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]]
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]
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]]
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])veE' = 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]]
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]]
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]]
Ç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]]
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]
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]
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
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]]
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
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]iseresult_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]
// ]
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>
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]
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]
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))iseis_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]
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, buradaNşu şekilde tanımlanır:cross_replicakullanılıyorsanum_replicascross_partitionkullanılıyorsanum_partitions
- (C5)
channel_typeşu şekilde tanımlanır:is_host_transfer = trueiseDEVICE_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)
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],:öğelerinindimensionskonumuna 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çinschedule. 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ındaindex_space(input_slices_converted)içindeki tümindexiçin.- Uygulamaya özel konumlarda, uygulamaya özel miktarda
init_values_convertedile 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ündetensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>)veis_promotable(element_type(inputs[i]), Ei). - (C7)
shape(results...) = shape(inputs...)dimensionsile eşleşeninputs...boyutları hariç. - (C8)
element_type(results[i]) = Eifor alliin[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]
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
roundToIntegralTiesToEvensemantiği kullanılarakmantissa_bitsile 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 bitlerimantissa_bits'ya kısaltılır. - Ardından, ara sonucun üs bitleri
exponent_bitstarafı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]
reduce_scatter
Anlam bilimi
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)ifchannel_id <= 0 and use_global_device_ids = false.cross_replica_and_partition(replica_groups)ifchannel_id > 0 and use_global_device_ids = false.flattened_ids(replica_groups)ifchannel_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_groupiçindeki tümsenderiçinresult@receiver = parts@sender[receiver_index], buradareceiver_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_replicakullanılıyorsanum_replicascross_replica_and_partitionkullanılıyorsanum_replicasflattened_idskullanılıyorsanum_processes
- (C5)
0 <= replica_groups < size(replica_groups). - (C6)
use_global_device_ids = trueisechannel_id > 0. - (C7)
computation,(tensor<E>, tensor<E>) -> (tensor<E>)türünde. Buradais_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]]
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.
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ündetensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>)veis_promotable(element_type(inputs[i]), Ei). - (C14)
same(shape(results...)). - (C15)
shape(results[0]) = num_windowsburada: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ümiiçinelement_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]]
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]
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>
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)iseelement_type(operand).element_type(operand)dışındaquantization_dimension(operand)vequantization_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]]
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] - 1dimensionskonumundadise.- 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]]
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 = NORMALiseis_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 = DEFAULTise uygulamaya bağlıdır.2iserng_algorithm = THREE_FRY.2veya3iserng_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]
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]
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]]
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.
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]buradasi,update_scatter_indexiçindeki bağımsız öğelerdir veindex_vector_dim<rank(scatter_indices)ise:,index_vector_dimdizinine eklenir.- Aksi takdirde
[scatter_indices[update_scatter_index]].
axes(inputs[0])içinded_inputiçin,full_start_index[d_input] = start_index[d_start]ised_input = scatter_dims_to_operand_dims[d_start].- Aksi takdirde
full_start_index[d_input] = 0.
axes(inputs[0])içinded_inputiçin,full_batching_index[d_input] = update_scatter_index[d_start - (d_start < index_vector_dim ? 0 : 1)]ifd_input = input_batching_dims[i_batching]ved_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]. Buradawi,update_window_indexiçindeki bağımsız öğelerdir ve0,inserted_window_dimsileinput_batching_dimsarası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çindeyseupdates_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ğeriupdated_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_dimile ilişkiliscatter_indicesboyutunun boyutu dahil değildir.update_window_dim_sizes <= shape(inputs[0])hariç olmak üzereinserted_window_dimsveinput_batching_dimsile ilişkiliinputs[0]içindeki boyutlar dahil değildir.combine,update_scatter_dim_sizesöğesiniupdate_scatter_dimsveupdate_window_dim_sizesöğesiniupdate_window_dimseksenlerine 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, buradais_promotable(element_type(inputs[i]), Ei). - (C24)
shape(inputs...) = shape(results...). - (C25)
element_type(results[i]) = Ei,[0,N)içindeki tümiiç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]]
// ]
// ]
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]]
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.
Daha resmi bir dille ifade etmek gerekirse:
selected_values = reduce_window_without_init(...)aşağıdaki girişlerle:inputs = [operand].window_dimensions,window_stridesvepaddingolduğ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)vereduce_window_without_init,reduce_windowile aynı şekilde çalışır. Tek fark, temelreduce'inschedule'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_indexiseselected_values[source_index],operand_indexkaynağındanoperandöğ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_windowsburada: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. BuradaE = element_type(operand). - (C10)
scatter,(tensor<E>, tensor<E>) -> tensor<E>türünde. Buradais_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]]
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, buradaNşu şekilde tanımlanır:cross_replicakullanılıyorsanum_replicascross_partitionkullanılıyorsanum_partitions
- (C5)
channel_typeşu şekilde tanımlanır:is_host_transfer = trueiseDEVICE_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
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]
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]
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]
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]
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]]
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]
// ]
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_indexiçindeki bağımsız öğelerdir ve:,adjusted_dimensionkonumuna 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üçüksetruedeğ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, buradaR = rank(inputs[0]). - (C5)
comparatortüründe(tensor<E1>, tensor<E1>, ..., tensor<EN-1>, tensor<EN-1>) -> tensor<i1>, whereEi = 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]]
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]]
çı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]]
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]
// ]
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]
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)iseelement_type(operand).element_type(operand)dışındaquantization_dimension(operand)vequantization_dimension(result)farklı olabilir.
- (C2)
permutation,range(rank(operand))öğesinin permütasyonudur. - (C3)
shape(result) = dim(operand, permutation...). - (C4)
is_per_axis_quantized(result)isequantization_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]]
// ]
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)ileshape(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 durumlardatuple<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))
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. BuradaTi = type(operand[i]). - (C2)
body,(T0, ..., TN-1) -> (T0, ..., TN-1)türündedir. BuradaTi = 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
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]]
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,complexkarşılaştırmaları #560, ve konvolüsyonwindow_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 → %2 → return ve %1 → %0 → %2 → return.
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
selfiç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 ilgiliTensorTypeveyaQuantizedTensorType'ninTensorElementTypeveyaQuantizedTensorElementTypebö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 Noneiçin bir kısayoldur.is_per_tensor_quantized(x: Value | Placeholder | Type) -> Value,is_quantized(x) and quantization_dimension(x) is Noneiçin bir kısayoldur.is_promotable(x: Type, y: Type) -> bool,xtürününytürüne yükseltilip yükseltilemeyeceğini kontrol eder.xvey,QuantizedTensorElementTypeolduğunda promosyon yalnızcastorage_typeiç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),xbirFloatTypeisetruedeğerini döndürür.xbir değer veya yer tutucuysa bu işlev,is_type_name(type(x))için bir kısayoldur.max_value(x: Type) -> Value, birTensorElementTypedeğerinin maksimum değerini döndürür.x,TensorElementTypedeğilseNonedeğerini döndürür.min_value(x: Type) -> Value,TensorElementTypeiçin mümkün olan en düşük değeri döndürür.x,TensorElementTypedeğilseNonedeğerini döndürür.member_name(x: Value | Placeholder | Type) -> Any. Tüm üye tanımlarımember_nameiçin kullanılabilir. Örneğin,tensor_element_type(x), ilgiliTensorTypeöğesininTensorElementTypebölümünü döndürür.xbir değer veya yer tutucuysa bu işlev,member_name(type(x))için bir kısayoldur.xuygun bir üyeye sahip bir tür değilse veya bu türden bir değer ya da yer tutucu değilseNonedeğerini döndürür.is_empty_algorithm(*args: Type), tüm nokta algoritması alanlarınınNoneolarak 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 (lhsverhs) alır veaddiş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 vexdeğerinitype(x)vedestination_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 vexöğelerinin tümüNaNisetrue, aksi takdirdefalsedeğerini döndürür.xbir tensör değilseNonedeğerini döndürür.is_sorted(x: Value) -> Value, tensörler üzerinde tanımlanır vexöğeleri, dizinlerinin artan sözcüksel sırasına göre artan düzende sıralanmışsatrue, aksi takdirdefalsedeğerini döndürür.xbir tensör değilseNonedeğerini döndürür.is_unique(x: Value) -> Value, tensörlerde tanımlanır vexöğesinde yinelenen öğe yoksatrue, aksi takdirdefalsedeğerini döndürür.xbir tensör değilseNonedeğerini döndürür.member_name(x: Value) -> Any, tüm değerlerin tüm üye tanımlarımember_nameiçin tanımlanır. Örneğin,real_part(x), ilgiliComplexConstantöğesininRealPartbölümünü döndürür.x, uygun bir üyeye sahip olmayan bir değerseNonedeğerini döndürür.same(x: Value) -> Value, tensörler üzerinde tanımlanır vexöğeleri birbirine eşitsetrue, aksi takdirdefalsedeğerini döndürür. Tensörde öğe yoksa bu durum "hepsi birbirine eşit" olarak kabul edilir. Yani işlevtruedeğerini döndürür.xtensör değilseNonedeğerini döndürür.split(x: Value, num_results: Value, axis: Value) -> Value, tensörler üzerinde tanımlanır veaxisekseni boyuncax'ninnum_resultsdilimini döndürür.xbir tensör veyadim(x, axis) % num_results != 0değilseNonedeğerini döndürür.is_defined_in_parent_scope(x: Value) -> Value, dizelerde tanımlanır vex, ilgili işlemin üst işleviyle aynı kapsamda tanımlanan bir işlevin adıysatruedeğerini döndürür.is_namespaced_op_name(x: Value) -> Value, dizelerde tanımlanır vexgeçerli bir işlem adıysa (yani şu normal ifadeye uyuyorsa)truedeğ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 gelenTensorTypeiçinsize(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).xbir tensör türü, nicelenmiş tensör türü veya bu türlerden birinin değeri ya da yer tutucusu değilseNonedeğ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ündemember_namearacı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_maxvequantization_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 ancakscalesvezero pointsfarklı 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.