StableHLO, मशीन में हाई-लेवल ऑपरेशन (HLO) के लिए इस्तेमाल होने वाला एक ऑपरेशन सेट है लर्निंग (एमएल) मॉडल. StableHLO, अलग-अलग प्लैटफ़ॉर्म के बीच पोर्टेबिलिटी लेयर के तौर पर काम करता है एमएल फ़्रेमवर्क और एमएल कंपाइलर: एमएल फ़्रेमवर्क जो StableHLO प्रोग्राम बनाते हैं एमएल कंपाइलर के साथ काम करते हैं, जो StableHLO प्रोग्राम का इस्तेमाल करते हैं.
हमारा मकसद, मशीन लर्निंग को आसान बनाने के साथ-साथ मशीन लर्निंग को बेहतर बनाने के लिए, मशीन लर्निंग सिस्टम को अलग-अलग एमएल फ़्रेमवर्क के बीच इंटरऑपरेबिलिटी (दूसरे सिस्टम के साथ काम करना), जैसे कि TensorFlow, JAX, और PyTorch) और ML कंपाइलर (जैसे कि XLA और IREE). उस ओर, यह इस दस्तावेज़ में StableHLO प्रोग्रामिंग भाषा की जानकारी दी गई है.
इस स्पेसिफ़िकेशन में तीन मुख्य सेक्शन शामिल हैं. सबसे पहले, प्रोग्राम सेक्शन में, StableHLO प्रोग्राम की बनावट के बारे में जानकारी दी जाती है इनमें StableHLO फ़ंक्शन शामिल होते हैं, जिनमें StableHLO ops शामिल होता है. उस स्ट्रक्चर में, Ops सेक्शन, व्यक्तिगत ऑपरेशन एक्ज़िक्यूशन सेक्शन सभी के लिए सिमेंटिक उपलब्ध कराता है ये Ops, किसी प्रोग्राम में एक साथ एक्ज़ीक्यूट किए जाते हैं. आख़िर में, नोटेशन सेक्शन में स्पेसिफ़िकेशन.
StableHLO की पिछली रिलीज़ की खास जानकारी देखने के लिए, रेपो खोलें पसंद की टैग की गई रिलीज़. उदाहरण के लिए, StableHLO v0.19.0 स्पेसिफ़िकेशन. StableHLO के हर छोटे वर्शन बंप पर होने वाले बदलावों को देखने के लिए, इसे देखें VhloDialect.td वर्शन में लॉग इन करें.
प्रोग्राम
Program ::= {Func}
StableHLO प्रोग्राम में आर्बिट्रेरी संख्या में StableHLO फ़ंक्शन होते हैं.
यहां @main
फ़ंक्शन वाले प्रोग्राम का उदाहरण दिया गया है, जिसमें तीन इनपुट हैं
(%image
, %weights
और %bias
) और 1 आउटपुट. फ़ंक्शन का मुख्य हिस्सा
में 6 ऑपरेशन हैं.
func.func @main(
%image: tensor<28x28xf32>,
%weights: tensor<784x10xf32>,
%bias: tensor<1x10xf32>
) -> tensor<1x10xf32> {
%0 = "stablehlo.reshape"(%image) : (tensor<28x28xf32>) -> tensor<1x784xf32>
%1 = "stablehlo.dot"(%0, %weights) : (tensor<1x784xf32>, tensor<784x10xf32>) -> tensor<1x10xf32>
%2 = "stablehlo.add"(%1, %bias) : (tensor<1x10xf32>, tensor<1x10xf32>) -> tensor<1x10xf32>
%3 = "stablehlo.constant"() {value = dense<0.0> : tensor<1x10xf32>} : () -> tensor<1x10xf32>
%4 = "stablehlo.maximum"(%2, %3) : (tensor<1x10xf32>, tensor<1x10xf32>) -> tensor<1x10xf32>
"func.return"(%4): (tensor<1x10xf32>) -> ()
}
फ़ंक्शन
Func ::= 'func' '.' 'func' FuncId FuncInputs FuncOutputs '{' FuncBody '}'
FuncInputs ::= '(' [FuncInput {',' FuncInput}] `)`
FuncInput ::= ValueId ':' ValueType
FuncOutputs ::= ['->' FuncOutput, {',' FuncOutput}]
FuncOutput ::= ValueType
FuncBody ::= {Op}
StableHLO फ़ंक्शन (जिन्हें नाम वाले फ़ंक्शन भी कहा जाता है) में एक आइडेंटिफ़ायर, इनपुट/आउटपुट, और एक बॉडी. आने वाले समय में, हम फ़ंक्शन के लिए अतिरिक्त मेटाडेटा की जानकारी दें, ताकि वे बेहतर तरीके से काम कर सकें HLO (#425, #626, #740, #744).
आइडेंटिफ़ायर
FuncId ::= '@' letter {letter | digit}
ValueId ::= '%' digit {digit}
| '%' letter {letter | digit}
letter ::= 'a' | ... | 'z' | 'A' | ... | 'Z' | '_'
digit ::= '0' | ... | '9'
StableHLO आइडेंटिफ़ायर, कई प्रोग्राम में मौजूद आइडेंटिफ़ायर से मिलते-जुलते होते हैं होती है, जिसकी दो विशेषताएं होती हैं: 1) सभी आइडेंटिफ़ायर अलग-अलग तरह के आइडेंटिफ़ायर में अंतर करें, 2) वैल्यू आइडेंटिफ़ायर StableHLO प्रोग्राम की जनरेशन को आसान बनाने के लिए पूरी तरह से न्यूमेरिक.
टाइप
Type ::= ValueType | NonValueType
ValueType ::= TensorType | QuantizedTensorType | TokenType | TupleType
NonValueType ::= TensorElementType | QuantizedTensorElementType | FunctionType | StringType
StableHLO टाइप को वैल्यू टाइप में रखा जाता है (इन्हें फ़र्स्ट-क्लास टाइप) जो StableHLO वैल्यू और नॉन-वैल्यू टाइप दिखाते हैं जो प्रोग्राम से जुड़े अन्य एलिमेंट के बारे में बताती हैं. StableHLO के टाइप, कई प्रोग्रामिंग भाषाओं में से एक है, जिसकी मुख्य विशेषता StableHLO एक खास डोमेन के लिए तैयार किया गया है, जिसकी वजह से कुछ असामान्य नतीजे मिलते हैं (उदाहरण के लिए, स्केलर टाइप वैल्यू टाइप नहीं हैं).
TensorType ::= 'tensor' '<' Shape TensorElementType '>'
Shape ::= {DimensionSize 'x'}
DimensionSize ::= digit {digit} | '?'
टेन्सर के टाइप टेंसर यानी कई डाइमेंशन वाले सरणियों को दिखाते हैं. उनके पास
आकार और एलिमेंट का टाइप, जिसमें आकार गैर-ऋणात्मक या
संबंधित डाइमेंशन साइज़ के बढ़ते क्रम में
डाइमेंशन (जिन्हें ऐक्सिस भी कहा जाता है) को 0
से R-1
तक के नंबर के साथ लिखा जाता है. कॉन्टेंट बनाने
डाइमेंशन की संख्या R
को रैंक कहा जाता है. उदाहरण के लिए, tensor<2x3xf32>
2x3
आकार और f32
एलिमेंट वाला टेंसर टाइप. इसमें दो डाइमेंशन हैं
(या, दूसरे शब्दों में, दो ऐक्सिस) - पहला डाइमेंशन और पहला डाइमेंशन - जिसके साइज़
नंबर 2 और 3 हैं. इसकी रैंक दो है.
आकार आंशिक या पूरी तरह से अज्ञात (डाइनैमिक) हो सकता है, जैसे tensor<?x2xf64>
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है
आंशिक रूप से अज्ञात है और tensor<?x?xf64>
पूरी तरह अज्ञात है. डाइनैमिक
डाइमेंशन के साइज़ को ?
का इस्तेमाल करके दिखाया जाता है. आकारों को अनरैंक नहीं किया जा सकता.
आने वाले समय में, हम ऐसे अन्य टेंसर टाइप एक्सप्लोर करने की योजना बना रहे हैं जो डाइमेंशन साइज़ और एलिमेंट टाइप. उदाहरण के लिए, लेआउट शामिल करने के लिए (#629) और विरलता (#1078).
QuantizedTensorType ::= 'tensor' '<' Shape QuantizedTensorElementType '>'
QuantizedTensorElementType ::= '!quant.uniform' '<'
QuantizationStorageType
['<' QuantizationStorageMin ':' QuantizationStorageMax '>']
':' QuantizationExpressedType
[':' QuantizationDimension]
',' QuantizationParameters '>'
QuantizationStorageType ::= IntegerType
QuantizationStorageMin ::= IntegerConstant
QuantizationStorageMax ::= IntegerConstant
QuantizationExpressedType ::= FloatType
QuantizationDimension ::= IntegerConstant
QuantizationParameters ::= QuantizationParameter
| '{' QuantizationParameter {',' QuantizationParameter} '}'
QuantizationParameter ::= QuantizationScale ':' QuantizationZeroPoint
QuantizationScale ::= FloatConstant
QuantizationZeroPoint ::= IntegerConstant
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
storage_type |
पूर्णांक का टाइप | (C1-C3), (C8) |
storage_min |
पूर्णांक कॉन्सटेंट | (C1), (C3), (C7) |
storage_max |
पूर्णांक कॉन्सटेंट | (C2), (C3), (C7) |
expressed_type |
फ़्लोटिंग-पॉइंट टाइप | (सी4) |
quantization_dimension |
वैकल्पिक पूर्णांक कॉन्सटेंट | (C10-C12) |
scales |
फ़्लोटिंग-पॉइंट कॉन्सटेंट की वैरायडिक संख्या | (C4-C6), (C9), (C10), (C13) |
zero_points |
पूर्णांक कॉन्सटेंट की वैरायडिक संख्या | (C7-C9) |
क्वांटाइज़ किए गए एलिमेंट टाइप, स्टोरेज टाइप के पूर्णांक वैल्यू को दिखाते हैं
storage_min
से storage_max
तक की श्रेणी (शामिल) जो इससे संबंधित है
दिखाए गए टाइप के फ़्लोटिंग-पॉइंट वैल्यू. दी गई पूर्णांक वैल्यू i
के लिए,
संबंधित फ़्लोटिंग-पॉइंट मान f
का हिसाब इस तरह से लगाया जा सकता है
f = (i - zero_point) * scale
, जहां scale
और zero_point
को कॉल किया जाता है
क्वांटाइज़ेशन पैरामीटर. storage_min
और storage_max
ज़रूरी नहीं हैं
व्याकरण में है, लेकिन डिफ़ॉल्ट तौर पर min_value(storage_type)
और
max_value(storage_type)
. क्वांटाइज़्ड एलिमेंट टाइप में
शर्तों को पूरा करना होगा:
- (C1)
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)
है, तोsize(scales) = 1
. - (C11)
0 <= quantization_dimension
.
इस समय, QuantizationScale
एक फ़्लोटिंग-पॉइंट कॉन्सटेंट है, लेकिन वहां
पूर्णांक-आधारित स्केल में ज़्यादा दिलचस्पी होना, जिसे मल्टीप्लायर से दिखाया गया हो और
शिफ़्ट. हम आने वाले समय में इस पर काम करने के बारे में सोच रहे हैं
(#1404).
QuantizationZeroPoint
के सिमैंटिक पर एक बातचीत चल रही है,
इसमें वे टाइप और वैल्यू शामिल होती हैं. साथ ही, यह भी जानकारी होती है कि क्या सिर्फ़ एक या
क्वांटाइज़्ड टेंसर टाइप में, कई शून्य पॉइंट हो सकते हैं. इसके आधार पर
इस चर्चा के परिणाम, शून्य बिंदु के लिए निर्देश बदल सकते हैं
आने वाले समय में (#1405).
एक अन्य चर्चा में QuantizationStorageMin
के सिमेंटिक्स शामिल हैं
और QuantizationStorageMax
तय करते हैं कि किसी कंस्ट्रेंट को
इन वैल्यू और क्वांटाइज़्ड टेंसर की वैल्यू पर लगाया गया
(#1406).
आखिर में, हम अज्ञात स्केल और शून्य को दर्शाने वाले तरीके के बारे में जानने की योजना बना रहे हैं जैसे हम अनजान लोगों को दिखाने के लिए डाइमेंशन का साइज़ (#1407).
क्वांटाइज़्ड टेंसर टाइप, क्वांटाइज़्ड एलिमेंट वाले टेंसर दिखाते हैं. ये टेंसर, सामान्य टेंसर की तरह ही होते हैं, अंतर सिर्फ़ इतना होता है कि उनके एलिमेंट इसमें सामान्य एलिमेंट के बजाय क्वांटाइज़्ड एलिमेंट टाइप होते हैं.
क्वांटाइज़्ड टेंसर में, क्वांटाइज़ेशन हर टेंसर के हिसाब से हो सकता है. इसका मतलब है कि
पूरे टेंसर के लिए एक scale
और zero_point
या हर ऐक्सिस पर एक वैल्यू हो सकती है,
मतलब कई scales
और zero_points
होने का मतलब है, इमेज के हर स्लाइस के लिए एक जोड़ा
कोई विशेष आयाम quantization_dimension
. औपचारिक तौर पर, टेंसर में t
हर एक्सिस पर संख्या के हिसाब से, dim(t, quantization_dimension)
स्लाइस हैं
quantization_dimension
में से: t[:, ..., 0, ..., :], t[:, ..., 1, ..., :]
,
वगैरह. i
वें स्लाइस के सभी एलिमेंट में scales[i]
और zero_points[i]
का इस्तेमाल इस तौर पर किया जाएगा
में अपने क्वांटाइज़ेशन पैरामीटर को जोड़ दिया जाता है. क्वांटाइज़्ड टेंसर के टाइप में ये शामिल हैं
सीमाएं:
- हर टेन्सर की क्वांटाइज़ेशन के लिए:
- कोई अतिरिक्त शर्त नहीं.
- हर ऐक्सिस पर प्रॉडक्ट की संख्या बढ़ाने के लिए:
- (C12)
quantization_dimension < rank(self)
. - (C13)
dim(self, quantization_dimension) = size(scales)
.
- (C12)
TokenType ::= 'token'
टोकन के टाइप, टोकन दिखाते हैं. जैसे, बनी और इस्तेमाल की गई ओपेक वैल्यू कुछ कार्रवाइयों से किया जा सकता है. टोकन का इस्तेमाल कार्रवाइयों को लागू करने का ऑर्डर देने के लिए किया जाता है जैसा कि इस्तेमाल करना सेक्शन में बताया गया है.
TupleType ::= 'tuple' '<' TupleElementTypes '>'
TupleElementTypes ::= [ValueType {',' ValueType}]
ट्यूपल टाइप, ट्यूपल को दिखाते हैं. जैसे, विषमांगी सूचियां. टपल्स एक लेगसी हैं
ऐसी सुविधा है जो सिर्फ़ HLO के साथ काम करने के लिए मौजूद है. HLO में, टपल्स
इसका इस्तेमाल वैरिडिक इनपुट और आउटपुट को दिखाने के लिए किया जाता है. StableHLO में, वैरायडिक इनपुट और
आउटपुट, नेटिव तौर पर काम करते हैं. साथ ही, StableHLO में टुपल का सिर्फ़ यह इस्तेमाल किया जाता है कि
HLO ABI को अच्छी तरह से दिखाता है, जहां उदाहरण के लिए, T
, tuple<T>
, और
tuple<tuple<T>>
किसी खास डेटा टाइप के आधार पर असल में अलग हो सकता है
लागू करना. आने वाले समय में, हम एचएलओ एबीआई में बदलाव करने की योजना बना रहे हैं
जिसकी मदद से हम StableHLO से ट्यूपल टाइप हटा सकते हैं
(#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 ::= 'f8E4M3FN' | 'f8E5M2' | 'f8E4M3FNUZ' | 'f8E5M2FNUZ'
| 'f8E4M3B11FNUZ' | 'bf16' | 'f16' | 'f32' | 'f64'
TensorFloat32 ::= 'tf32'
ComplexType ::= 'complex' '<' ComplexElementType '>'
ComplexElementType ::= 'f32' | 'f64'
एलिमेंट टाइप, टेंसर टाइप के एलिमेंट दिखाते हैं. कई तरह के कॉन्टेंट से अलग
नहीं हैं, तो ये प्रकार StableHLO में प्रथम श्रेणी के नहीं हैं. इसका मतलब है कि
StableHLO प्रोग्राम, सीधे तौर पर इस तरह की वैल्यू नहीं दिखा सकते. इसकी वजह से,
T
टाइप की अदिश वैल्यू को 0-डाइमेंशन वाले टेंसर के साथ दिखाना मुहावरेदार होता है
tensor<T>
टाइप की वैल्यू).
- बूलियन टाइप, बूलियन वैल्यू
true
औरfalse
को दिखाता है. - इंटिजर टाइप साइन (
si
) या अनसाइन किए गए (ui
) हो सकते हैं. साथ ही, काम करने वाली बिट की चौड़ाई (2
,4
,8
,16
,32
या64
) में से कोई एक. साइन किए गएsiN
टाइप,-2^(N-1)
से2^(N-1)-1
तक की पूर्णांक वैल्यू दिखाते हैं शामिल हैं, और अनसाइन किए गएuiN
टाइप,0
से लेकर इंटिजर वैल्यू को दिखाते हैं2^N-1
के साथ. - फ़्लोटिंग-पॉइंट के टाइप इनमें से कोई एक हो सकते हैं:
f8E4M3FN
औरf8E5M2
टाइप, जो FP8 फ़ॉर्मैट कीE4M3
औरE5M2
एन्कोडिंग में बताया गया है डीप लर्निंग के लिए FP8 फ़ॉर्मैट.E4M3
औरE5M2
से जुड़ेf8E4M3FNUZ
औरf8E5M2FNUZ
टाइप FP8 फ़ॉर्मैट की एन्कोडिंग में बताए गए हैं डीप न्यूरल नेटवर्क के लिए 8-बिट नंबर वाले फ़ॉर्मैट.- FP8 फ़ॉर्मैट की
E4M3
एन्कोडिंग से जुड़ाf8E4M3B11FNUZ
टाइप इसमें बताया गया है डीप न्यूरल नेटवर्क के लिए, हाइब्रिड 8-बिट फ़्लोटिंग पॉइंट (HFP8) ट्रेनिंग और अनुमान. bf16
टाइप, जो इसमें बताए गएbfloat16
फ़ॉर्मैट से जुड़ा है BFloat16: Cloud TPU पर बेहतर परफ़ॉर्मेंस पाने का सीक्रेट.- इसी तरह के
f16
,f32
, औरf64
टाइपbinary16
("हाफ़ सटीक"),binary32
("एकल सटीक") औरbinary64
("दोगुने सटीक") फ़ॉर्मैट में बताया गया है आईईईई 754 स्टैंडर्ड. tf32
टाइप, TensorFloat32 फ़ॉर्मैट से मेल खाता है और StableHLO में पूरी तरह से काम नहीं करता है.
- जटिल प्रकार ऐसे जटिल मान दिखाते हैं जिनका वास्तविक भाग होता है
और उसी एलिमेंट टाइप का कोई काल्पनिक हिस्सा. इस्तेमाल किया जा सकने वाला कॉम्प्लेक्स
टाइप
complex<f32>
हैं (दोनों हिस्सेf32
टाइप के हैं) औरcomplex<f64>
(दोनों हिस्सेf64
टाइप के हैं).
FunctionType ::= '(' InputTypes ')' '->' '(' OutputTypes ')'
InputTypes ::= [ValueType {',' ValueType}]
OutputTypes ::= [ValueType {',' ValueType}]
फ़ंक्शन टाइप नाम वाले और पहचान छिपाने वाले, दोनों तरह के फ़ंक्शन दिखाते हैं. उनके पास
इनपुट टाइप (->
की बाईं ओर मौजूद टाइप की सूची) और आउटपुट टाइप
(->
की दाईं ओर टाइप की सूची). कई प्रोग्रामिंग में
भाषाओं के आधार पर, फ़ंक्शन टाइप फ़र्स्ट क्लास हैं, लेकिन StableHLO में नहीं.
StringType ::= 'string'
स्ट्रिंग टाइप, बाइट के क्रम को दिखाता है. कई तरह के कॉन्टेंट से अलग भाषाओं के साथ-साथ, StableHLO में स्ट्रिंग टाइप फ़र्स्ट क्लास नहीं होता है. इसका इस्तेमाल सिर्फ़ इन कामों के लिए किया जाता है प्रोग्राम के एलिमेंट के लिए स्टैटिक मेटाडेटा की जानकारी दें.
ऑपरेशंस
StableHLO ऑपरेशन (जिन्हें ops भी कहा जाता है) एक बंद सेट का प्रतिनिधित्व करते हैं में हाई-लेवल ऑपरेशन के बारे में बताया गया है. जैसा कि ऊपर बताया गया है, StableHLO सिंटैक्स काफ़ी हद तक MLIR से प्रभावित होता है. यह ज़रूरी नहीं है कि एर्गोनॉमिक विकल्प है, लेकिन निश्चित रूप से यह StableHLO के एमएल फ़्रेमवर्क और एमएल कंपाइलर के बीच ज़्यादा इंटरऑपरेबिलिटी (दूसरे सिस्टम के साथ काम करना) बनाना.
Op ::= [OpOutputs] OpName OpInputs ':' OpSignature
OpName ::= '"' 'stablehlo' '.' OpMnemonic '"'
OpMnemonic ::= 'abs' | 'add' | ...
StableHLO ऑपरेशंस (जिन्हें ops भी कहा जाता है) का एक नाम है,
इनपुट/आउटपुट और एक हस्ताक्षर. नाम में stablehlo.
प्रीफ़िक्स शामिल है और
स्मृति एक ऐसी सुविधा है जो काम करने वाली कार्रवाइयों में से किसी एक की खास तौर पर पहचान करती है. इनके लिए नीचे देखें
उन सभी ऑपरेशन की पूरी सूची होगी जिनका इस्तेमाल किया जा सकता है.
OpInputs ::= OpInputValues OpInputFuncs OpInputAttrs
OpInputValues ::= '(' [OpInputValue {',' OpInputValue}] ')'
OpInputValue ::= ValueId
OpInputFuncs ::= ['(' OpInputFunc {',' OpInputFunc} ')']
OpInputAttrs ::= ['{' OpInputAttr {',' OpInputAttr} '}']
OpOutputs ::= [OpOutput {',' OpOutput} '=']
OpOutput ::= ValueId
ऑपरेशन इनपुट का इस्तेमाल करते हैं और आउटपुट बनाते हैं. इनपुट को इसमें कैटगरी में बांटा गया है
इनपुट वैल्यू (एक्ज़िक्यूशन के दौरान कैलकुलेट की गई), इनपुट फ़ंक्शन (दिया गए
स्थिर रूप से, क्योंकि StableHLO में फ़ंक्शन फ़र्स्ट-क्लास वैल्यू नहीं होते हैं) और
एट्रिब्यूट की वैल्यू डालें (स्टैटिक तरीके से भी दी गई). इनपुट और आउटपुट किस तरह के हैं
यह ऑपर्च्यूनिटी की वजह से बनाया जाता है और इसका इस्तेमाल किया जाता है. उदाहरण के लिए, add
op, दो इनपुट वैल्यू का इस्तेमाल करता है और एक आउटपुट वैल्यू देता है. इसके मुकाबले,
select_and_scatter
op, तीन इनपुट वैल्यू, दो इनपुट फ़ंक्शन, और
तीन इनपुट एट्रिब्यूट.
OpInputFunc ::= '{' Unused FuncInputs ':' FuncBody '}'
Unused ::= '^' digit {digit}
| '^' letter {letter | digit}
इनपुट फ़ंक्शन (जिन्हें अनाम फ़ंक्शन भी कहा जाता है) वे
नाम वाले फ़ंक्शन से मिलते-जुलते हैं, लेकिन शामिल हैं: 1) इनमें कोई आइडेंटिफ़ायर नहीं है (इसलिए)
नाम "अनाम"), 2) आउटपुट टाइप का एलान नहीं करते.
फ़ंक्शन के अंदर return
ऑप से अनुमान लगाया जाता है).
इनपुट फ़ंक्शन के सिंटैक्स में अभी इस्तेमाल न किया गया एक हिस्सा शामिल है (देखें
Unused
प्रोडक्शन, जो कि एमएलआईआर के साथ काम करने के लिए उपलब्ध है. MLIR में,
"क्षेत्र" एक सामान्य कॉन्सेप्ट है, जिसे जिसमें एक से ज़्यादा "ब्लॉक" हो सकते हैं
जंप ऑपरेशन के ज़रिए एक साथ जुड़े ऑपरेटर हैं. इन ब्लॉक में ऐसे आईडी हैं जो इससे जुड़े हैं
Unused
प्रोडक्शन में ऐसा किया गया हो, ताकि वे एक-दूसरे से अलग दिखें.
StableHLO में जंप ops नहीं है, इसलिए MLIR सिंटैक्स का संबंधित हिस्सा यह है
इस्तेमाल नहीं किया गया है (लेकिन अब भी मौजूद है).
OpInputAttr ::= OpInputAttrName '=' OpInputAttrValue
OpInputAttrName ::= letter {letter | digit}
OpInputAttrValue ::= Constant
इनपुट एट्रिब्यूट का एक नाम और एक वैल्यू होती है, जो इस्तेमाल की जा सकने वाली एट्रिब्यूट में से एक है
स्थिरांक. ये प्रोग्राम के लिए स्टैटिक मेटाडेटा तय करने का मुख्य तरीका हैं
एलिमेंट. उदाहरण के लिए, concatenate
op, dimension
एट्रिब्यूट का इस्तेमाल इन कामों के लिए करता है
वह डाइमेंशन तय करना जिसके ज़रिए इसकी इनपुट वैल्यू जोड़ी गई हैं. इसी तरह,
slice
सेशन, start_indices
और limit_indices
जैसे कई एट्रिब्यूट का इस्तेमाल करता है
का इस्तेमाल करें.
इस समय, जंगल में स्थित StableHLO प्रोग्राम में कभी-कभी एट्रिब्युट शामिल होते हैं जिनकी जानकारी इस दस्तावेज़ में नहीं दी गई है. आने वाले समय में, हम या तो इन एट्रिब्यूट को StableHLO ऑपसेट में सोख लें या उन्हें ऐसा करने से रोकें जो StableHLO प्रोग्राम में दिखते हैं. तब तक, यहां इन विज्ञापनों की सूची दी गई है विशेषताएं:
layout
(#629).mhlo.frontend_attributes
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है (#628).mhlo.sharding
(#619).output_operand_aliases
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है (#740).- जगह की जानकारी का मेटाडेटा (#594).
OpSignature ::= '(' [ValueType {',' ValueType}] ')' '->' '(' [ValueType {',' ValueType}] ')'
ऑप हस्ताक्षर में सभी इनपुट वैल्यू के टाइप शामिल होते हैं. जैसे,
->
की बाईं ओर) और सभी आउटपुट वैल्यू के टाइप (सूची
प्रकार ->
के दाईं ओर). सच में, इनपुट के टाइप
अनावश्यक और आउटपुट प्रकार लगभग हमेशा अनावश्यक होते हैं (क्योंकि
ज़्यादातर StableHLO ऑपरेशन, आउटपुट टाइप का अनुमान इनपुट से लगाया जा सकता है). फिर भी, ऑप
हस्ताक्षर जान-बूझकर StableHLO सिंटैक्स का हिस्सा है, ताकि MLIR के साथ काम किया जा सके.
नीचे एक ऑप का उदाहरण दिया गया है जिसका स्मरणिक select_and_scatter
है. यह तीन की खपत करता है
इनपुट वैल्यू (%operand
, %source
, और %init_value
), दो इनपुट फ़ंक्शन
और तीन इनपुट एट्रिब्यूट (window_dimensions
, window_strides
, और padding
).
ध्यान दें कि ऑपरेशन के सिग्नेचर में, इनपुट वैल्यू के टाइप ही कैसे शामिल होते हैं
(इसमें इनलाइन दिए जाने वाले इनपुट फ़ंक्शन और एट्रिब्यूट के टाइप नहीं होते).
%result = "stablehlo.select_and_scatter"(%operand, %source, %init_value) ({
^bb0(%arg0: tensor<i32>, %arg1: tensor<i32>):
%0 = "stablehlo.compare"(%arg0, %arg1) {
comparison_direction = #stablehlo<comparison_direction GE>
} : (tensor<i32>, tensor<i32>) -> tensor<i1>
"stablehlo.return"(%0) : (tensor<i1>) -> ()
}, {
^bb0(%arg0: tensor<i32>, %arg1: tensor<i32>):
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i32>, tensor<i32>) -> tensor<i32>
"stablehlo.return"(%0) : (tensor<i32>) -> ()
}) {
window_dimensions = dense<[3, 1]> : tensor<2xi64>,
window_strides = dense<[2, 1]> : tensor<2xi64>,
padding = dense<[[0, 1], [0, 0]]> : tensor<2x2xi64>
} : (tensor<4x2xi32>, tensor<2x2xi32>, tensor<i32>) -> tensor<4x2xi32>
स्थिरांक
Constant ::= BooleanConstant
| IntegerConstant
| FloatConstant
| ComplexConstant
| TensorConstant
| QuantizedTensorConstant
| StringConstant
| EnumConstant
StableHLO कॉन्सटेंट में, लिटरल और एक टाइप होता है, जो एक साथ
एक StableHLO वैल्यू. आम तौर पर, टाइप कॉन्सटैंट सिंटैक्स का हिस्सा होता है. हालांकि, इसमें शामिल नहीं
यह साफ़ तौर पर बताया जाता है (उदाहरण के लिए, किसी बूलियन कॉन्सटेंट में टाइप i1
होता है,
जबकि पूर्णांक कॉन्सटेंट के कई संभावित टाइप हो सकते हैं).
BooleanConstant ::= BooleanLiteral
BooleanLiteral ::= 'true' | 'false'
बूलियन कॉन्सटेंट, बूलियन वैल्यू true
और false
को दिखाते हैं. बूलियन
कॉन्सटेंट का टाइप i1
होता है.
IntegerConstant ::= IntegerLiteral ':' IntegerType
IntegerLiteral ::= ['-' | '+'] DecimalDigits
| ['-' | '+'] '0x' HexadecimalDigits
DecimalDigits ::= decimalDigit {decimalDigit}
HexadecimalDigits ::= hexadecimalDigit {hexadecimalDigit}
decimalDigit ::= '0' | ... | '9'
hexadecimalDigit ::= decimalDigit | 'a' | ... | 'f' | 'A' | ... | 'F'
इंटिजर कॉन्सटेंट, पूर्णांक वैल्यू को उन स्ट्रिंग के ज़रिए दिखाते हैं जिनमें दशमलव या हेक्साडेसिमल नोटेशन. अन्य आधार, जैसे कि बाइनरी या ऑक्टल का इस्तेमाल नहीं किया जा सकता. पूर्णांक कॉन्सटेंट में ये कंस्ट्रेंट होते हैं:
- (C1)
is_wellformed(integer_literal, integer_type)
.
FloatConstant ::= FloatLiteral ':' FloatType
FloatLiteral ::= SignPart IntegerPart FractionalPart ScientificPart
| '0x' [HexadecimalDigits]
SignPart ::= ['-' | '+']
IntegerPart ::= DecimalDigits
FractionalPart ::= ['.' [DecimalDigits]]
ScientificPart ::= [('e' | 'E') ['-' | '+'] DecimalDigits]
फ़्लोटिंग-पॉइंट कॉन्सटेंट ऐसी स्ट्रिंग के ज़रिए फ़्लोटिंग-पॉइंट वैल्यू दिखाते हैं दशमलव या वैज्ञानिक संकेतन का इस्तेमाल करें. इसके अलावा, हेक्साडेसिमल नोटेशन इसका इस्तेमाल फ़्लोटिंग-पॉइंट फ़ॉर्मैट में सीधे तौर पर बिट को तय करने के लिए किया जाता है संबंधित प्रकार. फ़्लोटिंग-पॉइंट कॉन्सटेंट में ये कंस्ट्रेंट होते हैं:
- (C1) अगर नॉन-हेक्साडेसिमल नोटेशन का इस्तेमाल किया जाता है,
is_wellformed(float_literal, float_type)
. - (C2) अगर हेक्साडेसिमल नोटेशन का इस्तेमाल किया जाता है,
size(hexadecimal_digits) = num_bits(float_type) / 4
.
ComplexConstant ::= ComplexLiteral ':' ComplexType
ComplexLiteral ::= '(' RealPart ',' ImaginaryPart ')'
RealPart ::= FloatLiteral
ImaginaryPart ::= FloatLiteral
जटिल स्थिरांक वास्तविक भाग की सूचियों का इस्तेमाल करके जटिल मान दिखाते हैं
(पहले आता है) और एक काल्पनिक हिस्सा (दूसरा आता है). उदाहरण के लिए,
(1.0, 0.0) : complex<f32>
, 1.0 + 0.0i
का प्रतिनिधित्व करता है और
(0.0, 1.0) : complex<f32>
, 0.0 + 1.0i
का प्रतिनिधित्व करता है. जिस क्रम में ये
हिस्सों को मेमोरी में स्टोर किया जाता है. इसे लागू करने के लिए तय किया जाता है. कॉम्प्लेक्स कॉन्सटेंट
कॉन्टेंट पर ये सीमाएं लागू होती हैं:
- (C1)
is_wellformed(real_part, complex_element_type(complex_type))
. - (C2)
is_wellformed(imaginary_part, complex_element_type(complex_type))
.
TensorConstant ::= TensorLiteral ':' TensorType
TensorLiteral ::= 'dense' '<' (DenseLiteral | ElementLiteral) '>'
DenseLiteral ::= DenseDimension | DenseElements
DenseDimension ::= '[' [DenseLiteral {',' DenseLiteral}] ']'
DenseElements ::= [ElementLiteral {',' ElementLiteral}]
ElementLiteral ::= BooleanLiteral | IntegerLiteral | FloatLiteral | ComplexLiteral
टेन्सर कॉन्सटेंट, नेस्ट की गई सूचियों का इस्तेमाल करके टेंसर वैल्यू दिखाते हैं
NumPy नोटेशन. उदाहरण के लिए, dense<[[1, 2, 3], [4, 5, 6]]> : tensor<2x3xi32>
इंडेक्स से एलिमेंट तक इस तरह की मैपिंग की मदद से, टेंसर वैल्यू दिखाता है:
{0, 0} => 1
, {0, 1} => 2
, {0, 2} => 3
, {1, 0} => 4
, {1, 1} => 5
,
{1, 2} => 6
. इसके बाद, इन एलिमेंट को मेमोरी में सेव करने का क्रम यह होता है
लागू किया जाना चाहिए. टेन्सर कॉन्सटेंट में ये कंस्ट्रेंट होते हैं:
- (C1)
has_syntax(tensor_literal, element_type(tensor_type))
, जहां:has_syntax(element_literal: Syntax, element_type: Type) = is_wellformed(element_literal, type)
.has_syntax(tensor_literal: List, element_type: Type) = has_syntax(tensor_literal..., element_type)
.
- (C2)
has_shape(tensor_literal, shape(tensor_type))
, जहां:has_shape(element_literal: Syntax, []) = true
.has_shape(tensor_literal: List, shape: List) = size(tensor_literal) = shape[0] and has_shape(tensor_literal..., shape[1:])
.- अगर ऐसा नहीं है, तो
false
.
QuantizedTensorConstant ::= QuantizedTensorLiteral ':' QuantizedTensorType
QuantizedTensorLiteral ::= 'dense' '<' (DenseLiteral | ElementLiteral) '>'
क्वांटाइज़्ड टेंसर कॉन्सटेंट क्वांटाइज़्ड टेंसर वैल्यू को दिखाता है. इसके लिए, नोटेशन, टेंसर कॉन्सटेंट के तौर पर होता है. इसमें एलिमेंट के कॉन्सटेंट के तौर पर स्टोरेज टाइप. क्वांटाइज़्ड टेंसर कॉन्सटेंट में ये कंस्ट्रेंट होते हैं:
- (C1)
has_syntax(quantized_tensor_literal, storage_type(quantized_tensor_type))
. - (C2)
has_shape(quantized_tensor_literal, shape(quantized_tensor_type))
.
StringConstant ::= StringLiteral
StringLiteral ::= '"' {stringCharacter | escapeSequence} '"'
stringCharacter ::= all ASCII characters except '\00', '\01', ... '\1f' and '"'
escapeSequence ::= '\' ('"' | '\' | 'n' | 't' | (hexadecimalDigit hexadecimalDigit))
स्ट्रिंग की लिटरल वैल्यू में ऐसे बाइट होते हैं जिन्हें ASCII वर्णों का इस्तेमाल करके तय किया जाता है और
एस्केप सीक्वेंस. ये कोड में बदलने के तरीके (एन्कोडिंग-एग्नोस्टिक) हैं. इसलिए, इन
बाइट लागू करने के लिए तय की जाती है. स्ट्रिंग की लिटरल वैल्यू का टाइप string
है.
ऑपरेशन
कुल
सिमैंटिक
operand
टेंसर पर एलिमेंट के हिसाब से abs ऑपरेशन करता है और result
जनरेट करता है
टेंसर. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- हस्ताक्षर किए गए पूर्णांकों के लिए: पूर्णांक मॉड्यूल.
- फ़्लोट के लिए: IEEE-754 से
abs
. - सम्मिश्र संख्याओं के लिए: जटिल मापांक.
- क्वांटाइज़्ड टाइप के लिए:
dequantize_op_quantize(abs, operand, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
साइन किए हुए पूर्णांक, फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1-सी2) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
साइन किए गए पूर्णांक या फ़्लोटिंग-पॉइंट टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1-सी2) |
कंस्ट्रेंट
- (C1)
shape(result) = shape(operand)
. - (C2)
baseline_element_type(result)
को इस तरह परिभाषित किया गया है:- अगर
is_complex(operand)
है, तोcomplex_element_type(element_type(operand))
. - अगर ऐसा नहीं है, तो
baseline_element_type(operand)
.
- अगर
उदाहरण
// %operand: [-2, 0, 2]
%result = "stablehlo.abs"(%operand) : (tensor<3xi32>) -> tensor<3xi32>
// %result: [2, 0, 2]
जोड़ें
सिमैंटिक
दो टेंसर lhs
और rhs
को एलिमेंट के हिसाब से जोड़ता है और इससे
result
टेंसर. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- बूलियन के लिए: लॉजिकल OR.
- पूर्णांकों के लिए: पूर्णांक को जोड़ना.
- फ़्लोट के लिए: IEEE-754 से
addition
. - सम्मिश्र संख्याओं के लिए: सम्मिश्र जोड़.
- क्वांटाइज़्ड टाइप के लिए:
dequantize_op_quantize(add, lhs, rhs, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | lhs |
टेंसर या क्वांटाइज़्ड टेंसर | (सी1-सी6) |
(I2) | rhs |
टेंसर या क्वांटाइज़्ड टेंसर | (C1-C5), (C7) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या क्वांटाइज़्ड टेंसर | (C1-C7) |
कंस्ट्रेंट
- अगर इस संक्रिया में गैर-संख्यात्मक टेंसर का इस्तेमाल किया गया है, तो:
- (C1)
type(lhs) = type(rhs) = type(result)
.
- (C1)
- अगर इस संक्रिया में क्वांटाइज़्ड टेंसर का इस्तेमाल किया जाता है:
- (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)
है, तोquantization_dimension(lhs) = quantization_dimension(result)
. - (C7) अगर
is_per_axis_quantized(rhs)
है, तोquantization_dimension(rhs) = quantization_dimension(result)
.
- (C2)
उदाहरण
// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.add"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[6, 8], [10, 12]]
after_all
सिमैंटिक
यह पक्का करता है कि inputs
को बनाने वाली कार्रवाइयां, किसी भी
जो result
पर निर्भर करती हैं. इस कार्रवाई को चलाने से कुछ नहीं होता है,
यह सिर्फ़ result
से inputs
तक के डेटा पर निर्भरता सेट करने के लिए मौजूद है.
इनपुट
लेबल | नाम | टाइप |
---|---|---|
(I1) | inputs |
token की वैरायडिक संख्या |
आउटपुट
नाम | टाइप |
---|---|
result |
token |
उदाहरण
// %input0: !stablehlo.token
// %input1: !stablehlo.token
%result = "stablehlo.after_all"(%input0, %input1) : (!stablehlo.token, !stablehlo.token) -> !stablehlo.token
all_gather
सिमैंटिक
StableHLO प्रोसेस ग्रिड में हर प्रोसेस ग्रुप के अंदर, वैल्यू को जोड़ता है
all_gather_dim
की हर प्रोसेस से, operands
टेंसर का बनाया जाता है और इस तरह से बनाया जाता है
results
टेंसर.
ऑपरेशन, StableHLO प्रोसेस ग्रिड को process_groups
में बांट देता है जो कि
इस तरह परिभाषित किया गया है:
cross_replica(replica_groups)
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है अगरchannel_id <= 0 and use_global_device_ids = false
है.cross_replica_and_partition(replica_groups)
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है अगरchannel_id > 0 and use_global_device_ids = false
है.flattened_ids(replica_groups)
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है अगरchannel_id > 0 and use_global_device_ids = true
है.
इसके बाद, हर process_group
में:
- सभी के लिए
operands...@receiver = [operand@sender for sender in process_group]
process_group
मेंreceiver
. - सभी के लिए
results...@process = concatenate(operands...@process, all_gather_dim)
process_group
मेंprocess
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operands |
टेंसर की वैरायडिक संख्या या हर टेंसर की क्वांटाइज़्ड टेंसर की संख्या | (C1), (C6) |
(I2) | all_gather_dim |
si64 टाइप का कॉन्स्टेंट |
(C1), (C6) |
(I3) | replica_groups |
si64 टाइप का 2-डाइमेंशन टेंसर कॉन्सटेंट |
(सी2-सी4) |
(आई4) | channel_id |
si64 टाइप का कॉन्स्टेंट |
(सी5) |
(I5) | use_global_device_ids |
i1 टाइप का कॉन्स्टेंट |
(सी5) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
results |
टेंसर की वैरायडिक संख्या या हर टेंसर की क्वांटाइज़्ड टेंसर की संख्या | (सी6) |
कंस्ट्रेंट
- (C1)
0 <= all_gather_dim < rank(operands...)
. - (C2)
is_unique(replica_groups)
. - (C3)
size(replica_groups)
को इस तरह परिभाषित किया गया है:- अगर
cross_replica
का इस्तेमाल किया जाता है, तोnum_replicas
. - अगर
cross_replica_and_partition
का इस्तेमाल किया जाता है, तोnum_replicas
. - अगर
flattened_ids
का इस्तेमाल किया जाता है, तोnum_processes
.
- अगर
- (C4)
0 <= replica_groups < size(replica_groups)
. - (C5) अगर
use_global_device_ids = true
है, तोchannel_id > 0
. - (C6)
type(results...) = type(operands...)
को छोड़कर:dim(results..., all_gather_dim) = dim(operands..., all_gather_dim) * dim(process_groups, 1)
.
उदाहरण
// 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
सिमैंटिक
StableHLO प्रोसेस ग्रिड में हर प्रोसेस ग्रुप के अंदर, एक रिडक्शन लागू होता है
हर प्रोसेस के लिए, operands
टेंसर की वैल्यू के लिए computation
फ़ंक्शन
और results
टेंसर बनाता है.
ऑपरेशन, StableHLO प्रोसेस ग्रिड को process_groups
में बांट देता है जो कि
इस तरह परिभाषित किया गया है:
cross_replica(replica_groups)
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है अगरchannel_id <= 0 and use_global_device_ids = false
है.cross_replica_and_partition(replica_groups)
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है अगरchannel_id > 0 and use_global_device_ids = false
है.flattened_ids(replica_groups)
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है अगरchannel_id > 0 and use_global_device_ids = true
है.
इसके बाद, हर process_group
में:
- कुछ बाइनरी ट्री के लिए
results...@process[result_index] = exec(schedule)
schedule
कहां:exec(node)
=computation(exec(node.left), exec(node.right))
.exec(leaf)
=leaf.value
.
schedule
लागू करने के बारे में तय किया गया बाइनरी ट्री है, जिसका क्रम में है ट्रैवर्सलto_destination_type(operands...@process_group...[result_index], type(func_inputs(computation)[0]))
है.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operands |
टेंसर की वैरायडिक संख्या या हर टेंसर की क्वांटाइज़्ड टेंसर की संख्या | (C5), (C6) |
(I2) | replica_groups |
si64 टाइप के 1-डाइमेंशन वाले टेंसर कॉन्सटेंट की वैरायडिक संख्या |
(सी1-सी3) |
(I3) | channel_id |
si64 टाइप का कॉन्स्टेंट |
(सी4) |
(आई4) | use_global_device_ids |
i1 टाइप का कॉन्स्टेंट |
(सी4) |
(I5) | computation |
फ़ंक्शन | (सी5) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
results |
टेंसर की वैरायडिक संख्या या हर टेंसर की क्वांटाइज़्ड टेंसर की संख्या | (C6-C7) |
कंस्ट्रेंट
- (C1)
is_unique(replica_groups)
. - (C2)
size(replica_groups)
को इस तरह परिभाषित किया गया है:- अगर
cross_replica
का इस्तेमाल किया जाता है, तोnum_replicas
. - अगर
cross_replica_and_partition
का इस्तेमाल किया जाता है, तोnum_replicas
. - अगर
flattened_ids
का इस्तेमाल किया जाता है, तोnum_processes
.
- अगर
- (C3)
0 <= replica_groups < size(replica_groups)
. - (C4) अगर
use_global_device_ids = true
है, तोchannel_id > 0
. - (C5)
computation
का टाइप(tensor<E>, tensor<E>) -> (tensor<E>)
है, जहांis_promotable(element_type(operand), E)
. - (C6)
shape(results...) = shape(operands...)
. - (C7)
element_type(results...) = E
.
उदाहरण
// 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
सिमैंटिक
StableHLO प्रोसेस ग्रिड में मौजूद प्रोसेस ग्रुप के हर एक प्रोसेस ग्रुप में,
split_dimension
के साथ-साथ operands
टेंसर को अलग-अलग हिस्सों में बांटता है
प्रक्रियाओं के बीच के हिस्से, बिखरे हुए हिस्सों को साथ-साथ जोड़ता है
concat_dimension
और results
टेंसर बनाता है.
ऑपरेशन, StableHLO प्रोसेस ग्रिड को process_groups
में बांट देता है जो कि
इस तरह परिभाषित किया गया है:
- अगर
channel_id <= 0
है, तोcross_replica(replica_groups)
. - अगर
channel_id > 0
है, तोcross_partition(replica_groups)
.
इसके बाद, हर process_group
में:
split_parts...@sender = split(operands...@sender, split_count, split_dimension)
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया हैprocess_group
के सभीsender
के लिए.scattered_parts...@receiver = [split_parts...@sender[receiver_index] for sender in process_group]
जहांreceiver_index = process_group.index(receiver)
.results...@process = concatenate(scattered_parts...@process, concat_dimension)
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operands |
टेंसर की वैरायडिक संख्या या हर टेंसर की क्वांटाइज़्ड टेंसर की संख्या | (C1-C3), (C9) |
(I2) | split_dimension |
si64 टाइप का कॉन्स्टेंट |
(C1), (C2), (C9) |
(I3) | concat_dimension |
si64 टाइप का कॉन्स्टेंट |
(C3), (C9) |
(आई4) | split_count |
si64 टाइप का कॉन्स्टेंट |
(C2), (C4), (C8), (C9) |
(I5) | replica_groups |
si64 टाइप का 2-डाइमेंशन टेंसर कॉन्सटेंट |
(C5-C8) |
(I6) | channel_id |
si64 टाइप का कॉन्स्टेंट |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
results |
टेंसर की वैरायडिक संख्या या हर टेंसर की क्वांटाइज़्ड टेंसर की संख्या | (सी9) |
कंस्ट्रेंट
- (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)
को इस तरह परिभाषित किया गया है:- अगर
cross_replica
का इस्तेमाल किया जाता है, तोnum_replicas
. - अगर
cross_partition
का इस्तेमाल किया जाता है, तोnum_partitions
.
- अगर
- (C7)
0 <= replica_groups < size(replica_groups)
. - (C8)
dim(replica_groups, 1) = split_count
. - (C9)
type(results...) = type(operands...)
, अगरsplit_dimension != concat_dimension
:dim(results..., split_dimension) = dim(operands..., split_dimension) / split_count
.dim(results..., concat_dimension) = dim(operands..., concat_dimension) * split_count
.
उदाहरण
// 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]]
और
सिमैंटिक
दो टेंसर lhs
और rhs
के एलिमेंट के हिसाब से AND फ़ंक्शन करता है और result
देता है
टेंसर. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- बूलियन के लिए: लॉजिकल AND.
- पूर्णांकों के लिए: बिट के अनुसार AND.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | lhs |
बूलियन या पूर्णांक टाइप का टेंसर | (सी1) |
(I2) | rhs |
बूलियन या पूर्णांक टाइप का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
बूलियन या पूर्णांक टाइप का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
type(lhs) = type(rhs) = type(result)
.
उदाहरण
// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.and"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[1, 2], [3, 0]]
atan2
सिमैंटिक
lhs
और rhs
टेंसर पर एलिमेंट के हिसाब से atan2 ऑपरेशन करता है और इससे
result
टेंसर. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- फ़्लोट के लिए: IEEE-754 से
atan2
. - कॉम्प्लेक्स नंबर के लिए: कॉम्प्लेक्स atan2.
- क्वांटाइज़्ड टाइप के लिए:
dequantize_op_quantize(atan2, lhs, rhs, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | lhs |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
(I2) | rhs |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)
.
उदाहरण
// %lhs: [0.0, 1.0, -1.0]
// %rhs: [0.0, 0.0, 0.0]
%result = "stablehlo.atan2"(%lhs, %rhs) : (tensor<3xf64>, tensor<3xf64>) -> tensor<3xf64>
// %result: [0.0, 1.57079637, -1.57079637] // [0.0, pi/2, -pi/2]
batch_norm_grad
सिमैंटिक
batch_norm_training
बैकप्रोपागेटिंग के कई इनपुट के ग्रेडिएंट को कैलकुलेट करता है
grad_output
से, grad_operand
, grad_scale
, और grad_offset
का प्रोडक्शन होता है
टेंसर. ज़्यादा औपचारिक रूप से, इस ऑपरेशन को अपघटन के रूप में दिखाया जा सकता है
Python सिंटैक्स का इस्तेमाल करने वाले मौजूदा StableHLO ऑपरेशन का उदाहरण नीचे दिया गया है:
def compute_sum(operand, feature_index):
(sum,) = reduce(
inputs=[operand],
init_values=[constant(0, element_type(operand))],
dimensions=[i for i in range(rank(operand)) if i != feature_index],
body=lambda x, y: add(x, y))
return sum
def compute_mean(operand, feature_index):
sum = compute_sum(operand, feature_index)
divisor = constant(size(operand) / dim(operand, feature_index),
element_type(operand))
divisor_bcast = broadcast_in_dim(divisor, [], type(sum))
return divide(sum, divisor_bcast)
def batch_norm_grad(operand, scale, mean, variance, grad_output, epsilon, feature_index):
# Broadcast inputs to type(operand)
scale_bcast = broadcast_in_dim(scale, [feature_index], type(operand))
mean_bcast = broadcast_in_dim(mean, [feature_index], type(operand))
variance_bcast = broadcast_in_dim(variance, [feature_index], type(operand))
epsilon_bcast = broadcast_in_dim(constant(epsilon, element_type(operand)), [],
type(operand))
# Perform normalization using the provided `mean` and `variance`
# Intermediate values will be useful for computing gradients
centered_operand = subtract(operand, mean_bcast)
stddev = sqrt(add(variance_bcast, epsilon_bcast))
normalized_operand = divide(centered_operand, stddev)
# Use the implementation from batchnorm_expander.cc in XLA
# Temporary variables have exactly the same names as in the C++ code
elements_per_feature = broadcast_in_dim(
constant(divide(size(operand), dim(operand, feature_index)),
element_type(grad_output)),
[], type(operand))
i1 = multiply(grad_output, elements_per_feature)
i2 = broadcast_in_dim(
compute_sum(grad_output, feature_index), [feature_index], type(operand))
i3 = broadcast_in_dim(
compute_sum(multiply(grad_output, centered_operand), feature_index),
[feature_index], type(operand))
i4 = multiply(i3, centered_operand)
i5 = divide(i4, add(variance_bcast, epsilon_bcast))
i6 = subtract(subtract(i1, i2), i5)
grad_operand =
multiply(divide(divide(scale_bcast, stddev), elements_per_feature), i6)
grad_scale =
compute_sum(multiply(grad_output, normalized_operand), feature_index)
grad_offset = compute_sum(grad_output, feature_index)
return grad_operand, grad_scale, grad_offset
क्वांटाइज़्ड टाइप के लिए,
dequantize_batch_norm_grad_or_training_quantize(lambda operand, scale, mean,
variance, grad_output: batch_norm_grad(operand, scale, mean, variance,
grad_output, epsilon, feature_index), operand, scale, mean, variance,
grad_output, type(grad_operand), type(grad_scale), type(feature_index))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (C1-C3), (C5) |
(I2) | scale |
फ़्लोटिंग-पॉइंट या हर टेंसर की क्वांटाइज़्ड टाइप का 1-डाइमेंशन टेंसर | (C2), (C4), (C5) |
(I3) | mean |
फ़्लोटिंग-पॉइंट या हर टेंसर की क्वांटाइज़्ड टाइप का 1-डाइमेंशन टेंसर | (C2), (C4) |
(आई4) | variance |
फ़्लोटिंग-पॉइंट या हर टेंसर की क्वांटाइज़्ड टाइप का 1-डाइमेंशन टेंसर | (C2), (C4) |
(I5) | grad_output |
फ़्लोटिंग-पॉइंट टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (C2), (C3) |
(I6) | epsilon |
f32 टाइप का कॉन्स्टेंट |
|
(I7) | feature_index |
si64 टाइप का कॉन्स्टेंट |
(C1), (C5) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
grad_operand |
फ़्लोटिंग-पॉइंट टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (C2), (C3) |
grad_scale |
फ़्लोटिंग-पॉइंट या हर टेंसर की क्वांटाइज़्ड टाइप का 1-डाइमेंशन टेंसर | (C2), (C4) |
grad_offset |
फ़्लोटिंग-पॉइंट या हर टेंसर की क्वांटाइज़्ड टाइप का 1-डाइमेंशन टेंसर | (C2), (C4) |
कंस्ट्रेंट
- (C1)
0 <= feature_index < rank(operand)
. - (C2)
operand
,scale
,mean
,variance
,grad_output
,grad_operand
,grad_scale
औरgrad_offset
काbaseline_element_type
एक जैसा है. - (C3)
operand
,grad_output
, औरgrad_operand
का आकार एक जैसा है. - (C4)
scale
,mean
,variance
,grad_scale
, औरgrad_offset
के पास एक ही आकार में. - (C5)
size(scale) = dim(operand, feature_index)
.
उदाहरण
// %operand: [
// [[1.0, 2.0], [3.0, 4.0]],
// [[3.0, 4.0], [1.0, 2.0]]
// ]
// %scale: [1.0, 1.0]
// %mean: [2.0, 3.0]
// %variance: [1.0, 1.0]
// %grad_output: [
// [[0.1, 0.1], [0.1, 0.1]],
// [[0.1, 0.1], [0.1, 0.1]]
// ]
%grad_operand, %grad_scale, %grad_offset =
"stablehlo.batch_norm_grad"(%operand, %scale, %mean, %variance, %grad_output) {
epsilon = 0.0 : f32,
feature_index = 2 : i64
} : (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>, tensor<2xf64>,
tensor<2x2x2xf64>) -> (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>)
// %grad_operand: [
// [[0.0, 0.0], [0.0, 0.0]],
// [[0.0, 0.0], [0.0, 0.0]]
// ]
// %grad_scale: [0.0, 0.0]
// %grad_offset: [0.4, 0.4]
batch_norm_inference
सिमैंटिक
इसे छोड़कर सभी डाइमेंशन में operand
टेंसर को नॉर्मलाइज़ करता है
feature_index
डाइमेंशन बनाता है और result
टेंसर बनाता है. औपचारिक तौर पर, यह
ऑपरेशन को मौजूदा StableHLO ऑपरेशन के डिकंपोज़िशन के तौर पर दिखाया जा सकता है
Python सिंटैक्स का इस्तेमाल इस तरह से करता है:
def batch_norm_inference(operand, scale, offset, mean, variance, epsilon, feature_index):
# Broadcast inputs to shape(operand)
scale_bcast = broadcast_in_dim(scale, [feature_index], type(operand))
offset_bcast = broadcast_in_dim(offset, [feature_index], type(operand))
mean_bcast = broadcast_in_dim(mean, [feature_index], type(operand))
variance_bcast = broadcast_in_dim(variance, [feature_index], type(operand))
epsilon_bcast = broadcast_in_dim(constant(epsilon, element_type(operand)), [],
type(operand))
# Perform normalization using the provided `mean` and `variance` instead of
# computing them like `batch_norm_training` does.
centered_operand = subtract(operand, mean_bcast)
stddev = sqrt(add(variance_bcast, epsilon_bcast))
normalized_operand = divide(centered_operand, stddev)
return add(multiply(scale_bcast, normalized_operand), offset_bcast)
क्वांटाइज़्ड टाइप के लिए,
dequantize_op_quantize(lambda operand, scale, offset, mean, variance:
batch_norm_inference(operand, scale, offset, mean, variance, epsilon,
feature_index), operand, scale, offset, mean, variance, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (C1-C7) |
(I2) | scale |
फ़्लोटिंग-पॉइंट या हर टेंसर की क्वांटाइज़्ड टाइप का 1-डाइमेंशन टेंसर | (C2), (C3) |
(I3) | offset |
फ़्लोटिंग-पॉइंट या हर टेंसर की क्वांटाइज़्ड टाइप का 1-डाइमेंशन टेंसर | (C2), (C4) |
(आई4) | mean |
फ़्लोटिंग-पॉइंट या हर टेंसर की क्वांटाइज़्ड टाइप का 1-डाइमेंशन टेंसर | (सी5) |
(I5) | variance |
फ़्लोटिंग-पॉइंट या हर टेंसर की क्वांटाइज़्ड टाइप का 1-डाइमेंशन टेंसर | (C2), (C6) |
(I6) | epsilon |
f32 टाइप का कॉन्स्टेंट |
|
(I7) | feature_index |
si64 टाइप का कॉन्स्टेंट |
(C1), (C3-C6) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (C2), (C7) |
कंस्ट्रेंट
- (C1)
0 <= feature_index < rank(operand)
. - (C2)
operand
,scale
,offset
,mean
,variance
, औरresult
के पास वहीbaseline_element_type
. - (C3)
size(scale) = dim(operand, feature_index)
. - (C4)
size(offset) = dim(operand, feature_index)
. - (C5)
size(mean) = dim(operand, feature_index)
. - (C6)
size(variance) = dim(operand, feature_index)
. - (C7)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// %operand: [
// [[1.0, 2.0], [3.0, 4.0]],
// [[3.0, 4.0], [1.0, 2.0]]
// ]
// %scale: [1.0, 1.0]
// %offset: [1.0, 1.0]
// %mean: [2.0, 3.0]
// %variance: [1.0, 1.0]
%result = "stablehlo.batch_norm_inference"(%operand, %scale, %offset, %mean, %variance) {
epsilon = 0.0 : f32,
feature_index = 2 : i64
} : (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>, tensor<2xf64>, tensor<2xf64>) -> tensor<2x2x2xf64>
// %result: [
// [[0.0, 0.0], [2.0, 2.0]],
// [[2.0, 2.0], [0.0, 0.0]]
// ]
batch_norm_training
सिमैंटिक
feature_index
को छोड़कर सभी डाइमेंशन में मीन और वैरियंस कैलकुलेट करता है
डाइमेंशन और operand
टेंसर को नॉर्मलाइज़ करता है, जिससे output
, batch_mean
बनता है
और batch_var
टेंसर. ज़्यादा औपचारिक रूप से, इस ऑपरेशन को
Python सिंटैक्स का इस्तेमाल करके, मौजूदा StableHLO ऑपरेशन को डीकंपोज़ करना
अनुसरण करता है:
def compute_mean(operand, feature_index):
(sum,) = reduce(
inputs=[operand],
init_values=[constant(0, element_type(operand))],
dimensions=[i for i in range(rank(operand)) if i != feature_index],
body=lambda x, y: add(x, y))
divisor = constant(size(operand) / dim(operand, feature_index),
element_type(operand))
divisor_bcast = broadcast_in_dim(divisor, [], type(sum))
return divide(sum, divisor_bcast)
def compute_variance(operand, feature_index):
mean = compute_mean(operand, feature_index)
mean_bcast = broadcast_in_dim(mean, [feature_index], type(operand))
centered_operand = subtract(operand, mean_bcast)
return compute_mean(mul(centered_operand, centered_operand), feature_index)
def batch_norm_training(operand, scale, offset, epsilon, feature_index):
mean = compute_mean(operand, feature_index)
variance = compute_variance(operand, feature_index)
return batch_norm_inference(operand, scale, offset, mean, variance, epsilon,
feature_index),
mean, variance
क्वांटाइज़्ड टाइप के लिए,
dequantize_batch_norm_grad_or_training_quantize(lambda operand, scale, offset:
batch_norm_training(operand, scale, offset, epsilon, feature_index), operand,
scale, offset, type(output), type(batch_mean), type(batch_var))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
(I2) | scale |
फ़्लोटिंग-पॉइंट या हर टेंसर की क्वांटाइज़्ड का 1-डाइमेंशन टेंसर | (C2), (C3) |
(I3) | offset |
फ़्लोटिंग-पॉइंट या हर टेंसर की क्वांटाइज़्ड का 1-डाइमेंशन टेंसर | (C2), (C4) |
(आई4) | epsilon |
f32 टाइप का कॉन्स्टेंट |
(C1), (C3-C6) |
(I5) | feature_index |
si64 टाइप का कॉन्स्टेंट |
(C1), (C3-C6) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
output |
फ़्लोटिंग-पॉइंट टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी7) |
batch_mean |
फ़्लोटिंग-पॉइंट या हर टेंसर की क्वांटाइज़्ड का 1-डाइमेंशन टेंसर | (C2), (C5) |
batch_var |
फ़्लोटिंग-पॉइंट या हर टेंसर की क्वांटाइज़्ड का 1-डाइमेंशन टेंसर | (C2), (C6) |
कंस्ट्रेंट
- (C1)
0 <= feature_index < rank(operand)
. - (C2)
operand
,scale
,offset
,batch_mean
,batch_var
, औरoutput
के पास वहीbaseline_element_type
. - (C3)
size(scale) = dim(operand, feature_index)
. - (C4)
size(offset) = dim(operand, feature_index)
. - (C5)
size(batch_mean) = dim(operand, feature_index)
. - (C6)
size(batch_var) = dim(operand, feature_index)
. - (C7)
baseline_type(output) = baseline_type(operand)
.
उदाहरण
// %operand: [
// [[1.0, 2.0], [3.0, 4.0]],
// [[3.0, 4.0], [1.0, 2.0]]
// ]
// %scale: [1.0, 1.0]
// %offset: [1.0, 1.0]
%output, %batch_mean, %batch_var = "stablehlo.batch_norm_training"(%operand, %scale, %offset) {
epsilon = 0.0 : f32,
feature_index = 2 : i64
} : (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>) ->
(tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>)
// %output: [
// [[0.0, 0.0], [2.0, 2.0]],
// [[2.0, 2.0], [0.0, 0.0]]
// ]
// %batch_mean: [2.0, 3.0]
// %batch_var: [1.0, 1.0]
bitcast_convert
सिमैंटिक
operand
टेंसर पर बिटकास्ट कार्रवाई करता है और result
टेंसर बनाता है
जहां पूरे operand
टेंसर के बिट को
result
टेंसर का टाइप.
इन देशों में E = element_type(operand)
, E' = element_type(result)
,
और R = rank(operand)
:
- अगर
num_bits(E') < num_bits(E)
,bits(result[i0, ..., iR-1, :]) = bits(operand[i0, ..., iR-1])
. - अगर
num_bits(E') > num_bits(E)
,bits(result[i0, ..., iR-2]) = bits(operand[i0, ..., iR-2, :])
. - अगर
num_bits(E') = num_bits(E)
,bits(result[i0, ..., iR-1]) = bits(operand[i0, ..., iR-1])
.
bits
, दी गई वैल्यू को मेमोरी में दिखाने के साथ-साथ उसके व्यवहार की जानकारी देता है
को लागू करना तय होता है, क्योंकि टेंसर का सटीक निरूपण होता है
लागू है, और एलिमेंट टाइप की सटीक जानकारी दी गई है
तय करें.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
टेंसर या क्वांटाइज़्ड टेंसर | (सी1-सी2) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या क्वांटाइज़्ड टेंसर | (सी1-सी2) |
कंस्ट्रेंट
- (C1)
E = is_quantized(operand) ? storage_type(operand) : element_type(operand)
,E' = is_quantized(result) ? storage_type(result) : element_type(result)
, औरR = rank(operand)
दिए गए:- अगर
num_bits(E') = num_bits(E)
, तोshape(result) = shape(operand)
. - अगर
num_bits(E') < num_bits(E)
: rank(result) = R + 1
.- सभी
0 <= i < R
के लिएdim(result, i) = dim(operand, i)
. dim(result, R) * num_bits(E') = num_bits(E)
.- अगर
num_bits(E') > num_bits(E)
: rank(result) = R - 1
.- सभी
0 <= i < R
के लिएdim(result, i) = dim(operand, i)
. dim(operand, R - 1) * num_bits(E) = num_bits(E')
.
- अगर
- (C2) अगर
is_complex(operand) or is_complex(result)
है, तोis_complex(operand) and is_complex(result)
.
उदाहरण
// %operand: 0x0123456789ABCDEF
%result = "stablehlo.bitcast_convert"(%operand) : (tensor<f64>) -> tensor<4xf16>
// %result: [0xCDEF, 0x89AB, 0x4567, 0x0123] // little-endian representation
broadcast_in_dim
सिमैंटिक
डेटा की डुप्लीकेट कॉपी बनाकर, इनपुट टेंसर के डाइमेंशन और/या रैंक को बढ़ाता है
यह operand
टेंसर में होता है और result
टेंसर बनाता है. औपचारिक तौर पर,
result[result_index] = operand[operand_index]
में सभी d
कहां देखें
axes(operand)
:
- अगर
dim(operand, d) = 1
है, तोoperand_index[d] = 0
. - अगर ऐसा नहीं है, तो
operand_index[d] = result_index[broadcast_dimensions[d]]
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
टेंसर या क्वांटाइज़्ड टेंसर | (C1-C2), (C5-C6) |
(I2) | broadcast_dimensions |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(सी2-सी6) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या क्वांटाइज़्ड टेंसर | (C1), (C3), (C5-C6) |
कंस्ट्रेंट
- (C1)
element_type(result)
देने वाली कंपनी:- अगर
!is_per_axis_quantized(operand)
है, तोelement_type(operand)
. quantization_dimension(operand)
को छोड़कर,element_type(operand)
,scales(operand)
औरzero_points(operand)
इनसे अलग हो सकती हैंquantization_dimension(result)
,scales(result)
, औरzero_points(result)
नहीं करना होगा.
- अगर
- (C2)
size(broadcast_dimensions) = rank(operand)
. - (C3)
0 <= broadcast_dimensions < rank(result)
. - (C4)
is_unique(broadcast_dimensions)
. - (C5)
axes(operand)
में सभीd
के लिए:dim(operand, d) = 1
याdim(operand, d) = dim(result, broadcast_dimensions[d])
.
- (C6) अगर
is_per_axis_quantized(result)
:quantization_dimension(result) = broadcast_dimensions[quantization_dimension(operand)]
.- अगर
dim(operand, quantization_dimension(operand)) = 1
, तोscales(result)[i] = scales(operand)[0] and zero_points(result)[i] = zero_points(operand)[0] for i in range(dim(result, quantization_dimension(result)))
.
उदाहरण
// %operand: [
// [1, 2, 3]
// ]
%result = "stablehlo.broadcast_in_dim"(%operand) {
broadcast_dimensions = array<i64: 2, 1>
} : (tensor<1x3xi32>) -> tensor<2x3x2xi32>
// %result: [
// [
// [1, 1],
// [2, 2],
// [3, 3]
// ],
// [
// [1, 1],
// [2, 2],
// [3, 3]
// ]
// ]
केस
सिमैंटिक
branches
से सिर्फ़ एक फ़ंक्शन चलाने पर आउटपुट मिलता है
यह index
की वैल्यू के हिसाब से तय होता है. औपचारिक तौर पर, result = selected_branch()
कहां:
- अगर
0 <= index < size(branches)
है, तोselected_branch = branches[index]
. - अगर ऐसा नहीं है, तो
selected_branch = branches[-1]
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | index |
si32 टाइप का 0-डाइमेंशन वाला टेंसर |
|
(I2) | branches |
फ़ंक्शन की वैरायडिक नंबर | (सी1-सी4) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
results |
टेंसर की वैरायडिक संख्या, क्वांटाइज़ किए गए टेंसर या टोकन | (सी4) |
कंस्ट्रेंट
- (C1)
0 < size(branches)
. - (C2)
input_types(branches...) = []
. - (C3)
same(output_types(branches...))
. - (C4)
type(results...) = output_types(branches[0])
.
उदाहरण
// %index: -1
// %result_branch0: [0, 0]
// %result_branch1: [1, 1]
%result0, %result1 = "stablehlo.case"(%index) ({
"stablehlo.return"(%result_branch0, %result_branch0) : (tensor<2xi64>, tensor<2xi64>) -> ()
}, {
"stablehlo.return"(%result_branch1, %result_branch1) : (tensor<2xi64>, tensor<2xi64>) -> ()
}) : (tensor<i32>) -> (tensor<2xi64>, tensor<2xi64>)
// %result0: [1, 1]
// %result1: [1, 1]
सीबीआरटी
सिमैंटिक
operand
टेंसर पर एलिमेंट के मुताबिक घन मूल की कार्रवाई करता है और इससे
result
टेंसर. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- फ़्लोट के लिए: IEEE-754 से
rootn(x, 3)
. - सम्मिश्र संख्याओं के लिए: सम्मिश्र घन मूल.
- क्वांटिफ़ाइड टाइप के लिए:
dequantize_op_quantize(cbrt, operand, type(result))
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// %operand: [0.0, 1.0, 8.0, 27.0]
%result = "stablehlo.cbrt"(%operand) : (tensor<4xf64>) -> tensor<4xf64>
// %result: [0.0, 1.0, 2.0, 3.0]
सील
सिमैंटिक
operand
टेंसर की एलिमेंट के हिसाब से सेल करता है और result
टेंसर बनाता है.
आईईईई-754 से roundToIntegralTowardPositive
ऑपरेशन लागू करता है
स्पेसिफ़िकेशन. क्वांटाइज़्ड टाइप के लिए,
dequantize_op_quantize(ceil, operand, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// %operand: [-0.8166, -0.2530, 0.2530, 0.8166, 2.0]
%result = "stablehlo.ceil"(%operand) : (tensor<5xf32>) -> tensor<5xf32>
// %result: [-0.0, -0.0, 1.0, 1.0, 2.0]
चोलस्की
सिमैंटिक
मैट्रिक्स के बैच के कोलेस्की अपघटन की गणना करता है.
ज़्यादा औपचारिक तौर पर, index_space(result)
में सभी i
के लिए,
result[i0, ..., iR-3, :, :]
इसका कोलेस्की अपघटन है
a[i0, ..., iR-3, :, :]
, निचले त्रिभुज के फ़ॉर्मैट में
(अगर lower
true
है) या ऊपरी त्रिभुज वाला (अगर lower
false
है) मैट्रिक्स.
सामने वाले त्रिभुज में आउटपुट वैल्यू, जैसे कि सख्त ऊपरी त्रिभुज या
इसके अनुसार सख्त निचले त्रिभुज, लागू करने के तरीके बनाए गए हैं.
अगर i
मौजूद है, जहां इनपुट मैट्रिक्स हर्मिटियन सकारात्मक-निश्चित नहीं है
मैट्रिक्स, तो व्यवहार तय नहीं होता है.
क्वांटाइज़्ड टाइप के लिए,
dequantize_op_quantize(lambda operand: cholesky(operand, lower), a, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | a |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1-सी3) |
(I2) | lower |
i1 टाइप का 0-डाइमेंशन टेंसर कॉन्सटेंट |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(a) = baseline_type(result)
. - (C2)
2 <= rank(a)
. - (C3)
dim(a, -2) = dim(a, -1)
.
उदाहरण
// %a: [
// [1.0, 2.0, 3.0],
// [2.0, 20.0, 26.0],
// [3.0, 26.0, 70.0]
// ]
%result = "stablehlo.cholesky"(%a) {
lower = true
} : (tensor<3x3xf32>) -> tensor<3x3xf64>
// %result: [
// [1.0, 0.0, 0.0],
// [2.0, 4.0, 0.0],
// [3.0, 5.0, 6.0]
// ]
क्लैंप
सिमैंटिक
operand
टेंसर के हर एलिमेंट को कम से कम और ज़्यादा से ज़्यादा के बीच जोड़ता है
वैल्यू और result
टेंसर बनाता है. औपचारिक तौर पर, result[result_index] =
minimum(maximum(operand[result_index], min_element), max_element)
,
जहां min_element = rank(min) = 0 ? min[] : min[result_index]
,
max_element = rank(max) = 0 ? max[] : max[result_index]
. क्वांटाइज़्ड टाइप के लिए,
dequantize_op_quantize(clamp, min, operand, max, type(result))
करता है.
जटिल संख्याओं को क्रम से लगाने में हैरान करने वाले सिमैंटिक, इसलिए, आने वाले समय में हम कॉम्प्लेक्स नंबर की सुविधा को बंद करने की योजना बना रहे हैं. इस कार्रवाई के लिए (#560).
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | min |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C1), (C3) |
(I2) | operand |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी1-सी4) |
(I3) | max |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C2), (C3) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी4) |
कंस्ट्रेंट
- (C1)
rank(min) = 0 or shape(min) = shape(operand)
. - (C2)
rank(max) = 0 or shape(max) = shape(operand)
. - (C3)
baseline_element_type(min) = baseline_element_type(operand) = baseline_element_type(max)
. - (C4)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// %min: [5, 10, 15]
// %operand: [3, 13, 23]
// %max: [10, 15, 20]
%result = "stablehlo.clamp"(%min, %operand, %max) : (tensor<3xi32>, tensor<3xi32>, tensor<3xi32>) -> tensor<3xi32>
// %result: [5, 13, 20]
collective_broadcast
सिमैंटिक
StableHLO प्रोसेस ग्रिड में हर प्रोसेस ग्रुप के अंदर,
सोर्स प्रोसेस से टारगेट प्रोसेस तक, operand
टेंसर का इस्तेमाल करें और
result
टेंसर.
ऑपरेशन, StableHLO प्रोसेस ग्रिड को process_groups
में बांट देता है जो कि
इस तरह परिभाषित किया गया है:
- अगर
channel_id <= 0
है, तोcross_replica(replica_groups)
. - अगर
channel_id > 0
है, तोcross_partition(replica_groups)
.
इसके बाद, result@process
देने वाली कंपनी:
operand@process_groups[i, 0]
, अगर कोईi
मौजूद हो और प्रोसेस इस तरह की होprocess_groups[i]
में.broadcast_in_dim(constant(is_quantized(result) ? quantize(0, element_type(result)) : 0, element_type(result)), [], type(result))
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है नहीं तो.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी3) |
(I2) | replica_groups |
si64 टाइप के 1-डाइमेंशन वाले टेंसर कॉन्सटेंट की वैरायडिक संख्या |
(C1), (C2) |
(I3) | channel_id |
si64 टाइप का कॉन्स्टेंट |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी3) |
कंस्ट्रेंट
- (C1)
is_unique(replica_groups)
. - (C2)
0 <= replica_groups < N
जहांN
को इस तरह परिभाषित किया गया है:- अगर
cross_replica
का इस्तेमाल किया जाता है, तोnum_replicas
. - अगर
cross_partition
का इस्तेमाल किया जाता है, तोnum_partitions
.
- अगर
- (C3)
type(result) = type(operand)
.
उदाहरण
// num_replicas: 4
// num_partitions: 1
// %operand@(0, 0): [[1, 2]]
// %operand@(1, 0): [[3, 4]]
// %operand@(2, 0): [[5, 6]]
// %operand@(3, 0): [[7, 8]]
%result = "stablehlo.collective_broadcast"(%operand) {
replica_groups = dense<[[2, 1]]> : tensor<1x2xi64>,
channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
} : (tensor1x2xi64>) -> tensor<1x2xi64>
// %result@(0, 0): [[0, 0]]
// %result@(1, 0): [[5, 6]]
// %result@(2, 0): [[5, 6]]
// %result@(3, 0): [[0, 0]]
collective_permute
सिमैंटिक
StableHLO प्रोसेस ग्रिड में मौजूद हर प्रोसेस ग्रुप के तहत,
सोर्स प्रोसेस से टारगेट प्रोसेस तक, operand
टेंसर बनाता है और नतीजे के तौर पर
result
टेंसर.
ऑपरेशन, StableHLO प्रोसेस ग्रिड को process_groups
में बांट देता है जो कि
इस तरह परिभाषित किया गया है:
- अगर
channel_id <= 0
है, तोcross_replica(source_target_pairs)
. - अगर
channel_id > 0
है, तोcross_partition(source_target_pairs)
.
इसके बाद, result@process
देने वाली कंपनी:
operand@process_groups[i, 0]
, अगर कोईi
मौजूद हो, तोprocess_groups[i, 1] = process
.broadcast_in_dim(constant(is_quantized(result) ? quantize(0, element_type(result)) : 0, element_type(result)), [], type(result))
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है नहीं तो.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी5) |
(I2) | source_target_pairs |
si64 टाइप का 2-डाइमेंशन टेंसर कॉन्सटेंट |
(सी1-सी4) |
(I3) | channel_id |
si64 टाइप का कॉन्स्टेंट |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
dim(source_target_pairs, 1) = 2
. - (C2)
is_unique(source_target_pairs[:, 0])
. - (C3)
is_unique(source_target_pairs[:, 1])
. - (C4)
0 <= source_target_pairs < N
, जहांN
का मतलब इस तरह है:- अगर
cross_replica
का इस्तेमाल किया जाता है, तोnum_replicas
. - अगर
cross_partition
का इस्तेमाल किया जाता है, तोnum_partitions
.
- अगर
- (C5)
type(result) = type(operand)
.
उदाहरण
// num_replicas: 3
// num_partitions: 1
// %operand@(0, 0): [[1, 2], [3, 4]]
// %operand@(1, 0): [[5, 6], [7, 8]]
// %operand@(2, 0): [[9, 10], [11, 12]]
%result = "stablehlo.collective_permute"(%operand) {
source_target_pairs = dense<[[0, 1], [1, 2]]> : tensor<2x2xi64>,
channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
} : (tensor<2x2xi64>) -> tensor<2x2xi64>
//
// %result@(0, 0): [[0, 0], [0, 0]]
// %result@(1, 0): [[1, 2], [3, 4]]
// %result@(2, 0): [[5, 6], [7, 8]]
तुलना करें
सिमैंटिक
lhs
और rhs
टेंसर की एलिमेंट के हिसाब से तुलना करता है
comparison_direction
और compare_type
से, result
टेंसर बनाता है.
comparison_direction
और compare_type
की वैल्यू ये हैं
सिमेंटिक्स:
बूलियन और इंटीजर टाइप के एलिमेंट के लिए:
EQ
:lhs = rhs
.NE
:lhs != rhs
.GE
:lhs >= rhs
.GT
:lhs > rhs
.LE
:lhs <= rhs
.LT
:lhs < rhs
.
compare_type = FLOAT
के साथ फ़्लोटिंग-पॉइंट एलिमेंट टाइप के लिए, op- मान लागू करता है
आईईईई-754 के ये ऑपरेशन:
EQ
:compareQuietEqual
.NE
:compareQuietNotEqual
.GE
:compareQuietGreaterEqual
.GT
:compareQuietGreater
.LE
:compareQuietLessEqual
.LT
:compareQuietLess
.
compare_type = TOTALORDER
वाले फ़्लोटिंग-पॉइंट एलिमेंट के लिए, op
इससे totalOrder
और compareQuietEqual
कार्रवाइयों का कॉम्बिनेशन इस्तेमाल करता है
आईईईई-754.
जटिल एलिमेंट टाइप के लिए, (real, imag)
पेयर की लेक्सिकोग्राफ़िक तुलना इस तरह है
दिए गए comparison_direction
और compare_type
का इस्तेमाल करके परफ़ॉर्म किया.
जटिल संख्याओं को क्रम से लगाने में हैरान करने वाले सिमैंटिक,
इसलिए, आने वाले समय में हम कॉम्प्लेक्स नंबर की सुविधा को बंद करने की योजना बना रहे हैं.
जब comparison_direction
, GE
, GT
, LE
या LT
हो
(#560).
क्वांटाइज़्ड टाइप के लिए. dequantize_compare(lhs, rhs,
comparison_direction)
करता है.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | lhs |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी1-सी3) |
(I2) | rhs |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी1-सी2) |
(I3) | comparison_direction |
EQ , NE , GE , GT , LE , और LT का कुल डेटा |
|
(आई4) | compare_type |
FLOAT , TOTALORDER , SIGNED , और UNSIGNED का कुल डेटा |
(सी3) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
बूलियन टाइप का टेंसर | (सी2) |
कंस्ट्रेंट
- (C1)
baseline_element_type(lhs) = baseline_element_type(rhs)
. - (C2)
shape(lhs) = shape(rhs) = shape(result)
. - (C3)
compare_type
को इस तरह परिभाषित किया गया है:- अगर
is_signed_integer(element_type(lhs))
है, तोSIGNED
. - अगर
is_unsigned_integer(element_type(lhs)) or is_boolean(element_type(lhs))
है, तोUNSIGNED
. - अगर
is_float(element_type(lhs))
है, तोFLOAT
याTOTALORDER
. - अगर
is_complex(element_type(lhs))
है, तोFLOAT
.
- अगर
उदाहरण
// %lhs: [1.0, 3.0]
// %rhs: [1.1, 2.9]
%result = "stablehlo.compare"(%lhs, %rhs) {
comparison_direction = #stablehlo<comparison_direction LT>,
compare_type = #stablehlo<comparison_type FLOAT>
} : (tensor<2xf32>, tensor<2xf32>) -> tensor<2xi1>
// %result: [true, false]
जटिल
सिमैंटिक
वास्तविक और के पेयर से एक कॉम्प्लेक्स वैल्यू पर एलिमेंट के हिसाब से कन्वर्ज़न करता है
काल्पनिक मान, lhs
और rhs
, और एक result
टेंसर बनाता है.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | lhs |
f32 या f64 टाइप का टेंसर |
(सी1-सी3) |
(I2) | rhs |
f32 या f64 टाइप का टेंसर |
(सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
कॉम्प्लेक्स टाइप का टेंसर | (C2), (C3) |
कंस्ट्रेंट
- (C1)
type(lhs) = type(rhs)
. - (C2)
shape(result) = shape(lhs)
. - (C3)
element_type(result)
का टाइपcomplex<E>
है, जहांE = element_type(lhs)
.
उदाहरण
// %lhs: [1.0, 3.0]
// %rhs: [2.0, 4.0]
%result = "stablehlo.complex"(%lhs, %rhs) : (tensor<2xf64>, tensor<2xf64>) -> tensor<2xcomplex<f64>>
// %result: [(1.0, 2.0), (3.0, 4.0)]
मिश्रित
सिमैंटिक
अन्य StableHLO ऑपरेशन से बने ऑपरेशन को इनकैप्सुलेट करता है,
इस वीडियो में, inputs
और composite_attributes
को लिया जा रहा है और results
वीडियो बनाया जा रहा है. कॉन्टेंट बनाने
ऑपरेशन के सिमैंटिक को decomposition
एट्रिब्यूट की मदद से लागू किया जाता है. कॉन्टेंट बनाने
प्रोग्राम में बदलाव किए बिना, composite
ऑप को इसके डिकपोज़िशन से बदला जा सकता है
सिमेंटिक्स. ऐसे मामलों में जहां अपघटन को इनलाइन करने से नतीजे नहीं मिलते
ऑप सिमैंटिक्स, custom_call
का इस्तेमाल करना पसंद है.
version
फ़ील्ड (डिफ़ॉल्ट रूप से 0
पर सेट होती है) का इस्तेमाल किसी कंपोज़िट की वैल्यू को दिखाने के लिए किया जाता है
सिमेंटिक्स बदल गया है.
इनपुट
लेबल | नाम | टाइप |
---|---|---|
(I1) | inputs |
वैल्यू की वैरायडिक संख्या |
(I2) | name |
string टाइप का कॉन्स्टेंट |
(I3) | composite_attributes |
एट्रिब्यूट डिक्शनरी |
(आई4) | decomposition |
string टाइप का कॉन्स्टेंट |
(I5) | version |
si32 टाइप का कॉन्स्टेंट |
आउटपुट
नाम | टाइप |
---|---|
results |
वैल्यू की वैरायडिक संख्या |
कंस्ट्रेंट
- (C1)
is_namespaced_op_name(name)
- (सी2)
is_defined_in_parent_scope(decomposition)
- (C3)
types(inputs...) == input_types(decomposition)
- (C4)
types(results...) == output_types(decomposition)
उदाहरण
%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>
जोड़ें
सिमैंटिक
inputs
को dimension
डाइमेंशन के साथ उसी क्रम में जोड़ता है जिस क्रम में दिया गया है
आर्ग्युमेंट और result
टेंसर बनाता है. औपचारिक तौर पर,
result[i0, ..., id, ..., iR-1] = inputs[k][i0, ..., kd, ..., iR-1]
, जहां:
id = d0 + ... + dk-1 + kd
.d
,dimension
के बराबर है औरd0
, ... डाइमेंशन काd
वां साइज़ हैinputs
का.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | inputs |
टेंसर की वैरायडिक संख्या या हर टेंसर की क्वांटाइज़्ड टेंसर की संख्या | (सी1-सी6) |
(I2) | dimension |
si64 टाइप का कॉन्स्टेंट |
(C2), (C4), (C6) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी5-सी6) |
कंस्ट्रेंट
- (C1)
same(element_type(inputs...))
. - (C2)
dim(inputs..., dimension)
को छोड़कर,same(shape(inputs...))
. - (C3)
0 < size(inputs)
. - (C4)
0 <= dimension < rank(inputs[0])
. - (C5)
element_type(result) = element_type(inputs[0])
. - (C6)
shape(result) = shape(inputs[0])
, इन्हें छोड़कर:dim(result, dimension) = dim(inputs[0], dimension) + ...
.
उदाहरण
// %input0: [[1, 2], [3, 4], [5, 6]]
// %input1: [[7, 8]]
%result = "stablehlo.concatenate"(%input0, %input1) {
dimension = 0 : i64
} : (tensor<3x2xi64>, tensor<1x2xi64>) -> tensor<4x2xi64>
// %result: [[1, 2], [3, 4], [5, 6], [7, 8]]
कॉन्सटेंट
सिमैंटिक
कॉन्स्टेंट value
से, output
टेंसर बनाता है.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | value |
कॉन्सटेंट | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
output |
टेंसर या क्वांटाइज़्ड टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
type(value) = type(output)
.
उदाहरण
%output = "stablehlo.constant"() {
value = dense<[[0.0, 1.0], [2.0, 3.0]]> : tensor<2x2xf32>
} : () -> tensor<2x2xf32>
// %output: [[0.0, 1.0], [2.0, 3.0]]
ग्राहक में बदलने वाले
सिमैंटिक
एक एलिमेंट से दूसरे टाइप में एलिमेंट के हिसाब से कन्वर्ज़न करता है
operand
टेंसर और result
टेंसर बनाता है.
boolean-to-any-supported-type के लिए, वैल्यू false
है
शून्य में बदल जाता है और true
मान एक में बदल जाता है. इसके लिए
any-supported-type-to-boolean रूपांतरण, शून्य मान को
false
और शून्य के अलावा किसी अन्य वैल्यू को true
में बदल दिया जाता है. इसे देखने का तरीका नीचे दिया गया है
और जटिल प्रकारों के लिए
काम करते हैं.
integer-टू-इंटीजर, integer-टू-फ़्लोटिंग-पॉइंट वाले कन्वर्ज़न के लिए या floating-point-to-floating-point, अगर सोर्स वैल्यू ठीक को डेस्टिनेशन टाइप में दिखाया जाता है, तो नतीजे के तौर पर मिलने वाली वैल्यू प्रतिनिधित्व. नहीं तो, व्यवहार अभी तय नहीं किया जा सकता (#180).
floating-point-to-integer वाले कन्वर्ज़न के लिए, फ़्रैक्शनल हिस्सा काट-छांट की गई है. अगर काट-छांट की गई वैल्यू को डेस्टिनेशन टाइप में नहीं दिखाया जा सकता, तो व्यवहार अभी तय नहीं है (#180).
कॉम्प्लेक्स-टू-कॉम्प्लेक्स वाले कन्वर्ज़न का तरीका कन्वर्ज़न के लिए, floating-point-to-floating-point कन्वर्ज़न काल्पनिक हिस्से.
complex-to-any-other-type और any-other-type-to-complex कन्वर्ज़न के लिए. सोर्स काल्पनिक मान को नज़रअंदाज़ कर दिया जाता है या डेस्टिनेशन काल्पनिक मान यह होता है शून्य है. वास्तविक भाग का रूपांतरण फ़्लोटिंग-पॉइंट कन्वर्ज़न.
सिद्धांत के तौर पर, इस ऑपरेशन में डिक्वांटाइज़ेशन की सुविधा इस्तेमाल की जा सकती है (कन्वर्ज़न से
क्वांटाइज़्ड टेंसर से रेगुलर टेंसर तक), क्वांटाइज़ेशन (रेगुलर से कन्वर्ज़न
टेंसर से क्वांटाइज़्ड टेंसर) और रीक्वांटाइज़ेशन (संख्या में बदलने वाले टेंसर के बीच कन्वर्ज़न)
टेंसर), लेकिन फ़िलहाल हमारे पास उसके लिए खास तौर पर काम करने वाले ऑपरेशन हैं -
पहले इस्तेमाल के उदाहरण के लिए uniform_dequantize
और पहली बार इस्तेमाल के लिए uniform_quantize
इस्तेमाल के दूसरे और तीसरे उदाहरण. आने वाले समय में, ये दोनों ऑपरेशन मर्ज किए जा सकते हैं
convert
(#1576) में.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
टेनसॉर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेनसॉर | (सी1) |
कंस्ट्रेंट
- (C1)
shape(operand) = shape(result)
.
उदाहरण
// %operand: [-1, 0, 1]
%result = "stablehlo.convert"(%operand) : (tensor<3xi64>) -> tensor<3xcomplex<f64>>
// %result: [(-1.0, 0.0), (0.0, 0.0), (1.0, 0.0)]
कन्वर्ज़न
सिमैंटिक
lhs
की विंडो और rhs
के स्लाइस के बीच, प्रॉडक्ट की गणना करता है और नतीजे देता है
result
. यहां दिए गए डायग्राम में दिखाया गया है कि result
में एलिमेंट का हिसाब कैसे लगाया जाता है
lhs
और rhs
को बेहतर तरीके से समझने के लिए, एक अच्छा उदाहरण दिया गया है.
ज़्यादा औपचारिक तौर पर, lhs
के हिसाब से इनपुट की इन रीफ़्रेमिंग पर विचार करें
lhs
की विंडो को दिखाने के लिए:
lhs_window_dimensions = lhs_shape(dim(lhs, input_batch_dimension), dim(rhs, kernel_spatial_dimensions), dim(lhs, input_feature_dimension))
.lhs_window_strides = lhs_shape(1, window_strides, 1)
.lhs_padding = lhs_shape([0, 0], padding, [0, 0])
.lhs_base_dilations = lhs_shape(1, lhs_dilation, 1)
.lhs_window_dilations = lhs_shape(1, rhs_dilation, 1)
.
इस रीफ़्रेमिंग में ये हेल्पर फ़ंक्शन इस्तेमाल किए जाते हैं:
lhs_shape(n, hw, c) = permute([n] + hw + [c], [input_batch_dimension] + input_spatial_dimensions + [input_feature_dimension])
.result_shape(n1, hw, c1) = permute([n1] + hw + [c1], [output_batch_dimension] + output_spatial_dimensions + [output_feature_dimension])
.permute([j0, j1, ..., jR-1], permutation) = [i0, i1, ..., iR-1]
जहांj[d] = i[permutation[d]]
.
अगर feature_group_count = 1
और batch_group_count = 1
है, तो सभी के लिए
index_space(dim(result, output_spatial_dimensions...))
में output_spatial_index
,
result[result_shape(:, output_spatial_index, :)] = dot_product
जहां:
padding_value = constant(0, element_type(lhs))
.padded_lhs = pad(lhs, padding_value, lhs_padding[:, 0], lhs_padding[:, 1], lhs_base_dilations - 1)
.lhs_window_start = lhs_shape(0, output_spatial_index, 0) * lhs_window_strides
.lhs_window = slice(padded_lhs, lhs_window_start, lhs_window_start + lhs_window_dimensions, lhs_window_dilations)
.reversed_lhs_window = reverse(lhs_window, [input_spatial_dimensions[dim] for dim in range(size(window_reversal)) if window_reversal[dim] = true])
. ऐसा लगता है कि इस सुविधा का इस्तेमाल नहीं किया गया है, इसलिए आने वाले समय में हम इसे हटाने की योजना बना रहे हैं (#1181).dot_product = dot_general(reversed_lhs_window, rhs, lhs_batching_dimensions=[], lhs_contracting_dimensions=input_spatial_dimensions + [input_feature_dimension], rhs_batching_dimensions=[], rhs_contracting_dimensions=kernel_spatial_dimensions + [kernel_input_feature_dimension])
.
अगर feature_group_count > 1
:
lhses = split(lhs, feature_group_count, input_feature_dimension)
.rhses = split(rhs, feature_group_count, kernel_output_feature_dimension)
.results... = convolution(lhses..., rhses..., ..., feature_group_count=1, ...)
.result = concatenate(results, output_feature_dimension)
.
अगर batch_group_count > 1
:
lhses = split(lhs, batch_group_count, input_batch_dimension)
.rhses = split(rhs, batch_group_count, kernel_output_feature_dimension)
.results... = convolution(lhses..., rhses..., ..., batch_group_count=1, ...)
.result = concatenate(results, output_feature_dimension)
.
क्वांटाइज़्ड टाइप के लिए, dequantize_op_quantize(
lambda lhs, rhs: convolution(lhs, rhs, window_strides, padding,
lhs_dilation, rhs_dilation, window_reversal, input_batch_dimension,
input_feature_dimension, input_spatial_dimensions,
kernel_input_feature_dimension, kernel_output_feature_dimension,
kernel_spatial_dimensions, output_batch_dimension,
output_feature_dimension, output_spatial_dimensions,
feature_group_count, batch_group_count, precision_config), lhs, rhs,
type(result))
परफ़ॉर्म करता है.
हाइब्रिड क्वांटाइज़्ड टाइप के लिए 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)
परफ़ॉर्म करता है.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | lhs |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C1), (C10-C11), (C14) (C25), (C27-C28), (C31-C32), (C34) |
(I2) | rhs |
टेंसर या क्वांटाइज़्ड टेंसर | (C1), (C14-C16), (C25), (C27-C29), (C31-C34) |
(I3) | window_strides |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C2-C3), (C25) |
(आई4) | padding |
si64 टाइप का 2-डाइमेंशन टेंसर कॉन्सटेंट |
(C4), (C25) |
(I5) | lhs_dilation |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C5-C6), (C25) |
(I6) | rhs_dilation |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C7-C8), (C25) |
(I7) | window_reversal |
i1 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(सी9) |
(I8) | input_batch_dimension |
si64 टाइप का कॉन्स्टेंट |
(C10), (C13), (C25) |
(I9) | input_feature_dimension |
si64 टाइप का कॉन्स्टेंट |
(C11), (C13-C14) |
(I10) | input_spatial_dimensions |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C12), (C13), (C25) |
(I11) | kernel_input_feature_dimension |
si64 टाइप का कॉन्स्टेंट |
(C14), (C18) |
(I12) | kernel_output_feature_dimension |
si64 टाइप का कॉन्स्टेंट |
(C15-C16), (C18), (C25), (C29) |
(I13) | kernel_spatial_dimensions |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C17-C18), (C25) |
(I14) | output_batch_dimension |
si64 टाइप का कॉन्स्टेंट |
(C20), (C25) |
(I15) | output_feature_dimension |
si64 टाइप का कॉन्स्टेंट |
(C20), (C25), (C30) |
(I16) | output_spatial_dimensions |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C19-C20), (C25) |
(I17) | feature_group_count |
si64 टाइप का कॉन्स्टेंट |
(C11), (C14), (C16), (C21), (C23) |
(I18) | batch_group_count |
si64 टाइप का कॉन्स्टेंट |
(C10), (C15), (C22), (C23), (C25) |
(I19) | precision_config |
DEFAULT , HIGH , और HIGHEST के ईनम की अलग-अलग संख्या |
(सी24) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या क्वांटाइज़्ड टेंसर | (C25-C28), (C30), (C32-34) |
कंस्ट्रेंट
- (C1)
N = rank(lhs) = rank(rhs)
. - (C2)
size(window_strides) = N - 2
. - (C3)
0 < window_strides
. - (C4)
shape(padding) = [N - 2, 2]
. - (C5)
size(lhs_dilation) = N - 2
. - (C6)
0 < lhs_dilation
. - (C7)
size(rhs_dilation) = N - 2
. - (C8)
0 < rhs_dilation
. - (C9)
size(window_reversal) = N - 2
. - (C10)
dim(lhs, input_batch_dimension) % batch_group_count = 0
. - (C11)
dim(lhs, input_feature_dimension) % feature_group_count = 0
. - (C12)
size(input_spatial_dimensions) = N - 2
. - (C13)
input_dimensions = [input_batch_dimension] + input_spatial_dimensions + [input_feature_dimension]
दिया गया:is_unique(input_dimensions)
.0 <= input_dimensions < N
.
- (C14)
dim(rhs, kernel_input_feature_dimension) = dim(lhs, input_feature_dimension) / feature_group_count
. - (C15)
dim(rhs, kernel_output_feature_dimension) % batch_group_count = 0
. - (C16)
dim(rhs, kernel_output_feature_dimension) % feature_group_count = 0
. - (C17)
size(kernel_spatial_dimensions) = N - 2
. - (C18)
kernel_dimensions = kernel_spatial_dimensions + [kernel_input_feature_dimension] + [kernel_output_feature_dimension]
दिया गया:is_unique(kernel_dimensions)
.0 <= kernel_dimensions < N
.
- (C19)
size(output_spatial_dimensions) = N - 2
. - (C20)
output_dimensions = [output_batch_dimension] + output_spatial_dimensions + [output_feature_dimension]
दिया गया:is_unique(output_dimensions)
.0 <= output_dimensions < N
.
- (C21)
0 < feature_group_count
. - (C22)
0 < batch_group_count
. - (C23)
feature_group_count = 1 or batch_group_count = 1
. - (C24)
size(precision_config) = 2
. - (C25)
dim(result, result_dim)
को इस तरह परिभाषित किया गया है:- अगर
result_dim = output_batch_dimension
है, तोdim(lhs, input_batch_dimension) / batch_group_count
. - अगर
result_dim = output_feature_dimension
है, तोdim(rhs, kernel_output_feature_dimension)
. num_windows
अन्य मामलों में, जहां:output_spatial_dimensions[spatial_dim] = result_dim
.lhs_dim = input_spatial_dimensions[spatial_dim]
.rhs_dim = kernel_spatial_dimensions[spatial_dim]
.dilated_input_shape[lhs_dim] = dim(lhs, lhs_dim) = 0 ? 0 : (dim(lhs, lhs_dim) - 1) * lhs_dilation[spatial_dim] + 1
.padded_input_shape[lhs_dim] = padding[spatial_dim, 0] + dilated_input_shape[lhs_dim] + padding[spatial_dim, 1]
.dilated_window_shape[lhs_dim] = dim(rhs, rhs_dim) = 0 ? 0 : (dim(rhs, rhs_dim) - 1) * rhs_dilation[spatial_dim] + 1
.is_empty_window[lhs_dim] = padded_input_shape[lhs_dim] = 0 || dilated_window_shape[lhs_dim] > padded_input_shape[lhs_dim]
.num_windows = is_empty_window[lhs_dim] ? 0 : floor((padded_input_shape[lhs_dim] - dilated_window_shape[lhs_dim]) / window_strides[spatial_dim]) + 1
.
- अगर
- (C26)
rank(result) = N
. - अगर इस संक्रिया में गैर-संख्यात्मक टेंसर का इस्तेमाल किया गया है, तो:
- (C27)
element_type(lhs) = element_type(rhs) = element_type(result)
.
- (C27)
- अगर इस संक्रिया में क्वांटाइज़्ड टेंसर का इस्तेमाल किया जाता है:
- (C28)
is_quantized(lhs) = is_quantized(result) and is_quantized(rhs)
. - (C29) अगर
is_per_axis_quantized(rhs)
, फिरquantization_dimension(rhs) = kernel_output_feature_dimension
. - (C30) अगर
is_per_axis_quantized(result)
है, तोquantization_dimension(result) = output_feature_dimension
. - अगर
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)
है, तोis_per_tensor_quantized(result)
. - अगर
!is_quantized(lhs)
: - (C34)
element_type(lhs) = expressed_type(rhs) = element_type(result)
.
- (C28)
उदाहरण
// %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]]
// ]]
कोज्या
सिमैंटिक
operand
टेंसर पर एलिमेंट के हिसाब से कोसाइन करता है और इससे
result
टेंसर. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- फ़्लोट के लिए: IEEE-754 से
cos
. - सम्मिश्र संख्याओं के लिए: सम्मिश्र कोसाइन.
- क्वांटाइज़्ड टाइप के लिए:
dequantize_op_quantize(cosine, operand, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// %operand: [
// [0.0, 1.57079632], // [0, pi/2]
// [3.14159265, 4.71238898] // [pi, 3pi/2]
// ]
%result = "stablehlo.cosine"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[1.0, 0.0], [-1.0, 0.0]]
count_leading_zeros
सिमैंटिक
operand
में शुरुआत में शून्य बिट की संख्या एलिमेंट के हिसाब से गिनती करता है
टेंसर बनाता है और result
टेंसर बनाता है.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
पूर्णांक टाइप का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
पूर्णांक टाइप का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
type(operand) = type(result)
.
उदाहरण
// %operand: [[0, 1], [128, -1]]
%result = "stablehlo.count_leading_zeros"(%operand) : (tensor<2x2xi64>) -> tensor<2x2xi64>
// %result: [[64, 63], [56, 0]]
custom_call
सिमैंटिक
लागू करने के बारे में तय की गई कार्रवाई call_target_name
को इनकैप्सुलेट करता है, जो
inputs
और called_computations
के साथ मिलकर results
बनाती हैं. has_side_effect
,
backend_config
और api_version
का इस्तेमाल, जानकारी देने के लिए किया जा सकता है
लागू करने से जुड़ा मेटाडेटा.
फ़िलहाल, इस कार्रवाई में काफ़ी अव्यवस्थित कलेक्शन है ऐसा मेटाडेटा जो सर्च इंजन की तरह काम करने वाली कंपनी की परफ़ॉर्मेंस में हुए बदलाव को दिखाता है XLA कंपाइलर का इस्तेमाल किया. आने वाले समय में, हम इस मेटाडेटा को एक जगह पर लाने की योजना बना रहे हैं (#741).
इनपुट
लेबल | नाम | टाइप |
---|---|---|
(I1) | inputs |
वैल्यू की वैरायडिक संख्या |
(I2) | call_target_name |
string टाइप का कॉन्स्टेंट |
(I3) | has_side_effect |
i1 टाइप का कॉन्स्टेंट |
(आई4) | backend_config |
string टाइप का कॉन्स्टेंट या एट्रिब्यूट डिक्शनरी |
(I5) | api_version |
si32 टाइप का कॉन्स्टेंट |
(I6) | called_computations |
string टाइप के कॉन्सटेंट की वैरायडिक संख्या |
आउटपुट
नाम | टाइप |
---|---|
results |
वैल्यू की वैरायडिक संख्या |
उदाहरण
%results = "stablehlo.custom_call"(%input0) {
call_target_name = "foo",
has_side_effect = false,
backend_config = {bar = 42 : i32},
api_version = 4 : i32,
called_computations = [@foo]
} : (tensor<f64>) -> tensor<f64>
विभाजन
सिमैंटिक
भाज्य lhs
और भाजक rhs
टेंसर और एलिमेंट के आधार पर भाग करता है
result
टेंसर बनाता है. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- पूर्णांकों के लिए: पूर्णांक विभाजन जो किसी भी वैल्यू के साथ बीजगणितीय भागफल बनाता है आंशिक भाग खारिज किया गया.
- फ़्लोट के लिए: IEEE-754 से
division
. - सम्मिश्र संख्याओं के लिए: जटिल विभाजन.
- क्वांटाइज़्ड टाइप के लिए:
dequantize_op_quantize(divide, lhs, rhs, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | lhs |
इंटीजर, फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
(I2) | rhs |
इंटीजर, फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
इंटीजर, फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)
.
उदाहरण
// %lhs: [17.1, -17.1, 17.1, -17.1]
// %rhs: [3.0, 3.0, -3.0, -3.0]
%result = "stablehlo.divide"(%lhs, %rhs) : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
// %result: [5.66666651, -5.66666651, -5.66666651, 5.66666651]
dot_general
सिमैंटिक
lhs
के स्लाइस और rhs
के स्लाइस के बीच, प्रॉडक्ट की गणना डॉट करता है और
result
टेंसर.
औपचारिक तौर पर, result[result_index] = dot_product
, जहां:
lhs_result_dimensions = [d for d in axes(lhs) and d not in lhs_batching_dimensions and d not in lhs_contracting_dimensions]
.rhs_result_dimensions = [d for d in axes(rhs) and d not in rhs_batching_dimensions and d not in rhs_contracting_dimensions]
.result_batching_index + result_lhs_index + result_rhs_index = result_index
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है जहांsize(result_batching_index) = size(lhs_batching_dimensions)
,size(result_lhs_index) = size(lhs_result_dimensions)
औरsize(result_rhs_index) = size(rhs_result_dimensions)
.transposed_lhs = transpose(lhs, lhs_batching_dimensions + lhs_result_dimensions + lhs_contracting_dimensions)
.transposed_lhs_slice = slice(transposed_lhs, result_batching_index + result_lhs_index + [:, ..., :])
.reshaped_lhs_slice = reshape(transposed_lhs_slice, dims(lhs, lhs_contracting_dimensions))
.transposed_rhs = transpose(rhs, rhs_batching_dimensions + rhs_result_dimensions + rhs_contracting_dimensions)
.transposed_rhs_slice = slice(transposed_rhs, result_batching_index + result_rhs_index + [:, ..., :])
.reshaped_rhs_slice = reshape(transposed_rhs_slice, dims(rhs, rhs_contracting_dimensions))
.dot_product = reduce( inputs=[multiply(reshaped_lhs_slice, reshaped_rhs_slice)], init_values=[constant(0, element_type(result))], dimensions=range(size(lhs_contracting_dimensions)), body=lambda x, y: add(x, y))
.
क्वांटाइज़्ड टाइप के लिए, dequantize_op_quantize(
lambda lhs, rhs: dot_general(lhs, rhs, lhs_batching_dimensions,
rhs_batching_dimensions, lhs_contracting_dimensions,
rhs_contracting_dimensions, precision_config), lhs, rhs, type(result))
परफ़ॉर्म करता है.
हाइब्रिड क्वांटाइज़्ड टाइप के लिए 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)
परफ़ॉर्म करता है.
precision_config
, स्पीड और सटीक होने के बीच के अंतर को कंट्रोल करता है
कंप्यूटेशन (अक्सेलरेटर बैकएंड पर). यह इनमें से कोई एक हो सकता है (
मोमेंट, इन ईनम वैल्यू के सिमेंटिक्स तय नहीं किए गए हैं, लेकिन हम
इस समस्या को हल करने के लिए
#755):
DEFAULT
: सबसे तेज़ कैलकुलेशन, लेकिन इसका सबसे कम सटीक अनुमान मूल नंबर.HIGH
: धीमी कैलकुलेशन, लेकिन मूल नंबर.HIGHEST
: सबसे धीमी कैलकुलेशन, लेकिन मूल नंबर.
DotAlgorithm
, लागू करने के लिए इस्तेमाल किए जाने वाले एल्गोरिदम की मुख्य प्रॉपर्टी के बारे में बताता है
डॉट ऑपरेशन, जो प्रिसिज़न भी परिभाषित करता है. अगर एल्गोरिदम एट्रिब्यूट
फ़ील्ड सेट हैं, तो precision_config
DEFAULT
होनी चाहिए. DotAlgorithms
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है
इसके लिए कोई डिफ़ॉल्ट वैल्यू न हो, क्योंकि डिफ़ॉल्ट पैरामीटर को लागू किया जाता है
तय किया गया है. इसलिए, सभी डॉट एल्गोरिदम फ़ील्ड को None
पर सेट किया जा सकता है, ताकि
खाली डॉट एल्गोरिदम, जो इसके बजाय precision_config
वैल्यू का इस्तेमाल करेगा.
DotAlgorithm
फ़ील्ड में शामिल हैं:
lhs_precision_type
औरrhs_precision_type
, वह सटीक जानकारी जो LHS और ऑपरेशन की दाईं ओर मौजूद वैल्यू में बदल दिया जाता है. प्रिसिज़न टाइप, और आउटपुट के स्टोरेज टाइप को अलग-अलग कर सकते हैं.accumulation_type
इकट्ठा करने के लिए इस्तेमाल की गई सटीक वैल्यू.lhs_component_count
,rhs_component_count
, औरnum_primitive_operations
तब लागू होती है, जब हम एक ऐसा एल्गोरिदम बनाते हैं जो LHS और/या RHS को कई कॉम्पोनेंट और कई सारे "प्रीमिटिव" होते हैं उन पर डॉट ऑपरेशन वैल्यू - आम तौर पर ज़्यादा सटीक जानकारी देने के लिए (उदाहरण के लिए, ज़्यादा सटीक गणना के लिए bfloat16 आर्टिफ़िशियल इंटेलिजेंस डेटाटाइप का इस्तेमाल करना: bf16_6x tf32_3x वगैरह). जिन एल्गोरिदम के लिए डिकंपोज़िशन नहीं हुआ है उनके लिए, ये वैल्यू1
पर सेट होना चाहिए.- कम सटीक तरीके से इकट्ठा होने की जानकारी देने के लिए
allow_imprecise_accumulation
को कुछ चरणों के लिए इस्तेमाल करने की अनुमति है (जैसे,CUBLASLT_MATMUL_DESC_FAST_ACCUM
).
DotAlgorithm
एट्रिब्यूट के उदाहरण:
// 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}
यह लागू करने पर निर्भर करता है कि किन कॉम्बिनेशन का इस्तेमाल किया जा सकता है. तय सीमा में आम तौर पर, इस बात की गारंटी नहीं है कि हर एल्गोरिदम StableHLO के उपभोक्ता के हिसाब से एक्सेलरेटर टाइप. अगर दिया गया एल्गोरिदम, नहीं दिखाई देता है, तो कोई गड़बड़ी वैकल्पिक है. StableHLO से पुष्टि करने की सुविधा से, पुष्टि करने में आसानी होगी. उन एल्गोरिदम को रोक रहा है जो किसी भी हार्डवेयर पर काम नहीं करते हैं.
xla_data.proto > Algorithm
देखें
का इस्तेमाल किया जा सकता है. टिकट #2483 का इस्तेमाल करके,
बैकएंड की मदद से काम करने वाले एल्गोरिदम पर, एक ही जगह पर दस्तावेज़ बनाने की सुविधा.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | lhs |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C5-C6), (C9-C10), (C12-C14), (C17-C18), (C20) |
(I2) | rhs |
टेंसर या क्वांटाइज़्ड टेंसर | (C7-C10), (C12-C20) |
(I3) | lhs_batching_dimensions |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C1), (C3), (C5), (C9), (C12) |
(आई4) | rhs_batching_dimensions |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C1), (C4), (C7), (C9) |
(I5) | lhs_contracting_dimensions |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C2), (C3), (C6), (C10) |
(I6) | rhs_contracting_dimensions |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C2), (C4), (C8), (C10), (C16) |
(I7) | precision_config |
DEFAULT , HIGH , और HIGHEST के ईनम की अलग-अलग संख्या |
(C11), (C21) |
(I8) | lhs_precision_type |
FloodType या TensorFloat32 | (सी21) |
(I9) | rhs_precision_type |
FloodType या TensorFloat32 | (सी21) |
(I10) | accumulation_type |
FloodType या TensorFloat32 | (सी21) |
(I11) | lhs_component_count |
si32 टाइप का कॉन्स्टेंट |
(C21), (C22) |
(I12) | rhs_component_count |
si32 टाइप का कॉन्स्टेंट |
(C21), (C23) |
(I13) | num_primitive_operations |
si32 टाइप का कॉन्स्टेंट |
(C21), (C24) |
(I14) | allow_imprecise_accumulation |
bool टाइप का कॉन्स्टेंट |
(सी21) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या क्वांटाइज़्ड टेंसर | (C12), (C14), (C18-C20) |
कंस्ट्रेंट
- (C1)
size(lhs_batching_dimensions) = size(rhs_batching_dimensions)
. - (C2)
size(lhs_contracting_dimensions) = size(rhs_contracting_dimensions)
. - (C3)
is_unique(lhs_batching_dimensions + lhs_contracting_dimensions)
. - (C4)
is_unique(rhs_batching_dimensions + rhs_contracting_dimensions)
. - (C5)
0 <= lhs_batching_dimensions < rank(lhs)
. - (C6)
0 <= lhs_contracting_dimensions < rank(lhs)
. - (C7)
0 <= rhs_batching_dimensions < rank(rhs)
. - (C8)
0 <= rhs_contracting_dimensions < rank(rhs)
. - (C9)
dim(lhs, lhs_batching_dimensions...) = dim(rhs, rhs_batching_dimensions...)
. - (C10)
dim(lhs, lhs_contracting_dimensions...) = dim(rhs, rhs_contracting_dimensions...)
. - (C11)
size(precision_config) = 2
. - (C12)
shape(result) = dim(lhs, lhs_batching_dimensions) + dim(lhs, lhs_result_dimensions) + dim(rhs, rhs_result_dimensions)
. - अगर इस संक्रिया में गैर-संख्यात्मक टेंसर का इस्तेमाल किया गया है, तो:
- (C13)
element_type(lhs) = element_type(rhs)
.
- (C13)
- अगर इस संक्रिया में क्वांटाइज़्ड टेंसर का इस्तेमाल किया जाता है:
- (C14)
is_quantized(lhs) = is_quantized(result) and is_quantized(rhs)
. - (C15)
zero_points(rhs) = 0
. - (C16) अगर
is_per_axis_quantized(rhs)
है, तोquantization_dimension(rhs)
,rhs_contracting_dimensions
में नहीं है. - अगर
is_quantized(lhs)
: - (C17)
storage_type(lhs) = storage_type(rhs)
. - (C18)
expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
. - (C19) अगर
is_per_tensor_quantized(rhs)
है, तोis_per_tensor_quantized(result)
. - अगर
!is_quantized(lhs)
: - (C20)
element_type(lhs) = expressed_type(rhs) = element_type(result)
.
- (C14)
- अगर
!is_empty_algorithm(lhs_precision_type, rhs_precision_type, accumulation_type, lhs_component_count, rhs_component_count, num_primitive_operations allow_imprecise_accumulation)
:- (C21)
precision_config... = DEFAULT
. - (C22)
0 < lhs_component_count
. - (C23)
0 < rhs_component_count
. - (C24)
0 < num_primitive_operations
.
- (C21)
उदाहरण
// %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
सिमैंटिक
यह ऑपरेशन इसके फ़ंक्शनल रूप से एक जैसा है
broadcast_in_dim
ऑप, लेकिन output_dimensions
के ज़रिए नतीजे का आकार डायनैमिक तौर पर बताया जाता है.
इस ऑपरेशन में वैकल्पिक एट्रिब्यूट known_expanding_dimensions
, known_non_expanding_dimensions
भी स्वीकार किए जाते हैं
डाइमेंशन के बढ़ते व्यवहार के बारे में अपनी अहम जानकारी ज़ाहिर करने के लिए.
अगर जानकारी नहीं दी गई है, तो माना गया है कि सभी डाइमेंशन बड़े हो सकते हैं.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
टेंसर या क्वांटाइज़्ड टेंसर | (C1-C2), (C5-C6), (C9) |
(I2) | output_dimensions |
पूर्णांक प्रकार का 1-विमीय टेंसर | (सी7) |
(I3) | broadcast_dimensions |
पूर्णांक टाइप का 1-डाइमेंशन कॉन्सटेंट टेंसर | (सी2-सी6) |
(आई4) | known_expanding_dimensions |
पूर्णांक टाइप का 1-डाइमेंशन कॉन्सटेंट टेंसर | (सी8-सी9) |
(I5) | known_non_expanding_dimensions |
पूर्णांक टाइप का 1-डाइमेंशन कॉन्सटेंट टेंसर | (सी8-सी9) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या क्वांटाइज़्ड टेंसर | (C1), (C3), (C5-C7) |
कंस्ट्रेंट
- (C1)
element_type(result)
देने वाली कंपनी:- अगर
!is_per_axis_quantized(operand)
है, तोelement_type(operand)
. quantization_dimension(operand)
को छोड़कर,element_type(operand)
,scales(operand)
औरzero_points(operand)
इनसे अलग हो सकती हैंquantization_dimension(result)
,scales(result)
, औरzero_points(result)
नहीं करना होगा.
- अगर
- (C2)
size(broadcast_dimensions) = rank(operand)
. - (C3)
0 <= broadcast_dimensions < rank(result)
. - (C4)
is_unique(broadcast_dimensions)
. - (C5)
axes(operand)
में सभीd
के लिए:dim(operand, d) = 1
याdim(operand, d) = dim(result, broadcast_dimensions[d])
.
- (C6) अगर
is_per_axis_quantized(result)
:quantization_dimension(result) = broadcast_dimensions[quantization_dimension(operand)]
.- अगर
dim(operand, quantization_dimension(operand)) = 1
, तोscales(result)[i] = scales(operand)[0] and zero_points(result)[i] = zero_points(operand)[0] for i in range(dim(result, quantization_dimension(result)))
.
- (C7)
size(output_dimensions) = rank(result)
. - (C8)
is_unique(known_expanding_dimensions + known_non_expanding_dimensions)
. - (C9)
0 <= known_expanding_dimensions < rank(operand)
. - (C10)
0 <= known_non_expanding_dimensions < rank(operand)
.
उदाहरण
// %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_non_expanding_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
सिमैंटिक
यह ऑपरेशन इसके फ़ंक्शनल रूप से एक जैसा है
बातचीत
ऑप, लेकिन padding
के ज़रिए पैडिंग (जगह) को डाइनैमिक तौर पर बताया गया है.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | lhs |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C1), (C10-C11), (C14) (C25), (C26-C27), (C30-C31), (C33) |
(I2) | rhs |
टेंसर या क्वांटाइज़्ड टेंसर | (C1), (C14-C16), (C26-C28), (C30-C33) |
(I3) | padding |
पूर्णांक टाइप का 2-डाइमेंशन वाला टेंसर | (सी4) |
(आई4) | window_strides |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(सी2-सी3) |
(I5) | lhs_dilation |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(सी5-सी6) |
(I6) | rhs_dilation |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C7-C8) |
(I7) | window_reversal |
i1 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(सी9) |
(I8) | input_batch_dimension |
si64 टाइप का कॉन्स्टेंट |
(C10), (C13) |
(I9) | input_feature_dimension |
si64 टाइप का कॉन्स्टेंट |
(C11), (C13-C14) |
(I10) | input_spatial_dimensions |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C12), (C13) |
(I11) | kernel_input_feature_dimension |
si64 टाइप का कॉन्स्टेंट |
(C14), (C18) |
(I12) | kernel_output_feature_dimension |
si64 टाइप का कॉन्स्टेंट |
(C15-C16), (C18), (C28) |
(I13) | kernel_spatial_dimensions |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C17-C18) |
(I14) | output_batch_dimension |
si64 टाइप का कॉन्स्टेंट |
(C20) |
(I15) | output_feature_dimension |
si64 टाइप का कॉन्स्टेंट |
(C20), (C29) |
(I16) | output_spatial_dimensions |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C19-C20) |
(I17) | feature_group_count |
si64 टाइप का कॉन्स्टेंट |
(C11), (C14), (C16), (C21), (C23) |
(I18) | batch_group_count |
si64 टाइप का कॉन्स्टेंट |
(C10), (C15), (C22), (C23) |
(I19) | precision_config |
DEFAULT , HIGH , और HIGHEST के ईनम की अलग-अलग संख्या |
(सी24) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या क्वांटाइज़्ड टेंसर | (C25-C27), (C29), (C31-C33) |
कंस्ट्रेंट
- (C1)
N = rank(lhs) = rank(rhs)
. - (C2)
size(window_strides) = N - 2
. - (C3)
0 < window_strides
. - (C4)
shape(padding) = [N - 2, 2]
. - (C5)
size(lhs_dilation) = N - 2
. - (C6)
0 < lhs_dilation
. - (C7)
size(rhs_dilation) = N - 2
. - (C8)
0 < rhs_dilation
. - (C9)
size(window_reversal) = N - 2
. - (C10)
dim(lhs, input_batch_dimension) % batch_group_count = 0
. - (C11)
dim(lhs, input_feature_dimension) % feature_group_count = 0
. - (C12)
size(input_spatial_dimensions) = N - 2
. - (C13)
input_dimensions = [input_batch_dimension] + input_spatial_dimensions + [input_feature_dimension]
दिया गया:is_unique(input_dimensions)
.0 <= input_dimensions < N
.
- (C14)
dim(rhs, kernel_input_feature_dimension) = dim(lhs, input_feature_dimension) / feature_group_count
. - (C15)
dim(rhs, kernel_output_feature_dimension) % batch_group_count = 0
. - (C16)
dim(rhs, kernel_output_feature_dimension) % feature_group_count = 0
. - (C17)
size(kernel_spatial_dimensions) = N - 2
. - (C18)
kernel_dimensions = kernel_spatial_dimensions + [kernel_input_feature_dimension] + [kernel_output_feature_dimension]
दिया गया:is_unique(kernel_dimensions)
.0 <= kernel_dimensions < N
.
- (C19)
size(output_spatial_dimensions) = N - 2
. - (C20)
output_dimensions = [output_batch_dimension] + output_spatial_dimensions + [output_feature_dimension]
दिया गया:is_unique(output_dimensions)
.0 <= output_dimensions < N
.
- (C21)
0 < feature_group_count
. - (C22)
0 < batch_group_count
. - (C23)
feature_group_count = 1 or batch_group_count = 1
. - (C24)
size(precision_config) = 2
. - (C25)
dim(result, result_dim)
को इस तरह परिभाषित किया गया है:- अगर
result_dim = output_batch_dimension
है, तोdim(lhs, input_batch_dimension) / batch_group_count
. - अगर
result_dim = output_feature_dimension
है, तोdim(rhs, kernel_output_feature_dimension)
. num_windows
अन्य मामलों में, जहां:output_spatial_dimensions[spatial_dim] = result_dim
.lhs_dim = input_spatial_dimensions[spatial_dim]
.rhs_dim = kernel_spatial_dimensions[spatial_dim]
.dilated_input_shape[lhs_dim] = dim(lhs, lhs_dim) = 0 ? 0 : (dim(lhs, lhs_dim) - 1) * lhs_dilation[spatial_dim] + 1
.padded_input_shape[lhs_dim] = padding[spatial_dim, 0] + dilated_input_shape[lhs_dim] + padding[spatial_dim, 1]
.dilated_window_shape[lhs_dim] = dim(rhs, rhs_dim) = 0 ? 0 : (dim(rhs, rhs_dim) - 1) * rhs_dilation[spatial_dim] + 1
.is_empty_window[lhs_dim] = padded_input_shape[lhs_dim] = 0 || dilated_window_shape[lhs_dim] > padded_input_shape[lhs_dim]
.num_windows = is_empty_window[lhs_dim] ? 0 : floor((padded_input_shape[lhs_dim] - dilated_window_shape[lhs_dim]) / window_strides[spatial_dim]) + 1
.
- अगर
- (C26)
rank(result) = N
. - अगर इस संक्रिया में गैर-संख्यात्मक टेंसर का इस्तेमाल किया गया है, तो:
- (C27)
element_type(lhs) = element_type(rhs) = element_type(result)
.
- (C27)
- अगर इस संक्रिया में क्वांटाइज़्ड टेंसर का इस्तेमाल किया जाता है:
- (C28)
is_quantized(lhs) = is_quantized(result) and is_quantized(rhs)
. - (C29) अगर
is_per_axis_quantized(rhs)
, फिरquantization_dimension(rhs) = kernel_output_feature_dimension
. - (C30) अगर
is_per_axis_quantized(result)
है, तोquantization_dimension(result) = output_feature_dimension
. - अगर
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)
है, तोis_per_tensor_quantized(result)
. - अगर
!is_quantized(lhs)
: - (C34)
element_type(lhs) = expressed_type(rhs) = element_type(result)
.
- (C28)
उदाहरण
// %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
सिमैंटिक
यह ऑपरेशन इसके फ़ंक्शनल रूप से एक जैसा है
इकट्ठा करना
op, slice_sizes
को मान के रूप में डायनैमिक तौर पर बताया गया है.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C1), (C7), (C10-C12), (C14) |
(I2) | start_indices |
पूर्णांक टाइप का टेंसर | (C2), (C3), (C13) |
(I3) | slice_sizes |
पूर्णांक प्रकार का 1-विमीय टेंसर | (C8), (C11-C13) |
(आई4) | offset_dims |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C1), (C4-C5), (C13) |
(I5) | collapsed_slice_dims |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C1), (C6-C8), (C13) |
(I6) | start_index_map |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C3), (C9), (C10) |
(I7) | index_vector_dim |
si64 टाइप का कॉन्स्टेंट |
(C2), (C3), (C13) |
(I8) | indices_are_sorted |
i1 टाइप का कॉन्स्टेंट |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C5), (C13-C14) |
कंस्ट्रेंट
- (C1)
rank(operand) = size(offset_dims) + size(collapsed_slice_dims)
. - (C2)
0 <= index_vector_dim <= rank(start_indices)
. - (C3)
size(start_index_map) = index_vector_dim < rank(start_indices) ? dim(start_indices, index_vector_dim) : 1
. - (C4)
is_unique(offset_dims) and is_sorted(offset_dims)
. - (C5)
0 <= offset_dims < rank(result)
. - (C6)
is_unique(collapsed_slice_dims) and is_sorted(collapsed_slice_dims)
. - (C7)
0 <= collapsed_slice_dims < rank(operand)
. - (C8)
slice_sizes[collapsed_slice_dims...] <= 1
. - (C9)
is_unique(start_index_map)
. - (C10)
0 <= start_index_map < rank(operand)
. - (C11)
size(slice_sizes) = rank(operand)
. - (C12)
0 <= slice_sizes <= shape(operand)
. - (C13)
shape(result) = combine(batch_dim_sizes, offset_dim_sizes)
जहां:batch_dim_sizes = shape(start_indices)
, सिर्फ़ डाइमेंशन का साइज़index_vector_dim
से संबंधितstart_indices
को शामिल नहीं किया गया है.offset_dim_sizes = shape(slice_sizes)
, सिर्फ़ डाइमेंशन के साइज़collapsed_slice_dims
से संबंधितslice_sizes
में शामिल नहीं किए गए हैं.combine
,batch_dim_sizes
कोbatch_dims
के हिसाब से ऐक्सिस पर लगाता है औरoffset_dims
के हिसाब से, ऐक्सिस परoffset_dim_sizes
.
- (C14)
element_type(operand) = element_type(result)
.
उदाहरण
// %operand: [
// [[1, 2], [3, 4], [5, 6], [7, 8]],
// [[9, 10],[11, 12], [13, 14], [15, 16]],
// [[17, 18], [19, 20], [21, 22], [23, 24]]
// ]
// %start_indices: [
// [[0, 0], [1, 0], [2, 1]],
// [[0, 1], [1, 1], [0, 2]]
// ]
// %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
सिमैंटिक
यह ऑपरेशन इसके फ़ंक्शनल रूप से एक जैसा है
आईओटा
ऑप, लेकिन output_shape
के ज़रिए नतीजे का आकार डायनैमिक तौर पर बताया जाता है.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | output_shape |
पूर्णांक प्रकार का 1-विमीय टेंसर | (C1), (C2) |
(I2) | iota_dimension |
si64 |
(सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
इंटीजर, फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी2) |
कंस्ट्रेंट
- (C1)
0 <= iota_dimension < size(output_shape)
. - (C2)
rank(result) = size(output_shape)
.
उदाहरण
%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
सिमैंटिक
यह ऑपरेशन इसके फ़ंक्शनल रूप से एक जैसा है
पैड
ठीक है, लेकिन edge_padding_low
, edge_padding_high
, और interior_padding
के साथ
को डाइनैमिक रूप से वैल्यू के तौर पर बताया जाता है.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C1), (C2), (C4) |
(I2) | padding_value |
0-डाइमेंशन वाला टेंसर या हर टेंसर क्वांटाइज़्ड टेंसर | (सी1) |
(I3) | edge_padding_low |
पूर्णांक प्रकार का 1-विमीय टेंसर | (C1), (C4) |
(आई4) | edge_padding_high |
पूर्णांक प्रकार का 1-विमीय टेंसर | (C1), (C4) |
(I5) | interior_padding |
पूर्णांक प्रकार का 1-विमीय टेंसर | (सी2-सी4) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी3-सी6) |
कंस्ट्रेंट
- (C1)
element_type(operand) = element_type(padding_value) = element_type(result)
. - (C2)
size(edge_padding_low) = size(edge_padding_high) = size(interior_padding) = rank(operand)
. - (C3)
0 <= interior_padding
. - (C4)
shape(result) = shape(operand) + edge_padding_low + max(shape(operand) - 1, 0) * interior_padding + edge_padding_high
.
उदाहरण
// %operand: [
// [1, 2, 3],
// [4, 5, 6]
// ]
// %padding_value: 0
// %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
सिमैंटिक
यह ऑपरेशन इसके फ़ंक्शनल रूप से एक जैसा है
आकार बदलना
ऑप, लेकिन output_shape
के ज़रिए नतीजे का आकार डायनैमिक तौर पर बताया जाता है.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
टेंसर या क्वांटाइज़्ड टेंसर | (सी1-सी3) |
(I2) | output_shape |
पूर्णांक प्रकार का 1-विमीय टेंसर | (सी4) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या क्वांटाइज़्ड टेंसर | (सी1-सी4) |
कंस्ट्रेंट
- (C1)
element_type(result)
देने वाली कंपनी:- अगर
!is_per_axis_quantized(operand)
है, तोelement_type(operand)
. element_type(operand)
, लेकिनquantization_dimension(operand)
और ऐसा न होने परquantization_dimension(result)
अलग हो सकती है.
- अगर
- (C2)
size(operand) = size(result)
. - (C3) अगर
is_per_axis_quantized(operand)
:reduce(dims(operand, [0, 1, ..., quantization_dimension(operand) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y) = reduce(dims(result, [0, 1, ..., quantization_dimension(result) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y)
.dim(operand, quantization_dimension(operand)) = dim(result, quantization_dimension(result))
.reduce(dims(operand, [quantization_dimension(operand) + 1, ..., rank(operand) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y) = reduce(dims(result, [quantization_dimension(result) + 1, ..., rank(result) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y)
.
- (C4)
size(output_shape) = rank(result)
.
उदाहरण
// %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
सिमैंटिक
डाइनैमिक तौर पर गिने गए शुरुआती इंडेक्स का इस्तेमाल करके, operand
से स्लाइस एक्सट्रैक्ट करता है
और result
टेंसर बनाता है. start_indices
में इसके शुरुआती इंडेक्स शामिल हैं
हर डाइमेंशन के लिए स्लाइस, जिस पर संभावित बदलाव हो सकता है और slice_sizes
इसमें हर डाइमेंशन के स्लाइस के साइज़ शामिल होने चाहिए. औपचारिक तौर पर,
result[result_index] = operand[operand_index]
कहां:
adjusted_start_indices = clamp(0, start_indices, shape(operand) - slice_sizes)
.operand_index = adjusted_start_indices + result_index
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C1), (C2), (C4) |
(I2) | start_indices |
पूर्णांक टाइप के 0-डाइमेंशन वाले टेंसर की वैरायडिक संख्या | (C2), (C3) |
(I3) | slice_sizes |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C2), (C4), (C5) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C1), (C5) |
कंस्ट्रेंट
- (C1)
element_type(operand) = element_type(result)
. - (C2)
size(start_indices) = size(slice_sizes) = rank(operand)
. - (C3)
same(type(start_indices...))
. - (C4)
0 <= slice_sizes <= shape(operand)
. - (C5)
shape(result) = slice_sizes
.
उदाहरण
// %operand: [
// [0, 0, 1, 1],
// [0, 0, 1, 1],
// [0, 0, 0, 0],
// [0, 0, 0, 0]
// ]
// %start_indices0: -1
// %start_indices1: 3
%result = "stablehlo.dynamic_slice"(%operand, %start_indices0, %start_indices1) {
slice_sizes = array<i64: 2, 2>
} : (tensor<4x4xi32>, tensor<i64>, tensor<i64>) -> tensor<2x2xi32>
// %result: [
// [1, 1],
// [1, 1]
// ]
dynamic_update_slice
सिमैंटिक
result
टेंसर बनाता है, जो इसे छोड़कर operand
टेंसर के बराबर होता है
start_indices
से शुरू होने वाला स्लाइस, update
की वैल्यू के साथ अपडेट होता है.
औपचारिक तौर पर, result[result_index]
को इस तरह परिभाषित किया गया है:
update[update_index]
, अगर0 <= update_index < shape(update)
कहां:adjusted_start_indices = clamp(0, start_indices, shape(operand) - shape(update))
.update_index = result_index - adjusted_start_indices
.
- अगर ऐसा नहीं है, तो
operand[result_index]
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C1-C4), (C6) |
(I2) | update |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C2), (C3), (C6) |
(I3) | start_indices |
पूर्णांक टाइप के 0-डाइमेंशन वाले टेंसर की वैरायडिक संख्या | (C4), (C5) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
type(operand) = type(result)
. - (C2)
element_type(update) = element_type(operand)
. - (C3)
rank(update) = rank(operand)
. - (C4)
size(start_indices) = rank(operand)
. - (C5)
same(type(start_indices...))
. - (C6)
0 <= shape(update) <= shape(operand)
.
उदाहरण
// %operand: [
// [1, 1, 0, 0],
// [1, 1, 0, 0],
// [1, 1, 1, 1],
// [1, 1, 1, 1]
// ]
// %update: [
// [1, 1],
// [1, 1]
// ]
// %start_indices0: -1
// %start_indices1: 3
%result = "stablehlo.dynamic_update_slice"(%operand, %update, %start_indices0, %start_indices1)
: (tensor<4x4xi32>, tensor<2x2xi32>, tensor<i64>, tensor<i64>) -> tensor<4x4xi32>
// %result: [
// [1, 1, 1, 1],
// [1, 1, 1, 1],
// [1, 1, 1, 1],
// [1, 1, 1, 1]
// ]
घातांकी
सिमैंटिक
operand
टेंसर पर एलिमेंट के हिसाब से चरघातांकीय संक्रिया करता है और इससे
result
टेंसर. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- फ़्लोट के लिए: IEEE-754 से
exp
. - सम्मिश्र संख्याओं के लिए: सम्मिश्र घातांक.
- क्वांटाइज़्ड टाइप के लिए:
dequantize_op_quantize(exponential, operand, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// %operand: [[0.0, 1.0], [2.0, 3.0]]
%result = "stablehlo.exponential"(%operand) : (tensor<2x2xf64>) -> tensor<2x2xf64>
// %result: [[1.0, 2.7182818284590451], [7.3890560989306504, 20.085536923187668]]
exponential_minus_one
सिमैंटिक
operand
टेंसर पर एलिमेंट के हिसाब से एक्सपोनेन्शियल माइनस एक संक्रिया करता है और
result
टेंसर बनाता है. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- फ़्लोट के लिए: IEEE-754 से
expm1
. - सम्मिश्र संख्याओं के लिए: सम्मिश्र घातांक से एक घटाएं.
- क्वांटाइज़्ड टाइप के लिए:
dequantize_op_quantize(exponential_minus_one, operand, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// %operand: [0.0, 1.0]
%result = "stablehlo.exponential_minus_one"(%operand) : (tensor<2xf64>) -> tensor<2xf64>
// %result: [0.0, 1.71828187]
एफ़एफ़टी
सिमैंटिक
रियल और कॉम्प्लेक्स के लिए फ़ॉरवर्ड और इन्वर्स फ़ूरियर रूपांतरण करता है इनपुट/आउटपुट.
fft_type
इनमें से एक है:
FFT
: कॉम्प्लेक्स से मुश्किल एफ़एफ़टी फ़ॉरवर्ड करें.IFFT
: इनवर्स कॉम्प्लेक्स से कॉम्प्लेक्स एफ़एफ़टी.RFFT
: रीयल-टू-कॉम्प्लेक्स एफ़एफ़टी फ़ॉरवर्ड करें.IRFFT
: रियल-टू-कॉम्प्लेक्स FFT (यानी जटिल लेता है, वास्तविक देता है).
औपचारिक रूप से, fft
फ़ंक्शन दिया गया है, जो
इनपुट के रूप में जटिल प्रकार, जो
आउटपुट और असंतत फूरिये रूपांतरण की गणना करता है:
fft_type = FFT
के लिए, result
को L की सीरीज़ के आखिरी नतीजे के तौर पर तय किया जाता है
कैलकुलेशन जहां L = size(fft_length)
. उदाहरण के लिए, L = 3
के लिए:
result1[i0, ..., :] = fft(operand[i0, ..., :])
.result2[i0, ..., :, iR-1] = fft(result1[i0, ..., :, iR-1])
.result[i0, ..., :, iR-2, iR-1] = fft(result2[i0, ..., :, iR-2, iR-1])
.
इसके अलावा, ifft
फ़ंक्शन दिया गया है, जिसमें एक ही तरह का हस्ताक्षर है और
fft
के व्युत्क्रम की गणना करता है:
fft_type = IFFT
के लिए, result
को कंप्यूटेशन (कंप्यूटेशन) के व्युत्क्रम के तौर पर परिभाषित किया जाता है
fft_type = FFT
के लिए. उदाहरण के लिए, L = 3
के लिए:
result1[i0, ..., :, iR-2, iR-1] = ifft(operand[i0, ..., :, iR-2, iR-1])
.result2[i0, ..., :, iR-1] = ifft(result1[i0, ..., :, iR-1])
.result[i0, ..., :] = ifft(result2[i0, ..., :])
.
इसके अलावा, rfft
फ़ंक्शन दिया गया है, जो
फ़्लोटिंग-पॉइंट टाइप, मुश्किल टाइप के 1-डाइमेंशन वाले टेंसर पैदा करता है
और इस तरह से काम करता है:
rfft(real_operand) = truncated_result
जहांcomplex_operand... = (real_operand..., 0.0)
.complex_result = fft(complex_operand)
.truncated_result = complex_result[:(rank(complex_result) / 2 + 1)]
.
(जब वास्तविक ऑपरेंड के लिए अलग फूरिये रूपांतरण की गणना की जाती है, तो पहले
नतीजे के N/2 + 1
एलिमेंट, बाकी के नतीजे के बारे में साफ़ तौर पर जानकारी देते हैं,
इसलिए गैर-ज़रूरी एलिमेंट की गिनती करने से बचने के लिए, rfft
के नतीजे को छोटा कर दिया जाता है).
fft_type = RFFT
के लिए, result
को L की सीरीज़ के आखिरी नतीजे के तौर पर तय किया जाता है
कैलकुलेशन जहां L = size(fft_length)
. उदाहरण के लिए, L = 3
के लिए:
result1[i0, ..., :] = rfft(operand[i0, ..., :])
.result2[i0, ..., :, iR-1] = fft(result1[i0, ..., :, iR-1])
.result[i0, ..., :, iR-2, iR-1] = fft(result2[i0, ..., :, iR-2, iR-1])
.
आखिर में, irfft
फ़ंक्शन दिया गया, जिसमें एक ही तरह का हस्ताक्षर है और
rfft
के व्युत्क्रम की गणना करता है:
fft_type = IRFFT
के लिए, result
को कंप्यूटेशन (कंप्यूटेशन) के व्युत्क्रम के तौर पर परिभाषित किया जाता है
fft_type = RFFT
के लिए. उदाहरण के लिए, L = 3
के लिए:
result1[i0, ..., :, iR-2, iR-1] = ifft(operand[i0, ..., :, iR-2, iR-1])
.result2[i0, ..., :, iR-1] = ifft(result1[i0, ..., :, iR-1])
.result[i0, ..., :] = irfft(result2[i0, ..., :])
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप का टेंसर | (C1), (C2), (C4), (C5) |
(I2) | fft_type |
FFT , IFFT , RFFT , और IRFFT का कुल डेटा |
(C2), (C5) |
(I3) | fft_length |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C1), (C3), (C4) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप का टेंसर | (C2), (C4), (C5) |
कंस्ट्रेंट
- (C1)
size(fft_length) <= rank(operand)
. - (C2)
operand
औरresult
एलिमेंट के बीच का संबंध अलग-अलग होता है:- अगर
fft_type = FFT
,element_type(operand)
औरelement_type(result)
उनका कॉम्प्लेक्स टाइप एक ही है. - अगर
fft_type = IFFT
,element_type(operand)
औरelement_type(result)
उनका कॉम्प्लेक्स टाइप एक ही है. - अगर
fft_type = RFFT
,element_type(operand)
एक फ़्लोटिंग-पॉइंट टाइप है औरelement_type(result)
, एक ही फ़्लोटिंग-पॉइंट का जटिल टाइप है सिमेंटिक्स. - अगर
fft_type = IRFFT
, तोelement_type(operand)
एक जटिल टाइप है औरelement_type(result)
एक ही फ़्लोटिंग-पॉइंट का प्रकार फ़्लोटिंग-पॉइंट है सिमेंटिक्स.
- अगर
- (C3)
1 <= size(fft_length) <= 3
. - (C4) अगर
operand
औरresult
के बीच में, तोreal
फ़्लोटिंग-पॉइंट टाइप को चुनें. इसके बाद,shape(real)[-size(fft_length):] = fft_length
. - (C5)
shape(result) = shape(operand)
, इन्हें छोड़कर:- अगर
fft_type = RFFT
,dim(result, -1) = dim(operand, -1) = 0 ? 0 : dim(operand, -1) / 2 + 1
. - अगर
fft_type = IRFFT
,dim(operand, -1) = dim(result, -1) = 0 ? 0 : dim(result, -1) / 2 + 1
.
- अगर
उदाहरण
// %operand: [(1.0, 0.0), (0.0, 0.0), (0.0, 0.0), (0.0, 0.0)]
%result = "stablehlo.fft"(%operand) {
fft_type = #stablehlo<fft_type FFT>,
fft_length = 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)]
फ़्लोर
सिमैंटिक
operand
टेंसर के एलिमेंट के हिसाब से फ़्लोर बनाता है और result
टेंसर बनाता है.
आईईईई-754 से roundToIntegralTowardNegative
ऑपरेशन लागू करता है
स्पेसिफ़िकेशन. क्वांटाइज़्ड टाइप के लिए,
dequantize_op_quantize(floor, operand, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// %operand: [-0.8166, -0.2530, 0.2530, 0.8166, 2.0]
%result = "stablehlo.floor"(%operand) : (tensor<5xf32>) -> tensor<5xf32>
// %result: [-1.0, -1.0, 0.0, 0.0, 2.0]
इकट्ठा करें
सिमैंटिक
start_indices
में दिए गए ऑफ़सेट से operand
टेंसर से स्लाइस इकट्ठा करता है
और result
टेंसर बनाता है.
नीचे दिया गया डायग्राम दिखाता है कि result
में एलिमेंट,
operand
पर जाकर, एक अच्छे उदाहरण का इस्तेमाल करें. इस डायग्राम में, result
के कुछ उदाहरण चुने गए हैं
और विस्तार से बताता है कि वे किन operand
इंडेक्स से जुड़े हैं.
ज़्यादा औपचारिक तौर पर, result[result_index] = operand[operand_index]
जहां:
batch_dims = [d for d in axes(result) and d not in offset_dims]
.batch_index = result_index[batch_dims...]
.start_index
को इस तरह से परिभाषित किया गया है:start_indices[bi0, ..., :, ..., biN]
जहांbi
अलग-अलग एलिमेंट होते हैंbatch_index
और:
कोindex_vector_dim
इंडेक्स में डाला जाता है, अगरindex_vector_dim
rank(start_indices)
.- अगर ऐसा नहीं है, तो
[start_indices[batch_index]]
.
axes(operand)
मेंd_operand
के लिए,full_start_index[d_operand] = clamp(start_index[d_start], 0, dim(operand, d_operand) - slice_sizes[d_operand])
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है अगरd_operand = start_index_map[d_start]
है.- अगर ऐसा नहीं है, तो
full_start_index[d_operand] = 0
.
axes(operand)
मेंd_operand
के लिए,full_batching_index[d_operand] = batch_index[d_start - (d_start < index_vector_dim ? 0 : 1)]
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है अगरd_operand = operand_batching_dims[i_batching]
औरd_start = start_indices_batching_dims[i_batching]
.- अगर ऐसा नहीं है, तो
full_batching_index[d_operand] = 0
.
offset_index = result_index[offset_dims...]
.full_offset_index = [oi0, ..., 0, ..., oiN]
, जहांoi
व्यक्तिगत हैंoffset_index
के एलिमेंट का इस्तेमाल किया जाता है और0
को इंडेक्स में शामिल किया जाता हैcollapsed_slice_dims
औरoperand_batching_dims
.operand_index = full_start_index + full_batching_index + full_offset_index
.
अगर indices_are_sorted
, true
है, तो लागू करने पर यह मान लिया जा सकता है कि
start_indices
को start_index_map
के हिसाब से क्रम में लगाया जाता है, नहीं तो
व्यवहार के बारे में नहीं बताया गया है. आम तौर पर, indices(result)
के सभी i1 < i2
के लिए,
full_start_index(i1) <= full_start_index(i2)
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C1), (C8), (C11), (C17), (C19-C21), (C23) |
(I2) | start_indices |
पूर्णांक टाइप का टेंसर | (C2-C3), (C14), (C17), (C22) |
(I3) | offset_dims |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C1), (C4-C5), (C22) |
(आई4) | collapsed_slice_dims |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C1), (C6-C9), (C22) |
(I5) | operand_batching_dims |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C1), (C6), (C10-C12), (C16-C18), (C22) |
(I6) | start_indices_batching_dims |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C13-C17) |
(I7) | start_index_map |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C3), (C18-C19) |
(I8) | index_vector_dim |
si64 टाइप का कॉन्स्टेंट |
(C2-C3), (C15), (C22) |
(I9) | slice_sizes |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C9), (C12), (C20-C22) |
(I10) | indices_are_sorted |
i1 टाइप का कॉन्स्टेंट |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C5), (C22-C23) |
कंस्ट्रेंट
- (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)
जहां:batch_dim_sizes = shape(start_indices)
, सिर्फ़ डाइमेंशन का साइज़index_vector_dim
से संबंधितstart_indices
को शामिल नहीं किया गया है.offset_dim_sizes = slice_sizes
, लेकिन इसमें डाइमेंशन का साइज़collapsed_slice_dims
और के संगतslice_sizes
operand_batching_dims
शामिल नहीं हैं.combine
,batch_dim_sizes
कोbatch_dims
के हिसाब से ऐक्सिस पर लगाता है औरoffset_dims
के हिसाब से, ऐक्सिस परoffset_dim_sizes
.
- (C23)
element_type(operand) = element_type(result)
.
उदाहरण
// %operand: [
// [
// [[1, 2], [3, 4], [5, 6], [7, 8]],
// [[9, 10],[11, 12], [13, 14], [15, 16]],
// [[17, 18], [19, 20], [21, 22], [23, 24]]
// ],
// [
// [[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
सिमैंटिक
operand
के दिए गए dimension
का साइज़ बनाता है. औपचारिक तौर पर,
result = dim(operand, dimension)
. सीमेंटिक का संबंध सिर्फ़ आकार से संबंधित है
का एक हिस्सा है. एलिमेंट का टाइप कुछ भी हो सकता है.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
टेंसर या क्वांटाइज़्ड टेंसर | (सी1) |
(I2) | dimension |
si64 टाइप का कॉन्स्टेंट |
(सी1) |
आउटपुट
नाम | टाइप |
---|---|
result |
si32 टाइप का 0-डाइमेंशन वाला टेंसर |
कंस्ट्रेंट
- (C1)
0 <= dimension < rank(operand)
.
उदाहरण
// %operand: [[1, 2, 3], [4, 5, 6]]
%result = "stablehlo.get_dimension_size"(%operand) {
dimension = 1 : i64
} : (tensor<2x3xi64>) -> tensor<i32>
// %result: 3
get_tuple_element
सिमैंटिक
operand
टपल की index
स्थिति पर एलिमेंट निकालता है और नतीजे के रूप में
result
. औपचारिक तौर पर, result = operand[index]
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
टपल | (C1), (C2) |
(I2) | index |
si32 टाइप का कॉन्स्टेंट |
(C1), (C2) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
काम करने वाला कोई भी टाइप | (सी2) |
कंस्ट्रेंट
- (C1)
0 <= index < size(operand)
. - (C2)
type(result) = tuple_element_types(operand)[index]
.
उदाहरण
// %operand: ([1.0, 2.0], (3))
index = 0 : i32
} : (tuple<tensor<2xf32>, tuple<tensor<i32>>>) -> tensor<2xf32>
// %result: [1.0, 2.0]
अगर
सिमैंटिक
true_branch
से सिर्फ़ एक फ़ंक्शन चलाने पर आउटपुट मिलता है या
pred
की वैल्यू के आधार पर false_branch
. औपचारिक तौर पर, result =
pred ? true_branch() : false_branch()
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | pred |
i1 टाइप का 0-डाइमेंशन वाला टेंसर |
|
(I2) | true_branch |
फ़ंक्शन | (सी1-सी3) |
(I3) | false_branch |
फ़ंक्शन | (C1), (C2) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
results |
टेंसर की वैरायडिक संख्या, क्वांटाइज़ किए गए टेंसर या टोकन | (सी3) |
कंस्ट्रेंट
- (C1)
input_types(true_branch) = input_types(false_branch) = []
. - (C2)
output_types(true_branch) = output_types(false_branch)
. - (C3)
type(results...) = output_types(true_branch)
.
उदाहरण
// %result_true_branch: 10
// %result_false_branch: 11
// %pred: true
%result = "stablehlo.if"(%pred) ({
"stablehlo.return"(%result_true_branch) : (tensor<i32>) -> ()
}, {
"stablehlo.return"(%result_false_branch) : (tensor<i32>) -> ()
}) : (tensor<i1>) -> tensor<i32>
// %result: 10
Imag
सिमैंटिक
एलिमेंट के हिसाब से, operand
से काल्पनिक हिस्से को एक्सट्रैक्ट करता है और नतीजे के तौर पर
result
टेंसर. औपचारिक तौर पर, हर एलिमेंट x
के लिए:
imag(x) = is_complex(x) ? imaginary_part(x) :
constant(0, element_type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप का टेंसर | (C1), (C2) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट टाइप का टेंसर | (C1), (C2) |
कंस्ट्रेंट
- (C1)
shape(result) = shape(operand)
. - (C2)
element_type(result)
को इस तरह परिभाषित किया गया है:- अगर
is_complex(operand)
है, तोcomplex_element_type(element_type(operand))
. - अगर ऐसा नहीं है, तो
element_type(operand)
.
- अगर
उदाहरण
// %operand: [(1.0, 2.0), (3.0, 4.0)]
%result = "stablehlo.imag"(%operand) : (tensor<2xcomplex<f32>>) -> tensor<2xf32>
// %result: [2.0, 4.0]
इनफ़ीड
सिमैंटिक
इनफ़ीड के डेटा को पढ़ता है और results
जनरेट करता है.
infeed_config
के सीमैंटिक को लागू किया जाता है.
results
में पेलोड मान पहले आने वाले पेलोड मान और आने वाले टोकन होते हैं
अंतिम. आने वाले समय में, हमारी योजना पेलोड और टोकन को दो हिस्सों में बांटने की है
साफ़ तौर पर जानकारी देने के लिए, अलग-अलग आउटपुट
(#670).
इनपुट
लेबल | नाम | टाइप |
---|---|---|
(I1) | token |
token |
(I2) | infeed_config |
string टाइप का कॉन्स्टेंट |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
results |
टेंसर की वैरायडिक संख्या, क्वांटाइज़ किए गए टेंसर या टोकन | (सी1-सी3) |
कंस्ट्रेंट
- (C1)
0 < size(results)
. - (C2)
is_empty(result[:-1])
याis_tensor(type(results[:-1]))
. - (C3)
is_token(type(results[-1]))
.
उदाहरण
// %token: !stablehlo.token
// infeed_queue[0]: [[1, 2], [3, 4]]
// infeed_queue[1]: [[5, 6], [7, 8]]
%results0:2 = "stablehlo.infeed"(%token) {
infeed_config = ""
} : (!stablehlo.token) -> (tensor<2x2xi64>, !stablehlo.token)
// results0#0: [[1, 2], [3, 4]]
%results1:2 = "stablehlo.infeed"(%token) {
infeed_config = ""
} : (!stablehlo.token) -> (tensor<2x2xi64>, !stablehlo.token)
// results1#0: [[5, 6], [7, 8]]
आईओटा
सिमैंटिक
output
टेंसर को शून्य से शुरू होने वाले बढ़ते क्रम में वैल्यू से भरता है
iota_dimension
डाइमेंशन के साथ. औपचारिक तौर पर,
output[output_index] = constant(is_quantized(output) ?
quantize(output_index[iota_dimension], element_type(output)) :
output_index[iota_dimension], element_type(output))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | iota_dimension |
si64 |
(सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
output |
इंटीजर, फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
0 <= iota_dimension < rank(output)
.
उदाहरण
%output = "stablehlo.iota"() {
iota_dimension = 0 : i64
} : () -> tensor<4x5xi32>
// %output: [
// [0, 0, 0, 0, 0],
// [1, 1, 1, 1, 1],
// [2, 2, 2, 2, 2],
// [3, 3, 3, 3, 3]
// ]
%output = "stablehlo.iota"() {
iota_dimension = 1 : i64
} : () -> tensor<4x5xi32>
// %output: [
// [0, 1, 2, 3, 4],
// [0, 1, 2, 3, 4],
// [0, 1, 2, 3, 4],
// [0, 1, 2, 3, 4]
// ]
is_finite
सिमैंटिक
एलिमेंट के हिसाब से जांच करता है कि x
की वैल्यू सीमित है या नहीं (यानी दोनों में से कोई भी वैल्यू नहीं है)
+Inf, -Inf, या NaN) और y
टेंसर नहीं बनाता है. isFinite
लागू करता है
आईईईई-754 स्पेसिफ़िकेशन के मुताबिक काम करती है. क्वांटिफ़ाइड टाइप के लिए नतीजा यह होता है
हमेशा true
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | x |
फ़्लोटिंग-पॉइंट टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
y |
बूलियन टाइप का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
shape(x) = shape(y)
.
उदाहरण
// Logical values: -Inf, +Inf, NaN, ...
// %x: [0xFFF0000000000000, 0x7FF0000000000000, 0x7FF8000000000000, -10.0, -0.0, 0.0, 10.0]
%y = "stablehlo.is_finite"(%x) : (tensor<7xf64) -> tensor<7xi1>
// %y: [false, false, false, true, true, true, true]
log
सिमैंटिक
operand
टेंसर पर एलिमेंट के हिसाब से लॉगारिद्म (लघुगणक) की कार्रवाई करता है और इससे
result
टेंसर. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- फ़्लोट के लिए: IEEE-754 से
log
. - सम्मिश्र संख्याओं के लिए: सम्मिश्र लॉगारिद्म.
- क्वांटाइज़्ड टाइप के लिए:
dequantize_op_quantize(log, operand, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// %operand: [[1.0, 2.0], [3.0, 4.0]]
%result = "stablehlo.log"(%operand) : (tensor<2x2xf64>) -> tensor<2x2xf64>
// %result: [[0.0, 0.69314718055994529], [1.0986122886681098, 1.3862943611198906]]
log_plus_one
सिमैंटिक
operand
टेंसर और एलिमेंट के हिसाब से लॉगारिद्म (लघुगणक) और एक संक्रिया करता है
result
टेंसर बनाता है. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- फ़्लोट के लिए: IEEE-754 से
logp1
. - सम्मिश्र संख्याओं के लिए: सम्मिश्र लॉगारिद्म प्लस वन.
- क्वांटाइज़्ड टाइप के लिए:
dequantize_op_quantize(log_plus_one, operand, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// %operand: [0.0, -0.999, 7.0, 6.38905621, 15.0]
%result = "stablehlo.log_plus_one"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// %result: [0.0, -6.90776825, 2.07944155, 2.0, 2.77258873]
लॉजिस्टिक
सिमैंटिक
operand
टेंसर पर एलिमेंट के हिसाब से लॉजिस्टिक ऑपरेशन करता है और
result
टेंसर. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- फ़्लोट के लिए: IEEE-754 से
division(1, addition(1, exp(-x)))
. - कॉम्प्लेक्स लॉजिस्टिक के लिए: कॉम्प्लेक्स लॉजिस्टिक.
- क्वांटाइज़्ड टाइप के लिए:
dequantize_op_quantize(logistic, operand, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// %operand: [[0.0, 1.0], [2.0, 3.0]]
%result = "stablehlo.logistic"(%operand) : (tensor<2x2xf64>) -> tensor<2x2xf64>
// %result: [[0.5, 0.73105858], [0.88079708, 0.95257413]]
मैप
सिमैंटिक
dimensions
और के साथ-साथ inputs
पर मैप फ़ंक्शन computation
लागू करता है
result
टेंसर बनाता है.
औपचारिक तौर पर, result[result_index] = computation(inputs...[result_index])
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | inputs |
टेंसर की वैरायडिक संख्या या हर टेंसर की क्वांटाइज़्ड टेंसर की संख्या | (सी1-सी4) |
(I2) | dimensions |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(सी3) |
(I3) | computation |
फ़ंक्शन | (सी4) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C1), (C4) |
कंस्ट्रेंट
- (C1)
shape(inputs...) = shape(result)
. - (C2)
0 < size(inputs) = N
. - (C3)
dimensions = range(rank(inputs[0]))
. - (C4)
computation
का टाइप(tensor<E0>, ..., tensor<EN-1>) -> tensor<E'>
है जहांEi = element_type(inputs[i])
औरE' = element_type(result)
हैं.
उदाहरण
// %input0: [[0, 1], [2, 3]]
// %input1: [[4, 5], [6, 7]]
%result = "stablehlo.map"(%input0, %input1) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = stablehlo.multiply %arg0, %arg1 : tensor<i64>
stablehlo.return %0 : tensor<i64>
}) {
dimensions = array<i64: 0, 1>
} : (tensor<2x2xi64>, tensor<2x2xi64>) -> tensor<2x2xi64>
// %result: [[0, 5], [12, 21]]
ज़्यादा से ज़्यादा
सिमैंटिक
टेंसर lhs
और rhs
पर एलिमेंट के हिसाब से सबसे बड़ी कार्रवाई करता है और नतीजे के तौर पर
result
टेंसर. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- बूलियन के लिए: लॉजिकल OR.
- पूर्णांकों के लिए: ज़्यादा से ज़्यादा पूर्णांक.
- फ़्लोट के लिए: IEEE-754 से
maximum
. - सम्मिश्र संख्याओं के लिए:
(real, imaginary)
पेयर के लिए लेक्सिकोग्राफ़िक ज़्यादा से ज़्यादा. जटिल संख्याओं को क्रम से लगाने में हैरान करने वाले सिमैंटिक, इसलिए, आने वाले समय में हम कॉम्प्लेक्स नंबर की सुविधा को बंद करने की योजना बना रहे हैं. इस कार्रवाई के लिए (#560). - क्वांटाइज़्ड टाइप के लिए:
dequantize_op_quantize(maximum, lhs, rhs, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | lhs |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी1) |
(I2) | rhs |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)
.
उदाहरण
// %lhs: [[1, 2], [7, 8]]
// %rhs: [[5, 6], [3, 4]]
%result = "stablehlo.maximum"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[5, 6], [7, 8]]
कम से कम
सिमैंटिक
टेंसर lhs
और rhs
पर एलिमेंट के हिसाब से कम से कम संक्रिया करता है और इससे
result
टेंसर. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- बूलियन के लिए: लॉजिकल AND.
- पूर्णांकों के लिए: कम से कम पूर्णांक.
- फ़्लोट के लिए: IEEE-754 से
minimum
. - कॉम्प्लेक्स नंबर के लिए:
(real, imaginary)
पेयर के लिए कम से कम लेक्सिकोग्राफ़िक. जटिल संख्याओं को क्रम से लगाने में हैरान करने वाले सिमैंटिक, इसलिए, आने वाले समय में हम कॉम्प्लेक्स नंबर की सुविधा को बंद करने की योजना बना रहे हैं. इस कार्रवाई के लिए (#560). - क्वांटाइज़्ड टाइप के लिए:
dequantize_op_quantize(minimum, lhs, rhs, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | lhs |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी1) |
(I2) | rhs |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)
.
उदाहरण
// %lhs: [[1, 2], [7, 8]]
// %rhs: [[5, 6], [3, 4]]
%result = "stablehlo.minimum"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[1, 2], [3, 4]]
गुणा
सिमैंटिक
दो टेंसर lhs
और rhs
के एलिमेंट के हिसाब से गुणनफल करता है और
result
टेंसर. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- बूलियन के लिए: लॉजिकल AND.
- पूर्णांकों के लिए: पूर्णांक का गुणा करना.
- फ़्लोट के लिए: IEEE-754 से
multiplication
. - सम्मिश्र संख्याओं के लिए: जटिल गुणा करना.
- क्वांटाइज़्ड टाइप के लिए:
dequantize_op_quantize(multiply, lhs, rhs, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | lhs |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी1) |
(I2) | rhs |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.multiply"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[5, 12], [21, 32]]
निगेट
सिमैंटिक
operand
टेंसर के एलिमेंट के हिसाब से निगेशन करता है और result
बनाता है
टेंसर. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- साइन किए गए पूर्णांकों के लिए: पूर्णांक निगेशन.
- साइन नहीं किए गए पूर्णांकों के लिए: बिटकास्ट से हस्ताक्षर किए गए पूर्णांक, पूर्णांक निगेशन, बिटकास्ट साइन नहीं किए गए पूर्णांक पर वापस जाएं.
- फ़्लोट के लिए: IEEE-754 से
negate
. - कॉम्प्लेक्स निगेशन के लिए: कॉम्प्लेक्स निगेशन.
- क्वांटाइज़्ड टाइप के लिए:
dequantize_op_quantize(negate, operand, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
इंटीजर, फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
इंटीजर, फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// Negation operation with integer Tensors
// %operand: [0, -2]
%result = "stablehlo.negate"(%operand) : (tensor<2xi32>) -> tensor<2xi32>
// %result: [0, 2]
// Negation operation with with complex tensors
// %operand: (2.5, 0.0)
%result = "stablehlo.negate"(%operand) : (tensor<1xcomplex<f32>>) -> tensor<1xcomplex<f32>>
// %result: [-2.5, -0.0]
नहीं
सिमैंटिक
टेंसर operand
के एलिमेंट के हिसाब से परफ़ॉर्म करता है और result
टेंसर बनाता है.
एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- बूलियन के लिए: लॉजिकल NOT.
- पूर्णांक के लिए: बिट के अनुसार NOT.
तर्क
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
operand |
बूलियन या पूर्णांक टाइप का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
बूलियन या पूर्णांक टाइप का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
type(operand) = type(result)
.
उदाहरण
// Bitwise operation with with integer tensors
// %operand: [[1, 2], [3, 4]]
%result = "stablehlo.not"(%operand) : (tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[-2, -3], [-4, -5]]
// Bitwise operation with with boolean tensors
// %operand: [true, false]
%result = "stablehlo.not"(%operand) : (tensor<2xi1>) -> tensor<2xi1>
// %result: [false, true]
optimization_barrier
सिमैंटिक
यह पक्का करता है कि operand
बनाने वाले ऑपरेशन,
ऐसी कार्रवाइयां जो result
पर निर्भर होती हैं और कंपाइलर के ट्रांसफ़ॉर्मेशन को रोकती हैं
एक जगह से दूसरी जगह पर जाने से रोका जा सकता है. इसके अलावा, यह ऑपरेशन है
कोई पहचान, उदाहरण result = operand
.
तर्क
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
operand |
टेंसर की वैरायडिक संख्या, हर टेंसर की क्वांटाइज़ किए गए टेंसर या टोकन | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर की वैरायडिक संख्या, हर टेंसर की क्वांटाइज़ किए गए टेंसर या टोकन | (सी1) |
कंस्ट्रेंट
- (C1)
type(operand...) = type(result...)
.
उदाहरण
// %operand0: 0.0
// %operand1: 1.0
%result0, %result1 = "stablehlo.optimization_barrier"(%operand0, %operand1) : (tensor<f32>, tensor<f32>) -> (tensor<f32>, tensor<f32>)
// %result0: 0.0
// %result1: 1.0
या
सिमैंटिक
दो टेंसर lhs
और rhs
के एलिमेंट के हिसाब से OR करता है और result
जनरेट करता है
टेंसर. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- बूलियन के लिए: लॉजिकल OR.
- पूर्णांक के लिए: बिट के अनुसार OR.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | lhs |
पूर्णांक या बूलियन टाइप का टेंसर | (सी1) |
(I2) | rhs |
पूर्णांक या बूलियन टाइप का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
पूर्णांक या बूलियन टाइप का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
type(lhs) = type(rhs) = type(result)
.
उदाहरण
// Bitwise operation with with integer tensors
// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.or"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[5, 6], [7, 12]]
// Logical operation with with boolean tensors
// %lhs: [[false, false], [true, true]]
// %rhs: [[false, true], [false, true]]
%result = "stablehlo.or"(%lhs, %rhs) : (tensor<2x2xi1>, tensor<2x2xi1>) -> tensor<2x2xi1>
// %result: [[false, true], [true, true]]
आउटफ़ीड
सिमैंटिक
आउटफ़ीड में inputs
लिखता है और result
टोकन बनाता है.
outfeed_config
के सीमैंटिक को लागू किया जाता है.
इनपुट
लेबल | नाम | टाइप |
---|---|---|
(I1) | inputs |
टेंसर या क्वांटाइज़्ड टेंसर की वैरायड संख्या |
(I2) | token |
token |
(I3) | outfeed_config |
string टाइप का कॉन्स्टेंट |
आउटपुट
नाम | टाइप |
---|---|
result |
token |
उदाहरण
%result = "stablehlo.outfeed"(%input0, %token) {
outfeed_config = ""
} : (tensor<2x2x2xi64>, !stablehlo.token) -> !stablehlo.token
पैड
सिमैंटिक
टेंसर के आस-पास पैडिंग के साथ-साथ एलिमेंट के बीच में, operand
को बड़ा करता है
दिए गए padding_value
के साथ टेंसर का मान.
edge_padding_low
और edge_padding_high
से जोड़ी गई पैडिंग (जगह) की जानकारी मिलती है
सबसे कम वैल्यू पर (इंडेक्स 0 के बगल में) और हाई-एंड (सबसे ज़्यादा इंडेक्स के बगल में) पर
हर डाइमेंशन का इस्तेमाल करती हैं. पैडिंग (जगह) की मात्रा नेगेटिव हो सकती है, जहां
नेगेटिव पैडिंग की कुल वैल्यू से पता चलता है कि कितने एलिमेंट हटाए जाने हैं
डाइमेंशन से बाहर रखा गया है.
interior_padding
से, इन दोनों के बीच जोड़ी जाने वाली पैडिंग (जगह) की जानकारी मिलती है
एलिमेंट शामिल करना है जो नेगेटिव नहीं हो सकते. अंदर की पैडिंग होती है
किनारे की पैडिंग के पहले इस तरह से रखें कि नेगेटिव एज पैडिंग, टारगेटिंग से एलिमेंट को हटा देगी
एक ही पैरामीटर के तौर पर जोड़ा जाता है.
औपचारिक तौर पर, result[result_index]
को इस तरह परिभाषित किया गया है:
operand[operand_index]
अगरresult_index = edge_padding_low + operand_index * (interior_padding + 1)
.- अगर ऐसा नहीं है, तो
padding_value
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C1), (C2), (C4) |
(I2) | padding_value |
0-डाइमेंशन वाला टेंसर या हर टेंसर क्वांटाइज़्ड टेंसर | (सी1) |
(I3) | edge_padding_low |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C1), (C4) |
(आई4) | edge_padding_high |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C1), (C4) |
(I5) | interior_padding |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(सी2-सी4) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी3-सी6) |
कंस्ट्रेंट
- (C1)
element_type(operand) = element_type(padding_value) = element_type(result)
. - (C2)
size(edge_padding_low) = size(edge_padding_high) = size(interior_padding) = rank(operand)
. - (C3)
0 <= interior_padding
. - (C4)
shape(result) = shape(operand) + edge_padding_low + max(shape(operand) - 1, 0) * interior_padding + edge_padding_high
.
उदाहरण
// %operand: [
// [1, 2, 3],
// [4, 5, 6]
// ]
// %padding_value: 0
%result = "stablehlo.pad"(%operand, %padding_value) {
edge_padding_low = 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
सिमैंटिक
इससे मौजूदा प्रोसेस का partition_id
बनता है.
आउटपुट
नाम | टाइप |
---|---|
result |
ui32 टाइप का 0-डाइमेंशन वाला टेंसर |
उदाहरण
%result = "stablehlo.partition_id"() : () -> tensor<ui32>
पॉप सीएनटी
सिमैंटिक
operand
टेंसर में सेट किए गए बिट की संख्या की एलिमेंट के हिसाब से गिनती करता है
और result
टेंसर बनाता है.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
पूर्णांक टाइप का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
पूर्णांक टाइप का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
type(operand) = type(result)
.
उदाहरण
// %operand: [0, 1, 2, 127]
%result = "stablehlo.popcnt"(%operand) : (tensor<4xi64>) -> tensor<4xi64>
// %result: [0, 1, 1, 7]
पावर
सिमैंटिक
lhs
टेंसर से rhs
टेंसर और एलिमेंट के हिसाब से एक्सपोनेंशिएट करता है
result
टेंसर बनाता है. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- पूर्णांकों के लिए: पूर्णांक घातांक.
- फ़्लोट के लिए: IEEE-754 से
pow
. - सम्मिश्र संख्याओं के लिए: सम्मिश्र घातांक.
- क्वांटाइज़्ड टाइप के लिए:
dequantize_op_quantize(power, lhs, rhs, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | lhs |
इंटीजर, फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
(I2) | rhs |
इंटीजर, फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
इंटीजर, फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// %lhs: [-2.0, -0.0, -36.0, 5.0, 3.0, 10000.0]
// %rhs: [2.0, 2.0, 1.1, 2.0, -1.0, 10.0]
%result = "stablehlo.power"(%lhs, %rhs) : (tensor<6xf64>, tensor<6xf64>) -> tensor<6xf64>
// %result: [4.0, 0.0, -nan, 25.0, 0.333333343, inf]
रीयल
सिमैंटिक
operand
से एलिमेंट के हिसाब से, रीयल पार्ट निकालता है और result
बनाता है
टेंसर. औपचारिक तौर पर, हर एलिमेंट x
के लिए:
real(x) = is_complex(x) ? real_part(x) : x
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप का टेंसर | (C1), (C2) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट टाइप का टेंसर | (C1), (C2) |
कंस्ट्रेंट
- (C1)
shape(result) = shape(operand)
. - (C2)
element_type(result)
को इस तरह परिभाषित किया गया है:- अगर
is_complex(operand)
है, तोcomplex_element_type(element_type(operand))
. - अगर ऐसा नहीं है, तो
element_type(operand)
.
- अगर
उदाहरण
// %operand: [(1.0, 2.0), (3.0, 4.0)]
%result = "stablehlo.real"(%operand) : (tensor<2xcomplex<f32>>) -> tensor<2xf32>
// %result: [1.0, 3.0]
रेवेन्यू
सिमैंटिक
channel_id
वाले चैनल से डेटा हासिल करता है और results
जनरेट करता है.
अगर is_host_transfer
true
है, तो कार्रवाई
होस्ट. ऐसा न होने पर, यह दूसरे डिवाइस से डेटा ट्रांसफ़र करता है. इसका क्या मतलब है
लागू किया जाना चाहिए. यह फ़्लैग इसमें दी गई जानकारी का डुप्लीकेट बनाता है
channel_type
, इसलिए भविष्य में हम उनमें से केवल एक को रखने की योजना बना रहे हैं
(#666).
results
में पेलोड मान पहले आने वाले पेलोड मान और आने वाले टोकन होते हैं
अंतिम. आने वाले समय में, हमारी योजना पेलोड और टोकन को दो हिस्सों में बांटने की है
साफ़ तौर पर जानकारी देने के लिए, अलग-अलग आउटपुट
(#670).
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | token |
token |
(सी4) |
(I2) | channel_id |
si64 टाइप का कॉन्स्टेंट |
|
(I3) | channel_type |
DEVICE_TO_DEVICE और HOST_TO_DEVICE का enum |
(सी1) |
(आई4) | is_host_transfer |
i1 टाइप का कॉन्स्टेंट |
(सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
results |
टेंसर की वैरायडिक संख्या, क्वांटाइज़ किए गए टेंसर या टोकन | (सी2-सी4) |
कंस्ट्रेंट
- (C1)
channel_type
को इस तरह परिभाषित किया गया है:- अगर
is_host_transfer = true
है, तोHOST_TO_DEVICE
, - अगर ऐसा नहीं है, तो
DEVICE_TO_DEVICE
.
- अगर
- (C2)
0 < size(results)
. - (C3)
is_empty(result[:-1])
याis_tensor(type(results[:-1]))
. - (C4)
is_token(type(results[-1]))
.
उदाहरण
%results0, %results1 = "stablehlo.recv"(%token) {
channel_handle = #stablehlo.channel_handle<handle = 1, type = 3>,
is_host_transfer = true
} : (!stablehlo.token) -> (tensor<2x2xi64>, !stablehlo.token)
कम करें
सिमैंटिक
लघुकरण फ़ंक्शन body
को inputs
और init_values
पर लागू करता है
dimensions
और results
टेंसर बनाता है.
कमी का क्रम लागू करने का तरीका तय होता है. इसका मतलब है कि body
और
init_values
को एक मोनोइड बनाना चाहिए, ताकि यह पक्का किया जा सके कि ऑपरेशन से
सभी इनपुट के लिए एक जैसे नतीजे मिलेंगे. हालांकि, यह शर्त
कई लोकप्रिय गिरावटों के लिए उपलब्ध नहीं होता है. उदाहरण के लिए, फ़्लोटिंग-पॉइंट जोड़
init_values
के लिए body
और शून्य वास्तव में मोनोइड नहीं बनाते, क्योंकि
फ़्लोटिंग-पॉइंट को जोड़ना असोसिएशन से जुड़ा नहीं है.
ज़्यादा औपचारिक तौर पर, results...[j0, ..., jR-1] = reduce(input_slices_converted)
जहां:
input_slices = inputs...[j0, ..., :, ..., jR-1]
, जहां:
डाले गए हैंdimensions
पर है.input_slices_converted = to_destination_type(input_slices..., type(func_inputs(body)[:len(func_inputs(body))//2])...)
.init_values_converted = to_destination_type(init_values..., type(func_inputs(body)[len(func_inputs(body))//2:])...)
.- कुछ बाइनरी ट्री के लिए
reduce(input_slices_converted) = exec(schedule)
schedule
कहां:exec(node) = body(exec(node.left), exec(node.right))
.exec(leaf) = leaf.value
.
schedule
, लागू करने के हिसाब से तय किया गया पूरा बाइनरी ट्री है, जिसका ऑर्डर में होता है ट्रैवर्सल में शामिल हैं:input_slices_converted...[index]
मान, इसमें सभीindex
के लिएindex_space(input_slices_converted)
के बढ़ते क्रम में लेक्सिकोग्राफ़िक क्रम में कुलindex
.- यह एक लागू की जाने वाली रकम के साथ इंटरफ़ेस में है
init_values_converted
, लागू करने के तय की गई जगहों पर.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | inputs |
टेंसर की वैरायडिक संख्या या हर टेंसर की क्वांटाइज़्ड टेंसर की संख्या | (C1-C4), (C6), (C7) |
(I2) | init_values |
0-डाइमेंशन वाले टेंसर या हर टेंसर की क्वांटाइज़्ड टेंसर की वैरायडिक संख्या | (C2), (C3) |
(I3) | dimensions |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C4), (C5), (C7) |
(आई4) | body |
फ़ंक्शन | (सी6) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
results |
टेंसर की वैरायडिक संख्या या हर टेंसर की क्वांटाइज़्ड टेंसर की संख्या | (C3), (C7), (C8) |
कंस्ट्रेंट
- (C1)
same(shape(inputs...))
. - (C2)
element_type(inputs...) = element_type(init_values...)
. - (C3)
0 < size(inputs) = size(init_values) = size(results) = N
. - (C4)
0 <= dimensions < rank(inputs[0])
. - (C5)
is_unique(dimensions)
. - (C6)
body
का टाइप(tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ...,
हैtensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>)
कहांis_promotable(element_type(inputs[i]), Ei)
. - (C7)
shape(results...) = shape(inputs...)
सिर्फ़ डाइमेंशनdimensions
से जुड़ेinputs...
के साइज़ शामिल नहीं किए गए हैं. [0,N)
में सभीi
के लिए (C8)element_type(results[i]) = Ei
.
उदाहरण
// %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
सिमैंटिक
operand
के एलिमेंट के हिसाब से कन्वर्ज़न को किसी अन्य फ़्लोटिंग-पॉइंट टाइप में करता है
जो exponent_bits
और mantissa_bits
का इस्तेमाल करता है और मूल फ़ोटो पर वापस जाता है
फ़्लोटिंग-पॉइंट टाइप और output
टेंसर बनाता है.
ज़्यादा औपचारिक तौर पर:
- ओरिजनल वैल्यू के मैंटिसा बिट को अपडेट करके, ओरिजनल वैल्यू को राउंड ऑफ़ किया जाता है
मान को निकटतम मान का ऐसा मान दें जिसे
mantissa_bits
के साथ दिखाया जा सकता है.roundToIntegralTiesToEven
सिमेंटिक्स. - फिर, अगर
mantissa_bits
, इसके मैंटिसा बिट की संख्या से कम है ओरिजनल वैल्यू है, तो मैंटिसा बिट कोmantissa_bits
तक छोटा करके रखा जाता है. - फिर, अगर मध्यवर्ती परिणाम के एक्सपोनेंट बिट
exponent_bits
द्वारा दी गई श्रेणी, मध्यवर्ती परिणाम से ओवरफ़्लो होता है इसके लिए, मूल चिह्न का इस्तेमाल करके इनफ़िनिटी या अंडरफ़्लो का इस्तेमाल करके शून्य पर जाएं मूल चिह्न. - क्वांटाइज़्ड टाइप के लिए,
dequantize_op_quantize( lambda operand: reduce_precision(operand, exponent_bits, mantissa_bits), operand, type(result))
परफ़ॉर्म करता है.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
(I2) | exponent_bits |
si32 टाइप का कॉन्स्टेंट |
(सी2) |
(I3) | mantissa_bits |
si32 टाइप का कॉन्स्टेंट |
(सी3) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
output |
फ़्लोटिंग-पॉइंट टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(operand) = baseline_type(output)
. - (C2)
1 <= exponent_bits
. - (C3)
0 <= mantissa_bits
.
उदाहरण
// Logical values: +Inf, NaN, +Denormal, 0.0, 65519.0, 65520.0
// %operand: [0x7FF0000000000000, 0x7FFFFFFFFFFFFFFF, 0x0000000000000001, 0.0, 65519.0, 65520.0]
%output = "stablehlo.reduce_precision"(%operand) {
exponent_bits = 5 : i32,
mantissa_bits = 10 : i32
} : (tensor<6xf64>) -> tensor<6xf64>
// Logical values: +Inf, NaN, 0.0, 0.0, 65504.0, +Inf
// %output: [0x7FF0000000000000, 0x7FFFFFFFFFFFFFFF, 0.0, 0.0, 65504.0, 0x7FF0000000000000]
reduce_scatter
सिमैंटिक
StableHLO प्रोसेस ग्रिड में हर प्रोसेस ग्रुप के अंदर, रिडक्शन करता है,
हर प्रोसेस के operand
टेंसर की वैल्यू पर, computations
का इस्तेमाल करके
scatter_dimension
के साथ कमी के परिणाम को भागों में और स्कैटर में विभाजित करता है
result
बनाने के लिए अलग-अलग प्रोसेस के बीच के हिस्से.
ऑपरेशन, StableHLO प्रोसेस ग्रिड को process_groups
में बांट देता है जो कि
इस तरह परिभाषित किया गया है:
cross_replica(replica_groups)
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है अगरchannel_id <= 0 and use_global_device_ids = false
है.cross_replica_and_partition(replica_groups)
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है अगरchannel_id > 0 and use_global_device_ids = false
है.flattened_ids(replica_groups)
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है अगरchannel_id > 0 and use_global_device_ids = true
है.
इसके बाद, हर process_group
में:
reduced_value = all_reduce(operand, replica_groups, channel_id, use_global_device_ids, computation)
.parts@sender = split(reduced_value@sender, dim(process_groups, 1), scatter_dimension)
.result@receiver = parts@sender[receiver_index]
में सभीsender
process_group
पर जहांreceiver_index = process_group.index(receiver)
है.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C1), (C2), (C7), (C8) |
(I2) | scatter_dimension |
si64 टाइप का कॉन्स्टेंट |
(C1), (C2), (C8) |
(I3) | replica_groups |
si64 टाइप का 2-डाइमेंशन टेंसर कॉन्सटेंट |
(सी3-सी5) |
(आई4) | channel_id |
si64 टाइप का कॉन्स्टेंट |
(सी6) |
(I5) | use_global_device_ids |
i1 टाइप का कॉन्स्टेंट |
(सी6) |
(I6) | computation |
फ़ंक्शन | (सी7) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी8-सी9) |
कंस्ट्रेंट
- (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)
को इस तरह परिभाषित किया गया है:- अगर
cross_replica
का इस्तेमाल किया जाता है, तोnum_replicas
. - अगर
cross_replica_and_partition
का इस्तेमाल किया जाता है, तोnum_replicas
. - अगर
flattened_ids
का इस्तेमाल किया जाता है, तोnum_processes
.
- अगर
- (C5)
0 <= replica_groups < size(replica_groups)
. - (C6) अगर
use_global_device_ids = true
है, तोchannel_id > 0
. - (C7)
computation
का टाइप(tensor<E>, tensor<E>) -> (tensor<E>)
है, जहांis_promotable(element_type(operand), E)
. - (C8)
shape(result) = shape(operand)
को छोड़कर:dim(result, scatter_dimension) = dim(operand, scatter_dimension) / dim(process_groups, 1)
.
- (C9)
element_type(result) = E
.
उदाहरण
// num_replicas: 2
// num_partitions: 1
// %operand@(0, 0): [[1, 2, 3, 4],
// [5, 6, 7, 8]]
// %operand@(1, 0): [[9, 10, 11, 12],
// [13, 14, 15, 16]]
%result = "stablehlo.reduce_scatter"(%operand) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
"stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
scatter_dimension = 1 : i64,
replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>,
channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
} : (tensor<2x4xi64>) -> tensor<2x2xi64>
//
// %result@(0, 0): [[10, 12],
// [18, 20]]
// %result@(1, 0): [[14, 16],
// [22, 24]]
reduce_window
सिमैंटिक
inputs
और init_values
की विंडो पर रिडक्शन फ़ंक्शन body
लागू करता है
और results
प्रोडक्शन करता है.
यहां दिए गए डायग्राम में दिखाया गया है कि results...
में एलिमेंट का हिसाब कैसे लगाया जाता है
inputs...
पर जाकर, एक अच्छे उदाहरण का इस्तेमाल करें.
औपचारिक तौर पर,
results...[result_index] = reduce(windows, init_values, axes(inputs...), body)
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है
(कम करें देखें) कहां:
padded_inputs = pad(inputs..., init_values..., padding[:, 0], padding[:, 1], base_dilations - 1)
.window_start = result_index * window_strides
.window_end = window_start + (window_dimensions - 1) * window_dilations + 1
.windows = slice(padded_inputs..., window_start, window_end, window_dilations)
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | inputs |
टेंसर की वैरायडिक संख्या या हर टेंसर की क्वांटाइज़्ड टेंसर की संख्या | (C1-C4), (C6), (C8), (C10), (C12), (C13), (C15) |
(I2) | init_values |
0-डाइमेंशन वाले टेंसर या हर टेंसर की क्वांटाइज़्ड टेंसर की वैरायडिक संख्या | (C1), (C13) |
(I3) | window_dimensions |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C4), (C5), (C15) |
(आई4) | window_strides |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C6), (C7), (C15) |
(I5) | base_dilations |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C8), (C9), (C15) |
(I6) | window_dilations |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C10), (C11), (C15) |
(I7) | padding |
si64 टाइप का 2-डाइमेंशन टेंसर कॉन्सटेंट |
(C12), (C15) |
(I8) | body |
फ़ंक्शन | (सी13) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
results |
टेंसर की वैरायडिक संख्या या हर टेंसर की क्वांटाइज़्ड टेंसर की संख्या | (C1), (C14-C16) |
कंस्ट्रेंट
- (C1)
0 < size(inputs) = size(init_values) = size(results) = N
. - (C2)
same(shape(inputs...))
. - (C3)
element_type(inputs...) = element_type(init_values...)
. - (C4)
size(window_dimensions) = rank(inputs[0])
. - (C5)
0 < window_dimensions
. - (C6)
size(window_strides) = rank(inputs[0])
. - (C7)
0 < window_strides
. - (C8)
size(base_dilations) = rank(inputs[0])
. - (C9)
0 < base_dilations
. - (C10)
size(window_dilations) = rank(inputs[0])
. - (C11)
0 < window_dilations
. - (C12)
shape(padding) = [rank(inputs[0]), 2]
. - (C13)
body
का टाइप(tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ...,
हैtensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>)
कहांis_promotable(element_type(inputs[i]), Ei)
. - (C14)
same(shape(results...))
. - (C15)
shape(results[0]) = num_windows
जहां:dilated_input_shape = shape(inputs[0]) = 0 ? 0 : (shape(inputs[0]) - 1) * base_dilations + 1
.padded_input_shape = padding[:, 0] + dilated_input_shape + padding[:, 1]
.dilated_window_shape = (window_dimensions - 1) * window_dilations + 1
.is_empty_window = padded_input_shape = 0 || dilated_window_shape > padded_input_shape
.num_windows = is_empty_window ? 0 : floor((padded_input_shape - dilated_window_shape) / window_strides) + 1
.
- (C16)
[0,N)
में सभीi
के लिएelement_type(results[i]) = Ei
.
उदाहरण
// %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]]
शेष
सिमैंटिक
भाज्य lhs
और भाजक rhs
के टेन्सर और भाजक के एलिमेंट के अनुसार शेषफल के आधार पर फ़ंक्शन करता है
result
टेंसर बनाता है.
औपचारिक रूप से, परिणाम का चिह्न भाज्यों से लिया जाता है और
नतीजे का निरपेक्ष मान हमेशा भाजक के निरपेक्ष मान से कम होता है.
बाकी बचे पैसों की गिनती lhs - d * rhs
के रूप में की जाती है, जहां d
इससे दी जाती है:
- पूर्णांकों के लिए:
stablehlo.divide(lhs, rhs)
. - फ़्लोट के लिए: राउंडिंग एट्रिब्यूट के साथ IEEE-754 से
division(lhs, rhs)
roundTowardZero
. - सम्मिश्र संख्याओं के लिए: TBD (#997).
- क्वांटाइज़्ड टाइप के लिए:
dequantize_op_quantize(remainder, lhs, rhs, type(result))
.
फ़्लोटिंग-पॉइंट एलिमेंट टाइप के लिए, यह ऑपरेशन,
IEEE-754 स्पेसिफ़िकेशन से remainder
ऑपरेशन, जिसमें d
एक इंटिग्रल वैल्यू है
सम संख्या के साथ lhs/rhs
की सटीक वैल्यू के सबसे करीब.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | lhs |
इंटीजर, फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
(I2) | rhs |
इंटीजर, फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
इंटीजर, फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// %lhs: [17, -17, 17, -17]
// %rhs: [3, 3, -3, -3]
%result = "stablehlo.remainder"(%lhs, %rhs) : (tensor<4xi64>, tensor<4xi64>) -> tensor<4xi64>
// %result: [2, -2, 2, -2]
replica_id
सिमैंटिक
इससे मौजूदा प्रोसेस का replica_id
बनता है.
आउटपुट
नाम | टाइप |
---|---|
result |
ui32 टाइप का 0-डाइमेंशन वाला टेंसर |
उदाहरण
%result = "stablehlo.replica_id"() : () -> tensor<ui32>
आकार बदलना
सिमैंटिक
operand
टेंसर को result
टेंसर के आकार देता है. सैद्धांतिक तौर पर, यह
कैननिकल निरूपण को एक जैसा बनाए रखता है, लेकिन हो सकता है कि इसमें बदलाव हो सकता है
आकार, जैसे tensor<2x3xf32>
से tensor<3x2xf32>
या tensor<6xf32>
तक.
ज़्यादा औपचारिक तौर पर, result[result_index] = operand[operand_index]
जहां
लेक्सिकोग्राफ़िक में result_index
और operand_index
की रैंक एक जैसी है
index_space(result)
और index_space(operand)
का ऑर्डर.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
टेंसर या क्वांटाइज़्ड टेंसर | (सी1-सी3) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या क्वांटाइज़्ड टेंसर | (सी1-सी3) |
कंस्ट्रेंट
- (C1)
element_type(result)
देने वाली कंपनी:- अगर
!is_per_axis_quantized(operand)
है, तोelement_type(operand)
. element_type(operand)
, लेकिनquantization_dimension(operand)
और ऐसा न होने परquantization_dimension(result)
अलग हो सकती है.
- अगर
- (C2)
size(operand) = size(result)
. - (C3) अगर
is_per_axis_quantized(operand)
:reduce(dims(operand, [0, 1, ..., quantization_dimension(operand) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y) = reduce(dims(result, [0, 1, ..., quantization_dimension(result) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y)
.dim(operand, quantization_dimension(operand)) = dim(result, quantization_dimension(result))
.reduce(dims(operand, [quantization_dimension(operand) + 1, ..., rank(operand) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y) = reduce(dims(result, [quantization_dimension(result) + 1, ..., rank(result) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y)
.
उदाहरण
// %operand: [[1, 2, 3], [4, 5, 6]]
%result = "stablehlo.reshape"(%operand) : (tensor<2x3xi32>) -> tensor<3x2xi32>
// %result: [[1, 2], [3, 4], [5, 6]]
विपरीत करें
सिमैंटिक
यह तय किए गए dimensions
के साथ-साथ, operand
में एलिमेंट के क्रम को उलटता है
और result
टेंसर बनाता है. औपचारिक तौर पर,
result[result_index] = operand[operand_index]
कहां:
operand_index[d] = dim(result, d) - result_index[d] - 1
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है अगरdimensions
मेंd
है.- अगर ऐसा नहीं है, तो
operand_index[d] = result_index[d]
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C1), (C3) |
(I2) | dimensions |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C2), (C3) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C1), (C3) |
कंस्ट्रेंट
- (C1)
type(operand) = type(result)
. - (C2)
is_unique(dimensions)
. - (C3)
0 <= dimensions < rank(result)
.
उदाहरण
// %operand = [[1, 2], [3, 4], [5, 6]]
%result = "stablehlo.reverse"(%operand) {
dimensions = array<i64: 1>
} : (tensor<3x2xi32>) -> tensor<3x2xi32>
// %result: [[2, 1], [4, 3], [6, 5]]
आरएनजी
सिमैंटिक
rng_distribution
एल्गोरिदम का इस्तेमाल करके, रैंडम नंबर जनरेट करता है और
दिए गए आकार shape
का result
टेंसर.
अगर rng_distribution = UNIFORM
है, तो कोई भी नंबर जनरेट होता है
[a, b)
इंटरवल में यूनिफ़ॉर्म डिस्ट्रिब्यूशन के बाद. अगर a >= b
,
व्यवहार के बारे में नहीं बताया गया है.
अगर rng_distribution = NORMAL
है, तो कोई भी नंबर जनरेट होता है
माध्य = a
और मानक विचलन = b
के साथ सामान्य वितरण के बाद.
अगर b < 0
, व्यवहार तय नहीं है.
रैंडम नंबर जनरेट करने का सही तरीका, इसे लागू करने के तरीके से तय होता है. इसके लिए उदाहरण के लिए, वे शायद सारणिक हों और नहीं भी, और छिपी हुई स्थिति के लिए.
कई हिस्सेदारों के साथ बातचीत करते समय, यह सेशन असरदार तरीके से की सुविधा उपलब्ध नहीं है. इसलिए, हम आने वाले समय में इसे हटाने की योजना बना रहे हैं (#597).
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | a |
पूर्णांक, बूलियन या फ़्लोटिंग-पॉइंट टाइप का 0-डाइमेंशन वाला टेंसर | (C1), (C2) |
(I2) | b |
पूर्णांक, बूलियन या फ़्लोटिंग-पॉइंट टाइप का 0-डाइमेंशन वाला टेंसर | (C1), (C2) |
(I3) | shape |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(सी3) |
(आई4) | rng_distribution |
UNIFORM और NORMAL का enum |
(सी2) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
पूर्णांक, बूलियन या फ़्लोटिंग-पॉइंट टाइप का टेंसर | (सी1-सी3) |
कंस्ट्रेंट
- (C1)
element_type(a) = element_type(b) = element_type(result)
. - (C2) अगर
rng_distribution = NORMAL
है, तोis_float(a)
. - (C3)
shape(result) = shape
.
उदाहरण
// %a = 0
// %b = 2
// %shape = [3, 3]
%result = "stablehlo.rng"(%a, %b, %shape) {
rng_distribution = #stablehlo<rng_distribution UNIFORM>
} : (tensor<i32>, tensor<i32>, tensor<2xi64>) -> tensor<3x3xi32>
// %result: [
// [1, 0, 1],
// [1, 1, 1],
// [0, 0, 0]
// ]
rng_bit_generator
सिमैंटिक
यह फ़ंक्शन एक जैसे रैंडम बिट से भरा गया output
दिखाता है और आउटपुट की अपडेट की गई स्थिति दिखाता है
स्यूडोरैंडम नंबर जनरेटर एल्गोरिदम rng_algorithm
का इस्तेमाल करके output_state
initial_state
को शुरुआती स्थिति दी गई है. आउटपुट की गारंटी दी जाती है
initial_state
का डिटरमिनिस्टिक फ़ंक्शन, लेकिन इसके होने की गारंटी नहीं है
दो अलग-अलग तरीकों से तय किया जा सकता है.
rng_algorithm
इनमें से एक है:
DEFAULT
: लागू करने के लिए तय किया गया एल्गोरिदम.THREE_FRY
: Fivefry एल्गोरिदम का लागू करने के बारे में तय किया गया वैरिएंट.*PHILOX
: Pilox एल्गोरिदम को लागू करने के लिए तय किया गया वैरिएंट.*
* देखें: सैलमन और अन्य एससी 2011. समानांतर यादृच्छिक संख्याएं: 1, 2, 3 जितनी आसान होती हैं.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | rng_algorithm |
DEFAULT , THREE_FRY , और PHILOX का कुल डेटा |
(सी2) |
(I2) | initial_state |
ui64 टाइप का 1-डाइमेंशन टेंसर |
(C1), (C2) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
output_state |
ui64 टाइप का 1-डाइमेंशन टेंसर |
(सी1) |
output |
इंटीजर या फ़्लोटिंग-पॉइंट टाइप का टेंसर |
कंस्ट्रेंट
- (C1)
type(initial_state) = type(output_state)
. - (C2)
size(initial_state)
को इस तरह परिभाषित किया गया है:- अगर
rng_algorithm = DEFAULT
है, तो लागू करने के बारे में तय किया जाता है. - अगर
rng_algorithm = THREE_FRY
है, तो2
. - अगर
rng_algorithm = PHILOX
है, तो2
या3
.
- अगर
उदाहरण
// %initial_state: [1, 2]
%output_state, %output = "stablehlo.rng_bit_generator"(%initial_state) {
rng_algorithm = #stablehlo<rng_algorithm THREE_FRY>
} : (tensor<2xui64>) -> (tensor<2xui64>, tensor<2x2xui64>)
// %output_state: [1, 6]
// %output: [
// [9236835810183407956, 16087790271692313299],
// [18212823393184779219, 2658481902456610144]
// ]
round_nearest_afz
सिमैंटिक
निकटतम पूर्णांक की ओर तत्व के अनुसार पूर्णांकन करता है, जिससे संबंध टूट जाते हैं
शून्य से, operand
टेंसर पर, result
टेंसर बनाता है. लागू करता है
आईईईई-754 स्पेसिफ़िकेशन से मिली roundToIntegralTiesToAway
कार्रवाई. इसके लिए
क्वांटाइज़्ड टाइप, परफ़ॉर्मेंस
dequantize_op_quantize(round_nearest_afz, operand, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// %operand = [-2.5, 0.4, 0.5, 0.6, 2.5]
%result = "stablehlo.round_nearest_afz"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// %result: [-3.0, 0.0, 1.0, 1.0, 3.0]
round_nearest_even
सिमैंटिक
निकटतम पूर्णांक की ओर तत्व के अनुसार पूर्णांकन करता है, जिससे संबंध टूट जाते हैं
operand
टेंसर पर, सम पूर्णांक की दिशा में result
बनाता है
टेंसर. आईईईई-754 से roundToIntegralTiesToEven
ऑपरेशन लागू करता है
स्पेसिफ़िकेशन. क्वांटाइज़्ड टाइप के लिए,
dequantize_op_quantize(round_nearest_even, operand, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// %operand = [-2.5, 0.4, 0.5, 0.6, 2.5]
%result = "stablehlo.round_nearest_even"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// %result: [-2.0, 0.0, 0.0, 1.0, 2.0]
rsqrt
सिमैंटिक
operand
टेंसर पर एलिमेंट के हिसाब से व्युत्क्रम (रिसिप्रोकल स्क्वेयर रूट) कार्रवाई करता है और
result
टेंसर बनाता है. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- फ़्लोट के लिए: IEEE-754 से
rSqrt
. - सम्मिश्र संख्याओं के लिए: सम्मिश्र व्युत्क्रम वर्ग मूल.
- क्वांटाइज़्ड टाइप के लिए:
dequantize_op_quantize(rsqrt, operand, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// %operand: [[1.0, 4.0], [9.0, 25.0]]
%result = "stablehlo.rsqrt"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[1.0, 0.5], [0.33333343, 0.2]]
स्कैटर
सिमैंटिक
results
टेंसर बनाता है, जो कि इसे छोड़कर inputs
टेंसर के बराबर होते हैं
scatter_indices
के तय किए गए कई स्लाइस, उनकी वैल्यू के साथ अपडेट किए गए हैं
update_computation
का इस्तेमाल करके updates
.
नीचे दिया गया डायग्राम दिखाता है कि updates...
में एलिमेंट,
results...
पर जाकर, एक अच्छे उदाहरण का इस्तेमाल करें. इस डायग्राम में कुछ उदाहरण दिए गए हैं
updates...
इंडेक्स और विस्तार से बताता है कि वे कौनसे results...
इंडेक्स करते हैं
के मुताबिक हैं.
index_space(updates[0])
में सभी update_index
के लिए, औपचारिक तौर पर:
update_scatter_dims = [d for d in axes(updates[0]) and d not in update_window_dims]
.update_scatter_index = update_index[update_scatter_dims...]
.start_index
को इस तरह से परिभाषित किया गया है:scatter_indices[si0, ..., :, ..., siN]
, जहांsi
व्यक्तिगत हैंupdate_scatter_index
और:
के तत्वों कोindex_vector_dim
इंडेक्स, अगरindex_vector_dim
<rank(scatter_indices)
.- अगर ऐसा नहीं है, तो
[scatter_indices[update_scatter_index]]
.
axes(inputs[0])
मेंd_input
के लिए,full_start_index[d_input] = start_index[d_start]
अगरd_input = scatter_dims_to_operand_dims[d_start]
.- अगर ऐसा नहीं है, तो
full_start_index[d_input] = 0
.
axes(inputs[0])
मेंd_input
के लिए,full_batching_index[d_input] = update_scatter_index[d_start - (d_start < index_vector_dim ? 0 : 1)]
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है अगरd_input = input_batching_dims[i_batching]
औरd_start = scatter_indices_batching_dims[i_batching]
.- अगर ऐसा नहीं है, तो
full_batching_index[d_input] = 0
.
update_window_index = update_index[update_window_dims...]
.full_window_index = [wi0, ..., 0, ..., wiN]
, जहांwi
व्यक्तिगत हैंupdate_window_index
के एलिमेंट का इस्तेमाल किया जाता है और0
को इंडेक्स में शामिल किया जाता हैinserted_window_dims
औरinput_batching_dims
.result_index = full_start_index + full_batching_index + full_window_index
.
यह देखते हुए, results = exec(schedule, inputs)
, जहां:
schedule
, इसका लागू करने के हिसाब से क्रमचय हैindex_space(updates[0])
.exec([update_index, ...], results) = exec([...], updated_results)
कहां:- अगर
result_index
,shape(results...)
के लिए सीमा के अंदर है updates_converted = to_destination_type( updates...[update_index], type(func_inputs(update_computation) [len(func_inputs(update_computation))//2:])... )
updated_values = update_computation(results...[result_index], updates_converted)
updated_results
,results...[result_index]
वालेresults
की कॉपी हैupdated_values...
पर सेट किया गया.- या फिर
updated_results = results
.
- अगर
exec([], results) = results
.
अगर indices_are_sorted
, true
है, तो लागू करने पर यह मान लिया जा सकता है कि
scatter_indices
, scatter_dims_to_operand_dims
के हिसाब से क्रम से लगाए गए हैं,
ऐसा नहीं होता है, तो व्यवहार तय नहीं होता है. ज़्यादा औपचारिक तौर पर, इस तारीख से सभी i1 < i2
indices(result)
, full_start_index(i1)
<= full_start_index(i2)
.
अगर unique_indices
, true
है, तो लागू करने पर यह मान लिया जा सकता है कि सभी
result_index
इंडेक्स का डेटा यूनीक है. अगर unique_indices
है
true
लेकिन बिखरने वाले इंडेक्स अलग-अलग नहीं हैं, तो व्यवहार ऐसा है
तय नहीं है.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | inputs |
टेंसर की वैरायडिक संख्या या हर टेंसर की क्वांटाइज़्ड टेंसर की संख्या | (C1), (C2), (C4-C6), (C11), (C13), (C18), (C21), (C23-C24) |
(I2) | scatter_indices |
पूर्णांक टाइप का टेंसर | (C4), (C15), (C19), (C22) |
(I3) | updates |
टेंसर की वैरायडिक संख्या या हर टेंसर की क्वांटाइज़्ड टेंसर की संख्या | (C3-C6), (C8) |
(आई4) | update_window_dims |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C2), (C4), (C7-C8) |
(I5) | inserted_window_dims |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C2), (C4), (C9-C11) |
(I6) | input_batching_dims |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C2), (C4), (C9), (C12-13), (C17-18), (C20) |
(I7) | scatter_indices_batching_dims |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C14-C18) |
(I8) | scatter_dims_to_operand_dims |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C19-C21) |
(I9) | index_vector_dim |
si64 टाइप का कॉन्स्टेंट |
(C4), (C16), (C19), (C22) |
(I10) | indices_are_sorted |
i1 टाइप का कॉन्स्टेंट |
|
(I11) | unique_indices |
i1 टाइप का कॉन्स्टेंट |
|
(I12) | update_computation |
फ़ंक्शन | (सी23) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
results |
टेंसर की वैरायडिक संख्या या हर टेंसर की क्वांटाइज़्ड टेंसर की संख्या | (C24-C25) |
कंस्ट्रेंट
- (C1)
same(shape(inputs...))
. - (C2) `रैंक(इनपुट[0]) = साइज़(update_window_dims) + साइज़(inserted_window_dims)
- size(input_batching_dims)`.
- (C3)
same(shape(updates...))
. - (C4)
shape(updates[0]) = combine(update_scatter_dim_sizes, update_window_dim_sizes)
जहां:- उसे छोड़कर
update_scatter_dim_sizes = shape(scatter_indices)
इसके मुताबिकscatter_indices
का डाइमेंशन साइज़index_vector_dim
शामिल नहीं है. - उसे छोड़कर
update_window_dim_sizes <= shape(inputs[0])
inserted_window_dims
के अनुरूपinputs[0]
में डाइमेंशन आकार औरinput_batching_dims
शामिल नहीं हैं. combine
,update_scatter_dim_sizes
को इससे जुड़े ऐक्सिस पर लगाता हैupdate_scatter_dims
औरupdate_window_dim_sizes
से जुड़े ऐक्सिसupdate_window_dims
तक.
- उसे छोड़कर
- (C5)
0 < size(inputs) = size(updates) = N
. - (C6)
element_type(updates...) = element_type(inputs...)
. - (C7)
is_unique(update_window_dims) and is_sorted(update_window_dims)
. - (C8)
0 <= update_window_dims < rank(updates[0])
. - (C9)
is_unique(concatenate(inserted_window_dims, input_batching_dims))
- (C10)
is_sorted(inserted_window_dims)
. - (C11)
0 <= inserted_window_dims < rank(inputs[0])
. - (C12)
is_sorted(input_batching_dims)
. - (C13)
0 <= input_batching_dims < rank(inputs[0]))
. - (C14)
is_unique(scatter_indices_batching_dims)
. - (C15)
0 <= scatter_indices_batching_dims < rank(scatter_indices)
. - (C16)
index_vector_dim not in scatter_indices_batching_dims
. - (C17)
size(input_batching_dims) == size(scatter_indices_batching_dims)
. - (C18)
dim(inputs[0], input_batching_dims...) = dim(scatter_indices, scatter_indices_batching_dims...)
. - (C19)
size(scatter_dims_to_operand_dims) = index_vector_dim < rank(scatter_indices) ? dim(scatter_indices, index_vector_dim) : 1
. - (C20)
is_unique(concatenate(scatter_dims_to_operand_dims, input_batching_dims))
. - (C21)
0 <= scatter_dims_to_operand_dims < rank(inputs[0])
. - (C22)
0 <= index_vector_dim <= rank(scatter_indices)
. - (C23)
update_computation
का टाइप(tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ..., tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>)
है, जहांis_promotable(element_type(inputs[i]), Ei)
है. - (C24)
shape(inputs...) = shape(results...)
. [0,N)
में सभीi
के लिए (C25)element_type(results[i]) = Ei
.
उदाहरण
// %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]]
// ]
// ]
चुनें
सिमैंटिक
जहां से हर एलिमेंट on_true
से चुना जाता है वहां से result
टेंसर बनता है या
pred
के संबंधित एलिमेंट की वैल्यू पर आधारित on_false
टेंसर.
ज़्यादा औपचारिक तौर पर, result[result_index] = pred_element ? on_true[result_index] :
on_false[result_index]
, जहां pred_element = rank(pred) = 0 ? pred[] :
pred[result_index]
. क्वांटाइज़्ड टाइप के लिए,
dequantize_select_quantize(pred, on_true, on_false, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | pred |
i1 टाइप का टेंसर |
(सी1) |
(I2) | on_true |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी1-सी2) |
(I3) | on_false |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी2) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (सी2) |
कंस्ट्रेंट
- (C1)
rank(pred) = 0 or shape(pred) = shape(on_true)
. - (C2)
baseline_type(on_true) = baseline_type(on_false) = baseline_type(result)
.
उदाहरण
// %pred: [[false, true], [true, false]]
// %on_true: [[1, 2], [3, 4]]
// %on_false: [[5, 6], [7, 8]]
%result = "stablehlo.select"(%pred, %on_true, %on_false) : (tensor<2x2xi1>, tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[5, 2], [3, 8]]
select_and_scatter
सिमैंटिक
scatter
का इस्तेमाल करके, source
टेंसर से वैल्यू दिखाता है. ये वैल्यू
select
का इस्तेमाल करके input
टेंसर के reduce_window
का नतीजा और इससे मिले नतीजे
result
टेंसर.
यहां दिए गए डायग्राम में दिखाया गया है कि result
में एलिमेंट का हिसाब कैसे लगाया जाता है
operand
और source
को बेहतर तरीके से समझने के लिए, एक अच्छा उदाहरण दिया गया है.
ज़्यादा औपचारिक तौर पर:
selected_values = reduce_window_without_init(...)
में ये इनपुट शामिल हैं:inputs = [operand].
window_dimensions
,window_strides
, औरpadding
का इस्तेमाल पहले किया जा रहा है.base_dilations = windows_dilations = 1
.body
को इस तरह से परिभाषित किया गया है:
def body(arg0: tensor<E>, arg1: tensor<E>) -> tensor<E>: return select(arg0, arg1) ? arg0 : arg1;
जहां
E = element_type(operand)
औरreduce_window_without_init
काम करते हैं बिलकुलreduce_window
की तरह, इसमें मौजूदा चीज़ों काschedule
शामिल नहीं हैreduce
(कम करें देखें) में, init वैल्यू शामिल नहीं हैं. फ़िलहाल, ऐसा है यह नहीं बताया गया कि क्या होगा अगर इससे जुड़ी विंडो में वैल्यू नहीं हैं (#731).result[result_index] = reduce([source_values], [init_value], [0], scatter)
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है कहां:source_values = [source[source_index] for source_index in source_indices]
.selected_index(source_index) = operand_index
अगरselected_values[source_index]
मेंoperand
एलिमेंट हैoperand_index
से.source_indices = [source_index for source_index in indices(source) if selected_index(source_index) = result_index]
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C1-C4), (C6), (C8-C11) |
(I2) | source |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C1), (C2) |
(I3) | init_value |
0-डाइमेंशन वाला टेंसर या हर टेंसर क्वांटाइज़्ड टेंसर | (सी3) |
(आई4) | window_dimensions |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C2), (C4), (C5) |
(I5) | window_strides |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C2), (C6), (C7) |
(I6) | padding |
si64 टाइप का 2-डाइमेंशन टेंसर कॉन्सटेंट |
(C2), (C8) |
(I7) | select |
फ़ंक्शन | (सी9) |
(I8) | scatter |
फ़ंक्शन | (C10) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C11-C12) |
कंस्ट्रेंट
- (C1)
element_type(operand) = element_type(source)
. - (C2)
shape(source) = num_windows
जहां:padded_operand_shape = padding[:, 0] + shape(operand) + padding[:, 1]
.is_empty_window = padded_operand_shape = 0 || window_dimensions > padded_operand_shape
.num_windows = is_empty_window ? 0 : floor((padded_operand_shape - window_dimensions) / window_strides) + 1
.
- (C3)
element_type(init_value) = element_type(operand)
. - (C4)
size(window_dimensions) = rank(operand)
. - (C5)
0 < window_dimensions
. - (C6)
size(window_strides) = rank(operand)
. - (C7)
0 < window_strides
. - (C8)
shape(padding) = [rank(operand), 2]
. - (C9)
select
का टाइप(tensor<E>, tensor<E>) -> tensor<i1>
है, जहांE = element_type(operand)
. - (C10)
scatter
का टाइप(tensor<E>, tensor<E>) -> tensor<E>
है, जहांis_promotable(element_type(operand), E)
. - (C11)
shape(operand) = shape(result)
. - (C12)
element_type(result) = E
.
उदाहरण
// %operand: [[1, 5], [2, 5], [3, 6], [4, 4]]
// %source: [[5, 6], [7, 8]]
// %init_value: 0
%result = "stablehlo.select_and_scatter"(%operand, %source, %init_value) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = "stablehlo.compare"(%arg0, %arg1) {
comparison_direction = #stablehlo<comparison_direction GE>
} : (tensor<i64>, tensor<i64>) -> tensor<i1>
"stablehlo.return"(%0) : (tensor<i1>) -> ()
}, {
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
"stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
window_dimensions = 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]]
भेजें
सिमैंटिक
यह inputs
को channel_id
चैनल पर भेजता है और result
टोकन जनरेट करता है.
अगर is_host_transfer
true
है, तो ऑपरेशन डेटा को
होस्ट. ऐसा न होने पर, यह डेटा को दूसरे डिवाइस पर ट्रांसफ़र कर देता है. इसका क्या मतलब है
लागू किया जाना चाहिए. यह फ़्लैग इसमें दी गई जानकारी का डुप्लीकेट बनाता है
channel_type
, इसलिए भविष्य में हम उनमें से केवल एक को रखने की योजना बना रहे हैं
(#666).
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | inputs |
टेंसर या क्वांटाइज़्ड टेंसर की वैरायड संख्या | |
(I2) | token |
token |
|
(I3) | channel_id |
si64 टाइप का कॉन्स्टेंट |
|
(आई4) | channel_type |
DEVICE_TO_DEVICE और DEVICE_TO_HOST का enum |
(सी1) |
(I5) | is_host_transfer |
i1 टाइप का कॉन्स्टेंट |
(सी1) |
आउटपुट
नाम | टाइप |
---|---|
result |
token |
कंस्ट्रेंट
- (C1)
channel_type
को इस तरह परिभाषित किया गया है:- अगर
is_host_transfer = true
है, तोDEVICE_TO_HOST
, - अगर ऐसा नहीं है, तो
DEVICE_TO_DEVICE
.
- अगर
उदाहरण
%result = "stablehlo.send"(%operand, %token) {
channel_handle = #stablehlo.channel_handle<handle = 1, type = 2>,
is_host_transfer = true
} : (tensor<2x2xi64>, !stablehlo.token) -> !stablehlo.token
shift_left
सिमैंटिक
lhs
टेंसर पर rhs
संख्या से एलिमेंट के हिसाब से लेफ़्ट-शिफ़्ट ऑपरेशन करता है
बिट का इस्तेमाल करता है और result
टेंसर बनाता है.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | lhs |
पूर्णांक टाइप का टेंसर | (सी1) |
(I2) | rhs |
पूर्णांक टाइप का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
पूर्णांक टाइप का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
type(lhs) = type(rhs) = type(result)
.
उदाहरण
// %lhs: [-1, 0, 1]
// %rhs: [1, 2, 3]
%result = "stablehlo.shift_left"(%lhs, %rhs): (tensor<3xi64>, tensor<3xi64>) -> tensor<3xi64>
// %result: [-2, 0, 8]
shift_right_arithmetic
सिमैंटिक
lhs
टेंसर पर एलिमेंट के हिसाब से अंकगणित के राइट शिफ़्ट ऑपरेशन को ऐसा करता है
rhs
बिट की संख्या और result
टेंसर बनाना.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | lhs |
पूर्णांक टाइप का टेंसर | (सी1) |
(I2) | rhs |
पूर्णांक टाइप का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
पूर्णांक टाइप का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
type(lhs) = type(rhs) = type(result)
.
उदाहरण
// %lhs: [-1, 0, 8]
// %rhs: [1, 2, 3]
%result = "stablehlo.shift_right_arithmetic"(%lhs, %rhs): (tensor<3xi64>, tensor<3xi64>) -> tensor<3xi64>
// %result: [-1, 0, 1]
shift_right_logical
सिमैंटिक
lhs
टेंसर पर rhs
के हिसाब से एलिमेंट के हिसाब से लॉजिकल राइट शिफ़्ट ऑपरेशन करता है
बिट की संख्या और result
टेंसर बनाता है.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | lhs |
पूर्णांक टाइप का टेंसर | (सी1) |
(I2) | rhs |
पूर्णांक टाइप का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
पूर्णांक टाइप का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
type(lhs) = type(rhs) = type(result)
.
उदाहरण
// %lhs: [-1, 0, 8]
// %rhs: [1, 2, 3]
%result = "stablehlo.shift_right_logical"(%lhs, %rhs): (tensor<3xi64>, tensor<3xi64>) -> tensor<3xi64>
// %result: [9223372036854775807, 0, 1]
हस्ताक्षर
सिमैंटिक
एलिमेंट के हिसाब से operand
का निशान दिखाता है और result
टेंसर बनाता है.
औपचारिक तौर पर, हर एलिमेंट x
के लिए सिमेंटिक्स को इसका इस्तेमाल करके बताया जा सकता है
Python सिंटैक्स इस तरह से है:
def sign(x):
if is_integer(x):
if compare(x, 0, LT, SIGNED): return -1
if compare(x, 0, EQ, SIGNED): return 0
return 1
elif is_float(x):
if is_nan(x): return NaN
if compare(x, -0.0, EQ, FLOAT): return -0.0
if compare(x, +0.0, EQ, FLOAT): return +0.0
if compare(x, 0.0, LT, FLOAT): return -1.0
return 1.0
elif is_complex(x):
if is_nan(real(x)) or is_nan(imag(x)): return (NaN, NaN)
if compare(x, (0.0, 0.0), EQ, FLOAT): return (0.0, 0.0)
return divide(x, convert(abs(x), type(x)))
क्वांटाइज़्ड टाइप के लिए,
dequantize_op_quantize(sign, operand, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
साइन किए हुए पूर्णांक, फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
साइन किए हुए पूर्णांक, फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// Logical values: +NaN, -1.0, -0.0, +0.0, 1.0
// operand: [0x7FFFFFFFFFFFFFFF, -1.0, -0.0, 0.0, 1.0]
%result = "stablehlo.sign"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// Logical values: +NaN, -1.0, -0.0, +0.0, 1.0
// %result: [0x7FFFFFFFFFFFFFFF, -1.0, -0.0, 0.0, 1.0]
ज्या
सिमैंटिक
operand
टेंसर पर एलिमेंट के हिसाब से साइन (sin) करता है और result
बनाता है
टेंसर. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- फ़्लोट के लिए: IEEE-754 से
sin
. - सम्मिश्र संख्याओं के लिए: सम्मिश्र ज्या.
- क्वांटाइज़्ड टाइप के लिए:
dequantize_op_quantize(sine, operand, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// %operand: [
// [0.0, 1.57079632], // [0, pi/2]
// [3.14159265, 4.71238898] // [pi, 3pi/2]
// ]
%result = "stablehlo.sine"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[0.0, 1.0], [0.0, -1.0]]
स्लाइस
सिमैंटिक
स्टैटिक तरीके से कंप्यूट किए गए शुरुआती इंडेक्स का इस्तेमाल करके, operand
से स्लाइस एक्सट्रैक्ट करता है
और result
टेंसर बनाता है. start_indices
में इसके शुरुआती इंडेक्स शामिल हैं
स्लाइस, limit_indices
में आखिरी इंडेक्स शामिल हैं
(खास तौर पर) हर डाइमेंशन के स्लाइस के लिए, और strides
में स्ट्राइड होते हैं
पैरामीटर का इस्तेमाल करें.
ज़्यादा औपचारिक तौर पर, result[result_index] = operand[operand_index]
जहां
operand_index = start_indices + result_index * strides
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C1-C3), (C5) |
(I2) | start_indices |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C2), (C3), (C5) |
(I3) | limit_indices |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C2), (C3), (C5) |
(आई4) | strides |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(C2), (C4) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या हर टेन्सर क्वांटाइज़्ड टेंसर | (C1), (C5) |
कंस्ट्रेंट
- (C1)
element_type(operand) = element_type(result)
. - (C2)
size(start_indices) = size(limit_indices) = size(strides) = rank(operand)
. - (C3)
0 <= start_indices <= limit_indices <= shape(operand)
. - (C4)
0 < strides
. - (C5)
shape(result) = ceil((limit_indices - start_indices) / strides)
.
उदाहरण
// %operand: [
// [0, 0, 0, 0],
// [0, 0, 1, 1],
// [0, 0, 1, 1]
// ]
%result = "stablehlo.slice"(%operand) {
start_indices = array<i64: 1, 2>,
limit_indices = array<i64: 3, 4>,
strides = array<i64: 1, 1>
} : (tensor<3x4xi64>) -> tensor<2x2xi64>
// % result: [
// [1, 1],
// [1, 1]
// ]
क्रम से लगाएं
सिमैंटिक
inputs
के 1-डाइमेंशन वाले स्लाइस को, डाइमेंशन dimension
के साथ एक साथ क्रम में लगाता है,
comparator
के हिसाब से और results
का प्रोडक्शन होता है.
अन्य कार्रवाइयों में मिलते-जुलते इनपुट के उलट, dimension
नेगेटिव वैल्यू की अनुमति देता है,
इस्तेमाल करें. आने वाले समय में इसकी अनुमति नहीं दी जाएगी
नियमित तौर पर किए जाने की वजह
(#1377).
अगर is_stable
सही है, तो क्रम स्थिर है, यानी
ऐसे एलिमेंट को सुरक्षित रखा जाता है जिन्हें तुलना करने वाले की ज़रूरत होती है. इस मामले के लिए
जहां एक ही इनपुट होता है, वहां दो एलिमेंट e1
और e2
माने जाते हैं
तुलना करने वाले के बराबर होना चाहिए, अगर
comparator(e1, e2) = comparator(e2, e1) = false
. फ़ॉर्मलाइज़ेशन यहां देखें
के लिए भी इसका इस्तेमाल किया जा सकता है.
index_space(results[0])
में सभी result_index
के लिए, औपचारिक तौर पर:
adjusted_dimension = dimension >= 0 ? dimension : rank(inputs[0]) + dimension
.result_slice = [ri0, ..., :, ..., riR-1]
, जहांriN
व्यक्तिगत हैंresult_index
के एलिमेंट और:
कोadjusted_dimension
पर डाला गया.inputs_together = (inputs[0]..., ..., inputs[N-1]...)
.results_together[result_slice] = sort(inputs_together[result_slice], comparator_together)
.- जहां
sort
1-डायमेंशनल स्लाइस को गैर-घटते क्रम में क्रम में लगाता है किcomparator_together
,true
लौटाता है अगर बाईं ओर का तर्क यह है दाईं ओर मौजूद दूसरे तर्क से कम. def comparator_together(lhs_together, rhs_together): args = [] for (lhs_el, rhs_el) in zip(lhs_together, rhs_together): args.append(lhs_el) args.append(rhs_el) return comparator(*args)
(results[0]..., ..., results[N-1]...) = results_together
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | inputs |
टेंसर की वैरायडिक संख्या या हर टेंसर की क्वांटाइज़्ड टेंसर की संख्या | (सी1-सी5) |
(I2) | dimension |
si64 टाइप का कॉन्स्टेंट |
(सी4) |
(I3) | is_stable |
i1 टाइप का कॉन्स्टेंट |
|
(आई4) | comparator |
फ़ंक्शन | (सी5) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
results |
टेंसर की वैरायडिक संख्या या हर टेंसर की क्वांटाइज़्ड टेंसर की संख्या | (C2), (C3) |
कंस्ट्रेंट
- (C1)
0 < size(inputs)
. - (C2)
type(inputs...) = type(results...)
. - (C3)
same(shape(inputs...) + shape(results...))
. - (C4)
-R <= dimension < R
, जहांR = rank(inputs[0])
. - (C5)
comparator
का टाइप(tensor<E1>, tensor<E1>, ..., tensor<EN-1>, tensor<EN-1>) -> tensor<i1>
, जहांEi = element_type(inputs[i])
है.
उदाहरण
// %input0 = [[1, 2, 3], [3, 2, 1]]
// %input1 = [[3, 2, 1], [1, 2, 3]]
%result0, %result1 = "stablehlo.sort"(%input0, %input1) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>, %arg2: tensor<i64>, %arg3: tensor<i64>):
%predicate = "stablehlo.compare"(%arg0, %arg1) {
comparison_direction = #stablehlo<comparison_direction GT>
} : (tensor<i64>, tensor<i64>) -> tensor<i1>
"stablehlo.return"(%predicate) : (tensor<i1>) -> ()
}) {
dimension = 0 : i64,
is_stable = true
} : (tensor<2x3xi64>, tensor<2x3xi64>) -> (tensor<2x3xi64>, tensor<2x3xi64>)
// %result0 = [[3, 2, 3], [1, 2, 1]]
// %result1 = [[1, 2, 1], [3, 2, 3]]
स्क्वेयर
सिमैंटिक
operand
टेंसर पर एलिमेंट के हिसाब से स्क्वेयर रूट ऑपरेशन करता है और इससे
result
टेंसर. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- फ़्लोट के लिए: IEEE-754 से
squareRoot
. - सम्मिश्र संख्याओं के लिए: सम्मिश्र वर्गमूल.
- क्वांटाइज़्ड टाइप के लिए:
dequantize_op_quantize(sqrt, operand, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// %operand: [[0.0, 1.0], [4.0, 9.0]]
%result = "stablehlo.sqrt"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[0.0, 1.0], [2.0, 3.0]]
घटाएं
सिमैंटिक
दो टेंसर lhs
और rhs
के एलिमेंट के हिसाब से घटाव करता है और इससे
result
टेंसर. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- पूर्णांकों के लिए: पूर्णांक घटाव.
- फ़्लोट के लिए: IEEE-754 से
subtraction
. - सम्मिश्र संख्याओं के लिए: जटिल घटाव.
- क्वांटाइज़्ड टाइप के लिए:
dequantize_op_quantize(subtract, lhs, rhs, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | lhs |
इंटीजर, फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
(I2) | rhs |
इंटीजर, फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
इंटीजर, फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)
.
उदाहरण
// %lhs: [[6, 8], [10, 12]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.subtract"(%lhs, %rhs) : (tensor<2x2xf32>, tensor<2x2xf32>) -> (tensor<2x2xf32>)
// %result: [[1, 2], [3, 4]]
tan
सिमैंटिक
operand
टेंसर पर एलिमेंट के हिसाब से टैंजेंट (tan) की संक्रिया करता है और इससे
result
टेंसर. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- फ़्लोट के लिए: IEEE-754 से
tan
. - सम्मिश्र संख्याओं के लिए: सम्मिश्र टैंजेंट.
- क्वांटाइज़्ड टाइप के लिए:
dequantize_op_quantize(tan, operand, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// %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]
// ]
तान
सिमैंटिक
operand
टेंसर और पर एलिमेंट के हिसाब से हाइपरबोलिक टैंजेंट ऑपरेशन करता है
result
टेंसर बनाता है. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- फ़्लोट के लिए: IEEE-754 से
tanh
. - कॉम्प्लेक्स नंबर के लिए: कॉम्प्लेक्स हाइपरबोलिक टैंजेंट.
- क्वांटाइज़्ड टाइप के लिए:
dequantize_op_quantize(tanh, operand, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_type(operand) = baseline_type(result)
.
उदाहरण
// %operand: [-1.0, 0.0, 1.0]
%result = "stablehlo.tanh"(%operand) : (tensor<3xf32>) -> tensor<3xf32>
// %result: [-0.76159416, 0.0, 0.76159416]
ट्रांसपोज़
सिमैंटिक
permutation
का इस्तेमाल करके operand
टेंसर के डाइमेंशन को अनुमति देता है और
result
टेंसर. औपचारिक तौर पर, result[result_index] = operand[operand_index]
जहां result_index[d] = operand_index[permutation[d]]
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
टेंसर या क्वांटाइज़्ड टेंसर | (सी1-सी4) |
(I2) | permutation |
si64 टाइप का 1-डाइमेंशन टेंसर कॉन्सटेंट |
(सी2-सी4) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टेंसर या क्वांटाइज़्ड टेंसर | (C1), (C3-C4) |
कंस्ट्रेंट
- (C1)
element_type(result)
देने वाली कंपनी:- अगर
!is_per_axis_quantized(operand)
है, तोelement_type(operand)
. element_type(operand)
, लेकिनquantization_dimension(operand)
और ऐसा न होने परquantization_dimension(result)
अलग हो सकती है.
- अगर
- (C2)
permutation
,range(rank(operand))
का क्रमचय (परम्यूटेशन) है. - (C3)
shape(result) = dim(operand, permutation...)
. - (C4) अगर
is_per_axis_quantized(result)
है, तोquantization_dimension(operand) = permutation(quantization_dimension(result))
.
उदाहरण
// %operand: [
// [[1,2], [3,4], [5,6]],
// [[7,8], [9,10], [11,12]]
// ]
%result = "stablehlo.transpose"(%operand) {
permutation = array<i64: 2, 1, 0>
} : (tensor<2x3x2xi32>) -> tensor<2x3x2xi32>
// %result: [
// [[1,7], [3,9], [5,11]],
// [[2,8], [4,10], [6,12]]
// ]
triangular_solve
सिमैंटिक
निचले या ऊपरी त्रिकोणीय वाले रैखिक समीकरणों की प्रणालियों के बैच हल करता है गुणांक वाले मैट्रिक्स से अलग-अलग वैल्यू हो.
औपचारिक तौर पर, a
और b
को दिए जाने पर, result[i0, ..., iR-3, :, :]
समाधान है
op(a[i0, ..., iR-3, :, :]) * x = b[i0, ..., iR-3, :, :]
तक जब left_side
हो
true
या x * op(a[i0, ..., iR-3, :, :]) = b[i0, ..., iR-3, :, :]
, जब
left_side
, false
है. वैरिएबल x
के लिए हल किया जा रहा है, जहां op(a)
तय किया जाता है
transpose_a
से मिला, जो इनमें से एक हो सकता है:
NO_TRANSPOSE
:a
को उसी रूप में इस्तेमाल करके कार्रवाई करें.TRANSPOSE
:a
को ट्रांसपोज़ करने पर कार्रवाई करें.ADJOINT
:a
के संयुग्मी ट्रांसपोज़ पर कार्रवाई करें.
अगर lower
true
है, तो इनपुट डेटा को a
के निचले त्रिभुज से ही पढ़ा जाएगा या
a
का ऊपर वाला त्रिकोण मानें, नहीं तो. आउटपुट डेटा उसी त्रिकोण में दिखाया जाता है;
दूसरे त्रिभुज की वैल्यू लागू करने के तरीके तय की गई हैं.
अगर unit_diagonal
सही है, तो लागू करने पर यह मान लिया जा सकता है कि डायगनल
a
के एलिमेंट 1 के बराबर होते हैं, वरना व्यवहार तय नहीं होता है.
क्वांटाइज़्ड टाइप के लिए,
dequantize_op_quantize(lambda x, y: triangular_solve(x, y, left_side, lower,
unit_diagonal, transpose_a), a, b, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | a |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1-सी3) |
(I2) | b |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1-सी4) |
(I3) | left_side |
i1 टाइप का कॉन्स्टेंट |
(सी3) |
(आई4) | lower |
i1 टाइप का कॉन्स्टेंट |
|
(I5) | unit_diagonal |
i1 टाइप का कॉन्स्टेंट |
|
(I6) | transpose_a |
NO_TRANSPOSE , TRANSPOSE , और ADJOINT का कुल डेटा |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट या कॉम्प्लेक्स टाइप या हर टेंसर क्वांटाइज़्ड टेंसर का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
baseline_element_type(a) = baseline_element_type(b)
. - (C2)
2 <= rank(a) = rank(b) = R
. - (C3)
shape(a)
औरshape(b)
के बीच का संबंध इस तरह से परिभाषित किया गया है:shape(a)[:-3] = shape(b)[:-3]
.dim(a, -2) = dim(a, -1) = dim(b, left_side ? -2 : -1)
.
- (C4)
baseline_type(b) = baseline_type(result)
.
उदाहरण
// %a = [
// [1.0, 0.0, 0.0],
// [2.0, 4.0, 0.0],
// [3.0, 5.0, 6.0]
// ]
// %b = [
// [2.0, 0.0, 0.0],
// [4.0, 8.0, 0.0],
// [6.0, 10.0, 12.0]
// ]
%result = "stablehlo.triangular_solve"(%a, %b) {
left_side = true,
lower = true,
unit_diagonal = false,
transpose_a = #stablehlo<transpose NO_TRANSPOSE>
} : (tensor<3x3xf32>, tensor<3x3xf32>) -> tensor<3x3xf32>
// %result: [
// [2.0, 0.0, 0.0],
// [0.0, 2.0, 0.0],
// [0.0, 0.0, 2.0]
// ]
टपल
सिमैंटिक
val
वैल्यू से result
टपल बनाता है.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | val |
वैल्यू की वैरायडिक संख्या | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
टपल | (सी1) |
कंस्ट्रेंट
- (C1)
result
का टाइपtuple<E0, ..., EN-1>
है, जहांEi = type(val[i])
है.
उदाहरण
// %val0: [1.0, 2.0]
// %val1: (3)
%result = "stablehlo.tuple"(%val0, %val1) : (tensor<2xf32>, tuple<tensor<i32>>) -> tuple<tensor<2xf32>, tuple<tensor<i32>>>
// %result: ([1.0, 2.0], (3))
uniform_dequantize
सिमैंटिक
यह फ़ंक्शन, क्वांटाइज़्ड टेंसर operand
को एलिमेंट के हिसाब से कन्वर्ट करता है
तय किए गए क्वांटाइज़ेशन पैरामीटर के मुताबिक, फ़्लोटिंग-पॉइंट टेंसर result
operand
टाइप के हिसाब से.
औपचारिक तौर पर, result = dequantize(operand)
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
क्वांटाइज़्ड टेंसर | (C1), (C2) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
फ़्लोटिंग-पॉइंट टाइप का टेंसर | (C1), (C2) |
कंस्ट्रेंट
- (C1)
shape(operand) = shape(result)
. - (C2)
element_type(result) = expressed_type(operand)
.
उदाहरण
// %operand: [10, 10]
%result = "stablehlo.uniform_dequantize"(%operand) : (tensor<2x!quant.uniform<i8:f32:0, {0.1:-30,0.5:-20}>>) -> tensor<2xf32>
// %result: [4.0, 15.0]
uniform_quantize
सिमैंटिक
फ़्लोटिंग-पॉइंट टेंसर या क्वांटाइज़्ड टेंसर का एलिमेंट के हिसाब से कन्वर्ज़न करता है
क्वांटाइज़ेशन के हिसाब से, operand
को क्वांटाइज़्ड टेंसर result
पर सेट करें
result
टाइप के ज़रिए तय किए गए पैरामीटर.
औपचारिक तौर पर,
- अगर
is_float(operand)
:result = quantize(operand, type(result))
.
- अगर
is_quantized(operand)
:float_result = dequantize(operand)
.result = quantize(float_result, type(result))
.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
फ़्लोटिंग-पॉइंट या क्वांटाइज़्ड टाइप का टेंसर | (C1), (C2) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
क्वांटाइज़्ड टेंसर | (C1), (C2) |
कंस्ट्रेंट
- (C1)
shape(operand) = shape(result)
. - (C2)
expressed_type(result) = is_float(operand) ? element_type(operand) : expressed_type(operand)
.
उदाहरण
// %operand: [4.0, 15.0]
%result = "stablehlo.uniform_quantize"(%operand) : (tensor<2xf32>) -> tensor<2x!quant.uniform<i8:f32:0, {0.1:-30,0.5:-20}>>
// %result: [10, 10]
// %operand: [10, 10]
%result = "stablehlo.uniform_quantize"(%operand) : (tensor<2x!quant.uniform<i8:f32:0, {0.1:-30,0.5:-20}>>) -> tensor<2x!quant.uniform<i8:f32:0, {0.1:-20,0.2:-30}>>
// %result: [20, 45]
जबकि
सिमैंटिक
body
फ़ंक्शन को 0 या उससे ज़्यादा बार चलाने पर आउटपुट देता है, जबकि
cond
फ़ंक्शन का आउटपुट true
है. औपचारिक तौर पर, सिमेंटिक्स को व्यक्त किया जा सकता है
Python सिंटैक्स का इस्तेमाल इस तरह से करता है:
internal_state = operand
while cond(*internal_state):
internal_state = body(*internal_state)
results = internal_state
अनंत लूप का व्यवहार अभी तय नहीं है (#383).
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | operand |
टेंसर की वैरायडिक संख्या, क्वांटाइज़ किए गए टेंसर या टोकन | (सी1-सी3) |
(I2) | cond |
फ़ंक्शन | (सी1) |
(I3) | body |
फ़ंक्शन | (सी2) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
results |
टेंसर की वैरायडिक संख्या, क्वांटाइज़ किए गए टेंसर या टोकन | (सी3) |
कंस्ट्रेंट
- (C1)
cond
का टाइप(T0, ..., TN-1) -> tensor<i1>
है, जहांTi = type(operand[i])
. - (C2)
body
का टाइप(T0, ..., TN-1) -> (T0, ..., TN-1)
है, जहांTi = type(operand[i])
. - (C3)
type(results...) = type(operand...)
.
उदाहरण
// %init_i: 1
// %init_sum: 0
// %one: 1
// %ten: 10
%results0, %results1 = "stablehlo.while"(%init_i, %init_sum) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%cond = "stablehlo.compare"(%arg0, %ten) {
comparison_direction = #stablehlo<comparison_direction LT>
} : (tensor<i64>, tensor<i64>) -> tensor<i1>
stablehlo.return %cond : tensor<i1>
}, {
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%new_sum = stablehlo.add %arg1, %one : tensor<i64>
%new_i = stablehlo.add %arg0, %one : tensor<i64>
stablehlo.return %new_i, %new_sum : tensor<i64>, tensor<i64>
}) : (tensor<i64>, tensor<i64>) -> (tensor<i64>, tensor<i64>)
// %results0: 10
// %results1: 10
एक्सओआर
सिमैंटिक
दो टेंसर lhs
और rhs
के एलिमेंट के हिसाब से XOR करता है और result
बनाता है
टेंसर. एलिमेंट टाइप के आधार पर, ये काम किए जाते हैं:
- बूलियन के लिए: लॉजिकल XOR.
- पूर्णांक के लिए: बिट के अनुसार XOR.
इनपुट
लेबल | नाम | टाइप | कंस्ट्रेंट |
---|---|---|---|
(I1) | lhs |
बूलियन या पूर्णांक टाइप का टेंसर | (सी1) |
(I2) | rhs |
बूलियन या पूर्णांक टाइप का टेंसर | (सी1) |
आउटपुट
नाम | टाइप | कंस्ट्रेंट |
---|---|---|
result |
बूलियन या पूर्णांक टाइप का टेंसर | (सी1) |
कंस्ट्रेंट
- (C1)
type(lhs) = type(rhs) = type(result)
.
उदाहरण
// Bitwise operation with with integer tensors
// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.xor"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[4, 4], [4, 12]]
// Logical operation with with boolean tensors
// %lhs: [[false, false], [true, true]]
// %rhs: [[false, true], [false, true]]
%result = "stablehlo.xor"(%lhs, %rhs) : (tensor<2x2xi1>, tensor<2x2xi1>) -> tensor<2x2xi1>
// %result: [[false, true], [true, false]]
भाषा सिंक करने की सुविधा
इस समय, जंगल में StableHLO प्रोग्राम कभी-कभी ऐसे ऑपरेशन होते हैं जो StableHLO की ओर से तय नहीं किए जाते हैं.
मॉड्यूल, फ़ंक्शन, कॉल, और रिटर्न
StableHLO, ModuleOp, FuncOp, CallOp, और रिटर्नOp. ऐसा करने से, मौजूदा एमएलआईआर मशीनरी के साथ बेहतर इंटरऑप की सुविधा इस्तेमाल की गई. काम के पास को लिखित तौर पर, FuncOp और ModuleOp, और कई सारे कंपाइलेशन को टारगेट करके तैयार किया जाता है पाइपलाइन में ये ऑपरेशन मौजूद होने की उम्मीद होती है. साथ काम करने से जुड़ी गारंटी इन ऑपरेशन पर लागू किया गया. अगर इन ऑपरेशन में कभी भी कुछ बदलता है असंगत तरीके से (यानी निकालना), सुरक्षित रखने के लिए StableHLO से मिलते-जुलते तरीके साथ काम करता है.
CHLO
CHLO ऑपसेट में उच्च स्तर की कार्रवाइयां होती हैं, जो StableHLO में डीकंपोज़ होती हैं. फ़िलहाल, इस बात की कोई गारंटी नहीं है कि सीएचएलओ के साथ यह काम करेगा या नहीं. साथ काम करने के लिए गारंटी के साथ, chlo-legalize-to-stablehlo पास क्रम से लगाने से पहले इस्तेमाल किया जाना चाहिए.
आकार से जुड़ी कार्रवाइयां
समुदाय में बुनियादी चीज़ों का इस्तेमाल करने के लिए, यह आम तौर पर इस्तेमाल किया जाता है
आकार की गणना करने के लिए, डाइनैमिक StableHLO प्रोग्राम में एमएलआईआर बोलियां इस्तेमाल की जाती हैं.
आम तौर पर, इनमें shape
भाषा शामिल है
shape_of
या num_elements
जैसे विकल्प, tensor
बोली
वर्शन, जैसे कि dim
या from_elements
और पहले से मौजूद index
टाइप.
डायनेमिज़म आरएफ़सी > O2
यह दिखाता है कि ये दायरे से बाहर हैं. हालांकि, कुछ तरह के index
के लिए भी कुछ काम किया जा सकता है
इसे इंटरऑप के लिए इस्तेमाल किया जाता है. इस बात की कोई गारंटी नहीं है कि इनके साथ काम करेगा या नहीं
ऑपरेशन या प्रकार. shape-legalize-to-stablehlo
पास का इस्तेमाल इन ऑपरेशन को पूरी तरह से काम करने वाले StableHLO ऑपरेशन में बदलने के लिए किया जा सकता है.
ऐसी कार्रवाइयां जो अब रोक दी गई हैं
ऐसे कई StableHLO ऑपरेशन हैं जो इनसे इनहेरिट किए गए थे MHLO जो अब सेवा में नहीं हैं और StableHLO से बाहर निकलने वाले हैं. इन विज्ञापनों में पूरा विवरण StableHLO v1.0 क्लीनअप #2283 में, ऐप्लिकेशन हटाए जाने की जानकारी मौजूद होती है. इस सुविधा के बंद होने से जुड़ी ट्रैकर से जुड़ी समस्या #2340 है.
ये कार्रवाइयां कुछ कैटगरी में आती हैं:
- "HLO में नहीं" StableHLO ऑपरेशन की एक कैटगरी होती है - जो शुरुआत में
StableHLO ओपसेट का इस्तेमाल किया जाता है, लेकिन बाद में यह माना गया कि यह ठीक से फ़िट नहीं हुआ:
broadcast
,create_token
,cross-replica-sum
,dot
,einsum
,torch_index_select
,unary_einsum
(#3). - इस्तेमाल नहीं किए गए ऑपरेशन - ये कार्रवाइयां शायद किसी भी समय उपयोगी रही हों, लेकिन ऑपरेशन
या तो पूरी तरह से विकसित नहीं हुआ था या इन ऑपरेशन का इस्तेमाल करने वाली पाइपलाइन
जवाब की ज़रूरत नहीं होगी, इसके लिए जवाब दिया गया. इसमें
map
,tuple
(#598),get_tuple_element
,rng
,complex
तुलनाएं #560, और कन्वर्ज़नwindow_reversal
(#1181).
इनमें से कुछ ऑपरेशन को आसानी से हटाया जा सकता है, क्योंकि उन्हें इसका इस्तेमाल करके दिखाया जा सकता है
मौजूदा ऑपरेशन (broadcast
, create_token
, cross-replica-sum
, dot
,
unary_einsum
) को एक्सपोर्ट किया जाएगा और मौजूदा कंपैटबिलिटी विंडो के बाद इसे हटा दिया जाएगा
पास (छह महीने). अन्य यूआरएल की जांच अब भी जारी है, ताकि उन्हें हटाया जा सके (einsum
,
get_tuple_element
, map
, rng
torch_index_select
, tuple
, complex
तुलनाएं, window_reversal
). लंबित समुदाय सुझाव,
ये ऑपरेशन या तो हटा दिए जाएंगे या पूरे सपोर्ट के साथ इन्हें स्पेसिफ़िकेशन में जोड़ दिए जाएंगे. पूरा होने तक
ये ऑपरेशन फ़्यूचर्स के बारे में पता है, लेकिन ये सिर्फ़ 6 महीनों के साथ काम करने की गारंटी देते हैं.
प्लान लागू करना
क्रम से लागू करना
main
फ़ंक्शन में इनपुट वैल्यू देकर, StableHLO प्रोग्राम चलाया जाता है
और आउटपुट वैल्यू की गणना की जा सकती है. फ़ंक्शन की आउटपुट वैल्यू का हिसाब लगाने के तरीके
इससे जुड़े return
ऑपरेशन में रूट किए गए ऑपरेशन के ग्राफ़ को एक्ज़ीक्यूट किया जा रहा है.
लागू होने का क्रम तब तक तय होता है, जब तक यह
dataflow, इसका मतलब है कि अगर ऑपरेशन को इस्तेमाल करने से पहले एक्ज़ीक्यूट किया जाता है. StableHLO में, सभी
साइड-इफ़ेक्टिंग ऑपरेशन, एक टोकन का इस्तेमाल करते हैं और एक टोकन बनाते हैं. हालांकि, एक से ज़्यादा टोकन
after_all
के ज़रिए एक टोकन में मल्टीप्लेक्स किया जाएगा), इसलिए साइड का एक्ज़ीक्यूशन ऑर्डर
इफ़ेक्ट भी डेटाफ़्लो के साथ अलाइन होते हैं. उदाहरण के लिए, नीचे दिए गए प्रोग्राम में
प्रोग्राम चलाने के दो संभावित ऑर्डर हैं: %0
→ %1
→ %2
→ return
और
%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>
}
औपचारिक रूप से, StableHLO प्रोसेस, इनमें से एक है:
1) StableHLO प्रोग्राम, 2) ऑपरेशन की स्थितियां (अभी तक एक्ज़ीक्यूट नहीं किया गया है,
) और 3) इंटरमीडिएट वैल्यू, जिन पर प्रोसेस काम कर रही है.
प्रोसेस, main
फ़ंक्शन के लिए इनपुट वैल्यू से शुरू होती है और आगे बढ़ती है
ऑपरेशन की स्थितियों और इंटरमीडिएट वैल्यू को अपडेट करने वाले ऑपरेशन का ग्राफ़ और
आउटपुट वैल्यू के साथ खत्म होती है. सुविधाओं को और औपचारिक तौर पर अभी तय नहीं किया गया है
(#484).
साथ-साथ एक्ज़ीक्यूशन
StableHLO प्रोग्राम, साथ-साथ चलाए जा सकते हैं और 2D प्रोसेस ग्रिड में व्यवस्थित किए जा सकते हैं
num_partitions
गुणा num_replicas
का, जो दोनों प्रकार ui32
है.
StableHLO प्रोसेस ग्रिड में, StableHLO का num_replicas * num_partitions
एक ही समय पर प्रोसेस होती हैं. हर प्रोसेस की अपनी एक खास बात होती है
process_id = (replica_id, partition_id)
, जहां
replica_ids = range(num_replicas)
में replica_id
और
partition_ids = range(num_partitions)
में partition_id
, जिसमें दोनों के पास
ui32
लिखें.
प्रोसेस ग्रिड के साइज़ को स्टैटिक रूप से हर प्रोग्राम के लिए जाना जाता है (
आने वाले समय में, हम इसे StableHLO प्रोग्राम का एक अहम हिस्सा बनाने की योजना बना रहे हैं
#650) और पोज़िशन
के अंदर प्रोसेस ग्रिड को हर प्रोसेस के लिए स्टैटिक तरीके से जाना जाता है. हर प्रोसेस में
replica_id
और
partition_id
ऑपरेशन
प्रोसेस ग्रिड में, प्रोग्राम एक जैसे हो सकते हैं. ऐसा "सिंगल प्रोग्राम, एक से ज़्यादा डेटा" शैली), सभी अलग-अलग हो सकते हैं ("एक से ज़्यादा प्रोग्राम, एक से ज़्यादा डेटा" स्टाइल) या बीच की कोई दूसरी चीज़ भी हो सकती है. आने वाले समय में, हम समानांतर StableHLO प्रोग्राम को तय करने से जुड़े दूसरे मुहावरों का समर्थन करने के लिए इसमें GSPMD (#619) भी शामिल है.
प्रोसेस ग्रिड में, प्रोसेस एक-दूसरे से अलग होती हैं - उनकी कार्रवाई की अलग-अलग स्थितियां होती हैं. उनके इनपुट/इंटरमीडिएट/आउटपुट वैल्यू अलग-अलग होती हैं और ज़्यादातर ऑपरेशन, प्रक्रियाओं के बीच अलग-अलग तरीके से चलाए जाते हैं और उनमें अपवाद के तौर पर कुछ जोड़ सकते हैं.
यह देखते हुए कि ज़्यादातर ऑपरेशन को चलाने के लिए सिर्फ़ उसी
प्रक्रिया के दौरान, इन वैल्यू को उनके नाम से साफ़ तौर पर देखा जा सकता है.
हालांकि, सामूहिक ऑपरेशन के सिमेंटिक्स की व्याख्या करते समय, यह पर्याप्त नहीं है और
जो name
मान को बताने के लिए नोटेशन name@process_id
को जनरेट करता है
एक खास प्रोसेस में शामिल किया जाता है. (इस नज़रिए से, बिना अनुमति वाले name
ऐसे हो सकते हैं
को name@(replica_id(), partition_id())
के लिए शॉर्टहैंड के तौर पर देखा गया).
सभी प्रोसेस के लिए एक्ज़ीक्यूशन का क्रम तय होता है. हालांकि, इसमें पॉइंट-टू-पॉइंट कम्यूनिकेशन और कलेक्टिव ऑपरेशन की मदद से सिंक करने की सुविधा जैसा कि नीचे बताया गया है.
पॉइंट-टू-पॉइंट कम्यूनिकेशन
StableHLO प्रोसेस,
StableHLO चैनल. चैनल को एक पॉज़िटिव आईडी से दिखाया जाता है
si64
. कई ऑपरेशन के ज़रिए, चैनल और
उन्हें चैनलों से न ले सकें.
ज़्यादा औपचारिकता, जैसे कि ये चैनल आईडी कहां से आते हैं, कैसे इससे उन्हें प्रोसेस के बारे में जानकारी मिलती है. साथ ही, उन्हें यह भी पता चलता है कि किस तरह का सिंक्रोनाइज़ेशन होता है उन्होंने टेक्नोलॉजी का इस्तेमाल शुरू किया है. यह अभी तय नहीं है (#484).
स्ट्रीमिंग कम्यूनिकेशन
StableHLO की हर प्रोसेस के पास दो स्ट्रीमिंग इंटरफ़ेस का ऐक्सेस होता है:
- इनफ़ीड, जिससे टेक्स्ट को पढ़ा जा सकता है.
- आउटफ़ीड, जिसे लिखा जा सकता है.
चैनलों के उलट, जिनका इस्तेमाल अलग-अलग प्रोसेस के बीच बातचीत करने के लिए किया जाता है. इनफ़ीड और आउटफ़ीड के लिए एक-दूसरे से जुड़ी अलग-अलग प्रक्रियाएं होती हैं. लागू करना-तय करना बंद करें.
ज़्यादा औपचारिकता, जैसे कि स्ट्रीमिंग कम्यूनिकेशन, कैसे एक्ज़ीक्यूट करता है यह अभी तय नहीं है कि ऑर्डर में किस तरह का सिंक किया जाएगा. (#484).
कलेक्टिव ऑपरेशन
StableHLO में छह कलेक्टिव ऑपरेशन हैं: all_gather
, all_reduce
,
all_to_all
, collective_broadcast
, collective_permute
, और
reduce_scatter
. ये सभी ऑपरेशन StableHLO प्रोसेस में, प्रोसेस को अलग-अलग करते हैं
StableHLO प्रोसेस ग्रुप में ग्रिड जोड़ें और
अन्य प्रोसेस ग्रुप से अलग, हर प्रोसेस ग्रुप.
हर प्रोसेस ग्रुप में, कलेक्टिव ऑपरेशन एक सिंक की सुविधा दे सकते हैं समस्या को हल करने में मदद मिलती है. ज़्यादा औपचारिकता, जैसे कि जिसमें यह बताया गया है कि सिंक होता है, प्रोसेस इस रुकावट तक कैसे पहुंचती हैं, यह अभी तय नहीं है कि ऐसा न होने पर क्या होगा (#484).
अगर प्रोसेस ग्रुप में क्रॉस-पार्टिशन कम्यूनिकेशन शामिल है, तो इसका मतलब है कि
प्रक्रिया समूह की ऐसी प्रक्रियाएं जिनके विभाजन आईडी अलग-अलग हैं, फिर निष्पादन
कलेक्टिव ऑपरेशन को एक चैनल की ज़रूरत होती है और कलेक्टिव ऑपरेशन को
si64
प्रकार का सकारात्मक channel_id
. क्रॉस-रेप्लिका कम्यूनिकेशन की ज़रूरत नहीं है
चैनल.
कलेक्टिव ऑपरेशन की रिपोर्ट, हर ऑपरेशन के लिए अलग होती है इनके बारे में ऊपर दिए गए अलग-अलग सेशन के सेक्शन में बताया गया है. हालांकि, रणनीति बनाकर इसमें प्रोसेस ग्रिड को प्रोसेस ग्रुप में बांटा जाता है. इन्हें इन ऑपरेशन के बीच शेयर किया जाता है और इस सेक्शन में इनके बारे में बताया गया है. औपचारिक रूप से, StableHLO ये चार रणनीतियां शामिल हैं.
cross_replica
हर प्रोसेस ग्रुप में सिर्फ़ क्रॉस-रेप्लिका कम्यूनिकेशन होते हैं. यह
कार्यनीति replica_groups
- प्रतिरूप आईडी की सूचियों की सूची - और कंप्यूट का इस्तेमाल करती है
partition_ids
के replica_groups
का एक कार्टीज़न प्रॉडक्ट. replica_groups
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है
यूनीक एलिमेंट होने चाहिए और सभी replica_ids
कवर किए जाने चाहिए. ज़्यादा औपचारिक तौर पर,
Python सिंटैक्स:
def cross_replica(replica_groups: List[List[ReplicaId]]) -> List[List[ProcessId]]:
for replica_group in replica_groups:
for partition_id in partition_ids:
process_group = []
for replica_id in replica_group:
process_group.append((replica_id, partition_id))
yield process_group
उदाहरण के लिए, replica_groups = [[0, 1], [2, 3]]
और num_partitions = 2
के लिए,
cross_replica
प्रोडक्शन होगी
[[(0, 0), (1, 0)], [(0, 1), (1, 1)], [(2, 0), (3, 0)], [(2, 1), (3, 1)]]
.
cross_partition
हर प्रोसेस ग्रुप में सिर्फ़ क्रॉस-पार्टिशन कम्यूनिकेशन होते हैं. यह
रणनीति, सेगमेंट आईडी की सूचियों की सूची - और partition_groups
का इस्तेमाल करती है
replica_ids
गुणा partition_groups
के कार्टीज़न गुणनफल की गणना करता है.
partition_groups
में यूनीक एलिमेंट होने चाहिए और इनमें सभी partition_ids
शामिल होने चाहिए.
Python सिंटैक्स का इस्तेमाल करके, औपचारिक रूप से:
def cross_partition(partition_groups: List[List[PartitionId]]) -> List[List[ProcessId]]:
for partition_group in partition_groups:
for replica_id in replica_ids:
process_group = []
for partition_id in partition_group:
process_group.append((replica_id, partition_id))
yield process_group
उदाहरण के लिए, partition_groups = [[0, 1]]
और num_replicas = 4
के लिए,
cross_partition
प्रोडक्शन होगी
[[(0, 0), (0, 1)], [(1, 0), (1, 1)], [(2, 0), (2, 1)], [(3, 0), (3, 1)]]
.
cross_replica_and_partition
क्रॉस-रेप्लिका और क्रॉस-पार्टिशन कम्यूनिकेशन, दोनों
प्रोसेस ग्रुप. इस रणनीति के लिए replica_groups
की ज़रूरत होती है - यह सूचियों की सूची है
प्रतिरूप आईडी - और इसके हिसाब से हर replica_group
के कार्टीज़न प्रॉडक्ट की गणना करता है
partition_ids
. replica_groups
में यूनीक एलिमेंट होने चाहिए और इनमें सभी एलिमेंट शामिल होने चाहिए
replica_ids
. Python सिंटैक्स का इस्तेमाल करके, औपचारिक रूप से:
def cross_replica_and_partition(replica_groups: List[List[ReplicaId]]) -> List[List[ProcessId]]:
for replica_group in replica_groups:
process_group = []
for partition_id in partition_ids:
for replica_id in replica_group:
process_group.append((replica_id, partition_id))
yield process_group
उदाहरण के लिए, replica_groups = [[0, 1], [2, 3]]
और num_partitions = 2
के लिए,
cross_replica_and_partition
प्रोडक्शन होगी
[[(0, 0), (1, 0), (0, 1), (1, 1)], [(2, 0), (3, 0), (2, 1), (3, 1)]]
.
flattened_ids
इस रणनीति के लिए, flattened_id_groups
की ज़रूरत है - यह "फ़्लैट की गई" सूचियों की सूची है
replica_id * num_partitions + partition_id
- और
उन्हें प्रोसेस आईडी में बदल देता है. flattened_id_groups
में यूनीक एलिमेंट होने चाहिए
और सभी process_ids
कवर करती हैं. Python सिंटैक्स का इस्तेमाल करके, औपचारिक रूप से:
def flattened_ids(flattened_id_groups: List[List[ui32]]) -> List[List[ProcessId]]:
for flattened_id_group in flattened_id_groups:
process_group = []
for flattened_id in flattened_id_group:
replica_id = flattened_id // num_partitions
partition_id = flattened_id % num_partitions
process_group.append((replica_id, partition_id))
yield process_group
उदाहरण के लिए, flattened_id_groups = [[0, 1, 2, 3], [4, 5, 6, 7]]
के लिए,
num_replicas = 4
और num_partitions = 2
, flattened_ids
के साथ मिलकर काम करेंगे
[[(0, 0), (0, 1), (1, 0), (1, 1)], [(2, 0), (2, 1), (3, 0), (3, 1)]]
.
सटीक जानकारी
फ़िलहाल, StableHLO, अंकों में सटीक होने की गारंटी नहीं देता है. हालांकि, आने वाले समय में इसकी स्थिति बदल सकती है (#1156).
क्वांटाइज़्ड ऑपरेशन का एक्ज़ीक्यूशन सिमेंटिक्स
क्वांटाइज़्ड StableHLO ऑपरेशन की परिभाषा, इस बात पर निर्भर करती है कि हार्डवेयर की ज़रूरतों और क्षमताओं को पूरा किया जाता है. उदाहरण के लिए, कुछ हार्डवेयर क्वांटाइज़्ड ऑपरेशन की व्याख्या करने के लिए और आखिर में आकलन करें" रणनीति. अन्य लोग पूरा परफ़ॉर्म कर सकते हैं पूर्णांक अंकगणित के साथ गणना. इस वजह से, क्वांटाइज़्ड StableHLO ऑपरेशन खास तौर पर, लागू करना. हाइब्रिड क्वांटाइज़ेशन की परिभाषा (#1575) इस पर आधारित होना चाहिए: यह स्पेसिफ़िकेशन में बताए गए अनुसार सिमेंटिक्स है ( 1792).
गड़बड़ियां
StableHLO प्रोग्राम की पुष्टि, कई तरह की पाबंदियों के ज़रिए की जाती है इसकी मदद से, रन टाइम से पहले कई तरह की गड़बड़ियों को रोका जा सकता है. हालांकि, गड़बड़ी की स्थितियां अब भी हो सकती हैं, जैसे कि पूर्णांक से होकर, आउट-ऑफ़-बाउंड ऐक्सेस वगैरह. जब तक साफ़ तौर पर इस बारे में न बताया गया हो, तब तक ये सभी गड़बड़ियां के नतीजे के तौर पर हम तय करते हैं कि यह ज़रूरी है या नहीं, लेकिन इसकी वजह से आने वाले समय में (#1157).
फ़्लोटिंग-पॉइंट अपवाद
इस नियम के अपवाद के तौर पर, StableHLO प्रोग्राम में फ़्लोटिंग-पॉइंट के अपवाद
अच्छे ढंग से तय किए गए व्यवहार होते हैं. ऐसी कार्रवाइयां जिनके नतीजे में
आईईईई-754 स्टैंडर्ड (अमान्य ऑपरेशन, हर सेगमेंट की संख्या, ओवरफ़्लो, अंडरफ़्लो या
सटीक अपवाद) डिफ़ॉल्ट नतीजे देते हैं (जैसा कि स्टैंडर्ड में बताया गया है) और
स्टेटस बताने वाले फ़्लैग को उठाए बिना, एक्ज़ीक्यूशन जारी रखना; इसके समान
स्टैंडर्ड से raiseNoFlag
अपवाद मैनेज करना. गैर-मानकों के लिए अपवाद
संक्रियाएं (उदाहरण के लिए, जटिल अंकगणित और कुछ ट्रांसेंडेंटल फ़ंक्शन)
लागू किया जाना चाहिए.
आकार मेल नहीं खाता
StableHLO, डाइनैमिक आकार के टेंसर के साथ काम करता है. हालांकि, आकृतियों का सहमत होना ज़रूरी है रनटाइम है, तो व्यवहार तय नहीं होता है. StableHLO, साफ़ तौर पर एक ऐसी ऑप उपलब्ध कराएं, जो दावा कर सके कि रनटाइम के समय टेंसर का एक आकार होता है. सही कोड जनरेट करने की ज़िम्मेदारी मैन्युफ़ैक्चरर की है.
खास उदाहरण के तौर पर, यह प्रोग्राम मान्य है. हालांकि, रनटाइम के दौरान,
%arg0
और %arg1
का सटीक आकार एक जैसा होना चाहिए. अगर ऐसा नहीं है, तो
प्रोग्राम के व्यवहार के बारे में नहीं बताया गया है:
func.func @foo(%arg0: tensor<?xi32>, %arg1: tensor<?xi32>) -> tensor<?xi32> {
%0 = stablehlo.add %arg0, %arg1 : tensor<?xi32>
return %0 : tensor<?xi32>
}
नोटेशन
सिंटैक्स की जानकारी देने के लिए, इस दस्तावेज़ में EBNF के बदले गए आईएसओ फ़्लेवर का इस्तेमाल किया गया है
सिंटैक्स (ISO/IEC 14977:1996,
Wikipedia),
दो बदलावों के साथ: 1) नियम =
के बजाय ::=
का इस्तेमाल करके तय किए जाते हैं,
2) स्ट्रिंग जोड़ने की प्रोसेस को ,
के बजाय, सीधे तौर पर जोड़ने की सुविधा का इस्तेमाल करके दिखाया जाता है.
सिमैंटिक के बारे में बताने के लिए (जैसे, "टाइप", "कॉन्सटेंट", और "ऑपरेशन" सेक्शन) में, हम ऐसे फ़ॉर्मूले इस्तेमाल कर रहे हैं जो सहायता के साथ बढ़ाए गए Python सिंटैक्स पर आधारित होते हैं का इस्तेमाल करें. यह काफ़ी कारगर है के लिए छोटे स्निपेट के लिए होता है, लेकिन बहुत कम मामलों में जब कोड के बड़े स्निपेट ज़रूरी है, तो हम वैनिला Python सिंटैक्स का इस्तेमाल करते हैं. यह सिंटैक्स हमेशा साफ़ तौर पर पेश किया जाता है.
फ़ॉर्मूला
आइए, देखते हैं कि dot_general
के उदाहरण के आधार पर फ़ॉर्मूला कैसे काम करते हैं
स्पेसिफ़िकेशन. इस कार्रवाई की एक सीमा यहां दी गई है:
dim(lhs, lhs_batching_dimensions...) = dim(rhs, rhs_batching_dimensions...)
.
इस फ़ॉर्मूला में इस्तेमाल किए गए नाम दो सोर्स से आते हैं: 1) ग्लोबल फ़ंक्शन,
उदाहरण के लिए, dim
, 2) प्रोग्राम के एलिमेंट से जुड़ी सदस्यों की परिभाषाएं, जैसे कि
lhs
, lhs_batching_dimensions
, rhs
, और rhs_batching_dimensions
इनपुट
"इनपुट" में परिभाषित किया गया है सेक्शन dot_general
का है.
जैसा कि ऊपर बताया गया है, इस फ़ॉर्मूला का सिंटैक्स Python पर आधारित है. इसमें कम समय में इस्तेमाल किए जा सकने वाले एक्सटेंशन. फ़ॉर्मूला को समझने के लिए, आइए पूरी तरह बदलें इसे वनिला Python सिंटैक्स में बदल देते हैं.
A) इन फ़ॉर्मूले में, हम समानता को दिखाने के लिए =
का इस्तेमाल कर रहे हैं. इसलिए, पहला चरण
यह तरीका अपनाकर, Python सिंटैक्स पाने के लिए, =
को ==
से बदला जा रहा है:
dim(lhs, lhs_batching_dimensions...) == dim(rhs, rhs_batching_dimensions...)
.
B) साथ ही, ये फ़ॉर्मूले, एलिप्स (...
) का इस्तेमाल करते हैं, जो अदिश व्यंजकों को बदलते हैं
टेंसर एक्सप्रेशन में बदल सकते हैं. कम शब्दों में कहें, तो f(xs...)
का मतलब है "हर
टेंसर xs
में अदिश x
, एक अदिश f(x)
की गणना करें और फिर सभी का मान निकालें
ये अदिश परिणाम एक साथ टेंसर परिणाम के रूप में होते हैं". वैनिला Python सिंटैक्स में,
हमारा उदाहरण फ़ॉर्मूला यहां बदल जाता है:
[dim(lhs, dim1) for dim1 in lhs_batching_dimensions] ==
[dim(rhs, dim2) for dim2 in rhs_batching_dimensions]
.
दीर्घवृत्त की वजह से अक्सर संभव है कि आप डैशबोर्ड पर
अलग-अलग स्केलर. हालांकि, कुछ पेचीदा मामलों में, लोअर-लेवल सेमी-अनौपचारिक
start_indices[bi0, ..., :, ..., biN]
फ़ॉर्मूला की तरह ही सिंटैक्स का इस्तेमाल किया जा सकता है
gather
स्पेसिफ़िकेशन के मुताबिक. संक्षिप्तता की सेवा में, हम
इस तरह के सिंटैक्स का अनुवाद वैनिला Python में करने के लिए, सटीक फ़ॉर्मलिज़्म उपलब्ध कराया जा सकता है.
उम्मीद है कि अब भी अलग-अलग पहलुओं को आसानी से समझा जा सकेगा.
अगर कुछ फ़ॉर्मूला साफ़ नहीं दिख रहे हैं, तो कृपया हमें बताएं. हम उन फ़ॉर्मूलों को
उन्हें बेहतर बनाना.
साथ ही, आप देखेंगे कि फ़ॉर्मूला सभी तरह की सूचियों को बड़ा करने के लिए एलिप्स का इस्तेमाल करते हैं, इसमें टेंसर, टेंसर की सूचियां (उदाहरण के लिए, वैरायडिक टेंसर की संख्या वगैरह. यह एक अन्य एरिया है, जहां हम सटीक जानकारी नहीं देते औपचारिकता (उदाहरण के लिए, सूचियां StableHLO टाइप सिस्टम का हिस्सा भी नहीं हैं) और समझने की क्षमता पर भरोसा करते हैं.
C) ध्यान देने लायक आखिरी नोटेशनल वाहन ब्रॉडकास्ट कर रहा है. हालांकि StableHLO opset, इंप्लिसिट ब्रॉडकास्टिंग के साथ काम नहीं करता, फ़ॉर्मूले में, कम अवधि के लिए भी किया जा सकता है. संक्षेप में, अगर एक अदिश का इस्तेमाल ऐसे कॉन्टेक्स्ट में किया जाता है जहां टेंसर की उम्मीद की जाती है, और स्केलर को अनुमानित आकार.
dot_general
उदाहरण को जारी रखने के लिए, यहां एक और कंस्ट्रेंट दिया गया है:
0 <= lhs_batching_dimensions < rank(lhs)
. जैसा कि dot_general
में बताया गया है
स्पेसिफ़िकेशन के हिसाब से, lhs_batching_dimensions
एक टेंसर है. हालांकि, 0
और
rank(lhs)
स्केलर हैं. इंप्लिसिट ब्रॉडकास्टिंग को लागू करने के बाद, फ़ॉर्मूला
[0, ..., 0] <= lhs_batching_dimensions < [rank(lhs), ..., rank(lhs)]
बन जाएं.
किसी खास dot_general
ऑपरेशन पर लागू होने पर, यह फ़ॉर्मूला
बूलियन के टेंसर का आकलन करें. जब फ़ॉर्मूला को कंस्ट्रेंट के रूप में इस्तेमाल किया जाता है, तो
कंस्ट्रेंट होल्ड करता है अगर फ़ॉर्मूला का आकलन या तो true
या टेंसर पर होता है
सिर्फ़ true
एलिमेंट हैं.
नाम
फ़ॉर्मूला में, लेक्सिकल स्कोप में ये शामिल हैं: 1) ग्लोबल फ़ंक्शन, 2) सदस्य की परिभाषाएं,
3) स्थानीय परिभाषाएं. ग्लोबल फ़ंक्शन की सूची यहां दी गई है. सूची एलिमेंट की परिभाषाएं प्रोग्राम एलिमेंट पर निर्भर करती हैं कि नोटेशन इस पर लागू किया गया:
- कार्रवाइयों के लिए, सदस्य की परिभाषाओं में "इनपुट" में बताए गए नाम शामिल होते हैं और "आउटपुट" सेक्शन.
- बाकी सभी के लिए, सदस्य की परिभाषाओं में
प्रोग्राम एलिमेंट, जिसका नाम संबंधित EBNF नॉन-टर्मिनल के नाम पर रखा गया है. ज़्यादातर
समय, इन संरचनात्मक हिस्सों के नाम इस तरह से लिए गए हैं कि
सांप के केस के लिए नॉन-टर्मिनल के नाम (उदाहरण के लिए
IntegerLiteral
=>integer_literal
), लेकिन कभी-कभी इस प्रोसेस में नामों को छोटा कर दिया जाता है (जैसे,QuantizationStorageType
=>storage_type
) होता है, जिसमें नाम "इनपुट" के समान रूप से पेश किया गया / "आउटपुट" कारोबार के सेक्शन खास जानकारी. - इसके अलावा, सदस्य की परिभाषाओं में हमेशा
self
शामिल होता है, ताकि संबंधित प्रोग्राम एलिमेंट.
वैल्यू
फ़ॉर्मूला का आकलन करते समय, वे इस तरह की वैल्यू के साथ काम करते हैं:
1) Value
(असल वैल्यू, जैसे कि dense<[[1, 2], [3, 4]]> : tensor<2x2xi32>
;
उन्हें हमेशा यह पता होता है कि उनका टाइप क्या है),
2) Placeholder
(आने वाले समय की वैल्यू, जैसे कि lhs
, rhs
या result
; उनकी असल वैल्यू
फ़िलहाल, वैल्यू के बारे में कोई जानकारी नहीं है. सिर्फ़ उनके टाइप के बारे में पता है),
3) Type
(टाइप" सेक्शन में बताए गए टाइप),
4) Function
(ग्लोबल फ़ंक्शन, जैसा कि "फ़ंक्शन" सेक्शन में बताया गया है).
कॉन्टेक्स्ट के आधार पर, नाम अलग-अलग वैल्यू की जानकारी दे सकते हैं. ज़्यादा देखें
खास तौर पर, "सेमैंटिक्स" ऑपरेशन के लिए सेक्शन (और अन्य प्रोग्राम के लिए इसी तरह का कोई सेक्शन
एलिमेंट) रनटाइम लॉजिक के बारे में बताता है, इसलिए सभी इनपुट Value
के तौर पर उपलब्ध होते हैं.
इसके उलट, "कंस्ट्रेंट" ops (और समकक्ष) के लिए अनुभाग
"कंपाइल-टाइम" लॉजिक, यानी कुछ ऐसा जिसे आम तौर पर रनटाइम से पहले लागू किया जाता है,
Value
की तरह कॉन्सटैंट इनपुट उपलब्ध होते हैं. साथ ही, अन्य इनपुट उपलब्ध होते हैं
सिर्फ़ Placeholder
के तौर पर उपलब्ध है.
नाम | "Semantics" में | "कंस्ट्रेंट" में |
---|---|---|
ग्लोबल फ़ंक्शन | Function |
Function |
कॉन्सटेंट इनपुट | Value |
Value |
नॉन-कॉन्सटेंट इनपुट | Value |
Placeholder |
आउटपुट | Value |
Placeholder |
स्थानीय परिभाषाएं | यह परिभाषा पर निर्भर करता है | यह परिभाषा पर निर्भर करता है |
आइए, एक उदाहरण transpose
कार्रवाई पर गौर करें:
%result = "stablehlo.transpose"(%operand) {
permutation = dense<[2, 1, 0]> : tensor<3xi64>
} : (tensor<2x3x2xi32>) -> tensor<2x3x2xi32>
इस ऑपरेशन के लिए, permutation
कॉन्स्टेंट है. इसलिए, यह Value
के तौर पर उपलब्ध होता है
दोनों में देखा जा सकता है. इसके उलट, operand
और result
सिमैंटिक में Value
के तौर पर उपलब्ध है, लेकिन कंस्ट्रेंट में सिर्फ़ Placeholder
के तौर पर उपलब्ध है.
फ़ंक्शन
अलग-अलग तरह के एलिमेंट बनाना
टाइप बनाने के लिए, ऐसा कोई फ़ंक्शन नहीं है. इसके बजाय, हम सीधे
टाइप सिंटैक्स का इस्तेमाल करें, क्योंकि आम तौर पर यह ज़्यादा छोटा होता है. उदाहरण के लिए,
function_type(
[tensor_type([], E), tensor_type([], E)], [tensor_type([], E)])
के बजाय (tensor<E>, tensor<E>) -> (tensor<E>)
.
टाइप के फ़ंक्शन
element_type
को टेंसर टाइप और क्वांटाइज़ किए गए टेंसर टाइप के हिसाब से तय किया गया है औरTensorElementType
याQuantizedTensorElementType
के तौर पर रिटर्न करता है का हिस्सा है.TensorType
QuantizedTensorType
def element_type(x: Value | Placeholder | Type):
if type(x) == TensorType:
return tensor_element_type(x)
if type(x) == QuantizedTensorType:
return quantized_tensor_element_type(x)
if type(x) is not Type:
return element_type(type(x))
is_per_axis_quantized(x: Value | Placeholder | Type) -> Value
एक शॉर्टकट हैis_quantized(x) and quantization_dimension(x) is not None
के लिए.is_per_tensor_quantized(x: Value | Placeholder | Type) -> Value
is_quantized(x) and quantization_dimension(x) is None
के लिए शॉर्टकट.is_promotable(x: Type, y: Type) -> bool
यह जांच करता है किx
टाइप का प्रमोशन किया जा सकता है या नहींy
टाइप करने के लिए. जबx
औरy
,QuantizedTensorElementType
होते हैं, तो प्रमोशन सिर्फ़storage_type
पर लागू होता है. प्रमोशन का यह खास वर्शन वर्तमान में न्यूनीकरण अभिकलन के संदर्भ में उपयोग किया जाता है ( RFC देखें).
def is_promotable(x: Type, y: Type) -> Value:
is_same_type = (is_bool(x) and is_bool(y)) or
(is_integer(x) and is_integer(y)) or (is_float(x) and is_float(y)) or
(is_complex(x) and is_complex(y)) or
(is_quantized(x) and is_quantized(y) and expressed_type(x) = expressed_type(y))
if is_same_type == False:
return False
if is_integer(x) or is_float(x):
return bitwidth(x) <= bitwidth(y)
if is_complex(x):
return bitwidth(element_type(x)) <= bitwidth(element_type(y))
if is_quantized(x):
return bitwidth(storage_type(x)) <= bitwidth(storage_type(y))
return false
is_quantized(x: Value | Placeholder | Type) -> Value
इनका शॉर्टकट है:is_quantized_tensor_element_type(x)
.is_type_name(x: Value | Placeholder | Type) -> Value
. सभी के लिए उपलब्ध प्रकार. उदाहरण के लिए, अगरx
एकFloatType
है, तोis_float(x)
true
वैल्यू दिखाता है. अगरx
कोई वैल्यू या प्लेसहोल्डर है, तो यह फ़ंक्शन इनके लिए शॉर्टकट के तौर पर काम करता हैis_type_name(type(x))
.max_value(x: Type) -> Value
किसीTensorElementType
. अगरx
,TensorElementType
नहीं है, तोNone
दिखाता है.min_value(x: Type) -> Value
सबसे कम संभावित वैल्यू दिखाता हैTensorElementType
. अगरx
,TensorElementType
नहीं है, तोNone
दिखाता है.member_name(x: Value | Placeholder | Type) -> Any
. सभी सदस्यों के लिए उपलब्ध सभी तरह कीmember_name
परिभाषाएं. उदाहरण के लिए,tensor_element_type(x)
इससे जुड़ेTensorType
काTensorElementType
वाला हिस्सा दिखाता है. अगरx
कोई वैल्यू या प्लेसहोल्डर है, तो यह फ़ंक्शन इनके लिए शॉर्टकट के तौर पर काम करता हैmember_name(type(x))
. अगरx
ऐसा टाइप नहीं है जिसका कोई सदस्य सही है, या इस तरह के टाइप की वैल्यू या प्लेसहोल्डर,None
दिखाता है.is_empty_algorithm(*args: Type)
जांचता है कि सभी डॉट एल्गोरिदम फ़ील्ड सेट हैं या नहींNone
तक. यह ज़रूरी है, क्योंकि डॉट एल्गोरिदम को लागू किया गया है डिफ़ॉल्ट व्यवहार है, इसलिए डिफ़ॉल्ट मान बताना गलत होगा.
वैल्यू बनाना
operation_name(*xs: Value | Type) -> Value
. सभी कार्रवाइयों के लिए उपलब्ध. उदाहरण के लिए,add(lhs, rhs)
दो टेंसर वैल्यूlhs
औरrhs
लेता है और इन इनपुट के साथadd
ऑपरेशन के मूल्यांकन का आउटपुट देता है. कुछ कामों के लिए, जैसेbroadcast_in_dim
, उनके आउटपुट टाइप ये हैं "लोड-बेयरिंग", यानी किसी कार्रवाई का मूल्यांकन करने के लिए ज़रूरी है. इस मामले में, फ़ंक्शन इन टाइप को आर्ग्युमेंट के तौर पर लेता है.
वैल्यू पर फ़ंक्शन
Python के सभी ऑपरेटर और फ़ंक्शन उपलब्ध हैं. उदाहरण के लिए, दोनों सदस्यता और स्लाइसिंग Python के नोटेशन, टेंसर और क्वांटाइज़ किए गए टेंसर में इंडेक्स करने के लिए उपलब्ध हैं और ट्यूपल्स.
to_destination_type(x: Value, destination_type: Type) -> Value
के बारे में जानकारी दी गई है टेंसर औरtype(x)
के आधार परx
का रूपांतरित मान देता है औरdestination_type
इस तरह से पाएं:
def to_destination_type(x: Value, destination_type: Ty