ข้อกำหนดของ StableHLO

StableHLO คือชุดการดำเนินการสำหรับการดำเนินการระดับสูง (HLO) ในโมเดลแมชชีนเลิร์นนิง (ML) StableHLO ทำงานเป็นเลเยอร์ความสามารถในการถ่ายโอนได้ระหว่างเฟรมเวิร์ก ML กับคอมไพเลอร์ ML ส่วนเฟรมเวิร์ก ML ที่สร้างโปรแกรม StableHLO จะเข้ากันได้กับคอมไพเลอร์ ML ที่ใช้โปรแกรม StableHLO

เป้าหมายของเราคือการลดความซับซ้อนและเร่งการพัฒนา ML ด้วยการสร้างความสามารถในการทำงานร่วมกันระหว่างเฟรมเวิร์ก ML ต่างๆ (เช่น TensorFlow, JAX และ PyTorch) และคอมไพเลอร์ ML (เช่น XLA และ IREE) จากนั้นเอกสารนี้จะกล่าวถึงข้อกำหนดสำหรับภาษาโปรแกรม StableHLO

ข้อกำหนดนี้ประกอบด้วยส่วนหลัก 3 ส่วน อย่างแรก ส่วนโปรแกรมจะอธิบายโครงสร้างของโปรแกรม StableHLO ซึ่งประกอบด้วยฟังก์ชัน StableHLO ที่ประกอบไปด้วย Ops ของ StableHLO ภายในโครงสร้างนั้น ส่วน Ops จะระบุความหมายของการดำเนินการแต่ละรายการ ส่วนการดำเนินการแสดงความหมายสำหรับการดำเนินการทั้งหมดนี้ที่ดำเนินการร่วมกันภายในโปรแกรม สุดท้าย ส่วนเครื่องหมายจะพูดถึงเครื่องหมายที่ใช้ตลอดข้อกำหนด

หากต้องการดูข้อมูลจำเพาะจาก StableHLO รุ่นก่อนหน้า ให้เปิดที่เก็บในรุ่นที่ติดแท็กที่สนใจ เช่น ข้อกำหนดเกี่ยวกับ StableHLO v0.19.0 หากต้องการดูการเปลี่ยนแปลงที่เกิดขึ้นในแต่ละเวอร์ชันย่อยของ StableHLO โปรดดูบันทึกเวอร์ชันใน VhloDialect.td

โปรแกรม

Program ::= {Func}

โปรแกรม StableHLO ประกอบด้วยฟังก์ชัน StableHLO กี่รายการก็ได้ ด้านล่างนี้เป็นโปรแกรมตัวอย่างที่มีฟังก์ชัน @main ซึ่งมีอินพุต 3 รายการ (%image, %weights และ %bias) และเอาต์พุต 1 รายการ ส่วนเนื้อหาของฟังก์ชัน มี 6 โอเปอเรเตอร์

func.func @main(
  %image: tensor<28x28xf32>,
  %weights: tensor<784x10xf32>,
  %bias: tensor<1x10xf32>
) -> tensor<1x10xf32> {
  %0 = "stablehlo.reshape"(%image) : (tensor<28x28xf32>) -> tensor<1x784xf32>
  %1 = "stablehlo.dot"(%0, %weights) : (tensor<1x784xf32>, tensor<784x10xf32>) -> tensor<1x10xf32>
  %2 = "stablehlo.add"(%1, %bias) : (tensor<1x10xf32>, tensor<1x10xf32>) -> tensor<1x10xf32>
  %3 = "stablehlo.constant"() {value = dense<0.0> : tensor<1x10xf32>} : () -> tensor<1x10xf32>
  %4 = "stablehlo.maximum"(%2, %3) : (tensor<1x10xf32>, tensor<1x10xf32>) -> tensor<1x10xf32>
  "func.return"(%4): (tensor<1x10xf32>) -> ()
}

ฟังก์ชัน

Func        ::= 'func' '.' 'func' FuncId FuncInputs FuncOutputs '{' FuncBody '}'
FuncInputs  ::= '(' [FuncInput {',' FuncInput}] `)`
FuncInput   ::= ValueId ':' ValueType
FuncOutputs ::= ['->' FuncOutput, {',' FuncOutput}]
FuncOutput  ::= ValueType
FuncBody    ::= {Op}

ฟังก์ชัน StableHLO (หรือที่เรียกว่าฟังก์ชันที่มีชื่อ) มีตัวระบุ อินพุต/เอาต์พุต และเนื้อหา ในอนาคต เราวางแผนที่จะเปิดตัวข้อมูลเมตาเพิ่มเติมสำหรับฟังก์ชันต่างๆ เพื่อให้เข้ากันได้กับ HLO (#425, #626, #740, #744) มากขึ้น

ตัวระบุ

FuncId  ::= '@' letter {letter | digit}
ValueId ::= '%' digit {digit}
          | '%' letter {letter | digit}
letter  ::= 'a' | ... | 'z' | 'A' | ... | 'Z' | '_'
digit   ::= '0' | ... | '9'

ตัวระบุ StableHLO คล้ายกับตัวระบุในภาษาโปรแกรมต่างๆ โดยมีลักษณะเฉพาะ 2 อย่าง ได้แก่ 1) ตัวระบุทั้งหมดมีตัวระบุที่แยกความแตกต่างของตัวระบุประเภทต่างๆ 2) ตัวระบุค่าเป็นตัวเลขโดยสมบูรณ์เพื่อลดความซับซ้อนในการสร้างโปรแกรม StableHLO

ประเภท

Type         ::= ValueType | NonValueType
ValueType    ::= TensorType | QuantizedTensorType | TokenType | TupleType
NonValueType ::= TensorElementType | QuantizedTensorElementType | FunctionType | StringType

ประเภท StableHLO ได้รับการจัดหมวดหมู่เป็นประเภทค่า (หรือเรียกว่าประเภท First-class) ซึ่งแสดงค่า StableHLO และประเภทที่ไม่ใช่ค่าซึ่งอธิบายองค์ประกอบอื่นๆ ของโปรแกรม ประเภท StableHLO คล้ายกับประเภทในภาษาโปรแกรมต่างๆ โดยความแปลกหลักๆ คือลักษณะการใช้งานที่เจาะจงโดเมนของ StableHLO ซึ่งทำให้เกิดผลลัพธ์ที่ผิดปกติ (เช่น ประเภทสเกลาร์ไม่ใช่ประเภทค่า)

TensorType ::= 'tensor' '<' Shape TensorElementType '>'
Shape ::= {DimensionSize 'x'}
DimensionSize ::= digit {digit} | '?'

ประเภท Tensor แสดงถึง Tensor ซึ่งก็คืออาร์เรย์หลายมิติ โดยจะมีรูปร่างและประเภทองค์ประกอบ โดยที่รูปร่างแสดงถึงขนาดมิติข้อมูลที่ไม่เป็นลบหรือไม่ทราบตามลำดับจากน้อยไปมากของมิติข้อมูลที่เกี่ยวข้อง (หรือที่เรียกว่าแกน) ซึ่งมีตัวเลขตั้งแต่ 0 ถึง R-1 จำนวนของมิติข้อมูล R เรียกว่า rank เช่น tensor<2x3xf32> เป็นประเภท Tensor ที่มีรูปร่าง 2x3 และประเภทองค์ประกอบ f32 ซึ่งประกอบด้วย 2 ด้าน (หรือ 2 แกน) ได้แก่ มิติข้อมูลที่ 0 และ 1 ที่มีขนาด 2 และ 3 อันดับเกมอยู่ที่ 2

รูปร่างอาจไม่รู้จักบางส่วนหรือทั้งหมด (แบบไดนามิก) เช่น tensor<?x2xf64> อาจไม่รู้จักบางส่วนและไม่รู้จัก tensor<?x?xf64> โดยสิ้นเชิง ขนาดของมิติข้อมูลแบบไดนามิกจะแสดงโดยใช้ ? รูปทรงต่างๆ ต้องไม่จัดอันดับ

ในอนาคต เราวางแผนที่จะสํารวจประเภท tensor ที่ขยายไปนอกเหนือจากขนาดมิติข้อมูลและประเภทองค์ประกอบ เช่น เพื่อรวมเลย์เอาต์ (#629) และจำนวนน้อย (#1078)

QuantizedTensorType ::= 'tensor' '<' Shape QuantizedTensorElementType '>'
QuantizedTensorElementType ::= '!quant.uniform' '<'
                  QuantizationStorageType
                  ['<' QuantizationStorageMin ':' QuantizationStorageMax '>']
                  ':' QuantizationExpressedType
                  [':' QuantizationDimension]
                  ',' QuantizationParameters '>'
QuantizationStorageType ::= IntegerType
QuantizationStorageMin ::= IntegerConstant
QuantizationStorageMax ::= IntegerConstant
QuantizationExpressedType ::= FloatType
QuantizationDimension ::= IntegerConstant
QuantizationParameters ::= QuantizationParameter
                         | '{' QuantizationParameter {',' QuantizationParameter} '}'
QuantizationParameter ::= QuantizationScale ':' QuantizationZeroPoint
QuantizationScale ::= FloatConstant
QuantizationZeroPoint ::= IntegerConstant
ชื่อ ประเภท ข้อจำกัด
storage_type ประเภทจำนวนเต็ม (C1-C3), (C8)
storage_min ค่าคงที่ที่เป็นจำนวนเต็ม (C1), (C3), (C7)
storage_max ค่าคงที่ที่เป็นจำนวนเต็ม (C2), (C3), (C7)
expressed_type ประเภทจุดลอยตัว (C4)
quantization_dimension ค่าคงที่จำนวนเต็มที่ไม่บังคับ (C10-C12)
scales จำนวนแปรผันของค่าคงที่จุดลอยตัว (C4-C6), (C9), (C10), (C13)
zero_points จำนวนแปรผันของค่าคงที่จำนวนเต็ม (C7-C9)

ประเภทองค์ประกอบที่ปรับขนาดแล้วแสดงค่าที่เป็นจำนวนเต็มของประเภทพื้นที่เก็บข้อมูลในช่วงตั้งแต่ storage_min ถึง storage_max (รวม) ที่ตรงกับค่าจุดลอยตัวของประเภทที่แสดง สำหรับค่าจำนวนเต็ม i ค่าทศนิยม f ที่เกี่ยวข้องจะคำนวณเป็น f = (i - zero_point) * scale โดยที่ scale และ zero_point จะเรียกว่าพารามิเตอร์การวัดปริมาณ storage_min และ storage_max เป็นค่าที่ไม่บังคับในไวยากรณ์ แต่จะมีค่าเริ่มต้นเป็น min_value(storage_type) และ max_value(storage_type) ตามลำดับ ประเภทองค์ประกอบที่ปรับขนาดแล้วมีข้อจำกัดต่อไปนี้

  • (C1) type(storage_min) = storage_type
  • (C2) type(storage_max) = storage_type
  • (C3) min_value(storage_type) <= storage_min < storage_max <= max_value(storage_type)
  • (C4) type(scales...) = expressed_type
  • (C5) 0 < scales
  • (C6) is_finite(scales...)
  • (C7) storage_min <= zero_points <= storage_max
  • (C8) type(zero_points...) = storage_type
  • (C9) size(scales) = size(zero_points)
  • (C10) หากเป็น is_empty(quantization_dimension) ให้จ่าย size(scales) = 1
  • (C11) 0 <= quantization_dimension

ในขณะนี้ QuantizationScale เป็นค่าคงที่เป็นจำนวนลอยตัว แต่มีความสนใจอย่างมากในสเกลที่อิงตามจำนวนเต็มซึ่งแสดงด้วยตัวคูณและการเปลี่ยนแปลง เรามีแผนที่จะสำรวจปัญหานี้ในอนาคตอันใกล้ (#1404)

ตอนนี้มีการพูดคุยถึงความหมายของ QuantizationZeroPoint อย่างต่อเนื่อง รวมถึงประเภท ค่า และขึ้นอยู่กับว่าอาจมีค่า 0 จุดเดียวหรือหลายจุดในประเภท tensor ที่เป็นจำนวนเชิงปริมาณหรือไม่ จากผลลัพธ์ของการพูดคุยนี้ ข้อกำหนดเกี่ยวกับคะแนน 0 อาจมีการเปลี่ยนแปลงในอนาคต (#1405)

มีการพูดคุยเรื่องอื่นที่กำลังดำเนินอยู่เกี่ยวข้องกับความหมายของ QuantizationStorageMin และ QuantizationStorageMax เพื่อตัดสินว่าควรตั้งข้อจำกัดใดๆ กับค่าเหล่านี้และค่าของ Tensor ที่วัดปริมาณไหม (#1406)

สุดท้ายนี้ เราวางแผนที่จะค้นหาการแสดงค่าจากสเกลที่ไม่รู้จักและจุด 0 จุดในลักษณะเดียวกับที่เราวางแผนจะแทนค่าขนาดของมิติข้อมูลที่ไม่รู้จัก (#1407)

ประเภท Tensor ที่วัดปริมาณแสดงถึง tensor ที่มีองค์ประกอบที่เล็กลง Tensor เหล่านี้เหมือนกับ Tensor ปกติทุกประการเว้นแต่ว่าองค์ประกอบจะมีประเภทองค์ประกอบที่เล็กลง ไม่ใช่ประเภทองค์ประกอบปกติ

ใน tensor ที่ทําให้เป็นควอติเซชันสามารถเป็น per-tensor ได้ ซึ่งหมายความว่าการมี scale และ zero_point 1 ค่าสําหรับ tensor ทั้งหมด หรืออาจเป็นต่อแกนก็ได้ ซึ่งหมายความว่าการมี scales และ zero_points หลายรายการ 1 คู่ต่อชิ้นส่วนของมิติข้อมูล quantization_dimension โดยเฉพาะ อย่างเป็นทางการใน Tensor t ที่มีการคำนวณตามแกน จะมีส่วน dim(t, quantization_dimension) ของ quantization_dimension: t[:, ..., 0, ..., :], t[:, ..., 1, ..., :] ฯลฯ องค์ประกอบทั้งหมดในส่วน i ใช้ scales[i] และ zero_points[i] เป็นพารามิเตอร์การหาปริมาณ ประเภท tensor ที่หาปริมาณมีข้อจํากัดต่อไปนี้

  • สําหรับปริมาณตาม tensor:
    • ไม่มีข้อจำกัดเพิ่มเติม
  • สำหรับการคำนวณปริมาณตามแกน
    • (C13) quantization_dimension < rank(self)
    • (C14) dim(self, quantization_dimension) = size(scales)
TokenType ::= 'token'

ประเภทโทเค็นแสดงถึงโทเค็น ซึ่งก็คือค่าทึบแสงที่ผลิตและใช้โดยการดําเนินการบางอย่าง โทเค็นมีไว้เพื่อกำหนดคำสั่งดำเนินการสำหรับการดำเนินการตามที่อธิบายไว้ในส่วนการดำเนินการ

TupleType ::= 'tuple' '<' TupleElementTypes '>'
TupleElementTypes ::= [ValueType {',' ValueType}]

ประเภท Tuple แสดงถึง tuple เช่น รายการที่แตกต่างกัน Tuples เป็นฟีเจอร์เดิม ที่ใช้ร่วมกับ HLO เท่านั้น ใน HLO จะใช้ทัชพอยต์เพื่อแสดง อินพุตและเอาต์พุตของตัวแปร ใน StableHLO ระบบจะรองรับอินพุตและเอาต์พุตแปรผันโดยค่าเริ่มต้น และการใช้ Tuples เพียงอย่างเดียวใน StableHLO คือการนำเสนอ HLO ABI อย่างครอบคลุม เช่น T, tuple<T> และ tuple<tuple<T>> อาจแตกต่างกันไปตามการใช้งานจริง เราวางแผนที่จะทําการเปลี่ยนแปลง HLO ABI ในอนาคต ซึ่งอาจนําประเภท Tuple ออกจาก StableHLO (#598)

TensorElementType ::= BooleanType | IntegerType | FloatType | ComplexType
BooleanType ::= 'i1'
IntegerType ::= SignedIntegerType | UnsignedIntegerType
SignedIntegerType ::= 'si4' | 'si8' | 'si16' | 'si32' | 'si64'
UnsignedIntegerType ::= 'ui4' | 'ui8' | 'ui16' | 'ui32' | 'ui64'
FloatType ::= 'f8E4M3FN' | 'f8E5M2' | 'f8E4M3FNUZ' | 'f8E5M2FNUZ'
            | 'f8E4M3B11FNUZ' | 'bf16' | 'f16' | 'f32' | 'f64'
ComplexType ::= 'complex' '<' ComplexElementType '>'
ComplexElementType ::= 'f32' | 'f64'

ประเภทองค์ประกอบแสดงถึงองค์ประกอบของประเภท Tensor ซึ่งต่างจากภาษาโปรแกรมหลายๆ ภาษา ตรงประเภทนี้ไม่ใช่คลาสแรกใน StableHLO ซึ่งหมายความว่าโปรแกรม StableHLO จะแสดงค่าประเภทเหล่านี้โดยตรงไม่ได้ (ดังนั้น ระบบจึงแสดงค่าสเกลาร์ของประเภท T ที่มีค่า tensor แบบ 0 มิติของประเภท tensor<T>)

  • ประเภทบูลีนแสดงค่าบูลีน true และ false
  • ประเภทจำนวนเต็มอาจเป็นแบบมีเครื่องหมาย (si) หรือไม่มีเครื่องหมาย (ui) และมี ความกว้างบิตที่รองรับอย่างใดอย่างหนึ่ง (4, 8, 16, 32 หรือ 64) ประเภท siN ที่ลงนามจะแสดงค่าจำนวนเต็มตั้งแต่ -2^(N-1) ถึง 2^(N-1)-1 ประเภท uiN ที่ไม่มีเครื่องหมายแสดงค่าจำนวนเต็มตั้งแต่ 0 ถึง 2^N-1
  • ประเภทจุดทศนิยมอาจเป็นประเภทใดประเภทหนึ่งดังต่อไปนี้
  • ประเภทที่ซับซ้อนแสดงถึงค่าเชิงซ้อนที่มีส่วนจริงและมีส่วนจินตภาพของประเภทองค์ประกอบเดียวกัน ประเภทที่ซับซ้อนที่รองรับคือ complex<f32> (ทั้ง 2 ส่วนเป็นประเภท f32) และ complex<f64> (ทั้ง 2 ส่วนเป็นประเภท f64)
FunctionType ::= '(' InputTypes ')' '->' '(' OutputTypes ')'
InputTypes ::= [ValueType {',' ValueType}]
OutputTypes ::= [ValueType {',' ValueType}]

ประเภทฟังก์ชันจะแสดงทั้งฟังก์ชันที่มีชื่อและแบบไม่ระบุตัวบุคคล ชุดข้อมูลจะมีประเภทอินพุต (รายการประเภททางซ้ายของ ->) และประเภทเอาต์พุต (รายการประเภททางด้านขวามือของ ->) สำหรับภาษาโปรแกรมหลายๆ ภาษา ประเภทฟังก์ชันจะเป็นคลาสแรก แต่ไม่มีใน StableHLO

StringType ::= 'string'

ประเภทสตริงจะแสดงลำดับของไบต์ ประเภทสตริงไม่ใช่คลาสแรกใน StableHLO ซึ่งใช้เพื่อระบุข้อมูลเมตาแบบคงที่สำหรับองค์ประกอบของโปรแกรมเท่านั้น ซึ่งต่างจากภาษาโปรแกรมหลายๆ ภาษา

การทำงาน

การดำเนินการของ StableHLO (หรือที่เรียกว่า ops) แสดงถึงชุดการดำเนินการระดับสูงแบบปิดในโมเดลแมชชีนเลิร์นนิง ดังที่กล่าวไว้ข้างต้น ไวยากรณ์ StableHLO ได้รับแรงบันดาลใจมาจาก MLIR เป็นหลัก ซึ่งไม่จำเป็นต้องเป็นทางเลือกที่เหมาะกับสรีระที่สุด แต่ก็เป็นไปได้ว่าเหมาะสมที่สุดสำหรับเป้าหมาย StableHLO ในการสร้างความสามารถในการทำงานร่วมกันระหว่างเฟรมเวิร์ก ML และคอมไพเลอร์ ML

Op            ::= [OpOutputs] OpName OpInputs ':' OpSignature
OpName        ::= '"' 'stablehlo' '.' OpMnemonic '"'
OpMnemonic    ::= 'abs' | 'add' | ...

การดำเนินการของ StableHLO (หรือที่เรียกว่า ops) จะมีชื่อ อินพุต/เอาต์พุต และลายเซ็น ชื่อประกอบด้วยคำนำหน้า stablehlo. และช่วยจำซึ่งระบุการดำเนินการที่รองรับโดยไม่ซ้ำกัน ดูรายการที่ครอบคลุมของการดำเนินการที่รองรับทั้งหมดด้านล่าง

OpInputs        ::= OpInputValues OpInputFuncs OpInputAttrs
OpInputValues   ::= '(' [OpInputValue {',' OpInputValue}] ')'
OpInputValue    ::= ValueId
OpInputFuncs    ::= ['(' OpInputFunc {',' OpInputFunc} ')']
OpInputAttrs    ::= ['{' OpInputAttr {',' OpInputAttr} '}']
OpOutputs       ::= [OpOutput {',' OpOutput} '=']
OpOutput        ::= ValueId

การดำเนินการจะใช้อินพุตและสร้างเอาต์พุต อินพุตจะจัดหมวดหมู่เป็นค่าอินพุต (คํานวณระหว่างการดำเนินการ), ฟังก์ชันอินพุต (ระบุแบบคงที่เนื่องจากในฟังก์ชัน StableHLO ไม่ใช่ค่าคลาสแรก) และแอตทริบิวต์อินพุต (ระบุแบบคงที่ด้วย) ประเภทของอินพุตและเอาต์พุตที่การดำเนินการ และสร้างขึ้นจะขึ้นอยู่กับการช่วยจำ เช่น add op ใช้ค่าอินพุต 2 ค่า และสร้างค่าเอาต์พุต 1 ค่า เมื่อเปรียบเทียบกัน ฟังก์ชัน select_and_scatter จะใช้ค่าอินพุต 3 ค่า ฟังก์ชันอินพุต 2 รายการ และแอตทริบิวต์อินพุต 3 รายการ

OpInputFunc ::= '{' Unused FuncInputs ':' FuncBody '}'
Unused      ::= '^' digit {digit}
              | '^' letter {letter | digit}

ฟังก์ชันอินพุต (หรือเรียกอีกอย่างว่าฟังก์ชันที่ไม่ระบุชื่อ) คล้ายกับฟังก์ชันที่มีชื่อ ยกเว้น 1) ไม่มีตัวระบุ (ชื่อ "ไม่ระบุชื่อ") 2) ไม่ประกาศประเภทเอาต์พุต (ประเภทเอาต์พุตจะอนุมานจาก return ภายในฟังก์ชัน)

ไวยากรณ์สำหรับฟังก์ชันอินพุตมีส่วนที่ไม่ได้ใช้งานในปัจจุบัน (ดูเวอร์ชันที่ใช้งานจริงของ Unused ด้านบน) ซึ่งมีไว้สำหรับ MLIR ที่เข้ากันได้กับ MLIR ใน MLIR มีแนวคิดกว้างๆ เกี่ยวกับ "ภูมิภาค" ซึ่งสามารถมี "บล็อก" ของ Ops หลายๆ แบบเชื่อมต่อกันผ่านการข้ามได้ บล็อกเหล่านี้มีรหัสที่สอดคล้องกับเวอร์ชันที่ใช้งานจริงของ Unused จึงแยกความแตกต่างจากกันได้ StableHLO ไม่มีการข้ามการดำเนินการ ระบบจึงไม่ได้ใช้ส่วนที่เกี่ยวข้องของไวยากรณ์ MLIR (แต่ก็ยังคงอยู่)

OpInputAttr      ::= OpInputAttrName '=' OpInputAttrValue
OpInputAttrName  ::= letter {letter | digit}
OpInputAttrValue ::= Constant

แอตทริบิวต์อินพุตมีชื่อและค่าซึ่งเป็นหนึ่งในค่าคงที่ที่รองรับ ซึ่งเป็นวิธีหลักในการระบุข้อมูลเมตาแบบคงที่สำหรับองค์ประกอบของโปรแกรม ตัวอย่างเช่น concatenate op ใช้แอตทริบิวต์ dimension เพื่อระบุมิติข้อมูลที่มีการต่อค่าอินพุตของมิติข้อมูลนั้น ในทำนองเดียวกัน slice op จะใช้แอตทริบิวต์หลายรายการ เช่น start_indices และ limit_indices เพื่อระบุขอบเขตที่ใช้ในการแบ่งค่าอินพุต

ในขณะนี้ โปรแกรม StableHLO ในส่วนกลางมีแอตทริบิวต์ที่ไม่ได้อธิบายไว้ในเอกสารนี้ ในอนาคต เราวางแผนที่จะซึมซับแอตทริบิวต์เหล่านี้ไว้ในตัวเลือกของ StableHLO หรือห้ามไม่ให้แอตทริบิวต์เหล่านี้ปรากฏในโปรแกรม StableHLO ส่วนรายการแอตทริบิวต์เหล่านี้มีดังนี้

  • layout (#629)
  • mhlo.frontend_attributes (#628)
  • mhlo.sharding (#619)
  • output_operand_aliases (#740)
  • ข้อมูลเมตาสถานที่ตั้ง (#594)
OpSignature ::= '(' [ValueType {',' ValueType}] ')' '->' '(' [ValueType {',' ValueType}] ')'

ลายเซ็น Op ประกอบด้วยประเภทของค่าอินพุตทั้งหมด (รายการประเภททางด้านซ้ายของ ->) และประเภทของค่าเอาต์พุตทั้งหมด (รายการประเภททางด้านขวามือของ ->) กล่าวคือ ประเภทอินพุตจะซ้ำซ้อนและประเภทเอาต์พุตมักจะซ้ำซ้อนกันเกือบทุกครั้ง (เนื่องจากการดำเนินการของ StableHLO ส่วนใหญ่อาจมีการอนุมานจากอินพุต) อย่างไรก็ตาม ลายเซ็นหน้าจอถือเป็นส่วนหนึ่งของไวยากรณ์ StableHLO เพื่อความเข้ากันได้กับ MLIR

ด้านล่างคือตัวอย่างการทดสอบที่การช่วยจำคือ select_and_scatter โดยใช้ค่าอินพุต 3 ค่า (%operand, %source และ %init_value), ฟังก์ชันอินพุต 2 รายการ และแอตทริบิวต์อินพุต 3 รายการ (window_dimensions, window_strides และ padding) โปรดทราบว่าลายเซ็นของการดำเนินการรวมเฉพาะประเภทของค่าอินพุต (แต่ไม่รวมถึงประเภทของฟังก์ชันและแอตทริบิวต์อินพุตที่ระบุแบบในหน้า) อย่างไร)

%result = "stablehlo.select_and_scatter"(%operand, %source, %init_value) ({
  ^bb0(%arg0: tensor<i32>, %arg1: tensor<i32>):
    %0 = "stablehlo.compare"(%arg0, %arg1) {
      comparison_direction = #stablehlo<comparison_direction GE>
    } : (tensor<i32>, tensor<i32>) -> tensor<i1>
    "stablehlo.return"(%0) : (tensor<i1>) -> ()
}, {
  ^bb0(%arg0: tensor<i32>, %arg1: tensor<i32>):
    %0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i32>, tensor<i32>) -> tensor<i32>
    "stablehlo.return"(%0) : (tensor<i32>) -> ()
}) {
  window_dimensions = dense<[3, 1]> : tensor<2xi64>,
  window_strides = dense<[2, 1]> : tensor<2xi64>,
  padding = dense<[[0, 1], [0, 0]]> : tensor<2x2xi64>
} : (tensor<4x2xi32>, tensor<2x2xi32>, tensor<i32>) -> tensor<4x2xi32>

ค่าคงที่

Constant ::= BooleanConstant
           | IntegerConstant
           | FloatConstant
           | ComplexConstant
           | TensorConstant
           | QuantizedTensorConstant
           | StringConstant
           | EnumConstant

ค่าคงที่ StableHLO มีค่าลิเทอรัลและประเภทซึ่งเมื่อรวมกันแล้วแสดงถึงค่า StableHLO โดยทั่วไป ประเภทเป็นส่วนหนึ่งของไวยากรณ์คงที่ ยกเว้นเมื่อค่าคงที่ (เช่น ค่าคงที่ของบูลีนมีประเภท i1 อย่างชัดเจน ในขณะที่ค่าคงที่จำนวนเต็มอาจมีประเภทที่เป็นไปได้หลายประเภท)

BooleanConstant ::= BooleanLiteral
BooleanLiteral  ::= 'true' | 'false'

ค่าคงที่บูลีนแสดงถึงค่าบูลีน true และ false ค่าคงที่บูลีนเป็นประเภท i1

IntegerConstant   ::= IntegerLiteral ':' IntegerType
IntegerLiteral    ::= ['-' | '+'] DecimalDigits
                    | ['-' | '+'] '0x' HexadecimalDigits
DecimalDigits     ::= decimalDigit {decimalDigit}
HexadecimalDigits ::= hexadecimalDigit {hexadecimalDigit}
decimalDigit      ::= '0' | ... | '9'
hexadecimalDigit  ::= decimalDigit | 'a' | ... | 'f' | 'A' | ... | 'F'

ค่าคงที่จำนวนเต็มแสดงค่าจำนวนเต็มผ่านสตริงที่ใช้สัญกรณ์ทศนิยมหรือเลขฐานสิบหก แต่ระบบจะไม่รองรับฐานอื่นๆ เช่น ไบนารีหรือฐานแปด ค่าคงที่ที่เป็นจำนวนเต็มจะมีข้อจำกัดต่อไปนี้

  • (C1) is_wellformed(integer_literal, integer_type)
FloatConstant  ::= FloatLiteral ':' FloatType
FloatLiteral   ::= SignPart IntegerPart FractionalPart ScientificPart
                 | '0x' [HexadecimalDigits]
SignPart       ::= ['-' | '+']
IntegerPart    ::= DecimalDigits
FractionalPart ::= ['.' [DecimalDigits]]
ScientificPart ::= [('e' | 'E') ['-' | '+'] DecimalDigits]

ค่าคงที่ของจุดลอยหมายถึงค่าจุดลอยตัวผ่านสตริงที่ใช้สัญกรณ์ทศนิยมหรือสัญกรณ์วิทยาศาสตร์ นอกจากนี้ สัญกรณ์เลขฐานสิบหกยังสามารถใช้เพื่อระบุบิตที่เกี่ยวข้องโดยตรงในรูปแบบจุดลอยตัวของประเภทที่เกี่ยวข้องได้ด้วย ค่าคงที่จุดลอยตัวมีข้อจำกัดต่อไปนี้

  • (C1) หากใช้สัญกรณ์ที่ไม่ใช่เลขฐานสิบหก is_wellformed(float_literal, float_type)
  • (C2) หากใช้สัญกรณ์ฐานสิบหก size(hexadecimal_digits) = num_bits(float_type) / 4
ComplexConstant ::= ComplexLiteral ':' ComplexType
ComplexLiteral  ::= '(' RealPart ',' ImaginaryPart ')'
RealPart        ::= FloatLiteral
ImaginaryPart   ::= FloatLiteral

ค่าคงที่เชิงซ้อนแทนค่าเชิงซ้อนโดยใช้รายการของส่วนจริง (มาก่อน) และส่วนจินตภาพ (มาก่อน) ตัวอย่างเช่น (1.0, 0.0) : complex<f32> แสดงถึง 1.0 + 0.0i และ (0.0, 1.0) : complex<f32> แสดงถึง 0.0 + 1.0i ลำดับการจัดเก็บข้อมูลส่วนเหล่านี้ไว้ในหน่วยความจำจะได้รับการกำหนดการติดตั้งใช้งาน ค่าคงที่แบบซับซ้อนจะมีข้อจำกัดต่อไปนี้

  • (C1) is_wellformed(real_part, complex_element_type(complex_type))
  • (C2) is_wellformed(imaginary_part, complex_element_type(complex_type))
TensorConstant ::= TensorLiteral ':' TensorType
TensorLiteral  ::= 'dense' '<' (DenseLiteral | ElementLiteral) '>'
DenseLiteral   ::= DenseDimension | DenseElements
DenseDimension ::= '[' [DenseLiteral {',' DenseLiteral}] ']'
DenseElements  ::= [ElementLiteral {',' ElementLiteral}]
ElementLiteral ::= BooleanLiteral | IntegerLiteral | FloatLiteral | ComplexLiteral

ค่าคงที่ Tensor แสดงถึงค่า tensor โดยใช้รายการที่ซ้อนกันที่ระบุผ่านสัญลักษณ์ NumPy เช่น dense<[[1, 2, 3], [4, 5, 6]]> : tensor<2x3xi32> แสดงค่า tensor ด้วยการแมปต่อไปนี้จากดัชนีไปยังองค์ประกอบ {0, 0} => 1, {0, 1} => 2, {0, 2} => 3, {1, 0} => 4, {1, 1} => 5, {1, 2} => 6 ลำดับการจัดเก็บองค์ประกอบเหล่านี้ไว้ในหน่วยความจำจะได้รับการกำหนดการติดตั้งใช้งาน ค่าคงที่ของ Tensor มีข้อจํากัดต่อไปนี้

  • (C1) has_syntax(tensor_literal, element_type(tensor_type)) โดยที่
    • has_syntax(element_literal: Syntax, element_type: Type) = is_wellformed(element_literal, type).
    • has_syntax(tensor_literal: List, element_type: Type) = has_syntax(tensor_literal..., element_type).
  • (C2) has_shape(tensor_literal, shape(tensor_type)) โดยที่
    • has_shape(element_literal: Syntax, []) = true.
    • has_shape(tensor_literal: List, shape: List) = size(tensor_literal) = shape[0] and has_shape(tensor_literal..., shape[1:]).
    • หรือfalse
QuantizedTensorConstant ::= QuantizedTensorLiteral ':' QuantizedTensorType
QuantizedTensorLiteral  ::= 'dense' '<' (DenseLiteral | ElementLiteral) '>'

ค่าคงที่ tensor ที่วัดปริมาณ แสดงถึงค่า tensor ที่เป็นจำนวนเชิงปริมาณโดยใช้เครื่องหมายเดียวกันกับค่าคงที่ tensor ที่มีองค์ประกอบที่ระบุเป็นค่าคงที่ของประเภทพื้นที่เก็บข้อมูล ค่าคงที่ tensor ที่หาปริมาณมีข้อจํากัดต่อไปนี้

  • (C1) has_syntax(quantized_tensor_literal, storage_type(quantized_tensor_type))
  • (C2) has_shape(quantized_tensor_literal, shape(quantized_tensor_type))
StringConstant  ::= StringLiteral
StringLiteral   ::= '"' {stringCharacter | escapeSequence} '"'
stringCharacter ::= all ASCII characters except '\00', '\01', ... '\1f' and '"'
escapeSequence  ::= '\' ('"' | '\' | 'n' | 't' | (hexadecimalDigit hexadecimalDigit))

ลิเทอรัลสตริงประกอบด้วยไบต์ที่ระบุโดยใช้อักขระ ASCII และลำดับหลีก รหัสเหล่านี้ไม่รองรับการเข้ารหัสภาษา ดังนั้นการตีความไบต์เหล่านี้จึงเป็นการกำหนดการติดตั้งใช้งาน ลิเทอรัลสตริงมีประเภท string

การดำเนินการ

abs

อรรถศาสตร์

ดำเนินการดำเนินการ abs ตามองค์ประกอบบน tensor ของ operand และสร้าง tensor ของ result ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับจำนวนเต็มแบบมีเครื่องหมาย: โมดูลัสจำนวนเต็ม
  • สำหรับแบบลอยตัว: abs จาก IEEE-754
  • สำหรับจำนวนเชิงซ้อน: โมดูลัสเชิงซ้อน
  • สำหรับประเภทที่นับจำนวน: dequantize_op_quantize(abs, operand, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor ของจำนวนเต็มแบบมีเครื่องหมาย ประเภทจุดลอยตัว หรือประเภทเชิงซ้อน หรือ tensor เชิงปริมาณแบบต่อ tensor (C1-C2)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของจำนวนเต็มที่มีเครื่องหมายหรือประเภทจุดลอยตัวหรือ tensor เชิงปริมาณแบบต่อ tensor (C1-C2)

ข้อจำกัด

  • (C1) shape(result) = shape(operand)
  • (C2) baseline_element_type(result) ให้คำจำกัดความดังนี้
    • complex_element_type(element_type(operand)) หากเป็น is_complex(operand)
    • baseline_element_type(operand) ไม่เช่นนั้น

ตัวอย่าง

// %operand: [-2, 0, 2]
%result = "stablehlo.abs"(%operand) : (tensor<3xi32>) -> tensor<3xi32>
// %result: [2, 0, 2]

ตัวอย่างเพิ่มเติม

เพิ่ม

อรรถศาสตร์

ดำเนินการเพิ่ม tensor 2 รายการในรูปแบบ lhs และ rhs และสร้าง result tensor ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับบูลีน: ตรรกะ OR
  • สำหรับจำนวนเต็ม: การเพิ่มจำนวนเต็ม
  • สำหรับแบบลอยตัว: addition จาก IEEE-754
  • สำหรับจำนวนเชิงซ้อน: การบวกเชิงซ้อน
  • สำหรับประเภทที่นับจำนวน: dequantize_op_quantize(add, lhs, rhs, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) lhs tensor หรือ tensor เชิงปริมาณ (C1-C6)
(I2) rhs tensor หรือ tensor เชิงปริมาณ (C1-C5), (C7)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือ tensor เชิงปริมาณ (C1-C7)

ข้อจำกัด

  • หากการดำเนินการใช้ Tensor แบบไม่วัดปริมาณจะดำเนินการต่อไปนี้
    • (C1) type(lhs) = type(rhs) = type(result)
  • หากการดำเนินการใช้ Tensor เชิงปริมาณ ให้ทำดังนี้
    • (C2) is_quantized(lhs) and is_quantized(rhs) and is_quantized(result)
    • (C3) storage_type(lhs) = storage_type(rhs) = storage_type(result)
    • (C4) expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
    • (C5) (is_per_axis_quantized(lhs) or is_per_axis_quantized(rhs)) = is_per_axis_quantized(result)
    • (C6) หากเป็น is_per_axis_quantized(lhs) ให้จ่าย quantization_dimension(lhs) = quantization_dimension(result)
    • (C7) หากเป็น is_per_axis_quantized(rhs) ให้จ่าย quantization_dimension(rhs) = quantization_dimension(result)

ตัวอย่าง

// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.add"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[6, 8], [10, 12]]

ตัวอย่างเพิ่มเติม

after_all

อรรถศาสตร์

ตรวจสอบว่าได้ดำเนินการสร้าง inputs ก่อนการดำเนินการที่ขึ้นอยู่กับ result การดำเนินการนี้จะไม่ดำเนินการใดๆ เพียงแต่สร้างทรัพยากร Dependency ของข้อมูลจาก result ไปยัง inputs เท่านั้น

อินพุต

ค่ายเพลง ชื่อ ประเภท
(I1) inputs จำนวนตัวแปรของ token

เอาต์พุต

ชื่อ ประเภท
result token

ตัวอย่าง

// %input0: !stablehlo.token
// %input1: !stablehlo.token
%result = "stablehlo.after_all"(%input0, %input1) : (!stablehlo.token, !stablehlo.token) -> !stablehlo.token

ตัวอย่างเพิ่มเติม

all_gather

อรรถศาสตร์

ภายในกลุ่มกระบวนการแต่ละกลุ่มในตารางกริดกระบวนการ StableHLO ให้เชื่อมโยงค่าของ tensor ของ operand จากแต่ละกระบวนการตาม all_gather_dim และสร้าง Tensor result

การดําเนินการนี้จะแบ่งตารางกริดการประมวลผลของ StableHLO เป็น process_groups ซึ่งมีคำจำกัดความดังนี้

  • cross_replica(replica_groups) หาก channel_id <= 0 and use_global_device_ids = false
  • cross_replica_and_partition(replica_groups) หาก channel_id > 0 and use_global_device_ids = false
  • flattened_ids(replica_groups) หาก channel_id > 0 and use_global_device_ids = true

หลังจากนั้น ภายในแต่ละ process_group:

  • operands@receiver = [operand@sender for sender in process_group]สำหรับreceiverทั้งหมดในprocess_group
  • result@process = concatenate(operands@process, all_gather_dim)สำหรับprocessทั้งหมดในprocess_group

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1), (C6)
(I2) all_gather_dim ค่าคงที่ประเภท si64 (C1), (C6)
(I3) replica_groups ค่าคงที่ tensor แบบ 2 มิติของประเภท si64 (C2-C4)
(I4) channel_id ค่าคงที่ประเภท si64 (C5)
(I5) use_global_device_ids ค่าคงที่ประเภท i1 (C5)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C6)

ข้อจำกัด

  • (C1) 0 <= all_gather_dim < rank(operand)
  • (C2) is_unique(replica_groups)
  • (C3) size(replica_groups) ให้คำจำกัดความดังนี้
    • num_replicas หากมีการใช้ cross_replica
    • num_replicas หากมีการใช้ cross_replica_and_partition
    • num_processes หากมีการใช้ flattened_ids
  • (C4) 0 <= replica_groups < size(replica_groups)
  • (C5) หากเป็น use_global_device_ids = true ให้จ่าย channel_id > 0
  • (C6) type(result) = type(operand) ยกเว้น:
    • dim(result, all_gather_dim) = dim(operand, all_gather_dim) * dim(process_groups, 1).

ตัวอย่าง

// num_replicas: 2
// num_partitions: 1
// %operand@(0, 0): [[1, 2], [3, 4]]
// %operand@(1, 0): [[5, 6], [7, 8]]
%result = "stablehlo.all_gather"(%operand) {
  all_gather_dim = 1 : i64,
  replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>,
  // channel_id = 0
  channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
  // use_global_device_ids = false
} : (tensor<2x2xi64>) -> tensor<2x4xi64>
// %result@(0, 0): [[1, 2, 5, 6], [3, 4, 7, 8]]
// %result@(1, 0): [[1, 2, 5, 6], [3, 4, 7, 8]]

ตัวอย่างเพิ่มเติม

all_reduce

อรรถศาสตร์

ภายในกลุ่มกระบวนการแต่ละกลุ่มในตารางกริดกระบวนการ StableHLO ให้ใช้ฟังก์ชันการลด computation กับค่าของ Tensor operand จากแต่ละกระบวนการและสร้าง Tensor result

การดําเนินการนี้จะแบ่งตารางกริดการประมวลผลของ StableHLO เป็น process_groups ซึ่งมีคำจำกัดความดังนี้

  • cross_replica(replica_groups) หาก channel_id <= 0 and use_global_device_ids = false
  • cross_replica_and_partition(replica_groups) หาก channel_id > 0 and use_global_device_ids = false
  • flattened_ids(replica_groups) หาก channel_id > 0 and use_global_device_ids = true

หลังจากนั้น ภายในแต่ละ process_group:

  • result@process[result_index] = exec(schedule) สำหรับไบนารีทรี schedule ที่:
    • exec(node) = computation(exec(node.left), exec(node.right))
    • exec(leaf) = leaf.value
  • schedule เป็นแผนผังไบนารีที่กำหนดการติดตั้งใช้งาน ซึ่งการส่งผ่านตามลำดับคือ to_destination_type(operands@process_group...[result_index], type(func_inputs(computation)[0]))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C5) (C6)
(I2) replica_groups จำนวนแปรผันของค่าคงที่ tensor 1 มิติของประเภท si64 (C1-C3)
(I3) channel_id ค่าคงที่ประเภท si64 (C4)
(I4) use_global_device_ids ค่าคงที่ประเภท i1 (C4)
(I5) computation ฟังก์ชัน (C5)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C6-C7)

ข้อจำกัด

  • (C1) is_unique(replica_groups)
  • (C2) size(replica_groups) ให้คำจำกัดความดังนี้
    • num_replicas หากมีการใช้ cross_replica
    • num_replicas หากมีการใช้ cross_replica_and_partition
    • num_processes หากมีการใช้ flattened_ids
  • (C3) 0 <= replica_groups < size(replica_groups)
  • (C4) หากเป็น use_global_device_ids = true ให้จ่าย channel_id > 0
  • (C5) computation ประเภท (tensor<E>, tensor<E>) -> (tensor<E>) ที่ is_promotable(element_type(operand), E)
  • (C6) shape(result) = shape(operand)
  • (C7) element_type(result) = E

ตัวอย่าง

// num_replicas: 2
// num_partitions: 1
// %operand@(0, 0): [1, 2, 3, 4]
// %operand@(1, 0): [5, 6, 7, 8]
%result = "stablehlo.all_reduce"(%operand) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
    "stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
  replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>,
  channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
} : (tensor<4xi64>) -> tensor<4xi64>
// %result@(0, 0): [6, 8, 10, 12]
// %result@(1, 0): [6, 8, 10, 12]

ตัวอย่างเพิ่มเติม

all_to_all

อรรถศาสตร์

all_to_all

ภายในกลุ่มกระบวนการแต่ละกลุ่มในตารางกริดของกระบวนการ StableHLO จะแบ่งค่าของ Tensor operand ตาม split_dimension ออกเป็นส่วนๆ แล้วกระจายส่วนที่แบ่งระหว่างกระบวนการ เชื่อมส่วนที่กระจัดกระจายไปตาม concat_dimension และสร้าง result Tensor

การดําเนินการนี้จะแบ่งตารางกริดการประมวลผลของ StableHLO เป็น process_groups ซึ่งมีคำจำกัดความดังนี้

  • cross_replica(replica_groups) หากเป็น channel_id <= 0
  • cross_partition(replica_groups) หากเป็น channel_id > 0

หลังจากนั้น ภายในแต่ละ process_group:

  • split_parts@sender = split(operand@sender, split_count, split_dimension) สำหรับsenderทั้งหมดในprocess_group
  • scattered_parts@receiver = [split_parts@sender[receiver_index] for sender in process_group] ที่ไหน receiver_index = process_group.index(receiver)
  • result@process = concatenate(scattered_parts@process, concat_dimension).

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1-C3) (C9)
(I2) split_dimension ค่าคงที่ประเภท si64 (C1), (C2), (C9)
(I3) concat_dimension ค่าคงที่ประเภท si64 (C3) (C9)
(I4) split_count ค่าคงที่ประเภท si64 (C2), (C4), (C8), (C9)
(I5) replica_groups ค่าคงที่ tensor แบบ 2 มิติของประเภท si64 (C5-C8)
(I6) channel_id ค่าคงที่ประเภท si64

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C9)

ข้อจำกัด

  • (C1) 0 <= split_dimension < rank(operand)
  • (C2) dim(operand, split_dimension) % split_count = 0
  • (C3) 0 <= concat_dimension < rank(operand)
  • (C4) 0 < split_count
  • (C5) is_unique(replica_groups)
  • (C6) size(replica_groups) ให้คำจำกัดความดังนี้
    • num_replicas หากมีการใช้ cross_replica
    • num_partitions หากมีการใช้ cross_partition
  • (C7) 0 <= replica_groups < size(replica_groups)
  • (C8) dim(replica_groups, 1) = split_count
  • (C9) type(result) = type(operand) ยกเว้นในกรณีต่อไปนี้
    • dim(result, split_dimension) = dim(operand, split_dimension) / split_count.
    • dim(result, concat_dimension) = dim(operand, concat_dimension) * split_count.

ตัวอย่าง

// num_replicas: 2
// num_partitions: 1
// %operand@(0, 0): [[1, 2, 3, 4],
//                   [5, 6, 7, 8]]
// %operand@(1, 0): [[9, 10, 11, 12],
//                   [13, 14, 15, 16]]
%result = "stablehlo.all_to_all"(%operand) {
  split_dimension = 1 : i64,
  concat_dimension = 0 : i64,
  split_count = 2 : i64,
  replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>
} : (tensor<2x4xi64>) -> tensor<4x2xi64>
// %result@(0, 0): [[1, 2],
//                  [5, 6],
//                  [9, 10],
//                  [13, 14]]
// %result@(1, 0): [[3, 4],
//                  [7, 8],
//                  [11, 12],
//                  [15, 16]]

ตัวอย่างเพิ่มเติม

และ

อรรถศาสตร์

ดำเนินการ AND ด้วยองค์ประกอบ AND ของ tensor 2 รายการ lhs และ rhs และสร้าง Tensor result ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับบูลีน: ตรรกะ AND
  • สำหรับจำนวนเต็ม: บิตไวส์ AND

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) lhs tensor ของประเภทบูลีนหรือจำนวนเต็ม (C1)
(I2) rhs tensor ของประเภทบูลีนหรือจำนวนเต็ม (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของประเภทบูลีนหรือจำนวนเต็ม (C1)

ข้อจำกัด

  • (C1) type(lhs) = type(rhs) = type(result)

ตัวอย่าง

// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.and"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[1, 2], [3, 0]]

ตัวอย่างเพิ่มเติม

atan2

อรรถศาสตร์

ดำเนินการ atan2 ตามองค์ประกอบบน lhs และ rhs Tensor และสร้าง result Tensor ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับแบบลอยตัว: atan2 จาก IEEE-754
  • สำหรับจำนวนเชิงซ้อน: เชิงซ้อน atan2
  • สำหรับประเภทที่นับจำนวน: dequantize_op_quantize(atan2, lhs, rhs, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) lhs tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)
