StableHLO คือชุดการดำเนินการสำหรับการดำเนินงานระดับสูง (HLO) ในเครื่อง การเรียนรู้ (ML) StableHLO ทำงานเป็นเลเยอร์ความสามารถในการพกพาระหว่าง เฟรมเวิร์ก ML และคอมไพเลอร์ ML: เฟรมเวิร์ก ML ที่ผลิตโปรแกรม StableHLO สามารถใช้ร่วมกับคอมไพเลอร์ ML ที่ใช้โปรแกรม StableHLO ได้
เป้าหมายของเราคือการลดความซับซ้อนและเร่งการพัฒนา ML ด้วยการสร้าง ความสามารถในการทำงานร่วมกันระหว่างเฟรมเวิร์ก ML ต่างๆ (เช่น TensorFlow, JAX และ PyTorch) และคอมไพเลอร์ ML (เช่น XLA และ IREE) สุดท้ายนี้ เอกสารระบุข้อกำหนดสำหรับภาษาโปรแกรม StableHLO
ข้อกำหนดนี้ประกอบด้วยส่วนหลักๆ 3 ส่วน อย่างแรก ฟิลด์ ส่วนโปรแกรมจะอธิบายโครงสร้างของโปรแกรม StableHLO ซึ่งประกอบด้วยฟังก์ชัน StableHLO ซึ่งประกอบไปด้วยการทำงานของ StableHLO ภายในโครงสร้างนั้น ส่วน Ops จะระบุความหมายของ ของ Google แต่ละราย ส่วนการดำเนินการจะให้ความหมายแก่ผู้ใช้ทั้งหมด การดำเนินการเหล่านี้ร่วมกันภายในโปรแกรม สุดท้าย ส่วนเครื่องหมายจะกล่าวถึงเครื่องหมายที่ใช้ในส่วน
หากต้องการดูข้อมูลจำเพาะจาก StableHLO รุ่นก่อนหน้า ให้เปิดที่เก็บที่ ผลงานที่ติดแท็กที่สนใจ ตัวอย่างเช่น ข้อกำหนดเฉพาะ StableHLO v0.19.0 หากต้องการดูการเปลี่ยนแปลงที่เกิดขึ้นในระดับย่อยของ StableHLO แต่ละเวอร์ชัน โปรดดูที่ ให้ลงชื่อเข้าสู่ระบบ VhloDialect.td
โปรแกรม
Program ::= {Func}
โปรแกรม StableHLO ประกอบด้วยฟังก์ชัน StableHLO ที่กําหนดเอง
ด้านล่างคือตัวอย่างโปรแกรมที่มีฟังก์ชัน @main
ซึ่งมีอินพุต 3 แบบ
(%image
, %weights
และ %bias
) และ 1 เอาต์พุต เนื้อหาของฟังก์ชัน
มี 6 Ops
func.func @main(
%image: tensor<28x28xf32>,
%weights: tensor<784x10xf32>,
%bias: tensor<1x10xf32>
) -> tensor<1x10xf32> {
%0 = "stablehlo.reshape"(%image) : (tensor<28x28xf32>) -> tensor<1x784xf32>
%1 = "stablehlo.dot"(%0, %weights) : (tensor<1x784xf32>, tensor<784x10xf32>) -> tensor<1x10xf32>
%2 = "stablehlo.add"(%1, %bias) : (tensor<1x10xf32>, tensor<1x10xf32>) -> tensor<1x10xf32>
%3 = "stablehlo.constant"() {value = dense<0.0> : tensor<1x10xf32>} : () -> tensor<1x10xf32>
%4 = "stablehlo.maximum"(%2, %3) : (tensor<1x10xf32>, tensor<1x10xf32>) -> tensor<1x10xf32>
"func.return"(%4): (tensor<1x10xf32>) -> ()
}
ฟังก์ชัน
Func ::= 'func' '.' 'func' FuncId FuncInputs FuncOutputs '{' FuncBody '}'
FuncInputs ::= '(' [FuncInput {',' FuncInput}] `)`
FuncInput ::= ValueId ':' ValueType
FuncOutputs ::= ['->' FuncOutput, {',' FuncOutput}]
FuncOutput ::= ValueType
FuncBody ::= {Op}
ฟังก์ชัน 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 ได้รับการจัดหมวดหมู่เป็นประเภทค่า (หรือที่เรียกว่า ประเภทคลาสแรก) ซึ่งแสดงค่า StableHLO และประเภทที่ไม่ใช่ค่า ซึ่งอธิบายองค์ประกอบอื่นๆ ของโปรแกรม ประเภท HLO ที่เสถียรจะคล้ายกับประเภทใน ภาษาโปรแกรมหลายภาษา ที่มีความพิเศษคือ StableHLO ลักษณะเฉพาะโดเมนซึ่งส่งผลให้เกิดผลลัพธ์ที่ผิดปกติบางอย่าง (เช่น ประเภทสเกลาร์ ไม่ใช่ประเภทค่า)
TensorType ::= 'tensor' '<' Shape TensorElementType '>'
Shape ::= {DimensionSize 'x'}
DimensionSize ::= digit {digit} | '?'
ประเภท Tensor แสดงถึง Tensor ซึ่งก็คืออาร์เรย์แบบหลายมิติ พวกเขามี
รูปร่าง และประเภทองค์ประกอบ โดยที่รูปร่างแสดงถึงค่าที่ไม่ติดลบหรือ
ขนาดมิติข้อมูลที่ไม่รู้จักตามลำดับจากน้อยไปมากของขนาดนั้นๆ
มิติข้อมูล (หรือเรียกอีกอย่างว่าแกน) ซึ่งมีหมายเลขตั้งแต่ 0
ถึง R-1
จำนวนมิติข้อมูล R
เรียกว่าอันดับ ตัวอย่างเช่น 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
รวมถึงประเภท ค่า และดูว่ามีแค่หรือ
อาจมีหลายจุดในประเภท Tensor ที่เล็กลง อิงตาม
ผลของการสนทนานี้ ข้อกำหนดเกี่ยวกับจุดศูนย์อาจมีการเปลี่ยนแปลง
ในอนาคต (#1405)
การสนทนาที่ดำเนินอยู่อีกรายการเกี่ยวข้องกับความหมายของ QuantizationStorageMin
และ QuantizationStorageMax
เพื่อระบุว่าควรมีข้อจำกัดใด
กำหนดให้กับค่าเหล่านี้และค่าของ Tensor
(#1406)
สุดท้าย เรากำลังวางแผนที่จะสำรวจการแสดงสเกลที่ไม่ทราบค่า 0 เช่นเดียวกับที่เราวางแผนจะสำรวจสิ่งที่ไม่มีข้อมูล ขนาด (#1407)
ประเภท tensor ที่กำหนดแสดงถึง Tensor ที่มีองค์ประกอบที่เล็กลง เหล่านี้ Tensor จะเหมือนกับ Tensor ปกติทุกประการ ยกเว้นตรงที่ มีประเภทองค์ประกอบที่เล็กลงแทนที่จะเป็นประเภทองค์ประกอบปกติ
ใน Tensor ที่เล็กลง การปรับเชิงปริมาณอาจเป็นแบบ ต่อ Tensor ได้ ซึ่งหมายความว่า
1 scale
และ zero_point
สำหรับ tensor ทั้งหมดหรืออาจเป็นแบบต่อแกน
ซึ่งหมายถึงการมี scales
และ zero_points
หลายคู่ โดยมี 1 คู่ต่อ 1 ส่วน
มิติข้อมูล quantization_dimension
อย่างเป็นทางการมากขึ้นใน tensor t
ด้วยการวัดขนาดต่อแกนจะมี dim(t, quantization_dimension)
ส่วน
จาก quantization_dimension
: t[:, ..., 0, ..., :], t[:, ..., 1, ..., :]
เป็นต้น องค์ประกอบทั้งหมดในชิ้นส่วนที่ i
ใช้ scales[i]
และ zero_points[i]
เป็น
พารามิเตอร์การวัดปริมาณ ประเภท Tensor ที่ปรับตามปริมาณมีสิ่งต่อไปนี้
ข้อจำกัด:
- สำหรับปริมาณต่อ Tensor:
- ไม่มีข้อจำกัดเพิ่มเติม
- สำหรับการวัดปริมาณต่อแกน
- (C12)
quantization_dimension < rank(self)
- (C13)
dim(self, quantization_dimension) = size(scales)
- (C12)
TokenType ::= 'token'
ประเภทโทเค็นแสดงถึงโทเค็น ซึ่งก็คือค่าทึบแสงที่ผลิตและใช้ จากการดำเนินการบางอย่าง ใช้โทเค็นเพื่อกำหนดลำดับการดำเนินการในการดำเนินงาน ตามที่อธิบายไว้ในส่วนการดำเนินการ
TupleType ::= 'tuple' '<' TupleElementTypes '>'
TupleElementTypes ::= [ValueType {',' ValueType}]
ประเภทของสิ่งมีชีวิตเดียวกันหมายถึงบุคคลที่ 1 เท่านั้น (Tuple) กล่าวคือ มีรายการที่ซ้ำกัน Tuples เป็นมรดก
ฟีเจอร์ที่มีไว้เฉพาะสำหรับความเข้ากันได้กับ HLO โดยใน HLO
ใช้เพื่อแสดงอินพุตและเอาต์พุตตัวแปร ใน StableHLO จะมีอินพุตแปรผันและ
เอาต์พุตได้รับการสนับสนุนโดยค่าเริ่มต้น และการใช้ Tuple เพียงอย่างเดียวใน 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 ::= 'si2' | 'si4' | 'si8' | 'si16' | 'si32' | 'si64'
UnsignedIntegerType ::= 'ui2' | 'ui4' | 'ui8' | 'ui16' | 'ui32' | 'ui64'
FloatType ::= 'f8E4M3FN' | 'f8E5M2' | 'f8E4M3FNUZ' | 'f8E5M2FNUZ'
| 'f8E4M3B11FNUZ' | 'bf16' | 'f16' | 'f32' | 'f64'
TensorFloat32 ::= 'tf32'
ComplexType ::= 'complex' '<' ComplexElementType '>'
ComplexElementType ::= 'f32' | 'f64'
ประเภทองค์ประกอบแสดงองค์ประกอบของประเภท Tensor ต่างจากหลายๆ โปรแกรม
ภาษาเหล่านี้ไม่ใช่คลาสแรกใน StableHLO ซึ่งหมายความว่า
โปรแกรม StableHLO จะแสดงค่าของประเภทเหล่านี้โดยตรงไม่ได้ (ด้วยเหตุนี้
มันมีเอกลักษณ์ในการแสดงค่าสเกลาร์ของประเภท T
ด้วย Tensor แบบ 0 มิติ
ประเภท tensor<T>
)
- ประเภทบูลีนแสดงถึงค่าบูลีน
true
และfalse
- ประเภทจำนวนเต็มเป็นได้ทั้งลายเซ็น (
si
) หรือไม่ลงชื่อ (ui
) และมี หนึ่งในความกว้างบิตที่รองรับ (2
,4
,8
,16
,32
หรือ64
) ประเภทsiN
ที่ลงนามแสดงค่าจำนวนเต็มตั้งแต่-2^(N-1)
ถึง2^(N-1)-1
ประเภทuiN
รวมและไม่มีเครื่องหมายแสดงค่าจำนวนเต็มตั้งแต่0
ถึง2^N-1
เท่านั้น - ประเภทจุดทศนิยมอาจเป็นอย่างใดอย่างหนึ่งต่อไปนี้
f8E4M3FN
และf8E5M2
ประเภทที่สัมพันธ์กับ การเข้ารหัสE4M3
และE5M2
ในรูปแบบ FP8 ตามที่อธิบายไว้ใน รูปแบบ FP8 สำหรับการเรียนรู้เชิงลึก- ประเภท
f8E4M3FNUZ
และf8E5M2FNUZ
ที่สอดคล้องกับE4M3
และE5M2
รูปแบบ FP8 ตามที่อธิบายไว้ใน รูปแบบตัวเลข 8 บิตสำหรับโครงข่ายระบบประสาทเทียมระดับลึก f8E4M3B11FNUZ
ประเภทที่สอดคล้องกับการเข้ารหัสE4M3
ของรูปแบบ FP8 อธิบายไว้ใน การฝึกและการอนุมานแบบไฮบริดของจุดลอยตัว 8 บิต (HFP8) สำหรับเครือข่ายประสาทเทียมระดับลึกbf16
ประเภทที่สอดคล้องกับรูปแบบbfloat16
ที่อธิบายไว้ใน BFloat16: เคล็ดลับสู่ประสิทธิภาพสูงบน Cloud TPUf16
,f32
และf64
ประเภทที่เกี่ยวข้องตามลำดับbinary16
("ความแม่นยำครึ่งหนึ่ง"),binary32
("ความแม่นยำครั้งเดียว") และbinary64
("ความแม่นยำสองเท่า") ที่อธิบายใน มาตรฐาน IEEE 754- ประเภท
tf32
สอดคล้องกับรูปแบบ TensorFloat32 และมีการรองรับที่จำกัดใน StableHLO
- ประเภทที่ซับซ้อนหมายถึงค่าที่ซับซ้อนซึ่งมีส่วนจริง
และส่วนจินตภาพขององค์ประกอบประเภทเดียวกัน กลุ่มที่รองรับ
ประเภทคือ
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 (หรือเรียกว่าการดำเนินการ) มีชื่อ
อินพุต/เอาต์พุตและลายเซ็น ชื่อประกอบด้วยคำนำหน้า stablehlo.
และ
ช่วยจำ ซึ่งระบุ Ops ที่สนับสนุนโดยไม่ซ้ำกัน ดูด้านล่างสำหรับ
ซึ่งเป็นรายการที่ครอบคลุมการดำเนินการทั้งหมดที่รองรับ
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
มีแนวคิดที่กว้างขึ้นเกี่ยวกับ "ภูมิภาค" ซึ่งสามารถมี "การบล็อก" ได้หลายรายการ
ของการดำเนินการที่เชื่อมโยงกัน บล็อกเหล่านี้มีรหัสที่สอดคล้องกับ
เป็นเวอร์ชันที่ใช้งานจริง Unused
เพื่อให้แยกความแตกต่างได้
StableHLO ไม่มีการดำเนินการข้าม ดังนั้นส่วนที่เกี่ยวข้องของไวยากรณ์ MLIR คือ
ไม่ได้ใช้ (แต่ยังคงอยู่)
OpInputAttr ::= OpInputAttrName '=' OpInputAttrValue
OpInputAttrName ::= letter {letter | digit}
OpInputAttrValue ::= Constant
แอตทริบิวต์อินพุตมีชื่อและค่าซึ่งเป็นหนึ่งในแอตทริบิวต์ที่รองรับ
ค่าคงที่นี้ เป็นวิธีหลักในการระบุข้อมูลเมตาแบบคงที่สำหรับรายการ
จากองค์ประกอบเหล่านี้ ตัวอย่างเช่น การดำเนินการ concatenate
ใช้แอตทริบิวต์ dimension
เพื่อ
ระบุมิติข้อมูลที่มีการต่อค่าอินพุต ในทำนองเดียวกัน
การดำเนินการ slice
ใช้แอตทริบิวต์หลายรายการ เช่น start_indices
และ limit_indices
เพื่อระบุขอบเขตที่ใช้ในการแบ่งค่าอินพุต
ปัจจุบันโปรแกรม StableHLO ในป่านี้บางครั้งอาจมีคุณสมบัติ ซึ่งไม่ได้อธิบายไว้ในเอกสารนี้ ในอนาคต เราวางแผนที่จะ ดูดซับแอตทริบิวต์เหล่านี้เข้าสู่กลุ่มกลยุทธ์ StableHLO หรือยับยั้งแอตทริบิวต์เหล่านี้ ปรากฏในโปรแกรม StableHLO ในระหว่างนี้ ลองดูรายการต่อไปนี้ ดังนี้
layout
(#629)mhlo.frontend_attributes
(#628)mhlo.sharding
(#619)output_operand_aliases
(#740)- ข้อมูลเมตาของตำแหน่ง (#594)
OpSignature ::= '(' [ValueType {',' ValueType}] ')' '->' '(' [ValueType {',' ValueType}] ')'
Op signature ประกอบด้วยประเภทของค่าอินพุตทั้งหมด (รายการประเภทใน
ด้านซ้ายมือของ ->
) และประเภทของค่าเอาต์พุตทั้งหมด (รายการ
ประเภทที่อยู่ทางด้านขวาของ ->
) กล่าวอย่างเจาะจงก็คือ ประเภทอินพุตคือ
ซ้ำซ้อน และเอาต์พุตประเภท
ก็มักจะซ้ำซ้อนกันเกือบทุกครั้ง (เนื่องจากสำหรับ
การดำเนินการ StableHLO ส่วนใหญ่
สามารถอนุมานประเภทเอาต์พุตได้จากอินพุต) อย่างไรก็ตาม การดำเนินการ
ลายเซ็นเป็นส่วนหนึ่งของไวยากรณ์ StableHLO อย่างตั้งใจเพื่อให้เข้ากันได้กับ MLIR
ด้านล่างนี้เป็นตัวอย่างการดำเนินการที่ฟีเจอร์การจำคือ select_and_scatter
ใช้ 3
ค่าอินพุต (%operand
, %source
และ %init_value
) ฟังก์ชันอินพุต 2 รายการ
และแอตทริบิวต์อินพุต 3 รายการ (window_dimensions
, window_strides
และ padding
)
โปรดสังเกตว่าลายเซ็นของ Opin จะมีเฉพาะประเภทของค่าอินพุตเท่านั้นได้อย่างไร
(แต่ไม่ใช่ประเภทของฟังก์ชันอินพุตและแอตทริบิวต์ที่มีให้ในบรรทัด)
%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
ค่าคงที่ HLO ประกอบด้วยลิเทอรัลและประเภทที่แสดงร่วมกัน
ค่า 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 และ
Escape Sequence แต่สามารถเข้าใจการเข้ารหัสได้ ดังนั้นการตีความ
จำนวนไบต์ได้รับการกำหนดตามการใช้งาน ลิเทอรัลสตริงมีประเภท string
การดำเนินการ
ท้อง
อรรถศาสตร์
ทำการดำเนินการ abs แบบองค์ประกอบบน Tensor ของ operand
และสร้าง result
Tensor ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับจำนวนเต็มที่มีเครื่องหมาย: โมดูลัสจำนวนเต็ม
- สำหรับแบบลอย:
abs
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: โมดูลัสเชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(abs, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor ของจำนวนเต็มที่มีการลงชื่อ จุดลอยตัว หรือประเภทเชิงซ้อน หรือ Tensor ควอนไทล์ | (C1-C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของจำนวนเต็มที่มีการลงชื่อหรือประเภทจุดลอยตัวหรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (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 จำนวน operands
จากแต่ละกระบวนการตาม all_gather_dim
และสร้าง
Tensor จำนวน results
รายการ
การดำเนินการนี้จะแยกตารางกริดประมวลผล StableHLO ออกเป็น process_groups
ซึ่ง
โดยมีคำจำกัดความดังนี้
cross_replica(replica_groups)
หากเป็นchannel_id <= 0 and use_global_device_ids = false
cross_replica_and_partition(replica_groups)
หากเป็นchannel_id > 0 and use_global_device_ids = false
flattened_ids(replica_groups)
หากเป็นchannel_id > 0 and use_global_device_ids = true
หลังจากนั้น ภายในแต่ละ process_group
:
operands...@receiver = [operand@sender for sender in process_group]
สำหรับทุกคนreceiver
ในprocess_group
results...@process = concatenate(operands...@process, all_gather_dim)
สำหรับทุกคนprocess
ในprocess_group
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operands |
จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว | (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) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว | (C6) |
ข้อจำกัด
- (C1)
0 <= all_gather_dim < rank(operands...)
- (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(results...) = type(operands...)
ยกเว้นdim(results..., all_gather_dim) = dim(operands..., all_gather_dim) * dim(process_groups, 1)
ตัวอย่าง
// num_replicas: 2
// num_partitions: 1
// %operand0@(0, 0): [[1, 2], [3, 4]]
// %operand0@(1, 0): [[5, 6], [7, 8]]
// %operand1@(0, 0): [[11, 12], [13, 14]]
// %operand1@(1, 0): [[15, 16], [17, 18]]
%result:2 = "stablehlo.all_gather"(%operand0, %operand1) {
all_gather_dim = 1 : i64,
replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>,
// channel_id = 0
channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
// use_global_device_ids = false
} : (tensor<2x2xi64>, tensor<2x2xi64>) -> (tensor<2x4xi64>, tensor<2x4xi64>)
// %result0@(0, 0): [[1, 2, 5, 6], [3, 4, 7, 8]]
// %result0@(1, 0): [[1, 2, 5, 6], [3, 4, 7, 8]]
// %result1@(0, 0): [[11, 12, 15, 16], [13, 14, 17, 18]]
// %result1@(1, 0): [[11, 12, 15, 16], [13, 14, 17, 18]]
all_reduce
อรรถศาสตร์
ภายในกลุ่มกระบวนการแต่ละกลุ่มในตารางกระบวนการ StableHLO ให้ใช้การลด
ฟังก์ชัน computation
เป็นค่าของ tensor ของ operands
จากแต่ละกระบวนการ
และสร้าง results
Tensor
การดำเนินการนี้จะแยกตารางกริดประมวลผล StableHLO ออกเป็น process_groups
ซึ่ง
โดยมีคำจำกัดความดังนี้
cross_replica(replica_groups)
หากเป็นchannel_id <= 0 and use_global_device_ids = false
cross_replica_and_partition(replica_groups)
หากเป็นchannel_id > 0 and use_global_device_ids = false
flattened_ids(replica_groups)
หากเป็นchannel_id > 0 and use_global_device_ids = true
หลังจากนั้น ภายในแต่ละ process_group
:
results...@process[result_index] = exec(schedule)
สำหรับแผนผังไบนารีบางทรีschedule
โดยที่exec(node)
=computation(exec(node.left), exec(node.right))
exec(leaf)
=leaf.value
schedule
คือแผนผังไบนารีที่กำหนดโดยการติดตั้งใช้งาน ซึ่งมีลำดับ การส่งผ่านคือto_destination_type(operands...@process_group...[result_index], type(func_inputs(computation)[0]))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operands |
จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว | (C5), (C6) |
(I2) | replica_groups |
จำนวนแปรผันของค่าคงที่ 1 มิติของประเภท si64 |
(C1-C3) |
(I3) | channel_id |
ค่าคงที่ของประเภท si64 |
(C4) |
(I4) | use_global_device_ids |
ค่าคงที่ของประเภท i1 |
(C4) |
(I5) | computation |
ฟังก์ชัน | (C5) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว | (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(results...) = shape(operands...)
- (C7)
element_type(results...) = E
ตัวอย่าง
// num_replicas: 2
// num_partitions: 1
// %operand0@(0, 0): [1, 2, 3, 4]
// %operand0@(1, 0): [5, 6, 7, 8]
// %operand1@(0, 0): [9, 10, 11, 12]
// %operand1@(1, 0): [13, 14, 15, 16]
%result:2 = "stablehlo.all_reduce"(%operand0, %operand0) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
"stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>,
// channel_id = 0
channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
// use_global_device_ids = false
} : (tensor<4xi64>, tensor<4xi64>) -> (tensor<4xi64>, tensor<4xi64>)
// %result0@(0, 0): [6, 8, 10, 12]
// %result0@(1, 0): [6, 8, 10, 12]
// %result1@(0, 0): [22, 24, 26, 28]
// %result1@(1, 0): [22, 24, 26, 28]
all_to_all
อรรถศาสตร์
ภายในกลุ่มกระบวนการแต่ละกลุ่มในตารางการประมวลผล StableHLO ให้แยกค่าของ
Tensor สี operands
ตาม split_dimension
แบ่งออกเป็นส่วนต่างๆ กระจายตัว
เพื่อนำกระบวนการบางส่วนมาต่อกัน ส่วนที่กระจัดกระจายอยู่ตาม
concat_dimension
และสร้าง results
Tensor
การดำเนินการนี้จะแยกตารางกริดประมวลผล StableHLO ออกเป็น process_groups
ซึ่ง
โดยมีคำจำกัดความดังนี้
cross_replica(replica_groups)
หากเป็นchannel_id <= 0
cross_partition(replica_groups)
หากเป็นchannel_id > 0
หลังจากนั้น ภายในแต่ละ process_group
:
split_parts...@sender = split(operands...@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)
results...@process = concatenate(scattered_parts...@process, concat_dimension)
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operands |
จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว | (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 |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว | (C9) |
ข้อจำกัด
- (C1)
0 <= split_dimension < rank(operands...)
- (C2)
dim(operands..., split_dimension) % split_count = 0
- (C3)
0 <= concat_dimension < rank(operands...)
- (C4)
0 < split_count
- (C5)
is_unique(replica_groups)
- (C6)
size(replica_groups)
มีความหมายดังต่อไปนี้num_replicas
หากใช้cross_replica
num_partitions
หากใช้cross_partition
- (C7)
0 <= replica_groups < size(replica_groups)
- (C8)
dim(replica_groups, 1) = split_count
- (C9)
type(results...) = type(operands...)
ยกเว้นในกรณีที่split_dimension != concat_dimension
dim(results..., split_dimension) = dim(operands..., split_dimension) / split_count
dim(results..., concat_dimension) = dim(operands..., concat_dimension) * split_count
ตัวอย่าง
// num_replicas: 2
// num_partitions: 1
// %operand1@(0, 0): [[1, 2, 3, 4],
// [5, 6, 7, 8]]
// %operand1@(1, 0): [[9, 10, 11, 12],
// [13, 14, 15, 16]]
// %operand2@(0, 0): [[17, 18, 19, 20],
// [21, 22, 23, 24]]
// %operand2@(1, 0): [[25, 26, 27, 28],
// [29, 30, 31, 32]]
%result:2 = "stablehlo.all_to_all"(%operand1, %operand2) {
split_dimension = 1 : i64,
concat_dimension = 0 : i64,
split_count = 2 : i64,
replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>
// channel_id = 0
} : (tensor<2x4xi64>, tensor<2x4xi64>) -> (tensor<4x2xi64>, tensor<4x2xi64>)
// %result#0@(0, 0): [[1, 2], [5, 6], [9, 10], [13, 14]]
// %result#0@(1, 0): [[3, 4], [7, 8], [11, 12], [15, 16]]
// %result#1@(0, 0): [[17, 18], [21, 22], [25, 26], [29, 30]]
// %result#1@(1, 0): [[19, 20], [23, 24], [27, 28], [31, 32]]
และ
อรรถศาสตร์
ดำเนินการ AND ตามองค์ประกอบที่มี 2 Tensor คือ lhs
และ rhs
และสร้าง result
Tensor ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับบูลีน: ตรรกะ AND
- สำหรับจำนวนเต็ม: Bitwise 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 ที่แปลงค่าเป็น 1 ส่วน | (C1) |
(I2) | rhs |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (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
อรรถศาสตร์
คำนวณการไล่ระดับสีของอินพุตหลายรายการของ Backpropagating ของ batch_norm_training
จาก grad_output
และผลิต grad_operand
, grad_scale
และ grad_offset
Tensor อย่างเป็นทางการมากขึ้น การทำงานนี้สามารถแสดงเป็นการย่อยสลายเป็น
การดำเนินการ 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 ที่แปลงค่าเป็น 1 เซนเซอร์ | (C1-C3), (C5) |
(I2) | scale |
ความเครียด 1 มิติของจุดลอยตัวหรือต่อประเภทควอนเซอร์ | (C2), (C4), (C5) |
(I3) | mean |
ความเครียด 1 มิติของจุดลอยตัวหรือต่อประเภทควอนเซอร์ | (C2), (C4) |
(I4) | variance |
ความเครียด 1 มิติของจุดลอยตัวหรือต่อประเภทควอนเซอร์ | (C2), (C4) |
(I5) | grad_output |
tensor ของประเภทจุดลอยตัวหรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (C2), (C3) |
(I6) | epsilon |
ค่าคงที่ของประเภท f32 |
|
(I7) | feature_index |
ค่าคงที่ของประเภท si64 |
(C1), (C5) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
grad_operand |
tensor ของประเภทจุดลอยตัวหรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (C2), (C3) |
grad_scale |
ความเครียด 1 มิติของจุดลอยตัวหรือต่อประเภทควอนเซอร์ | (C2), (C4) |
grad_offset |
ความเครียด 1 มิติของจุดลอยตัวหรือต่อประเภทควอนเซอร์ | (C2), (C4) |
ข้อจำกัด
- (C1)
0 <= feature_index < rank(operand)
- (C2)
operand
,scale
,mean
,variance
,grad_output
,grad_operand
grad_scale
และgrad_offset
มีbaseline_element_type
เดียวกัน - (C3)
operand
,grad_output
และgrad_operand
มีรูปร่างเดียวกัน - (C4)
scale
,mean
,variance
,grad_scale
และgrad_offset
มี รูปทรงเดียวกัน - (C5)
size(scale) = dim(operand, feature_index)
ตัวอย่าง
// %operand: [
// [[1.0, 2.0], [3.0, 4.0]],
// [[3.0, 4.0], [1.0, 2.0]]
// ]
// %scale: [1.0, 1.0]
// %mean: [2.0, 3.0]
// %variance: [1.0, 1.0]
// %grad_output: [
// [[0.1, 0.1], [0.1, 0.1]],
// [[0.1, 0.1], [0.1, 0.1]]
// ]
%grad_operand, %grad_scale, %grad_offset =
"stablehlo.batch_norm_grad"(%operand, %scale, %mean, %variance, %grad_output) {
epsilon = 0.0 : f32,
feature_index = 2 : i64
} : (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>, tensor<2xf64>,
tensor<2x2x2xf64>) -> (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>)
// %grad_operand: [
// [[0.0, 0.0], [0.0, 0.0]],
// [[0.0, 0.0], [0.0, 0.0]]
// ]
// %grad_scale: [0.0, 0.0]
// %grad_offset: [0.4, 0.4]
batch_norm_inference
อรรถศาสตร์
ปรับ 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 ที่แปลงค่าเป็น 1 เซนเซอร์ | (C1-C7) |
(I2) | scale |
ความเครียด 1 มิติของจุดลอยตัวหรือต่อประเภทควอนเซอร์ | (C2), (C3) |
(I3) | offset |
ความเครียด 1 มิติของจุดลอยตัวหรือต่อประเภทควอนเซอร์ | (C2), (C4) |
(I4) | mean |
ความเครียด 1 มิติของจุดลอยตัวหรือต่อประเภทควอนเซอร์ | (C5) |
(I5) | variance |
ความเครียด 1 มิติของจุดลอยตัวหรือต่อประเภทควอนเซอร์ | (C2), (C6) |
(I6) | epsilon |
ค่าคงที่ของประเภท f32 |
|
(I7) | feature_index |
ค่าคงที่ของประเภท si64 |
(C1), (C3-C6) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของประเภทจุดลอยตัวหรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (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
Tensor อย่างเป็นทางการมากขึ้น การดำเนินงานนี้สามารถกำหนดเป็น
ย่อยให้กับการดำเนินการ 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 ที่แปลงค่าเป็น 1 เซนเซอร์ | (C1) |
(I2) | scale |
ความเครียด 1 มิติของจุดลอยตัวหรือต่อ 1 เซนเซอร์ที่แปลงค่าเป็นจำนวน 1 มิติ | (C2), (C3) |
(I3) | offset |
ความเครียด 1 มิติของจุดลอยตัวหรือต่อ 1 เซนเซอร์ที่แปลงค่าเป็นจำนวน 1 มิติ | (C2), (C4) |
(I4) | epsilon |
ค่าคงที่ของประเภท f32 |
(C1), (C3-C6) |
(I5) | feature_index |
ค่าคงที่ของประเภท si64 |
(C1), (C3-C6) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
output |
tensor ของประเภทจุดลอยตัวหรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (C7) |
batch_mean |
ความเครียด 1 มิติของจุดลอยตัวหรือต่อ 1 เซนเซอร์ที่แปลงค่าเป็นจำนวน 1 มิติ | (C2), (C5) |
batch_var |
ความเครียด 1 มิติของจุดลอยตัวหรือต่อ 1 เซนเซอร์ที่แปลงค่าเป็นจำนวน 1 มิติ | (C2), (C6) |
ข้อจำกัด
- (C1)
0 <= feature_index < rank(operand)
- (C2)
operand
,scale
,offset
,batch_mean
,batch_var
และoutput
baseline_element_type
เดียวกัน - (C3)
size(scale) = dim(operand, feature_index)
- (C4)
size(offset) = dim(operand, feature_index)
- (C5)
size(batch_mean) = dim(operand, feature_index)
- (C6)
size(batch_var) = dim(operand, feature_index)
- (C7)
baseline_type(output) = baseline_type(operand)
ตัวอย่าง
// %operand: [
// [[1.0, 2.0], [3.0, 4.0]],
// [[3.0, 4.0], [1.0, 2.0]]
// ]
// %scale: [1.0, 1.0]
// %offset: [1.0, 1.0]
%output, %batch_mean, %batch_var = "stablehlo.batch_norm_training"(%operand, %scale, %offset) {
epsilon = 0.0 : f32,
feature_index = 2 : i64
} : (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>) ->
(tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>)
// %output: [
// [[0.0, 0.0], [2.0, 2.0]],
// [[2.0, 2.0], [0.0, 0.0]]
// ]
// %batch_mean: [2.0, 3.0]
// %batch_var: [1.0, 1.0]
bitcast_convert
อรรถศาสตร์
ดำเนินการบิตแคสต์บน 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
แสดงผลการแทนค่าในหน่วยความจำของค่าที่ระบุและลักษณะการทำงานของค่าดังกล่าว
มีการกำหนดการใช้งานเนื่องจากการนำเสนอ tensor ที่แน่นอนคือ
การกำหนดการติดตั้ง และการนำเสนอประเภทองค์ประกอบที่แน่นอนคือ
แบบกำหนดเองได้ด้วย
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(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 |
จำนวนแปรผันของ Tensor, Tensor ที่เล็กลง หรือโทเค็น | (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]
CBT
อรรถศาสตร์
ดำเนินการรากลูกบาศก์ที่ชี้องค์ประกอบบน tensor ของ operand
และสร้าง
result
Tensor ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับแบบลอย:
rootn(x, 3)
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: รากที่สามเชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(cbrt, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (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 ที่แปลงค่าเป็น 1 เซนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของประเภทจุดลอยตัวหรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (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
ซึ่งเมทริกซ์อินพุตไม่ใช่ค่าจำกัดความบวกของเฮอร์มิเชียน
เมทริกซ์ ลักษณะการทำงานจะไม่ได้ที่กำหนดไว้
สำหรับประเภทที่เล็กลง จะดำเนินการ
dequantize_op_quantize(lambda operand: cholesky(operand, lower), a, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | a |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (C1-C3) |
(I2) | lower |
ค่าคงที่ tensor ของประเภท i1 ค่าคงที่ 0 มิติ |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (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 ตั้งแต่กระบวนการต้นทางไปจนถึงกระบวนการเป้าหมายและสร้าง
result
Tensor
การดำเนินการนี้จะแยกตารางกริดประมวลผล 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 |
จำนวนแปรผันของค่าคงที่ 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 ให้ส่งค่าของแอตทริบิวต์
operand
Tensor จากกระบวนการต้นทางไปยังกระบวนการเป้าหมายและสร้าง
result
Tensor
การดำเนินการนี้จะแยกตารางกริดประมวลผล 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]
ซับซ้อน
อรรถศาสตร์
ทำ Conversion ตามองค์ประกอบเป็นค่าเชิงซ้อนจากคู่ของค่าจริงและ
ค่าจินตภาพ 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>
เชื่อมต่อ
อรรถศาสตร์
เชื่อม 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 |
จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว | (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
อรรถศาสตร์
ทำ Conversion ตามองค์ประกอบจากประเภทองค์ประกอบหนึ่งไปยังอีกประเภทหนึ่งใน
operand
Tensor และสร้าง Tensor ขนาด result
สำหรับ Conversion boolean-to-any-supported-type ค่า false
จะเป็น
แปลงเป็น 0 และแปลงค่า true
เป็น 1 สำหรับ
any-supported-type-to-boolean ระบบจะแปลงค่าเป็น 0
false
และค่าที่ไม่ใช่ 0 จะแปลงเป็น true
โปรดดูวิธีดำเนินการด้านล่าง
ใช้งานได้สำหรับประเภทที่ซับซ้อน
สำหรับ Conversion ที่เกี่ยวข้องกับจำนวนเต็มถึงจำนวนเต็ม จำนวนเต็มถึงจุดทศนิยม หรือfloating-point-to-floating-point หากค่าของแหล่งที่มามีค่าเท่ากับ ที่แสดงในประเภทปลายทาง ค่าผลลัพธ์จะเท่ากับ การให้คำแนะนำ มิฉะนั้น ระบบจะแจ้งลักษณะการทำงานในภายหลัง (#180)
สำหรับ Conversion ที่เกี่ยวข้องกับfloating-point-to-integer ส่วนที่เป็นเศษส่วนจะเป็น ที่ถูกตัด หากไม่สามารถแสดงค่าที่ตัดในประเภทปลายทาง จะมีลักษณะการทำงานเดิมเมื่อใด (#180)
Conversion ที่เกี่ยวข้องกับซับซ้อนไปซับซ้อนมีลักษณะการทำงานเหมือนกับของ floating-point-to-floating-point สำหรับการแปลงค่าจริงและ ส่วนจินตภาพ
สำหรับ Conversion complex-to-any-other-type และ Conversion complex-to-any-other-type ระบบจะไม่สนใจค่าจินตภาพต้นทาง หรือค่าจินตภาพปลายทางคือ เป็นศูนย์ตามลำดับ การแปลงส่วนจริงเป็นไปตาม Conversion แบบจุดลอยตัว
โดยหลักการแล้ว การดำเนินการนี้อาจแสดงการลดปริมาณ (Conversion จาก
Quenized tensor เป็น tensor ปกติ) การแปลงปริมาณ (Conversion จากปกติ
tensor เป็น Tensor ที่เล็กลง) และการแปลงปริมาณอีกครั้ง (การแปลงระหว่างการวัดที่เล็กลง
tensors) แต่ในขณะนี้เรามีการดำเนินการเฉพาะสำหรับเรื่องดังกล่าว
uniform_dequantize
สำหรับ Use Case แรกและ uniform_quantize
สำหรับ
กรณีการใช้งานที่ 2 และ 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)]
คอนโวลูชัน
อรรถศาสตร์
ประมวลผลผลิตภัณฑ์แบบจุดระหว่างหน้าต่างของ 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) |
(I15) | 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
และสร้างพารามิเตอร์
result
Tensor ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับแบบลอย:
cos
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: โคไซน์เชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(cosine, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (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
อรรถศาสตร์
ดำเนินการนับตามองค์ประกอบของจำนวนบิตนำใน operand
tensor และสร้าง 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 = 42 : i32},
api_version = 4 : i32,
called_computations = [@foo]
} : (tensor<f64>) -> tensor<f64>
หาร
อรรถศาสตร์
ทำการแบ่งตัวของตัวหาร lhs
และตัวหาร rhs
ตัวตั้งและตัวหาร
สร้าง Tensor ของ result
ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับจำนวนเต็ม: การหารจำนวนเต็มที่สร้างผลหารพีชคณิตด้วยค่าใดๆ ทิ้งส่วนที่เป็นเศษส่วนแล้ว
- สำหรับแบบลอย:
division
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: การหารเชิงซ้อน
- สำหรับประเภทที่เล็กลง
dequantize_op_quantize(divide, lhs, rhs, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
tensor ของจำนวนเต็ม จุดลอยตัวหรือประเภทเชิงซ้อน หรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (C1) |
(I2) | rhs |
tensor ของจำนวนเต็ม จุดลอยตัวหรือประเภทเชิงซ้อน หรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของจำนวนเต็ม จุดลอยตัว หรือประเภทเชิงซ้อน หรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (C1) |
ข้อจำกัด
- (C1)
baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)
ตัวอย่าง
// %lhs: [17.1, -17.1, 17.1, -17.1]
// %rhs: [3.0, 3.0, -3.0, -3.0]
%result = "stablehlo.divide"(%lhs, %rhs) : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
// %result: [5.66666651, -5.66666651, -5.66666651, 5.66666651]
dot_general
อรรถศาสตร์
ประมวลผลผลิตภัณฑ์แบบจุดระหว่างส่วนต่างๆ ของ lhs
และส่วนย่อยของ rhs
และสร้าง
tensor ของ result
อย่างเป็นทางการเพิ่มเติมคือ result[result_index] = dot_product
ซึ่ง
lhs_result_dimensions = [d for d in axes(lhs) and d not in lhs_batching_dimensions and d not in lhs_contracting_dimensions]
rhs_result_dimensions = [d for d in axes(rhs) and d not in rhs_batching_dimensions and d not in rhs_contracting_dimensions]
result_batching_index + result_lhs_index + result_rhs_index = result_index
โดยที่size(result_batching_index) = size(lhs_batching_dimensions)
size(result_lhs_index) = size(lhs_result_dimensions)
และsize(result_rhs_index) = size(rhs_result_dimensions)
transposed_lhs = transpose(lhs, lhs_batching_dimensions + lhs_result_dimensions + lhs_contracting_dimensions)
transposed_lhs_slice = slice(transposed_lhs, result_batching_index + result_lhs_index + [:, ..., :])
reshaped_lhs_slice = reshape(transposed_lhs_slice, dims(lhs, lhs_contracting_dimensions))
transposed_rhs = transpose(rhs, rhs_batching_dimensions + rhs_result_dimensions + rhs_contracting_dimensions)
transposed_rhs_slice = slice(transposed_rhs, result_batching_index + result_rhs_index + [:, ..., :])
reshaped_rhs_slice = reshape(transposed_rhs_slice, dims(rhs, rhs_contracting_dimensions))
dot_product = reduce( inputs=[multiply(reshaped_lhs_slice, reshaped_rhs_slice)], init_values=[constant(0, element_type(result))], dimensions=range(size(lhs_contracting_dimensions)), body=lambda x, y: add(x, y))
วันที่
สำหรับประเภทที่เล็กลง จะดำเนินการ dequantize_op_quantize(
lambda lhs, rhs: dot_general(lhs, rhs, lhs_batching_dimensions,
rhs_batching_dimensions, lhs_contracting_dimensions,
rhs_contracting_dimensions, precision_config), lhs, rhs, type(result))
สำหรับประเภทที่เล็กลงของจำนวนแบบผสม จะดำเนินการ 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
: การคำนวณช้าที่สุด แต่ประมาณที่แม่นยำที่สุดกับ หมายเลขเดิม
DotAlgorithm
ระบุพร็อพเพอร์ตี้หลักของอัลกอริทึมที่จะนำมาใช้
จะใช้จุด ซึ่งจะกำหนดความแม่นยำด้วย หากแอตทริบิวต์อัลกอริทึม
ได้รับการตั้งค่าแล้ว precision_config
ต้องเป็น DEFAULT
DotAlgorithms
ไม่มีค่าเริ่มต้นเนื่องจากพารามิเตอร์เริ่มต้นคือการติดตั้งใช้งาน
กำหนดไว้ จึงอาจตั้งค่าฟิลด์อัลกอริทึมจุดทั้งหมดเป็น None
เพื่อระบุ
อัลกอริทึมจุดว่าง ซึ่งจะใช้ค่า precision_config
แทน
DotAlgorithm
ช่องประกอบด้วย
lhs_precision_type
และrhs_precision_type
ความแม่นยำที่ LHS และ RHS ของการดำเนินการจะปัดเป็น ประเภทความแม่นยํานั้นไม่เกี่ยวข้องกับ ประเภทพื้นที่เก็บข้อมูลของอินพุตและเอาต์พุตaccumulation_type
ความแม่นยำที่ใช้ในการสะสมlhs_component_count
rhs_component_count
และnum_primitive_operations
มีผลเมื่อเราสร้างอัลกอริทึมซึ่งจะสลาย LHS และ/หรือ RHS เป็น หลายคอมโพเนนต์ และดำเนินการ "พื้นฐาน" หลายอย่าง การดำเนินการกับจุดเหล่านั้น - มักเพื่อจำลองความแม่นยำที่สูงขึ้น (เช่น การใช้ประโยชน์จากประเภทข้อมูลปัญญาประดิษฐ์ (AI) bFloat 16 เพื่อการคำนวณที่แม่นยำยิ่งขึ้น: bf16_6x tf32_3x ฯลฯ) สำหรับอัลกอริทึมที่ไม่มีการแยกส่วน ค่าเหล่านี้ ควรตั้งค่าเป็น1
allow_imprecise_accumulation
เพื่อระบุว่ามีการสะสมที่ความแม่นยำต่ำกว่าหรือไม่ ซึ่งทำได้ในบางขั้นตอน (เช่นCUBLASLT_MATMUL_DESC_FAST_ACCUM
)
ตัวอย่างแอตทริบิวต์ DotAlgorithm
// Inputs are casted to tf32, and then accumulated in f32:
{lhs_precision_type = tf32,
rhs_precision_type = tf32,
accumulation_type = f32,
lhs_component_count = 1,
rhs_component_count = 1,
num_primitive_operations = 1,
allow_imprecise_accumulation = false}
// bf16_6x: each input is decomposed to 3 bf16 components, then 6 dot operations are done on those components, and the result is accumulated in f32.
{lhs_precision_type = bf16,
rhs_precision_type = bf16,
accumulation_type = f32,
lhs_component_count = 3,
rhs_component_count = 3,
num_primitive_operations = 6,
allow_imprecise_accumulation = false}
// Inputs are (casted to) f8e5m2, and we accumulate in f32, but for some steps we may accumulate in lower precision.
{lhs_precision_type = f8e5m2,
rhs_precision_type = f8e5m2,
accumulation_type = f32,
lhs_component_count = 1,
rhs_component_count = 1,
num_primitive_operations = 1,
allow_imprecise_accumulation = true}
ทั้งนี้ ขึ้นอยู่กับการติดตั้งใช้งานที่จะตัดสินใจว่าจะรองรับชุดค่าผสมใด ใน ไม่ได้รับประกันว่าอัลกอริทึมแต่ละรายการจะได้รับการสนับสนุนในแต่ละ ประเภท Accelerator ตามผู้บริโภค StableHLO หากอัลกอริทึมที่ระบุไม่ ข้อผิดพลาดควรเพิ่มขึ้น ไม่ใช่การกลับไปใช้ ทางเลือก การยืนยัน StableHLO จะให้การยืนยันที่ดีที่สุด ป้องกันอัลกอริทึมที่ยังไม่ได้รับการรองรับในฮาร์ดแวร์ใดๆ
โปรดดู xla_data.proto > Algorithm
สำหรับค่าอัลกอริทึมที่รองรับบางค่า ตั๋ว #2483 แสดงแผนในการสร้าง
เอกสารแบบรวมศูนย์บนอัลกอริทึมที่รองรับโดยแบ็กเอนด์
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(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), (C21) |
(I8) | lhs_precision_type |
FloatType หรือ TensorFloat32 | (C21) |
(I9) | rhs_precision_type |
FloatType หรือ TensorFloat32 | (C21) |
(I10) | accumulation_type |
FloatType หรือ TensorFloat32 | (C21) |
(I11) | lhs_component_count |
ค่าคงที่ของประเภท si32 |
(C21), (C22) |
(I12) | rhs_component_count |
ค่าคงที่ของประเภท si32 |
(C21), (C23) |
(I13) | num_primitive_operations |
ค่าคงที่ของประเภท si32 |
(C21), (C24) |
(I14) | allow_imprecise_accumulation |
ค่าคงที่ของประเภท bool |
(C21) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
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)
- หาก
!is_empty_algorithm(lhs_precision_type, rhs_precision_type, accumulation_type, lhs_component_count, rhs_component_count, num_primitive_operations allow_imprecise_accumulation)
:- (C21)
precision_config... = DEFAULT
- (C22)
0 < lhs_component_count
- (C23)
0 < rhs_component_count
- (C24)
0 < num_primitive_operations
- (C21)
ตัวอย่าง
// %lhs: [
// [[1, 2],
// [3, 4]],
// [[5, 6],
// [7, 8]]
// ]
// %rhs: [
// [[1, 0],
// [0, 1]],
// [[1, 0],
// [0, 1]]
// ]
%result = "stablehlo.dot_general"(%lhs, %rhs) {
dot_dimension_numbers = #stablehlo.dot<
lhs_batching_dimensions = [0],
rhs_batching_dimensions = [0],
lhs_contracting_dimensions = [2],
rhs_contracting_dimensions = [1]
>,
precision_config = [#stablehlo<precision DEFAULT>, #stablehlo<precision DEFAULT>],
algorithm = #stablehlo.dot_algorithm<
lhs_precision_type = tf32,
rhs_precision_type = tf32,
accumulation_type = f32,
lhs_component_count = 1,
rhs_component_count = 1,
num_primitive_operations = 1,
allow_imprecise_accumulation = false
>
} : (tensor<2x2x2xi64>, tensor<2x2x2xi64>) -> tensor<2x2x2xi64>
// %result: [
// [[1, 2],
// [3, 4]],
// [[5, 6],
// [7, 8]]
// ]
dynamic_broadcast_in_dim
อรรถศาสตร์
การดำเนินการนี้มีฟังก์ชันการทำงานเหมือนกับ
broadcast_in_dim
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
อรรถศาสตร์
การดำเนินการนี้มีฟังก์ชันการทำงานเหมือนกับ
อ๊ะ แต่ระบุระยะห่างจากขอบแบบไดนามิกผ่าน 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) |
(I15) | 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
อรรถศาสตร์
การดำเนินการนี้มีฟังก์ชันการทำงานเหมือนกับ
รวบรวม
การดำเนินการที่ 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
op แต่รูปร่างผลลัพธ์จะระบุแบบไดนามิกผ่าน output_shape
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | output_shape |
Tensor 1 มิติของประเภทจำนวนเต็ม | (C1), (C2) |
(I2) | iota_dimension |
si64 |
(C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของจำนวนเต็ม จุดลอยตัว หรือประเภทเชิงซ้อน หรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (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
อรรถศาสตร์
การดำเนินการนี้มีฟังก์ชันการทำงานเหมือนกับ
แพด
op แต่มี edge_padding_low
, edge_padding_high
และ interior_padding
เป็นค่าแบบไดนามิก
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือต่อ tensor ในการปรับปริมาณ | (C1), (C2), (C4) |
(I2) | padding_value |
Tensor จำนวน 0 มิติหรือ Tensor ต่อ 1 เมตริก | (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
อรรถศาสตร์
การดำเนินการนี้มีฟังก์ชันการทำงานเหมือนกับ
ปรับรูปร่าง
op แต่รูปร่างผลลัพธ์จะระบุแบบไดนามิกผ่าน 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 |
จำนวนแปรปรวนของ tenor ที่เป็น 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 |
จำนวนแปรปรวนของ tenor ที่เป็น 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]
// ]
เลขชี้กำลัง
อรรถศาสตร์
ทำการดำเนินการเอ็กซ์โปเนนเชียลระดับธาตุใน tensor ของ operand
และสร้าง
result
Tensor ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับแบบลอย:
exp
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: เลขชี้กำลังเชิงซ้อน
- สำหรับประเภทที่เล็กลง
dequantize_op_quantize(exponential, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (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 ที่แปลงค่าเป็น 1 ส่วน | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (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
ซึ่งเท็น 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
ซึ่งสร้าง Tensor 1 มิติของ
ประเภทจุดลอยตัว จะสร้าง Tensor 1 มิติของประเภทเชิงซ้อน
ความหมายและผลของจุดลอยตัวเดียวกัน:
rfft(real_operand) = truncated_result
ที่complex_operand... = (real_operand..., 0.0)
complex_result = fft(complex_operand)
truncated_result = complex_result[:(rank(complex_result) / 2 + 1)]
(เมื่อการแปลงฟูรีเยที่เป็นการคำนวณหาตัวถูกดำเนินการจริง ตัวแปรแรก
N/2 + 1
ของผลลัพธ์จะระบุส่วนที่เหลือของผลลัพธ์อย่างชัดเจน
ระบบจึงตัดผลลัพธ์ของ rfft
เพื่อหลีกเลี่ยงการประมวลผลองค์ประกอบที่ซ้ำกัน)
สำหรับ fft_type = RFFT
result
หมายถึงผลลัพธ์สุดท้ายของชุด L
การคำนวณที่ L = size(fft_length)
ตัวอย่างเช่น สำหรับ L = 3
result1[i0, ..., :] = rfft(operand[i0, ..., :])
result2[i0, ..., :, iR-1] = fft(result1[i0, ..., :, iR-1])
result[i0, ..., :, iR-2, iR-1] = fft(result2[i0, ..., :, iR-2, iR-1])
สุดท้าย ได้รับฟังก์ชัน irfft
ที่มีลายเซ็นประเภทเดียวกันและ
จะคำนวณผกผันของ rfft
สำหรับ fft_type = IRFFT
result
หมายถึงผกผันของการคำนวณ
เป็นเวลา fft_type = RFFT
ตัวอย่างเช่น สำหรับ L = 3
result1[i0, ..., :, iR-2, iR-1] = ifft(operand[i0, ..., :, iR-2, iR-1])
result2[i0, ..., :, iR-1] = ifft(result1[i0, ..., :, iR-1])
result[i0, ..., :] = irfft(result2[i0, ..., :])
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(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 ที่แปลงค่าเป็น 1 เซนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของประเภทจุดลอยตัวหรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (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]
รวบรวม
อรรถศาสตร์
รวบรวมส่วนต่างๆ จาก Tensor ของ operand
จากออฟเซ็ตที่ระบุไว้ใน start_indices
และสร้าง Tensor result
แผนภาพต่อไปนี้แสดงวิธีที่องค์ประกอบใน result
แมปกับองค์ประกอบใน
operand
โดยใช้ตัวอย่างที่เป็นรูปธรรม แผนภาพจะเลือกตัวอย่าง result
บางส่วน
และอธิบายรายละเอียดว่าดัชนี operand
ใดเชื่อมโยงกับดัชนีเหล่านั้น
อย่างเป็นทางการมากขึ้น result[result_index] = operand[operand_index]
ซึ่ง
batch_dims = [d for d in axes(result) and d not in offset_dims]
batch_index = result_index[batch_dims...]
start_index
มีความหมายดังนี้start_indices[bi0, ..., :, ..., biN]
โดยที่bi
เป็นองค์ประกอบเดี่ยวใน แทรกbatch_index
และ:
ที่ดัชนีindex_vector_dim
หากindex_vector_dim
<rank(start_indices)
- จ่าย
[start_indices[batch_index]]
- สำหรับ
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
ของทูเปิล 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]
ถ้า
อรรถศาสตร์
สร้างเอาต์พุตจากการเรียกใช้ฟังก์ชันเดียวจาก true_branch
หรือ
false_branch
ขึ้นอยู่กับค่าของ pred
หรือ result =
pred ? true_branch() : false_branch()
อย่างเป็นทางการ
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | pred |
Tensor 0 มิติของประเภท i1 |
|
(I2) | true_branch |
ฟังก์ชัน | (C1-C3) |
(I3) | false_branch |
ฟังก์ชัน | (C1), (C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวนแปรผันของ Tensor, Tensor ที่เล็กลง หรือโทเค็น | (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
Imag
อรรถศาสตร์
แยกส่วนจินตภาพ ตามองค์ประกอบ จาก operand
และจะสร้าง
result
Tensor อย่างเป็นทางการมากขึ้นสำหรับองค์ประกอบ 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 |
จำนวนแปรผันของ Tensor, Tensor ที่เล็กลง หรือโทเค็น | (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 ที่แปลงค่าเป็น 1 เซนเซอร์ | (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
เป็น แน่นอน (ไม่ใช่ทั้ง 2 อย่าง)
+Inf, -Inf, or NaN) และสร้าง tensor ของ y
ใช้ isFinite
จากข้อกำหนด IEEE-754 สำหรับประเภทที่เล็กลง ผลลัพธ์คือ
true
เสมอ
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | x |
tensor ของประเภทจุดลอยตัวหรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (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]
บันทึก
อรรถศาสตร์
ทำการดำเนินการลอการิทึมตามองค์ประกอบบน tensor ของ operand
และสร้าง
result
Tensor ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับแบบลอย:
log
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: ลอการิทึมเชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(log, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (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 ที่แปลงค่าเป็น 1 ส่วน | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (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
และสร้าง
result
Tensor ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับแบบลอย:
division(1, addition(1, exp(-x)))
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: ตรรกะแบบซับซ้อน
- สำหรับประเภทที่เล็กลง
dequantize_op_quantize(logistic, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (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]]
แผนที่
อรรถศาสตร์
ใช้ฟังก์ชันแผนที่ computation
กับ inputs
ตาม dimensions
และ
สร้าง Tensor ได้ result
หรือ result[result_index] = computation(inputs...[result_index])
อย่างเป็นทางการ
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | inputs |
จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว | (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]]
สูงสุด
อรรถศาสตร์
ทำการดำเนินการสูงสุดตามองค์ประกอบใน Tensor lhs
และ rhs
และสร้าง
result
Tensor ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับบูลีน: ตรรกะ 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]]
ขั้นต่ำ
อรรถศาสตร์
ดำเนินการขั้นต่ำตามองค์ประกอบใน Tensor lhs
และ rhs
และสร้าง
result
Tensor ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับบูลีน: ตรรกะ 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]]
คูณ
อรรถศาสตร์
แสดงผลคูณเชิงองค์ประกอบของ 2 Tensor คือ lhs
และ rhs
และสร้าง
result
Tensor ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับบูลีน: ตรรกะ 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 ที่แปลงค่าเป็น 1 เซนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของจำนวนเต็ม จุดลอยตัว หรือประเภทเชิงซ้อน หรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (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]
ไม่ใช่
อรรถศาสตร์
ดำเนินการตามองค์ประกอบที่ไม่ใช่ tensor operand
และสร้าง tensor ของ result
ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับบูลีน: ตรรกะ NOT
- สำหรับจำนวนเต็ม: บิตไวส์ 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 สำหรับ 2 Tensor สำหรับ lhs
และ rhs
และสร้าง result
Tensor ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับบูลีน: ตรรกะ OR
- สำหรับจำนวนเต็ม: Bitwise 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 |
จำนวนแปรผันของ Tensor หรือ Tensor ที่เล็กลง |
(I2) | token |
token |
(I3) | outfeed_config |
ค่าคงที่ของประเภท string |
เอาต์พุต
ชื่อ | ประเภท |
---|---|
result |
token |
ตัวอย่าง
%result = "stablehlo.outfeed"(%input0, %token) {
outfeed_config = ""
} : (tensor<2x2x2xi64>, !stablehlo.token) -> !stablehlo.token
แพด
อรรถศาสตร์
ขยาย operand
ด้วยระยะห่างจากขอบรอบๆ Tensor และระหว่างองค์ประกอบ
ของ Tensor ที่มี padding_value
ที่ระบุ
edge_padding_low
และ edge_padding_high
ระบุระยะห่างจากขอบที่เพิ่มเข้ามา
อยู่ในระดับต่ำ (ถัดจากดัชนี 0) และระดับไฮเอนด์ (ถัดจากดัชนีสูงสุด) ของ
แต่ละมิติข้อมูลตามลำดับ ระยะห่างจากขอบอาจเป็นลบ โดย
ค่าสัมบูรณ์ของระยะห่างจากขอบเชิงลบจะระบุจำนวนองค์ประกอบที่จะนำออก
จากมิติข้อมูลที่ระบุ
interior_padding
ระบุจำนวนระยะห่างจากขอบที่เพิ่มระหว่างสองเท่า
แต่ละมิติข้อมูล ซึ่งอาจไม่เป็นค่าลบ มีระยะห่างจากขอบภายใน
ก่อนระยะห่างจากขอบของขอบซึ่งจะทำให้ระยะห่างจากขอบที่เป็นลบจะทำให้องค์ประกอบต่างๆ ออกไป
โอเปอแรนด์ที่มีด้านใน
result[result_index]
อย่างเป็นทางการหมายถึง
operand[operand_index]
หากresult_index = edge_padding_low + operand_index * (interior_padding + 1)
- จ่าย
padding_value
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือต่อ tensor ในการปรับปริมาณ | (C1), (C2), (C4) |
(I2) | padding_value |
Tensor จำนวน 0 มิติหรือ Tensor ต่อ 1 เมตริก | (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>
ป๊อปคอต
อรรถศาสตร์
ดำเนินการนับตามองค์ประกอบของจำนวนบิตที่ตั้งค่าไว้ใน 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]
พาวเวอร์
อรรถศาสตร์
ทำการยกกำลังตามธาตุของ lhs
Tensor คูณ rhs
Tensor และ
สร้าง Tensor ของ result
ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับจำนวนเต็ม: เลขยกกำลังจำนวนเต็ม
- สำหรับแบบลอย:
pow
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: การยกกำลังเชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(power, lhs, rhs, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
tensor ของจำนวนเต็ม จุดลอยตัว หรือประเภทเชิงซ้อน หรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (C1) |
(I2) | rhs |
tensor ของจำนวนเต็ม จุดลอยตัว หรือประเภทเชิงซ้อน หรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของจำนวนเต็ม จุดลอยตัว หรือประเภทเชิงซ้อน หรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (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
และสร้าง result
Tensor อย่างเป็นทางการมากขึ้นสำหรับองค์ประกอบ 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]
Revv
อรรถศาสตร์
รับข้อมูลจากช่องที่มี channel_id
และสร้าง results
หาก is_host_transfer
คือ true
การดำเนินการจะโอนข้อมูลจาก
เป็นโฮสต์ มิเช่นนั้น ระบบจะโอนข้อมูลจากอุปกรณ์อื่น หมายความว่าอย่างไร
ที่กำหนดโดยการติดตั้งใช้งาน ธงนี้ซ้ำกับข้อมูลที่ให้ไว้ใน
channel_type
ดังนั้นในอนาคตเราจึงวางแผนที่จะเก็บเพียงรายการเดียวไว้
(#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 |
จำนวนแปรผันของ Tensor, Tensor ที่เล็กลง หรือโทเค็น | (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 |
จำนวนแปรผันของ Tensor หรือ Tensor ต่อ Tensor ที่เล็กลง | (C1-C4), (C6), (C7) |
(I2) | init_values |
จำนวนแปรปรวนของ Tensor ที่มี 0 มิติ หรือ Tensor ต่อ 4 ตัว | (C2), (C3) |
(I3) | dimensions |
ค่าคงที่ tensor ใน 1 มิติของประเภท si64 |
(C4), (C5), (C7) |
(I4) | body |
ฟังก์ชัน | (C6) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว | (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
และกลับไปเป็นต้นฉบับ
ประเภทจุดลอยตัวและสร้าง Tensor ขึ้น output
อย่างเป็นทางการเพิ่มเติม
- ระบบจะอัปเดตบิตแมนทิสซาของค่าเดิมเพื่อปัดเศษค่าดั้งเดิม
เป็นค่าที่ใกล้เคียงที่สุดที่แสดงได้ด้วย
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 ที่แปลงค่าเป็น 1 เซนเซอร์ | (C1) |
(I2) | exponent_bits |
ค่าคงที่ของประเภท si32 |
(C2) |
(I3) | mantissa_bits |
ค่าคงที่ของประเภท si32 |
(C3) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
output |
tensor ของประเภทจุดลอยตัวหรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (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 |
จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว | (C1-C4), (C6), (C8), (C10), (C12), (C13), (C15) |
(I2) | init_values |
จำนวนแปรปรวนของ Tensor ที่มี 0 มิติ หรือ Tensor ต่อ 4 ตัว | (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 |
จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว | (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 และ
สร้าง 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 ที่แปลงค่าเป็น 1 เซนเซอร์ | (C1) |
(I2) | rhs |
tensor ของจำนวนเต็ม จุดลอยตัวหรือประเภทเชิงซ้อน หรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของจำนวนเต็ม จุดลอยตัวหรือประเภทเชิงซ้อน หรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (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>
ปรับรูปร่าง
อรรถศาสตร์
ดำเนินการปรับรูปร่างของ operand
เป็น Tensor เป็น result
โดยหลักการแล้ว
ยังคงรักษาการนำเสนอ Canonical เดิมไว้ แต่อาจมีการเปลี่ยนแปลง
รูปร่าง เช่น จาก 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
อรรถศาสตร์
สร้างตัวเลขสุ่มโดยใช้อัลกอริทึม rng_distribution
และจะสร้าง
ระยะทาง result
ของรูปร่างที่กำหนด 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 ที่แปลงค่าเป็น 1 เซนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของประเภทจุดลอยตัวหรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (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
และสร้าง result
Tensor ใช้การดำเนินการ roundToIntegralTiesToEven
จาก IEEE-754
สำหรับประเภทที่เล็กลง จะดำเนินการ
dequantize_op_quantize(round_nearest_even, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor ของประเภทจุดลอยตัวหรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของประเภทจุดลอยตัวหรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (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
อรรถศาสตร์
ดำเนินการรากที่ 2 กลับด้านธาตุใน tensor ของ operand
และ
สร้าง tensor ของ result
ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับแบบลอย:
rSqrt
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: รากที่สองของส่วนกลับเชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(rsqrt, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (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]]
แผนภูมิกระจาย
อรรถศาสตร์
สร้าง Tensor จำนวน results
ซึ่งเท่ากับ Tensor จำนวน inputs
ยกเว้นค่าดังกล่าว
ส่วนต่างๆ ที่ scatter_indices
ระบุจะได้รับการอัปเดตด้วยค่า
updates
กำลังใช้ update_computation
แผนภาพต่อไปนี้แสดงวิธีที่องค์ประกอบใน updates...
แมปกับองค์ประกอบใน
results...
โดยใช้ตัวอย่างที่เป็นรูปธรรม แผนภาพจะเลือกตัวอย่าง 2-3 ข้อ
updates...
ดัชนีและอธิบายอย่างละเอียดว่า 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 |
จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว | (C1), (C2), (C4-C6), (C11), (C13), (C18), (C21), (C23-C24) |
(I2) | scatter_indices |
Tensor ของประเภทจำนวนเต็ม | (C4), (C15), (C19), (C22) |
(I3) | updates |
จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว | (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 |
จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว | (C24-C25) |
ข้อจำกัด
- (C1)
same(shape(inputs...))
- (C2) `rank(inputs[0]) = size(update_window_dims) + size(inserted_window_dims)
- size(input_batching_dims)`.
- (C3)
same(shape(updates...))
- (C4)
shape(updates[0]) = combine(update_scatter_dim_sizes, update_window_dim_sizes)
โดยที่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
หรือ
tensor ของ on_false
โดยอิงตามค่าขององค์ประกอบที่เกี่ยวข้องของ 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 ต่อ 1 เมตริก | (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
ดังนั้นในอนาคตเราจึงวางแผนที่จะเก็บเพียงรายการเดียวไว้
(#666)
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | inputs |
จำนวนแปรผันของ Tensor หรือ 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
อรรถศาสตร์
ดำเนินการ Shift ซ้ายขององค์ประกอบบน lhs
tensor ตามตัวเลข 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 ของ 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 ควอนไทล์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
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
และสร้าง result
Tensor ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับแบบลอย:
sin
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: ไซน์เชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(sine, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (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]
// ]
จัดเรียง
อรรถศาสตร์
จัดเรียงส่วนแบ่ง 1 มิติของ inputs
ตามมิติข้อมูล dimension
เข้าด้วยกัน
ตาม comparator
และผลิต results
dimension
อนุญาตค่าลบ ซึ่งต่างจากอินพุตที่คล้ายกันในการดำเนินการอื่นๆ
ด้วยความหมายดังที่อธิบายด้านล่างนี้ ในอนาคต URL นี้อาจไม่ได้รับอนุญาต
เพื่อความสอดคล้อง
(#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 |
จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว | (C1-C5) |
(I2) | dimension |
ค่าคงที่ของประเภท si64 |
(C4) |
(I3) | is_stable |
ค่าคงที่ของประเภท i1 |
|
(I4) | comparator |
ฟังก์ชัน | (C5) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว | (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]]
SQL
อรรถศาสตร์
ดำเนินการรากที่ 2 ที่อิงตามองค์ประกอบบน tensor ของ operand
และสร้าง
result
Tensor ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับแบบลอย:
squareRoot
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: รากที่สองเชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(sqrt, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (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]]
ลบ
อรรถศาสตร์
ดำเนินการลบ 2 Tensor สำหรับองค์ประกอบ lhs
และ rhs
ตามองค์ประกอบ แล้วสร้าง
result
Tensor ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับจำนวนเต็ม: การลบจำนวนเต็ม
- สำหรับแบบลอย:
subtraction
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: การลบเชิงซ้อน
- สำหรับประเภทที่เล็กลง
dequantize_op_quantize(subtract, lhs, rhs, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
tensor ของจำนวนเต็ม จุดลอยตัว หรือประเภทเชิงซ้อน หรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (C1) |
(I2) | rhs |
tensor ของจำนวนเต็ม จุดลอยตัว หรือประเภทเชิงซ้อน หรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของจำนวนเต็ม จุดลอยตัว หรือประเภทเชิงซ้อน หรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (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]]
tan
อรรถศาสตร์
ดำเนินการแทนเจนต์ที่มีระดับองค์ประกอบใน Tensor ของ operand
และสร้าง
result
Tensor ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับแบบลอย:
tan
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: แทนเจนต์เชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(tan, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (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.tan"(%operand) : (tensor<2x2xf64>) -> tensor<2x2xf64>
// %result: [
// [0.0, 1.63312e+16],
// [0.0, 5.44375e+15]
// ]
แทนห์
อรรถศาสตร์
ทำการดำเนินการไฮเปอร์โบลิกแทนเจนต์ตามองค์ประกอบบน tensor ของ operand
และ
สร้าง tensor ของ result
ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับแบบลอย:
tanh
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: ไฮเปอร์โบลิกแทนเจนต์เชิงซ้อน
- สำหรับประเภทที่เล็กลง
dequantize_op_quantize(tanh, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (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
และสร้างพารามิเตอร์
result
Tensor อย่างเป็นทางการเพิ่มเติม 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 ที่แปลงค่าเป็น 1 ส่วน | (C1-C3) |
(I2) | b |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (C1-C4) |
(I3) | left_side |
ค่าคงที่ของประเภท i1 |
(C3) |
(I4) | lower |
ค่าคงที่ของประเภท i1 |
|
(I5) | unit_diagonal |
ค่าคงที่ของประเภท i1 |
|
(I6) | transpose_a |
enum ของ NO_TRANSPOSE , TRANSPOSE และ ADJOINT |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน | (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
ลักษณะการทำงานของลูปอนันต์จะมีการกำหนดภายหลัง (#383)
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
จำนวนแปรผันของ Tensor, Tensor ที่เล็กลง หรือโทเค็น | (C1-C3) |
(I2) | cond |
ฟังก์ชัน | (C1) |
(I3) | body |
ฟังก์ชัน | (C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวนแปรผันของ Tensor, Tensor ที่เล็กลง หรือโทเค็น | (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 ที่ชี้องค์ประกอบด้วย 2 Tensor คือ lhs
และ rhs
และสร้าง result
Tensor ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับบูลีน: ตรรกะ XOR
- สำหรับจำนวนเต็ม: Bitwise 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
ฝั่งตรงข้ามของ 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
สามารถใช้เพื่อแปลงการดำเนินการเหล่านี้เป็น Ops ของ StableHLO ที่สนับสนุนอย่างสมบูรณ์
การดำเนินการที่เลิกใช้งานแล้ว
มีการดำเนินการ StableHLO หลายรายการที่รับช่วงมาจาก MHLO ซึ่งเลิกใช้งานแล้วและกำลังออกจาก StableHLO รายละเอียดทั้งหมดเกี่ยวกับเรื่องเหล่านี้ การนำออกจะอยู่ใน StableHLO v1.0 Cleanup #2283 ปัญหาเครื่องมือติดตามสำหรับการเลิกใช้งานเหล่านี้คือ #2340
โดยการดำเนินการเหล่านี้แบ่งออกเป็น 2-3 หมวดหมู่ ดังนี้
- "ไม่ได้อยู่ใน HLO" หมวดหมู่การดำเนินงาน StableHLO - ในตอนแรกมันเป็นส่วนหนึ่งของ
ตัวเลือก StableHLO แต่ภายหลังมีการพิจารณาได้ไม่ดีนัก:
broadcast
,create_token
,cross-replica-sum
,dot
,einsum
torch_index_select
unary_einsum
(#3) - การดำเนินการที่ไม่ได้ใช้ - การดำเนินการเหล่านี้อาจมีประโยชน์ในช่วงหนึ่ง แต่การดำเนินการ
ด้อยพัฒนา หรือไปป์ไลน์ที่ใช้การดำเนินการเหล่านี้
เปลี่ยนโครงสร้างภายในโค้ดเพื่อไม่ให้จำเป็นต้องใช้อีกต่อไป ซึ่งรวมถึง
map
,tuple
(#598) การเปรียบเทียบget_tuple_element
,rng
,complex
#560, และ 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
และการคำนวณค่าเอาต์พุต ค่าเอาต์พุตของฟังก์ชันจะคำนวณตาม
การเรียกใช้กราฟของการดำเนินการที่รูทในการดำเนินการ return
ที่เกี่ยวข้อง
ลำดับการดำเนินการจะได้รับการกำหนดการใช้งาน ตราบใดที่สอดคล้องกับ
โฟลว์ข้อมูล นั่นคือเมื่อมีการเรียกใช้การดำเนินการก่อนการใช้งาน ใน 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 พร้อมกันได้โดยจัดแบ่งเป็นตารางกริดกระบวนการแบบ 2 มิติ
ของ num_replicas
ตาม num_partitions
ซึ่งทั้งคู่เป็นประเภท 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)
ภายในตารางกระบวนการนั้น กระบวนการส่วนใหญ่จะเป็นอิสระจากกัน มีสถานะการดำเนินการแตกต่างกัน รวมถึงมีค่าอินพุต/กลาง/เอาต์พุตแยกกัน และการดำเนินการส่วนใหญ่จะถูกดำเนินการแยกกันในระหว่างกระบวนการ ยกเว้นการดำเนินการรวมจำนวนเล็กน้อยที่อธิบายด้านล่าง
เนื่องจากการดำเนินการของ Ops ส่วนใหญ่จึงใช้เพียงค่าจาก
ส่วนใหญ่แล้ว การอ้างอิงค่าเหล่านี้ด้วยชื่อมักจะไม่ชัดเจน
อย่างไรก็ตาม เมื่ออธิบายความหมายของการทำงานรวม นั่นถือว่าไม่เพียงพอ และ
ที่เป็นสาเหตุของเครื่องหมาย name@process_id
เพื่ออ้างถึงค่า name
ภายในกระบวนการหนึ่งๆ โดยเฉพาะ (จากมุมมองนี้ name
ที่ไม่มีสิทธิ์อาจ
ซึ่งถือเป็นชวเลขสำหรับ name@(replica_id(), partition_id())
)
ลำดับการดำเนินการในกระบวนการต่างๆ มีการกำหนดการใช้งานแล้ว ยกเว้น การซิงค์ที่นำมาใช้โดยการสื่อสารแบบจุดต่อจุดและการดำเนินการร่วมกัน ตามที่อธิบายไว้ด้านล่าง
การสื่อสารแบบจุดต่อจุด
กระบวนการ StableHLO สามารถสื่อสารกันได้ผ่าน
เวอร์ชัน StableHLO ช่องจะแสดงเป็นรหัสเชิงบวกของประเภท
si64
การดำเนินการต่างๆ ทำให้สามารถส่งค่าไปยังช่องและ
รับจากช่องต่างๆ
รูปแบบที่เป็นทางการเพิ่มเติม เช่น ว่ารหัสแชแนลเหล่านี้มาจากไหน อย่างไร จะรับรู้กระบวนการเหล่านั้น และประเภทของการซิงโครไนซ์คืออะไร ที่ได้รับการแนะนำมาจะได้รับการแจ้งภายหลัง (#484)
การสื่อสารแบบสตรีมมิง
ทุกกระบวนการของ StableHLO จะสามารถเข้าถึงอินเทอร์เฟซสตรีมมิง 2 แบบ ได้แก่
- Infeed ที่สามารถอ่านได้
- โฆษณานอกฟีดที่เขียนถึงได้
ต่างจากช่องทางที่ใช้เพื่อสื่อสารระหว่างกระบวนการ และด้วยเหตุนี้ มีกระบวนการทั้ง 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,
วิกิพีเดีย)
โดยมีการแก้ไข 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...)
ข) และสูตรเหล่านี้ยังรองรับจุดไข่ปลา (...
) ซึ่งเปลี่ยนนิพจน์สเกลาร์
เป็นนิพจน์ 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 ใน
หวังว่าเนื้อหานี้จะยังคงเข้าใจได้ง่ายโดยพิจารณาเป็นรายกรณีไป
โปรดแจ้งให้เราทราบหากมีสูตรบางสูตรที่ทึบแสง และเราจะพยายามดำเนินการ
เพื่อปรับปรุงให้ดีขึ้น
นอกจากนี้ คุณจะเห็นว่าสูตรใช้จุดไข่ปลาเพื่อขยายรายการทุกประเภท รวมถึง Tensor รายการของ Tensor (เช่น อาจเกิดจากตัวแปร variadic) จำนวนของ Tensor) เป็นต้น นี่เป็นอีกพื้นที่หนึ่งที่เราไม่ได้ระบุ ความเป็นทางการ (เช่น รายการไม่ได้เป็นส่วนหนึ่งของระบบประเภท 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
(ประเภทตามที่กำหนดไว้ในส่วน "ประเภท")
4) Function
(ฟังก์ชันส่วนกลางตามที่กำหนดไว้ในส่วน "ฟังก์ชัน")
ชื่ออาจอ้างอิงถึงค่าที่แตกต่างกัน ขึ้นอยู่กับบริบท เพิ่มเติม
โดยเฉพาะอย่างยิ่ง "ความหมาย" สำหรับการดำเนินการ (และเทียบเท่ากับโปรแกรมอื่น)
) จะกำหนดตรรกะรันไทม์ ดังนั้นอินพุตทั้งหมดจะพร้อมใช้งานเป็น Value
ในทางกลับกัน "ข้อจำกัด" สำหรับการดำเนินการ (และรายการเทียบเท่า)
"เวลาคอมไพล์" คือสิ่งที่มักจะดำเนินการก่อนรันไทม์
จึงมีเฉพาะอินพุตคงที่เท่านั้นที่จะแสดงเป็น Value
ส่วนอินพุตอื่นๆ จะมีค่า
พร้อมให้ใช้งานในรูปแบบ Placeholder
เท่านั้น
ชื่อ | ใน "ความหมาย" | ใน "ข้อจำกัด" |
---|---|---|
ฟังก์ชันส่วนกลาง | 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
is_empty_algorithm(*args: Type)
ตรวจสอบว่าได้ตั้งค่าฟิลด์อัลกอริทึมของจุดทั้งหมดหรือไม่ ไปยังNone
ซึ่งจำเป็นต้องมีเนื่องจากอัลกอริทึมของจุดมีการกำหนดการใช้งาน พฤติกรรมที่เป็นค่าเริ่มต้น ดังนั้นการระบุค่าเริ่มต้นจึงไม่ถูกต้อง
การสร้างมูลค่า
operation_name(*xs: Value | Type) -> Value
ใช้ได้สำหรับการดำเนินงานทั้งหมด ตัวอย่างเช่นadd(lhs, rhs)
ใช้ค่า Tensor 2 ค่าlhs
และrhs
และ แสดงผลเอาต์พุตของการประเมินการดำเนินการadd
ด้วยข้อมูลเหล่านี้ สำหรับการดำเนินการบางอย่าง เช่นbroadcast_in_dim
ประเภทของเอาต์พุตคือ "รับน้ำหนักบรรทุก" กล่าวคือ จำเป็นสำหรับการประเมินการดำเนินการ ในกรณีนี้ ฟังก์ชัน จะใช้ประเภทเหล่านี้เป็นอาร์กิวเมนต์
ฟังก์ชันสำหรับค่า
โอเปอเรเตอร์และฟังก์ชันทั้งหมดของ Python จะพร้อมใช้งาน เช่น ทั้งคู่ การสมัครใช้บริการ และการแบ่งส่วน หมายเหตุจาก Python พร้อมสำหรับการจัดทำดัชนีเป็น Tensor, Tensor ที่เล็กลง และ Tuples
to_destination_type(x: Value, destination_type: Type) -> Value
กำหนดไว้เมื่อ tensor แสดงผลค่าที่แปลงของ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
กำหนดไว้ใน tensor และแสดงค่าtrue
หาก องค์ประกอบทั้งหมดของx
จะเป็นNaN
หรือfalse
หากx
ไม่ใช่ Tensor แสดงผลNone
is_sorted(x: Value) -> Value
กำหนดไว้ใน tensor และแสดงค่าtrue
หาก องค์ประกอบของx
จะได้รับการจัดเรียงตามจากน้อยไปหามาก เรียงลำดับแบบพจนานุกรมของดัชนีหรือfalse
ในกรณีอื่นๆ หากx
ไม่ใช่ tensor แสดงผลNone
is_unique(x: Value) -> Value
กำหนดไว้ใน tensor และแสดงค่าtrue
หากเป็นx
ไม่มีองค์ประกอบที่ซ้ำกันหรือไม่มีfalse
หากx
ไม่ใช่ Tensor แสดงผลNone
คำจำกัดความของ
member_name(x: Value) -> Any
คือคำจำกัดความของสมาชิกทั้งหมดmember_name
ของค่าทั้งหมด เช่นreal_part(x)
จะแสดงผลRealPart
ของComplexConstant
ที่เกี่ยวข้อง หากx
ไม่ใช่ค่าที่มี สมาชิกที่เหมาะสม แสดงผลNone
same(x: Value) -> Value
กำหนดไว้ใน tensor และแสดงค่า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 ที่เล็กลงและ เปลี่ยนเป็น "เกณฑ์พื้นฐาน" ซึ่งก็คือประเภทที่มีรูปทรงเดียวกันแต่มี พารามิเตอร์การวัดปริมาณของประเภทองค์ประกอบรีเซ็ตเป็นค่าเริ่มต้น นี่คือ ใช้เป็นเคล็ดลับที่มีประโยชน์ในการเปรียบเทียบทั้ง 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 =