StableHLO คือชุดการดำเนินการสำหรับการดำเนินการระดับสูง (HLO) ในโมเดลแมชชีนเลิร์นนิง (ML) StableHLO ทำงานเป็นเลเยอร์การถ่ายโอนได้ระหว่างเฟรมเวิร์ก ML กับคอมไพเลอร์ ML เฟรมเวิร์ก ML ที่สร้างโปรแกรม StableHLO ใช้ได้กับคอมไพเลอร์ ML ที่ใช้โปรแกรม StableHLO
เป้าหมายของเราคือการลดความซับซ้อนและเร่งการพัฒนา ML ด้วยการสร้างความสามารถในการทำงานร่วมกันระหว่างเฟรมเวิร์ก ML ที่หลากหลาย (เช่น TensorFlow, JAX และ PyTorch) และคอมไพเลอร์ ML (เช่น XLA และ IREE) ในส่วนดังกล่าว เอกสารนี้จะระบุข้อกำหนดสำหรับภาษาโปรแกรมของ StableHLO
ข้อกำหนดนี้ประกอบด้วยส่วนหลัก 3 ส่วน ประการแรก ส่วนโปรแกรมจะอธิบายโครงสร้างของโปรแกรม StableHLO ซึ่งประกอบด้วยฟังก์ชัน StableHLO ที่ประกอบด้วย Ops ของ StableHLO ภายในโครงสร้างนั้น ส่วน Ops จะระบุความหมายของการดำเนินการแต่ละรายการ ส่วนการดำเนินการจะให้ข้อมูลความหมายสำหรับการดำเนินการทั้งหมดเหล่านี้ที่ดำเนินการร่วมกันภายในโปรแกรม สุดท้าย ส่วนหมายเหตุจะพูดถึงสัญกรณ์ที่ใช้ตลอดทั้งข้อกำหนด
โปรแกรม
Program ::= {Func}
โปรแกรม StableHLO ประกอบด้วยฟังก์ชัน StableHLO กี่ฟังก์ชันก็ได้
ด้านล่างนี้เป็นโปรแกรมตัวอย่างที่มีฟังก์ชัน @main
ซึ่งมีอินพุต 3 รายการ (%image
, %weights
และ %bias
) และเอาต์พุต 1 รายการ ส่วนเนื้อหาของฟังก์ชัน
มี 6 Ops
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}
ฟังก์ชัน SttableHLO (หรือที่เรียกว่าฟังก์ชันที่มีชื่อ) มีตัวระบุ อินพุต/เอาต์พุต และเนื้อหา ในอนาคต เราวางแผนที่จะเปิดตัวข้อมูลเมตาเพิ่มเติมสำหรับฟังก์ชันต่างๆ เพื่อให้เข้ากันได้กับ HLO (#425, #626, #740, #744) ได้ดียิ่งขึ้น
ตัวระบุ
FuncId ::= '@' letter {letter | digit}
ValueId ::= '%' digit {digit}
| '%' letter {letter | digit}
letter ::= 'a' | ... | 'z' | 'A' | ... | 'Z' | '_'
digit ::= '0' | ... | '9'
ตัวระบุ StableHLO คล้ายกับตัวระบุในภาษาโปรแกรมต่างๆ โดยมีลักษณะเฉพาะ 2 ประการ ได้แก่ 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}
ประเภท Tensor แสดงถึง tensors ซึ่งก็คืออาร์เรย์หลายมิติ ซึ่งประกอบด้วยรูปร่างและประเภทองค์ประกอบ โดยที่รูปร่างแสดงถึงขนาดที่ไม่เป็นลบ โดยเรียงตามลำดับจากน้อยไปมากของมิติข้อมูลที่เกี่ยวข้อง (หรือที่เรียกว่าแกน) โดยมีตัวเลขตั้งแต่ 0
ถึง R-1
จำนวนของมิติข้อมูลR
เรียกว่าอันดับ ตัวอย่างเช่น tensor<2x3xf32>
เป็นประเภท Tensor ที่มีรูปร่าง 2x3
และประเภทองค์ประกอบ f32
ซึ่งประกอบด้วย 2 มิติ (หรือ 2 แกน) ได้แก่ มิติที่ 0 และมิติข้อมูลที่ 1 ซึ่งมีขนาด 2 และ 3 อันดับที่ 2
แอตทริบิวต์นี้ระบุการรองรับรูปร่างคงที่ในตำแหน่งที่ขนาดของมิติข้อมูลเป็นที่รู้จักแบบคงที่ ในอนาคต เราวางแผนที่จะเพิ่มการรองรับรูปร่างแบบไดนามิกที่ไม่ทราบขนาดของมิติข้อมูลบางส่วนหรือทั้งหมด (#8) นอกจากนี้ เรายังมีแผนที่จะสำรวจการขยายประเภท tensor นอกเหนือจากขนาดมิติข้อมูลและประเภทองค์ประกอบ ยกตัวอย่างเช่น เพื่อรวมเลย์เอาต์ (#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-C4) (C9) |
storage_min |
ค่าคงที่จำนวนเต็ม | (C2), (C4), (C8) |
storage_max |
ค่าคงที่จำนวนเต็ม | (C3), (C4), (C8) |
expressed_type |
ประเภทจุดลอยตัว | (C1), (C5) |
quantization_dimension |
ค่าคงที่จำนวนเต็มที่ไม่บังคับ | (C11-C13) |
scales |
จำนวนตัวแปรของค่าคงที่จุดลอยตัว | (C5-C7), (C10), (C11), (C13) |
zero_points |
จำนวนคงที่จำนวนเต็มสำหรับตัวแปร | (C8-C10) |
ประเภทองค์ประกอบที่เล็กลงแสดงค่าที่เป็นจำนวนเต็มของประเภทพื้นที่เก็บข้อมูลในช่วงตั้งแต่ 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)
num_bits(storage_type) < num_bits(expressed_type)
- (C2)
type(storage_min) = storage_type
- (C3)
type(storage_max) = storage_type
- (C4)
min_value(storage_type) <= storage_min < storage_max <= max_value(storage_type)
- (C5)
type(scales...) = expressed_type
- (C6)
0 < scales
- (C7)
is_finite(scales...)
- (C8)
storage_min <= zero_points <= storage_max
- (C9)
type(zero_points...) = storage_type
- (C10)
size(scales) = size(zero_points)
- (C11) หากเป็น
is_empty(quantization_dimension)
ให้size(scales) = 1
- (C12)
0 <= quantization_dimension
ตอนนี้ QuantizationScale
เป็นค่าคงที่ของจุดลอยตัว แต่มีความสนใจอย่างมากในสเกลที่อิงตามจำนวนเต็มซึ่งแสดงตัวคูณและ Shift เรามีแผนที่จะสำรวจสิ่งนี้ในอนาคตอันใกล้
(#1404)
เรายังมีการพูดคุยเรื่องความหมายของ QuantizationZeroPoint
อยู่อย่างต่อเนื่อง ซึ่งรวมถึงประเภท ค่า และขึ้นอยู่กับว่าในประเภท tensor เชิงปริมาณมีจุด 1 จุดหรือหลายจุดหรือไม่ จากผลการพูดคุยครั้งนี้ ข้อกำหนดเกี่ยวกับคะแนน 0 อาจมีการเปลี่ยนแปลงในอนาคต (#1405)
การพูดคุยที่ดำเนินอยู่อีกรายการเกี่ยวข้องกับความหมายของ QuantizationStorageMin
และ QuantizationStorageMax
เพื่อระบุว่าควรกำหนดข้อจำกัดใดกับค่าเหล่านี้และสำหรับค่าของ tensors เชิงปริมาณ (#1406)
สุดท้ายนี้ เราวางแผนที่จะสำรวจโดยใช้ค่าจากขนาดที่ไม่รู้จักและจุด 0 จุด ซึ่งคล้ายกับที่เราวางแผนจะหาค่าแทนขนาดมิติข้อมูลที่ไม่รู้จัก (#1407)
ประเภท tensor ที่เล็กลงแสดง tensors ที่มีองค์ประกอบที่เล็กลง Tensor เหล่านี้เหมือนกับ Tensor ปกติทุกประการ ยกเว้นว่าองค์ประกอบมีประเภทองค์ประกอบในเชิงปริมาณ ไม่ใช่ประเภทองค์ประกอบปกติ
ใน tensor ที่วัดปริมาณได้ การหาปริมาณอาจเท่ากับ per-tensor ซึ่งหมายความว่ามี scale
1 ค่าและ zero_point
สำหรับ tensor ทั้งหมด หรืออาจเป็นต่อแกนก็ได้ ซึ่งหมายความว่ามี scales
และ zero_points
หลายรายการ 1 คู่ต่อสไลซ์ของมิติข้อมูลหนึ่งๆ quantization_dimension
อย่างเป็นทางการใน tensor t
ที่มีการคำนวณเชิงปริมาณตามแกนจะมี dim(t, quantization_dimension)
ส่วนของ quantization_dimension
: t[:, ..., 0, ..., :], t[:, ..., 1, ..., :]
ฯลฯ องค์ประกอบทั้งหมดใน i
ส่วนจะใช้ scales[i]
และ zero_points[i]
เป็นพารามิเตอร์การหาปริมาณ ประเภท tensor ที่แบ่งทศนิยมมีข้อจํากัดดังต่อไปนี้
- สําหรับการกําหนดจํานวนตาม tensor
- ไม่มีข้อจำกัดเพิ่มเติม
- สําหรับการหาปริมาณตามแกน:
- (C12)
quantization_dimension < rank(self)
- (C13)
dim(self, quantization_dimension) = size(scales)
- (C12)
TokenType ::= 'token'
ประเภทโทเค็นแสดงถึงโทเค็น ซึ่งก็คือค่าทึบแสงที่ผลิตและใช้โดยการดําเนินการบางอย่าง โทเค็นใช้สำหรับกำหนดคำสั่งปฏิบัติการของการดำเนินการตามที่อธิบายไว้ในส่วนการดำเนินการ
TupleType ::= 'tuple' '<' TupleElementTypes '>'
TupleElementTypes ::= [ValueType {',' ValueType}]
ประเภท Tuple คือ tuple ในรายการที่แตกต่างกัน Tuple เป็นฟีเจอร์เดิมที่จะใช้ได้เฉพาะกับ HLO เท่านั้น ใน HLO จะใช้ Tuples
เพื่อแสดงถึงอินพุตและเอาต์พุตจากตัวแปร ใน StableHLO ระบบจะรองรับอินพุตและเอาต์พุตแบบแปรผันโดยค่าเริ่มต้น และการใช้ tuples เพียงอย่างเดียวใน StableHLO ก็คือการแสดง HLO ABI อย่างครอบคลุม เช่น T
, tuple<T>
และ tuple<tuple<T>>
อาจแตกต่างกันไปตามการใช้งานจริง เราวางแผนที่จะทําการเปลี่ยนแปลง HLO ABI ในอนาคตซึ่งอาจนําประเภท tuple ออกจาก StableHLO (#598)
TensorElementType ::= BooleanType | IntegerType | FloatType | ComplexType
BooleanType ::= 'i1'
IntegerType ::= SignedIntegerType | UnsignedIntegerType
SignedIntegerType ::= 'si4' | 'si8' | 'si16' | 'si32' | 'si64'
UnsignedIntegerType ::= 'ui4' | 'ui8' | 'ui16' | 'ui32' | 'ui64'
FloatType ::= 'f8E4M3FN' | 'f8E5M2' | 'f8E4M3FNUZ' | 'f8E5M2FNUZ'
| 'f8E4M3B11FNUZ' | 'bf16' | 'f16' | 'f32' | 'f64'
ComplexType ::= 'complex' '<' ComplexElementType '>'
ComplexElementType ::= 'f32' | 'f64'
ประเภทองค์ประกอบแสดงถึงองค์ประกอบของประเภท Tensor ประเภทเหล่านี้ไม่ใช่คลาสแรกใน StableHLO ซึ่งต่างจากภาษาโปรแกรมหลายๆ ภาษา ซึ่งหมายความว่าโปรแกรม StableHLO จะแสดงค่าประเภทเหล่านี้โดยตรงไม่ได้ (ดังนั้น ระบบจึงแสดงค่าสเกลาร์ของประเภท T
ที่มีค่า tensor แบบ 0 มิติของประเภท tensor<T>
)
- ประเภทบูลีน แสดงค่าบูลีน
true
และfalse
- ประเภทจำนวนเต็มอาจมีเครื่องหมาย (
si
) หรือไม่มีเครื่องหมาย (ui
) และมี ความกว้างบิตที่รองรับอย่างใดอย่างหนึ่ง (4
,8
,16
,32
หรือ64
) ประเภทsiN
ที่ลงนามจะแสดงค่าจำนวนเต็มตั้งแต่-2^(N-1)
ถึง2^(N-1)-1
โดยรวม ประเภทuiN
ที่ไม่มีเครื่องหมายจะแสดงค่าจำนวนเต็มตั้งแต่0
ถึง2^N-1
- ประเภทจุดทศนิยมอาจเป็นประเภทใดประเภทหนึ่งต่อไปนี้
- ประเภท
f8E4M3FN
และf8E5M2
ที่สอดคล้องกับการเข้ารหัสE4M3
และE5M2
ของรูปแบบ FP8 ตามลำดับที่อธิบายไว้ในรูปแบบ FP8 สำหรับการเรียนรู้เชิงลึก - ประเภท
f8E4M3FNUZ
และf8E5M2FNUZ
ที่สอดคล้องกับการเข้ารหัสE4M3
และE5M2
ของรูปแบบ FP8 ซึ่งอธิบายไว้ในรูปแบบตัวเลข 8 บิตสำหรับโครงข่ายประสาทส่วนลึก f8E4M3B11FNUZ
ประเภทที่สอดคล้องกับการเข้ารหัสE4M3
ของรูปแบบ FP8 ตามที่อธิบายไว้ในการฝึกและการอนุมานสำหรับโครงข่ายประสาทส่วนลึก (HFP8) แบบ 8 บิตแบบผสม- ประเภท
bf16
ที่สอดคล้องกับรูปแบบbfloat16
ที่อธิบายไว้ใน BFloat16: เคล็ดลับสู่ประสิทธิภาพสูงบน Cloud TPU - ประเภท
f16
,f32
และf64
ที่สอดคล้องกับรูปแบบbinary16
("ความแม่นยําครึ่งหนึ่ง"),binary32
("ความแม่นยําเดี่ยว") และbinary64
("ความแม่นยําแบบทวีคูณ") ตามลำดับที่อธิบายไว้ใน มาตรฐาน IEEE 754
- ประเภท
- ประเภทที่ซับซ้อนแสดงถึงค่าเชิงซ้อนที่มีส่วนจริงและส่วนจินตภาพเป็นประเภทองค์ประกอบเดียวกัน ประเภทที่ซับซ้อนที่รองรับคือ
complex<f32>
(ทั้ง 2 ส่วนเป็นประเภทf32
) และcomplex<f64>
(ทั้ง 2 ส่วนเป็นประเภทf64
)
FunctionType ::= '(' InputTypes ')' '->' '(' OutputTypes ')'
InputTypes ::= [ValueType {',' ValueType}]
OutputTypes ::= [ValueType {',' ValueType}]
ประเภทฟังก์ชันจะแสดงทั้งฟังก์ชันที่มีชื่อและไม่ระบุตัวตน โดยมีประเภทอินพุต (รายการประเภททางด้านซ้ายของ ->
) และประเภทเอาต์พุต (รายการประเภททางด้านขวามือของ ->
) สำหรับภาษาโปรแกรมหลายๆ ภาษา ประเภทฟังก์ชันจะเป็นคลาสแรก แต่ไม่อยู่ใน StableHLO
StringType ::= 'string'
ประเภทสตริงแสดงลำดับของไบต์ ประเภทสตริงไม่ใช่คลาสแรกใน StableHLO ซึ่งต่างจากภาษาโปรแกรมหลายๆ ภาษา ซึ่งใช้เพื่อระบุข้อมูลเมตาแบบคงที่สำหรับองค์ประกอบของโปรแกรมเท่านั้น
การทำงาน
การดำเนินการของ SttableHLO (หรือที่เรียกว่า ops) แสดงถึงชุดการดำเนินการระดับสูงแบบปิดในโมเดลแมชชีนเลิร์นนิง ดังที่กล่าวไว้ข้างต้น ไวยากรณ์ StableHLO ได้รับแรงบันดาลใจอย่างมากจาก MLIR ซึ่งไม่จำเป็นต้องเป็นทางเลือกที่เหมาะกับสรีรศาสตร์มากที่สุด แต่เห็นได้ชัดว่าเหมาะสมที่สุดสำหรับเป้าหมาย StableHLO ในการสร้างความสามารถในการทำงานร่วมกันระหว่างเฟรมเวิร์ก ML และคอมไพเลอร์ ML
Op ::= [OpOutputs] OpName OpInputs ':' OpSignature
OpName ::= '"' 'stablehlo' '.' OpMnemonic '"'
OpMnemonic ::= 'abs' | 'add' | ...
การดำเนินการของ SttableHLO (หรือที่เรียกว่า ops) จะมีชื่อ อินพุต/เอาต์พุต และลายเซ็น ชื่อมีคำนำหน้า stablehlo.
และช่วยจำซึ่งระบุการดำเนินการที่รองรับโดยไม่ซ้ำกัน ดูรายการที่ครอบคลุมของการดำเนินการทั้งหมดที่รองรับด้านล่าง
ในขณะนี้ โปรแกรม StableHLO ในระบบทรัพยากรธรรมชาติมีการดำเนินการที่ไม่ได้อธิบายไว้ในเอกสารนี้ ในอนาคต เราวางแผนที่จะดูดกลืนการดำเนินการเหล่านี้ลงในตัวเลือกของ StableHLO หรือห้ามไม่ให้การดำเนินการเหล่านี้ปรากฏในโปรแกรม StableHLO ในระหว่างนี้ โปรดดูรายการการดำเนินงานต่อไปนี้
builtin.module
,func.func
,func.call
และfunc.return
(#425)chlo
การดำเนินการ (#602)- หมวดหมู่ "ไม่อยู่ใน HLO" ของการดำเนินการของ StableHLO ซึ่งตอนแรกเป็นส่วนหนึ่งของ
ตัวเลือกของ StableHLO แต่ภายหลังได้รับการพิจารณาว่าไม่เหมาะกับการใช้งาน:
broadcast
,create_token
,cross-replica-sum
,dot
,einsum
,torch_index_select
,unary_einsum
(#3) - หมวดหมู่ "Dynamism" ของปฏิบัติการ StableHLO ถูกลงทุนจาก
MHLO แต่เรายังไม่กำหนด:
compute_reshape_shape
,cstr_reshapable
,dynamic_broadcast_in_dim
,dynamic_conv
,dynamic_gather
,dynamic_iota
,dynamic_pad
,dynamic_reshape
,real_dynamic_slice
,set_dimension_size
(#8) - การคำนวณรูปร่าง รวมถึงการดำเนินการ
arith
,shape
และtensor
(#8)
OpInputs ::= OpInputValues OpInputFuncs OpInputAttrs
OpInputValues ::= '(' [OpInputValue {',' OpInputValue}] ')'
OpInputValue ::= ValueId
OpInputFuncs ::= ['(' OpInputFunc {',' OpInputFunc} ')']
OpInputAttrs ::= ['{' OpInputAttr {',' OpInputAttr} '}']
OpOutputs ::= [OpOutput {',' OpOutput} '=']
OpOutput ::= ValueId
การดำเนินการจะใช้อินพุตและสร้างเอาต์พุต อินพุตจะได้รับการจัดหมวดหมู่เป็นค่าอินพุต (คํานวณระหว่างการดําเนินการ) ฟังก์ชันอินพุต (มีแบบคงที่เนื่องจากในฟังก์ชัน StableHLO ไม่ใช่ค่าระดับเฟิร์ส) และแอตทริบิวต์อินพุต (ระบุแบบคงที่) ชนิดของอินพุตและเอาต์พุตที่ใช้และผลิตโดยการทดสอบจะขึ้นอยู่กับการช่วยจำ เช่น add
op ใช้ค่าอินพุต 2 ค่าและสร้างค่าเอาต์พุต 1 ค่า เมื่อเปรียบเทียบกันแล้ว การดำเนินการ select_and_scatter
จะใช้ค่าอินพุต 3 ค่า ฟังก์ชันอินพุต 2 ฟังก์ชัน และแอตทริบิวต์อินพุต 3 รายการ
OpInputFunc ::= '{' Unused FuncInputs ':' FuncBody '}'
Unused ::= '^' digit {digit}
| '^' letter {letter | digit}
ฟังก์ชันอินพุต (หรือเรียกว่าฟังก์ชันที่ไม่ระบุตัวตน) คล้ายกับฟังก์ชันที่มีชื่ออย่างมาก ยกเว้นว่า 1) ไม่มีตัวระบุ (จึงชื่อ "ไม่ระบุชื่อ") 2) ไม่ประกาศประเภทเอาต์พุต (ประเภทเอาต์พุตจะอนุมานจาก op return
ภายในฟังก์ชัน)
ไวยากรณ์สำหรับฟังก์ชันอินพุตประกอบด้วยส่วนที่ไม่มีการใช้งานในปัจจุบัน (ดูเวอร์ชันที่ใช้งานจริงของ Unused
ด้านบน) ซึ่งมีไว้สำหรับ MLIR ใน MLIR มีแนวคิดกว้างๆ เกี่ยวกับ "ภูมิภาค" ซึ่งอาจมี "การบล็อก" ของ Ops หลาย "บล็อก" ที่เชื่อมต่อเข้าด้วยกันผ่านการข้าม บล็อกเหล่านี้มีรหัสที่สอดคล้องกับเวอร์ชันที่ใช้งานจริงของ Unused
จึงแยกความแตกต่างจากกันได้
StableHLO ไม่มีการข้ามการดำเนินการ ดังนั้นจึงไม่มีการใช้ส่วนที่เกี่ยวข้องของไวยากรณ์ MLIR (แต่ยังคงอยู่)
OpInputAttr ::= OpInputAttrName '=' OpInputAttrValue
OpInputAttrName ::= letter {letter | digit}
OpInputAttrValue ::= Constant
แอตทริบิวต์อินพุตมีชื่อและค่าซึ่งเป็นหนึ่งในค่าคงที่ที่รองรับ ซึ่งเป็นวิธีหลักในการระบุข้อมูลเมตาแบบคงที่สำหรับองค์ประกอบของโปรแกรม ตัวอย่างเช่น concatenate
op ใช้แอตทริบิวต์ dimension
เพื่อระบุมิติข้อมูลที่จะใช้ค่าอินพุตต่อกัน ในทำนองเดียวกัน slice
op จะใช้แอตทริบิวต์หลายรายการ เช่น 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}] ')'
ลายเซ็น Op ประกอบด้วยประเภทของค่าอินพุตทั้งหมด (รายการประเภททางด้านซ้ายของ ->
) และประเภทค่าเอาต์พุตทั้งหมด (รายการประเภททางด้านขวามือของ ->
) กล่าวโดยละเอียดคือประเภทอินพุตมีความซ้ำซ้อนและประเภทเอาต์พุตเกือบตลอดเวลาเช่นกัน (เนื่องจากการทำงานของ StableHLO ส่วนใหญ่อาจมีการอนุมานประเภทเอาต์พุตจากอินพุต) อย่างไรก็ตาม สัญลักษณ์ op
เป็นส่วนหนึ่งของไวยากรณ์ StableHLO โดยเฉพาะเพื่อให้เข้ากันได้กับ MLIR
ด้านล่างคือตัวอย่างการทดสอบที่มีฟังก์ชันช่วยจำคือ select_and_scatter
โดยใช้ค่าอินพุต 3 รายการ (%operand
, %source
และ %init_value
), ฟังก์ชันอินพุต 2 รายการ
และแอตทริบิวต์อินพุต 3 รายการ (window_dimensions
, window_strides
และ padding
)
โปรดทราบว่าลายเซ็นของ op มีเฉพาะประเภทของค่าอินพุตเท่านั้น (แต่ไม่รวมประเภทของฟังก์ชันและแอตทริบิวต์ที่ป้อนในหน้า)
%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
ค่าคงที่เชิงซ้อนแสดงค่าเชิงซ้อนโดยใช้รายการของส่วนจริง
(มาก่อน) และส่วนจินตภาพ (เกิดเป็นลำดับที่ 2) ตัวอย่างเช่น (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
ค่าคงที่ Tensor แสดงถึงค่า tensor โดยใช้รายการแบบซ้อนที่ระบุผ่านรูปแบบ NumPy ตัวอย่างเช่น dense<[[1, 2, 3], [4, 5, 6]]> : tensor<2x3xi32>
แสดงค่า tensor ที่มีการแมปต่อไปนี้จากดัชนีถึงองค์ประกอบ {0, 0} => 1
, {0, 1} => 2
, {0, 2} => 3
, {1, 0} => 4
, {1, 1} => 5
, {1, 2} => 6
ลำดับที่เก็บองค์ประกอบเหล่านี้ไว้ในหน่วยความจำจะได้รับการกำหนดการใช้งาน ค่าคงที่ของ Tensor มีข้อจำกัดต่อไปนี้
- (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) '>'
ค่าคงที่ tensor ที่เล็กลงแสดงค่า tensor เชิงปริมาณโดยใช้เครื่องหมายเดียวกับค่าคงที่ tensor ที่มีองค์ประกอบที่ระบุเป็นค่าคงที่ของประเภทพื้นที่เก็บข้อมูล ค่าคงที่ tensor ที่หาค่าเป็นตัวเลขมีข้อจำกัดต่อไปนี้
- (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
การดำเนินการ
abs
อรรถศาสตร์
ดำเนินการ abs ตามองค์ประกอบบน tensor ใน operand
และสร้าง tensor result
ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับจำนวนเต็มแบบมีเครื่องหมาย: จำนวนเต็มโมดูลัส
- สำหรับเลขทศนิยม:
abs
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: โมดูลัสเชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(abs, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
Tensor ของจำนวนเต็มแบบมีเครื่องหมาย ประเภทจุดลอยตัว หรือประเภทเชิงซ้อน หรือ tensor ที่เล็กลงแบบต่อ tensor | (C1-C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของจำนวนเต็มแบบมีเครื่องหมายหรือประเภทจุดลอยตัวหรือ tensor ที่เล็กลงแบบต่อ tensor | (C1-C2) |
ข้อจำกัด
- (C1)
shape(result) = shape(operand)
- (C2)
baseline_element_type(result)
ให้คำจำกัดความไว้ดังนี้complex_element_type(element_type(operand))
หากis_complex(operand)
- หากไม่ใช่
baseline_element_type(operand)
ตัวอย่าง
// %operand: [-2, 0, 2]
%result = "stablehlo.abs"(%operand) : (tensor<3xi32>) -> tensor<3xi32>
// %result: [2, 0, 2]
เพิ่ม
อรรถศาสตร์
เพิ่ม Tensor จำนวน 2 รายการ ได้แก่ lhs
และ rhs
ตามองค์ประกอบ แล้วสร้าง result
Tensor ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับบูลีน: logical OR
- สำหรับจำนวนเต็ม: การเพิ่มจำนวนเต็ม
- สำหรับเลขทศนิยม:
addition
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: การบวกเชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(add, lhs, rhs, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | lhs |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
(I2) | rhs |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
ข้อจำกัด
- (C1)
baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)
ตัวอย่าง
// %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
การดำเนินการของการดำเนินการนี้จะไม่มีผลใดๆ จะมีเพียงการสร้างทรัพยากร Dependency จาก result
ไปยัง inputs
เท่านั้น
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท |
---|---|---|
(1) | 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 จะเชื่อมโยงค่าของ Tensor operand
จากแต่ละกระบวนการตาม all_gather_dim
แล้วสร้าง Tensor 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
:
operands@receiver = [operand@sender for sender in process_group]
สำหรับreceiver
ทั้งหมดในprocess_group
result@process = concatenate(operands@process, all_gather_dim)
สำหรับprocess
ทั้งหมดในprocess_group
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1), (C6) |
(I2) | all_gather_dim |
ค่าคงที่ของประเภท si64 |
(C1), (C6) |
(1) | replica_groups |
ค่าคงที่ tensor 2 มิติของประเภท si64 |
(C2-C4) |
(I4) | channel_id |
ค่าคงที่ของประเภท si64 |
(C5) |
(1) | use_global_device_ids |
ค่าคงที่ของประเภท i1 |
(C5) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C6) |
ข้อจำกัด
- (C1)
0 <= all_gather_dim < rank(operand)
- (C2)
is_unique(replica_groups)
- (C3)
size(replica_groups)
ให้คำจำกัดความไว้ดังนี้num_replicas
หากใช้cross_replica
num_replicas
หากใช้cross_replica_and_partition
num_processes
หากใช้flattened_ids
- (C4)
0 <= replica_groups < size(replica_groups)
- (C5) หากเป็น
use_global_device_ids = true
ให้จ่ายchannel_id > 0
- (C6)
type(result) = type(operand)
ยกเว้นสิ่งต่อไปนี้dim(result, all_gather_dim) = dim(operand, all_gather_dim) * dim(process_groups, 1)
.
ตัวอย่าง
// num_replicas: 2
// num_partitions: 1
// %operand@(0, 0): [[1, 2], [3, 4]]
// %operand@(1, 0): [[5, 6], [7, 8]]
%result = "stablehlo.all_gather"(%operand) {
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<2x4xi64>
// %result@(0, 0): [[1, 2, 5, 6], [3, 4, 7, 8]]
// %result@(1, 0): [[1, 2, 5, 6], [3, 4, 7, 8]]
all_reduce
อรรถศาสตร์
ภายในแต่ละกลุ่มกระบวนการในตารางกระบวนการของ StableHLO ให้ใช้ฟังก์ชันการลด computation
กับค่าของ operand
Tensor จากแต่ละกระบวนการและสร้าง Tensor 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
:
result@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]))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C5) (C6) |
(I2) | replica_groups |
จำนวนแปรผันของค่าคงที่ tensor 1 มิติของประเภท si64 |
(C1-C3) |
(1) | channel_id |
ค่าคงที่ของประเภท si64 |
(C4) |
(I4) | use_global_device_ids |
ค่าคงที่ของประเภท i1 |
(C4) |
(1) | computation |
ฟังก์ชัน | (C5) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C6-C7) |
ข้อจำกัด
- (C1)
is_unique(replica_groups)
- (C2)
size(replica_groups)
ให้คำจำกัดความไว้ดังนี้num_replicas
หากใช้cross_replica
num_replicas
หากใช้cross_replica_and_partition
num_processes
หากใช้flattened_ids
- (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(result) = shape(operand)
- (C7)
element_type(result) = E
ตัวอย่าง
// num_replicas: 2
// num_partitions: 1
// %operand@(0, 0): [1, 2, 3, 4]
// %operand@(1, 0): [5, 6, 7, 8]
%result = "stablehlo.all_reduce"(%operand) ({
^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_handle = #stablehlo.channel_handle<handle = 0, type = 0>
} : (tensor<i64>) -> tensor<i64>
// %result@(0, 0): [6, 8, 10, 12]
// %result@(1, 0): [6, 8, 10, 12]
all_to_all
อรรถศาสตร์
ภายในแต่ละกลุ่มกระบวนการในตารางกระบวนการของ StableHLO จะแบ่งค่า Tensor operand
ตาม split_dimension
ออกเป็นส่วนต่างๆ กระจายส่วนที่แยกระหว่างกระบวนการ เชื่อมต่อส่วนที่กระจัดกระจายไปตาม concat_dimension
และสร้าง result
Tensor
การดำเนินการจะแยกตารางกริดกระบวนการของ StableHLO เป็น process_groups
ซึ่งมีคำจำกัดความดังนี้
cross_replica(replica_groups)
หากchannel_id <= 0
cross_partition(replica_groups)
หากchannel_id > 0
หลังจากนั้น ภายในแต่ละ process_group
:
split_parts@sender = split(operand@sender, split_count, split_dimension)
สำหรับsender
ทั้งหมดในprocess_group
scattered_parts@receiver = [split_parts@sender[receiver_index] for sender in process_group]
โดยที่receiver_index = process_group.index(receiver)
result@process = concatenate(scattered_parts@process, concat_dimension)
.
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1-C3), (C9) |
(I2) | split_dimension |
ค่าคงที่ของประเภท si64 |
(C1), (C2), (C9) |
(1) | concat_dimension |
ค่าคงที่ของประเภท si64 |
(C3), (C9) |
(I4) | split_count |
ค่าคงที่ของประเภท si64 |
(C2), (C4), (C8), (C9) |
(1) | replica_groups |
ค่าคงที่ tensor 2 มิติของประเภท si64 |
(C5-C8) |
(1) | channel_id |
ค่าคงที่ของประเภท si64 |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C9) |
ข้อจำกัด
- (C1)
0 <= split_dimension < rank(operand)
- (C2)
dim(operand, split_dimension) % split_count = 0
- (C3)
0 <= concat_dimension < rank(operand)
- (C4)
0 < split_count
- (C5)
is_unique(replica_groups)
- (C6)
size(replica_groups)
ให้คำจำกัดความไว้ดังนี้num_replicas
หากใช้cross_replica
num_partitions
หากใช้cross_partition
- (C7)
0 <= replica_groups < size(replica_groups)
- (C8)
dim(replica_groups, 1) = split_count
- (C9)
type(result) = type(operand)
ยกเว้นสิ่งต่อไปนี้dim(result, split_dimension) = dim(operand, split_dimension) / split_count
.dim(result, concat_dimension) = dim(operand, concat_dimension) * split_count
.
ตัวอย่าง
// 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.all_to_all"(%operand) {
split_dimension = 1 : i64,
concat_dimension = 0 : i64,
split_count = 2 : i64,
replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>
} : (tensor<2x4xi64>) -> tensor<4x2xi64>
// %result@(0, 0): [[1, 2],
// [5, 6],
// [9, 10],
// [13, 14]]
// %result@(1, 0): [[3, 4],
// [7, 8],
// [11, 12],
// [15, 16]]
และ
อรรถศาสตร์
ดำเนินการ AND ตามองค์ประกอบตาม tensor จำนวน 2 รายการ lhs
และ rhs
แล้วสร้าง result
tensor ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับบูลีน: ตรรกะ AND
- สำหรับจำนวนเต็ม: บิตไวส์ AND
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | lhs |
Tensor ของประเภทบูลีนหรือจำนวนเต็ม | (C1) |
(I2) | rhs |
Tensor ของประเภทบูลีนหรือจำนวนเต็ม | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor ของประเภทบูลีนหรือจำนวนเต็ม | (C1) |
ข้อจำกัด
- (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
อรรถศาสตร์
ดำเนินการดำเนินการ atan2 ตามองค์ประกอบใน lhs
และ rhs
Tensor และสร้าง Tensor result
ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับเลขทศนิยม:
atan2
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: จำนวนเชิงซ้อน atan2
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(atan2, lhs, rhs, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | lhs |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
(I2) | rhs |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
ข้อจำกัด
- (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
และสร้าง Tensor grad_operand
, grad_scale
และ grad_offset
อย่างเป็นทางการ การดำเนินการนี้อาจแสดงเป็นการแยกย่อยการดำเนินการ StableHLO ที่มีอยู่โดยใช้ไวยากรณ์ Python ดังนี้
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))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor ที่วัดปริมาณแล้ว | (C1-C3), (C5) |
(I2) | scale |
tensor 1 มิติของชนิดจุดลอยตัวหรือต่อ tensor ที่เล็กลง | (C2), (C4), (C5) |
(1) | mean |
tensor 1 มิติของชนิดจุดลอยตัวหรือต่อ tensor ที่เล็กลง | (C2), (C4) |
(I4) | variance |
tensor 1 มิติของชนิดจุดลอยตัวหรือต่อ tensor ที่เล็กลง | (C2), (C4) |
(1) | grad_output |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor ที่วัดปริมาณแล้ว | (C2), (C3) |
(1) | epsilon |
ค่าคงที่ของประเภท f32 |
|
(1) | feature_index |
ค่าคงที่ของประเภท si64 |
(C1), (C5) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
grad_operand |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor ที่วัดปริมาณแล้ว | (C2), (C3) |
grad_scale |
tensor 1 มิติของชนิดจุดลอยตัวหรือต่อ tensor ที่เล็กลง | (C2), (C4) |
grad_offset |
tensor 1 มิติของชนิดจุดลอยตัวหรือต่อ tensor ที่เล็กลง | (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
อรรถศาสตร์
ทำให้ Tensor operand
เป็นมาตรฐานในทุกมิติข้อมูลยกเว้นมิติข้อมูล feature_index
และสร้าง Tensor 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))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor ที่วัดปริมาณแล้ว | (C1-C7) |
(I2) | scale |
tensor 1 มิติของชนิดจุดลอยตัวหรือต่อ tensor ที่เล็กลง | (C2), (C3) |
(1) | offset |
tensor 1 มิติของชนิดจุดลอยตัวหรือต่อ tensor ที่เล็กลง | (C2), (C4) |
(I4) | mean |
tensor 1 มิติของชนิดจุดลอยตัวหรือต่อ tensor ที่เล็กลง | (C5) |
(1) | variance |
tensor 1 มิติของชนิดจุดลอยตัวหรือต่อ tensor ที่เล็กลง | (C2) (C6) |
(1) | epsilon |
ค่าคงที่ของประเภท f32 |
|
(1) | feature_index |
ค่าคงที่ของประเภท si64 |
(C1), (C3-C6) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor ที่วัดปริมาณแล้ว | (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
และปรับ tensor ของ operand
ที่ทำให้เกิด output
, batch_mean
และ batch_var
เป็นมาตรฐาน อย่างเป็นทางการ การดำเนินการนี้อาจแสดงเป็นการแยกย่อยการดำเนินการ StableHLO ที่มีอยู่โดยใช้ไวยากรณ์ Python ดังนี้
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))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor ที่วัดปริมาณแล้ว | (C1) |
(I2) | scale |
tensor 1 มิติของจุดลอยตัวหรือต่อ tensor ที่เล็กลง | (C2), (C3) |
(1) | offset |
tensor 1 มิติของจุดลอยตัวหรือต่อ tensor ที่เล็กลง | (C2), (C4) |
(I4) | epsilon |
ค่าคงที่ของประเภท f32 |
(C1), (C3-C6) |
(1) | feature_index |
ค่าคงที่ของประเภท si64 |
(C1), (C3-C6) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
output |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor ที่วัดปริมาณแล้ว | (C7) |
batch_mean |
tensor 1 มิติของจุดลอยตัวหรือต่อ tensor ที่เล็กลง | (C2), (C5) |
batch_var |
tensor 1 มิติของจุดลอยตัวหรือต่อ tensor ที่เล็กลง | (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
อรรถศาสตร์
ดำเนินการบิตแคสต์บน Tensor operand
และสร้าง result
Tensor ซึ่งมีการตีความบิตของ Tensor ทั้งหมด operand
อีกครั้งโดยใช้ประเภทของ Tensor ของ 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
จะแสดงผลค่าที่กำหนดในหน่วยความจำ และลักษณะการทำงานของค่าดังกล่าวเป็นการกำหนดการติดตั้งใช้งาน เนื่องจากการแสดง tensors ที่แท้จริงนั้นเป็นตัวกำหนดการติดตั้งใช้งาน และการนำเสนอประเภทองค์ประกอบที่แน่นอนนั้นมีการกำหนดการติดตั้งใช้งานด้วยเช่นกัน
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor หรือ tensor ที่วัดปริมาณแล้ว | (C1-C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือ tensor ที่วัดปริมาณแล้ว | (C1-C2) |
ข้อจำกัด
- (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
.dim(result, i) = dim(operand, i)
สำหรับ0 <= i < R
ทั้งหมดdim(result, R) * num_bits(E') = num_bits(E)
.- หาก
num_bits(E') > num_bits(E)
: rank(result) = R - 1
.dim(result, i) = dim(operand, i)
สำหรับ0 <= i < R
ทั้งหมด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
อรรถศาสตร์
ขยายมิติข้อมูลและ/หรืออันดับของ Tensor อินพุตโดยการทำซ้ำข้อมูลใน Tensor operand
และสร้าง Tensor result
เป็นทางการมากขึ้นแล้ว
result[result_index] = operand[operand_index]
สถานที่สำหรับ d
ทั้งหมดใน
axes(operand)
:
operand_index[d] = 0
หากdim(operand, d) = 1
- หากไม่ใช่
operand_index[d] = result_index[broadcast_dimensions[d]]
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor หรือ tensor ที่วัดปริมาณแล้ว | (C1-C2), (C5-C6) |
(I2) | broadcast_dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2-C6) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือ tensor ที่วัดปริมาณแล้ว | (C1), (C3), (C5-C6) |
ข้อจำกัด
- (C1)
element_type(result)
ให้บริการโดยelement_type(operand)
หากเป็น!is_per_axis_quantized(operand)
element_type(operand)
เว้นแต่ว่าquantization_dimension(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) สําหรับ
d
ทั้งหมดในaxes(operand)
ให้ทําดังนี้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]
// ]
// ]
เคส
อรรถศาสตร์
สร้างเอาต์พุตจากการทำงานเพียง 1 ฟังก์ชันจาก branches
โดยขึ้นอยู่กับค่าของ index
อย่างเป็นทางการ result = selected_branch()
ที่
selected_branch = branches[index]
หาก0 <= index < size(branches)
- หากไม่ใช่
selected_branch = branches[-1]
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | index |
Tensor แบบ 0 มิติของประเภท si32 |
|
(I2) | branches |
จำนวนฟังก์ชันต่างๆ | (C1-C4) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวน tensors หลากหลายแบบ, tensors ในเชิงปริมาณ หรือโทเค็น | (C4) |
ข้อจำกัด
- (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]
Cbrt
อรรถศาสตร์
ดำเนินการรากลูกบาศก์ตามองค์ประกอบตามองค์ประกอบใน Tensor operand
และสร้าง Tensor result
ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับเลขทศนิยม:
rootn(x, 3)
จาก IEEE-754 - สําหรับจํานวนเชิงซ้อน: รากจํานวนเชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(cbrt, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
ข้อจำกัด
- (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]
Ceil
อรรถศาสตร์
ดำเนินการ Tensor ตามองค์ประกอบตาม tensor ของ operand
และสร้าง Tensor result
ใช้การดำเนินการ roundToIntegralTowardPositive
จากข้อกำหนด IEEE-754 สำหรับประเภทที่แบ่งปริมาณแล้ว จะแสดงผล dequantize_op_quantize(ceil, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor ที่วัดปริมาณแล้ว | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor ที่วัดปริมาณแล้ว | (C1) |
ข้อจำกัด
- (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]
Cholesky
อรรถศาสตร์
คำนวณการแยกตัวของชูเลสกี้ของเมทริกซ์กลุ่มหนึ่ง
อย่างเป็นทางการสำหรับ i
ทั้งหมดใน index_space(result)
result[i0, ..., iR-3, :, :]
คือการแยกตัวแบบ Cholesky ของ
a[i0, ..., iR-3, :, :]
ในรูปแบบของสามเหลี่ยมล่าง
(หาก lower
เป็น true
) หรือเมทริกซ์รูปสามเหลี่ยมบน (หาก lower
เป็น false
)
ค่าเอาต์พุตในรูปสามเหลี่ยมตรงข้ามกัน เช่น รูปสามเหลี่ยมด้านบนที่เข้มงวดหรือสามเหลี่ยมล่างสุดแคบตามลำดับ จะได้รับการกำหนดการนำไปใช้งาน
หากมี i
ที่เมทริกซ์อินพุตไม่ใช่เมทริกซ์บวกลบของเฮอร์มิเชียน จะไม่มีการระบุลักษณะการทำงาน
สำหรับประเภทที่แบ่งปริมาณแล้ว จะแสดงผล dequantize_op_quantize(lambda operand: cholesky(operand, lower), a, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | a |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1-C3) |
(I2) | lower |
ค่าคงที่ tensor 0 มิติของประเภท i1 |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
ข้อจำกัด
- (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]
// ]
ที่ยึด
อรรถศาสตร์
ยึดทุกองค์ประกอบของ tensor operand
ระหว่างค่าต่ำสุดและสูงสุด แล้วสร้าง tensor 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)
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | min |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1), (C3) |
(I2) | operand |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1-C4) |
(1) | max |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C2), (C3) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C4) |
ข้อจำกัด
- (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 ให้ส่งค่า Tensor operand
จากกระบวนการต้นทางไปยังกระบวนการเป้าหมายและสร้าง Tensor result
การดำเนินการจะแยกตารางกริดกระบวนการของ StableHLO เป็น process_groups
ซึ่งมีคำจำกัดความดังนี้
cross_replica(replica_groups)
หากchannel_id <= 0
cross_partition(replica_groups)
หากchannel_id > 0
หลังจากนั้น result@process
จะมอบให้โดย
operand@process_groups[i, 0]
หากมีi
เพื่อให้กระบวนการอยู่ในprocess_groups[i]
broadcast_in_dim(constant(0, element_type(result)), [], type(result))
ไม่เช่นนั้น
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
Tensor | (C3) |
(I2) | replica_groups |
จำนวนแปรผันของค่าคงที่ tensor 1 มิติของประเภท si64 |
(C1), (C2) |
(1) | channel_id |
ค่าคงที่ของประเภท si64 |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor | (C3) |
ข้อจำกัด
- (C1)
is_unique(replica_groups)
- (C2)
0 <= replica_groups < N
โดยให้นิยามN
ว่าnum_replicas
หากใช้cross_replica
num_partitions
หากใช้cross_partition
- (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 ให้ส่งค่าของ Tensor operand
จากกระบวนการต้นทางไปยังกระบวนการเป้าหมายและสร้าง Tensor result
การดำเนินการจะแยกตารางกริดกระบวนการของ StableHLO เป็น process_groups
ซึ่งมีคำจำกัดความดังนี้
cross_replica(source_target_pairs)
หากchannel_id <= 0
cross_partition(source_target_pairs)
หากchannel_id > 0
หลังจากนั้น 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))
ไม่เช่นนั้น
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C5) |
(I2) | source_target_pairs |
ค่าคงที่ tensor 2 มิติของประเภท si64 |
(C1-C4) |
(1) | channel_id |
ค่าคงที่ของประเภท si64 |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
ข้อจำกัด
- (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
ว่าnum_replicas
หากใช้cross_replica
num_partitions
หากใช้cross_partition
- (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]]
เปรียบเทียบ
อรรถศาสตร์
ทำการเปรียบเทียบ tensors lhs
และ rhs
ตามองค์ประกอบตาม comparison_direction
และ compare_type
แล้วสร้าง result
Tensor
ค่าของ 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
การทดสอบจะใช้การดำเนินการ IEEE-754 ต่อไปนี้
EQ
:compareQuietEqual
NE
:compareQuietNotEqual
GE
:compareQuietGreaterEqual
GT
:compareQuietGreater
LE
:compareQuietLessEqual
LT
:compareQuietLess
สำหรับประเภทองค์ประกอบจุดลอยตัวที่มี compare_type = TOTALORDER
การทดสอบจะใช้ชุดค่าผสมของการดำเนินการ totalOrder
และ compareQuietEqual
จาก IEEE-754 ดูเหมือนว่าจะไม่มีการใช้งานฟีเจอร์นี้ เราจึงมีแผนที่จะนำออกในอนาคต (#584)
สําหรับประเภทองค์ประกอบที่ซับซ้อน การเปรียบเทียบแบบพจนานุกรมของคู่ (real, imag)
จะดําเนินการโดยใช้ comparison_direction
และ compare_type
ที่ให้ไว้
การตั้งอันดับด้วยจำนวนเชิงซ้อนเกี่ยวข้องกับความหมายที่น่าประหลาดใจ ดังนั้นในอนาคตเราจึงวางแผนที่จะยกเลิกการรองรับจำนวนเชิงซ้อนเมื่อ comparison_direction
เท่ากับ GE
, GT
, LE
หรือ LT
(#560)
สำหรับประเภทที่แบ่งปริมาณแล้ว จะแสดงผล dequantize_compare(lhs, rhs,
comparison_direction)
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | lhs |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1-C3) |
(I2) | rhs |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1-C2) |
(1) | comparison_direction |
enum ของ EQ , NE , GE , GT , LE และ LT |
|
(I4) | compare_type |
enum ของ FLOAT , TOTALORDER , SIGNED และ UNSIGNED |
(C3) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor ของประเภทบูลีน | (C2) |
ข้อจำกัด
- (C1)
baseline_element_type(lhs) = baseline_element_type(rhs)
- (C2)
shape(lhs) = shape(rhs) = shape(result)
- (C3)
compare_type
ให้คำจำกัดความไว้ดังนี้SIGNED
หากis_signed_integer(element_type(lhs))
UNSIGNED
หากis_unsigned_integer(element_type(lhs)) or is_boolean(element_type(lhs))
FLOAT
หรือTOTALORDER
หากเป็นis_float(element_type(lhs))
FLOAT
หากis_complex(element_type(lhs))
ตัวอย่าง
// %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
และสร้าง Tensor result
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | lhs |
Tensor ประเภท f32 หรือ f64 |
(C1-C3) |
(I2) | rhs |
Tensor ประเภท f32 หรือ f64 |
(C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor ของประเภทที่ซับซ้อน | (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)]
concatenate
อรรถศาสตร์
เชื่อมต่อ inputs
ในมิติข้อมูล dimension
ในลำดับเดียวกันกับอาร์กิวเมนต์ที่ระบุ และสร้าง result
Tensor อย่างเป็นทางการคือ
result[i0, ..., id, ..., iR-1] = inputs[k][i0, ..., kd, ..., iR-1]
ซึ่ง
id = d0 + ... + dk-1 + kd
.d
เท่ากับdimension
และd0
... เป็นขนาดมิติข้อมูลที่d
ของinputs
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | inputs |
จำนวน tensors แบบแปรผันหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1-C6) |
(I2) | dimension |
ค่าคงที่ของประเภท si64 |
(C2), (C4), (C6) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C5-C6) |
ข้อจำกัด
- (C1)
same(element_type(inputs...))
- (C2)
same(shape(inputs...))
ยกเว้นdim(inputs..., dimension)
- (C3)
0 < size(inputs)
- (C4)
0 <= dimension < rank(inputs[0])
- (C5)
element_type(result) = element_type(inputs[0])
- (C6)
shape(result) = shape(inputs[0])
ยกเว้นกรณีต่อไปนี้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]]
ค่าคงที่
อรรถศาสตร์
สร้าง output
Tensor จาก value
คงที่
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | value |
ค่าคงที่ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
output |
tensor หรือ tensor ที่วัดปริมาณแล้ว | (C1) |
ข้อจำกัด
- (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]]
ทำให้เกิด Conversion
อรรถศาสตร์
ทำ Conversion ตามองค์ประกอบจากประเภทองค์ประกอบหนึ่งไปเป็นอีกประเภทหนึ่งใน operand
Tensor และสร้าง Tensor result
สำหรับ Conversion boolean-to-any-supported-type ค่า false
จะแปลงไปเป็น 0 และแปลงค่า true
เป็น 1 สำหรับ Conversion any-supported-type-to-boolean ระบบจะแปลงค่า 0 เป็น false
และค่าที่ไม่ใช่ 0 จะถูกแปลงเป็น true
ดูวิธีการทำงาน
สำหรับประเภทที่ซับซ้อนได้ที่ด้านล่าง
สำหรับ Conversion ที่เกี่ยวข้องกับ integer-to-integer, integer-to-Floing-point หรือ Floating-point-to-Floing-point หากค่าแหล่งที่มาสามารถนำเสนอได้ในประเภทปลายทางทุกประการ ค่าผลลัพธ์จะเป็นการแทนค่าที่ตรงกับความเป็นจริง มิเช่นนั้น ลักษณะการทำงานจะเป็น TBD (#180)
สำหรับ Conversion ที่เกี่ยวข้องกับ floating-point-to-integer ระบบจะตัดส่วนที่เป็นเศษส่วนออก หากแสดงค่าที่ตัดในประเภทปลายทางไม่ได้ ลักษณะการทำงานจะเป็น TBD (#180)
Conversion ที่เกี่ยวข้องกับ complex-to-complex ใช้ลักษณะการทำงานเดียวกันกับ Conversion ของ floating-point-to-Floing-point สำหรับการแปลงส่วนจริงและส่วนจินตภาพ
สำหรับ Conversion แบบ complex-to-any-other-type และ complex-to-any-other-type ระบบจะไม่สนใจค่าจินตภาพของแหล่งที่มาหรือค่าจินตภาพปลายทางจะเป็น 0 ตามลำดับ การแปลงส่วนจริงจะเป็นไปตาม Conversion จุดลอยตัว
ตามหลักแล้ว การดําเนินการนี้อาจแสดงลําดับความสําคัญ (การแปลงจาก tensors ที่ทําให้เล็กลงเป็น tensors ปกติ) การทําให้ปริมาณ (การแปลงจาก tensors ปกติไปเป็น tensors เชิงปริมาณ) และการแปลงค่าซ้ำ (Conversion ระหว่าง tensors เชิงปริมาณ) แต่ในตอนนี้เราได้ทำการดำเนินการเฉพาะให้กับ tensor ดังกล่าว -uniform_dequantize
สำหรับ Use Case แรกและ uniform_quantize
สำหรับ Use Case ครั้งที่ 2 และ 3 ในอนาคต การดำเนินการทั้ง 2 อย่างนี้อาจผสานรวมเป็น convert
(#1576)
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
Tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor | (C1) |
ข้อจำกัด
- (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)]
Convolution
อรรถศาสตร์
การประมวลผลจะจุดผลิตภัณฑ์ระหว่างหน้าต่างของ 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
สำหรับ
output_spatial_index
ทั้งหมดใน index_space(dim(result, output_spatial_dimensions...))
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))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | lhs |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1), (C10-C11), (C14) (C25), (C27-C30) |
(I2) | rhs |
tensor หรือ tensor ที่วัดปริมาณแล้ว | (C1), (C14-C16), (C25), (C27-C32) |
(1) | window_strides |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2-C3), (C25) |
(I4) | padding |
ค่าคงที่ tensor 2 มิติของประเภท si64 |
(C4) (C25) |
(1) | lhs_dilation |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C5-C6), (C25) |
(1) | rhs_dilation |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C7-C8), (C25) |
(1) | window_reversal |
ค่าคงที่ tensor แบบ 1 มิติของประเภท i1 |
(C9) |
(i8) | input_batch_dimension |
ค่าคงที่ของประเภท si64 |
(C10), (C13), (C25) |
(I9) | input_feature_dimension |
ค่าคงที่ของประเภท si64 |
(C11), (C13-C14) |
(10) | input_spatial_dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C12), (C13), (C25) |
(11) | kernel_input_feature_dimension |
ค่าคงที่ของประเภท si64 |
(C14), (C18) |
(12) | kernel_output_feature_dimension |
ค่าคงที่ของประเภท si64 |
(C15-C16), (C18), (C25), (C32) |
(13) | kernel_spatial_dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C17-C18), (C25) |
(14) | output_batch_dimension |
ค่าคงที่ของประเภท si64 |
(C20) (C25) |
(15) | output_feature_dimension |
ค่าคงที่ของประเภท si64 |
(C20), (C25), (C33) |
(16) | output_spatial_dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C19-C20) (C25) |
(17) | feature_group_count |
ค่าคงที่ของประเภท si64 |
(C11), (C14), (C16), (C21), (C23) |
(18) | batch_group_count |
ค่าคงที่ของประเภท si64 |
(C10), (C15), (C22), (C23), (C25) |
(19) | precision_config |
จำนวน enum ของ DEFAULT , HIGH และ HIGHEST |
(C24) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือ tensor ที่วัดปริมาณแล้ว | (C25-C28), (C30-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)
ให้คำจำกัดความไว้ดังนี้dim(lhs, input_batch_dimension) / batch_group_count
หากresult_dim = output_batch_dimension
dim(rhs, kernel_output_feature_dimension)
หากresult_dim = 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
- หากการดำเนินการใช้ Tensor แบบไม่วัดปริมาณ:
- (C27)
element_type(lhs) = element_type(rhs) = element_type(result)
- (C27)
- หากการดำเนินการใช้ tensors ที่วัดปริมาณแล้ว ให้ทำดังนี้
- (C28)
is_quantized_tensor(lhs) and is_quantized_tensor(rhs) and is_quantized_tensor(result)
- (C29)
storage_type(lhs) = storage_type(rhs)
- (C30)
expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
- (C31) หากเป็น
is_per_tensor_quantized(rhs)
ให้is_per_tensor_quantized(result)
- (C32) หากเป็น
is_per_axis_quantized(rhs)
ให้quantization_dimension(rhs) = kernel_output_feature_dimension
- (C33) หากเป็น
is_per_axis_quantized(result)
ให้quantization_dimension(result) = output_feature_dimension
- (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 = dense<4> : tensor<2xi64>,
padding = dense<0> : tensor<2x2xi64>,
lhs_dilation = dense<2> : tensor<2xi64>,
rhs_dilation = dense<1> : tensor<2xi64>,
window_reversal = dense<false> : tensor<2xi1>,
// 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]>,
feature_group_count = 1 : i64,
batch_group_count = 1 : i64,
precision_config = [#stablehlo<precision DEFAULT>, #stablehlo<precision DEFAULT>]
} : (tensor<1x4x4x1xi32>, tensor<3x3x1x1xi32>) -> tensor<1x2x2x1xi32>
// %result: [[
// [[10], [26]],
// [[46], [62]]
// ]]
โคไซน์
อรรถศาสตร์
ดำเนินการดำเนินการโคไซน์ตามองค์ประกอบบน Tensor operand
และสร้าง Tensor result
ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับเลขทศนิยม:
cos
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: โคไซน์เชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(cosine, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
ข้อจำกัด
- (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
อรรถศาสตร์
ดำเนินการนับตามองค์ประกอบของจำนวนบิตนำ 0 บิตใน Tensor ใน operand
และสร้าง tensor result
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
Tensor ของประเภทจำนวนเต็ม | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor ของประเภทจำนวนเต็ม | (C1) |
ข้อจำกัด
- (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)
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท |
---|---|---|
(1) | inputs |
จำนวนค่าที่แตกต่างกัน |
(I2) | call_target_name |
ค่าคงที่ของประเภท string |
(1) | has_side_effect |
ค่าคงที่ของประเภท i1 |
(I4) | backend_config |
ค่าคงที่ของประเภท string |
(1) | api_version |
ค่าคงที่ของประเภท si32 |
(1) | called_computations |
จำนวนคงที่ของชนิด string |
เอาต์พุต
ชื่อ | ประเภท |
---|---|
results |
จำนวนค่าที่แตกต่างกัน |
ตัวอย่าง
%results = "stablehlo.custom_call"(%input0) {
call_target_name = "foo",
has_side_effect = false,
backend_config = "bar",
api_version = 1 : i32,
called_computations = [@foo]
} : (tensor<f64>) -> tensor<f64>
หาร
อรรถศาสตร์
ทำการหาร Tensor หาร lhs
และตัวหาร rhs
ตามองค์ประกอบ แล้วสร้าง result
Tensor ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับจำนวนเต็ม: การหารจำนวนเต็มที่สร้างผลหารพีชคณิตที่มีเศษส่วนใดๆ ที่ถูกทิ้ง
- สำหรับเลขทศนิยม:
division
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: การหารเชิงซ้อน
- สำหรับประเภทที่เล็กลง
dequantize_op_quantize(divide, lhs, rhs, type(result))
.
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | lhs |
tensor ของจำนวนเต็ม ชนิดจุดลอยตัว หรือชนิดเชิงซ้อน หรือ tensor ที่วัดปริมาณด้วยต่อ tensor | (C1) |
(I2) | rhs |
tensor ของจำนวนเต็ม ชนิดจุดลอยตัว หรือชนิดเชิงซ้อน หรือ tensor ที่วัดปริมาณด้วยต่อ tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของจำนวนเต็ม จุดลอยตัว หรือชนิดเชิงซ้อน หรือ tensor ที่วัดปริมาณด้วยต่อ tensor | (C1) |
ข้อจำกัด
- (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
จะสร้าง tensor จำนวน 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))
ซึ่งจะระบุเฉพาะความหมายสำหรับการหาปริมาณต่อ tensor เท่านั้น การคำนวณจำนวนตามแกนอยู่ระหว่างดำเนินการ (#1574) นอกจากนี้ ในอนาคตเราอาจพิจารณาเพิ่มการรองรับการระบุปริมาณแบบผสม (#1575)
precision_config
จะควบคุมการทดแทนกันระหว่างความเร็วและความแม่นยำสำหรับการคำนวณแบ็กเอนด์ของ Accelerator ซึ่งอาจเป็นอย่างใดอย่างหนึ่งต่อไปนี้ (ในขณะนี้ ระบบไม่ได้กำหนดความหมายของค่า enum เหล่านี้ไว้ แต่เรามีแผนที่จะจัดการเรื่องนี้ใน #755)
DEFAULT
: การคำนวณเร็วที่สุด แต่ใกล้เคียงตัวเลขเดิมน้อยที่สุดHIGH
: การคำนวณช้าลง แต่ใกล้เคียงตัวเลขเดิมมากกว่าHIGHEST
: การคำนวณแบบช้าที่สุด แต่เป็นการคาดประมาณที่แม่นยำที่สุดกับจำนวนเดิม
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | lhs |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C5-C6), (C9-C10), (C12-C16) |
(I2) | rhs |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C7-C10), (C12) |
(1) | lhs_batching_dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C1), (C3), (C5), (C9), (C12) |
(I4) | rhs_batching_dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C1), (C4), (C7), (C9) |
(1) | lhs_contracting_dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C3), (C6), (C10) |
(1) | rhs_contracting_dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C4), (C8), (C10) |
(1) | precision_config |
จำนวน enum ของ DEFAULT , HIGH และ HIGHEST |
(C11) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C12), (C14), (C16) |
ข้อจำกัด
- (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)
- หากการดำเนินการใช้ Tensor แบบไม่วัดปริมาณ:
- (C13)
element_type(lhs) = element_type(rhs)
- (C13)
- หากการดำเนินการใช้ tensors ที่วัดปริมาณแล้ว ให้ทำดังนี้
- (C14)
is_quantized(lhs) and is_quantized(rhs) and is_quantized(result)
- (C15)
storage_type(lhs) = storage_type(rhs)
- (C16)
expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
- (C17)
zero_points(rhs) = 0
- (C14)
ตัวอย่าง
// %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>]
} : (tensor<2x2x2xi64>, tensor<2x2x2xi64>) -> tensor<2x2x2xi64>
// %result: [
// [[1, 2],
// [3, 4]],
// [[5, 6],
// [7, 8]]
// ]
dynamic_slice
อรรถศาสตร์
แยกสไลซ์จาก operand
โดยใช้ดัชนีเริ่มต้นที่คำนวณแบบไดนามิก และสร้าง Tensor 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
.
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1), (C2), (C4) |
(I2) | start_indices |
จำนวนตัวแปรของ tensors 0 มิติของจำนวนเต็ม | (C2), (C3) |
(1) | slice_sizes |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C4), (C5) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (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 = dense<[2, 2]> : tensor<2xi64>
} : (tensor<4x4xi32>, tensor<i64>, tensor<i64>) -> tensor<2x2xi32>
// %result: [
// [1, 1],
// [1, 1]
// ]
dynamic_update_slice
อรรถศาสตร์
สร้าง result
tensor ซึ่งเท่ากับ operand
tensor เว้นแต่สไลซ์ที่เริ่มต้นที่ 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]
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1-C4) (C6) |
(I2) | update |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C2), (C3), (C6) |
(1) | start_indices |
จำนวนตัวแปรของ tensors 0 มิติของจำนวนเต็ม | (C4) (C5) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
ข้อจำกัด
- (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]
// ]
เลขชี้กำลัง
อรรถศาสตร์
ดำเนินการเลขชี้กำลังตามองค์ประกอบใน Tensor operand
และสร้าง Tensor result
ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับเลขทศนิยม:
exp
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: เลขชี้กำลังเชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(exponential, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
ข้อจำกัด
- (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
อรรถศาสตร์
ดำเนินการเลขชี้กำลังตามเชิงองค์ประกอบลบ 1 การดำเนินการใน tensor operand
และสร้าง tensor result
ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับเลขทศนิยม:
expm1
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: เลขชี้กำลังเชิงซ้อนลบ 1
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(exponential_minus_one, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
ข้อจำกัด
- (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
อรรถศาสตร์
ทำการแปลงฟูรีเยแบบไปข้างหน้าและผกผันสำหรับอินพุต/เอาต์พุตจริงและที่ซับซ้อน
fft_type
เป็นหนึ่งในค่าต่อไปนี้
FFT
: FFT แบบซับซ้อนสู่ซับซ้อนIFFT
: FFT เชิงซ้อนไปเชิงซ้อนแบบผกผันRFFT
: ส่งต่อ FFT แบบจริงสู่ข้อมูลที่ซับซ้อนIRFFT
: FFT แบบผกผันจริงถึงซับซ้อน (นั่นคือ ใช้ค่าที่ซับซ้อน แสดงผลจริง)
อย่างเป็นทางการมากขึ้น จากฟังก์ชัน fft
ซึ่งนำ tensors แบบ 1 มิติของประเภทที่ซับซ้อนมาเป็นอินพุต จะสร้าง tensor แบบ 1 มิติของประเภทเดียวกันกับเอาต์พุตแล้วคำนวณการแปลงฟูรีเยที่แยกจากกันโดยสิ้นเชิง ดังนี้
สำหรับ 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
ซึ่งจะใช้ tensors 1 มิติของประเภทจุดลอยตัว จะสร้าง tensor แบบ 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, ..., :])
.
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
Tensor ของชนิดจุดลอยตัวหรือเชิงซ้อน | (C1), (C2), (C4), (C5) |
(I2) | fft_type |
enum ของ FFT , IFFT , RFFT และ IRFFT |
(C2), (C5) |
(1) | fft_length |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C1), (C3), (C4) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor ของชนิดจุดลอยตัวหรือเชิงซ้อน | (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
มี tensorreal
ของประเภทจุดลอยตัว ให้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 = dense<4> : tensor<1xi64>
} : (tensor<4xcomplex<f32>>) -> tensor<4xcomplex<f32>>
// %result: [(1.0, 0.0), (1.0, 0.0), (1.0, 0.0), (1.0, 0.0)]
ชั้น
อรรถศาสตร์
ดำเนินการราคาพื้นตามองค์ประกอบของ tensor operand
และสร้าง Tensor result
ใช้การดำเนินการ roundToIntegralTowardNegative
จากข้อกำหนด IEEE-754 สำหรับประเภทที่แบ่งปริมาณแล้ว จะแสดงผล dequantize_op_quantize(floor, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor ที่วัดปริมาณแล้ว | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor ที่วัดปริมาณแล้ว | (C1) |
ข้อจำกัด
- (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]
รวบรวม
อรรถศาสตร์
รวบรวมชิ้นส่วนจาก operand
Tensor จากออฟเซ็ตที่ระบุใน start_indices
และสร้าง result
Tensor
แผนภาพต่อไปนี้แสดงลักษณะที่องค์ประกอบใน result
จับคู่กับองค์ประกอบใน operand
โดยใช้ตัวอย่างที่เป็นรูปธรรม แผนภาพนี้เลือกตัวอย่างดัชนี result
2-3 รายการและอธิบายรายละเอียดว่าดัชนี 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]]
- สำหรับ
d_operand
ในaxes(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
offset_index = result_index[offset_dims...]
.full_offset_index = [oi0, ..., 0, ..., oiN]
โดยที่oi
เป็นองค์ประกอบเดี่ยวในoffset_index
และแทรก0
ที่ดัชนีจากcollapsed_slice_dims
operand_index = full_start_index + full_offset_index
หาก indices_are_sorted
คือ true
การติดตั้งใช้งานจะถือว่ามีการจัดเรียง start_indices
ตาม start_index_map
ไม่เช่นนั้นจะไม่มีการกำหนดลักษณะการทำงาน อย่างเป็นทางการ สำหรับ i1 < i2
ทั้งหมดจาก indices(result)
full_start_index(i1) <= full_start_index(i2)
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1), (C7), (C10-C12), (C14) |
(I2) | start_indices |
Tensor ของประเภทจำนวนเต็ม | (C2), (C3), (C13) |
(1) | offset_dims |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C1), (C4-C5), (C13) |
(I4) | collapsed_slice_dims |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C1), (C6-C8), (C13) |
(1) | start_index_map |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C3), (C9), (C10) |
(1) | index_vector_dim |
ค่าคงที่ของประเภท si64 |
(C2), (C3), (C13) |
(1) | slice_sizes |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C8), (C11-C13) |
(i8) | indices_are_sorted |
ค่าคงที่ของประเภท i1 |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (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)
เว้นแต่ว่าจะไม่รวมขนาดมิติข้อมูลstart_indices
ที่สอดคล้องกับindex_vector_dim
offset_dim_sizes = shape(slice_sizes)
เว้นแต่ว่าจะไม่มีการรวมขนาดของมิติข้อมูลในslice_sizes
ที่สอดคล้องกับcollapsed_slice_dims
combine
วางbatch_dim_sizes
ที่แกนที่สัมพันธ์กับbatch_dims
และoffset_dim_sizes
ในแกนที่สัมพันธ์กับoffset_dims
- (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]]
// ]
%result = "stablehlo.gather"(%operand, %start_indices) {
dimension_numbers = #stablehlo.gather<
offset_dims = [2, 3],
collapsed_slice_dims = [0],
start_index_map = [1, 0],
index_vector_dim = 2>,
slice_sizes = dense<[1, 2, 2]> : tensor<3xi64>,
indices_are_sorted = false
} : (tensor<3x4x2xi32>, tensor<2x3x2xi64>) -> tensor<2x3x2x2xi32>
// %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]]
// ]
// ]
get_dimension_size
อรรถศาสตร์
จะสร้างขนาดของ dimension
ที่ระบุของ operand
เป็นทางการมากขึ้นแล้ว
result = dim(operand, dimension)
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
Tensor | (C1) |
(I2) | dimension |
ค่าคงที่ของประเภท si64 |
(C1) |
เอาต์พุต
ชื่อ | ประเภท |
---|---|
result |
Tensor แบบ 0 มิติของประเภท si32 |
ข้อจำกัด
- (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
อรรถศาสตร์
แยกองค์ประกอบที่ตำแหน่ง index
ของ Tuple operand
และสร้าง result
เป็นทางการมากขึ้นแล้วนะ result = operand[index]
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tuple | (C1), (C2) |
(I2) | index |
ค่าคงที่ของประเภท si32 |
(C1), (C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
ประเภทใดก็ได้ที่รองรับ | (C2) |
ข้อจำกัด
- (C1)
0 <= index < size(operand)
- (C2)
type(result) = tuple_element_types(operand)[index]
ตัวอย่าง
// %operand: ([1.0, 2.0], (3))
%result = "stablehlo.get_tuple_element"(%operand) {
index = 0 : i32
} : (tuple<tensor<2xf32>, tuple<tensor<i32>>>) -> tensor<2xf32>
// %result: [1.0, 2.0]
if
อรรถศาสตร์
สร้างเอาต์พุตจากการรันฟังก์ชันจาก true_branch
หรือ false_branch
เพียง 1 ฟังก์ชัน โดยขึ้นอยู่กับค่าของ pred
เป็นทางการมากขึ้นแล้วนะ result =
pred ? true_branch() : false_branch()
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | pred |
Tensor แบบ 0 มิติของประเภท i1 |
|
(I2) | true_branch |
ฟังก์ชัน | (C1-C3) |
(1) | false_branch |
ฟังก์ชัน | (C1), (C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวน tensors หลากหลายแบบ, tensors ในเชิงปริมาณ หรือโทเค็น | (C3) |
ข้อจำกัด
- (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
ภาพ
อรรถศาสตร์
แยกส่วนจินตภาพจาก "องค์ประกอบ" ออกจาก operand
และสร้าง Tensor result
เป็นทางการมากขึ้นสำหรับองค์ประกอบ x
แต่ละรายการ:
imag(x) = is_complex(x) ? imaginary_part(x) :
constant(0, element_type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
Tensor ของชนิดจุดลอยตัวหรือเชิงซ้อน | (C1), (C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor ของประเภทจุดลอยตัว | (C1), (C2) |
ข้อจำกัด
- (C1)
shape(result) = shape(operand)
- (C2)
element_type(result)
ให้คำจำกัดความไว้ดังนี้complex_element_type(element_type(operand))
หากis_complex(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
ประกอบด้วยค่าเพย์โหลดซึ่งมาก่อนและโทเค็นที่อยู่ท้ายสุด ในอนาคต เรามีแผนที่จะแยกเพย์โหลดและโทเค็นออกเป็นเอาต์พุต 2 แบบแยกกันเพื่อปรับปรุงความชัดเจน (#670)
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท |
---|---|---|
(1) | token |
token |
(I2) | infeed_config |
ค่าคงที่ของประเภท string |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวน tensors หลากหลายแบบ, tensors ในเชิงปริมาณ หรือโทเค็น | (C1-C3) |
ข้อจำกัด
- (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]]
Iota
อรรถศาสตร์
เติม Tensor output
ด้วยค่าตามลำดับที่เพิ่มขึ้นโดยเริ่มจาก 0 ตามมิติข้อมูล iota_dimension
อย่างเป็นทางการ
output[result_index] = constant(is_quantized(output) ?
quantize(result_index[iota_dimension], element_type(output)) :
result_index[iota_dimension], element_type(output))
.
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | iota_dimension |
si64 |
(C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
output |
tensor ของจำนวนเต็ม ชนิดจุดลอยตัว หรือชนิดเชิงซ้อน หรือ tensor ที่วัดปริมาณด้วยต่อ tensor | (C1) |
ข้อจำกัด
- (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) และสร้าง Tensor y
ใช้การดำเนินการ isFinite
จากข้อกำหนด IEEE-754 สำหรับประเภทที่เล็กลง ผลลัพธ์จะเป็น true
เสมอ
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | x |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor ที่วัดปริมาณแล้ว | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
y |
Tensor ของประเภทบูลีน | (C1) |
ข้อจำกัด
- (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
อรรถศาสตร์
ดำเนินการใช้ลอการิทึมตามองค์ประกอบใน tensor ใน operand
และสร้าง tensor result
ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับเลขทศนิยม:
log
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: ลอการิทึมเชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(log, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
ข้อจำกัด
- (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
อรรถศาสตร์
ดำเนินการลอการิทึมตามองค์ประกอบพร้อมการดำเนินการ 1 อย่างใน operand
Tensor และสร้าง Tensor result
ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับเลขทศนิยม:
logp1
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: ลอการิทึมเชิงซ้อนบวก 1
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(log_plus_one, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
ข้อจำกัด
- (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
Tensor และสร้าง Tensor result
ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับเลขทศนิยม:
division(1, addition(1, exp(-x)))
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: โลจิสติกส์เชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(logistic, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
ข้อจำกัด
- (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]]
map
อรรถศาสตร์
ใช้ฟังก์ชันแผนที่ computation
กับ inputs
ตาม dimensions
และสร้าง Tensor result
เป็นทางการมากขึ้นแล้วนะ result[result_index] = computation(inputs...[result_index])
โปรดทราบว่าขณะนี้ dimensions
ไม่มีการใช้งานและมีแนวโน้มที่จะถูกนำออกในอนาคต (#487)
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | inputs |
จำนวน tensors แบบแปรผันหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1-C4) |
(I2) | dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C3) |
(1) | computation |
ฟังก์ชัน | (C4) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (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 = dense<[0, 1]> : tensor<2xi64>
} : (tensor<2x2xi64>, tensor<2x2xi64>) -> tensor<2x2xi64>
// %result: [[0, 5], [12, 21]]
สูงสุด
อรรถศาสตร์
ดำเนินการสูงสุดตามองค์ประกอบตามองค์ประกอบบน tensors lhs
และ rhs
และสร้าง Tensor result
ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับบูลีน: logical OR
- สำหรับจำนวนเต็ม: จำนวนเต็มสูงสุด
- สำหรับเลขทศนิยม:
maximum
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: จำนวนสูงสุดแบบพจนานุกรมสำหรับคู่
(real, imaginary)
การตั้งลำดับในจำนวนเชิงซ้อนเกี่ยวข้องกับความหมายที่น่าประหลาดใจ ดังนั้นในอนาคตเราจึงวางแผนที่จะยกเลิกการรองรับจำนวนเชิงซ้อนในการดำเนินการนี้ (#560) - สำหรับประเภทที่เล็กลง
dequantize_op_quantize(maximum, lhs, rhs, type(result))
.
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | lhs |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
(I2) | rhs |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
ข้อจำกัด
- (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]]
ขั้นต่ำ
อรรถศาสตร์
ดำเนินการขั้นต่ำตามองค์ประกอบตามองค์ประกอบบน tensors lhs
และ rhs
และสร้าง tensor เพียง result
ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับบูลีน: ตรรกะ AND
- สำหรับจำนวนเต็ม: จำนวนเต็มขั้นต่ำ
- สำหรับเลขทศนิยม:
minimum
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: จำนวนขั้นต่ำของพจนานุกรมสำหรับคู่
(real, imaginary)
การตั้งลำดับในจำนวนเชิงซ้อนเกี่ยวข้องกับความหมายที่น่าประหลาดใจ ดังนั้นในอนาคตเราจึงวางแผนที่จะยกเลิกการรองรับจำนวนเชิงซ้อนในการดำเนินการนี้ (#560) - สำหรับประเภทที่เล็กลง
dequantize_op_quantize(minimum, lhs, rhs, type(result))
.
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | lhs |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
(I2) | rhs |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
ข้อจำกัด
- (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]]
คูณ
อรรถศาสตร์
สร้างผลคูณตามองค์ประกอบของ tensors 2 ตัว lhs
และ rhs
แล้วสร้าง Tensor result
ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับบูลีน: ตรรกะ AND
- สำหรับจำนวนเต็ม: การคูณจำนวนเต็ม
- สำหรับเลขทศนิยม:
multiplication
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: การคูณเชิงซ้อน
- สำหรับประเภทที่เล็กลง
dequantize_op_quantize(multiply, lhs, rhs, type(result))
.
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | lhs |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
(I2) | rhs |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
ข้อจำกัด
- (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
Tensor และสร้าง result
Tensor ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สําหรับจํานวนเต็มที่มีเครื่องหมาย: การปฏิเสธจํานวนเต็ม
- สำหรับจำนวนเต็มที่ไม่มีเครื่องหมาย: บิตแคสต์ไปยังจำนวนเต็มแบบมีเครื่องหมาย นิเสธที่เป็นจำนวนเต็ม บิตแคสต์ย้อนกลับไปยังจำนวนเต็มที่ไม่มีเครื่องหมาย
- สำหรับเลขทศนิยม:
negate
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: นิเสธเชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(negate, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor ของจำนวนเต็ม จุดลอยตัว หรือชนิดเชิงซ้อน หรือ tensor ที่วัดปริมาณด้วยต่อ tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของจำนวนเต็ม จุดลอยตัว หรือชนิดเชิงซ้อน หรือ tensor ที่วัดปริมาณด้วยต่อ tensor | (C1) |
ข้อจำกัด
- (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]
ไม่ใช่
อรรถศาสตร์
ดำเนินการ NOT แบบองค์ประกอบตาม tensor operand
และสร้าง tensor result
ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับบูลีน: ตรรกะ NOT
- สำหรับจำนวนเต็ม: Bitwise ไม่ใช่
อาร์กิวเมนต์
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
operand |
Tensor ของประเภทบูลีนหรือจำนวนเต็ม | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor ของประเภทบูลีนหรือจำนวนเต็ม | (C1) |
ข้อจำกัด
- (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 |
จำนวน tensors แบบแปรผัน, ต่อ tensor ที่วัดค่า Tensor หรือโทเค็น | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
จำนวน tensors แบบแปรผัน, ต่อ tensor ที่วัดค่า Tensor หรือโทเค็น | (C1) |
ข้อจำกัด
- (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
หรือ
อรรถศาสตร์
ดำเนินการ OR ตามองค์ประกอบของ tensor จำนวน 2 รายการ lhs
และ rhs
แล้วสร้าง result
Tensor ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับบูลีน: logical OR
- สำหรับจำนวนเต็ม: บิตไวส์ OR
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | lhs |
Tensor ของจำนวนเต็มหรือประเภทบูลีน | (C1) |
(I2) | rhs |
Tensor ของจำนวนเต็มหรือประเภทบูลีน | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor ของจำนวนเต็มหรือประเภทบูลีน | (C1) |
ข้อจำกัด
- (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
มีการกำหนดการนำไปใช้งาน
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท |
---|---|---|
(1) | inputs |
จำนวน tensors แบบแปรผันหรือ tensors เชิงปริมาณ |
(I2) | token |
token |
(1) | outfeed_config |
ค่าคงที่ของประเภท string |
เอาต์พุต
ชื่อ | ประเภท |
---|---|
result |
token |
ตัวอย่าง
%result = "stablehlo.outfeed"(%inputs0, %token) {
outfeed_config = ""
} : (tensor<2x2x2xi64>, !stablehlo.token) -> !stablehlo.token
Pad
อรรถศาสตร์
ขยาย operand
โดยเพิ่มระยะห่างจากขอบรอบๆ Tensor รวมถึงระหว่างองค์ประกอบของ tensor ด้วย padding_value
ที่กำหนด
edge_padding_low
และ edge_padding_high
จะระบุจำนวนระยะห่างจากขอบที่เพิ่มขึ้นในส่วนล่าง (ถัดจากดัชนี 0) และระดับไฮเอนด์ (ถัดจากดัชนีสูงสุด) ของแต่ละมิติข้อมูลตามลำดับ ระยะห่างจากขอบอาจเป็นค่าลบได้ โดยค่าสัมบูรณ์ของระยะห่างจากขอบเชิงลบจะระบุจำนวนองค์ประกอบที่จะนำออกจากมิติข้อมูลที่ระบุ
interior_padding
ระบุระยะห่างจากขอบที่เพิ่มระหว่างองค์ประกอบ 2 รายการในแต่ละมิติข้อมูล ซึ่งต้องไม่เป็นค่าลบ ระยะห่างจากขอบภายในเกิดขึ้นก่อนระยะห่างจากขอบเนื่องจากระยะห่างจากขอบที่เป็นลบจะนำองค์ประกอบออกจากตัวถูกดำเนินการแบบบุนวมภายใน
อย่างเป็นทางการ result[result_index]
ให้คำนิยามไว้ว่า
operand[operand_index]
หากresult_index = edge_padding_low + operand_index * (interior_padding + 1)
- หากไม่ใช่
padding_value
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1), (C2), (C4) |
(I2) | padding_value |
tensor แบบ 0 มิติหรือต่อ tensor ที่วัดปริมาณแล้ว | (C1) |
(1) | edge_padding_low |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C1), (C4) |
(I4) | edge_padding_high |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C1), (C4) |
(1) | interior_padding |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2-C4) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C3-C6) |
ข้อจำกัด
- (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 = dense<[0, 1]> : tensor<2xi64>,
edge_padding_high = dense<[2, 1]> : tensor<2xi64>,
interior_padding = dense<[1, 2]> : tensor<2xi64>
} : (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 |
Tensor แบบ 0 มิติของประเภท ui32 |
ตัวอย่าง
%result = "stablehlo.partition_id"() : () -> tensor<ui32>
Popcnt
อรรถศาสตร์
ดำเนินการนับจำนวนบิตตามองค์ประกอบตามจำนวนบิตที่กำหนดไว้ใน operand
Tensor และสร้าง result
Tensor
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
Tensor ของประเภทจำนวนเต็ม | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor ของประเภทจำนวนเต็ม | (C1) |
ข้อจำกัด
- (C1)
type(operand) = type(result)
ตัวอย่าง
// %operand: [0, 1, 2, 127]
%result = "stablehlo.popcnt"(%operand) : (tensor<4xi64>) -> tensor<4xi64>
// %result: [0, 1, 1, 7]
พาวเวอร์
อรรถศาสตร์
คำนวณเลขยกกำลังของ lhs
tensor ด้วย rhs
Tensor และสร้าง result
Tensor ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับจำนวนเต็ม: เลขยกกำลังจำนวนเต็ม
- สำหรับเลขทศนิยม:
pow
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: เลขชี้กำลังเชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(power, lhs, rhs, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | lhs |
tensor ของจำนวนเต็ม จุดลอยตัว หรือชนิดเชิงซ้อน หรือ tensor ที่วัดปริมาณด้วยต่อ tensor | (C1) |
(I2) | rhs |
tensor ของจำนวนเต็ม จุดลอยตัว หรือชนิดเชิงซ้อน หรือ tensor ที่วัดปริมาณด้วยต่อ tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของจำนวนเต็ม จุดลอยตัว หรือชนิดเชิงซ้อน หรือ tensor ที่วัดปริมาณด้วยต่อ tensor | (C1) |
ข้อจำกัด
- (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
และสร้าง Tensor result
เป็นทางการมากขึ้นสำหรับองค์ประกอบ x
แต่ละรายการ:
real(x) = is_complex(x) ? real_part(x) : x
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
Tensor ของชนิดจุดลอยตัวหรือเชิงซ้อน | (C1), (C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor ของประเภทจุดลอยตัว | (C1), (C2) |
ข้อจำกัด
- (C1)
shape(result) = shape(operand)
- (C2)
element_type(result)
ให้คำจำกัดความไว้ดังนี้complex_element_type(element_type(operand))
หากis_complex(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]
recv
อรรถศาสตร์
รับข้อมูลจากช่องที่มี channel_id
และสร้าง results
หาก is_host_transfer
คือ true
การดำเนินการดังกล่าวจะโอนข้อมูลจากโฮสต์ ไม่เช่นนั้น ระบบจะโอนข้อมูลจากอุปกรณ์อื่น ซึ่งหมายถึง
มีการกำหนดการติดตั้งใช้งาน แฟล็กนี้ซ้ำกับข้อมูลที่ระบุไว้ใน
channel_type
ดังนั้นในอนาคตเราวางแผนที่จะเก็บไว้เพียงตัวเดียว
(#666)
results
ประกอบด้วยค่าเพย์โหลดซึ่งมาก่อนและโทเค็นที่อยู่ท้ายสุด ในอนาคต เรามีแผนที่จะแยกเพย์โหลดและโทเค็นออกเป็นเอาต์พุต 2 แบบแยกกันเพื่อปรับปรุงความชัดเจน (#670)
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | token |
token |
(C4) |
(I2) | channel_id |
ค่าคงที่ของประเภท si64 |
|
(1) | channel_type |
enum ของ DEVICE_TO_DEVICE และ HOST_TO_DEVICE |
(C1) |
(I4) | is_host_transfer |
ค่าคงที่ของประเภท i1 |
(C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวน tensors หลากหลายแบบ, tensors ในเชิงปริมาณ หรือโทเค็น | (C2-C4) |
ข้อจำกัด
- (C1)
channel_type
ให้คำจำกัดความไว้ดังนี้HOST_TO_DEVICE
หากเป็นis_host_transfer = true
- หากไม่ใช่
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
Tensor
ลำดับของการลดมีการกำหนดการใช้งาน ซึ่งหมายความว่า body
และ init_values
ต้องเป็นแบบโมนอยด์เพื่อรับประกันว่าการดำเนินการดังกล่าวจะสร้างผลลัพธ์เดียวกันสำหรับอินพุตทั้งหมดในการใช้งานทั้งหมด แต่เงื่อนไขนี้กลับใช้กับการลดยอดนิยมจำนวนมากไม่ได้ เช่น การเพิ่มจุดลอยตัวของ body
และ 0 สำหรับ init_values
ไม่ได้สร้างโมนอยด์ เพราะการเพิ่มจุดลอยตัวไม่เชื่อมโยงกัน
อย่างเป็นทางการ 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
ที่กำหนดโดยการใช้งานที่ตำแหน่งที่กำหนดการนำไปใช้งาน
- ค่า
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | inputs |
จำนวน tensors แบบแปรผันหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1-C4), (C6), (C7) |
(I2) | init_values |
จำนวน tensors แบบ 0 มิติหรือต่อ tensor เชิงปริมาณ | (C2), (C3) |
(1) | dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C4), (C5), (C7) |
(I4) | body |
ฟังก์ชัน | (C6) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวน tensors แบบแปรผันหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (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...)
เว้นแต่ว่าจะไม่มีมิติข้อมูลขนาดinputs...
ที่สอดคล้องกับdimensions
- (C8)
element_type(results[i]) = Ei
สําหรับi
ทั้งหมดใน[0,N)
ตัวอย่าง
// %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 = dense<1> : tensor<1xi64>
} : (tensor<1x6xi64>, tensor<i64>) -> tensor<1xi64>
// %result = [15]
reduce_precision
อรรถศาสตร์
ทำการแปลง Element-wise จาก operand
ไปเป็นประเภทจุดลอยตัวอื่นที่ใช้ exponent_bits
และ mantissa_bits
และกลับไปใช้ประเภทจุดลอยตัวดั้งเดิมและสร้าง output
Tensor
เป็นทางการมากขึ้น:
- ระบบจะอัปเดตบิตตั๊กแตนของค่าเดิมให้ปัดเศษค่าเดิมให้เป็นค่าที่ใกล้เคียงที่สุดที่แสดงด้วย
mantissa_bits
โดยใช้อรรถศาสตร์roundToIntegralTiesToEven
- จากนั้น หาก
mantissa_bits
น้อยกว่าจำนวนบิตของตั๊กแตนตำข้าวของค่าเดิม บิตของตั๊กแตนจะถูกตัดเป็นmantissa_bits
- จากนั้น หากบิตของเลขชี้กำลังของผลลัพธ์ตรงกลางไม่พอดีกับช่วงที่ระบุโดย
exponent_bits
ผลลัพธ์ตรงกลางจะเกินค่าอนันต์โดยใช้เครื่องหมายเดิมหรือส่วนล่างลงไปเป็น 0 โดยใช้เครื่องหมายเดิม - สำหรับประเภทที่แบ่งปริมาณแล้ว ให้เรียกใช้
dequantize_op_quantize( lambda operand: reduce_precision(operand, exponent_bits, mantissa_bits), operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor ที่วัดปริมาณแล้ว | (C1) |
(I2) | exponent_bits |
ค่าคงที่ของประเภท si32 |
(C2) |
(1) | mantissa_bits |
ค่าคงที่ของประเภท si32 |
(C3) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
output |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor ที่วัดปริมาณแล้ว | (C1) |
ข้อจำกัด
- (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 ให้ดำเนินการลดค่าโดยใช้ computations
กับค่าของ operand
Tensor จากแต่ละกระบวนการจะแยกผลลัพธ์การลดตาม 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)
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1), (C2), (C7), (C8) |
(I2) | scatter_dimension |
ค่าคงที่ของประเภท si64 |
(C1), (C2), (C8) |
(1) | replica_groups |
ค่าคงที่ tensor 2 มิติของประเภท si64 |
(C3-C5) |
(I4) | channel_id |
ค่าคงที่ของประเภท si64 |
(C6) |
(1) | use_global_device_ids |
ค่าคงที่ของประเภท i1 |
(C6) |
(1) | computation |
ฟังก์ชัน | (C7) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C8-C9) |
ข้อจำกัด
- (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)
ให้คำจำกัดความไว้ดังนี้num_replicas
หากใช้cross_replica
num_replicas
หากใช้cross_replica_and_partition
num_processes
หากใช้flattened_ids
- (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
อรรถศาสตร์
ใช้ฟังก์ชันการลด body
กับหน้าต่างของ inputs
และ init_values
และสร้าง 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)
.
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | inputs |
จำนวน tensors แบบแปรผันหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1-C4), (C6), (C8), (C10), (C12), (C13), (C15) |
(I2) | init_values |
จำนวน tensors แบบ 0 มิติหรือต่อ tensor เชิงปริมาณ | (C1), (C13) |
(1) | window_dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C4), (C5), (C15) |
(I4) | window_strides |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C6), (C7), (C15) |
(1) | base_dilations |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C8), (C9), (C15) |
(1) | window_dilations |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C10), (C11), (C15) |
(1) | padding |
ค่าคงที่ tensor 2 มิติของประเภท si64 |
(C12), (C15) |
(i8) | body |
ฟังก์ชัน | (C13) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวน tensors แบบแปรผันหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (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)
element_type(results[i]) = Ei
สำหรับi
ทั้งหมดใน[0,N)
ตัวอย่าง
// %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 = dense<[2, 1]> : tensor<2xi64>,
window_strides = dense<[4, 1]> : tensor<2xi64>,
base_dilations = dense<[2, 1]> : tensor<2xi64>,
window_dilations = dense<[3, 1]> : tensor<2xi64>,
padding = dense<[[2, 1], [0, 0]]> : tensor<2x2xi64>
} : (tensor<3x2xi64>, tensor<i64>) -> tensor<2x2xi64>
// %result = [[0, 0], [3, 4]]
เศษ
อรรถศาสตร์
ดำเนินการคำนวณเศษที่เหลือของเงินปันผล lhs
และตัวหาร rhs
ตัวหาร แล้วสร้าง result
Tensor
หรืออย่างเป็นทางการ เครื่องหมายของผลลัพธ์จะนำมาจากตัวหาร และค่าสัมบูรณ์ของผลลัพธ์จะน้อยกว่าค่าสัมบูรณ์ของตัวหาร
เศษที่เหลือจะคำนวณเป็น lhs - d * rhs
โดย d
จะกำหนดโดย:
- สำหรับจำนวนเต็ม:
stablehlo.divide(lhs, rhs)
- สำหรับเลขทศนิยม:
division(lhs, rhs)
จาก IEEE-754 ที่มีแอตทริบิวต์การปัดเศษroundTowardZero
- สำหรับจำนวนเชิงซ้อน: TBD (#997)
- สำหรับประเภทที่เล็กลง
dequantize_op_quantize(remainder, lhs, rhs, type(result))
.
สำหรับประเภทองค์ประกอบจุดลอยตัว การดำเนินการนี้ตรงข้ามกับการดำเนินการ remainder
จากข้อกำหนด IEEE-754 โดยที่ d
เป็นค่าปริพันธ์ที่ใกล้เคียงที่สุดกับค่าที่แน่นอนของ lhs/rhs
โดยมีค่าเสมอกัน
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | lhs |
tensor ของจำนวนเต็ม ชนิดจุดลอยตัว หรือชนิดเชิงซ้อน หรือ tensor ที่วัดปริมาณด้วยต่อ tensor | (C1) |
(I2) | rhs |
tensor ของจำนวนเต็ม ชนิดจุดลอยตัว หรือชนิดเชิงซ้อน หรือ tensor ที่วัดปริมาณด้วยต่อ tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของจำนวนเต็ม ชนิดจุดลอยตัว หรือชนิดเชิงซ้อน หรือ tensor ที่วัดปริมาณด้วยต่อ tensor | (C1) |
ข้อจำกัด
- (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 |
Tensor แบบ 0 มิติของประเภท ui32 |
ตัวอย่าง
%result = "stablehlo.replica_id"() : () -> tensor<ui32>
ปรับรูปร่าง
อรรถศาสตร์
ดำเนินการปรับรูป Tensor operand
เป็น result
Tensor โดยหลักการแล้ว การคงรูปแบบ Canonical ให้คงเดิมแต่อาจเปลี่ยนรูปร่างได้ เช่น จาก tensor<2x3xf32>
เป็น tensor<3x2xf32>
หรือ tensor<6xf32>
เป็นทางการมากขึ้น result[result_index] = operand[operand_index]
โดยที่ result_index
และ operand_index
มีอันดับเดียวกันในลำดับแบบพจนานุกรมของ index_space(result)
และ index_space(operand)
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor หรือ tensor ที่วัดปริมาณแล้ว | (C1-C3) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือ tensor ที่วัดปริมาณแล้ว | (C1-C3) |
ข้อจำกัด
- (C1)
element_type(result)
ให้บริการโดยelement_type(operand)
หากเป็น!is_per_axis_quantized(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]]
ย้อนกลับ
อรรถศาสตร์
กลับลำดับขององค์ประกอบใน operand
ตาม dimensions
ที่ระบุและสร้าง result
Tensor เป็นทางการมากขึ้น
result[result_index] = operand[operand_index]
ซึ่ง
operand_index[d] = dim(result, d) - result_index[d] - 1
หากเป็นd
ในdimensions
- หากไม่ใช่
operand_index[d] = result_index[d]
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1), (C3) |
(I2) | dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C3) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (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 = dense<1> : tensor<1xi64>
} : (tensor<3x2xi32>) -> tensor<3x2xi32>
// %result: [[2, 1], [4, 3], [6, 5]]
คำตอบ
อรรถศาสตร์
สร้างตัวเลขสุ่มโดยใช้อัลกอริทึม rng_distribution
และสร้าง result
tensor ของรูปร่างที่กำหนด shape
หากค่าเป็น rng_distribution = UNIFORM
ระบบจะสร้างหมายเลขสุ่มหลังจากการกระจายที่สม่ำเสมอในช่วง [a, b)
หากเป็น a >= b
จะไม่มีการกำหนดลักษณะการทำงาน
หากค่าเป็น rng_distribution = NORMAL
ระบบจะสร้างตัวเลขสุ่มขึ้นตามการแจกแจงปกติที่มีค่าเฉลี่ย = a
และส่วนเบี่ยงเบนมาตรฐาน = b
หากเป็น b < 0
ระบบจะไม่ได้กำหนดลักษณะการทำงาน
วิธีการสร้างตัวเลขสุ่มที่แน่ชัดนั้นกำหนดไว้ว่าการนำไปใช้งาน ตัวอย่างเช่น โฆษณาเหล่านี้อาจใช้หรือไม่มีการกำหนดสถานะ และอาจใช้หรือไม่ใช้สถานะซ่อน
ในการพูดคุยกับผู้ถือผลประโยชน์ร่วมหลายราย พบว่าความเห็นนี้สิ้นสุดลงอย่างมีประสิทธิภาพแล้ว ดังนั้นในอนาคตเราจึงมีแผนที่จะหาวิธีนำการทดสอบออก (#597)
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | a |
tensor แบบ 0 มิติของจำนวนเต็ม บูลีน หรือประเภทจุดลอยตัว | (C1), (C2) |
(I2) | b |
tensor แบบ 0 มิติของจำนวนเต็ม บูลีน หรือประเภทจุดลอยตัว | (C1), (C2) |
(1) | shape |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C3) |
(I4) | rng_distribution |
enum ของ UNIFORM และ NORMAL |
(C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของจำนวนเต็ม บูลีน หรือประเภทจุดลอยตัว | (C1-C3) |
ข้อจำกัด
- (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
ที่เต็มไปด้วยบิตแบบสุ่มแบบเดียวกันและสถานะเอาต์พุตที่อัปเดต output_state
โดยใช้อัลกอริทึมของโปรแกรมสร้างตัวเลขสุ่ม rng_algorithm
ที่กำหนดสถานะเริ่มต้นเป็น initial_state
เอาต์พุตเหล่านี้รับประกันได้ว่าเป็นฟังก์ชันที่กำหนดของ initial_state
แต่ไม่รับประกันว่าจะตัดสินได้จากการใช้งานจริง
rng_algorithm
เป็นหนึ่งในค่าต่อไปนี้
DEFAULT
: อัลกอริทึมที่กำหนดการใช้งานTHREE_FRY
: ตัวแปรที่กำหนดโดยการใช้งานของอัลกอริทึม Threefry*PHILOX
: ตัวแปรที่ปรับใช้ของอัลกอริทึม Philox*
* ดู: Salmon et al. SC 2011. เลขสุ่มคู่ขนาน: ง่ายเหมือนนับ 1, 2, 3
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | rng_algorithm |
enum ของ DEFAULT , THREE_FRY และ PHILOX |
(C2) |
(I2) | initial_state |
Tensor แบบ 1 มิติของประเภท ui64 |
(C1), (C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
output_state |
Tensor แบบ 1 มิติของประเภท ui64 |
(C1) |
output |
Tensor ของจำนวนเต็มหรือประเภทจุดลอยตัว |
ข้อจำกัด
- (C1)
type(initial_state) = type(output_state)
- (C2)
size(initial_state)
ให้คำจำกัดความไว้ดังนี้- การใช้งานกำหนดไว้หากเป็น
rng_algorithm = DEFAULT
2
หากrng_algorithm = THREE_FRY
2
หรือ3
หากเป็นrng_algorithm = PHILOX
- การใช้งานกำหนดไว้หากเป็น
ตัวอย่าง
// %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
อรรถศาสตร์
ทำการปัดเศษแบบองค์ประกอบตามจำนวนเต็มที่ใกล้เคียงที่สุด โดยตัดความสัมพันธ์ออกจาก 0 ใน tensor ของ operand
และสร้าง Tensor result
ใช้การดำเนินการ roundToIntegralTiesToAway
จากข้อกำหนด IEEE-754 สำหรับประเภทที่เล็กลง จะแสดงผล dequantize_op_quantize(round_nearest_afz, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor ที่วัดปริมาณแล้ว | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor ที่วัดปริมาณแล้ว | (C1) |
ข้อจำกัด
- (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
อรรถศาสตร์
ทำการปัดเศษตามองค์ประกอบตามจำนวนเต็มที่ใกล้เคียงที่สุด โดยตัดความสัมพันธ์ที่มีต่อจำนวนเต็มคู่ใน tensor ใน operand
และสร้าง Tensor result
ใช้การดำเนินการ roundToIntegralTiesToEven
จากข้อกำหนด IEEE-754 สำหรับประเภทที่แบ่งปริมาณแล้ว จะแสดงผล dequantize_op_quantize(round_nearest_even, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor ที่วัดปริมาณแล้ว | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor ที่วัดปริมาณแล้ว | (C1) |
ข้อจำกัด
- (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
อรรถศาสตร์
ดำเนินการประมวลผลรากที่สองตามองค์ประกอบตามองค์ประกอบบน Tensor operand
และสร้าง tensor result
ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับเลขทศนิยม:
rSqrt
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: รากที่สองเชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(rsqrt, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
ข้อจำกัด
- (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]]
scatter
อรรถศาสตร์
สร้าง results
Tensor ซึ่งเท่ากับ inputs
tensors เว้นแต่ชิ้นส่วนหลายชิ้นที่ระบุโดย scatter_indices
จะได้รับการอัปเดตด้วยค่า updates
โดยใช้ update_computation
แผนภาพต่อไปนี้แสดงลักษณะที่องค์ประกอบใน updates...
จับคู่กับองค์ประกอบใน results...
โดยใช้ตัวอย่างที่เป็นรูปธรรม ไดอะแกรมจะเลือกตัวอย่างดัชนี updates...
2-3 รายการและอธิบายรายละเอียดว่าดัชนี results...
ใดเกี่ยวข้อง
อย่างเป็นทางการ สำหรับ update_index
ทั้งหมดใน index_space(updates[0])
:
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]]
- สำหรับ
d_input
ในaxes(inputs[0])
full_start_index[d_input] = start_index[d_start]
หากd_input = scatter_dims_to_operand_dims[d_start]
- หากไม่ใช่
full_start_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
result_index = full_start_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
โดยตั้งค่าresults...[result_index]
เป็น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
แต่ดัชนีที่กระจายอยู่นั้นซ้ำกัน จะไม่มีการกำหนดลักษณะการทำงาน
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | inputs |
จำนวน tensors แบบแปรผันหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1), (C2), (C4-C6), (C10), (C13), (C15-C16) |
(I2) | scatter_indices |
Tensor ของประเภทจำนวนเต็ม | (C4), (C11), (C14) |
(1) | updates |
จำนวน tensors แบบแปรผันหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C3-C6), (C8) |
(I4) | update_window_dims |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C4), (C7), (C8) |
(1) | inserted_window_dims |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C4), (C9), (C10) |
(1) | scatter_dims_to_operand_dims |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C11-C13) |
(1) | index_vector_dim |
ค่าคงที่ของประเภท si64 |
(C4), (C11), (C14) |
(i8) | indices_are_sorted |
ค่าคงที่ของประเภท i1 |
|
(I9) | unique_indices |
ค่าคงที่ของประเภท i1 |
|
(10) | update_computation |
ฟังก์ชัน | (C15) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวน tensors แบบแปรผันหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C15-C17) |
ข้อจำกัด
- (C1)
same(shape(inputs...))
- (C2)
rank(inputs[0]) = size(update_window_dims) + size(inserted_window_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])
เว้นแต่ว่าจะไม่รวมขนาดมิติข้อมูลในinputs[0]
ที่สอดคล้องกับinserted_window_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(inserted_window_dims) and is_sorted(update_window_dims)
- (C10)
0 <= inserted_window_dims < rank(inputs[0])
- (C11)
size(scatter_dims_to_operand_dims) = index_vector_dim < rank(scatter_indices) ? dim(scatter_indices, index_vector_dim) : 1
- (C12)
is_unique(scatter_dims_to_operand_dims)
- (C13)
0 <= scatter_dims_to_operand_dims < rank(inputs[0])
- (C14)
0 <= index_vector_dim <= rank(scatter_indices)
- (C15)
update_computation
มีประเภท(tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ..., tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>)
ที่is_promotable(element_type(inputs[i]), Ei)
- (C16)
shape(inputs...) = shape(results...)
- (C17)
element_type(results[i]) = Ei
สําหรับi
ทั้งหมดใน[0,N)
ตัวอย่าง
// %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]]
// ]
// %scatter_indices: [[[0, 2], [1, 0], [2, 1]], [[0, 1], [1, 0], [0, 9]]]
// %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 = [2, 3],
inserted_window_dims = [0],
scatter_dims_to_operand_dims = [1, 0],
index_vector_dim = 2>,
indices_are_sorted = false,
unique_indices = false
} : (tensor<3x4x2xi64>, tensor<2x3x2xi64>, tensor<2x3x2x2xi64>) -> tensor<3x4x2xi64>
// %result: [
// [[1, 2], [5, 6], [7, 8], [7, 8]],
// [[10, 11], [12, 13], [14, 15], [16, 17]],
// [[18, 19], [20, 21], [21, 22], [23, 24]]
// ]
เลือก
อรรถศาสตร์
สร้าง result
Tensor ที่เลือกองค์ประกอบแต่ละรายการจาก on_true
หรือ on_false
Tensor ตามค่าขององค์ประกอบ pred
ที่สอดคล้องกัน
เป็นทางการมากขึ้น 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))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | pred |
Tensor ประเภท i1 |
(C1) |
(I2) | on_true |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1-C2) |
(1) | on_false |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C2) |
ข้อจำกัด
- (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
อรรถศาสตร์
กระจายค่าจาก source
tensor โดยใช้ scatter
ตามผลลัพธ์ของ reduce_window
ของ input
tensor โดยใช้ select
และสร้าง
tensor. result
แผนภาพต่อไปนี้แสดงวิธีคำนวณองค์ประกอบใน result
จาก operand
และ source
โดยใช้ตัวอย่างที่เป็นรูปธรรม
เป็นทางการมากขึ้น:
selected_values = reduce_window_without_init(...)
พร้อมอินพุตต่อไปนี้- `inputs = [ตัวถูกดำเนินการ]
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]
.
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1-C4), (C6), (C8-C11) |
(I2) | source |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1), (C2) |
(1) | init_value |
tensor แบบ 0 มิติหรือต่อ tensor ที่วัดปริมาณแล้ว | (C3) |
(I4) | window_dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C4), (C5) |
(1) | window_strides |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C6), (C7) |
(1) | padding |
ค่าคงที่ tensor 2 มิติของประเภท si64 |
(C2), (C8) |
(1) | select |
ฟังก์ชัน | (C9) |
(i8) | scatter |
ฟังก์ชัน | (C10) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (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 = dense<[3, 1]> : tensor<2xi64>,
window_strides = dense<[2, 1]> : tensor<2xi64>,
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)
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | inputs |
จำนวน tensors แบบแปรผันหรือ tensors เชิงปริมาณ | |
(I2) | token |
token |
|
(1) | channel_id |
ค่าคงที่ของประเภท si64 |
|
(I4) | channel_type |
enum ของ DEVICE_TO_DEVICE และ DEVICE_TO_HOST |
(C1) |
(1) | is_host_transfer |
ค่าคงที่ของประเภท i1 |
(C1) |
เอาต์พุต
ชื่อ | ประเภท |
---|---|
result |
token |
ข้อจำกัด
- (C1)
channel_type
ให้คำจำกัดความไว้ดังนี้DEVICE_TO_HOST
หากเป็นis_host_transfer = true
- หากไม่ใช่
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
อรรถศาสตร์
ดำเนินการใช้ชิฟท์ด้านซ้ายตามองค์ประกอบบน Tensor lhs
ตามจำนวนบิต rhs
และสร้าง Tensor result
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | lhs |
Tensor ของประเภทจำนวนเต็ม | (C1) |
(I2) | rhs |
Tensor ของประเภทจำนวนเต็ม | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor ของประเภทจำนวนเต็ม | (C1) |
ข้อจำกัด
- (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
อรรถศาสตร์
ดำเนินการ Shift ขวาสำหรับเลขคณิตตามองค์ประกอบบน tensor ใน lhs
ตามจำนวนบิต rhs
และสร้าง result
Tensor
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | lhs |
Tensor ของประเภทจำนวนเต็ม | (C1) |
(I2) | rhs |
Tensor ของประเภทจำนวนเต็ม | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor ของประเภทจำนวนเต็ม | (C1) |
ข้อจำกัด
- (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
และสร้าง Tensor result
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | lhs |
Tensor ของประเภทจำนวนเต็ม | (C1) |
(I2) | rhs |
Tensor ของประเภทจำนวนเต็ม | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor ของประเภทจำนวนเต็ม | (C1) |
ข้อจำกัด
- (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
และสร้าง tensor 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))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
Tensor ของจำนวนเต็มแบบมีเครื่องหมาย ประเภทจุดลอยตัว หรือประเภทเชิงซ้อน หรือ tensor ที่เล็กลงแบบต่อ tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor ของจำนวนเต็มแบบมีเครื่องหมาย ประเภทจุดลอยตัว หรือประเภทเชิงซ้อน หรือ tensor ที่เล็กลงแบบต่อ tensor | (C1) |
ข้อจำกัด
- (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]
ไซน์
อรรถศาสตร์
ดำเนินการดำเนินการไซน์ตามองค์ประกอบใน Tensor operand
และสร้าง Tensor result
ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับเลขทศนิยม:
sin
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: ไซน์เชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(sine, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
ข้อจำกัด
- (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
โดยใช้ดัชนีเริ่มต้นที่คำนวณแบบคงที่
และสร้าง tensor result
start_indices
มีดัชนีเริ่มต้นของสไลซ์สำหรับแต่ละมิติข้อมูล ส่วน limit_indices
มีดัชนีสิ้นสุด (เฉพาะตัว) สำหรับสไลซ์ของแต่ละมิติข้อมูล และ strides
มีข้อมูลขีดคั่นสำหรับแต่ละมิติข้อมูล
อย่างเป็นทางการคือ result[result_index] = operand[operand_index]
ที่ไหน
operand_index = start_indices + result_index * strides
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1-C3), (C5) |
(I2) | start_indices |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C3), (C5) |
(1) | limit_indices |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C3), (C5) |
(I4) | strides |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C4) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ tensor ที่วัดปริมาณด้วย tensor | (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 = dense<[1, 2]> : tensor<2xi64>,
limit_indices = dense<[3, 4]> : tensor<2xi64>,
strides = dense<1> : tensor<2xi64>
} : (tensor<3x4xi64>) -> tensor<2x2xi64>
// % result: [
// [1, 1],
// [1, 1]
// ]
จัดเรียง
อรรถศาสตร์
จัดเรียงชิ้นส่วน 1 มิติของ inputs
ตามมิติข้อมูล dimension
ร่วมกัน โดยอิงตาม comparator
และสร้าง results
dimension
จะอนุญาตค่าลบซึ่งมีอรรถศาสตร์ที่อธิบายไว้ด้านล่าง ซึ่งต่างจากอินพุตที่คล้ายกันในการดําเนินการอื่นๆ ในอนาคตระบบอาจไม่อนุญาตให้ใช้การให้สิทธิ์นี้เนื่องด้วยเหตุผลด้านความสอดคล้อง (#1377)
หาก is_stable
เป็นจริง การจัดเรียงจะคงที่ กล่าวคือ ลำดับขององค์ประกอบที่ถือว่าเท่ากันโดยตัวเปรียบเทียบจะยังคงเดิม สำหรับกรณีที่มีอินพุตเดียว องค์ประกอบ 2 รายการ ได้แก่ e1
และ e2
จะถือว่าเท่ากันโดยตัวเปรียบเทียบในกรณีที่ comparator(e1, e2) = comparator(e2, e1) = false
เท่านั้น ดูความเป็นทางการด้านล่าง
เพื่อดูว่าข้อมูลเหล่านี้เข้ากับอินพุตต่างๆ อย่างไร
อย่างเป็นทางการ สำหรับ result_index
ทั้งหมดใน index_space(results[0])
:
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
หากอาร์กิวเมนต์ด้านซ้ายมือน้อยกว่าอาร์กิวเมนต์ที่ 2 ด้านขวามือ 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
.
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | inputs |
จำนวน tensors แบบแปรผันหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1-C5) |
(I2) | dimension |
ค่าคงที่ของประเภท si64 |
(C4) |
(1) | is_stable |
ค่าคงที่ของประเภท i1 |
|
(I4) | comparator |
ฟังก์ชัน | (C5) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวน tensors แบบแปรผันหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (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]]
sqrt
อรรถศาสตร์
ดำเนินการใช้รากที่สองของเอลิเมนต์ใน Tensor operand
และสร้าง Tensor result
ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับเลขทศนิยม:
squareRoot
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: รากที่สองเชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(sqrt, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
ข้อจำกัด
- (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]]
ลบ
อรรถศาสตร์
ทำการลบ tensors 2 แบบ lhs
และ rhs
แล้วสร้าง
result
tensor ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับจำนวนเต็ม: การลบจำนวนเต็ม
- สำหรับเลขทศนิยม:
subtraction
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: การลบเชิงซ้อน
- สำหรับประเภทที่เล็กลง
dequantize_op_quantize(subtract, lhs, rhs, type(result))
.
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | lhs |
tensor ของจำนวนเต็ม จุดลอยตัว หรือชนิดเชิงซ้อน หรือ tensor ที่วัดปริมาณด้วยต่อ tensor | (C1) |
(I2) | rhs |
tensor ของจำนวนเต็ม จุดลอยตัว หรือชนิดเชิงซ้อน หรือ tensor ที่วัดปริมาณด้วยต่อ tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของจำนวนเต็ม จุดลอยตัว หรือชนิดเชิงซ้อน หรือ tensor ที่วัดปริมาณด้วยต่อ tensor | (C1) |
ข้อจำกัด
- (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]]
Tanh
อรรถศาสตร์
ดำเนินการดำเนินการไฮเปอร์โบลิกแทนเจนต์แบบ Element-wise ใน tensor operand
และสร้าง Tensor result
ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับเลขทศนิยม:
tanh
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: ไฮเปอร์โบลิกแทนเจนต์เชิงซ้อน
- สำหรับประเภทที่เล็กลง
dequantize_op_quantize(tanh, operand, type(result))
.
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
ข้อจำกัด
- (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]
สลับตำแหน่ง
อรรถศาสตร์
เรียงสับเปลี่ยนมิติข้อมูลของ operand
Tensor โดยใช้ permutation
และสร้าง result
Tensor อย่างเป็นทางการคือ result[result_index] = operand[operand_index]
ที่ result_index[d] = operand_index[permutation[d]]
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor หรือ tensor ที่วัดปริมาณแล้ว | (C1-C4) |
(I2) | permutation |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2-C4) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือ tensor ที่วัดปริมาณแล้ว | (C1), (C3-C4) |
ข้อจำกัด
- (C1)
element_type(result)
ให้บริการโดยelement_type(operand)
หากเป็น!is_per_axis_quantized(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 = dense<[2, 1, 0]> : tensor<3xi64>
} : (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
ข้อมูลที่ป้อนจะอ่านจากสามเหลี่ยมล่างของ a
เท่านั้น หาก lower
เป็น true
หรือสามเหลี่ยมบนของ 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))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | a |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1-C3) |
(I2) | b |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1-C4) |
(1) | left_side |
ค่าคงที่ของประเภท i1 |
(C3) |
(I4) | lower |
ค่าคงที่ของประเภท i1 |
|
(1) | unit_diagonal |
ค่าคงที่ของประเภท i1 |
|
(1) | transpose_a |
enum ของ NO_TRANSPOSE , TRANSPOSE และ ADJOINT |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของชนิดจุดลอยตัวหรือชนิดเชิงซ้อนหรือต่อ tensor ที่วัดปริมาณด้วย tensor | (C1) |
ข้อจำกัด
- (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]
// ]
tuple
อรรถศาสตร์
สร้าง Tuple result
จากค่า val
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | val |
จำนวนค่าที่แตกต่างกัน | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tuple | (C1) |
ข้อจำกัด
- (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
อรรถศาสตร์
ทำการแปลง tensor เชิงปริมาณ operand
เป็น tensor แบบจุดลอยตัว result
ตามพารามิเตอร์เชิงปริมาณที่กำหนดโดยประเภท operand
เป็นทางการมากขึ้นแล้วนะ result = dequantize(operand)
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor ที่วัดปริมาณแล้ว | (C1), (C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor ของประเภทจุดลอยตัว | (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
อรรถศาสตร์
แปลง tensor แบบ Floating Point หรือ tensor เชิงปริมาณ
operand
เป็น tensor ที่วัดปริมาณด้วย result
ตามพารามิเตอร์การทำเชิงปริมาณที่กำหนดโดยประเภท result
อย่างเป็นทางการ
- หากเป็น
is_float(operand)
result = quantize(operand, type(result))
.
- หากเป็น
is_quantized(operand)
float_result = dequantize(operand)
.result = quantize(float_result, type(result))
.
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
tensor ของชนิดจุดลอยตัวหรือแบบตัวปริมาณ | (C1), (C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ที่วัดปริมาณแล้ว | (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
ลักษณะการทำงานของการวนซ้ำที่ไม่มีสิ้นสุดคือ TBD (#383)
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | operand |
จำนวน tensors หลากหลายแบบ, tensors ในเชิงปริมาณ หรือโทเค็น | (C1-C3) |
(I2) | cond |
ฟังก์ชัน | (C1) |
(1) | body |
ฟังก์ชัน | (C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวน tensors หลากหลายแบบ, tensors ในเชิงปริมาณ หรือโทเค็น | (C3) |
ข้อจำกัด
- (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
Xor
อรรถศาสตร์
ดำเนินการ XOR ตามองค์ประกอบของ tensor 2 รายการ lhs
และ rhs
แล้วสร้าง result
tensor ระบบจะดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับบูลีน: ตรรกะ XOR
- สำหรับจำนวนเต็ม: Bitwise XOR
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(1) | lhs |
Tensor ของประเภทบูลีนหรือจำนวนเต็ม | (C1) |
(I2) | rhs |
Tensor ของประเภทบูลีนหรือจำนวนเต็ม | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor ของประเภทบูลีนหรือจำนวนเต็ม | (C1) |
ข้อจำกัด
- (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 จะดำเนินการโดยระบุค่าอินพุตให้กับฟังก์ชัน main
และค่าเอาต์พุตการคำนวณ ระบบจะคํานวณค่าเอาต์พุตของฟังก์ชันโดยการเรียกใช้กราฟของ Ops ที่รูทในตัวเลือก return
ที่สอดคล้องกัน
ลำดับการดำเนินการมีการกำหนดไว้สำหรับการใช้งานตราบใดที่สอดคล้องกับโฟลว์ข้อมูล กล่าวคือ เมื่อมีการดำเนินการ Ops ก่อนที่จะใช้งาน ใน StableHLO การดำเนินการที่ส่งผลข้างเคียงทั้งหมดจะใช้ 1 โทเค็นและสร้างโทเค็น 1 รายการ (สามารถรวมโทเค็นหลายรายการไว้ในโทเค็นเดียวผ่าน after_all
ได้) เพื่อให้ลำดับการดำเนินการของผลข้างเคียงสอดคล้องกับโฟลว์ข้อมูลด้วย คำสั่งการดำเนินการที่เป็นไปได้ของโปรแกรมตัวอย่างด้านบนคือ %0
→ %1
→ %2
→ %3
→ %4
→ return
หรือ %3
→ %0
→
%1
→ %2
→ %4
→ return
หรืออย่างเป็นทางการ กระบวนการของ StableHLO ประกอบด้วย 1) โปรแกรม StableHLO, 2) สถานะการดำเนินการ (ยังไม่ได้ดำเนินการ หรือดำเนินการแล้ว) และ 3) ค่าขั้นกลางที่กระบวนการกําลังดําเนินการ ได้แก่ 1) โปรแกรม StableHLO
กระบวนการเริ่มต้นด้วยค่าอินพุตสำหรับฟังก์ชัน main
แล้วดำเนินการต่อผ่านกราฟของการดำเนินการอัปเดตสถานะการดำเนินการและค่ากลางและค่าสุดท้ายด้วยค่าเอาต์พุต การประกาศอย่างเป็นทางการจะมีขึ้นภายหลัง
(#484)
การดำเนินการพร้อมกัน
โปรแกรม StableHLO ดำเนินการพร้อมกันได้ โดยจัดระเบียบเป็นตารางกระบวนการ 2 มิติของ num_replicas
โดย num_partitions
ซึ่งทั้ง 2 โปรแกรมมีประเภท ui32
ในตารางกริดกระบวนการของ StableHLO กระบวนการของ StableHLO ดำเนินการ num_replicas * num_partitions
รายการพร้อมกัน แต่ละกระบวนการมี process_id = (replica_id, partition_id)
ที่ไม่ซ้ำกัน โดยที่ replica_id
ใน replica_ids = range(num_replicas)
และ partition_id
ใน partition_ids = range(num_partitions)
ซึ่งทั้งคู่มีประเภท ui32
ทุกๆ โปรแกรมทราบขนาดของตารางกริดกระบวนการ (ในอนาคต เราวางแผนที่จะทำให้เป็นส่วนที่ชัดเจนของโปรแกรม StableHLO #650)) และทราบตำแหน่งภายในตารางกริดของกระบวนการเป็นแบบคงที่สำหรับทุกกระบวนการ แต่ละกระบวนการมีสิทธิ์เข้าถึงตำแหน่งภายในตารางกริดของกระบวนการผ่านการดำเนินการ replica_id
และ partition_id
ภายในตารางกระบวนการ โปรแกรมอาจเหมือนกันทั้งหมด (ในรูปแบบ "โปรแกรมเดียว ข้อมูลหลายรายการ") หรือแตกต่างกันได้ (ในรูปแบบ "หลายโปรแกรม ข้อมูลหลายรายการ") หรืออื่นๆ ระหว่างนั้น ในอนาคต เราวางแผนที่จะเพิ่มการรองรับสำนวนอื่นๆ ของการกำหนดโปรแกรม StableHLO พร้อมกัน ซึ่งรวมถึง GSPMD (#619)
ภายในตารางกริดของกระบวนการ กระบวนการส่วนใหญ่จะเป็นอิสระจากกัน กล่าวคือมีสถานะการดำเนินการแยกกัน ค่าอินพุต/สื่อกลาง/เอาต์พุตแยกกัน และการดำเนินการส่วนใหญ่จะดำเนินการแยกกันระหว่างกระบวนการ โดยมีข้อยกเว้นของการดำเนินการโดยรวมจำนวนหนึ่งตามที่อธิบายไว้ด้านล่าง
เนื่องจากการดำเนินการของการดำเนินการส่วนใหญ่ใช้เฉพาะค่าจากกระบวนการเดียวกัน การอ้างอิงค่าเหล่านี้ด้วยชื่อจึงมักไม่ชัดเจน
อย่างไรก็ตาม เมื่ออธิบายความหมายของการดำเนินการโดยรวมนั้นไม่เพียงพอ และเป็นที่มาของสัญลักษณ์ name@process_id
เพื่ออ้างถึงค่า name
ภายในกระบวนการใดกระบวนการหนึ่ง (จากมุมมองนี้ name
ที่ไม่เข้าเกณฑ์อาจมองได้ว่าเป็นชวเลขสำหรับ name@(replica_id(), partition_id())
)
คำสั่งดำเนินการข้ามกระบวนการจะกำหนดตามการติดตั้งใช้งาน ยกเว้นการซิงค์ที่เกิดจากการสื่อสารแบบจุดต่อจุดและการดำเนินการร่วมตามที่อธิบายไว้ด้านล่าง
การสื่อสารแบบจุดต่อจุด
กระบวนการของ StableHLO สามารถสื่อสารกันได้ผ่านช่องทางของ StableHLO แชแนลจะแสดงด้วยรหัสเชิงบวกประเภท si64
คุณสามารถส่งค่าไปยังแชแนลและรับค่าจากแชแนลได้โดยอาศัยการดำเนินการที่หลากหลาย
ความเป็นทางการเพิ่มเติม เช่น รหัสแชแนลเหล่านี้มาจากที่ใด โปรแกรมรับรู้ถึงรหัสเหล่านี้อย่างไร และขั้นตอนการซิงค์ข้อมูลแบบใดมาจากข้อมูลดังกล่าว จะแจ้งภายหลัง (#484)
การสื่อสารผ่านสตรีมมิง
กระบวนการของ StableHLO ทุกกระบวนการมีสิทธิ์เข้าถึงอินเทอร์เฟซสตรีมมิง 2 รายการดังนี้
- Infeed ที่อ่านได้
- Outfeed ที่ระบบเขียนได้
และต่างจากแชแนลที่ใช้สื่อสารระหว่างกระบวนการต่างๆ จึงมีกระบวนการอยู่ทั้ง 2 ฝั่ง ในฟีดในฟีดและฟีดภายนอกมีการกำหนดไว้แล้ว
ความเป็นทางการเพิ่มเติม เช่น การสื่อสารผ่านสตรีมมิงมีอิทธิพลต่อคำสั่งการดำเนินการอย่างไรและประเภทของการซิงค์ที่จะนำมาใช้ในภายหลัง เช่น แจ้งภายหลัง (#484)
การดำเนินการร่วมกัน
ระบบดำเนินการร่วมกัน 6 รายการใน StableHLO ได้แก่ all_gather
, all_reduce
,
all_to_all
, collective_broadcast
, collective_permute
และ
reduce_scatter
การดำเนินการทั้งหมดนี้แยกกระบวนการในตารางกระบวนการ StableHLO ออกเป็นกลุ่มกระบวนการ StableHLO และดำเนินการคำนวณร่วมภายในแต่ละกลุ่มกระบวนการ โดยแยกจากกลุ่มกระบวนการอื่นๆ
ภายในกลุ่มกระบวนการแต่ละกลุ่ม การดำเนินการร่วมอาจพบอุปสรรคในการซิงค์ ความเป็นทางการเพิ่มเติม เช่น การให้รายละเอียดว่าการซิงค์นี้เกิดขึ้นเมื่อใด กระบวนการต่างๆ มาถึงอุปสรรคนี้ได้อย่างไร และจะเกิดอะไรขึ้นหากไม่เป็นเช่นนั้น จะแจ้งภายหลัง (#484)
หากกลุ่มกระบวนการเกี่ยวข้องกับการสื่อสารแบบข้ามพาร์ติชัน กล่าวคือ มีกระบวนการในกลุ่มกระบวนการที่มีรหัสพาร์ติชันแตกต่างกัน การดำเนินการของ ฝั่งองค์กร จะต้องใช้แชนเนล และการทำงานร่วมกันแบบรวมต้องมี channel_id
ที่เป็นบวกประเภท si64
การสื่อสารข้ามแบบจำลองไม่จำเป็นต้องมี
แชแนล
การคำนวณที่ดำเนินการโดยกลุ่มการดำเนินการร่วมกันนั้นเฉพาะเจาะจงสำหรับแต่ละการดำเนินการ และมีคำอธิบายในส่วนการดำเนินการของแต่ละส่วนด้านบน อย่างไรก็ตาม กลยุทธ์ที่แบ่งตารางกระบวนการออกเป็นกลุ่มกระบวนการจะมีการแชร์กันระหว่างการดำเนินการเหล่านี้ ซึ่งมีอธิบายไว้ในส่วนนี้ อย่างเป็นทางการคือ StableHLO รองรับ กลยุทธ์ 4 แบบต่อไปนี้
cross_replica
เฉพาะการสื่อสารจากตัวจำลองที่เกิดขึ้นภายในแต่ละกลุ่มกระบวนการเท่านั้น กลยุทธ์นี้ใช้ replica_groups
ซึ่งเป็นรายการรหัสตัวจำลอง และคำนวณผลคูณคาร์ทีเซียนของ replica_groups
ภายในวันที่ partition_ids
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
ซึ่งเป็นรายการรหัสพาร์ติชัน และคำนวณผลคูณคาร์ทีเซียนของ partition_groups
ตาม replica_ids
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 ได้รับการตรวจสอบผ่านชุดข้อจำกัดขนาดใหญ่สำหรับการดำเนินการรายบุคคล ซึ่งจะตัดข้อผิดพลาดประเภทต่างๆ ก่อนการเรียกใช้ อย่างไรก็ตาม เงื่อนไขข้อผิดพลาดยังคงเกิดขึ้นได้ เช่น เมื่อมีข้อมูลเกินจํานวนเต็ม การเข้าถึงเกินขอบเขต ฯลฯ ข้อผิดพลาดทั้งหมดเหล่านี้ส่งผลให้เกิดลักษณะการทํางานที่กําหนดการติดตั้งใช้งาน ซึ่งอาจมีการเปลี่ยนแปลงในอนาคต (#1157) เว้นแต่จะมีการเรียกอย่างชัดแจ้ง
ข้อยกเว้นของกฎนี้คือ ข้อยกเว้นจุดลอยตัวในโปรแกรม StableHLO มีลักษณะการทำงานที่กำหนดไว้อย่างชัดเจน การดำเนินการที่ทำให้เกิดข้อยกเว้นซึ่งกำหนดโดยมาตรฐาน IEEE-754 (การดำเนินการที่ไม่ถูกต้อง การแบ่งทีละศูนย์ การล้น ส่วนที่เกินมา หรือข้อยกเว้นที่ไม่ตรง) จะให้ผลลัพธ์เริ่มต้น (ตามที่กำหนดไว้ในมาตรฐาน) และดำเนินการต่อไปโดยไม่เพิ่มแฟล็กสถานะที่เกี่ยวข้อง ซึ่งคล้ายกับการจัดการข้อยกเว้น raiseNoFlag
จากมาตรฐาน ข้อยกเว้นสำหรับการดำเนินการที่ไม่เป็นมาตรฐาน (เช่น เลขคณิตที่ซับซ้อนและฟังก์ชันสืบเนื่องบางอย่าง) มีการกำหนดการนำไปใช้งาน
เครื่องหมาย
ในการอธิบายไวยากรณ์ เอกสารนี้ใช้เวอร์ชัน ISO ที่แก้ไขแล้วของไวยากรณ์ EBNF (ISO/IEC 14977:1996, Wikipedia) โดยมีการแก้ไข 2 ประการ ได้แก่ 1) กฎกำหนดโดยใช้ ::=
แทนที่จะเป็น =
2) การต่อกันจะแสดงโดยใช้การวางตัวต่อกันแทนการใช้ ,
สำหรับการอธิบายอรรถศาสตร์ (เช่น ภายในส่วน "ประเภท" "ค่าคงที่" และ "Ops") เราจะใช้สูตรที่อิงตามไวยากรณ์ Python ที่ขยายเพิ่มพร้อมด้วยการรองรับการแสดงการทำงานของอาร์เรย์อย่างกระชับตามที่อธิบายไว้ด้านล่าง วิธีนี้ใช้ได้ดีกับข้อมูลโค้ดสั้นๆ แต่ในบางกรณีซึ่งพบได้ไม่บ่อยนักเมื่อต้องขอข้อมูลโค้ดขนาดใหญ่ เราจะใช้ไวยากรณ์ Python แบบวานิลลาซึ่งมีการระบุไว้อย่างชัดเจนเสมอ
สูตร
มาสำรวจวิธีการทำงานของสูตรตามตัวอย่างจากข้อกำหนด dot_general
กัน หนึ่งในข้อจำกัดสำหรับการดำเนินการนี้มีลักษณะดังต่อไปนี้ dim(lhs, lhs_batching_dimensions...) = dim(rhs, rhs_batching_dimensions...)
ชื่อที่ใช้ในสูตรนี้มาจากแหล่งที่มา 2 แหล่ง ได้แก่ 1) ฟังก์ชันส่วนกลาง (เช่น dim
) 2) คำนิยามสมาชิกขององค์ประกอบโปรแกรมที่สอดคล้องกัน ซึ่งก็คืออินพุต lhs
, lhs_batching_dimensions
, rhs
และ rhs_batching_dimensions
ที่กำหนดไว้ในส่วน "อินพุต" ของ dot_general
ดังที่กล่าวไว้ข้างต้น ไวยากรณ์ของสูตรนี้คือแบบ Python ที่มีส่วนขยายบางส่วนที่เน้นความกระชับ เพื่อให้เข้าใจสูตร เรามาเปลี่ยนรูปแบบเป็นไวยากรณ์ Python แบบวานิลลากัน
ตอบ) ในสูตรเหล่านี้ เราใช้ =
เพื่อแสดงความเท่ากัน ดังนั้นขั้นตอนแรกในการได้รับไวยากรณ์ Python จะแทนที่ =
ด้วย ==
ดังนี้
dim(lhs, lhs_batching_dimensions...) == dim(rhs, rhs_batching_dimensions...)
B) นอกจากนี้ สูตรเหล่านี้ยังรองรับจุดไข่ปลา (...
) ซึ่งเปลี่ยนนิพจน์สเกลาร์เป็นนิพจน์ tensor โดยสรุปแล้ว f(xs...)
หมายถึง "สำหรับ x
สเกลาร์แต่ละรายการใน tensor xs
ให้คำนวณสเกลาร์ f(x)
แล้วแสดงผลลัพธ์สเกลาร์เหล่านี้ทั้งหมดรวมกันเป็นผลลัพธ์ Tensor" ในไวยากรณ์ 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 โดยหวังว่าเนื้อหาจะยังเข้าใจได้ง่ายโดยแยกเป็นรายกรณีไป
โปรดแจ้งให้เราทราบหากบางสูตรดูไม่ชัดเจนและเราจะพยายามปรับปรุง
คุณจะสังเกตเห็นว่าสูตรใช้จุดไข่ปลาเพื่อขยายรายการทุกประเภท รวมถึง tensors, รายการ tensors (ซึ่งอาจเกิดจากจำนวน tensors แปรปรวน) ฯลฯ นี่เป็นอีกเรื่องหนึ่งที่เราไม่ได้ระบุความเป็นทางการที่แน่นอน (เช่น รายการไม่ได้เป็นส่วนหนึ่งของระบบประเภท StableHLO ที่เข้าใจได้ง่าย) และอาศัยการเข้าใจรูปแบบ
ค) สัญลักษณ์สำคัญข้อสุดท้ายที่เราใช้คือการออกอากาศโดยนัย แม้ว่าตัวเลือกของ StableHLO จะไม่รองรับการออกอากาศโดยนัย แต่สูตรเหล่านี้ก็รองรับในรูปแบบของความกระชับเช่นกัน สรุปง่ายๆ ก็คือ หากใช้สเกลาร์ในบริบทที่คาดว่า tensor ก็จะแสดงสเกลาร์เป็นรูปร่างที่คาดไว้
ต่อไปนี้คือข้อจำกัดอีก 1 ข้อเพื่อแสดงตัวอย่าง dot_general
ต่อ 0 <= lhs_batching_dimensions < rank(lhs)
ตามที่ระบุไว้ในข้อมูลจำเพาะของ dot_general
lhs_batching_dimensions
คือ Tensor แต่ทั้ง 0
และ rank(lhs)
เป็นสเกลาร์ หลังจากเราใช้การออกอากาศโดยนัยแล้ว สูตรจะกลายเป็น [0, ..., 0] <= lhs_batching_dimensions < [rank(lhs), ..., rank(lhs)]
เมื่อใช้กับการดำเนินการ dot_general
ที่เฉพาะเจาะจง สูตรนี้จะประเมินโดยใช้ tensor ของบูลีน เมื่อใช้สูตรเป็นข้อจำกัด ข้อจำกัดจะระงับหากสูตรประเมินเป็น true
หรือกับ tensor ที่มีองค์ประกอบ 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
(ประเภทตามที่กำหนดในส่วน "ประเภท") ตามที่ให้คำจำกัดความไว้ในส่วน "ฟังก์ชันร่วม)Function
ชื่ออาจหมายถึงค่าที่ต่างกัน ทั้งนี้ขึ้นอยู่กับบริบท กล่าวอย่างเจาะจงคือ ส่วน "Semantics" สำหรับ Ops (และองค์ประกอบที่เทียบเท่าสำหรับองค์ประกอบอื่นๆ ของโปรแกรม) จะกำหนดตรรกะรันไทม์ ดังนั้นอินพุตทั้งหมดจึงพร้อมใช้งานเป็น Value
ในทางตรงกันข้าม ส่วน "ข้อจำกัด" สำหรับการดำเนินการ (และที่เทียบเท่า) จะกำหนดตรรกะ "เวลาคอมไพล์" ซึ่งก็คือสิ่งที่มักดำเนินการก่อนรันไทม์ ดังนั้นจะมีเฉพาะอินพุตคงที่ที่พร้อมใช้งานเป็น 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
ในข้อจำกัดเท่านั้น
ฟังก์ชัน
การสร้างประเภทต่างๆ
โดยจะไม่มีฟังก์ชันที่ใช้สร้างประเภทได้ แต่เราจะใช้ไวยากรณ์ประเภทโดยตรงแทนเนื่องจากรูปแบบนี้จะกระชับกว่า เช่น (tensor<E>, tensor<E>) -> (tensor<E>)
แทนที่จะเป็น function_type(
[tensor_type([], E), tensor_type([], E)], [tensor_type([], E)])
ฟังก์ชันเกี่ยวกับประเภท
element_type
กำหนดไว้ในประเภท tensor และประเภท tensor ที่วัดปริมาณแล้วและผลลัพธ์กลับมา ตามลําดับ ส่วน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
พร้อมใช้งานสำหรับ ทุกประเภท เช่นis_float(x)
จะแสดงผลtrue
หากx
เป็นFloatType
หาก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)
จะแสดงผลส่วนTensorElementType
ของTensorType
ที่ตรงกัน หากx
เป็นค่าหรือตัวยึดตำแหน่ง ฟังก์ชันนี้จะเป็นทางลัดสำหรับmember_name(type(x))
หากx
ไม่ใช่ประเภทที่มีสมาชิกที่เหมาะสม หรือมีค่าหรือตัวยึดตำแหน่งของประเภทดังกล่าว ระบบจะแสดงผลNone
โครงสร้างของค่า
operation_name(*xs: Value | Type) -> Value
พร้อมใช้งานสำหรับการดำเนินการทั้งหมด ตัวอย่างเช่นadd(lhs, rhs)
รับค่า tensor 2 ค่าlhs
และrhs
และแสดงค่าเอาต์พุตของการประเมินการดำเนินการadd
ด้วยอินพุตเหล่านี้ สำหรับการดำเนินการบางอย่าง เช่นbroadcast_in_dim
ประเภทของเอาต์พุตคือ "การรับน้ำหนัก" นั่นคือจำเป็นสำหรับการประเมินการดำเนินการ ในกรณีนี้ ฟังก์ชันนี้ จะใช้ประเภทเหล่านี้เป็นอาร์กิวเมนต์
ฟังก์ชันของค่า
โอเปอเรเตอร์และฟังก์ชันทั้งหมดของ Python พร้อมใช้งาน เช่น ทั้งเครื่องหมาย subscription และ Slicing จาก Python สามารถจัดทำดัชนีเป็น tensors, tensors แบบวัดปริมาณ และ tuple ได้
to_destination_type(x: Value, destination_type: Type) -> Value
กำหนดไว้ตาม tensors และแสดงผลค่าที่แปลงแล้วของx
โดยอิงตามtype(x)
และdestination_type
ดังนี้
def to_destination_type(x: Value, destination_type: Type) -> Value:
if type(x) == destination_type:
return x
if is_quantized(destination_type):
if is_quantized(type(x)):
return quantize(x, destination_type)
assert is_float(type(x))
return quantize(x, destination_type)
if is_quantized(type(x)):
assert destination_type = expressed_type(type(x))
return dequantize(type(x))
return convert(x, destination_type)
มีการพูดคุยล่วงหน้าเกี่ยวกับการรวมการดำเนินการ convert
, uniform_quantize
และ uniform_dequantize
(#1576)
หลังจากผสานแล้ว เราไม่จำเป็นต้องใช้ฟังก์ชันข้างต้น และจะใช้ชื่อการดำเนินการสำหรับ convert
แทนได้
is_nan(x: Value) -> Value
จะได้รับการกำหนดใน tensors และแสดงผลtrue
หากองค์ประกอบทั้งหมดของx
เป็นNaN
หรือfalse
ในกรณีอื่นๆ หากx
ไม่ใช่ Tensor จะแสดงผลNone
มีการกำหนด
is_sorted(x: Value) -> Value
ใน tensors และจะแสดงผลtrue
หากองค์ประกอบของx
ได้รับการจัดเรียงจากน้อยไปมากตามลำดับพจนานุกรมของดัชนีจากน้อยไปมากของดัชนี หรือfalse
ในกรณีอื่นๆ หากx
ไม่ใช่ Tensor จะแสดงผลNone
is_unique(x: Value) -> Value
จะได้รับการกำหนดใน Tensor และแสดงค่าtrue
หากx
ไม่มีองค์ประกอบที่ซ้ำกันหรือfalse
ในกรณีอื่นๆ หากx
ไม่ใช่ Tensor จะแสดงผลNone
member_name(x: Value) -> Any
สำหรับคำจำกัดความสมาชิกทั้งหมดmember_name
สำหรับค่าทั้งหมด เช่นreal_part(x)
จะแสดงผลส่วนRealPart
ของComplexConstant
ที่ตรงกัน หากx
ไม่ใช่ค่าที่มีสมาชิกที่เหมาะสม ระบบจะแสดงผลNone
same(x: Value) -> Value
จะได้รับการกำหนดใน tensors และแสดงผลtrue
หากองค์ประกอบx
ทั้งหมดเท่ากัน หรือfalse
ในกรณีอื่นๆ หาก tensor ไม่มีองค์ประกอบ ระบบจะนับเป็น "ทั้งหมดเท่ากับซึ่งกันและกัน" กล่าวคือ ฟังก์ชันจะแสดงผลtrue
หากx
ไม่ใช่ Tensor จะแสดงผลNone
split(x: Value, num_results: Value, axis: Value) -> Value
กำหนดไว้ใน Tensor และแสดงผลส่วนnum_results
ของx
ตามแกนaxis
หากx
ไม่ใช่ Tensor หรือdim(x, axis) % num_results != 0
จะแสดงผลNone
การคํานวณรูปร่าง
axes(x: Value | Placeholder | Type) -> Value
เป็นทางลัดสำหรับrange(rank(x))
dim(x: Value | Placeholder | Type, axis: Value) -> Value
เป็นทางลัดสำหรับshape(x)[axis]
dims(x: Value | Placeholder | Type, axes: List) -> List
เป็นทางลัดสำหรับlist(map(lambda axis: dim(x, axis), axes))
index_space(x: Value | Placeholder | Type) -> Value
กำหนดไว้ใน Tensor และแสดงดัชนีsize(x)
สำหรับTensorType
ที่สอดคล้องซึ่งเรียงลำดับแบบพจนานุกรมจากน้อยไปมาก เช่น[0, ..., 0]
,[0, ..., 1]
, ...,shape(x) - 1
หากx
ไม่ใช่ประเภท tensor, ประเภท tensor ที่เล็กลง หรือค่าหรือตัวยึดตำแหน่งของประเภทเหล่านี้ จะแสดงผลNone
rank(x: Value | Placeholder | Type) -> Value
เป็นทางลัดสำหรับsize(shape(x))
shape(x: Value | Placeholder | Type) -> Value
กำหนดไว้ในส่วน "ฟังก์ชันเกี่ยวกับประเภท" ผ่านmember_name
size(x: Value | Placeholder | Type) -> Value
เป็นทางลัดสำหรับreduce(lambda x, y: x * y, shape(x))
การคํานวณเชิงปริมาณ
def baseline_element_type(x: Value | Placeholder | Type) -> Type
เป็น ทางลัดสำหรับelement_type(baseline_type(x))
baseline_type
กำหนดไว้ในประเภท tensor และประเภท tensor ที่วัดปริมาณแล้ว แล้วแปลงค่าเหล่านี้เป็น "baseline" กล่าวคือ เป็นประเภทที่มีรูปร่างเหมือนกันแต่มีพารามิเตอร์เชิงปริมาณของประเภทองค์ประกอบจะรีเซ็ตเป็นค่าเริ่มต้น ข้อมูลนี้ใช้เป็นเคล็ดลับที่มีประโยชน์ในการเปรียบเทียบทั้ง tensor และ tensor ในเชิงปริมาณอย่างเท่าเทียมกัน ซึ่งต้องใช้ค่อนข้างบ่อย สำหรับประเภทที่เล็กลง การดำเนินการนี้ช่วยให้เปรียบเทียบประเภทที่ไม่สนใจพารามิเตอร์เชิงปริมาณ ซึ่งได้แก่shape
,storage_type
,expressed_type
,storage_min
,storage_max
และquantization_dimension
(สำหรับประเภทที่เล็กลงตามแกน 1 แกน) ต้องตรงกันทั้งหมด แต่scales
กับzero points
อาจแตกต่างกัน
def baseline_type(x: Value | Placeholder | Type) -> Type:
if type(x) == TensorType:
return x
if type(x) == QuantizedTensorType:
element_type = quantized_tensor_element_type(x)
baseline_element_type = QuantizedTensorElementType(
storage_type = storage_type(element_type),
storage_min = storage_min(element_type),
storage_max = storage_max(element_type),
expressed_type = expressed_type(element_type),
quantization_dimension = quantization_dimension(element_type),
scales = [constant(1.0, expressed_type(element_type))] * dim(x, quantization_dimension(element_type)),
zero_points = [constant(0, storage_type(element_type))] * dim(x, quantization_dimension(element_type)))
return QuantizedTensorType(shape(x), baseline_element_type)
if type(x) is not Type:
return baseline_element_type(type(x))
dequantize
กำหนดไว้ในประเภท tensor ที่วัดปริมาณแล้วและเปลี่ยนให้เป็น tensor แบบจุดลอยตัว กรณีนี้เกิดขึ้นผ่านการแปลงองค์ประกอบที่วัดปริมาณแล้วซึ่งแสดงค่าจำนวนเต็มของประเภทพื้นที่เก็บข้อมูลให้เป็นค่าจุดลอยตัวที่สอดคล้องกันของประเภทที่แสดงโดยใช้จุด 0 และมาตราส่วนที่เชื่อมโยงกับประเภทองค์ประกอบที่เล็กลง
def compute_zero_points(quantized_type, result_type):
if is_per_tensor_quantized(quantized_type):
return broadcast_in_dim(constant(zero_point(quantized_type), storage_type(quantized_type)), [], result_type)
if is_per_axis_quantized(quantized_type):
for i in index_space(result_type):
d = quantization_dimension(quantized_type)
zero_points[i] = zero_points(quantized_type)[i[d]]
return zero_points
def compute_scales(quantized_type, result_type):
if is_per_tensor_quantized(quantized_type):
return broadcast_in_dim(constant(scale(quantized_type), expressed_type(quantized_type)), [],
type(result_type))
if is_per_axis_quantized(quantized_type):
for i in index_space(result_type):
d = quantization_dimension(quantized_type)
scales[i] = scales(quantized_type)[i[d]]
return scales
def dequantize(x: Value) -> Value:
assert is_quantized(x)
x_storage = bitcast_convert(x, storage_type(x))
x_storage_sub = x_storage - compute_zero_points(type(x), type(x_storage))
x_expressed_sub = convert(x_storage_sub, expressed_type(x))
return x_expressed_sub * compute_scales(type(x), type(x_expressed_sub))
quantize
กำหนดไว้ในประเภท tensor ของจุดลอยตัว แล้วเปลี่ยนให้เป็น tensor เชิงปริมาณ กรณีนี้เกิดขึ้นผ่านการแปลงค่าจุดลอยตัวของประเภทที่แสดงเป็นค่าจำนวนเต็มที่สอดคล้องของประเภทพื้นที่เก็บข้อมูลโดยใช้จุด 0 และมาตราส่วนที่เชื่อมโยงกับประเภทองค์ประกอบที่วัดปริมาณแล้ว
def quantize(x: Value, type: Type) -> Value:
assert is_float(x) and is_quantized(type)
x_expressed_rounded = round_nearest_even(x / compute_scales(type, type(x)))
x_storage_rounded = convert(x_expressed_rounded, storage_type(type))
x_storage_add = x_storage_rounded + compute_zero_points(type, type(x_storage_rounded))
x_storage = clamp(storage_min(type), x_storage_add, storage_max(type))
return bitcast_convert(x_storage, type)
dequantize_op_quantize
ใช้เพื่อระบุการคำนวณแบบ Element-wise ใน Tensor ที่วัดปริมาณ จะแสดงผลเท่ากัน กล่าวคือ เปลี่ยนองค์ประกอบที่ปริมาณเป็นเชิงปริมาณเป็นประเภทที่แสดงผล จากนั้นดำเนินการ แล้วคำนวณปริมาณ กล่าวคือ เปลี่ยนผลลัพธ์กลับเป็นประเภทพื้นที่เก็บข้อมูล ในขณะนี้ ฟังก์ชันนี้ทำงานได้เฉพาะ สำหรับการวัดปริมาณต่อ tensor เท่านั้น ระบบกำลังดำเนินการคำนวณจำนวนตามแกน (#1574)
def dequantize_op_quantize(op, *inputs_and_output_type):
inputs = inputs_and_output_type[:-1]
output_type = inputs_and_output_type[-1]
float_inputs = map(dequantize, inputs)
float_result = op(*float_inputs)
return quantize(float_result, output_type)
def dequantize_batch_norm_grad_or_training_quantize(op, *inputs_and_output_types):
inputs = inputs_and_output_type[:-3]
float_inputs = map(dequantize, inputs)
float_results = op(*float_inputs)
return map(quantize, float_results, inputs_and_output_type[-3:])
def dequantize_compare(lhs, rhs, comparison_direction):
float_lhs = dequantize(lhs)
float_rhs = dequantize(rhs)
return compare(float_lhs, float_rhs, comparison_direction, FLOAT)
def dequantize_select_quantize(pred, on_true, on_false, output_type):
float_on_true = dequantize(on_true)
float_on_false = dequantize(on_false)
float_result = select(pred, float_on_true, float_on_false)
return quantize(float_result, output_type)
การคำนวณแบบตารางกริด
cross_partition(replica_groups: Value) -> Value
ดูส่วน "cross_replica" ด้านบนcross_replica(replica_groups: Value) -> Value
ดูส่วน "cross_replica" ด้านบนcross_replica_and_partition(replica_groups: Value) -> Value
ดูส่วน "cross_replica_and_partition" ด้านบนflattened_ids(replica_groups: Value) -> Value
ดูส่วน "flattened_ids" ด้านบน