(I2) rhs tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)

ตัวอย่าง

// %lhs: [0.0, 1.0, -1.0]
// %rhs: [0.0, 0.0, 0.0]
%result = "stablehlo.atan2"(%lhs, %rhs) : (tensor<3xf64>, tensor<3xf64>) -> tensor<3xf64>
// %result: [0.0, 1.57079637, -1.57079637] // [0.0, pi/2, -pi/2]

ตัวอย่างเพิ่มเติม

batch_norm_grad

อรรถศาสตร์

ประมวลผลการไล่ระดับสีของอินพุตหลายรายการของ batch_norm_training การเผยแพร่ย้อนกลับจาก grad_output และสร้าง Tensor grad_operand, grad_scale และ grad_offset กล่าวคือ การดําเนินการนี้อาจแสดงเป็นการแยกย่อยการดําเนินการ StableHLO ที่มีอยู่โดยใช้ไวยากรณ์ Python ดังนี้

def compute_sum(operand, feature_index):
  (sum,) = reduce(
      inputs=[operand],
      init_values=[constant(0, element_type(operand))],
      dimensions=[i for i in range(rank(operand)) if i != feature_index],
      body=lambda x, y: add(x, y))
  return sum

def compute_mean(operand, feature_index):
  sum = compute_sum(operand, feature_index)
  divisor = constant(size(operand) / dim(operand, feature_index),
                     element_type(operand))
  divisor_bcast = broadcast_in_dim(divisor, [], type(sum))
  return divide(sum, divisor_bcast)

def batch_norm_grad(operand, scale, mean, variance, grad_output, epsilon, feature_index):
  # Broadcast inputs to type(operand)
  scale_bcast = broadcast_in_dim(scale, [feature_index], type(operand))
  mean_bcast = broadcast_in_dim(mean, [feature_index], type(operand))
  variance_bcast = broadcast_in_dim(variance, [feature_index], type(operand))
  epsilon_bcast = broadcast_in_dim(constant(epsilon, element_type(operand)), [],
                                   type(operand))

  # Perform normalization using the provided `mean` and `variance`
  # Intermediate values will be useful for computing gradients
  centered_operand = subtract(operand, mean_bcast)
  stddev = sqrt(add(variance_bcast, epsilon_bcast))
  normalized_operand = divide(centered_operand, stddev)

  # Use the implementation from batchnorm_expander.cc in XLA
  # Temporary variables have exactly the same names as in the C++ code
  elements_per_feature = broadcast_in_dim(
      constant(divide(size(operand), dim(operand, feature_index)),
               element_type(grad_output)),
      [], type(operand))
  i1 = multiply(grad_output, elements_per_feature)
  i2 = broadcast_in_dim(
      compute_sum(grad_output, feature_index), [feature_index], type(operand))
  i3 = broadcast_in_dim(
      compute_sum(multiply(grad_output, centered_operand), feature_index),
      [feature_index], type(operand))
  i4 = multiply(i3, centered_operand)
  i5 = divide(i4, add(variance_bcast, epsilon_bcast))
  i6 = subtract(subtract(i1, i2), i5)

  grad_operand =
      multiply(divide(divide(scale_bcast, stddev), elements_per_feature), i6)
  grad_scale =
      compute_sum(multiply(grad_output, normalized_operand), feature_index)
  grad_offset = compute_sum(grad_output, feature_index)

  return grad_operand, grad_scale, grad_offset

สำหรับประเภทที่แบ่งปริมาณแล้ว จะแสดงผล dequantize_batch_norm_grad_or_training_quantize(lambda operand, scale, mean, variance, grad_output: batch_norm_grad(operand, scale, mean, variance, grad_output, epsilon, feature_index), operand, scale, mean, variance, grad_output, type(grad_operand), type(grad_scale), type(feature_index))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ (C1-C3), (C5)
(I2) scale Tensor แบบ 1 มิติของประเภทจุดลอยตัวหรือต่อเทนเซอร์เชิงปริมาณ (C2), (C4), (C5)
(I3) mean Tensor แบบ 1 มิติของประเภทจุดลอยตัวหรือต่อเทนเซอร์เชิงปริมาณ (C2), (C4)
(I4) variance Tensor แบบ 1 มิติของประเภทจุดลอยตัวหรือต่อเทนเซอร์เชิงปริมาณ (C2), (C4)
(I5) grad_output tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ (C2), (C3)
(I6) epsilon ค่าคงที่ประเภท f32
(I7) feature_index ค่าคงที่ประเภท si64 (C1), (C5)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
grad_operand tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ (C2), (C3)
grad_scale Tensor แบบ 1 มิติของประเภทจุดลอยตัวหรือต่อเทนเซอร์เชิงปริมาณ (C2), (C4)
grad_offset Tensor แบบ 1 มิติของประเภทจุดลอยตัวหรือต่อเทนเซอร์เชิงปริมาณ (C2), (C4)

ข้อจำกัด

  • (C1) 0 <= feature_index < rank(operand)
  • (C2) operand, scale, mean, variance, grad_output, grad_operand, grad_scale และ grad_offset มี baseline_element_type เดียวกัน
  • (C3) operand, grad_output และ grad_operand มีรูปร่างเดียวกัน
  • (C4) scale, mean, variance, grad_scale และ grad_offset มีรูปร่างเดียวกัน
  • (C5) size(scale) = dim(operand, feature_index)

ตัวอย่าง

// %operand: [
//            [[1.0, 2.0], [3.0, 4.0]],
//            [[3.0, 4.0], [1.0, 2.0]]
//           ]
// %scale: [1.0, 1.0]
// %mean: [2.0, 3.0]
// %variance: [1.0, 1.0]
// %grad_output: [
//                [[0.1, 0.1], [0.1, 0.1]],
//                [[0.1, 0.1], [0.1, 0.1]]
//               ]
%grad_operand, %grad_scale, %grad_offset =
"stablehlo.batch_norm_grad"(%operand, %scale, %mean, %variance, %grad_output) {
  epsilon = 0.0 : f32,
  feature_index = 2 : i64
} : (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>, tensor<2xf64>,
     tensor<2x2x2xf64>) -> (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>)
// %grad_operand: [
//                 [[0.0, 0.0], [0.0, 0.0]],
//                 [[0.0, 0.0], [0.0, 0.0]]
//                ]
// %grad_scale:  [0.0, 0.0]
// %grad_offset: [0.4, 0.4]

batch_norm_inference

อรรถศาสตร์

ปรับ tensor ของ operand ให้เป็นมาตรฐานในมิติข้อมูลทั้งหมดยกเว้นมิติข้อมูล feature_index และสร้าง Tensor result การดำเนินการเช่นนี้อาจแสดงเป็นการแยกตัวของการดำเนินการ StableHLO ที่มีอยู่โดยใช้ไวยากรณ์ Python ดังต่อไปนี้

def batch_norm_inference(operand, scale, offset, mean, variance, epsilon, feature_index):
  # Broadcast inputs to shape(operand)
  scale_bcast = broadcast_in_dim(scale, [feature_index], type(operand))
  offset_bcast = broadcast_in_dim(offset, [feature_index], type(operand))
  mean_bcast = broadcast_in_dim(mean, [feature_index], type(operand))
  variance_bcast = broadcast_in_dim(variance, [feature_index], type(operand))
  epsilon_bcast = broadcast_in_dim(constant(epsilon, element_type(operand)), [],
                                   type(operand))

  # Perform normalization using the provided `mean` and `variance` instead of
  # computing them like `batch_norm_training` does.
  centered_operand = subtract(operand, mean_bcast)
  stddev = sqrt(add(variance_bcast, epsilon_bcast))
  normalized_operand = divide(centered_operand, stddev)
  return add(multiply(scale_bcast, normalized_operand), offset_bcast)

สำหรับประเภทที่แบ่งปริมาณแล้ว จะแสดงผล dequantize_op_quantize(lambda operand, scale, offset, mean, variance: batch_norm_inference(operand, scale, offset, mean, variance, epsilon, feature_index), operand, scale, offset, mean, variance, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ (C1-C7)
(I2) scale Tensor แบบ 1 มิติของประเภทจุดลอยตัวหรือต่อเทนเซอร์เชิงปริมาณ (C2), (C3)
(I3) offset Tensor แบบ 1 มิติของประเภทจุดลอยตัวหรือต่อเทนเซอร์เชิงปริมาณ (C2), (C4)
(I4) mean Tensor แบบ 1 มิติของประเภทจุดลอยตัวหรือต่อเทนเซอร์เชิงปริมาณ (C5)
(I5) variance Tensor แบบ 1 มิติของประเภทจุดลอยตัวหรือต่อเทนเซอร์เชิงปริมาณ (C2), (C6)
(I6) epsilon ค่าคงที่ประเภท f32
(I7) feature_index ค่าคงที่ประเภท si64 (C1), (C3-C6)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ (C2), (C7)

ข้อจำกัด

  • (C1) 0 <= feature_index < rank(operand)
  • (C2) operand, scale, offset, mean, variance และ result มี baseline_element_type เหมือนกัน
  • (C3) size(scale) = dim(operand, feature_index)
  • (C4) size(offset) = dim(operand, feature_index)
  • (C5) size(mean) = dim(operand, feature_index)
  • (C6) size(variance) = dim(operand, feature_index)
  • (C7) baseline_type(operand) = baseline_type(result)

ตัวอย่าง

// %operand: [
//            [[1.0, 2.0], [3.0, 4.0]],
//            [[3.0, 4.0], [1.0, 2.0]]
//           ]
// %scale: [1.0, 1.0]
// %offset: [1.0, 1.0]
// %mean: [2.0, 3.0]
// %variance: [1.0, 1.0]
%result = "stablehlo.batch_norm_inference"(%operand, %scale, %offset, %mean, %variance) {
  epsilon = 0.0 : f32,
  feature_index = 2 : i64
} : (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>, tensor<2xf64>, tensor<2xf64>) -> tensor<2x2x2xf64>
// %result: [
//           [[0.0, 0.0], [2.0, 2.0]],
//           [[2.0, 2.0], [0.0, 0.0]]
//          ]

batch_norm_training

อรรถศาสตร์

คํานวณค่าเฉลี่ยและความแปรปรวนในมิติข้อมูลทั้งหมดยกเว้นมิติข้อมูล feature_index และปรับ tensor ของ operand ที่ผลิต output, batch_mean และ batch_var ให้เป็นมาตรฐาน กล่าวคือ การดําเนินการนี้สามารถแสดงเป็นการแยกย่อยการดําเนินการ StableHLO ที่มีอยู่โดยใช้ไวยากรณ์ Python ดังนี้

def compute_mean(operand, feature_index):
  (sum,) = reduce(
      inputs=[operand],
      init_values=[constant(0, element_type(operand))],
      dimensions=[i for i in range(rank(operand)) if i != feature_index],
      body=lambda x, y: add(x, y))
  divisor = constant(size(operand) / dim(operand, feature_index),
                     element_type(operand))
  divisor_bcast = broadcast_in_dim(divisor, [], type(sum))
  return divide(sum, divisor_bcast)

def compute_variance(operand, feature_index):
  mean = compute_mean(operand, feature_index)
  mean_bcast = broadcast_in_dim(mean, [feature_index], type(operand))
  centered_operand = subtract(operand, mean_bcast)
  return compute_mean(mul(centered_operand, centered_operand), feature_index)

def batch_norm_training(operand, scale, offset, epsilon, feature_index):
  mean = compute_mean(operand, feature_index)
  variance = compute_variance(operand, feature_index)
  return batch_norm_inference(operand, scale, offset, mean, variance, epsilon,
                              feature_index),
         mean, variance

สำหรับประเภทที่แบ่งปริมาณแล้ว จะแสดงผล dequantize_batch_norm_grad_or_training_quantize(lambda operand, scale, offset: batch_norm_training(operand, scale, offset, epsilon, feature_index), operand, scale, offset, type(output), type(batch_mean), type(batch_var))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ (C1)
(I2) scale tensor 1 มิติของจุดลอยตัวหรือต่อ tensor เชิงปริมาณ (C2), (C3)
(I3) offset tensor 1 มิติของจุดลอยตัวหรือต่อ tensor เชิงปริมาณ (C2), (C4)
(I4) epsilon ค่าคงที่ประเภท f32 (C1), (C3-C6)
(I5) feature_index ค่าคงที่ประเภท si64 (C1), (C3-C6)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
output tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ (C7)
batch_mean tensor 1 มิติของจุดลอยตัวหรือต่อ tensor เชิงปริมาณ (C2), (C5)
batch_var tensor 1 มิติของจุดลอยตัวหรือต่อ tensor เชิงปริมาณ (C2), (C6)

ข้อจำกัด

  • (C1) 0 <= feature_index < rank(operand)
  • (C2) operand, scale, offset, batch_mean, batch_var และ output มี baseline_element_type เหมือนกัน
  • (C3) size(scale) = dim(operand, feature_index)
  • (C4) size(offset) = dim(operand, feature_index)
  • (C5) size(batch_mean) = dim(operand, feature_index)
  • (C6) size(batch_var) = dim(operand, feature_index)
  • (C7) baseline_type(output) = baseline_type(operand)

ตัวอย่าง

// %operand: [
//            [[1.0, 2.0], [3.0, 4.0]],
//            [[3.0, 4.0], [1.0, 2.0]]
//           ]
// %scale: [1.0, 1.0]
// %offset: [1.0, 1.0]
%output, %batch_mean, %batch_var = "stablehlo.batch_norm_training"(%operand, %scale, %offset) {
  epsilon = 0.0 : f32,
  feature_index = 2 : i64
} : (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>) ->
    (tensor<2x2x2xf64>, tensor<2xf64>, tensor<2xf64>)
// %output: [
//           [[0.0, 0.0], [2.0, 2.0]],
//           [[2.0, 2.0], [0.0, 0.0]]
//          ]
// %batch_mean: [2.0, 3.0]
// %batch_var: [1.0, 1.0]

bitcast_convert

อรรถศาสตร์

ดำเนินการบิตแคสต์บน tensor ของ operand และสร้าง Tensor result ซึ่งจะมีการตีความบิตของ tensor ของ operand ทั้งหมดใหม่โดยใช้ประเภทของ tensor ของ result

อย่างเป็นทางการมากขึ้นสำหรับ E = element_type(operand), E' = element_type(result) และ R = rank(operand)

  • หาก num_bits(E') < num_bits(E), bits(result[i0, ..., iR-1, :]) = bits(operand[i0, ..., iR-1])
  • หาก num_bits(E') > num_bits(E), bits(result[i0, ..., iR-2]) = bits(operand[i0, ..., iR-2, :])
  • หาก num_bits(E') = num_bits(E), bits(result[i0, ..., iR-1]) = bits(operand[i0, ..., iR-1])

bits จะแสดงผลค่าที่กำหนดในหน่วยความจำและลักษณะการทำงานเป็นการกำหนดการติดตั้งใช้งาน เนื่องจากการแสดง tensors ที่แน่นอนเป็นสิ่งที่กำหนดการติดตั้งใช้งาน และการแสดงประเภทองค์ประกอบที่แน่นอนมีการกำหนดการใช้งานด้วยเช่นกัน

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor หรือ tensor เชิงปริมาณ (C1-C2)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือ tensor เชิงปริมาณ (C1-C2)

ข้อจำกัด

  • (C1) ให้ E = is_quantized(operand) ? storage_type(operand) : element_type(operand), E' = is_quantized(result) ? storage_type(result) : element_type(result) และ R = rank(operand):
    • หากเป็น num_bits(E') = num_bits(E) shape(result) = shape(operand)
    • หาก num_bits(E') < num_bits(E):
    • rank(result) = R + 1.
    • dim(result, i) = dim(operand, i) สำหรับ0 <= i < Rทั้งหมด
    • dim(result, R) * num_bits(E') = num_bits(E).
    • หาก num_bits(E') > num_bits(E):
    • rank(result) = R - 1.
    • dim(result, i) = dim(operand, i) สำหรับ0 <= i < Rทั้งหมด
    • dim(operand, R - 1) * num_bits(E) = num_bits(E').
  • (C2) หากเป็น is_complex(operand) or is_complex(result) ให้ทำดังนี้ is_complex(operand) and is_complex(result)

ตัวอย่าง

// %operand: 0x0123456789ABCDEF
%result = "stablehlo.bitcast_convert"(%operand) : (tensor<f64>) -> tensor<4xf16>
// %result: [0xCDEF, 0x89AB, 0x4567, 0x0123] // little-endian representation

ตัวอย่างเพิ่มเติม

broadcast_in_dim

อรรถศาสตร์

ขยายมิติข้อมูลและ/หรืออันดับของ tensor อินพุตโดยการทำซ้ำข้อมูลใน tensor ของ operand และสร้าง tensor ของ result อย่างเป็นทางการ result[result_index] = operand[operand_index] สำหรับ d ทั้งหมดใน axes(operand):

  • operand_index[d] = 0 หากเป็น dim(operand, d) = 1
  • operand_index[d] = result_index[broadcast_dimensions[d]] ไม่เช่นนั้น

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor หรือ tensor เชิงปริมาณ (C1-C2), (C5-C6)
(I2) broadcast_dimensions ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C2-C6)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือ tensor เชิงปริมาณ (C1), (C3), (C5-C6)

ข้อจำกัด

  • (C1) element_type(result) มอบให้โดย
    • element_type(operand) หากเป็น !is_per_axis_quantized(operand)
    • element_type(operand) ยกเว้น quantization_dimension(operand), scales(operand) และ zero_points(operand) อาจแตกต่างจาก quantization_dimension(result), scales(result) และ zero_points(result)
  • (C2) size(broadcast_dimensions) = rank(operand)
  • (C3) 0 <= broadcast_dimensions < rank(result)
  • (C4) is_unique(broadcast_dimensions)
  • (C5) สำหรับ d ทั้งหมดใน axes(operand):
    • dim(operand, d) = 1หรือ
    • dim(operand, d) = dim(result, broadcast_dimensions[d]).
  • (C6) หาก is_per_axis_quantized(result):
    • quantization_dimension(result) = broadcast_dimensions[quantization_dimension(operand)].
    • หากเป็น dim(operand, quantization_dimension(operand)) = 1 ให้ scales(result)[i] = scales(operand)[0] and zero_points(result)[i] = zero_points(operand)[0] for i in range(dim(result, quantization_dimension(result)))

ตัวอย่าง

// %operand: [
//            [1, 2, 3]
//           ]
%result = "stablehlo.broadcast_in_dim"(%operand) {
  broadcast_dimensions = array<i64: 2, 1>
} : (tensor<1x3xi32>) -> tensor<2x3x2xi32>
// %result: [
//            [
//             [1, 1],
//             [2, 2],
//             [3, 3]
//            ],
//            [
//             [1, 1],
//             [2, 2],
//             [3, 3]
//            ]
//          ]

ตัวอย่างเพิ่มเติม

เคส

อรรถศาสตร์

สร้างเอาต์พุตจากการเรียกใช้ฟังก์ชันเดียวจาก branches โดยขึ้นอยู่กับค่าของ index อย่างเป็นทางการ result = selected_branch() ซึ่ง

  • selected_branch = branches[index] หากเป็น 0 <= index < size(branches)
  • selected_branch = branches[-1] ไม่เช่นนั้น

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) index Tensor แบบ 0 มิติของประเภท si32
(I2) branches จำนวนฟังก์ชันแปรผัน (C1-C4)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
results จำนวน tensors แบบแปรผัน, tensors เชิงปริมาณหรือโทเค็น (C4)

ข้อจำกัด

  • (C1) 0 < size(branches)
  • (C2) input_types(branches...) = []
  • (C3) same(output_types(branches...))
  • (C4) type(results...) = output_types(branches[0])

ตัวอย่าง

// %index: -1
// %result_branch0: [0, 0]
// %result_branch1: [1, 1]
%result0, %result1 = "stablehlo.case"(%index) ({
  "stablehlo.return"(%result_branch0, %result_branch0) : (tensor<2xi64>, tensor<2xi64>) -> ()
}, {
  "stablehlo.return"(%result_branch1, %result_branch1) : (tensor<2xi64>, tensor<2xi64>) -> ()
}) : (tensor<i32>) -> (tensor<2xi64>, tensor<2xi64>)
// %result0: [1, 1]
// %result1: [1, 1]

ตัวอย่างเพิ่มเติม

Cbrt

อรรถศาสตร์

ดำเนินการรากลูกบาศก์ตามองค์ประกอบใน tensor ของ operand และสร้าง Tensor result ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับแบบลอยตัว: rootn(x, 3) จาก IEEE-754
  • สำหรับจำนวนเชิงซ้อน: รากที่สามเชิงซ้อน
  • สำหรับประเภทที่วัดปริมาณ: dequantize_op_quantize(cbrt, operand, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) baseline_type(operand) = baseline_type(result)

ตัวอย่าง

// %operand: [0.0, 1.0, 8.0, 27.0]
%result = "stablehlo.cbrt"(%operand) : (tensor<4xf64>) -> tensor<4xf64>
// %result: [0.0, 1.0, 2.0, 3.0]

ตัวอย่างเพิ่มเติม

Ceil

อรรถศาสตร์

สร้าง ceil ตามองค์ประกอบของ tensor ของ operand และสร้าง tensor แบบ result ใช้การดำเนินการ roundToIntegralTowardPositive จากข้อกำหนด IEEE-754 สำหรับประเภทที่แบ่งปริมาณแล้ว จะแสดงผล dequantize_op_quantize(ceil, operand, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) baseline_type(operand) = baseline_type(result)

ตัวอย่าง

// %operand: [-0.8166, -0.2530, 0.2530, 0.8166, 2.0]
%result = "stablehlo.ceil"(%operand) : (tensor<5xf32>) -> tensor<5xf32>
// %result: [-0.0, -0.0, 1.0, 1.0, 2.0]

ตัวอย่างเพิ่มเติม

Cholesky

อรรถศาสตร์

คำนวณการแตกตัวของ Cholesky ของกลุ่มเมทริกซ์

อย่างเป็นทางการสำหรับ i ทั้งหมดใน index_space(result) result[i0, ..., iR-3, :, :] คือการแตกตัวแบบ Cholesky ของ a[i0, ..., iR-3, :, :] ในรูปแบบของเมทริกซ์รูปสามเหลี่ยมล่าง (หาก lower เป็น true) หรือเมทริกซ์รูปสามเหลี่ยมบน (หาก lower เป็น false) ค่าเอาต์พุตในสามเหลี่ยมตรงข้าม ได้แก่ สามเหลี่ยมด้านบนที่เข้มงวดหรือสามเหลี่ยมล่างสุดที่เกี่ยวข้องจะเป็นตัวกำหนดการติดตั้งใช้งาน

หากมี i อยู่โดยที่เมทริกซ์อินพุตไม่ใช่เมทริกซ์ค่าบวกลบของ Hermitian จะไม่มีการกำหนดลักษณะการทำงาน

สำหรับประเภทที่แบ่งปริมาณแล้ว จะแสดงผล dequantize_op_quantize(lambda operand: cholesky(operand, lower), a, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) a tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1-C3)
(I2) lower ค่าคงที่ tensor แบบ 0 มิติของประเภท i1

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) baseline_type(a) = baseline_type(result)
  • (C2) 2 <= rank(a)
  • (C3) dim(a, -2) = dim(a, -1)

ตัวอย่าง

// %a: [
//      [1.0, 2.0, 3.0],
//      [2.0, 20.0, 26.0],
//      [3.0, 26.0, 70.0]
//     ]
%result = "stablehlo.cholesky"(%a) {
  lower = true
} : (tensor<3x3xf32>) -> tensor<3x3xf64>
// %result: [
//           [1.0, 0.0, 0.0],
//           [2.0, 4.0, 0.0],
//           [3.0, 5.0, 6.0]
//          ]

แคลมป์

อรรถศาสตร์

ยึดทุกองค์ประกอบของ Tensor operand ระหว่างค่าต่ำสุดและสูงสุดและสร้าง Tensor result อย่างเป็นทางการคือ result[result_index] = minimum(maximum(operand[result_index], min_element), max_element) ที่ min_element = rank(min) = 0 ? min[] : min[result_index], max_element = rank(max) = 0 ? max[] : max[result_index] สำหรับประเภทที่วัดปริมาณ ให้ใช้ dequantize_op_quantize(clamp, min, operand, max, type(result))

การกำหนดลำดับด้วยจำนวนเชิงซ้อนเกี่ยวข้องกับความหมายที่คาดไม่ถึง ดังนั้นในอนาคตเราจึงวางแผนที่จะนำการรองรับจำนวนเชิงซ้อนออกสำหรับการดำเนินการนี้ (#560)

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) min tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1), (C3)
(I2) operand tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1-C4)
(I3) max tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C2), (C3)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C4)

ข้อจำกัด

  • (C1) rank(min) = 0 or shape(min) = shape(operand)
  • (C2) rank(max) = 0 or shape(max) = shape(operand)
  • (C3) baseline_element_type(min) = baseline_element_type(operand) = baseline_element_type(max)
  • (C4) baseline_type(operand) = baseline_type(result)

ตัวอย่าง

// %min: [5, 10, 15]
// %operand: [3, 13, 23]
// %max: [10, 15, 20]
%result = "stablehlo.clamp"(%min, %operand, %max) : (tensor<3xi32>, tensor<3xi32>, tensor<3xi32>) -> tensor<3xi32>
// %result: [5, 13, 20]

ตัวอย่างเพิ่มเติม

collective_broadcast

อรรถศาสตร์

ภายในกลุ่มกระบวนการแต่ละกลุ่มในตารางกริดกระบวนการ StableHLO ให้ส่งค่าของ operand Tensor จากกระบวนการต้นทางไปยังกระบวนการเป้าหมายและสร้าง Tensor result

การดําเนินการนี้จะแบ่งตารางกริดการประมวลผลของ StableHLO เป็น process_groups ซึ่งมีคำจำกัดความดังนี้

  • cross_replica(replica_groups) หากเป็น channel_id <= 0
  • cross_partition(replica_groups) หากเป็น channel_id > 0

หลังจากนั้น result@process จะมอบให้โดย:

  • operand@process_groups[i, 0] หากมี i เพื่อให้กระบวนการอยู่ใน process_groups[i]
  • broadcast_in_dim(constant(is_quantized(result) ? quantize(0, element_type(result)) : 0, element_type(result)), [], type(result)) ไม่เช่นนั้น

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C3)
(I2) replica_groups จำนวนแปรผันของค่าคงที่ tensor 1 มิติของประเภท si64 (C1), (C2)
(I3) channel_id ค่าคงที่ประเภท si64

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C3)

ข้อจำกัด

  • (C1) is_unique(replica_groups)
  • (C2) 0 <= replica_groups < N โดยให้คำนิยาม N เป็น
    • num_replicas หากมีการใช้ cross_replica
    • num_partitions หากมีการใช้ cross_partition
  • (C3) type(result) = type(operand)

ตัวอย่าง

// num_replicas: 4
// num_partitions: 1
// %operand@(0, 0): [[1, 2]]
// %operand@(1, 0): [[3, 4]]
// %operand@(2, 0): [[5, 6]]
// %operand@(3, 0): [[7, 8]]
%result = "stablehlo.collective_broadcast"(%operand) {
  replica_groups = dense<[[2, 1]]> : tensor<1x2xi64>,
  channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
} : (tensor1x2xi64>) -> tensor<1x2xi64>
// %result@(0, 0): [[0, 0]]
// %result@(1, 0): [[5, 6]]
// %result@(2, 0): [[5, 6]]
// %result@(3, 0): [[0, 0]]

collective_permute

อรรถศาสตร์

ภายในกลุ่มกระบวนการแต่ละกลุ่มในตารางกริดกระบวนการ StableHLO ระบบจะส่งค่าของ Tensor จาก operand จากกระบวนการต้นทางไปยังกระบวนการเป้าหมายและสร้าง Tensor result

การดําเนินการนี้จะแบ่งตารางกริดการประมวลผลของ StableHLO เป็น process_groups ซึ่งมีคำจำกัดความดังนี้

  • cross_replica(source_target_pairs) หากเป็น channel_id <= 0
  • cross_partition(source_target_pairs) หากเป็น channel_id > 0

หลังจากนั้น result@process จะมอบให้โดย:

  • operand@process_groups[i, 0] หากมี i ก็แสดงว่า process_groups[i, 1] = process
  • broadcast_in_dim(constant(is_quantized(result) ? quantize(0, element_type(result)) : 0, element_type(result)), [], type(result)) ไม่เช่นนั้น

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C5)
(I2) source_target_pairs ค่าคงที่ tensor แบบ 2 มิติของประเภท si64 (C1-C4)
(I3) channel_id ค่าคงที่ประเภท si64

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) dim(source_target_pairs, 1) = 2
  • (C2) is_unique(source_target_pairs[:, 0])
  • (C3) is_unique(source_target_pairs[:, 1])
  • (C4) 0 <= source_target_pairs < N โดยให้คำนิยาม N เป็น
    • num_replicas หากมีการใช้ cross_replica
    • num_partitions หากมีการใช้ cross_partition
  • (C5) type(result) = type(operand)

ตัวอย่าง

