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 จะระบุความหมายของการดำเนินการแต่ละรายการ ส่วนการดำเนินการแสดงความหมายสำหรับการดำเนินการทั้งหมดนี้ที่ดำเนินการร่วมกันภายในโปรแกรม สุดท้าย ส่วนเครื่องหมายจะพูดถึงเครื่องหมายที่ใช้ตลอดข้อกำหนด
หากต้องการดูข้อมูลจำเพาะจาก StableHLO รุ่นก่อนหน้า ให้เปิดที่เก็บในรุ่นที่ติดแท็กที่สนใจ เช่น ข้อกำหนดเกี่ยวกับ StableHLO v0.19.0 หากต้องการดูการเปลี่ยนแปลงที่เกิดขึ้นในแต่ละเวอร์ชันย่อยของ StableHLO โปรดดูบันทึกเวอร์ชันใน VhloDialect.td
โปรแกรม
Program ::= {Func}
โปรแกรม StableHLO ประกอบด้วยฟังก์ชัน StableHLO กี่รายการก็ได้
ด้านล่างนี้เป็นโปรแกรมตัวอย่างที่มีฟังก์ชัน @main
ซึ่งมีอินพุต 3 รายการ (%image
, %weights
และ %bias
) และเอาต์พุต 1 รายการ ส่วนเนื้อหาของฟังก์ชัน
มี 6 โอเปอเรเตอร์
func.func @main(
%image: tensor<28x28xf32>,
%weights: tensor<784x10xf32>,
%bias: tensor<1x10xf32>
) -> tensor<1x10xf32> {
%0 = "stablehlo.reshape"(%image) : (tensor<28x28xf32>) -> tensor<1x784xf32>
%1 = "stablehlo.dot"(%0, %weights) : (tensor<1x784xf32>, tensor<784x10xf32>) -> tensor<1x10xf32>
%2 = "stablehlo.add"(%1, %bias) : (tensor<1x10xf32>, tensor<1x10xf32>) -> tensor<1x10xf32>
%3 = "stablehlo.constant"() {value = dense<0.0> : tensor<1x10xf32>} : () -> tensor<1x10xf32>
%4 = "stablehlo.maximum"(%2, %3) : (tensor<1x10xf32>, tensor<1x10xf32>) -> tensor<1x10xf32>
"func.return"(%4): (tensor<1x10xf32>) -> ()
}
ฟังก์ชัน
Func ::= 'func' '.' 'func' FuncId FuncInputs FuncOutputs '{' FuncBody '}'
FuncInputs ::= '(' [FuncInput {',' FuncInput}] `)`
FuncInput ::= ValueId ':' ValueType
FuncOutputs ::= ['->' FuncOutput, {',' FuncOutput}]
FuncOutput ::= ValueType
FuncBody ::= {Op}
ฟังก์ชัน StableHLO (หรือที่เรียกว่าฟังก์ชันที่มีชื่อ) มีตัวระบุ อินพุต/เอาต์พุต และเนื้อหา ในอนาคต เราวางแผนที่จะเปิดตัวข้อมูลเมตาเพิ่มเติมสำหรับฟังก์ชันต่างๆ เพื่อให้เข้ากันได้กับ HLO (#425, #626, #740, #744) มากขึ้น
ตัวระบุ
FuncId ::= '@' letter {letter | digit}
ValueId ::= '%' digit {digit}
| '%' letter {letter | digit}
letter ::= 'a' | ... | 'z' | 'A' | ... | 'Z' | '_'
digit ::= '0' | ... | '9'
ตัวระบุ StableHLO คล้ายกับตัวระบุในภาษาโปรแกรมต่างๆ โดยมีลักษณะเฉพาะ 2 อย่าง ได้แก่ 1) ตัวระบุทั้งหมดมีตัวระบุที่แยกความแตกต่างของตัวระบุประเภทต่างๆ 2) ตัวระบุค่าเป็นตัวเลขโดยสมบูรณ์เพื่อลดความซับซ้อนในการสร้างโปรแกรม StableHLO
ประเภท
Type ::= ValueType | NonValueType
ValueType ::= TensorType | QuantizedTensorType | TokenType | TupleType
NonValueType ::= TensorElementType | QuantizedTensorElementType | FunctionType | StringType
ประเภท StableHLO ได้รับการจัดหมวดหมู่เป็นประเภทค่า (หรือเรียกว่าประเภท First-class) ซึ่งแสดงค่า StableHLO และประเภทที่ไม่ใช่ค่าซึ่งอธิบายองค์ประกอบอื่นๆ ของโปรแกรม ประเภท StableHLO คล้ายกับประเภทในภาษาโปรแกรมต่างๆ โดยความแปลกหลักๆ คือลักษณะการใช้งานที่เจาะจงโดเมนของ StableHLO ซึ่งทำให้เกิดผลลัพธ์ที่ผิดปกติ (เช่น ประเภทสเกลาร์ไม่ใช่ประเภทค่า)
TensorType ::= 'tensor' '<' Shape TensorElementType '>'
Shape ::= {DimensionSize 'x'}
DimensionSize ::= digit {digit} | '?'
ประเภท Tensor แสดงถึง Tensor ซึ่งก็คืออาร์เรย์หลายมิติ โดยจะมีรูปร่างและประเภทองค์ประกอบ โดยที่รูปร่างแสดงถึงขนาดมิติข้อมูลที่ไม่เป็นลบหรือไม่ทราบตามลำดับจากน้อยไปมากของมิติข้อมูลที่เกี่ยวข้อง (หรือที่เรียกว่าแกน) ซึ่งมีตัวเลขตั้งแต่ 0
ถึง R-1
จำนวนของมิติข้อมูล R
เรียกว่า rank เช่น tensor<2x3xf32>
เป็นประเภท Tensor ที่มีรูปร่าง 2x3
และประเภทองค์ประกอบ f32
ซึ่งประกอบด้วย 2 ด้าน (หรือ 2 แกน) ได้แก่ มิติข้อมูลที่ 0 และ 1 ที่มีขนาด 2 และ 3 อันดับเกมอยู่ที่ 2
รูปร่างอาจไม่รู้จักบางส่วนหรือทั้งหมด (แบบไดนามิก) เช่น tensor<?x2xf64>
อาจไม่รู้จักบางส่วนและไม่รู้จัก tensor<?x?xf64>
โดยสิ้นเชิง ขนาดของมิติข้อมูลแบบไดนามิกจะแสดงโดยใช้ ?
รูปทรงต่างๆ ต้องไม่จัดอันดับ
ในอนาคต เราวางแผนที่จะสํารวจประเภท 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-C3), (C8) |
storage_min |
ค่าคงที่ที่เป็นจำนวนเต็ม | (C1), (C3), (C7) |
storage_max |
ค่าคงที่ที่เป็นจำนวนเต็ม | (C2), (C3), (C7) |
expressed_type |
ประเภทจุดลอยตัว | (C4) |
quantization_dimension |
ค่าคงที่จำนวนเต็มที่ไม่บังคับ | (C10-C12) |
scales |
จำนวนแปรผันของค่าคงที่จุดลอยตัว | (C4-C6), (C9), (C10), (C13) |
zero_points |
จำนวนแปรผันของค่าคงที่จำนวนเต็ม | (C7-C9) |
ประเภทองค์ประกอบที่ปรับขนาดแล้วแสดงค่าที่เป็นจำนวนเต็มของประเภทพื้นที่เก็บข้อมูลในช่วงตั้งแต่ storage_min
ถึง storage_max
(รวม) ที่ตรงกับค่าจุดลอยตัวของประเภทที่แสดง สำหรับค่าจำนวนเต็ม i
ค่าทศนิยม f
ที่เกี่ยวข้องจะคำนวณเป็น f = (i - zero_point) * scale
โดยที่ scale
และ zero_point
จะเรียกว่าพารามิเตอร์การวัดปริมาณ storage_min
และ storage_max
เป็นค่าที่ไม่บังคับในไวยากรณ์ แต่จะมีค่าเริ่มต้นเป็น min_value(storage_type)
และ max_value(storage_type)
ตามลำดับ ประเภทองค์ประกอบที่ปรับขนาดแล้วมีข้อจำกัดต่อไปนี้
- (C1)
type(storage_min) = storage_type
- (C2)
type(storage_max) = storage_type
- (C3)
min_value(storage_type) <= storage_min < storage_max <= max_value(storage_type)
- (C4)
type(scales...) = expressed_type
- (C5)
0 < scales
- (C6)
is_finite(scales...)
- (C7)
storage_min <= zero_points <= storage_max
- (C8)
type(zero_points...) = storage_type
- (C9)
size(scales) = size(zero_points)
- (C10) หากเป็น
is_empty(quantization_dimension)
ให้จ่ายsize(scales) = 1
- (C11)
0 <= quantization_dimension
ในขณะนี้ QuantizationScale
เป็นค่าคงที่เป็นจำนวนลอยตัว แต่มีความสนใจอย่างมากในสเกลที่อิงตามจำนวนเต็มซึ่งแสดงด้วยตัวคูณและการเปลี่ยนแปลง เรามีแผนที่จะสำรวจปัญหานี้ในอนาคตอันใกล้ (#1404)
ตอนนี้มีการพูดคุยถึงความหมายของ QuantizationZeroPoint
อย่างต่อเนื่อง รวมถึงประเภท ค่า และขึ้นอยู่กับว่าอาจมีค่า 0 จุดเดียวหรือหลายจุดในประเภท tensor ที่เป็นจำนวนเชิงปริมาณหรือไม่ จากผลลัพธ์ของการพูดคุยนี้ ข้อกำหนดเกี่ยวกับคะแนน 0 อาจมีการเปลี่ยนแปลงในอนาคต (#1405)
มีการพูดคุยเรื่องอื่นที่กำลังดำเนินอยู่เกี่ยวข้องกับความหมายของ QuantizationStorageMin
และ QuantizationStorageMax
เพื่อตัดสินว่าควรตั้งข้อจำกัดใดๆ กับค่าเหล่านี้และค่าของ Tensor ที่วัดปริมาณไหม (#1406)
สุดท้ายนี้ เราวางแผนที่จะค้นหาการแสดงค่าจากสเกลที่ไม่รู้จักและจุด 0 จุดในลักษณะเดียวกับที่เราวางแผนจะแทนค่าขนาดของมิติข้อมูลที่ไม่รู้จัก (#1407)
ประเภท Tensor ที่วัดปริมาณแสดงถึง tensor ที่มีองค์ประกอบที่เล็กลง Tensor เหล่านี้เหมือนกับ Tensor ปกติทุกประการเว้นแต่ว่าองค์ประกอบจะมีประเภทองค์ประกอบที่เล็กลง ไม่ใช่ประเภทองค์ประกอบปกติ
ใน tensor ที่ทําให้เป็นควอติเซชันสามารถเป็น per-tensor ได้ ซึ่งหมายความว่าการมี scale
และ zero_point
1 ค่าสําหรับ 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:
- ไม่มีข้อจำกัดเพิ่มเติม
- สำหรับการคำนวณปริมาณตามแกน
- (C13)
quantization_dimension < rank(self)
- (C14)
dim(self, quantization_dimension) = size(scales)
- (C13)
TokenType ::= 'token'
ประเภทโทเค็นแสดงถึงโทเค็น ซึ่งก็คือค่าทึบแสงที่ผลิตและใช้โดยการดําเนินการบางอย่าง โทเค็นมีไว้เพื่อกำหนดคำสั่งดำเนินการสำหรับการดำเนินการตามที่อธิบายไว้ในส่วนการดำเนินการ
TupleType ::= 'tuple' '<' TupleElementTypes '>'
TupleElementTypes ::= [ValueType {',' ValueType}]
ประเภท Tuple แสดงถึง tuple เช่น รายการที่แตกต่างกัน Tuples เป็นฟีเจอร์เดิม
ที่ใช้ร่วมกับ HLO เท่านั้น ใน HLO จะใช้ทัชพอยต์เพื่อแสดง
อินพุตและเอาต์พุตของตัวแปร ใน 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 ตามที่อธิบายไว้ในการฝึกและการอนุมานสำหรับโครงข่ายประสาทส่วนลึก (Hybrid 8 บิต Floating Point (HFP8))- ประเภท
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 ซึ่งใช้เพื่อระบุข้อมูลเมตาแบบคงที่สำหรับองค์ประกอบของโปรแกรมเท่านั้น ซึ่งต่างจากภาษาโปรแกรมหลายๆ ภาษา
การทำงาน
การดำเนินการของ StableHLO (หรือที่เรียกว่า ops) แสดงถึงชุดการดำเนินการระดับสูงแบบปิดในโมเดลแมชชีนเลิร์นนิง ดังที่กล่าวไว้ข้างต้น ไวยากรณ์ StableHLO ได้รับแรงบันดาลใจมาจาก MLIR เป็นหลัก ซึ่งไม่จำเป็นต้องเป็นทางเลือกที่เหมาะกับสรีระที่สุด แต่ก็เป็นไปได้ว่าเหมาะสมที่สุดสำหรับเป้าหมาย StableHLO ในการสร้างความสามารถในการทำงานร่วมกันระหว่างเฟรมเวิร์ก ML และคอมไพเลอร์ ML
Op ::= [OpOutputs] OpName OpInputs ':' OpSignature
OpName ::= '"' 'stablehlo' '.' OpMnemonic '"'
OpMnemonic ::= 'abs' | 'add' | ...
การดำเนินการของ StableHLO (หรือที่เรียกว่า ops) จะมีชื่อ อินพุต/เอาต์พุต และลายเซ็น ชื่อประกอบด้วยคำนำหน้า stablehlo.
และช่วยจำซึ่งระบุการดำเนินการที่รองรับโดยไม่ซ้ำกัน ดูรายการที่ครอบคลุมของการดำเนินการที่รองรับทั้งหมดด้านล่าง
OpInputs ::= OpInputValues OpInputFuncs OpInputAttrs
OpInputValues ::= '(' [OpInputValue {',' OpInputValue}] ')'
OpInputValue ::= ValueId
OpInputFuncs ::= ['(' OpInputFunc {',' OpInputFunc} ')']
OpInputAttrs ::= ['{' OpInputAttr {',' OpInputAttr} '}']
OpOutputs ::= [OpOutput {',' OpOutput} '=']
OpOutput ::= ValueId
การดำเนินการจะใช้อินพุตและสร้างเอาต์พุต อินพุตจะจัดหมวดหมู่เป็นค่าอินพุต (คํานวณระหว่างการดำเนินการ), ฟังก์ชันอินพุต (ระบุแบบคงที่เนื่องจากในฟังก์ชัน StableHLO ไม่ใช่ค่าคลาสแรก) และแอตทริบิวต์อินพุต (ระบุแบบคงที่ด้วย) ประเภทของอินพุตและเอาต์พุตที่การดำเนินการ
และสร้างขึ้นจะขึ้นอยู่กับการช่วยจำ เช่น add
op ใช้ค่าอินพุต 2 ค่า และสร้างค่าเอาต์พุต 1 ค่า เมื่อเปรียบเทียบกัน ฟังก์ชัน select_and_scatter
จะใช้ค่าอินพุต 3 ค่า ฟังก์ชันอินพุต 2 รายการ และแอตทริบิวต์อินพุต 3 รายการ
OpInputFunc ::= '{' Unused FuncInputs ':' FuncBody '}'
Unused ::= '^' digit {digit}
| '^' letter {letter | digit}
ฟังก์ชันอินพุต (หรือเรียกอีกอย่างว่าฟังก์ชันที่ไม่ระบุชื่อ) คล้ายกับฟังก์ชันที่มีชื่อ ยกเว้น 1) ไม่มีตัวระบุ (ชื่อ "ไม่ระบุชื่อ") 2) ไม่ประกาศประเภทเอาต์พุต (ประเภทเอาต์พุตจะอนุมานจาก return
ภายในฟังก์ชัน)
ไวยากรณ์สำหรับฟังก์ชันอินพุตมีส่วนที่ไม่ได้ใช้งานในปัจจุบัน (ดูเวอร์ชันที่ใช้งานจริงของ Unused
ด้านบน) ซึ่งมีไว้สำหรับ MLIR ที่เข้ากันได้กับ 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 ส่วนใหญ่อาจมีการอนุมานจากอินพุต) อย่างไรก็ตาม ลายเซ็นหน้าจอถือเป็นส่วนหนึ่งของไวยากรณ์ StableHLO เพื่อความเข้ากันได้กับ MLIR
ด้านล่างคือตัวอย่างการทดสอบที่การช่วยจำคือ select_and_scatter
โดยใช้ค่าอินพุต 3 ค่า (%operand
, %source
และ %init_value
), ฟังก์ชันอินพุต 2 รายการ
และแอตทริบิวต์อินพุต 3 รายการ (window_dimensions
, window_strides
และ padding
)
โปรดทราบว่าลายเซ็นของการดำเนินการรวมเฉพาะประเภทของค่าอินพุต (แต่ไม่รวมถึงประเภทของฟังก์ชันและแอตทริบิวต์อินพุตที่ระบุแบบในหน้า) อย่างไร)
%result = "stablehlo.select_and_scatter"(%operand, %source, %init_value) ({
^bb0(%arg0: tensor<i32>, %arg1: tensor<i32>):
%0 = "stablehlo.compare"(%arg0, %arg1) {
comparison_direction = #stablehlo<comparison_direction GE>
} : (tensor<i32>, tensor<i32>) -> tensor<i1>
"stablehlo.return"(%0) : (tensor<i1>) -> ()
}, {
^bb0(%arg0: tensor<i32>, %arg1: tensor<i32>):
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i32>, tensor<i32>) -> tensor<i32>
"stablehlo.return"(%0) : (tensor<i32>) -> ()
}) {
window_dimensions = dense<[3, 1]> : tensor<2xi64>,
window_strides = dense<[2, 1]> : tensor<2xi64>,
padding = dense<[[0, 1], [0, 0]]> : tensor<2x2xi64>
} : (tensor<4x2xi32>, tensor<2x2xi32>, tensor<i32>) -> tensor<4x2xi32>
ค่าคงที่
Constant ::= BooleanConstant
| IntegerConstant
| FloatConstant
| ComplexConstant
| TensorConstant
| QuantizedTensorConstant
| StringConstant
| EnumConstant
ค่าคงที่ StableHLO มีค่าลิเทอรัลและประเภทซึ่งเมื่อรวมกันแล้วแสดงถึงค่า StableHLO โดยทั่วไป ประเภทเป็นส่วนหนึ่งของไวยากรณ์คงที่ ยกเว้นเมื่อค่าคงที่ (เช่น ค่าคงที่ของบูลีนมีประเภท i1
อย่างชัดเจน ในขณะที่ค่าคงที่จำนวนเต็มอาจมีประเภทที่เป็นไปได้หลายประเภท)
BooleanConstant ::= BooleanLiteral
BooleanLiteral ::= 'true' | 'false'
ค่าคงที่บูลีนแสดงถึงค่าบูลีน true
และ false
ค่าคงที่บูลีนเป็นประเภท i1
IntegerConstant ::= IntegerLiteral ':' IntegerType
IntegerLiteral ::= ['-' | '+'] DecimalDigits
| ['-' | '+'] '0x' HexadecimalDigits
DecimalDigits ::= decimalDigit {decimalDigit}
HexadecimalDigits ::= hexadecimalDigit {hexadecimalDigit}
decimalDigit ::= '0' | ... | '9'
hexadecimalDigit ::= decimalDigit | 'a' | ... | 'f' | 'A' | ... | 'F'
ค่าคงที่จำนวนเต็มแสดงค่าจำนวนเต็มผ่านสตริงที่ใช้สัญกรณ์ทศนิยมหรือเลขฐานสิบหก แต่ระบบจะไม่รองรับฐานอื่นๆ เช่น ไบนารีหรือฐานแปด ค่าคงที่ที่เป็นจำนวนเต็มจะมีข้อจำกัดต่อไปนี้
- (C1)
is_wellformed(integer_literal, integer_type)
FloatConstant ::= FloatLiteral ':' FloatType
FloatLiteral ::= SignPart IntegerPart FractionalPart ScientificPart
| '0x' [HexadecimalDigits]
SignPart ::= ['-' | '+']
IntegerPart ::= DecimalDigits
FractionalPart ::= ['.' [DecimalDigits]]
ScientificPart ::= [('e' | 'E') ['-' | '+'] DecimalDigits]
ค่าคงที่ของจุดลอยหมายถึงค่าจุดลอยตัวผ่านสตริงที่ใช้สัญกรณ์ทศนิยมหรือสัญกรณ์วิทยาศาสตร์ นอกจากนี้ สัญกรณ์เลขฐานสิบหกยังสามารถใช้เพื่อระบุบิตที่เกี่ยวข้องโดยตรงในรูปแบบจุดลอยตัวของประเภทที่เกี่ยวข้องได้ด้วย ค่าคงที่จุดลอยตัวมีข้อจำกัดต่อไปนี้
- (C1) หากใช้สัญกรณ์ที่ไม่ใช่เลขฐานสิบหก
is_wellformed(float_literal, float_type)
- (C2) หากใช้สัญกรณ์ฐานสิบหก
size(hexadecimal_digits) = num_bits(float_type) / 4
ComplexConstant ::= ComplexLiteral ':' ComplexType
ComplexLiteral ::= '(' RealPart ',' ImaginaryPart ')'
RealPart ::= FloatLiteral
ImaginaryPart ::= FloatLiteral
ค่าคงที่เชิงซ้อนแทนค่าเชิงซ้อนโดยใช้รายการของส่วนจริง (มาก่อน) และส่วนจินตภาพ (มาก่อน) ตัวอย่างเช่น (1.0, 0.0) : complex<f32>
แสดงถึง 1.0 + 0.0i
และ (0.0, 1.0) : complex<f32>
แสดงถึง 0.0 + 1.0i
ลำดับการจัดเก็บข้อมูลส่วนเหล่านี้ไว้ในหน่วยความจำจะได้รับการกำหนดการติดตั้งใช้งาน ค่าคงที่แบบซับซ้อนจะมีข้อจำกัดต่อไปนี้
- (C1)
is_wellformed(real_part, complex_element_type(complex_type))
- (C2)
is_wellformed(imaginary_part, complex_element_type(complex_type))
TensorConstant ::= TensorLiteral ':' TensorType
TensorLiteral ::= 'dense' '<' (DenseLiteral | ElementLiteral) '>'
DenseLiteral ::= DenseDimension | DenseElements
DenseDimension ::= '[' [DenseLiteral {',' DenseLiteral}] ']'
DenseElements ::= [ElementLiteral {',' ElementLiteral}]
ElementLiteral ::= BooleanLiteral | IntegerLiteral | FloatLiteral | ComplexLiteral
ค่าคงที่ 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))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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 ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับบูลีน: ตรรกะ OR
- สำหรับจำนวนเต็ม: การเพิ่มจำนวนเต็ม
- สำหรับแบบลอยตัว:
addition
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: การบวกเชิงซ้อน
- สำหรับประเภทที่นับจำนวน:
dequantize_op_quantize(add, lhs, rhs, type(result))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
tensor หรือ tensor เชิงปริมาณ | (C1-C6) |
(I2) | rhs |
tensor หรือ tensor เชิงปริมาณ | (C1-C5), (C7) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือ tensor เชิงปริมาณ | (C1-C7) |
ข้อจำกัด
- หากการดำเนินการใช้ Tensor แบบไม่วัดปริมาณจะดำเนินการต่อไปนี้
- (C1)
type(lhs) = type(rhs) = type(result)
- (C1)
- หากการดำเนินการใช้ Tensor เชิงปริมาณ ให้ทำดังนี้
- (C2)
is_quantized(lhs) and is_quantized(rhs) and is_quantized(result)
- (C3)
storage_type(lhs) = storage_type(rhs) = storage_type(result)
- (C4)
expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
- (C5)
(is_per_axis_quantized(lhs) or is_per_axis_quantized(rhs)) = is_per_axis_quantized(result)
- (C6) หากเป็น
is_per_axis_quantized(lhs)
ให้จ่ายquantization_dimension(lhs) = quantization_dimension(result)
- (C7) หากเป็น
is_per_axis_quantized(rhs)
ให้จ่ายquantization_dimension(rhs) = quantization_dimension(result)
- (C2)
ตัวอย่าง
// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.add"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[6, 8], [10, 12]]
after_all
อรรถศาสตร์
ตรวจสอบว่าได้ดำเนินการสร้าง inputs
ก่อนการดำเนินการที่ขึ้นอยู่กับ result
การดำเนินการนี้จะไม่ดำเนินการใดๆ เพียงแต่สร้างทรัพยากร Dependency ของข้อมูลจาก result
ไปยัง inputs
เท่านั้น
อินพุต
ค่ายเพลง | ชื่อ | ประเภท |
---|---|---|
(I1) | inputs |
จำนวนตัวแปรของ token |
เอาต์พุต
ชื่อ | ประเภท |
---|---|
result |
token |
ตัวอย่าง
// %input0: !stablehlo.token
// %input1: !stablehlo.token
%result = "stablehlo.after_all"(%input0, %input1) : (!stablehlo.token, !stablehlo.token) -> !stablehlo.token
all_gather
อรรถศาสตร์
ภายในกลุ่มกระบวนการแต่ละกลุ่มในตารางกริดกระบวนการ StableHLO ให้เชื่อมโยงค่าของ 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
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1), (C6) |
(I2) | all_gather_dim |
ค่าคงที่ประเภท si64 |
(C1), (C6) |
(I3) | replica_groups |
ค่าคงที่ tensor แบบ 2 มิติของประเภท si64 |
(C2-C4) |
(I4) | channel_id |
ค่าคงที่ประเภท si64 |
(C5) |
(I5) | use_global_device_ids |
ค่าคงที่ประเภท i1 |
(C5) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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
กับค่าของ Tensor operand
จากแต่ละกระบวนการและสร้าง 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]))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C5) (C6) |
(I2) | replica_groups |
จำนวนแปรผันของค่าคงที่ tensor 1 มิติของประเภท si64 |
(C1-C3) |
(I3) | channel_id |
ค่าคงที่ประเภท si64 |
(C4) |
(I4) | use_global_device_ids |
ค่าคงที่ประเภท i1 |
(C4) |
(I5) | computation |
ฟังก์ชัน | (C5) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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<4xi64>) -> tensor<4xi64>
// %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)
.
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1-C3) (C9) |
(I2) | split_dimension |
ค่าคงที่ประเภท si64 |
(C1), (C2), (C9) |
(I3) | concat_dimension |
ค่าคงที่ประเภท si64 |
(C3) (C9) |
(I4) | split_count |
ค่าคงที่ประเภท si64 |
(C2), (C4), (C8), (C9) |
(I5) | replica_groups |
ค่าคงที่ tensor แบบ 2 มิติของประเภท si64 |
(C5-C8) |
(I6) | channel_id |
ค่าคงที่ประเภท si64 |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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 ด้วยองค์ประกอบ AND ของ tensor 2 รายการ lhs
และ rhs
และสร้าง Tensor result
ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับบูลีน: ตรรกะ AND
- สำหรับจำนวนเต็ม: บิตไวส์ AND
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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 และสร้าง result
Tensor ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับแบบลอยตัว:
atan2
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: เชิงซ้อน atan2
- สำหรับประเภทที่นับจำนวน:
dequantize_op_quantize(atan2, lhs, rhs, type(result))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ | (C1) |
(I2) | rhs |
tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ | (C1-C3), (C5) |
(I2) | scale |
Tensor แบบ 1 มิติของประเภทจุดลอยตัวหรือต่อเทนเซอร์เชิงปริมาณ | (C2), (C4), (C5) |
(I3) | mean |
Tensor แบบ 1 มิติของประเภทจุดลอยตัวหรือต่อเทนเซอร์เชิงปริมาณ | (C2), (C4) |
(I4) | variance |
Tensor แบบ 1 มิติของประเภทจุดลอยตัวหรือต่อเทนเซอร์เชิงปริมาณ | (C2), (C4) |
(I5) | grad_output |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ | (C2), (C3) |
(I6) | epsilon |
ค่าคงที่ประเภท f32 |
|
(I7) | feature_index |
ค่าคงที่ประเภท si64 |
(C1), (C5) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
grad_operand |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ | (C2), (C3) |
grad_scale |
Tensor แบบ 1 มิติของประเภทจุดลอยตัวหรือต่อเทนเซอร์เชิงปริมาณ | (C2), (C4) |
grad_offset |
Tensor แบบ 1 มิติของประเภทจุดลอยตัวหรือต่อเทนเซอร์เชิงปริมาณ | (C2), (C4) |
ข้อจำกัด
- (C1)
0 <= feature_index < rank(operand)
- (C2)
operand
,scale
,mean
,variance
,grad_output
,grad_operand
,grad_scale
และgrad_offset
มีbaseline_element_type
เดียวกัน - (C3)
operand
,grad_output
และgrad_operand
มีรูปร่างเดียวกัน - (C4)
scale
,mean
,variance
,grad_scale
และgrad_offset
มีรูปร่างเดียวกัน - (C5)
size(scale) = dim(operand, feature_index)
ตัวอย่าง
// %operand: [
// [[1.0, 2.0], [3.0, 4.0]],
// [[3.0, 4.0], [1.0, 2.0]]
// ]
// %scale: [1.0, 1.0]
// %mean: [2.0, 3.0]
// %variance: [1.0, 1.0]
// %grad_output: [
// [[0.1, 0.1], [0.1, 0.1]],
// [[0.1, 0.1], [0.1, 0.1]]
// ]
%grad_operand, %grad_scale, %grad_offset =
"stablehlo.batch_norm_grad"(%operand, %scale, %mean, %variance, %grad_output) {
epsilon = 0.0 : f32,
feature_index = 2 : i64
} : (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>, tensor<2xf64>,
tensor<2x2x2xf64>) -> (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>)
// %grad_operand: [
// [[0.0, 0.0], [0.0, 0.0]],
// [[0.0, 0.0], [0.0, 0.0]]
// ]
// %grad_scale: [0.0, 0.0]
// %grad_offset: [0.4, 0.4]
batch_norm_inference
อรรถศาสตร์
ปรับ 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))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ | (C1-C7) |
(I2) | scale |
Tensor แบบ 1 มิติของประเภทจุดลอยตัวหรือต่อเทนเซอร์เชิงปริมาณ | (C2), (C3) |
(I3) | offset |
Tensor แบบ 1 มิติของประเภทจุดลอยตัวหรือต่อเทนเซอร์เชิงปริมาณ | (C2), (C4) |
(I4) | mean |
Tensor แบบ 1 มิติของประเภทจุดลอยตัวหรือต่อเทนเซอร์เชิงปริมาณ | (C5) |
(I5) | variance |
Tensor แบบ 1 มิติของประเภทจุดลอยตัวหรือต่อเทนเซอร์เชิงปริมาณ | (C2), (C6) |
(I6) | epsilon |
ค่าคงที่ประเภท f32 |
|
(I7) | 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))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ | (C1) |
(I2) | scale |
tensor 1 มิติของจุดลอยตัวหรือต่อ tensor เชิงปริมาณ | (C2), (C3) |
(I3) | offset |
tensor 1 มิติของจุดลอยตัวหรือต่อ tensor เชิงปริมาณ | (C2), (C4) |
(I4) | epsilon |
ค่าคงที่ประเภท f32 |
(C1), (C3-C6) |
(I5) | 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
และสร้าง Tensor result
ซึ่งจะมีการตีความบิตของ 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 ที่แน่นอนเป็นสิ่งที่กำหนดการติดตั้งใช้งาน และการแสดงประเภทองค์ประกอบที่แน่นอนมีการกำหนดการใช้งานด้วยเช่นกัน
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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]]
ไม่เช่นนั้น
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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]
// ]
// ]
เคส
อรรถศาสตร์
สร้างเอาต์พุตจากการเรียกใช้ฟังก์ชันเดียวจาก branches
โดยขึ้นอยู่กับค่าของ index
อย่างเป็นทางการ result = selected_branch()
ซึ่ง
selected_branch = branches[index]
หากเป็น0 <= index < size(branches)
selected_branch = branches[-1]
ไม่เช่นนั้น
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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
อรรถศาสตร์
สร้าง ceil ตามองค์ประกอบของ tensor ของ operand
และสร้าง tensor แบบ result
ใช้การดำเนินการ roundToIntegralTowardPositive
จากข้อกำหนด IEEE-754 สำหรับประเภทที่แบ่งปริมาณแล้ว จะแสดงผล dequantize_op_quantize(ceil, operand, type(result))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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
อรรถศาสตร์
คำนวณการแตกตัวของ Cholesky ของกลุ่มเมทริกซ์
อย่างเป็นทางการสำหรับ i
ทั้งหมดใน index_space(result)
result[i0, ..., iR-3, :, :]
คือการแตกตัวแบบ Cholesky ของ
a[i0, ..., iR-3, :, :]
ในรูปแบบของเมทริกซ์รูปสามเหลี่ยมล่าง (หาก lower
เป็น true
) หรือเมทริกซ์รูปสามเหลี่ยมบน (หาก lower
เป็น false
)
ค่าเอาต์พุตในสามเหลี่ยมตรงข้าม ได้แก่ สามเหลี่ยมด้านบนที่เข้มงวดหรือสามเหลี่ยมล่างสุดที่เกี่ยวข้องจะเป็นตัวกำหนดการติดตั้งใช้งาน
หากมี i
อยู่โดยที่เมทริกซ์อินพุตไม่ใช่เมทริกซ์ค่าบวกลบของ Hermitian จะไม่มีการกำหนดลักษณะการทำงาน
สำหรับประเภทที่แบ่งปริมาณแล้ว จะแสดงผล dequantize_op_quantize(lambda operand: cholesky(operand, lower), a, type(result))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | a |
tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ | (C1-C3) |
(I2) | lower |
ค่าคงที่ tensor แบบ 0 มิติของประเภท i1 |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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)
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | min |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1), (C3) |
(I2) | operand |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1-C4) |
(I3) | max |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C2), (C3) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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 ให้ส่งค่าของ
operand
Tensor จากกระบวนการต้นทางไปยังกระบวนการเป้าหมายและสร้าง 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(is_quantized(result) ? quantize(0, element_type(result)) : 0, element_type(result)), [], type(result))
ไม่เช่นนั้น
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C3) |
(I2) | replica_groups |
จำนวนแปรผันของค่าคงที่ tensor 1 มิติของประเภท si64 |
(C1), (C2) |
(I3) | channel_id |
ค่าคงที่ประเภท si64 |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ 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))
ไม่เช่นนั้น
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C5) |
(I2) | source_target_pairs |
ค่าคงที่ tensor แบบ 2 มิติของประเภท si64 |
(C1-C4) |
(I3) | channel_id |
ค่าคงที่ประเภท si64 |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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]]
เปรียบเทียบ
อรรถศาสตร์
ทำการเปรียบเทียบ Tensor ตาม lhs
และ rhs
ตาม comparison_direction
และ compare_type
และสร้าง Tensor result
ค่าของ comparison_direction
และ compare_type
มีความหมายต่อไปนี้
สำหรับประเภทองค์ประกอบบูลีนและจำนวนเต็ม
EQ
:lhs = rhs
NE
:lhs != rhs
GE
:lhs >= rhs
GT
:lhs > rhs
LE
:lhs <= rhs
LT
:lhs < rhs
สำหรับประเภทองค์ประกอบจุดลอยตัวที่มี compare_type = FLOAT
การทดสอบจะใช้การดำเนินการ IEEE-754 ต่อไปนี้
EQ
:compareQuietEqual
NE
:compareQuietNotEqual
GE
:compareQuietGreaterEqual
GT
:compareQuietGreater
LE
:compareQuietLessEqual
LT
:compareQuietLess
สำหรับประเภทองค์ประกอบจุดลอยตัวที่มี compare_type = TOTALORDER
ฝั่งตรงข้ามจะใช้ชุดค่าผสมของการดำเนินการ totalOrder
และ compareQuietEqual
จาก IEEE-754
สําหรับประเภทองค์ประกอบที่ซับซ้อน การเปรียบเทียบพจนานุกรมของคู่ (real, imag)
จะดําเนินการโดยใช้ comparison_direction
และ compare_type
ที่ระบุ
การกำหนดลำดับด้วยจำนวนเชิงซ้อนเกี่ยวข้องกับความหมายที่คาดไม่ถึง ดังนั้นในอนาคตเราวางแผนที่จะนำการสนับสนุนจำนวนเชิงซ้อนออกเมื่อ comparison_direction
คือ GE
, GT
, LE
หรือ LT
(#560)
สำหรับประเภทที่วัดปริมาณ ดำเนินการ dequantize_compare(lhs, rhs,
comparison_direction)
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1-C3) |
(I2) | rhs |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1-C2) |
(I3) | 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
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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)]
การผสม
อรรถศาสตร์
สรุปการดำเนินการที่สร้างขึ้น (ประกอบ) ของการดำเนินการ StableHLO อื่นๆ ที่รับ inputs
และ composite_attributes
และการสร้าง results
อรรถศาสตร์ของตัวเลือกมีการใช้งานโดยแอตทริบิวต์ decomposition
คุณแทนที่การดำเนินการ composite
ด้วยการแยกย่อยได้โดยไม่ต้องเปลี่ยนความหมายของโปรแกรม ในกรณีที่อินไลน์การแตกตัวไม่ตรงตามความหมายที่ตรงกัน ให้ใช้ custom_call
ช่อง version
(ค่าเริ่มต้นเป็น 0
) ใช้เพื่อแสดงถึงการเปลี่ยนแปลงทางอรรถศาสตร์ของคอมโพสิต
อินพุต
ค่ายเพลง | ชื่อ | ประเภท |
---|---|---|
(I1) | inputs |
จำนวนค่าตัวแปร |
(I2) | name |
ค่าคงที่ประเภท string |
(I3) | composite_attributes |
พจนานุกรมแอตทริบิวต์ |
(I4) | decomposition |
ค่าคงที่ประเภท string |
(I5) | version |
ค่าคงที่ประเภท si32 |
เอาต์พุต
ชื่อ | ประเภท |
---|---|
results |
จำนวนค่าตัวแปร |
ข้อจำกัด
- (C1)
is_namespaced_op_name(name)
- (C2)
is_defined_in_parent_scope(decomposition)
- (C3)
types(inputs...) == input_types(decomposition)
- (C4)
types(results...) == output_types(decomposition)
ตัวอย่าง
%results = "stablehlo.composite"(%input0, %input1) {
name = "my_namespace.my_op",
composite_attributes = {
my_attribute = "my_value"
},
decomposition = @my_op,
version = 1 : i32
} : (tensor<f32>, tensor<f32>) -> tensor<f32>
concatenate
อรรถศาสตร์
เชื่อมต่อ inputs
ตามมิติข้อมูล dimension
ในลำดับเดียวกับอาร์กิวเมนต์ที่ระบุ และสร้าง Tensor result
ซึ่งก็คือ result[i0, ..., id, ..., iR-1] = inputs[k][i0, ..., kd, ..., iR-1]
ซึ่งเป็น
id = d0 + ... + dk-1 + kd
.d
เท่ากับdimension
และd0
, ... เป็นขนาดมิติข้อมูลที่d
ของinputs
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | inputs |
จำนวนตัวแปรของ tensors หรือ tensor แบบต่อ tensor เชิงปริมาณ | (C1-C6) |
(I2) | dimension |
ค่าคงที่ประเภท si64 |
(C2), (C4), (C6) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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]]
ค่าคงที่
อรรถศาสตร์
สร้าง Tensor output
จาก value
คงที่
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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
อรรถศาสตร์
ทำการแปลงตามองค์ประกอบจากประเภทองค์ประกอบหนึ่งไปเป็นอีกประเภทด้วย tensor ของ operand
และสร้าง 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 ของ Floing-point-to-Floing-point สำหรับการแปลงส่วนจริงและส่วนจินตภาพ
สำหรับ Conversion แบบ complex-to-any-other-type และ complex-to-any-other-type ระบบจะไม่สนใจค่าจินตภาพต้นทางหรือค่าจินตภาพปลายทางเป็น 0 ตามลำดับ Conversion ของส่วนจริงจะเป็นไปตาม Conversion จุดลอยตัว
ในหลักการแล้ว การดำเนินการนี้อาจบอกถึงการแบ่งข้อมูล (การแปลงจาก tensors เชิงปริมาณเป็น tensors แบบปกติ) การคำนวณเชิงปริมาณ (การแปลงจาก tensor ปกติเป็น tensors เชิงปริมาณ) และการคำนวณซ้ำ (การแปลงระหว่าง tensors เชิงปริมาณ) แต่ในขณะนี้เราได้ทำการดำเนินการเฉพาะสำหรับ Use Case ดังกล่าว uniform_dequantize
สำหรับ Use Case แรก และ uniform_quantize
สำหรับ Use Case ที่สองและ 3 ในอนาคต การดำเนินการ 2 อย่างนี้อาจผสานรวมเป็น convert
(#1576)
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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))
สำหรับประเภทแบบผสม ให้ดำเนินการ hybrid_dequantize_then_op(
lambda lhs, rhs: convolution(lhs, rhs, window_strides, padding,
lhs_dilation, rhs_dilation, window_reversal, input_batch_dimension,
input_feature_dimension, input_spatial_dimensions,
kernel_input_feature_dimension, kernel_output_feature_dimension,
kernel_spatial_dimensions, output_batch_dimension,
output_feature_dimension, output_spatial_dimensions,
feature_group_count, batch_group_count, precision_config), lhs, rhs)
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1), (C10-C11), (C14) (C25), (C27-C28), (C31-C32) (C34) |
(I2) | rhs |
tensor หรือ tensor เชิงปริมาณ | (C1), (C14-C16), (C25), (C27-C29), (C31-C34) |
(I3) | window_strides |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2-C3), (C25) |
(I4) | padding |
ค่าคงที่ tensor แบบ 2 มิติของประเภท si64 |
(C4), (C25) |
(I5) | lhs_dilation |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C5-C6), (C25) |
(I6) | rhs_dilation |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C7-C8), (C25) |
(I7) | window_reversal |
ค่าคงที่ tensor แบบ 1 มิติของประเภท i1 |
(C9) |
(I8) | input_batch_dimension |
ค่าคงที่ประเภท si64 |
(C10), (C13), (C25) |
(I9) | input_feature_dimension |
ค่าคงที่ประเภท si64 |
(C11), (C13-C14) |
(I10) | input_spatial_dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C12), (C13), (C25) |
(I11) | kernel_input_feature_dimension |
ค่าคงที่ประเภท si64 |
(C14) (C18) |
(I12) | kernel_output_feature_dimension |
ค่าคงที่ประเภท si64 |
(C15-C16), (C18), (C25), (C29) |
(I13) | kernel_spatial_dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C17-C18), (C25) |
(I14) | output_batch_dimension |
ค่าคงที่ประเภท si64 |
(C20) (C25) |
(15) | output_feature_dimension |
ค่าคงที่ประเภท si64 |
(C20), (C25), (C30) |
(I16) | output_spatial_dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C19-C20), (C25) |
(I17) | feature_group_count |
ค่าคงที่ประเภท si64 |
(C11), (C14), (C16), (C21), (C23) |
(I18) | batch_group_count |
ค่าคงที่ประเภท si64 |
(C10), (C15), (C22), (C23), (C25) |
(I19) | precision_config |
จำนวน Enum ที่แตกต่างกันของ DEFAULT , HIGH และ HIGHEST |
(C24) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือ tensor เชิงปริมาณ | (C25-C28), (C30), (C32-34) |
ข้อจำกัด
- (C1)
N = rank(lhs) = rank(rhs)
- (C2)
size(window_strides) = N - 2
- (C3)
0 < window_strides
- (C4)
shape(padding) = [N - 2, 2]
- (C5)
size(lhs_dilation) = N - 2
- (C6)
0 < lhs_dilation
- (C7)
size(rhs_dilation) = N - 2
- (C8)
0 < rhs_dilation
- (C9)
size(window_reversal) = N - 2
- (C10)
dim(lhs, input_batch_dimension) % batch_group_count = 0
- (C11)
dim(lhs, input_feature_dimension) % feature_group_count = 0
- (C12)
size(input_spatial_dimensions) = N - 2
- (C13) ให้
input_dimensions = [input_batch_dimension] + input_spatial_dimensions + [input_feature_dimension]
:is_unique(input_dimensions)
.0 <= input_dimensions < N
.
- (C14)
dim(rhs, kernel_input_feature_dimension) = dim(lhs, input_feature_dimension) / feature_group_count
- (C15)
dim(rhs, kernel_output_feature_dimension) % batch_group_count = 0
- (C16)
dim(rhs, kernel_output_feature_dimension) % feature_group_count = 0
- (C17)
size(kernel_spatial_dimensions) = N - 2
- (C18) ให้
kernel_dimensions = kernel_spatial_dimensions + [kernel_input_feature_dimension] + [kernel_output_feature_dimension]
:is_unique(kernel_dimensions)
.0 <= kernel_dimensions < N
.
- (C19)
size(output_spatial_dimensions) = N - 2
- (C20) ให้
output_dimensions = [output_batch_dimension] + output_spatial_dimensions + [output_feature_dimension]
:is_unique(output_dimensions)
.0 <= output_dimensions < N
.
- (C21)
0 < feature_group_count
- (C22)
0 < batch_group_count
- (C23)
feature_group_count = 1 or batch_group_count = 1
- (C24)
size(precision_config) = 2
- (C25)
dim(result, result_dim)
ให้คำจำกัดความดังนี้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)
- หากการดำเนินการใช้ Tensor เชิงปริมาณ ให้ทำดังนี้
- (C28)
is_quantized(lhs) = is_quantized(result) and is_quantized(rhs)
- (C29) หากเป็น
is_per_axis_quantized(rhs)
ให้จ่ายquantization_dimension(rhs) = kernel_output_feature_dimension
- (C30) หากเป็น
is_per_axis_quantized(result)
ให้ทำดังนี้quantization_dimension(result) = output_feature_dimension
- หาก
is_quantized(lhs)
: - (C31)
storage_type(lhs) = storage_type(rhs)
- (C32)
expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
- (C33) หากเป็น
is_per_tensor_quantized(rhs)
ให้ทำดังนี้is_per_tensor_quantized(result)
- หาก
!is_quantized(lhs)
: - (C34)
element_type(lhs) = expressed_type(rhs) = element_type(result)
- (C28)
ตัวอย่าง
// %lhs: [[
// [
// [1], [2], [5], [6]
// ],
// [
// [3], [4], [7], [8]
// ],
// [
// [10], [11], [14], [15]
// ],
// [
// [12], [13], [16], [17]
// ]
// ]]
//
// %rhs: [
// [[[1]], [[1]], [[1]]],
// [[[1]], [[1]], [[1]]],
// [[[1]], [[1]], [[1]]]
// ]
%result = "stablehlo.convolution"(%lhs, %rhs) {
window_strides = array<i64: 4, 4>,
padding = dense<0> : tensor<2x2xi64>,
lhs_dilation = array<i64: 2, 2>,
rhs_dilation = array<i64: 1, 1>,
window_reversal = array<i1: false, false>,
// In the StableHLO dialect, dimension numbers are encoded via:
// `[<input dimensions>]x[<kernel dimensions>]->[output dimensions]`.
// "b" is batch dimension, "f" is feature dimension,
// "i" is input feature dimension, "o" is output feature dimension,
// "0/1/etc" are spatial dimensions.
dimension_numbers = #stablehlo.conv<[b, 0, 1, f]x[0, 1, i, o]->[b, 0, 1, f]>,
batch_group_count = 1 : i64,
feature_group_count = 1 : i64,
precision_config = [#stablehlo<precision DEFAULT>, #stablehlo<precision DEFAULT>]
} : (tensor<1x4x4x1xi64>, tensor<3x3x1x1xi64>) -> tensor<1x2x2x1xi64>
// %result: [[
// [[10], [26]],
// [[46], [62]]
// ]]
โคไซน์
อรรถศาสตร์
ดำเนินการหาโคไซน์ตามองค์ประกอบบน tensor ของ operand
และสร้าง Tensor result
ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับแบบลอยตัว:
cos
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: โคไซน์เชิงซ้อน
- สำหรับประเภทที่นับจำนวน:
dequantize_op_quantize(cosine, operand, type(result))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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)
อินพุต
ค่ายเพลง | ชื่อ | ประเภท |
---|---|---|
(I1) | inputs |
จำนวนค่าตัวแปร |
(I2) | call_target_name |
ค่าคงที่ประเภท string |
(I3) | has_side_effect |
ค่าคงที่ประเภท i1 |
(I4) | backend_config |
ค่าคงที่ประเภท string |
(I5) | api_version |
ค่าคงที่ประเภท si32 |
(I6) | called_computations |
จำนวนแปรผันของค่าคงที่ประเภท string |
เอาต์พุต
ชื่อ | ประเภท |
---|---|
results |
จำนวนค่าตัวแปร |
ตัวอย่าง
%results = "stablehlo.custom_call"(%input0) {
call_target_name = "foo",
has_side_effect = false,
backend_config = "bar",
api_version = 1 : i32,
called_computations = [@foo]
} : (tensor<f64>) -> tensor<f64>
หาร
อรรถศาสตร์
หารหาร lhs
ตามองค์ประกอบและหาร rhs
Tensor และสร้าง Tensor แบบ result
ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับจำนวนเต็ม: การหารจำนวนเต็มที่สร้างผลหารพีชคณิตที่มีส่วนที่เป็นเศษส่วนทิ้ง
- สำหรับแบบลอยตัว:
division
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: การหารเชิงซ้อน
- สำหรับประเภทที่วัดปริมาณ:
dequantize_op_quantize(divide, lhs, rhs, type(result))
.
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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
และสร้าง result
Tensor
อย่างเป็นทางการคือ result[result_index] = dot_product
ซึ่งมีคุณสมบัติดังนี้
lhs_result_dimensions = [d for d in axes(lhs) and d not in lhs_batching_dimensions and d not in lhs_contracting_dimensions]
.rhs_result_dimensions = [d for d in axes(rhs) and d not in rhs_batching_dimensions and d not in rhs_contracting_dimensions]
.result_batching_index + result_lhs_index + result_rhs_index = result_index
ที่size(result_batching_index) = size(lhs_batching_dimensions)
,size(result_lhs_index) = size(lhs_result_dimensions)
และsize(result_rhs_index) = size(rhs_result_dimensions)
transposed_lhs = transpose(lhs, lhs_batching_dimensions + lhs_result_dimensions + lhs_contracting_dimensions)
.transposed_lhs_slice = slice(transposed_lhs, result_batching_index + result_lhs_index + [:, ..., :])
.reshaped_lhs_slice = reshape(transposed_lhs_slice, dims(lhs, lhs_contracting_dimensions))
.transposed_rhs = transpose(rhs, rhs_batching_dimensions + rhs_result_dimensions + rhs_contracting_dimensions)
.transposed_rhs_slice = slice(transposed_rhs, result_batching_index + result_rhs_index + [:, ..., :])
.reshaped_rhs_slice = reshape(transposed_rhs_slice, dims(rhs, rhs_contracting_dimensions))
.dot_product = reduce( inputs=[multiply(reshaped_lhs_slice, reshaped_rhs_slice)], init_values=[constant(0, element_type(result))], dimensions=range(size(lhs_contracting_dimensions)), body=lambda x, y: add(x, y))
สำหรับประเภทที่วัดปริมาณ ให้ดำเนินการ dequantize_op_quantize(
lambda lhs, rhs: dot_general(lhs, rhs, lhs_batching_dimensions,
rhs_batching_dimensions, lhs_contracting_dimensions,
rhs_contracting_dimensions, precision_config), lhs, rhs, type(result))
สำหรับประเภทแบบผสม ให้ดำเนินการ hybrid_dequantize_then_op(
lambda lhs, rhs: dot_general(lhs, rhs, lhs_batching_dimensions,
rhs_batching_dimensions, lhs_contracting_dimensions,
rhs_contracting_dimensions, precision_config), lhs, rhs)
precision_config
จะควบคุมการทดแทนกันระหว่างความเร็วและความแม่นยำสำหรับการคำนวณในแบ็กเอนด์ของ Accelerator ซึ่งอาจเป็นอย่างใดอย่างหนึ่งต่อไปนี้ (ในขณะนี้ อรรถศาสตร์ของค่า enum เหล่านี้ไม่ได้ระบุไว้ แต่เรามีแผนที่จะแก้ไขปัญหานี้ใน #755)
DEFAULT
: การคำนวณเร็วที่สุด แต่ใกล้เคียงของตัวเลขเดิมที่แม่นยำน้อยที่สุดHIGH
: การคำนวณช้ากว่า แต่ประมาณตัวเลขเดิมได้แม่นยำกว่าHIGHEST
: การคำนวณอย่างช้าที่สุด แต่ใกล้เคียงที่สุดกับตัวเลขเดิมที่แม่นยำที่สุด
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C5-C6), (C9-C10), (C12-C14), (C17-C18), (C20) |
(I2) | rhs |
tensor หรือ tensor เชิงปริมาณ | (C7-C10), (C12-C20) |
(I3) | lhs_batching_dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C1), (C3), (C5), (C9), (C12) |
(I4) | rhs_batching_dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C1), (C4), (C7), (C9) |
(I5) | lhs_contracting_dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C3), (C6), (C10) |
(I6) | rhs_contracting_dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C4), (C8), (C10), (C16) |
(I7) | precision_config |
จำนวน Enum ที่แตกต่างกันของ DEFAULT , HIGH และ HIGHEST |
(C11) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือ tensor เชิงปริมาณ | (C12), (C14), (C18-C20) |
ข้อจำกัด
- (C1)
size(lhs_batching_dimensions) = size(rhs_batching_dimensions)
- (C2)
size(lhs_contracting_dimensions) = size(rhs_contracting_dimensions)
- (C3)
is_unique(lhs_batching_dimensions + lhs_contracting_dimensions)
- (C4)
is_unique(rhs_batching_dimensions + rhs_contracting_dimensions)
- (C5)
0 <= lhs_batching_dimensions < rank(lhs)
- (C6)
0 <= lhs_contracting_dimensions < rank(lhs)
- (C7)
0 <= rhs_batching_dimensions < rank(rhs)
- (C8)
0 <= rhs_contracting_dimensions < rank(rhs)
- (C9)
dim(lhs, lhs_batching_dimensions...) = dim(rhs, rhs_batching_dimensions...)
- (C10)
dim(lhs, lhs_contracting_dimensions...) = dim(rhs, rhs_contracting_dimensions...)
- (C11)
size(precision_config) = 2
- (C12)
shape(result) = dim(lhs, lhs_batching_dimensions) + dim(lhs, lhs_result_dimensions) + dim(rhs, rhs_result_dimensions)
- หากการดำเนินการใช้ Tensor แบบไม่วัดปริมาณจะดำเนินการต่อไปนี้
- (C13)
element_type(lhs) = element_type(rhs)
- (C13)
- หากการดำเนินการใช้ Tensor เชิงปริมาณ ให้ทำดังนี้
- (C14)
is_quantized(lhs) = is_quantized(result) and is_quantized(rhs)
- (C15)
zero_points(rhs) = 0
- (C16) หากเป็น
is_per_axis_quantized(rhs)
ก็ให้quantization_dimension(rhs)
ไม่ใช่ในrhs_contracting_dimensions
- หาก
is_quantized(lhs)
: - (C17)
storage_type(lhs) = storage_type(rhs)
- (C18)
expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
- (C19) หากเป็น
is_per_tensor_quantized(rhs)
ให้ทำดังนี้is_per_tensor_quantized(result)
- หาก
!is_quantized(lhs)
: - (C20)
element_type(lhs) = expressed_type(rhs) = element_type(result)
- (C14)
ตัวอย่าง
// %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_broadcast_in_dim
อรรถศาสตร์
การดำเนินการนี้เหมือนกับ
broadcast_in_dim op แต่ระบบจะระบุรูปร่างผลลัพธ์แบบไดนามิกผ่านทาง output_dimensions
การดำเนินการยังยอมรับแอตทริบิวต์ที่ไม่บังคับ known_expanding_dimensions
, known_non_expanding_dimensions
เพื่อแสดงความรู้แบบคงที่เกี่ยวกับพฤติกรรมการขยายของมิติข้อมูล
หากไม่ระบุ ระบบจะถือว่ามิติข้อมูลทั้งหมดอาจขยายอยู่
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือ tensor เชิงปริมาณ | (C1-C2), (C5-C6), (C9) |
(I2) | output_dimensions |
Tensor แบบ 1 มิติของประเภทจำนวนเต็ม | (C7) |
(I3) | broadcast_dimensions |
Tensor คงที่แบบ 1 มิติของประเภทจำนวนเต็ม | (C2-C6) |
(I4) | known_expanding_dimensions |
Tensor คงที่แบบ 1 มิติของประเภทจำนวนเต็ม | (C8-C9) |
(I5) | known_non_expanding_dimensions |
Tensor คงที่แบบ 1 มิติของประเภทจำนวนเต็ม | (C8-C9) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือ tensor เชิงปริมาณ | (C1), (C3), (C5-C7) |
ข้อจำกัด
- (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)))
- (C7)
size(output_dimensions) = rank(result)
- (C8)
is_unique(known_expanding_dimensions + known_non_expanding_dimensions)
- (C9)
0 <= known_expanding_dimensions < rank(operand)
- (C10)
0 <= known_non_expanding_dimensions < rank(operand)
ตัวอย่าง
// %operand: [
// [1, 2, 3]
// ]
%operand = stablehlo.constant dense<[[1, 2, 3]]> : tensor<1x3xi64>
%output_dimensions = stablehlo.constant dense<[2, 3, 2]> : tensor<3xi64>
%result = "stablehlo.dynamic_broadcast_in_dim"(%operand, %output_dimensions) {
broadcast_dimensions = array<i64: 2, 1>,
known_expanding_dimensions = array<i64: 0>,
known_non_expanding_dimensions = array<i64: 1>
} : (tensor<1x3xi64>, tensor<3xi64>) -> tensor<2x3x2xi64>
// %result: [
// [
// [1, 1],
// [2, 2],
// [3, 3]
// ],
// [
// [1, 1],
// [2, 2],
// [3, 3]
// ]
// ]
dynamic_conv
อรรถศาสตร์
การดำเนินการนี้มีฟังก์ชันการทำงานเหมือนกับ convolution op แต่มีการระบุระยะห่างจากขอบแบบไดนามิกผ่าน padding
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1), (C10-C11), (C14) (C25), (C26-C27), (C30-C31) (C33) |
(I2) | rhs |
tensor หรือ tensor เชิงปริมาณ | (C1), (C14-C16), (C26-C28), (C30-C33) |
(I3) | padding |
Tensor แบบ 2 มิติของประเภทจำนวนเต็ม | (C4) |
(I4) | window_strides |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2-C3) |
(I5) | lhs_dilation |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C5-C6) |
(I6) | rhs_dilation |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C7-C8) |
(I7) | window_reversal |
ค่าคงที่ tensor แบบ 1 มิติของประเภท i1 |
(C9) |
(I8) | input_batch_dimension |
ค่าคงที่ประเภท si64 |
(C10), (C13) |
(I9) | input_feature_dimension |
ค่าคงที่ประเภท si64 |
(C11), (C13-C14) |
(I10) | input_spatial_dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C12), (C13) |
(I11) | kernel_input_feature_dimension |
ค่าคงที่ประเภท si64 |
(C14) (C18) |
(I12) | kernel_output_feature_dimension |
ค่าคงที่ประเภท si64 |
(C15-C16), (C18), (C28) |
(I13) | kernel_spatial_dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C17-C18) |
(I14) | output_batch_dimension |
ค่าคงที่ประเภท si64 |
(C20) |
(15) | output_feature_dimension |
ค่าคงที่ประเภท si64 |
(C20) (C29) |
(I16) | output_spatial_dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C19-C20) |
(I17) | feature_group_count |
ค่าคงที่ประเภท si64 |
(C11), (C14), (C16), (C21), (C23) |
(I18) | batch_group_count |
ค่าคงที่ประเภท si64 |
(C10), (C15), (C22), (C23) |
(I19) | precision_config |
จำนวน Enum ที่แตกต่างกันของ DEFAULT , HIGH และ HIGHEST |
(C24) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือ tensor เชิงปริมาณ | (C25-C27), (C29), (C31-C33) |
ข้อจำกัด
- (C1)
N = rank(lhs) = rank(rhs)
- (C2)
size(window_strides) = N - 2
- (C3)
0 < window_strides
- (C4)
shape(padding) = [N - 2, 2]
- (C5)
size(lhs_dilation) = N - 2
- (C6)
0 < lhs_dilation
- (C7)
size(rhs_dilation) = N - 2
- (C8)
0 < rhs_dilation
- (C9)
size(window_reversal) = N - 2
- (C10)
dim(lhs, input_batch_dimension) % batch_group_count = 0
- (C11)
dim(lhs, input_feature_dimension) % feature_group_count = 0
- (C12)
size(input_spatial_dimensions) = N - 2
- (C13) ให้
input_dimensions = [input_batch_dimension] + input_spatial_dimensions + [input_feature_dimension]
:is_unique(input_dimensions)
.0 <= input_dimensions < N
.
- (C14)
dim(rhs, kernel_input_feature_dimension) = dim(lhs, input_feature_dimension) / feature_group_count
- (C15)
dim(rhs, kernel_output_feature_dimension) % batch_group_count = 0
- (C16)
dim(rhs, kernel_output_feature_dimension) % feature_group_count = 0
- (C17)
size(kernel_spatial_dimensions) = N - 2
- (C18) ให้
kernel_dimensions = kernel_spatial_dimensions + [kernel_input_feature_dimension] + [kernel_output_feature_dimension]
:is_unique(kernel_dimensions)
.0 <= kernel_dimensions < N
.
- (C19)
size(output_spatial_dimensions) = N - 2
- (C20) ให้
output_dimensions = [output_batch_dimension] + output_spatial_dimensions + [output_feature_dimension]
:is_unique(output_dimensions)
.0 <= output_dimensions < N
.
- (C21)
0 < feature_group_count
- (C22)
0 < batch_group_count
- (C23)
feature_group_count = 1 or batch_group_count = 1
- (C24)
size(precision_config) = 2
- (C25)
dim(result, result_dim)
ให้คำจำกัดความดังนี้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)
- หากการดำเนินการใช้ Tensor เชิงปริมาณ ให้ทำดังนี้
- (C28)
is_quantized(lhs) = is_quantized(result) and is_quantized(rhs)
- (C29) หากเป็น
is_per_axis_quantized(rhs)
ให้จ่ายquantization_dimension(rhs) = kernel_output_feature_dimension
- (C30) หากเป็น
is_per_axis_quantized(result)
ให้ทำดังนี้quantization_dimension(result) = output_feature_dimension
- หาก
is_quantized(lhs)
: - (C31)
storage_type(lhs) = storage_type(rhs)
- (C32)
expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
- (C33) หากเป็น
is_per_tensor_quantized(rhs)
ให้ทำดังนี้is_per_tensor_quantized(result)
- หาก
!is_quantized(lhs)
: - (C34)
element_type(lhs) = expressed_type(rhs) = element_type(result)
- (C28)
ตัวอย่าง
// %lhs: [[
// [[1], [2], [5], [6]],
// [[3], [4], [7], [8]],
// [[10], [11], [14], [15]],
// [[12], [13], [16], [17]]
// ]]
//
// %rhs: [
// [[[1]], [[1]], [[1]]],
// [[[1]], [[1]], [[1]]],
// [[[1]], [[1]], [[1]]]
// ]
// %padding: [[1, 1],
// [1, 1]]
%result = "stablehlo.dynamic_conv"(%lhs, %rhs, %padding) {
window_strides = array<i64: 4, 4>,
lhs_dilation = array<i64: 2, 2>,
rhs_dilation = array<i64: 1, 1>,
window_reversal = array<i1: false, false>,
dimension_numbers = #stablehlo.conv<raw
input_batch_dimension = 0,
input_feature_dimension = 3,
input_spatial_dimensions = [0, 1],
kernel_input_feature_dimension = 2,
kernel_output_feature_dimension = 3,
kernel_spatial_dimensions = [0, 1],
output_batch_dimension = 0,
output_feature_dimension = 3,
output_spatial_dimensions = [1, 2]
>,
feature_group_count = 1 : i64,
batch_group_count = 1 : i64,
precision_config = [#stablehlo<precision DEFAULT>, #stablehlo<precision DEFAULT>]
} : (tensor<1x4x4x1xi64>, tensor<3x3x1x1xi64>, tensor<2x2xi64>) -> tensor<1x2x2x1xi64>
// %result: [[
// [[1], [5]],
// [[10], [14]]
// ]]
dynamic_gather
อรรถศาสตร์
การดำเนินการนี้มีฟังก์ชันการทำงานเหมือนกับ gather op โดยมี slice_sizes
ระบุเป็นค่าแบบไดนามิก
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1), (C7), (C10-C12), (C14) |
(I2) | start_indices |
Tensor ของประเภทจำนวนเต็ม | (C2), (C3), (C13) |
(I3) | slice_sizes |
Tensor แบบ 1 มิติของประเภทจำนวนเต็ม | (C8) (C11-C13) |
(I4) | offset_dims |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C1), (C4-C5), (C13) |
(I5) | collapsed_slice_dims |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C1), (C6-C8), (C13) |
(I6) | start_index_map |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C3), (C9), (C10) |
(I7) | index_vector_dim |
ค่าคงที่ประเภท si64 |
(C2), (C3), (C13) |
(I8) | indices_are_sorted |
ค่าคงที่ประเภท i1 |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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]]
// ]
// %slize_sizes: [1, 2, 2]
%result = "stablehlo.dynamic_gather"(%operand, %start_indices, %slize_sizes) {
dimension_numbers = #stablehlo.gather<
offset_dims = [2, 3],
collapsed_slice_dims = [0],
start_index_map = [1, 0],
index_vector_dim = 2>,
indices_are_sorted = false
} : (tensor<3x4x2xi64>, tensor<2x3x2xi64>, tensor<3xi64>) -> tensor<2x3x2x2xi64>
// %result: [
// [
// [[1, 2], [3, 4]],
// [[3, 4], [5, 6]],
// [[13, 14], [15, 16]]
// ],
// [
// [[9, 10], [11, 12]],
// [[11, 12], [13, 14]],
// [[17, 18], [19, 20]]
// ]
// ]
dynamic_iota
อรรถศาสตร์
การดำเนินการนี้มีฟังก์ชันการทำงานเหมือนกับ iota แต่รูปร่างผลลัพธ์จะถูกระบุแบบไดนามิกผ่านทาง output_shape
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | output_shape |
Tensor แบบ 1 มิติของประเภทจำนวนเต็ม | (C1), (C2) |
(I2) | iota_dimension |
si64 |
(C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของจำนวนเต็ม จุดลอยตัว หรือประเภทเชิงซ้อน หรือต่อ tensor เชิงปริมาณแบบต่อ tensor | (C2) |
ข้อจำกัด
- (C1)
0 <= iota_dimension < size(output_shape)
- (C2)
rank(result) = size(output_shape)
ตัวอย่าง
%output_shape = stablehlo.constant dense<[4, 5]> : tensor<2xi64>
%result = "stablehlo.dynamic_iota"(%output_shape) {
iota_dimension = 0 : i64
} : (tensor<2xi64>) -> tensor<4x5xi64>
// %result: [
// [0, 0, 0, 0, 0],
// [1, 1, 1, 1, 1],
// [2, 2, 2, 2, 2],
// [3, 3, 3, 3, 3]
// ]
dynamic_pad
อรรถศาสตร์
การดำเนินการนี้มีฟังก์ชันการทำงานเหมือนกับ pad op แต่มีการระบุ edge_padding_low
, edge_padding_high
และ interior_padding
เป็นค่าแบบไดนามิก
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1), (C2), (C4) |
(I2) | padding_value |
tensor แบบ 0 มิติหรือต่อ tensor เชิงปริมาณ | (C1) |
(I3) | edge_padding_low |
Tensor แบบ 1 มิติของประเภทจำนวนเต็ม | (C1), (C4) |
(I4) | edge_padding_high |
Tensor แบบ 1 มิติของประเภทจำนวนเต็ม | (C1), (C4) |
(I5) | interior_padding |
Tensor แบบ 1 มิติของประเภทจำนวนเต็ม | (C2-C4) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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
// %edge_padding_low: [0, 1]
// %edge_padding_high: [2, 1]
// %interior_padding: [1, 2]
%result = "stablehlo.dynamic_pad"(%operand, %padding_value,
%edge_padding_low, %edge_padding_high, %interior_padding
) : (tensor<2x3xi64>, tensor<i64>, tensor<2xi64>, tensor<2xi64>, tensor<2xi64>) -> tensor<5x9xi64>
// %result: [
// [0, 1, 0, 0, 2, 0, 0, 3, 0],
// [0, 0, 0, 0, 0, 0, 0, 0, 0],
// [0, 4, 0, 0, 5, 0, 0, 6, 0],
// [0, 0, 0, 0, 0, 0, 0, 0, 0],
// [0, 0, 0, 0, 0, 0, 0, 0, 0]
// ]
dynamic_reshape
อรรถศาสตร์
การดำเนินการนี้มีฟังก์ชันการทำงานเหมือนกับตัวเลือกปรับรูปร่าง แต่ระบบจะระบุรูปร่างผลลัพธ์แบบไดนามิกผ่าน output_shape
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือ tensor เชิงปริมาณ | (C1-C3) |
(I2) | output_shape |
Tensor แบบ 1 มิติของประเภทจำนวนเต็ม | (C4) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือ tensor เชิงปริมาณ | (C1-C4) |
ข้อจำกัด
- (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)
.
- (C4)
size(output_shape) = rank(result)
ตัวอย่าง
// %operand: [[1, 2, 3], [4, 5, 6]]
// %output_shape: [3, 2]
%result = "stablehlo.dynamic_reshape"(%operand, %output_shape) : (tensor<2x3xi64>, tensor<2xi64>) -> tensor<3x2xi64>
// %result: [[1, 2], [3, 4], [5, 6]]
dynamic_slice
อรรถศาสตร์
แยกสไลซ์จาก operand
โดยใช้ดัชนีเริ่มต้นที่คำนวณแบบไดนามิกและสร้าง 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
.
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1), (C2), (C4) |
(I2) | start_indices |
จำนวนตัวแปรของ tensors 0 มิติของประเภทจำนวนเต็ม | (C2), (C3) |
(I3) | slice_sizes |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C4), (C5) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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 = array<i64: 2, 2>
} : (tensor<4x4xi32>, tensor<i64>, tensor<i64>) -> tensor<2x2xi32>
// %result: [
// [1, 1],
// [1, 1]
// ]
dynamic_update_slice
อรรถศาสตร์
สร้าง tensor ของ result
ซึ่งเท่ากับ tensor ของ operand
เว้นแต่ว่าชิ้นส่วนที่เริ่มที่ start_indices
จะได้รับการอัปเดตด้วยค่าใน update
ชื่อเรียกอย่างเป็นทางการว่า result[result_index]
update[update_index]
หาก0 <= update_index < shape(update)
ที่:adjusted_start_indices = clamp(0, start_indices, shape(operand) - shape(update))
.update_index = result_index - adjusted_start_indices
.
operand[result_index]
ไม่เช่นนั้น
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1-C4), (C6) |
(I2) | update |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C2), (C3), (C6) |
(I3) | start_indices |
จำนวนตัวแปรของ tensors 0 มิติของประเภทจำนวนเต็ม | (C4), (C5) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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]
// ]
เลขชี้กำลัง
อรรถศาสตร์
ทำการดำเนินการแบบเลขชี้กำลังตามองค์ประกอบบน operand
tensor และสร้าง tensor result
ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับแบบลอยตัว:
exp
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: เลขชี้กำลังเชิงซ้อน
- สำหรับประเภทที่วัดปริมาณ:
dequantize_op_quantize(exponential, operand, type(result))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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 มิติของประเภทจุดลอยตัว จะสร้าง tensors 1 มิติของตรรกะของจุดลอยตัวเดียวกันประเภทที่ซับซ้อนและทํางานดังนี้
rfft(real_operand) = truncated_result
ตำแหน่งcomplex_operand... = (real_operand..., 0.0)
.complex_result = fft(complex_operand)
.truncated_result = complex_result[:(rank(complex_result) / 2 + 1)]
.
(เมื่อระบบคำนวณการแปลงฟูรีเยที่แยกต่างหากเพื่อหาตัวถูกดำเนินการจริง องค์ประกอบ N/2 + 1
แรกของผลลัพธ์จะกำหนดผลลัพธ์ที่เหลืออย่างชัดเจน ดังนั้นผลลัพธ์ของ rfft
จะถูกตัดออกเพื่อหลีกเลี่ยงการประมวลผลองค์ประกอบที่ซ้ำซ้อน)
สำหรับ fft_type = RFFT
ค่า result
คือผลลัพธ์สุดท้ายของชุดการคำนวณ L ที่ L = size(fft_length)
ตัวอย่างเช่น สำหรับ L = 3
result1[i0, ..., :] = rfft(operand[i0, ..., :])
.result2[i0, ..., :, iR-1] = fft(result1[i0, ..., :, iR-1])
.result[i0, ..., :, iR-2, iR-1] = fft(result2[i0, ..., :, iR-2, iR-1])
.
สุดท้าย กำหนดฟังก์ชัน irfft
ที่มีลายเซ็นประเภทเดียวกันและคำนวณค่าผกผันของ rfft
ดังนี้
สำหรับ fft_type = IRFFT
ค่า result
จะหมายถึงค่าผกผันของการคำนวณสำหรับ fft_type = RFFT
ตัวอย่างเช่น สำหรับ L = 3
result1[i0, ..., :, iR-2, iR-1] = ifft(operand[i0, ..., :, iR-2, iR-1])
.result2[i0, ..., :, iR-1] = ifft(result1[i0, ..., :, iR-1])
.result[i0, ..., :] = irfft(result2[i0, ..., :])
.
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
Tensor ของประเภทจุดลอยตัวหรือประเภทเชิงซ้อน | (C1), (C2), (C4), (C5) |
(I2) | fft_type |
enum ของ FFT , IFFT , RFFT และ IRFFT |
(C2), (C5) |
(I3) | 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 = array<i64: 4>
} : (tensor<4xcomplex<f32>>) -> tensor<4xcomplex<f32>>
// %result: [(1.0, 0.0), (1.0, 0.0), (1.0, 0.0), (1.0, 0.0)]
ชั้น
อรรถศาสตร์
ดำเนินการราคาพื้นตามองค์ประกอบของ tensor ของ operand
และสร้าง tensor แบบ result
ใช้การดำเนินการ roundToIntegralTowardNegative
จากข้อกำหนด IEEE-754 สำหรับประเภทที่แบ่งปริมาณแล้ว จะแสดงผล dequantize_op_quantize(floor, operand, type(result))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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
ไม่เช่นนั้น
- สำหรับ
d_operand
ในaxes(operand)
full_batching_index[d_operand] = batch_index[d_start - (d_start < index_vector_dim ? 0 : 1)]
หากd_operand = operand_batching_dims[i_batching]
และd_start = start_indices_batching_dims[i_batching]
full_batching_index[d_operand] = 0
ไม่เช่นนั้น
offset_index = result_index[offset_dims...]
.full_offset_index = [oi0, ..., 0, ..., oiN]
โดยที่oi
เป็นองค์ประกอบเดี่ยวในoffset_index
และแทรก0
ที่ดัชนีจากcollapsed_slice_dims
และoperand_batching_dims
operand_index = full_start_index + full_batching_index + full_offset_index
หาก indices_are_sorted
คือ true
การติดตั้งใช้งานจะถือว่ามีการจัดเรียง start_indices
ตาม start_index_map
หากไม่มีการกำหนดลักษณะการทำงาน อย่างเป็นทางการสำหรับ i1 < i2
ทั้งหมดจาก indices(result)
full_start_index(i1) <= full_start_index(i2)
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1), (C8), (C11), (C17), (C19-C21), (C23) |
(I2) | start_indices |
Tensor ของประเภทจำนวนเต็ม | (C2-C3), (C14), (C17), (C22) |
(I3) | offset_dims |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C1), (C4-C5), (C22) |
(I4) | collapsed_slice_dims |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C1), (C6-C9), (C22) |
(I5) | operand_batching_dims |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C1), (C6), (C10-C12), (C16-C18), (C22) |
(I6) | start_indices_batching_dims |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C13-C17) |
(I7) | start_index_map |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C3), (C18-C19) |
(I8) | index_vector_dim |
ค่าคงที่ประเภท si64 |
(C2-C3), (C15), (C22) |
(I9) | slice_sizes |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C9), (C12), (C20-C22) |
(I10) | indices_are_sorted |
ค่าคงที่ประเภท i1 |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C5), (C22-C23) |
ข้อจำกัด
- (C1)
rank(operand) = size(offset_dims) + size(collapsed_slice_dims) + size(operand_batching_dims)
- (C2)
0 <= index_vector_dim <= rank(start_indices)
- (C3)
size(start_index_map) = index_vector_dim < rank(start_indices) ? dim(start_indices, index_vector_dim) : 1
- (C4)
is_unique(offset_dims) and is_sorted(offset_dims)
- (C5)
0 <= offset_dims < rank(result)
- (C6)
is_unique(concatenate(collapsed_slice_dims, operand_batching_dims))
- (C7)
is_sorted(collapsed_slice_dims)
- (C8)
0 <= collapsed_slice_dims < rank(operand)
- (C9)
slice_sizes[collapsed_slice_dims...] <= 1
- (C10)
is_sorted(operand_batching_dims)
- (C11)
0 <= operand_batching_dims < rank(operand)
- (C12)
slice_sizes[operand_batching_dims...] <= 1
- (C13)
is_unique(start_indices_batching_dims)
- (C14)
0 <= start_indices_batching_dims < rank(start_indices)
- (C15)
index_vector_dim not in start_indices_batching_dims
- (C16)
size(operand_batching_dims) == size(start_indices_batching_dims)
- (C17)
dim(operand, operand_batching_dims...) = dim(start_indices, start_indices_batching_dims...)
- (C18)
is_unique(concatenate(start_index_map, operand_batching_dims))
- (C19)
0 <= start_index_map < rank(operand)
- (C20)
size(slice_sizes) = rank(operand)
- (C21)
0 <= slice_sizes <= shape(operand)
- (C22)
shape(result) = combine(batch_dim_sizes, offset_dim_sizes)
โดยที่batch_dim_sizes = shape(start_indices)
เว้นแต่ว่าจะไม่มีขนาดมิติข้อมูลของstart_indices
ที่สอดคล้องกับindex_vector_dim
offset_dim_sizes = slice_sizes
เว้นแต่ว่าจะไม่มีขนาดของมิติข้อมูลในslice_sizes
ที่สอดคล้องกับcollapsed_slice_dims
และoperand_batching_dims
combine
วางbatch_dim_sizes
ที่แกนที่สัมพันธ์กับbatch_dims
และoffset_dim_sizes
ที่แกนที่สอดคล้องกับoffset_dims
- (C23)
element_type(operand) = element_type(result)
ตัวอย่าง
// %operand: [
// [
// [[1, 2], [3, 4], [5, 6], [7, 8]],
// [[9, 10],[11, 12], [13, 14], [15, 16]],
// [[17, 18], [19, 20], [21, 22], [23, 24]]
// ],
// [
// [[25, 26], [27, 28], [29, 30], [31, 32]],
// [[33, 34], [35, 36], [37, 38], [39, 40]],
// [[41, 42], [43, 44], [45, 46], [47, 48]]
// ]
// ]
// %start_indices: [
// [
// [[0, 0], [1, 0], [2, 1]],
// [[0, 1], [1, 1], [0, 9]]
// ],
// [
// [[0, 0], [2, 1], [2, 2]],
// [[1, 2], [0, 1], [1, 0]]
// ]
// ]
%result = "stablehlo.gather"(%operand, %start_indices) {
dimension_numbers = #stablehlo.gather<
offset_dims = [3, 4],
collapsed_slice_dims = [1],
operand_batching_dims = [0],
start_indices_batching_dims = [1],
start_index_map = [2, 1],
index_vector_dim = 3>,
slice_sizes = array<i64: 1, 1, 2, 2>,
indices_are_sorted = false
} : (tensor<2x3x4x2xi32>, tensor<2x2x3x2xi64>) -> tensor<2x2x3x2x2xi32>
// %result: [
// [
// [
// [[1, 2], [3, 4]],
// [[3, 4], [5, 6]],
// [[13, 14], [15, 16]]
// ],
// [
// [[33, 34], [35, 36]],
// [[35, 36], [37, 38]],
// [[41, 42], [43, 44]]
// ]
// ],
// [
// [
// [[1, 2], [3, 4]],
// [[13, 14], [15, 16]],
// [[21, 22], [23, 24]]
// ],
// [
// [[43, 44], [45, 46]],
// [[33, 34], [35, 36]],
// [[27, 28], [29, 30]]
// ]
// ]
// ]
get_dimension_size
อรรถศาสตร์
สร้างขนาดของ dimension
ที่ระบุของ operand
อย่างเป็นทางการคือ
result = dim(operand, dimension)
ความหมายนี้เกี่ยวข้องกับ
องค์ประกอบรูปร่างของประเภทเท่านั้น ประเภทองค์ประกอบอาจเป็นอะไรก็ได้
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือ 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]
อย่างเป็นทางการ
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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))
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()
อย่างเป็นทางการ
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | pred |
Tensor แบบ 0 มิติของประเภท i1 |
|
(I2) | true_branch |
ฟังก์ชัน | (C1-C3) |
(I3) | 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))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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)
อินพุต
ค่ายเพลง | ชื่อ | ประเภท |
---|---|---|
(I1) | 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[output_index] = constant(is_quantized(output) ?
quantize(output_index[iota_dimension], element_type(output)) :
output_index[iota_dimension], element_type(output))
.
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | iota_dimension |
si64 |
(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
เสมอ
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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 การดำเนินการใน tensor ของ operand
และสร้าง tensor ของ result
ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับแบบลอยตัว:
logp1
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: ลอการิทึมเชิงซ้อนบวก 1
- สำหรับประเภทที่วัดปริมาณ:
dequantize_op_quantize(log_plus_one, operand, type(result))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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]
โลจิสติกส์
อรรถศาสตร์
ดำเนินการโลจิสติกส์ตามองค์ประกอบบน tensor ของ operand
และสร้าง Tensor result
ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับแบบลอยตัว:
division(1, addition(1, exp(-x)))
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: โลจิสติกส์เชิงซ้อน
- สำหรับประเภทที่วัดปริมาณ:
dequantize_op_quantize(logistic, operand, type(result))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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])
อย่างเป็นทางการ
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | inputs |
จำนวนตัวแปรของ tensors หรือ tensor แบบต่อ tensor เชิงปริมาณ | (C1-C4) |
(I2) | dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C3) |
(I3) | computation |
ฟังก์ชัน | (C4) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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 = array<i64: 0, 1>
} : (tensor<2x2xi64>, tensor<2x2xi64>) -> tensor<2x2xi64>
// %result: [[0, 5], [12, 21]]
สูงสุด
อรรถศาสตร์
ดำเนินการสูงสุดตามองค์ประกอบตามองค์ประกอบบน tensors lhs
และ rhs
และสร้าง Tensor result
ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับบูลีน: ตรรกะ OR
- สำหรับจำนวนเต็ม: จำนวนเต็มสูงสุด
- สำหรับแบบลอยตัว:
maximum
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: พจนานุกรมสูงสุดสำหรับคู่
(real, imaginary)
การกำหนดลำดับด้วยจำนวนเชิงซ้อนเกี่ยวข้องกับความหมายที่คาดไม่ถึง ดังนั้นในอนาคตเราจึงวางแผนที่จะนำการรองรับจำนวนเชิงซ้อนออกสำหรับการดำเนินการนี้ (#560) - สำหรับประเภทที่วัดปริมาณ:
dequantize_op_quantize(maximum, lhs, rhs, type(result))
.
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1) |
(I2) | rhs |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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))
.
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1) |
(I2) | rhs |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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]]
คูณ
อรรถศาสตร์
สร้างผลคูณตามองค์ประกอบจาก tensor 2 ตัว lhs
และ rhs
และสร้าง tensor ขนาด result
ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับบูลีน: ตรรกะ AND
- สำหรับจำนวนเต็ม: การคูณจำนวนเต็ม
- สำหรับแบบลอยตัว:
multiplication
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: การคูณเชิงซ้อน
- สำหรับประเภทที่วัดปริมาณ:
dequantize_op_quantize(multiply, lhs, rhs, type(result))
.
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1) |
(I2) | rhs |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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
- สำหรับจำนวนเต็ม: บิตไวส์ไม่ใช่
อาร์กิวเมนต์
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
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 |
จำนวน Tensor แบบแปรผัน, โทเค็นหรือโทเค็นต่อ tensor เชิงปริมาณ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
จำนวน 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
และสร้าง tensor ของ result
ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับบูลีน: ตรรกะ OR
- สำหรับจำนวนเต็ม: บิตไวส์ OR
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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
กำหนดไว้สำหรับการใช้งาน
อินพุต
ค่ายเพลง | ชื่อ | ประเภท |
---|---|---|
(I1) | inputs |
จำนวน tensors แบบแปรผันหรือ Tensor เชิงปริมาณ |
(I2) | token |
token |
(I3) | outfeed_config |
ค่าคงที่ประเภท string |
เอาต์พุต
ชื่อ | ประเภท |
---|---|
result |
token |
ตัวอย่าง
%result = "stablehlo.outfeed"(%input0, %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
ไม่เช่นนั้น
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1), (C2), (C4) |
(I2) | padding_value |
tensor แบบ 0 มิติหรือต่อ tensor เชิงปริมาณ | (C1) |
(I3) | edge_padding_low |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C1), (C4) |
(I4) | edge_padding_high |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C1), (C4) |
(I5) | interior_padding |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2-C4) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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 = array<i64: 0, 1>,
edge_padding_high = array<i64: 2, 1>,
interior_padding = array<i64: 1, 2>
} : (tensor<2x3xi32>, tensor<i32>) -> tensor<5x9xi32>
// %result: [
// [0, 1, 0, 0, 2, 0, 0, 3, 0],
// [0, 0, 0, 0, 0, 0, 0, 0, 0],
// [0, 4, 0, 0, 5, 0, 0, 6, 0],
// [0, 0, 0, 0, 0, 0, 0, 0, 0],
// [0, 0, 0, 0, 0, 0, 0, 0, 0]
// ]
partition_id
อรรถศาสตร์
สร้าง partition_id
ของกระบวนการปัจจุบัน
เอาต์พุต
ชื่อ | ประเภท |
---|---|
result |
Tensor แบบ 0 มิติของประเภท ui32 |
ตัวอย่าง
%result = "stablehlo.partition_id"() : () -> tensor<ui32>
Popcnt
อรรถศาสตร์
ดำเนินการนับตามองค์ประกอบของจำนวนบิตที่กำหนดไว้ใน tensor ของ operand
และสร้าง tensor ของ result
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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]
พาวเวอร์
อรรถศาสตร์
สร้าง exponentiation ของ lhs
tensor ด้วย rhs
tensor และสร้าง result
tensor ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับจำนวนเต็ม: เลขยกกำลังจำนวนเต็ม
- สำหรับแบบลอยตัว:
pow
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: เลขชี้กำลังเชิงซ้อน
- สำหรับประเภทที่นับจำนวน:
dequantize_op_quantize(power, lhs, rhs, type(result))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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]
รับ
อรรถศาสตร์
รับข้อมูลจากช่องด้วย channel_id
และสร้าง results
หาก is_host_transfer
คือ true
การดำเนินการจะโอนข้อมูลจากโฮสต์ ไม่เช่นนั้น ระบบจะโอนข้อมูลจากอุปกรณ์อื่น ซึ่งหมายถึง
การใช้งานตามที่กำหนดไว้ แฟล็กนี้ซ้ำกับข้อมูลที่ให้ไว้ใน channel_type
ดังนั้นในอนาคตเราวางแผนที่จะเก็บไว้เพียง 1 รายการเท่านั้น (#666)
results
ประกอบด้วยค่าเพย์โหลดซึ่งมาก่อนและโทเค็นสุดท้าย ในอนาคต เราวางแผนที่จะแยกเพย์โหลดและโทเค็นออกเป็นเอาต์พุตแยกกัน 2 รายการเพื่อปรับปรุงความชัดเจน (#670)
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | token |
token |
(C4) |
(I2) | channel_id |
ค่าคงที่ประเภท si64 |
|
(I3) | 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
และสร้าง Tensor results
ลำดับของการลดมีการกำหนดเป็นการติดตั้งใช้งาน ซึ่งหมายความว่า 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
ที่กำหนดการติดตั้งใช้งานในตำแหน่งที่กำหนดการติดตั้งใช้งาน
- ค่า
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | inputs |
จำนวนตัวแปรของ tensors หรือ tensor แบบต่อ tensor เชิงปริมาณ | (C1-C4), (C6), (C7) |
(I2) | init_values |
จำนวนแปรผันของ tensor 0 มิติหรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C2), (C3) |
(I3) | 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 = array<i64: 1>
} : (tensor<1x6xi64>, tensor<i64>) -> tensor<1xi64>
// %result = [15]
reduce_precision
อรรถศาสตร์
แปลง 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))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ | (C1) |
(I2) | exponent_bits |
ค่าคงที่ประเภท si32 |
(C2) |
(I3) | 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
กับค่าของ Tensor operand
จากแต่ละกระบวนการจะแบ่งผลลัพธ์การลดตาม scatter_dimension
ออกเป็นส่วนต่างๆ และกระจายส่วนที่แยกระหว่างกระบวนการเพื่อสร้าง result
การดําเนินการนี้จะแบ่งตารางกริดการประมวลผลของ StableHLO เป็น process_groups
ซึ่งมีคำจำกัดความดังนี้
cross_replica(replica_groups)
หากchannel_id <= 0 and use_global_device_ids = false
cross_replica_and_partition(replica_groups)
หากchannel_id > 0 and use_global_device_ids = false
flattened_ids(replica_groups)
หากchannel_id > 0 and use_global_device_ids = true
หลังจากนั้น ภายในแต่ละ process_group
:
reduced_value = all_reduce(operand, replica_groups, channel_id, use_global_device_ids, computation)
.parts@sender = split(reduced_value@sender, dim(process_groups, 1), scatter_dimension)
.result@receiver = parts@sender[receiver_index]
สำหรับsender
ทั้งหมดในprocess_group
โดยที่receiver_index = process_group.index(receiver)
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1), (C2), (C7), (C8) |
(I2) | scatter_dimension |
ค่าคงที่ประเภท si64 |
(C1), (C2), (C8) |
(I3) | replica_groups |
ค่าคงที่ tensor แบบ 2 มิติของประเภท si64 |
(C3-C5) |
(I4) | channel_id |
ค่าคงที่ประเภท si64 |
(C6) |
(I5) | use_global_device_ids |
ค่าคงที่ประเภท i1 |
(C6) |
(I6) | computation |
ฟังก์ชัน | (C7) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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)
.
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | inputs |
จำนวนตัวแปรของ tensors หรือ tensor แบบต่อ tensor เชิงปริมาณ | (C1-C4), (C6), (C8), (C10), (C12), (C13), (C15) |
(I2) | init_values |
จำนวนแปรผันของ tensor 0 มิติหรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1), (C13) |
(I3) | window_dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C4), (C5), (C15) |
(I4) | window_strides |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C6), (C7), (C15) |
(I5) | base_dilations |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C8), (C9), (C15) |
(I6) | window_dilations |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C10), (C11), (C15) |
(I7) | 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 = array<i64: 2, 1>,
window_strides = array<i64: 4, 1>,
base_dilations = array<i64: 2, 1>,
window_dilations = array<i64: 3, 1>,
padding = dense<[[2, 1], [0, 0]]> : tensor<2x2xi64>
} : (tensor<3x2xi64>, tensor<i64>) -> tensor<2x2xi64>
// %result = [[0, 0], [3, 4]]
เศษ
อรรถศาสตร์
สร้างเศษส่วนขององค์ประกอบของตัวหาร lhs
และตัวหาร rhs
ตัวหาร แล้วสร้าง Tensor result
หรือกล่าวอีกนัยหนึ่งคือ เครื่องหมายของผลลัพธ์ที่ได้จะมาจากตัวหาร และค่าสัมบูรณ์ของผลลัพธ์จะน้อยกว่าค่าสัมบูรณ์ของตัวหารเสมอ
เศษจะคำนวณเป็น 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
มากที่สุดโดยมีค่าเท่ากัน
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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
ให้เป็น Tensor แบบ result
โดยหลักการแล้วก็ต้องใช้การนำเสนอตามรูปแบบบัญญัติเดิมแต่อาจเปลี่ยนรูปร่าง เช่น จาก tensor<2x3xf32>
เป็น tensor<3x2xf32>
หรือ tensor<6xf32>
เป็นทางการมากขึ้น result[result_index] = operand[operand_index]
โดยที่ result_index
และ operand_index
มีอันดับเดียวกันในลำดับพจนานุกรมของ index_space(result)
และ index_space(operand)
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
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
ที่ระบุและสร้าง Tensor result
อย่างเป็นทางการ
result[result_index] = operand[operand_index]
ซึ่ง
operand_index[d] = dim(result, d) - result_index[d] - 1
หากเป็นd
ในdimensions
operand_index[d] = result_index[d]
ไม่เช่นนั้น
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1), (C3) |
(I2) | dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C3) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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 = array<i64: 1>
} : (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)
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | a |
tensor แบบ 0 มิติของจำนวนเต็ม บูลีน หรือประเภทจุดลอยตัว | (C1), (C2) |
(I2) | b |
tensor แบบ 0 มิติของจำนวนเต็ม บูลีน หรือประเภทจุดลอยตัว | (C1), (C2) |
(I3) | 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
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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
tensors ที่เท่ากับ 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
ไม่เช่นนั้น
- สำหรับ
d_input
ในaxes(inputs[0])
full_batching_index[d_input] = update_scatter_index[d_start - (d_start < index_vector_dim ? 0 : 1)]
หากd_input = input_batching_dims[i_batching]
และd_start = scatter_indices_batching_dims[i_batching]
full_batching_index[d_input] = 0
ไม่เช่นนั้น
update_window_index = update_index[update_window_dims...]
.full_window_index = [wi0, ..., 0, ..., wiN]
โดยที่wi
เป็นองค์ประกอบเดี่ยวในupdate_window_index
และแทรก0
ที่ดัชนีจากinserted_window_dims
และinput_batching_dims
result_index = full_start_index + full_batching_index + full_window_index
.
ทำให้ results = exec(schedule, inputs)
โดยที่
schedule
เป็นการเรียงสับเปลี่ยนindex_space(updates[0])
ที่กำหนดการติดตั้งใช้งานexec([update_index, ...], results) = exec([...], updated_results)
ซึ่ง:- หาก
result_index
อยู่ในขอบเขตของshape(results...)
updates_converted = to_destination_type( updates...[update_index], type(func_inputs(update_computation) [len(func_inputs(update_computation))//2:])... )
updated_values = update_computation(results...[result_index], updates_converted)
updated_results
เป็นสำเนาของresults
ที่มีการตั้งค่า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
แต่ดัชนีที่กระจัดกระจายไม่ใช่ค่าที่ไม่ซ้ำ จะไม่มีการระบุลักษณะการทำงาน
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | inputs |
จำนวนตัวแปรของ tensors หรือ tensor แบบต่อ tensor เชิงปริมาณ | (C1), (C2), (C4-C6), (C11), (C13), (C18), (C21), (C23-C24) |
(I2) | scatter_indices |
Tensor ของประเภทจำนวนเต็ม | (C4), (C15), (C19), (C22) |
(I3) | updates |
จำนวนตัวแปรของ tensors หรือ tensor แบบต่อ tensor เชิงปริมาณ | (C3-C6), (C8) |
(I4) | update_window_dims |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C4), (C7-C8) |
(I5) | inserted_window_dims |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C4), (C9-C11) |
(I6) | input_batching_dims |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C4), (C9), (C12-13), (C17-18), (C20) |
(I7) | scatter_indices_batching_dims |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C14-C18) |
(I8) | scatter_dims_to_operand_dims |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C19-C21) |
(I9) | index_vector_dim |
ค่าคงที่ประเภท si64 |
(C4), (C16), (C19), (C22) |
(I10) | indices_are_sorted |
ค่าคงที่ประเภท i1 |
|
(I11) | unique_indices |
ค่าคงที่ประเภท i1 |
|
(I12) | update_computation |
ฟังก์ชัน | (C23) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวนตัวแปรของ tensors หรือ tensor แบบต่อ tensor เชิงปริมาณ | (C24-C25) |
ข้อจำกัด
- (C1)
same(shape(inputs...))
- (C2) `rank(inputs[0]) = size(update_window_dims) + ขนาด(inserted_window_dims)
- size(input_batching_dims)`
- (C3)
same(shape(updates...))
- (C4)
shape(updates[0]) = combine(update_scatter_dim_sizes, update_window_dim_sizes)
ที่:update_scatter_dim_sizes = shape(scatter_indices)
เว้นแต่ว่าจะไม่มีขนาดมิติข้อมูลของscatter_indices
ที่สอดคล้องกับindex_vector_dim
update_window_dim_sizes <= shape(inputs[0])
เว้นแต่ว่าจะไม่มีขนาดของมิติข้อมูลในinputs[0]
ที่สอดคล้องกับinserted_window_dims
และinput_batching_dims
combine
วางupdate_scatter_dim_sizes
ที่แกนที่สัมพันธ์กับupdate_scatter_dims
และupdate_window_dim_sizes
ที่แกนที่ตรงกับupdate_window_dims
- (C5)
0 < size(inputs) = size(updates) = N
- (C6)
element_type(updates...) = element_type(inputs...)
- (C7)
is_unique(update_window_dims) and is_sorted(update_window_dims)
- (C8)
0 <= update_window_dims < rank(updates[0])
- (C9)
is_unique(concatenate(inserted_window_dims, input_batching_dims))
- (C10)
is_sorted(inserted_window_dims)
- (C11)
0 <= inserted_window_dims < rank(inputs[0])
- (C12)
is_sorted(input_batching_dims)
- (C13)
0 <= input_batching_dims < rank(inputs[0]))
- (C14)
is_unique(scatter_indices_batching_dims)
- (C15)
0 <= scatter_indices_batching_dims < rank(scatter_indices)
- (C16)
index_vector_dim not in scatter_indices_batching_dims
- (C17)
size(input_batching_dims) == size(scatter_indices_batching_dims)
- (C18)
dim(inputs[0], input_batching_dims...) = dim(scatter_indices, scatter_indices_batching_dims...)
- (C19)
size(scatter_dims_to_operand_dims) = index_vector_dim < rank(scatter_indices) ? dim(scatter_indices, index_vector_dim) : 1
- (C20)
is_unique(concatenate(scatter_dims_to_operand_dims, input_batching_dims))
- (C21)
0 <= scatter_dims_to_operand_dims < rank(inputs[0])
- (C22)
0 <= index_vector_dim <= rank(scatter_indices)
- (C23)
update_computation
เป็นประเภท(tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ..., tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>)
โดยที่is_promotable(element_type(inputs[i]), Ei)
- (C24)
shape(inputs...) = shape(results...)
- (C25)
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]]
// ],
// [
// [[25, 26], [27, 28], [29, 30], [31, 32]],
// [[33, 34], [35, 36], [37, 38], [39, 40]],
// [[41, 42], [43, 44], [45, 46], [47, 48]]
// ]
// ]
// %scatter_indices: [
// [
// [[0, 0], [1, 0], [2, 1]],
// [[0, 1], [1, 1], [0, 9]]
// ],
// [
// [[0, 0], [2, 1], [2, 2]],
// [[1, 2], [0, 1], [1, 0]]
// ]
// ]
// %update: [
// [
// [[1, 1], [1, 1], [1, 1]],
// [[1, 1], [1, 1], [1, 1]]
// ],
// [
// [[1, 1], [1, 1], [1, 1]],
// [[1, 1], [1, 1], [1, 1]]
// ]
// ]
%result = "stablehlo.scatter"(%input, %scatter_indices, %update) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
"stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
scatter_dimension_numbers = #stablehlo.scatter<
update_window_dims = [3, 4],
inserted_window_dims = [1],
input_batching_dims = [0],
scatter_indices_batching_dims = [1],
scatter_dims_to_operand_dims = [2, 1],
index_vector_dim = 3>,
indices_are_sorted = false,
unique_indices = false
} : (tensor<2x3x4x2xi64>, tensor<2x2x3x2xi64>, tensor<2x2x3x2x2xi64>) -> tensor<2x3x4x2xi64>
// %result: [
// [
// [[3, 4], [6, 7], [6, 7], [7, 8]],
// [[9, 10],[11, 12], [15, 16], [17, 18]],
// [[17, 18], [19, 20], [22, 23], [24, 25]]
// ],
// [
// [[25, 26], [28, 29], [30, 31], [31, 32]],
// [[35, 36], [38, 39], [38, 39], [39, 40]],
// [[41, 42], [44, 45], [46, 47], [47, 48]]
// ]
// ]
เลือก
อรรถศาสตร์
สร้าง tensor ของ result
เมื่อเลือกองค์ประกอบแต่ละรายการจาก 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))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | pred |
Tensor ประเภท i1 |
(C1) |
(I2) | on_true |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1-C2) |
(I3) | on_false |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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
อรรถศาสตร์
กระจายค่าจาก tensor ของ source
โดยใช้ scatter
โดยอิงตามผลลัพธ์ของ reduce_window
ของ tensor ของ input
โดยใช้ select
และสร้าง Tensor result
แผนภาพต่อไปนี้แสดงวิธีที่องค์ประกอบใน result
คํานวณจาก operand
และ source
โดยใช้ตัวอย่างที่เป็นรูปธรรม
เป็นทางการมากขึ้น
selected_values = reduce_window_without_init(...)
พร้อมอินพุตต่อไปนี้inputs = [operand].
window_dimensions
,window_strides
และpadding
ซึ่งใช้ตามเดิมbase_dilations = windows_dilations = 1
.body
ให้คำนิยามไว้ดังนี้
def body(arg0: tensor<E>, arg1: tensor<E>) -> tensor<E>: return select(arg0, arg1) ? arg0 : arg1;
โดยที่
E = element_type(operand)
และreduce_window_without_init
ทำงานเหมือนกับreduce_window
ทุกประการ ยกเว้นว่าschedule
ของreduce
ที่สำคัญ (ดูลด) จะไม่รวมค่า init ปัจจุบันยังไม่มีการระบุถึงสิ่งที่จะเกิดขึ้นหากหน้าต่างที่เกี่ยวข้องไม่มีค่า (#731)result[result_index] = reduce([source_values], [init_value], [0], scatter)
ตำแหน่ง:source_values = [source[source_index] for source_index in source_indices]
.selected_index(source_index) = operand_index
หากselected_values[source_index]
มีองค์ประกอบoperand
จากoperand_index
source_indices = [source_index for source_index in indices(source) if selected_index(source_index) = result_index]
.
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1-C4), (C6), (C8-C11) |
(I2) | source |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1), (C2) |
(I3) | init_value |
tensor แบบ 0 มิติหรือต่อ tensor เชิงปริมาณ | (C3) |
(I4) | window_dimensions |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C4), (C5) |
(I5) | window_strides |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C6), (C7) |
(I6) | padding |
ค่าคงที่ tensor แบบ 2 มิติของประเภท si64 |
(C2), (C8) |
(I7) | select |
ฟังก์ชัน | (C9) |
(I8) | scatter |
ฟังก์ชัน | (C10) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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 = array<i64: 3, 1>,
window_strides = array<i64: 2, 1>,
padding = dense<[[0, 1], [0, 0]]> : tensor<2x2xi64>
} : (tensor<4x2xi64>, tensor<2x2xi64>, tensor<i64>) -> tensor<4x2xi64>
// %result: [[0, 0], [0, 0], [5, 14], [7, 0]]
ส่ง
อรรถศาสตร์
ส่ง inputs
ไปยังช่อง channel_id
และสร้างโทเค็น result
หาก is_host_transfer
คือ true
การดำเนินการจะโอนข้อมูลไปยังโฮสต์ ไม่เช่นนั้น ระบบจะโอนข้อมูลไปยังอุปกรณ์อื่น ซึ่งหมายถึง
การใช้งานตามที่กำหนดไว้ แฟล็กนี้ซ้ำกับข้อมูลที่ให้ไว้ใน channel_type
ดังนั้นในอนาคตเราวางแผนที่จะเก็บไว้เพียง 1 รายการเท่านั้น (#666)
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | inputs |
จำนวน tensors แบบแปรผันหรือ Tensor เชิงปริมาณ | |
(I2) | token |
token |
|
(I3) | channel_id |
ค่าคงที่ประเภท si64 |
|
(I4) | channel_type |
enum ของ DEVICE_TO_DEVICE และ DEVICE_TO_HOST |
(C1) |
(I5) | 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
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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
อรรถศาสตร์
ดำเนินการใช้ชิฟท์ด้านขวาตามหลักคณิตศาสตร์บน tensor ของ lhs
ตามจำนวนบิต rhs
และสร้าง Tensor result
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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
อรรถศาสตร์
ดำเนินการใช้ Tensor แบบการเปลี่ยนแปลงในเชิงตรรกะตามองค์ประกอบบน tensor ของ lhs
ตามจำนวนบิต rhs
และสร้าง tensor result
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ | (C1-C3), (C5) |
(I2) | start_indices |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C3), (C5) |
(I3) | limit_indices |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C3), (C5) |
(I4) | strides |
ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 |
(C2), (C4) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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 = array<i64: 1, 2>,
limit_indices = array<i64: 3, 4>,
strides = array<i64: 1, 1>
} : (tensor<3x4xi64>) -> tensor<2x2xi64>
// % result: [
// [1, 1],
// [1, 1]
// ]
จัดเรียง
อรรถศาสตร์
จัดเรียงชิ้นส่วน inputs
ส่วน 1 มิติตามมิติข้อมูล dimension
เข้าด้วยกันตาม comparator
และสร้าง results
dimension
จะอนุญาตค่าลบ ซึ่งต่างจากอินพุตที่คล้ายกันในการดําเนินการอื่นๆ ตรงที่อธิบายไว้ด้านล่าง ในอนาคต เราอาจไม่อนุญาตให้ทำเช่นนี้เนื่องจากเหตุผลด้านความสอดคล้อง (#1377)
หาก is_stable
เป็นจริง การจัดเรียงจะคงที่ กล่าวคือ ลำดับที่เกี่ยวข้องขององค์ประกอบที่พบว่ามีค่าเท่ากันโดยตัวเปรียบเทียบจะยังคงอยู่ สำหรับกรณีที่มีอินพุตเดียว องค์ประกอบ 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
.
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | inputs |
จำนวนตัวแปรของ tensors หรือ tensor แบบต่อ tensor เชิงปริมาณ | (C1-C5) |
(I2) | dimension |
ค่าคงที่ประเภท si64 |
(C4) |
(I3) | 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))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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]]
ลบ
อรรถศาสตร์
ดำเนินการลบ tensor จำนวน 2 ตัว lhs
และ rhs
ตามองค์ประกอบ แล้วสร้าง Tensor result
ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับจำนวนเต็ม: การลบจำนวนเต็ม
- สำหรับแบบลอยตัว:
subtraction
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: การลบเชิงซ้อน
- สำหรับประเภทที่วัดปริมาณ:
dequantize_op_quantize(subtract, lhs, rhs, type(result))
.
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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]]
แทนห์
อรรถศาสตร์
ทำการดำเนินการไฮเปอร์โบลิกแทนเจนต์ตามองค์ประกอบบน tensor ของ operand
และสร้าง tensor ของ result
ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับแบบลอยตัว:
tanh
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: ไฮเปอร์โบลิกแทนเจนต์เชิงซ้อน
- สำหรับประเภทที่วัดปริมาณ:
dequantize_op_quantize(tanh, operand, type(result))
.
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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]
สลับตำแหน่ง
อรรถศาสตร์
เรียงสับเปลี่ยนมิติข้อมูลของ tensor ของ operand
โดยใช้ permutation
และสร้าง Tensor result
อย่างเป็นทางการคือ result[result_index] = operand[operand_index]
ที่ result_index[d] = operand_index[permutation[d]]
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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 = array<i64: 2, 1, 0>
} : (tensor<2x3x2xi32>) -> tensor<2x3x2xi32>
// %result: [
// [[1,7], [3,9], [5,11]],
// [[2,8], [4,10], [6,12]]
// ]
triangular_solve
อรรถศาสตร์
แก้ชุดระบบสมการเชิงเส้นที่มีเมทริกซ์สัมประสิทธิ์สามเหลี่ยมล่างหรือบน
สำหรับ a
และ b
ในทางปฏิบัติแล้ว result[i0, ..., iR-3, :, :]
คือคำตอบของ op(a[i0, ..., iR-3, :, :]) * x = b[i0, ..., iR-3, :, :]
เมื่อ left_side
คือ true
หรือ x * op(a[i0, ..., iR-3, :, :]) = b[i0, ..., iR-3, :, :]
เมื่อ left_side
เป็น false
เพื่อหาตัวแปร x
โดยที่ op(a)
จะกำหนดโดย transpose_a
ซึ่งอาจเป็นอย่างใดอย่างหนึ่งต่อไปนี้
NO_TRANSPOSE
: ดำเนินการโดยใช้a
ตามที่เป็นอยู่TRANSPOSE
: ดำเนินการกับการสลับตำแหน่งa
ADJOINT
: ดำเนินการแทนสังยุคa
ข้อมูลที่ป้อนจะอ่านจากสามเหลี่ยมล่างของ 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))
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | a |
tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ | (C1-C3) |
(I2) | b |
tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ | (C1-C4) |
(I3) | left_side |
ค่าคงที่ประเภท i1 |
(C3) |
(I4) | lower |
ค่าคงที่ประเภท i1 |
|
(I5) | unit_diagonal |
ค่าคงที่ประเภท i1 |
|
(I6) | transpose_a |
enum ของ NO_TRANSPOSE , TRANSPOSE และ ADJOINT |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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)
อย่างเป็นทางการ
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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 แบบจุดลอยตัวหรือ 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))
.
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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)
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
จำนวน tensors แบบแปรผัน, tensors เชิงปริมาณหรือโทเค็น | (C1-C3) |
(I2) | cond |
ฟังก์ชัน | (C1) |
(I3) | 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
และสร้าง tensor ของ result
ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับบูลีน: ตรรกะ XOR
- สำหรับจำนวนเต็ม: บิตไวส์ XOR
อินพุต
ค่ายเพลง | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | 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 ทั่วไปมีการดำเนินการที่ไม่ได้กำหนดโดย StableHLO ในบางครั้ง
โมดูล ฟังก์ชัน การเรียก และการคืนสินค้า
StableHLO ใช้การดำเนินการ MLIR แบบอัปสตรีมสำหรับ ModuleOp, FuncOp, CallOp และ ReturnOp การดำเนินการดังกล่าวมีขึ้นเพื่อการทำงานร่วมกันที่ดีขึ้นกับเครื่องจักร MLIR ที่มีอยู่ เนื่องจากมีการเขียนบัตรผ่านที่มีประโยชน์จำนวนมากโดยกำหนดเป้าหมาย FuncOp และ ModuleOp และมีไปป์ไลน์การคอมไพล์จำนวนมากที่คาดว่าจะมีการดำเนินการเหล่านี้ ระบบจะนำการรับประกันความเข้ากันได้เต็มรูปแบบ ไปใช้กับการดำเนินการเหล่านี้ หากมีการเปลี่ยนแปลงใดๆ เกี่ยวกับการดำเนินการเหล่านี้ในลักษณะที่เข้ากันไม่ได้ (เช่น การนำออก) ระบบจะเพิ่มไฟล์ที่เทียบเท่าของ StableHLO เพื่อรักษาความเข้ากันได้
เชโล
ตัวเลือก CHLO มีการดำเนินการระดับสูงกว่าที่แตกตัวเป็น StableHLO ขณะนี้ยังไม่มีการรับประกันความเข้ากันได้สำหรับ CHLO เพื่อรับประกันความเข้ากันได้ คุณต้องใช้บัตร chlo-legalize-to-stablehlo ก่อนการเรียงอันดับ
การดำเนินการของรูปร่าง
เป็นกรณีการใช้งานทั่วไปในชุมชนที่ใช้การดำเนินการบางอย่างจากภาษาหลักของ MLIR ในโปรแกรม StableHLO แบบไดนามิกเพื่อคำนวณรูปร่าง
ที่พบบ่อยที่สุด ได้แก่ shape
ภาษาถิ่น
เช่น shape_of
หรือ num_elements
, tensor
ภาษา
เช่น dim
หรือ from_elements
และประเภท index
ในตัว
Dynamism RFC > O2 บ่งบอกว่าสิ่งเหล่านี้อยู่นอกขอบเขต แต่การรองรับ index
ประเภทนั้นรวมไว้เพื่อวัตถุประสงค์ด้านการทำงานร่วมกัน เราไม่รับประกันความเข้ากันได้สำหรับ
การดำเนินการหรือประเภทเหล่านี้ คุณจะใช้บัตร shape-legalize-to-stablehlo เพื่อแปลงการดำเนินการเหล่านี้เป็นการดำเนินการ StableHLO ที่รองรับอย่างเต็มรูปแบบได้
การดำเนินการที่เลิกใช้งานแล้ว
มีการดำเนินการของ StableHLO หลายรายการที่รับช่วงมาจาก MHLO ซึ่งเลิกใช้งานแล้วและอยู่ระหว่างการหยุดให้บริการ StableHLO ดูรายละเอียดทั้งหมดเกี่ยวกับการนำออกเหล่านี้ได้ในการล้างข้อมูลของ StableHLO v1.0 #2283 ปัญหาเครื่องมือติดตามสำหรับการเลิกใช้งานเหล่านี้คือ #2340
การดำเนินการเหล่านี้แบ่งออกเป็น 2-3 หมวดหมู่ ดังนี้
- หมวดหมู่การดำเนินการของ StableHLO "ไม่อยู่ใน HLO" ซึ่งตอนแรกเป็นส่วนหนึ่งของ
ฝ่ายปฏิบัติการ StableHLO แต่ภายหลังมีการพิจารณาว่าไม่เหมาะสม
broadcast
,create_token
,cross-replica-sum
,dot
,einsum
,torch_index_select
,unary_einsum
(#3) - การดำเนินการที่ไม่ได้ใช้งาน - การดำเนินการเหล่านี้อาจมีประโยชน์ในบางจุด แต่การดำเนินการอาจด้อยพัฒนาหรือมีการเปลี่ยนแปลงไปป์ไลน์ที่ใช้การดำเนินการเหล่านี้เพื่อไม่ให้ต้องใช้การดำเนินการดังกล่าวอีกต่อไป ซึ่งรวมถึง
map
,tuple
(#598),get_tuple_element
,rng
,complex
การเปรียบเทียบ #560 และ Convolutionwindow_reversal
(#1181)
การดำเนินการเหล่านี้บางส่วนสามารถนำออกได้ง่ายๆ เนื่องจากสามารถแสดงโดยใช้การดำเนินการที่มีอยู่ (broadcast
, create_token
, cross-replica-sum
, dot
, unary_einsum
) และจะถูกนำออกหลังพ้นกรอบเวลาความเข้ากันได้ที่มีอยู่ (6 เดือน) ระบบกำลังสำรวจรายการอื่นๆ เพื่อนำออก (einsum
,
get_tuple_element
, map
, rng
torch_index_select
, tuple
, complex
การเปรียบเทียบ, window_reversal
) ความคิดเห็นจากชุมชนที่รอดำเนินการ
จะถูกนำออก หรือเพิ่มไปยังข้อกำหนดพร้อมกับการสนับสนุนเต็มรูปแบบ เราจะรับประกันความสามารถในการใช้งานร่วมกันเป็นเวลาเพียง 6 เดือนเท่านั้นจนกว่าเราจะรู้อนาคตการดำเนินการเหล่านี้
การลงมือปฏิบัติ
การดำเนินการตามลำดับ
โปรแกรม StableHLO จะดำเนินการโดยการระบุค่าอินพุตให้กับฟังก์ชัน main
และค่าเอาต์พุตการคำนวณ ค่าเอาต์พุตของฟังก์ชันจะคํานวณโดยการเรียกใช้กราฟของ Ops ที่รูทในฟังก์ชัน return
ที่สอดคล้องกัน
ลำดับการดำเนินการได้รับการนิยามถึงการใช้งาน ตราบใดที่สอดคล้องกับโฟลว์ข้อมูล กล่าวคือ มีการดำเนินการ Ops ก่อนการใช้งาน ใน StableHLO การดำเนินการที่ส่งผลข้างเคียงทั้งหมดจะใช้ 1 โทเค็นและสร้างโทเค็น 1 โทเค็น (สามารถรวมโทเค็นหลายรายการเข้าเป็นโทเค็นเดียวผ่าน after_all
ได้) ดังนั้นลำดับการดำเนินการของผลข้างเคียงจึงสอดคล้องกับโฟลว์ข้อมูลด้วย ตัวอย่างเช่น ในโปรแกรมด้านล่างมีคำสั่งการดำเนินการที่เป็นไปได้ 2 คำสั่ง ได้แก่ %0
→ %1
→ %2
→ return
และ %1
→ %0
→ %2
→ return
func.func @main() -> tensor<f64> {
%0 = stablehlo.constant dense<1.0> : tensor<f64>
%1 = stablehlo.constant dense<2.0> : tensor<f64>
%2 = stablehlo.add %0, %1 : tensor<f64>
return %2 : tensor<f64>
}
หรืออีกนัยหนึ่งคือ กระบวนการ StableHLO ประกอบด้วย 1) โปรแกรม StableHLO, 2) สถานะการดำเนินการ (ยังไม่ได้ดำเนินการ, ดำเนินการแล้ว) และ 3) ค่ากลางที่กระบวนการนี้ทำงานอยู่
กระบวนการเริ่มต้นด้วยค่าอินพุตไปยังฟังก์ชัน main
จากนั้นจะดำเนินการต่อผ่านกราฟของการดำเนินการที่อัปเดตสถานะการดำเนินการ ค่ากลาง และเสร็จสิ้นด้วยค่าเอาต์พุต จะมีพิธีการเพิ่มเติมในภายหลัง
(#484)
การดำเนินการพร้อมกัน
โปรแกรม StableHLO ดำเนินการพร้อมกันได้ โดยจัดระเบียบเป็นตารางการประมวลผลแบบ 2D ของ num_replicas
โดย num_partitions
ซึ่งทั้ง 2 โปรแกรมเป็นประเภท ui32
ในตารางกริดการประมวลผลของ StableHLO จะมีการดำเนินการ num_replicas * num_partitions
ของกระบวนการ StableHLO พร้อมกัน แต่ละกระบวนการจะมี 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 เชิงปริมาณอาจแตกต่างกันไปโดยขึ้นอยู่กับข้อกำหนดด้านฮาร์ดแวร์และความสามารถของฮาร์ดแวร์ ตัวอย่างเช่น ฮาร์ดแวร์บางตัวอาจเลือกตีความการดำเนินการเชิงปริมาณโดยใช้กลยุทธ์ "จัดเรียงลำดับ ดำเนินการจุดลอยตัว" และสุดท้าย "ทำให้เป็นปริมาณ" ขณะที่รายอื่นๆ อาจทำการคำนวณทั้งหมดด้วยเลขคณิตที่เป็นจำนวนเต็ม ดังนั้น การตีความการดำเนินการ StableHLO เชิงปริมาณจะขึ้นอยู่กับการใช้งานที่เฉพาะเจาะจง การตีความเชิงปริมาณแบบผสม (#1575) ควรอิงตามอรรถศาสตร์ตามที่ระบุไว้ในข้อกำหนด (ผ่าน 1792)
ข้อผิดพลาด
โปรแกรม StableHLO จะได้รับการตรวจสอบผ่านข้อจำกัดจำนวนมากสำหรับการดำเนินการแต่ละรายการ ซึ่งจะตัดคลาสของข้อผิดพลาดต่างๆ ออกก่อนหมดเวลา อย่างไรก็ตาม เงื่อนไขข้อผิดพลาดจะยังคงเป็นไปได้ เช่น ผ่านจํานวนที่เกินจํานวนเต็ม การเข้าถึงนอกขอบเขต และอื่นๆ ข้อผิดพลาดทั้งหมดเหล่านี้ส่งผลให้เกิดลักษณะการทํางานที่กำหนดโดยการติดตั้งใช้งาน แต่อาจมีการเปลี่ยนแปลงในอนาคต (#1157) เว้นแต่จะมีการเรียกไว้อย่างชัดเจน
ข้อยกเว้นจุดลอยตัว
ข้อยกเว้นของกฎข้อนี้ระบุไว้ว่าเป็นข้อยกเว้นแบบจุดลอยตัวในโปรแกรม StableHLO การดำเนินการที่ทำให้เกิดข้อยกเว้นซึ่งมาตรฐาน IEEE-754 กำหนดไว้ (การดำเนินการที่ไม่ถูกต้อง, การหารต่อศูนย์, การดำเนินการเพิ่มเติม, ค่าที่น้อยเกินกำหนด หรือข้อยกเว้นที่ไม่ตรงจุด) จะให้ผลลัพธ์เริ่มต้น (ตามที่ให้คำจำกัดความไว้ในมาตรฐาน) และดำเนินการต่อไปโดยไม่เพิ่มแฟล็กสถานะที่เกี่ยวข้อง ซึ่งคล้ายกับการจัดการข้อยกเว้น raiseNoFlag
จากมาตรฐาน ข้อยกเว้นสำหรับการดำเนินการที่ไม่เป็นไปตามมาตรฐาน (เช่น เลขคณิตที่ซับซ้อนและฟังก์ชันสืบเนื่องบางอย่าง) จะได้รับการกำหนดการใช้งาน
รูปร่างไม่ตรงกัน
StableHLO รองรับ Tensor รูปทรงแบบไดนามิก แต่รูปร่างจะต้องสอดคล้องกันในรันไทม์ มิเช่นนั้นจะไม่มีการระบุลักษณะการทำงาน StableHLO ไม่ได้ระบุการดำเนินการอย่างชัดแจ้งที่ยืนยันว่า tensor มีรูปร่างที่กำหนดขณะรันไทม์ การสร้างโค้ดที่ถูกต้องเป็นความรับผิดชอบของผู้ผลิต
ตัวอย่างเช่น โปรแกรมด้านล่างถือว่าถูกต้อง แต่ขณะรันไทม์ รูปร่างที่แน่นอนของ %arg0
และ %arg1
จะต้องเหมือนกัน มิเช่นนั้นจะไม่มีการกำหนดลักษณะการทำงานของโปรแกรม ดังนี้
func.func @foo(%arg0: tensor<?xi32>, %arg1: tensor<?xi32>) -> tensor<?xi32> {
%0 = stablehlo.add %arg0, %arg1 : tensor<?xi32>
return %0 : tensor<?xi32>
}
เครื่องหมาย
ในการอธิบายไวยากรณ์ เอกสารฉบับนี้ใช้เวอร์ชัน ISO ที่แก้ไขแล้วของไวยากรณ์ EBNF (ISO/IEC 14977:1996, Wikipedia) โดยมีการแก้ไข 2 รายการ คือ 1) กำหนดกฎโดยใช้ ::=
แทนที่จะเป็น =
2) การต่อกันแสดงโดยใช้การเรียงต่อกันแทนที่จะใช้ ,
สำหรับการอธิบายความหมาย (เช่น ภายในส่วน "ประเภท" "ค่าคงที่" และ "การดำเนินการ") เราจะใช้สูตรที่อิงตามไวยากรณ์ 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 จะมีการแสดงสเกลาร์เป็นรูปร่างที่คาดไว้
โปรดดูข้อจำกัดอีกข้อหนึ่งเพื่อดำเนินการตามตัวอย่าง 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
ในทางตรงกันข้าม ส่วน "Constraints" สำหรับการดำเนินการ (และที่เทียบเท่า) จะกำหนดตรรกะ "เวลาคอมไพล์" ซึ่งก็คือสิ่งที่มักดำเนินการก่อนรันไทม์ ดังนั้นมีเพียงอินพุตคงที่เท่านั้นที่จะพร้อมใช้งานเป็น 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
จะได้รับการกำหนดใน tensors และแสดงผล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
is_defined_in_parent_scope(x: Value) -> Value
กำหนดไว้ในสตริงและแสดงผลtrue
หากx
คือชื่อของฟังก์ชันที่กำหนดไว้ในขอบเขตเดียวกับฟังก์ชันระดับบนสุดของการดำเนินการที่เกี่ยวข้องis_namespaced_op_name(x: Value) -> Value
กำหนดไว้ในสตริงและผลลัพธ์true
หากx
เป็นชื่อ op ที่ถูกต้อง กรณีนี้จะเป็นไปตามนิพจน์ทั่วไปต่อไปนี้:[a-zA-Z][a-zA-Z0-9_]*([.][a-zA-Z0-9_$]+)+
การคำนวณรูปร่าง
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
(สำหรับประเภทที่ปรับขนาดตามแกน) ต้องตรงกันทั้งหมด แต่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, result_type: Type) -> Value:
assert is_float(x) and is_quantized(result_type)
zero_points = compute_zero_points(result_type, TensorType(shape(x), storage_type(result_type)))
converted_zero_points = convert(zero_points, expressed_type(result_type))
converted_min = convert(storage_min(result_type), expressed_type(result_type))
converted_max = convert(storage_max(result_type), expressed_type(result_type))
x_scaled = x / compute_scales(result_type, type(x))
x_scaled_add_zp = x_scaled + converted_zero_points
x_clamped = clamp(converted_min, x_scaled_add_zp, converted_max)
x_rounded = round_nearest_even(x_clamped)
return convert(x_rounded, result_type)
dequantize_op_quantize
ใช้เพื่อระบุการคำนวณแบบ 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)
hybrid_dequantize_then_op
ใช้เพื่อระบุปริมาณเฉพาะน้ำหนักสำหรับการดำเนินการแบบผสมที่ยอมรับ Lh ในจุดลอยตัวและ rh ในประเภทที่เป็นจำนวนเชิงปริมาณ ซึ่งจะจัดลำดับอินพุตที่วัดปริมาณไว้ในประเภทที่แสดง และทำการคำนวณแบบ Float ประเภทองค์ประกอบของ Float lhs tensor และประเภท tensor แบบ Quantized rhs ที่แสดงต้องเหมือนกัน
def hybrid_dequantize_then_op(op, lhs, rhs):
assert(is_float(lhs) and is_quantized(rhs) and element_type(lhs) == expressed_type(rhs))
return op(lhs, dequantize(rhs))
การคำนวณตารางกริด
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" ด้านบน
ไดนามิก
ค่า StableHLO มีขนาดมิติข้อมูลแบบไดนามิกได้ เช่น tensor<?xi64>
อย่างไรก็ตาม ค่า StableHLO ต้องไม่มีจำนวนมิติข้อมูลแบบไดนามิก (ไดนามิกที่ไม่มีการจัดอันดับ เช่น tensor<*xi64>
) ตัวดำเนินการและผลลัพธ์ได้รับอนุญาตให้ใช้ขนาดมิติข้อมูลแบบไดนามิก แม้ว่าจะมีข้อจำกัดเกี่ยวกับขนาดก็ตาม ข้อจำกัดจะได้รับการยืนยันแบบคงที่หากทำได้ มิเช่นนั้น จะเลื่อนไปยังรันไทม์และการทำงานที่ไม่ตรงกันจะส่งผลให้เกิดลักษณะการทำงานที่ไม่ระบุ โปรดดูตัวอย่างด้านล่าง
รูปทรงที่ไม่ตรงกันสำหรับการดำเนินการแบบองค์ประกอบไม่รอบด้าน
ลองพิจารณาโปรแกรมของเล่นต่อไปนี้
func.func @foo(%arg0: tensor<?xf64>) {
%0 = stablehlo.abs %arg0 : (tensor<?xf64>) -> tensor<2xf64>
return
}
โปรแกรมดังกล่าวผิดปกติ เนื่องจากไม่ใช่เรื่องธรรมดาที่จะทราบรูปร่างของผลลัพธ์ แต่ไม่ทราบรูปร่างของอินพุต อย่างไรก็ตาม นี่เป็นโปรแกรม StableHLO ที่ถูกต้อง เป็นไปไม่ได้ที่จะตรวจสอบการดำเนินการ abs
แบบคงที่ในโปรแกรมนี้ เนื่องจากไม่ทราบรูปร่างที่แน่นอนของตัวถูกดำเนินการ อย่างไรก็ตาม รูปทรงนั้นเข้ากันได้เป็นอย่างดีและอาจตรวจสอบแบบคงที่ได้ ดังนั้น ?
อาจกลายเป็น 2
ระหว่างรันไทม์และจะไม่เกิดปัญหาใดๆ แต่ ?
อาจกลายเป็นจำนวนเต็มอื่นๆ ก็ได้ ซึ่งในกรณีนี้ไม่มีการกำหนดลักษณะการทำงาน
โปรดทราบว่าหากขนาดมิติข้อมูลเป็นแบบไดนามิกในผลลัพธ์ จะไม่มีลักษณะการทำงานที่ไม่ได้กำหนด แน่นอนว่าไม่มีขนาดที่ "คาดการณ์" ผลที่ได้จะไม่ตรงกัน
รูปร่างที่ไม่ตรงกันสำหรับการดำเนินการ Elementwise แบบไบนารี
ลองพิจารณาโปรแกรมของเล่นต่อไปนี้
func.func @foo(%arg0: tensor<?xf64>, %arg1: tensor<?xf64>) {
%0 = stablehlo.add %arg0, %arg0 : (tensor<?xf64>, tensor<?xf64>) -> tensor<?xf64>
return
}
เมื่อกล่าวถึงการดำเนินการแบบ Elementwise แบบไบนารี รูปร่างของอินพุตและผลลัพธ์ต้องสอดคล้องกันขณะรันไทม์ ในเวลาคอมไพล์ มิติข้อมูลคงที่ต้องเท่ากัน มิฉะนั้นก็ต้องใช้งานร่วมกันได้ หากมิติข้อมูลใดก็ตามเป็นแบบไดนามิกในอินพุต อาจมีลักษณะการทำงานที่ไม่ได้กำหนดในระหว่างรันไทม์ เนื่องจากขนาดแบบไดนามิกอาจไม่ตรงกับขนาดที่สอดคล้องกันในตัวถูกดำเนินการอื่น (ไม่ว่าจะเป็นแบบคงที่หรือแบบไดนามิก) หากอินพุตทั้งหมดเป็นแบบคงที่ ผลลัพธ์จะเป็นแบบไดนามิกหรือไม่มีความสำคัญ: มิติข้อมูลที่รู้จักแบบคงที่จะได้รับการตรวจสอบแบบคงที่ และมิติข้อมูลแบบไดนามิกไม่มีข้อจำกัดใดๆ
รูปร่างที่ไม่ตรงกันสำหรับการดำเนินการที่ใช้รูปร่างเอาต์พุตเป็นโอเปอแรนด์
ลองพิจารณาโปรแกรมของเล่นต่อไปนี้
func.func @foo(%arg0: tensor<2xi32>) {
%0 = stablehlo.dynamic_iota %arg0, dim = 0 : (tensor<2xi32>) -> tensor<3x4xi64>
return
}
ค่าในตัวถูกดำเนินการรูปร่างขณะรันไทม์ต้องตรงกับรูปร่างของผลลัพธ์ ไม่เช่นนั้นจะไม่มีการกำหนดลักษณะการทำงานไว้ นั่นคือ ขณะรันไทม์ %arg0
ต้องมีค่า dense<[3, 4]> : tensor<2xi32>
หากตัวถูกดำเนินการของรูปร่างมีค่าคงที่ ก็จะได้รับการยืนยันแบบคงที่ได้ หากรูปร่างผลลัพธ์เป็นแบบไดนามิกทั้งหมด จะไม่สามารถไม่ตรงกันได้