StableHLO คือชุดการดำเนินการสำหรับการดำเนินการระดับสูง (HLO) ในโมเดลแมชชีนเลิร์นนิง StableHLO ทำงานเป็นเลเยอร์ความสามารถในการพกพาระหว่างเฟรมเวิร์ก ML และคอมไพเลอร์ ML โดยเฟรมเวิร์ก ML ที่สร้างโปรแกรม StableHLO สามารถใช้งานร่วมกับคอมไพเลอร์ ML ที่ใช้โปรแกรม StableHLO
เป้าหมายของเราคือการลดความซับซ้อนและเร่งการพัฒนา ML โดยการสร้างความสามารถในการทำงานร่วมกันมากขึ้นระหว่างเฟรมเวิร์ก ML ต่างๆ (เช่น TensorFlow, JAX และ PyTorch) กับคอมไพเลอร์ ML (เช่น XLA และ IREE) ด้วยเหตุนี้ เอกสารนี้จึงระบุข้อกําหนดสําหรับภาษาโปรแกรม StableHLO
ข้อกําหนดนี้มี 3 ส่วนหลักๆ ประการแรก ส่วนโปรแกรมจะอธิบายโครงสร้างของโปรแกรม StableHLO ซึ่งประกอบด้วยฟังก์ชัน StableHLO ที่ประกอบไปด้วยการดำเนินการ StableHLO ภายในโครงสร้างดังกล่าว ส่วน Ops จะระบุความหมายของ Ops แต่ละรายการ ส่วนการดำเนินการจะระบุความหมายของการดำเนินการทั้งหมดเหล่านี้ที่ทำงานร่วมกันภายในโปรแกรม สุดท้าย ส่วนสัญลักษณ์จะอธิบายสัญลักษณ์ที่ใช้ตลอดทั้งข้อกำหนด
หากต้องการดูข้อกำหนดจาก StableHLO เวอร์ชันก่อนหน้า ให้เปิดที่เก็บรีโปที่รุ่นที่ติดแท็กที่ต้องการ เช่น ข้อกําหนดของ StableHLO v0.19.0 หากต้องการดูการเปลี่ยนแปลงที่เกิดขึ้นเมื่อมีการอัปเกรด StableHLO เป็นเวอร์ชันย่อยแต่ละเวอร์ชัน โปรดดูบันทึกเวอร์ชันใน VhloDialect.td
โปรแกรม
Program ::= {Func}
โปรแกรม StableHLO ประกอบด้วยฟังก์ชัน StableHLO กี่รายการก็ได้
ด้านล่างนี้คือตัวอย่างโปรแกรมที่มีฟังก์ชัน @main
ซึ่งมีอินพุต 3 รายการ (%image
, %weights
และ %bias
) และเอาต์พุต 1 รายการ เนื้อความของฟังก์ชันมีการดำเนินการ 6 รายการ
func.func @main(
%image: tensor<28x28xf32>,
%weights: tensor<784x10xf32>,
%bias: tensor<1x10xf32>
) -> tensor<1x10xf32> {
%0 = "stablehlo.reshape"(%image) : (tensor<28x28xf32>) -> tensor<1x784xf32>
%1 = "stablehlo.dot"(%0, %weights) : (tensor<1x784xf32>, tensor<784x10xf32>) -> tensor<1x10xf32>
%2 = "stablehlo.add"(%1, %bias) : (tensor<1x10xf32>, tensor<1x10xf32>) -> tensor<1x10xf32>
%3 = "stablehlo.constant"() {value = dense<0.0> : tensor<1x10xf32>} : () -> tensor<1x10xf32>
%4 = "stablehlo.maximum"(%2, %3) : (tensor<1x10xf32>, tensor<1x10xf32>) -> tensor<1x10xf32>
"func.return"(%4): (tensor<1x10xf32>) -> ()
}
ฟังก์ชัน
Func ::= 'func' '.' 'func' FuncId FuncInputs FuncOutputs '{' FuncBody '}'
FuncInputs ::= '(' [FuncInput {',' FuncInput}] `)`
FuncInput ::= ValueId ':' ValueType
FuncOutputs ::= ['->' FuncOutput, {',' FuncOutput}]
FuncOutput ::= ValueType
FuncBody ::= {Op}
ฟังก์ชัน StableHLO (หรือที่เรียกว่าฟังก์ชันที่มีชื่อ) ประกอบด้วยตัวระบุ อินพุต/เอาต์พุต และเนื้อหา ในอนาคต เราวางแผนที่จะเปิดตัวข้อมูลเมตาเพิ่มเติมสำหรับฟังก์ชันเพื่อให้ใช้งานร่วมกับ HLO ได้ดียิ่งขึ้น (#425, #626, #740, #744)
รหัสระบุ
FuncId ::= '@' letter {letter | digit}
ValueId ::= '%' digit {digit}
| '%' letter {letter | digit}
letter ::= 'a' | ... | 'z' | 'A' | ... | 'Z' | '_'
digit ::= '0' | ... | '9'
ตัวระบุ StableHLO คล้ายกับตัวระบุในภาษาโปรแกรมหลายภาษา โดยมี 2 ลักษณะเฉพาะ ได้แก่ 1) ตัวระบุทั้งหมดมีสัญลักษณ์ซึ่งช่วยแยกความแตกต่างระหว่างตัวระบุประเภทต่างๆ และ 2) ตัวระบุค่าอาจเป็นตัวเลขล้วนๆ เพื่อให้การสร้างโปรแกรม StableHLO ง่ายขึ้น
ประเภท
Type ::= ValueType | NonValueType
ValueType ::= TensorType | QuantizedTensorType | TokenType | TupleType
NonValueType ::= TensorElementType | QuantizedTensorElementType | FunctionType | StringType
ประเภท StableHLO ได้รับการจัดหมวดหมู่เป็นประเภทค่า (หรือเรียกว่าประเภทคลาสเฟิร์สคลาส) ที่แสดงถึงค่า StableHLO และประเภทที่ไม่ใช่ค่าซึ่งอธิบายองค์ประกอบอื่นๆ ของโปรแกรม ประเภท StableHLO คล้ายกับประเภทในภาษาโปรแกรมหลายภาษา โดยความแปลกประหลาดหลักคือลักษณะเฉพาะของโดเมนของ StableHLO ซึ่งส่งผลให้เกิดผลลัพธ์ที่ผิดปกติบางอย่าง (เช่น ประเภทสเกลาร์ไม่ใช่ประเภทค่า)
TensorType ::= 'tensor' '<' Shape TensorElementType '>'
Shape ::= {DimensionSize 'x'}
DimensionSize ::= digit {digit} | '?'
ประเภท Tensor แสดงถึง Tensor หรืออาร์เรย์หลายมิติ โดยจะมีรูปร่างและประเภทองค์ประกอบ โดยรูปร่างจะแสดงขนาดมิติข้อมูลที่ไม่ใช่ค่าลบหรือไม่ทราบค่าตามลําดับจากน้อยไปมากของมิติข้อมูลที่เกี่ยวข้อง (หรือที่เรียกว่าแกน) ซึ่งระบุหมายเลขตั้งแต่ 0
ถึง R-1
จำนวนมิติข้อมูลที่ R
เรียกว่าอันดับ เช่น tensor<2x3xf32>
เป็นประเภทเทนเซอร์ที่มีรูปร่าง 2x3
และประเภทองค์ประกอบ f32
ข้อมูลมี 2 มิติ (หรืออีกนัยหนึ่งคือ 2 แกน) ได้แก่ มิติที่ 0 และมิติที่ 1 ซึ่งมีขนาด 2 และ 3 อันดับคือ 2
รูปร่างอาจไม่รู้จักบางส่วนหรือทั้งหมด (แบบไดนามิก) เช่น tensor<?x2xf64>
ไม่รู้จักบางส่วนและ tensor<?x?xf64>
ไม่รู้จักเลย ระบบจะแสดงขนาดมิติข้อมูลแบบไดนามิกโดยใช้ ?
รูปร่างจะจัดลําดับไม่ได้
ในอนาคต เราวางแผนที่จะขยายประเภทของเทมพอร์เป็นมากกว่าขนาดมิติข้อมูลและประเภทองค์ประกอบ เช่น เพื่อรวมเลย์เอาต์ (#629) และความถี่ต่ำ (#1078)
QuantizedTensorType ::= 'tensor' '<' Shape QuantizedTensorElementType '>'
QuantizedTensorElementType ::= '!quant.uniform' '<'
QuantizationStorageType
['<' QuantizationStorageMin ':' QuantizationStorageMax '>']
':' QuantizationExpressedType
[':' QuantizationDimension]
',' QuantizationParameters '>'
QuantizationStorageType ::= IntegerType
QuantizationStorageMin ::= IntegerLiteral
QuantizationStorageMax ::= IntegerLiteral
QuantizationExpressedType ::= FloatType
QuantizationDimension ::= IntegerLiteral
QuantizationParameters ::= QuantizationParameter
| '{' QuantizationParameter {',' QuantizationParameter} '}'
QuantizationParameter ::= QuantizationScale [':' QuantizationZeroPoint]
QuantizationScale ::= FloatLiteral
QuantizationZeroPoint ::= IntegerLiteral
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
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
- (ค2)
type(storage_max) = storage_type
- (C3)
min_value(storage_type) <= storage_min < storage_max <= max_value(storage_type)
- (C4)
type(scales...) = expressed_type
- (C5)
0 < scales
- (C6)
is_finite(scales...)
- (C7)
storage_min <= zero_points <= storage_max
- (C8)
type(zero_points...) = storage_type
- (C9)
size(scales) = size(zero_points)
- (C10) ถ้า
is_empty(quantization_dimension)
ให้size(scales) = 1
- (C11)
0 <= quantization_dimension
ปัจจุบัน QuantizationScale
คือค่าคงที่ทศนิยม แต่เราสนใจสเกลที่อิงตามจำนวนเต็ม ซึ่งแสดงด้วยตัวคูณและการเลื่อน เราวางแผนที่จะสำรวจเรื่องนี้ในอนาคตอันใกล้ (#1404)
มีการพูดคุยกันอย่างต่อเนื่องเกี่ยวกับความหมายของ QuantizationZeroPoint
ซึ่งรวมถึงประเภท ค่า และพิจารณาว่าจะมีจุด 0 จุด 1 จุดหรืออาจเป็น 0 จุดในประเภท Tensor ที่เล็กลงหรือไม่ จากผลการพูดคุยครั้งนี้ ข้อกําหนดเกี่ยวกับจุดศูนย์อาจมีการเปลี่ยนแปลงในอนาคต (#1405)
การพูดคุยอีกเรื่องหนึ่งที่กำลังดำเนินอยู่เกี่ยวข้องกับความหมายของ QuantizationStorageMin
และ QuantizationStorageMax
เพื่อพิจารณาว่าควรมีข้อจำกัดสำหรับค่าเหล่านี้และค่าของ Tensor ที่แปลงค่าเป็นจำนวนเต็มหรือไม่ (#1406)
สุดท้าย เราวางแผนที่จะสำรวจการนำเสนอรูปแบบที่ไม่รู้จักและจุดเริ่มต้น เช่นเดียวกับที่เราวางแผนที่จะสำรวจการนำเสนอขนาดมิติข้อมูลที่ไม่ทราบ (#1407)
ประเภท tensor ที่กำหนดแสดงถึง Tensor ที่มีองค์ประกอบที่เล็กลง tensor เหล่านี้เหมือนกับ tensor ปกติทุกประการ เว้นแต่องค์ประกอบของ Tensor จะมีประเภทองค์ประกอบที่เล็กลงแทนที่จะเป็นประเภทองค์ประกอบปกติ
ในเทนเซอร์ที่ผ่านการแปลงค่า การแปลงค่าอาจเป็นต่อเทนเซอร์ ซึ่งหมายความว่ามี scale
และ zero_point
1 คู่สำหรับเทนเซอร์ทั้งรายการ หรืออาจเป็นต่อแกน ซึ่งหมายความว่ามี scales
และ zero_points
หลายคู่ โดย 1 คู่ต่อส่วนย่อยของมิติข้อมูล quantization_dimension
ที่เฉพาะเจาะจง กล่าวอย่างเป็นทางการคือ ในเทนเซอร์ 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}]
ประเภททูเปิลแสดงถึงทูเปิล เช่น รายการที่หลากหลาย Tuples เป็นฟีเจอร์เดิมที่มีไว้เพื่อใช้งานร่วมกับ HLO เท่านั้น ใน HLO ระบบจะใช้ทูเพลเพื่อแสดงอินพุตและเอาต์พุตแบบผันแปร ใน StableHLO ระบบจะรองรับอินพุตและเอาต์พุตแบบผันแปรโดยค่าเริ่มต้น และการใช้ทูเพลตใน StableHLO มีไว้เพื่อแสดง HLO ABI อย่างครอบคลุมเท่านั้น เช่น T
, tuple<T>
และ tuple<tuple<T>>
อาจแตกต่างกันอย่างมากโดยขึ้นอยู่กับการใช้งาน ในอนาคต เราวางแผนที่จะเปลี่ยนแปลง HLO ABI ซึ่งอาจทำให้เรานำประเภททูเปิลออกจาก 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 ::= 'f4E2M1FN' | 'f6E2M3FN' | 'f6E3M2FN' | 'f8E3M4' | 'f8E4M3'
| 'f8E4M3FN' | 'f8E4M3FNUZ' | 'f8E4M3B11FNUZ' | 'f8E5M2'
| 'f8E5M2FNUZ' | 'f8E8M0FNU' | 'bf16' | 'f16' | 'f32' | 'f64'
TensorFloat32 ::= 'tf32'
ComplexType ::= 'complex' '<' ComplexElementType '>'
ComplexElementType ::= 'f32' | 'f64'
ประเภทองค์ประกอบแสดงองค์ประกอบของประเภท Tensor ภาษาประเภทนี้ต่างจากภาษาโปรแกรมหลายภาษา ตรงไม่ใช่คลาสแรกใน StableHLO ซึ่งหมายความว่าโปรแกรม StableHLO จะแสดงค่าประเภทเหล่านี้โดยตรงไม่ได้ (ดังนั้นจึงใช้รูปแบบการแสดงค่าสเกลาร์ประเภท T
ด้วยค่าเทนเซอร์ 0 มิติประเภท tensor<T>
)
- ประเภทบูลีนแสดงค่าบูลีน
true
และfalse
- ประเภทจำนวนเต็มอาจเป็นแบบมีเครื่องหมาย (
si
) หรือแบบไม่มีเครื่องหมาย (ui
) และมีขนาดบิตที่รองรับอย่างใดอย่างหนึ่ง (2
,4
,8
,16
,32
หรือ64
) ประเภทsiN
แบบมีเครื่องหมายแสดงค่าจำนวนเต็มตั้งแต่-2^(N-1)
ถึง2^(N-1)-1
โดยรวม และประเภทuiN
แบบไม่มีเครื่องหมายแสดงค่าจำนวนเต็มตั้งแต่0
ถึง2^N-1
โดยรวม - ประเภทตัวเลขทศนิยมอาจเป็นอย่างใดอย่างหนึ่งต่อไปนี้
- ตัวเลขทศนิยม 8 บิต
f8E3M4
,f8E4M3
และf8E5M2
ตามรูปแบบ IEEE-754 - ประเภท
f8E4M3FN
และf8E5M2
สอดคล้องกับการเข้ารหัสE4M3
และE5M2
ของรูปแบบ FP8 ที่อธิบายไว้ในรูปแบบ FP8 สําหรับการเรียนรู้เชิงลึก - ประเภท
f8E4M3FNUZ
และf8E5M2FNUZ
ที่สอดคล้องกับการเข้ารหัสE4M3
และE5M2
ของรูปแบบ FP8 ที่อธิบายไว้ในรูปแบบตัวเลข 8 บิตสําหรับเครือข่ายประสาทเทียมลึก f8E4M3B11FNUZ
ประเภทที่สอดคล้องกับการเข้ารหัสE4M3
ของรูปแบบ FP8 ที่อธิบายไว้ในการฝึกและการอนุมาน 8 บิตแบบไฮบริด (HFP8) สำหรับเครือข่ายระบบประสาทแบบลึก- ประเภท
bf16
ที่สอดคล้องกับรูปแบบbfloat16
ที่อธิบายไว้ใน BFloat16: เคล็ดลับสู่ประสิทธิภาพสูงบน Cloud TPU - ประเภท
f16
,f32
และf64
สอดคล้องกับรูปแบบbinary16
("ครึ่งความแม่นยำ"),binary32
("ความแม่นยำเดี่ยว") และbinary64
("ความแม่นยำคู่") ตามลำดับที่อธิบายไว้ในมาตรฐาน IEEE 754 - ประเภท
tf32
สอดคล้องกับรูปแบบ TensorFloat32 และรองรับใน StableHLO แบบจํากัด f4E2M1FN
,f6E2M3FN
,f6E3M2FN
และf8E8M0FNU
MX (Microscaling) ประเภท ที่อธิบายไว้ใน ข้อมูลจำเพาะของรูปแบบ Microscaling ของ OCP
- ตัวเลขทศนิยม 8 บิต
- ประเภทที่ซับซ้อนหมายถึงค่าเชิงซ้อนที่มีส่วนจริงและส่วนจินตภาพขององค์ประกอบประเภทเดียวกัน ประเภทเชิงซ้อนที่รองรับคือ
complex<f32>
(ทั้ง 2 ส่วนเป็นประเภทf32
) และcomplex<f64>
(ทั้ง 2 ส่วนเป็นประเภทf64
)
FunctionType ::= '(' InputTypes ')' '->' '(' OutputTypes ')'
InputTypes ::= [ValueType {',' ValueType}]
OutputTypes ::= [ValueType {',' ValueType}]
ประเภทฟังก์ชันแสดงทั้งฟังก์ชันที่มีชื่อและฟังก์ชันที่ไม่มีชื่อ ฟังก์ชันมีประเภทอินพุต (รายการประเภททางด้านซ้ายของ ->
) และประเภทเอาต์พุต (รายการประเภททางด้านขวาของ ->
) ในภาษาโปรแกรมหลายภาษา ประเภทฟังก์ชันจะเป็นประเภทระดับบนสุด แต่ไม่ใช่ใน StableHLO
StringType ::= 'string'
ประเภทสตริงแสดงลำดับไบต์ ประเภทสตริงไม่ใช่คลาสแรกใน StableHLO และจะใช้เพื่อระบุข้อมูลเมตาแบบคงที่สำหรับองค์ประกอบของโปรแกรมเท่านั้น ซึ่งต่างจากในภาษาโปรแกรมหลายภาษา
การดำเนินการ
การดำเนินการ StableHLO (หรือที่เรียกว่าการดำเนินการ) หมายถึงชุดการดำเนินการระดับสูงแบบปิดในโมเดลแมชชีนเลิร์นนิง ตามที่เราได้กล่าวไปข้างต้น ไวยากรณ์ของ StableHLO ได้รับแรงบันดาลใจอย่างมากจาก MLIR ซึ่งไม่ใช่ทางเลือกที่เหมาะกับการใช้งานมากที่สุด แต่อาจกล่าวได้ว่าเหมาะกับเป้าหมายของ StableHLO ในการสร้างความสามารถในการทำงานร่วมกันมากขึ้นระหว่างเฟรมเวิร์ก ML กับคอมไพเลอร์ ML
Op ::= [OpOutputs] OpName OpInputs ':' OpSignature
OpName ::= '"' 'stablehlo' '.' OpMnemonic '"'
OpMnemonic ::= 'abs' | 'add' | ...
การดำเนินการ StableHLO (หรือที่เรียกว่า ops) มีชื่อ อินพุต/เอาต์พุต และลายเซ็น ชื่อประกอบด้วยคำนำหน้า stablehlo.
และคําช่วยจําซึ่งระบุการดำเนินการที่รองรับรายการใดรายการหนึ่งที่ไม่ซ้ำกัน ดูรายการการดำเนินการทั้งหมดที่รองรับได้ที่ด้านล่าง
OpInputs ::= OpInputValues OpInputFuncs OpInputAttrs
OpInputValues ::= '(' [OpInputValue {',' OpInputValue}] ')'
OpInputValue ::= ValueId
OpInputFuncs ::= ['(' OpInputFunc {',' OpInputFunc} ')']
OpInputAttrs ::= ['{' OpInputAttr {',' OpInputAttr} '}']
OpOutputs ::= [OpOutput {',' OpOutput} '=']
OpOutput ::= ValueId
การดำเนินการจะใช้อินพุตและสร้างเอาต์พุต อินพุตจะแบ่งออกเป็นหมวดหมู่ ได้แก่ ค่าอินพุต (คํานวณระหว่างการดําเนินการ) ฟังก์ชันอินพุต (ระบุแบบคงที่ เนื่องจากใน StableHLO ฟังก์ชันไม่ใช่ค่าระดับบนสุด) และคุณลักษณะอินพุต (ระบุแบบคงที่เช่นกัน) ประเภทของอินพุตและเอาต์พุตที่ใช้และสร้างขึ้นโดยการดำเนินการจะขึ้นอยู่กับความสามารถในการจำ เช่น add
op ใช้ค่าอินพุต 2 ค่าและสร้างค่าเอาต์พุต 1 ค่า ในทางกลับกัน select_and_scatter
op จะใช้ค่าอินพุต 3 ค่า ฟังก์ชันอินพุต 2 รายการ และแอตทริบิวต์อินพุต 3 รายการ
OpInputFunc ::= '{' Unused FuncInputs ':' FuncBody '}'
Unused ::= '^' digit {digit}
| '^' letter {letter | digit}
ฟังก์ชันอินพุต (หรือที่เรียกว่าฟังก์ชันนิรนาม) คล้ายกับฟังก์ชันที่มีชื่อมาก ยกเว้นว่า 1) ไม่มีตัวระบุ (จึงเป็นที่มาของชื่อ "นิรนาม") 2) ไม่ประกาศประเภทเอาต์พุต (ระบบจะอนุมานประเภทเอาต์พุตจาก return
op ภายในฟังก์ชัน)
รูปแบบคำสั่งสำหรับฟังก์ชันอินพุตมีส่วนที่ไม่ได้ใช้งานในปัจจุบัน (ดูUnused
เวอร์ชันที่ใช้งานจริงด้านบน) ซึ่งมีไว้เพื่อใช้งานร่วมกับ MLIR ใน MLIR จะมีแนวคิด "ภูมิภาค" ทั่วไปมากขึ้น ซึ่งอาจมี "บล็อก" ของการดำเนินการหลายรายการที่เชื่อมต่อกันผ่านการดำเนินการ Jump บล็อกเหล่านี้มีรหัสที่สอดคล้องกับUnused
เวอร์ชันที่ใช้งานจริงเพื่อให้แยกความแตกต่างกันได้
StableHLO ไม่มีการข้าม ดังนั้นระบบจึงไม่ได้ใช้ส่วนที่เกี่ยวข้องของไวยากรณ์ MLIR (แต่ยังคงอยู่)
OpInputAttr ::= OpInputAttrName '=' OpInputAttrValue
OpInputAttrName ::= letter {letter | digit}
OpInputAttrValue ::= Constant
แอตทริบิวต์อินพุตมีชื่อและค่าซึ่งเป็นหนึ่งในค่าคงที่ที่รองรับ ซึ่งเป็นวิธีหลักในการระบุข้อมูลเมตาแบบคงที่สำหรับองค์ประกอบโปรแกรม เช่น อ็อป concatenate
ใช้แอตทริบิวต์ dimension
เพื่อระบุมิติข้อมูลที่จะใช้ต่อท้ายค่าอินพุต ในทํานองเดียวกัน slice
op ใช้แอตทริบิวต์หลายรายการ เช่น start_indices
และ limit_indices
เพื่อระบุขอบเขตที่ใช้แบ่งค่าอินพุต
ขณะนี้ โปรแกรม StableHLO ที่ใช้จริงบางครั้งอาจมีแอตทริบิวต์ที่ไม่ได้อธิบายไว้ในเอกสารนี้ ในอนาคต เราวางแผนที่จะรวมแอตทริบิวต์เหล่านี้ไว้ในชุดคำสั่ง StableHLO หรือห้ามไม่ให้แอตทริบิวต์เหล่านี้ปรากฏในโปรแกรม StableHLO ในระหว่างนี้ โปรดดูรายการแอตทริบิวต์เหล่านี้
layout
(#629)mhlo.frontend_attributes
(#628)mhlo.sharding
(#619)output_operand_aliases
(#740)- ข้อมูลเมตาของตำแหน่ง (#594)
OpSignature ::= '(' [ValueType {',' ValueType}] ')' '->' '(' [ValueType {',' ValueType}] ')'
ลายเซ็นการดำเนินการประกอบด้วยประเภทของค่าอินพุตทั้งหมด (รายการประเภททางด้านซ้ายของ ->
) และประเภทของค่าเอาต์พุตทั้งหมด (รายการประเภททางด้านขวาของ ->
) ในทางเทคนิคแล้ว ประเภทอินพุตจะซ้ำซ้อนและประเภทเอาต์พุตก็ซ้ำซ้อนเกือบทุกครั้งด้วย (เนื่องจากสำหรับการดำเนินการ StableHLO ส่วนใหญ่ ประเภทเอาต์พุตจะอนุมานได้จากอินพุต) อย่างไรก็ตาม ลายเซ็น op
ก็ตั้งใจเป็นส่วนหนึ่งของไวยากรณ์ StableHLO เพื่อความเข้ากันได้กับ MLIR
ด้านล่างนี้คือตัวอย่างการดำเนินการที่มีคําช่วยจําคือ select_and_scatter
ระบบจะใช้ค่าอินพุต 3 ค่า (%operand
, %source
และ %init_value
), ฟังก์ชันอินพุต 2 รายการ
และแอตทริบิวต์อินพุต 3 รายการ (window_dimensions
, window_strides
และ padding
)
โปรดทราบว่าลายเซ็นของการดำเนินการมีเฉพาะประเภทของค่าอินพุต (แต่ไม่ใช่ประเภทของฟังก์ชันอินพุตและแอตทริบิวต์ที่ป้อนในบรรทัด)
%result = "stablehlo.select_and_scatter"(%operand, %source, %init_value) ({
^bb0(%arg0: tensor<i32>, %arg1: tensor<i32>):
%0 = "stablehlo.compare"(%arg0, %arg1) {
comparison_direction = #stablehlo<comparison_direction GE>
} : (tensor<i32>, tensor<i32>) -> tensor<i1>
"stablehlo.return"(%0) : (tensor<i1>) -> ()
}, {
^bb0(%arg0: tensor<i32>, %arg1: tensor<i32>):
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i32>, tensor<i32>) -> tensor<i32>
"stablehlo.return"(%0) : (tensor<i32>) -> ()
}) {
window_dimensions = dense<[3, 1]> : tensor<2xi64>,
window_strides = dense<[2, 1]> : tensor<2xi64>,
padding = dense<[[0, 1], [0, 0]]> : tensor<2x2xi64>
} : (tensor<4x2xi32>, tensor<2x2xi32>, tensor<i32>) -> tensor<4x2xi32>
ค่าคงที่
Constant ::= BooleanConstant
| IntegerConstant
| FloatConstant
| ComplexConstant
| TensorConstant
| QuantizedTensorConstant
| StringConstant
| EnumConstant
ค่าคงที่ StableHLO มีนิพจน์และประเภทที่ร่วมกันแสดงค่า StableHLO โดยทั่วไป ประเภทเป็นส่วนหนึ่งของไวยากรณ์ของค่าคงที่ ยกเว้นในกรณีที่ไม่คลุมเครือ (เช่น ค่าคงที่บูลีนมีประเภท i1
อย่างชัดเจน ในขณะที่ค่าคงที่จำนวนเต็มอาจมีประเภทได้หลายประเภท)
BooleanConstant ::= BooleanLiteral
BooleanLiteral ::= 'true' | 'false'
ค่าคงที่บูลีนแสดงค่าบูลีน true
และ false
ค่าคงที่บูลีนมีประเภท i1
IntegerConstant ::= IntegerLiteral ':' IntegerType
IntegerLiteral ::= ['-' | '+'] DecimalDigits
| ['-' | '+'] '0x' HexadecimalDigits
DecimalDigits ::= decimalDigit {decimalDigit}
HexadecimalDigits ::= hexadecimalDigit {hexadecimalDigit}
decimalDigit ::= '0' | ... | '9'
hexadecimalDigit ::= decimalDigit | 'a' | ... | 'f' | 'A' | ... | 'F'
ค่าคงที่จำนวนเต็มแสดงค่าจำนวนเต็มผ่านสตริงที่ใช้การเขียนเลขทศนิยมหรือเลขฐาน 16 ระบบไม่รองรับฐานอื่นๆ เช่น ฐาน 2 หรือฐาน 8 ค่าคงที่จำนวนเต็มมีข้อจำกัดต่อไปนี้
- (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))
- (ค2)
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>
represent a tensor value with the following mapping from indices to elements:
{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) '>'
ค่าคงที่เทนเซอร์ที่แปลงค่าเป็นจำนวนเต็มแสดงค่าเทนเซอร์ที่แปลงค่าเป็นจำนวนเต็มโดยใช้การเขียนแบบเดียวกับค่าคงที่เทนเซอร์ โดยมีองค์ประกอบที่ระบุเป็นค่าคงที่ของประเภทพื้นที่เก็บข้อมูล ค่าคงที่เทนเซอร์ที่แปลงค่าเป็นจำนวนเต็มมีข้อจำกัดต่อไปนี้
- (C1)
has_syntax(quantized_tensor_literal, storage_type(quantized_tensor_type))
- (ค2)
has_shape(quantized_tensor_literal, shape(quantized_tensor_type))
StringConstant ::= StringLiteral
StringLiteral ::= '"' {stringCharacter | escapeSequence} '"'
stringCharacter ::= all ASCII characters except '\00', '\01', ... '\1f' and '"'
escapeSequence ::= '\' ('"' | '\' | 'n' | 't' | (hexadecimalDigit hexadecimalDigit))
สตริงที่แท้จริงประกอบด้วยไบต์ที่ระบุโดยใช้อักขระ ASCII และลำดับการหนี โดยจะไม่สนใจการโค้ด ดังนั้นการตีความไบต์เหล่านี้จะขึ้นอยู่กับการใช้งาน ค่าสตริงล้วนมีประเภท string
การดำเนินการ
abs
ความหมาย
ดำเนินการ abs ตามองค์ประกอบในเทนเซอร์ operand
และสร้างเทนเซอร์ result
ทําสิ่งต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับจำนวนเต็มที่มีเครื่องหมาย: โมดูลัสจำนวนเต็ม
- สำหรับตัวเลขทศนิยม:
abs
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: โมดูลัสเชิงซ้อน
- สำหรับประเภทที่มีการแปลงเป็นจำนวนเต็ม:
dequantize_op_quantize(abs, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทนเซอร์ของจำนวนเต็มที่มีเครื่องหมาย ทศนิยม หรือประเภทเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1-C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ของจำนวนเต็มที่มีเครื่องหมายหรือประเภททศนิยม หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (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
และสร้าง Tensor result
ทําสิ่งต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สําหรับบูลีน: OR เชิงตรรกะ
- สําหรับจํานวนเต็ม: การเพิ่มจํานวนเต็ม
- สำหรับตัวเลขทศนิยม:
addition
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: การบวกเชิงซ้อน
- สำหรับประเภทที่มีการแปลงเป็นจำนวนเต็ม:
dequantize_op_quantize(add, lhs, rhs, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
เทนเซอร์หรือเทนเซอร์ที่ผ่านการแปลงค่าเป็นจำนวนเต็ม | (C1-C6) |
(I2) | rhs |
tensor หรือ tensor แบบเชิงปริมาณ | (C1-C5), (C7) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์หรือเทนเซอร์ที่ผ่านการแปลงค่าเป็นจำนวนเต็ม | (C1-C7) |
ข้อจำกัด
- หากการดำเนินการใช้เทนเซอร์ที่ไม่ผ่านการแปลงค่า ให้ทำดังนี้
- (C1)
type(lhs) = type(rhs) = type(result)
- (C1)
- หากการดำเนินการใช้ Tensor ที่เล็กลง
- (ค2)
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)
- (ค2)
ตัวอย่าง
// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.add"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[6, 8], [10, 12]]
after_all
ความหมาย
ตรวจสอบว่าการดำเนินการที่สร้าง inputs
ทำงานก่อนการดำเนินการใดๆ ที่ขึ้นอยู่กับ result
การดำเนินการนี้ไม่มีผลใดๆ ทั้งสิ้น มีไว้เพื่อกำหนดการพึ่งพาข้อมูลจาก result
ถึง inputs
เท่านั้น
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท |
---|---|---|
(I1) | inputs |
จำนวน token แบบผันแปร |
เอาต์พุต
ชื่อ | ประเภท |
---|---|
result |
token |
ตัวอย่าง
// %input0: !stablehlo.token
// %input1: !stablehlo.token
%result = "stablehlo.after_all"(%input0, %input1) : (!stablehlo.token, !stablehlo.token) -> !stablehlo.token
all_gather
ความหมาย
ภายในกลุ่มกระบวนการแต่ละกลุ่มในตารางกริดกระบวนการ StableHLO ให้ต่อค่าของเทอร์เซอร์ operands
จากแต่ละกระบวนการตาม all_gather_dim
และสร้างเทอร์เซอร์ results
การดำเนินการนี้จะแบ่งตารางกริดของกระบวนการ StableHLO เป็น process_groups
ซึ่งได้กำหนดไว้ดังต่อไปนี้
cross_replica(replica_groups)
ifchannel_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)
ifchannel_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 |
จำนวนเทนเซอร์แบบผันแปรหรือเทนเซอร์ที่แปลงค่าต่อเทนเซอร์ | (C1), (C6) |
(I2) | all_gather_dim |
ค่าคงที่ประเภท si64 |
(C1), (C6) |
(I3) | replica_groups |
ค่าคงที่เทนเซอร์ 2 มิติประเภท si64 |
(C2-C4) |
(I4) | channel_id |
ค่าคงที่ของประเภท si64 |
(C5) |
(I5) | use_global_device_ids |
ค่าคงที่ประเภท i1 |
(C5) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวนเทนเซอร์แบบผันแปรหรือเทนเซอร์ที่แปลงค่าต่อเทนเซอร์ | (C6) |
ข้อจำกัด
- (C1)
0 <= all_gather_dim < rank(operands...)
- (ค2)
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
กับค่าของเทนเซอร์ operands
จากแต่ละกระบวนการ และสร้างเทนเซอร์ results
การดำเนินการนี้จะแบ่งตารางกริดกระบวนการ StableHLO เป็น process_groups
ซึ่งกําหนดไว้ดังนี้
cross_replica(replica_groups)
ifchannel_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)
ifchannel_id > 0 and use_global_device_ids = true
หลังจากนั้น ให้ทำดังนี้ภายในแต่ละ process_group
results...@process[result_index] = exec(schedule)
สำหรับต้นไม้ไบนารีบางต้นschedule
โดยที่exec(node)
=computation(exec(node.left), exec(node.right))
exec(leaf)
=leaf.value
schedule
คือแผนผังไบนารีที่กำหนดโดยการใช้งาน ซึ่งมีการข้ามผ่านตามลำดับเป็นto_destination_type(operands...@process_group...[result_index], type(func_inputs(computation)[0]))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operands |
จำนวนเทนเซอร์แบบผันแปรหรือเทนเซอร์ที่แปลงค่าต่อเทนเซอร์ | (C5), (C6) |
(I2) | replica_groups |
จำนวนตัวแปรของค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C1-C3) |
(I3) | channel_id |
ค่าคงที่ประเภท si64 |
(C4) |
(I4) | use_global_device_ids |
ค่าคงที่ประเภท i1 |
(C4) |
(I5) | computation |
ฟังก์ชัน | (C5) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวนเทนเซอร์แบบผันแปรหรือเทนเซอร์ที่แปลงค่าต่อเทนเซอร์ | (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...)
- (ค7)
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 ให้แยกค่าของเทนเซอร์ operands
ตาม split_dimension
ออกเป็นส่วนๆ กระจายส่วนที่แยกไว้ระหว่างกระบวนการต่างๆ ต่อส่วนที่กระจัดกระจายตาม concat_dimension
และสร้างเทนเซอร์ results
การดำเนินการนี้จะแบ่งตารางกริดของกระบวนการ 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 |
จำนวนเทนเซอร์แบบผันแปรหรือเทนเซอร์ที่แปลงค่าต่อเทนเซอร์ | (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 |
ค่าคงที่เทนเซอร์ 2 มิติประเภท si64 |
(C5-C8) |
(I6) | channel_id |
ค่าคงที่ประเภท si64 |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวนเทนเซอร์แบบผันแปรหรือเทนเซอร์ที่แปลงค่าต่อเทนเซอร์ | (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
และสร้าง Tensor result
ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สําหรับบูลีน: AND เชิงตรรกะ
- สำหรับจำนวนเต็ม: Bitwise AND
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
เทนเซอร์ประเภทบูลีนหรือจำนวนเต็ม | (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
และสร้างเทนเซอร์ result
ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับแบบลอย:
atan2
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: complex atan2
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(atan2, lhs, rhs, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
(I2) | rhs |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
ข้อจำกัด
- (C1)
baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)
ตัวอย่าง
// %lhs: [0.0, 1.0, -1.0]
// %rhs: [0.0, 0.0, 0.0]
%result = "stablehlo.atan2"(%lhs, %rhs) : (tensor<3xf64>, tensor<3xf64>) -> tensor<3xf64>
// %result: [0.0, 1.57079637, -1.57079637] // [0.0, pi/2, -pi/2]
batch_norm_grad
ความหมาย
ประมวลผลการไล่ระดับสีของอินพุตหลายรายการของ batch_norm_training
Backpropagating จาก 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 |
เทนเซอร์ประเภทจุดลอยตัวหรือเทนเซอร์ที่แปลงเป็นจำนวนเต็มตามแต่ละเทนเซอร์ | (C1-C3), (C5) |
(I2) | scale |
เทนเซอร์ 1 มิติของประเภทจำนวนจุดลอยตัวหรือจำนวนที่ปัดเศษตามเทนเซอร์ | (C2), (C4), (C5) |
(I3) | mean |
ความเครียด 1 มิติของจุดลอยตัวหรือประเภทต่อ 1 เซนเซอร์ | (C2), (C4) |
(I4) | variance |
ความเครียด 1 มิติของจุดลอยตัวหรือประเภทต่อ 1 เซนเซอร์ | (C2), (C4) |
(I5) | grad_output |
เทนเซอร์ประเภทจุดลอยตัวหรือเทนเซอร์ที่แปลงเป็นจำนวนเต็มตามแต่ละเทนเซอร์ | (C2), (C3) |
(I6) | epsilon |
ค่าคงที่ประเภท f32 |
|
(I7) | feature_index |
ค่าคงที่ประเภท si64 |
(C1), (C5) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
grad_operand |
เทนเซอร์ประเภทจุดลอยตัวหรือเทนเซอร์ที่แปลงเป็นจำนวนเต็มตามแต่ละเทนเซอร์ | (C2), (C3) |
grad_scale |
เทนเซอร์ 1 มิติของประเภทจำนวนจุดลอยตัวหรือจำนวนที่ปัดเศษตามเทนเซอร์ | (C2), (C4) |
grad_offset |
ความเครียด 1 มิติของจุดลอยตัวหรือประเภทต่อ 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 |
เทนเซอร์ประเภทจุดลอยตัวหรือเทนเซอร์ที่แปลงเป็นจำนวนเต็มตามแต่ละเทนเซอร์ | (C1-C7) |
(I2) | scale |
เทนเซอร์ 1 มิติของประเภทจำนวนจุดลอยตัวหรือจำนวนที่ปัดเศษตามเทนเซอร์ | (C2), (C3) |
(I3) | offset |
ความเครียด 1 มิติของจุดลอยตัวหรือประเภทต่อ 1 เซนเซอร์ | (C2), (C4) |
(I4) | mean |
เทนเซอร์ 1 มิติของประเภทจำนวนจุดลอยตัวหรือจำนวนที่ปัดเศษตามเทนเซอร์ | (C5) |
(I5) | variance |
เทนเซอร์ 1 มิติของประเภทจำนวนจุดลอยตัวหรือจำนวนที่ปัดเศษตามเทนเซอร์ | (C2), (C6) |
(I6) | epsilon |
ค่าคงที่ประเภท f32 |
|
(I7) | feature_index |
ค่าคงที่ประเภท si64 |
(C1), (C3-C6) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภทจุดลอยตัวหรือเทนเซอร์ที่แปลงเป็นจำนวนเต็มตามแต่ละเทนเซอร์ | (C2), (C7) |
ข้อจำกัด
- (C1)
0 <= feature_index < rank(operand)
- (C2)
operand
,scale
,offset
,mean
,variance
และresult
มีbaseline_element_type
เดียวกัน - (C3)
size(scale) = dim(operand, feature_index)
- (C4)
size(offset) = dim(operand, feature_index)
- (C5)
size(mean) = dim(operand, feature_index)
- (C6)
size(variance) = dim(operand, feature_index)
- (ค7)
baseline_type(operand) = baseline_type(result)
ตัวอย่าง
// %operand: [
// [[1.0, 2.0], [3.0, 4.0]],
// [[3.0, 4.0], [1.0, 2.0]]
// ]
// %scale: [1.0, 1.0]
// %offset: [1.0, 1.0]
// %mean: [2.0, 3.0]
// %variance: [1.0, 1.0]
%result = "stablehlo.batch_norm_inference"(%operand, %scale, %offset, %mean, %variance) {
epsilon = 0.0 : f32,
feature_index = 2 : i64
} : (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>, tensor<2xf64>, tensor<2xf64>) -> tensor<2x2x2xf64>
// %result: [
// [[0.0, 0.0], [2.0, 2.0]],
// [[2.0, 2.0], [0.0, 0.0]]
// ]
batch_norm_training
ความหมาย
คํานวณค่าเฉลี่ยและความแปรปรวนในทุกมิติข้อมูล ยกเว้นมิติข้อมูล feature_index
และทำให้เทนเซอร์ operand
เป็นมาตรฐาน ซึ่งจะสร้างเทนเซอร์ output
, batch_mean
และ batch_var
รูปแบบที่เป็นทางการมากขึ้น อาจแสดงเป็นอนุพันธ์ของการดำเนินการ 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 มิติของจำนวนจุดลอยตัวหรือจำนวนจุดลอยตัวต่อเทนเซอร์ | (C2), (C3) |
(I3) | offset |
ความเครียด 1 มิติของจุดลอยตัวหรือต่อ 1 เซนเซอร์ที่แปลงค่าเป็นจำนวน 1 มิติ | (C2), (C4) |
(I4) | epsilon |
ค่าคงที่ประเภท f32 |
(C1), (C3-C6) |
(I5) | feature_index |
ค่าคงที่ประเภท si64 |
(C1), (C3-C6) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
output |
เทนเซอร์ประเภทจุดลอยตัวหรือเทนเซอร์ที่แปลงเป็นจำนวนเต็มตามแต่ละเทนเซอร์ | (C7) |
batch_mean |
เทนเซอร์ 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)
- (ค7)
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 |
เทนเซอร์หรือเทนเซอร์ที่ผ่านการแปลงค่าเป็นจำนวนเต็ม | (C1-C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์หรือเทนเซอร์ที่ผ่านการแปลงค่าเป็นจำนวนเต็ม | (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
ความหมาย
ขยายมิติข้อมูลและ/หรืออันดับของเทมพอร์ลอินพุตโดยการทำซ้ำข้อมูลในเทมพอร์ล operand
และสร้างเทมพอร์ล 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 |
เทนเซอร์หรือเทนเซอร์ที่ผ่านการแปลงค่าเป็นจำนวนเต็ม | (C1-C2), (C5-C6) |
(I2) | broadcast_dimensions |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C2-C6) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์หรือเทนเซอร์ที่ผ่านการแปลงค่าเป็นจำนวนเต็ม | (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)
ตามลำดับ
- (ค2)
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
เพียง 1 รายการเท่านั้น โดยขึ้นอยู่กับค่าของ index
เขียนเป็นทางการคือ result = selected_branch()
โดยที่
selected_branch = branches[index]
หากเป็น0 <= index < size(branches)
- จ่าย
selected_branch = branches[-1]
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | index |
เทนเซอร์ 0 มิติประเภท si32 |
|
(I2) | branches |
จำนวนฟังก์ชันแปรผัน | (C1-C4) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวนเทนเซอร์ เทนเซอร์ที่แปลงเป็นจำนวนจริง หรือโทเค็นแบบผันแปร | (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
ความหมาย
ดำเนินการรากคิวบิกทีละองค์ประกอบในเทนเซอร์ operand
และสร้างเทนเซอร์ result
ทําสิ่งต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับตัวเลขทศนิยม:
rootn(x, 3)
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: รากที่สามเชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(cbrt, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (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
ความหมาย
ดำเนินการปัดเศษทศนิยมขึ้นทีละองค์ประกอบของเทนเซอร์ operand
และสร้างเทนเซอร์ 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
ที่เมทริกซ์อินพุตไม่ใช่เมทริกซ์ Hermitian ที่แน่นอนเชิงบวก ระบบจะไม่ระบุลักษณะการทำงาน
สําหรับประเภทที่กําหนดค่าได้ ให้ทําการ
dequantize_op_quantize(lambda operand: cholesky(operand, lower), a, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | a |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1-C3) |
(I2) | lower |
ค่าคงที่ tensor ของประเภท i1 ค่าคงที่ 0 มิติ |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
ข้อจำกัด
- (C1)
baseline_type(a) = baseline_type(result)
- (ค2)
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 ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C1), (C3) |
(I2) | operand |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C1-C4) |
(I3) | max |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C2), (C3) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C4) |
ข้อจำกัด
- (C1)
rank(min) = 0 or shape(min) = shape(operand)
- (ค2)
rank(max) = 0 or shape(max) = shape(operand)
- (C3)
baseline_element_type(min) = baseline_element_type(operand) = baseline_element_type(max)
- (C4)
baseline_type(operand) = baseline_type(result)
ตัวอย่าง
// %min: [5, 10, 15]
// %operand: [3, 13, 23]
// %max: [10, 15, 20]
%result = "stablehlo.clamp"(%min, %operand, %max) : (tensor<3xi32>, tensor<3xi32>, tensor<3xi32>) -> tensor<3xi32>
// %result: [5, 13, 20]
collective_broadcast
ความหมาย
ภายในกลุ่มกระบวนการแต่ละกลุ่มในตารางกริดกระบวนการ StableHLO ให้ส่งค่าของเทนเซอร์ operand
จากกระบวนการต้นทางไปยังกระบวนการเป้าหมายและสร้างเทนเซอร์ result
การดำเนินการนี้จะแบ่งตารางกริดกระบวนการ StableHLO เป็น process_groups
ซึ่งกําหนดไว้ดังนี้
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 ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C3) |
(I2) | replica_groups |
จำนวนตัวแปรของค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C1), (C2) |
(I3) | channel_id |
ค่าคงที่ของประเภท si64 |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C3) |
ข้อจำกัด
- (C1)
is_unique(replica_groups)
- (C2)
0 <= replica_groups < N
โดยที่N
หมายถึงnum_replicas
หากใช้cross_replica
num_partitions
หากใช้cross_partition
- (C3)
type(result) = type(operand)
ตัวอย่าง
// num_replicas: 4
// num_partitions: 1
// %operand@(0, 0): [[1, 2]]
// %operand@(1, 0): [[3, 4]]
// %operand@(2, 0): [[5, 6]]
// %operand@(3, 0): [[7, 8]]
%result = "stablehlo.collective_broadcast"(%operand) {
replica_groups = dense<[[2, 1]]> : tensor<1x2xi64>,
channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
} : (tensor1x2xi64>) -> tensor<1x2xi64>
// %result@(0, 0): [[0, 0]]
// %result@(1, 0): [[5, 6]]
// %result@(2, 0): [[5, 6]]
// %result@(3, 0): [[0, 0]]
collective_permute
อรรถศาสตร์
ภายในกลุ่มกระบวนการแต่ละกลุ่มในตารางกริดประมวลผล StableHLO ให้ส่งค่าของ Tensor operand
จากกระบวนการต้นทางไปยังกระบวนการเป้าหมายและสร้าง Tensor result
การดำเนินการนี้จะแบ่งตารางกริดกระบวนการ StableHLO เป็น process_groups
ซึ่งกําหนดไว้ดังนี้
cross_replica(source_target_pairs)
หากchannel_id <= 0
cross_partition(source_target_pairs)
หากchannel_id > 0
หลังจากนั้น result@process
จะคำนวณจากข้อมูลต่อไปนี้
operand@process_groups[i, 0]
หากมีi
ที่ว่าprocess_groups[i, 1] = process
broadcast_in_dim(constant(is_quantized(result) ? quantize(0, element_type(result)) : 0, element_type(result)), [], type(result))
หรือ
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือต่อ tensor ในการปรับปริมาณ | (C5) |
(I2) | source_target_pairs |
ค่าคงที่เทนเซอร์ 2 มิติประเภท si64 |
(C1-C4) |
(I3) | channel_id |
ค่าคงที่ของประเภท si64 |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C1) |
ข้อจำกัด
- (C1)
dim(source_target_pairs, 1) = 2
- (ค2)
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 ที่แปลงค่าเป็นจำนวนเต็มต่อ 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 |
เทนเซอร์ประเภทบูลีน | (C2) |
ข้อจำกัด
- (C1)
baseline_element_type(lhs) = baseline_element_type(rhs)
- (ค2)
shape(lhs) = shape(rhs) = shape(result)
- (C3)
compare_type
มีคำจำกัดความดังนี้SIGNED
หากis_signed_integer(element_type(lhs))
UNSIGNED
หากเป็นis_unsigned_integer(element_type(lhs)) or is_boolean(element_type(lhs))
FLOAT
หรือTOTALORDER
หากis_float(element_type(lhs))
FLOAT
หากis_complex(element_type(lhs))
ตัวอย่าง
// %lhs: [1.0, 3.0]
// %rhs: [1.1, 2.9]
%result = "stablehlo.compare"(%lhs, %rhs) {
comparison_direction = #stablehlo<comparison_direction LT>,
compare_type = #stablehlo<comparison_type FLOAT>
} : (tensor<2xf32>, tensor<2xf32>) -> tensor<2xi1>
// %result: [true, false]
ซับซ้อน
ความหมาย
แปลงองค์ประกอบเป็นค่าเชิงซ้อนจากคู่ค่าจริงและจินตภาพ lhs
และ rhs
และสร้างเทนเซอร์ result
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
เทนเซอร์ประเภท f32 หรือ f64 |
(C1-C3) |
(I2) | rhs |
เทนเซอร์ประเภท f32 หรือ f64 |
(C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor ของประเภทที่ซับซ้อน | (C2), (C3) |
ข้อจำกัด
- (C1)
type(lhs) = type(rhs)
- (ค2)
shape(result) = shape(lhs)
- (C3)
element_type(result)
เป็นประเภทcomplex<E>
โดยที่E = element_type(lhs)
ตัวอย่าง
// %lhs: [1.0, 3.0]
// %rhs: [2.0, 4.0]
%result = "stablehlo.complex"(%lhs, %rhs) : (tensor<2xf64>, tensor<2xf64>) -> tensor<2xcomplex<f64>>
// %result: [(1.0, 2.0), (3.0, 4.0)]
การผสม
ความหมาย
บรรจุการดำเนินการที่สร้างขึ้น (ประกอบด้วย) การดำเนินการ StableHLO อื่นๆ โดยนำ inputs
และ composite_attributes
มาสร้าง results
แอตทริบิวต์ decomposition
จะนําความหมายของการดำเนินการไปใช้ คุณสามารถแทนที่การดําเนินการ composite
ด้วยการเปลี่ยนรูปแบบได้โดยไม่ต้องเปลี่ยนความหมายของโปรแกรม ในกรณีที่ในบรรทัดการแยกย่อยไม่ได้ให้ความหมายด้านตรงข้ามเหมือนกัน ให้เลือกใช้ custom_call
ช่อง version
(ค่าเริ่มต้นคือ 0
) ใช้ระบุเมื่อมีการเปลี่ยนแปลงความหมายของการผสม
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท |
---|---|---|
(I1) | inputs |
จำนวนค่าแบบผันแปร |
(I2) | name |
ค่าคงที่ประเภท string |
(I3) | composite_attributes |
พจนานุกรมแอตทริบิวต์ |
(I4) | decomposition |
ค่าคงที่ประเภท string |
(I5) | version |
ค่าคงที่ประเภท si32 |
เอาต์พุต
ชื่อ | ประเภท |
---|---|
results |
จำนวนค่าแบบผันแปร |
ข้อจำกัด
- (C1)
is_namespaced_op_name(name)
- (C2)
is_defined_in_parent_scope(decomposition)
- (C3)
types(inputs...) == input_types(decomposition)
- (C4)
types(results...) == output_types(decomposition)
ตัวอย่าง
%results = "stablehlo.composite"(%input0, %input1) {
name = "my_namespace.my_op",
composite_attributes = {
my_attribute = "my_value"
},
decomposition = @my_op,
version = 1 : i32
} : (tensor<f32>, tensor<f32>) -> tensor<f32>
concatenate
ความหมาย
ต่อinputs
ตามมิติข้อมูล dimension
ในลําดับเดียวกับอาร์กิวเมนต์ที่ระบุ และสร้างเทนเซอร์ result
หรืออย่างเป็นทางการ
result[i0, ..., id, ..., iR-1] = inputs[k][i0, ..., kd, ..., iR-1]
ซึ่ง:
id = d0 + ... + dk-1 + kd
d
เท่ากับdimension
และd0
, ... เป็นขนาดมิติข้อมูลที่d
ของinputs
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | inputs |
จำนวนเทนเซอร์แบบผันแปรหรือเทนเซอร์ที่แปลงค่าต่อเทนเซอร์ | (C1-C6) |
(I2) | dimension |
ค่าคงที่ประเภท si64 |
(C2), (C4), (C6) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C5-C6) |
ข้อจำกัด
- (C1)
same(element_type(inputs...))
- (C2)
same(shape(inputs...))
ยกเว้นdim(inputs..., dimension)
- (C3)
0 < size(inputs)
- (C4)
0 <= dimension < rank(inputs[0])
- (C5)
element_type(result) = element_type(inputs[0])
- (C6)
shape(result) = shape(inputs[0])
ยกเว้นในกรณีต่อไปนี้dim(result, dimension) = dim(inputs[0], dimension) + ...
ตัวอย่าง
// %input0: [[1, 2], [3, 4], [5, 6]]
// %input1: [[7, 8]]
%result = "stablehlo.concatenate"(%input0, %input1) {
dimension = 0 : i64
} : (tensor<3x2xi64>, tensor<1x2xi64>) -> tensor<4x2xi64>
// %result: [[1, 2], [3, 4], [5, 6], [7, 8]]
ค่าคงที่
ความหมาย
สร้างเทนเซอร์ output
จากค่าคงที่ 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
ความหมาย
ทำการแปลงทีละองค์ประกอบจากองค์ประกอบประเภทหนึ่งไปยังอีกประเภทหนึ่งในเทนเซอร์ operand
และสร้างเทนเซอร์ result
สําหรับการเปลี่ยนค่า boolean เป็นประเภทที่รองรับ ระบบจะแปลงค่า false
เป็น 0 และแปลงค่า true
เป็น 1 สําหรับการแปลง any-supported-type-to-boolean ระบบจะแปลงค่า 0 เป็น false
และแปลงค่าที่ไม่ใช่ 0 เป็น true
ดูวิธีการทํางานของการดำเนินการนี้กับประเภทที่ซับซ้อนได้ที่ด้านล่าง
สำหรับ Conversion ที่เกี่ยวข้องกับ integer-to-integer, integer-to-Floing-point หรือ Floating-point-to-Floing-point หากค่าต้นทางสามารถแสดงในประเภทปลายทางได้อย่างถูกต้อง ค่าผลลัพธ์จะเป็นค่าการเป็นตัวแทนที่ถูกต้อง มิฉะนั้น ระบบจะกำหนดลักษณะการทำงานในภายหลัง (#180)
สําหรับการแปลงที่เกี่ยวข้องกับทศนิยมเป็นจํานวนเต็ม ระบบจะตัดเศษส่วน หากค่าที่ถูกตัดให้สั้นลงแสดงในประเภทปลายทางไม่ได้ ลักษณะการทํางานจะยังไม่ทราบ (#180)
Conversion ที่เกี่ยวข้องกับ Conversion แบบซับซ้อนไปซับซ้อนมีลักษณะการทำงานเดียวกันกับ Conversion จุดลอยตัวไปยังจุดลอยตัว สำหรับการแปลงส่วนจริงและส่วนจินตภาพ
สําหรับการเปลี่ยนประเภทจากเชิงซ้อนเป็นประเภทอื่นๆ และประเภทอื่นๆ เป็นเชิงซ้อน ระบบจะไม่สนใจค่าจินตภาพของต้นทางหรือตั้งค่าจินตภาพของปลายทางเป็น 0 ตามลําดับ การแปลงของส่วนที่เป็นจำนวนจริงจะเป็นไปตามการแปลงทศนิยม
โดยหลักการแล้ว การดำเนินการนี้อาจแสดงการลดจำนวน (Conversion จาก Tensor ที่เล็กลงเป็น Tensor ปกติ) การแปลงปริมาณ (การแปลงจาก Tensor ปกติเป็น Tensor ที่ควอนไซส์) และการแปลงจำนวนใหม่ (การแปลงระหว่าง Tensor ที่เล็กลง) แต่ในตอนนี้เรามีการดำเนินการเฉพาะสำหรับ -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]
wherej[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 ที่แปลงค่าเป็นจำนวนเต็มต่อ 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 |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C2-C3), (C25) |
(I4) | padding |
ค่าคงที่เทนเซอร์ 2 มิติประเภท si64 |
(C4), (C25) |
(I5) | lhs_dilation |
ค่าคงที่ tensor ใน 1 มิติของประเภท si64 |
(C5-C6), (C25) |
(I6) | rhs_dilation |
ค่าคงที่เทนเซอร์ 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 |
ค่าคงที่เทนเซอร์ 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 |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C17-C18), (C25) |
(I14) | output_batch_dimension |
ค่าคงที่ของประเภท si64 |
(C20), (C25) |
(I15) | output_feature_dimension |
ค่าคงที่ประเภท si64 |
(C20), (C25), (C30) |
(I16) | output_spatial_dimensions |
ค่าคงที่เทนเซอร์ 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 |
จำนวนรายการแบบผันแปรของ DEFAULT , HIGH และ HIGHEST |
(C24) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor หรือ tensor แบบเชิงปริมาณ | (C25-C28), (C30), (C32-34) |
ข้อจำกัด
- (C1)
N = rank(lhs) = rank(rhs)
- (ค2)
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
- (ค7)
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
- หากการดำเนินการใช้เทนเซอร์ที่ไม่ผ่านการแปลงค่า ให้ทำดังนี้
- (C27)
element_type(lhs) = element_type(rhs) = element_type(result)
- (C27)
- หากการดำเนินการใช้เทนเซอร์ที่แปลงค่าเป็นจำนวนเต็ม ให้ทำดังนี้
- (C28)
is_quantized(lhs) = is_quantized(result) and is_quantized(rhs)
- (C29) ถ้า
is_per_axis_quantized(rhs)
ให้quantization_dimension(rhs) = kernel_output_feature_dimension
- (C30) หาก
is_per_axis_quantized(result)
ให้quantization_dimension(result) = output_feature_dimension
- ในกรณี
is_quantized(lhs)
- (C31)
storage_type(lhs) = storage_type(rhs)
- (C32)
expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
- (C33) ถ้า
is_per_tensor_quantized(rhs)
ให้is_per_tensor_quantized(result)
- ในกรณี
!is_quantized(lhs)
- (C34)
element_type(lhs) = expressed_type(rhs) = element_type(result)
- (C28)
ตัวอย่าง
// %lhs: [[
// [
// [1], [2], [5], [6]
// ],
// [
// [3], [4], [7], [8]
// ],
// [
// [10], [11], [14], [15]
// ],
// [
// [12], [13], [16], [17]
// ]
// ]]
//
// %rhs: [
// [[[1]], [[1]], [[1]]],
// [[[1]], [[1]], [[1]]],
// [[[1]], [[1]], [[1]]]
// ]
%result = "stablehlo.convolution"(%lhs, %rhs) {
window_strides = array<i64: 4, 4>,
padding = dense<0> : tensor<2x2xi64>,
lhs_dilation = array<i64: 2, 2>,
rhs_dilation = array<i64: 1, 1>,
window_reversal = array<i1: false, false>,
// In the StableHLO dialect, dimension numbers are encoded via:
// `[<input dimensions>]x[<kernel dimensions>]->[output dimensions]`.
// "b" is batch dimension, "f" is feature dimension,
// "i" is input feature dimension, "o" is output feature dimension,
// "0/1/etc" are spatial dimensions.
dimension_numbers = #stablehlo.conv<[b, 0, 1, f]x[0, 1, i, o]->[b, 0, 1, f]>,
batch_group_count = 1 : i64,
feature_group_count = 1 : i64,
precision_config = [#stablehlo<precision DEFAULT>, #stablehlo<precision DEFAULT>]
} : (tensor<1x4x4x1xi64>, tensor<3x3x1x1xi64>) -> tensor<1x2x2x1xi64>
// %result: [[
// [[10], [26]],
// [[46], [62]]
// ]]
โคไซน์
ความหมาย
ดำเนินการโคไซน์ตามองค์ประกอบบน tensor ของ operand
และสร้าง Tensor result
ทําสิ่งต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับตัวเลขทศนิยม:
cos
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: โคไซน์เชิงซ้อน
- สำหรับประเภทที่มีการแปลงเป็นจำนวนเต็ม:
dequantize_op_quantize(cosine, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
ข้อจำกัด
- (C1)
baseline_type(operand) = baseline_type(result)
ตัวอย่าง
// %operand: [
// [0.0, 1.57079632], // [0, pi/2]
// [3.14159265, 4.71238898] // [pi, 3pi/2]
// ]
%result = "stablehlo.cosine"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[1.0, 0.0], [-1.0, 0.0]]
count_leading_zeros
ความหมาย
นับจํานวนบิต 0 นําหน้าขององค์ประกอบในเทนเซอร์ operand
และสร้างเทนเซอร์ result
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทนเซอร์ประเภทจำนวนเต็ม | (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
และสร้างเทนเซอร์ result
ทําสิ่งต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สําหรับจํานวนเต็ม: การหารจํานวนเต็มซึ่งให้ผลหารพีชคณิตโดยทิ้งเศษส่วน
- สำหรับแบบลอย:
division
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: การหารจำนวนเชิงซ้อน
- สำหรับประเภทที่มีการแปลงค่าเป็นจำนวนเต็ม ให้ทำดังนี้
dequantize_op_quantize(divide, lhs, rhs, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
เทนเซอร์ประเภทจำนวนเต็ม ทศนิยม หรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
(I2) | rhs |
เทนเซอร์ประเภทจำนวนเต็ม ทศนิยม หรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภทจำนวนเต็ม ทศนิยม หรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (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 ออกเป็นคอมโพเนนต์หลายรายการ และดำเนินการ DOT "พื้นฐาน" หลายรายการกับค่าเหล่านั้น ซึ่งมักจะเป็นการจําลองความแม่นยําที่สูงขึ้น (เช่น การใช้ประโยชน์จากประเภทข้อมูลปัญญาประดิษฐ์ bfloat16 สําหรับการคํานวณที่มีความแม่นยําสูงขึ้น: BF16_6x tf32_3x ฯลฯ) สําหรับอัลกอริทึมที่ไม่มีการสลาย ให้ตั้งค่าเหล่านี้เป็น1
allow_imprecise_accumulation
เพื่อระบุว่าอนุญาตให้มีการสะสมที่ความแม่นยำต่ำกว่าในบางขั้นตอนหรือไม่ (เช่นCUBLASLT_MATMUL_DESC_FAST_ACCUM
)
ตัวอย่างแอตทริบิวต์ DotAlgorithm
// Inputs are casted to tf32, and then accumulated in f32:
{lhs_precision_type = tf32,
rhs_precision_type = tf32,
accumulation_type = f32,
lhs_component_count = 1,
rhs_component_count = 1,
num_primitive_operations = 1,
allow_imprecise_accumulation = false}
// bf16_6x: each input is decomposed to 3 bf16 components, then 6 dot operations are done on those components, and the result is accumulated in f32.
{lhs_precision_type = bf16,
rhs_precision_type = bf16,
accumulation_type = f32,
lhs_component_count = 3,
rhs_component_count = 3,
num_primitive_operations = 6,
allow_imprecise_accumulation = false}
// Inputs are (casted to) f8e5m2, and we accumulate in f32, but for some steps we may accumulate in lower precision.
{lhs_precision_type = f8e5m2,
rhs_precision_type = f8e5m2,
accumulation_type = f32,
lhs_component_count = 1,
rhs_component_count = 1,
num_primitive_operations = 1,
allow_imprecise_accumulation = true}
ขึ้นอยู่กับการติดตั้งใช้งานว่าจะรองรับชุดค่าผสมใด โดยทั่วไปแล้ว เราไม่รับประกันว่าผู้ใช้ StableHLO จะรองรับอัลกอริทึมแต่ละรายการในประเภทเร่งความเร็วแต่ละประเภท หากระบบไม่รองรับอัลกอริทึมหนึ่งๆ ก็ควรแสดงข้อผิดพลาดแทนที่จะเปลี่ยนไปใช้อัลกอริทึมอื่น การยืนยัน StableHLO จะดำเนินการยืนยันอย่างดีที่สุดเพื่อไม่ให้อัลกอริทึมที่ไม่ทราบว่ามีการใช้งานในฮาร์ดแวร์ใดๆ
โปรดดูค่าอัลกอริทึมที่รองรับบางค่าใน xla_data.proto > Algorithm
ตั๋ว #2483 บันทึกแผนการสร้างเอกสารแบบรวมศูนย์เกี่ยวกับอัลกอริทึมที่รองรับโดยแบ็กเอนด์
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C5-C6), (C9-C10), (C12-C14), (C17-C18), (C20) |
(I2) | rhs |
เทนเซอร์หรือเทนเซอร์ที่ผ่านการแปลงค่าเป็นจำนวนเต็ม | (C7-C10), (C12-C20) |
(I3) | lhs_batching_dimensions |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C1), (C3), (C5), (C9), (C12) |
(I4) | rhs_batching_dimensions |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C1), (C4), (C7), (C9) |
(I5) | lhs_contracting_dimensions |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C2), (C3), (C6), (C10) |
(I6) | rhs_contracting_dimensions |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C2), (C4), (C8), (C10), (C16) |
(I7) | precision_config |
จำนวนรายการแบบผันแปรของ 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 |
เทนเซอร์หรือเทนเซอร์ที่ผ่านการแปลงค่าเป็นจำนวนเต็ม | (C12), (C14), (C18-C20) |
ข้อจำกัด
- (C1)
size(lhs_batching_dimensions) = size(rhs_batching_dimensions)
- (ค2)
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)
- (ค7)
0 <= rhs_batching_dimensions < rank(rhs)
- (C8)
0 <= rhs_contracting_dimensions < rank(rhs)
- (C9)
dim(lhs, lhs_batching_dimensions...) = dim(rhs, rhs_batching_dimensions...)
- (C10)
dim(lhs, lhs_contracting_dimensions...) = dim(rhs, rhs_contracting_dimensions...)
- (C11)
size(precision_config) = 2
- (C12)
shape(result) = dim(lhs, lhs_batching_dimensions) + dim(lhs, lhs_result_dimensions) + dim(rhs, rhs_result_dimensions)
- หากการดำเนินการใช้เทนเซอร์ที่ไม่ผ่านการแปลงค่า ให้ทำดังนี้
- (C13)
element_type(lhs) = element_type(rhs)
- (C13)
- หากการดำเนินการใช้เทนเซอร์ที่แปลงค่าเป็นจำนวนเต็ม ให้ทำดังนี้
- (C14)
is_quantized(lhs) = is_quantized(result) and is_quantized(rhs)
- (C15)
zero_points(rhs) = 0
- (C16) หากเป็น
is_per_axis_quantized(rhs)
แสดงว่าquantization_dimension(rhs)
ไม่ใช่ในrhs_contracting_dimensions
- ในกรณี
is_quantized(lhs)
- (C17)
storage_type(lhs) = storage_type(rhs)
- (C18)
expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
- (C19) ถ้า
is_per_tensor_quantized(rhs)
ให้is_per_tensor_quantized(result)
- ในกรณี
!is_quantized(lhs)
- (C20)
element_type(lhs) = expressed_type(rhs) = element_type(result)
- (C14)
- หาก
!is_empty_algorithm(lhs_precision_type, rhs_precision_type, accumulation_type, lhs_component_count, rhs_component_count, num_primitive_operations allow_imprecise_accumulation)
- (C21)
precision_config... = DEFAULT
- (C22)
0 < lhs_component_count
- (C23)
0 < rhs_component_count
- (C24)
0 < num_primitive_operations
- (C21)
ตัวอย่าง
// %lhs: [
// [[1, 2],
// [3, 4]],
// [[5, 6],
// [7, 8]]
// ]
// %rhs: [
// [[1, 0],
// [0, 1]],
// [[1, 0],
// [0, 1]]
// ]
%result = "stablehlo.dot_general"(%lhs, %rhs) {
dot_dimension_numbers = #stablehlo.dot<
lhs_batching_dimensions = [0],
rhs_batching_dimensions = [0],
lhs_contracting_dimensions = [2],
rhs_contracting_dimensions = [1]
>,
precision_config = [#stablehlo<precision DEFAULT>, #stablehlo<precision DEFAULT>],
algorithm = #stablehlo.dot_algorithm<
lhs_precision_type = tf32,
rhs_precision_type = tf32,
accumulation_type = f32,
lhs_component_count = 1,
rhs_component_count = 1,
num_primitive_operations = 1,
allow_imprecise_accumulation = false
>
} : (tensor<2x2x2xi64>, tensor<2x2x2xi64>) -> tensor<2x2x2xi64>
// %result: [
// [[1, 2],
// [3, 4]],
// [[5, 6],
// [7, 8]]
// ]
dynamic_broadcast_in_dim
ความหมาย
การดำเนินการนี้มีฟังก์ชันการทำงานเหมือนกับ broadcast_in_dimop แต่จะมีการระบุรูปแบบผลลัพธ์แบบไดนามิกผ่าน output_dimensions
นอกจากนี้ การดำเนินการยังยอมรับแอตทริบิวต์ที่ไม่บังคับ known_expanding_dimensions
, known_nonexpanding_dimensions
เพื่อแสดงความรู้แบบคงที่เกี่ยวกับลักษณะการขยายตัวของมิติข้อมูล
หากไม่ได้ระบุ ระบบจะถือว่ามิติข้อมูลทั้งหมดอาจขยาย
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทนเซอร์หรือเทนเซอร์ที่ผ่านการแปลงค่าเป็นจำนวนเต็ม | (C1-C2), (C5-C6), (C9) |
(I2) | output_dimensions |
เทนเซอร์ 1 มิติประเภทจำนวนเต็ม | (C7) |
(I3) | broadcast_dimensions |
เทนเซอร์ค่าคงที่ 1 มิติของประเภทจำนวนเต็ม | (C2-C6) |
(I4) | known_expanding_dimensions |
เทนเซอร์ค่าคงที่ 1 มิติของประเภทจำนวนเต็ม | (C8-C9) |
(I5) | known_nonexpanding_dimensions |
เทนเซอร์ค่าคงที่ 1 มิติของประเภทจำนวนเต็ม | (C8-C9) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์หรือเทนเซอร์ที่ผ่านการแปลงค่าเป็นจำนวนเต็ม | (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)
ตามลำดับ
- (ค2)
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_nonexpanding_dimensions)
- (C9)
0 <= known_expanding_dimensions < rank(operand)
- (C10)
0 <= known_nonexpanding_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_nonexpanding_dimensions = array<i64: 1>
} : (tensor<1x3xi64>, tensor<3xi64>) -> tensor<2x3x2xi64>
// %result: [
// [
// [1, 1],
// [2, 2],
// [3, 3]
// ],
// [
// [1, 1],
// [2, 2],
// [3, 3]
// ]
// ]
dynamic_conv
ความหมาย
การดำเนินการนี้มีฟังก์ชันการทำงานเหมือนกับ convolution op แต่จะมีการระบุการเติมข้อมูลแบบไดนามิกผ่าน padding
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
tensor หรือต่อ tensor ในการปรับปริมาณ | (C1), (C10-C11), (C14) (C25), (C26-C27), (C30-C31), (C33) |
(I2) | rhs |
เทนเซอร์หรือเทนเซอร์ที่ผ่านการแปลงค่าเป็นจำนวนเต็ม | (C1), (C14-C16), (C26-C28), (C30-C33) |
(I3) | padding |
เทนเซอร์ 2 มิติประเภทจำนวนเต็ม | (C4) |
(I4) | window_strides |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C2-C3) |
(I5) | lhs_dilation |
ค่าคงที่ tensor ใน 1 มิติของประเภท si64 |
(C5-C6) |
(I6) | rhs_dilation |
ค่าคงที่เทนเซอร์ 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 |
ค่าคงที่เทนเซอร์ 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 |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C17-C18) |
(I14) | output_batch_dimension |
ค่าคงที่ประเภท si64 |
(C20) |
(I15) | output_feature_dimension |
ค่าคงที่ประเภท si64 |
(C20), (C29) |
(I16) | output_spatial_dimensions |
ค่าคงที่เทนเซอร์ 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 |
จำนวนรายการแบบผันแปรของ DEFAULT , HIGH และ HIGHEST |
(C24) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์หรือเทนเซอร์ที่ผ่านการแปลงค่าเป็นจำนวนเต็ม | (C25-C27), (C29), (C31-C33) |
ข้อจำกัด
- (C1)
N = rank(lhs) = rank(rhs)
- (ค2)
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
- (ค7)
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
- หากการดำเนินการใช้เทนเซอร์ที่ไม่ผ่านการแปลงค่า ให้ทำดังนี้
- (C27)
element_type(lhs) = element_type(rhs) = element_type(result)
- (C27)
- หากการดำเนินการใช้เทนเซอร์ที่แปลงค่าเป็นจำนวนเต็ม ให้ทำดังนี้
- (C28)
is_quantized(lhs) = is_quantized(result) and is_quantized(rhs)
- (C29) ถ้า
is_per_axis_quantized(rhs)
ให้quantization_dimension(rhs) = kernel_output_feature_dimension
- (C30) หาก
is_per_axis_quantized(result)
ให้quantization_dimension(result) = output_feature_dimension
- ในกรณี
is_quantized(lhs)
- (C31)
storage_type(lhs) = storage_type(rhs)
- (C32)
expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
- (C33) ถ้า
is_per_tensor_quantized(rhs)
ให้is_per_tensor_quantized(result)
- ในกรณี
!is_quantized(lhs)
- (C34)
element_type(lhs) = expressed_type(rhs) = element_type(result)
- (C28)
ตัวอย่าง
// %lhs: [[
// [[1], [2], [5], [6]],
// [[3], [4], [7], [8]],
// [[10], [11], [14], [15]],
// [[12], [13], [16], [17]]
// ]]
//
// %rhs: [
// [[[1]], [[1]], [[1]]],
// [[[1]], [[1]], [[1]]],
// [[[1]], [[1]], [[1]]]
// ]
// %padding: [[1, 1],
// [1, 1]]
%result = "stablehlo.dynamic_conv"(%lhs, %rhs, %padding) {
window_strides = array<i64: 4, 4>,
lhs_dilation = array<i64: 2, 2>,
rhs_dilation = array<i64: 1, 1>,
window_reversal = array<i1: false, false>,
dimension_numbers = #stablehlo.conv<raw
input_batch_dimension = 0,
input_feature_dimension = 3,
input_spatial_dimensions = [0, 1],
kernel_input_feature_dimension = 2,
kernel_output_feature_dimension = 3,
kernel_spatial_dimensions = [0, 1],
output_batch_dimension = 0,
output_feature_dimension = 3,
output_spatial_dimensions = [1, 2]
>,
feature_group_count = 1 : i64,
batch_group_count = 1 : i64,
precision_config = [#stablehlo<precision DEFAULT>, #stablehlo<precision DEFAULT>]
} : (tensor<1x4x4x1xi64>, tensor<3x3x1x1xi64>, tensor<2x2xi64>) -> tensor<1x2x2x1xi64>
// %result: [[
// [[1], [5]],
// [[10], [14]]
// ]]
dynamic_gather
ความหมาย
การดำเนินการนี้มีฟังก์ชันการทำงานเหมือนกับ gather op โดยที่ slice_sizes
จะระบุเป็นค่าแบบไดนามิก
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C1), (C7), (C10-C12), (C14) |
(I2) | start_indices |
เทนเซอร์ประเภทจำนวนเต็ม | (C2), (C3), (C13) |
(I3) | slice_sizes |
เทนเซอร์ 1 มิติประเภทจำนวนเต็ม | (C8), (C11-C13) |
(I4) | offset_dims |
ค่าคงที่ tensor ใน 1 มิติของประเภท si64 |
(C1), (C4-C5), (C13) |
(I5) | collapsed_slice_dims |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C1), (C6-C8), (C13) |
(I6) | start_index_map |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C3), (C9), (C10) |
(I7) | index_vector_dim |
ค่าคงที่ของประเภท si64 |
(C2), (C3), (C13) |
(I8) | indices_are_sorted |
ค่าคงที่ประเภท i1 |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C5), (C13-C14) |
ข้อจำกัด
- (C1)
rank(operand) = size(offset_dims) + size(collapsed_slice_dims)
- (ค2)
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)
- (ค7)
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 |
เทนเซอร์ 1 มิติประเภทจำนวนเต็ม | (C1), (C2) |
(I2) | iota_dimension |
si64 |
(C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภทจำนวนเต็ม ทศนิยม หรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C2) |
ข้อจำกัด
- (C1)
0 <= iota_dimension < size(output_shape)
- (ค2)
rank(result) = size(output_shape)
ตัวอย่าง
%output_shape = stablehlo.constant dense<[4, 5]> : tensor<2xi64>
%result = "stablehlo.dynamic_iota"(%output_shape) {
iota_dimension = 0 : i64
} : (tensor<2xi64>) -> tensor<4x5xi64>
// %result: [
// [0, 0, 0, 0, 0],
// [1, 1, 1, 1, 1],
// [2, 2, 2, 2, 2],
// [3, 3, 3, 3, 3]
// ]
dynamic_pad
ความหมาย
การดำเนินการนี้มีฟังก์ชันการทำงานเหมือนกับการดำเนินการ pad แต่มีการระบุ edge_padding_low
, edge_padding_high
และ interior_padding
เป็นค่าแบบไดนามิก
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือต่อ tensor ในการปรับปริมาณ | (C1), (C2), (C4) |
(I2) | padding_value |
เทนเซอร์ 0 มิติหรือเทนเซอร์ที่แปลงค่าเป็นจำนวนเต็มต่อเทนเซอร์ | (C1) |
(I3) | edge_padding_low |
เทนเซอร์ 1 มิติประเภทจำนวนเต็ม | (C1), (C4) |
(I4) | edge_padding_high |
เทนเซอร์ 1 มิติประเภทจำนวนเต็ม | (C1), (C4) |
(I5) | interior_padding |
เทนเซอร์ 1 มิติประเภทจำนวนเต็ม | (C2-C4) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C3-C6) |
ข้อจำกัด
- (C1)
element_type(operand) = element_type(padding_value) = element_type(result)
- (C2)
size(edge_padding_low) = size(edge_padding_high) = size(interior_padding) = rank(operand)
- (C3)
0 <= interior_padding
- (C4)
shape(result) = shape(operand) + edge_padding_low + max(shape(operand) - 1, 0) * interior_padding + edge_padding_high
ตัวอย่าง
// %operand: [
// [1, 2, 3],
// [4, 5, 6]
// ]
// %padding_value: 0
// %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
อรรถศาสตร์
การดำเนินการนี้มีฟังก์ชันการทำงานเหมือนกับ reshape แต่จะมีการระบุรูปแบบผลลัพธ์แบบไดนามิกผ่าน output_shape
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือ tensor แบบเชิงปริมาณ | (C1-C3) |
(I2) | output_shape |
เทนเซอร์ 1 มิติประเภทจำนวนเต็ม | (C4) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์หรือเทนเซอร์ที่ผ่านการแปลงค่าเป็นจำนวนเต็ม | (C1-C4) |
ข้อจำกัด
- (C1)
element_type(result)
คำนวณจากข้อมูลต่อไปนี้element_type(operand)
หาก!is_per_axis_quantized(operand)
element_type(operand)
ยกเว้นว่าquantization_dimension(operand)
และquantization_dimension(result)
อาจแตกต่างกัน
- (ค2)
size(operand) = size(result)
- (C3) หาก
is_per_axis_quantized(operand)
reduce(dims(operand, [0, 1, ..., quantization_dimension(operand) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y) = reduce(dims(result, [0, 1, ..., quantization_dimension(result) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y)
dim(operand, quantization_dimension(operand)) = dim(result, quantization_dimension(result))
reduce(dims(operand, [quantization_dimension(operand) + 1, ..., rank(operand) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y) = reduce(dims(result, [quantization_dimension(result) + 1, ..., rank(result) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y)
- (C4)
size(output_shape) = rank(result)
ตัวอย่าง
// %operand: [[1, 2, 3], [4, 5, 6]]
// %output_shape: [3, 2]
%result = "stablehlo.dynamic_reshape"(%operand, %output_shape) : (tensor<2x3xi64>, tensor<2xi64>) -> tensor<3x2xi64>
// %result: [[1, 2], [3, 4], [5, 6]]
dynamic_slice
อรรถศาสตร์
ดึงข้อมูลส่วนจาก operand
โดยใช้ดัชนีเริ่มต้นที่คำนวณแบบไดนามิก และสร้างเทนเซอร์ result
start_indices
มีดัชนีเริ่มต้นของส่วนสำหรับมิติข้อมูลแต่ละรายการซึ่งอาจมีการปรับ และ slice_sizes
มีขนาดของส่วนสำหรับมิติข้อมูลแต่ละรายการ ในรูปแบบที่เป็นทางการ
result[result_index] = operand[operand_index]
โดยที่
adjusted_start_indices = clamp(0, start_indices, shape(operand) - slice_sizes)
operand_index = adjusted_start_indices + result_index
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือต่อ tensor ในการปรับปริมาณ | (C1), (C2), (C4) |
(I2) | start_indices |
จำนวนแปรผันของ tenor ที่เป็น 0 มิติของประเภทจำนวนเต็ม | (C2), (C3) |
(I3) | slice_sizes |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C2), (C4), (C5) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C1), (C5) |
ข้อจำกัด
- (C1)
element_type(operand) = element_type(result)
- (ค2)
size(start_indices) = size(slice_sizes) = rank(operand)
- (C3)
same(type(start_indices...))
- (C4)
0 <= slice_sizes <= shape(operand)
- (C5)
shape(result) = slice_sizes
ตัวอย่าง
// %operand: [
// [0, 0, 1, 1],
// [0, 0, 1, 1],
// [0, 0, 0, 0],
// [0, 0, 0, 0]
// ]
// %start_indices0: -1
// %start_indices1: 3
%result = "stablehlo.dynamic_slice"(%operand, %start_indices0, %start_indices1) {
slice_sizes = array<i64: 2, 2>
} : (tensor<4x4xi32>, tensor<i64>, tensor<i64>) -> tensor<2x2xi32>
// %result: [
// [1, 1],
// [1, 1]
// ]
dynamic_update_slice
ความหมาย
สร้างเทนเซอร์ result
ที่เท่ากับเทนเซอร์ operand
ยกเว้นว่าจะมีการอัปเดตส่วนเริ่มต้นที่ start_indices
ด้วยค่าใน update
result[result_index]
มีคำจำกัดความอย่างเป็นทางการดังนี้
update[update_index]
if0 <= update_index < shape(update)
where: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 ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C1-C4), (C6) |
(I2) | update |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C2), (C3), (C6) |
(I3) | start_indices |
จำนวนแปรผันของ tenor ที่เป็น 0 มิติของประเภทจำนวนเต็ม | (C4), (C5) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C1) |
ข้อจำกัด
- (C1)
type(operand) = type(result)
- (C2)
element_type(update) = element_type(operand)
- (C3)
rank(update) = rank(operand)
- (C4)
size(start_indices) = rank(operand)
- (C5)
same(type(start_indices...))
- (C6)
0 <= shape(update) <= shape(operand)
ตัวอย่าง
// %operand: [
// [1, 1, 0, 0],
// [1, 1, 0, 0],
// [1, 1, 1, 1],
// [1, 1, 1, 1]
// ]
// %update: [
// [1, 1],
// [1, 1]
// ]
// %start_indices0: -1
// %start_indices1: 3
%result = "stablehlo.dynamic_update_slice"(%operand, %update, %start_indices0, %start_indices1)
: (tensor<4x4xi32>, tensor<2x2xi32>, tensor<i64>, tensor<i64>) -> tensor<4x4xi32>
// %result: [
// [1, 1, 1, 1],
// [1, 1, 1, 1],
// [1, 1, 1, 1],
// [1, 1, 1, 1]
// ]
เลขชี้กำลัง
ความหมาย
ดำเนินการเลขชี้กำลังทีละองค์ประกอบกับเทนเซอร์ operand
และสร้างเทนเซอร์ result
ทําสิ่งต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับตัวเลขทศนิยม:
exp
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: รูปยกกำลังเชิงซ้อน
- สําหรับประเภทที่มีการแปลงค่าเป็นจำนวนเต็ม ให้ใช้รูปแบบต่อไปนี้
dequantize_op_quantize(exponential, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (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 ตามองค์ประกอบในเทนเซอร์ operand
และสร้างเทนเซอร์ result
ทําสิ่งต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับตัวเลขทศนิยม:
expm1
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: เลขยกกำลังลบด้วย 1
- สําหรับประเภทที่มีการแปลงค่าเป็นจำนวนเต็ม ให้ใช้รูปแบบต่อไปนี้
dequantize_op_quantize(exponential_minus_one, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (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
ซึ่งนำ Tensor 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
ซึ่งรับเทนเซอร์ 1 มิติประเภทเลขทศนิยม จะสร้างเทนเซอร์ 1 มิติประเภทเชิงซ้อนที่มีความหมายแบบเลขทศนิยมเดียวกันและทํางานดังนี้
rfft(real_operand) = truncated_result
wherecomplex_operand... = (real_operand..., 0.0)
complex_result = fft(complex_operand)
truncated_result = complex_result[:(rank(complex_result) / 2 + 1)]
(เมื่อคำนวณการแปลง Fourier แบบไม่ต่อเนื่องสำหรับตัวดำเนินการจริง องค์ประกอบ N/2 + 1
แรกของผลลัพธ์จะกำหนดผลลัพธ์ที่เหลืออย่างชัดเจน ดังนั้นระบบจะตัดผลลัพธ์ของ rfft
ให้สั้นลงเพื่อหลีกเลี่ยงการคำนวณองค์ประกอบที่ซ้ำกัน)
สำหรับ fft_type = RFFT
result
หมายถึงผลลัพธ์สุดท้ายของชุดการคํานวณ L ที่ L = size(fft_length)
ตัวอย่างเช่น สำหรับ L = 3
result1[i0, ..., :] = rfft(operand[i0, ..., :])
result2[i0, ..., :, iR-1] = fft(result1[i0, ..., :, iR-1])
result[i0, ..., :, iR-2, iR-1] = fft(result2[i0, ..., :, iR-2, iR-1])
สุดท้ายนี้ ฟังก์ชัน irfft
ซึ่งมีลายเซ็นประเภทเดียวกันและคำนวณผลผกผันของ rfft
สําหรับ fft_type = IRFFT
ระบบจะกําหนด result
เป็นค่าผกผันของการคํานวณสําหรับ fft_type = RFFT
เช่น สำหรับ L = 3
result1[i0, ..., :, iR-2, iR-1] = ifft(operand[i0, ..., :, iR-2, iR-1])
result2[i0, ..., :, iR-1] = ifft(result1[i0, ..., :, iR-1])
result[i0, ..., :] = irfft(result2[i0, ..., :])
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทนเซอร์ประเภทจุดลอยตัวหรือประเภทคอมเพล็กซ์ | (C1), (C2), (C4), (C5) |
(I2) | fft_type |
enum ของ FFT , IFFT , RFFT และ IRFFT |
(C2), (C5) |
(I3) | fft_length |
ค่าคงที่เทนเซอร์ 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
ของประเภทจุดลอยตัว 1 ค่าแล้วshape(real)[-size(fft_length):] = fft_length
- (C5)
shape(result) = shape(operand)
ยกเว้น- หาก
fft_type = RFFT
dim(result, -1) = dim(operand, -1) = 0 ? 0 : dim(operand, -1) / 2 + 1
- หากเป็น
fft_type = IRFFT
dim(operand, -1) = dim(result, -1) = 0 ? 0 : dim(result, -1) / 2 + 1
- หาก
ตัวอย่าง
// %operand: [(1.0, 0.0), (0.0, 0.0), (0.0, 0.0), (0.0, 0.0)]
%result = "stablehlo.fft"(%operand) {
fft_type = #stablehlo<fft_type FFT>,
fft_length = array<i64: 4>
} : (tensor<4xcomplex<f32>>) -> tensor<4xcomplex<f32>>
// %result: [(1.0, 0.0), (1.0, 0.0), (1.0, 0.0), (1.0, 0.0)]
ชั้น
ความหมาย
ดำเนินการปัดเศษตามองค์ประกอบของเทนเซอร์ operand
และสร้างเทนเซอร์ result
ใช้การดำเนินการ 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]
รวบรวม
อรรถศาสตร์
รวบรวมส่วนต่างๆ จากเทนเซอร์ operand
จากออฟเซตที่ระบุใน start_indices
และสร้างเทนเซอร์ result
แผนภาพต่อไปนี้แสดงวิธีที่องค์ประกอบใน result
แมปกับองค์ประกอบใน operand
โดยใช้ตัวอย่างที่เป็นรูปธรรม แผนภาพจะเลือกresult
ตัวอย่างดัชนี 2-3 รายการ และอธิบายรายละเอียดว่าดัชนี operand
ใดที่สอดคล้องกับดัชนีนั้น
เขียนเป็นทางการคือ result[result_index] = operand[operand_index]
โดยที่
batch_dims = [d for d in axes(result) and d not in offset_dims]
batch_index = result_index[batch_dims...]
start_index
หมายถึงstart_indices[bi0, ..., :, ..., biN]
โดยที่bi
คือองค์ประกอบแต่ละรายการในbatch_index
และ:
มีการแทรกที่ดัชนีindex_vector_dim
หากindex_vector_dim
<rank(start_indices)
[start_indices[batch_index]]
ในกรณีอื่น
- สำหรับ
d_operand
ในaxes(operand)
full_start_index[d_operand] = clamp(start_index[d_start], 0, dim(operand, d_operand) - slice_sizes[d_operand])
ifd_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)]
ifd_operand = operand_batching_dims[i_batching]
andd_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 ที่แปลงค่าเป็นจำนวนเต็มต่อ 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 |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C1), (C6-C9), (C22) |
(I5) | operand_batching_dims |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C1), (C6), (C10-C12), (C16-C18), (C22) |
(I6) | start_indices_batching_dims |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C13-C17) |
(I7) | start_index_map |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C3), (C18-C19) |
(I8) | index_vector_dim |
ค่าคงที่ประเภท si64 |
(C2-C3), (C15), (C22) |
(I9) | slice_sizes |
ค่าคงที่เทนเซอร์ 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)
- (ค2)
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))
- (ค7)
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)
where: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)
ความหมายเกี่ยวข้องกับองค์ประกอบ
รูปร่างของประเภทเท่านั้น element-type อาจเป็นอะไรก็ได้
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือ tensor แบบเชิงปริมาณ | (C1) |
(I2) | dimension |
ค่าคงที่ประเภท si64 |
(C1) |
เอาต์พุต
ชื่อ | ประเภท |
---|---|
result |
เทนเซอร์ 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)
- (ค2)
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
เพียง 1 รายการเท่านั้น โดยขึ้นอยู่กับค่าของ pred
หรือจะเรียกอย่างเป็นทางการว่า result =
pred ? true_branch() : false_branch()
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | pred |
เทนเซอร์ 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) = []
- (ค2)
output_types(true_branch) = output_types(false_branch)
- (C3)
type(results...) = output_types(true_branch)
ตัวอย่าง
// %result_true_branch: 10
// %result_false_branch: 11
// %pred: true
%result = "stablehlo.if"(%pred) ({
"stablehlo.return"(%result_true_branch) : (tensor<i32>) -> ()
}, {
"stablehlo.return"(%result_false_branch) : (tensor<i32>) -> ()
}) : (tensor<i1>) -> tensor<i32>
// %result: 10
imag
ความหมาย
ดึงข้อมูลส่วนจินตภาพทีละองค์ประกอบจาก operand
และสร้างเทนเซอร์ result
เขียนอย่างเป็นทางการมากขึ้นสำหรับองค์ประกอบ x
แต่ละรายการ ดังนี้
imag(x) = is_complex(x) ? imaginary_part(x) :
constant(0, element_type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทนเซอร์ประเภทจุดลอยตัวหรือประเภทคอมเพล็กซ์ | (C1), (C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภทจุดลอยตัว | (C1), (C2) |
ข้อจำกัด
- (C1)
shape(result) = shape(operand)
- (C2)
element_type(result)
มีความหมายดังต่อไปนี้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 |
จำนวนเทนเซอร์ เทนเซอร์ที่แปลงเป็นจำนวนจริง หรือโทเค็นแบบผันแปร | (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
ความหมาย
เติมค่าในเทนเซอร์ 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 |
เทนเซอร์ประเภทจำนวนเต็ม ทศนิยม หรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
ข้อจำกัด
- (C1)
0 <= iota_dimension < rank(output)
ตัวอย่าง
%output = "stablehlo.iota"() {
iota_dimension = 0 : i64
} : () -> tensor<4x5xi32>
// %output: [
// [0, 0, 0, 0, 0],
// [1, 1, 1, 1, 1],
// [2, 2, 2, 2, 2],
// [3, 3, 3, 3, 3]
// ]
%output = "stablehlo.iota"() {
iota_dimension = 1 : i64
} : () -> tensor<4x5xi32>
// %output: [
// [0, 1, 2, 3, 4],
// [0, 1, 2, 3, 4],
// [0, 1, 2, 3, 4],
// [0, 1, 2, 3, 4]
// ]
is_finite
ความหมาย
ดำเนินการตรวจสอบทีละองค์ประกอบว่าค่าใน x
เป็นจำนวนจำกัดหรือไม่ (กล่าวคือ ไม่ใช่ +Inf, -Inf หรือ NaN) และสร้างเทนเซอร์ y
ใช้การดำเนินการ isFinite
จากข้อกำหนด IEEE-754 สําหรับประเภทที่มีการแปลงค่าเป็นจำนวนเต็ม ผลลัพธ์จะเป็น true
เสมอ
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | x |
tensor ของประเภทจุดลอยตัวหรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
y |
เทนเซอร์ประเภทบูลีน | (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
และสร้าง Tensor result
ทําสิ่งต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับแบบลอย:
log
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: ลอการิทึมเชิงซ้อน
- สำหรับประเภทที่มีการแปลงเป็นจำนวนเต็ม:
dequantize_op_quantize(log, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
ข้อจำกัด
- (C1)
baseline_type(operand) = baseline_type(result)
ตัวอย่าง
// %operand: [[1.0, 2.0], [3.0, 4.0]]
%result = "stablehlo.log"(%operand) : (tensor<2x2xf64>) -> tensor<2x2xf64>
// %result: [[0.0, 0.69314718055994529], [1.0986122886681098, 1.3862943611198906]]
log_plus_one
ความหมาย
ดำเนินการลอการิทึมตามองค์ประกอบบวก 1 รายการในเทนเซอร์ operand
และสร้างเทนเซอร์ result
ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับตัวเลขทศนิยม:
logp1
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: ลอการิทึมเชิงซ้อนบวก 1
- สําหรับประเภทที่มีการแปลงค่าเป็นจำนวนเต็ม ให้ใช้รูปแบบต่อไปนี้
dequantize_op_quantize(log_plus_one, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
ข้อจำกัด
- (C1)
baseline_type(operand) = baseline_type(result)
ตัวอย่าง
// %operand: [0.0, -0.999, 7.0, 6.38905621, 15.0]
%result = "stablehlo.log_plus_one"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// %result: [0.0, -6.90776825, 2.07944155, 2.0, 2.77258873]
โลจิสติกส์
อรรถศาสตร์
ดำเนินการโลจิสติกส์ตามองค์ประกอบบน tensor ของ operand
และสร้าง Tensor result
ทําสิ่งต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับแบบลอย:
division(1, addition(1, exp(-x)))
จาก IEEE-754 - สําหรับจํานวนเชิงซ้อน: ลอจิสติกเชิงซ้อน
- สําหรับประเภทที่มีการแปลงค่าเป็นจำนวนเต็ม ให้ใช้รูปแบบต่อไปนี้
dequantize_op_quantize(logistic, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (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
และสร้างเทนเซอร์ result
หรือจะเรียกอย่างเป็นทางการว่า result[result_index] = computation(inputs...[result_index])
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | inputs |
จำนวนเทนเซอร์แบบผันแปรหรือเทนเซอร์ที่แปลงค่าต่อเทนเซอร์ | (C1-C4) |
(I2) | dimensions |
ค่าคงที่ tensor ใน 1 มิติของประเภท si64 |
(C3) |
(I3) | computation |
ฟังก์ชัน | (C4) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C1), (C4) |
ข้อจำกัด
- (C1)
shape(inputs...) = shape(result)
- (ค2)
0 < size(inputs) = N
- (C3)
dimensions = range(rank(inputs[0]))
- (C4)
computation
มีประเภท(tensor<E0>, ..., tensor<EN-1>) -> tensor<E'>
โดยที่Ei = element_type(inputs[i])
และE' = element_type(result)
ตัวอย่าง
// %input0: [[0, 1], [2, 3]]
// %input1: [[4, 5], [6, 7]]
%result = "stablehlo.map"(%input0, %input1) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = stablehlo.multiply %arg0, %arg1 : tensor<i64>
stablehlo.return %0 : tensor<i64>
}) {
dimensions = array<i64: 0, 1>
} : (tensor<2x2xi64>, tensor<2x2xi64>) -> tensor<2x2xi64>
// %result: [[0, 5], [12, 21]]
สูงสุด
ความหมาย
ดำเนินการตามองค์ประกอบสูงสุดกับเทนเซอร์ lhs
และ rhs
และสร้างเทนเซอร์ result
ทําสิ่งต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สําหรับบูลีน: OR เชิงตรรกะ
- สําหรับจํานวนเต็ม: จํานวนเต็มสูงสุด
- สำหรับแบบลอย:
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 ที่แปลงค่าเป็นจำนวนเต็มต่อ 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]]
ขั้นต่ำ
อรรถศาสตร์
ดำเนินการขั้นต่ำแบบองค์ประกอบต่อองค์ประกอบกับเทนเซอร์ lhs
และ rhs
และสร้างเทนเซอร์ result
ทําสิ่งต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สําหรับบูลีน: AND เชิงตรรกะ
- สําหรับจํานวนเต็ม: จํานวนเต็มขั้นต่ำ
- สำหรับตัวเลขทศนิยม:
minimum
จาก IEEE-754 - สำหรับจํานวนเชิงซ้อน: น้อยที่สุดตามลําดับตัวอักษรสําหรับคู่
(real, imaginary)
การกำหนดลําดับสำหรับจํานวนเชิงซ้อนเกี่ยวข้องกับความหมายที่แปลกประหลาด ดังนั้นในอนาคตเราจึงวางแผนที่จะยกเลิกการรองรับจํานวนเชิงซ้อนสําหรับการดำเนินการนี้ (#560) - สำหรับประเภทที่เล็กลง
dequantize_op_quantize(minimum, lhs, rhs, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
tensor หรือต่อ tensor ในการปรับปริมาณ | (C1) |
(I2) | rhs |
tensor หรือต่อ tensor ในการปรับปริมาณ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ 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 รายการ lhs
และ rhs
และสร้างเทนเซอร์ result
ทําสิ่งต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สําหรับบูลีน: AND เชิงตรรกะ
- สําหรับจํานวนเต็ม: การคูณจํานวนเต็ม
- สำหรับแบบลอย:
multiplication
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: การคูณเชิงซ้อน
- สำหรับประเภทที่มีการแปลงค่าเป็นจำนวนเต็ม ให้ทำดังนี้
dequantize_op_quantize(multiply, lhs, rhs, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
tensor หรือต่อ tensor ในการปรับปริมาณ | (C1) |
(I2) | rhs |
tensor หรือต่อ tensor ในการปรับปริมาณ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ 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
และสร้างเทนเซอร์ result
ทําสิ่งต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สําหรับจํานวนเต็มที่มีเครื่องหมาย: การปฏิเสธจํานวนเต็ม
- สําหรับจํานวนเต็มแบบไม่มีเครื่องหมาย: บิตแคสต์เป็นจํานวนเต็มแบบมีเครื่องหมาย การปฏิเสธจํานวนเต็ม บิตแคสต์กลับเป็นจํานวนเต็มแบบไม่มีเครื่องหมาย
- สำหรับตัวเลขทศนิยม:
negate
จาก IEEE-754 - สําหรับจํานวนเชิงซ้อน: การปฏิเสธเชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(negate, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทนเซอร์ประเภทจำนวนเต็ม ทศนิยม หรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภทจำนวนเต็ม ทศนิยม หรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (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
- สำหรับจำนวนเต็ม: Bitwise 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 รายการ lhs
และ rhs
และสร้างเทนเซอร์ result
ทําสิ่งต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สําหรับบูลีน: OR เชิงตรรกะ
- สําหรับจํานวนเต็ม: บิตไวส์ OR
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
เทนเซอร์ประเภทจำนวนเต็มหรือบูลีน | (C1) |
(I2) | rhs |
เทนเซอร์ประเภทจำนวนเต็มหรือบูลีน | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภทจำนวนเต็มหรือบูลีน | (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]]
Outfeed
ความหมาย
เขียน inputs
ไปยังเอาต์ฟีดและสร้างโทเค็น result
ความหมายของ outfeed_config
ขึ้นอยู่กับการใช้งาน
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท |
---|---|---|
(I1) | inputs |
จำนวนเทนเซอร์แบบผันแปรหรือเทนเซอร์ที่ผ่านการแปลงค่าเป็นจำนวนจริง |
(I2) | token |
token |
(I3) | outfeed_config |
ค่าคงที่ประเภท string |
เอาต์พุต
ชื่อ | ประเภท |
---|---|
result |
token |
ตัวอย่าง
%result = "stablehlo.outfeed"(%input0, %token) {
outfeed_config = ""
} : (tensor<2x2x2xi64>, !stablehlo.token) -> !stablehlo.token
แผ่น
ความหมาย
ขยาย operand
ด้วยระยะห่างจากขอบรอบๆ เทรนเนอร์ รวมถึงระหว่างองค์ประกอบของ Tensor ด้วย padding_value
ที่ระบุ
edge_padding_low
และ edge_padding_high
ระบุจำนวนการถ่วงที่เพิ่มไว้ที่ปลายด้านต่ำ (ถัดจากดัชนี 0) และปลายด้านสูง (ถัดจากดัชนีสูงสุด) ของมิติข้อมูลแต่ละรายการตามลำดับ จำนวนการถ่วงสามารถเป็นค่าลบได้ โดยค่าสัมบูรณ์ของการถ่วงเชิงลบจะระบุจํานวนองค์ประกอบที่จะนําออกจากมิติข้อมูลที่ระบุ
interior_padding
ระบุจำนวนระยะห่างจากเส้นขอบที่เพิ่มระหว่างองค์ประกอบ 2 รายการในแต่ละมิติข้อมูล ซึ่งต้องไม่เป็นค่าลบ การถอดขอบภายในจะเกิดขึ้นก่อนการถอดขอบด้านข้างเพื่อให้การถอดขอบด้านข้างเชิงลบนำองค์ประกอบออกจากตัวดำเนินการที่มีการถอดขอบภายใน
result[result_index]
มีคำจำกัดความอย่างเป็นทางการดังนี้
operand[operand_index]
ifresult_index = edge_padding_low + operand_index * (interior_padding + 1)
padding_value
ในกรณีอื่น
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
tensor หรือต่อ tensor ในการปรับปริมาณ | (C1), (C2), (C4) |
(I2) | padding_value |
เทนเซอร์ 0 มิติหรือเทนเซอร์ที่แปลงค่าเป็นจำนวนเต็มต่อเทนเซอร์ | (C1) |
(I3) | edge_padding_low |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C1), (C4) |
(I4) | edge_padding_high |
ค่าคงที่ tensor ใน 1 มิติของประเภท si64 |
(C1), (C4) |
(I5) | interior_padding |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C2-C4) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C3-C6) |
ข้อจำกัด
- (C1)
element_type(operand) = element_type(padding_value) = element_type(result)
- (C2)
size(edge_padding_low) = size(edge_padding_high) = size(interior_padding) = rank(operand)
- (C3)
0 <= interior_padding
- (C4)
shape(result) = shape(operand) + edge_padding_low + max(shape(operand) - 1, 0) * interior_padding + edge_padding_high
ตัวอย่าง
// %operand: [
// [1, 2, 3],
// [4, 5, 6]
// ]
// %padding_value: 0
%result = "stablehlo.pad"(%operand, %padding_value) {
edge_padding_low = 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 |
เทนเซอร์ 0 มิติประเภท ui32 |
ตัวอย่าง
%result = "stablehlo.partition_id"() : () -> tensor<ui32>
popcnt
ความหมาย
ดำเนินการนับตามองค์ประกอบตามจำนวนบิตที่ตั้งค่าไว้ใน tensor ของ operand
และสร้าง tensor ขนาด result
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทนเซอร์ประเภทจำนวนเต็ม | (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]
พาวเวอร์
ความหมาย
ทำการยกกำลังตามองค์ประกอบของ tensor ของ lhs
ด้วย rhs
tensor และสร้าง Tensor ขนาด result
ทําสิ่งต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สําหรับจํานวนเต็ม: เลขยกกำลังจำนวนเต็ม
- สำหรับตัวเลขทศนิยม:
pow
จาก IEEE-754 - สําหรับจํานวนเชิงซ้อน: การยกกำลังเชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(power, lhs, rhs, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
เทนเซอร์ประเภทจำนวนเต็ม ทศนิยม หรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
(I2) | rhs |
เทนเซอร์ประเภทจำนวนเต็ม ทศนิยม หรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภทจำนวนเต็ม ทศนิยม หรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (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
เขียนอย่างเป็นทางการมากขึ้นสำหรับองค์ประกอบ x
แต่ละรายการ ดังนี้
real(x) = is_complex(x) ? real_part(x) : x
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทนเซอร์ประเภทจุดลอยตัวหรือประเภทคอมเพล็กซ์ | (C1), (C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภทจุดลอยตัว | (C1), (C2) |
ข้อจำกัด
- (C1)
shape(result) = shape(operand)
- (C2)
element_type(result)
มีความหมายดังต่อไปนี้complex_element_type(element_type(operand))
หากis_complex(operand)
- จ่าย
element_type(operand)
ตัวอย่าง
// %operand: [(1.0, 2.0), (3.0, 4.0)]
%result = "stablehlo.real"(%operand) : (tensor<2xcomplex<f32>>) -> tensor<2xf32>
// %result: [1.0, 3.0]
recv
ความหมาย
รับข้อมูลจากแชแนลที่มี channel_id
และสร้าง results
หาก is_host_transfer
เป็น true
การดำเนินการจะโอนข้อมูลจากโฮสต์ ไม่เช่นนั้น ระบบจะโอนข้อมูลจากอุปกรณ์อื่น ซึ่งหมายความว่า
การกำหนดการติดตั้งใช้งาน แฟล็กนี้ซ้ำกับข้อมูลที่ให้ไว้ใน channel_type
ดังนั้นในอนาคตเราจึงวางแผนที่จะเก็บไว้เพียง 1 รายการเท่านั้น (#666)
results
ประกอบด้วยค่าเพย์โหลดที่มาก่อนและโทเค็นที่ตามหลัง ในอนาคตเราวางแผนที่จะแยกเพย์โหลดและโทเค็นออกเป็น 2 ออกพุตแยกกันเพื่อปรับปรุงความชัดเจน (#670)
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | token |
token |
(C4) |
(I2) | channel_id |
ค่าคงที่ประเภท si64 |
|
(I3) | channel_type |
enum ของ DEVICE_TO_DEVICE และ HOST_TO_DEVICE |
(C1) |
(I4) | is_host_transfer |
ค่าคงที่ประเภท i1 |
(C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวนเทนเซอร์ เทนเซอร์ที่แปลงเป็นจำนวนจริง หรือโทเค็นแบบผันแปร | (C2-C4) |
ข้อจำกัด
- (C1)
channel_type
หมายถึงHOST_TO_DEVICE
หากis_host_transfer = true
DEVICE_TO_DEVICE
ในกรณีอื่น
- (ค2)
0 < size(results)
- (C3)
is_empty(result[:-1])
หรือis_tensor(type(results[:-1]))
- (C4)
is_token(type(results[-1]))
ตัวอย่าง
%results0, %results1 = "stablehlo.recv"(%token) {
channel_handle = #stablehlo.channel_handle<handle = 1, type = 3>,
is_host_transfer = true
} : (!stablehlo.token) -> (tensor<2x2xi64>, !stablehlo.token)
ลด
ความหมาย
ใช้ฟังก์ชันการลด body
กับ inputs
และ init_values
ตาม dimensions
และสร้างเทนเซอร์ results
ลําดับของการลดคือการกําหนดการใช้งาน ซึ่งหมายความว่า body
และ init_values
ต้องอยู่ในรูปแบบโมนอยด์เพื่อรับประกันว่าการดําเนินการจะสร้างผลลัพธ์เดียวกันสําหรับอินพุตทั้งหมดสําหรับการติดตั้งใช้งานทั้งหมด อย่างไรก็ตาม เงื่อนไขนี้ใช้ไม่ได้กับการลดราคายอดนิยมหลายรายการ เช่น การเพิ่มจุดลอยตัวสำหรับ 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 |
จำนวนเทนเซอร์แบบผันแปรหรือเทนเซอร์ที่แปลงค่าต่อเทนเซอร์ | (C1-C4), (C6), (C7) |
(I2) | init_values |
เทนเซอร์ 0 มิติจํานวนไม่จํากัดหรือเทนเซอร์ที่แปลงค่าเป็นจำนวนจริงต่อเทนเซอร์ | (C2), (C3) |
(I3) | dimensions |
ค่าคงที่ tensor ใน 1 มิติของประเภท si64 |
(C4), (C5), (C7) |
(I4) | body |
ฟังก์ชัน | (C6) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวนแปรผันของ Tensor หรือ Tensor ต่อ Tensor ที่เล็กลง | (C3), (C7), (C8) |
ข้อจำกัด
- (C1)
same(shape(inputs...))
- (ค2)
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
ผลลัพธ์กลางจะล้นเป็นอนันต์โดยใช้เครื่องหมายเดิม หรือจะต่ำกว่าศูนย์โดยใช้เครื่องหมายเดิม - สำหรับประเภทที่เล็กลง จะดำเนินการ
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
กับค่าของเทนเซอร์ operand
จากแต่ละกระบวนการ โดยแบ่งผลลัพธ์ของการลดตาม scatter_dimension
ออกเป็นส่วนๆ และกระจายส่วนต่างๆ ที่แยกไว้ระหว่างกระบวนการต่างๆ เพื่อสร้าง result
การดำเนินการนี้จะแบ่งตารางกริดของกระบวนการ StableHLO เป็น process_groups
ซึ่งได้กำหนดไว้ดังต่อไปนี้
cross_replica(replica_groups)
ifchannel_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)
ifchannel_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 ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C1), (C2), (C7), (C8) |
(I2) | scatter_dimension |
ค่าคงที่ของประเภท si64 |
(C1), (C2), (C8) |
(I3) | replica_groups |
ค่าคงที่เทนเซอร์ 2 มิติประเภท si64 |
(C3-C5) |
(I4) | channel_id |
ค่าคงที่ประเภท si64 |
(C6) |
(I5) | use_global_device_ids |
ค่าคงที่ประเภท i1 |
(C6) |
(I6) | computation |
ฟังก์ชัน | (C7) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C8-C9) |
ข้อจำกัด
- (C1)
dim(operand, scatter_dimension) % dim(process_groups, 1) = 0
- (ค2)
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)
(ดูreduce) โดยที่
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 ต่อ Tensor ที่เล็กลง | (C1-C4), (C6), (C8), (C10), (C12), (C13), (C15) |
(I2) | init_values |
เทนเซอร์ 0 มิติจํานวนไม่จํากัดหรือเทนเซอร์ที่แปลงค่าเป็นจำนวนจริงต่อเทนเซอร์ | (C1), (C13) |
(I3) | window_dimensions |
ค่าคงที่ tensor ใน 1 มิติของประเภท si64 |
(C4), (C5), (C15) |
(I4) | window_strides |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C6), (C7), (C15) |
(I5) | base_dilations |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C8), (C9), (C15) |
(I6) | window_dilations |
ค่าคงที่ tensor ใน 1 มิติของประเภท si64 |
(C10), (C11), (C15) |
(I7) | padding |
ค่าคงที่เทนเซอร์ 2 มิติประเภท si64 |
(C12), (C15) |
(I8) | body |
ฟังก์ชัน | (C13) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวนเทนเซอร์แบบผันแปรหรือเทนเซอร์ที่แปลงค่าต่อเทนเซอร์ | (C1), (C14-C16) |
ข้อจำกัด
- (C1)
0 < size(inputs) = size(init_values) = size(results) = N
- (ค2)
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])
- (ค7)
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
และพจน์ divisor rhs
และสร้างพจน์ 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 |
เทนเซอร์ประเภทจำนวนเต็ม ทศนิยม หรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
(I2) | rhs |
เทนเซอร์ประเภทจำนวนเต็ม ทศนิยม หรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภทจำนวนเต็ม ทศนิยม หรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (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 |
เทนเซอร์ 0 มิติประเภท ui32 |
ตัวอย่าง
%result = "stablehlo.replica_id"() : () -> tensor<ui32>
ปรับรูปร่าง
ความหมาย
เปลี่ยนรูปแบบของเทมเพลต operand
เป็นเทมเพลต 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)
อาจแตกต่างกัน
- (ค2)
size(operand) = size(result)
- (C3) หาก
is_per_axis_quantized(operand)
reduce(dims(operand, [0, 1, ..., quantization_dimension(operand) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y) = reduce(dims(result, [0, 1, ..., quantization_dimension(result) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y)
dim(operand, quantization_dimension(operand)) = dim(result, quantization_dimension(result))
reduce(dims(operand, [quantization_dimension(operand) + 1, ..., rank(operand) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y) = reduce(dims(result, [quantization_dimension(result) + 1, ..., rank(result) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y)
ตัวอย่าง
// %operand: [[1, 2, 3], [4, 5, 6]]
%result = "stablehlo.reshape"(%operand) : (tensor<2x3xi32>) -> tensor<3x2xi32>
// %result: [[1, 2], [3, 4], [5, 6]]
กลับกัน
ความหมาย
กลับลําดับขององค์ประกอบใน operand
ตาม dimensions
ที่ระบุ และสร้างเทนเซอร์ result
ในรูปแบบที่เป็นทางการ
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 ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C1), (C3) |
(I2) | dimensions |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C2), (C3) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C1), (C3) |
ข้อจำกัด
- (C1)
type(operand) = type(result)
- (ค2)
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 |
เทนเซอร์ 0 มิติของประเภทจำนวนเต็ม บูลีน หรือจุดลอยตัว | (C1), (C2) |
(I2) | b |
Tensor จำนวนเต็ม 0 มิติของจำนวนเต็ม บูลีน หรือประเภทจุดลอยตัว | (C1), (C2) |
(I3) | shape |
ค่าคงที่ tensor ใน 1 มิติของประเภท si64 |
(C3) |
(I4) | rng_distribution |
enum ของ UNIFORM และ NORMAL |
(C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภทจำนวนเต็ม บูลีน หรือทศนิยม | (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 |
เทนเซอร์ 1 มิติประเภท ui64 |
(C1), (C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
output_state |
เทนเซอร์ 1 มิติประเภท ui64 |
(C1) |
output |
เทนเซอร์ประเภทจำนวนเต็มหรือจำนวนจุดลอยตัว |
ข้อจำกัด
- (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 ในเทนเซอร์ operand
และสร้างเทนเซอร์ 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
และสร้าง Tensor ขึ้น result
ใช้การดำเนินการ 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
ความหมาย
ดำเนินการรากที่สองแบบทวีคูณย้อนกลับทีละองค์ประกอบในเทนเซอร์ operand
และสร้างเทนเซอร์ result
ทําสิ่งต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับตัวเลขทศนิยม:
rSqrt
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: รากที่สองของส่วนกลับเชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(rsqrt, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (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
ซึ่งเท่ากับ inputs
tensor เว้นแต่ว่าสไลซ์หลายส่วนที่ระบุโดย scatter_indices
จะได้รับการอัปเดตด้วยค่า updates
โดยใช้ update_computation
แผนภาพต่อไปนี้แสดงวิธีที่องค์ประกอบใน updates...
แมปกับองค์ประกอบใน results...
โดยใช้ตัวอย่างที่ชัดเจน แผนภาพจะเลือกupdates...
ดัชนีตัวอย่าง 2-3 รายการและอธิบายรายละเอียดว่าresults...
ดัชนีใดที่สอดคล้องกับดัชนีตัวอย่าง
เขียนเป็นทางการมากขึ้นสำหรับ update_index
ทั้งหมดใน index_space(updates[0])
update_scatter_dims = [d for d in axes(updates[0]) and d not in update_window_dims]
update_scatter_index = update_index[update_scatter_dims...]
start_index
มีความหมายดังนี้scatter_indices[si0, ..., :, ..., siN]
โดยที่si
คือองค์ประกอบแต่ละรายการในupdate_scatter_index
และ:
จะแทรกที่ดัชนีindex_vector_dim
หากindex_vector_dim
<rank(scatter_indices)
[scatter_indices[update_scatter_index]]
ในกรณีอื่น
- สำหรับ
d_input
ในaxes(inputs[0])
full_start_index[d_input] = start_index[d_start]
ifd_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)]
ifd_input = input_batching_dims[i_batching]
andd_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)
where:- หาก
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 |
จำนวนเทนเซอร์แบบผันแปรหรือเทนเซอร์ที่แปลงค่าต่อเทนเซอร์ | (C1), (C2), (C4-C6), (C11), (C13), (C18), (C21), (C23-C24) |
(I2) | scatter_indices |
เทนเซอร์ประเภทจำนวนเต็ม | (C4), (C15), (C19), (C22) |
(I3) | updates |
จำนวนเทนเซอร์แบบผันแปรหรือเทนเซอร์ที่แปลงค่าต่อเทนเซอร์ | (C3-C6), (C8) |
(I4) | update_window_dims |
ค่าคงที่เทนเซอร์ 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 |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C14-C18) |
(I8) | scatter_dims_to_operand_dims |
ค่าคงที่เทนเซอร์ 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 |
จำนวนเทนเซอร์แบบผันแปรหรือเทนเซอร์ที่แปลงค่าต่อเทนเซอร์ | (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...)
- (ค7)
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]]
// ]
// ]
เลือก
ความหมาย
สร้างเทนเซอร์ result
โดยเลือกแต่ละองค์ประกอบจากเทนเซอร์ on_true
หรือ 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 |
เทนเซอร์ประเภท i1 |
(C1) |
(I2) | on_true |
tensor หรือต่อ tensor ในการปรับปริมาณ | (C1-C2) |
(I3) | on_false |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C2) |
ข้อจำกัด
- (C1)
rank(pred) = 0 or shape(pred) = shape(on_true)
- (ค2)
baseline_type(on_true) = baseline_type(on_false) = baseline_type(result)
ตัวอย่าง
// %pred: [[false, true], [true, false]]
// %on_true: [[1, 2], [3, 4]]
// %on_false: [[5, 6], [7, 8]]
%result = "stablehlo.select"(%pred, %on_true, %on_false) : (tensor<2x2xi1>, tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[5, 2], [3, 8]]
select_and_scatter
ความหมาย
กระจายค่าจากเทนเซอร์ source
โดยใช้ scatter
โดยอิงตามผลลัพธ์ของ reduce_window
ของเทนเซอร์ input
โดยใช้ select
และสร้างเทนเซอร์ 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
ที่อยู่เบื้องหลัง (ดู reduce) จะไม่รวมค่าเริ่มต้น ขณะนี้ยังไม่ได้ระบุว่าจะเกิดอะไรขึ้นหากหน้าต่างที่เกี่ยวข้องไม่มีค่า (#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
ifselected_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 ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C1-C4), (C6), (C8-C11) |
(I2) | source |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C1), (C2) |
(I3) | init_value |
เทนเซอร์ 0 มิติหรือเทนเซอร์ที่แปลงค่าเป็นจำนวนเต็มต่อเทนเซอร์ | (C3) |
(I4) | window_dimensions |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C2), (C4), (C5) |
(I5) | window_strides |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C2), (C6), (C7) |
(I6) | padding |
ค่าคงที่เทนเซอร์ 2 มิติประเภท si64 |
(C2), (C8) |
(I7) | select |
ฟังก์ชัน | (C9) |
(I8) | scatter |
ฟังก์ชัน | (C10) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C11-C12) |
ข้อจำกัด
- (C1)
element_type(operand) = element_type(source)
- (C2)
shape(source) = num_windows
โดยที่padded_operand_shape = padding[:, 0] + shape(operand) + padding[:, 1]
is_empty_window = padded_operand_shape = 0 || window_dimensions > padded_operand_shape
num_windows = is_empty_window ? 0 : floor((padded_operand_shape - window_dimensions) / window_strides) + 1
- (C3)
element_type(init_value) = element_type(operand)
- (C4)
size(window_dimensions) = rank(operand)
- (C5)
0 < window_dimensions
- (C6)
size(window_strides) = rank(operand)
- (ค7)
0 < window_strides
- (C8)
shape(padding) = [rank(operand), 2]
- (C9)
select
มีประเภท(tensor<E>, tensor<E>) -> tensor<i1>
โดยที่E = element_type(operand)
- (C10)
scatter
มีประเภท(tensor<E>, tensor<E>) -> tensor<E>
โดยที่is_promotable(element_type(operand), E)
- (C11)
shape(operand) = shape(result)
- (C12)
element_type(result) = E
ตัวอย่าง
// %operand: [[1, 5], [2, 5], [3, 6], [4, 4]]
// %source: [[5, 6], [7, 8]]
// %init_value: 0
%result = "stablehlo.select_and_scatter"(%operand, %source, %init_value) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = "stablehlo.compare"(%arg0, %arg1) {
comparison_direction = #stablehlo<comparison_direction GE>
} : (tensor<i64>, tensor<i64>) -> tensor<i1>
"stablehlo.return"(%0) : (tensor<i1>) -> ()
}, {
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
"stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
window_dimensions = array<i64: 3, 1>,
window_strides = array<i64: 2, 1>,
padding = dense<[[0, 1], [0, 0]]> : tensor<2x2xi64>
} : (tensor<4x2xi64>, tensor<2x2xi64>, tensor<i64>) -> tensor<4x2xi64>
// %result: [[0, 0], [0, 0], [5, 14], [7, 0]]
ส่ง
ความหมาย
ส่ง inputs
ไปยังช่อง channel_id
และสร้างโทเค็น result
หาก is_host_transfer
เป็น true
การดำเนินการจะโอนข้อมูลไปยังโฮสต์ ไม่เช่นนั้น ระบบจะโอนข้อมูลไปยังอุปกรณ์อื่น ความหมายของค่านี้คือ
ขึ้นอยู่กับการใช้งาน แฟล็กนี้ซ้ำกับข้อมูลที่ให้ไว้ใน channel_type
ดังนั้นในอนาคตเราจึงวางแผนที่จะเก็บไว้เพียง 1 รายการเท่านั้น (#666)
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | inputs |
จำนวนเทนเซอร์แบบผันแปรหรือเทนเซอร์ที่ผ่านการแปลงค่าเป็นจำนวนจริง | |
(I2) | token |
token |
|
(I3) | channel_id |
ค่าคงที่ของประเภท si64 |
|
(I4) | channel_type |
enum ของ DEVICE_TO_DEVICE และ DEVICE_TO_HOST |
(C1) |
(I5) | is_host_transfer |
ค่าคงที่ของประเภท i1 |
(C1) |
เอาต์พุต
ชื่อ | ประเภท |
---|---|
result |
token |
ข้อจำกัด
- (C1)
channel_type
หมายถึงDEVICE_TO_HOST
หากis_host_transfer = true
- จ่าย
DEVICE_TO_DEVICE
ตัวอย่าง
%result = "stablehlo.send"(%operand, %token) {
channel_handle = #stablehlo.channel_handle<handle = 1, type = 2>,
is_host_transfer = true
} : (tensor<2x2xi64>, !stablehlo.token) -> !stablehlo.token
shift_left
ความหมาย
ทำการดำเนินการลูกศรซ้ายจากองค์ประกอบบน tensor ของ lhs
ด้วยจํานวนบิต rhs
และสร้าง tensor ขนาด result
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
เทนเซอร์ประเภทจำนวนเต็ม | (C1) |
(I2) | rhs |
เทนเซอร์ประเภทจำนวนเต็ม | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor ของประเภทจำนวนเต็ม | (C1) |
ข้อจำกัด
- (C1)
type(lhs) = type(rhs) = type(result)
ตัวอย่าง
// %lhs: [-1, 0, 1]
// %rhs: [1, 2, 3]
%result = "stablehlo.shift_left"(%lhs, %rhs): (tensor<3xi64>, tensor<3xi64>) -> tensor<3xi64>
// %result: [-2, 0, 8]
shift_right_arithmetic
ความหมาย
ทำการดำเนินการ Shift ขวาของเอลิเมนต์ใน lhs
Tensor ด้วย
rhs
จำนวนบิตและสร้าง result
tensor
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
เทนเซอร์ประเภทจำนวนเต็ม | (C1) |
(I2) | rhs |
เทนเซอร์ประเภทจำนวนเต็ม | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor ของประเภทจำนวนเต็ม | (C1) |
ข้อจำกัด
- (C1)
type(lhs) = type(rhs) = type(result)
ตัวอย่าง
// %lhs: [-1, 0, 8]
// %rhs: [1, 2, 3]
%result = "stablehlo.shift_right_arithmetic"(%lhs, %rhs): (tensor<3xi64>, tensor<3xi64>) -> tensor<3xi64>
// %result: [-1, 0, 1]
shift_right_logical
ความหมาย
ดำเนินการเลื่อนไปทางขวาแบบตรรกะทีละองค์ประกอบในเทนเซอร์ lhs
โดยจำนวนบิต rhs
และสร้างเทนเซอร์ result
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
เทนเซอร์ประเภทจำนวนเต็ม | (C1) |
(I2) | rhs |
เทนเซอร์ประเภทจำนวนเต็ม | (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
ตามองค์ประกอบและสร้างเทนเซอร์ 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 |
เทนเซอร์ของจำนวนเต็มที่มีเครื่องหมาย ทศนิยม หรือประเภทเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
ข้อจำกัด
- (C1)
baseline_type(operand) = baseline_type(result)
ตัวอย่าง
// Logical values: +NaN, -1.0, -0.0, +0.0, 1.0
// operand: [0x7FFFFFFFFFFFFFFF, -1.0, -0.0, 0.0, 1.0]
%result = "stablehlo.sign"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// Logical values: +NaN, -1.0, -0.0, +0.0, 1.0
// %result: [0x7FFFFFFFFFFFFFFF, -1.0, -0.0, 0.0, 1.0]
ไซน์
ความหมาย
ดำเนินการไซน์ตามองค์ประกอบบน tensor ของ operand
และสร้าง Tensor ขนาด result
ดำเนินการต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับแบบลอย:
sin
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: ไซน์เชิงซ้อน
- สำหรับประเภทที่มีการแปลงเป็นจำนวนเต็ม:
dequantize_op_quantize(sine, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (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 ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C1-C3), (C5) |
(I2) | start_indices |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C2), (C3), (C5) |
(I3) | limit_indices |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C2), (C3), (C5) |
(I4) | strides |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C2), (C4) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
Tensor หรือ Tensor ที่แปลงค่าเป็นจำนวนเต็มต่อ Tensor | (C1), (C5) |
ข้อจำกัด
- (C1)
element_type(operand) = element_type(result)
- (ค2)
size(start_indices) = size(limit_indices) = size(strides) = rank(operand)
- (C3)
0 <= start_indices <= limit_indices <= shape(operand)
- (C4)
0 < strides
- (C5)
shape(result) = ceil((limit_indices - start_indices) / strides)
ตัวอย่าง
// %operand: [
// [0, 0, 0, 0],
// [0, 0, 1, 1],
// [0, 0, 1, 1]
// ]
%result = "stablehlo.slice"(%operand) {
start_indices = array<i64: 1, 2>,
limit_indices = array<i64: 3, 4>,
strides = array<i64: 1, 1>
} : (tensor<3x4xi64>) -> tensor<2x2xi64>
// % result: [
// [1, 1],
// [1, 1]
// ]
จัดเรียง
ความหมาย
จัดเรียงชิ้นส่วน inputs
แบบ 1 มิติตามมิติข้อมูล dimension
เข้าด้วยกันตาม comparator
แล้วสร้าง results
dimension
ต่างจากอินพุตที่คล้ายกันในการดำเนินการอื่นๆ เนื่องจากอนุญาตให้ใช้ค่าลบ โดยมีความหมายตามที่อธิบายไว้ด้านล่าง ในอนาคต การกระทำนี้อาจไม่ได้รับอนุญาต
ด้วยเหตุผลด้านความสอดคล้อง
(#1377)
หาก is_stable
เป็นจริง การจัดเรียงจะมีค่าคงที่ กล่าวคือ ลำดับสัมพัทธ์ขององค์ประกอบที่ถือว่าเท่ากับตัวเปรียบเทียบจะยังคงอยู่ ในกรณีที่มีอินพุตเดียว 2 องค์ประกอบ e1
และ e2
จะถือว่าเท่ากันโดยตัวเปรียบเทียบหากและเฉพาะในกรณีที่comparator(e1, e2) = comparator(e2, e1) = false
ดูการเขียนเป็นรูปแบบด้านล่างเพื่อดูวิธีทั่วไปสำหรับอินพุตหลายรายการ
เขียนเป็นทางการมากขึ้นสำหรับ result_index
ทั้งหมดใน index_space(results[0])
adjusted_dimension = dimension >= 0 ? dimension : rank(inputs[0]) + dimension
result_slice = [ri0, ..., :, ..., riR-1]
โดยที่riN
คือองค์ประกอบแต่ละรายการในresult_index
และ:
จะแทรกอยู่ที่adjusted_dimension
inputs_together = (inputs[0]..., ..., inputs[N-1]...)
results_together[result_slice] = sort(inputs_together[result_slice], comparator_together)
- โดยที่
sort
จะจัดเรียงส่วนของมิติข้อมูล 1 มิติตามลําดับที่ไม่ใช่จากน้อยไปมาก โดยคาดหวังว่าcomparator_together
จะแสดงผลtrue
หากอาร์กิวเมนต์ด้านซ้ายน้อยกว่าอาร์กิวเมนต์ที่ 2 ทางด้านขวา def comparator_together(lhs_together, rhs_together): args = [] for (lhs_el, rhs_el) in zip(lhs_together, rhs_together): args.append(lhs_el) args.append(rhs_el) return comparator(*args)
(results[0]..., ..., results[N-1]...) = results_together
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | inputs |
จำนวนเทนเซอร์แบบผันแปรหรือเทนเซอร์ที่แปลงค่าต่อเทนเซอร์ | (C1-C5) |
(I2) | dimension |
ค่าคงที่ประเภท si64 |
(C4) |
(I3) | is_stable |
ค่าคงที่ประเภท i1 |
|
(I4) | comparator |
ฟังก์ชัน | (C5) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
results |
จำนวนเทนเซอร์แบบผันแปรหรือเทนเซอร์ที่แปลงค่าต่อเทนเซอร์ | (C2), (C3) |
ข้อจำกัด
- (C1)
0 < size(inputs)
- (ค2)
type(inputs...) = type(results...)
- (C3)
same(shape(inputs...) + shape(results...))
- (C4)
-R <= dimension < R
โดยที่R = rank(inputs[0])
- (C5)
comparator
เป็นประเภท(tensor<E1>, tensor<E1>, ..., tensor<EN-1>, tensor<EN-1>) -> tensor<i1>
, โดยที่Ei = element_type(inputs[i])
ตัวอย่าง
// %input0 = [[1, 2, 3], [3, 2, 1]]
// %input1 = [[3, 2, 1], [1, 2, 3]]
%result0, %result1 = "stablehlo.sort"(%input0, %input1) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>, %arg2: tensor<i64>, %arg3: tensor<i64>):
%predicate = "stablehlo.compare"(%arg0, %arg1) {
comparison_direction = #stablehlo<comparison_direction GT>
} : (tensor<i64>, tensor<i64>) -> tensor<i1>
"stablehlo.return"(%predicate) : (tensor<i1>) -> ()
}) {
dimension = 0 : i64,
is_stable = true
} : (tensor<2x3xi64>, tensor<2x3xi64>) -> (tensor<2x3xi64>, tensor<2x3xi64>)
// %result0 = [[3, 2, 3], [1, 2, 1]]
// %result1 = [[1, 2, 1], [3, 2, 3]]
sqrt
ความหมาย
ดำเนินการถอดรากที่สองทีละองค์ประกอบในเทนเซอร์ operand
และสร้างเทนเซอร์ result
ทําสิ่งต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับแบบลอย:
squareRoot
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: รากที่สองของจำนวนเชิงซ้อน
- สำหรับประเภทที่เล็กลง:
dequantize_op_quantize(sqrt, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (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 รายการ lhs
และ rhs
และสร้างเทนเซอร์ result
ทําสิ่งต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สําหรับจํานวนเต็ม: การลบจํานวนเต็ม
- สำหรับตัวเลขทศนิยม:
subtraction
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: การลบเชิงซ้อน
- สำหรับประเภทที่มีการแปลงค่าเป็นจำนวนเต็ม ให้ทำดังนี้
dequantize_op_quantize(subtract, lhs, rhs, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
เทนเซอร์ประเภทจำนวนเต็ม ทศนิยม หรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
(I2) | rhs |
เทนเซอร์ประเภทจำนวนเต็ม ทศนิยม หรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภทจำนวนเต็ม ทศนิยม หรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (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
ความหมาย
ดำเนินการแทนเจนต์ทีละองค์ประกอบในเทนเซอร์ operand
และสร้างเทนเซอร์ result
ทําสิ่งต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับตัวเลขทศนิยม:
tan
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: แทนเจนต์เชิงซ้อน
- สำหรับประเภทที่มีการแปลงเป็นจำนวนเต็ม:
dequantize_op_quantize(tan, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (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]
// ]
tanh
อรรถศาสตร์
ดำเนินการไฮเปอร์โบลิกแทนเจนต์ระดับองค์ประกอบบน operand
tensor และสร้าง result
tensor ทําสิ่งต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สำหรับตัวเลขทศนิยม:
tanh
จาก IEEE-754 - สำหรับจำนวนเชิงซ้อน: ไฮเปอร์โบลิกแทนเจนต์เชิงซ้อน
- สำหรับประเภทที่มีการแปลงค่าเป็นจำนวนเต็ม ให้ทำดังนี้
dequantize_op_quantize(tanh, operand, type(result))
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
ข้อจำกัด
- (C1)
baseline_type(operand) = baseline_type(result)
ตัวอย่าง
// %operand: [-1.0, 0.0, 1.0]
%result = "stablehlo.tanh"(%operand) : (tensor<3xf32>) -> tensor<3xf32>
// %result: [-0.76159416, 0.0, 0.76159416]
เปลี่ยนลําดับ
ความหมาย
เปลี่ยนลําดับมิติข้อมูลของเทนเซอร์ operand
โดยใช้ permutation
และสร้างเทนเซอร์ result
เขียนเป็นทางการคือ result[result_index] = operand[operand_index]
โดยที่ result_index[d] = operand_index[permutation[d]]
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทนเซอร์หรือเทนเซอร์ที่ผ่านการแปลงค่าเป็นจำนวนเต็ม | (C1-C4) |
(I2) | permutation |
ค่าคงที่เทนเซอร์ 1 มิติประเภท si64 |
(C2-C4) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์หรือเทนเซอร์ที่ผ่านการแปลงค่าเป็นจำนวนเต็ม | (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
: ดำเนินการกับ Conjugate Transpose ของ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 |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1-C3) |
(I2) | b |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1-C4) |
(I3) | left_side |
ค่าคงที่ประเภท i1 |
(C3) |
(I4) | lower |
ค่าคงที่ประเภท i1 |
|
(I5) | unit_diagonal |
ค่าคงที่ประเภท i1 |
|
(I6) | transpose_a |
enum ของ NO_TRANSPOSE , TRANSPOSE และ ADJOINT |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภททศนิยมหรือเชิงซ้อน หรือเทนเซอร์ที่ผ่านการแปลงเชิงปริมาณต่อเทนเซอร์ | (C1) |
ข้อจำกัด
- (C1)
baseline_element_type(a) = baseline_element_type(b)
- (ค2)
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]
// ]
มัด
ความหมาย
สร้างทูเปิล 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
ความหมาย
ทำการแปลงทีละองค์ประกอบของเทนเซอร์ที่ผ่านการแปลงค่า operand
เป็นเทนเซอร์แบบจุดลอยตัว result
ตามพารามิเตอร์การแปลงค่าที่กําหนดโดยประเภท operand
หรือจะเรียกอย่างเป็นทางการว่า result = dequantize(operand)
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | operand |
เทนเซอร์ที่แปลงค่าเป็นจำนวนเต็ม | (C1), (C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ประเภทจุดลอยตัว | (C1), (C2) |
ข้อจำกัด
- (C1)
shape(operand) = shape(result)
- (ค2)
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 |
เทนเซอร์ประเภทจุดลอยตัวหรือแบบเชิงปริมาณ | (C1), (C2) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
เทนเซอร์ที่แปลงค่าเป็นจำนวนเต็ม | (C1), (C2) |
ข้อจำกัด
- (C1)
shape(operand) = shape(result)
- (ค2)
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 |
จำนวนเทนเซอร์ เทนเซอร์ที่แปลงเป็นจำนวนจริง หรือโทเค็นแบบผันแปร | (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 รายการ lhs
และ rhs
และสร้างเทนเซอร์ result
ทําสิ่งต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ
- สําหรับบูลีน: XOR เชิงตรรกะ
- สําหรับจำนวนเต็ม: บิตไวส์ XOR
อินพุต
ป้ายกำกับ | ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|---|
(I1) | lhs |
เทนเซอร์ประเภทบูลีนหรือจำนวนเต็ม | (C1) |
(I2) | rhs |
tensor ของประเภทบูลีนหรือจำนวนเต็ม | (C1) |
เอาต์พุต
ชื่อ | ประเภท | ข้อจำกัด |
---|---|---|
result |
tensor ของประเภทบูลีนหรือจำนวนเต็ม | (C1) |
ข้อจำกัด
- (C1)
type(lhs) = type(rhs) = type(result)
ตัวอย่าง
// Bitwise operation with with integer tensors
// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.xor"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[4, 4], [4, 12]]
// Logical operation with with boolean tensors
// %lhs: [[false, false], [true, true]]
// %rhs: [[false, true], [false, true]]
%result = "stablehlo.xor"(%lhs, %rhs) : (tensor<2x2xi1>, tensor<2x2xi1>) -> tensor<2x2xi1>
// %result: [[false, true], [true, false]]
การทำงานร่วมกันของภาษาถิ่น
ขณะนี้ โปรแกรม StableHLO ที่ใช้จริงบางครั้งอาจมีการดำเนินการที่ StableHLO ไม่ได้กำหนด
โมดูล ฟังก์ชัน การเรียก และผลลัพธ์
StableHLO ใช้การดำเนินการอัปสตรีม MLIR สำหรับ ModuleOp, FuncOp, CallOp และ ReturnOp การดำเนินการนี้ทำขึ้นเพื่อให้ทำงานร่วมกันกับกลไก MLIR ที่มีอยู่ได้ดียิ่งขึ้น เนื่องจากมีการเขียนการผ่านข้อมูลจำนวนมากที่มีประโยชน์เพื่อกำหนดเป้าหมาย FuncOp และ ModuleOp และไปป์ไลน์การคอมไพล์จำนวนมากคาดหวังว่าจะมีการดำเนินการเหล่านี้ การดำเนินการเหล่านี้ใช้การรับประกันความเข้ากันได้อย่างเต็มรูปแบบ หากมีการเปลี่ยนแปลงเกี่ยวกับการดำเนินการเหล่านี้ในลักษณะที่เข้ากันไม่ได้ (เช่น การนำออก) ระบบจะเพิ่มรายการที่เทียบเท่าของ StableHLO เพื่อรักษาความเข้ากันได้
ชโล
ชุดการดำเนินการ CHLO มีการดำเนินการในระดับที่สูงขึ้นซึ่งจะแยกออกเป็น StableHLO ปัจจุบันยังไม่มีการรับประกันความเข้ากันได้สำหรับ CHLO คุณต้องใช้ chlo-legalize-to-stablehlo pass ก่อนการแปลงเป็นอนุกรมเพื่อรับประกันความเข้ากันได้
การดำเนินการรูปร่าง
การใช้การดำเนินการบางอย่างจากภาษา MLIR หลักในโปรแกรม StableHLO แบบไดนามิกเพื่อดำเนินการคำนวณรูปร่างเป็น Use Case ทั่วไปในชุมชน
โดยปกติแล้ว คำสั่งเหล่านี้จะประกอบด้วยรูปแบบ shape
อย่างเช่น shape_of
หรือ num_elements
, รูปแบบ tensor
อย่างเช่น dim
หรือ from_elements
และประเภท index
ในตัว
Dynamism RFC > O2 ระบุว่ารายการเหล่านี้อยู่นอกขอบเขต แต่มีการรองรับindex
บางประเภทเพื่อวัตถุประสงค์ในการทํางานร่วมกัน เราไม่รับประกันความเข้ากันได้สำหรับอุปกรณ์หรือประเภทเหล่านี้ คุณสามารถใช้พาส shape-legalize-to-stablehlo เพื่อแปลงการดำเนินการเหล่านี้เป็นการดำเนินการ StableHLO ที่รองรับอย่างเต็มรูปแบบ
การดำเนินการที่เลิกใช้งาน
การดำเนินการ StableHLO หลายรายการที่รับค่ามาจาก MHLO นั้นเลิกใช้งานแล้วและกำลังจะออกจาก StableHLO ดูรายละเอียดทั้งหมดเกี่ยวกับการนําออกเหล่านี้ได้ใน StableHLO v1.0 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
ซึ่งทั้ง 2 โปรแกรมเป็นประเภท ui32
ในตารางกระบวนการ StableHLO กระบวนการ num_replicas * num_partitions
ของ StableHLO จะทำงานพร้อมกัน แต่ละกระบวนการจะมี process_id = (replica_id, partition_id)
ที่ไม่ซ้ำกัน โดยที่ replica_id
ใน replica_ids = range(num_replicas)
และ partition_id
ใน partition_ids = range(num_partitions)
ต่างก็มีประเภท ui32
เราจะทราบขนาดของตารางกระบวนการแบบคงที่สำหรับทุกโปรแกรม (ในอนาคต เรากำลังวางแผนที่จะทำให้ตารางนี้เป็นส่วนที่ชัดเจนของโปรแกรม StableHLO
#650) และอันดับภายในตารางกระบวนการจะรู้กันอยู่แล้วสำหรับทุกกระบวนการ แต่ละกระบวนการจะเข้าถึงตำแหน่งของกระบวนการภายในตารางกริดกระบวนการได้ผ่านการดำเนินการ replica_id
และ partition_id
ในตารางกริดกระบวนการ โปรแกรมทั้งหมดอาจเหมือนกัน (ในรูปแบบ "โปรแกรมเดียว ข้อมูลหลายรายการ") ทั้งหมดอาจแตกต่างกัน (ในรูปแบบ "โปรแกรมหลายรายการ ข้อมูลหลายรายการ") หรือเป็นแบบผสมก็ได้ ในอนาคต เราวางแผนที่จะเปิดตัวการรองรับนิพจน์อื่นๆ ในการกําหนดโปรแกรม StableHLO แบบขนาน ซึ่งรวมถึง GSPMD (#619)
ในตารางกริดกระบวนการ กระบวนการส่วนใหญ่จะแยกจากกัน โดยมีสถานะการดำเนินการแยกกัน ค่าอินพุต/กลาง/เอาต์พุตแยกกัน และการดำเนินการส่วนใหญ่จะดำเนินการแยกกันระหว่างกระบวนการต่างๆ ยกเว้นการดำเนินการแบบรวมจำนวนเล็กน้อยที่อธิบายไว้ด้านล่าง
เนื่องจากการดำเนินการของ Ops ส่วนใหญ่ใช้เฉพาะค่าจากกระบวนการเดียวกัน จึงสามารถอ้างถึงค่าเหล่านี้ด้วยชื่อได้ไม่ชัดเจน
อย่างไรก็ตาม เมื่ออธิบายความหมายของการดำเนินการแบบรวม รูปแบบดังกล่าวไม่เพียงพอ และนั่นทำให้เกิดเครื่องหมาย name@process_id
เพื่ออ้างอิงค่า name
ภายในกระบวนการหนึ่งๆ (จากมุมมองนี้ name
ที่ไม่เข้าเกณฑ์จะมองว่าเป็นชื่อย่อของ name@(replica_id(), partition_id())
ได้)
ลําดับการดําเนินการในกระบวนการต่างๆ จะกําหนดโดยการใช้งาน ยกเว้นการซิงค์ที่เกิดจากการสื่อสารแบบจุดต่อจุดและการดำเนินการแบบรวมตามที่อธิบายไว้ด้านล่าง
การสื่อสารแบบจุดต่อจุด
กระบวนการ StableHLO สามารถสื่อสารกันได้ผ่านแชแนล StableHLO ช่องจะแสดงด้วยรหัสบวกประเภท si64
คุณสามารถส่งค่าไปยังแชแนลและรับค่าจากแชแนลผ่านการดำเนินการต่างๆ
รายละเอียดเพิ่มเติม เช่น แหล่งที่มาของรหัสช่องเหล่านี้ วิธีที่โปรแกรมประมวลผลจะรับรู้รหัสเหล่านี้ และประเภทการซิงค์ที่รหัสเหล่านี้นำมาใช้ อยู่ระหว่างพิจารณา (#484)
การสื่อสารแบบสตรีม
ทุกกระบวนการของ StableHLO จะสามารถเข้าถึงอินเทอร์เฟซสตรีมมิง 2 แบบ ได้แก่
- ฟีดที่อ่านได้
- โฆษณานอกฟีดที่เขียนถึงได้
ซึ่งแตกต่างจากแชแนลที่ใช้เพื่อสื่อสารระหว่างกระบวนการต่างๆ จึงมีกระบวนการที่ปลายทั้ง 2 ด้าน แต่อินฟีดและเอาต์ฟีดจะกำหนดการติดตั้งใช้งานที่ปลายอีกด้านหนึ่ง
การกำหนดรูปแบบเพิ่มเติม เช่น วิธีที่การสื่อสารแบบสตรีมส่งผลต่อลําดับการดําเนินการและการซิงค์ประเภทใดที่นำมาใช้ในการสื่อสารนั้น อยู่ระหว่างพิจารณา (#484)
การดำเนินการแบบรวม
การดำเนินการแบบรวมใน StableHLO มี 6 รายการ ได้แก่ 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 กำหนด (การดำเนินการที่ไม่ถูกต้อง การหารด้วย 0 การเกินจำนวน การต่ำกว่าจำนวน หรือข้อยกเว้นที่ไม่แน่นอน) จะแสดงผลลัพธ์เริ่มต้น (ตามที่ระบุไว้ในมาตรฐาน) และดำเนินการต่อโดยไม่ยกธงสถานะที่เกี่ยวข้อง ซึ่งคล้ายกับ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>
}
เครื่องหมาย
เอกสารนี้ใช้รูปแบบ EBNF ของ ISO ที่แก้ไขแล้ว (ISO/IEC 14977:1996, Wikipedia) เพื่ออธิบายไวยากรณ์ โดยมีการแก้ไข 2 อย่าง ได้แก่ 1) กำหนดกฎโดยใช้ ::=
แทน =
2) การต่อกันแสดงโดยใช้การอยู่ต่อกันแทนที่จะเป็น ,
สําหรับการอธิบายความหมาย (เช่น ภายในส่วน "ประเภท" "ค่าคงที่" และ "การดําเนินการ") เราใช้สูตรที่อิงตามไวยากรณ์ Python ที่ขยายให้รองรับการแสดงการดําเนินการกับอาร์เรย์อย่างกระชับตามที่อธิบายไว้ด้านล่าง วิธีนี้ได้ผลดีกับข้อมูลโค้ดขนาดเล็ก แต่ในกรณีที่จำเป็นต้องใช้ข้อมูลโค้ดขนาดใหญ่ซึ่งเกิดขึ้นไม่บ่อยนัก เราจะใช้ไวยากรณ์ Python พื้นฐานซึ่งจะแสดงอย่างชัดแจ้งเสมอ
สูตร
มาดูวิธีการทำงานของสูตรตามตัวอย่างจากข้อกำหนด dot_general
กัน ข้อจำกัดข้อหนึ่งของการดำเนินการนี้มีลักษณะดังนี้
dim(lhs, lhs_batching_dimensions...) = dim(rhs, rhs_batching_dimensions...)
ชื่อที่ใช้ในสูตรนี้มาจากแหล่งที่มา 2 แหล่ง ได้แก่ 1) ฟังก์ชันส่วนกลาง ได้แก่ dim
2) คําจํากัดความของสมาชิกขององค์ประกอบโปรแกรมที่เกี่ยวข้อง ซึ่งได้แก่ อินพุต lhs
, lhs_batching_dimensions
, rhs
และ rhs_batching_dimensions
ที่กําหนดไว้ในส่วน "อินพุต" ของ dot_general
ดังที่กล่าวไว้ข้างต้น ไวยากรณ์ของสูตรนี้เป็นแบบ Python โดยมีส่วนขยายบางส่วนที่เน้นเรื่องความกระชับ มาดูกันว่าสูตรนี้ทำงานอย่างไร โดยเราจะเปลี่ยนรูปแบบเป็นไวยากรณ์ Python พื้นฐาน
ตอบ) ในสูตรเหล่านี้ เราใช้ =
เพื่อแสดงความเท่ากัน ดังนั้นขั้นตอนแรกในการรับไวยากรณ์ Python คือแทนที่ =
ด้วย ==
ดังนี้ dim(lhs, lhs_batching_dimensions...) == dim(rhs, rhs_batching_dimensions...)
ข) นอกจากนี้ สูตรเหล่านี้ยังรองรับเครื่องหมายขีดกลาง (...
) ซึ่งจะเปลี่ยนนิพจน์สเกลาร์เป็นนิพจน์เทนเซอร์ กล่าวโดยย่อคือ f(xs...)
หมายถึง "สําหรับ x
ที่เป็นสเกลาร์แต่ละรายการในเทนเซอร์ xs
ให้คํานวณ f(x)
ที่เป็นสเกลาร์ จากนั้นแสดงผลลัพธ์สเกลาร์ทั้งหมดเหล่านี้ร่วมกันเป็นผลลัพธ์เทนเซอร์" ในไวยากรณ์ Python เวอร์ชันมาตรฐาน สูตรตัวอย่างจะเปลี่ยนเป็น [dim(lhs, dim1) for dim1 in lhs_batching_dimensions] ==
[dim(rhs, dim2) for dim2 in rhs_batching_dimensions]
การใช้เครื่องหมายจุดไข่ปลาช่วยให้คุณหลีกเลี่ยงการทำงานในระดับสเกลาร์แต่ละรายการได้บ่อยครั้ง อย่างไรก็ตาม ในบางกรณีที่ค่อนข้างซับซ้อน อาจมีการใช้ไวยากรณ์กึ่งไม่เป็นทางการในระดับต่ำกว่าเหมือนในสูตร start_indices[bi0, ..., :, ..., biN]
จากข้อกำหนดเฉพาะ gather
เราไม่ได้ระบุรูปแบบที่แน่นอนในการแปลไวยากรณ์ดังกล่าวเป็น Python เวอร์ชันมาตรฐานเพื่อลดความซับซ้อน และหวังว่าผู้ใช้จะเข้าใจได้ทันทีในแต่ละกรณี
โปรดแจ้งให้เราทราบหากสูตรบางสูตรดูทึบ เราจะพยายามปรับปรุงสูตรเหล่านั้น
นอกจากนี้ คุณยังจะเห็นด้วยว่าสูตรใช้เครื่องหมายจุดไข่ปลาเพื่อขยายรายการทุกประเภท ซึ่งรวมถึงเทนเซอร์ รายการเทนเซอร์ (ซึ่งอาจมาจากเทนเซอร์จํานวนตัวแปร) เป็นต้น นี่เป็นอีกด้านที่เราไม่ได้ระบุรูปแบบที่แน่นอน (เช่น รายการไม่ได้เป็นส่วนหนึ่งของระบบประเภท StableHLO) แต่อาศัยความเข้าใจที่ง่ายดายแทน
ค) รูปแบบการเขียนสุดท้ายที่เราใช้ซึ่งควรค่าแก่การกล่าวถึงคือการออกอากาศโดยนัย แม้ว่าตัวเลือก StableHLO จะไม่รองรับการออกอากาศโดยนัย แต่สูตรก็รองรับด้วยเพื่อความกระชับ กล่าวโดยย่อคือ หากใช้สเกลาร์ในบริบทที่ควรจะเป็นเทนเซอร์ ระบบจะกระจายสเกลาร์ไปยังรูปร่างที่คาดไว้
ตัวอย่าง dot_general
ต่อไปคือข้อจำกัดอีกข้อหนึ่ง
0 <= lhs_batching_dimensions < rank(lhs)
ตามที่กำหนดไว้ในข้อกำหนด dot_general
lhs_batching_dimensions
คือเทนเซอร์ แต่ทั้ง 0
และ rank(lhs)
เป็นสเกลาร์ หลังจากใช้การออกอากาศโดยนัยแล้ว สูตรจะกลายเป็น [0, ..., 0] <= lhs_batching_dimensions < [rank(lhs), ..., rank(lhs)]
เมื่อใช้กับการดำเนินการ dot_general
หนึ่งๆ สูตรนี้จะประเมินเป็นเทนเซอร์ของบูลีน เมื่อมีการใช้สูตรเป็นข้อจำกัด ข้อจำกัดจะระงับหากสูตรประเมินเป็น true
หรือเป็น tensor ที่มีเฉพาะองค์ประกอบ true
ชื่อ
ในสูตร ขอบเขตคำศัพท์ประกอบด้วย 1) ฟังก์ชันส่วนกลาง 2) คำนิยามสมาชิก
3) คําจํากัดความในเครื่อง รายการฟังก์ชันส่วนกลางมีดังนี้ รายการคำจำกัดความขององค์ประกอบจะขึ้นอยู่กับองค์ประกอบของโปรแกรมที่ใช้เครื่องหมายกำกับ
- สําหรับการดำเนินการ คําจํากัดความของสมาชิกจะรวมชื่อที่ระบุในส่วน "อินพุต" และ "เอาต์พุต"
- สำหรับสิ่งอื่นๆ คำจำกัดความสมาชิกรวมถึงส่วนโครงสร้างขององค์ประกอบโปรแกรม ซึ่งตั้งชื่อตาม EBNF ที่ไม่ใช่เทอร์มินัลที่ตรงกัน ส่วนใหญ่แล้ว ชื่อของส่วนโครงสร้างเหล่านี้จะมาจากการเปลี่ยนชื่อขององค์ประกอบที่ไม่ใช่เทอร์มินัลเป็นรูปแบบ Snake Case (เช่น
IntegerLiteral
=>integer_literal
) แต่บางครั้งชื่อก็อาจมีการย่อในกระบวนการ (เช่นQuantizationStorageType
=>storage_type
) ในกรณีนี้ ระบบจะแสดงชื่ออย่างชัดเจนคล้ายกับส่วน "อินพุต" / "เอาต์พุต" ในข้อกำหนดการทํางาน - นอกจากนี้ คําจํากัดความของสมาชิกจะใส่
self
เสมอเพื่ออ้างอิงองค์ประกอบโปรแกรมที่เกี่ยวข้อง
ค่า
เมื่อประเมินสูตร สูตรจะทำงานกับค่าประเภทต่อไปนี้
1) Value
(ค่าจริง เช่น dense<[[1, 2], [3, 4]]> : tensor<2x2xi32>
จะรู้ประเภทของตนเสมอ)
2) Placeholder
(ค่าในอนาคต เช่น lhs
, rhs
หรือ result
และยังไม่ทราบค่าจริง รู้จักเฉพาะประเภทเท่านั้น)
3) Type
(ประเภทตามที่กำหนดไว้ในส่วน "ประเภท")
4) ในส่วน "ฟังก์ชันส่วนกลาง"),
4) Function
(ฟังก์ชันตามที่กำหนดไว้")
ชื่ออาจหมายถึงค่าที่แตกต่างกัน ทั้งนี้ขึ้นอยู่กับบริบท กล่าวอย่างเจาะจงก็คือ ส่วน "Semantics" สำหรับการดำเนินการ (และเทียบเท่ากับองค์ประกอบอื่นๆ ของโปรแกรม) จะกำหนดตรรกะรันไทม์ ดังนั้นอินพุตทั้งหมดจึงพร้อมใช้งานเป็น Value
ในทางตรงกันข้าม ส่วน "ข้อจำกัด" สำหรับการดำเนินการ (และค่าที่เทียบเท่ากับ) จะกำหนดตรรกะ "เวลาคอมไพล์" กล่าวคือ เป็นสิ่งที่จะดำเนินการก่อนรันไทม์ ดังนั้นมีเพียงอินพุตคงที่ที่พร้อมใช้งานเป็น Value
และอินพุตอื่นๆ จะใช้ได้เป็น Placeholder
เท่านั้น
ชื่อ | ใน "Semantics" | ใน "ข้อจำกัด" |
---|---|---|
ฟังก์ชันส่วนกลาง | Function |
Function |
อินพุตคงที่ | Value |
Value |
อินพุตที่ไม่คงที่ | Value |
Placeholder |
เอาต์พุต | Value |
Placeholder |
คําจํากัดความในท้องถิ่น | ขึ้นอยู่กับคำจำกัดความ | ขึ้นอยู่กับคำจำกัดความ |
มาดูตัวอย่างการดำเนินการ transpose
กัน
%result = "stablehlo.transpose"(%operand) {
permutation = dense<[2, 1, 0]> : tensor<3xi64>
} : (tensor<2x3x2xi32>) -> tensor<2x3x2xi32>
สำหรับการดำเนินการนี้ permutation
เป็นค่าคงที่ จึงมีให้ใช้เป็น Value
ทั้งในความหมายและข้อจำกัด ในทางตรงกันข้าม operand
และ result
จะใช้เป็น Value
ในความหมายได้ แต่จะใช้เป็น Placeholder
ในข้อจำกัดได้เท่านั้น
ฟังก์ชัน
การก่อสร้างประเภท
ไม่มีฟังก์ชันที่ใช้สร้างประเภทได้ แต่เราจะใช้ไวยากรณ์ประเภทโดยตรงแทน เนื่องจากมักจะกระชับกว่า เช่น ใช้ (tensor<E>, tensor<E>) -> (tensor<E>)
แทน function_type(
[tensor_type([], E), tensor_type([], E)], [tensor_type([], E)])
ฟังก์ชันในประเภท
element_type
ได้รับการกําหนดในประเภท Tensor และประเภท Tensor ที่แปลงค่าเป็นจำนวนเต็ม และแสดงผลTensorElementType
หรือQuantizedTensorElementType
ของTensorType
หรือQuantizedTensorType
ที่เกี่ยวข้องตามลําดับ
def element_type(x: Value | Placeholder | Type):
if type(x) == TensorType:
return tensor_element_type(x)
if type(x) == QuantizedTensorType:
return quantized_tensor_element_type(x)
if type(x) is not Type:
return element_type(type(x))
is_per_axis_quantized(x: Value | Placeholder | Type) -> Value
เป็นทางลัดสำหรับis_quantized(x) and quantization_dimension(x) is not None
is_per_tensor_quantized(x: Value | Placeholder | Type) -> Value
เป็นทางลัดสำหรับis_quantized(x) and quantization_dimension(x) is None
is_promotable(x: Type, y: Type) -> bool
ตรวจสอบว่าประเภทx
สามารถเลื่อนระดับเป็นประเภทy
ได้หรือไม่ เมื่อx
และy
เป็นQuantizedTensorElementType
โปรโมชันจะมีผลกับstorage_type
เท่านั้น ปัจจุบันโปรโมชันเวอร์ชันนี้ใช้ในบริบทของการคำนวณการลด (โปรดดูรายละเอียดเพิ่มเติมที่ RFC)
def is_promotable(x: Type, y: Type) -> Value:
is_same_type = (is_bool(x) and is_bool(y)) or
(is_integer(x) and is_integer(y)) or (is_float(x) and is_float(y)) or
(is_complex(x) and is_complex(y)) or
(is_quantized(x) and is_quantized(y) and expressed_type(x) = expressed_type(y))
if is_same_type == False:
return False
if is_integer(x) or is_float(x):
return bitwidth(x) <= bitwidth(y)
if is_complex(x):
return bitwidth(element_type(x)) <= bitwidth(element_type(y))
if is_quantized(x):
return bitwidth(storage_type(x)) <= bitwidth(storage_type(y))
return false
is_quantized(x: Value | Placeholder | Type) -> Value
เป็นทางลัดสำหรับis_quantized_tensor_element_type(x)
is_type_name(x: Value | Placeholder | Type) -> Value
ใช้ได้กับ ทุกประเภท เช่นis_float(x)
จะแสดงผลเป็นtrue
หากx
เป็นFloatType
หากx
เป็นค่าหรือตัวยึดตําแหน่ง ฟังก์ชันนี้จะใช้เป็นทางลัดสําหรับis_type_name(type(x))
max_value(x: Type) -> Value
แสดงผลค่าสูงสุดของTensorElementType
หากx
ไม่ใช่TensorElementType
ระบบจะแสดงผลNone
min_value(x: Type) -> Value
แสดงผลค่าต่ำสุดที่เป็นไปได้ของTensorElementType
หากx
ไม่ใช่TensorElementType
จะแสดงผลNone
member_name(x: Value | Placeholder | Type) -> Any
. พร้อมใช้งานสำหรับคำจำกัดความmember_name
ของสมาชิกทุกประเภท ตัวอย่างเช่นtensor_element_type(x)
จะแสดงผลส่วนTensorElementType
ของTensorType
ที่เกี่ยวข้อง หากx
เป็นค่าหรือตัวยึดตําแหน่ง ฟังก์ชันนี้จะใช้เป็นทางลัดสําหรับmember_name(type(x))
หากx
ไม่ใช่ประเภทที่มีสมาชิกที่เหมาะสม หรือค่าหรือตัวยึดตําแหน่งประเภทดังกล่าว ระบบจะแสดงผลNone
is_empty_algorithm(*args: Type)
ตรวจสอบว่าช่องอัลกอริทึมจุดทั้งหมดตั้งค่าเป็นNone
หรือไม่ ซึ่งจําเป็นเนื่องจากอัลกอริทึมของจุดมีลักษณะการทํางานเริ่มต้นที่กําหนดโดยการใช้งาน ดังนั้นการระบุค่าเริ่มต้นจึงไม่ถูกต้อง
การสร้างค่า
operation_name(*xs: Value | Type) -> Value
. ใช้ได้กับการดำเนินการทั้งหมด เช่นadd(lhs, rhs)
จะรับค่าเทนเซอร์ 2 ค่า ได้แก่lhs
และrhs
แล้วแสดงผลลัพธ์ของการประเมินการดำเนินการadd
ด้วยอินพุตเหล่านี้ สําหรับการดำเนินการบางอย่าง เช่นbroadcast_in_dim
ประเภทเอาต์พุตจะ "รับน้ำหนัก" กล่าวคือ ต้องใช้ในการประเมินการดำเนินการ ในกรณีนี้ ฟังก์ชันจะใช้ประเภทเหล่านี้เป็นอาร์กิวเมนต์
ฟังก์ชันสำหรับค่า
ออปเรเตอร์และฟังก์ชันของ Python ทั้งหมดพร้อมใช้งาน เช่น คุณสามารถระบุทั้งนิพจน์การสมัครใช้บริการและการแบ่งส่วนจาก Python เพื่อจัดทำดัชนีใน Tensor, Tensor ที่ผ่านการแปลงเชิงปริมาณ และทูเพลต
to_destination_type(x: Value, destination_type: Type) -> Value
ได้รับการกําหนดในเทนเซอร์และแสดงผลค่าที่แปลงแล้วของ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
ไม่ใช่เทนเซอร์ ระบบจะแสดงผลNone
is_unique(x: Value) -> Value
กำหนดไว้ในเทนเซอร์และแสดงผลเป็นtrue
หากx
ไม่มีองค์ประกอบที่ซ้ำกัน หรือแสดงผลเป็นfalse
ในกรณีอื่น หากx
ไม่ใช่เทนเซอร์ ระบบจะแสดงผลNone
member_name(x: Value) -> Any
ได้รับการกําหนดสำหรับคําจํากัดความของสมาชิกทั้งหมดmember_name
ของค่าทั้งหมด ตัวอย่างเช่นreal_part(x)
จะแสดงผลส่วนRealPart
ของComplexConstant
ที่เกี่ยวข้อง หากx
ไม่ใช่ค่าที่มีสมาชิกที่เหมาะสม ระบบจะแสดงผลNone
same(x: Value) -> Value
จะกำหนดด้วย tensor และแสดงtrue
หากองค์ประกอบของx
ทั้งหมดเท่ากัน หรือfalse
หากไม่เป็นเช่นนั้น หากเทนเซอร์ไม่มีองค์ประกอบ ระบบจะถือว่า "ทั้งหมดเท่ากัน" กล่าวคือ ฟังก์ชันจะแสดงผลtrue
หากx
ไม่ใช่เทนเซอร์ ระบบจะแสดงผลNone
split(x: Value, num_results: Value, axis: Value) -> Value
ได้รับการกําหนดในเทนเซอร์และแสดงผลส่วน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
เป็นชื่อการดำเนินการที่ถูกต้อง ซึ่งก็คือเป็นไปตามนิพจน์ทั่วไป[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
ไม่ใช่ประเภทของเทมพอร์ ประเภทของเทมพอร์ที่แปลงค่าเป็นจำนวนเต็ม หรือค่า หรือตัวยึดตําแหน่งของประเภทใดประเภทหนึ่งเหล่านี้ ระบบจะแสดงผล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 = expressed_type(element_type),
quantization_dimension = quantization_dimension(element_type),
scales = [constant(1.0, expressed_type(element_type))] * dim(x, quantization_dimension(element_type)),
zero_points = [constant(0, storage_type(element_type))] * dim(x, quantization_dimension(element_type)))
return QuantizedTensorType(shape(x), baseline_element_type)
if type(x) is not Type:
return baseline_element_type(type(x))
dequantize
กำหนดในประเภท Tensor ที่แปลงค่าเป็นจำนวนเต็มและเปลี่ยนให้เป็นประเภท Tensor แบบทศนิยม ซึ่งเกิดขึ้นผ่านการแปลงองค์ประกอบที่ปรับเป็นจำนวนเต็มซึ่งแสดงค่าจำนวนเต็มของประเภทพื้นที่เก็บข้อมูลเป็นค่าทศนิยมที่สอดคล้องกันของประเภทที่แสดงโดยใช้จุดศูนย์และมาตราส่วนซึ่งเชื่อมโยงกับประเภทองค์ประกอบที่ปรับเป็นจำนวนเต็ม
def compute_zero_points(quantized_type, result_type):
if is_per_tensor_quantized(quantized_type):
return broadcast_in_dim(constant(zero_point(quantized_type), storage_type(quantized_type)), [], result_type)
if is_per_axis_quantized(quantized_type):
for i in index_space(result_type):
d = quantization_dimension(quantized_type)
zero_points[i] = zero_points(quantized_type)[i[d]]
return zero_points
def compute_scales(quantized_type, result_type):
if is_per_tensor_quantized(quantized_type):
return broadcast_in_dim(constant(scale(quantized_type), expressed_type(quantized_type)), [],
type(result_type))
if is_per_axis_quantized(quantized_type):
for i in index_space(result_type):
d = quantization_dimension(quantized_type)
scales[i] = scales(quantized_type)[i[d]]
return scales
def dequantize(x: Value) -> Value:
assert is_quantized(x)
x_storage = bitcast_convert(x, storage_type(x))
x_storage_sub = x_storage - compute_zero_points(type(x), type(x_storage))
x_expressed_sub = convert(x_storage_sub, expressed_type(x))
return x_expressed_sub * compute_scales(type(x), type(x_expressed_sub))
quantize
กำหนดในประเภท Tensor แบบทศนิยมและเปลี่ยนเป็นประเภท Tensor แบบปัดเศษ ซึ่งเกิดขึ้นผ่านการแปลงค่าจุดลอยตัวของประเภทที่แสดงเป็นค่าจำนวนเต็มที่สอดคล้องของประเภทพื้นที่เก็บข้อมูล โดยใช้จุดเป็น 0 และสเกลที่เชื่อมโยงกับประเภทองค์ประกอบที่ควอนซ์
def quantize(x: Value, result_type: Type) -> Value:
assert is_float(x) and is_quantized(result_type)
zero_points = compute_zero_points(result_type, TensorType(shape(x), storage_type(result_type)))
converted_zero_points = convert(zero_points, expressed_type(result_type))
converted_min = convert(storage_min(result_type), expressed_type(result_type))
converted_max = convert(storage_max(result_type), expressed_type(result_type))
x_scaled = x / compute_scales(result_type, type(x))
x_scaled_add_zp = x_scaled + converted_zero_points
x_clamped = clamp(converted_min, x_scaled_add_zp, converted_max)
x_rounded = round_nearest_even(x_clamped)
return convert(x_rounded, result_type)
dequantize_op_quantize
ใช้เพื่อระบุการคำนวณระดับองค์ประกอบบน Tensor แบบควอนซ์ โดยจะแปลงค่าจากรูปแบบเชิงปริมาณเป็นรูปแบบที่แสดง จากนั้นจะดำเนินการ แล้วแปลงค่ากลับเป็นรูปแบบการจัดเก็บ ปัจจุบันฟังก์ชันนี้ใช้ได้กับการแปลงค่าเป็นจำนวนเต็มต่อเทนเซอร์เท่านั้น การวัดขนาดต่อแกนอยู่ระหว่างดำเนินการ (#1574)
def dequantize_op_quantize(op, *inputs_and_output_type):
inputs = inputs_and_output_type[:-1]
output_type = inputs_and_output_type[-1]
float_inputs = map(dequantize, inputs)
float_result = op(*float_inputs)
return quantize(float_result, output_type)
def dequantize_batch_norm_grad_or_training_quantize(op, *inputs_and_output_types):
inputs = inputs_and_output_type[:-3]
float_inputs = map(dequantize, inputs)
float_results = op(*float_inputs)
return map(quantize, float_results, inputs_and_output_type[-3:])
def dequantize_compare(lhs, rhs, comparison_direction):
float_lhs = dequantize(lhs)
float_rhs = dequantize(rhs)
return compare(float_lhs, float_rhs, comparison_direction, FLOAT)
def dequantize_select_quantize(pred, on_true, on_false, output_type):
float_on_true = dequantize(on_true)
float_on_false = dequantize(on_false)
float_result = select(pred, float_on_true, float_on_false)
return quantize(float_result, output_type)
hybrid_dequantize_then_op
ใช้เพื่อระบุการแปลงค่าเฉพาะน้ำหนักสําหรับการดําเนินการแบบผสมซึ่งยอมรับ lhs ในประเภททศนิยมและ rhs ในประเภทที่แปลงค่าแล้ว โดยจะแปลงอินพุตที่ผ่านการแปลงเชิงปริมาณเป็นประเภทที่แสดงและดำเนินการคํานวณในรูปแบบ float ประเภทองค์ประกอบของเทมพอริง lhs แบบลอยตัวและประเภทที่แสดงของเทมพอริง rhs แบบเชิงปริมาณควรเหมือนกัน
def hybrid_dequantize_then_op(op, lhs, rhs):
assert(is_float(lhs) and is_quantized(rhs) and element_type(lhs) == expressed_type(rhs))
return op(lhs, dequantize(rhs))
การคํานวณตารางกริด
cross_partition(replica_groups: Value) -> Value
ดูส่วน "cross_replica" ด้านบนcross_replica(replica_groups: Value) -> Value
ดูส่วน "cross_replica" ด้านบนcross_replica_and_partition(replica_groups: Value) -> Value
ดูส่วน "cross_replica_and_partition" ด้านบนflattened_ids(replica_groups: Value) -> Value
ดูส่วน "flattened_ids" ด้านบน
ความคิดวิพากษ์วิจารณ์
ค่า StableHLO อาจมีขนาดมิติข้อมูลแบบไดนามิก เช่น tensor<?xi64>
อย่างไรก็ตาม ค่า StableHLO ต้องไม่มีมิติข้อมูลเป็นจำนวนแบบไดนามิก (ไดนามิกที่ไม่มีอันดับ เช่น tensor<*xi64>
) ตัวดำเนินการและผลลัพธ์ได้รับอนุญาตให้ใช้ขนาดมิติข้อมูลแบบไดนามิก แม้ว่าจะมีข้อจำกัดเกี่ยวกับขนาดก็ตาม ระบบจะยืนยันข้อจำกัดแบบคงที่หากเป็นไปได้ ไม่เช่นนั้นระบบจะเลื่อนไปไว้ที่รันไทม์และความไม่ตรงกันจะส่งผลให้เกิดลักษณะการทำงานที่ไม่ระบุ โปรดดูตัวอย่างด้านล่าง
รูปร่างไม่ตรงกันสําหรับการดำเนินการแบบอนุภาคเดียว
ลองพิจารณาโปรแกรมของเล่นต่อไปนี้
func.func @foo(%arg0: tensor<?xf64>) {
%0 = stablehlo.abs %arg0 : (tensor<?xf64>) -> tensor<2xf64>
return
}
โปรแกรมดังกล่าวนี้ไม่ปกติ เนื่องจากปกติแล้วจะไม่ทราบรูปร่างของผลลัพธ์ แต่ไม่ทราบรูปร่างของอินพุต อย่างไรก็ตาม นี่เป็นโปรแกรม StableHLO ที่ถูกต้อง ไม่สามารถตรวจสอบการดำเนินการ abs
แบบคงที่ในโปรแกรมนี้ได้ เนื่องจากไม่ทราบรูปแบบที่แน่นอนของออพอเรนด อย่างไรก็ตาม รูปร่างต่างๆ เข้ากันได้อย่างแน่นอน และสามารถตรวจสอบแบบคงที่ได้ว่า ?
อาจกลายเป็น 2
ขณะรันไทม์ และจะไม่มีปัญหาใดๆ อย่างไรก็ตาม ?
อาจกลายเป็นจำนวนเต็มอื่นๆ ก็ได้ ซึ่งในกรณีนี้ ลักษณะการทํางานจะไม่มีการกําหนด
โปรดทราบว่าหากขนาดมิติข้อมูลเป็นแบบไดนามิกในผลลัพธ์ ลักษณะการทํางานจะไม่สามารถกำหนดได้ จริงๆ แล้วไม่มีขนาดที่ "คาดหวัง" ดังนั้นจึงไม่สามารถ ไม่ตรงกันได้
รูปร่างไม่ตรงกันสําหรับการดำเนินการแบบองค์ประกอบของไบนารี
ลองดูโปรแกรมจำลองต่อไปนี้
func.func @foo(%arg0: tensor<?xf64>, %arg1: tensor<?xf64>) {
%0 = stablehlo.add %arg0, %arg0 : (tensor<?xf64>, tensor<?xf64>) -> tensor<?xf64>
return
}
สำหรับการดำเนินการแบบองค์ประกอบของไบนารี รูปร่างของอินพุตและผลลัพธ์ต้องตรงกันเมื่อรันไทม์ ขณะคอมไพล์ มิติข้อมูลแบบคงที่ต้องเท่ากัน ไม่เช่นนั้นก็ต้องทำงานร่วมกันได้เท่านั้น หากมิติข้อมูลใดในอินพุตเป็นแบบไดนามิก ระบบอาจแสดงลักษณะการทำงานที่ไม่ระบุไว้ที่รันไทม์ เนื่องจากขนาดแบบไดนามิกอาจไม่ตรงกับขนาดที่เกี่ยวข้องในโอเปอเรนดอื่น (ไม่ว่าจะเป็นแบบคงที่หรือแบบไดนามิก) หากอินพุตทั้งหมดเป็นแบบคงที่ ผลลัพธ์จะเป็นแบบไดนามิกหรือไม่ก็ไม่สำคัญ ระบบจะตรวจสอบมิติข้อมูลที่ทราบแบบคงที่ และมิติข้อมูลแบบไดนามิกจะไม่มีข้อจำกัดใดๆ
รูปร่างไม่ตรงกันสําหรับการดำเนินการที่ใช้รูปร่างเอาต์พุตเป็นตัวถูกดำเนินการ
ลองดูโปรแกรมจำลองต่อไปนี้
func.func @foo(%arg0: tensor<2xi32>) {
%0 = stablehlo.dynamic_iota %arg0, dim = 0 : (tensor<2xi32>) -> tensor<3x4xi64>
return
}
ค่าในโอเปอเรเตอร์รูปร่างที่รันไทม์ต้องตรงกับรูปร่างของผลลัพธ์ ไม่เช่นนั้นระบบจะไม่ระบุลักษณะการทำงาน กล่าวคือ %arg0
ต้องมีค่าเป็น dense<[3, 4]> : tensor<2xi32>
ขณะรันไทม์ หากตัวดำเนินการรูปร่างเป็นค่าคงที่ การดำเนินการนี้จะตรวจสอบแบบคงที่ได้ หากรูปร่างของผลลัพธ์เป็นแบบไดนามิกทั้งหมด ก็จะไม่มีการจับคู่ที่ไม่ตรงกัน