// num_replicas: 3
// num_partitions: 1
// %operand@(0, 0): [[1, 2], [3, 4]]
// %operand@(1, 0): [[5, 6], [7, 8]]
// %operand@(2, 0): [[9, 10], [11, 12]]
%result = "stablehlo.collective_permute"(%operand) {
  source_target_pairs = dense<[[0, 1], [1, 2]]> : tensor<2x2xi64>,
  channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
} : (tensor<2x2xi64>) -> tensor<2x2xi64>
//
// %result@(0, 0): [[0, 0], [0, 0]]
// %result@(1, 0): [[1, 2], [3, 4]]
// %result@(2, 0): [[5, 6], [7, 8]]

ตัวอย่างเพิ่มเติม

เปรียบเทียบ

อรรถศาสตร์

ทำการเปรียบเทียบ Tensor ตาม lhs และ rhs ตาม comparison_direction และ compare_type และสร้าง Tensor result

ค่าของ comparison_direction และ compare_type มีความหมายต่อไปนี้

สำหรับประเภทองค์ประกอบบูลีนและจำนวนเต็ม

  • EQ: lhs = rhs
  • NE: lhs != rhs
  • GE: lhs >= rhs
  • GT: lhs > rhs
  • LE: lhs <= rhs
  • LT: lhs < rhs

สำหรับประเภทองค์ประกอบจุดลอยตัวที่มี compare_type = FLOAT การทดสอบจะใช้การดำเนินการ IEEE-754 ต่อไปนี้

  • EQ: compareQuietEqual
  • NE: compareQuietNotEqual
  • GE: compareQuietGreaterEqual
  • GT: compareQuietGreater
  • LE: compareQuietLessEqual
  • LT: compareQuietLess

สำหรับประเภทองค์ประกอบจุดลอยตัวที่มี compare_type = TOTALORDER ฝั่งตรงข้ามจะใช้ชุดค่าผสมของการดำเนินการ totalOrder และ compareQuietEqual จาก IEEE-754

สําหรับประเภทองค์ประกอบที่ซับซ้อน การเปรียบเทียบพจนานุกรมของคู่ (real, imag) จะดําเนินการโดยใช้ comparison_direction และ compare_type ที่ระบุ การกำหนดลำดับด้วยจำนวนเชิงซ้อนเกี่ยวข้องกับความหมายที่คาดไม่ถึง ดังนั้นในอนาคตเราวางแผนที่จะนำการสนับสนุนจำนวนเชิงซ้อนออกเมื่อ comparison_direction คือ GE, GT, LE หรือ LT (#560)

สำหรับประเภทที่วัดปริมาณ ดำเนินการ dequantize_compare(lhs, rhs, comparison_direction)

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) lhs tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1-C3)
(I2) rhs tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1-C2)
(I3) comparison_direction enum ของ EQ, NE, GE, GT, LE และ LT
(I4) compare_type enum ของ FLOAT, TOTALORDER, SIGNED และ UNSIGNED (C3)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของประเภทบูลีน (C2)

ข้อจำกัด

  • (C1) baseline_element_type(lhs) = baseline_element_type(rhs)
  • (C2) shape(lhs) = shape(rhs) = shape(result)
  • (C3) compare_type ให้คำจำกัดความดังนี้
    • SIGNED หากเป็น is_signed_integer(element_type(lhs))
    • UNSIGNED หากเป็น is_unsigned_integer(element_type(lhs)) or is_boolean(element_type(lhs))
    • FLOAT หรือ TOTALORDER หากเป็น is_float(element_type(lhs))
    • FLOAT หากเป็น is_complex(element_type(lhs))

ตัวอย่าง

// %lhs: [1.0, 3.0]
// %rhs: [1.1, 2.9]
%result = "stablehlo.compare"(%lhs, %rhs) {
  comparison_direction = #stablehlo<comparison_direction LT>,
  compare_type = #stablehlo<comparison_type FLOAT>
} : (tensor<2xf32>, tensor<2xf32>) -> tensor<2xi1>
// %result: [true, false]

ตัวอย่างเพิ่มเติม

ซับซ้อน

อรรถศาสตร์

ทำการแปลงตามองค์ประกอบเป็นค่าที่ซับซ้อนจากคู่ของค่าจริงและค่าจินตภาพ lhs และ rhs แล้วสร้าง Tensor result

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) lhs Tensor ประเภท f32 หรือ f64 (C1-C3)
(I2) rhs Tensor ประเภท f32 หรือ f64 (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result Tensor ของประเภทเชิงซ้อน (C2), (C3)

ข้อจำกัด

  • (C1) type(lhs) = type(rhs)
  • (C2) shape(result) = shape(lhs)
  • (C3) element_type(result) ประเภท complex<E> ที่ E = element_type(lhs)

ตัวอย่าง

// %lhs: [1.0, 3.0]
// %rhs: [2.0, 4.0]
%result = "stablehlo.complex"(%lhs, %rhs) : (tensor<2xf64>, tensor<2xf64>) -> tensor<2xcomplex<f64>>
// %result: [(1.0, 2.0), (3.0, 4.0)]

ตัวอย่างเพิ่มเติม

การผสม

อรรถศาสตร์

สรุปการดำเนินการที่สร้างขึ้น (ประกอบ) ของการดำเนินการ StableHLO อื่นๆ ที่รับ inputs และ composite_attributes และการสร้าง results อรรถศาสตร์ของตัวเลือกมีการใช้งานโดยแอตทริบิวต์ decomposition คุณแทนที่การดำเนินการ composite ด้วยการแยกย่อยได้โดยไม่ต้องเปลี่ยนความหมายของโปรแกรม ในกรณีที่อินไลน์การแตกตัวไม่ตรงตามความหมายที่ตรงกัน ให้ใช้ custom_call

ช่อง version (ค่าเริ่มต้นเป็น 0) ใช้เพื่อแสดงถึงการเปลี่ยนแปลงทางอรรถศาสตร์ของคอมโพสิต

อินพุต

ค่ายเพลง ชื่อ ประเภท
(I1) inputs จำนวนค่าตัวแปร
(I2) name ค่าคงที่ประเภท string
(I3) composite_attributes พจนานุกรมแอตทริบิวต์
(I4) decomposition ค่าคงที่ประเภท string
(I5) version ค่าคงที่ประเภท si32

เอาต์พุต

ชื่อ ประเภท
results จำนวนค่าตัวแปร

ข้อจำกัด

  • (C1) is_namespaced_op_name(name)
  • (C2) is_defined_in_parent_scope(decomposition)
  • (C3) types(inputs...) == input_types(decomposition)
  • (C4) types(results...) == output_types(decomposition)

ตัวอย่าง

%results = "stablehlo.composite"(%input0, %input1) {
  name = "my_namespace.my_op",
  composite_attributes = {
    my_attribute = "my_value"
  },
  decomposition = @my_op,
  version = 1 : i32
} : (tensor<f32>, tensor<f32>) -> tensor<f32>

ตัวอย่างเพิ่มเติม

concatenate

อรรถศาสตร์

เชื่อมต่อ inputs ตามมิติข้อมูล dimension ในลำดับเดียวกับอาร์กิวเมนต์ที่ระบุ และสร้าง Tensor result ซึ่งก็คือ result[i0, ..., id, ..., iR-1] = inputs[k][i0, ..., kd, ..., iR-1] ซึ่งเป็น

  1. id = d0 + ... + dk-1 + kd.
  2. d เท่ากับ dimension และ d0, ... เป็นขนาดมิติข้อมูลที่ d ของ inputs

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) inputs จำนวนตัวแปรของ tensors หรือ tensor แบบต่อ tensor เชิงปริมาณ (C1-C6)
(I2) dimension ค่าคงที่ประเภท si64 (C2), (C4), (C6)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C5-C6)

ข้อจำกัด

  • (C1) same(element_type(inputs...))
  • (C2) same(shape(inputs...)) ยกเว้น dim(inputs..., dimension)
  • (C3) 0 < size(inputs)
  • (C4) 0 <= dimension < rank(inputs[0])
  • (C5) element_type(result) = element_type(inputs[0])
  • (C6) shape(result) = shape(inputs[0]) ยกเว้นในกรณีต่อไปนี้
    • dim(result, dimension) = dim(inputs[0], dimension) + ....

ตัวอย่าง

// %input0: [[1, 2], [3, 4], [5, 6]]
// %input1: [[7, 8]]
%result = "stablehlo.concatenate"(%input0, %input1) {
  dimension = 0 : i64
} : (tensor<3x2xi64>, tensor<1x2xi64>) -> tensor<4x2xi64>
// %result: [[1, 2], [3, 4], [5, 6], [7, 8]]

ตัวอย่างเพิ่มเติม

ค่าคงที่

อรรถศาสตร์

สร้าง Tensor output จาก value คงที่

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) value ค่าคงที่ (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
output tensor หรือ tensor เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) type(value) = type(output)

ตัวอย่าง

%output = "stablehlo.constant"() {
  value = dense<[[0.0, 1.0], [2.0, 3.0]]> : tensor<2x2xf32>
} : () -> tensor<2x2xf32>
// %output: [[0.0, 1.0], [2.0, 3.0]]

ตัวอย่างเพิ่มเติม

ทำให้เกิด Conversion

อรรถศาสตร์

ทำการแปลงตามองค์ประกอบจากประเภทองค์ประกอบหนึ่งไปเป็นอีกประเภทด้วย tensor ของ operand และสร้าง tensor ของ result

สำหรับ Conversion boolean-to-any-supported-type ค่า false จะแปลงเป็น 0 และจะแปลงค่า true เป็น 1 สำหรับ Conversion any-supported-type-to-boolean ค่า 0 จะถูกแปลงเป็น false และค่าที่ไม่ใช่ 0 จะถูกแปลงเป็น true ดูวิธีการทำงานสำหรับประเภทที่ซับซ้อนได้ที่ด้านล่าง

สำหรับ Conversion ที่เกี่ยวข้องกับ integer-to-integer, integer-to-Floing-point หรือ Floating-point-to-Floing-point หากค่าแหล่งที่มาแสดงในประเภทปลายทางได้ตรงทุกประการ ค่าผลลัพธ์คือการเป็นตัวแทนที่แน่นอน มิฉะนั้น ลักษณะการทำงานจะเป็น TBD (#180)

สำหรับ Conversion ที่เกี่ยวข้องกับfloating-point-to-integer ระบบจะตัดส่วนที่เป็นเศษส่วนให้สั้นลง หากค่าที่ตัดออกไม่สามารถแสดงในประเภทปลายทางได้ ลักษณะการทำงานจะเป็น TBD (#180)

Conversion ที่เกี่ยวข้องกับ complex-to-complex ใช้ลักษณะการทำงานเดียวกันกับ Conversion ของ Floing-point-to-Floing-point สำหรับการแปลงส่วนจริงและส่วนจินตภาพ

สำหรับ Conversion แบบ complex-to-any-other-type และ complex-to-any-other-type ระบบจะไม่สนใจค่าจินตภาพต้นทางหรือค่าจินตภาพปลายทางเป็น 0 ตามลำดับ Conversion ของส่วนจริงจะเป็นไปตาม Conversion จุดลอยตัว

ในหลักการแล้ว การดำเนินการนี้อาจบอกถึงการแบ่งข้อมูล (การแปลงจาก tensors เชิงปริมาณเป็น tensors แบบปกติ) การคำนวณเชิงปริมาณ (การแปลงจาก tensor ปกติเป็น tensors เชิงปริมาณ) และการคำนวณซ้ำ (การแปลงระหว่าง tensors เชิงปริมาณ) แต่ในขณะนี้เราได้ทำการดำเนินการเฉพาะสำหรับ Use Case ดังกล่าว uniform_dequantize สำหรับ Use Case แรก และ uniform_quantize สำหรับ Use Case ที่สองและ 3 ในอนาคต การดำเนินการ 2 อย่างนี้อาจผสานรวมเป็น convert (#1576)

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand Tensor (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result Tensor (C1)

ข้อจำกัด

  • (C1) shape(operand) = shape(result)

ตัวอย่าง

// %operand: [-1, 0, 1]
%result = "stablehlo.convert"(%operand) : (tensor<3xi64>) -> tensor<3xcomplex<f64>>
// %result: [(-1.0, 0.0), (0.0, 0.0), (1.0, 0.0)]

ตัวอย่างเพิ่มเติม

Convolution

อรรถศาสตร์

การประมวลผลจะจุดผลิตภัณฑ์ระหว่างกรอบเวลาของ lhs และชิ้นส่วนของ rhs และสร้าง result แผนภาพต่อไปนี้แสดงวิธีที่องค์ประกอบใน result คํานวณจาก lhs และ rhs โดยใช้ตัวอย่างที่เป็นรูปธรรม

Convolution

พิจารณาการจัดเฟรมอินพุตใหม่ต่อไปนี้อย่างเป็นทางการใน lhs เพื่อให้แสดงกรอบเวลาของ lhs ได้

  • lhs_window_dimensions = lhs_shape(dim(lhs, input_batch_dimension), dim(rhs, kernel_spatial_dimensions), dim(lhs, input_feature_dimension)).
  • lhs_window_strides = lhs_shape(1, window_strides, 1).
  • lhs_padding = lhs_shape([0, 0], padding, [0, 0]).
  • lhs_base_dilations = lhs_shape(1, lhs_dilation, 1).
  • lhs_window_dilations = lhs_shape(1, rhs_dilation, 1).

การจัดเฟรมใหม่นี้ใช้ฟังก์ชันตัวช่วยต่อไปนี้

  • lhs_shape(n, hw, c) = permute([n] + hw + [c], [input_batch_dimension] + input_spatial_dimensions + [input_feature_dimension]).
  • result_shape(n1, hw, c1) = permute([n1] + hw + [c1], [output_batch_dimension] + output_spatial_dimensions + [output_feature_dimension]).
  • permute([j0, j1, ..., jR-1], permutation) = [i0, i1, ..., iR-1] ที่ j[d] = i[permutation[d]]

หากเป็น feature_group_count = 1 และ batch_group_count = 1 สำหรับ output_spatial_index ทั้งหมดใน index_space(dim(result, output_spatial_dimensions...)) result[result_shape(:, output_spatial_index, :)] = dot_product โดยที่:

  • padding_value = constant(0, element_type(lhs)).
  • padded_lhs = pad(lhs, padding_value, lhs_padding[:, 0], lhs_padding[:, 1], lhs_base_dilations - 1).
  • lhs_window_start = lhs_shape(0, output_spatial_index, 0) * lhs_window_strides.
  • lhs_window = slice(padded_lhs, lhs_window_start, lhs_window_start + lhs_window_dimensions, lhs_window_dilations).
  • reversed_lhs_window = reverse(lhs_window, [input_spatial_dimensions[dim] for dim in range(size(window_reversal)) if window_reversal[dim] = true]) ดูเหมือนว่าฟีเจอร์นี้ไม่ได้ใช้งาน ดังนั้นในอนาคตเราจึงวางแผนที่จะนำฟีเจอร์นี้ออก (#1181)
  • dot_product = dot_general(reversed_lhs_window, rhs, lhs_batching_dimensions=[], lhs_contracting_dimensions=input_spatial_dimensions + [input_feature_dimension], rhs_batching_dimensions=[], rhs_contracting_dimensions=kernel_spatial_dimensions + [kernel_input_feature_dimension]).

หาก feature_group_count > 1:

  • lhses = split(lhs, feature_group_count, input_feature_dimension).
  • rhses = split(rhs, feature_group_count, kernel_output_feature_dimension).
  • results... = convolution(lhses..., rhses..., ..., feature_group_count=1, ...).
  • result = concatenate(results, output_feature_dimension).

หาก batch_group_count > 1:

  • lhses = split(lhs, batch_group_count, input_batch_dimension).
  • rhses = split(rhs, batch_group_count, kernel_output_feature_dimension).
  • results... = convolution(lhses..., rhses..., ..., batch_group_count=1, ...).
  • result = concatenate(results, output_feature_dimension)

สำหรับประเภทที่วัดปริมาณ ให้ดำเนินการ dequantize_op_quantize( lambda lhs, rhs: convolution(lhs, rhs, window_strides, padding, lhs_dilation, rhs_dilation, window_reversal, input_batch_dimension, input_feature_dimension, input_spatial_dimensions, kernel_input_feature_dimension, kernel_output_feature_dimension, kernel_spatial_dimensions, output_batch_dimension, output_feature_dimension, output_spatial_dimensions, feature_group_count, batch_group_count, precision_config), lhs, rhs, type(result))

สำหรับประเภทแบบผสม ให้ดำเนินการ hybrid_dequantize_then_op( lambda lhs, rhs: convolution(lhs, rhs, window_strides, padding, lhs_dilation, rhs_dilation, window_reversal, input_batch_dimension, input_feature_dimension, input_spatial_dimensions, kernel_input_feature_dimension, kernel_output_feature_dimension, kernel_spatial_dimensions, output_batch_dimension, output_feature_dimension, output_spatial_dimensions, feature_group_count, batch_group_count, precision_config), lhs, rhs)

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) lhs tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1), (C10-C11), (C14) (C25), (C27-C28), (C31-C32) (C34)
(I2) rhs tensor หรือ tensor เชิงปริมาณ (C1), (C14-C16), (C25), (C27-C29), (C31-C34)
(I3) window_strides ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C2-C3), (C25)
(I4) padding ค่าคงที่ tensor แบบ 2 มิติของประเภท si64 (C4), (C25)
(I5) lhs_dilation ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C5-C6), (C25)
(I6) rhs_dilation ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C7-C8), (C25)
(I7) window_reversal ค่าคงที่ tensor แบบ 1 มิติของประเภท i1 (C9)
(I8) input_batch_dimension ค่าคงที่ประเภท si64 (C10), (C13), (C25)
(I9) input_feature_dimension ค่าคงที่ประเภท si64 (C11), (C13-C14)
(I10) input_spatial_dimensions ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C12), (C13), (C25)
(I11) kernel_input_feature_dimension ค่าคงที่ประเภท si64 (C14) (C18)
(I12) kernel_output_feature_dimension ค่าคงที่ประเภท si64 (C15-C16), (C18), (C25), (C29)
(I13) kernel_spatial_dimensions ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C17-C18), (C25)
(I14) output_batch_dimension ค่าคงที่ประเภท si64 (C20) (C25)
(15) output_feature_dimension ค่าคงที่ประเภท si64 (C20), (C25), (C30)
(I16) output_spatial_dimensions ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C19-C20), (C25)
(I17) feature_group_count ค่าคงที่ประเภท si64 (C11), (C14), (C16), (C21), (C23)
(I18) batch_group_count ค่าคงที่ประเภท si64 (C10), (C15), (C22), (C23), (C25)
(I19) precision_config จำนวน Enum ที่แตกต่างกันของ DEFAULT, HIGH และ HIGHEST (C24)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือ tensor เชิงปริมาณ (C25-C28), (C30), (C32-34)

ข้อจำกัด

  • (C1) N = rank(lhs) = rank(rhs)
  • (C2) size(window_strides) = N - 2
  • (C3) 0 < window_strides
  • (C4) shape(padding) = [N - 2, 2]
  • (C5) size(lhs_dilation) = N - 2
  • (C6) 0 < lhs_dilation
  • (C7) size(rhs_dilation) = N - 2
  • (C8) 0 < rhs_dilation
  • (C9) size(window_reversal) = N - 2
  • (C10) dim(lhs, input_batch_dimension) % batch_group_count = 0
  • (C11) dim(lhs, input_feature_dimension) % feature_group_count = 0
  • (C12) size(input_spatial_dimensions) = N - 2
  • (C13) ให้ input_dimensions = [input_batch_dimension] + input_spatial_dimensions + [input_feature_dimension]:
    • is_unique(input_dimensions).
    • 0 <= input_dimensions < N.
  • (C14) dim(rhs, kernel_input_feature_dimension) = dim(lhs, input_feature_dimension) / feature_group_count
  • (C15) dim(rhs, kernel_output_feature_dimension) % batch_group_count = 0
  • (C16) dim(rhs, kernel_output_feature_dimension) % feature_group_count = 0
  • (C17) size(kernel_spatial_dimensions) = N - 2
  • (C18) ให้ kernel_dimensions = kernel_spatial_dimensions + [kernel_input_feature_dimension] + [kernel_output_feature_dimension]:
    • is_unique(kernel_dimensions).
    • 0 <= kernel_dimensions < N.
  • (C19) size(output_spatial_dimensions) = N - 2
  • (C20) ให้ output_dimensions = [output_batch_dimension] + output_spatial_dimensions + [output_feature_dimension]:
    • is_unique(output_dimensions).
    • 0 <= output_dimensions < N.
  • (C21) 0 < feature_group_count
  • (C22) 0 < batch_group_count
  • (C23) feature_group_count = 1 or batch_group_count = 1
  • (C24) size(precision_config) = 2
  • (C25) dim(result, result_dim) ให้คำจำกัดความดังนี้
    • dim(lhs, input_batch_dimension) / batch_group_count หากเป็น result_dim = output_batch_dimension
    • dim(rhs, kernel_output_feature_dimension) หากเป็น result_dim = output_feature_dimension
    • num_windows ไม่เช่นนั้นให้ทำดังนี้
    • output_spatial_dimensions[spatial_dim] = result_dim.
    • lhs_dim = input_spatial_dimensions[spatial_dim].
    • rhs_dim = kernel_spatial_dimensions[spatial_dim].
    • dilated_input_shape[lhs_dim] = dim(lhs, lhs_dim) = 0 ? 0 : (dim(lhs, lhs_dim) - 1) * lhs_dilation[spatial_dim] + 1.
    • padded_input_shape[lhs_dim] = padding[spatial_dim, 0] + dilated_input_shape[lhs_dim] + padding[spatial_dim, 1].
    • dilated_window_shape[lhs_dim] = dim(rhs, rhs_dim) = 0 ? 0 : (dim(rhs, rhs_dim) - 1) * rhs_dilation[spatial_dim] + 1.
    • is_empty_window[lhs_dim] = padded_input_shape[lhs_dim] = 0 || dilated_window_shape[lhs_dim] > padded_input_shape[lhs_dim].
    • num_windows = is_empty_window[lhs_dim] ? 0 : floor((padded_input_shape[lhs_dim] - dilated_window_shape[lhs_dim]) / window_strides[spatial_dim]) + 1.
  • (C26) rank(result) = N
  • หากการดำเนินการใช้ Tensor แบบไม่วัดปริมาณจะดำเนินการต่อไปนี้
    • (C27) element_type(lhs) = element_type(rhs) = element_type(result)
  • หากการดำเนินการใช้ Tensor เชิงปริมาณ ให้ทำดังนี้
    • (C28) is_quantized(lhs) = is_quantized(result) and is_quantized(rhs)
    • (C29) หากเป็น is_per_axis_quantized(rhs) ให้จ่าย quantization_dimension(rhs) = kernel_output_feature_dimension
    • (C30) หากเป็น is_per_axis_quantized(result) ให้ทำดังนี้ quantization_dimension(result) = output_feature_dimension
    • หาก is_quantized(lhs):
    • (C31) storage_type(lhs) = storage_type(rhs)
    • (C32) expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
    • (C33) หากเป็น is_per_tensor_quantized(rhs) ให้ทำดังนี้ is_per_tensor_quantized(result)
    • หาก !is_quantized(lhs):
    • (C34) element_type(lhs) = expressed_type(rhs) = element_type(result)

ตัวอย่าง

// %lhs: [[
//        [
//          [1], [2], [5], [6]
//        ],
//        [
//          [3], [4], [7], [8]
//        ],
//        [
//          [10], [11], [14], [15]
//        ],
//        [
//          [12], [13], [16], [17]
//        ]
//      ]]
//
// %rhs: [
//        [[[1]], [[1]], [[1]]],
//        [[[1]], [[1]], [[1]]],
//        [[[1]], [[1]], [[1]]]
//       ]
%result = "stablehlo.convolution"(%lhs, %rhs) {
  window_strides = array<i64: 4, 4>,
  padding = dense<0> : tensor<2x2xi64>,
  lhs_dilation = array<i64: 2, 2>,
  rhs_dilation = array<i64: 1, 1>,
  window_reversal = array<i1: false, false>,
  // In the StableHLO dialect, dimension numbers are encoded via:
  // `[<input dimensions>]x[<kernel dimensions>]->[output dimensions]`.
  // "b" is batch dimension, "f" is feature dimension,
  // "i" is input feature dimension, "o" is output feature dimension,
  // "0/1/etc" are spatial dimensions.
  dimension_numbers = #stablehlo.conv<[b, 0, 1, f]x[0, 1, i, o]->[b, 0, 1, f]>,
  batch_group_count = 1 : i64,
  feature_group_count = 1 : i64,
  precision_config = [#stablehlo<precision DEFAULT>, #stablehlo<precision DEFAULT>]
} : (tensor<1x4x4x1xi64>, tensor<3x3x1x1xi64>) -> tensor<1x2x2x1xi64>
// %result: [[
//            [[10], [26]],
//            [[46], [62]]
//          ]]

ตัวอย่างเพิ่มเติม

โคไซน์

อรรถศาสตร์

ดำเนินการหาโคไซน์ตามองค์ประกอบบน tensor ของ operand และสร้าง Tensor result ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับแบบลอยตัว: cos จาก IEEE-754
  • สำหรับจำนวนเชิงซ้อน: โคไซน์เชิงซ้อน
  • สำหรับประเภทที่นับจำนวน: dequantize_op_quantize(cosine, operand, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) baseline_type(operand) = baseline_type(result)

ตัวอย่าง

// %operand: [
//            [0.0, 1.57079632],       // [0, pi/2]
//            [3.14159265, 4.71238898] // [pi, 3pi/2]
//           ]
%result = "stablehlo.cosine"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[1.0, 0.0], [-1.0, 0.0]]

ตัวอย่างเพิ่มเติม

count_leading_zeros

อรรถศาสตร์

นับจำนวนตามองค์ประกอบของจำนวนบิตนำหน้า 0 ใน tensor ของ operand และสร้าง tensor ของ result

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand Tensor ของประเภทจำนวนเต็ม (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result Tensor ของประเภทจำนวนเต็ม (C1)

ข้อจำกัด

  • (C1) type(operand) = type(result)

ตัวอย่าง

// %operand: [[0, 1], [128, -1]]
%result = "stablehlo.count_leading_zeros"(%operand) : (tensor<2x2xi64>) -> tensor<2x2xi64>
// %result: [[64, 63], [56, 0]]

ตัวอย่างเพิ่มเติม

custom_call

อรรถศาสตร์

สรุปการดำเนินการ call_target_name ที่กำหนดการติดตั้งใช้งานซึ่งใช้เวลา inputs และ called_computations และสร้าง results คุณสามารถใช้ has_side_effect, backend_config และ api_version เพื่อให้ข้อมูลเมตาที่กำหนดในการใช้งานเพิ่มเติม

ในขณะนี้ การดำเนินการนี้มีคอลเล็กชันข้อมูลเมตาที่ไม่เป็นระเบียบนัก ซึ่งสะท้อนให้เห็นถึงวิวัฒนาการตามธรรมชาติของการดำเนินการที่คู่กันในคอมไพเลอร์ XLA เราวางแผนที่จะรวมข้อมูลเมตานี้ในอนาคต (#741)

อินพุต

ค่ายเพลง ชื่อ ประเภท
(I1) inputs จำนวนค่าตัวแปร
(I2) call_target_name ค่าคงที่ประเภท string
(I3) has_side_effect ค่าคงที่ประเภท i1
(I4) backend_config ค่าคงที่ประเภท string
(I5) api_version ค่าคงที่ประเภท si32
(I6) called_computations จำนวนแปรผันของค่าคงที่ประเภท string

เอาต์พุต

ชื่อ ประเภท
results จำนวนค่าตัวแปร

ตัวอย่าง

%results = "stablehlo.custom_call"(%input0) {
  call_target_name = "foo",
  has_side_effect = false,
  backend_config = "bar",
  api_version = 1 : i32,
  called_computations = [@foo]
} : (tensor<f64>) -> tensor<f64>

หาร

อรรถศาสตร์

หารหาร lhs ตามองค์ประกอบและหาร rhs Tensor และสร้าง Tensor แบบ result ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับจำนวนเต็ม: การหารจำนวนเต็มที่สร้างผลหารพีชคณิตที่มีส่วนที่เป็นเศษส่วนทิ้ง
  • สำหรับแบบลอยตัว: division จาก IEEE-754
  • สำหรับจำนวนเชิงซ้อน: การหารเชิงซ้อน
  • สำหรับประเภทที่วัดปริมาณ:
    • dequantize_op_quantize(divide, lhs, rhs, type(result)).

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) lhs tensor ของจำนวนเต็ม ประเภทจุดลอยตัวหรือประเภทเชิงซ้อน หรือ tensor เชิงปริมาณแบบต่อ tensor (C1)
(I2) rhs tensor ของจำนวนเต็ม ประเภทจุดลอยตัวหรือประเภทเชิงซ้อน หรือ tensor เชิงปริมาณแบบต่อ tensor (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของจำนวนเต็ม จุดลอยตัว หรือประเภทเชิงซ้อน หรือต่อ tensor เชิงปริมาณแบบต่อ tensor (C1)

ข้อจำกัด

  • (C1) baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)

ตัวอย่าง

// %lhs: [17.1, -17.1, 17.1, -17.1]
// %rhs: [3.0, 3.0, -3.0, -3.0]
%result = "stablehlo.divide"(%lhs, %rhs) : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
// %result: [5.66666651, -5.66666651, -5.66666651, 5.66666651]

ตัวอย่างเพิ่มเติม

dot_general

อรรถศาสตร์

การประมวลผลจะจุดไอเทมระหว่าง lhs กับชิ้นส่วน rhs และสร้าง result Tensor

อย่างเป็นทางการคือ result[result_index] = dot_product ซึ่งมีคุณสมบัติดังนี้

  • lhs_result_dimensions = [d for d in axes(lhs) and d not in lhs_batching_dimensions and d not in lhs_contracting_dimensions].
  • rhs_result_dimensions = [d for d in axes(rhs) and d not in rhs_batching_dimensions and d not in rhs_contracting_dimensions].
  • result_batching_index + result_lhs_index + result_rhs_index = result_index ที่ size(result_batching_index) = size(lhs_batching_dimensions), size(result_lhs_index) = size(lhs_result_dimensions) และ size(result_rhs_index) = size(rhs_result_dimensions)
  • transposed_lhs = transpose(lhs, lhs_batching_dimensions + lhs_result_dimensions + lhs_contracting_dimensions).
  • transposed_lhs_slice = slice(transposed_lhs, result_batching_index + result_lhs_index + [:, ..., :]).
  • reshaped_lhs_slice = reshape(transposed_lhs_slice, dims(lhs, lhs_contracting_dimensions)).
  • transposed_rhs = transpose(rhs, rhs_batching_dimensions + rhs_result_dimensions + rhs_contracting_dimensions).
  • transposed_rhs_slice = slice(transposed_rhs, result_batching_index + result_rhs_index + [:, ..., :]).
  • reshaped_rhs_slice = reshape(transposed_rhs_slice, dims(rhs, rhs_contracting_dimensions)).
  • dot_product = reduce( inputs=[multiply(reshaped_lhs_slice, reshaped_rhs_slice)], init_values=[constant(0, element_type(result))], dimensions=range(size(lhs_contracting_dimensions)), body=lambda x, y: add(x, y))

สำหรับประเภทที่วัดปริมาณ ให้ดำเนินการ dequantize_op_quantize( lambda lhs, rhs: dot_general(lhs, rhs, lhs_batching_dimensions, rhs_batching_dimensions, lhs_contracting_dimensions, rhs_contracting_dimensions, precision_config), lhs, rhs, type(result))

สำหรับประเภทแบบผสม ให้ดำเนินการ hybrid_dequantize_then_op( lambda lhs, rhs: dot_general(lhs, rhs, lhs_batching_dimensions, rhs_batching_dimensions, lhs_contracting_dimensions, rhs_contracting_dimensions, precision_config), lhs, rhs)

precision_config จะควบคุมการทดแทนกันระหว่างความเร็วและความแม่นยำสำหรับการคำนวณในแบ็กเอนด์ของ Accelerator ซึ่งอาจเป็นอย่างใดอย่างหนึ่งต่อไปนี้ (ในขณะนี้ อรรถศาสตร์ของค่า enum เหล่านี้ไม่ได้ระบุไว้ แต่เรามีแผนที่จะแก้ไขปัญหานี้ใน #755)

  • DEFAULT: การคำนวณเร็วที่สุด แต่ใกล้เคียงของตัวเลขเดิมที่แม่นยำน้อยที่สุด
  • HIGH: การคำนวณช้ากว่า แต่ประมาณตัวเลขเดิมได้แม่นยำกว่า
  • HIGHEST: การคำนวณอย่างช้าที่สุด แต่ใกล้เคียงที่สุดกับตัวเลขเดิมที่แม่นยำที่สุด

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) lhs tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C5-C6), (C9-C10), (C12-C14), (C17-C18), (C20)
(I2) rhs tensor หรือ tensor เชิงปริมาณ (C7-C10), (C12-C20)
(I3) lhs_batching_dimensions ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C1), (C3), (C5), (C9), (C12)
(I4) rhs_batching_dimensions ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C1), (C4), (C7), (C9)
(I5) lhs_contracting_dimensions ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C2), (C3), (C6), (C10)
(I6) rhs_contracting_dimensions ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C2), (C4), (C8), (C10), (C16)
(I7) precision_config จำนวน Enum ที่แตกต่างกันของ DEFAULT, HIGH และ HIGHEST (C11)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือ tensor เชิงปริมาณ (C12), (C14), (C18-C20)

ข้อจำกัด

  • (C1) size(lhs_batching_dimensions) = size(rhs_batching_dimensions)
  • (C2) size(lhs_contracting_dimensions) = size(rhs_contracting_dimensions)
  • (C3) is_unique(lhs_batching_dimensions + lhs_contracting_dimensions)
  • (C4) is_unique(rhs_batching_dimensions + rhs_contracting_dimensions)
  • (C5) 0 <= lhs_batching_dimensions < rank(lhs)
  • (C6) 0 <= lhs_contracting_dimensions < rank(lhs)
  • (C7) 0 <= rhs_batching_dimensions < rank(rhs)
  • (C8) 0 <= rhs_contracting_dimensions < rank(rhs)
  • (C9) dim(lhs, lhs_batching_dimensions...) = dim(rhs, rhs_batching_dimensions...)
  • (C10) dim(lhs, lhs_contracting_dimensions...) = dim(rhs, rhs_contracting_dimensions...)
  • (C11) size(precision_config) = 2
  • (C12) shape(result) = dim(lhs, lhs_batching_dimensions) + dim(lhs, lhs_result_dimensions) + dim(rhs, rhs_result_dimensions)
  • หากการดำเนินการใช้ Tensor แบบไม่วัดปริมาณจะดำเนินการต่อไปนี้
    • (C13) element_type(lhs) = element_type(rhs)
  • หากการดำเนินการใช้ Tensor เชิงปริมาณ ให้ทำดังนี้
    • (C14) is_quantized(lhs) = is_quantized(result) and is_quantized(rhs)
    • (C15) zero_points(rhs) = 0
    • (C16) หากเป็น is_per_axis_quantized(rhs) ก็ให้ quantization_dimension(rhs) ไม่ใช่ใน rhs_contracting_dimensions
    • หาก is_quantized(lhs):
    • (C17) storage_type(lhs) = storage_type(rhs)
    • (C18) expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
    • (C19) หากเป็น is_per_tensor_quantized(rhs) ให้ทำดังนี้ is_per_tensor_quantized(result)
    • หาก !is_quantized(lhs):
    • (C20) element_type(lhs) = expressed_type(rhs) = element_type(result)

ตัวอย่าง

// %lhs: [
//        [[1, 2],
//         [3, 4]],
//        [[5, 6],
//         [7, 8]]
//       ]
// %rhs: [
//        [[1, 0],
//         [0, 1]],
//        [[1, 0],
//         [0, 1]]
//       ]
%result = "stablehlo.dot_general"(%lhs, %rhs) {
  dot_dimension_numbers = #stablehlo.dot<
    lhs_batching_dimensions = [0],
    rhs_batching_dimensions = [0],
    lhs_contracting_dimensions = [2],
    rhs_contracting_dimensions = [1]
  >,
  precision_config = [#stablehlo<precision DEFAULT>, #stablehlo<precision DEFAULT>]
} : (tensor<2x2x2xi64>, tensor<2x2x2xi64>) -> tensor<2x2x2xi64>
// %result: [
//           [[1, 2],
//            [3, 4]],
//           [[5, 6],
//            [7, 8]]
//          ]

ตัวอย่างเพิ่มเติม

dynamic_broadcast_in_dim

อรรถศาสตร์

การดำเนินการนี้เหมือนกับ broadcast_in_dim op แต่ระบบจะระบุรูปร่างผลลัพธ์แบบไดนามิกผ่านทาง output_dimensions

การดำเนินการยังยอมรับแอตทริบิวต์ที่ไม่บังคับ known_expanding_dimensions, known_non_expanding_dimensions เพื่อแสดงความรู้แบบคงที่เกี่ยวกับพฤติกรรมการขยายของมิติข้อมูล หากไม่ระบุ ระบบจะถือว่ามิติข้อมูลทั้งหมดอาจขยายอยู่

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor หรือ tensor เชิงปริมาณ (C1-C2), (C5-C6), (C9)
(I2) output_dimensions Tensor แบบ 1 มิติของประเภทจำนวนเต็ม (C7)
(I3) broadcast_dimensions Tensor คงที่แบบ 1 มิติของประเภทจำนวนเต็ม (C2-C6)
(I4) known_expanding_dimensions Tensor คงที่แบบ 1 มิติของประเภทจำนวนเต็ม (C8-C9)
(I5) known_non_expanding_dimensions Tensor คงที่แบบ 1 มิติของประเภทจำนวนเต็ม (C8-C9)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือ tensor เชิงปริมาณ (C1), (C3), (C5-C7)

ข้อจำกัด

  • (C1) element_type(result) มอบให้โดย
    • element_type(operand) หากเป็น !is_per_axis_quantized(operand)
    • element_type(operand) ยกเว้น quantization_dimension(operand), scales(operand) และ zero_points(operand) อาจแตกต่างจาก quantization_dimension(result), scales(result) และ zero_points(result)
  • (C2) size(broadcast_dimensions) = rank(operand)
  • (C3) 0 <= broadcast_dimensions < rank(result)
  • (C4) is_unique(broadcast_dimensions)
  • (C5) สำหรับ d ทั้งหมดใน axes(operand):
    • dim(operand, d) = 1หรือ
    • dim(operand, d) = dim(result, broadcast_dimensions[d]).
  • (C6) หาก is_per_axis_quantized(result):
    • quantization_dimension(result) = broadcast_dimensions[quantization_dimension(operand)].
    • หากเป็น dim(operand, quantization_dimension(operand)) = 1 ให้ scales(result)[i] = scales(operand)[0] and zero_points(result)[i] = zero_points(operand)[0] for i in range(dim(result, quantization_dimension(result)))
  • (C7) size(output_dimensions) = rank(result)
  • (C8) is_unique(known_expanding_dimensions + known_non_expanding_dimensions)
  • (C9) 0 <= known_expanding_dimensions < rank(operand)
  • (C10) 0 <= known_non_expanding_dimensions < rank(operand)

ตัวอย่าง

// %operand: [
//            [1, 2, 3]
//           ]
%operand = stablehlo.constant dense<[[1, 2, 3]]> : tensor<1x3xi64>
%output_dimensions = stablehlo.constant dense<[2, 3, 2]> : tensor<3xi64>
%result = "stablehlo.dynamic_broadcast_in_dim"(%operand, %output_dimensions) {
  broadcast_dimensions = array<i64: 2, 1>,
  known_expanding_dimensions = array<i64: 0>,
  known_non_expanding_dimensions = array<i64: 1>
} : (tensor<1x3xi64>, tensor<3xi64>) -> tensor<2x3x2xi64>
// %result: [
//            [
//             [1, 1],
//             [2, 2],
//             [3, 3]
//            ],
//            [
//             [1, 1],
//             [2, 2],
//             [3, 3]
//            ]
//          ]

ตัวอย่างเพิ่มเติม

dynamic_conv

อรรถศาสตร์

การดำเนินการนี้มีฟังก์ชันการทำงานเหมือนกับ convolution op แต่มีการระบุระยะห่างจากขอบแบบไดนามิกผ่าน padding

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) lhs tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1), (C10-C11), (C14) (C25), (C26-C27), (C30-C31) (C33)
(I2) rhs tensor หรือ tensor เชิงปริมาณ (C1), (C14-C16), (C26-C28), (C30-C33)
(I3) padding Tensor แบบ 2 มิติของประเภทจำนวนเต็ม (C4)
(I4) window_strides ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C2-C3)
(I5) lhs_dilation ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C5-C6)
(I6) rhs_dilation ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C7-C8)
(I7) window_reversal ค่าคงที่ tensor แบบ 1 มิติของประเภท i1 (C9)
(I8) input_batch_dimension ค่าคงที่ประเภท si64 (C10), (C13)
(I9) input_feature_dimension ค่าคงที่ประเภท si64 (C11), (C13-C14)
(I10) input_spatial_dimensions ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C12), (C13)
(I11) kernel_input_feature_dimension ค่าคงที่ประเภท si64 (C14) (C18)
(I12) kernel_output_feature_dimension ค่าคงที่ประเภท si64 (C15-C16), (C18), (C28)
(I13) kernel_spatial_dimensions ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C17-C18)
(I14) output_batch_dimension ค่าคงที่ประเภท si64 (C20)
(15) output_feature_dimension ค่าคงที่ประเภท si64 (C20) (C29)
(I16) output_spatial_dimensions ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C19-C20)
(I17) feature_group_count ค่าคงที่ประเภท si64 (C11), (C14), (C16), (C21), (C23)
(I18) batch_group_count ค่าคงที่ประเภท si64 (C10), (C15), (C22), (C23)
(I19) precision_config จำนวน Enum ที่แตกต่างกันของ DEFAULT, HIGH และ HIGHEST (C24)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือ tensor เชิงปริมาณ (C25-C27), (C29), (C31-C33)

