StableHLO, makine öğrenimi (ML) modellerindeki üst düzey işlemler (HLO) için bir işlem grubudur. StableHLO, farklı ML çerçeveleri ve ML derleyicileri arasında bir taşınabilirlik katmanı olarak çalışır: StableHLO programları üreten ML çerçeveleri, StableHLO programlarını kullanan ML derleyicileriyle uyumludur.
Amacımız, çeşitli makine öğrenimi çerçeveleri (TensorFlow, JAX ve PyTorch gibi) ile makine öğrenimi derleyicileri (XLA ve IREE gibi) arasında daha fazla birlikte çalışabilirlik sağlayarak makine öğrenimi geliştirme sürecini basitleştirmek ve hızlandırmak. Bu amaçla, bu belgede StableHLO programlama dili için bir spesifikasyon sunulmaktadır.
Bu spesifikasyon üç ana bölümden oluşur. İlk olarak Programlar bölümünde, kendileri StableHLO işlemlerinden oluşan StableHLO işlevlerinden oluşan StableHLO programlarının yapısı açıklanmaktadır. Bu yapıda İşlemler bölümü, ayrı işlemlerin anlamlarını belirtir. Yürütme bölümü, bir programda birlikte yürütülen tüm bu işlemler için anlam sağlar. Son olarak Notasyon bölümünde, spesifikasyon boyunca kullanılan notasyon ele alınmaktadır.
StableHLO'nun önceki bir sürümüne ait spesifikasyonu görüntülemek için ilgili etiketlenmiş sürümde deposu açın. Örneğin, StableHLO v0.19.0 Spesifikasyonu. StableHLO'nun her küçük sürüm yükseltmesinde gerçekleşen değişiklikleri görüntülemek için VhloDialect.td'deki sürüm günlüğüne bakın.
Programlar
Program ::= {Func}
StableHLO programları, rastgele sayıda StableHLO işlevinden oluşur.
Aşağıda, 3 giriş (%image
, %weights
ve %bias
) ve 1 çıkışa sahip bir @main
işlevi içeren örnek bir program verilmiştir. İşlevin gövdesinde 6 işlem vardır.
func.func @main(
%image: tensor<28x28xf32>,
%weights: tensor<784x10xf32>,
%bias: tensor<1x10xf32>
) -> tensor<1x10xf32> {
%0 = "stablehlo.reshape"(%image) : (tensor<28x28xf32>) -> tensor<1x784xf32>
%1 = "stablehlo.dot"(%0, %weights) : (tensor<1x784xf32>, tensor<784x10xf32>) -> tensor<1x10xf32>
%2 = "stablehlo.add"(%1, %bias) : (tensor<1x10xf32>, tensor<1x10xf32>) -> tensor<1x10xf32>
%3 = "stablehlo.constant"() {value = dense<0.0> : tensor<1x10xf32>} : () -> tensor<1x10xf32>
%4 = "stablehlo.maximum"(%2, %3) : (tensor<1x10xf32>, tensor<1x10xf32>) -> tensor<1x10xf32>
"func.return"(%4): (tensor<1x10xf32>) -> ()
}
İşlevler
Func ::= 'func' '.' 'func' FuncId FuncInputs FuncOutputs '{' FuncBody '}'
FuncInputs ::= '(' [FuncInput {',' FuncInput}] `)`
FuncInput ::= ValueId ':' ValueType
FuncOutputs ::= ['->' FuncOutput, {',' FuncOutput}]
FuncOutput ::= ValueType
FuncBody ::= {Op}
StableHLO işlevleri (adlandırılmış işlevler olarak da bilinir), bir tanımlayıcı, giriş/çıkış ve bir gövdeye sahiptir. Gelecekte, HLO ile daha iyi uyumluluk elde etmek için işlevler için ek meta veriler sunmayı planlıyoruz (#425, #626, #740, #744).
Tanımlayıcılar
FuncId ::= '@' letter {letter | digit}
ValueId ::= '%' digit {digit}
| '%' letter {letter | digit}
letter ::= 'a' | ... | 'z' | 'A' | ... | 'Z' | '_'
digit ::= '0' | ... | '9'
StableHLO tanımlayıcıları, birçok programlama dilindeki tanımlayıcılara benzer, ancak iki özelliği vardır: 1) tüm tanımlayıcıların farklı tanımlayıcı türlerini ayırt eden eş değerleri vardır, 2) değer tanımlayıcıları StableHLO programlarının oluşturulmasını basitleştirmek için tamamen sayısal olabilir.
Türler
Type ::= ValueType | NonValueType
ValueType ::= TensorType | QuantizedTensorType | TokenType | TupleType
NonValueType ::= TensorElementType | QuantizedTensorElementType | FunctionType | StringType
StableHLO türleri, StableHLO değerlerini temsil eden değer türleri (birinci sınıf türler olarak da bilinir) ve diğer program öğelerini tanımlayan değer olmayan türler olarak kategorize edilir. StableHLO türleri, birçok programlama dilindeki türlere benzer. Temel özelliği, bazı sıra dışı sonuçlara yol açan StableHLO'nun alana özgü yapısıdır (ör. skaler türler değer türleri değildir).
TensorType ::= 'tensor' '<' Shape TensorElementType '>'
Shape ::= {DimensionSize 'x'}
DimensionSize ::= digit {digit} | '?'
Tenör türleri, tenörleri (yani çok boyutlu dizileri) temsil eder. Bu öğelerin bir şekli ve öğe türü vardır. Şekle, 0
ile R-1
arasında numaralandırılan ve ilgili boyutların (eksenler olarak da bilinir) artan sırasına göre negatif olmayan veya bilinmeyen boyut boyutlarını temsil eder. Boyut sayısı R
'e sıralama adı verilir. Örneğin tensor<2x3xf32>
, 2x3
şekline ve f32
öğe türüne sahip bir tensör türüdür. 0. boyut ve 1. boyut olmak üzere iki boyutu (veya başka bir deyişle iki ekseni) vardır. Bu boyutların boyutları 2 ve 3'tür. Sıralaması 2.
Şekiller kısmen veya tamamen bilinmeyen (dinamik) olabilir. Örneğin, tensor<?x2xf64>
kısmen bilinmiyor, tensor<?x?xf64>
tamamen bilinmiyor. Dinamik boyut boyutları, ?
kullanılarak gösterilir. Şekillerin sıralaması geri alınamaz.
Gelecekte, tensör türlerini boyut boyutlarının ve öğe türlerinin ötesine genişleterek, örneğin düzenler (#629) ve seyreklik (#1078) eklemeyi planlıyoruz.
QuantizedTensorType ::= 'tensor' '<' Shape QuantizedTensorElementType '>'
QuantizedTensorElementType ::= '!quant.uniform' '<'
QuantizationStorageType
['<' QuantizationStorageMin ':' QuantizationStorageMax '>']
':' QuantizationExpressedType
[':' QuantizationDimension]
',' QuantizationParameters '>'
QuantizationStorageType ::= IntegerType
QuantizationStorageMin ::= IntegerLiteral
QuantizationStorageMax ::= IntegerLiteral
QuantizationExpressedType ::= FloatType
QuantizationDimension ::= IntegerLiteral
QuantizationParameters ::= QuantizationParameter
| '{' QuantizationParameter {',' QuantizationParameter} '}'
QuantizationParameter ::= QuantizationScale [':' QuantizationZeroPoint]
QuantizationScale ::= FloatLiteral
QuantizationZeroPoint ::= IntegerLiteral
Ad | Tür | Sınırlamalar |
---|---|---|
storage_type |
tam sayı türü | (C1-C3), (C8) |
storage_min |
tam sayı sabiti | (C1), (C3), (C7) |
storage_max |
tam sayı sabiti | (C2), (C3), (C7) |
expressed_type |
kayan nokta türü | (C4) |
quantization_dimension |
isteğe bağlı tam sayı sabiti | (C10-C12) |
scales |
kayan nokta sabitlerinin değişken sayısı | (C4-C6), (C9), (C10), (C13) |
zero_points |
tam sayı sabitlerinin değişken sayısı | (C7-C9) |
Kantitatif öğe türleri, storage_min
ile storage_max
arasındaki (dahil) aralıkta bir depolama türü tam sayı değerlerini temsil eder. Bu değerler, ifade edilen tür kayan nokta değerlerine karşılık gelir. Belirli bir tam sayı değeri i
için karşılık gelen kayan nokta değeri (f
), f = (i - zero_point) * scale
olarak hesaplanabilir. Burada scale
ve zero_point
değerine nicelleştirme parametreleri denir. storage_min
ve storage_max
dil bilgisinde isteğe bağlıdır ancak sırasıyla min_value(storage_type)
ve max_value(storage_type)
varsayılan değerlerine sahiptir. Ölçülmüş öğe türleri aşağıdaki kısıtlamalara sahiptir:
- (C1)
type(storage_min) = storage_type
. - (C2)
type(storage_max) = storage_type
. - (C3)
min_value(storage_type) <= storage_min < storage_max <= max_value(storage_type)
. - (C4)
type(scales...) = expressed_type
. - (C5)
0 < scales
. - (C6)
is_finite(scales...)
. - (C7)
storage_min <= zero_points <= storage_max
. - (C8)
type(zero_points...) = storage_type
- (C9)
size(scales) = size(zero_points)
. - (C10)
is_empty(quantization_dimension)
isesize(scales) = 1
. - (C11)
0 <= quantization_dimension
.
Şu anda QuantizationScale
kayan noktalı bir sabit olsa da çarpanlar ve kaydırmalarla temsil edilen tam sayıya dayalı ölçeklere yönelik güçlü bir ilgi var. Bu özelliği yakın gelecekte araştırmayı planlıyoruz
(#1404).
Tür, değerler ve kesikli bir tensör türünde yalnızca bir veya birden fazla sıfır noktası bulunup bulunamayacağı da dahil olmak üzere QuantizationZeroPoint
'ün semantiği hakkında devam eden bir tartışma var. Bu tartışmanın sonuçlarına göre, sıfır noktayla ilgili spesifikasyon gelecekte değişebilir (#1405).
Devam eden bir diğer tartışma, bu değerlere ve kesikli tenzorların değerlerine herhangi bir kısıtlama uygulanıp uygulanmayacağını belirlemek için QuantizationStorageMin
ve QuantizationStorageMax
'nin semantiğiyle ilgilidir (#1406).
Son olarak, bilinmeyen boyut boyutlarını (#1407) temsil etmeyi planladığımız gibi, bilinmeyen ölçekleri ve sıfır noktaları temsil etmeyi de planlıyoruz.
Kantitatifleştirilmiş tenör türleri, kantitatifleştirilmiş öğelere sahip tenörleri temsil eder. Bu tensörler, öğelerinin normal öğe türleri yerine kesikli öğe türlerine sahip olması dışında normal tensörlerle tamamen aynıdır.
Kesirli tensörlerde kesirli sayım tensör başına olabilir. Bu durumda, tensörün tamamı için bir scale
ve zero_point
bulunur. Kesirli sayım eksen başına da olabilir. Bu durumda, belirli bir boyut quantization_dimension
'nin dilimi başına bir çift olmak üzere birden fazla scales
ve zero_points
bulunur. Daha resmi bir ifadeyle, eksen başına kesme işlemi uygulanmış bir t
tensörde quantization_dimension
'nin dim(t, quantization_dimension)
dilimi vardır: t[:, ..., 0, ..., :], t[:, ..., 1, ..., :]
vb. i
. dilimdeki tüm öğeler, kesme parametreleri olarak scales[i]
ve zero_points[i]
kullanır. Ölçülmüş tenör türleri aşağıdaki kısıtlamalara sahiptir:
- Tensör başına kesme için:
- Ek kısıtlama yoktur.
- Eksen başına kesme için:
- (C12)
quantization_dimension < rank(self)
- (C13)
dim(self, quantization_dimension) = size(scales)
.
- (C12)
TokenType ::= 'token'
Jeton türleri, jetonları (yani bazı işlemler tarafından üretilen ve tüketilen opak değerleri) temsil eder. Jetonlar, Yürütme bölümünde açıklandığı gibi işlemlere yürütme sırası uygulamak için kullanılır.
TupleType ::= 'tuple' '<' TupleElementTypes '>'
TupleElementTypes ::= [ValueType {',' ValueType}]
Tuple türleri, grupları (heterojen listeler) temsil eder. Tuplar, yalnızca HLO ile uyumluluk için mevcut olan eski bir özelliktir. HLO'da, değişken sayıda giriş ve çıkışı temsil etmek için kümeler kullanılır. StableHLO'da değişken girişler ve çıkışlar doğal olarak desteklenir. StableHLO'da tupların tek kullanımı, HLO ABI'yi kapsamlı bir şekilde temsil etmektir. Örneğin, T
, tuple<T>
ve tuple<tuple<T>>
belirli bir uygulamaya bağlı olarak önemli ölçüde farklı olabilir. Gelecekte, HLO ABI'de StableHLO'dan tuple türlerini kaldırmamıza olanak tanıyabilecek değişiklikler yapmayı planlıyoruz (#598).
TensorElementType ::= BooleanType | IntegerType | FloatType | ComplexType
BooleanType ::= 'i1'
IntegerType ::= SignedIntegerType | UnsignedIntegerType
SignedIntegerType ::= 'si2' | 'si4' | 'si8' | 'si16' | 'si32' | 'si64'
UnsignedIntegerType ::= 'ui2' | 'ui4' | 'ui8' | 'ui16' | 'ui32' | 'ui64'
FloatType ::= 'f4E2M1FN' | 'f6E2M3FN' | 'f6E3M2FN' | 'f8E3M4' | 'f8E4M3'
| 'f8E4M3FN' | 'f8E4M3FNUZ' | 'f8E4M3B11FNUZ' | 'f8E5M2'
| 'f8E5M2FNUZ' | 'f8E8M0FNU' | 'bf16' | 'f16' | 'f32' | 'f64'
TensorFloat32 ::= 'tf32'
ComplexType ::= 'complex' '<' ComplexElementType '>'
ComplexElementType ::= 'f32' | 'f64'
Öğe türleri, tensör türlerinin öğelerini temsil eder. Birçok programlama dilinin aksine, bu türler StableHLO'da birinci sınıf değildir. Bu, StableHLO programlarının bu türlerin değerlerini doğrudan temsil edemeyeceği anlamına gelir (sonuç olarak, T
türündeki skaler değerleri tensor<T>
türündeki 0 boyutlu tenör değerleriyle temsil etmek idiomatiktir).
- Boole türü,
true
vefalse
boole değerlerini temsil eder. - Tam sayı türleri, imzalı (
si
) veya imzasız (ui
) olabilir ve desteklenen bit genişliklerinden birine (2
,4
,8
,16
,32
veya64
) sahip olabilir. İmzalısiN
türleri,-2^(N-1)
ile2^(N-1)-1
dahil arasındaki tam sayı değerlerini, imzasızuiN
türleri ise0
ile2^N-1
dahil arasındaki tam sayı değerlerini temsil eder. - Kayan nokta türleri aşağıdakilerden biri olabilir:
f8E3M4
,f8E4M3
vef8E5M2
8 bitlik kayan nokta numaraları (IEEE-754 kurallarına uygun).- Derin Öğrenme için FP8 Biçimleri bölümünde açıklanan FP8 biçiminin sırasıyla
E4M3
veE5M2
kodlamalarına karşılık gelenf8E4M3FN
vef8E5M2
türleri. - Derin Sinir Ağları için 8 Bit Sayısal Biçimler bölümünde açıklanan FP8 biçimlerinin
E4M3
veE5M2
kodlamalarına karşılık gelenf8E4M3FNUZ
vef8E5M2FNUZ
türleri. - Derin Nöral Ağlar için Karma 8 Bitlik Kayan Nokta (HFP8) Eğitimi ve Tahmini bölümünde açıklanan FP8 biçimlerinin
E4M3
kodlamasına karşılık gelenf8E4M3B11FNUZ
türü. - BFloat16: Cloud TPU'larda yüksek performansın sırrı başlıklı makalede açıklanan
bfloat16
biçimine karşılık gelenbf16
türü. - IEEE 754 standardında açıklanan
binary16
("yarım hassasiyet"),binary32
("tek hassasiyet") vebinary64
("çift hassasiyet") biçimlerine karşılık gelenf16
,f32
vef64
türleri. tf32
türü, TensorFloat32 biçimine karşılık gelir ve StableHLO'da sınırlı destek alır.- OCP Mikro Ölçeklendirme Biçimleri Spesifikasyonu'nda açıklanan
f4E2M1FN
,f6E2M3FN
,f6E3M2FN
vef8E8M0FNU
MX (mikro ölçeklendirme) türleri.
- Karmaşık türler, aynı öğe türünde reel bir bölüme ve sanal bir bölüme sahip karmaşık değerleri temsil eder. Desteklenen karmaşık türler
complex<f32>
(her iki bölüm def32
türündedir) vecomplex<f64>
(her iki bölüm def64
türündedir) türleridir.
FunctionType ::= '(' InputTypes ')' '->' '(' OutputTypes ')'
InputTypes ::= [ValueType {',' ValueType}]
OutputTypes ::= [ValueType {',' ValueType}]
İşlev türleri hem adlandırılmış hem de anonim işlevleri temsil eder. Bunlar giriş türlerine (->
'ün sol tarafındaki tür listesi) ve çıkış türlerine (->
'ün sağ tarafındaki tür listesi) sahiptir. Birçok programlama dilinde işlev türleri birinci sınıftır ancak StableHLO'da değildir.
StringType ::= 'string'
Dize türü, bayt dizilerini temsil eder. Birçok programlama dilinin aksine, dize türü StableHLO'da birinci sınıf değildir ve yalnızca program öğeleri için statik meta verileri belirtmek amacıyla kullanılır.
İşlemler
StableHLO işlemleri (işlemler olarak da bilinir), makine öğrenimi modellerindeki kapalı bir üst düzey işlem grubunu temsil eder. Yukarıda da belirtildiği gibi, StableHLO söz dizimi büyük ölçüde MLIR'den esinlenmiştir. MLIR her zaman en ergonomik alternatif olmasa da StableHLO'nun ML çerçeveleri ile ML derleyicileri arasında daha fazla birlikte çalışabilirlik oluşturma hedefine en uygun seçenektir.
Op ::= [OpOutputs] OpName OpInputs ':' OpSignature
OpName ::= '"' 'stablehlo' '.' OpMnemonic '"'
OpMnemonic ::= 'abs' | 'add' | ...
StableHLO işlemleri (işlemler olarak da bilinir) bir ada, giriş/çıkışa ve imzaya sahiptir. Ad, stablehlo.
ön eki ve desteklenen işlemlerden birini benzersiz şekilde tanımlayan bir hatırlatıcıdan oluşur. Desteklenen tüm işlemlerin kapsamlı bir listesini aşağıda bulabilirsiniz.
OpInputs ::= OpInputValues OpInputFuncs OpInputAttrs
OpInputValues ::= '(' [OpInputValue {',' OpInputValue}] ')'
OpInputValue ::= ValueId
OpInputFuncs ::= ['(' OpInputFunc {',' OpInputFunc} ')']
OpInputAttrs ::= ['{' OpInputAttr {',' OpInputAttr} '}']
OpOutputs ::= [OpOutput {',' OpOutput} '=']
OpOutput ::= ValueId
İşlemler girişler tüketir ve çıktılar oluşturur. Girişler, giriş değerleri (yürütme sırasında hesaplanır), giriş işlevleri (StableHLO'da işlevler birinci sınıf değerler olmadığı için statik olarak sağlanır) ve giriş özellikleri (ayrıca statik olarak sağlanır) olarak sınıflandırılır. Bir işlem tarafından tüketilen ve üretilen giriş ve çıkışların türü, o işlemin anımsatıcısına bağlıdır. Örneğin, add
op 2 giriş değeri tüketir ve 1 çıkış değeri oluşturur. Buna karşılık, select_and_scatter
işlemi 3 giriş değeri, 2 giriş işlevi ve 3 giriş özelliği kullanır.
OpInputFunc ::= '{' Unused FuncInputs ':' FuncBody '}'
Unused ::= '^' digit {digit}
| '^' letter {letter | digit}
Giriş işlevleri (anonim işlevler olarak da bilinir), adlandırılmış işlevlere çok benzer. Bununla birlikte, aşağıdakiler dışında adlandırılmış işlevlere benzerler: 1) Tanımlayıcıları yoktur (bu nedenle "anonim" adı kullanılır), 2) Çıkış türlerini belirtmezler (Çıkış türleri, işlev içindeki return
op'sinden anlaşılır).
Giriş işlevlerinin söz dizimi, şu anda kullanılmayan bir kısmı (yukarıdaki Unused
üretimine bakın) içeriyor. Bu parça MLIR ile uyumludur. MLIR'de, atlama işlemleri aracılığıyla birbirine bağlı birden fazla işlem "bloğu" içerebilen daha genel bir "bölge" kavramı vardır. Bu blokların, birbirinden ayırt edilebilmesi için Unused
üretimine karşılık gelen kimlikleri vardır.
StableHLO'da atlama işlemleri olmadığından MLIR söz dizesinin ilgili kısmı kullanılmaz (ancak yine de mevcuttur).
OpInputAttr ::= OpInputAttrName '=' OpInputAttrValue
OpInputAttrName ::= letter {letter | digit}
OpInputAttrValue ::= Constant
Giriş özelliklerinin bir adı ve desteklenen sabit değerlerinden biri olan bir değeri vardır. Program öğeleri için statik meta verileri belirtmenin birincil yoludur. Örneğin, concatenate
işlemi, giriş değerlerinin birleştirildiği boyutu belirtmek için dimension
özelliğini kullanır. Benzer şekilde, slice
işlemi, giriş değerini dilimlemek için kullanılan sınırları belirtmek için start_indices
ve limit_indices
gibi birden fazla özellik kullanır.
Şu anda kullanımdaki StableHLO programları bazen bu dokümanda açıklanmayan özellikler içeriyor. Gelecekte bu özellikleri StableHLO işletim sistemine dahil etmeyi veya StableHLO programlarında görünmelerini yasaklamayı planlıyoruz. Bu sırada, bu özelliklerin listesini aşağıda bulabilirsiniz:
layout
(#629).mhlo.frontend_attributes
(#628).mhlo.sharding
(#619).output_operand_aliases
(#740).- Konum meta verileri (#594).
OpSignature ::= '(' [ValueType {',' ValueType}] ')' '->' '(' [ValueType {',' ValueType}] ')'
İşlem imzası, tüm giriş değerlerinin türlerinden (->
'nin sol tarafındaki tür listesi) ve tüm çıkış değerlerinin türlerinden (->
'nin sağ tarafındaki tür listesi) oluşur. Giriş türleri ve çıkış türleri genellikle gereksizdir (çünkü çoğu StableHLO işleminde çıkış türleri girişlerden çıkarılabilir). Yine de op türü, MLIR ile uyumluluk için StableHLO söz dizesinin bir parçası olarak bilinçli olarak tasarlanmıştır.
Aşağıda, select_and_scatter
kısaltması olan bir örnek işlem verilmiştir. 3 giriş değeri (%operand
, %source
ve %init_value
), 2 giriş işlevi ve 3 giriş özelliği (window_dimensions
, window_strides
ve padding
) tüketir. İşlemin imzasının yalnızca giriş değerlerinin türlerini içerdiğini (ancak satır içi olarak sağlanan giriş işlevlerinin ve özelliklerin türlerini içermediğini) unutmayın.
%result = "stablehlo.select_and_scatter"(%operand, %source, %init_value) ({
^bb0(%arg0: tensor<i32>, %arg1: tensor<i32>):
%0 = "stablehlo.compare"(%arg0, %arg1) {
comparison_direction = #stablehlo<comparison_direction GE>
} : (tensor<i32>, tensor<i32>) -> tensor<i1>
"stablehlo.return"(%0) : (tensor<i1>) -> ()
}, {
^bb0(%arg0: tensor<i32>, %arg1: tensor<i32>):
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i32>, tensor<i32>) -> tensor<i32>
"stablehlo.return"(%0) : (tensor<i32>) -> ()
}) {
window_dimensions = dense<[3, 1]> : tensor<2xi64>,
window_strides = dense<[2, 1]> : tensor<2xi64>,
padding = dense<[[0, 1], [0, 0]]> : tensor<2x2xi64>
} : (tensor<4x2xi32>, tensor<2x2xi32>, tensor<i32>) -> tensor<4x2xi32>
Sabitler
Constant ::= BooleanConstant
| IntegerConstant
| FloatConstant
| ComplexConstant
| TensorConstant
| QuantizedTensorConstant
| StringConstant
| EnumConstant
StableHLO sabitleri, birlikte bir StableHLO değerini temsil eden bir değişmez ve bir türe sahiptir. Türü, açık olmadığı durumlar hariç (ör. doğru/yanlış sabitinin türü açıkça i1
iken tam sayı sabitinin birden fazla olası türü olabilir) genellikle sabit söz dizesinin bir parçasıdır.
BooleanConstant ::= BooleanLiteral
BooleanLiteral ::= 'true' | 'false'
Boole sabitleri, true
ve false
boole değerlerini temsil eder. Boole sabitleri i1
türüne sahiptir.
IntegerConstant ::= IntegerLiteral ':' IntegerType
IntegerLiteral ::= ['-' | '+'] DecimalDigits
| ['-' | '+'] '0x' HexadecimalDigits
DecimalDigits ::= decimalDigit {decimalDigit}
HexadecimalDigits ::= hexadecimalDigit {hexadecimalDigit}
decimalDigit ::= '0' | ... | '9'
hexadecimalDigit ::= decimalDigit | 'a' | ... | 'f' | 'A' | ... | 'F'
Tam sayı sabitleri, ondalık veya onaltılık gösterim kullanan dizeler aracılığıyla tam sayı değerlerini temsil eder. Diğer tabanlar (ör. ikili veya sekizlik) desteklenmez. Tam sayı sabitleri aşağıdaki kısıtlamalara sahiptir:
- (C1)
is_wellformed(integer_literal, integer_type)
.
FloatConstant ::= FloatLiteral ':' FloatType
FloatLiteral ::= SignPart IntegerPart FractionalPart ScientificPart
| '0x' [HexadecimalDigits]
SignPart ::= ['-' | '+']
IntegerPart ::= DecimalDigits
FractionalPart ::= ['.' [DecimalDigits]]
ScientificPart ::= [('e' | 'E') ['-' | '+'] DecimalDigits]
Kayan nokta sabitleri, ondalık veya bilimsel gösterim kullanan dizeler aracılığıyla kayan nokta değerlerini temsil eder. Ayrıca, onaltılık gösterim, temel bitleri ilgili türün kayan nokta biçiminde doğrudan belirtmek için de kullanılabilir. Kayan noktalı sabitler aşağıdaki kısıtlamalara sahiptir:
- (C1) Onaltılık olmayan gösterim kullanılıyorsa
is_wellformed(float_literal, float_type)
. - (C2) Onaltılık gösterim kullanılıyorsa
size(hexadecimal_digits) = num_bits(float_type) / 4
.
ComplexConstant ::= ComplexLiteral ':' ComplexType
ComplexLiteral ::= '(' RealPart ',' ImaginaryPart ')'
RealPart ::= FloatLiteral
ImaginaryPart ::= FloatLiteral
Karmaşık sabitler, gerçek kısım (ilk sırada gelir) ve sanal kısım (ikinci sırada gelir) listelerini kullanarak karmaşık değerleri temsil eder. Örneğin, (1.0, 0.0) : complex<f32>
, 1.0 + 0.0i
'u, (0.0, 1.0) : complex<f32>
ise 0.0 + 1.0i
'ı temsil eder. Bu parçaların bellekte depolanma sırası, uygulamaya göre belirlenir. Karmaşık sabitler aşağıdaki kısıtlamalara sahiptir:
- (C1)
is_wellformed(real_part, complex_element_type(complex_type))
. - (C2)
is_wellformed(imaginary_part, complex_element_type(complex_type))
.
TensorConstant ::= TensorLiteral ':' TensorType
TensorLiteral ::= 'dense' '<' (DenseLiteral | ElementLiteral) '>'
DenseLiteral ::= DenseDimension | DenseElements
DenseDimension ::= '[' [DenseLiteral {',' DenseLiteral}] ']'
DenseElements ::= [ElementLiteral {',' ElementLiteral}]
ElementLiteral ::= BooleanLiteral | IntegerLiteral | FloatLiteral | ComplexLiteral
Tensor sabitleri, NumPy gösterimi ile belirtilen iç içe geçmiş listeleri kullanan tensör değerlerini temsil eder. Örneğin dense<[[1, 2, 3], [4, 5, 6]]> : tensor<2x3xi32>
, dizinlerden öğelere yapılan aşağıdaki eşlemeyle bir tensör değerini temsil eder: {0, 0} => 1
, {0, 1} => 2
, {0, 2} => 3
, {1, 0} => 4
, {1, 1} => 5
,{1, 2} => 6
. Bu öğelerin bellekte depolanma sırası, uygulamaya göre belirlenir. Tensör sabitleri aşağıdaki kısıtlamalara sahiptir:
- (C1)
has_syntax(tensor_literal, element_type(tensor_type))
. Burada:has_syntax(element_literal: Syntax, element_type: Type) = is_wellformed(element_literal, type)
.has_syntax(tensor_literal: List, element_type: Type) = has_syntax(tensor_literal..., element_type)
.
- (C2)
has_shape(tensor_literal, shape(tensor_type))
, burada:has_shape(element_literal: Syntax, []) = true
.has_shape(tensor_literal: List, shape: List) = size(tensor_literal) = shape[0] and has_shape(tensor_literal..., shape[1:])
.- aksi takdirde
false
.
QuantizedTensorConstant ::= QuantizedTensorLiteral ':' QuantizedTensorType
QuantizedTensorLiteral ::= 'dense' '<' (DenseLiteral | ElementLiteral) '>'
Nicelleştirilmiş tensör sabitleri, tensör sabitleriyle aynı gösterimi kullanan nicelenmiş tensör değerlerini temsil eder ve öğeler, depolama türlerinin sabitleri olarak belirtilir. Ölçülmüş tenör sabitleri aşağıdaki kısıtlamalara sahiptir:
- (C1)
has_syntax(quantized_tensor_literal, storage_type(quantized_tensor_type))
. - (C2)
has_shape(quantized_tensor_literal, shape(quantized_tensor_type))
.
StringConstant ::= StringLiteral
StringLiteral ::= '"' {stringCharacter | escapeSequence} '"'
stringCharacter ::= all ASCII characters except '\00', '\01', ... '\1f' and '"'
escapeSequence ::= '\' ('"' | '\' | 'n' | 't' | (hexadecimalDigit hexadecimalDigit))
Dize sabit değerleri, ASCII karakterleri ve kaçış dizileri kullanılarak belirtilen baytlardan oluşur. Kodlamaya duyarlı değildirler. Bu nedenle, bu baytların yorumlanması uygulamaya göre belirlenir. Dize değişmezleri string
türüne sahiptir.
İşlemler
abs
Anlam
operand
tensörü üzerinde öğe düzeyinde abs işlemi gerçekleştirir ve result
tensörü üretir. Öğe türüne bağlı olarak aşağıdakileri yapar:
- İmzalı tam sayılar için: tamsayı modülü.
- Kayan reklamlar için: IEEE-754'ten
abs
. - Karmaşık sayılar için: karmaşık modül.
- Miktarlanmış türler için:
dequantize_op_quantize(abs, operand, type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
işaretli tam sayı, kayan nokta veya karmaşık türde veya tensör başına kesirli tensör | (C1-C2) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
işaretli tam sayı veya kayan nokta türündeki veya tensör başına kesirli tensör | (C1-C2) |
Sınırlamalar
- (C1)
shape(result) = shape(operand)
. - (C2)
baseline_element_type(result)
şu şekilde tanımlanır:is_complex(operand)
isecomplex_element_type(element_type(operand))
.- Aksi takdirde
baseline_element_type(operand)
değerini alır.
Örnekler
// %operand: [-2, 0, 2]
%result = "stablehlo.abs"(%operand) : (tensor<3xi32>) -> tensor<3xi32>
// %result: [2, 0, 2]
add
Anlam bilimi
İki tensör lhs
ve rhs
'ün öğe bazında toplama işlemini gerçekleştirir ve result
tensörü oluşturur. Öğe türüne bağlı olarak aşağıdakiler gerçekleşir:
- Boole değerleri için: mantıksal VEYA.
- Tam sayılar için: tamsayı toplama.
- Kayan noktalı sayılar için: IEEE-754'ten
addition
. - Karmaşık sayılar için: karmaşık toplama.
- Kesirli türler için:
dequantize_op_quantize(add, lhs, rhs, type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | lhs |
tenzor veya kesirli tenzor | (C1-C6) |
(I2) | rhs |
tenzor veya kesirli tenzor | (C1-C5), (C7) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tenzor veya kesirli tenzor | (C1-C7) |
Sınırlamalar
- İşlemde kesirli olmayan tenzorlar kullanılıyorsa:
- (C1)
type(lhs) = type(rhs) = type(result)
.
- (C1)
- İşlemde kesirli tenzorlar kullanılıyorsa:
- (C2)
is_quantized(lhs) and is_quantized(rhs) and is_quantized(result)
. - (C3)
storage_type(lhs) = storage_type(rhs) = storage_type(result)
. - (C4)
expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
. - (C5)
(is_per_axis_quantized(lhs) or is_per_axis_quantized(rhs)) = is_per_axis_quantized(result)
. - (C6)
is_per_axis_quantized(lhs)
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
inputs
değerini üreten işlemlerin, result
değerine bağlı tüm işlemlerden önce yürütülmesini sağlar. Bu işlemin yürütülmesi hiçbir şey yapmaz. Yalnızca result
ile inputs
arasında veri bağımlılıkları oluşturmak için vardır.
Girişler
Şirket | Ad | Tür |
---|---|---|
(I1) | inputs |
token değişken sayısı |
Çıkışlar
Ad | Tür |
---|---|
result |
token |
Örnekler
// %input0: !stablehlo.token
// %input1: !stablehlo.token
%result = "stablehlo.after_all"(%input0, %input1) : (!stablehlo.token, !stablehlo.token) -> !stablehlo.token
all_gather
Anlam bilimi
StableHLO işlem ızgarasındaki her işlem grubunda, all_gather_dim
boyunca her işlemden alınan operands
tenzorlarının değerlerini birleştirir ve results
tenzorları oluşturur.
İşlem, StableHLO işlem ızgarasını aşağıdaki gibi tanımlanan process_groups
olarak böler:
cross_replica(replica_groups)
channel_id <= 0 and use_global_device_ids = false
ise.channel_id > 0 and use_global_device_ids = false
isecross_replica_and_partition(replica_groups)
.flattened_ids(replica_groups)
channel_id > 0 and use_global_device_ids = true
ise.
Ardından her bir process_group
içinde:
process_group
adlı kuruluş biriminde tümreceiver
içinoperands...@receiver = [operand@sender for sender in process_group]
.process_group
kapsamındaki tümprocess
içinresults...@process = concatenate(operands...@process, all_gather_dim)
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operands |
değişken sayıda tenör veya tenör başına kesikli tenörler | (C1), (C6) |
(I2) | all_gather_dim |
si64 türünün sabiti |
(C1), (C6) |
(I3) | replica_groups |
si64 türündeki 2 boyutlu tensör sabit |
(C2-C4) |
(I4) | channel_id |
si64 türünün sabiti |
(C5) |
(I5) | use_global_device_ids |
i1 türünün sabiti |
(C5) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
results |
değişken sayıda tenör veya tenör başına kesikli tenörler | (C6) |
Sınırlamalar
- (C1)
0 <= all_gather_dim < rank(operands...)
. - (C2)
is_unique(replica_groups)
. - (C3)
size(replica_groups)
şu şekilde tanımlanır:cross_replica
kullanılıyorsanum_replicas
.cross_replica_and_partition
kullanılıyorsanum_replicas
.flattened_ids
kullanılıyorsanum_processes
.
- (C4)
0 <= replica_groups < size(replica_groups)
- (C5)
use_global_device_ids = true
isechannel_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 ızgarasındaki her işlem grubunda, her işlemdeki operands
tenörlerinin değerlerine bir azaltma işlevi computation
uygular ve results
tenörü oluşturur.
İşlem, StableHLO süreç ızgarasını şu şekilde tanımlanan process_groups
şeklinde ayırır:
cross_replica(replica_groups)
channel_id <= 0 and use_global_device_ids = false
ise.channel_id > 0 and use_global_device_ids = false
isecross_replica_and_partition(replica_groups)
.flattened_ids(replica_groups)
channel_id > 0 and use_global_device_ids = true
ise.
Ardından her bir process_group
içinde:
results...@process[result_index] = exec(schedule)
için bazı ikili ağaçschedule
şöyledir:exec(node)
=computation(exec(node.left), exec(node.right))
.exec(leaf)
=leaf.value
.
schedule
, sıralı traversal'ıto_destination_type(operands...@process_group...[result_index], type(func_inputs(computation)[0]))
olan, uygulama tanımlı bir ikili ağaçtır.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operands |
değişken sayıda tenör veya tenör başına kesikli tenörler | (C5), (C6) |
(I2) | replica_groups |
si64 türündeki 1 boyutlu tensör sabitlerinin değişken sayısı |
(C1-C3) |
(I3) | channel_id |
si64 türündeki sabit |
(C4) |
(I4) | use_global_device_ids |
i1 türünün sabiti |
(C4) |
(I5) | computation |
işlev | (C5) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
results |
değişken sayıda tenör veya tenör başına kesikli tenörler | (C6-C7) |
Sınırlamalar
- (C1)
is_unique(replica_groups)
. - (C2)
size(replica_groups)
şu şekilde tanımlanır:cross_replica
kullanılıyorsanum_replicas
.cross_replica_and_partition
kullanılıyorsanum_replicas
.flattened_ids
kullanılıyorsanum_processes
.
- (C3)
0 <= replica_groups < size(replica_groups)
. - (C4)
use_global_device_ids = true
isechannel_id > 0
. - (C5)
computation
,is_promotable(element_type(operand), E)
olduğunda(tensor<E>, tensor<E>) -> (tensor<E>)
türüne sahiptir. - (C6)
shape(results...) = shape(operands...)
. - (C7)
element_type(results...) = E
.
Örnekler
// num_replicas: 2
// num_partitions: 1
// %operand0@(0, 0): [1, 2, 3, 4]
// %operand0@(1, 0): [5, 6, 7, 8]
// %operand1@(0, 0): [9, 10, 11, 12]
// %operand1@(1, 0): [13, 14, 15, 16]
%result:2 = "stablehlo.all_reduce"(%operand0, %operand0) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
"stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>,
// channel_id = 0
channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
// use_global_device_ids = false
} : (tensor<4xi64>, tensor<4xi64>) -> (tensor<4xi64>, tensor<4xi64>)
// %result0@(0, 0): [6, 8, 10, 12]
// %result0@(1, 0): [6, 8, 10, 12]
// %result1@(0, 0): [22, 24, 26, 28]
// %result1@(1, 0): [22, 24, 26, 28]
all_to_all
Anlam bilimi
StableHLO işlem ızgarasındaki her işlem grubunda, operands
tenzorlarının değerlerini split_dimension
boyunca parçalara ayırır, ayrılan parçaları işlemler arasında dağıtır, dağıtılan parçaları concat_dimension
boyunca birleştirir ve results
tenzorları oluşturur.
İşlem, StableHLO işlem ızgarasını aşağıdaki gibi tanımlanan process_groups
olarak böler:
channel_id <= 0
isecross_replica(replica_groups)
.channel_id > 0
isecross_partition(replica_groups)
.
Daha sonra, her process_group
içinde:
process_group
adlı kuruluş biriminde tümsender
içinsplit_parts...@sender = split(operands...@sender, split_count, split_dimension)
scattered_parts...@receiver = [split_parts...@sender[receiver_index] for sender in process_group]
buradareceiver_index = process_group.index(receiver)
.results...@process = concatenate(scattered_parts...@process, concat_dimension)
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operands |
değişken sayıda tenör veya tenör başına kesikli tenörler | (C1-C3), (C9) |
(I2) | split_dimension |
si64 türündeki sabit |
(C1), (C2), (C9) |
(I3) | concat_dimension |
si64 türündeki sabit |
(C3), (C9) |
(I4) | split_count |
si64 türündeki sabit |
(C2), (C4), (C8), (C9) |
(I5) | replica_groups |
si64 türündeki 2 boyutlu tensör sabit |
(C5-C8) |
(I6) | channel_id |
si64 türünün sabiti |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
results |
değişken sayıda tenör veya tenör başına kesikli tenörler | (C9) |
Sınırlamalar
- (C1)
0 <= split_dimension < rank(operands...)
. - (C2)
dim(operands..., split_dimension) % split_count = 0
. - (C3)
0 <= concat_dimension < rank(operands...)
. - (C4)
0 < split_count
. - (C5)
is_unique(replica_groups)
- (C6)
size(replica_groups)
şu şekilde tanımlanır:cross_replica
kullanılıyorsanum_replicas
.cross_partition
kullanılıyorsanum_partitions
.
- (C7)
0 <= replica_groups < size(replica_groups)
. - (C8)
dim(replica_groups, 1) = split_count
. - (C9)
split_dimension != concat_dimension
isetype(results...) = type(operands...)
dışında:dim(results..., split_dimension) = dim(operands..., split_dimension) / split_count
.dim(results..., concat_dimension) = dim(operands..., concat_dimension) * split_count
.
Örnekler
// num_replicas: 2
// num_partitions: 1
// %operand1@(0, 0): [[1, 2, 3, 4],
// [5, 6, 7, 8]]
// %operand1@(1, 0): [[9, 10, 11, 12],
// [13, 14, 15, 16]]
// %operand2@(0, 0): [[17, 18, 19, 20],
// [21, 22, 23, 24]]
// %operand2@(1, 0): [[25, 26, 27, 28],
// [29, 30, 31, 32]]
%result:2 = "stablehlo.all_to_all"(%operand1, %operand2) {
split_dimension = 1 : i64,
concat_dimension = 0 : i64,
split_count = 2 : i64,
replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>
// channel_id = 0
} : (tensor<2x4xi64>, tensor<2x4xi64>) -> (tensor<4x2xi64>, tensor<4x2xi64>)
// %result#0@(0, 0): [[1, 2], [5, 6], [9, 10], [13, 14]]
// %result#0@(1, 0): [[3, 4], [7, 8], [11, 12], [15, 16]]
// %result#1@(0, 0): [[17, 18], [21, 22], [25, 26], [29, 30]]
// %result#1@(1, 0): [[19, 20], [23, 24], [27, 28], [31, 32]]
ve
Anlam bilimi
İki lhs
ve rhs
tenörünün öğe bazında VE işlemini gerçekleştirir ve bir result
tenörü oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:
- Boolelar için: mantıksal VE.
- Tam sayılar için: bit tabanlı VE.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | lhs |
boole veya tam sayı türündeki tenör | (C1) |
(I2) | rhs |
boole veya tam sayı türündeki tensor | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
boole veya tam sayı türündeki tenör | (C1) |
Sınırlamalar
- (C1)
type(lhs) = type(rhs) = type(result)
.
Örnekler
// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.and"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[1, 2], [3, 0]]
atan2
Anlam bilimi
lhs
ve rhs
tensöründe öğe bazında atan2 işlemi gerçekleştirir ve bir result
tensörü oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:
- Kayan reklamlar için: IEEE-754'ten
atan2
. - Karmaşık sayılar için: karmaşık atan2.
- Kesirli türler için:
dequantize_op_quantize(atan2, lhs, rhs, type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | lhs |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
(I2) | rhs |
kayan nokta veya karmaşık tür ya da tensör başına miktarlandırılmış tensör tensörü | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Sınırlamalar
- (C1)
baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)
.
Örnekler
// %lhs: [0.0, 1.0, -1.0]
// %rhs: [0.0, 0.0, 0.0]
%result = "stablehlo.atan2"(%lhs, %rhs) : (tensor<3xf64>, tensor<3xf64>) -> tensor<3xf64>
// %result: [0.0, 1.57079637, -1.57079637] // [0.0, pi/2, -pi/2]
batch_norm_grad
Anlam bilimi
grad_output
'dan geri yayılan batch_norm_training
girişlerinin gradyanlarını hesaplar ve grad_operand
, grad_scale
ve grad_offset
tensörlerini oluşturur. Daha resmi bir ifadeyle bu işlem, Python söz dizimi kullanılarak mevcut StableHLO işlemlerine aşağıdaki şekilde ayrılarak ifade edilebilir:
def compute_sum(operand, feature_index):
(sum,) = reduce(
inputs=[operand],
init_values=[constant(0, element_type(operand))],
dimensions=[i for i in range(rank(operand)) if i != feature_index],
body=lambda x, y: add(x, y))
return sum
def compute_mean(operand, feature_index):
sum = compute_sum(operand, feature_index)
divisor = constant(size(operand) / dim(operand, feature_index),
element_type(operand))
divisor_bcast = broadcast_in_dim(divisor, [], type(sum))
return divide(sum, divisor_bcast)
def batch_norm_grad(operand, scale, mean, variance, grad_output, epsilon, feature_index):
# Broadcast inputs to type(operand)
scale_bcast = broadcast_in_dim(scale, [feature_index], type(operand))
mean_bcast = broadcast_in_dim(mean, [feature_index], type(operand))
variance_bcast = broadcast_in_dim(variance, [feature_index], type(operand))
epsilon_bcast = broadcast_in_dim(constant(epsilon, element_type(operand)), [],
type(operand))
# Perform normalization using the provided `mean` and `variance`
# Intermediate values will be useful for computing gradients
centered_operand = subtract(operand, mean_bcast)
stddev = sqrt(add(variance_bcast, epsilon_bcast))
normalized_operand = divide(centered_operand, stddev)
# Use the implementation from batchnorm_expander.cc in XLA
# Temporary variables have exactly the same names as in the C++ code
elements_per_feature = broadcast_in_dim(
constant(divide(size(operand), dim(operand, feature_index)),
element_type(grad_output)),
[], type(operand))
i1 = multiply(grad_output, elements_per_feature)
i2 = broadcast_in_dim(
compute_sum(grad_output, feature_index), [feature_index], type(operand))
i3 = broadcast_in_dim(
compute_sum(multiply(grad_output, centered_operand), feature_index),
[feature_index], type(operand))
i4 = multiply(i3, centered_operand)
i5 = divide(i4, add(variance_bcast, epsilon_bcast))
i6 = subtract(subtract(i1, i2), i5)
grad_operand =
multiply(divide(divide(scale_bcast, stddev), elements_per_feature), i6)
grad_scale =
compute_sum(multiply(grad_output, normalized_operand), feature_index)
grad_offset = compute_sum(grad_output, feature_index)
return grad_operand, grad_scale, grad_offset
Miktarı ölçülmüş türlerde, dequantize_batch_norm_grad_or_training_quantize(lambda operand, scale, mean,
variance, grad_output: batch_norm_grad(operand, scale, mean, variance,
grad_output, epsilon, feature_index), operand, scale, mean, variance,
grad_output, type(grad_operand), type(grad_scale), type(feature_index))
gerçekleştirir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
Kayan nokta türündeki veya tensör başına kesirli tensör | (C1-C3); (C5) |
(I2) | scale |
Kayan nokta veya tensör başına kesirli cinsinden 1 boyutlu tensör | (C2), (C4), (C5) |
(I3) | mean |
Kayan nokta veya tensör başına kesirli cinsinden 1 boyutlu tensör | (C2), (C4) |
(I4) | variance |
Kayan nokta veya tensör başına miktarlandırılmış türde 1 boyutlu tensör | (C2), (C4) |
(I5) | grad_output |
Kayan nokta türündeki veya tensör başına kesirli tensör | (C2), (C3) |
(I6) | epsilon |
f32 türündeki sabit |
|
(I7) | feature_index |
si64 türündeki sabit |
(C1), (C5) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
grad_operand |
Kayan nokta türündeki veya tensör başına kesirli tensör | (C2), (C3) |
grad_scale |
Kayan nokta veya tensör başına miktarlandırılmış türde 1 boyutlu tensör | (C2), (C4) |
grad_offset |
Kayan nokta veya tensör başına kesirli cinsinden 1 boyutlu tensör | (C2), (C4) |
Sınırlamalar
- (C1)
0 <= feature_index < rank(operand)
. - (C2)
operand
,scale
,mean
,variance
,grad_output
,grad_operand
,grad_scale
vegrad_offset
aynıbaseline_element_type
değerine sahiptir. - (C3)
operand
,grad_output
vegrad_operand
aynı şekle sahiptir. - (C4)
scale
,mean
,variance
,grad_scale
vegrad_offset
aynı şekle sahiptir. - (C5)
size(scale) = dim(operand, feature_index)
Örnekler
// %operand: [
// [[1.0, 2.0], [3.0, 4.0]],
// [[3.0, 4.0], [1.0, 2.0]]
// ]
// %scale: [1.0, 1.0]
// %mean: [2.0, 3.0]
// %variance: [1.0, 1.0]
// %grad_output: [
// [[0.1, 0.1], [0.1, 0.1]],
// [[0.1, 0.1], [0.1, 0.1]]
// ]
%grad_operand, %grad_scale, %grad_offset =
"stablehlo.batch_norm_grad"(%operand, %scale, %mean, %variance, %grad_output) {
epsilon = 0.0 : f32,
feature_index = 2 : i64
} : (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>, tensor<2xf64>,
tensor<2x2x2xf64>) -> (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>)
// %grad_operand: [
// [[0.0, 0.0], [0.0, 0.0]],
// [[0.0, 0.0], [0.0, 0.0]]
// ]
// %grad_scale: [0.0, 0.0]
// %grad_offset: [0.4, 0.4]
batch_norm_inference
Anlam
operand
tensörünü feature_index
boyutu hariç tüm boyutlarda normalize eder ve bir result
tensörü oluşturur. Daha resmi bir ifadeyle bu işlem, Python söz dizimini kullanarak mevcut StableHLO işlemlerinin bir ayrışımı olarak şu şekilde ifade edilebilir:
def batch_norm_inference(operand, scale, offset, mean, variance, epsilon, feature_index):
# Broadcast inputs to shape(operand)
scale_bcast = broadcast_in_dim(scale, [feature_index], type(operand))
offset_bcast = broadcast_in_dim(offset, [feature_index], type(operand))
mean_bcast = broadcast_in_dim(mean, [feature_index], type(operand))
variance_bcast = broadcast_in_dim(variance, [feature_index], type(operand))
epsilon_bcast = broadcast_in_dim(constant(epsilon, element_type(operand)), [],
type(operand))
# Perform normalization using the provided `mean` and `variance` instead of
# computing them like `batch_norm_training` does.
centered_operand = subtract(operand, mean_bcast)
stddev = sqrt(add(variance_bcast, epsilon_bcast))
normalized_operand = divide(centered_operand, stddev)
return add(multiply(scale_bcast, normalized_operand), offset_bcast)
Miktarı belirlenmiş türler için dequantize_op_quantize(lambda operand, scale, offset, mean, variance:
batch_norm_inference(operand, scale, offset, mean, variance, epsilon,
feature_index), operand, scale, offset, mean, variance, type(result))
işlemini gerçekleştirir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
Kayan nokta türündeki veya tensör başına kesirli tensör | (C1-C7) |
(I2) | scale |
Kayan nokta veya tensör başına kesirli cinsinden 1 boyutlu tensör | (C2), (C3) |
(I3) | offset |
Kayan nokta veya tensör başına kesirli cinsinden 1 boyutlu tensör | (C2), (C4) |
(I4) | mean |
Kayan nokta veya tensör başına kesirli cinsinden 1 boyutlu tensör | (C5) |
(I5) | variance |
Kayan nokta veya tensör başına miktarlandırılmış türde 1 boyutlu tensör | (C2), (C6) |
(I6) | epsilon |
f32 türündeki sabit |
|
(I7) | feature_index |
si64 türünün sabiti |
(C1), (C3-C6) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
Kayan nokta türündeki veya tensör başına kesirli tensör | (C2), (C7) |
Sınırlamalar
- (C1)
0 <= feature_index < rank(operand)
. - (C2)
operand
,scale
,offset
,mean
,variance
veresult
aynıbaseline_element_type
değerine sahiptir. - (C3)
size(scale) = dim(operand, feature_index)
. - (C4)
size(offset) = dim(operand, feature_index)
. - (C5)
size(mean) = dim(operand, feature_index)
- (C6)
size(variance) = dim(operand, feature_index)
. - (C7)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// %operand: [
// [[1.0, 2.0], [3.0, 4.0]],
// [[3.0, 4.0], [1.0, 2.0]]
// ]
// %scale: [1.0, 1.0]
// %offset: [1.0, 1.0]
// %mean: [2.0, 3.0]
// %variance: [1.0, 1.0]
%result = "stablehlo.batch_norm_inference"(%operand, %scale, %offset, %mean, %variance) {
epsilon = 0.0 : f32,
feature_index = 2 : i64
} : (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>, tensor<2xf64>, tensor<2xf64>) -> tensor<2x2x2xf64>
// %result: [
// [[0.0, 0.0], [2.0, 2.0]],
// [[2.0, 2.0], [0.0, 0.0]]
// ]
batch_norm_training
Anlam bilimi
feature_index
boyutu hariç tüm boyutlarda ortalama ve varyansı hesaplar ve operand
tenzorunu normalleştirerek output
, batch_mean
ve batch_var
tenzorlarını oluşturur. Daha resmi bir ifadeyle, bu işlem aşağıdaki gibi Python söz dizimi kullanılarak mevcut StableHLO işlemlerine ayrıştırma olarak ifade edilebilir:
def compute_mean(operand, feature_index):
(sum,) = reduce(
inputs=[operand],
init_values=[constant(0, element_type(operand))],
dimensions=[i for i in range(rank(operand)) if i != feature_index],
body=lambda x, y: add(x, y))
divisor = constant(size(operand) / dim(operand, feature_index),
element_type(operand))
divisor_bcast = broadcast_in_dim(divisor, [], type(sum))
return divide(sum, divisor_bcast)
def compute_variance(operand, feature_index):
mean = compute_mean(operand, feature_index)
mean_bcast = broadcast_in_dim(mean, [feature_index], type(operand))
centered_operand = subtract(operand, mean_bcast)
return compute_mean(mul(centered_operand, centered_operand), feature_index)
def batch_norm_training(operand, scale, offset, epsilon, feature_index):
mean = compute_mean(operand, feature_index)
variance = compute_variance(operand, feature_index)
return batch_norm_inference(operand, scale, offset, mean, variance, epsilon,
feature_index),
mean, variance
Miktarı ölçülmüş türlerde, dequantize_batch_norm_grad_or_training_quantize(lambda operand, scale, offset:
batch_norm_training(operand, scale, offset, epsilon, feature_index), operand,
scale, offset, type(output), type(batch_mean), type(batch_var))
gerçekleştirir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
Kayan nokta türündeki veya tensör başına kesirli tensör | (C1) |
(I2) | scale |
Kayan nokta veya tensör başına kesirli 1 boyutlu tensör | (C2), (C3) |
(I3) | offset |
Kayan nokta veya tensör başına miktarlandırılmış 1 boyutlu tensör | (C2), (C4) |
(I4) | epsilon |
f32 türünün sabiti |
(C1), (C3-C6) |
(I5) | feature_index |
si64 türündeki sabit |
(C1), (C3-C6) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
output |
Kayan nokta türündeki veya tensör başına kesirli tensör | (C7) |
batch_mean |
Kayan nokta veya tensör başına kesirli 1 boyutlu tensör | (C2), (C5) |
batch_var |
Kayan nokta veya tensör başına kesirli 1 boyutlu tensör | (C2), (C6) |
Sınırlamalar
- (C1)
0 <= feature_index < rank(operand)
. - (C2)
operand
,scale
,offset
,batch_mean
,batch_var
veoutput
aynıbaseline_element_type
değerine sahiptir. - (C3)
size(scale) = dim(operand, feature_index)
. - (C4)
size(offset) = dim(operand, feature_index)
. - (C5)
size(batch_mean) = dim(operand, feature_index)
- (C6)
size(batch_var) = dim(operand, feature_index)
. - (C7)
baseline_type(output) = baseline_type(operand)
.
Örnekler
// %operand: [
// [[1.0, 2.0], [3.0, 4.0]],
// [[3.0, 4.0], [1.0, 2.0]]
// ]
// %scale: [1.0, 1.0]
// %offset: [1.0, 1.0]
%output, %batch_mean, %batch_var = "stablehlo.batch_norm_training"(%operand, %scale, %offset) {
epsilon = 0.0 : f32,
feature_index = 2 : i64
} : (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>) ->
(tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>)
// %output: [
// [[0.0, 0.0], [2.0, 2.0]],
// [[2.0, 2.0], [0.0, 0.0]]
// ]
// %batch_mean: [2.0, 3.0]
// %batch_var: [1.0, 1.0]
bitcast_convert
Anlam bilimi
operand
tensöründe bir bit yayınlama işlemi gerçekleştirir ve operand
tenörünün tümünün bitlerinin result
tenörünün türü kullanılarak yeniden yorumlandığı bir result
tensörü oluşturur.
Daha resmi bir ifadeyle, E = element_type(operand)
, E' = element_type(result)
ve R = rank(operand)
için:
num_bits(E') < num_bits(E)
isebits(result[i0, ..., iR-1, :]) = bits(operand[i0, ..., iR-1])
.num_bits(E') > num_bits(E)
isebits(result[i0, ..., iR-2]) = bits(operand[i0, ..., iR-2, :])
.num_bits(E') = num_bits(E)
isebits(result[i0, ..., iR-1]) = bits(operand[i0, ..., iR-1])
.
bits
, belirli bir değerin bellekteki temsilini döndürür. Tensörlerin tam temsilinin uygulama tanımlı olması ve öğe türlerinin tam temsilinin de uygulama tanımlı olması nedeniyle bu davranışı uygulama tanımlıdır.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
tenzor veya kesirli tenzor | (C1-C2) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensör veya nicel tensör | (C1-C2) |
Sınırlamalar
- (C1)
E = is_quantized(operand) ? storage_type(operand) : element_type(operand)
,E' = is_quantized(result) ? storage_type(result) : element_type(result)
veR = rank(operand)
çerçevesinde:num_bits(E') = num_bits(E)
iseshape(result) = shape(operand)
.num_bits(E') < num_bits(E)
ise:rank(result) = R + 1
.dim(result, i) = dim(operand, i)
için0 <= i < R
.dim(result, R) * num_bits(E') = num_bits(E)
.num_bits(E') > num_bits(E)
ise:rank(result) = R - 1
.dim(result, i) = dim(operand, i)
için0 <= i < R
.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
operand
tenzorundaki verileri kopyalayarak bir giriş tenzorunun boyutlarını ve/veya rütbesini genişletir ve bir result
tenzoru oluşturur. Daha resmi bir ifadeyle, axes(operand)
içindeki tüm d
için result[result_index] = operand[operand_index]
:
dim(operand, d) = 1
iseoperand_index[d] = 0
.- Aksi takdirde
operand_index[d] = result_index[broadcast_dimensions[d]]
değerini alır.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
tenzor veya kesirli tenzor | (C1-C2), (C5-C6) |
(I2) | broadcast_dimensions |
si64 türünde 1 boyutlu tensör sabiti |
(C2-C6) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensör veya nicel tensör | (C1), (C3), (C5-C6) |
Sınırlamalar
- (C1)
element_type(result)
şu şekilde hesaplanır:!is_per_axis_quantized(operand)
iseelement_type(operand)
.element_type(operand)
, ancakquantization_dimension(operand)
,scales(operand)
vezero_points(operand)
sırasıylaquantization_dimension(result)
,scales(result)
vezero_points(result)
'den farklı olabilir.
- (C2)
size(broadcast_dimensions) = rank(operand)
. - (C3)
0 <= broadcast_dimensions < rank(result)
. - (C4)
is_unique(broadcast_dimensions)
. - (C5)
axes(operand)
içindeki tümd
için:dim(operand, d) = 1
veyadim(operand, d) = dim(result, broadcast_dimensions[d])
.
- (C6)
is_per_axis_quantized(result)
ise:quantization_dimension(result) = broadcast_dimensions[quantization_dimension(operand)]
.dim(operand, quantization_dimension(operand)) = 1
isescales(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
index
değerine bağlı olarak branches
içinden tam olarak bir işlevin yürütülmesiyle elde edilen çıktıyı oluşturur. Daha resmi bir ifadeyle, result = selected_branch()
burada:
0 <= index < size(branches)
iseselected_branch = branches[index]
.- Aksi takdirde
selected_branch = branches[-1]
değerini alır.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | index |
si32 türündeki 0 boyutlu tensör |
|
(I2) | branches |
değişken sayıda işlev | (C1-C4) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
results |
değişken tensör, nicel tensör veya jeton sayısı | (C4) |
Sınırlamalar
- (C1)
0 < size(branches)
. - (C2)
input_types(branches...) = []
. - (C3)
same(output_types(branches...))
. - (C4)
type(results...) = output_types(branches[0])
.
Örnekler
// %index: -1
// %result_branch0: [0, 0]
// %result_branch1: [1, 1]
%result0, %result1 = "stablehlo.case"(%index) ({
"stablehlo.return"(%result_branch0, %result_branch0) : (tensor<2xi64>, tensor<2xi64>) -> ()
}, {
"stablehlo.return"(%result_branch1, %result_branch1) : (tensor<2xi64>, tensor<2xi64>) -> ()
}) : (tensor<i32>) -> (tensor<2xi64>, tensor<2xi64>)
// %result0: [1, 1]
// %result1: [1, 1]
cbrt
Anlam bilimi
operand
tensörü üzerinde öğe tabanlı kübik kök işlemi gerçekleştirir ve result
tensörü üretir. Öğe türüne bağlı olarak aşağıdakileri yapar:
- Kayan noktalı sayılar için: IEEE-754'ten
rootn(x, 3)
. - Karmaşık sayılar için: karmaşık küp kökü.
- Kesirli türler için:
dequantize_op_quantize(cbrt, operand, type(result))
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Sınırlamalar
- (C1)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// %operand: [0.0, 1.0, 8.0, 27.0]
%result = "stablehlo.cbrt"(%operand) : (tensor<4xf64>) -> tensor<4xf64>
// %result: [0.0, 1.0, 2.0, 3.0]
ceil
Anlam bilimi
operand
tenzorunun öğe bazında üst sınırını gerçekleştirir ve bir result
tenzoru oluşturur.
IEEE-754 spesifikasyonundaki roundToIntegralTowardPositive
işlemini uygular. Miktarı belirlenmiş türler için dequantize_op_quantize(ceil, operand, type(result))
işlemini gerçekleştirir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
Kayan nokta türündeki veya tensör başına kesirli tensör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta türünde veya tensör başına miktarlandırılmış tensörün tensörü | (C1) |
Sınırlamalar
- (C1)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// %operand: [-0.8166, -0.2530, 0.2530, 0.8166, 2.0]
%result = "stablehlo.ceil"(%operand) : (tensor<5xf32>) -> tensor<5xf32>
// %result: [-0.0, -0.0, 1.0, 1.0, 2.0]
cholesky
Anlam
Bir dizi matrisin Cholesky ayrışmasını hesaplar.
Daha resmi bir ifadeyle, index_space(result)
içindeki tüm i
için result[i0, ..., iR-3, :, :]
, a[i0, ..., iR-3, :, :]
'ın alt üçgen (lower
true
ise) veya üst üçgen (lower
false
ise) matris biçiminde Cholesky ayrışımıdır.
Karşıt üçgendeki çıkış değerleri (ör. katı üst üçgen veya buna karşılık gelen katı alt üçgen) uygulama tanımlıdır.
Girdi matrisinin Hermitian pozitif tanımlı bir matrisi olmadığı i
varsa davranış tanımsızdır.
Miktarı ölçülmüş türlerde, dequantize_op_quantize(lambda operand: cholesky(operand, lower), a, type(result))
gerçekleştirir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | a |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1-C3) |
(I2) | lower |
i1 türündeki 0 boyutlu tensör sabit |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Sınırlamalar
- (C1)
baseline_type(a) = baseline_type(result)
. - (C2)
2 <= rank(a)
. - (C3)
dim(a, -2) = dim(a, -1)
.
Örnekler
// %a: [
// [1.0, 2.0, 3.0],
// [2.0, 20.0, 26.0],
// [3.0, 26.0, 70.0]
// ]
%result = "stablehlo.cholesky"(%a) {
lower = true
} : (tensor<3x3xf32>) -> tensor<3x3xf64>
// %result: [
// [1.0, 0.0, 0.0],
// [2.0, 4.0, 0.0],
// [3.0, 5.0, 6.0]
// ]
kelepçe
Anlam bilimi
operand
tenzorunun her bir öğesini minimum ve maksimum değer arasında sıkıştırır ve bir result
tenzoru oluşturur. Daha resmi bir ifadeyle, result[result_index] =
minimum(maximum(operand[result_index], min_element), max_element)
,
burada min_element = rank(min) = 0 ? min[] : min[result_index]
,
max_element = rank(max) = 0 ? max[] : max[result_index]
. Nicel türlerde dequantize_op_quantize(clamp, min, operand, max, type(result))
olarak performans gösterir.
Karmaşık sayılara sıralama uygulamak şaşırtıcı anlamlar içerir. Bu nedenle, gelecekte bu işlem için karmaşık sayılar desteğini kaldırmayı planlıyoruz (#560).
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | min |
tensör veya tensör başına miktarlandırılmış tensör | (C1), (C3) |
(I2) | operand |
tensor veya tensor başına kesikli tensor | (C1-C4) |
(I3) | max |
tensor veya tensor başına kesikli tensor | (C2), (C3) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensör veya tensör başına miktarlandırılmış tensör | (C4) |
Sınırlamalar
- (C1)
rank(min) = 0 or shape(min) = shape(operand)
. - (C2)
rank(max) = 0 or shape(max) = shape(operand)
. - (C3)
baseline_element_type(min) = baseline_element_type(operand) = baseline_element_type(max)
. - (C4)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// %min: [5, 10, 15]
// %operand: [3, 13, 23]
// %max: [10, 15, 20]
%result = "stablehlo.clamp"(%min, %operand, %max) : (tensor<3xi32>, tensor<3xi32>, tensor<3xi32>) -> tensor<3xi32>
// %result: [5, 13, 20]
collective_broadcast
Anlam bilimi
StableHLO işlem ızgarasındaki her işlem grubunda, operand
tenzorunun değerini kaynak işlemden hedef işlemlere gönderin ve bir result
tenzoru oluşturun.
İşlem, StableHLO işlem ızgarasını aşağıdaki gibi tanımlanan process_groups
olarak böler:
channel_id <= 0
isecross_replica(replica_groups)
.channel_id > 0
isecross_partition(replica_groups)
.
Ardından result@process
şu şekilde hesaplanır:
operand@process_groups[i, 0]
, işlemprocess_groups[i]
içinde olduğundai
varsa.broadcast_in_dim(constant(is_quantized(result) ? quantize(0, element_type(result)) : 0, element_type(result)), [], type(result))
aksi takdirde.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
tensör veya tensör başına miktarlandırılmış tensör | (C3) |
(I2) | replica_groups |
si64 türündeki 1 boyutlu tensör sabitlerinin değişken sayısı |
(C1), (C2) |
(I3) | channel_id |
si64 türündeki sabit |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensör veya tensör başına miktarlandırılmış tensör | (C3) |
Sınırlamalar
- (C1)
is_unique(replica_groups)
. - (C2)
0 <= replica_groups < N
; buradaN
şu şekilde tanımlanır:cross_replica
kullanılıyorsanum_replicas
.cross_partition
kullanı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, operand
tensörü değeri kaynak işlemden hedef işleme gönderilir ve bir result
tensörü üretir.
İşlem, StableHLO işlem ızgarasını aşağıdaki gibi tanımlanan process_groups
olarak böler:
channel_id <= 0
isecross_replica(source_target_pairs)
.channel_id > 0
isecross_partition(source_target_pairs)
.
Ardından result@process
şu şekilde hesaplanır:
operand@process_groups[i, 0]
(process_groups[i, 1] = process
gibi biri
varsa).broadcast_in_dim(constant(is_quantized(result) ? quantize(0, element_type(result)) : 0, element_type(result)), [], type(result))
aksi takdirde.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
tensor veya tensor başına kesikli tensor | (C5) |
(I2) | source_target_pairs |
si64 türünde 2 boyutlu tensör sabiti |
(C1-C4) |
(I3) | channel_id |
si64 türündeki sabit |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensör veya tensör başına miktarlandırılmış tensör | (C1) |
Sınırlamalar
- (C1)
dim(source_target_pairs, 1) = 2
. - (C2)
is_unique(source_target_pairs[:, 0])
. - (C3)
is_unique(source_target_pairs[:, 1])
. - (C4)
0 <= source_target_pairs < N
. BuradaN
şu şekilde tanımlanır:cross_replica
kullanılıyorsanum_replicas
.cross_partition
kullanı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
tenörlerinin comparison_direction
ve compare_type
'e göre öğe bazında karşılaştırmasını yapar ve bir result
tenörü oluşturur.
comparison_direction
ve compare_type
değerleri şu anlamlara sahiptir:
Boole ve tam sayı öğe türleri için:
EQ
:lhs = rhs
.NE
:lhs != rhs
.GE
:lhs >= rhs
.GT
:lhs > rhs
.LE
:lhs <= rhs
.LT
:lhs < rhs
.
compare_type = FLOAT
içeren kayan nokta öğe türleri için op, aşağıdaki IEEE-754 işlemlerini uygular:
EQ
:compareQuietEqual
.NE
:compareQuietNotEqual
.GE
:compareQuietGreaterEqual
.GT
:compareQuietGreater
.LE
:compareQuietLessEqual
.LT
:compareQuietLess
.
compare_type = TOTALORDER
içeren kayan noktalı öğe türleri için op, IEEE-754'teki totalOrder
ve compareQuietEqual
işlemlerinin bir kombinasyonunu kullanır.
Karmaşık öğe türleri için, sağlanan comparison_direction
ve compare_type
kullanılarak (real, imag)
çiftlerinin alfabetik karşılaştırması yapılır.
Karmaşık sayılara sıralama uygulamak şaşırtıcı anlamlar içerir. Bu nedenle, gelecekte comparison_direction
GE
, GT
, LE
veya LT
olduğunda karmaşık sayı desteğini kaldırmayı planlıyoruz (#560).
Kesirli türler için dequantize_compare(lhs, rhs,
comparison_direction)
işlemini gerçekleştirir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | lhs |
tensor veya tensor başına kesikli tensor | (C1-C3) |
(I2) | rhs |
tensor veya tensor başına kesikli tensor | (C1-C2) |
(I3) | comparison_direction |
EQ , NE , GE , GT , LE ve LT değerlerini içeren bir enum |
|
(I4) | compare_type |
FLOAT , TOTALORDER , SIGNED ve UNSIGNED değerlerini içeren bir enum |
(C3) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
boole türündeki tensör | (C2) |
Sınırlamalar
- (C1)
baseline_element_type(lhs) = baseline_element_type(rhs)
. - (C2)
shape(lhs) = shape(rhs) = shape(result)
. - (C3)
compare_type
şu şekilde tanımlanır:is_signed_integer(element_type(lhs))
iseSIGNED
.is_unsigned_integer(element_type(lhs)) or is_boolean(element_type(lhs))
iseUNSIGNED
.is_float(element_type(lhs))
iseFLOAT
veyaTOTALORDER
.is_complex(element_type(lhs))
iseFLOAT
.
Ö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
Gerçek ve sanal değerlerden (lhs
ve rhs
) oluşan iki değerden karmaşık bir değere öğe düzeyinde dönüştürme gerçekleştirir ve bir result
tensörü üretir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | lhs |
f32 veya f64 türündeki tensör |
(C1-C3) |
(I2) | rhs |
f32 veya f64 türündeki tensör |
(C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
karmaşık türde tensör | (C2), (C3) |
Sınırlamalar
- (C1)
type(lhs) = type(rhs)
. - (C2)
shape(result) = shape(lhs)
. - (C3)
element_type(result)
,E = element_type(lhs)
olduğundacomplex<E>
türünde.
Örnekler
// %lhs: [1.0, 3.0]
// %rhs: [2.0, 4.0]
%result = "stablehlo.complex"(%lhs, %rhs) : (tensor<2xf64>, tensor<2xf64>) -> tensor<2xcomplex<f64>>
// %result: [(1.0, 2.0), (3.0, 4.0)]
birleşik
Anlam bilimi
inputs
ve composite_attributes
'yi alıp results
üreterek diğer StableHLO işlemlerinden oluşan bir işlemi kapsar. Op'nin semantikleri decomposition
özelliği tarafından uygulanır. composite
işlemi, program semantiklerini değiştirmeden ayrıştırmasıyla değiştirilebilir. Ayrıştırmanın satır içi olarak yerleştirilmesinin aynı işlem semantiğini sağlamadığı durumlarda custom_call
kullanmayı tercih edin.
version
alanı (varsayılan olarak 0
değerine ayarlanır), bileşenin anlamının ne zaman değiştiğini belirtmek için kullanılır.
Girişler
Şirket | Ad | Tür |
---|---|---|
(I1) | inputs |
değişken değer sayısı |
(I2) | name |
string türündeki sabit |
(I3) | composite_attributes |
özellik sözlüğü |
(I4) | decomposition |
string türündeki sabit |
(I5) | version |
si32 türünün sabiti |
Çıkışlar
Ad | Tür |
---|---|
results |
değişken değer sayısı |
Sınırlamalar
- (C1)
is_namespaced_op_name(name)
- (C2)
is_defined_in_parent_scope(decomposition)
- (C3)
types(inputs...) == input_types(decomposition)
- (C4)
types(results...) == output_types(decomposition)
Örnekler
%results = "stablehlo.composite"(%input0, %input1) {
name = "my_namespace.my_op",
composite_attributes = {
my_attribute = "my_value"
},
decomposition = @my_op,
version = 1 : i32
} : (tensor<f32>, tensor<f32>) -> tensor<f32>
birleştirmek
Anlam
inputs
öğesini, belirtilen bağımsız değişkenlerle aynı sırada dimension
boyutu boyunca birleştirir ve bir result
tensörü oluşturur. Daha resmi bir ifadeyle,
result[i0, ..., id, ..., iR-1] = inputs[k][i0, ..., kd, ..., iR-1]
, burada:
id = d0 + ... + dk-1 + kd
.d
,dimension
değerine eşit ved0
, ...inputs
öğesinind
. boyut boyutlarıdır.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | inputs |
değişken sayıda tensör veya tensör başına miktarlandırılmış tensör | (C1-C6) |
(I2) | dimension |
si64 türündeki sabit |
(C2), (C4), (C6) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensör veya tensör başına miktarlandırılmış tensör | (C5-C6) |
Sınırlamalar
- (C1)
same(element_type(inputs...))
. - (C2)
dim(inputs..., dimension)
hariçsame(shape(inputs...))
. - (C3)
0 < size(inputs)
. - (C4)
0 <= dimension < rank(inputs[0])
. - (C5)
element_type(result) = element_type(inputs[0])
. - (C6) Aşağıdakiler hariç
shape(result) = shape(inputs[0])
:dim(result, dimension) = dim(inputs[0], dimension) + ...
.
Örnekler
// %input0: [[1, 2], [3, 4], [5, 6]]
// %input1: [[7, 8]]
%result = "stablehlo.concatenate"(%input0, %input1) {
dimension = 0 : i64
} : (tensor<3x2xi64>, tensor<1x2xi64>) -> tensor<4x2xi64>
// %result: [[1, 2], [3, 4], [5, 6], [7, 8]]
sabit
Anlam
Sabit bir value
değerinden output
tensörü oluşturur.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | value |
sabit | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
output |
tenzor veya kesirli tenzor | (C1) |
Sınırlamalar
- (C1)
type(value) = type(output)
.
Örnekler
%output = "stablehlo.constant"() {
value = dense<[[0.0, 1.0], [2.0, 3.0]]> : tensor<2x2xf32>
} : () -> tensor<2x2xf32>
// %output: [[0.0, 1.0], [2.0, 3.0]]
Dönüşüm gerçekleştirme
Anlam
operand
tenzorunda bir öğe türünden diğerine öğe bazında dönüşüm gerçekleştirir ve bir result
tenzoru oluşturur.
boolean-to-any-supported-type dönüşümleri için false
değeri sıfıra ve true
değeri bire dönüştürülür. any-supported-type-to-boolean dönüşümleri için sıfır değeri false
değerine, sıfır olmayan değerler ise true
değerine dönüştürülür. Bunun karmaşık türler için nasıl çalıştığını aşağıda görebilirsiniz.
Tam sayı ile tam sayı, tam sayı ile kayan nokta veya kayan nokta ile kayan nokta dönüşümleri söz konusu olduğunda, kaynak değer hedef türünde tam olarak temsil edilebiliyorsa sonuç değeri bu tam temsildir. Aksi takdirde davranış henüz belirlenmemiştir (#180).
floating-point-to-integer dönüşümleri içeren dönüşümlerde kesirli kısım kısaltılır. Kısaltılmış değer hedef türünde temsil edilemiyorsa davranış TBD olur (#180).
Karmaşıktan karmaşığa dönüşüm, gerçek ve sanal kısımları dönüştürmek için kayan noktadan kayan noktaya dönüşümlerin aynı davranışını izler.
Karmaşıktan başka bir türe ve başka bir türden karmaşığa dönüşümlerde sırasıyla kaynak karmaşık değer yok sayılır veya hedef karmaşık değer sıfırlanır. Gerçek kısmın dönüştürülmesi, kayan nokta dönüşümlerini izler.
Bu işlem, prensipte kesirli sayılaştırmayı (kesirli sayılaştırılmış tenzorlardan normal tenzorlara dönüşüm), kesirli sayılaştırmayı (normal tenzorlardan kesirli sayılaştırılmış tenzorlara dönüşüm) ve yeniden kesirli sayılaştırmayı (kesirli sayılaştırılmış tenzorlar arasında dönüşüm) ifade edebilir ancak şu anda bunun için özel işlemlerimiz var: ilk kullanım alanı için uniform_dequantize
ve ikinci ve üçüncü kullanım alanları için uniform_quantize
. Gelecekte bu iki işlem convert
ile birleştirilebilir (#1576).
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
Tensor | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
Tensor | (C1) |
Sınırlamalar
- (C1)
shape(operand) = shape(result)
.
Örnekler
// %operand: [-1, 0, 1]
%result = "stablehlo.convert"(%operand) : (tensor<3xi64>) -> tensor<3xcomplex<f64>>
// %result: [(-1.0, 0.0), (0.0, 0.0), (1.0, 0.0)]
konvolüsyon
Anlam bilimi
lhs
pencereleri ile rhs
dilimleri arasındaki iç çarpımları hesaplar ve result
değerini döndürür. Aşağıdaki şemada, result
öğelerinin lhs
ve rhs
'den nasıl hesaplandığı somut bir örnekle gösterilmektedir.
Daha resmi bir ifadeyle, lhs
pencerelerini ifade edebilmek için girişlerin lhs
açısından aşağıdaki şekilde yeniden çerçevelendiğini düşünün:
lhs_window_dimensions = lhs_shape(dim(lhs, input_batch_dimension), dim(rhs, kernel_spatial_dimensions), dim(lhs, input_feature_dimension))
.lhs_window_strides = lhs_shape(1, window_strides, 1)
.lhs_padding = lhs_shape([0, 0], padding, [0, 0])
.lhs_base_dilations = lhs_shape(1, lhs_dilation, 1)
.lhs_window_dilations = lhs_shape(1, rhs_dilation, 1)
.
Bu yeniden çerçeveleme işleminde aşağıdaki yardımcı işlevler kullanılır:
lhs_shape(n, hw, c) = permute([n] + hw + [c], [input_batch_dimension] + input_spatial_dimensions + [input_feature_dimension])
.result_shape(n1, hw, c1) = permute([n1] + hw + [c1], [output_batch_dimension] + output_spatial_dimensions + [output_feature_dimension])
.permute([j0, j1, ..., jR-1], permutation) = [i0, i1, ..., iR-1]
buradaj[d] = i[permutation[d]]
.
feature_group_count = 1
ve batch_group_count = 1
ise index_space(dim(result, output_spatial_dimensions...))
içindeki tüm output_spatial_index
için result[result_shape(:, output_spatial_index, :)] = dot_product
:
padding_value = constant(0, element_type(lhs))
.padded_lhs = pad(lhs, padding_value, lhs_padding[:, 0], lhs_padding[:, 1], lhs_base_dilations - 1)
.lhs_window_start = lhs_shape(0, output_spatial_index, 0) * lhs_window_strides
.lhs_window = slice(padded_lhs, lhs_window_start, lhs_window_start + lhs_window_dimensions, lhs_window_dilations)
.reversed_lhs_window = reverse(lhs_window, [input_spatial_dimensions[dim] for dim in range(size(window_reversal)) if window_reversal[dim] = true])
. Bu özelliğin kullanılmadığı anlaşılıyor. Bu nedenle, ileride bu özelliği kaldırmayı planlıyoruz (#1181).dot_product = dot_general(reversed_lhs_window, rhs, lhs_batching_dimensions=[], lhs_contracting_dimensions=input_spatial_dimensions + [input_feature_dimension], rhs_batching_dimensions=[], rhs_contracting_dimensions=kernel_spatial_dimensions + [kernel_input_feature_dimension])
.
feature_group_count > 1
ise:
lhses = split(lhs, feature_group_count, input_feature_dimension)
.rhses = split(rhs, feature_group_count, kernel_output_feature_dimension)
.results... = convolution(lhses..., rhses..., ..., feature_group_count=1, ...)
.result = concatenate(results, output_feature_dimension)
.
batch_group_count > 1
ise:
lhses = split(lhs, batch_group_count, input_batch_dimension)
.rhses = split(rhs, batch_group_count, kernel_output_feature_dimension)
.results... = convolution(lhses..., rhses..., ..., batch_group_count=1, ...)
.result = concatenate(results, output_feature_dimension)
.
Miktarı belirlenmiş türler için dequantize_op_quantize(
lambda lhs, rhs: convolution(lhs, rhs, window_strides, padding,
lhs_dilation, rhs_dilation, window_reversal, input_batch_dimension,
input_feature_dimension, input_spatial_dimensions,
kernel_input_feature_dimension, kernel_output_feature_dimension,
kernel_spatial_dimensions, output_batch_dimension,
output_feature_dimension, output_spatial_dimensions,
feature_group_count, batch_group_count, precision_config), lhs, rhs,
type(result))
işlemini gerçekleştirir.
Karma kesirli türler için hybrid_dequantize_then_op(
lambda lhs, rhs: convolution(lhs, rhs, window_strides, padding,
lhs_dilation, rhs_dilation, window_reversal, input_batch_dimension,
input_feature_dimension, input_spatial_dimensions,
kernel_input_feature_dimension, kernel_output_feature_dimension,
kernel_spatial_dimensions, output_batch_dimension,
output_feature_dimension, output_spatial_dimensions,
feature_group_count, batch_group_count, precision_config), lhs, rhs)
işlemini gerçekleştirir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | lhs |
tensor veya tensor başına kesikli tensor | (C1), (C10-C11), (C14) (C25), (C27-C28), (C31-C32), (C34) |
(I2) | rhs |
tenzor veya kesirli tenzor | (C1), (C14-C16), (C25), (C27-C29), (C31-C34) |
(I3) | window_strides |
si64 türündeki 1 boyutlu tensör sabiti |
(C2-C3), (C25) |
(I4) | padding |
si64 türündeki 2 boyutlu tensör sabit |
(C4), (C25) |
(I5) | lhs_dilation |
si64 türündeki 1 boyutlu tensör sabiti |
(C5-C6), (C25) |
(I6) | rhs_dilation |
si64 türündeki 1 boyutlu tensör sabiti |
(C7-C8), (C25) |
(I7) | window_reversal |
i1 türünde 1 boyutlu tensör sabiti |
(C9) |
(I8) | input_batch_dimension |
si64 türündeki sabit |
(C10), (C13), (C25) |
(I9) | input_feature_dimension |
si64 türündeki sabit |
(C11), (C13-C14) |
(I10) | input_spatial_dimensions |
si64 türündeki 1 boyutlu tensör sabiti |
(C12), (C13), (C25) |
(I11) | kernel_input_feature_dimension |
si64 türündeki sabit |
(C14), (C18) |
(I12) | kernel_output_feature_dimension |
si64 türündeki sabit |
(C15-C16), (C18), (C25), (C29) |
(I13) | kernel_spatial_dimensions |
si64 türündeki 1 boyutlu tensör sabiti |
(C17-C18), (C25) |
(I14) | output_batch_dimension |
si64 türündeki sabit |
(C20), (C25) |
(I15) | output_feature_dimension |
si64 türündeki sabit |
(C20), (C25), (C30) |
(I16) | output_spatial_dimensions |
si64 türündeki 1 boyutlu tensör sabiti |
(C19-C20), (C25) |
(I17) | feature_group_count |
si64 türündeki sabit |
(C11), (C14), (C16), (C21), (C23) |
(I18) | batch_group_count |
si64 türündeki sabit |
(C10), (C15), (C22), (C23), (C25) |
(I19) | precision_config |
DEFAULT , HIGH ve HIGHEST türetilmiş türleri için değişken sayıda enum |
(C24) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tenzor veya kesirli tenzor | (C25-C28), (C30), (C32-34) |
Sınırlamalar
- (C1)
N = rank(lhs) = rank(rhs)
. - (C2)
size(window_strides) = N - 2
. - (C3)
0 < window_strides
. - (C4)
shape(padding) = [N - 2, 2]
. - (C5)
size(lhs_dilation) = N - 2
. - (C6)
0 < lhs_dilation
. - (C7)
size(rhs_dilation) = N - 2
. - (C8)
0 < rhs_dilation
- (C9)
size(window_reversal) = N - 2
. - (C10)
dim(lhs, input_batch_dimension) % batch_group_count = 0
. - (C11)
dim(lhs, input_feature_dimension) % feature_group_count = 0
- (C12)
size(input_spatial_dimensions) = N - 2
- (C13)
input_dimensions = [input_batch_dimension] + input_spatial_dimensions + [input_feature_dimension]
ile ilgili:is_unique(input_dimensions)
.0 <= input_dimensions < N
.
- (C14)
dim(rhs, kernel_input_feature_dimension) = dim(lhs, input_feature_dimension) / feature_group_count
- (C15)
dim(rhs, kernel_output_feature_dimension) % batch_group_count = 0
. - (C16)
dim(rhs, kernel_output_feature_dimension) % feature_group_count = 0
- (C17)
size(kernel_spatial_dimensions) = N - 2
. - (C18)
kernel_dimensions = kernel_spatial_dimensions + [kernel_input_feature_dimension] + [kernel_output_feature_dimension]
ile ilgili:is_unique(kernel_dimensions)
.0 <= kernel_dimensions < N
.
- (C19)
size(output_spatial_dimensions) = N - 2
- (C20)
output_dimensions = [output_batch_dimension] + output_spatial_dimensions + [output_feature_dimension]
verildiğinde:is_unique(output_dimensions)
.0 <= output_dimensions < N
.
- (C21)
0 < feature_group_count
. - (C22)
0 < batch_group_count
. - (C23)
feature_group_count = 1 or batch_group_count = 1
. - (C24)
size(precision_config) = 2
- (C25)
dim(result, result_dim)
şu şekilde tanımlanır:result_dim = output_batch_dimension
isedim(lhs, input_batch_dimension) / batch_group_count
.result_dim = output_feature_dimension
isedim(rhs, kernel_output_feature_dimension)
.num_windows
aksi takdirde:output_spatial_dimensions[spatial_dim] = result_dim
.lhs_dim = input_spatial_dimensions[spatial_dim]
.rhs_dim = kernel_spatial_dimensions[spatial_dim]
.dilated_input_shape[lhs_dim] = dim(lhs, lhs_dim) = 0 ? 0 : (dim(lhs, lhs_dim) - 1) * lhs_dilation[spatial_dim] + 1
.padded_input_shape[lhs_dim] = padding[spatial_dim, 0] + dilated_input_shape[lhs_dim] + padding[spatial_dim, 1]
.dilated_window_shape[lhs_dim] = dim(rhs, rhs_dim) = 0 ? 0 : (dim(rhs, rhs_dim) - 1) * rhs_dilation[spatial_dim] + 1
.is_empty_window[lhs_dim] = padded_input_shape[lhs_dim] = 0 || dilated_window_shape[lhs_dim] > padded_input_shape[lhs_dim]
.num_windows = is_empty_window[lhs_dim] ? 0 : floor((padded_input_shape[lhs_dim] - dilated_window_shape[lhs_dim]) / window_strides[spatial_dim]) + 1
.
- (C26)
rank(result) = N
. - İşlemde miktarlandırılmamış tensörler kullanılıyorsa:
- (C27)
element_type(lhs) = element_type(rhs) = element_type(result)
.
- (C27)
- İşlemde kesirli tenzorlar 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)
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ü üzerinde element düzeyinde kosinüs işlemi gerçekleştirir ve result
tensörü üretir. Öğe türüne bağlı olarak aşağıdakiler gerçekleşir:
- Kayan noktalı sayılar için: IEEE-754'ten
cos
. - Karmaşık sayılar için: karmaşık kosinüs.
- Kesirli türler için:
dequantize_op_quantize(cosine, operand, type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Sınırlamalar
- (C1)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// %operand: [
// [0.0, 1.57079632], // [0, pi/2]
// [3.14159265, 4.71238898] // [pi, 3pi/2]
// ]
%result = "stablehlo.cosine"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[1.0, 0.0], [-1.0, 0.0]]
count_leading_zeros
Anlam bilimi
operand
tenzorundaki baştaki sıfır bitlerinin sayısını öğe bazında sayar ve bir result
tenzoru oluşturur.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
tam sayı türündeki tensör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tam sayı türündeki tensör | (C1) |
Sınırlamalar
- (C1)
type(operand) = type(result)
.
Örnekler
// %operand: [[0, 1], [128, -1]]
%result = "stablehlo.count_leading_zeros"(%operand) : (tensor<2x2xi64>) -> tensor<2x2xi64>
// %result: [[64, 63], [56, 0]]
custom_call
Anlam bilimi
inputs
ve called_computations
değerini alıp results
değerini döndüren uygulama tanımlı bir işlem call_target_name
'ü kapsar. has_side_effect
, backend_config
ve api_version
, uygulama tanımlı ek meta veriler sağlamak için kullanılabilir.
Şu anda bu işlem, XLA derleyicideki eşdeğer işleminin organik gelişimini yansıtan, oldukça düzensiz bir meta veri koleksiyonu içeriyor. Gelecekte bu meta verileri birleştirmeyi planlıyoruz (#741).
Girişler
Şirket | Ad | Tür |
---|---|---|
(I1) | inputs |
değişken değer sayısı |
(I2) | call_target_name |
string türündeki sabit |
(I3) | has_side_effect |
i1 türündeki sabit |
(I4) | backend_config |
string türündeki sabit veya özellik sözlüğü |
(I5) | api_version |
si32 türündeki sabit |
(I6) | called_computations |
string türündeki değişken sayıda sabit |
Çıkışlar
Ad | Tür |
---|---|
results |
değişken değer sayısı |
Örnekler
%results = "stablehlo.custom_call"(%input0) {
call_target_name = "foo",
has_side_effect = false,
backend_config = {bar = 42 : i32},
api_version = 4 : i32,
called_computations = [@foo]
} : (tensor<f64>) -> tensor<f64>
bölü
Anlam bilimi
Pay lhs
ve bölen rhs
tenörlerinin öğe bazında bölünmesini gerçekleştirir ve bir result
tenörü oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:
- Tam sayılar için: kesirli parçalar çıkarılarak cebirsel bölümü oluşturan tam sayı bölme.
- Kayan noktalı sayılar için: IEEE-754'ten
division
. - Karmaşık sayılar için: karmaşık bölme.
- Kesirli türler için:
dequantize_op_quantize(divide, lhs, rhs, type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | lhs |
tam sayı, kayan nokta veya karmaşık tür ya da tensör başına miktarlandırılmış tensör tensörü | (C1) |
(I2) | rhs |
tam sayı, kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
Tam sayı, kayan nokta veya karmaşık türde bir tensör ya da tensör başına kesirli tensör | (C1) |
Sınırlamalar
- (C1)
baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)
.
Örnekler
// %lhs: [17.1, -17.1, 17.1, -17.1]
// %rhs: [3.0, 3.0, -3.0, -3.0]
%result = "stablehlo.divide"(%lhs, %rhs) : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
// %result: [5.66666651, -5.66666651, -5.66666651, 5.66666651]
dot_general
Anlam bilimi
lhs
dilimlerinin rhs
dilimleriyle iç çarpımlarını hesaplar ve bir result
tensörü oluşturur.
Daha resmi olarak, result[result_index] = dot_product
, burada:
lhs_result_dimensions = [d for d in axes(lhs) and d not in lhs_batching_dimensions and d not in lhs_contracting_dimensions]
.rhs_result_dimensions = [d for d in axes(rhs) and d not in rhs_batching_dimensions and d not in rhs_contracting_dimensions]
.result_batching_index + result_lhs_index + result_rhs_index = result_index
Buradasize(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))
.
Miktarı belirlenmiş türler için dequantize_op_quantize(
lambda lhs, rhs: dot_general(lhs, rhs, lhs_batching_dimensions,
rhs_batching_dimensions, lhs_contracting_dimensions,
rhs_contracting_dimensions, precision_config), lhs, rhs, type(result))
işlemini gerçekleştirir.
Karma kesirli türler için hybrid_dequantize_then_op(
lambda lhs, rhs: dot_general(lhs, rhs, lhs_batching_dimensions,
rhs_batching_dimensions, lhs_contracting_dimensions,
rhs_contracting_dimensions, precision_config), lhs, rhs)
işlemini gerçekleştirir.
precision_config
, hızlandırıcı arka uçlarındaki hesaplamalar için hız ile doğruluk arasındaki dengeyi kontrol eder. Bu, aşağıdakilerden biri olabilir (şu anda bu enum değerlerinin semantikleri yeterince belirtilmemiştir ancak bu sorunu #755 ile çözmeyi planlıyoruz):
DEFAULT
: En hızlı hesaplamadır, ancak orijinal sayıya en az doğru tahmindir.HIGH
: Daha yavaş hesaplama, ancak orijinal sayıya daha yakın bir yaklaşım.HIGHEST
: En yavaş hesaplama yöntemidir ancak orijinal sayıya en yakın yaklaşık değerdir.
DotAlgorithm
, nokta işlemini uygulamak için kullanılan ve hassasiyeti de tanımlayan algoritmanın ana özelliklerini tanımlar. Algoritma özellik alanları ayarlanmışsa precision_config
, DEFAULT
olmalıdır. DotAlgorithms
öğesinin varsayılan bir değeri yoktur. Çünkü varsayılan parametreler uygulama tarafından tanımlanmıştır. Dolayısıyla tüm nokta algoritması alanları, boş bir nokta algoritması belirtmek için None
olarak ayarlanabilir. Bu algoritma, bunun yerine precision_config
değerini kullanır.
DotAlgorithm
alanları şunları içerir:
lhs_precision_type
verhs_precision_type
, işlemin sol ve sağ tarafının yuvarlandığı hassasiyettir. Hassasiyet türleri, giriş ve çıkışın depolama türlerinden bağımsızdır.accumulation_type
Toplama için kullanılan hassasiyet.lhs_component_count
,rhs_component_count
venum_primitive_operations
, sol taraf ve/veya sağ tarafı birden fazla bileşene ayıran ve bu değerler üzerinde birden fazla "ilkel" nokta işlemi yapan bir algoritma uygularken geçerlidir. Bu işlemler genellikle daha yüksek bir hassasiyeti taklit etmek için yapılır (ör. Daha Yüksek Hassasiyetli Hesaplamalar İçin bfloat16 Yapay Zeka Veri Türü'nden Yararlanma: bf16_6x tf32_3x vb.). Ayrıştırma içermeyen algoritmalar için bu değerler1
olarak ayarlanmalıdır.- Bazı adımlarda (ör.
CUBLASLT_MATMUL_DESC_FAST_ACCUM
) daha düşük hassasiyette veri toplamaya izin verilip verilmediğini belirtmek içinallow_imprecise_accumulation
kullanın.
Örnek DotAlgorithm
özellikleri:
// Inputs are casted to tf32, and then accumulated in f32:
{lhs_precision_type = tf32,
rhs_precision_type = tf32,
accumulation_type = f32,
lhs_component_count = 1,
rhs_component_count = 1,
num_primitive_operations = 1,
allow_imprecise_accumulation = false}
// bf16_6x: each input is decomposed to 3 bf16 components, then 6 dot operations are done on those components, and the result is accumulated in f32.
{lhs_precision_type = bf16,
rhs_precision_type = bf16,
accumulation_type = f32,
lhs_component_count = 3,
rhs_component_count = 3,
num_primitive_operations = 6,
allow_imprecise_accumulation = false}
// Inputs are (casted to) f8e5m2, and we accumulate in f32, but for some steps we may accumulate in lower precision.
{lhs_precision_type = f8e5m2,
rhs_precision_type = f8e5m2,
accumulation_type = f32,
lhs_component_count = 1,
rhs_component_count = 1,
num_primitive_operations = 1,
allow_imprecise_accumulation = true}
Hangi kombinasyonların desteklendiğine karar vermek uygulamalara bağlıdır. Genel olarak, StableHLO tüketicisi tarafından her algoritmanın her hızlandırıcı türünde desteklendiği garanti edilmez. Belirli bir algoritma desteklenmiyorsa alternatife geçmek yerine bir hata oluşturulmalıdır. StableHLO doğrulaması, herhangi bir donanımda desteklenmediği bilinen algoritmaların kullanılmasını önleyerek en iyi doğrulama yöntemini sunar.
Desteklenen bazı algoritma değerleri için xla_data.proto > Algorithm
bölümüne bakın. 2483 numaralı destek kaydı, arka uç tarafından desteklenen algoritmalar hakkında merkezi bir doküman oluşturma planını içerir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | lhs |
tensor veya tensor başına kesikli tensor | (C5-C6), (C9-C10), (C12-C14), (C17-C18), (C20) |
(I2) | rhs |
tenzor veya kesirli tenzor | (C7-C10), (C12-C20) |
(I3) | lhs_batching_dimensions |
si64 türündeki 1 boyutlu tensör sabiti |
(C1), (C3), (C5), (C9), (C12) |
(I4) | rhs_batching_dimensions |
si64 türünde 1 boyutlu tensör sabiti |
(C1), (C4), (C7), (C9) |
(I5) | lhs_contracting_dimensions |
si64 türünde 1 boyutlu tensör sabiti |
(C2), (C3), (C6), (C10) |
(I6) | rhs_contracting_dimensions |
si64 türündeki 1 boyutlu tensör sabiti |
(C2), (C4), (C8), (C10), (C16) |
(I7) | precision_config |
DEFAULT , HIGH ve HIGHEST türetilmiş türleri için değişken sayıda enum |
(C11), (C21) |
(I8) | lhs_precision_type |
floatType veya Tensorfloat32 | (C21) |
(I9) | rhs_precision_type |
FloatType veya TensorFloat32 | (C21) |
(I10) | accumulation_type |
FloatType veya TensorFloat32 | (C21) |
(I11) | lhs_component_count |
si32 türünün sabiti |
(C21), (C22) |
(I12) | rhs_component_count |
si32 türünün sabiti |
(C21), (C23) |
(I13) | num_primitive_operations |
si32 türündeki sabit |
(C21), (C24) |
(I14) | allow_imprecise_accumulation |
bool türündeki sabit |
(C21) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tenzor veya kesirli tenzor | (C12), (C14), (C18-C20) |
Sınırlamalar
- (C1)
size(lhs_batching_dimensions) = size(rhs_batching_dimensions)
. - (C2)
size(lhs_contracting_dimensions) = size(rhs_contracting_dimensions)
. - (C3)
is_unique(lhs_batching_dimensions + lhs_contracting_dimensions)
. - (C4)
is_unique(rhs_batching_dimensions + rhs_contracting_dimensions)
- (C5)
0 <= lhs_batching_dimensions < rank(lhs)
. - (C6)
0 <= lhs_contracting_dimensions < rank(lhs)
. - (C7)
0 <= rhs_batching_dimensions < rank(rhs)
. - (C8)
0 <= rhs_contracting_dimensions < rank(rhs)
. - (C9)
dim(lhs, lhs_batching_dimensions...) = dim(rhs, rhs_batching_dimensions...)
. - (C10)
dim(lhs, lhs_contracting_dimensions...) = dim(rhs, rhs_contracting_dimensions...)
. - (C11)
size(precision_config) = 2
. - (C12)
shape(result) = dim(lhs, lhs_batching_dimensions) + dim(lhs, lhs_result_dimensions) + dim(rhs, rhs_result_dimensions)
. - İşlemde miktarlandırılmamış tensörler kullanılıyorsa:
- (C13)
element_type(lhs) = element_type(rhs)
- (C13)
- İşlemde nicel tensörler kullanılıyorsa:
- (C14)
is_quantized(lhs) = is_quantized(result) and is_quantized(rhs)
. - (C15)
zero_points(rhs) = 0
. - (C16)
is_per_axis_quantized(rhs)
isequantization_dimension(rhs)
rhs_contracting_dimensions
içinde değildir. is_quantized(lhs)
ise:- (C17)
storage_type(lhs) = storage_type(rhs)
. - (C18)
expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
. - (C19)
is_per_tensor_quantized(rhs)
iseis_per_tensor_quantized(result)
. !is_quantized(lhs)
ise:- (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, broadcast_in_dim çalışma biçimiyle işlevsel olarak aynıdır ancak sonuç şekli output_dimensions
aracılığıyla dinamik olarak belirtilir.
İşlemde, boyutların genişleme davranışı hakkındaki statik bilgileri ifade etmek için isteğe bağlı known_expanding_dimensions
, known_nonexpanding_dimensions
özellikleri de kabul edilir.
Belirtilmezse tüm boyutların genişleyebileceği varsayılır.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
tenzor veya kesirli tenzor | (C1-C2), (C5-C6), (C9) |
(I2) | output_dimensions |
Tam sayı türündeki 1 boyutlu tenör | (C7) |
(I3) | broadcast_dimensions |
Tam sayı türünde 1 boyutlu sabit tensör | (C2-C6) |
(I4) | known_expanding_dimensions |
Tam sayı türündeki 1 boyutlu sabit tensör | (C8-C9) |
(I5) | known_nonexpanding_dimensions |
Tam sayı türünde 1 boyutlu sabit tensör | (C8-C9) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensör veya nicel tensör | (C1), (C3), (C5-C7) |
Sınırlamalar
- (C1)
element_type(result)
şu şekilde hesaplanır:!is_per_axis_quantized(operand)
iseelement_type(operand)
.element_type(operand)
, ancakquantization_dimension(operand)
,scales(operand)
vezero_points(operand)
sırasıylaquantization_dimension(result)
,scales(result)
vezero_points(result)
'den farklı olabilir.
- (C2)
size(broadcast_dimensions) = rank(operand)
. - (C3)
0 <= broadcast_dimensions < rank(result)
. - (C4)
is_unique(broadcast_dimensions)
. - (C5)
axes(operand)
içindeki tümd
için:dim(operand, d) = 1
veyadim(operand, d) = dim(result, broadcast_dimensions[d])
.
- (C6)
is_per_axis_quantized(result)
ise:quantization_dimension(result) = broadcast_dimensions[quantization_dimension(operand)]
.dim(operand, quantization_dimension(operand)) = 1
isescales(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 toplama işleviyle aynıdır ancak dolgu, padding
aracılığıyla dinamik olarak belirtilir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | lhs |
tensor veya tensor başına kesikli tensor | (C1), (C10-C11), (C14) (C25), (C26-C27), (C30-C31), (C33) |
(I2) | rhs |
tensör veya nicel tensör | (C1), (C14-C16), (C26-C28), (C30-C33) |
(I3) | padding |
Tam sayı türünde 2 boyutlu tensör | (C4) |
(I4) | window_strides |
si64 türündeki 1 boyutlu tensör sabiti |
(C2-C3) |
(I5) | lhs_dilation |
si64 türündeki 1 boyutlu tensör sabiti |
(C5-C6) |
(I6) | rhs_dilation |
si64 türündeki 1 boyutlu tensör sabiti |
(C7-C8) |
(I7) | window_reversal |
i1 türünde 1 boyutlu tensör sabiti |
(C9) |
(I8) | input_batch_dimension |
si64 türündeki sabit |
(C10), (C13) |
(I9) | input_feature_dimension |
si64 türündeki sabit |
(C11), (C13-C14) |
(I10) | input_spatial_dimensions |
si64 türünde 1 boyutlu tensör sabiti |
(C12), (C13) |
(I11) | kernel_input_feature_dimension |
si64 türündeki sabit |
(C14), (C18) |
(I12) | kernel_output_feature_dimension |
si64 türündeki sabit |
(C15-C16), (C18), (C28) |
(I13) | kernel_spatial_dimensions |
si64 türündeki 1 boyutlu tensör sabiti |
(C17-C18) |
(I14) | output_batch_dimension |
si64 türünün sabiti |
(C20) |
(I15) | output_feature_dimension |
si64 türünün sabiti |
(C20), (C29) |
(I16) | output_spatial_dimensions |
si64 türünde 1 boyutlu tensör sabiti |
(C19-C20) |
(I17) | feature_group_count |
si64 türündeki sabit |
(C11), (C14), (C16), (C21), (C23) |
(I18) | batch_group_count |
si64 türündeki sabit |
(C10), (C15), (C22), (C23) |
(I19) | precision_config |
DEFAULT , HIGH ve HIGHEST türetilmiş türleri için değişken sayıda enum |
(C24) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tenzor veya kesirli tenzor | (C25-C27), (C29), (C31-C33) |
Sınırlamalar
- (C1)
N = rank(lhs) = rank(rhs)
. - (C2)
size(window_strides) = N - 2
. - (C3)
0 < window_strides
. - (C4)
shape(padding) = [N - 2, 2]
. - (C5)
size(lhs_dilation) = N - 2
. - (C6)
0 < lhs_dilation
. - (C7)
size(rhs_dilation) = N - 2
. - (C8)
0 < rhs_dilation
- (C9)
size(window_reversal) = N - 2
. - (C10)
dim(lhs, input_batch_dimension) % batch_group_count = 0
. - (C11)
dim(lhs, input_feature_dimension) % feature_group_count = 0
- (C12)
size(input_spatial_dimensions) = N - 2
- (C13)
input_dimensions = [input_batch_dimension] + input_spatial_dimensions + [input_feature_dimension]
ile ilgili:is_unique(input_dimensions)
.0 <= input_dimensions < N
.
- (C14)
dim(rhs, kernel_input_feature_dimension) = dim(lhs, input_feature_dimension) / feature_group_count
- (C15)
dim(rhs, kernel_output_feature_dimension) % batch_group_count = 0
. - (C16)
dim(rhs, kernel_output_feature_dimension) % feature_group_count = 0
- (C17)
size(kernel_spatial_dimensions) = N - 2
. - (C18)
kernel_dimensions = kernel_spatial_dimensions + [kernel_input_feature_dimension] + [kernel_output_feature_dimension]
ile ilgili:is_unique(kernel_dimensions)
.0 <= kernel_dimensions < N
.
- (C19)
size(output_spatial_dimensions) = N - 2
- (C20)
output_dimensions = [output_batch_dimension] + output_spatial_dimensions + [output_feature_dimension]
verildiğinde:is_unique(output_dimensions)
.0 <= output_dimensions < N
.
- (C21)
0 < feature_group_count
. - (C22)
0 < batch_group_count
. - (C23)
feature_group_count = 1 or batch_group_count = 1
. - (C24)
size(precision_config) = 2
- (C25)
dim(result, result_dim)
şu şekilde tanımlanır:result_dim = output_batch_dimension
isedim(lhs, input_batch_dimension) / batch_group_count
.result_dim = output_feature_dimension
isedim(rhs, kernel_output_feature_dimension)
.num_windows
aksi takdirde:output_spatial_dimensions[spatial_dim] = result_dim
.lhs_dim = input_spatial_dimensions[spatial_dim]
.rhs_dim = kernel_spatial_dimensions[spatial_dim]
.dilated_input_shape[lhs_dim] = dim(lhs, lhs_dim) = 0 ? 0 : (dim(lhs, lhs_dim) - 1) * lhs_dilation[spatial_dim] + 1
.padded_input_shape[lhs_dim] = padding[spatial_dim, 0] + dilated_input_shape[lhs_dim] + padding[spatial_dim, 1]
.dilated_window_shape[lhs_dim] = dim(rhs, rhs_dim) = 0 ? 0 : (dim(rhs, rhs_dim) - 1) * rhs_dilation[spatial_dim] + 1
.is_empty_window[lhs_dim] = padded_input_shape[lhs_dim] = 0 || dilated_window_shape[lhs_dim] > padded_input_shape[lhs_dim]
.num_windows = is_empty_window[lhs_dim] ? 0 : floor((padded_input_shape[lhs_dim] - dilated_window_shape[lhs_dim]) / window_strides[spatial_dim]) + 1
.
- (C26)
rank(result) = N
. - İşlemde miktarlandırılmamış tensörler kullanılıyorsa:
- (C27)
element_type(lhs) = element_type(rhs) = element_type(result)
.
- (C27)
- İşlemde kesirli tenzorlar 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)
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ğeri dinamik olarak belirtildiğinde işlevsel olarak gather işlevine eşittir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
tensor veya tensor başına kesikli tensor | (C1), (C7), (C10-C12), (C14) |
(I2) | start_indices |
tam sayı türündeki tensör | (C2), (C3), (C13) |
(I3) | slice_sizes |
Tam sayı türündeki 1 boyutlu tenör | (C8), (C11-C13) |
(I4) | offset_dims |
si64 türündeki 1 boyutlu tensör sabiti |
(C1); (C4-C5); (C13) |
(I5) | collapsed_slice_dims |
si64 türündeki 1 boyutlu tensör sabiti |
(C1), (C6-C8), (C13) |
(I6) | start_index_map |
si64 türündeki 1 boyutlu tensör sabiti |
(C3), (C9), (C10) |
(I7) | index_vector_dim |
si64 türündeki sabit |
(C2), (C3), (C13) |
(I8) | indices_are_sorted |
i1 türünün sabiti |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensor veya tensor başına kesikli tensor | (C5), (C13-C14) |
Sınırlamalar
- (C1)
rank(operand) = size(offset_dims) + size(collapsed_slice_dims)
. - (C2)
0 <= index_vector_dim <= rank(start_indices)
. - (C3)
size(start_index_map) = index_vector_dim < rank(start_indices) ? dim(start_indices, index_vector_dim) : 1
. - (C4)
is_unique(offset_dims) and is_sorted(offset_dims)
. - (C5)
0 <= offset_dims < rank(result)
. - (C6)
is_unique(collapsed_slice_dims) and is_sorted(collapsed_slice_dims)
. - (C7)
0 <= collapsed_slice_dims < rank(operand)
. - (C8)
slice_sizes[collapsed_slice_dims...] <= 1
. - (C9)
is_unique(start_index_map)
. - (C10)
0 <= start_index_map < rank(operand)
. - (C11)
size(slice_sizes) = rank(operand)
. - (C12)
0 <= slice_sizes <= shape(operand)
- (C13)
shape(result) = combine(batch_dim_sizes, offset_dim_sizes)
burada:batch_dim_sizes = shape(start_indices)
dışındaindex_vector_dim
'e karşılık gelenstart_indices
boyut boyutu dahil edilmemiştir.offset_dim_sizes = shape(slice_sizes)
dışında,slice_sizes
ürünündecollapsed_slice_dims
'a karşılık gelen boyut boyutları dahil edilmemiştir.combine
,batch_dim_sizes
öğesinioffset_dims
öğesine karşılık gelen eksenlerebatch_dims
veoffset_dim_sizes
karşılık gelen eksenlere yerleştirir.
- (C14)
element_type(operand) = element_type(result)
.
Örnekler
// %operand: [
// [[1, 2], [3, 4], [5, 6], [7, 8]],
// [[9, 10],[11, 12], [13, 14], [15, 16]],
// [[17, 18], [19, 20], [21, 22], [23, 24]]
// ]
// %start_indices: [
// [[0, 0], [1, 0], [2, 1]],
// [[0, 1], [1, 1], [0, 2]]
// ]
// %slize_sizes: [1, 2, 2]
%result = "stablehlo.dynamic_gather"(%operand, %start_indices, %slize_sizes) {
dimension_numbers = #stablehlo.gather<
offset_dims = [2, 3],
collapsed_slice_dims = [0],
start_index_map = [1, 0],
index_vector_dim = 2>,
indices_are_sorted = false
} : (tensor<3x4x2xi64>, tensor<2x3x2xi64>, tensor<3xi64>) -> tensor<2x3x2x2xi64>
// %result: [
// [
// [[1, 2], [3, 4]],
// [[3, 4], [5, 6]],
// [[13, 14], [15, 16]]
// ],
// [
// [[9, 10], [11, 12]],
// [[11, 12], [13, 14]],
// [[17, 18], [19, 20]]
// ]
// ]
dynamic_iota
Anlam
Bu işlem işlevsel olarak iota işlevine benzer ancak sonuç şekli output_shape
aracılığıyla dinamik olarak belirtilir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | output_shape |
Tam sayı türündeki 1 boyutlu tenör | (C1), (C2) |
(I2) | iota_dimension |
si64 |
(C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
Tam sayı, kayan nokta veya karmaşık türde bir tensör ya da tensör başına kesirli tensör | (C2) |
Sınırlamalar
- (C1)
0 <= iota_dimension < size(output_shape)
. - (C2)
rank(result) = size(output_shape)
.
Örnekler
%output_shape = stablehlo.constant dense<[4, 5]> : tensor<2xi64>
%result = "stablehlo.dynamic_iota"(%output_shape) {
iota_dimension = 0 : i64
} : (tensor<2xi64>) -> tensor<4x5xi64>
// %result: [
// [0, 0, 0, 0, 0],
// [1, 1, 1, 1, 1],
// [2, 2, 2, 2, 2],
// [3, 3, 3, 3, 3]
// ]
dynamic_pad
Anlam bilimi
Bu işlem işlevsel olarak pad işlevine benzer ancak edge_padding_low
, edge_padding_high
ve interior_padding
değerleri dinamik olarak belirtilir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
tensör veya tensör başına miktarlandırılmış tensör | (C1), (C2), (C4) |
(I2) | padding_value |
0 boyutlu tensör veya tensör başına miktarlandırılmış tensör | (C1) |
(I3) | edge_padding_low |
Tam sayı türündeki 1 boyutlu tenör | (C1), (C4) |
(I4) | edge_padding_high |
Tam sayı türünde 1 boyutlu tensör | (C1), (C4) |
(I5) | interior_padding |
Tam sayı türündeki 1 boyutlu tenör | (C2-C4) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensör veya tensör başına miktarlandırılmış tensör | (C3-C6) |
Sınırlamalar
- (C1)
element_type(operand) = element_type(padding_value) = element_type(result)
. - (C2)
size(edge_padding_low) = size(edge_padding_high) = size(interior_padding) = rank(operand)
. - (C3)
0 <= interior_padding
. - (C4)
shape(result) = shape(operand) + edge_padding_low + max(shape(operand) - 1, 0) * interior_padding + edge_padding_high
.
Örnekler
// %operand: [
// [1, 2, 3],
// [4, 5, 6]
// ]
// %padding_value: 0
// %edge_padding_low: [0, 1]
// %edge_padding_high: [2, 1]
// %interior_padding: [1, 2]
%result = "stablehlo.dynamic_pad"(%operand, %padding_value,
%edge_padding_low, %edge_padding_high, %interior_padding
) : (tensor<2x3xi64>, tensor<i64>, tensor<2xi64>, tensor<2xi64>, tensor<2xi64>) -> tensor<5x9xi64>
// %result: [
// [0, 1, 0, 0, 2, 0, 0, 3, 0],
// [0, 0, 0, 0, 0, 0, 0, 0, 0],
// [0, 4, 0, 0, 5, 0, 0, 6, 0],
// [0, 0, 0, 0, 0, 0, 0, 0, 0],
// [0, 0, 0, 0, 0, 0, 0, 0, 0]
// ]
dynamic_reshape
Anlam
Bu işlem işlevsel olarak reshape işleviyle aynıdır ancak sonuç şekli output_shape
aracılığıyla dinamik olarak belirtilir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
tenzor veya kesirli tenzor | (C1-C3) |
(I2) | output_shape |
Tam sayı türünde 1 boyutlu tensör | (C4) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensör veya nicel tensör | (C1-C4) |
Sınırlamalar
- (C1)
element_type(result)
şu şekilde hesaplanır:!is_per_axis_quantized(operand)
iseelement_type(operand)
.element_type(operand)
, ancakquantization_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
Dinamik olarak hesaplanan başlangıç dizinlerini kullanarak operand
'ten bir dilim çıkarır ve result
tensörü oluşturur. start_indices
, olası düzenlemeye tabi her boyut için dilimin başlangıç dizinlerini içerir ve slice_sizes
, her boyuta ait dilimin boyutlarını içerir. Daha resmi bir ifadeyle,
result[result_index] = operand[operand_index]
burada:
adjusted_start_indices = clamp(0, start_indices, shape(operand) - slice_sizes)
.operand_index = adjusted_start_indices + result_index
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
tensör veya tensör başına miktarlandırılmış tensör | (C1), (C2), (C4) |
(I2) | start_indices |
tam sayı türündeki 0 boyutlu tensörlerin değişken sayısı | (C2), (C3) |
(I3) | slice_sizes |
si64 türündeki 1 boyutlu tensör sabiti |
(C2), (C4), (C5) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensor veya tensor başına kesikli tensor | (C1), (C5) |
Sınırlamalar
- (C1)
element_type(operand) = element_type(result)
. - (C2)
size(start_indices) = size(slice_sizes) = rank(operand)
. - (C3)
same(type(start_indices...))
. - (C4)
0 <= slice_sizes <= shape(operand)
. - (C5)
shape(result) = slice_sizes
Örnekler
// %operand: [
// [0, 0, 1, 1],
// [0, 0, 1, 1],
// [0, 0, 0, 0],
// [0, 0, 0, 0]
// ]
// %start_indices0: -1
// %start_indices1: 3
%result = "stablehlo.dynamic_slice"(%operand, %start_indices0, %start_indices1) {
slice_sizes = array<i64: 2, 2>
} : (tensor<4x4xi32>, tensor<i64>, tensor<i64>) -> tensor<2x2xi32>
// %result: [
// [1, 1],
// [1, 1]
// ]
dynamic_update_slice
Anlam bilimi
start_indices
ile başlayan dilim update
içindeki değerlerle güncellenmesi dışında, operand
tensörüne eşit bir result
tensörü oluşturur.
Daha resmi bir şekilde result[result_index]
şu şekilde tanımlanır:
0 <= update_index < shape(update)
iseupdate[update_index]
:adjusted_start_indices = clamp(0, start_indices, shape(operand) - shape(update))
.update_index = result_index - adjusted_start_indices
.
- Aksi takdirde
operand[result_index]
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
tensor veya tensor başına kesikli tensor | (C1-C4); (C6) |
(I2) | update |
tensor veya tensor başına kesikli tensor | (C2), (C3), (C6) |
(I3) | start_indices |
tam sayı türündeki 0 boyutlu tensörlerin değişken sayısı | (C4), (C5) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensör veya tensör başına miktarlandırılmış tensör | (C1) |
Sınırlamalar
- (C1)
type(operand) = type(result)
. - (C2)
element_type(update) = element_type(operand)
. - (C3)
rank(update) = rank(operand)
. - (C4)
size(start_indices) = rank(operand)
- (C5)
same(type(start_indices...))
- (C6)
0 <= shape(update) <= shape(operand)
.
Örnekler
// %operand: [
// [1, 1, 0, 0],
// [1, 1, 0, 0],
// [1, 1, 1, 1],
// [1, 1, 1, 1]
// ]
// %update: [
// [1, 1],
// [1, 1]
// ]
// %start_indices0: -1
// %start_indices1: 3
%result = "stablehlo.dynamic_update_slice"(%operand, %update, %start_indices0, %start_indices1)
: (tensor<4x4xi32>, tensor<2x2xi32>, tensor<i64>, tensor<i64>) -> tensor<4x4xi32>
// %result: [
// [1, 1, 1, 1],
// [1, 1, 1, 1],
// [1, 1, 1, 1],
// [1, 1, 1, 1]
// ]
üstel
Anlam bilimi
operand
tenzorunda öğe bazında üstel işlem gerçekleştirir ve bir result
tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:
- Kayan reklamlar için: IEEE-754'ten
exp
. - Karmaşık sayılar için: karmaşık üs.
- Kesirli türler için:
dequantize_op_quantize(exponential, operand, type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Sınırlamalar
- (C1)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// %operand: [[0.0, 1.0], [2.0, 3.0]]
%result = "stablehlo.exponential"(%operand) : (tensor<2x2xf64>) -> tensor<2x2xf64>
// %result: [[1.0, 2.7182818284590451], [7.3890560989306504, 20.085536923187668]]
exponential_minus_one
Anlam bilimi
operand
tenzorunda öğe bazında üstel eksi bir işlemi gerçekleştirir ve bir result
tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:
- Kayan noktalı sayılar için: IEEE-754'ten
expm1
. - Karmaşık sayılar için: karmaşık üssün bir eksi değeri.
- Kesirli türler için:
dequantize_op_quantize(exponential_minus_one, operand, type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Sınırlamalar
- (C1)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// %operand: [0.0, 1.0]
%result = "stablehlo.exponential_minus_one"(%operand) : (tensor<2xf64>) -> tensor<2xf64>
// %result: [0.0, 1.71828187]
fft
Anlam bilimi
Gerçek ve karmaşık girişler/çıktılar için ileri ve ters Fourier dönüşümlerini gerçekleştirir.
fft_type
aşağıdakilerden biridir:
FFT
: Karmaşıktan karmaşığa ileri FFT.IFFT
: Karmaşıktan karmaşığa ters FFT.RFFT
: Gerçekten karmaşık FFT'ye yönlendirme.IRFFT
: Ters gerçeğe dayalı FFT (ör. karmaşık alır, gerçek sonucu döndürür).
Daha resmi bir ifadeyle, karmaşık türlerde 1 boyutlu tenzorları giriş olarak alan, çıkış olarak aynı türde 1 boyutlu tenzorlar üreten ve ayrık Fourier dönüşümünü hesaplayan fft
işlevi verildiğinde:
fft_type = FFT
için result
, L = size(fft_length)
olan bir dizi L hesaplamasının nihai sonucu olarak tanımlanır. Örneğin, L = 3
için:
result1[i0, ..., :] = fft(operand[i0, ..., :])
.result2[i0, ..., :, iR-1] = fft(result1[i0, ..., :, iR-1])
.result[i0, ..., :, iR-2, iR-1] = fft(result2[i0, ..., :, iR-2, iR-1])
.
Ayrıca, aynı tür imzasına sahip olan ve fft
işlevinin tersini hesaplayan ifft
işlevi verildiğinde:
fft_type = IFFT
için result
, fft_type = FFT
hesaplamalarının tersi olarak tanımlanır. Örneğin, L = 3
için:
result1[i0, ..., :, iR-2, iR-1] = ifft(operand[i0, ..., :, iR-2, iR-1])
.result2[i0, ..., :, iR-1] = ifft(result1[i0, ..., :, iR-1])
.result[i0, ..., :] = ifft(result2[i0, ..., :])
.
Ayrıca, rfft
işlevi, kayan nokta türünde 1 boyutlu tenzorlar alır, aynı kayan nokta semantiğine sahip karmaşık türde 1 boyutlu tenzorlar oluşturur ve aşağıdaki gibi çalışır:
rfft(real_operand) = truncated_result
neredecomplex_operand... = (real_operand..., 0.0)
.complex_result = fft(complex_operand)
.truncated_result = complex_result[:(rank(complex_result) / 2 + 1)]
.
(Dijital Fourier dönüşümü gerçek operatörler için hesaplandığında, sonucun ilk N/2 + 1
öğeleri sonucun geri kalanını açıkça tanımlar. Bu nedenle, rfft
sonucu gereksiz öğelerin hesaplanmasını önlemek için kısaltılır.)
fft_type = RFFT
için result
, L = size(fft_length)
olan bir dizi L hesaplamasının nihai sonucu olarak tanımlanır. Örneğin, L = 3
için:
result1[i0, ..., :] = rfft(operand[i0, ..., :])
.result2[i0, ..., :, iR-1] = fft(result1[i0, ..., :, iR-1])
.result[i0, ..., :, iR-2, iR-1] = fft(result2[i0, ..., :, iR-2, iR-1])
.
Son olarak, aynı tür imzaya sahip olan ve rfft
işlevinin tersini hesaplayan irfft
işlevine göz atalım:
fft_type = IRFFT
için result
, fft_type = RFFT
için hesaplamaların tersi olarak tanımlanır. Örneğin, L = 3
için:
result1[i0, ..., :, iR-2, iR-1] = ifft(operand[i0, ..., :, iR-2, iR-1])
.result2[i0, ..., :, iR-1] = ifft(result1[i0, ..., :, iR-1])
.result[i0, ..., :] = irfft(result2[i0, ..., :])
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
kayan nokta veya karmaşık türde tensör | (C1), (C2), (C4), (C5) |
(I2) | fft_type |
FFT , IFFT , RFFT ve IRFFT sıralaması |
(C2), (C5) |
(I3) | fft_length |
si64 türündeki 1 boyutlu tensör sabiti |
(C1), (C3), (C4) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta veya karmaşık türde tensör | (C2), (C4), (C5) |
Sınırlamalar
- (C1)
size(fft_length) <= rank(operand)
. - (C2)
operand
ileresult
öğe türleri arasındaki ilişki değişiklik gösterir: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 = RFFT
iseelement_type(operand)
bir kayan nokta türü,element_type(result)
ise aynı kayan nokta semantiğinin karmaşık bir türüdür.fft_type = IRFFT
iseelement_type(operand)
karmaşık bir türse veelement_type(result)
aynı kayan nokta anlamına sahip bir kayan nokta türüdür.
- (C3)
1 <= size(fft_length) <= 3
. - (C4)
operand
veresult
arasında kayan nokta türüne sahip birreal
tensörü varsashape(real)[-size(fft_length):] = fft_length
. - (C5) Şunlar hariç
shape(result) = shape(operand)
:fft_type = RFFT
isedim(result, -1) = dim(operand, -1) = 0 ? 0 : dim(operand, -1) / 2 + 1
.fft_type = IRFFT
isedim(operand, -1) = dim(result, -1) = 0 ? 0 : dim(result, -1) / 2 + 1
.
Örnekler
// %operand: [(1.0, 0.0), (0.0, 0.0), (0.0, 0.0), (0.0, 0.0)]
%result = "stablehlo.fft"(%operand) {
fft_type = #stablehlo<fft_type FFT>,
fft_length = array<i64: 4>
} : (tensor<4xcomplex<f32>>) -> tensor<4xcomplex<f32>>
// %result: [(1.0, 0.0), (1.0, 0.0), (1.0, 0.0), (1.0, 0.0)]
kat
Anlam bilimi
Element tabanlı tabanda operand
tensörü gerçekleştirir ve bir result
tensörü üretir.
IEEE-754 spesifikasyonundaki roundToIntegralTowardNegative
işlemini uygular. Miktarı ölçülmüş türlerde, dequantize_op_quantize(floor, operand, type(result))
gerçekleştirir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
Kayan nokta türündeki veya tensör başına kesirli tensör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta türünde veya tensör başına miktarlandırılmış tensörün tensörü | (C1) |
Sınırlamalar
- (C1)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// %operand: [-0.8166, -0.2530, 0.2530, 0.8166, 2.0]
%result = "stablehlo.floor"(%operand) : (tensor<5xf32>) -> tensor<5xf32>
// %result: [-1.0, -1.0, 0.0, 0.0, 2.0]
topla
Anlam
start_indices
içinde belirtilen ofsetlerden operand
tensöründen dilimleri toplar ve bir result
tensörü üretir.
Aşağıdaki şemada, result
öğelerinin operand
öğeleriyle nasıl eşlendiği somut bir örnekle gösterilmektedir. Diyagramda birkaç örnek result
dizin seçilir ve bunların hangi operand
dizinlerine karşılık geldiği ayrıntılı olarak açıklanır.
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_index
içindeki bağımsız öğelerdir veindex_vector_dim
<rank(start_indices)
ise:
,index_vector_dim
dizine yerleştirilir.- Aksi takdirde
[start_indices[batch_index]]
değerini alır.
axes(operand)
içinded_operand
içinfull_start_index[d_operand] = clamp(start_index[d_start], 0, dim(operand, d_operand) - slice_sizes[d_operand])
d_operand = start_index_map[d_start]
ise.- Aksi takdirde
full_start_index[d_operand] = 0
.
axes(operand)
içinded_operand
içinfull_batching_index[d_operand] = batch_index[d_start - (d_start < index_vector_dim ? 0 : 1)]
d_operand = operand_batching_dims[i_batching]
ved_start = start_indices_batching_dims[i_batching]
ise.- Aksi takdirde
full_batching_index[d_operand] = 0
değerini alır.
offset_index = result_index[offset_dims...]
.full_offset_index = [oi0, ..., 0, ..., oiN]
; buradaoi
,offset_index
içindeki bağımsız öğelerdir ve0
,collapsed_slice_dims
ileoperand_batching_dims
arasındaki dizinlere eklenir.operand_index = full_start_index + full_batching_index + full_offset_index
.
indices_are_sorted
değeri true
ise uygulama, start_indices
değerinin start_index_map
öğesine göre sıralandığını varsayabilir. Aksi takdirde davranış tanımsızdır. Daha resmî bir şekilde ifade etmek gerekirse indices(result)
,
full_start_index(i1) <= full_start_index(i2)
tarafından sağlanan tüm i1 < i2
için.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
tensor veya tensor başına kesikli tensor | (C1), (C8), (C11), (C17), (C19-C21), (C23) |
(I2) | start_indices |
tam sayı türündeki tensör | (C2-C3), (C14), (C17), (C22) |
(I3) | offset_dims |
si64 türündeki 1 boyutlu tensör sabiti |
(C1), (C4-C5), (C22) |
(I4) | collapsed_slice_dims |
si64 türündeki 1 boyutlu tensör sabiti |
(C1), (C6-C9), (C22) |
(I5) | operand_batching_dims |
si64 türünde 1 boyutlu tensör sabiti |
(C1), (C6), (C10-C12), (C16-C18), (C22) |
(I6) | start_indices_batching_dims |
si64 türündeki 1 boyutlu tensör sabiti |
(C13-C17) |
(I7) | start_index_map |
si64 türündeki 1 boyutlu tensör sabiti |
(C3), (C18-C19) |
(I8) | index_vector_dim |
si64 türünün sabiti |
(C2-C3), (C15), (C22) |
(I9) | slice_sizes |
si64 türünde 1 boyutlu tensör sabiti |
(C9), (C12), (C20-C22) |
(I10) | indices_are_sorted |
i1 türündeki sabit |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensör veya tensör başına miktarlandırılmış tensör | (C5), (C22-C23) |
Sınırlamalar
- (C1)
rank(operand) = size(offset_dims) + size(collapsed_slice_dims) + size(operand_batching_dims)
. - (C2)
0 <= index_vector_dim <= rank(start_indices)
. - (C3)
size(start_index_map) = index_vector_dim < rank(start_indices) ? dim(start_indices, index_vector_dim) : 1
. - (C4)
is_unique(offset_dims) and is_sorted(offset_dims)
. - (C5)
0 <= offset_dims < rank(result)
. - (C6)
is_unique(concatenate(collapsed_slice_dims, operand_batching_dims))
- (C7)
is_sorted(collapsed_slice_dims)
. - (C8)
0 <= collapsed_slice_dims < rank(operand)
- (C9)
slice_sizes[collapsed_slice_dims...] <= 1
. - (C10)
is_sorted(operand_batching_dims)
. - (C11)
0 <= operand_batching_dims < rank(operand)
. - (C12)
slice_sizes[operand_batching_dims...] <= 1
. - (C13)
is_unique(start_indices_batching_dims)
. - (C14)
0 <= start_indices_batching_dims < rank(start_indices)
- (C15)
index_vector_dim not in start_indices_batching_dims
. - (C16)
size(operand_batching_dims) == size(start_indices_batching_dims)
. - (C17)
dim(operand, operand_batching_dims...) = dim(start_indices, start_indices_batching_dims...)
. - (C18)
is_unique(concatenate(start_index_map, operand_batching_dims))
. - (C19)
0 <= start_index_map < rank(operand)
. - (C20)
size(slice_sizes) = rank(operand)
. - (C21)
0 <= slice_sizes <= shape(operand)
. - (C22)
shape(result) = combine(batch_dim_sizes, offset_dim_sizes)
; burada:batch_dim_sizes = shape(start_indices)
, ancakindex_vector_dim
'ye karşılık gelenstart_indices
boyutu dahil değildir.offset_dim_sizes = slice_sizes
, ancakslice_sizes
'dakicollapsed_slice_dims
veoperand_batching_dims
'a karşılık gelen boyut boyutları dahil edilmez.combine
,batch_dim_sizes
öğesinioffset_dims
öğesine karşılık gelen eksenlerebatch_dims
veoffset_dim_sizes
karşılık gelen eksenlere yerleştirir.
- (C23)
element_type(operand) = element_type(result)
.
Örnekler
// %operand: [
// [
// [[1, 2], [3, 4], [5, 6], [7, 8]],
// [[9, 10],[11, 12], [13, 14], [15, 16]],
// [[17, 18], [19, 20], [21, 22], [23, 24]]
// ],
// [
// [[25, 26], [27, 28], [29, 30], [31, 32]],
// [[33, 34], [35, 36], [37, 38], [39, 40]],
// [[41, 42], [43, 44], [45, 46], [47, 48]]
// ]
// ]
// %start_indices: [
// [
// [[0, 0], [1, 0], [2, 1]],
// [[0, 1], [1, 1], [0, 9]]
// ],
// [
// [[0, 0], [2, 1], [2, 2]],
// [[1, 2], [0, 1], [1, 0]]
// ]
// ]
%result = "stablehlo.gather"(%operand, %start_indices) {
dimension_numbers = #stablehlo.gather<
offset_dims = [3, 4],
collapsed_slice_dims = [1],
operand_batching_dims = [0],
start_indices_batching_dims = [1],
start_index_map = [2, 1],
index_vector_dim = 3>,
slice_sizes = array<i64: 1, 1, 2, 2>,
indices_are_sorted = false
} : (tensor<2x3x4x2xi32>, tensor<2x2x3x2xi64>) -> tensor<2x2x3x2x2xi32>
// %result: [
// [
// [
// [[1, 2], [3, 4]],
// [[3, 4], [5, 6]],
// [[13, 14], [15, 16]]
// ],
// [
// [[33, 34], [35, 36]],
// [[35, 36], [37, 38]],
// [[41, 42], [43, 44]]
// ]
// ],
// [
// [
// [[1, 2], [3, 4]],
// [[13, 14], [15, 16]],
// [[21, 22], [23, 24]]
// ],
// [
// [[43, 44], [45, 46]],
// [[33, 34], [35, 36]],
// [[27, 28], [29, 30]]
// ]
// ]
// ]
get_dimension_size
Anlam bilimi
operand
öğesinin belirtilen dimension
boyutunu döndürür. Daha resmi ifade etmek gerekirse,
result = dim(operand, dimension)
. Anlambilim, yalnızca türün şekil bileşeniyle ilgilidir. Öğe türü herhangi bir şey olabilir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
tenzor veya kesirli tenzor | (C1) |
(I2) | dimension |
si64 türünün sabiti |
(C1) |
Çıkışlar
Ad | Tür |
---|---|
result |
si32 türündeki 0 boyutlu tensör |
Sınırlamalar
- (C1)
0 <= dimension < rank(operand)
.
Örnekler
// %operand: [[1, 2, 3], [4, 5, 6]]
%result = "stablehlo.get_dimension_size"(%operand) {
dimension = 1 : i64
} : (tensor<2x3xi64>) -> tensor<i32>
// %result: 3
get_tuple_element
Anlam bilimi
operand
unsurunun index
konumundaki öğeyi çıkarır ve bir result
üretir. Daha resmi bir ifadeyle result = operand[index]
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
tuple | (C1), (C2) |
(I2) | index |
si32 türünün sabiti |
(C1), (C2) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
Desteklenen tüm türler | (C2) |
Sınırlamalar
- (C1)
0 <= index < size(operand)
. - (C2)
type(result) = tuple_element_types(operand)[index]
.
Örnekler
// %operand: ([1.0, 2.0], (3))
index = 0 : i32
} : (tuple<tensor<2xf32>, tuple<tensor<i32>>>) -> tensor<2xf32>
// %result: [1.0, 2.0]
koşul:
Anlam bilimi
pred
değerine bağlı olarak true_branch
veya false_branch
'ten tam olarak bir işlevin yürütülmesiyle elde edilen çıktıyı oluşturur. Daha resmi bir ifadeyle result =
pred ? true_branch() : false_branch()
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | pred |
i1 türündeki 0 boyutlu tensör |
|
(I2) | true_branch |
işlev | (C1-C3) |
(I3) | false_branch |
işlev | (C1), (C2) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
results |
değişken sayıda tenör, kesirli tenör veya jeton | (C3) |
Sınırlamalar
- (C1)
input_types(true_branch) = input_types(false_branch) = []
. - (C2)
output_types(true_branch) = output_types(false_branch)
. - (C3)
type(results...) = output_types(true_branch)
.
Örnekler
// %result_true_branch: 10
// %result_false_branch: 11
// %pred: true
%result = "stablehlo.if"(%pred) ({
"stablehlo.return"(%result_true_branch) : (tensor<i32>) -> ()
}, {
"stablehlo.return"(%result_false_branch) : (tensor<i32>) -> ()
}) : (tensor<i1>) -> tensor<i32>
// %result: 10
imag
Anlam bilimi
operand
öğesinden sanal kısmı öğe bazında çıkarır ve bir result
tensörü oluşturur. Daha resmi olarak, her öğe için x
:
imag(x) = is_complex(x) ? imaginary_part(x) :
constant(0, element_type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
kayan nokta veya karmaşık türde tensör | (C1), (C2) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta türündeki tensör | (C1), (C2) |
Sınırlamalar
- (C1)
shape(result) = shape(operand)
. - (C2)
element_type(result)
şu şekilde tanımlanır:is_complex(operand)
isecomplex_element_type(element_type(operand))
.- Aksi takdirde
element_type(operand)
değerini alır.
Örnekler
// %operand: [(1.0, 2.0), (3.0, 4.0)]
%result = "stablehlo.imag"(%operand) : (tensor<2xcomplex<f32>>) -> tensor<2xf32>
// %result: [2.0, 4.0]
feed
Anlam bilimi
Giriş feed'inden verileri okur ve results
oluşturur.
infeed_config
semantiği uygulamaya göre tanımlanır.
results
, önce gelen yük değerleri ve en son gelen bir jetondan oluşur. Gelecekte, netliği artırmak için yükü ve jetonu iki ayrı çıkışa ayırmayı planlıyoruz (#670).
Girişler
Şirket | Ad | Tür |
---|---|---|
(I1) | token |
token |
(I2) | infeed_config |
string türündeki sabit |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
results |
değişken sayıda tenör, kesirli tenör veya jeton | (C1-C3) |
Sınırlamalar
- (C1)
0 < size(results)
. - (C2)
is_empty(result[:-1])
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
Bir output
tensörünü, iota_dimension
boyutu boyunca sıfırdan başlayarak artan düzende değerlerle doldurur. Daha resmi ifade etmek gerekirse
output[output_index] = constant(is_quantized(output) ?
quantize(output_index[iota_dimension], element_type(output)) :
output_index[iota_dimension], element_type(output))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | iota_dimension |
si64 |
(C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
output |
Tam sayı, kayan nokta veya karmaşık türde bir tensör ya da tensör başına kesirli tensör | (C1) |
Sınırlamalar
- (C1)
0 <= iota_dimension < rank(output)
.
Örnekler
%output = "stablehlo.iota"() {
iota_dimension = 0 : i64
} : () -> tensor<4x5xi32>
// %output: [
// [0, 0, 0, 0, 0],
// [1, 1, 1, 1, 1],
// [2, 2, 2, 2, 2],
// [3, 3, 3, 3, 3]
// ]
%output = "stablehlo.iota"() {
iota_dimension = 1 : i64
} : () -> tensor<4x5xi32>
// %output: [
// [0, 1, 2, 3, 4],
// [0, 1, 2, 3, 4],
// [0, 1, 2, 3, 4],
// [0, 1, 2, 3, 4]
// ]
is_finite
Anlam bilimi
x
'teki değerin sonlu olup olmadığını (yani +Inf, -Inf veya NaN olup olmadığını) öğe bazında kontrol eder ve bir y
tensörü oluşturur. IEEE-754 spesifikasyonundaki isFinite
işlemini uygular. Miktarı ölçülmüş türler için sonuç her zaman true
olur.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | x |
Kayan nokta türündeki veya tensör başına kesirli tensör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
y |
boole türündeki tensör | (C1) |
Sınırlamalar
- (C1)
shape(x) = shape(y)
.
Örnekler
// Logical values: -Inf, +Inf, NaN, ...
// %x: [0xFFF0000000000000, 0x7FF0000000000000, 0x7FF8000000000000, -10.0, -0.0, 0.0, 10.0]
%y = "stablehlo.is_finite"(%x) : (tensor<7xf64) -> tensor<7xi1>
// %y: [false, false, false, true, true, true, true]
log
Anlam
operand
tenzorunda öğe bazında logaritma işlemi gerçekleştirir ve bir result
tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:
- Kayan noktalı sayılar için: IEEE-754'ten
log
. - Karmaşık sayılar için: karmaşık logaritma.
- Kesirli türler için:
dequantize_op_quantize(log, operand, type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Sınırlamalar
- (C1)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// %operand: [[1.0, 2.0], [3.0, 4.0]]
%result = "stablehlo.log"(%operand) : (tensor<2x2xf64>) -> tensor<2x2xf64>
// %result: [[0.0, 0.69314718055994529], [1.0986122886681098, 1.3862943611198906]]
log_plus_one
Anlam
operand
tenzorunda öğe bazında logaritma artı bir işlemi gerçekleştirir ve bir result
tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:
- Kayan reklamlar için: IEEE-754'ten
logp1
. - Karmaşık sayılar için: karmaşık logaritma artı bir.
- Kesirli türler için:
dequantize_op_quantize(log_plus_one, operand, type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Sınırlamalar
- (C1)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// %operand: [0.0, -0.999, 7.0, 6.38905621, 15.0]
%result = "stablehlo.log_plus_one"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// %result: [0.0, -6.90776825, 2.07944155, 2.0, 2.77258873]
mantıksal
Anlam bilimi
operand
tenzorunda öğe bazında mantıksal işlem gerçekleştirir ve bir result
tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakiler gerçekleşir:
- Kayan noktalı sayılar için: IEEE-754'ten
division(1, addition(1, exp(-x)))
. - Karmaşık sayılar için: karmaşık mantıksal.
- Kesirli türler için:
dequantize_op_quantize(logistic, operand, type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Sınırlamalar
- (C1)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// %operand: [[0.0, 1.0], [2.0, 3.0]]
%result = "stablehlo.logistic"(%operand) : (tensor<2x2xf64>) -> tensor<2x2xf64>
// %result: [[0.5, 0.73105858], [0.88079708, 0.95257413]]
harita
Anlam bilimi
dimensions
boyunca computation
harita işlevini inputs
'e uygular ve bir result
tensörü oluşturur.
Daha resmi olarak, result[result_index] = computation(inputs...[result_index])
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | inputs |
değişken sayıda tenör veya tenör başına kesikli tenörler | (C1-C4) |
(I2) | dimensions |
si64 türünde 1 boyutlu tensör sabiti |
(C3) |
(I3) | computation |
işlev | (C4) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensor veya tensor başına kesikli tensor | (C1), (C4) |
Sınırlamalar
- (C1)
shape(inputs...) = shape(result)
. - (C2)
0 < size(inputs) = N
. - (C3)
dimensions = range(rank(inputs[0]))
. - (C4)
computation
,(tensor<E0>, ..., tensor<EN-1>) -> tensor<E'>
türündedir (Ei = element_type(inputs[i])
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
lhs
ve rhs
tenzorları üzerinde öğe bazında maksimum işlemi gerçekleştirir ve bir result
tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:
- Boolelar için: mantıksal VEYA.
- Tam sayılar için: tam sayı maksimumu.
- Kayan reklamlar için: IEEE-754'ten
maximum
. - Karmaşık sayılar için:
(real, imaginary)
çifti için alfabetik sıraya göre maksimum değer. Karmaşık sayılara sıralama uygulamak şaşırtıcı anlamlar içerir. Bu nedenle, gelecekte bu işlem için karmaşık sayılar desteğini kaldırmayı planlıyoruz (#560). - Kesirli türler için:
dequantize_op_quantize(maximum, lhs, rhs, type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | lhs |
tensor veya tensor başına kesikli tensor | (C1) |
(I2) | rhs |
tensor veya tensor başına kesikli tensor | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensör veya tensör başına miktarlandırılmış tensör | (C1) |
Sınırlamalar
- (C1)
baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)
.
Örnekler
// %lhs: [[1, 2], [7, 8]]
// %rhs: [[5, 6], [3, 4]]
%result = "stablehlo.maximum"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[5, 6], [7, 8]]
minimum
Anlam
lhs
ve rhs
tenzorları üzerinde öğe bazında minimum işlemi gerçekleştirir ve bir result
tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:
- Boole değerleri için: mantıksal VE.
- Tam sayılar için: minimum tam sayı.
- Kayan noktalı sayılar için: IEEE-754'ten
minimum
. - Karmaşık sayılar için:
(real, imaginary)
çifti için alfabetik minimum. Karmaşık sayılara sıralama uygulamak şaşırtıcı anlamlar içerir. Bu nedenle, gelecekte bu işlem için karmaşık sayı desteğini kaldırmayı planlıyoruz (#560). - Kesirli türler için:
dequantize_op_quantize(minimum, lhs, rhs, type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | lhs |
tensor veya tensor başına kesikli tensor | (C1) |
(I2) | rhs |
tensor veya tensor başına kesikli tensor | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensör veya tensör başına miktarlandırılmış tensör | (C1) |
Sınırlamalar
- (C1)
baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)
.
Örnekler
// %lhs: [[1, 2], [7, 8]]
// %rhs: [[5, 6], [3, 4]]
%result = "stablehlo.minimum"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[1, 2], [3, 4]]
Çarpma
Anlam
İki tensör lhs
ve rhs
'ün öğe bazında çarpımını gerçekleştirir ve bir result
tensörü oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:
- Boolelar için: mantıksal VE.
- Tam sayılar için: tam sayı çarpımı.
- Kayan noktalı sayılar için: IEEE-754'ten
multiplication
. - Karmaşık sayılar için: karmaşık çarpma.
- Kesirli türler için:
dequantize_op_quantize(multiply, lhs, rhs, type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | lhs |
tensor veya tensor başına kesikli tensor | (C1) |
(I2) | rhs |
tensor veya tensor başına kesikli tensor | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensör veya tensör başına miktarlandırılmış tensör | (C1) |
Sınırlamalar
- (C1)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.multiply"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[5, 12], [21, 32]]
işareti değiştir
Anlam bilimi
operand
tenzorunun öğe bazında olumsuzlamasını gerçekleştirir ve bir result
tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:
- İşaretli tam sayılar için: Tam sayı olumsuzlama.
- İşaretsiz tam sayılar için: işaretli tam sayıya bitcast, tam sayı reddi, işaretsiz tam sayıya geri bitcast.
- Kayan noktalı sayılar için: IEEE-754'ten
negate
. - Karmaşık sayılar için: karmaşık reddi.
- Kesirli türler için:
dequantize_op_quantize(negate, operand, type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
Tam sayı, kayan nokta veya karmaşık türde bir tensör ya da tensör başına kesirli tensör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
Tam sayı, kayan nokta veya karmaşık türde bir tensör ya da tensör başına kesirli tensör | (C1) |
Sınırlamalar
- (C1)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// Negation operation with integer Tensors
// %operand: [0, -2]
%result = "stablehlo.negate"(%operand) : (tensor<2xi32>) -> tensor<2xi32>
// %result: [0, 2]
// Negation operation with with complex tensors
// %operand: (2.5, 0.0)
%result = "stablehlo.negate"(%operand) : (tensor<1xcomplex<f32>>) -> tensor<1xcomplex<f32>>
// %result: [-2.5, -0.0]
değil
Anlam
operand
tensörünün öğe bazında DEĞİL işlemini gerçekleştirir ve bir result
tensörü oluşturur.
Öğe türüne bağlı olarak aşağıdakiler gerçekleşir:
- Boolelar için: mantıksal DEĞİL.
- Tam sayılar için: bit tabanlı DEĞİL.
Bağımsız değişkenler
Ad | Tür | Sınırlamalar |
---|---|---|
operand |
boole veya tam sayı türündeki tenör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
boole veya tam sayı türündeki tenör | (C1) |
Sınırlamalar
- (C1)
type(operand) = type(result)
.
Örnekler
// Bitwise operation with with integer tensors
// %operand: [[1, 2], [3, 4]]
%result = "stablehlo.not"(%operand) : (tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[-2, -3], [-4, -5]]
// Bitwise operation with with boolean tensors
// %operand: [true, false]
%result = "stablehlo.not"(%operand) : (tensor<2xi1>) -> tensor<2xi1>
// %result: [false, true]
optimization_barrier
Anlam
operand
değerini üreten işlemlerin, result
değerine bağlı tüm işlemlerden önce yürütülmesini sağlar ve derleyici dönüşümlerinin işlemleri engellemeye çalışmasını önler. Bunun dışında işlem bir kimliktir (ör. result = operand
).
Bağımsız değişkenler
Ad | Tür | Sınırlamalar |
---|---|---|
operand |
değişken tensör, tensör başına nicel tensör veya jeton sayısı | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
değişken tensör, tensör başına nicel tensör veya jeton sayısı | (C1) |
Sınırlamalar
- (C1)
type(operand...) = type(result...)
.
Örnekler
// %operand0: 0.0
// %operand1: 1.0
%result0, %result1 = "stablehlo.optimization_barrier"(%operand0, %operand1) : (tensor<f32>, tensor<f32>) -> (tensor<f32>, tensor<f32>)
// %result0: 0.0
// %result1: 1.0
veya
Anlam bilimi
lhs
ve rhs
iki tensörü için öğe düzeyinde VEYA gerçekleştirir ve bir result
tensörü üretir. Öğe türüne bağlı olarak aşağıdakileri yapar:
- Boolelar için: mantıksal VEYA.
- Tam sayılar için: bit tabanlı VEYA.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | lhs |
tam sayı veya boole türündeki tenör | (C1) |
(I2) | rhs |
tam sayı veya boole türündeki tenör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tam sayı veya boole türündeki tenör | (C1) |
Sınırlamalar
- (C1)
type(lhs) = type(rhs) = type(result)
.
Örnekler
// Bitwise operation with with integer tensors
// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.or"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[5, 6], [7, 12]]
// Logical operation with with boolean tensors
// %lhs: [[false, false], [true, true]]
// %rhs: [[false, true], [false, true]]
%result = "stablehlo.or"(%lhs, %rhs) : (tensor<2x2xi1>, tensor<2x2xi1>) -> tensor<2x2xi1>
// %result: [[false, true], [true, true]]
çıkış feed'i
Anlam
Çıkış feed'ine inputs
yazar ve bir result
jetonu oluşturur.
outfeed_config
semantiği uygulamaya göre tanımlanır.
Girişler
Şirket | Ad | Tür |
---|---|---|
(I1) | inputs |
değişken sayıda tensör veya kesirli tensör |
(I2) | token |
token |
(I3) | outfeed_config |
string türünün sabiti |
Çıkışlar
Ad | Tür |
---|---|
result |
token |
Örnekler
%result = "stablehlo.outfeed"(%input0, %token) {
outfeed_config = ""
} : (tensor<2x2x2xi64>, !stablehlo.token) -> !stablehlo.token
ped
Anlam bilimi
operand
değerini, tensörün çevresindeki ve verilen padding_value
değerine sahip tensör öğeleri arasındaki dolguyla genişletir.
edge_padding_low
ve edge_padding_high
, sırasıyla her boyutun alt ucunda (0 dizininin yanında) ve üst ucunda (en yüksek dizinin yanında) eklenen dolgu miktarını belirtir. Dolgu miktarı negatif olabilir. Burada, negatif dolgunun mutlak değeri belirtilen boyuttan kaldırılacak öğe sayısını gösterir.
interior_padding
, her boyuttaki herhangi iki öğe arasına eklenen dolgu miktarını belirtir ve negatif olmayabilir. İç dolgu, kenar dolgu işleminden önce gerçekleşir. Böylece negatif kenar dolgu, iç dolgulu operatörden öğeleri kaldırır.
Daha resmi olarak, result[result_index]
şu şekilde tanımlanır:
operand[operand_index]
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 miktarlandırılmış tensör | (C1), (C2), (C4) |
(I2) | padding_value |
0 boyutlu tensör veya tensör başına miktarlandırılmış tensör | (C1) |
(I3) | edge_padding_low |
si64 türündeki 1 boyutlu tensör sabiti |
(C1), (C4) |
(I4) | edge_padding_high |
si64 türünde 1 boyutlu tensör sabiti |
(C1), (C4) |
(I5) | interior_padding |
si64 türündeki 1 boyutlu tensör sabiti |
(C2-C4) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensör veya tensör başına miktarlandırılmış tensör | (C3-C6) |
Sınırlamalar
- (C1)
element_type(operand) = element_type(padding_value) = element_type(result)
. - (C2)
size(edge_padding_low) = size(edge_padding_high) = size(interior_padding) = rank(operand)
. - (C3)
0 <= interior_padding
. - (C4)
shape(result) = shape(operand) + edge_padding_low + max(shape(operand) - 1, 0) * interior_padding + edge_padding_high
.
Örnekler
// %operand: [
// [1, 2, 3],
// [4, 5, 6]
// ]
// %padding_value: 0
%result = "stablehlo.pad"(%operand, %padding_value) {
edge_padding_low = array<i64: 0, 1>,
edge_padding_high = array<i64: 2, 1>,
interior_padding = array<i64: 1, 2>
} : (tensor<2x3xi32>, tensor<i32>) -> tensor<5x9xi32>
// %result: [
// [0, 1, 0, 0, 2, 0, 0, 3, 0],
// [0, 0, 0, 0, 0, 0, 0, 0, 0],
// [0, 4, 0, 0, 5, 0, 0, 6, 0],
// [0, 0, 0, 0, 0, 0, 0, 0, 0],
// [0, 0, 0, 0, 0, 0, 0, 0, 0]
// ]
partition_id
Anlam
Mevcut işlemin partition_id
'ünü oluşturur.
Çıkışlar
Ad | Tür |
---|---|
result |
ui32 türündeki 0 boyutlu tensör |
Örnekler
%result = "stablehlo.partition_id"() : () -> tensor<ui32>
popcnt
Anlam bilimi
operand
tensöründe ayarlanan bit sayısının öğe bazında sayımını yapar ve bir result
tensörü üretir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
tam sayı türündeki tensör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tam sayı türündeki tensör | (C1) |
Sınırlamalar
- (C1)
type(operand) = type(result)
.
Örnekler
// %operand: [0, 1, 2, 127]
%result = "stablehlo.popcnt"(%operand) : (tensor<4xi64>) -> tensor<4xi64>
// %result: [0, 1, 1, 7]
güç
Anlam bilimi
lhs
tenzorunun rhs
tenzoruyla öğe bazında üssünü alır ve bir result
tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:
- Tam sayılar için: tam sayı üss alma.
- Kayan reklamlar için: IEEE-754'ten
pow
. - Karmaşık sayılar için: karmaşık üs alma.
- Miktarlanmış türler için:
dequantize_op_quantize(power, lhs, rhs, type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | lhs |
Tam sayı, kayan nokta veya karmaşık türde bir tensör ya da tensör başına kesirli tensör | (C1) |
(I2) | rhs |
Tam sayı, kayan nokta veya karmaşık türde bir tensör ya da tensör başına kesirli tensör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
Tam sayı, kayan nokta veya karmaşık türde bir tensör ya da tensör başına kesirli tensör | (C1) |
Sınırlamalar
- (C1)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// %lhs: [-2.0, -0.0, -36.0, 5.0, 3.0, 10000.0]
// %rhs: [2.0, 2.0, 1.1, 2.0, -1.0, 10.0]
%result = "stablehlo.power"(%lhs, %rhs) : (tensor<6xf64>, tensor<6xf64>) -> tensor<6xf64>
// %result: [4.0, 0.0, -nan, 25.0, 0.333333343, inf]
gerçek
Anlam bilimi
operand
öğesinden gerçek kısmı öğe bazında ayıklayıp bir result
tensörü oluşturur. Daha resmi olarak, her öğe için x
:
real(x) = is_complex(x) ? real_part(x) : x
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
kayan nokta veya karmaşık türde tensör | (C1), (C2) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta türündeki tensör | (C1), (C2) |
Sınırlamalar
- (C1)
shape(result) = shape(operand)
. - (C2)
element_type(result)
şu şekilde tanımlanır:is_complex(operand)
isecomplex_element_type(element_type(operand))
.- Aksi takdirde
element_type(operand)
değerini alır.
Örnekler
// %operand: [(1.0, 2.0), (3.0, 4.0)]
%result = "stablehlo.real"(%operand) : (tensor<2xcomplex<f32>>) -> tensor<2xf32>
// %result: [1.0, 3.0]
recv
Anlam bilimi
channel_id
içeren bir kanaldan veri alır ve results
oluşturur.
is_host_transfer
true
ise işlem, verileri ana makineden aktarır. Aksi takdirde, başka bir cihazdan veri aktarır. Yani uygulamaya bağlıdır. Bu işaret, channel_type
içinde sağlanan bilgileri yinelediği için gelecekte bunlardan yalnızca birini tutmayı planlıyoruz
(#666).
results
, önce gelen yük değerleri ve en son gelen bir jetondan oluşur. Gelecekte yükü ve jetonu iki ayrı çıkışa bölerek daha anlaşılır hale getirmeyi planlıyoruz (#670).
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | token |
token |
(C4) |
(I2) | channel_id |
si64 türündeki sabit |
|
(I3) | channel_type |
DEVICE_TO_DEVICE ve HOST_TO_DEVICE türetilmiş liste |
(C1) |
(I4) | is_host_transfer |
i1 türündeki sabit |
(C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
results |
değişken sayıda tenör, kesirli tenör veya jeton | (C2-C4) |
Sınırlamalar
- (C1)
channel_type
şu şekilde tanımlanır:is_host_transfer = true
iseHOST_TO_DEVICE
,- Aksi takdirde
DEVICE_TO_DEVICE
değerini alır.
- (C2)
0 < size(results)
. - (C3)
is_empty(result[:-1])
veyais_tensor(type(results[:-1]))
. - (C4)
is_token(type(results[-1]))
.
Örnekler
%results0, %results1 = "stablehlo.recv"(%token) {
channel_handle = #stablehlo.channel_handle<handle = 1, type = 3>,
is_host_transfer = true
} : (!stablehlo.token) -> (tensor<2x2xi64>, !stablehlo.token)
reduce
Anlam bilimi
dimensions
boyunca inputs
ve init_values
'ye bir azaltma işlevi body
uygular ve results
tenzorları oluşturur.
İndirimlerin sırası uygulama tanımlıdır. Diğer bir deyişle, işlemin tüm uygulamalarda tüm girişler için aynı sonuçları vermesini garanti etmek üzere body
ve init_values
bir monoid oluşturmalıdır. Ancak bu durum, birçok popüler indirim için geçerli değildir. Örneğin, body
için kayan nokta toplama ve init_values
için sıfır, kayan nokta toplama ilişkili olmadığından aslında bir monoid oluşturmaz.
Daha resmi bir ifadeyle, results...[j0, ..., jR-1] = reduce(input_slices_converted)
burada:
input_slices = inputs...[j0, ..., :, ..., jR-1]
,:
dimensions
yerine eklenir.input_slices_converted = to_destination_type(input_slices..., type(func_inputs(body)[:len(func_inputs(body))//2])...)
.init_values_converted = to_destination_type(init_values..., type(func_inputs(body)[len(func_inputs(body))//2:])...)
.- Bazı ikili ağaç türleri için
reduce(input_slices_converted) = exec(schedule)
schedule
burada:exec(node) = body(exec(node.left), exec(node.right))
.exec(leaf) = leaf.value
.
schedule
, sıralı traversal'ı aşağıdakilerden oluşan, uygulama tanımlı bir tam ikili ağaçtır:index
değerleri,index_space(input_slices_converted)
'deki tümindex
içinindex
'ün artan sözlük sıralamasına göre.input_slices_converted...[index]
- Uygulamada tanımlanan konumlarda uygulamada tanımlanan miktarda
init_values_converted
ile birlikte kullanılır.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | inputs |
değişken sayıda tenör veya tenör başına kesikli tenörler | (C1-C4), (C6), (C7) |
(I2) | init_values |
0 boyutlu tensörlerin veya tensör başına miktarlandırılmış tensörlerin değişken sayısı | (C2), (C3) |
(I3) | dimensions |
si64 türündeki 1 boyutlu tensör sabiti |
(C4), (C5), (C7) |
(I4) | body |
işlev | (C6) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
results |
değişken sayıda tenör veya tenör başına kesikli tenörler | (C3), (C7), (C8) |
Sınırlamalar
- (C1)
same(shape(inputs...))
. - (C2)
element_type(inputs...) = element_type(init_values...)
. - (C3)
0 < size(inputs) = size(init_values) = size(results) = N
. - (C4)
0 <= dimensions < rank(inputs[0])
. - (C5)
is_unique(dimensions)
. - (C6)
body
,(tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ...,
türündedirtensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>)
veis_promotable(element_type(inputs[i]), Ei)
. - (C7)
dimensions
'ye karşılık geleninputs...
boyutlarının dahil edilmemesi dışındashape(results...) = shape(inputs...)
. - (C8)
[0,N)
içindeki tümi
içinelement_type(results[i]) = Ei
.
Örnekler
// %input = [[0, 1, 2, 3, 4, 5]]
// %init_value = 0
%result = "stablehlo.reduce"(%input, %init_value) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
"stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
dimensions = array<i64: 1>
} : (tensor<1x6xi64>, tensor<i64>) -> tensor<1xi64>
// %result = [15]
reduce_precision
Anlam
operand
öğesini, exponent_bits
ve mantissa_bits
kullanan başka bir kayan nokta türüne ve orijinal kayan nokta türüne geri dönüştürür ve bir output
tenzoru oluşturur.
Daha resmi bir dille:
- Orijinal değerin mantisa bitleri, orijinal değeri
roundToIntegralTiesToEven
semantiği kullanılarakmantissa_bits
ile temsil edilebilen en yakın değere yuvarlayacak şekilde güncellenir. - Daha sonra,
mantissa_bits
, orijinal değerin mantis bit sayısından küçükse mantissa bitlerimantissa_bits
olacak şekilde kısaltılır. - Ardından, ara sonucun üssünün bitleri
exponent_bits
tarafından sağlanan aralığa sığmazsa ara sonuç, orijinal işareti kullanarak sonsuzluk değerine taşma veya orijinal işareti kullanarak sıfır değerine alt taşma yapar. - Miktarı ölçülmüş türlerde,
dequantize_op_quantize( lambda operand: reduce_precision(operand, exponent_bits, mantissa_bits), operand, type(result))
gerçekleştirir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
Kayan nokta türündeki veya tensör başına kesirli tensör | (C1) |
(I2) | exponent_bits |
si32 türünün sabiti |
(C2) |
(I3) | mantissa_bits |
si32 türünün sabiti |
(C3) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
output |
kayan nokta türünde veya tensör başına miktarlandırılmış tensörün tensörü | (C1) |
Sınırlamalar
- (C1)
baseline_type(operand) = baseline_type(output)
. - (C2)
1 <= exponent_bits
. - (C3)
0 <= mantissa_bits
.
Örnekler
// Logical values: +Inf, NaN, +Denormal, 0.0, 65519.0, 65520.0
// %operand: [0x7FF0000000000000, 0x7FFFFFFFFFFFFFFF, 0x0000000000000001, 0.0, 65519.0, 65520.0]
%output = "stablehlo.reduce_precision"(%operand) {
exponent_bits = 5 : i32,
mantissa_bits = 10 : i32
} : (tensor<6xf64>) -> tensor<6xf64>
// Logical values: +Inf, NaN, 0.0, 0.0, 65504.0, +Inf
// %output: [0x7FF0000000000000, 0x7FFFFFFFFFFFFFFF, 0.0, 0.0, 65504.0, 0x7FF0000000000000]
reduce_scatter
Anlam bilimi
StableHLO işlem ızgarasındaki her işlem grubunda, her işlemden gelen operand
tensörünün değerleri üzerinde computations
kullanarak azaltma işlemi gerçekleştirir, azaltma sonucunu scatter_dimension
boyunca parçalara ayırır ve result
oluşturmak için bölünmüş parçaları işlemler arasında dağıtır.
İşlem, StableHLO süreç ızgarasını şu şekilde tanımlanan process_groups
şeklinde ayırır:
cross_replica(replica_groups)
channel_id <= 0 and use_global_device_ids = false
ise.channel_id > 0 and use_global_device_ids = false
isecross_replica_and_partition(replica_groups)
.flattened_ids(replica_groups)
channel_id > 0 and use_global_device_ids = true
ise.
Daha sonra, her process_group
içinde:
reduced_value = all_reduce(operand, replica_groups, channel_id, use_global_device_ids, computation)
.parts@sender = split(reduced_value@sender, dim(process_groups, 1), scatter_dimension)
.process_group
'dereceiver_index = process_group.index(receiver)
olan tümsender
içinresult@receiver = parts@sender[receiver_index]
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
tensor veya tensor başına kesikli tensor | (C1), (C2), (C7), (C8) |
(I2) | scatter_dimension |
si64 türündeki sabit |
(C1), (C2), (C8) |
(I3) | replica_groups |
si64 türündeki 2 boyutlu tensör sabit |
(C3-C5) |
(I4) | channel_id |
si64 türündeki sabit |
(C6) |
(I5) | use_global_device_ids |
i1 türündeki sabit |
(C6) |
(I6) | computation |
işlev | (C7) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensor veya tensor başına kesikli tensor | (C8-C9) |
Sınırlamalar
- (C1)
dim(operand, scatter_dimension) % dim(process_groups, 1) = 0
. - (C2)
0 <= scatter_dimension < rank(operand)
. - (C3)
is_unique(replica_groups)
. - (C4)
size(replica_groups)
şu şekilde tanımlanır:cross_replica
kullanılıyorsanum_replicas
.cross_replica_and_partition
kullanılıyorsanum_replicas
.flattened_ids
kullanılıyorsanum_processes
.
- (C5)
0 <= replica_groups < size(replica_groups)
- (C6)
use_global_device_ids = true
isechannel_id > 0
. - (C7)
computation
,is_promotable(element_type(operand), E)
olduğunda(tensor<E>, tensor<E>) -> (tensor<E>)
türüne sahiptir. - (C8)
shape(result) = shape(operand)
hariç:dim(result, scatter_dimension) = dim(operand, scatter_dimension) / dim(process_groups, 1)
.
- (C9)
element_type(result) = E
.
Örnekler
// num_replicas: 2
// num_partitions: 1
// %operand@(0, 0): [[1, 2, 3, 4],
// [5, 6, 7, 8]]
// %operand@(1, 0): [[9, 10, 11, 12],
// [13, 14, 15, 16]]
%result = "stablehlo.reduce_scatter"(%operand) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
"stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
scatter_dimension = 1 : i64,
replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>,
channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
} : (tensor<2x4xi64>) -> tensor<2x2xi64>
//
// %result@(0, 0): [[10, 12],
// [18, 20]]
// %result@(1, 0): [[14, 16],
// [22, 24]]
reduce_window
Anlam bilimi
inputs
ve init_values
pencerelerine bir azaltma işlevi body
uygular ve results
değerini döndürür.
Aşağıdaki şemada, somut bir örnek kullanılarak results...
içindeki öğelerin inputs...
parametresinden nasıl hesaplandığı gösterilmektedir.
Daha resmi bir şekilde,
results...[result_index] = reduce(windows, init_values, axes(inputs...), body)
(reduce işlevine bakın) şu geçerlidir:
padded_inputs = pad(inputs..., init_values..., padding[:, 0], padding[:, 1], base_dilations - 1)
.window_start = result_index * window_strides
.window_end = window_start + (window_dimensions - 1) * window_dilations + 1
.windows = slice(padded_inputs..., window_start, window_end, window_dilations)
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | inputs |
değişken sayıda tensör veya tensör başına miktarlandırılmış tensör | (C1-C4), (C6), (C8), (C10), (C12), (C13), (C15) |
(I2) | init_values |
0 boyutlu tensörlerin veya tensör başına kesikli tensörlerin değişken sayısı | (C1), (C13) |
(I3) | window_dimensions |
si64 türünde 1 boyutlu tensör sabiti |
(C4), (C5), (C15) |
(I4) | window_strides |
si64 türündeki 1 boyutlu tensör sabiti |
(C6), (C7), (C15) |
(I5) | base_dilations |
si64 türündeki 1 boyutlu tensör sabiti |
(C8), (C9), (C15) |
(I6) | window_dilations |
si64 türündeki 1 boyutlu tensör sabiti |
(C10), (C11), (C15) |
(I7) | padding |
si64 türünde 2 boyutlu tensör sabiti |
(C12), (C15) |
(I8) | body |
işlev | (C13) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
results |
değişken sayıda tenör veya tenör başına kesikli tenörler | (C1), (C14-C16) |
Sınırlamalar
- (C1)
0 < size(inputs) = size(init_values) = size(results) = N
. - (C2)
same(shape(inputs...))
. - (C3)
element_type(inputs...) = element_type(init_values...)
. - (C4)
size(window_dimensions) = rank(inputs[0])
- (C5)
0 < window_dimensions
. - (C6)
size(window_strides) = rank(inputs[0])
. - (C7)
0 < window_strides
. - (C8)
size(base_dilations) = rank(inputs[0])
. - (C9)
0 < base_dilations
. - (C10)
size(window_dilations) = rank(inputs[0])
. - (C11)
0 < window_dilations
. - (C12)
shape(padding) = [rank(inputs[0]), 2]
. - (C13)
body
,(tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ...,
türündedirtensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>)
veis_promotable(element_type(inputs[i]), Ei)
. - (C14)
same(shape(results...))
- (C15)
shape(results[0]) = num_windows
burada:dilated_input_shape = shape(inputs[0]) = 0 ? 0 : (shape(inputs[0]) - 1) * base_dilations + 1
.padded_input_shape = padding[:, 0] + dilated_input_shape + padding[:, 1]
.dilated_window_shape = (window_dimensions - 1) * window_dilations + 1
.is_empty_window = padded_input_shape = 0 || dilated_window_shape > padded_input_shape
.num_windows = is_empty_window ? 0 : floor((padded_input_shape - dilated_window_shape) / window_strides) + 1
.
- (C16)
[0,N)
kapsamındaki tümi
iç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
lhs
bölen ve bölen rhs
tensörlerinin öğe bazında geri kalanını gerçekleştirir ve bir result
tensörü oluşturur.
Daha resmi bir ifadeyle, sonucun işareti paydan alınır ve sonucun mutlak değeri her zaman bölenin mutlak değerinden azdır.
Kalan değer lhs - d * rhs
olarak hesaplanır. Burada d
değeri şu şekilde bulunur:
- Tam sayılar için:
stablehlo.divide(lhs, rhs)
. - Kayan reklamlar için: IEEE-754'ten, yuvarlama özelliğiyle
division(lhs, rhs)
roundTowardZero
. - Karmaşık sayılar için: TBD (#997).
- Kesirli türler için:
dequantize_op_quantize(remainder, lhs, rhs, type(result))
.
Kayan nokta öğe türlerinde bu işlem, IEEE-754 spesifikasyonundaki remainder
işleminin tersidir. Burada d
, eşit ile bağlantılı olan lhs/rhs
tam değerine en yakın integral değerdir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | lhs |
tam sayı, kayan nokta veya karmaşık tür ya da tensör başına miktarlandırılmış tensör tensörü | (C1) |
(I2) | rhs |
tam sayı, kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tam sayı, kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Sınırlamalar
- (C1)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// %lhs: [17, -17, 17, -17]
// %rhs: [3, 3, -3, -3]
%result = "stablehlo.remainder"(%lhs, %rhs) : (tensor<4xi64>, tensor<4xi64>) -> tensor<4xi64>
// %result: [2, -2, 2, -2]
replica_id
Anlam bilimi
Mevcut işlemin replica_id
'ünü oluşturur.
Çıkışlar
Ad | Tür |
---|---|
result |
ui32 türündeki 0 boyutlu tensör |
Örnekler
%result = "stablehlo.replica_id"() : () -> tensor<ui32>
yeniden şekillendirme
Anlam bilimi
operand
tenörünü result
tenörüne yeniden şekillendirir. Kavramsal olarak bu, aynı standart gösterimin korunması ancak şeklin potansiyel olarak değiştirilmesi (ör. tensor<2x3xf32>
yerine tensor<3x2xf32>
veya tensor<6xf32>
) anlamına gelir.
Daha resmi bir ifadeyle, result_index
ve operand_index
'nin index_space(result)
ve index_space(operand)
'in alfabetik sıralamasında aynı konuma sahip olduğu result[result_index] = operand[operand_index]
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
tenzor veya kesirli tenzor | (C1-C3) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tenzor veya kesirli tenzor | (C1-C3) |
Sınırlamalar
- (C1)
element_type(result)
şu şekilde hesaplanır:!is_per_axis_quantized(operand)
iseelement_type(operand)
.element_type(operand)
, ancakquantization_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]]
geri al
Anlam bilimi
Belirtilen dimensions
boyunca operand
'teki öğelerin sırasını tersine çevirir ve bir result
tensörü oluşturur. Daha resmi bir ifadeyle,
result[result_index] = operand[operand_index]
burada:
dimensions
konumundad
iseoperand_index[d] = dim(result, d) - result_index[d] - 1
- Aksi takdirde
operand_index[d] = result_index[d]
değerini alır.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
tensör veya tensör başına miktarlandırılmış tensör | (C1), (C3) |
(I2) | dimensions |
si64 türündeki 1 boyutlu tensör sabiti |
(C2), (C3) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensor veya tensor başına kesikli tensor | (C1), (C3) |
Sınırlamalar
- (C1)
type(operand) = type(result)
. - (C2)
is_unique(dimensions)
. - (C3)
0 <= dimensions < rank(result)
.
Örnekler
// %operand = [[1, 2], [3, 4], [5, 6]]
%result = "stablehlo.reverse"(%operand) {
dimensions = array<i64: 1>
} : (tensor<3x2xi32>) -> tensor<3x2xi32>
// %result: [[2, 1], [4, 3], [6, 5]]
rng
Anlam
rng_distribution
algoritmasını kullanarak rastgele sayılar oluşturur ve belirli bir shape
şeklindeki result
tensörünü üretir.
rng_distribution = UNIFORM
ise [a, b)
aralığı üzerindeki tek tip dağılım uygulanarak rastgele sayılar oluşturulur. a >= b
ise davranış tanımlanmamıştır.
rng_distribution = NORMAL
ise rastgele sayılar, ortalama = a
ve standart sapma = b
olan normal dağılımı izleyerek oluşturulur.
b < 0
ise davranış tanımlanmamıştır.
Rastgele sayıların tam olarak nasıl oluşturulduğu, uygulama tarafından tanımlanır. Örneğin, bu modeller deterministik olabilir veya olmayabilir ve gizli durum kullanabilir veya kullanmayabilir.
Pek çok paydaşla yaptığımız görüşmelerde bu operasyon, oldukça etkili bir şekilde kullanımdan kaldırıldı. Bu nedenle gelecekte bu seçeneği kaldırmayı planlıyoruz (#597).
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | a |
Tam sayı, boole veya kayan nokta türündeki 0 boyutlu tensör | (C1), (C2) |
(I2) | b |
Tam sayı, boole veya kayan nokta türündeki 0 boyutlu tensör | (C1), (C2) |
(I3) | shape |
si64 türünde 1 boyutlu tensör sabiti |
(C3) |
(I4) | rng_distribution |
UNIFORM ve NORMAL türetilmiş liste |
(C2) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tam sayı, boole veya kayan nokta türündeki tenör | (C1-C3) |
Sınırlamalar
- (C1)
element_type(a) = element_type(b) = element_type(result)
. - (C2)
rng_distribution = NORMAL
iseis_float(a)
. - (C3)
shape(result) = shape
.
Örnekler
// %a = 0
// %b = 2
// %shape = [3, 3]
%result = "stablehlo.rng"(%a, %b, %shape) {
rng_distribution = #stablehlo<rng_distribution UNIFORM>
} : (tensor<i32>, tensor<i32>, tensor<2xi64>) -> tensor<3x3xi32>
// %result: [
// [1, 0, 1],
// [1, 1, 1],
// [0, 0, 0]
// ]
rng_bit_generator
Anlam bilimi
Başlangıç durumu initial_state
verildiğinde, rng_algorithm
sözde rastgele sayı oluşturucu algoritmasını kullanarak tekdüze rastgele bitlerle dolu bir output
ve güncellenmiş bir çıkış durumu output_state
döndürür. Sonucun initial_state
öğesinin deterministik işlevi olacağı garanti edilir ancak uygulamalar arasında deterministik olacağı garanti edilmez.
rng_algorithm
aşağıdakilerden biridir:
DEFAULT
: Uygulama tanımlı algoritma.THREE_FRY
: Threefry algoritmasının uygulama tanımlı varyantı.*PHILOX
: Philox algoritmasının uygulama tanımlı varyantı.*
* Bkz. Salmon ve diğerleri SC 2011. Paralel rastgele sayılar: 1, 2, 3 kadar kolay.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | rng_algorithm |
DEFAULT , THREE_FRY ve PHILOX değerlerini içeren bir enum |
(C2) |
(I2) | initial_state |
ui64 türündeki 1 boyutlu tensör |
(C1), (C2) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
output_state |
ui64 türündeki 1 boyutlu tensör |
(C1) |
output |
tam sayı veya kayan nokta türünde tensör |
Sınırlamalar
- (C1)
type(initial_state) = type(output_state)
. - (C2)
size(initial_state)
şu şekilde tanımlanır:rng_algorithm = DEFAULT
durumunda uygulama tanımlanır.rng_algorithm = THREE_FRY
ise2
.rng_algorithm = PHILOX
ise2
veya3
.
Örnekler
// %initial_state: [1, 2]
%output_state, %output = "stablehlo.rng_bit_generator"(%initial_state) {
rng_algorithm = #stablehlo<rng_algorithm THREE_FRY>
} : (tensor<2xui64>) -> (tensor<2xui64>, tensor<2x2xui64>)
// %output_state: [1, 6]
// %output: [
// [9236835810183407956, 16087790271692313299],
// [18212823393184779219, 2658481902456610144]
// ]
round_nearest_afz
Anlam bilimi
operand
tensöründe, sıfırdan farklı olan eşit değerleri sıfırdan farklı bir değere atayarak öğe bazında en yakın tam sayıya yuvarlama işlemi gerçekleştirir ve bir result
tensörü oluşturur. IEEE-754 spesifikasyonundaki roundToIntegralTiesToAway
işlemini uygular. Kesirli türler için dequantize_op_quantize(round_nearest_afz, operand, type(result))
işlemini gerçekleştirir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
Kayan nokta türündeki veya tensör başına kesirli tensör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta türünde veya tensör başına miktarlandırılmış tensörün tensörü | (C1) |
Sınırlamalar
- (C1)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// %operand = [-2.5, 0.4, 0.5, 0.6, 2.5]
%result = "stablehlo.round_nearest_afz"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// %result: [-3.0, 0.0, 1.0, 1.0, 3.0]
round_nearest_even
Anlam
operand
tenzorunda, en yakın tam sayıya doğru öğe bazında yuvarlama yapar ve eşitlik durumunda çift sayıya doğru yuvarlama yapar. Ardından result
tenzoru oluşturur. IEEE-754 spesifikasyonundaki roundToIntegralTiesToEven
işlemini uygular. Miktarı belirlenmiş türler için dequantize_op_quantize(round_nearest_even, operand, type(result))
işlemini gerçekleştirir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
Kayan nokta türündeki veya tensör başına kesirli tensör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta türünde veya tensör başına miktarlandırılmış tensörün tensörü | (C1) |
Sınırlamalar
- (C1)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// %operand = [-2.5, 0.4, 0.5, 0.6, 2.5]
%result = "stablehlo.round_nearest_even"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// %result: [-2.0, 0.0, 0.0, 1.0, 2.0]
rsqrt
Anlam
operand
tensörü üzerinde element düzeyinde ters karekök işlemi gerçekleştirir ve bir result
tensörü üretir. Öğe türüne bağlı olarak aşağıdakiler gerçekleşir:
- Kayan reklamlar için: IEEE-754'ten
rSqrt
. - Karmaşık sayılar için: karmaşık ters karekökü.
- Kesirli türler için:
dequantize_op_quantize(rsqrt, operand, type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Sınırlamalar
- (C1)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// %operand: [[1.0, 4.0], [9.0, 25.0]]
%result = "stablehlo.rsqrt"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[1.0, 0.5], [0.33333343, 0.2]]
dağılım
Anlam bilimi
scatter_indices
tarafından belirtilen birkaç dilimin update_computation
kullanılarak updates
değerleriyle güncellenmesi dışında inputs
tenörlerine eşit results
tenörleri oluşturur.
Aşağıdaki şemada, updates...
öğelerinin results...
öğeleriyle nasıl eşlendiği somut bir örnekle gösterilmektedir. Diyagramda birkaç örnek updates...
dizini seçilir ve bu dizinlerin hangi results...
dizinlerine karşılık geldiği ayrıntılı olarak açıklanır.
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_index
içindeki bağımsız öğelerdir ve:
,index_vector_dim
<rank(scatter_indices)
iseindex_vector_dim
dizinine eklenir.- Aksi takdirde
[scatter_indices[update_scatter_index]]
.
axes(inputs[0])
içinded_input
içinfull_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
değerini alır.
axes(inputs[0])
içinded_input
içinfull_batching_index[d_input] = update_scatter_index[d_start - (d_start < index_vector_dim ? 0 : 1)]
d_input = input_batching_dims[i_batching]
ved_start = scatter_indices_batching_dims[i_batching]
ise.- Aksi takdirde
full_batching_index[d_input] = 0
değerini alır.
update_window_index = update_index[update_window_dims...]
.full_window_index = [wi0, ..., 0, ..., wiN]
; buradawi
,update_window_index
içindeki bağımsız öğelerdir ve0
,inserted_window_dims
ileinput_batching_dims
arasındaki dizinlere eklenir.result_index = full_start_index + full_batching_index + full_window_index
.
Bu durumda results = exec(schedule, inputs)
, şu şekilde tanımlanır:
schedule
,index_space(updates[0])
öğesinin uygulama tanımlı bir permütasyonudur.exec([update_index, ...], results) = exec([...], updated_results)
where:result_index
,shape(results...)
için sınırların iç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]
updated_values...
olarak ayarlanmışresults
'un bir kopyasıdır.- Aksi halde
updated_results = results
.
exec([], results) = results
.
indices_are_sorted
değeri true
ise uygulama, scatter_indices
öğesinin scatter_dims_to_operand_dims
ile göreceli olarak sıralandığını varsayabilir. Aksi takdirde davranış tanımlanmamış olur. Daha resmi bir ifadeyle, indices(result)
kaynağından gelen tüm i1 < i2
için
full_start_index(i1)
<= full_start_index(i2)
.
unique_indices
true
ise uygulama, dağıtılan tüm result_index
dizinlerinin benzersiz olduğunu varsayabilir. unique_indices
değeri true
ise ancak dağıtılan dizinler benzersiz değilse davranış tanımsızdır.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | inputs |
değişken sayıda tenör veya tenör başına kesikli tenörler | (C1), (C2), (C4-C6), (C11), (C13), (C18), (C21), (C23-C24) |
(I2) | scatter_indices |
tam sayı türündeki tensör | (C4), (C15), (C19), (C22) |
(I3) | updates |
değişken sayıda tensör veya tensör başına miktarlandırılmış tensör | (C3-C6), (C8) |
(I4) | update_window_dims |
si64 türündeki 1 boyutlu tensör sabiti |
(C2), (C4), (C7-C8) |
(I5) | inserted_window_dims |
si64 türünde 1 boyutlu tensör sabiti |
(C2), (C4), (C9-C11) |
(I6) | input_batching_dims |
si64 türündeki 1 boyutlu tensör sabiti |
(C2), (C4), (C9), (C12-13), (C17-18), (C20) |
(I7) | scatter_indices_batching_dims |
si64 türündeki 1 boyutlu tensör sabiti |
(C14-C18) |
(I8) | scatter_dims_to_operand_dims |
si64 türündeki 1 boyutlu tensör sabiti |
(C19-C21) |
(I9) | index_vector_dim |
si64 türündeki sabit |
(C4), (C16), (C19), (C22) |
(I10) | indices_are_sorted |
i1 türündeki sabit |
|
(I11) | unique_indices |
i1 türündeki sabit |
|
(I12) | update_computation |
işlev | (C23) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
results |
değişken sayıda tensör veya tensör başına miktarlandırılmış tensör | (C24-C25) |
Sınırlamalar
- (C1)
same(shape(inputs...))
. - (C2) `rank(inputs[0]) = boyut(update_window_dims) + boyut(inserted_window_dims)
- size(input_batching_dims)`.
- (C3)
same(shape(updates...))
. - (C4)
shape(updates[0]) = combine(update_scatter_dim_sizes, update_window_dim_sizes)
; burada:update_scatter_dim_sizes = shape(scatter_indices)
dışındaindex_vector_dim
'e karşılık gelenscatter_indices
boyut boyutu dahil edilmemiştir.update_window_dim_sizes <= shape(inputs[0])
, ancakinputs[0]
'dakiinserted_window_dims
veinput_batching_dims
'a karşılık gelen boyut boyutları dahil edilmez.combine
,update_scatter_dim_sizes
öğesiniupdate_window_dims
öğesine karşılık gelen eksenlereupdate_scatter_dims
veupdate_window_dim_sizes
karşılık gelen eksenlere yerleştirir.
- (C5)
0 < size(inputs) = size(updates) = N
- (C6)
element_type(updates...) = element_type(inputs...)
. - (C7)
is_unique(update_window_dims) and is_sorted(update_window_dims)
. - (C8)
0 <= update_window_dims < rank(updates[0])
- (C9)
is_unique(concatenate(inserted_window_dims, input_batching_dims))
- (C10)
is_sorted(inserted_window_dims)
. - (C11)
0 <= inserted_window_dims < rank(inputs[0])
. - (C12)
is_sorted(input_batching_dims)
. - (C13)
0 <= input_batching_dims < rank(inputs[0]))
- (C14)
is_unique(scatter_indices_batching_dims)
. - (C15)
0 <= scatter_indices_batching_dims < rank(scatter_indices)
. - (C16)
index_vector_dim not in scatter_indices_batching_dims
. - (C17)
size(input_batching_dims) == size(scatter_indices_batching_dims)
- (C18)
dim(inputs[0], input_batching_dims...) = dim(scatter_indices, scatter_indices_batching_dims...)
. - (C19)
size(scatter_dims_to_operand_dims) = index_vector_dim < rank(scatter_indices) ? dim(scatter_indices, index_vector_dim) : 1
. - (C20)
is_unique(concatenate(scatter_dims_to_operand_dims, input_batching_dims))
. - (C21)
0 <= scatter_dims_to_operand_dims < rank(inputs[0])
. - (C22)
0 <= index_vector_dim <= rank(scatter_indices)
. - (C23)
update_computation
,is_promotable(element_type(inputs[i]), Ei)
olduğunda(tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ..., tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>)
türündedir. - (C24)
shape(inputs...) = shape(results...)
. - (C25)
[0,N)
içindeki tümi
içinelement_type(results[i]) = Ei
.
Örnekler
// %input: [
// [
// [[1, 2], [3, 4], [5, 6], [7, 8]],
// [[9, 10],[11, 12], [13, 14], [15, 16]],
// [[17, 18], [19, 20], [21, 22], [23, 24]]
// ],
// [
// [[25, 26], [27, 28], [29, 30], [31, 32]],
// [[33, 34], [35, 36], [37, 38], [39, 40]],
// [[41, 42], [43, 44], [45, 46], [47, 48]]
// ]
// ]
// %scatter_indices: [
// [
// [[0, 0], [1, 0], [2, 1]],
// [[0, 1], [1, 1], [0, 9]]
// ],
// [
// [[0, 0], [2, 1], [2, 2]],
// [[1, 2], [0, 1], [1, 0]]
// ]
// ]
// %update: [
// [
// [[1, 1], [1, 1], [1, 1]],
// [[1, 1], [1, 1], [1, 1]]
// ],
// [
// [[1, 1], [1, 1], [1, 1]],
// [[1, 1], [1, 1], [1, 1]]
// ]
// ]
%result = "stablehlo.scatter"(%input, %scatter_indices, %update) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
"stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
scatter_dimension_numbers = #stablehlo.scatter<
update_window_dims = [3, 4],
inserted_window_dims = [1],
input_batching_dims = [0],
scatter_indices_batching_dims = [1],
scatter_dims_to_operand_dims = [2, 1],
index_vector_dim = 3>,
indices_are_sorted = false,
unique_indices = false
} : (tensor<2x3x4x2xi64>, tensor<2x2x3x2xi64>, tensor<2x2x3x2x2xi64>) -> tensor<2x3x4x2xi64>
// %result: [
// [
// [[3, 4], [6, 7], [6, 7], [7, 8]],
// [[9, 10],[11, 12], [15, 16], [17, 18]],
// [[17, 18], [19, 20], [22, 23], [24, 25]]
// ],
// [
// [[25, 26], [28, 29], [30, 31], [31, 32]],
// [[35, 36], [38, 39], [38, 39], [39, 40]],
// [[41, 42], [44, 45], [46, 47], [47, 48]]
// ]
// ]
seç
Anlam bilimi
Her bir öğenin pred
'daki ilgili öğenin değerine göre on_true
veya on_false
tenzorundan seçildiği bir result
tenzoru oluşturur.
Daha resmi olarak, result[result_index] = pred_element ? on_true[result_index] :
on_false[result_index]
(pred_element = rank(pred) = 0 ? pred[] :
pred[result_index]
). Miktarı ölçülmüş türlerde, dequantize_select_quantize(pred, on_true, on_false, type(result))
gerçekleştirir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | pred |
i1 türündeki tensör |
(C1) |
(I2) | on_true |
tensor veya tensor başına kesikli tensor | (C1-C2) |
(I3) | on_false |
tensör veya tensör başına miktarlandırılmış tensör | (C2) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensor veya tensor başına kesikli tensor | (C2) |
Sınırlamalar
- (C1)
rank(pred) = 0 or shape(pred) = shape(on_true)
. - (C2)
baseline_type(on_true) = baseline_type(on_false) = baseline_type(result)
.
Örnekler
// %pred: [[false, true], [true, false]]
// %on_true: [[1, 2], [3, 4]]
// %on_false: [[5, 6], [7, 8]]
%result = "stablehlo.select"(%pred, %on_true, %on_false) : (tensor<2x2xi1>, tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[5, 2], [3, 8]]
select_and_scatter
Anlam bilimi
select
kullanarak input
tensöründen reduce_window
sonucuna göre scatter
kullanarak source
tensöründen gelen değerleri dağıtır ve bir result
tensörü üretir.
Aşağıdaki şemada, result
öğelerinin operand
ve source
'den nasıl hesaplandığı somut bir örnekle gösterilmektedir.
Daha resmi bir dille:
selected_values = reduce_window_without_init(...)
aşağıdaki girişlerle:inputs = [operand].
window_dimensions
,window_strides
vepadding
, olduğu gibi kullanılır.base_dilations = windows_dilations = 1
.body
şu şekilde tanımlanır:
def body(arg0: tensor<E>, arg1: tensor<E>) -> tensor<E>: return select(arg0, arg1) ? arg0 : arg1;
Burada
E = element_type(operand)
vereduce_window_without_init
, temelreduce
'inschedule
(reduce bölümüne bakın) özelliğinin ilk değer içermemesi dışındareduce_window
gibi çalışır. İlgili pencerede değer yoksa ne olacağı şu anda belirtilmemiştir (#731).result[result_index] = reduce([source_values], [init_value], [0], scatter)
Burada:source_values = [source[source_index] for source_index in source_indices]
.selected_values[source_index]
,operand_index
kaynağındanoperand
öğesine sahipseselected_index(source_index) = operand_index
.source_indices = [source_index for source_index in indices(source) if selected_index(source_index) = result_index]
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
tensor veya tensor başına kesikli tensor | (C1-C4), (C6), (C8-C11) |
(I2) | source |
tensör veya tensör başına miktarlandırılmış tensör | (C1), (C2) |
(I3) | init_value |
0 boyutlu tensör veya tensör başına miktarlandırılmış tensör | (C3) |
(I4) | window_dimensions |
si64 türündeki 1 boyutlu tensör sabiti |
(C2), (C4), (C5) |
(I5) | window_strides |
si64 türündeki 1 boyutlu tensör sabiti |
(C2), (C6), (C7) |
(I6) | padding |
si64 türündeki 2 boyutlu tensör sabit |
(C2), (C8) |
(I7) | select |
işlev | (C9) |
(I8) | scatter |
işlev | (C10) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensor veya tensor başına kesikli tensor | (C11-C12) |
Sınırlamalar
- (C1)
element_type(operand) = element_type(source)
. - (C2)
shape(source) = num_windows
burada:padded_operand_shape = padding[:, 0] + shape(operand) + padding[:, 1]
.is_empty_window = padded_operand_shape = 0 || window_dimensions > padded_operand_shape
.num_windows = is_empty_window ? 0 : floor((padded_operand_shape - window_dimensions) / window_strides) + 1
.
- (C3)
element_type(init_value) = element_type(operand)
. - (C4)
size(window_dimensions) = rank(operand)
. - (C5)
0 < window_dimensions
. - (C6)
size(window_strides) = rank(operand)
. - (C7)
0 < window_strides
. - (C8)
shape(padding) = [rank(operand), 2]
. - (C9)
select
,E = element_type(operand)
olduğunda(tensor<E>, tensor<E>) -> tensor<i1>
türüne sahiptir. - (C10)
scatter
,is_promotable(element_type(operand), E)
olduğunda(tensor<E>, tensor<E>) -> tensor<E>
türüne sahiptir. - (C11)
shape(operand) = shape(result)
. - (C12)
element_type(result) = E
Örnekler
// %operand: [[1, 5], [2, 5], [3, 6], [4, 4]]
// %source: [[5, 6], [7, 8]]
// %init_value: 0
%result = "stablehlo.select_and_scatter"(%operand, %source, %init_value) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = "stablehlo.compare"(%arg0, %arg1) {
comparison_direction = #stablehlo<comparison_direction GE>
} : (tensor<i64>, tensor<i64>) -> tensor<i1>
"stablehlo.return"(%0) : (tensor<i1>) -> ()
}, {
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
"stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
window_dimensions = array<i64: 3, 1>,
window_strides = array<i64: 2, 1>,
padding = dense<[[0, 1], [0, 0]]> : tensor<2x2xi64>
} : (tensor<4x2xi64>, tensor<2x2xi64>, tensor<i64>) -> tensor<4x2xi64>
// %result: [[0, 0], [0, 0], [5, 14], [7, 0]]
gönder
Anlam bilimi
channel_id
kanalına inputs
gönderir ve result
jetonu oluşturur.
is_host_transfer
true
ise işlem, verileri ana makineye aktarır. Aksi takdirde veriler başka bir cihaza aktarılır. Bunun anlamı, uygulama tanımlıdır. Bu işaret, channel_type
alanında sağlanan bilgileri kopyalar. Bu nedenle, gelecekte bunlardan yalnızca birini (#666) kullanmayı planlıyoruz.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | inputs |
değişken sayıda tensör veya kesirli tensör | |
(I2) | token |
token |
|
(I3) | channel_id |
si64 türünün sabiti |
|
(I4) | channel_type |
DEVICE_TO_DEVICE ve DEVICE_TO_HOST türetilmiş liste |
(C1) |
(I5) | is_host_transfer |
i1 türündeki sabit |
(C1) |
Çıkışlar
Ad | Tür |
---|---|
result |
token |
Sınırlamalar
- (C1)
channel_type
şu şekilde tanımlanır:is_host_transfer = true
iseDEVICE_TO_HOST
,- Aksi takdirde
DEVICE_TO_DEVICE
değerini alır.
Örnekler
%result = "stablehlo.send"(%operand, %token) {
channel_handle = #stablehlo.channel_handle<handle = 1, type = 2>,
is_host_transfer = true
} : (tensor<2x2xi64>, !stablehlo.token) -> !stablehlo.token
shift_left
Anlam
lhs
tensörü üzerinde rhs
bit sayısı kadar öğe düzeyinde sol kayma işlemi gerçekleştirir ve bir result
tensörü üretir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | lhs |
tam sayı türündeki tensör | (C1) |
(I2) | rhs |
tam sayı türündeki tensör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tam sayı türündeki tensör | (C1) |
Sınırlamalar
- (C1)
type(lhs) = type(rhs) = type(result)
.
Örnekler
// %lhs: [-1, 0, 1]
// %rhs: [1, 2, 3]
%result = "stablehlo.shift_left"(%lhs, %rhs): (tensor<3xi64>, tensor<3xi64>) -> tensor<3xi64>
// %result: [-2, 0, 8]
shift_right_arithmetic
Anlam bilimi
lhs
tensöründe rhs
bit sayısı kadar öğe bazında aritmetik sağ kaydırma işlemi gerçekleştirir ve bir result
tensörü oluşturur.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | lhs |
tam sayı türündeki tensör | (C1) |
(I2) | rhs |
tam sayı türündeki tensör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tam sayı türündeki tensör | (C1) |
Sınırlamalar
- (C1)
type(lhs) = type(rhs) = type(result)
.
Örnekler
// %lhs: [-1, 0, 8]
// %rhs: [1, 2, 3]
%result = "stablehlo.shift_right_arithmetic"(%lhs, %rhs): (tensor<3xi64>, tensor<3xi64>) -> tensor<3xi64>
// %result: [-1, 0, 1]
shift_right_logical
Anlam bilimi
lhs
tensöründe rhs
bit sayısı kadar öğe bazında mantıksal sağ kaydırma işlemi gerçekleştirir ve bir result
tensörü oluşturur.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | lhs |
tam sayı türündeki tensör | (C1) |
(I2) | rhs |
tam sayı türündeki tensör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tam sayı türündeki tensör | (C1) |
Sınırlamalar
- (C1)
type(lhs) = type(rhs) = type(result)
.
Örnekler
// %lhs: [-1, 0, 8]
// %rhs: [1, 2, 3]
%result = "stablehlo.shift_right_logical"(%lhs, %rhs): (tensor<3xi64>, tensor<3xi64>) -> tensor<3xi64>
// %result: [9223372036854775807, 0, 1]
işaret
Anlam bilimi
operand
öğesinin işaretini döndürür ve bir result
tensörü oluşturur.
Daha resmi bir şekilde, her x
öğesi için anlamlar Python söz dizimi kullanılarak aşağıdaki gibi ifade edilebilir:
def sign(x):
if is_integer(x):
if compare(x, 0, LT, SIGNED): return -1
if compare(x, 0, EQ, SIGNED): return 0
return 1
elif is_float(x):
if is_nan(x): return NaN
if compare(x, -0.0, EQ, FLOAT): return -0.0
if compare(x, +0.0, EQ, FLOAT): return +0.0
if compare(x, 0.0, LT, FLOAT): return -1.0
return 1.0
elif is_complex(x):
if is_nan(real(x)) or is_nan(imag(x)): return (NaN, NaN)
if compare(x, (0.0, 0.0), EQ, FLOAT): return (0.0, 0.0)
return divide(x, convert(abs(x), type(x)))
Miktarı ölçülmüş türlerde, dequantize_op_quantize(sign, operand, type(result))
gerçekleştirir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
işaretli tam sayı, kayan nokta veya karmaşık tür ya da tensör başına miktarlandırılmış tensörün tensörü | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
işaretli tam sayı, kayan nokta veya karmaşık türde veya tensör başına kesirli tensör | (C1) |
Sınırlamalar
- (C1)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// Logical values: +NaN, -1.0, -0.0, +0.0, 1.0
// operand: [0x7FFFFFFFFFFFFFFF, -1.0, -0.0, 0.0, 1.0]
%result = "stablehlo.sign"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// Logical values: +NaN, -1.0, -0.0, +0.0, 1.0
// %result: [0x7FFFFFFFFFFFFFFF, -1.0, -0.0, 0.0, 1.0]
sinüs
Anlam
operand
tenzorunda öğe bazında sinüs işlemi gerçekleştirir ve bir result
tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:
- Kayan noktalı sayılar için: IEEE-754'ten
sin
. - Karmaşık sayılar için: karmaşık sinüs.
- Kesirli türler için:
dequantize_op_quantize(sine, operand, type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Sınırlamalar
- (C1)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// %operand: [
// [0.0, 1.57079632], // [0, pi/2]
// [3.14159265, 4.71238898] // [pi, 3pi/2]
// ]
%result = "stablehlo.sine"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[0.0, 1.0], [0.0, -1.0]]
slice
Anlam bilimi
Statik olarak hesaplanmış başlangıç dizinlerini kullanarak operand
öğesinden bir dilim çıkarır ve bir result
tensörü üretir. start_indices
, her boyut için dilimin başlangıç dizinlerini, limit_indices
her boyut için dilimin bitiş dizinlerini (hariç) ve strides
her boyut için adımlara sahiptir.
Daha resmi bir ifadeyle, result[result_index] = operand[operand_index]
where
operand_index = start_indices + result_index * strides
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
tensör veya tensör başına miktarlandırılmış tensör | (C1-C3); (C5) |
(I2) | start_indices |
si64 türünde 1 boyutlu tensör sabiti |
(C2), (C3), (C5) |
(I3) | limit_indices |
si64 türündeki 1 boyutlu tensör sabiti |
(C2), (C3), (C5) |
(I4) | strides |
si64 türündeki 1 boyutlu tensör sabiti |
(C2), (C4) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensor veya tensor başına kesikli tensor | (C1), (C5) |
Sınırlamalar
- (C1)
element_type(operand) = element_type(result)
. - (C2)
size(start_indices) = size(limit_indices) = size(strides) = rank(operand)
. - (C3)
0 <= start_indices <= limit_indices <= shape(operand)
. - (C4)
0 < strides
. - (C5)
shape(result) = ceil((limit_indices - start_indices) / strides)
.
Örnekler
// %operand: [
// [0, 0, 0, 0],
// [0, 0, 1, 1],
// [0, 0, 1, 1]
// ]
%result = "stablehlo.slice"(%operand) {
start_indices = array<i64: 1, 2>,
limit_indices = array<i64: 3, 4>,
strides = array<i64: 1, 1>
} : (tensor<3x4xi64>) -> tensor<2x2xi64>
// % result: [
// [1, 1],
// [1, 1]
// ]
sıralama
Anlam
inputs
'ün 1 boyutlu dilimlerini dimension
boyutu boyunca birlikte, bir comparator
'ye göre sıralar ve results
oluşturur.
Diğer işlemlerdeki benzer girişlerin aksine dimension
, aşağıda açıklanan semantikle birlikte negatif değerlere izin verir. Gelecekte tutarlılık nedeniyle buna izin verilmeyebilir (#1377).
is_stable
doğruysa sıralama kararlıdır. Yani karşılaştırıcı tarafından eşit kabul edilen öğelerin göreceli sırası korunur. Tek bir girişin olduğu durumda, iki öğe e1
ve e2
, karşılaştırıcı tarafından comparator(e1, e2) = comparator(e2, e1) = false
ise ve yalnızca bu durumda eşit olarak kabul edilir. Bunun birden çok girdiye nasıl genelleştiğini öğrenmek için aşağıdaki resmileştirmeye bakın.
Daha resmi bir ifadeyle, index_space(results[0])
içindeki tüm result_index
için:
adjusted_dimension = dimension >= 0 ? dimension : rank(inputs[0]) + dimension
.result_slice = [ri0, ..., :, ..., riR-1]
; buradariN
,result_index
'deki bağımsız öğelerdir ve:
,adjusted_dimension
'e eklenir.inputs_together = (inputs[0]..., ..., inputs[N-1]...)
.results_together[result_slice] = sort(inputs_together[result_slice], comparator_together)
.- Burada
sort
, 1 boyutlu bir dilimi azalan olmayan düzende sıralar.comparator_together
, sol taraftaki bağımsız değişken sağ taraftaki ikinci bağımsız değişkenden azsatrue
döndürür. def comparator_together(lhs_together, rhs_together): args = [] for (lhs_el, rhs_el) in zip(lhs_together, rhs_together): args.append(lhs_el) args.append(rhs_el) return comparator(*args)
(results[0]..., ..., results[N-1]...) = results_together
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | inputs |
değişken sayıda tenör veya tenör başına kesikli tenörler | (C1-C5) |
(I2) | dimension |
si64 türündeki sabit |
(C4) |
(I3) | is_stable |
i1 türündeki sabit |
|
(I4) | comparator |
işlev | (C5) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
results |
değişken sayıda tenör veya tenör başına kesikli tenörler | (C2), (C3) |
Sınırlamalar
- (C1)
0 < size(inputs)
. - (C2)
type(inputs...) = type(results...)
. - (C3)
same(shape(inputs...) + shape(results...))
. - (C4)
-R <= dimension < R
, buradaR = rank(inputs[0])
. - (C5)
comparator
,(tensor<E1>, tensor<E1>, ..., tensor<EN-1>, tensor<EN-1>) -> tensor<i1>
türünde (Ei = element_type(inputs[i])
).
Örnekler
// %input0 = [[1, 2, 3], [3, 2, 1]]
// %input1 = [[3, 2, 1], [1, 2, 3]]
%result0, %result1 = "stablehlo.sort"(%input0, %input1) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>, %arg2: tensor<i64>, %arg3: tensor<i64>):
%predicate = "stablehlo.compare"(%arg0, %arg1) {
comparison_direction = #stablehlo<comparison_direction GT>
} : (tensor<i64>, tensor<i64>) -> tensor<i1>
"stablehlo.return"(%predicate) : (tensor<i1>) -> ()
}) {
dimension = 0 : i64,
is_stable = true
} : (tensor<2x3xi64>, tensor<2x3xi64>) -> (tensor<2x3xi64>, tensor<2x3xi64>)
// %result0 = [[3, 2, 3], [1, 2, 1]]
// %result1 = [[1, 2, 1], [3, 2, 3]]
sqrt
Anlam bilimi
operand
tenzorunda öğe bazında karekök işlemi gerçekleştirir ve result
tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:
- Kayan noktalı sayılar için: IEEE-754'ten
squareRoot
. - Karmaşık sayılar için: karmaşık karekökü.
- Kesirli türler için:
dequantize_op_quantize(sqrt, operand, type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Sınırlamalar
- (C1)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// %operand: [[0.0, 1.0], [4.0, 9.0]]
%result = "stablehlo.sqrt"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[0.0, 1.0], [2.0, 3.0]]
çıkarma
Anlam bilimi
İki tenzor lhs
ve rhs
'un öğe bazında çıkarımını gerçekleştirir ve bir result
tenzoru oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:
- Tam sayılar için: tam sayı çıkarma.
- Kayan noktalı sayılar için: IEEE-754'ten
subtraction
. - Karmaşık sayılar için: karmaşık çıkarma.
- Kesirli türler için:
dequantize_op_quantize(subtract, lhs, rhs, type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | lhs |
Tam sayı, kayan nokta veya karmaşık türde bir tensör ya da tensör başına kesirli tensör | (C1) |
(I2) | rhs |
Tam sayı, kayan nokta veya karmaşık türde bir tensör ya da tensör başına kesirli tensör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
Tam sayı, kayan nokta veya karmaşık türde bir tensör ya da tensör başına kesirli tensör | (C1) |
Sınırlamalar
- (C1)
baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)
.
Örnekler
// %lhs: [[6, 8], [10, 12]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.subtract"(%lhs, %rhs) : (tensor<2x2xf32>, tensor<2x2xf32>) -> (tensor<2x2xf32>)
// %result: [[1, 2], [3, 4]]
tan
Anlam
operand
tensöründe öğe bazında tanjant işlemi gerçekleştirir ve bir result
tensörü oluşturur. Öğe türüne bağlı olarak aşağıdakileri yapar:
- Kayan noktalı sayılar için: IEEE-754'ten
tan
. - Karmaşık sayılar için: karmaşık tanjant.
- Kesirli türler için:
dequantize_op_quantize(tan, operand, type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Sınırlamalar
- (C1)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// %operand: [
// [0.0, 1.57079632], // [0, pi/2]
// [3.14159265, 4.71238898] // [pi, 3pi/2]
// ]
%result = "stablehlo.tan"(%operand) : (tensor<2x2xf64>) -> tensor<2x2xf64>
// %result: [
// [0.0, 1.63312e+16],
// [0.0, 5.44375e+15]
// ]
tanh
Anlam bilimi
operand
tensörü üzerinde element düzeyinde hiperbolik tanjant işlemi gerçekleştirir ve result
tensörü üretir. Öğe türüne bağlı olarak aşağıdakiler gerçekleşir:
- Kayan noktalı sayılar için: IEEE-754'ten
tanh
. - Karmaşık sayılar için: karmaşık hiperbolik tanjant.
- Miktarlanmış türler için:
dequantize_op_quantize(tanh, operand, type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Sınırlamalar
- (C1)
baseline_type(operand) = baseline_type(result)
.
Örnekler
// %operand: [-1.0, 0.0, 1.0]
%result = "stablehlo.tanh"(%operand) : (tensor<3xf32>) -> tensor<3xf32>
// %result: [-0.76159416, 0.0, 0.76159416]
transpoze
Anlam bilimi
permutation
kullanarak operand
tensörünün boyutlarını korur ve result
tensörü üretir. Daha resmi bir ifadeyle, result[result_index] = operand[operand_index]
burada result_index[d] = operand_index[permutation[d]]
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
tenzor veya kesirli tenzor | (C1-C4) |
(I2) | permutation |
si64 türündeki 1 boyutlu tensör sabiti |
(C2-C4) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tensör veya nicel tensör | (C1), (C3-C4) |
Sınırlamalar
- (C1)
element_type(result)
şu şekilde hesaplanır:!is_per_axis_quantized(operand)
iseelement_type(operand)
.element_type(operand)
, ancakquantization_dimension(operand)
vequantization_dimension(result)
farklı olabilir.
- (C2)
permutation
,range(rank(operand))
'un bir permütasyonudur. - (C3)
shape(result) = dim(operand, permutation...)
. - (C4)
is_per_axis_quantized(result)
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ı matrislerine sahip doğrusal denklem sistemleri gruplarını çözer.
Daha resmi olmak gerekirse a
ve b
için result[i0, ..., iR-3, :, :]
, left_side
true
olduğunda x * op(a[i0, ..., iR-3, :, :]) = b[i0, ..., iR-3, :, :]
veya left_side
false
olduğunda op(a[i0, ..., iR-3, :, :]) * x = b[i0, ..., iR-3, :, :]
için çözümdür. op(a)
, transpose_a
ile belirlendiği x
değişkenini bulur. Bu değişken aşağıdakilerden biri olabilir:
NO_TRANSPOSE
:a
'u olduğu gibi kullanarak işlemi gerçekleştirin.TRANSPOSE
: İşlemia
'un transpozesiyle gerçekleştirin.ADJOINT
: İşlemia
'un eşlenik transpozu üzerinde gerçekleştirir.
Giriş verileri, lower
true
ise yalnızca a
'ün alt üçgeninden, aksi takdirde a
'ün üst üçgeninden okunur. Çıkış verileri aynı üçgende döndürülür; diğer üçgendeki değerler uygulama tanımlıdır.
unit_diagonal
doğruysa uygulama, a
'un köşegen öğelerinin 1'e eşit olduğunu varsayabilir. Aksi takdirde davranış tanımlanmaz.
Miktarı belirlenmiş türler için dequantize_op_quantize(lambda x, y: triangular_solve(x, y, left_side, lower,
unit_diagonal, transpose_a), a, b, type(result))
işlemini gerçekleştirir.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | a |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1-C3) |
(I2) | b |
kayan nokta veya karmaşık tür ya da tensör başına miktarlandırılmış tensör tensörü | (C1-C4) |
(I3) | left_side |
i1 türündeki sabit |
(C3) |
(I4) | lower |
i1 türündeki sabit |
|
(I5) | unit_diagonal |
i1 türünün sabiti |
|
(I6) | transpose_a |
NO_TRANSPOSE , TRANSPOSE ve ADJOINT değerlerini içeren bir enum |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta veya karmaşık türde tenör ya da tenör başına kesirli tenör | (C1) |
Sınırlamalar
- (C1)
baseline_element_type(a) = baseline_element_type(b)
. - (C2)
2 <= rank(a) = rank(b) = R
. - (C3)
shape(a)
ileshape(b)
arasındaki ilişki aşağıdaki gibi tanımlanır:shape(a)[:-3] = shape(b)[:-3]
.dim(a, -2) = dim(a, -1) = dim(b, left_side ? -2 : -1)
.
- (C4)
baseline_type(b) = baseline_type(result)
.
Örnekler
// %a = [
// [1.0, 0.0, 0.0],
// [2.0, 4.0, 0.0],
// [3.0, 5.0, 6.0]
// ]
// %b = [
// [2.0, 0.0, 0.0],
// [4.0, 8.0, 0.0],
// [6.0, 10.0, 12.0]
// ]
%result = "stablehlo.triangular_solve"(%a, %b) {
left_side = true,
lower = true,
unit_diagonal = false,
transpose_a = #stablehlo<transpose NO_TRANSPOSE>
} : (tensor<3x3xf32>, tensor<3x3xf32>) -> tensor<3x3xf32>
// %result: [
// [2.0, 0.0, 0.0],
// [0.0, 2.0, 0.0],
// [0.0, 0.0, 2.0]
// ]
tuple
Anlam bilimi
val
değerlerinden bir result
tuple oluşturur.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | val |
değişken değer sayısı | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
tuple | (C1) |
Sınırlamalar
- (C1)
result
,Ei = type(val[i])
olduğundatuple<E0, ..., EN-1>
türüne sahiptir.
Örnekler
// %val0: [1.0, 2.0]
// %val1: (3)
%result = "stablehlo.tuple"(%val0, %val1) : (tensor<2xf32>, tuple<tensor<i32>>) -> tuple<tensor<2xf32>, tuple<tensor<i32>>>
// %result: ([1.0, 2.0], (3))
uniform_dequantize
Anlam
operand
türü tarafından tanımlanan niceleme parametrelerine göre, miktarlandırılmış operand
tensörü result
ile kayan nokta tensörüne öğe düzeyinde dönüştürme yapar.
Daha resmi bir ifadeyle result = dequantize(operand)
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
nicel tensör | (C1), (C2) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kayan nokta türündeki tensör | (C1), (C2) |
Sınırlamalar
- (C1)
shape(operand) = shape(result)
. - (C2)
element_type(result) = expressed_type(operand)
.
Örnekler
// %operand: [10, 10]
%result = "stablehlo.uniform_dequantize"(%operand) : (tensor<2x!quant.uniform<i8:f32:0, {0.1:-30,0.5:-20}>>) -> tensor<2xf32>
// %result: [4.0, 15.0]
uniform_quantize
Anlam
result
türü tarafından tanımlanan kesme noktaları parametrelerine göre, kayan noktalı tenzor veya kesikli tenzor operand
'ü kesikli tenzor result
'a öğe bazında dönüştürür.
Daha resmi bir dille,
is_float(operand)
ise:result = quantize(operand, type(result))
.
is_quantized(operand)
ise:float_result = dequantize(operand)
.result = quantize(float_result, type(result))
.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
kayan nokta veya kesirli türde bir tenör | (C1), (C2) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
kesirli tensör | (C1), (C2) |
Sınırlamalar
- (C1)
shape(operand) = shape(result)
. - (C2)
expressed_type(result) = is_float(operand) ? element_type(operand) : expressed_type(operand)
.
Örnekler
// %operand: [4.0, 15.0]
%result = "stablehlo.uniform_quantize"(%operand) : (tensor<2xf32>) -> tensor<2x!quant.uniform<i8:f32:0, {0.1:-30,0.5:-20}>>
// %result: [10, 10]
// %operand: [10, 10]
%result = "stablehlo.uniform_quantize"(%operand) : (tensor<2x!quant.uniform<i8:f32:0, {0.1:-30,0.5:-20}>>) -> tensor<2x!quant.uniform<i8:f32:0, {0.1:-20,0.2:-30}>>
// %result: [20, 45]
iken
Anlam
cond
işlevi true
çıktısını verirken body
işlevinin yürütülmesinden elde edilen çıktıyı 0 veya daha fazla kez üretir. Daha resmi bir şekilde, semantikler Python söz dizimini kullanarak aşağıdaki gibi ifade edilebilir:
internal_state = operand
while cond(*internal_state):
internal_state = body(*internal_state)
results = internal_state
Sonsuz döngünün davranışı TBD'dir (#383).
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | operand |
değişken sayıda tenör, kesirli tenör veya jeton | (C1-C3) |
(I2) | cond |
işlev | (C1) |
(I3) | body |
işlev | (C2) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
results |
değişken sayıda tenör, kesirli tenör veya jeton | (C3) |
Sınırlamalar
- (C1)
cond
,Ti = type(operand[i])
olduğunda(T0, ..., TN-1) -> tensor<i1>
türündedir. - (C2)
body
,Ti = type(operand[i])
olduğunda(T0, ..., TN-1) -> (T0, ..., TN-1)
türündedir. - (C3)
type(results...) = type(operand...)
.
Örnekler
// %init_i: 1
// %init_sum: 0
// %one: 1
// %ten: 10
%results0, %results1 = "stablehlo.while"(%init_i, %init_sum) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%cond = "stablehlo.compare"(%arg0, %ten) {
comparison_direction = #stablehlo<comparison_direction LT>
} : (tensor<i64>, tensor<i64>) -> tensor<i1>
stablehlo.return %cond : tensor<i1>
}, {
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%new_sum = stablehlo.add %arg1, %one : tensor<i64>
%new_i = stablehlo.add %arg0, %one : tensor<i64>
stablehlo.return %new_i, %new_sum : tensor<i64>, tensor<i64>
}) : (tensor<i64>, tensor<i64>) -> (tensor<i64>, tensor<i64>)
// %results0: 10
// %results1: 10
xor
Anlam bilimi
İki lhs
ve rhs
tensörü için öğe tabanlı XOR gerçekleştirir ve bir result
tensörü üretir. Öğe türüne bağlı olarak aşağıdakileri yapar:
- Boole değerleri için: mantıksal VEYA.
- Tam sayılar için: bit tabanlı XOR.
Girişler
Şirket | Ad | Tür | Sınırlamalar |
---|---|---|---|
(I1) | lhs |
boole veya tam sayı türündeki tenör | (C1) |
(I2) | rhs |
boole veya tam sayı türündeki tensor | (C1) |
Çıkışlar
Ad | Tür | Sınırlamalar |
---|---|---|
result |
boole veya tam sayı türündeki tenör | (C1) |
Sınırlamalar
- (C1)
type(lhs) = type(rhs) = type(result)
.
Örnekler
// Bitwise operation with with integer tensors
// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.xor"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[4, 4], [4, 12]]
// Logical operation with with boolean tensors
// %lhs: [[false, false], [true, true]]
// %rhs: [[false, true], [false, true]]
%result = "stablehlo.xor"(%lhs, %rhs) : (tensor<2x2xi1>, tensor<2x2xi1>) -> tensor<2x2xi1>
// %result: [[false, true], [true, false]]
Lehçe birlikte çalışabilirliği
Şu anda kullanımdaki StableHLO programları bazen StableHLO tarafından tanımlanmayan işlemler içeriyor.
Modül, İşlev, Arama ve İade
StableHLO, ModuleOp, FuncOp, CallOp ve ReturnOp için yayın öncesi MLIR işlemlerini kullanır. FuncOp ve ModuleOp'u hedefleyen birçok faydalı geçiş yazıldığından ve birçok derleme ardışık düzeninde bu işlemlerin mevcut olması beklendiğinden bu, mevcut MLIR makineleriyle daha iyi birlikte çalışmak için yapıldı. Bu işlemlere tam uyumluluk garantileri uygulanır. Bu işlemlerle ilgili uyumlu olmayan bir değişiklik (ör. kaldırma) olursa uyumluluğu korumak için StableHLO eşdeğerleri eklenir.
CHLO
CHLO opset'i, StableHLO'ya ayrıştırılan daha yüksek düzey işlemler içerir. Şu anda CHLO için uyumluluk garantisi yoktur. Uyumluluk garantileri için serileştirmeden önce chlo-legalize-to-stablehlo geçişi kullanılmalıdır.
Şekil İşlemleri
Şekil hesaplamaları yapmak için dinamik StableHLO programlarında temel MLIR lehçelerinden belirli işlemleri kullanmak, toplulukta yaygın bir kullanım alanıdır.
Bunlar arasında en çok shape_of
veya num_elements
gibi shape
lehçesi işlemleri, dim
veya from_elements
gibi tensor
lehçesi işlemleri ve yerleşik index
türü bulunur.
Dinamik RFC > O2, bunları kapsam dışında olarak belirtir ancak birlikte çalışabilirlik amacıyla index
türleri için bazı destekler dahil edilmiştir. Bu işlemler veya türler için uyumluluk garantisi yoktur. shape-legalize-to-stablehlo ardışık düzeni, bu işlemleri tam olarak desteklenen StableHLO işlemlerine dönüştürmek için kullanılabilir.
Kullanımdan Kaldırılan İşlemler
MHLO'dan devralınan ve desteği sonlandırılan, StableHLO'dan kullanımdan kaldırılmakta olan çeşitli StableHLO işlemleri vardır. Bu kaldırma işlemleriyle ilgili tüm ayrıntıları StableHLO v1.0 Cleanup #2283'te bulabilirsiniz. Bu desteğin sonlandırılmasıyla ilgili takip numarası #2340'dır.
Bu işlemler birkaç kategoriye ayrılır:
- StableHLO operasyonlarının "HLO" kategorisinde değil. Bunlar başlangıçta StableHLO işletim sisteminin bir parçasıydı ancak daha sonra uygun olmadığı belirlendi:
broadcast
,create_token
,cross-replica-sum
,dot
,einsum
,torch_index_select
,unary_einsum
(#3). - Kullanılmayan işlemler: Bu işlemler bir noktada faydalı olabilir ancak işlemler yeterince geliştirilmemiş veya bu işlemleri kullanan ardışık düzenler artık bunları gerektirmeyecek şekilde yeniden düzenlenmiştir. Buna
map
,tuple
(#598),get_tuple_element
,rng
,complex
karşılaştırmaları #560 vewindow_reversal
(#1181) convolve işlevi dahildir.
Mevcut işlemler (broadcast
, create_token
, cross-replica-sum
, dot
, unary_einsum
) kullanılarak ifade edilebildikleri için bu işlemlerin bazıları kolayca kaldırılabilir ve mevcut uyumluluk aralığı (6 ay) geçtikten sonra kaldırılır. Diğerleri, kaldırılma olasılığı açısından incelenmeye devam ediyor (einsum
,
get_tuple_element
, map
, rng
torch_index_select
, tuple
, complex
karşılaştırmaları, window_reversal
). Topluluk geri bildirimleri doğrultusunda bu işlemler kaldırılır veya tam destekli olarak spesifikasyona eklenir. Bu operasyonların gelecekleri öğrenilene kadar yalnızca 6 aylık uyumluluk garanti edilir.
Yürütme
Sıralı yürütme
StableHLO programı, main
işlevine giriş değerleri sağlanarak ve çıkış değerleri hesaplanarak yürütülür. Bir işlevin çıkış değerleri, karşılık gelen return
işlemindeki kök işlemleri grafiğini yürütülerek hesaplanır.
Veri akışıyla uyumlu olduğu sürece (ör. işlemler kullanımlarından önce yürütülüyorsa) yürütme sırası uygulama tarafından tanımlanır. StableHLO'da, yan etki oluşturan tüm işlemler bir jeton tüketir ve bir jeton üretir (after_all
aracılığıyla birden fazla jeton tek bir jetonda birleştirilebilir). Bu nedenle, yan etkilerin yürütme sırası da veri akışıyla uyumludur. Örneğin, aşağıdaki programda olası iki yürütme siparişi vardır: %0
→ %1
→ %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 şunların bir birleşimidir: 1) StableHLO programı, 2) işlem durumları (henüz yürütülmedi, zaten yürütüldü) ve 3) sürecin üzerinde çalıştığı ara değerler.
İşlem, main
işlevine ait giriş değerleriyle başlar, işlem durumlarını ve ara değerleri güncelleyen işlemler grafiğinde ilerler ve çıkış değerleriyle sona erer. Daha fazla resmileştirme henüz belirlenmedi (#484).
Paralel yürütme
StableHLO programları paralel olarak yürütülebilir ve her ikisi de ui32
türüne sahip olan num_replicas
x num_partitions
boyutunda bir 2D işlem ızgarasına düzenlenebilir.
StableHLO işlem ızgarasındaki num_replicas * num_partitions
StableHLO işlemi aynı anda yürütülüyor. Her sürecin benzersiz bir process_id = (replica_id, partition_id)
değeri vardır. replica_ids = range(num_replicas)
içindeki replica_id
ve partition_ids = range(num_partitions)
içindeki partition_id
, ui32
türüne sahiptir.
İşlem ızgarasının boyutu her program için statik olarak bilinir (İleride bunu StableHLO programlarının #650 açık bir parçası haline getirmeyi planlıyoruz) ve işlem ızgarasındaki konum her işlem için statik olarak bilinir. Her işlem, replica_id
ve partition_id
işlemleri aracılığıyla işlem ızgarasındaki konumuna erişebilir.
Süreç çizelgesinde programların tümü aynı ("Tek Program, Birden Çok Veri" stilinde), tümü farklı ("Çoklu Program, Birden Çok Veri" stilinde) veya ikisi arasında bir seçenek olabilir. Gelecekte, GSPMD (#619) dahil olmak üzere paralel StableHLO programlarını tanımlamayla ilgili diğer deyimler için de destek sunmayı planlıyoruz.
Süreç ızgarasında, süreçler büyük ölçüde birbirinden bağımsızdır. Ayrı çalışma durumları vardır, ayrı giriş/ara/çıktı değerleri bulunur ve işlemlerin çoğu, aşağıda açıklanan az sayıda toplu işlem hariç olmak üzere, süreçler arasında ayrı ayrı yürütülür.
İşlemlerin çoğunun yürütülmesinde yalnızca aynı işlemdeki değerler kullanıldığı için bu değerlere adlarıyla başvurmak genellikle net bir ifadedir.
Ancak toplu işlemlerin anlamını açıklarken bu yeterli değildir ve belirli bir işlemdeki name
değerini belirtmek için name@process_id
gösterimi kullanılır. (Bu açıdan, niteliksiz name
, name@(replica_id(), partition_id())
için kısaltma olarak görülebilir.)
Aşağıda açıklandığı gibi, noktadan noktaya iletişim ve toplu işlemlerin sağladığı senkronizasyon hariç olmak üzere, süreçler genelindeki yürütme sırası uygulama tanımlıdır.
Bire bir iletişim
StableHLO süreçleri, StableHLO kanalları üzerinden birbirleriyle iletişim kurabilir. Kanallar, si64
türündeki pozitif bir kimlikle temsil edilir. Çeşitli işlemler aracılığıyla, kanallara değer göndermek ve bunları kanallardan almak mümkündür.
Bu kanal kimliklerinin nereden geldiği, programların bu kimlikleri nasıl bildiği ve bu kimliklerle nasıl bir senkronizasyon sağlandığı gibi konularla ilgili daha fazla bilgi daha sonra paylaşılacaktır (#484).
Akış iletişimi
Her StableHLO işlemi iki akış arayüzüne erişebilir:
- Okunabilen feed.
- Yazılabilen outfeed.
İşlemler arasında iletişim kurmak için kullanılan ve bu nedenle her iki ucunda da işlem bulunan kanalların aksine, feed'lerin diğer ucu uygulama tarafından tanımlanır.
Daha ayrıntılı hale getirme, ör. iletişim akışının yürütme sırasını nasıl etkilediği ve bunun ne tür bir senkronizasyonu başlattığı henüz belli değildir (#484).
Toplu işlemler
StableHLO'da altı adet ortak işlem vardır: all_gather
, all_reduce
,
all_to_all
, collective_broadcast
, collective_permute
ve reduce_scatter
. Tüm bu işlemler, StableHLO işlem ızgarasındaki işlemleri StableHLO işlem gruplarına ayırır ve her işlem grubunda diğer işlem gruplarından bağımsız olarak ortak bir hesaplama yürütür.
Her işlem grubunda toplu işlemler bir senkronizasyon engeli oluşturabilir. Bu senkronizasyonun tam olarak ne zaman gerçekleştiği, işlemlerin bu engele tam olarak nasıl ulaştığı ve ulaşmaması durumunda ne olduğu gibi konuların daha ayrıntılı olarak açıklanması henüz belirlenmedi (#484).
İşlem grubu, bölümler arası iletişim içeriyorsa (ör. işlem grubunda bölüm kimlikleri farklı olan işlemler varsa) toplu işlemin yürütülmesi için bir kanal gerekir ve toplu işlem, si64
türündeki pozitif bir channel_id
sağlamalıdır. Çapraz kopya iletişimde kanallara
ihtiyaç yoktur.
Toplu işlemler tarafından gerçekleştirilen hesaplamalar, bireysel işlemlere özgüdür ve yukarıdaki bireysel işlem bölümlerinde açıklanmaktadır. Ancak işlem ızgarasının işlem gruplarına ayrıldığı stratejiler bu operasyonlar arasında paylaşılır ve bu bölümde açıklanır. Daha resmi bir ifadeyle, StableHLO aşağıdaki dört stratejiyi destekler.
cross_replica
Her bir işlem grubunda yalnızca kopyalar arası iletişim gerçekleşir. Bu stratejide, replica_groups
(replika kimlik listelerinden) oluşan bir liste ve partition_ids
ile replica_groups
öğesinin Kartezyen ürünü hesaplanır. replica_groups
, benzersiz öğelere sahip olmalı ve tüm replica_ids
öğelerini kapsamalıdır. Daha resmi olarak, Python söz dizimini kullanarak:
def cross_replica(replica_groups: List[List[ReplicaId]]) -> List[List[ProcessId]]:
for replica_group in replica_groups:
for partition_id in partition_ids:
process_group = []
for replica_id in replica_group:
process_group.append((replica_id, partition_id))
yield process_group
Örneğin, replica_groups = [[0, 1], [2, 3]]
ve num_partitions = 2
için cross_replica
, [[(0, 0), (1, 0)], [(0, 1), (1, 1)], [(2, 0), (3, 0)], [(2, 1), (3, 1)]]
değerini döndürür.
cross_partition
Her bir işlem grubunda yalnızca bölümler arası iletişim gerçekleşir. Bu strateji, bölüm kimliklerinin listelerinin listesi olan partition_groups
'yi alır ve partition_groups
ile replica_ids
'nin Kartezyen çarpımını hesaplar.
partition_groups
benzersiz öğelere sahip olmalı ve tüm partition_ids
öğelerini kapsamalıdır.
Daha resmi bir ifadeyle, Python söz dizimini kullanarak:
def cross_partition(partition_groups: List[List[PartitionId]]) -> List[List[ProcessId]]:
for partition_group in partition_groups:
for replica_id in replica_ids:
process_group = []
for partition_id in partition_group:
process_group.append((replica_id, partition_id))
yield process_group
Örneğin, partition_groups = [[0, 1]]
ve num_replicas = 4
için cross_partition
, [[(0, 0), (0, 1)], [(1, 0), (1, 1)], [(2, 0), (2, 1)], [(3, 0), (3, 1)]]
üretir.
cross_replica_and_partition
Her süreç grubu içinde hem çapraz replikalı hem de bölümler arası iletişimler gerçekleşebilir. Bu strateji, kopya kimliklerinin listelerinin listesi olan replica_groups
'yi alır ve her replica_group
için partition_ids
'ye göre Kartezyen çarpımlarını hesaplar. replica_groups
benzersiz öğelere sahip olmalı ve tüm replica_ids
öğelerini kapsamalıdır. Daha resmi bir şekilde, Python söz dizimini kullanarak:
def cross_replica_and_partition(replica_groups: List[List[ReplicaId]]) -> List[List[ProcessId]]:
for replica_group in replica_groups:
process_group = []
for partition_id in partition_ids:
for replica_id in replica_group:
process_group.append((replica_id, partition_id))
yield process_group
Örneğin, replica_groups = [[0, 1], [2, 3]]
ve num_partitions = 2
için cross_replica_and_partition
, [[(0, 0), (1, 0), (0, 1), (1, 1)], [(2, 0), (3, 0), (2, 1), (3, 1)]]
değerini döndürür.
flattened_ids
Bu strateji, flattened_id_groups
'ü (replica_id * num_partitions + partition_id
biçiminde "düzleştirilmiş" işlem kimliklerinin listelerinin listesi) alır ve bunları işlem kimliklerine dönüştürür. flattened_id_groups
, benzersiz öğelere sahip olmalı ve tüm process_ids
öğelerini kapsamalıdır. Daha resmi bir şekilde, Python söz dizimini kullanarak:
def flattened_ids(flattened_id_groups: List[List[ui32]]) -> List[List[ProcessId]]:
for flattened_id_group in flattened_id_groups:
process_group = []
for flattened_id in flattened_id_group:
replica_id = flattened_id // num_partitions
partition_id = flattened_id % num_partitions
process_group.append((replica_id, partition_id))
yield process_group
Örneğin, flattened_id_groups = [[0, 1, 2, 3], [4, 5, 6, 7]]
, num_replicas = 4
ve num_partitions = 2
için flattened_ids
, [[(0, 0), (0, 1), (1, 0), (1, 1)], [(2, 0), (2, 1), (3, 0), (3, 1)]]
değerini döndürür.
Doğruluk
StableHLO şu anda sayısal doğruluk konusunda garanti vermez ancak bu durum gelecekte değişebilir (#1156).
Ölçülen işlemin yürütme anlamı
Ölçülen StableHLO işlemlerinin yorumlanması, donanım gereksinimlerine ve özelliklerine bağlı olarak değişiklik gösterebilir. Örneğin, bazı donanımlar "küme çözme, kayan nokta işlemi gerçekleştirme ve son olarak küme oluşturma" stratejisini kullanarak kesirli işlemleri yorumlayabilir. Diğerleri ise hesaplamanın tamamını tam sayı aritmetiğiyle gerçekleştirebilir. Sonuç olarak, kesirli StableHLO işlemlerinin yorumlanması yalnızca belirli uygulamaya göre belirlenir. Karma örneklemenin (#1575) yorumu, spesifikasyonda (1792 aracılığıyla) belirtilen semantiklerine dayalı olmalıdır.
Hatalar
StableHLO programları, her bir işlem için kapsamlı bir kısıtlama grubu aracılığıyla doğrulanır. Bu kısıtlama grubu, çalışma zamanından önce birçok hata sınıfını ortadan kaldırır. Bununla birlikte, hata koşulları (ör.tam sayı taşmaları, sınır dışı erişimler vb. aracılığıyla) yine de mümkündür. Açıkça belirtilmediği sürece tüm bu hatalar uygulama tanımlı davranışla sonuçlanır, ancak bu durum ileride değişebilir (#1157).
Kayan nokta istisnaları
Bu kuralın istisnası olarak, StableHLO programlarındaki kayan nokta istisnaları iyi tanımlanmış bir davranışa sahiptir. IEEE-754 standardı tarafından tanımlanan istisnalarla sonuçlanan işlemler (geçersiz işlem, sıfıra bölme, taşma, eksik taşma veya yanlış istisnalar), varsayılan sonuçları (standartta tanımlandığı şekilde) üretir ve ilgili durum işaretini kaldırmadan yürütmeye devam eder. Bu, standarttaki raiseNoFlag
istisna işleme özelliğine benzer. Standart olmayan işlemler (ör. karmaşık aritmetik ve belirli aşkın işlevler) için istisnalar uygulamaya göre tanımlanır.
Şekil uyuşmazlıkları
StableHLO, dinamik olarak şekillendirilmiş tenzorları destekler. Ancak şekillerin çalışma zamanında eşleşmesi gerekir. Aksi takdirde davranış tanımlanmaz. StableHLO, bir tensörün çalışma zamanında belirli bir şekle sahip olduğunu doğrulayabilecek bir işlem açıkça sağlamaz. Doğru kodu oluşturma sorumluluğu yapımcıya aittir.
Somut bir örnek vermek gerekirse aşağıdaki programın geçerliliği vardır. Ancak, çalışma zamanında %arg0
ve %arg1
öğelerinin tam şekilleri aynı olmalıdır. Aksi takdirde, programın davranışı tanımlanmamış olur:
func.func @foo(%arg0: tensor<?xi32>, %arg1: tensor<?xi32>) -> tensor<?xi32> {
%0 = stablehlo.add %arg0, %arg1 : tensor<?xi32>
return %0 : tensor<?xi32>
}
Notasyon
Bu dokümanda, EBNF söz dizimini açıklamak için EBNF söz dizisinin değiştirilmiş ISO versiyonu (ISO/IEC 14977:1996, Wikipedia) kullanılmaktadır. Bu versiyonda iki değişiklik yapılmıştır: 1) Kurallar =
yerine ::=
kullanılarak tanımlanır.
2) dize birleştirme işlemi ,
yerine yan yana ekleme kullanılarak ifade edilir.
Anlamı (yani "Türler", "Sabitler" ve "İşlemler" bölümlerinde) açıklamak için aşağıda açıklandığı gibi dizi işlemlerini kısa ve öz şekilde ifade etme desteğiyle genişletilmiş Python söz dizimine dayalı formüller kullanırız. Bu yöntem küçük kod snippet'leri için iyi çalışır ancak daha büyük kod snippet'lerinin gerekli olduğu nadir durumlarda her zaman açıkça tanıtılan standart Python söz dizimini kullanırız.
Formüller
dot_general
spesifikasyonundan alınan bir örneğe dayanarak formüllerin nasıl çalıştığını keşfedelim. Bu işlemle ilgili kısıtlamalardan biri aşağıdaki gibidir:
dim(lhs, lhs_batching_dimensions...) = dim(rhs, rhs_batching_dimensions...)
.
Bu formülde kullanılan adlar iki kaynaktan gelir: 1) genel işlevler (ör. dim
), 2) ilgili program öğesinin üye tanımları (ör. dot_general
'in "Girişler" bölümünde tanımlanan lhs
, lhs_batching_dimensions
, rhs
ve rhs_batching_dimensions
girişleri).
Yukarıda da belirtildiği gibi, bu formülün söz dizimi Python tabanlı olup bazı kısaltmalara sahiptir. Formülü anlamak için bunu standart Python söz dizimine dönüştürelim.
C: Bu formüllerde eşitliği temsil etmek için =
kullanıyoruz. Dolayısıyla Python söz dizimini elde etmeye yönelik ilk adım, =
'yi aşağıdaki gibi ==
ile değiştirmektir:
dim(lhs, lhs_batching_dimensions...) == dim(rhs, rhs_batching_dimensions...)
.
B) Ayrıca bu formüller, skaler ifadeleri tensör ifadelerine dönüştüren elipsleri (...
) destekler. Özetlemek gerekirse f(xs...)
, kabaca "xs
tensörindeki her skaler x
için bir skaler f(x)
hesaplayıp tüm bu skaler sonuçları birlikte bir tensör sonucu olarak döndürme" anlamına gelir. Basit Python söz diziminde, örnek formülümüzün şekli şu şekilde değişir:
[dim(lhs, dim1) for dim1 in lhs_batching_dimensions] ==
[dim(rhs, dim2) for dim2 in rhs_batching_dimensions]
.
Elipsler sayesinde bağımsız skaler düzeyinde çalışmaktan genellikle kaçınmak mümkündür. Ancak bazı karmaşık durumlarda, gather
spesifikasyonundaki start_indices[bi0, ..., :, ..., biN]
formülünde olduğu gibi alt düzey yarı resmi söz dizimi kullanılabilir. Özlülük sağlamak amacıyla, bu tür söz dizimlerini standart Python'a çevirmek için tam bir biçimsellik sağlamayız. Bununla birlikte, her duruma göre sezgisel olarak anlaşılabilir olmasını umuyoruz.
Belirli formüllerin anlaşılır olmadığını düşünüyorsanız lütfen bize bildirin. Bu formüller üzerinde iyileştirme yapmaya çalışacağız.
Ayrıca, formüllerin; tensörler, tensör listeleri (ör. değişken sayıda tensörden oluşabilir) vb. dahil olmak üzere her türlü listeyi genişletmek için elips kullandığını fark edeceksiniz. Bu, tam bir biçimcilik sağlamadığımız (ör. listeler StableHLO tür sisteminin bile bir parçası değildir) ve bunun yerine sezgisel anlaşılabilirliğe güvendiğimiz başka bir alandır.
C) Kullandığımız son kayda değer gösterim aracı, örtük yayındır. StableHLO opset'i, örtülü yayını desteklemezken formüller bunu destekler ve ayrıca kısalık sağlar. Özetlemek gerekirse, bir skaler, bir tensörün beklendiği bir bağlamda kullanılırsa skaler, beklenen şekle yayınlanır.
dot_general
örneğine devam etmek için başka bir kısıtlama daha verelim:
0 <= lhs_batching_dimensions < rank(lhs)
. dot_general
spesifikasyonunda tanımlandığı gibi, lhs_batching_dimensions
bir tensördür ancak hem 0
hem de rank(lhs)
skalerdir. Örtük yayını uyguladıktan sonra formül [0, ..., 0] <= lhs_batching_dimensions < [rank(lhs), ..., rank(lhs)]
olur.
Bu formül, belirli bir dot_general
işlemine uygulandığında doğru/yanlış değerleri içeren bir tensör olarak değerlendirilir. Formüller kısıtlama olarak kullanıldığında, formül true
veya yalnızca true
öğesi olan bir tensör olarak değerlendirilirse kısıtlama geçerli olur.
Adlar
Formüllerde sözlüksel kapsam şunları içerir: 1) genel işlevler, 2) üye tanımları,
3) yerel tanımlar. Genel işlevlerin listesi aşağıda verilmiştir. Öğe tanımlarının listesi, gösterimin uygulandığı program öğesine bağlıdır:
- İşlemler için üye tanımları, "Girişler" ve "Çıkışlar" bölümlerinde tanıtılan adları içerir.
- Diğer tüm üye tanımları, program öğesinin yapısal parçalarını içerir ve ilgili EBNF sonlu olmayan öğelerinin adından türetilir. Çoğu zaman bu yapısal parçaların adları, terminal olmayan öğelerin adlarının yılan büyük/küçük harf düzenine
IntegerLiteral
integer_literal
QuantizationStorageType
storage_type
- Ayrıca, üye tanımları her zaman ilgili program öğesine atıfta bulunmak için
self
içerir.
Değerler
Formüller değerlendirilirken aşağıdaki değer türleriyle çalışır:
1) Value
(gerçek değerler, ör. dense<[[1, 2], [3, 4]]> : tensor<2x2xi32>
; türleri her zaman bilinir),
2) Placeholder
(gelecekteki değerler, ör. lhs
, rhs
veya result
; gerçek değerleri henüz bilinmez, yalnızca türleri bilinir),
3) Type
("Türler" bölümünde tanımlandığı şekilde türler),
4) Function
("İşlevler" bölümünde tanımlandığı şekilde genel işlevler).
Bağlama bağlı olarak adlar farklı değerlere işaret edebilir. Daha ayrıntılı belirtmek gerekirse, işlemler (ve diğer program öğelerinin eşdeğerleri) için "Anlamsal" bölümü, çalışma zamanı mantığını tanımlar. Bu nedenle, tüm girişler Value
olarak kullanılabilir.
Buna karşılık, işlemler (ve eşdeğerleri) için "Kısıtlar" bölümü, "derleme zamanı" mantığını (yani genellikle çalışma zamanından önce yürütülen bir şey) tanımlar. Bu nedenle, yalnızca sabit girişler Value
olarak kullanılabilir ve diğer girişler yalnızca Placeholder
olarak kullanılabilir.
Adlar | "Anlambilim" bölümünde | "Kısıtlar" bölümünde |
---|---|---|
Genel işlevler | Function |
Function |
Sabit girişler | Value |
Value |
Sabit olmayan girişler | Value |
Placeholder |
Çıkışlar | Value |
Placeholder |
Yerel tanımlar | Tanımlamaya bağlıdır | Tanımlamaya bağlıdır |
Bir örnek transpose
işlemini inceleyelim:
%result = "stablehlo.transpose"(%operand) {
permutation = dense<[2, 1, 0]> : tensor<3xi64>
} : (tensor<2x3x2xi32>) -> tensor<2x3x2xi32>
Bu işlemde permutation
sabit olduğundan hem semantikte hem de kısıtlamalarda Value
olarak kullanılabilir. Buna karşılık, operand
ve result
, anlamsal olarak bir Value
olarak ancak kısıtlamalarda yalnızca Placeholder
olarak kullanılabilir.
İşlevler
Tür oluşturma
Tür oluşturmak için kullanılabilecek işlev yoktur. Bunun yerine, genellikle daha kısa olduğu için doğrudan tür söz dizimini kullanırız. Ör. function_type(
[tensor_type([], E), tensor_type([], E)], [tensor_type([], E)])
yerine (tensor<E>, tensor<E>) -> (tensor<E>)
.
Türlerde işlevler
element_type
, tenör türlerinde ve kesirli tenör türlerinde tanımlanır ve sırasıyla ilgiliTensorType
veyaQuantizedTensorType
öğesininTensorElementType
ya daQuantizedTensorElementType
bölümünü döndürür.
def element_type(x: Value | Placeholder | Type):
if type(x) == TensorType:
return tensor_element_type(x)
if type(x) == QuantizedTensorType:
return quantized_tensor_element_type(x)
if type(x) is not Type:
return element_type(type(x))
is_per_axis_quantized(x: Value | Placeholder | Type) -> Value
,is_quantized(x) and quantization_dimension(x) is not None
için bir kısayoldur.is_per_tensor_quantized(x: Value | Placeholder | Type) -> Value
,is_quantized(x) and quantization_dimension(x) is None
için kısayoldur.is_promotable(x: Type, y: Type) -> bool
,x
türününy
türüne yükseltilip yükseltilemeyeceğini kontrol eder.x
vey
QuantizedTensorElementType
olduğunda promosyon yalnızcastorage_type
'e uygulanır. Promosyonun bu sürümü şu anda azaltma hesaplaması bağlamında kullanılmaktadır (daha fazla bilgi için RFC'ye bakın).
def is_promotable(x: Type, y: Type) -> Value:
is_same_type = (is_bool(x) and is_bool(y)) or
(is_integer(x) and is_integer(y)) or (is_float(x) and is_float(y)) or
(is_complex(x) and is_complex(y)) or
(is_quantized(x) and is_quantized(y) and expressed_type(x) = expressed_type(y))
if is_same_type == False:
return False
if is_integer(x) or is_float(x):
return bitwidth(x) <= bitwidth(y)
if is_complex(x):
return bitwidth(element_type(x)) <= bitwidth(element_type(y))
if is_quantized(x):
return bitwidth(storage_type(x)) <= bitwidth(storage_type(y))
return false
is_quantized(x: Value | Placeholder | Type) -> Value
,is_quantized_tensor_element_type(x)
için bir kısayoldur.is_type_name(x: Value | Placeholder | Type) -> Value
. Tüm türlerde kullanılabilir. Örneğin,x
birFloatType
iseis_float(x)
,true
değerini döndürür.x
bir değer veya yer tutucuysa bu işlev,is_type_name(type(x))
için bir kısayoldur.max_value(x: Type) -> Value
, birTensorElementType
değerinin maksimum değerini döndürür.x
birTensorElementType
değilseNone
döndürülür.min_value(x: Type) -> Value
,TensorElementType
için mümkün olan en düşük değeri döndürür.x
birTensorElementType
değilseNone
döndürülür.member_name(x: Value | Placeholder | Type) -> Any
. Tüm türlerdeki tüm üye tanımlarımember_name
için kullanılabilir. Örneğintensor_element_type(x)
, karşılık gelenTensorType
öğesininTensorElementType
bölümünü döndürür.x
bir değer veya yer tutucuysa bu işlev,member_name(type(x))
için bir kısayoldur.x
, uygun bir üyesi olan bir tür değilse veya bu türde bir değer ya da yer tutucu değilseNone
döndürülür.is_empty_algorithm(*args: Type)
, tüm nokta algoritması alanlarınınNone
olarak ayarlanıp ayarlanmadığını kontrol eder. Nokta algoritmalarının uygulamada tanımlanmış varsayılan davranışları olduğundan bu gereklidir. Bu nedenle, varsayılan bir değer belirtmek yanlış olur.
Değerlerin oluşturulması
operation_name(*xs: Value | Type) -> Value
. Tüm işlemler için kullanılabilir. Örneğin,add(lhs, rhs)
iki tenör değerilhs
verhs
alır veadd
işleminin bu girişlerle değerlendirilmesinin sonucunu döndürür. Bazı işlemler (ör.broadcast_in_dim
) için çıkış türleri "yük taşıyıcı"dır, yani bir işlemin değerlendirilmesi için gereklidir. Bu durumda işlev, bu türleri bağımsız değişken olarak alır.
Değerler üzerinde işlevler
Python'un tüm operatörleri ve işlevleri kullanılabilir. Örneğin Python'daki abonelik ve dilimleme gösterimleri, tensörlere, miktarlandırılmış tensörlere ve tuple'lara dizine eklenebilir.
to_destination_type(x: Value, destination_type: Type) -> Value
, tensörlerde tanımlanır vex
değerinin dönüştürülmüş değerinitype(x)
vedestination_type
'a göre aşağıdaki gibi döndürür:
def to_destination_type(x: Value, destination_type: Type) -> Value:
if type(x) == destination_type:
return x
if is_quantized(destination_type):
if is_quantized(type(x)):
return quantize(x, destination_type)
assert is_float(type(x))
return quantize(x, destination_type)
if is_quantized(type(x)):
assert destination_type = expressed_type(type(x))
return dequantize(type(x))
return convert(x, destination_type)
convert
, uniform_quantize
ve uniform_dequantize
işlemlerinin birleştirilmesi hakkında erken bir tartışma var (#1576).
Birleştirme işleminden sonra yukarıdaki işleve ihtiyacımız kalmaz ve bunun yerine convert
için işlem adını kullanabiliriz.
is_nan(x: Value) -> Value
, tensörlerde tanımlanır vex
öğesinin tüm öğeleriNaN
veya aksi takdirdefalse
isetrue
değerini döndürür.x
bir tensör değilseNone
değerini döndürür.is_sorted(x: Value) -> Value
, tensörlerde tanımlanır vex
öğeleri dizinlerinin artan alfabetik sırasına göre artan düzende sıralanmışsatrue
döndürür, aksi takdirdefalse
döndürür.x
bir tensör değilseNone
döndürülür.is_unique(x: Value) -> Value
, tensörlerde tanımlanır vex
'de kopya öğe yoksatrue
, aksi takdirdefalse
döndürür.x
bir tensör değilseNone
döndürülür.member_name(x: Value) -> Any
, tüm değerlerin tüm üye tanımları için tanımlanır.member_name
Örneğin,real_part(x)
, ilgiliComplexConstant
öğesininRealPart
bölümünü döndürür.x
, uygun bir üyesi olan bir değer değilseNone
döndürülür.same(x: Value) -> Value
, tensörlerde tanımlanır vex
öğelerinin tümü birbirine eşitsetrue
, aksi takdirdefalse
döndürür. Tensör öğe içermiyorsa "tümü birbirine eşit" olarak kabul edilir. Yani işlevtrue
döndürür.x
bir tensör değilseNone
döndürülür.split(x: Value, num_results: Value, axis: Value) -> Value
, tensörlerde tanımlanır veaxis
ekseni boyuncax
'ninnum_results
dilimlerini döndürür.x
bir tensör veyadim(x, axis) % num_results != 0
değilseNone
döndürülü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ıysatrue
döndürür.is_namespaced_op_name(x: Value) -> Value
, dizelerde tanımlanır vex
geçerli bir işlem adıysa (yani aşağıdaki normal ifadeye uyarsa)true
döndürür:[a-zA-Z][a-zA-Z0-9_]*([.][a-zA-Z0-9_$]+)+
Şekil hesaplamaları
axes(x: Value | Placeholder | Type) -> Value
,range(rank(x))
için bir kısayoldur.dim(x: Value | Placeholder | Type, axis: Value) -> Value
,shape(x)[axis]
için bir kısayoldur.dims(x: Value | Placeholder | Type, axes: List) -> List
,list(map(lambda axis: dim(x, axis), axes))
için bir kısayoldur.index_space(x: Value | Placeholder | Type) -> Value
, tensörlerde tanımlanır ve karşılık gelenTensorType
için[0, ..., 0]
,[0, ..., 1]
, ...,shape(x) - 1
şeklinde artan alfabetik sırayla dizilmişsize(x)
dizinleri döndürür.x
bir tensör türü, kesirli tensör türü, değer veya bu türlerden birinin yer tutucusu değilseNone
döndürülür.rank(x: Value | Placeholder | Type) -> Value
,size(shape(x))
için bir kısayoldur.shape(x: Value | Placeholder | Type) -> Value
,member_name
aracılığıyla "Türlerdeki işlevler" bölümünde tanımlanır.size(x: Value | Placeholder | Type) -> Value
,reduce(lambda x, y: x * y, shape(x))
için bir kısayoldur.
Kesirli sayı hesaplamaları
def baseline_element_type(x: Value | Placeholder | Type) -> Type
,element_type(baseline_type(x))
için kısayoldur.baseline_type
, tenör türleri ve kesirli tenör türleri üzerinde tanımlanır ve bunları bir "temel çizgiye", yani aynı şekle sahip ancak öğe türünün kesirli parametreleri varsayılan değerlere sıfırlanmış bir türe dönüştürür. Bu, oldukça sık ihtiyaç duyulan tensör ve nicel tensör türlerini eşit şekilde karşılaştırmak için kullanışlı bir yöntem olarak kullanılır. Bu, kesirli türler için kesirli parametreler göz ardı edilerek türlerin karşılaştırılmasını sağlar. Yanishape
,storage_type
,expressed_type
,storage_min
,storage_max
vequantization_dimension
(eksen başına kesirli tür için) değerlerinin tümü eşleşmelidir ancakscales
vezero points
farklı olabilir.
def baseline_type(x: Value | Placeholder | Type) -> Type:
if type(x) == TensorType:
return x
if type(x) == QuantizedTensorType:
element_type = quantized_tensor_element_type(x)
baseline_element_type = QuantizedTensorElementType(
storage_type = storage_type(element_type),
storage_min = storage_min(element_type),
storage_max = storage_max(element_type),
expressed_type = expressed_type(element_type),
quantization_dimension = quantization_dimension(element_type),
scales = [constant(1.0, expressed_type(element_type))] * dim(x, quantization_dimension(element_type)),
zero_points = [constant(0, storage_type(element_type))] * dim(x, quantization_dimension(element_type)))
return QuantizedTensorType(shape(x), baseline_element_type)
if type(x) is not Type:
return baseline_element_type(type(x))
dequantize
, kesirli vektör türlerinde tanımlanır ve bunları kayan nokta vektör türlerine dönüştürür. Bu işlem, depolama alanı türünün tam sayı değerlerini temsil eden kesikli öğeleri, kesikli öğe türüyle ilişkili sıfır noktası ve ölçek kullanılarak ifade edilen türün karşılık gelen kayan nokta değerlerine dönüştürerek gerçekleştirilir.
def compute_zero_points(quantized_type, result_type):
if is_per_tensor_quantized(quantized_type):
return broadcast_in_dim(constant(zero_point(quantized_type), storage_type(quantized_type)), [], result_type)
if is_per_axis_quantized(quantized_type):
for i in index_space(result_type):
d = quantization_dimension(quantized_type)
zero_points[i] = zero_points(quantized_type)[i[d]]
return zero_points
def compute_scales(quantized_type, result_type):
if is_per_tensor_quantized(quantized_type):
return broadcast_in_dim(constant(scale(quantized_type), expressed_type(quantized_type)), [],
type(result_type))
if is_per_axis_quantized(quantized_type):
for i in index_space(result_type):
d = quantization_dimension(quantized_type)
scales[i] = scales(quantized_type)[i[d]]
return scales
def dequantize(x: Value) -> Value:
assert is_quantized(x)
x_storage = bitcast_convert(x, storage_type(x))
x_storage_sub = x_storage - compute_zero_points(type(x), type(x_storage))
x_expressed_sub = convert(x_storage_sub, expressed_type(x))
return x_expressed_sub * compute_scales(type(x), type(x_expressed_sub))
quantize
, kayan noktalı tenör türlerinde tanımlanır ve bunları kesirli tenör türlerine dönüştürür. Bu işlem, miktarlandırılmış öğe türüyle ilişkili sıfır noktası ve ölçeği kullanılarak ifade edilen türdeki kayan nokta değerlerinin depolama türünün karşılık gelen tam sayı değerlerine dönüştürülmesiyle gerçekleşir.
def quantize(x: Value, result_type: Type) -> Value:
assert is_float(x) and is_quantized(result_type)
zero_points = compute_zero_points(result_type, TensorType(shape(x), storage_type(result_type)))
converted_zero_points = convert(zero_points, expressed_type(result_type))
converted_min = convert(storage_min(result_type), expressed_type(result_type))
converted_max = convert(storage_max(result_type), expressed_type(result_type))
x_scaled = x / compute_scales(result_type, type(x))
x_scaled_add_zp = x_scaled + converted_zero_points
x_clamped = clamp(converted_min, x_scaled_add_zp, converted_max)
x_rounded = round_nearest_even(x_clamped)
return convert(x_rounded, result_type)
dequantize_op_quantize
, kesikli tenzorlarda öğe bazında hesaplamaları belirtmek için kullanılır. Önce nicelleştirmeyi kaldırır (yani nicelleştirilmiş öğeleri ifade edilen türlerine dönüştürür), ardından bir işlem gerçekleştirir ve daha sonra nicelleştirme yapar (yani sonuçları tekrar depolama türlerine dönüştürür). Bu işlev şu anda yalnızca tensör başına kesme işlemi için kullanılabilir. Eksen başına kesme işlemi üzerinde çalışılıyor (#1574).
def dequantize_op_quantize(op, *inputs_and_output_type):
inputs = inputs_and_output_type[:-1]
output_type = inputs_and_output_type[-1]
float_inputs = map(dequantize, inputs)
float_result = op(*float_inputs)
return quantize(float_result, output_type)
def dequantize_batch_norm_grad_or_training_quantize(op, *inputs_and_output_types):
inputs = inputs_and_output_type[:-3]
float_inputs = map(dequantize, inputs)
float_results = op(*float_inputs)
return map(quantize, float_results, inputs_and_output_type[-3:])
def dequantize_compare(lhs, rhs, comparison_direction):
float_lhs = dequantize(lhs)
float_rhs = dequantize(rhs)
return compare(float_lhs, float_rhs, comparison_direction, FLOAT)
def dequantize_select_quantize(pred, on_true, on_false, output_type):
float_on_true = dequantize(on_true)
float_on_false = dequantize(on_false)
float_result = select(pred, float_on_true, float_on_false)
return quantize(float_result, output_type)
hybrid_dequantize_then_op
, kayan noktalı olarak lh ve miktarlandırılmış türlerde rh'leri kabul eden karma işlem için yalnızca ağırlıkla ilgili miktarlandırmayı belirtmek amacıyla kullanılır. Ölçülmüş girişleri ifade edilen türlerine göre dequantize eder ve hesaplamayı float olarak gerçekleştirir. Kayan lhs tensörünün öğe türü ve ifade edilen nicel rhs tensörü türü aynı olmalıdır.
def hybrid_dequantize_then_op(op, lhs, rhs):
assert(is_float(lhs) and is_quantized(rhs) and element_type(lhs) == expressed_type(rhs))
return op(lhs, dequantize(rhs))
Izgara hesaplamaları
cross_partition(replica_groups: Value) -> Value
. Yukarıdaki "cross_replica" bölümüne bakın.cross_replica(replica_groups: Value) -> Value
. Yukarıdaki "cross_replica" bölümüne bakın.cross_replica_and_partition(replica_groups: Value) -> Value
. Yukarıdaki "cross_replica_and_partition" bölümüne bakın.flattened_ids(replica_groups: Value) -> Value
. Yukarıdaki "flattened_ids" bölümüne bakın.
Dinamizm
StableHLO değerleri dinamik boyut boyutlarına sahip olabilir (ör. tensor<?xi64>
).
Ancak StableHLO değerleri dinamik sayıda boyuta sahip olamaz (sıralanmamış dinamizm, ör. tensor<*xi64>
). Operan ve sonuçlarda, boyutlar üzerinde kısıtlamalar olsa bile dinamik boyut boyutlarının kullanılmasına izin verilir. Kısıtlamalar, mümkünse statik olarak doğrulanır. Aksi takdirde, çalışma zamanına ertelenirler ve uyuşmazlıklar tanımlanmamış davranışa yol açar. Örnekler için aşağıya bakın.
Bir öğeyle ilgili tek adımlı işlemler için şekil uyuşmazlıkları
Aşağıdaki oyuncak programı düşünün:
func.func @foo(%arg0: tensor<?xf64>) {
%0 = stablehlo.abs %arg0 : (tensor<?xf64>) -> tensor<2xf64>
return
}
Sonucun şeklinin bilinmesi yaygın olmasa da girdinin şekli bilinmediği için böyle bir program olağan dışıdır. Yine de bu geçerli bir StableHLO programıdır. Operanın tam şekli bilinmediği için bu programdaki abs
işlemini statik olarak doğrulamak mümkün değildir. Ancak şekiller kesinlikle uyumludur ve bu durum statik olarak kontrol edilebilir: ?
, çalışma zamanında 2
olabilir ve herhangi bir sorun yaşanmaz. Ancak ?
başka bir tam sayı da olabilir. Bu durumda davranış tanımlanmaz.
Sonuçta bir boyut boyutu dinamikse tanımlanmamış davranış olmayacağını unutmayın. "Beklenen" boyut olmadığından eşleşme sorunu olamaz.
İkili öğe bazında işlemler için şekil uyuşmazlıkları
Aşağıdaki oyuncak programı düşünün:
func.func @foo(%arg0: tensor<?xf64>, %arg1: tensor<?xf64>) {
%0 = stablehlo.add %arg0, %arg0 : (tensor<?xf64>, tensor<?xf64>) -> tensor<?xf64>
return
}
İkili öğe bazında işlemlerde, girişlerin ve sonucun şekilleri çalışma zamanında aynı olmalıdır. Statik boyutlar derleme zamanında eşit olmalıdır. Aksi takdirde yalnızca uyumlu olmaları gerekir. Girişlerde herhangi bir boyut dinamikse dinamik boyut, diğer operatördeki (statik veya dinamik) ilgili boyutla eşleşmeyebileceğinden çalışma zamanında tanımlanmamış bir davranış olabilir. Tüm girişler statikse sonucun dinamik olup olmadığı önemli değildir: Statik olarak bilinen boyutlar statik olarak kontrol edilir ve dinamik boyutlar herhangi bir kısıtlama getirmez.
Çıktı şeklini işlenen olarak alan işlemler için şekil uyuşmazlıkları
Aşağıdaki oyuncak programı düşünün:
func.func @foo(%arg0: tensor<2xi32>) {
%0 = stablehlo.dynamic_iota %arg0, dim = 0 : (tensor<2xi32>) -> tensor<3x4xi64>
return
}
Çalışma zamanında şekil operatöründe bulunan değerler, sonucun şekliyle eşleşmelidir. Aksi takdirde davranış tanımlanmaz. Yani, çalışma zamanında %arg0
değerinin dense<[3, 4]> : tensor<2xi32>
olması gerekir. Şekil operanı sabitse bu durum statik olarak doğrulanabilir. Sonuç şekli tamamen dinamikse bir uyumsuzluk oluşamaz.