ข้อจำกัด

  • (C1) N = rank(lhs) = rank(rhs)
  • (C2) size(window_strides) = N - 2
  • (C3) 0 < window_strides
  • (C4) shape(padding) = [N - 2, 2]
  • (C5) size(lhs_dilation) = N - 2
  • (C6) 0 < lhs_dilation
  • (C7) size(rhs_dilation) = N - 2
  • (C8) 0 < rhs_dilation
  • (C9) size(window_reversal) = N - 2
  • (C10) dim(lhs, input_batch_dimension) % batch_group_count = 0
  • (C11) dim(lhs, input_feature_dimension) % feature_group_count = 0
  • (C12) size(input_spatial_dimensions) = N - 2
  • (C13) ให้ input_dimensions = [input_batch_dimension] + input_spatial_dimensions + [input_feature_dimension]:
    • is_unique(input_dimensions).
    • 0 <= input_dimensions < N.
  • (C14) dim(rhs, kernel_input_feature_dimension) = dim(lhs, input_feature_dimension) / feature_group_count
  • (C15) dim(rhs, kernel_output_feature_dimension) % batch_group_count = 0
  • (C16) dim(rhs, kernel_output_feature_dimension) % feature_group_count = 0
  • (C17) size(kernel_spatial_dimensions) = N - 2
  • (C18) ให้ kernel_dimensions = kernel_spatial_dimensions + [kernel_input_feature_dimension] + [kernel_output_feature_dimension]:
    • is_unique(kernel_dimensions).
    • 0 <= kernel_dimensions < N.
  • (C19) size(output_spatial_dimensions) = N - 2
  • (C20) ให้ output_dimensions = [output_batch_dimension] + output_spatial_dimensions + [output_feature_dimension]:
    • is_unique(output_dimensions).
    • 0 <= output_dimensions < N.
  • (C21) 0 < feature_group_count
  • (C22) 0 < batch_group_count
  • (C23) feature_group_count = 1 or batch_group_count = 1
  • (C24) size(precision_config) = 2
  • (C25) dim(result, result_dim) ให้คำจำกัดความดังนี้
    • dim(lhs, input_batch_dimension) / batch_group_count หากเป็น result_dim = output_batch_dimension
    • dim(rhs, kernel_output_feature_dimension) หากเป็น result_dim = output_feature_dimension
    • num_windows ไม่เช่นนั้นให้ทำดังนี้
    • output_spatial_dimensions[spatial_dim] = result_dim.
    • lhs_dim = input_spatial_dimensions[spatial_dim].
    • rhs_dim = kernel_spatial_dimensions[spatial_dim].
    • dilated_input_shape[lhs_dim] = dim(lhs, lhs_dim) = 0 ? 0 : (dim(lhs, lhs_dim) - 1) * lhs_dilation[spatial_dim] + 1.
    • padded_input_shape[lhs_dim] = padding[spatial_dim, 0] + dilated_input_shape[lhs_dim] + padding[spatial_dim, 1].
    • dilated_window_shape[lhs_dim] = dim(rhs, rhs_dim) = 0 ? 0 : (dim(rhs, rhs_dim) - 1) * rhs_dilation[spatial_dim] + 1.
    • is_empty_window[lhs_dim] = padded_input_shape[lhs_dim] = 0 || dilated_window_shape[lhs_dim] > padded_input_shape[lhs_dim].
    • num_windows = is_empty_window[lhs_dim] ? 0 : floor((padded_input_shape[lhs_dim] - dilated_window_shape[lhs_dim]) / window_strides[spatial_dim]) + 1.
  • (C26) rank(result) = N
  • หากการดำเนินการใช้ Tensor แบบไม่วัดปริมาณจะดำเนินการต่อไปนี้
    • (C27) element_type(lhs) = element_type(rhs) = element_type(result)
  • หากการดำเนินการใช้ Tensor เชิงปริมาณ ให้ทำดังนี้
    • (C28) is_quantized(lhs) = is_quantized(result) and is_quantized(rhs)
    • (C29) หากเป็น is_per_axis_quantized(rhs) ให้จ่าย quantization_dimension(rhs) = kernel_output_feature_dimension
    • (C30) หากเป็น is_per_axis_quantized(result) ให้ทำดังนี้ quantization_dimension(result) = output_feature_dimension
    • หาก is_quantized(lhs):
    • (C31) storage_type(lhs) = storage_type(rhs)
    • (C32) expressed_type(lhs) = expressed_type(rhs) = expressed_type(result)
    • (C33) หากเป็น is_per_tensor_quantized(rhs) ให้ทำดังนี้ is_per_tensor_quantized(result)
    • หาก !is_quantized(lhs):
    • (C34) element_type(lhs) = expressed_type(rhs) = element_type(result)

ตัวอย่าง

// %lhs: [[
//        [[1], [2], [5], [6]],
//        [[3], [4], [7], [8]],
//        [[10], [11], [14], [15]],
//        [[12], [13], [16], [17]]
//      ]]
//
// %rhs: [
//         [[[1]], [[1]], [[1]]],
//         [[[1]], [[1]], [[1]]],
//         [[[1]], [[1]], [[1]]]
//        ]
// %padding: [[1, 1],
//            [1, 1]]
%result = "stablehlo.dynamic_conv"(%lhs, %rhs, %padding) {
  window_strides = array<i64: 4, 4>,
  lhs_dilation = array<i64: 2, 2>,
  rhs_dilation = array<i64: 1, 1>,
  window_reversal = array<i1: false, false>,
  dimension_numbers = #stablehlo.conv<raw
    input_batch_dimension = 0,
    input_feature_dimension = 3,
    input_spatial_dimensions = [0, 1],
    kernel_input_feature_dimension = 2,
    kernel_output_feature_dimension = 3,
    kernel_spatial_dimensions = [0, 1],
    output_batch_dimension = 0,
    output_feature_dimension = 3,
    output_spatial_dimensions = [1, 2]
  >,
  feature_group_count = 1 : i64,
  batch_group_count = 1 : i64,
  precision_config = [#stablehlo<precision DEFAULT>, #stablehlo<precision DEFAULT>]
} : (tensor<1x4x4x1xi64>, tensor<3x3x1x1xi64>, tensor<2x2xi64>) -> tensor<1x2x2x1xi64>
// %result: [[
//            [[1], [5]],
//            [[10], [14]]
//          ]]

ตัวอย่างเพิ่มเติม

dynamic_gather

อรรถศาสตร์

การดำเนินการนี้มีฟังก์ชันการทำงานเหมือนกับ gather op โดยมี slice_sizes ระบุเป็นค่าแบบไดนามิก

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1), (C7), (C10-C12), (C14)
(I2) start_indices Tensor ของประเภทจำนวนเต็ม (C2), (C3), (C13)
(I3) slice_sizes Tensor แบบ 1 มิติของประเภทจำนวนเต็ม (C8) (C11-C13)
(I4) offset_dims ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C1), (C4-C5), (C13)
(I5) collapsed_slice_dims ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C1), (C6-C8), (C13)
(I6) start_index_map ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C3), (C9), (C10)
(I7) index_vector_dim ค่าคงที่ประเภท si64 (C2), (C3), (C13)
(I8) indices_are_sorted ค่าคงที่ประเภท i1

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C5), (C13-C14)

ข้อจำกัด

  • (C1) rank(operand) = size(offset_dims) + size(collapsed_slice_dims)
  • (C2) 0 <= index_vector_dim <= rank(start_indices)
  • (C3) size(start_index_map) = index_vector_dim < rank(start_indices) ? dim(start_indices, index_vector_dim) : 1
  • (C4) is_unique(offset_dims) and is_sorted(offset_dims)
  • (C5) 0 <= offset_dims < rank(result)
  • (C6) is_unique(collapsed_slice_dims) and is_sorted(collapsed_slice_dims)
  • (C7) 0 <= collapsed_slice_dims < rank(operand)
  • (C8) slice_sizes[collapsed_slice_dims...] <= 1
  • (C9) is_unique(start_index_map)
  • (C10) 0 <= start_index_map < rank(operand)
  • (C11) size(slice_sizes) = rank(operand)
  • (C12) 0 <= slice_sizes <= shape(operand)
  • (C13) shape(result) = combine(batch_dim_sizes, offset_dim_sizes) โดยที่
    • batch_dim_sizes = shape(start_indices) เว้นแต่ว่าจะไม่มีขนาดมิติข้อมูลของ start_indices ที่สอดคล้องกับ index_vector_dim
    • offset_dim_sizes = shape(slice_sizes) เว้นแต่ว่าจะไม่มีขนาดของมิติข้อมูลใน slice_sizes ที่สัมพันธ์กับ collapsed_slice_dims
    • combine วาง batch_dim_sizes ที่แกนที่สัมพันธ์กับ batch_dims และ offset_dim_sizes ที่แกนที่สอดคล้องกับ offset_dims
  • (C14) element_type(operand) = element_type(result)

ตัวอย่าง

// %operand: [
//            [[1, 2], [3, 4], [5, 6], [7, 8]],
//            [[9, 10],[11, 12], [13, 14], [15, 16]],
//            [[17, 18], [19, 20], [21, 22], [23, 24]]
//           ]
// %start_indices: [
//                  [[0, 0], [1, 0], [2, 1]],
//                  [[0, 1], [1, 1], [0, 2]]
//                 ]
// %slize_sizes: [1, 2, 2]
%result = "stablehlo.dynamic_gather"(%operand, %start_indices, %slize_sizes) {
  dimension_numbers = #stablehlo.gather<
    offset_dims = [2, 3],
    collapsed_slice_dims = [0],
    start_index_map = [1, 0],
    index_vector_dim = 2>,
  indices_are_sorted = false
} : (tensor<3x4x2xi64>, tensor<2x3x2xi64>, tensor<3xi64>) -> tensor<2x3x2x2xi64>
// %result: [
//            [
//              [[1, 2], [3, 4]],
//              [[3, 4], [5, 6]],
//              [[13, 14], [15, 16]]
//            ],
//            [
//              [[9, 10], [11, 12]],
//              [[11, 12], [13, 14]],
//              [[17, 18], [19, 20]]
//            ]
//          ]

ตัวอย่างเพิ่มเติม

dynamic_iota

อรรถศาสตร์

การดำเนินการนี้มีฟังก์ชันการทำงานเหมือนกับ iota แต่รูปร่างผลลัพธ์จะถูกระบุแบบไดนามิกผ่านทาง output_shape

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) output_shape Tensor แบบ 1 มิติของประเภทจำนวนเต็ม (C1), (C2)
(I2) iota_dimension si64 (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของจำนวนเต็ม จุดลอยตัว หรือประเภทเชิงซ้อน หรือต่อ tensor เชิงปริมาณแบบต่อ tensor (C2)

ข้อจำกัด

  • (C1) 0 <= iota_dimension < size(output_shape)
  • (C2) rank(result) = size(output_shape)

ตัวอย่าง

%output_shape = stablehlo.constant dense<[4, 5]> : tensor<2xi64>
%result = "stablehlo.dynamic_iota"(%output_shape) {
  iota_dimension = 0 : i64
} : (tensor<2xi64>) -> tensor<4x5xi64>
// %result: [
//           [0, 0, 0, 0, 0],
//           [1, 1, 1, 1, 1],
//           [2, 2, 2, 2, 2],
//           [3, 3, 3, 3, 3]
//          ]

ตัวอย่างเพิ่มเติม

dynamic_pad

อรรถศาสตร์

การดำเนินการนี้มีฟังก์ชันการทำงานเหมือนกับ pad op แต่มีการระบุ edge_padding_low, edge_padding_high และ interior_padding เป็นค่าแบบไดนามิก

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1), (C2), (C4)
(I2) padding_value tensor แบบ 0 มิติหรือต่อ tensor เชิงปริมาณ (C1)
(I3) edge_padding_low Tensor แบบ 1 มิติของประเภทจำนวนเต็ม (C1), (C4)
(I4) edge_padding_high Tensor แบบ 1 มิติของประเภทจำนวนเต็ม (C1), (C4)
(I5) interior_padding Tensor แบบ 1 มิติของประเภทจำนวนเต็ม (C2-C4)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C3-C6)

ข้อจำกัด

  • (C1) element_type(operand) = element_type(padding_value) = element_type(result)
  • (C2) size(edge_padding_low) = size(edge_padding_high) = size(interior_padding) = rank(operand)
  • (C3) 0 <= interior_padding
  • (C4) shape(result) = shape(operand) + edge_padding_low + max(shape(operand) - 1, 0) * interior_padding + edge_padding_high

ตัวอย่าง

// %operand: [
//            [1, 2, 3],
//            [4, 5, 6]
//           ]
// %padding_value: 0
// %edge_padding_low: [0, 1]
// %edge_padding_high: [2, 1]
// %interior_padding: [1, 2]
%result = "stablehlo.dynamic_pad"(%operand, %padding_value,
  %edge_padding_low, %edge_padding_high, %interior_padding
) : (tensor<2x3xi64>, tensor<i64>, tensor<2xi64>, tensor<2xi64>, tensor<2xi64>) -> tensor<5x9xi64>
// %result: [
//           [0, 1, 0, 0, 2, 0, 0, 3, 0],
//           [0, 0, 0, 0, 0, 0, 0, 0, 0],
//           [0, 4, 0, 0, 5, 0, 0, 6, 0],
//           [0, 0, 0, 0, 0, 0, 0, 0, 0],
//           [0, 0, 0, 0, 0, 0, 0, 0, 0]
//          ]

ตัวอย่างเพิ่มเติม

dynamic_reshape

อรรถศาสตร์

การดำเนินการนี้มีฟังก์ชันการทำงานเหมือนกับตัวเลือกปรับรูปร่าง แต่ระบบจะระบุรูปร่างผลลัพธ์แบบไดนามิกผ่าน output_shape

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor หรือ tensor เชิงปริมาณ (C1-C3)
(I2) output_shape Tensor แบบ 1 มิติของประเภทจำนวนเต็ม (C4)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือ tensor เชิงปริมาณ (C1-C4)

ข้อจำกัด

  • (C1) element_type(result) มอบให้โดย
    • element_type(operand) หากเป็น !is_per_axis_quantized(operand)
    • element_type(operand) ยกเว้น quantization_dimension(operand) และ quantization_dimension(result) อาจแตกต่างกัน
  • (C2) size(operand) = size(result)
  • (C3) หาก is_per_axis_quantized(operand):
    • reduce(dims(operand, [0, 1, ..., quantization_dimension(operand) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y) = reduce(dims(result, [0, 1, ..., quantization_dimension(result) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y).
    • dim(operand, quantization_dimension(operand)) = dim(result, quantization_dimension(result)).
    • reduce(dims(operand, [quantization_dimension(operand) + 1, ..., rank(operand) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y) = reduce(dims(result, [quantization_dimension(result) + 1, ..., rank(result) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y).
  • (C4) size(output_shape) = rank(result)

ตัวอย่าง

// %operand: [[1, 2, 3], [4, 5, 6]]
// %output_shape: [3, 2]
%result = "stablehlo.dynamic_reshape"(%operand, %output_shape) : (tensor<2x3xi64>, tensor<2xi64>) -> tensor<3x2xi64>
// %result: [[1, 2], [3, 4], [5, 6]]

ตัวอย่างเพิ่มเติม

dynamic_slice

อรรถศาสตร์

แยกสไลซ์จาก operand โดยใช้ดัชนีเริ่มต้นที่คำนวณแบบไดนามิกและสร้าง Tensor แบบ result start_indices มีดัชนีเริ่มต้นของสไลซ์สำหรับแต่ละมิติข้อมูลที่ขึ้นอยู่กับการปรับเปลี่ยนที่เป็นไปได้ และ slice_sizes มีขนาดของชิ้นส่วนสำหรับแต่ละมิติข้อมูล อย่างเป็นทางการ result[result_index] = operand[operand_index] ซึ่ง

  • adjusted_start_indices = clamp(0, start_indices, shape(operand) - slice_sizes).
  • operand_index = adjusted_start_indices + result_index.

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1), (C2), (C4)
(I2) start_indices จำนวนตัวแปรของ tensors 0 มิติของประเภทจำนวนเต็ม (C2), (C3)
(I3) slice_sizes ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C2), (C4), (C5)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1), (C5)

ข้อจำกัด

  • (C1) element_type(operand) = element_type(result)
  • (C2) size(start_indices) = size(slice_sizes) = rank(operand)
  • (C3) same(type(start_indices...))
  • (C4) 0 <= slice_sizes <= shape(operand)
  • (C5) shape(result) = slice_sizes

ตัวอย่าง

// %operand: [
//            [0, 0, 1, 1],
//            [0, 0, 1, 1],
//            [0, 0, 0, 0],
//            [0, 0, 0, 0]
//           ]
// %start_indices0: -1
// %start_indices1: 3
%result = "stablehlo.dynamic_slice"(%operand, %start_indices0, %start_indices1) {
  slice_sizes = array<i64: 2, 2>
} : (tensor<4x4xi32>, tensor<i64>, tensor<i64>) -> tensor<2x2xi32>
// %result: [
//           [1, 1],
//           [1, 1]
//          ]

ตัวอย่างเพิ่มเติม

dynamic_update_slice

อรรถศาสตร์

สร้าง tensor ของ result ซึ่งเท่ากับ tensor ของ operand เว้นแต่ว่าชิ้นส่วนที่เริ่มที่ start_indices จะได้รับการอัปเดตด้วยค่าใน update ชื่อเรียกอย่างเป็นทางการว่า result[result_index]

  • update[update_index] หาก 0 <= update_index < shape(update) ที่:
    • adjusted_start_indices = clamp(0, start_indices, shape(operand) - shape(update)).
    • update_index = result_index - adjusted_start_indices.
  • operand[result_index] ไม่เช่นนั้น

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1-C4), (C6)
(I2) update tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C2), (C3), (C6)
(I3) start_indices จำนวนตัวแปรของ tensors 0 มิติของประเภทจำนวนเต็ม (C4), (C5)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) type(operand) = type(result)
  • (C2) element_type(update) = element_type(operand)
  • (C3) rank(update) = rank(operand)
  • (C4) size(start_indices) = rank(operand)
  • (C5) same(type(start_indices...))
  • (C6) 0 <= shape(update) <= shape(operand)

ตัวอย่าง

// %operand: [
//            [1, 1, 0, 0],
//            [1, 1, 0, 0],
//            [1, 1, 1, 1],
//            [1, 1, 1, 1]
//           ]
// %update: [
//           [1, 1],
//           [1, 1]
//          ]
// %start_indices0: -1
// %start_indices1: 3
%result = "stablehlo.dynamic_update_slice"(%operand, %update, %start_indices0, %start_indices1)
  : (tensor<4x4xi32>, tensor<2x2xi32>, tensor<i64>, tensor<i64>) -> tensor<4x4xi32>
// %result: [
//           [1, 1, 1, 1],
//           [1, 1, 1, 1],
//           [1, 1, 1, 1],
//           [1, 1, 1, 1]
//          ]

ตัวอย่างเพิ่มเติม

เลขชี้กำลัง

อรรถศาสตร์

ทำการดำเนินการแบบเลขชี้กำลังตามองค์ประกอบบน operand tensor และสร้าง tensor result ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับแบบลอยตัว: exp จาก IEEE-754
  • สำหรับจำนวนเชิงซ้อน: เลขชี้กำลังเชิงซ้อน
  • สำหรับประเภทที่วัดปริมาณ: dequantize_op_quantize(exponential, operand, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) baseline_type(operand) = baseline_type(result)

ตัวอย่าง

// %operand: [[0.0, 1.0], [2.0, 3.0]]
%result = "stablehlo.exponential"(%operand) : (tensor<2x2xf64>) -> tensor<2x2xf64>
// %result: [[1.0, 2.7182818284590451], [7.3890560989306504, 20.085536923187668]]

ตัวอย่างเพิ่มเติม

exponential_minus_one

อรรถศาสตร์

ดำเนินการเลขชี้กำลังเชิงองค์ประกอบลบ 1 การดำเนินการใน tensor ของ operand และสร้าง tensor ของ result ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับแบบลอยตัว: expm1 จาก IEEE-754
  • สำหรับจำนวนเชิงซ้อน: เลขเชิงซ้อน - ลบ 1
  • สำหรับประเภทที่วัดปริมาณ: dequantize_op_quantize(exponential_minus_one, operand, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) baseline_type(operand) = baseline_type(result)

ตัวอย่าง

// %operand: [0.0, 1.0]
%result = "stablehlo.exponential_minus_one"(%operand) : (tensor<2xf64>) -> tensor<2xf64>
// %result: [0.0, 1.71828187]

ตัวอย่างเพิ่มเติม

fft

อรรถศาสตร์

ทำการแปลงฟูรีเยแบบไปข้างหน้าและผกผันสำหรับอินพุต/เอาต์พุตจริงและที่ซับซ้อน

fft_type เป็นหนึ่งในค่าต่อไปนี้

  • FFT: ส่งต่อ FFT ที่ซับซ้อนไปซับซ้อน
  • IFFT: FFT แบบผกผันเชิงซ้อน
  • RFFT: ส่งต่อ FFT แบบจริงที่ไปซับซ้อน
  • IRFFT: FFT แบบผกผันจริงถึงซับซ้อน (กล่าวคือ ใช้ค่าที่ซับซ้อน แสดงผลจริง)

เป็นทางการมากขึ้น โดยใช้ฟังก์ชัน fft ซึ่งนำ tensors แบบ 1 มิติของประเภทเชิงซ้อนเป็นอินพุต จะสร้าง tensor แบบ 1 มิติที่เป็นประเภทเดียวกันกับเอาต์พุต และคำนวณการแปลงฟูรีเยที่แยกจากกันโดยสิ้นเชิง ดังนี้

สำหรับ fft_type = FFT ค่า result คือผลลัพธ์สุดท้ายของชุดการคำนวณ L ที่ L = size(fft_length) ตัวอย่างเช่น สำหรับ L = 3

  • result1[i0, ..., :] = fft(operand[i0, ..., :]).
  • result2[i0, ..., :, iR-1] = fft(result1[i0, ..., :, iR-1]).
  • result[i0, ..., :, iR-2, iR-1] = fft(result2[i0, ..., :, iR-2, iR-1]).

นอกจากนี้ เมื่อเลือกฟังก์ชัน ifft ที่มีลายเซ็นประเภทเดียวกันและคำนวณค่าผกผันของ fft ดังนี้

สำหรับ fft_type = IFFT ค่า result จะหมายถึงค่าผกผันของการคำนวณสำหรับ fft_type = FFT ตัวอย่างเช่น สำหรับ L = 3

  • result1[i0, ..., :, iR-2, iR-1] = ifft(operand[i0, ..., :, iR-2, iR-1]).
  • result2[i0, ..., :, iR-1] = ifft(result1[i0, ..., :, iR-1]).
  • result[i0, ..., :] = ifft(result2[i0, ..., :]).

นอกจากนี้ ด้วยฟังก์ชัน rfft ซึ่งจะใช้ tensors 1 มิติของประเภทจุดลอยตัว จะสร้าง tensors 1 มิติของตรรกะของจุดลอยตัวเดียวกันประเภทที่ซับซ้อนและทํางานดังนี้

  • rfft(real_operand) = truncated_result ตำแหน่ง
  • complex_operand... = (real_operand..., 0.0).
  • complex_result = fft(complex_operand).
  • truncated_result = complex_result[:(rank(complex_result) / 2 + 1)].

(เมื่อระบบคำนวณการแปลงฟูรีเยที่แยกต่างหากเพื่อหาตัวถูกดำเนินการจริง องค์ประกอบ N/2 + 1 แรกของผลลัพธ์จะกำหนดผลลัพธ์ที่เหลืออย่างชัดเจน ดังนั้นผลลัพธ์ของ rfft จะถูกตัดออกเพื่อหลีกเลี่ยงการประมวลผลองค์ประกอบที่ซ้ำซ้อน)

สำหรับ fft_type = RFFT ค่า result คือผลลัพธ์สุดท้ายของชุดการคำนวณ L ที่ L = size(fft_length) ตัวอย่างเช่น สำหรับ L = 3

  • result1[i0, ..., :] = rfft(operand[i0, ..., :]).
  • result2[i0, ..., :, iR-1] = fft(result1[i0, ..., :, iR-1]).
  • result[i0, ..., :, iR-2, iR-1] = fft(result2[i0, ..., :, iR-2, iR-1]).

สุดท้าย กำหนดฟังก์ชัน irfft ที่มีลายเซ็นประเภทเดียวกันและคำนวณค่าผกผันของ rfft ดังนี้

สำหรับ fft_type = IRFFT ค่า result จะหมายถึงค่าผกผันของการคำนวณสำหรับ fft_type = RFFT ตัวอย่างเช่น สำหรับ L = 3

  • result1[i0, ..., :, iR-2, iR-1] = ifft(operand[i0, ..., :, iR-2, iR-1]).
  • result2[i0, ..., :, iR-1] = ifft(result1[i0, ..., :, iR-1]).
  • result[i0, ..., :] = irfft(result2[i0, ..., :]).

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand Tensor ของประเภทจุดลอยตัวหรือประเภทเชิงซ้อน (C1), (C2), (C4), (C5)
(I2) fft_type enum ของ FFT, IFFT, RFFT และ IRFFT (C2), (C5)
(I3) fft_length ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C1), (C3), (C4)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result Tensor ของประเภทจุดลอยตัวหรือประเภทเชิงซ้อน (C2), (C4), (C5)

ข้อจำกัด

  • (C1) size(fft_length) <= rank(operand)
  • (C2) ความสัมพันธ์ระหว่างประเภทองค์ประกอบ operand กับ result จะแตกต่างกันไปดังนี้
    • หาก fft_type = FFT, element_type(operand) และ element_type(result) มีประเภทที่ซับซ้อนเหมือนกัน
    • หาก fft_type = IFFT, element_type(operand) และ element_type(result) มีประเภทที่ซับซ้อนเหมือนกัน
    • หาก fft_type = RFFT element_type(operand) จะเป็นประเภทจุดลอยตัว และ element_type(result) เป็นประเภทเชิงซ้อนของอรรถศาสตร์จุดลอยตัวเดียวกัน
    • หาก fft_type = IRFFT element_type(operand) เป็นประเภทที่ซับซ้อนและ element_type(result) เป็นประเภทจุดลอยตัวของความหมายของจุดลอยตัวเดียวกัน
  • (C3) 1 <= size(fft_length) <= 3
  • (C4) หากระหว่าง operand กับ result มี tensor real ของประเภทจุดลอยตัว ให้ shape(real)[-size(fft_length):] = fft_length
  • (C5) shape(result) = shape(operand) ยกเว้นในกรณีต่อไปนี้
    • หาก fft_type = RFFT, dim(result, -1) = dim(operand, -1) = 0 ? 0 : dim(operand, -1) / 2 + 1
    • หาก fft_type = IRFFT, dim(operand, -1) = dim(result, -1) = 0 ? 0 : dim(result, -1) / 2 + 1

ตัวอย่าง

// %operand: [(1.0, 0.0), (0.0, 0.0), (0.0, 0.0), (0.0, 0.0)]
%result = "stablehlo.fft"(%operand) {
  fft_type = #stablehlo<fft_type FFT>,
  fft_length = array<i64: 4>
} : (tensor<4xcomplex<f32>>) -> tensor<4xcomplex<f32>>
// %result: [(1.0, 0.0), (1.0, 0.0), (1.0, 0.0), (1.0, 0.0)]

ชั้น

อรรถศาสตร์

ดำเนินการราคาพื้นตามองค์ประกอบของ tensor ของ operand และสร้าง tensor แบบ result ใช้การดำเนินการ roundToIntegralTowardNegative จากข้อกำหนด IEEE-754 สำหรับประเภทที่แบ่งปริมาณแล้ว จะแสดงผล dequantize_op_quantize(floor, operand, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) baseline_type(operand) = baseline_type(result)

ตัวอย่าง

// %operand: [-0.8166, -0.2530, 0.2530, 0.8166, 2.0]
%result = "stablehlo.floor"(%operand) : (tensor<5xf32>) -> tensor<5xf32>
// %result: [-1.0, -1.0, 0.0, 0.0, 2.0]

ตัวอย่างเพิ่มเติม

รวบรวม

อรรถศาสตร์

รวบรวมชิ้นส่วนจาก operand Tensor จากออฟเซ็ตที่ระบุไว้ใน start_indices และสร้าง result Tensor

แผนภาพต่อไปนี้แสดงลักษณะที่องค์ประกอบใน result แมปกับองค์ประกอบใน operand โดยใช้ตัวอย่างที่เป็นรูปธรรม แผนภาพนี้เลือกตัวอย่างดัชนี result 2-3 รายการและอธิบายรายละเอียดว่าดัชนีนั้นตรงกับ operand ใด

รวบรวม

อย่างเป็นทางการ result[result_index] = operand[operand_index] ซึ่ง

  • batch_dims = [d for d in axes(result) and d not in offset_dims].
  • batch_index = result_index[batch_dims...].
  • start_index ให้คำจำกัดความดังนี้
    • start_indices[bi0, ..., :, ..., biN] โดยที่ bi เป็นองค์ประกอบเดี่ยวใน batch_index และ : จะแทรกที่ดัชนี index_vector_dim หาก index_vector_dim < rank(start_indices)
    • [start_indices[batch_index]] ไม่เช่นนั้น
  • สำหรับ d_operand ใน axes(operand)
    • full_start_index[d_operand] = clamp(start_index[d_start], 0, dim(operand, d_operand) - slice_sizes[d_operand]) หาก d_operand = start_index_map[d_start]
    • full_start_index[d_operand] = 0 ไม่เช่นนั้น
  • สำหรับ d_operand ใน axes(operand)
    • full_batching_index[d_operand] = batch_index[d_start - (d_start < index_vector_dim ? 0 : 1)] หาก d_operand = operand_batching_dims[i_batching] และ d_start = start_indices_batching_dims[i_batching]
    • full_batching_index[d_operand] = 0 ไม่เช่นนั้น
  • offset_index = result_index[offset_dims...].
  • full_offset_index = [oi0, ..., 0, ..., oiN] โดยที่ oi เป็นองค์ประกอบเดี่ยวใน offset_index และแทรก 0 ที่ดัชนีจาก collapsed_slice_dims และ operand_batching_dims
  • operand_index = full_start_index + full_batching_index + full_offset_index

หาก indices_are_sorted คือ true การติดตั้งใช้งานจะถือว่ามีการจัดเรียง start_indices ตาม start_index_map หากไม่มีการกำหนดลักษณะการทำงาน อย่างเป็นทางการสำหรับ i1 < i2 ทั้งหมดจาก indices(result) full_start_index(i1) <= full_start_index(i2)

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1), (C8), (C11), (C17), (C19-C21), (C23)
(I2) start_indices Tensor ของประเภทจำนวนเต็ม (C2-C3), (C14), (C17), (C22)
(I3) offset_dims ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C1), (C4-C5), (C22)
(I4) collapsed_slice_dims ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C1), (C6-C9), (C22)
(I5) operand_batching_dims ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C1), (C6), (C10-C12), (C16-C18), (C22)
(I6) start_indices_batching_dims ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C13-C17)
(I7) start_index_map ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C3), (C18-C19)
(I8) index_vector_dim ค่าคงที่ประเภท si64 (C2-C3), (C15), (C22)
(I9) slice_sizes ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C9), (C12), (C20-C22)
(I10) indices_are_sorted ค่าคงที่ประเภท i1

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C5), (C22-C23)

ข้อจำกัด

  • (C1) rank(operand) = size(offset_dims) + size(collapsed_slice_dims) + size(operand_batching_dims)
  • (C2) 0 <= index_vector_dim <= rank(start_indices)
  • (C3) size(start_index_map) = index_vector_dim < rank(start_indices) ? dim(start_indices, index_vector_dim) : 1
  • (C4) is_unique(offset_dims) and is_sorted(offset_dims)
  • (C5) 0 <= offset_dims < rank(result)
  • (C6) is_unique(concatenate(collapsed_slice_dims, operand_batching_dims))
  • (C7) is_sorted(collapsed_slice_dims)
  • (C8) 0 <= collapsed_slice_dims < rank(operand)
  • (C9) slice_sizes[collapsed_slice_dims...] <= 1
  • (C10) is_sorted(operand_batching_dims)
  • (C11) 0 <= operand_batching_dims < rank(operand)
  • (C12) slice_sizes[operand_batching_dims...] <= 1
  • (C13) is_unique(start_indices_batching_dims)
  • (C14) 0 <= start_indices_batching_dims < rank(start_indices)
  • (C15) index_vector_dim not in start_indices_batching_dims
  • (C16) size(operand_batching_dims) == size(start_indices_batching_dims)
  • (C17) dim(operand, operand_batching_dims...) = dim(start_indices, start_indices_batching_dims...)
  • (C18) is_unique(concatenate(start_index_map, operand_batching_dims))
  • (C19) 0 <= start_index_map < rank(operand)
  • (C20) size(slice_sizes) = rank(operand)
  • (C21) 0 <= slice_sizes <= shape(operand)
  • (C22) shape(result) = combine(batch_dim_sizes, offset_dim_sizes) โดยที่
    • batch_dim_sizes = shape(start_indices) เว้นแต่ว่าจะไม่มีขนาดมิติข้อมูลของ start_indices ที่สอดคล้องกับ index_vector_dim
    • offset_dim_sizes = slice_sizes เว้นแต่ว่าจะไม่มีขนาดของมิติข้อมูลใน slice_sizes ที่สอดคล้องกับ collapsed_slice_dims และ operand_batching_dims
    • combine วาง batch_dim_sizes ที่แกนที่สัมพันธ์กับ batch_dims และ offset_dim_sizes ที่แกนที่สอดคล้องกับ offset_dims
  • (C23) element_type(operand) = element_type(result)

ตัวอย่าง

// %operand: [
//            [
//             [[1, 2], [3, 4], [5, 6], [7, 8]],
//             [[9, 10],[11, 12], [13, 14], [15, 16]],
//             [[17, 18], [19, 20], [21, 22], [23, 24]]
//            ],
//            [
//             [[25, 26], [27, 28], [29, 30], [31, 32]],
//             [[33, 34], [35, 36], [37, 38], [39, 40]],
//             [[41, 42], [43, 44], [45, 46], [47, 48]]
//            ]
//           ]
// %start_indices: [
//                  [
//                   [[0, 0], [1, 0], [2, 1]],
//                   [[0, 1], [1, 1], [0, 9]]
//                  ],
//                  [
//                   [[0, 0], [2, 1], [2, 2]],
//                   [[1, 2], [0, 1], [1, 0]]
//                  ]
//                 ]
%result = "stablehlo.gather"(%operand, %start_indices) {
  dimension_numbers = #stablehlo.gather<
    offset_dims = [3, 4],
    collapsed_slice_dims = [1],
    operand_batching_dims = [0],
    start_indices_batching_dims = [1],
    start_index_map = [2, 1],
    index_vector_dim = 3>,
  slice_sizes = array<i64: 1, 1, 2, 2>,
  indices_are_sorted = false
} : (tensor<2x3x4x2xi32>, tensor<2x2x3x2xi64>) -> tensor<2x2x3x2x2xi32>
// %result: [
//           [
//            [
//             [[1, 2], [3, 4]],
//             [[3, 4], [5, 6]],
//             [[13, 14], [15, 16]]
//            ],
//            [
//             [[33, 34], [35, 36]],
//             [[35, 36], [37, 38]],
//             [[41, 42], [43, 44]]
//            ]
//           ],
//           [
//            [
//             [[1, 2], [3, 4]],
//             [[13, 14], [15, 16]],
//             [[21, 22], [23, 24]]
//            ],
//            [
//             [[43, 44], [45, 46]],
//             [[33, 34], [35, 36]],
//             [[27, 28], [29, 30]]
//            ]
//           ]
//          ]

ตัวอย่างเพิ่มเติม

get_dimension_size

อรรถศาสตร์

สร้างขนาดของ dimension ที่ระบุของ operand อย่างเป็นทางการคือ result = dim(operand, dimension) ความหมายนี้เกี่ยวข้องกับ องค์ประกอบรูปร่างของประเภทเท่านั้น ประเภทองค์ประกอบอาจเป็นอะไรก็ได้

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor หรือ tensor เชิงปริมาณ (C1)
(I2) dimension ค่าคงที่ประเภท si64 (C1)

เอาต์พุต

ชื่อ ประเภท
result Tensor แบบ 0 มิติของประเภท si32

ข้อจำกัด

  • (C1) 0 <= dimension < rank(operand)

ตัวอย่าง

// %operand: [[1, 2, 3], [4, 5, 6]]
%result = "stablehlo.get_dimension_size"(%operand) {
  dimension = 1 : i64
} : (tensor<2x3xi64>) -> tensor<i32>
// %result: 3

ตัวอย่างเพิ่มเติม

get_tuple_element

อรรถศาสตร์

แยกองค์ประกอบที่ตำแหน่ง index ของ Tuple operand และสร้าง result result = operand[index] อย่างเป็นทางการ

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tuple (C1), (C2)
(I2) index ค่าคงที่ประเภท si32 (C1), (C2)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result ประเภทที่รองรับ (C2)

ข้อจำกัด

  • (C1) 0 <= index < size(operand)
  • (C2) type(result) = tuple_element_types(operand)[index]

ตัวอย่าง

// %operand: ([1.0, 2.0], (3))
  index = 0 : i32
} : (tuple<tensor<2xf32>, tuple<tensor<i32>>>) -> tensor<2xf32>
// %result: [1.0, 2.0]

ตัวอย่างเพิ่มเติม

if

อรรถศาสตร์

สร้างเอาต์พุตจากการรันฟังก์ชันจาก true_branch หรือ false_branch เพียง 1 ฟังก์ชัน โดยขึ้นอยู่กับค่าของ pred result = pred ? true_branch() : false_branch() อย่างเป็นทางการ

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) pred Tensor แบบ 0 มิติของประเภท i1
(I2) true_branch ฟังก์ชัน (C1-C3)
(I3) false_branch ฟังก์ชัน (C1), (C2)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
results จำนวน tensors แบบแปรผัน, tensors เชิงปริมาณหรือโทเค็น (C3)

ข้อจำกัด

  • (C1) input_types(true_branch) = input_types(false_branch) = []
  • (C2) output_types(true_branch) = output_types(false_branch)
  • (C3) type(results...) = output_types(true_branch)

ตัวอย่าง

// %result_true_branch: 10
// %result_false_branch: 11
// %pred: true
%result = "stablehlo.if"(%pred) ({
  "stablehlo.return"(%result_true_branch) : (tensor<i32>) -> ()
}, {
  "stablehlo.return"(%result_false_branch) : (tensor<i32>) -> ()
}) : (tensor<i1>) -> tensor<i32>
// %result: 10

ตัวอย่างเพิ่มเติม

ภาพ

อรรถศาสตร์

แยกส่วนจินตภาพตามหลักองค์ประกอบจาก operand และสร้าง Tensor result อย่างเป็นทางการสำหรับองค์ประกอบ x แต่ละรายการมีดังนี้ imag(x) = is_complex(x) ? imaginary_part(x) : constant(0, element_type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand Tensor ของประเภทจุดลอยตัวหรือประเภทเชิงซ้อน (C1), (C2)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result Tensor ของประเภทจุดลอยตัว (C1), (C2)

ข้อจำกัด

  • (C1) shape(result) = shape(operand)
  • (C2) element_type(result) ให้คำจำกัดความดังนี้
    • complex_element_type(element_type(operand)) หากเป็น is_complex(operand)
    • element_type(operand) ไม่เช่นนั้น

ตัวอย่าง

// %operand: [(1.0, 2.0), (3.0, 4.0)]
%result = "stablehlo.imag"(%operand) : (tensor<2xcomplex<f32>>) -> tensor<2xf32>
// %result: [2.0, 4.0]

ตัวอย่างเพิ่มเติม

ในฟีด

อรรถศาสตร์

อ่านข้อมูลจากในฟีดและสร้าง results

ความหมายของ infeed_config กำหนดไว้สำหรับการใช้งาน

results ประกอบด้วยค่าเพย์โหลดซึ่งมาก่อนและโทเค็นสุดท้าย ในอนาคต เราวางแผนที่จะแยกเพย์โหลดและโทเค็นออกเป็นเอาต์พุตแยกกัน 2 รายการเพื่อปรับปรุงความชัดเจน (#670)

อินพุต

ค่ายเพลง ชื่อ ประเภท
(I1) token token
(I2) infeed_config ค่าคงที่ประเภท string

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
results จำนวน tensors แบบแปรผัน, tensors เชิงปริมาณหรือโทเค็น (C1-C3)

ข้อจำกัด

  • (C1) 0 < size(results)
  • (C2) is_empty(result[:-1]) หรือ is_tensor(type(results[:-1]))
  • (C3) is_token(type(results[-1]))

ตัวอย่าง

// %token: !stablehlo.token
// infeed_queue[0]: [[1, 2], [3, 4]]
// infeed_queue[1]: [[5, 6], [7, 8]]
%results0:2 = "stablehlo.infeed"(%token) {
  infeed_config = ""
} : (!stablehlo.token) -> (tensor<2x2xi64>, !stablehlo.token)
// results0#0: [[1, 2], [3, 4]]
%results1:2 = "stablehlo.infeed"(%token) {
  infeed_config = ""
} : (!stablehlo.token) -> (tensor<2x2xi64>, !stablehlo.token)
// results1#0: [[5, 6], [7, 8]]

ตัวอย่างเพิ่มเติม

Iota

อรรถศาสตร์

เติม tensor ของ output ด้วยค่าตามลำดับที่เพิ่มขึ้นโดยเริ่มจาก 0 ควบคู่ไปกับมิติข้อมูล iota_dimension อย่างเป็นทางการ

output[output_index] = constant(is_quantized(output) ? quantize(output_index[iota_dimension], element_type(output)) : output_index[iota_dimension], element_type(output)).

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) iota_dimension si64 (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
output tensor ของจำนวนเต็ม จุดลอยตัว หรือประเภทเชิงซ้อน หรือต่อ tensor เชิงปริมาณแบบต่อ tensor (C1)

ข้อจำกัด

  • (C1) 0 <= iota_dimension < rank(output)

ตัวอย่าง

%output = "stablehlo.iota"() {
  iota_dimension = 0 : i64
} : () -> tensor<4x5xi32>
// %output: [
//           [0, 0, 0, 0, 0],
//           [1, 1, 1, 1, 1],
//           [2, 2, 2, 2, 2],
//           [3, 3, 3, 3, 3]
//          ]

%output = "stablehlo.iota"() {
  iota_dimension = 1 : i64
} : () -> tensor<4x5xi32>
// %output: [
//           [0, 1, 2, 3, 4],
//           [0, 1, 2, 3, 4],
//           [0, 1, 2, 3, 4],
//           [0, 1, 2, 3, 4]
//          ]

ตัวอย่างเพิ่มเติม

is_finite

อรรถศาสตร์

ตรวจสอบตามองค์ประกอบเพื่อดูว่าค่าใน x เป็นค่าจำกัดหรือไม่ (กล่าวคือ ไม่ใช่ +Inf, -Inf หรือ NaN) และสร้าง tensor ของ y ใช้การดำเนินการisFiniteจากข้อกำหนด IEEE-754 สำหรับประเภทที่วัดปริมาณ ผลลัพธ์จะเป็น true เสมอ

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) x tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
y tensor ของประเภทบูลีน (C1)

ข้อจำกัด

  • (C1) shape(x) = shape(y)

ตัวอย่าง

// Logical values: -Inf, +Inf, NaN, ...
// %x: [0xFFF0000000000000, 0x7FF0000000000000, 0x7FF8000000000000, -10.0, -0.0, 0.0, 10.0]
%y = "stablehlo.is_finite"(%x) : (tensor<7xf64) -> tensor<7xi1>
// %y: [false, false, false, true, true, true, true]

ตัวอย่างเพิ่มเติม

log

อรรถศาสตร์

ดำเนินการลอการิทึมระดับองค์ประกอบบน tensor ของ operand และสร้าง Tensor result ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับแบบลอยตัว: log จาก IEEE-754
  • สำหรับจำนวนเชิงซ้อน: ลอการิทึมเชิงซ้อน
  • สำหรับประเภทที่นับจำนวน: dequantize_op_quantize(log, operand, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) baseline_type(operand) = baseline_type(result)

ตัวอย่าง

// %operand: [[1.0, 2.0], [3.0, 4.0]]
%result = "stablehlo.log"(%operand) : (tensor<2x2xf64>) -> tensor<2x2xf64>
// %result: [[0.0, 0.69314718055994529], [1.0986122886681098, 1.3862943611198906]]

ตัวอย่างเพิ่มเติม

log_plus_one

อรรถศาสตร์

ดำเนินการลอการิทึมตามองค์ประกอบบวก 1 การดำเนินการใน tensor ของ operand และสร้าง tensor ของ result ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับแบบลอยตัว: logp1 จาก IEEE-754
  • สำหรับจำนวนเชิงซ้อน: ลอการิทึมเชิงซ้อนบวก 1
  • สำหรับประเภทที่วัดปริมาณ: dequantize_op_quantize(log_plus_one, operand, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) baseline_type(operand) = baseline_type(result)

ตัวอย่าง

// %operand: [0.0, -0.999, 7.0, 6.38905621, 15.0]
%result = "stablehlo.log_plus_one"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// %result: [0.0, -6.90776825, 2.07944155, 2.0, 2.77258873]

ตัวอย่างเพิ่มเติม

โลจิสติกส์

อรรถศาสตร์

ดำเนินการโลจิสติกส์ตามองค์ประกอบบน tensor ของ operand และสร้าง Tensor result ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับแบบลอยตัว: division(1, addition(1, exp(-x))) จาก IEEE-754
  • สำหรับจำนวนเชิงซ้อน: โลจิสติกส์เชิงซ้อน
  • สำหรับประเภทที่วัดปริมาณ: dequantize_op_quantize(logistic, operand, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) baseline_type(operand) = baseline_type(result)

ตัวอย่าง

// %operand: [[0.0, 1.0], [2.0, 3.0]]
%result = "stablehlo.logistic"(%operand) : (tensor<2x2xf64>) -> tensor<2x2xf64>
// %result: [[0.5, 0.73105858], [0.88079708, 0.95257413]]

ตัวอย่างเพิ่มเติม

map

อรรถศาสตร์

ใช้ฟังก์ชันแผนที่ computation กับ inputs ตาม dimensions และสร้าง Tensor result

result[result_index] = computation(inputs...[result_index]) อย่างเป็นทางการ

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) inputs จำนวนตัวแปรของ tensors หรือ tensor แบบต่อ tensor เชิงปริมาณ (C1-C4)
(I2) dimensions ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C3)
(I3) computation ฟังก์ชัน (C4)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1), (C4)

ข้อจำกัด

  • (C1) shape(inputs...) = shape(result)
  • (C2) 0 < size(inputs) = N
  • (C3) dimensions = range(rank(inputs[0]))
  • (C4) computation ประเภท (tensor<E0>, ..., tensor<EN-1>) -> tensor<E'> ที่ Ei = element_type(inputs[i]) และ E' = element_type(result)

ตัวอย่าง

// %input0: [[0, 1], [2, 3]]
// %input1: [[4, 5], [6, 7]]
%result = "stablehlo.map"(%input0, %input1) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %0 = stablehlo.multiply %arg0, %arg1 : tensor<i64>
    stablehlo.return %0 : tensor<i64>
}) {
  dimensions = array<i64: 0, 1>
} : (tensor<2x2xi64>, tensor<2x2xi64>) -> tensor<2x2xi64>
// %result: [[0, 5], [12, 21]]

ตัวอย่างเพิ่มเติม

สูงสุด

อรรถศาสตร์

ดำเนินการสูงสุดตามองค์ประกอบตามองค์ประกอบบน tensors lhs และ rhs และสร้าง Tensor result ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับบูลีน: ตรรกะ OR
  • สำหรับจำนวนเต็ม: จำนวนเต็มสูงสุด
  • สำหรับแบบลอยตัว: maximum จาก IEEE-754
  • สำหรับจำนวนเชิงซ้อน: พจนานุกรมสูงสุดสำหรับคู่ (real, imaginary) การกำหนดลำดับด้วยจำนวนเชิงซ้อนเกี่ยวข้องกับความหมายที่คาดไม่ถึง ดังนั้นในอนาคตเราจึงวางแผนที่จะนำการรองรับจำนวนเชิงซ้อนออกสำหรับการดำเนินการนี้ (#560)
  • สำหรับประเภทที่วัดปริมาณ:
    • dequantize_op_quantize(maximum, lhs, rhs, type(result)).

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) lhs tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1)
(I2) rhs tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)

ตัวอย่าง

// %lhs: [[1, 2], [7, 8]]
// %rhs: [[5, 6], [3, 4]]
%result = "stablehlo.maximum"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[5, 6], [7, 8]]

ตัวอย่างเพิ่มเติม

ขั้นต่ำ

อรรถศาสตร์

ดำเนินการทำงานขั้นต่ำตามองค์ประกอบบน tensors lhs และ rhs และสร้าง tensor result ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับบูลีน: ตรรกะ AND
  • สำหรับจำนวนเต็ม: จำนวนเต็มขั้นต่ำ
  • สำหรับแบบลอยตัว: minimum จาก IEEE-754
  • สำหรับจำนวนเชิงซ้อน: เลขพจนานุกรมขั้นต่ำสำหรับคู่ (real, imaginary) การกำหนดลำดับด้วยจำนวนเชิงซ้อนเกี่ยวข้องกับความหมายที่คาดไม่ถึง ดังนั้นในอนาคตเราจึงวางแผนที่จะนำการรองรับจำนวนเชิงซ้อนออกสำหรับการดำเนินการนี้ (#560)
  • สำหรับประเภทที่วัดปริมาณ:
    • dequantize_op_quantize(minimum, lhs, rhs, type(result)).

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) lhs tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1)
(I2) rhs tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)

ตัวอย่าง

// %lhs: [[1, 2], [7, 8]]
// %rhs: [[5, 6], [3, 4]]
%result = "stablehlo.minimum"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[1, 2], [3, 4]]

ตัวอย่างเพิ่มเติม

คูณ

อรรถศาสตร์

สร้างผลคูณตามองค์ประกอบจาก tensor 2 ตัว lhs และ rhs และสร้าง tensor ขนาด result ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับบูลีน: ตรรกะ AND
  • สำหรับจำนวนเต็ม: การคูณจำนวนเต็ม
  • สำหรับแบบลอยตัว: multiplication จาก IEEE-754
  • สำหรับจำนวนเชิงซ้อน: การคูณเชิงซ้อน
  • สำหรับประเภทที่วัดปริมาณ:
    • dequantize_op_quantize(multiply, lhs, rhs, type(result)).

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) lhs tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1)
(I2) rhs tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) baseline_type(operand) = baseline_type(result)

ตัวอย่าง

// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.multiply"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[5, 12], [21, 32]]

ตัวอย่างเพิ่มเติม

สลับเครื่องหมาย

อรรถศาสตร์

ดำเนินการนิเสธตามองค์ประกอบของ operand tensor และสร้าง result tensor ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับจำนวนเต็มแบบมีเครื่องหมาย: นิเสธที่เป็นจำนวนเต็ม
  • สำหรับจำนวนเต็มที่ไม่มีเครื่องหมาย: บิตแคสต์ไปยังจำนวนเต็มแบบมีเครื่องหมาย นิหารจำนวนเต็ม บิตแคสต์ จะกลับไปเป็นจำนวนเต็มที่ไม่มีเครื่องหมาย
  • สำหรับแบบลอยตัว: negate จาก IEEE-754
  • สำหรับจำนวนเชิงซ้อน: นิเสธเชิงซ้อน
  • สำหรับประเภทที่วัดปริมาณ: dequantize_op_quantize(negate, operand, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor ของจำนวนเต็ม จุดลอยตัว หรือประเภทเชิงซ้อน หรือต่อ tensor เชิงปริมาณแบบต่อ tensor (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของจำนวนเต็ม จุดลอยตัว หรือประเภทเชิงซ้อน หรือต่อ tensor เชิงปริมาณแบบต่อ tensor (C1)

ข้อจำกัด

  • (C1) baseline_type(operand) = baseline_type(result)

ตัวอย่าง

// Negation operation with integer Tensors
// %operand: [0, -2]
%result = "stablehlo.negate"(%operand) : (tensor<2xi32>) -> tensor<2xi32>
// %result: [0, 2]

// Negation operation with with complex tensors
// %operand: (2.5, 0.0)
%result = "stablehlo.negate"(%operand) : (tensor<1xcomplex<f32>>) -> tensor<1xcomplex<f32>>
// %result: [-2.5, -0.0]

ตัวอย่างเพิ่มเติม

ไม่ใช่

อรรถศาสตร์

ดำเนินการ NOT แบบองค์ประกอบตาม tensor operand และสร้าง tensor แบบ result ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับบูลีน: ตรรกะ NOT
  • สำหรับจำนวนเต็ม: บิตไวส์ไม่ใช่

อาร์กิวเมนต์

ชื่อ ประเภท ข้อจำกัด
operand tensor ของประเภทบูลีนหรือจำนวนเต็ม (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของประเภทบูลีนหรือจำนวนเต็ม (C1)

ข้อจำกัด

  • (C1) type(operand) = type(result)

ตัวอย่าง

// Bitwise operation with with integer tensors
// %operand: [[1, 2], [3, 4]]
%result = "stablehlo.not"(%operand) : (tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[-2, -3], [-4, -5]]

// Bitwise operation with with boolean tensors
// %operand: [true, false]
%result = "stablehlo.not"(%operand) : (tensor<2xi1>) -> tensor<2xi1>
// %result: [false, true]

ตัวอย่างเพิ่มเติม

optimization_barrier

อรรถศาสตร์

ตรวจสอบว่าได้มีการดำเนินการที่สร้าง operand ก่อนการดำเนินการใดๆ ที่ขึ้นอยู่กับ result และป้องกันไม่ให้การเปลี่ยนรูปแบบคอมไพเลอร์ย้ายการดำเนินการข้ามสิ่งกีดขวาง นอกเหนือจากนั้น การดำเนินการเป็น ข้อมูลประจำตัว เช่น result = operand

อาร์กิวเมนต์

ชื่อ ประเภท ข้อจำกัด
operand จำนวน Tensor แบบแปรผัน, โทเค็นหรือโทเค็นต่อ tensor เชิงปริมาณ (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result จำนวน Tensor แบบแปรผัน, โทเค็นหรือโทเค็นต่อ tensor เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) type(operand...) = type(result...)

ตัวอย่าง

// %operand0: 0.0
// %operand1: 1.0
%result0, %result1 = "stablehlo.optimization_barrier"(%operand0, %operand1) : (tensor<f32>, tensor<f32>) -> (tensor<f32>, tensor<f32>)
// %result0: 0.0
// %result1: 1.0

ตัวอย่างเพิ่มเติม

หรือ

อรรถศาสตร์

ดำเนินการ OR ตามองค์ประกอบของ tensor 2 รายการ lhs และ rhs และสร้าง tensor ของ result ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับบูลีน: ตรรกะ OR
  • สำหรับจำนวนเต็ม: บิตไวส์ OR

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) lhs Tensor ของจำนวนเต็มหรือประเภทบูลีน (C1)
(I2) rhs Tensor ของจำนวนเต็มหรือประเภทบูลีน (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result Tensor ของจำนวนเต็มหรือประเภทบูลีน (C1)

ข้อจำกัด

  • (C1) type(lhs) = type(rhs) = type(result)

ตัวอย่าง

// Bitwise operation with with integer tensors
// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.or"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[5, 6], [7, 12]]

// Logical operation with with boolean tensors
// %lhs: [[false, false], [true, true]]
// %rhs: [[false, true], [false, true]]
%result = "stablehlo.or"(%lhs, %rhs) : (tensor<2x2xi1>, tensor<2x2xi1>) -> tensor<2x2xi1>
// %result: [[false, true], [true, true]]

ตัวอย่างเพิ่มเติม

ฟีดนอก

อรรถศาสตร์

เขียน inputs ไปยังฟีดออกและสร้างโทเค็น result

ความหมายของ outfeed_config กำหนดไว้สำหรับการใช้งาน

อินพุต

ค่ายเพลง ชื่อ ประเภท
(I1) inputs จำนวน tensors แบบแปรผันหรือ Tensor เชิงปริมาณ
(I2) token token
(I3) outfeed_config ค่าคงที่ประเภท string

เอาต์พุต

ชื่อ ประเภท
result token

ตัวอย่าง

%result = "stablehlo.outfeed"(%input0, %token) {
  outfeed_config = ""
} : (tensor<2x2x2xi64>, !stablehlo.token) -> !stablehlo.token

ตัวอย่างเพิ่มเติม

Pad

อรรถศาสตร์

ขยาย operand ด้วยระยะห่างจากขอบรอบๆ Tensor รวมถึงระหว่างองค์ประกอบของ tensor ด้วย padding_value ที่กำหนด

edge_padding_low และ edge_padding_high จะระบุจำนวนระยะห่างจากขอบที่เพิ่มลงในระดับล่าง (ข้างดัชนี 0) และระดับไฮเอนด์ (ถัดจากดัชนีสูงสุด) ของแต่ละมิติข้อมูลตามลำดับ ระยะห่างจากขอบอาจเป็นค่าลบได้ โดยค่าสัมบูรณ์ของระยะห่างจากขอบเชิงลบจะระบุจำนวนองค์ประกอบที่จะนำออกจากมิติข้อมูลที่ระบุ

interior_padding ระบุระยะห่างจากขอบที่เพิ่มระหว่างองค์ประกอบ 2 รายการในแต่ละมิติข้อมูลซึ่งต้องไม่เป็นค่าลบ ระยะห่างจากขอบภายในเกิดขึ้นก่อนระยะห่างจากขอบ กล่าวคือ ระยะห่างจากขอบที่ด้านลบจะนำองค์ประกอบออกจากตัวถูกดำเนินการที่เพิ่มภายใน

ชื่อเรียกอย่างเป็นทางการว่า result[result_index]

  • operand[operand_index] หาก result_index = edge_padding_low + operand_index * (interior_padding + 1)
  • padding_value ไม่เช่นนั้น

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1), (C2), (C4)
(I2) padding_value tensor แบบ 0 มิติหรือต่อ tensor เชิงปริมาณ (C1)
(I3) edge_padding_low ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C1), (C4)
(I4) edge_padding_high ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C1), (C4)
(I5) interior_padding ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C2-C4)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C3-C6)

ข้อจำกัด

  • (C1) element_type(operand) = element_type(padding_value) = element_type(result)
  • (C2) size(edge_padding_low) = size(edge_padding_high) = size(interior_padding) = rank(operand)
  • (C3) 0 <= interior_padding
  • (C4) shape(result) = shape(operand) + edge_padding_low + max(shape(operand) - 1, 0) * interior_padding + edge_padding_high

ตัวอย่าง

// %operand: [
//            [1, 2, 3],
//            [4, 5, 6]
//           ]
// %padding_value: 0
%result = "stablehlo.pad"(%operand, %padding_value) {
  edge_padding_low = array<i64: 0, 1>,
  edge_padding_high = array<i64: 2, 1>,
  interior_padding = array<i64: 1, 2>
} : (tensor<2x3xi32>, tensor<i32>) -> tensor<5x9xi32>
// %result: [
//           [0, 1, 0, 0, 2, 0, 0, 3, 0],
//           [0, 0, 0, 0, 0, 0, 0, 0, 0],
//           [0, 4, 0, 0, 5, 0, 0, 6, 0],
//           [0, 0, 0, 0, 0, 0, 0, 0, 0],
//           [0, 0, 0, 0, 0, 0, 0, 0, 0]
//          ]

ตัวอย่างเพิ่มเติม

partition_id

อรรถศาสตร์

สร้าง partition_id ของกระบวนการปัจจุบัน

เอาต์พุต

ชื่อ ประเภท
result Tensor แบบ 0 มิติของประเภท ui32

ตัวอย่าง

%result = "stablehlo.partition_id"() : () -> tensor<ui32>

ตัวอย่างเพิ่มเติม

Popcnt

อรรถศาสตร์

ดำเนินการนับตามองค์ประกอบของจำนวนบิตที่กำหนดไว้ใน tensor ของ operand และสร้าง tensor ของ result

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand Tensor ของประเภทจำนวนเต็ม (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result Tensor ของประเภทจำนวนเต็ม (C1)

ข้อจำกัด

  • (C1) type(operand) = type(result)

ตัวอย่าง

// %operand: [0, 1, 2, 127]
%result = "stablehlo.popcnt"(%operand) : (tensor<4xi64>) -> tensor<4xi64>
// %result: [0, 1, 1, 7]

ตัวอย่างเพิ่มเติม

พาวเวอร์

อรรถศาสตร์

สร้าง exponentiation ของ lhs tensor ด้วย rhs tensor และสร้าง result tensor ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับจำนวนเต็ม: เลขยกกำลังจำนวนเต็ม
  • สำหรับแบบลอยตัว: pow จาก IEEE-754
  • สำหรับจำนวนเชิงซ้อน: เลขชี้กำลังเชิงซ้อน
  • สำหรับประเภทที่นับจำนวน: dequantize_op_quantize(power, lhs, rhs, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) lhs tensor ของจำนวนเต็ม จุดลอยตัว หรือประเภทเชิงซ้อน หรือต่อ tensor เชิงปริมาณแบบต่อ tensor (C1)
(I2) rhs tensor ของจำนวนเต็ม จุดลอยตัว หรือประเภทเชิงซ้อน หรือต่อ tensor เชิงปริมาณแบบต่อ tensor (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของจำนวนเต็ม จุดลอยตัว หรือประเภทเชิงซ้อน หรือต่อ tensor เชิงปริมาณแบบต่อ tensor (C1)

ข้อจำกัด

  • (C1) baseline_type(operand) = baseline_type(result)

ตัวอย่าง

// %lhs: [-2.0, -0.0, -36.0, 5.0, 3.0, 10000.0]
// %rhs: [2.0, 2.0, 1.1, 2.0, -1.0, 10.0]
%result = "stablehlo.power"(%lhs, %rhs) : (tensor<6xf64>, tensor<6xf64>) -> tensor<6xf64>
// %result: [4.0, 0.0, -nan, 25.0, 0.333333343, inf]

ตัวอย่างเพิ่มเติม

เรียล

อรรถศาสตร์

แยกส่วนจริงตามองค์ประกอบจาก operand และสร้าง Tensor result อย่างเป็นทางการสำหรับองค์ประกอบ x แต่ละรายการมีดังนี้ real(x) = is_complex(x) ? real_part(x) : x

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand Tensor ของประเภทจุดลอยตัวหรือประเภทเชิงซ้อน (C1), (C2)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result Tensor ของประเภทจุดลอยตัว (C1), (C2)

ข้อจำกัด

  • (C1) shape(result) = shape(operand)
  • (C2) element_type(result) ให้คำจำกัดความดังนี้
    • complex_element_type(element_type(operand)) หากเป็น is_complex(operand)
    • element_type(operand) ไม่เช่นนั้น

ตัวอย่าง

// %operand: [(1.0, 2.0), (3.0, 4.0)]
%result = "stablehlo.real"(%operand) : (tensor<2xcomplex<f32>>) -> tensor<2xf32>
// %result: [1.0, 3.0]

ตัวอย่างเพิ่มเติม

รับ

อรรถศาสตร์

รับข้อมูลจากช่องด้วย channel_id และสร้าง results

หาก is_host_transfer คือ true การดำเนินการจะโอนข้อมูลจากโฮสต์ ไม่เช่นนั้น ระบบจะโอนข้อมูลจากอุปกรณ์อื่น ซึ่งหมายถึง การใช้งานตามที่กำหนดไว้ แฟล็กนี้ซ้ำกับข้อมูลที่ให้ไว้ใน channel_type ดังนั้นในอนาคตเราวางแผนที่จะเก็บไว้เพียง 1 รายการเท่านั้น (#666)

results ประกอบด้วยค่าเพย์โหลดซึ่งมาก่อนและโทเค็นสุดท้าย ในอนาคต เราวางแผนที่จะแยกเพย์โหลดและโทเค็นออกเป็นเอาต์พุตแยกกัน 2 รายการเพื่อปรับปรุงความชัดเจน (#670)

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) token token (C4)
(I2) channel_id ค่าคงที่ประเภท si64
(I3) channel_type enum ของ DEVICE_TO_DEVICE และ HOST_TO_DEVICE (C1)
(I4) is_host_transfer ค่าคงที่ประเภท i1 (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
results จำนวน tensors แบบแปรผัน, tensors เชิงปริมาณหรือโทเค็น (C2-C4)

ข้อจำกัด

  • (C1) channel_type ให้คำจำกัดความดังนี้
    • HOST_TO_DEVICE หากเป็น is_host_transfer = true
    • DEVICE_TO_DEVICE ไม่เช่นนั้น
  • (C2) 0 < size(results)
  • (C3) is_empty(result[:-1]) หรือ is_tensor(type(results[:-1]))
  • (C4) is_token(type(results[-1]))

ตัวอย่าง

%results0, %results1 = "stablehlo.recv"(%token) {
  channel_handle = #stablehlo.channel_handle<handle = 1, type = 3>,
  is_host_transfer = true
} : (!stablehlo.token) -> (tensor<2x2xi64>, !stablehlo.token)

ตัวอย่างเพิ่มเติม

ลด

อรรถศาสตร์

ใช้ฟังก์ชันการลด body กับ inputs และ init_values ตาม dimensions และสร้าง Tensor results

ลำดับของการลดมีการกำหนดเป็นการติดตั้งใช้งาน ซึ่งหมายความว่า body และ init_values ต้องสร้างโมนอยด์เพื่อรับประกันว่าการดำเนินการจะให้ผลลัพธ์เดียวกันสำหรับอินพุตทั้งหมดในการใช้งานทั้งหมด แต่เงื่อนไขนี้กลับไม่สามารถลดความนิยมลงมากนักได้ เช่น การเพิ่มจุดลอยตัวของ body และ 0 สำหรับ init_values จะไม่สร้างโมนอยด์ เพราะการเพิ่มจุดลอยตัวไม่เชื่อมโยงกัน

อย่างเป็นทางการ results...[j0, ..., jR-1] = reduce(input_slices_converted) ซึ่ง

  • input_slices = inputs...[j0, ..., :, ..., jR-1] โดยแทรก : ที่ dimensions
  • input_slices_converted = to_destination_type(input_slices..., type(func_inputs(body)[:len(func_inputs(body))//2])...).
  • init_values_converted = to_destination_type(init_values..., type(func_inputs(body)[len(func_inputs(body))//2:])...).
  • reduce(input_slices_converted) = exec(schedule) สำหรับไบนารีทรี schedule ที่:
    • exec(node) = body(exec(node.left), exec(node.right)).
    • exec(leaf) = leaf.value.
  • schedule คือแผนผังไบนารีเต็มรูปแบบที่กำหนดการติดตั้งใช้งาน ซึ่งการส่งผ่านตามลำดับต้องประกอบด้วยสิ่งต่อไปนี้
    • ค่า input_slices_converted...[index] สำหรับทั้ง index ใน index_space(input_slices_converted) โดยเรียงลำดับแบบพจนานุกรมจากน้อยไปมากที่ index
    • สลับกับจำนวน init_values_converted ที่กำหนดการติดตั้งใช้งานในตำแหน่งที่กำหนดการติดตั้งใช้งาน

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) inputs จำนวนตัวแปรของ tensors หรือ tensor แบบต่อ tensor เชิงปริมาณ (C1-C4), (C6), (C7)
(I2) init_values จำนวนแปรผันของ tensor 0 มิติหรือต่อ tensor เทนเซอร์เชิงปริมาณ (C2), (C3)
(I3) dimensions ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C4), (C5), (C7)
(I4) body ฟังก์ชัน (C6)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
results จำนวนตัวแปรของ tensors หรือ tensor แบบต่อ tensor เชิงปริมาณ (C3), (C7), (C8)

ข้อจำกัด

  • (C1) same(shape(inputs...))
  • (C2) element_type(inputs...) = element_type(init_values...)
  • (C3) 0 < size(inputs) = size(init_values) = size(results) = N
  • (C4) 0 <= dimensions < rank(inputs[0])
  • (C5) is_unique(dimensions)
  • (C6) body เป็นประเภท (tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ..., tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>) โดยที่ is_promotable(element_type(inputs[i]), Ei)
  • (C7) shape(results...) = shape(inputs...) เว้นแต่ว่าจะไม่มีมิติข้อมูลขนาด inputs... ที่สอดคล้องกับ dimensions
  • (C8) element_type(results[i]) = Ei สำหรับ i ทั้งหมดใน [0,N)

ตัวอย่าง

// %input = [[0, 1, 2, 3, 4, 5]]
// %init_value = 0
%result = "stablehlo.reduce"(%input, %init_value) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
    "stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
  dimensions = array<i64: 1>
} : (tensor<1x6xi64>, tensor<i64>) -> tensor<1xi64>
// %result = [15]

ตัวอย่างเพิ่มเติม

reduce_precision

อรรถศาสตร์

แปลง operand เป็นองค์ประกอบแบบจุดลอยตัวอื่นที่ใช้ exponent_bits และ mantissa_bits และกลับไปที่ประเภทจุดลอยตัวดั้งเดิมและสร้าง output Tensor

เป็นทางการมากขึ้น

  • ระบบจะอัปเดตบิตตั๊กแตนของค่าเดิมให้ปัดเศษค่าเดิมให้เป็นค่าที่ใกล้เคียงที่สุดที่แสดงด้วย mantissa_bits โดยใช้ความหมายของ roundToIntegralTiesToEven
  • จากนั้น หาก mantissa_bits น้อยกว่าจํานวนบิตของตั๊กแตนของค่าเดิม ระบบจะตัดบิตของตั๊กแตนออกเป็น mantissa_bits
  • จากนั้น หากบิตของเลขชี้กำลังของผลลัพธ์ตรงกลางไม่พอดีกับช่วงที่ระบุโดย exponent_bits ผลลัพธ์ระดับกลางจะล้นไปเป็นอนันต์โดยใช้เครื่องหมายเดิมหรือส่วนล่างสุดเป็น 0 โดยใช้เครื่องหมายเดิม
  • สำหรับประเภทที่วัดปริมาณ ให้ดำเนินการ dequantize_op_quantize( lambda operand: reduce_precision(operand, exponent_bits, mantissa_bits), operand, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ (C1)
(I2) exponent_bits ค่าคงที่ประเภท si32 (C2)
(I3) mantissa_bits ค่าคงที่ประเภท si32 (C3)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
output tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) baseline_type(operand) = baseline_type(output)
  • (C2) 1 <= exponent_bits
  • (C3) 0 <= mantissa_bits

ตัวอย่าง

// Logical values: +Inf, NaN, +Denormal, 0.0, 65519.0, 65520.0
// %operand: [0x7FF0000000000000, 0x7FFFFFFFFFFFFFFF, 0x0000000000000001, 0.0, 65519.0, 65520.0]
%output = "stablehlo.reduce_precision"(%operand) {
  exponent_bits = 5 : i32,
  mantissa_bits = 10 : i32
} : (tensor<6xf64>) -> tensor<6xf64>
// Logical values: +Inf, NaN, 0.0, 0.0, 65504.0, +Inf
// %output: [0x7FF0000000000000, 0x7FFFFFFFFFFFFFFF, 0.0, 0.0, 65504.0, 0x7FF0000000000000]

ตัวอย่างเพิ่มเติม

reduce_scatter

อรรถศาสตร์

reduce_scatter

ภายในกลุ่มกระบวนการแต่ละกลุ่มในตารางกริดของกระบวนการ StableHLO แล้วทำการลดค่าโดยใช้ computations กับค่าของ Tensor operand จากแต่ละกระบวนการจะแบ่งผลลัพธ์การลดตาม scatter_dimension ออกเป็นส่วนต่างๆ และกระจายส่วนที่แยกระหว่างกระบวนการเพื่อสร้าง result

การดําเนินการนี้จะแบ่งตารางกริดการประมวลผลของ StableHLO เป็น process_groups ซึ่งมีคำจำกัดความดังนี้

  • cross_replica(replica_groups) หาก channel_id <= 0 and use_global_device_ids = false
  • cross_replica_and_partition(replica_groups) หาก channel_id > 0 and use_global_device_ids = false
  • flattened_ids(replica_groups) หาก channel_id > 0 and use_global_device_ids = true

หลังจากนั้น ภายในแต่ละ process_group:

  • reduced_value = all_reduce(operand, replica_groups, channel_id, use_global_device_ids, computation).
  • parts@sender = split(reduced_value@sender, dim(process_groups, 1), scatter_dimension).
  • result@receiver = parts@sender[receiver_index] สำหรับ sender ทั้งหมดใน process_group โดยที่ receiver_index = process_group.index(receiver)

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1), (C2), (C7), (C8)
(I2) scatter_dimension ค่าคงที่ประเภท si64 (C1), (C2), (C8)
(I3) replica_groups ค่าคงที่ tensor แบบ 2 มิติของประเภท si64 (C3-C5)
(I4) channel_id ค่าคงที่ประเภท si64 (C6)
(I5) use_global_device_ids ค่าคงที่ประเภท i1 (C6)
(I6) computation ฟังก์ชัน (C7)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C8-C9)

ข้อจำกัด

  • (C1) dim(operand, scatter_dimension) % dim(process_groups, 1) = 0
  • (C2) 0 <= scatter_dimension < rank(operand)
  • (C3) is_unique(replica_groups)
  • (C4) size(replica_groups) ให้คำจำกัดความดังนี้
    • num_replicas หากมีการใช้ cross_replica
    • num_replicas หากมีการใช้ cross_replica_and_partition
    • num_processes หากมีการใช้ flattened_ids
  • (C5) 0 <= replica_groups < size(replica_groups)
  • (C6) หากเป็น use_global_device_ids = true ให้จ่าย channel_id > 0
  • (C7) computation ประเภท (tensor<E>, tensor<E>) -> (tensor<E>) ที่ is_promotable(element_type(operand), E)
  • (C8) shape(result) = shape(operand) ยกเว้นในกรณีต่อไปนี้
    • dim(result, scatter_dimension) = dim(operand, scatter_dimension) / dim(process_groups, 1).
  • (C9) element_type(result) = E

ตัวอย่าง

// num_replicas: 2
// num_partitions: 1
// %operand@(0, 0): [[1, 2, 3, 4],
//                   [5, 6, 7, 8]]
// %operand@(1, 0): [[9, 10, 11, 12],
//                   [13, 14, 15, 16]]
%result = "stablehlo.reduce_scatter"(%operand) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
  %0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
  "stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
  scatter_dimension = 1 : i64,
  replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>,
  channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
} : (tensor<2x4xi64>) -> tensor<2x2xi64>
//
// %result@(0, 0): [[10, 12],
//                  [18, 20]]
// %result@(1, 0): [[14, 16],
//                  [22, 24]]

ตัวอย่างเพิ่มเติม

reduce_window

อรรถศาสตร์

ใช้ฟังก์ชันการลด body กับหน้าต่าง inputs และ init_values และสร้าง results

แผนภาพต่อไปนี้แสดงวิธีที่องค์ประกอบใน results... คํานวณจาก inputs... โดยใช้ตัวอย่างที่เป็นรูปธรรม

reduce_window

อย่างเป็นทางการ results...[result_index] = reduce(windows, init_values, axes(inputs...), body) (ดูส่วนลด) ซึ่งมีลักษณะดังนี้

  • padded_inputs = pad(inputs..., init_values..., padding[:, 0], padding[:, 1], base_dilations - 1).
  • window_start = result_index * window_strides.
  • window_end = window_start + (window_dimensions - 1) * window_dilations + 1.
  • windows = slice(padded_inputs..., window_start, window_end, window_dilations).

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) inputs จำนวนตัวแปรของ tensors หรือ tensor แบบต่อ tensor เชิงปริมาณ (C1-C4), (C6), (C8), (C10), (C12), (C13), (C15)
(I2) init_values จำนวนแปรผันของ tensor 0 มิติหรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1), (C13)
(I3) window_dimensions ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C4), (C5), (C15)
(I4) window_strides ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C6), (C7), (C15)
(I5) base_dilations ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C8), (C9), (C15)
(I6) window_dilations ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C10), (C11), (C15)
(I7) padding ค่าคงที่ tensor แบบ 2 มิติของประเภท si64 (C12), (C15)
(I8) body ฟังก์ชัน (C13)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
results จำนวนตัวแปรของ tensors หรือ tensor แบบต่อ tensor เชิงปริมาณ (C1), (C14-C16)

ข้อจำกัด

  • (C1) 0 < size(inputs) = size(init_values) = size(results) = N
  • (C2) same(shape(inputs...))
  • (C3) element_type(inputs...) = element_type(init_values...)
  • (C4) size(window_dimensions) = rank(inputs[0])
  • (C5) 0 < window_dimensions
  • (C6) size(window_strides) = rank(inputs[0])
  • (C7) 0 < window_strides
  • (C8) size(base_dilations) = rank(inputs[0])
  • (C9) 0 < base_dilations
  • (C10) size(window_dilations) = rank(inputs[0])
  • (C11) 0 < window_dilations
  • (C12) shape(padding) = [rank(inputs[0]), 2]
  • (C13) body ประเภท (tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ..., tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>) โดยที่ is_promotable(element_type(inputs[i]), Ei)
  • (C14) same(shape(results...))
  • (C15) shape(results[0]) = num_windows โดยที่
    • dilated_input_shape = shape(inputs[0]) = 0 ? 0 : (shape(inputs[0]) - 1) * base_dilations + 1.
    • padded_input_shape = padding[:, 0] + dilated_input_shape + padding[:, 1].
    • dilated_window_shape = (window_dimensions - 1) * window_dilations + 1.
    • is_empty_window = padded_input_shape = 0 || dilated_window_shape > padded_input_shape.
    • num_windows = is_empty_window ? 0 : floor((padded_input_shape - dilated_window_shape) / window_strides) + 1.
  • (C16) element_type(results[i]) = Ei สำหรับ i ทั้งหมดใน [0,N)

ตัวอย่าง

// %input = [[1, 2], [3, 4], [5, 6]]
// %init_value = 0
%result = "stablehlo.reduce_window"(%input, %init_value) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
    "stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
  window_dimensions = array<i64: 2, 1>,
  window_strides = array<i64: 4, 1>,
  base_dilations = array<i64: 2, 1>,
  window_dilations = array<i64: 3, 1>,
  padding = dense<[[2, 1], [0, 0]]> : tensor<2x2xi64>
} : (tensor<3x2xi64>, tensor<i64>) -> tensor<2x2xi64>
// %result = [[0, 0], [3, 4]]

ตัวอย่างเพิ่มเติม

เศษ

อรรถศาสตร์

สร้างเศษส่วนขององค์ประกอบของตัวหาร lhs และตัวหาร rhs ตัวหาร แล้วสร้าง Tensor result

หรือกล่าวอีกนัยหนึ่งคือ เครื่องหมายของผลลัพธ์ที่ได้จะมาจากตัวหาร และค่าสัมบูรณ์ของผลลัพธ์จะน้อยกว่าค่าสัมบูรณ์ของตัวหารเสมอ เศษจะคำนวณเป็น lhs - d * rhs โดย d ได้จาก

  • สำหรับจำนวนเต็ม: stablehlo.divide(lhs, rhs)
  • สำหรับทศนิยม: division(lhs, rhs) จาก IEEE-754 ที่มีแอตทริบิวต์การปัดเศษ roundTowardZero
  • สำหรับจำนวนเชิงซ้อน: TBD (#997)
  • สำหรับประเภทที่วัดปริมาณ:
    • dequantize_op_quantize(remainder, lhs, rhs, type(result)).

สำหรับประเภทองค์ประกอบที่มีจุดลอยตัว การดําเนินการนี้แตกต่างจากการดําเนินการ remainder จากข้อกําหนดของ IEEE-754 โดยที่ d เป็นค่าปริพันธ์ซึ่งใกล้เคียงค่าที่แน่นอนของ lhs/rhs มากที่สุดโดยมีค่าเท่ากัน

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) lhs tensor ของจำนวนเต็ม ประเภทจุดลอยตัวหรือประเภทเชิงซ้อน หรือ tensor เชิงปริมาณแบบต่อ tensor (C1)
(I2) rhs tensor ของจำนวนเต็ม ประเภทจุดลอยตัวหรือประเภทเชิงซ้อน หรือ tensor เชิงปริมาณแบบต่อ tensor (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของจำนวนเต็ม ประเภทจุดลอยตัวหรือประเภทเชิงซ้อน หรือ tensor เชิงปริมาณแบบต่อ tensor (C1)

ข้อจำกัด

  • (C1) baseline_type(operand) = baseline_type(result)

ตัวอย่าง

// %lhs: [17, -17, 17, -17]
// %rhs: [3, 3, -3, -3]
%result = "stablehlo.remainder"(%lhs, %rhs) : (tensor<4xi64>, tensor<4xi64>) -> tensor<4xi64>
// %result: [2, -2, 2, -2]

ตัวอย่างเพิ่มเติม

replica_id

อรรถศาสตร์

สร้าง replica_id ของกระบวนการปัจจุบัน

เอาต์พุต

ชื่อ ประเภท
result Tensor แบบ 0 มิติของประเภท ui32

ตัวอย่าง

%result = "stablehlo.replica_id"() : () -> tensor<ui32>

ตัวอย่างเพิ่มเติม

ปรับรูปร่าง

อรรถศาสตร์

ปรับรูปของ Tensor ของ operand ให้เป็น Tensor แบบ result โดยหลักการแล้วก็ต้องใช้การนำเสนอตามรูปแบบบัญญัติเดิมแต่อาจเปลี่ยนรูปร่าง เช่น จาก tensor<2x3xf32> เป็น tensor<3x2xf32> หรือ tensor<6xf32>

เป็นทางการมากขึ้น result[result_index] = operand[operand_index] โดยที่ result_index และ operand_index มีอันดับเดียวกันในลำดับพจนานุกรมของ index_space(result) และ index_space(operand)

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor หรือ tensor เชิงปริมาณ (C1-C3)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือ tensor เชิงปริมาณ (C1-C3)

ข้อจำกัด

  • (C1) element_type(result) มอบให้โดย
    • element_type(operand) หากเป็น !is_per_axis_quantized(operand)
    • element_type(operand) ยกเว้น quantization_dimension(operand) และ quantization_dimension(result) อาจแตกต่างกัน
  • (C2) size(operand) = size(result)
  • (C3) หาก is_per_axis_quantized(operand):
    • reduce(dims(operand, [0, 1, ..., quantization_dimension(operand) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y) = reduce(dims(result, [0, 1, ..., quantization_dimension(result) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y).
    • dim(operand, quantization_dimension(operand)) = dim(result, quantization_dimension(result)).
    • reduce(dims(operand, [quantization_dimension(operand) + 1, ..., rank(operand) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y) = reduce(dims(result, [quantization_dimension(result) + 1, ..., rank(result) - 1]), init_values=1, dimensions=[0], body=lambda x, y: x * y).

ตัวอย่าง

// %operand: [[1, 2, 3], [4, 5, 6]]
%result = "stablehlo.reshape"(%operand) : (tensor<2x3xi32>) -> tensor<3x2xi32>
// %result: [[1, 2], [3, 4], [5, 6]]

ตัวอย่างเพิ่มเติม

ย้อนกลับ

อรรถศาสตร์

กลับลำดับขององค์ประกอบใน operand ตาม dimensions ที่ระบุและสร้าง Tensor result อย่างเป็นทางการ result[result_index] = operand[operand_index] ซึ่ง

  • operand_index[d] = dim(result, d) - result_index[d] - 1 หากเป็น d ใน dimensions
  • operand_index[d] = result_index[d] ไม่เช่นนั้น

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1), (C3)
(I2) dimensions ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C2), (C3)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1), (C3)

ข้อจำกัด

  • (C1) type(operand) = type(result)
  • (C2) is_unique(dimensions)
  • (C3) 0 <= dimensions < rank(result)

ตัวอย่าง

// %operand = [[1, 2], [3, 4], [5, 6]]
%result = "stablehlo.reverse"(%operand) {
  dimensions = array<i64: 1>
} : (tensor<3x2xi32>) -> tensor<3x2xi32>
// %result: [[2, 1], [4, 3], [6, 5]]

ตัวอย่างเพิ่มเติม

คำตอบ

อรรถศาสตร์

สร้างตัวเลขสุ่มโดยใช้อัลกอริทึม rng_distribution และสร้าง result tensor ของรูปร่าง shape ที่กำหนด

หากค่าเป็น rng_distribution = UNIFORM ระบบจะสร้างตัวเลขสุ่มตามการกระจายที่สม่ำเสมอในช่วง [a, b) หากเป็น a >= b จะไม่มีการระบุลักษณะการทำงาน

หากเป็น rng_distribution = NORMAL ระบบจะสร้างจำนวนสุ่มตามการแจกแจงปกติที่มีค่าเฉลี่ย = a และส่วนเบี่ยงเบนมาตรฐาน = b หากเป็น b < 0 จะไม่มีการกําหนดลักษณะการทำงาน

วิธีการที่แน่นอนในการสร้างตัวเลขสุ่มจะขึ้นอยู่กับการนำไปใช้ ตัวอย่างเช่น อาจมีหรือไม่มีการกำหนดว่าจะให้หรือไม่ และอาจใช้หรือไม่ใช้สถานะซ่อนก็ได้

ในการพูดคุยกับผู้มีส่วนเกี่ยวข้องหลายราย การดำเนินการดังกล่าวดูเหมือนจะเลิกใช้งานไปแล้ว ดังนั้นในอนาคต เราจึงวางแผนที่จะพิจารณานำความคิดเห็นดังกล่าวออก (#597)

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) a tensor แบบ 0 มิติของจำนวนเต็ม บูลีน หรือประเภทจุดลอยตัว (C1), (C2)
(I2) b tensor แบบ 0 มิติของจำนวนเต็ม บูลีน หรือประเภทจุดลอยตัว (C1), (C2)
(I3) shape ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C3)
(I4) rng_distribution enum ของ UNIFORM และ NORMAL (C2)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result Tensor ของจำนวนเต็ม บูลีน หรือประเภทจุดลอยตัว (C1-C3)

ข้อจำกัด

  • (C1) element_type(a) = element_type(b) = element_type(result)
  • (C2) หากเป็น rng_distribution = NORMAL ให้จ่าย is_float(a)
  • (C3) shape(result) = shape

ตัวอย่าง

// %a = 0
// %b = 2
// %shape = [3, 3]
%result = "stablehlo.rng"(%a, %b, %shape) {
  rng_distribution = #stablehlo<rng_distribution UNIFORM>
} : (tensor<i32>, tensor<i32>, tensor<2xi64>) -> tensor<3x3xi32>
// %result: [
//           [1, 0, 1],
//           [1, 1, 1],
//           [0, 0, 0]
//          ]

rng_bit_generator

อรรถศาสตร์

แสดงผล output ที่มีบิตแบบสุ่มที่สม่ำเสมอและสถานะเอาต์พุตที่อัปเดต output_state โดยใช้อัลกอริทึมตัวสร้างตัวเลขสุ่ม rng_algorithm ที่มีสถานะเริ่มต้น initial_state เอาต์พุตนี้รับประกันว่าจะเป็นฟังก์ชันเชิงกำหนดของ initial_state แต่ไม่รับประกันว่าจะวัดผลระหว่างการใช้งานจริง

rng_algorithm เป็นหนึ่งในค่าต่อไปนี้

  • DEFAULT: อัลกอริทึมที่กำหนดการติดตั้งใช้งาน
  • THREE_FRY: ตัวแปรที่กำหนดโดยการใช้งานของอัลกอริทึม Threefry*
  • PHILOX: ตัวแปรของอัลกอริทึม Philox ที่ติดตั้งใช้งาน*

* ดู: Salmon et al. SC 2011 เลขสุ่มคู่ขนาน: ง่ายเหมือนเลข 1, 2, 3

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) rng_algorithm enum ของ DEFAULT, THREE_FRY และ PHILOX (C2)
(I2) initial_state Tensor แบบ 1 มิติของประเภท ui64 (C1), (C2)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
output_state Tensor แบบ 1 มิติของประเภท ui64 (C1)
output Tensor ของจำนวนเต็มหรือประเภทจุดลอยตัว

ข้อจำกัด

  • (C1) type(initial_state) = type(output_state)
  • (C2) size(initial_state) ให้คำจำกัดความดังนี้
    • การใช้งานที่กำหนดหาก rng_algorithm = DEFAULT
    • 2 หากเป็น rng_algorithm = THREE_FRY
    • 2 หรือ 3 หากเป็น rng_algorithm = PHILOX

ตัวอย่าง

// %initial_state: [1, 2]
%output_state, %output = "stablehlo.rng_bit_generator"(%initial_state) {
  rng_algorithm = #stablehlo<rng_algorithm THREE_FRY>
} : (tensor<2xui64>) -> (tensor<2xui64>, tensor<2x2xui64>)
// %output_state: [1, 6]
// %output: [
//           [9236835810183407956, 16087790271692313299],
//           [18212823393184779219, 2658481902456610144]
//          ]

round_nearest_afz

อรรถศาสตร์

ทำการปัดเศษตามองค์ประกอบไปยังจำนวนเต็มที่ใกล้เคียงที่สุด แบ่งค่าเสมอจาก 0 ด้วย tensor ของ operand และสร้าง tensor ของ result ใช้การดำเนินการ roundToIntegralTiesToAway จากข้อกำหนด IEEE-754 สำหรับประเภทที่แบ่งปริมาณแล้ว จะแสดงผล dequantize_op_quantize(round_nearest_afz, operand, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) baseline_type(operand) = baseline_type(result)

ตัวอย่าง

// %operand = [-2.5, 0.4, 0.5, 0.6, 2.5]
%result = "stablehlo.round_nearest_afz"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// %result: [-3.0, 0.0, 1.0, 1.0, 3.0]

ตัวอย่างเพิ่มเติม

round_nearest_even

อรรถศาสตร์

ทำการปัดเศษตามองค์ประกอบไปยังจำนวนเต็มที่ใกล้เคียงที่สุด แบ่งค่าเชื่อมโยงเข้ากับจำนวนเต็มคู่ใน tensor ของ operand และสร้าง tensor ของ result ใช้การดำเนินการ roundToIntegralTiesToEven จากข้อกำหนด IEEE-754 สำหรับประเภทที่แบ่งปริมาณแล้ว จะแสดงผล dequantize_op_quantize(round_nearest_even, operand, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของชนิดจุดลอยตัวหรือต่อ tensor เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) baseline_type(operand) = baseline_type(result)

ตัวอย่าง

// %operand = [-2.5, 0.4, 0.5, 0.6, 2.5]
%result = "stablehlo.round_nearest_even"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// %result: [-2.0, 0.0, 0.0, 1.0, 2.0]

ตัวอย่างเพิ่มเติม

RSQrt

อรรถศาสตร์

ดำเนินการประมวลผลรากที่สองตามองค์ประกอบบน tensor ของ operand และสร้าง tensor ของ result ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับแบบลอยตัว: rSqrt จาก IEEE-754
  • สำหรับจำนวนเชิงซ้อน: รากที่สองของส่วนกลับเชิงซ้อน
  • สำหรับประเภทที่นับจำนวน: dequantize_op_quantize(rsqrt, operand, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) baseline_type(operand) = baseline_type(result)

ตัวอย่าง

// %operand: [[1.0, 4.0], [9.0, 25.0]]
%result = "stablehlo.rsqrt"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[1.0, 0.5], [0.33333343, 0.2]]

ตัวอย่างเพิ่มเติม

scatter

อรรถศาสตร์

สร้าง results tensors ที่เท่ากับ inputs tensors เว้นแต่ว่าชิ้นส่วนหลายชิ้นที่ระบุโดย scatter_indices จะได้รับการอัปเดตด้วยค่า updates โดยใช้ update_computation

แผนภาพต่อไปนี้แสดงลักษณะที่องค์ประกอบใน updates... แมปกับองค์ประกอบใน results... โดยใช้ตัวอย่างที่เป็นรูปธรรม แผนภาพนี้เลือกตัวอย่างดัชนี updates... 2-3 รายการ และอธิบายรายละเอียดว่า results... ใดของดัชนีนั้น

scatter

อย่างเป็นทางการสำหรับ update_index ทั้งหมดใน index_space(updates[0]):

  • update_scatter_dims = [d for d in axes(updates[0]) and d not in update_window_dims].
  • update_scatter_index = update_index[update_scatter_dims...].
  • start_index ให้คำจำกัดความดังนี้
    • scatter_indices[si0, ..., :, ..., siN] โดยที่ si เป็นองค์ประกอบเดี่ยวใน update_scatter_index และ : จะแทรกที่ดัชนี index_vector_dim หาก index_vector_dim < rank(scatter_indices)
    • [scatter_indices[update_scatter_index]] ไม่เช่นนั้น
  • สำหรับ d_input ใน axes(inputs[0])
    • full_start_index[d_input] = start_index[d_start] หาก d_input = scatter_dims_to_operand_dims[d_start]
    • full_start_index[d_input] = 0 ไม่เช่นนั้น
  • สำหรับ d_input ใน axes(inputs[0])
    • full_batching_index[d_input] = update_scatter_index[d_start - (d_start < index_vector_dim ? 0 : 1)] หาก d_input = input_batching_dims[i_batching] และ d_start = scatter_indices_batching_dims[i_batching]
    • full_batching_index[d_input] = 0 ไม่เช่นนั้น
  • update_window_index = update_index[update_window_dims...].
  • full_window_index = [wi0, ..., 0, ..., wiN] โดยที่ wi เป็นองค์ประกอบเดี่ยวใน update_window_index และแทรก 0 ที่ดัชนีจาก inserted_window_dims และ input_batching_dims
  • result_index = full_start_index + full_batching_index + full_window_index.

ทำให้ results = exec(schedule, inputs) โดยที่

  • schedule เป็นการเรียงสับเปลี่ยน index_space(updates[0]) ที่กำหนดการติดตั้งใช้งาน
  • exec([update_index, ...], results) = exec([...], updated_results) ซึ่ง:
    • หาก result_index อยู่ในขอบเขตของ shape(results...)
    • updates_converted = to_destination_type( updates...[update_index], type(func_inputs(update_computation) [len(func_inputs(update_computation))//2:])... )
    • updated_values = update_computation(results...[result_index], updates_converted)
    • updated_results เป็นสำเนาของ results ที่มีการตั้งค่า results...[result_index] เป็น updated_values...
    • ไม่เช่นนั้น
    • updated_results = results.
  • exec([], results) = results.

หาก indices_are_sorted คือ true การติดตั้งใช้งานจะสันนิษฐานได้ว่า scatter_indices ได้รับการจัดเรียงตาม scatter_dims_to_operand_dims หรือไม่ก็ไม่มีการกำหนดลักษณะการทํางาน อย่างเป็นทางการสำหรับ i1 < i2 ทั้งหมดจาก indices(result), full_start_index(i1) <= full_start_index(i2)

หาก unique_indices คือ true การติดตั้งใช้งานจะสันนิษฐานได้ว่าดัชนี result_index ทั้งหมดกระจัดกระจายไม่ซ้ำกัน หาก unique_indices เท่ากับ true แต่ดัชนีที่กระจัดกระจายไม่ใช่ค่าที่ไม่ซ้ำ จะไม่มีการระบุลักษณะการทำงาน

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) inputs จำนวนตัวแปรของ tensors หรือ tensor แบบต่อ tensor เชิงปริมาณ (C1), (C2), (C4-C6), (C11), (C13), (C18), (C21), (C23-C24)
(I2) scatter_indices Tensor ของประเภทจำนวนเต็ม (C4), (C15), (C19), (C22)
(I3) updates จำนวนตัวแปรของ tensors หรือ tensor แบบต่อ tensor เชิงปริมาณ (C3-C6), (C8)
(I4) update_window_dims ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C2), (C4), (C7-C8)
(I5) inserted_window_dims ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C2), (C4), (C9-C11)
(I6) input_batching_dims ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C2), (C4), (C9), (C12-13), (C17-18), (C20)
(I7) scatter_indices_batching_dims ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C14-C18)
(I8) scatter_dims_to_operand_dims ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C19-C21)
(I9) index_vector_dim ค่าคงที่ประเภท si64 (C4), (C16), (C19), (C22)
(I10) indices_are_sorted ค่าคงที่ประเภท i1
(I11) unique_indices ค่าคงที่ประเภท i1
(I12) update_computation ฟังก์ชัน (C23)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
results จำนวนตัวแปรของ tensors หรือ tensor แบบต่อ tensor เชิงปริมาณ (C24-C25)

ข้อจำกัด

  • (C1) same(shape(inputs...))
  • (C2) `rank(inputs[0]) = size(update_window_dims) + ขนาด(inserted_window_dims)
    • size(input_batching_dims)`
  • (C3) same(shape(updates...))
  • (C4) shape(updates[0]) = combine(update_scatter_dim_sizes, update_window_dim_sizes) ที่:
    • update_scatter_dim_sizes = shape(scatter_indices) เว้นแต่ว่าจะไม่มีขนาดมิติข้อมูลของ scatter_indices ที่สอดคล้องกับ index_vector_dim
    • update_window_dim_sizes <= shape(inputs[0]) เว้นแต่ว่าจะไม่มีขนาดของมิติข้อมูลใน inputs[0] ที่สอดคล้องกับ inserted_window_dims และ input_batching_dims
    • combine วาง update_scatter_dim_sizes ที่แกนที่สัมพันธ์กับ update_scatter_dims และ update_window_dim_sizes ที่แกนที่ตรงกับ update_window_dims
  • (C5) 0 < size(inputs) = size(updates) = N
  • (C6) element_type(updates...) = element_type(inputs...)
  • (C7) is_unique(update_window_dims) and is_sorted(update_window_dims)
  • (C8) 0 <= update_window_dims < rank(updates[0])
  • (C9) is_unique(concatenate(inserted_window_dims, input_batching_dims))
  • (C10) is_sorted(inserted_window_dims)
  • (C11) 0 <= inserted_window_dims < rank(inputs[0])
  • (C12) is_sorted(input_batching_dims)
  • (C13) 0 <= input_batching_dims < rank(inputs[0]))
  • (C14) is_unique(scatter_indices_batching_dims)
  • (C15) 0 <= scatter_indices_batching_dims < rank(scatter_indices)
  • (C16) index_vector_dim not in scatter_indices_batching_dims
  • (C17) size(input_batching_dims) == size(scatter_indices_batching_dims)
  • (C18) dim(inputs[0], input_batching_dims...) = dim(scatter_indices, scatter_indices_batching_dims...)
  • (C19) size(scatter_dims_to_operand_dims) = index_vector_dim < rank(scatter_indices) ? dim(scatter_indices, index_vector_dim) : 1
  • (C20) is_unique(concatenate(scatter_dims_to_operand_dims, input_batching_dims))
  • (C21) 0 <= scatter_dims_to_operand_dims < rank(inputs[0])
  • (C22) 0 <= index_vector_dim <= rank(scatter_indices)
  • (C23) update_computation เป็นประเภท (tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ..., tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>) โดยที่ is_promotable(element_type(inputs[i]), Ei)
  • (C24) shape(inputs...) = shape(results...)
  • (C25) element_type(results[i]) = Ei สำหรับ i ทั้งหมดใน [0,N)

ตัวอย่าง

// %input: [
//          [
//           [[1, 2], [3, 4], [5, 6], [7, 8]],
//           [[9, 10],[11, 12], [13, 14], [15, 16]],
//           [[17, 18], [19, 20], [21, 22], [23, 24]]
//          ],
//          [
//           [[25, 26], [27, 28], [29, 30], [31, 32]],
//           [[33, 34], [35, 36], [37, 38], [39, 40]],
//           [[41, 42], [43, 44], [45, 46], [47, 48]]
//          ]
//         ]
// %scatter_indices: [
//                    [
//                     [[0, 0], [1, 0], [2, 1]],
//                     [[0, 1], [1, 1], [0, 9]]
//                    ],
//                    [
//                     [[0, 0], [2, 1], [2, 2]],
//                     [[1, 2], [0, 1], [1, 0]]
//                    ]
//                   ]
// %update: [
//           [
//            [[1, 1], [1, 1], [1, 1]],
//            [[1, 1], [1, 1], [1, 1]]
//           ],
//           [
//            [[1, 1], [1, 1], [1, 1]],
//            [[1, 1], [1, 1], [1, 1]]
//           ]
//          ]
%result = "stablehlo.scatter"(%input, %scatter_indices, %update) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
    "stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
  scatter_dimension_numbers = #stablehlo.scatter<
    update_window_dims = [3, 4],
    inserted_window_dims = [1],
    input_batching_dims = [0],
    scatter_indices_batching_dims = [1],
    scatter_dims_to_operand_dims = [2, 1],
    index_vector_dim = 3>,
  indices_are_sorted = false,
  unique_indices = false
} : (tensor<2x3x4x2xi64>, tensor<2x2x3x2xi64>, tensor<2x2x3x2x2xi64>) -> tensor<2x3x4x2xi64>
// %result: [
//           [
//            [[3, 4], [6, 7], [6, 7], [7, 8]],
//            [[9, 10],[11, 12], [15, 16], [17, 18]],
//            [[17, 18], [19, 20], [22, 23], [24, 25]]
//           ],
//           [
//            [[25, 26], [28, 29], [30, 31], [31, 32]],
//            [[35, 36], [38, 39], [38, 39], [39, 40]],
//            [[41, 42], [44, 45], [46, 47], [47, 48]]
//           ]
//          ]

ตัวอย่างเพิ่มเติม

เลือก

อรรถศาสตร์

สร้าง tensor ของ result เมื่อเลือกองค์ประกอบแต่ละรายการจาก on_true หรือ on_false tensor โดยอิงตามค่าขององค์ประกอบที่สอดคล้องกันของ pred อย่างเป็นทางการคือ result[result_index] = pred_element ? on_true[result_index] : on_false[result_index] ซึ่งคือ pred_element = rank(pred) = 0 ? pred[] : pred[result_index] สำหรับประเภทที่แบ่งปริมาณแล้ว จะแสดงผล dequantize_select_quantize(pred, on_true, on_false, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) pred Tensor ประเภท i1 (C1)
(I2) on_true tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1-C2)
(I3) on_false tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C2)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C2)

ข้อจำกัด

  • (C1) rank(pred) = 0 or shape(pred) = shape(on_true)
  • (C2) baseline_type(on_true) = baseline_type(on_false) = baseline_type(result)

ตัวอย่าง

// %pred: [[false, true], [true, false]]
// %on_true: [[1, 2], [3, 4]]
// %on_false: [[5, 6], [7, 8]]
%result = "stablehlo.select"(%pred, %on_true, %on_false) : (tensor<2x2xi1>, tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[5, 2], [3, 8]]

ตัวอย่างเพิ่มเติม

select_and_scatter

อรรถศาสตร์

กระจายค่าจาก tensor ของ source โดยใช้ scatter โดยอิงตามผลลัพธ์ของ reduce_window ของ tensor ของ input โดยใช้ select และสร้าง Tensor result

แผนภาพต่อไปนี้แสดงวิธีที่องค์ประกอบใน result คํานวณจาก operand และ source โดยใช้ตัวอย่างที่เป็นรูปธรรม

select_and_scatter

เป็นทางการมากขึ้น

  • selected_values = reduce_window_without_init(...) พร้อมอินพุตต่อไปนี้

    • inputs = [operand].
    • window_dimensions, window_strides และ padding ซึ่งใช้ตามเดิม
    • base_dilations = windows_dilations = 1.
    • body ให้คำนิยามไว้ดังนี้
    def body(arg0: tensor<E>, arg1: tensor<E>) -> tensor<E>:
      return select(arg0, arg1) ? arg0 : arg1;
    

    โดยที่ E = element_type(operand) และ reduce_window_without_init ทำงานเหมือนกับ reduce_window ทุกประการ ยกเว้นว่า schedule ของ reduce ที่สำคัญ (ดูลด) จะไม่รวมค่า init ปัจจุบันยังไม่มีการระบุถึงสิ่งที่จะเกิดขึ้นหากหน้าต่างที่เกี่ยวข้องไม่มีค่า (#731)

  • result[result_index] = reduce([source_values], [init_value], [0], scatter) ตำแหน่ง:

    • source_values = [source[source_index] for source_index in source_indices].
    • selected_index(source_index) = operand_index หาก selected_values[source_index] มีองค์ประกอบ operand จาก operand_index
    • source_indices = [source_index for source_index in indices(source) if selected_index(source_index) = result_index].

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1-C4), (C6), (C8-C11)
(I2) source tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1), (C2)
(I3) init_value tensor แบบ 0 มิติหรือต่อ tensor เชิงปริมาณ (C3)
(I4) window_dimensions ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C2), (C4), (C5)
(I5) window_strides ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C2), (C6), (C7)
(I6) padding ค่าคงที่ tensor แบบ 2 มิติของประเภท si64 (C2), (C8)
(I7) select ฟังก์ชัน (C9)
(I8) scatter ฟังก์ชัน (C10)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C11-C12)

ข้อจำกัด

  • (C1) element_type(operand) = element_type(source)
  • (C2) shape(source) = num_windows ที่:
    • padded_operand_shape = padding[:, 0] + shape(operand) + padding[:, 1].
    • is_empty_window = padded_operand_shape = 0 || window_dimensions > padded_operand_shape.
    • num_windows = is_empty_window ? 0 : floor((padded_operand_shape - window_dimensions) / window_strides) + 1.
  • (C3) element_type(init_value) = element_type(operand)
  • (C4) size(window_dimensions) = rank(operand)
  • (C5) 0 < window_dimensions
  • (C6) size(window_strides) = rank(operand)
  • (C7) 0 < window_strides
  • (C8) shape(padding) = [rank(operand), 2]
  • (C9) select ประเภท (tensor<E>, tensor<E>) -> tensor<i1> ที่ E = element_type(operand)
  • (C10) scatter เป็นประเภท (tensor<E>, tensor<E>) -> tensor<E> โดยที่ is_promotable(element_type(operand), E)
  • (C11) shape(operand) = shape(result)
  • (C12) element_type(result) = E

ตัวอย่าง

// %operand: [[1, 5], [2, 5], [3, 6], [4, 4]]
// %source: [[5, 6], [7, 8]]
// %init_value: 0
%result = "stablehlo.select_and_scatter"(%operand, %source, %init_value) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %0 = "stablehlo.compare"(%arg0, %arg1) {
      comparison_direction = #stablehlo<comparison_direction GE>
    } : (tensor<i64>, tensor<i64>) -> tensor<i1>
    "stablehlo.return"(%0) : (tensor<i1>) -> ()
}, {
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
    "stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
  window_dimensions = array<i64: 3, 1>,
  window_strides = array<i64: 2, 1>,
  padding = dense<[[0, 1], [0, 0]]> : tensor<2x2xi64>
} : (tensor<4x2xi64>, tensor<2x2xi64>, tensor<i64>) -> tensor<4x2xi64>
// %result: [[0, 0], [0, 0], [5, 14], [7, 0]]

ตัวอย่างเพิ่มเติม

ส่ง

อรรถศาสตร์

ส่ง inputs ไปยังช่อง channel_id และสร้างโทเค็น result

หาก is_host_transfer คือ true การดำเนินการจะโอนข้อมูลไปยังโฮสต์ ไม่เช่นนั้น ระบบจะโอนข้อมูลไปยังอุปกรณ์อื่น ซึ่งหมายถึง การใช้งานตามที่กำหนดไว้ แฟล็กนี้ซ้ำกับข้อมูลที่ให้ไว้ใน channel_type ดังนั้นในอนาคตเราวางแผนที่จะเก็บไว้เพียง 1 รายการเท่านั้น (#666)

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) inputs จำนวน tensors แบบแปรผันหรือ Tensor เชิงปริมาณ
(I2) token token
(I3) channel_id ค่าคงที่ประเภท si64
(I4) channel_type enum ของ DEVICE_TO_DEVICE และ DEVICE_TO_HOST (C1)
(I5) is_host_transfer ค่าคงที่ประเภท i1 (C1)

เอาต์พุต

ชื่อ ประเภท
result token

ข้อจำกัด

  • (C1) channel_type ให้คำจำกัดความดังนี้
    • DEVICE_TO_HOST หากเป็น is_host_transfer = true
    • DEVICE_TO_DEVICE ไม่เช่นนั้น

ตัวอย่าง

%result = "stablehlo.send"(%operand, %token) {
  channel_handle = #stablehlo.channel_handle<handle = 1, type = 2>,
  is_host_transfer = true
} : (tensor<2x2xi64>, !stablehlo.token) -> !stablehlo.token

ตัวอย่างเพิ่มเติม

shift_left

อรรถศาสตร์

ดำเนินการชิฟท์ซ้ายแบบใช้องค์ประกอบบน tensor ของ lhs ตามจำนวนบิต rhs และสร้าง Tensor result

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) lhs Tensor ของประเภทจำนวนเต็ม (C1)
(I2) rhs Tensor ของประเภทจำนวนเต็ม (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result Tensor ของประเภทจำนวนเต็ม (C1)

ข้อจำกัด

  • (C1) type(lhs) = type(rhs) = type(result)

ตัวอย่าง

// %lhs: [-1, 0, 1]
// %rhs: [1, 2, 3]
%result = "stablehlo.shift_left"(%lhs, %rhs): (tensor<3xi64>, tensor<3xi64>) -> tensor<3xi64>
// %result: [-2, 0, 8]

ตัวอย่างเพิ่มเติม

shift_right_arithmetic

อรรถศาสตร์

ดำเนินการใช้ชิฟท์ด้านขวาตามหลักคณิตศาสตร์บน tensor ของ lhs ตามจำนวนบิต rhs และสร้าง Tensor result

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) lhs Tensor ของประเภทจำนวนเต็ม (C1)
(I2) rhs Tensor ของประเภทจำนวนเต็ม (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result Tensor ของประเภทจำนวนเต็ม (C1)

ข้อจำกัด

  • (C1) type(lhs) = type(rhs) = type(result)

ตัวอย่าง

// %lhs: [-1, 0, 8]
// %rhs: [1, 2, 3]
%result = "stablehlo.shift_right_arithmetic"(%lhs, %rhs): (tensor<3xi64>, tensor<3xi64>) -> tensor<3xi64>
// %result: [-1, 0, 1]

ตัวอย่างเพิ่มเติม

shift_right_logical

อรรถศาสตร์

ดำเนินการใช้ Tensor แบบการเปลี่ยนแปลงในเชิงตรรกะตามองค์ประกอบบน tensor ของ lhs ตามจำนวนบิต rhs และสร้าง tensor result

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) lhs Tensor ของประเภทจำนวนเต็ม (C1)
(I2) rhs Tensor ของประเภทจำนวนเต็ม (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result Tensor ของประเภทจำนวนเต็ม (C1)

ข้อจำกัด

  • (C1) type(lhs) = type(rhs) = type(result)

ตัวอย่าง

// %lhs: [-1, 0, 8]
// %rhs: [1, 2, 3]
%result = "stablehlo.shift_right_logical"(%lhs, %rhs): (tensor<3xi64>, tensor<3xi64>) -> tensor<3xi64>
// %result: [9223372036854775807, 0, 1]

ตัวอย่างเพิ่มเติม

เครื่องหมาย

อรรถศาสตร์

แสดงผลเครื่องหมายขององค์ประกอบ operand และสร้าง Tensor result อย่างเป็นทางการ สำหรับแต่ละองค์ประกอบ x อรรถศาสตร์สามารถแสดงโดยใช้ไวยากรณ์ Python ได้ดังนี้

def sign(x):
  if is_integer(x):
    if compare(x, 0, LT, SIGNED): return -1
    if compare(x, 0, EQ, SIGNED): return 0
    return 1
  elif is_float(x):
    if is_nan(x): return NaN
    if compare(x, -0.0, EQ, FLOAT): return -0.0
    if compare(x, +0.0, EQ, FLOAT): return +0.0
    if compare(x, 0.0, LT, FLOAT): return -1.0
    return 1.0
  elif is_complex(x):
    if is_nan(real(x)) or is_nan(imag(x)): return (NaN, NaN)
    if compare(x, (0.0, 0.0), EQ, FLOAT): return (0.0, 0.0)
    return divide(x, convert(abs(x), type(x)))

สำหรับประเภทที่แบ่งปริมาณแล้ว จะแสดงผล dequantize_op_quantize(sign, operand, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor ของจำนวนเต็มแบบมีเครื่องหมาย ประเภทจุดลอยตัว หรือประเภทเชิงซ้อน หรือ tensor เชิงปริมาณแบบต่อ tensor (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของจำนวนเต็มแบบมีเครื่องหมาย ประเภทจุดลอยตัว หรือประเภทเชิงซ้อน หรือ tensor เชิงปริมาณแบบต่อ tensor (C1)

ข้อจำกัด

  • (C1) baseline_type(operand) = baseline_type(result)

ตัวอย่าง

// Logical values: +NaN, -1.0, -0.0, +0.0, 1.0
// operand: [0x7FFFFFFFFFFFFFFF, -1.0, -0.0, 0.0, 1.0]
%result = "stablehlo.sign"(%operand) : (tensor<5xf64>) -> tensor<5xf64>
// Logical values: +NaN, -1.0, -0.0, +0.0, 1.0
// %result: [0x7FFFFFFFFFFFFFFF, -1.0, -0.0, 0.0, 1.0]

ตัวอย่างเพิ่มเติม

ไซน์

อรรถศาสตร์

ดำเนินการไซน์ตามองค์ประกอบบน tensor ของ operand และสร้าง tensor ของ result ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับแบบลอยตัว: sin จาก IEEE-754
  • สำหรับจำนวนเชิงซ้อน: ไซน์เชิงซ้อน
  • สำหรับประเภทที่นับจำนวน: dequantize_op_quantize(sine, operand, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) baseline_type(operand) = baseline_type(result)

ตัวอย่าง

// %operand: [
//            [0.0, 1.57079632],       // [0, pi/2]
//            [3.14159265, 4.71238898] // [pi, 3pi/2]
//           ]
%result = "stablehlo.sine"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[0.0, 1.0], [0.0, -1.0]]

ตัวอย่างเพิ่มเติม

ส่วนแบ่ง

อรรถศาสตร์

แยกชิ้นส่วนจาก operand โดยใช้ดัชนีเริ่มต้นที่คำนวณแบบคงที่และสร้าง Tensor แบบ result start_indices มีดัชนีเริ่มต้นของสไลซ์สำหรับแต่ละมิติข้อมูล limit_indices มีดัชนีสิ้นสุด (เฉพาะตัว) สำหรับสไลซ์ของแต่ละมิติข้อมูล และ strides มีข้อมูลความก้าวหน้าของแต่ละมิติข้อมูล

อย่างเป็นทางการคือ result[result_index] = operand[operand_index] ซึ่ง operand_index = start_indices + result_index * strides

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1-C3), (C5)
(I2) start_indices ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C2), (C3), (C5)
(I3) limit_indices ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C2), (C3), (C5)
(I4) strides ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C2), (C4)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือต่อ tensor เทนเซอร์เชิงปริมาณ (C1), (C5)

ข้อจำกัด

  • (C1) element_type(operand) = element_type(result)
  • (C2) size(start_indices) = size(limit_indices) = size(strides) = rank(operand)
  • (C3) 0 <= start_indices <= limit_indices <= shape(operand)
  • (C4) 0 < strides
  • (C5) shape(result) = ceil((limit_indices - start_indices) / strides)

ตัวอย่าง

// %operand: [
//            [0, 0, 0, 0],
//            [0, 0, 1, 1],
//            [0, 0, 1, 1]
//           ]
%result = "stablehlo.slice"(%operand) {
  start_indices = array<i64: 1, 2>,
  limit_indices = array<i64: 3, 4>,
  strides = array<i64: 1, 1>
} : (tensor<3x4xi64>) -> tensor<2x2xi64>
// % result: [
//            [1, 1],
//            [1, 1]
//           ]

ตัวอย่างเพิ่มเติม

จัดเรียง

อรรถศาสตร์

จัดเรียงชิ้นส่วน inputs ส่วน 1 มิติตามมิติข้อมูล dimension เข้าด้วยกันตาม comparator และสร้าง results

dimension จะอนุญาตค่าลบ ซึ่งต่างจากอินพุตที่คล้ายกันในการดําเนินการอื่นๆ ตรงที่อธิบายไว้ด้านล่าง ในอนาคต เราอาจไม่อนุญาตให้ทำเช่นนี้เนื่องจากเหตุผลด้านความสอดคล้อง (#1377)

หาก is_stable เป็นจริง การจัดเรียงจะคงที่ กล่าวคือ ลำดับที่เกี่ยวข้องขององค์ประกอบที่พบว่ามีค่าเท่ากันโดยตัวเปรียบเทียบจะยังคงอยู่ สำหรับกรณีที่มีอินพุตเดียว องค์ประกอบ 2 รายการ e1 และ e2 จะถือว่าเหมือนกันโดยตัวเปรียบเทียบในกรณีที่ comparator(e1, e2) = comparator(e2, e1) = false เท่านั้น ดูความเป็นทางการด้านล่าง เพื่อดูว่าข้อมูลนี้ตรงกับอินพุตหลายรายการอย่างไร

อย่างเป็นทางการสำหรับ result_index ทั้งหมดใน index_space(results[0]):

  • adjusted_dimension = dimension >= 0 ? dimension : rank(inputs[0]) + dimension.
  • result_slice = [ri0, ..., :, ..., riR-1] โดยที่ riN เป็นองค์ประกอบแต่ละรายการใน result_index และแทรก : ที่ adjusted_dimension
  • inputs_together = (inputs[0]..., ..., inputs[N-1]...).
  • results_together[result_slice] = sort(inputs_together[result_slice], comparator_together).
  • ที่ sort จะจัดเรียงชิ้นส่วน 1 มิติตามลําดับจากมากไปน้อย โดยคาดหวังว่า comparator_together จะแสดงผล true หากอาร์กิวเมนต์ที่ด้านซ้ายมือน้อยกว่าอาร์กิวเมนต์ที่ 2 ด้านขวา
  • def comparator_together(lhs_together, rhs_together):
      args = []
      for (lhs_el, rhs_el) in zip(lhs_together, rhs_together):
        args.append(lhs_el)
        args.append(rhs_el)
      return comparator(*args)
    
  • (results[0]..., ..., results[N-1]...) = results_together.

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) inputs จำนวนตัวแปรของ tensors หรือ tensor แบบต่อ tensor เชิงปริมาณ (C1-C5)
(I2) dimension ค่าคงที่ประเภท si64 (C4)
(I3) is_stable ค่าคงที่ประเภท i1
(I4) comparator ฟังก์ชัน (C5)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
results จำนวนตัวแปรของ tensors หรือ tensor แบบต่อ tensor เชิงปริมาณ (C2), (C3)

ข้อจำกัด

  • (C1) 0 < size(inputs)
  • (C2) type(inputs...) = type(results...)
  • (C3) same(shape(inputs...) + shape(results...))
  • (C4) -R <= dimension < R โดยที่ R = rank(inputs[0])
  • (C5) comparator เป็นประเภท (tensor<E1>, tensor<E1>, ..., tensor<EN-1>, tensor<EN-1>) -> tensor<i1> โดยที่ Ei = element_type(inputs[i])

ตัวอย่าง

// %input0 = [[1, 2, 3], [3, 2, 1]]
// %input1 = [[3, 2, 1], [1, 2, 3]]
%result0, %result1 = "stablehlo.sort"(%input0, %input1) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>, %arg2: tensor<i64>, %arg3: tensor<i64>):
    %predicate = "stablehlo.compare"(%arg0, %arg1) {
      comparison_direction = #stablehlo<comparison_direction GT>
    } : (tensor<i64>, tensor<i64>) -> tensor<i1>
    "stablehlo.return"(%predicate) : (tensor<i1>) -> ()
}) {
  dimension = 0 : i64,
  is_stable = true
} : (tensor<2x3xi64>, tensor<2x3xi64>) -> (tensor<2x3xi64>, tensor<2x3xi64>)
// %result0 = [[3, 2, 3], [1, 2, 1]]
// %result1 = [[1, 2, 1], [3, 2, 3]]

ตัวอย่างเพิ่มเติม

sqrt

อรรถศาสตร์

ดำเนินการดำเนินการเกี่ยวกับรากที่สองตามองค์ประกอบบน tensor ของ operand และสร้าง Tensor result ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับแบบลอยตัว: squareRoot จาก IEEE-754
  • สำหรับจำนวนเชิงซ้อน: รากที่สองเชิงซ้อน
  • สำหรับประเภทที่นับจำนวน: dequantize_op_quantize(sqrt, operand, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) baseline_type(operand) = baseline_type(result)

ตัวอย่าง

// %operand: [[0.0, 1.0], [4.0, 9.0]]
%result = "stablehlo.sqrt"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[0.0, 1.0], [2.0, 3.0]]

ตัวอย่างเพิ่มเติม

ลบ

อรรถศาสตร์

ดำเนินการลบ tensor จำนวน 2 ตัว lhs และ rhs ตามองค์ประกอบ แล้วสร้าง Tensor result ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับจำนวนเต็ม: การลบจำนวนเต็ม
  • สำหรับแบบลอยตัว: subtraction จาก IEEE-754
  • สำหรับจำนวนเชิงซ้อน: การลบเชิงซ้อน
  • สำหรับประเภทที่วัดปริมาณ:
    • dequantize_op_quantize(subtract, lhs, rhs, type(result)).

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) lhs tensor ของจำนวนเต็ม จุดลอยตัว หรือประเภทเชิงซ้อน หรือต่อ tensor เชิงปริมาณแบบต่อ tensor (C1)
(I2) rhs tensor ของจำนวนเต็ม จุดลอยตัว หรือประเภทเชิงซ้อน หรือต่อ tensor เชิงปริมาณแบบต่อ tensor (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของจำนวนเต็ม จุดลอยตัว หรือประเภทเชิงซ้อน หรือต่อ tensor เชิงปริมาณแบบต่อ tensor (C1)

ข้อจำกัด

  • (C1) baseline_type(lhs) = baseline_type(rhs) = baseline_type(result)

ตัวอย่าง

// %lhs: [[6, 8], [10, 12]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.subtract"(%lhs, %rhs) : (tensor<2x2xf32>, tensor<2x2xf32>) -> (tensor<2x2xf32>)
// %result: [[1, 2], [3, 4]]

ตัวอย่างเพิ่มเติม

แทนห์

อรรถศาสตร์

ทำการดำเนินการไฮเปอร์โบลิกแทนเจนต์ตามองค์ประกอบบน tensor ของ operand และสร้าง tensor ของ result ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับแบบลอยตัว: tanh จาก IEEE-754
  • สำหรับจำนวนเชิงซ้อน: ไฮเปอร์โบลิกแทนเจนต์เชิงซ้อน
  • สำหรับประเภทที่วัดปริมาณ:
    • dequantize_op_quantize(tanh, operand, type(result)).

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) baseline_type(operand) = baseline_type(result)

ตัวอย่าง

// %operand: [-1.0, 0.0, 1.0]
%result = "stablehlo.tanh"(%operand) : (tensor<3xf32>) -> tensor<3xf32>
// %result: [-0.76159416, 0.0, 0.76159416]

ตัวอย่างเพิ่มเติม

สลับตำแหน่ง

อรรถศาสตร์

เรียงสับเปลี่ยนมิติข้อมูลของ tensor ของ operand โดยใช้ permutation และสร้าง Tensor result อย่างเป็นทางการคือ result[result_index] = operand[operand_index] ที่ result_index[d] = operand_index[permutation[d]]

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand tensor หรือ tensor เชิงปริมาณ (C1-C4)
(I2) permutation ค่าคงที่ tensor แบบ 1 มิติของประเภท si64 (C2-C4)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor หรือ tensor เชิงปริมาณ (C1), (C3-C4)

ข้อจำกัด

  • (C1) element_type(result) มอบให้โดย
    • element_type(operand) หากเป็น !is_per_axis_quantized(operand)
    • element_type(operand) ยกเว้น quantization_dimension(operand) และ quantization_dimension(result) อาจแตกต่างกัน
  • (C2) permutation เป็นการเรียงสับเปลี่ยน range(rank(operand))
  • (C3) shape(result) = dim(operand, permutation...)
  • (C4) หากเป็น is_per_axis_quantized(result) ให้ทำดังนี้ quantization_dimension(operand) = permutation(quantization_dimension(result))

ตัวอย่าง

// %operand: [
//            [[1,2], [3,4], [5,6]],
//            [[7,8], [9,10], [11,12]]
//           ]
%result = "stablehlo.transpose"(%operand) {
  permutation = array<i64: 2, 1, 0>
} : (tensor<2x3x2xi32>) -> tensor<2x3x2xi32>
// %result: [
//           [[1,7], [3,9], [5,11]],
//           [[2,8], [4,10], [6,12]]
//          ]

ตัวอย่างเพิ่มเติม

triangular_solve

อรรถศาสตร์

แก้ชุดระบบสมการเชิงเส้นที่มีเมทริกซ์สัมประสิทธิ์สามเหลี่ยมล่างหรือบน

สำหรับ a และ b ในทางปฏิบัติแล้ว result[i0, ..., iR-3, :, :] คือคำตอบของ op(a[i0, ..., iR-3, :, :]) * x = b[i0, ..., iR-3, :, :] เมื่อ left_side คือ true หรือ x * op(a[i0, ..., iR-3, :, :]) = b[i0, ..., iR-3, :, :] เมื่อ left_side เป็น false เพื่อหาตัวแปร x โดยที่ op(a) จะกำหนดโดย transpose_a ซึ่งอาจเป็นอย่างใดอย่างหนึ่งต่อไปนี้

  • NO_TRANSPOSE: ดำเนินการโดยใช้ a ตามที่เป็นอยู่
  • TRANSPOSE: ดำเนินการกับการสลับตำแหน่ง a
  • ADJOINT: ดำเนินการแทนสังยุค a

ข้อมูลที่ป้อนจะอ่านจากสามเหลี่ยมล่างของ a เท่านั้น หาก lower เป็น true หรือรูปสามเหลี่ยมบนของ a หากไม่ใช่ ระบบจะแสดงผลข้อมูลเอาต์พุตในสามเหลี่ยมเดียวกัน ค่าในสามเหลี่ยมอื่นเป็นการกำหนดการติดตั้งใช้งาน

หาก unit_diagonal เป็นจริง การติดตั้งใช้งานจะสันนิษฐานได้ว่าองค์ประกอบในแนวทแยงมุมของ a เท่ากับ 1 หากไม่มีการกำหนดลักษณะการทำงาน

สำหรับประเภทที่แบ่งปริมาณแล้ว จะแสดงผล dequantize_op_quantize(lambda x, y: triangular_solve(x, y, left_side, lower, unit_diagonal, transpose_a), a, b, type(result))

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) a tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1-C3)
(I2) b tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1-C4)
(I3) left_side ค่าคงที่ประเภท i1 (C3)
(I4) lower ค่าคงที่ประเภท i1
(I5) unit_diagonal ค่าคงที่ประเภท i1
(I6) transpose_a enum ของ NO_TRANSPOSE, TRANSPOSE และ ADJOINT

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของชนิดจุดลอยตัวหรือประเภทเชิงซ้อนหรือต่อ tensor เชิงปริมาณ (C1)

ข้อจำกัด

  • (C1) baseline_element_type(a) = baseline_element_type(b)
  • (C2) 2 <= rank(a) = rank(b) = R
  • (C3) ความสัมพันธ์ระหว่าง shape(a) กับ shape(b) มีความหมายดังนี้
    • shape(a)[:-3] = shape(b)[:-3].
    • dim(a, -2) = dim(a, -1) = dim(b, left_side ? -2 : -1).
  • (C4) baseline_type(b) = baseline_type(result)

ตัวอย่าง

// %a = [
//       [1.0, 0.0, 0.0],
//       [2.0, 4.0, 0.0],
//       [3.0, 5.0, 6.0]
//      ]
// %b = [
//       [2.0, 0.0, 0.0],
//       [4.0, 8.0, 0.0],
//       [6.0, 10.0, 12.0]
//      ]
%result = "stablehlo.triangular_solve"(%a, %b) {
  left_side = true,
  lower = true,
  unit_diagonal = false,
  transpose_a = #stablehlo<transpose NO_TRANSPOSE>
} : (tensor<3x3xf32>, tensor<3x3xf32>) -> tensor<3x3xf32>
// %result: [
//           [2.0, 0.0, 0.0],
//           [0.0, 2.0, 0.0],
//           [0.0, 0.0, 2.0]
//          ]

tuple

อรรถศาสตร์

สร้าง Tuple result จากค่า val

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) val จำนวนค่าตัวแปร (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tuple (C1)

ข้อจำกัด

  • (C1) result ได้ประเภท tuple<E0, ..., EN-1> โดยที่ Ei = type(val[i])

ตัวอย่าง

// %val0: [1.0, 2.0]
// %val1: (3)
%result = "stablehlo.tuple"(%val0, %val1) : (tensor<2xf32>, tuple<tensor<i32>>) -> tuple<tensor<2xf32>, tuple<tensor<i32>>>
// %result: ([1.0, 2.0], (3))

ตัวอย่างเพิ่มเติม

uniform_dequantize

อรรถศาสตร์

แปลงแกนประกอบตามองค์ประกอบของ tensor เชิงปริมาณ operand เป็น tensor จุดลอยตัว result ตามพารามิเตอร์การวัดปริมาณที่กำหนดโดยประเภท operand

result = dequantize(operand) อย่างเป็นทางการ

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand Tensor เชิงปริมาณ (C1), (C2)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result Tensor ของประเภทจุดลอยตัว (C1), (C2)

ข้อจำกัด

  • (C1) shape(operand) = shape(result)
  • (C2) element_type(result) = expressed_type(operand)

ตัวอย่าง

// %operand: [10, 10]
%result = "stablehlo.uniform_dequantize"(%operand) : (tensor<2x!quant.uniform<i8:f32:0, {0.1:-30,0.5:-20}>>) -> tensor<2xf32>
// %result: [4.0, 15.0]

uniform_quantize

อรรถศาสตร์

ทำการแปลง tensor แบบจุดลอยตัวหรือ tensor เชิงปริมาณ operand เป็น tensor เชิงปริมาณ result ตามพารามิเตอร์การวัดปริมาณที่กำหนดโดยประเภท result

อย่างเป็นทางการ

  • หากเป็น is_float(operand)
    • result = quantize(operand, type(result)).
  • หากเป็น is_quantized(operand)
    • float_result = dequantize(operand).
    • result = quantize(float_result, type(result)).

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand Tensor ของประเภทจุดลอยตัวหรือเชิงปริมาณ (C1), (C2)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result Tensor เชิงปริมาณ (C1), (C2)

ข้อจำกัด

  • (C1) shape(operand) = shape(result)
  • (C2) expressed_type(result) = is_float(operand) ? element_type(operand) : expressed_type(operand)

ตัวอย่าง

// %operand: [4.0, 15.0]
%result = "stablehlo.uniform_quantize"(%operand) : (tensor<2xf32>) -> tensor<2x!quant.uniform<i8:f32:0, {0.1:-30,0.5:-20}>>
// %result: [10, 10]

// %operand: [10, 10]
%result = "stablehlo.uniform_quantize"(%operand) : (tensor<2x!quant.uniform<i8:f32:0, {0.1:-30,0.5:-20}>>) -> tensor<2x!quant.uniform<i8:f32:0, {0.1:-20,0.2:-30}>>
// %result: [20, 45]

ฟังขณะ

อรรถศาสตร์

สร้างเอาต์พุตจากการเรียกใช้ฟังก์ชัน body อย่างน้อย 0 ครั้งขณะที่ฟังก์ชัน cond เอาต์พุต true ยิ่งไปกว่านั้น อรรถศาสตร์สามารถแสดงด้วยไวยากรณ์ Python ได้ดังนี้

internal_state = operand
while cond(*internal_state):
  internal_state = body(*internal_state)
results = internal_state

ลักษณะการทำงานของลูปที่ไม่สิ้นสุดคือ TBD (#383)

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) operand จำนวน tensors แบบแปรผัน, tensors เชิงปริมาณหรือโทเค็น (C1-C3)
(I2) cond ฟังก์ชัน (C1)
(I3) body ฟังก์ชัน (C2)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
results จำนวน tensors แบบแปรผัน, tensors เชิงปริมาณหรือโทเค็น (C3)

ข้อจำกัด

  • (C1) cond เป็นประเภท (T0, ..., TN-1) -> tensor<i1> โดยที่ Ti = type(operand[i])
  • (C2) body เป็นประเภท (T0, ..., TN-1) -> (T0, ..., TN-1) โดยที่ Ti = type(operand[i])
  • (C3) type(results...) = type(operand...)

ตัวอย่าง

// %init_i: 1
// %init_sum: 0
// %one: 1
// %ten: 10
%results0, %results1 = "stablehlo.while"(%init_i, %init_sum) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %cond = "stablehlo.compare"(%arg0, %ten) {
      comparison_direction = #stablehlo<comparison_direction LT>
    } : (tensor<i64>, tensor<i64>) -> tensor<i1>
    stablehlo.return %cond : tensor<i1>
  }, {
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %new_sum = stablehlo.add %arg1, %one : tensor<i64>
    %new_i = stablehlo.add %arg0, %one : tensor<i64>
    stablehlo.return %new_i, %new_sum : tensor<i64>, tensor<i64>
}) : (tensor<i64>, tensor<i64>) -> (tensor<i64>, tensor<i64>)
// %results0: 10
// %results1: 10

ตัวอย่างเพิ่มเติม

Xor

อรรถศาสตร์

ดำเนินการ XOR ตามองค์ประกอบของ tensor 2 รายการ lhs และ rhs และสร้าง tensor ของ result ดำเนินการดังต่อไปนี้โดยขึ้นอยู่กับประเภทองค์ประกอบ

  • สำหรับบูลีน: ตรรกะ XOR
  • สำหรับจำนวนเต็ม: บิตไวส์ XOR

อินพุต

ค่ายเพลง ชื่อ ประเภท ข้อจำกัด
(I1) lhs tensor ของประเภทบูลีนหรือจำนวนเต็ม (C1)
(I2) rhs tensor ของประเภทบูลีนหรือจำนวนเต็ม (C1)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของประเภทบูลีนหรือจำนวนเต็ม (C1)

ข้อจำกัด

  • (C1) type(lhs) = type(rhs) = type(result)

ตัวอย่าง

// Bitwise operation with with integer tensors
// %lhs: [[1, 2], [3, 4]]
// %rhs: [[5, 6], [7, 8]]
%result = "stablehlo.xor"(%lhs, %rhs) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// %result: [[4, 4], [4, 12]]

// Logical operation with with boolean tensors
// %lhs: [[false, false], [true, true]]
// %rhs: [[false, true], [false, true]]
%result = "stablehlo.xor"(%lhs, %rhs) : (tensor<2x2xi1>, tensor<2x2xi1>) -> tensor<2x2xi1>
// %result: [[false, true], [true, false]]

ตัวอย่างเพิ่มเติม

การทำงานร่วมกันภาษาถิ่น

ในขณะนี้ โปรแกรม StableHLO ทั่วไปมีการดำเนินการที่ไม่ได้กำหนดโดย StableHLO ในบางครั้ง

โมดูล ฟังก์ชัน การเรียก และการคืนสินค้า

StableHLO ใช้การดำเนินการ MLIR แบบอัปสตรีมสำหรับ ModuleOp, FuncOp, CallOp และ ReturnOp การดำเนินการดังกล่าวมีขึ้นเพื่อการทำงานร่วมกันที่ดีขึ้นกับเครื่องจักร MLIR ที่มีอยู่ เนื่องจากมีการเขียนบัตรผ่านที่มีประโยชน์จำนวนมากโดยกำหนดเป้าหมาย FuncOp และ ModuleOp และมีไปป์ไลน์การคอมไพล์จำนวนมากที่คาดว่าจะมีการดำเนินการเหล่านี้ ระบบจะนำการรับประกันความเข้ากันได้เต็มรูปแบบ ไปใช้กับการดำเนินการเหล่านี้ หากมีการเปลี่ยนแปลงใดๆ เกี่ยวกับการดำเนินการเหล่านี้ในลักษณะที่เข้ากันไม่ได้ (เช่น การนำออก) ระบบจะเพิ่มไฟล์ที่เทียบเท่าของ StableHLO เพื่อรักษาความเข้ากันได้

เชโล

ตัวเลือก CHLO มีการดำเนินการระดับสูงกว่าที่แตกตัวเป็น StableHLO ขณะนี้ยังไม่มีการรับประกันความเข้ากันได้สำหรับ CHLO เพื่อรับประกันความเข้ากันได้ คุณต้องใช้บัตร chlo-legalize-to-stablehlo ก่อนการเรียงอันดับ

การดำเนินการของรูปร่าง

เป็นกรณีการใช้งานทั่วไปในชุมชนที่ใช้การดำเนินการบางอย่างจากภาษาหลักของ MLIR ในโปรแกรม StableHLO แบบไดนามิกเพื่อคำนวณรูปร่าง ที่พบบ่อยที่สุด ได้แก่ shapeภาษาถิ่น เช่น shape_of หรือ num_elements, tensor ภาษา เช่น dim หรือ from_elements และประเภท index ในตัว

Dynamism RFC > O2 บ่งบอกว่าสิ่งเหล่านี้อยู่นอกขอบเขต แต่การรองรับ index ประเภทนั้นรวมไว้เพื่อวัตถุประสงค์ด้านการทำงานร่วมกัน เราไม่รับประกันความเข้ากันได้สำหรับ การดำเนินการหรือประเภทเหล่านี้ คุณจะใช้บัตร shape-legalize-to-stablehlo เพื่อแปลงการดำเนินการเหล่านี้เป็นการดำเนินการ StableHLO ที่รองรับอย่างเต็มรูปแบบได้

การดำเนินการที่เลิกใช้งานแล้ว

มีการดำเนินการของ StableHLO หลายรายการที่รับช่วงมาจาก MHLO ซึ่งเลิกใช้งานแล้วและอยู่ระหว่างการหยุดให้บริการ StableHLO ดูรายละเอียดทั้งหมดเกี่ยวกับการนำออกเหล่านี้ได้ในการล้างข้อมูลของ StableHLO v1.0 #2283 ปัญหาเครื่องมือติดตามสำหรับการเลิกใช้งานเหล่านี้คือ #2340

การดำเนินการเหล่านี้แบ่งออกเป็น 2-3 หมวดหมู่ ดังนี้

  • หมวดหมู่การดำเนินการของ StableHLO "ไม่อยู่ใน HLO" ซึ่งตอนแรกเป็นส่วนหนึ่งของ ฝ่ายปฏิบัติการ StableHLO แต่ภายหลังมีการพิจารณาว่าไม่เหมาะสม broadcast, create_token, cross-replica-sum, dot, einsum, torch_index_select, unary_einsum (#3)
  • การดำเนินการที่ไม่ได้ใช้งาน - การดำเนินการเหล่านี้อาจมีประโยชน์ในบางจุด แต่การดำเนินการอาจด้อยพัฒนาหรือมีการเปลี่ยนแปลงไปป์ไลน์ที่ใช้การดำเนินการเหล่านี้เพื่อไม่ให้ต้องใช้การดำเนินการดังกล่าวอีกต่อไป ซึ่งรวมถึง map, tuple (#598), get_tuple_element, rng, complex การเปรียบเทียบ #560 และ Convolution window_reversal (#1181)

การดำเนินการเหล่านี้บางส่วนสามารถนำออกได้ง่ายๆ เนื่องจากสามารถแสดงโดยใช้การดำเนินการที่มีอยู่ (broadcast, create_token, cross-replica-sum, dot, unary_einsum) และจะถูกนำออกหลังพ้นกรอบเวลาความเข้ากันได้ที่มีอยู่ (6 เดือน) ระบบกำลังสำรวจรายการอื่นๆ เพื่อนำออก (einsum, get_tuple_element, map, rng torch_index_select, tuple, complex การเปรียบเทียบ, window_reversal) ความคิดเห็นจากชุมชนที่รอดำเนินการ จะถูกนำออก หรือเพิ่มไปยังข้อกำหนดพร้อมกับการสนับสนุนเต็มรูปแบบ เราจะรับประกันความสามารถในการใช้งานร่วมกันเป็นเวลาเพียง 6 เดือนเท่านั้นจนกว่าเราจะรู้อนาคตการดำเนินการเหล่านี้

การลงมือปฏิบัติ

การดำเนินการตามลำดับ

โปรแกรม StableHLO จะดำเนินการโดยการระบุค่าอินพุตให้กับฟังก์ชัน main และค่าเอาต์พุตการคำนวณ ค่าเอาต์พุตของฟังก์ชันจะคํานวณโดยการเรียกใช้กราฟของ Ops ที่รูทในฟังก์ชัน return ที่สอดคล้องกัน

ลำดับการดำเนินการได้รับการนิยามถึงการใช้งาน ตราบใดที่สอดคล้องกับโฟลว์ข้อมูล กล่าวคือ มีการดำเนินการ Ops ก่อนการใช้งาน ใน StableHLO การดำเนินการที่ส่งผลข้างเคียงทั้งหมดจะใช้ 1 โทเค็นและสร้างโทเค็น 1 โทเค็น (สามารถรวมโทเค็นหลายรายการเข้าเป็นโทเค็นเดียวผ่าน after_all ได้) ดังนั้นลำดับการดำเนินการของผลข้างเคียงจึงสอดคล้องกับโฟลว์ข้อมูลด้วย ตัวอย่างเช่น ในโปรแกรมด้านล่างมีคำสั่งการดำเนินการที่เป็นไปได้ 2 คำสั่ง ได้แก่ %0%1%2return และ %1%0%2return

func.func @main() -> tensor<f64> {
  %0 = stablehlo.constant dense<1.0> : tensor<f64>
  %1 = stablehlo.constant dense<2.0> : tensor<f64>
  %2 = stablehlo.add %0, %1 : tensor<f64>
  return %2 : tensor<f64>
}

หรืออีกนัยหนึ่งคือ กระบวนการ StableHLO ประกอบด้วย 1) โปรแกรม StableHLO, 2) สถานะการดำเนินการ (ยังไม่ได้ดำเนินการ, ดำเนินการแล้ว) และ 3) ค่ากลางที่กระบวนการนี้ทำงานอยู่ กระบวนการเริ่มต้นด้วยค่าอินพุตไปยังฟังก์ชัน main จากนั้นจะดำเนินการต่อผ่านกราฟของการดำเนินการที่อัปเดตสถานะการดำเนินการ ค่ากลาง และเสร็จสิ้นด้วยค่าเอาต์พุต จะมีพิธีการเพิ่มเติมในภายหลัง (#484)

การดำเนินการพร้อมกัน

โปรแกรม StableHLO ดำเนินการพร้อมกันได้ โดยจัดระเบียบเป็นตารางการประมวลผลแบบ 2D ของ num_replicas โดย num_partitions ซึ่งทั้ง 2 โปรแกรมเป็นประเภท ui32

ในตารางกริดการประมวลผลของ StableHLO จะมีการดำเนินการ num_replicas * num_partitions ของกระบวนการ StableHLO พร้อมกัน แต่ละกระบวนการจะมี process_id = (replica_id, partition_id) ที่ไม่ซ้ำกัน โดยที่ replica_id ใน replica_ids = range(num_replicas) และ partition_id ใน partition_ids = range(num_partitions) ซึ่งทั้งคู่มีประเภท ui32

ขนาดของตารางกริดการประมวลผลเป็นที่ทราบกันดีอยู่แล้วสำหรับทุกโปรแกรม (ในอนาคตเราวางแผนที่จะทำให้ตารางดังกล่าวเป็นส่วนสำคัญของโปรแกรม StableHLO #650) และมีการกำหนดตำแหน่งภายในตารางกริดของกระบวนการในเชิงสถิติสำหรับทุกกระบวนการ แต่ละกระบวนการมีสิทธิ์เข้าถึงตำแหน่งของตนภายในตารางกริดของกระบวนการผ่านการดำเนินการ replica_id และ partition_id

ภายในตารางกระบวนการ โปรแกรมทั้งหมดอาจเหมือนกัน (ในสไตล์ "โปรแกรมเดียว ข้อมูลหลายรายการ") อาจแตกต่างกัน (ในรูปแบบ "หลายโปรแกรม ข้อมูลหลายรายการ") หรืออื่นๆ ในอนาคต เราวางแผนที่จะเพิ่มการสนับสนุนสำหรับสำนวนอื่นๆ ของการกำหนดโปรแกรม StableHLO ควบคู่กัน ซึ่งรวมถึง GSPMD (#619)

ภายในตารางกริดของกระบวนการ กระบวนการส่วนใหญ่จะเป็นอิสระจากกัน กล่าวคือมีสถานะการดำเนินการแยกกัน ค่าอินพุต/สื่อกลาง/เอาต์พุตแยกกัน และการดำเนินการส่วนใหญ่จะดำเนินการแยกกันระหว่างกระบวนการต่างๆ โดยยกเว้นการดำเนินการรวมจำนวนเล็กน้อยตามที่อธิบายไว้ด้านล่าง

เนื่องจากการดำเนินการส่วนใหญ่ใช้เพียงค่าจากกระบวนการเดียวกัน ทำให้เรียกค่าเหล่านี้ด้วยชื่อได้ไม่กำกวม อย่างไรก็ตาม การอธิบายความหมายของการดำเนินการโดยรวมนั้นไม่เพียงพอ และเป็นที่มาของสัญลักษณ์ name@process_id เพื่ออ้างถึงค่า name ภายในกระบวนการใดกระบวนการหนึ่ง (จากมุมมองนี้ name ที่ไม่เข้าเกณฑ์สามารถมองเป็นชวเลขสำหรับ name@(replica_id(), partition_id())) ได้

คำสั่งดำเนินการข้ามกระบวนการจะได้รับการกำหนดการติดตั้งใช้งาน ยกเว้นการซิงค์ที่เกิดจากการสื่อสารแบบจุดต่อจุดและการดำเนินการร่วมตามที่อธิบายไว้ด้านล่าง

การสื่อสารแบบจุดต่อจุด

กระบวนการของ StableHLO สามารถสื่อสารกันได้ผ่านแชแนลของ StableHLO แชแนลจะแสดงด้วยรหัสเชิงบวกประเภท si64 การส่งค่าไปยังแชแนลและการรับค่าจากแชแนลสามารถผ่านการดำเนินการที่หลากหลายได้

ความเป็นทางการเพิ่มเติม เช่น ที่มาของรหัสแชแนลเหล่านี้ วิธีที่กระบวนการรับรู้ถึงโปรแกรมเหล่านี้ และประเภทของการซิงค์ที่เกิดจากรหัสดังกล่าว จะแจ้งภายหลัง (#484)

การสื่อสารผ่านสตรีมมิง

ทุกกระบวนการของ StableHLO มีสิทธิ์เข้าถึงอินเทอร์เฟซสตรีมมิง 2 อินเทอร์เฟซ ดังนี้

  • Infeed ที่อ่านได้
  • Outfeed ที่เขียนได้

ในฟีดและฟีดภายนอกจะมีส่วนกำหนดการติดตั้งใช้งานเอง ซึ่งต่างจากแชแนลที่ใช้สื่อสารระหว่างกระบวนการต่างๆ และมีกระบวนการทั้ง 2 ด้าน

ความเป็นทางการเพิ่มเติม เช่น ผลของการสื่อสารผ่านสตรีมมิงที่มีต่อคำสั่งการดำเนินการและประเภทของการซิงค์ที่นำมาใช้นั้น จะเป็นการแจ้งภายหลัง (#484)

หน่วยปฏิบัติการ

มีการดำเนินการร่วมกัน 6 อย่างใน StableHLO ได้แก่ all_gather, all_reduce, all_to_all, collective_broadcast, collective_permute และ reduce_scatter การดำเนินการทั้งหมดนี้แยกกระบวนการในตารางกริดของกระบวนการ StableHLO ออกเป็นกลุ่มกระบวนการของ StableHLO และดำเนินการคำนวณร่วมภายในแต่ละกลุ่มกระบวนการ โดยแยกจากกลุ่มกระบวนการอื่นๆ

ภายในกลุ่มกระบวนการแต่ละกลุ่ม การดำเนินการร่วมอาจเพิ่มอุปสรรคในการซิงค์ การทำให้เป็นทางการเพิ่มเติม เช่น การอธิบายรายละเอียดว่าการซิงค์นี้เกิดขึ้นเมื่อใด กระบวนการต่างๆ จะสร้างอุปสรรคนี้ได้อย่างไร และจะเกิดอะไรขึ้นหากไม่เป็นเช่นนั้น จะแจ้งภายหลัง (#484)

หากกลุ่มกระบวนการเกี่ยวข้องกับการสื่อสารข้ามพาร์ติชัน กล่าวคือ มีกระบวนการในกลุ่มกระบวนการที่มีรหัสพาร์ติชันแตกต่างกัน การดำเนินการของฝั่งตรงข้ามจะต้องมีแชแนล และคำสั่ง ร่วมจะต้องระบุ channel_id ที่เป็นบวกของประเภท si64 การสื่อสารข้ามการจำลองไม่จำเป็นต้องมี แชแนล

การคำนวณที่ดำเนินการโดยหน่วยดำเนินการเป็นกลุ่มจะมีการดำเนินการเฉพาะของแต่ละการดำเนินการและมีอธิบายไว้ในส่วนการดำเนินการของแต่ละส่วนข้างต้น อย่างไรก็ตาม กลยุทธ์ที่แบ่งตารางกระบวนการออกเป็นกลุ่มกระบวนการจะแชร์ระหว่างการดำเนินการเหล่านี้ และได้อธิบายไว้ในส่วนนี้ ส่วนอย่างเป็นทางการคือ StableHLO รองรับ กลยุทธ์ 4 ประการต่อไปนี้

cross_replica

เฉพาะการสื่อสารข้ามโมเดลที่เกิดขึ้นภายในแต่ละกลุ่มกระบวนการ กลยุทธ์นี้ใช้ replica_groups ซึ่งเป็นรายการรหัสตัวจำลอง และคำนวณผลคูณคาร์ทีเซียนของ replica_groups ภายในวันที่ partition_ids replica_groups ต้องมีองค์ประกอบที่ไม่ซ้ำกันและครอบคลุม replica_ids ทั้งหมด เป็นทางการมากขึ้น โดยใช้ไวยากรณ์ Python

def cross_replica(replica_groups: List[List[ReplicaId]]) -> List[List[ProcessId]]:
  for replica_group in replica_groups:
    for partition_id in partition_ids:
      process_group = []
      for replica_id in replica_group:
        process_group.append((replica_id, partition_id))
      yield process_group

ตัวอย่างเช่น สำหรับ replica_groups = [[0, 1], [2, 3]] และ num_partitions = 2 แล้ว cross_replica จะให้ผลลัพธ์เป็น [[(0, 0), (1, 0)], [(0, 1), (1, 1)], [(2, 0), (3, 0)], [(2, 1), (3, 1)]]

cross_partition

เฉพาะการสื่อสารข้ามพาร์ติชันจะเกิดขึ้นภายในกลุ่มกระบวนการแต่ละกลุ่มเท่านั้น กลยุทธ์นี้จะใช้ partition_groups ซึ่งเป็นรายการรหัสพาร์ติชัน และคำนวณผลคูณคาร์ทีเซียนของ partition_groups ภายในวันที่ replica_ids partition_groups ต้องมีองค์ประกอบที่ไม่ซ้ำกันและครอบคลุม partition_ids ทั้งหมด เป็นทางการมากขึ้นโดยใช้ไวยากรณ์ Python

def cross_partition(partition_groups: List[List[PartitionId]]) -> List[List[ProcessId]]:
  for partition_group in partition_groups:
    for replica_id in replica_ids:
      process_group = []
      for partition_id in partition_group:
        process_group.append((replica_id, partition_id))
      yield process_group

ตัวอย่างเช่น สำหรับ partition_groups = [[0, 1]] และ num_replicas = 4 แล้ว cross_partition จะให้ผลลัพธ์เป็น [[(0, 0), (0, 1)], [(1, 0), (1, 1)], [(2, 0), (2, 1)], [(3, 0), (3, 1)]]

cross_replica_and_partition

การสื่อสารทั้งจากการจำลองและข้ามพาร์ติชันอาจเกิดขึ้นภายในกลุ่มกระบวนการแต่ละกลุ่ม กลยุทธ์นี้จะใช้ replica_groups ซึ่งเป็นรายการรหัสข้อมูลจำลอง และคำนวณผลิตภัณฑ์คาร์ทีเซียนของแต่ละ replica_group ตาม partition_ids replica_groups ต้องมีองค์ประกอบที่ไม่ซ้ำกันและครอบคลุม replica_ids ทั้งหมด เป็นทางการมากขึ้นโดยใช้ไวยากรณ์ Python

def cross_replica_and_partition(replica_groups: List[List[ReplicaId]]) -> List[List[ProcessId]]:
  for replica_group in replica_groups:
    process_group = []
    for partition_id in partition_ids:
      for replica_id in replica_group:
        process_group.append((replica_id, partition_id))
    yield process_group

ตัวอย่างเช่น สำหรับ replica_groups = [[0, 1], [2, 3]] และ num_partitions = 2 แล้ว cross_replica_and_partition จะให้ผลลัพธ์เป็น [[(0, 0), (1, 0), (0, 1), (1, 1)], [(2, 0), (3, 0), (2, 1), (3, 1)]]

flattened_ids

กลยุทธ์นี้จะใช้ flattened_id_groups ซึ่งเป็นรายการรหัสกระบวนการที่อยู่ในรูปแบบ replica_id * num_partitions + partition_id แล้วเปลี่ยนให้เป็นรหัสกระบวนการ flattened_id_groups ต้องมีองค์ประกอบที่ไม่ซ้ำกัน และครอบคลุม process_ids ทั้งหมด เป็นทางการมากขึ้นโดยใช้ไวยากรณ์ Python

def flattened_ids(flattened_id_groups: List[List[ui32]]) -> List[List[ProcessId]]:
  for flattened_id_group in flattened_id_groups:
    process_group = []
    for flattened_id in flattened_id_group:
      replica_id = flattened_id // num_partitions
      partition_id = flattened_id % num_partitions
      process_group.append((replica_id, partition_id))
    yield process_group

ตัวอย่างเช่น สำหรับ flattened_id_groups = [[0, 1, 2, 3], [4, 5, 6, 7]], num_replicas = 4 และ num_partitions = 2 แล้ว flattened_ids จะสร้าง [[(0, 0), (0, 1), (1, 0), (1, 1)], [(2, 0), (2, 1), (3, 0), (3, 1)]]

ความแม่นยำ

ในขณะนี้ StableHLO ไม่รับประกันความถูกต้องของตัวเลข แต่อาจมีการเปลี่ยนแปลงในอนาคต (#1156)

อรรถศาสตร์ของการดำเนินการเชิงปริมาณ

การตีความการดำเนินการ StableHLO เชิงปริมาณอาจแตกต่างกันไปโดยขึ้นอยู่กับข้อกำหนดด้านฮาร์ดแวร์และความสามารถของฮาร์ดแวร์ ตัวอย่างเช่น ฮาร์ดแวร์บางตัวอาจเลือกตีความการดำเนินการเชิงปริมาณโดยใช้กลยุทธ์ "จัดเรียงลำดับ ดำเนินการจุดลอยตัว" และสุดท้าย "ทำให้เป็นปริมาณ" ขณะที่รายอื่นๆ อาจทำการคำนวณทั้งหมดด้วยเลขคณิตที่เป็นจำนวนเต็ม ดังนั้น การตีความการดำเนินการ StableHLO เชิงปริมาณจะขึ้นอยู่กับการใช้งานที่เฉพาะเจาะจง การตีความเชิงปริมาณแบบผสม (#1575) ควรอิงตามอรรถศาสตร์ตามที่ระบุไว้ในข้อกำหนด (ผ่าน 1792)

ข้อผิดพลาด

โปรแกรม StableHLO จะได้รับการตรวจสอบผ่านข้อจำกัดจำนวนมากสำหรับการดำเนินการแต่ละรายการ ซึ่งจะตัดคลาสของข้อผิดพลาดต่างๆ ออกก่อนหมดเวลา อย่างไรก็ตาม เงื่อนไขข้อผิดพลาดจะยังคงเป็นไปได้ เช่น ผ่านจํานวนที่เกินจํานวนเต็ม การเข้าถึงนอกขอบเขต และอื่นๆ ข้อผิดพลาดทั้งหมดเหล่านี้ส่งผลให้เกิดลักษณะการทํางานที่กำหนดโดยการติดตั้งใช้งาน แต่อาจมีการเปลี่ยนแปลงในอนาคต (#1157) เว้นแต่จะมีการเรียกไว้อย่างชัดเจน

ข้อยกเว้นจุดลอยตัว

ข้อยกเว้นของกฎข้อนี้ระบุไว้ว่าเป็นข้อยกเว้นแบบจุดลอยตัวในโปรแกรม StableHLO การดำเนินการที่ทำให้เกิดข้อยกเว้นซึ่งมาตรฐาน IEEE-754 กำหนดไว้ (การดำเนินการที่ไม่ถูกต้อง, การหารต่อศูนย์, การดำเนินการเพิ่มเติม, ค่าที่น้อยเกินกำหนด หรือข้อยกเว้นที่ไม่ตรงจุด) จะให้ผลลัพธ์เริ่มต้น (ตามที่ให้คำจำกัดความไว้ในมาตรฐาน) และดำเนินการต่อไปโดยไม่เพิ่มแฟล็กสถานะที่เกี่ยวข้อง ซึ่งคล้ายกับการจัดการข้อยกเว้น raiseNoFlag จากมาตรฐาน ข้อยกเว้นสำหรับการดำเนินการที่ไม่เป็นไปตามมาตรฐาน (เช่น เลขคณิตที่ซับซ้อนและฟังก์ชันสืบเนื่องบางอย่าง) จะได้รับการกำหนดการใช้งาน

รูปร่างไม่ตรงกัน

StableHLO รองรับ Tensor รูปทรงแบบไดนามิก แต่รูปร่างจะต้องสอดคล้องกันในรันไทม์ มิเช่นนั้นจะไม่มีการระบุลักษณะการทำงาน StableHLO ไม่ได้ระบุการดำเนินการอย่างชัดแจ้งที่ยืนยันว่า tensor มีรูปร่างที่กำหนดขณะรันไทม์ การสร้างโค้ดที่ถูกต้องเป็นความรับผิดชอบของผู้ผลิต

ตัวอย่างเช่น โปรแกรมด้านล่างถือว่าถูกต้อง แต่ขณะรันไทม์ รูปร่างที่แน่นอนของ %arg0 และ %arg1 จะต้องเหมือนกัน มิเช่นนั้นจะไม่มีการกำหนดลักษณะการทำงานของโปรแกรม ดังนี้

func.func @foo(%arg0: tensor<?xi32>, %arg1: tensor<?xi32>) -> tensor<?xi32> {
    %0 = stablehlo.add %arg0, %arg1 : tensor<?xi32>
    return %0 : tensor<?xi32>
}

เครื่องหมาย

ในการอธิบายไวยากรณ์ เอกสารฉบับนี้ใช้เวอร์ชัน ISO ที่แก้ไขแล้วของไวยากรณ์ EBNF (ISO/IEC 14977:1996, Wikipedia) โดยมีการแก้ไข 2 รายการ คือ 1) กำหนดกฎโดยใช้ ::= แทนที่จะเป็น =

2) การต่อกันแสดงโดยใช้การเรียงต่อกันแทนที่จะใช้ ,

สำหรับการอธิบายความหมาย (เช่น ภายในส่วน "ประเภท" "ค่าคงที่" และ "การดำเนินการ") เราจะใช้สูตรที่อิงตามไวยากรณ์ Python ที่ขยายให้รองรับการแสดงการทำงานของอาร์เรย์อย่างกระชับตามที่อธิบายไว้ด้านล่าง วิธีนี้ใช้ได้ดีสำหรับข้อมูลโค้ดสั้นๆ แต่ในกรณีที่ต้องขอข้อมูลโค้ดขนาดใหญ่กว่าปกติ เราจะใช้ไวยากรณ์ Python แบบวานิลลาซึ่งจะแสดงขึ้นมาอย่างชัดเจนเสมอ

สูตร

มาสำรวจวิธีการทำงานของสูตรตามตัวอย่างจากข้อกำหนด dot_general กัน หนึ่งในข้อจำกัดสำหรับการดำเนินการนี้มีดังนี้ dim(lhs, lhs_batching_dimensions...) = dim(rhs, rhs_batching_dimensions...)

ชื่อที่ใช้ในสูตรนี้มาจากแหล่งที่มา 2 แหล่ง ได้แก่ 1) ฟังก์ชันส่วนกลาง (เช่น dim) 2) คำจำกัดความสมาชิกขององค์ประกอบโปรแกรมที่สอดคล้องกัน ซึ่งก็คืออินพุต lhs, lhs_batching_dimensions, rhs และ rhs_batching_dimensions ที่กำหนดไว้ในส่วน "อินพุต" ของ dot_general

ดังที่กล่าวไว้ข้างต้น ไวยากรณ์ของสูตรนี้คือแบบ Python ที่มีส่วนขยายบางรายการที่เน้นความกระชับ เพื่อให้เข้าใจสูตร เราจะแปลงสูตรเป็นไวยากรณ์ Python แบบวานิลลา

ตอบ) ในสูตรเหล่านี้ เราใช้ = เพื่อแสดงความเท่ากัน ดังนั้นขั้นตอนแรกในการได้รับไวยากรณ์ Python จะแทนที่ = ด้วย == ดังนี้ dim(lhs, lhs_batching_dimensions...) == dim(rhs, rhs_batching_dimensions...)

B) นอกจากนี้ สูตรเหล่านี้ยังรองรับจุดไข่ปลา (...) ซึ่งเปลี่ยนนิพจน์สเกลาร์เป็นนิพจน์ tensor โดยสรุปแล้ว f(xs...) หมายถึง "x สำหรับสเกลาร์แต่ละรายการใน tensor xs ให้คำนวณสเกลาร์ f(x) แล้วแสดงผลสเกลาร์เหล่านี้ทั้งหมดร่วมกันเป็นผลลัพธ์ tensor" ในไวยากรณ์ Python วานิลลา สูตรตัวอย่างจะเปลี่ยนเป็น [dim(lhs, dim1) for dim1 in lhs_batching_dimensions] == [dim(rhs, dim2) for dim2 in rhs_batching_dimensions]

ด้วยการใช้จุดไข่ปลา คุณมักจะหลีกเลี่ยงการทำงานในระดับสเกลาร์เดี่ยวได้ อย่างไรก็ตาม ในบางกรณีที่มีความซับซ้อน อาจมีการใช้ไวยากรณ์กึ่งไม่เป็นทางการในระดับต่ำกว่าอย่างเช่นในสูตร start_indices[bi0, ..., :, ..., biN] จากข้อกำหนดของ gather เราไม่ได้ระบุรูปแบบที่ชัดเจนสำหรับการแปลไวยากรณ์เป็นวานิลลา Python เพื่อให้บริการการเขียนให้กระชับขึ้น เนื่องจากหวังว่าผู้ใช้จะเข้าใจได้เป็นรายกรณีไป โปรดแจ้งให้เราทราบหากมีบางสูตรที่ดูไม่ชัดเจนและเราจะพยายาม ปรับปรุงสูตรเหล่านั้น

คุณจะสังเกตเห็นว่าสูตรใช้จุดไข่ปลาในการขยายรายการทุกประเภท รวมถึง tensors, รายการ tensors (ซึ่งอาจเกิดจากจำนวน tensors แบบแปรปรวน) เป็นต้น นี่เป็นอีกประเด็นหนึ่งที่เราไม่ได้กำหนดความเป็นทางการที่แน่นอน (เช่น รายการไม่ได้เป็นส่วนหนึ่งของระบบประเภท StableHLO ที่เข้าใจได้เสียด้วยซ้ำ) และ อาศัยหลักการที่เข้าใจไม่ได้

ค) ยานพาหนะที่ใช้สัญลักษณ์สำคัญข้อสุดท้ายที่เราใช้คือการออกอากาศโดยนัย แม้ว่าตัวเลือกของ StableHLO จะไม่รองรับการออกอากาศโดยนัย แต่สูตรนั้นก็รองรับรูปแบบการเขียนที่สั้นกระชับด้วยเช่นกัน กล่าวโดยสรุป ถ้ามีการใช้สเกลาร์ในบริบทที่คาดว่า Tensor จะมีการแสดงสเกลาร์เป็นรูปร่างที่คาดไว้

โปรดดูข้อจำกัดอีกข้อหนึ่งเพื่อดำเนินการตามตัวอย่าง dot_general ต่อไป 0 <= lhs_batching_dimensions < rank(lhs) ตามที่ระบุไว้ในข้อกำหนด dot_general lhs_batching_dimensions คือ tensor แต่ทั้ง 0 และ rank(lhs) เป็นสเกลาร์ หลังจากใช้การออกอากาศโดยนัยแล้ว สูตรจะกลายเป็น [0, ..., 0] <= lhs_batching_dimensions < [rank(lhs), ..., rank(lhs)]

เมื่อใช้กับการดำเนินการ dot_general ที่เฉพาะเจาะจง สูตรนี้จะประเมินกับ tensor ของบูลีน เมื่อใช้สูตรเป็นเงื่อนไข ข้อจำกัดจะระงับหากสูตรประเมินเป็น true หรือกับ tensor ซึ่งมีเฉพาะองค์ประกอบ true

ชื่อ

ในสูตรต่างๆ ขอบเขตคำศัพท์ ได้แก่ 1) ฟังก์ชันส่วนกลาง 2) คำนิยามสมาชิก

3) คำจำกัดความในท้องถิ่น รายการฟังก์ชันส่วนกลางมีดังนี้ รายการการกำหนดองค์ประกอบจะขึ้นอยู่กับองค์ประกอบโปรแกรมที่ใช้สัญลักษณ์ต่อไปนี้

  • สำหรับการดำเนินการ คำจำกัดความของสมาชิกจะรวมชื่อที่แนะนำในส่วน "อินพุต" และ "เอาต์พุต"
  • สำหรับสิ่งอื่นๆ ที่เหลือ คำจำกัดความของสมาชิกประกอบด้วยส่วนโครงสร้างขององค์ประกอบโปรแกรม โดยตั้งชื่อตามรายการที่ไม่ใช่เทอร์มินัล EBNF ที่เกี่ยวข้อง โดยส่วนใหญ่แล้ว ชื่อของชิ้นส่วนโครงสร้างเหล่านี้จะได้มาจากการแปลงชื่อที่ไม่ใช่เทอร์มินัลให้เป็นตัวพิมพ์ใหญ่ (เช่น IntegerLiteral => integer_literal) แต่บางครั้งชื่อจะถูกย่อในขั้นตอนดังกล่าว (เช่น QuantizationStorageType => storage_type) ซึ่งในกรณีนี้ระบบจะแนะนำชื่อในทำนองเดียวกับ "อินพุต" / "เอาต์พุต" อย่างชัดเจนในการดําเนินการ
  • นอกจากนี้ คําจํากัดความของสมาชิกจะใส่ self เสมอเพื่ออ้างถึงองค์ประกอบโปรแกรมที่เกี่ยวข้อง

ค่า

เมื่อประเมินสูตร สูตรจะทำงานกับค่าประเภทต่อไปนี้ 1) Value (ค่าจริง เช่น dense<[[1, 2], [3, 4]]> : tensor<2x2xi32> รู้ประเภทอยู่เสมอ) 2) Placeholder (ค่าในอนาคต เช่น lhs, rhs หรือ result เรายังไม่รู้ค่าจริง แต่จะทราบเฉพาะประเภทของค่า) 3) Type (ประเภทตามที่ระบุไว้ในส่วน "ประเภท") ตามที่ระบุไว้ในส่วน Function (ฟังก์ชันส่วนกลาง)

ชื่ออาจสื่อถึงค่าที่ต่างกัน ทั้งนี้ขึ้นอยู่กับบริบท กล่าวอย่างเจาะจงก็คือ ส่วน "Semantics" สำหรับ Ops (และองค์ประกอบที่เทียบเท่าสำหรับองค์ประกอบโปรแกรมอื่นๆ) จะกำหนดตรรกะรันไทม์ ดังนั้นอินพุตทั้งหมดจึงพร้อมใช้งานเป็น Value ในทางตรงกันข้าม ส่วน "Constraints" สำหรับการดำเนินการ (และที่เทียบเท่า) จะกำหนดตรรกะ "เวลาคอมไพล์" ซึ่งก็คือสิ่งที่มักดำเนินการก่อนรันไทม์ ดังนั้นมีเพียงอินพุตคงที่เท่านั้นที่จะพร้อมใช้งานเป็น Value และอินพุตอื่นๆ จะพร้อมใช้งานเป็น Placeholder เท่านั้น

ชื่อ ใน "Semantics" ใน "ข้อจำกัด"
ฟังก์ชันส่วนกลาง Function Function
อินพุตแบบคงที่ Value Value
อินพุตที่ไม่คงที่ Value Placeholder
เอาต์พุต Value Placeholder
คำจำกัดความในพื้นที่ ขึ้นอยู่กับคำจำกัดความ ขึ้นอยู่กับคำจำกัดความ

ลองมาดูตัวอย่างการดำเนินการ transpose กัน

%result = "stablehlo.transpose"(%operand) {
  permutation = dense<[2, 1, 0]> : tensor<3xi64>
} : (tensor<2x3x2xi32>) -> tensor<2x3x2xi32>

สำหรับการดำเนินการนี้ permutation เป็นค่าคงที่ ดังนั้นจึงพร้อมใช้งานเป็น Value ทั้งในความหมายและข้อจำกัด ในทางตรงกันข้าม operand และ result จะพร้อมใช้งานเป็น Value ในความหมาย แต่เป็น Placeholder ในข้อจำกัดเท่านั้น

ฟังก์ชัน

โครงสร้างประเภทต่างๆ

ไม่มีฟังก์ชันที่ใช้สร้างประเภทได้ แต่เราจะใช้ไวยากรณ์ประเภท โดยตรงแทนเนื่องจากรูปแบบนี้จะกระชับมากกว่า เช่น (tensor<E>, tensor<E>) -> (tensor<E>) แทนที่จะเป็น function_type( [tensor_type([], E), tensor_type([], E)], [tensor_type([], E)])

ฟังก์ชันเกี่ยวกับประเภท

  • element_type กำหนดไว้ตามประเภท tensor และประเภท tensor ที่วัดปริมาณและผลลัพธ์และผลลัพธ์ ตามลำดับ ส่วน TensorElementType หรือ QuantizedTensorElementType ของ TensorType หรือ QuantizedTensorType ที่สอดคล้องกัน
def element_type(x: Value | Placeholder | Type):
 if type(x) == TensorType:
    return tensor_element_type(x)
  if type(x) == QuantizedTensorType:
    return quantized_tensor_element_type(x)
  if type(x) is not Type:
    return element_type(type(x))
  • is_per_axis_quantized(x: Value | Placeholder | Type) -> Value เป็นทางลัดสำหรับ is_quantized(x) and quantization_dimension(x) is not None

  • is_per_tensor_quantized(x: Value | Placeholder | Type) -> Value เป็นทางลัดสำหรับ is_quantized(x) and quantization_dimension(x) is None

  • is_promotable(x: Type, y: Type) -> bool จะตรวจสอบว่าประเภท x ได้รับการโปรโมตเป็นประเภท y หรือไม่ เมื่อ x และ y เป็น QuantizedTensorElementType โปรโมชันจะใช้กับ storage_type เท่านั้น ปัจจุบันโปรโมชันเวอร์ชันเฉพาะนี้ใช้ในบริบทของการคำนวณการลด (ดูรายละเอียดเพิ่มเติมใน RFC)

def is_promotable(x: Type, y: Type) -> Value:
  is_same_type = (is_bool(x) and is_bool(y)) or
    (is_integer(x) and is_integer(y)) or (is_float(x) and is_float(y)) or
    (is_complex(x) and is_complex(y)) or
    (is_quantized(x) and is_quantized(y) and expressed_type(x) = expressed_type(y))

  if is_same_type == False:
    return False

  if is_integer(x) or is_float(x):
    return bitwidth(x) <= bitwidth(y)

  if is_complex(x):
    return bitwidth(element_type(x)) <= bitwidth(element_type(y))

  if is_quantized(x):
    return bitwidth(storage_type(x)) <= bitwidth(storage_type(y))

  return false
  • is_quantized(x: Value | Placeholder | Type) -> Value เป็นทางลัดสำหรับ is_quantized_tensor_element_type(x)

  • is_type_name(x: Value | Placeholder | Type) -> Value พร้อมใช้งานสำหรับ ทุกประเภท เช่น is_float(x) จะแสดงผล true หาก x เป็น FloatType หาก x เป็นค่าหรือตัวยึดตำแหน่ง ฟังก์ชันนี้จะเป็นทางลัดสำหรับ is_type_name(type(x))

  • max_value(x: Type) -> Value แสดงผลค่าสูงสุดของ TensorElementType หาก x ไม่ใช่ TensorElementType จะแสดงผล None

  • min_value(x: Type) -> Value จะแสดงผลค่าต่ำสุดที่เป็นไปได้ของ TensorElementType หาก x ไม่ใช่ TensorElementType จะแสดงผล None

  • member_name(x: Value | Placeholder | Type) -> Any พร้อมใช้งานสำหรับคำจำกัดความของสมาชิกทั้งหมดmember_nameทุกประเภท เช่น tensor_element_type(x) จะแสดงผลส่วน TensorElementType ของ TensorType ที่สอดคล้องกัน หาก x เป็นค่าหรือตัวยึดตำแหน่ง ฟังก์ชันนี้จะเป็นทางลัดสำหรับ member_name(type(x)) หาก x ไม่ใช่ประเภทที่มีสมาชิกที่เหมาะสม หรือค่าหรือตัวยึดตำแหน่งของประเภทดังกล่าว จะแสดงผล None

โครงสร้างของค่า

  • operation_name(*xs: Value | Type) -> Value พร้อมใช้งานสำหรับการดำเนินการทั้งหมด ตัวอย่างเช่น add(lhs, rhs) จะใช้ค่า tensor 2 ค่า lhs และ rhs และแสดงผลผลลัพธ์ของการประเมินการดำเนินการ add ด้วยอินพุตเหล่านี้ สำหรับการดำเนินการบางอย่าง เช่น broadcast_in_dim ประเภทของเอาต์พุตคือ "รับน้ำหนัก" นั่นคือ จำเป็นสำหรับการประเมินการดำเนินการ ในกรณีนี้ ฟังก์ชันจะใช้ประเภทเหล่านี้เป็นอาร์กิวเมนต์

ฟังก์ชันเกี่ยวกับค่า

  • โอเปอเรเตอร์และฟังก์ชันทั้งหมดของ Python พร้อมใช้งาน เช่น ทั้งเครื่องหมาย subscription และ slicing จาก Python พร้อมสำหรับการจัดทำดัชนีใน tensors, tensors แบบวัดปริมาณ และ tuple

  • to_destination_type(x: Value, destination_type: Type) -> Value กําหนดตาม tensors และแสดงผลค่าที่แปลงแล้วของ x โดยอิงตาม type(x) และ destination_type ดังนี้

def to_destination_type(x: Value, destination_type: Type) -> Value:
  if type(x) == destination_type:
    return x

  if is_quantized(destination_type):
    if is_quantized(type(x)):
      return quantize(x, destination_type)
    assert is_float(type(x))
    return quantize(x, destination_type)

  if is_quantized(type(x)):
    assert destination_type = expressed_type(type(x))
    return dequantize(type(x))

  return convert(x, destination_type)

ขณะนี้มีการอภิปรายเกี่ยวกับการผสานรวมการดำเนินการ convert, uniform_quantize และ uniform_dequantize (#1576) หลังจากผสานรวมแล้ว เราไม่จำเป็นต้องใช้ฟังก์ชันข้างต้น และจะใช้ชื่อการดำเนินการสำหรับ convert แทนได้

  • is_nan(x: Value) -> Value จะได้รับการกำหนดใน tensors และแสดงผล true หากองค์ประกอบทั้งหมดของ x เป็น NaN หรือ false ในกรณีอื่นๆ หาก x ไม่ใช่ Tensor จะแสดงผล None

  • is_sorted(x: Value) -> Value กำหนดไว้ใน tensors และจะแสดงผล true หากองค์ประกอบของ x ได้รับการจัดเรียงจากน้อยไปมากตามลำดับของดัชนีจากน้อยไปมากของดัชนี หรือ false ในกรณีอื่นๆ หาก x ไม่ใช่ Tensor จะแสดงผล None

  • is_unique(x: Value) -> Value จะได้รับการกำหนดใน tensors และแสดงผล true หาก x ไม่มีองค์ประกอบที่ซ้ำกัน หรือไม่เช่นนั้น false หาก x ไม่ใช่ Tensor จะแสดงผล None

  • member_name(x: Value) -> Any กำหนดไว้สำหรับคำจำกัดความของสมาชิกทั้งหมด member_name ของค่าทั้งหมด เช่น real_part(x) จะแสดงผลส่วน RealPart ของ ComplexConstant ที่ตรงกัน หาก x ไม่ใช่ค่าที่มีสมาชิกที่เหมาะสม จะแสดงผล None

  • same(x: Value) -> Value จะได้รับการกำหนดใน tensors และแสดงผล true หากองค์ประกอบของ x ทั้งหมดเท่ากันหรือ false ในกรณีอื่นๆ หาก tensor ไม่มีองค์ประกอบ ระบบจะนับเป็น "ทั้งหมดเท่ากับซึ่งกันและกัน" กล่าวคือ ฟังก์ชันจะแสดงผล true หาก x ไม่ใช่ Tensor จะแสดงผล None

  • split(x: Value, num_results: Value, axis: Value) -> Value กำหนดไว้ด้วย Tensor และแสดงผลส่วน num_results ของ x ตามแกน axis หาก x ไม่ใช่ Tensor หรือ dim(x, axis) % num_results != 0 จะแสดงผล None

  • is_defined_in_parent_scope(x: Value) -> Value กำหนดไว้ในสตริงและแสดงผล true หาก x คือชื่อของฟังก์ชันที่กำหนดไว้ในขอบเขตเดียวกับฟังก์ชันระดับบนสุดของการดำเนินการที่เกี่ยวข้อง

  • is_namespaced_op_name(x: Value) -> Value กำหนดไว้ในสตริงและผลลัพธ์ true หาก x เป็นชื่อ op ที่ถูกต้อง กรณีนี้จะเป็นไปตามนิพจน์ทั่วไปต่อไปนี้: [a-zA-Z][a-zA-Z0-9_]*([.][a-zA-Z0-9_$]+)+

การคำนวณรูปร่าง

  • axes(x: Value | Placeholder | Type) -> Value เป็นทางลัดสำหรับ range(rank(x))

  • dim(x: Value | Placeholder | Type, axis: Value) -> Value เป็นทางลัดสำหรับ shape(x)[axis]

  • dims(x: Value | Placeholder | Type, axes: List) -> List เป็นทางลัดสำหรับ list(map(lambda axis: dim(x, axis), axes))

  • index_space(x: Value | Placeholder | Type) -> Value กำหนดไว้ใน Tensor และแสดงดัชนี size(x) สำหรับ TensorType ที่จัดเรียงตามลำดับแบบพจนานุกรมจากน้อยไปมาก เช่น [0, ..., 0], [0, ..., 1], ...,shape(x) - 1 หาก x ไม่ใช่ประเภท tensor, ประเภท Tensor เชิงปริมาณ หรือค่าหรือตัวยึดตำแหน่งของประเภทเหล่านี้ จะแสดงผล None

  • rank(x: Value | Placeholder | Type) -> Value เป็นทางลัดสำหรับ size(shape(x))

  • shape(x: Value | Placeholder | Type) -> Value กำหนดไว้ในส่วน "ฟังก์ชันในประเภท" ผ่าน member_name

  • size(x: Value | Placeholder | Type) -> Value เป็นทางลัดสำหรับ reduce(lambda x, y: x * y, shape(x))

การคํานวณหาปริมาณ

  • def baseline_element_type(x: Value | Placeholder | Type) -> Type เป็นทางลัดสำหรับ element_type(baseline_type(x))

  • baseline_type จะกำหนดตามประเภท tensor และประเภท tensor ที่วัดปริมาณแล้ว แล้วแปลงเป็น "baseline" กล่าวคือ เป็นประเภทที่มีรูปทรงเดียวกันแต่มีพารามิเตอร์การวัดปริมาณของประเภทองค์ประกอบจะรีเซ็ตเป็นค่าเริ่มต้น ข้อมูลนี้ใช้เป็นเคล็ดลับที่เป็นประโยชน์ในการเปรียบเทียบทั้ง tensor และประเภท tensor เชิงปริมาณอย่างเท่าเทียมกัน ซึ่งจำเป็นต้องมีอยู่บ่อยครั้ง สำหรับประเภทที่วัดปริมาณ การดำเนินการนี้จะเปิดใช้การเปรียบเทียบประเภทที่ละเว้นพารามิเตอร์เชิงปริมาณ กล่าวคือ shape, storage_type, expressed_type, storage_min, storage_max และ quantization_dimension (สำหรับประเภทที่ปรับขนาดตามแกน) ต้องตรงกันทั้งหมด แต่ scales กับ zero points อาจแตกต่างกัน

def baseline_type(x: Value | Placeholder | Type) -> Type:
  if type(x) == TensorType:
    return x
  if type(x) == QuantizedTensorType:
    element_type = quantized_tensor_element_type(x)
    baseline_element_type = QuantizedTensorElementType(
      storage_type = storage_type(element_type),
      storage_min = storage_min(element_type),
      storage_max = storage_max(element_type),
      expressed_type = expressed_type(element_type),
      quantization_dimension = quantization_dimension(element_type),
      scales = [constant(1.0, expressed_type(element_type))] * dim(x, quantization_dimension(element_type)),
      zero_points = [constant(0, storage_type(element_type))] * dim(x, quantization_dimension(element_type)))
    return QuantizedTensorType(shape(x), baseline_element_type)
  if type(x) is not Type:
    return baseline_element_type(type(x))
  • dequantize จะกำหนดในประเภท Tensor เชิงปริมาณและเปลี่ยนเป็นประเภท Tensor จุดลอยตัว กรณีนี้เกิดขึ้นผ่านการแปลงองค์ประกอบเชิงปริมาณซึ่งแสดงค่าจำนวนเต็มของประเภทพื้นที่เก็บข้อมูลเป็นค่าจุดลอยตัวที่สอดคล้องกันของประเภทที่แสดงโดยใช้จุด 0 และมาตราส่วนที่เชื่อมโยงกับประเภทองค์ประกอบที่วัดปริมาณ
def compute_zero_points(quantized_type, result_type):
  if is_per_tensor_quantized(quantized_type):
    return broadcast_in_dim(constant(zero_point(quantized_type), storage_type(quantized_type)), [], result_type)
  if is_per_axis_quantized(quantized_type):
    for i in index_space(result_type):
      d = quantization_dimension(quantized_type)
      zero_points[i] = zero_points(quantized_type)[i[d]]
    return zero_points

def compute_scales(quantized_type, result_type):
  if is_per_tensor_quantized(quantized_type):
    return broadcast_in_dim(constant(scale(quantized_type), expressed_type(quantized_type)), [],
            type(result_type))
  if is_per_axis_quantized(quantized_type):
    for i in index_space(result_type):
      d = quantization_dimension(quantized_type)
      scales[i] = scales(quantized_type)[i[d]]
    return scales

def dequantize(x: Value) -> Value:
  assert is_quantized(x)
  x_storage = bitcast_convert(x, storage_type(x))
  x_storage_sub = x_storage - compute_zero_points(type(x), type(x_storage))
  x_expressed_sub = convert(x_storage_sub, expressed_type(x))
  return x_expressed_sub * compute_scales(type(x), type(x_expressed_sub))
  • quantize กำหนดไว้ในประเภท Tensor จุดลอยตัว แล้วเปลี่ยนเป็นประเภท tensor ที่เป็นจำนวนเชิงปริมาณ กรณีนี้เกิดขึ้นผ่านการแปลงค่าทศนิยมของประเภทที่แสดงเป็นค่าจำนวนเต็มที่สอดคล้องของประเภทพื้นที่เก็บข้อมูลโดยใช้จุด 0 และมาตราส่วนที่เชื่อมโยงกับประเภทองค์ประกอบที่วัดปริมาณ
def quantize(x: Value, result_type: Type) -> Value:
  assert is_float(x) and is_quantized(result_type)
  zero_points = compute_zero_points(result_type, TensorType(shape(x), storage_type(result_type)))
  converted_zero_points = convert(zero_points, expressed_type(result_type))
  converted_min = convert(storage_min(result_type), expressed_type(result_type))
  converted_max = convert(storage_max(result_type), expressed_type(result_type))

  x_scaled = x / compute_scales(result_type, type(x))
  x_scaled_add_zp = x_scaled + converted_zero_points
  x_clamped = clamp(converted_min, x_scaled_add_zp, converted_max)
  x_rounded = round_nearest_even(x_clamped)
  return convert(x_rounded, result_type)
  • dequantize_op_quantize ใช้เพื่อระบุการคำนวณแบบ Element-wise บน Tensor เชิงปริมาณ ระบบจะจัดลำดับความสำคัญขององค์ประกอบ กล่าวคือ เปลี่ยนองค์ประกอบเชิงปริมาณเป็นประเภทที่แสดง จากนั้นดำเนินการและคำนวณปริมาณ กล่าวคือ เปลี่ยนผลลัพธ์กลับไปเป็นประเภทพื้นที่เก็บข้อมูล ปัจจุบันฟังก์ชันนี้ใช้งานได้กับ การวัดปริมาณตาม tensor เท่านั้น การคำนวณจำนวนตามแกนอยู่ระหว่างดำเนินการ (#1574)
def dequantize_op_quantize(op, *inputs_and_output_type):
  inputs = inputs_and_output_type[:-1]
  output_type = inputs_and_output_type[-1]

  float_inputs = map(dequantize, inputs)
  float_result = op(*float_inputs)
  return quantize(float_result, output_type)

def dequantize_batch_norm_grad_or_training_quantize(op, *inputs_and_output_types):
  inputs = inputs_and_output_type[:-3]
  float_inputs = map(dequantize, inputs)
  float_results = op(*float_inputs)
  return map(quantize, float_results, inputs_and_output_type[-3:])

def dequantize_compare(lhs, rhs, comparison_direction):
  float_lhs = dequantize(lhs)
  float_rhs = dequantize(rhs)
  return compare(float_lhs, float_rhs, comparison_direction, FLOAT)

def dequantize_select_quantize(pred, on_true, on_false, output_type):
  float_on_true = dequantize(on_true)
  float_on_false = dequantize(on_false)
  float_result = select(pred, float_on_true, float_on_false)
  return quantize(float_result, output_type)
  • hybrid_dequantize_then_op ใช้เพื่อระบุปริมาณเฉพาะน้ำหนักสำหรับการดำเนินการแบบผสมที่ยอมรับ Lh ในจุดลอยตัวและ rh ในประเภทที่เป็นจำนวนเชิงปริมาณ ซึ่งจะจัดลำดับอินพุตที่วัดปริมาณไว้ในประเภทที่แสดง และทำการคำนวณแบบ Float ประเภทองค์ประกอบของ Float lhs tensor และประเภท tensor แบบ Quantized rhs ที่แสดงต้องเหมือนกัน
def hybrid_dequantize_then_op(op, lhs, rhs):
  assert(is_float(lhs) and is_quantized(rhs) and element_type(lhs) == expressed_type(rhs))
  return op(lhs, dequantize(rhs))

การคำนวณตารางกริด

  • cross_partition(replica_groups: Value) -> Value ดูส่วน "cross_replica" ด้านบน

  • cross_replica(replica_groups: Value) -> Value ดูส่วน "cross_replica" ด้านบน

  • cross_replica_and_partition(replica_groups: Value) -> Value ดูส่วน "cross_replica_and_partition" ด้านบน

  • flattened_ids(replica_groups: Value) -> Value ดูส่วน "flattened_ids" ด้านบน

ไดนามิก

ค่า StableHLO มีขนาดมิติข้อมูลแบบไดนามิกได้ เช่น tensor<?xi64> อย่างไรก็ตาม ค่า StableHLO ต้องไม่มีจำนวนมิติข้อมูลแบบไดนามิก (ไดนามิกที่ไม่มีการจัดอันดับ เช่น tensor<*xi64>) ตัวดำเนินการและผลลัพธ์ได้รับอนุญาตให้ใช้ขนาดมิติข้อมูลแบบไดนามิก แม้ว่าจะมีข้อจำกัดเกี่ยวกับขนาดก็ตาม ข้อจำกัดจะได้รับการยืนยันแบบคงที่หากทำได้ มิเช่นนั้น จะเลื่อนไปยังรันไทม์และการทำงานที่ไม่ตรงกันจะส่งผลให้เกิดลักษณะการทำงานที่ไม่ระบุ โปรดดูตัวอย่างด้านล่าง

รูปทรงที่ไม่ตรงกันสำหรับการดำเนินการแบบองค์ประกอบไม่รอบด้าน

ลองพิจารณาโปรแกรมของเล่นต่อไปนี้

func.func @foo(%arg0: tensor<?xf64>) {
  %0 = stablehlo.abs %arg0 : (tensor<?xf64>) -> tensor<2xf64>
  return
}

โปรแกรมดังกล่าวผิดปกติ เนื่องจากไม่ใช่เรื่องธรรมดาที่จะทราบรูปร่างของผลลัพธ์ แต่ไม่ทราบรูปร่างของอินพุต อย่างไรก็ตาม นี่เป็นโปรแกรม StableHLO ที่ถูกต้อง เป็นไปไม่ได้ที่จะตรวจสอบการดำเนินการ abs แบบคงที่ในโปรแกรมนี้ เนื่องจากไม่ทราบรูปร่างที่แน่นอนของตัวถูกดำเนินการ อย่างไรก็ตาม รูปทรงนั้นเข้ากันได้เป็นอย่างดีและอาจตรวจสอบแบบคงที่ได้ ดังนั้น ? อาจกลายเป็น 2 ระหว่างรันไทม์และจะไม่เกิดปัญหาใดๆ แต่ ? อาจกลายเป็นจำนวนเต็มอื่นๆ ก็ได้ ซึ่งในกรณีนี้ไม่มีการกำหนดลักษณะการทำงาน

โปรดทราบว่าหากขนาดมิติข้อมูลเป็นแบบไดนามิกในผลลัพธ์ จะไม่มีลักษณะการทำงานที่ไม่ได้กำหนด แน่นอนว่าไม่มีขนาดที่ "คาดการณ์" ผลที่ได้จะไม่ตรงกัน

รูปร่างที่ไม่ตรงกันสำหรับการดำเนินการ Elementwise แบบไบนารี

ลองพิจารณาโปรแกรมของเล่นต่อไปนี้

func.func @foo(%arg0: tensor<?xf64>, %arg1: tensor<?xf64>) {
  %0 = stablehlo.add %arg0, %arg0 : (tensor<?xf64>, tensor<?xf64>) -> tensor<?xf64>
  return
}

เมื่อกล่าวถึงการดำเนินการแบบ Elementwise แบบไบนารี รูปร่างของอินพุตและผลลัพธ์ต้องสอดคล้องกันขณะรันไทม์ ในเวลาคอมไพล์ มิติข้อมูลคงที่ต้องเท่ากัน มิฉะนั้นก็ต้องใช้งานร่วมกันได้ หากมิติข้อมูลใดก็ตามเป็นแบบไดนามิกในอินพุต อาจมีลักษณะการทำงานที่ไม่ได้กำหนดในระหว่างรันไทม์ เนื่องจากขนาดแบบไดนามิกอาจไม่ตรงกับขนาดที่สอดคล้องกันในตัวถูกดำเนินการอื่น (ไม่ว่าจะเป็นแบบคงที่หรือแบบไดนามิก) หากอินพุตทั้งหมดเป็นแบบคงที่ ผลลัพธ์จะเป็นแบบไดนามิกหรือไม่มีความสำคัญ: มิติข้อมูลที่รู้จักแบบคงที่จะได้รับการตรวจสอบแบบคงที่ และมิติข้อมูลแบบไดนามิกไม่มีข้อจำกัดใดๆ

รูปร่างที่ไม่ตรงกันสำหรับการดำเนินการที่ใช้รูปร่างเอาต์พุตเป็นโอเปอแรนด์

ลองพิจารณาโปรแกรมของเล่นต่อไปนี้

func.func @foo(%arg0: tensor<2xi32>) {
  %0 = stablehlo.dynamic_iota %arg0, dim = 0 : (tensor<2xi32>) -> tensor<3x4xi64>
  return
}

ค่าในตัวถูกดำเนินการรูปร่างขณะรันไทม์ต้องตรงกับรูปร่างของผลลัพธ์ ไม่เช่นนั้นจะไม่มีการกำหนดลักษณะการทำงานไว้ นั่นคือ ขณะรันไทม์ %arg0 ต้องมีค่า dense<[3, 4]> : tensor<2xi32> หากตัวถูกดำเนินการของรูปร่างมีค่าคงที่ ก็จะได้รับการยืนยันแบบคงที่ได้ หากรูปร่างผลลัพธ์เป็นแบบไดนามิกทั้งหมด จะไม่สามารถไม่ตรงกันได้