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

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

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

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

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

โปรแกรม

Program ::= {Func}

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

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

ฟังก์ชัน

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

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

รหัสระบุ

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

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

ประเภท

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

StringType ::= 'string'

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

ค่าคงที่

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

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

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

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

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

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

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

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

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

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

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

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

  • (C1) has_syntax(tensor_literal, element_type(tensor_type)) ซึ่งมีดังนี้
    • has_syntax(element_literal: Syntax, element_type: Type) = is_wellformed(element_literal, type)
    • has_syntax(tensor_literal: List, element_type: Type) = has_syntax(tensor_literal..., element_type)
  • (C2) has_shape(tensor_literal, shape(tensor_type)) ซึ่งมีดังนี้
    • has_shape(element_literal: Syntax, []) = true
    • has_shape(tensor_literal: List, shape: List) = size(tensor_literal) = shape[0] and has_shape(tensor_literal..., shape[1:])
    • หรือไม่เช่นนั้น false
QuantizedTensorConstant ::= QuantizedTensorLiteral ':' QuantizedTensorType
QuantizedTensorLiteral  ::= 'dense' '<' (DenseLiteral | ElementLiteral) '>'

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

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

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

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

ท้อง

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

เพิ่ม

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

  • หากการดำเนินการใช้ Tensor ที่ไม่ใช่เชิงปริมาณ
    • (C1) type(lhs) = type(rhs) = type(result)
  • หากการดำเนินการใช้ 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 จำนวน operands จากแต่ละกระบวนการตาม all_gather_dim และสร้าง Tensor จำนวน results รายการ

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

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

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

  • operands...@receiver = [operand@sender for sender in process_group] สำหรับทุกคน receiverในprocess_group
  • results...@process = concatenate(operands...@process, all_gather_dim) สำหรับทุกคน processในprocess_group

อินพุต

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

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
results จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว (C6)

ข้อจำกัด

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

ตัวอย่าง

// num_replicas: 2
// num_partitions: 1
// %operand0@(0, 0): [[1, 2], [3, 4]]
// %operand0@(1, 0): [[5, 6], [7, 8]]
// %operand1@(0, 0): [[11, 12], [13, 14]]
// %operand1@(1, 0): [[15, 16], [17, 18]]
%result:2 = "stablehlo.all_gather"(%operand0, %operand1) {
  all_gather_dim = 1 : i64,
  replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>,
  // channel_id = 0
  channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
  // use_global_device_ids = false
} : (tensor<2x2xi64>, tensor<2x2xi64>) -> (tensor<2x4xi64>, tensor<2x4xi64>)
// %result0@(0, 0): [[1, 2, 5, 6], [3, 4, 7, 8]]
// %result0@(1, 0): [[1, 2, 5, 6], [3, 4, 7, 8]]
// %result1@(0, 0): [[11, 12, 15, 16], [13, 14, 17, 18]]
// %result1@(1, 0): [[11, 12, 15, 16], [13, 14, 17, 18]]

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

all_reduce

อรรถศาสตร์

ภายในกลุ่มกระบวนการแต่ละกลุ่มในตารางกระบวนการ StableHLO ให้ใช้การลด ฟังก์ชัน computation เป็นค่าของ tensor ของ operands จากแต่ละกระบวนการ และสร้าง results Tensor

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

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

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

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

อินพุต

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

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
results จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว (C6-C7)

ข้อจำกัด

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

ตัวอย่าง

// num_replicas: 2
// num_partitions: 1
// %operand0@(0, 0): [1, 2, 3, 4]
// %operand0@(1, 0): [5, 6, 7, 8]
// %operand1@(0, 0): [9, 10, 11, 12]
// %operand1@(1, 0): [13, 14, 15, 16]
%result:2 = "stablehlo.all_reduce"(%operand0, %operand0) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %0 = "stablehlo.add"(%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
    "stablehlo.return"(%0) : (tensor<i64>) -> ()
}) {
  replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>,
  // channel_id = 0
  channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
  // use_global_device_ids = false
} : (tensor<4xi64>, tensor<4xi64>) -> (tensor<4xi64>, tensor<4xi64>)
// %result0@(0, 0): [6, 8, 10, 12]
// %result0@(1, 0): [6, 8, 10, 12]
// %result1@(0, 0): [22, 24, 26, 28]
// %result1@(1, 0): [22, 24, 26, 28]

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

all_to_all

อรรถศาสตร์

all_to_all

ภายในกลุ่มกระบวนการแต่ละกลุ่มในตารางการประมวลผล StableHLO ให้แยกค่าของ Tensor สี operands ตาม split_dimension แบ่งออกเป็นส่วนต่างๆ กระจายตัว เพื่อนำกระบวนการบางส่วนมาต่อกัน ส่วนที่กระจัดกระจายอยู่ตาม concat_dimension และสร้าง results Tensor การดำเนินการนี้จะแยกตารางกริดประมวลผล StableHLO ออกเป็น process_groups ซึ่ง โดยมีคำจำกัดความดังนี้

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

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

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

อินพุต

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

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
results จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว (C9)

ข้อจำกัด

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

ตัวอย่าง

// num_replicas: 2
// num_partitions: 1
// %operand1@(0, 0): [[1, 2, 3, 4],
//                    [5, 6, 7, 8]]
// %operand1@(1, 0): [[9, 10, 11, 12],
//                    [13, 14, 15, 16]]
// %operand2@(0, 0): [[17, 18, 19, 20],
//                    [21, 22, 23, 24]]
// %operand2@(1, 0): [[25, 26, 27, 28],
//                    [29, 30, 31, 32]]
%result:2 = "stablehlo.all_to_all"(%operand1, %operand2) {
  split_dimension = 1 : i64,
  concat_dimension = 0 : i64,
  split_count = 2 : i64,
  replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>
  // channel_id = 0
} : (tensor<2x4xi64>, tensor<2x4xi64>) -> (tensor<4x2xi64>, tensor<4x2xi64>)
// %result#0@(0, 0): [[1, 2], [5, 6], [9, 10], [13, 14]]
// %result#0@(1, 0): [[3, 4], [7, 8], [11, 12], [15, 16]]
// %result#1@(0, 0): [[17, 18], [21, 22], [25, 26], [29, 30]]
// %result#1@(1, 0): [[19, 20], [23, 24], [27, 28], [31, 32]]

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

และ

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

atan2

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

batch_norm_grad

อรรถศาสตร์

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

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

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

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

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

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

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

  return grad_operand, grad_scale, grad_offset

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

batch_norm_inference

อรรถศาสตร์

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

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

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

สำหรับประเภทที่เล็กลง จะดำเนินการ dequantize_op_quantize(lambda operand, scale, offset, mean, variance: batch_norm_inference(operand, scale, offset, mean, variance, epsilon, feature_index), operand, scale, offset, mean, variance, type(result))

อินพุต

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

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
result tensor ของประเภทจุดลอยตัวหรือ tensor ที่แปลงค่าเป็น 1 เซนเซอร์ (C2), (C7)

ข้อจำกัด

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

ตัวอย่าง

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

batch_norm_training

อรรถศาสตร์

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

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

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

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

สำหรับประเภทที่เล็กลง จะดำเนินการ dequantize_batch_norm_grad_or_training_quantize(lambda operand, scale, offset: batch_norm_training(operand, scale, offset, epsilon, feature_index), operand, scale, offset, type(output), type(batch_mean), type(batch_var))

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

bitcast_convert

อรรถศาสตร์

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

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

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

broadcast_in_dim

อรรถศาสตร์

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

  • operand_index[d] = 0 หากเป็น dim(operand, d) = 1
  • จ่าย operand_index[d] = result_index[broadcast_dimensions[d]]

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

เคส

อรรถศาสตร์

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

  • selected_branch = branches[index] หากเป็น 0 <= index < size(branches)
  • จ่าย selected_branch = branches[-1]

อินพุต

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

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
results จำนวนแปรผันของ Tensor, Tensor ที่เล็กลง หรือโทเค็น (C4)

ข้อจำกัด

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

ตัวอย่าง

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

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

CBT

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

Ceil

อรรถศาสตร์

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

Cholesky

อรรถศาสตร์

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

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

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

สำหรับประเภทที่เล็กลง จะดำเนินการ dequantize_op_quantize(lambda operand: cholesky(operand, lower), a, type(result))

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

แบบหนีบ

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

collective_broadcast

อรรถศาสตร์

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

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

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

หลังจากนั้น result@process จะได้รับรายการโดย:

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

  • (C1) is_unique(replica_groups)
  • (C2) 0 <= replica_groups < N โดยที่ N มีความหมายดังนี้
    • num_replicas หากใช้ cross_replica
    • num_partitions หากใช้ cross_partition
  • (C3) type(result) = type(operand)

ตัวอย่าง

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

collective_permute

อรรถศาสตร์

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

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

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

หลังจากนั้น result@process จะได้รับรายการโดย:

  • operand@process_groups[i, 0] หากมี i ที่เป็นเช่นนั้น process_groups[i, 1] = process
  • broadcast_in_dim(constant(is_quantized(result) ? quantize(0, element_type(result)) : 0, element_type(result)), [], type(result)) หรือไม่เช่นนั้น

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

  • (C1) dim(source_target_pairs, 1) = 2
  • (C2) is_unique(source_target_pairs[:, 0])
  • (C3) is_unique(source_target_pairs[:, 1])
  • (C4) 0 <= source_target_pairs < N โดยที่ N มีความหมายดังนี้
    • num_replicas หากใช้ cross_replica
    • num_partitions หากใช้ cross_partition
  • (C5) type(result) = type(operand)

ตัวอย่าง

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

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

เปรียบเทียบ

อรรถศาสตร์

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

ค่าของ comparison_direction และ compare_type มีค่าต่อไปนี้ อรรถศาสตร์:

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

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

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

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

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

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

สำหรับประเภทที่เล็กลง ทำการ dequantize_compare(lhs, rhs, comparison_direction)

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

ซับซ้อน

อรรถศาสตร์

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

การผสม

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

เชื่อมต่อ

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

  • (C1) same(element_type(inputs...))
  • (C2) same(shape(inputs...)) ยกเว้น dim(inputs..., dimension)
  • (C3) 0 < size(inputs)
  • (C4) 0 <= dimension < rank(inputs[0])
  • (C5) element_type(result) = element_type(inputs[0])
  • (C6) shape(result) = shape(inputs[0]) ยกเว้น
    • dim(result, dimension) = dim(inputs[0], dimension) + ...

ตัวอย่าง

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

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

ค่าคงที่

อรรถศาสตร์

สร้าง tensor ของ output จาก value คงที่

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

ทำให้เกิด Conversion

อรรถศาสตร์

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

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

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

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

Conversion ที่เกี่ยวข้องกับซับซ้อนไปซับซ้อนมีลักษณะการทำงานเหมือนกับของ floating-point-to-floating-point สำหรับการแปลงค่าจริงและ ส่วนจินตภาพ

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

คอนโวลูชัน

อรรถศาสตร์

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

คอนโวลูชัน

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

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

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

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

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

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

หาก feature_group_count > 1:

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

หาก batch_group_count > 1:

  • lhses = split(lhs, batch_group_count, input_batch_dimension)
  • rhses = split(rhs, batch_group_count, kernel_output_feature_dimension)
  • results... = convolution(lhses..., rhses..., ..., batch_group_count=1, ...)
  • result = concatenate(results, output_feature_dimension) วันที่

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

count_leading_zeros

อรรถศาสตร์

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

custom_call

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ตัวอย่าง

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

หาร

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

dot_general

อรรถศาสตร์

ประมวลผลผลิตภัณฑ์แบบจุดระหว่างส่วนต่างๆ ของ lhs และส่วนย่อยของ rhs และสร้าง tensor ของ result

อย่างเป็นทางการเพิ่มเติมคือ result[result_index] = dot_product ซึ่ง

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

สำหรับประเภทที่เล็กลง จะดำเนินการ dequantize_op_quantize( lambda lhs, rhs: dot_general(lhs, rhs, lhs_batching_dimensions, rhs_batching_dimensions, lhs_contracting_dimensions, rhs_contracting_dimensions, precision_config), lhs, rhs, type(result))

สำหรับประเภทที่เล็กลงของจำนวนแบบผสม จะดำเนินการ hybrid_dequantize_then_op( lambda lhs, rhs: dot_general(lhs, rhs, lhs_batching_dimensions, rhs_batching_dimensions, lhs_contracting_dimensions, rhs_contracting_dimensions, precision_config), lhs, rhs)

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

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

DotAlgorithm ระบุพร็อพเพอร์ตี้หลักของอัลกอริทึมที่จะนำมาใช้ จะใช้จุด ซึ่งจะกำหนดความแม่นยำด้วย หากแอตทริบิวต์อัลกอริทึม ได้รับการตั้งค่าแล้ว precision_config ต้องเป็น DEFAULT DotAlgorithms ไม่มีค่าเริ่มต้นเนื่องจากพารามิเตอร์เริ่มต้นคือการติดตั้งใช้งาน กำหนดไว้ จึงอาจตั้งค่าฟิลด์อัลกอริทึมจุดทั้งหมดเป็น None เพื่อระบุ อัลกอริทึมจุดว่าง ซึ่งจะใช้ค่า precision_config แทน

DotAlgorithm ช่องประกอบด้วย

  • lhs_precision_type และ rhs_precision_type ความแม่นยำที่ LHS และ RHS ของการดำเนินการจะปัดเป็น ประเภทความแม่นยํานั้นไม่เกี่ยวข้องกับ ประเภทพื้นที่เก็บข้อมูลของอินพุตและเอาต์พุต
  • accumulation_type ความแม่นยำที่ใช้ในการสะสม
  • lhs_component_count rhs_component_count และnum_primitive_operations มีผลเมื่อเราสร้างอัลกอริทึมซึ่งจะสลาย LHS และ/หรือ RHS เป็น หลายคอมโพเนนต์ และดำเนินการ "พื้นฐาน" หลายอย่าง การดำเนินการกับจุดเหล่านั้น - มักเพื่อจำลองความแม่นยำที่สูงขึ้น (เช่น การใช้ประโยชน์จากประเภทข้อมูลปัญญาประดิษฐ์ (AI) bFloat 16 เพื่อการคำนวณที่แม่นยำยิ่งขึ้น: bf16_6x tf32_3x ฯลฯ) สำหรับอัลกอริทึมที่ไม่มีการแยกส่วน ค่าเหล่านี้ ควรตั้งค่าเป็น 1
  • allow_imprecise_accumulation เพื่อระบุว่ามีการสะสมที่ความแม่นยำต่ำกว่าหรือไม่ ซึ่งทำได้ในบางขั้นตอน (เช่น CUBLASLT_MATMUL_DESC_FAST_ACCUM)

ตัวอย่างแอตทริบิวต์ DotAlgorithm

// Inputs are casted to tf32, and then accumulated in f32:
{lhs_precision_type = tf32,
 rhs_precision_type = tf32,
 accumulation_type = f32,
 lhs_component_count = 1,
 rhs_component_count = 1,
 num_primitive_operations = 1,
 allow_imprecise_accumulation = false}


// bf16_6x: each input is decomposed to 3 bf16 components, then 6 dot operations are done on those components, and the result is accumulated in f32.
{lhs_precision_type = bf16,
 rhs_precision_type = bf16,
 accumulation_type = f32,
 lhs_component_count = 3,
 rhs_component_count = 3,
 num_primitive_operations = 6,
 allow_imprecise_accumulation = false}


// Inputs are (casted to) f8e5m2, and we accumulate in f32, but for some steps we may accumulate in lower precision.
{lhs_precision_type = f8e5m2,
 rhs_precision_type = f8e5m2,
 accumulation_type = f32,
 lhs_component_count = 1,
 rhs_component_count = 1,
 num_primitive_operations = 1,
 allow_imprecise_accumulation = true}

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

โปรดดู xla_data.proto > Algorithm สำหรับค่าอัลกอริทึมที่รองรับบางค่า ตั๋ว #2483 แสดงแผนในการสร้าง เอกสารแบบรวมศูนย์บนอัลกอริทึมที่รองรับโดยแบ็กเอนด์

อินพุต

ป้ายกำกับ ชื่อ ประเภท ข้อจำกัด
(I1) lhs tensor หรือต่อ tensor ในการปรับปริมาณ (C5-C6), (C9-C10), (C12-C14), (C17-C18), (C20)
(I2) rhs tensor หรือ tensor แบบเชิงปริมาณ (C7-C10), (C12-C20)
(I3) lhs_batching_dimensions ค่าคงที่ tensor ใน 1 มิติของประเภท si64 (C1), (C3), (C5), (C9), (C12)
(I4) rhs_batching_dimensions ค่าคงที่ tensor ใน 1 มิติของประเภท si64 (C1), (C4), (C7), (C9)
(I5) lhs_contracting_dimensions ค่าคงที่ tensor ใน 1 มิติของประเภท si64 (C2), (C3), (C6), (C10)
(I6) rhs_contracting_dimensions ค่าคงที่ tensor ใน 1 มิติของประเภท si64 (C2), (C4), (C8), (C10), (C16)
(I7) precision_config จำนวน Enum แปรผันของ DEFAULT, HIGH และ HIGHEST (C11), (C21)
(I8) lhs_precision_type FloatType หรือ TensorFloat32 (C21)
(I9) rhs_precision_type FloatType หรือ TensorFloat32 (C21)
(I10) accumulation_type FloatType หรือ TensorFloat32 (C21)
(I11) lhs_component_count ค่าคงที่ของประเภท si32 (C21), (C22)
(I12) rhs_component_count ค่าคงที่ของประเภท si32 (C21), (C23)
(I13) num_primitive_operations ค่าคงที่ของประเภท si32 (C21), (C24)
(I14) allow_imprecise_accumulation ค่าคงที่ของประเภท bool (C21)

เอาต์พุต

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

ข้อจำกัด

  • (C1) size(lhs_batching_dimensions) = size(rhs_batching_dimensions)
  • (C2) size(lhs_contracting_dimensions) = size(rhs_contracting_dimensions)
  • (C3) is_unique(lhs_batching_dimensions + lhs_contracting_dimensions)
  • (C4) is_unique(rhs_batching_dimensions + rhs_contracting_dimensions)
  • (C5) 0 <= lhs_batching_dimensions < rank(lhs)
  • (C6) 0 <= lhs_contracting_dimensions < rank(lhs)
  • (C7) 0 <= rhs_batching_dimensions < rank(rhs)
  • (C8) 0 <= rhs_contracting_dimensions < rank(rhs)
  • (C9) dim(lhs, lhs_batching_dimensions...) = dim(rhs, rhs_batching_dimensions...)
  • (C10) dim(lhs, lhs_contracting_dimensions...) = dim(rhs, rhs_contracting_dimensions...)
  • (C11) size(precision_config) = 2
  • (C12) shape(result) = dim(lhs, lhs_batching_dimensions) + dim(lhs, lhs_result_dimensions) + dim(rhs, rhs_result_dimensions)
  • หากการดำเนินการใช้ Tensor ที่ไม่ใช่เชิงปริมาณ
    • (C13) element_type(lhs) = element_type(rhs)
  • หากการดำเนินการใช้ 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)
  • หาก !is_empty_algorithm(lhs_precision_type, rhs_precision_type, accumulation_type, lhs_component_count, rhs_component_count, num_primitive_operations allow_imprecise_accumulation):
    • (C21) precision_config... = DEFAULT
    • (C22) 0 < lhs_component_count
    • (C23) 0 < rhs_component_count
    • (C24) 0 < num_primitive_operations

ตัวอย่าง

// %lhs: [
//        [[1, 2],
//         [3, 4]],
//        [[5, 6],
//         [7, 8]]
//       ]
// %rhs: [
//        [[1, 0],
//         [0, 1]],
//        [[1, 0],
//         [0, 1]]
//       ]
%result = "stablehlo.dot_general"(%lhs, %rhs) {
  dot_dimension_numbers = #stablehlo.dot<
    lhs_batching_dimensions = [0],
    rhs_batching_dimensions = [0],
    lhs_contracting_dimensions = [2],
    rhs_contracting_dimensions = [1]
  >,
  precision_config = [#stablehlo<precision DEFAULT>, #stablehlo<precision DEFAULT>],
  algorithm = #stablehlo.dot_algorithm<
    lhs_precision_type = tf32,
    rhs_precision_type = tf32,
    accumulation_type = f32,
    lhs_component_count = 1,
    rhs_component_count = 1,
    num_primitive_operations = 1,
    allow_imprecise_accumulation = false
  >
} : (tensor<2x2x2xi64>, tensor<2x2x2xi64>) -> tensor<2x2x2xi64>
// %result: [
//           [[1, 2],
//            [3, 4]],
//           [[5, 6],
//            [7, 8]]
//          ]

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

dynamic_broadcast_in_dim

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

dynamic_conv

อรรถศาสตร์

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

อรรถศาสตร์

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

dynamic_iota

อรรถศาสตร์

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

dynamic_pad

อรรถศาสตร์

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

dynamic_reshape

อรรถศาสตร์

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

dynamic_slice

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

dynamic_update_slice

อรรถศาสตร์

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

  • update[update_index] หาก 0 <= update_index < shape(update) ที่:
    • adjusted_start_indices = clamp(0, start_indices, shape(operand) - shape(update))
    • update_index = result_index - adjusted_start_indices
  • จ่าย operand[result_index]

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

เลขชี้กำลัง

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

exponential_minus_one

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

fft

อรรถศาสตร์

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

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

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

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

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

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

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

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

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

นอกจากนี้ จะได้รับฟังก์ชัน rfft ซึ่งสร้าง Tensor 1 มิติของ ประเภทจุดลอยตัว จะสร้าง Tensor 1 มิติของประเภทเชิงซ้อน ความหมายและผลของจุดลอยตัวเดียวกัน:

  • rfft(real_operand) = truncated_result ที่
  • complex_operand... = (real_operand..., 0.0)
  • complex_result = fft(complex_operand)
  • truncated_result = complex_result[:(rank(complex_result) / 2 + 1)]

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

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

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

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

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

  • (C1) size(fft_length) <= rank(operand)
  • (C2) ความสัมพันธ์ระหว่างองค์ประกอบประเภท operand และ result จะแตกต่างกันไป
    • หากเป็น fft_type = FFT, element_type(operand) และ element_type(result) มีรูปแบบที่ซับซ้อนเหมือนกัน
    • หากเป็น fft_type = IFFT, element_type(operand) และ element_type(result) มีรูปแบบที่ซับซ้อนเหมือนกัน
    • หากเป็น fft_type = RFFT element_type(operand) เป็นประเภทจุดลอยตัวและ element_type(result) เป็นประเภทเชิงซ้อนของจุดลอยตัวเดียวกัน อรรถศาสตร์
    • หากเป็น fft_type = IRFFT element_type(operand) เป็นประเภทที่ซับซ้อนและ element_type(result) เป็นประเภทจุดลอยตัวของจุดลอยตัวเดียวกัน อรรถศาสตร์
  • (C3) 1 <= size(fft_length) <= 3
  • (C4) หากใน operand และ result มี 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 ที่แปลงค่าเป็น 1 เซนเซอร์ (C1)

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

รวบรวม

อรรถศาสตร์

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

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

รวบรวม

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

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

get_dimension_size

อรรถศาสตร์

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

get_tuple_element

อรรถศาสตร์

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

ถ้า

อรรถศาสตร์

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

อินพุต

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

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
results จำนวนแปรผันของ Tensor, Tensor ที่เล็กลง หรือโทเค็น (C3)

ข้อจำกัด

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

ตัวอย่าง

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

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

Imag

อรรถศาสตร์

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

ในฟีด

อรรถศาสตร์

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

กำหนดความหมายของ infeed_config ในการใช้งานแล้ว

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

อินพุต

ป้ายกำกับ ชื่อ ประเภท
(I1) token token
(I2) infeed_config ค่าคงที่ของประเภท string

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
results จำนวนแปรผันของ Tensor, Tensor ที่เล็กลง หรือโทเค็น (C1-C3)

ข้อจำกัด

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

ตัวอย่าง

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

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

Iota

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

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

is_finite

อรรถศาสตร์

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

บันทึก

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

log_plus_one

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

โลจิสติกส์

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

แผนที่

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

สูงสุด

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

ขั้นต่ำ

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

คูณ

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

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

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

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

ไม่ใช่

อรรถศาสตร์

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

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

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

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

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

optimization_barrier

อรรถศาสตร์

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

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

ชื่อ ประเภท ข้อจำกัด
operand จำนวนตัวแปรของ Tensor ต่อ Tensor ที่แปลงค่าเป็นจำนวนหรือโทเค็น (C1)

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

หรือ

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

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

ฟีดนอกฟีด

อรรถศาสตร์

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

กำหนดความหมายของ outfeed_config ในการใช้งานแล้ว

อินพุต

ป้ายกำกับ ชื่อ ประเภท
(I1) inputs จำนวนแปรผันของ Tensor หรือ Tensor ที่เล็กลง
(I2) token token
(I3) outfeed_config ค่าคงที่ของประเภท string

เอาต์พุต

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

ตัวอย่าง

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

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

แพด

อรรถศาสตร์

ขยาย operand ด้วยระยะห่างจากขอบรอบๆ Tensor และระหว่างองค์ประกอบ ของ Tensor ที่มี padding_value ที่ระบุ

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

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

result[result_index] อย่างเป็นทางการหมายถึง

  • operand[operand_index] หาก result_index = edge_padding_low + operand_index * (interior_padding + 1)
  • จ่าย padding_value

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

partition_id

อรรถศาสตร์

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

เอาต์พุต

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

ตัวอย่าง

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

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

ป๊อปคอต

อรรถศาสตร์

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

พาวเวอร์

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

เรียล

อรรถศาสตร์

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

Revv

อรรถศาสตร์

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

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

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

อินพุต

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

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
results จำนวนแปรผันของ Tensor, Tensor ที่เล็กลง หรือโทเค็น (C2-C4)

ข้อจำกัด

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

ตัวอย่าง

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

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

ลด

อรรถศาสตร์

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

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

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

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

อินพุต

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

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
results จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว (C3), (C7), (C8)

ข้อจำกัด

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

ตัวอย่าง

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

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

reduce_precision

อรรถศาสตร์

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

อย่างเป็นทางการเพิ่มเติม

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

reduce_scatter

อรรถศาสตร์

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 จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว (C1-C4), (C6), (C8), (C10), (C12), (C13), (C15)
(I2) init_values จำนวนแปรปรวนของ Tensor ที่มี 0 มิติ หรือ Tensor ต่อ 4 ตัว (C1), (C13)
(I3) window_dimensions ค่าคงที่ tensor ใน 1 มิติของประเภท si64 (C4), (C5), (C15)
(I4) window_strides ค่าคงที่ tensor ใน 1 มิติของประเภท si64 (C6), (C7), (C15)
(I5) base_dilations ค่าคงที่ tensor ใน 1 มิติของประเภท si64 (C8), (C9), (C15)
(I6) window_dilations ค่าคงที่ tensor ใน 1 มิติของประเภท si64 (C10), (C11), (C15)
(I7) padding ค่าคงที่ tensor แบบ 2 มิติของประเภท si64 (C12), (C15)
(I8) body ฟังก์ชัน (C13)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
results จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว (C1), (C14-C16)

ข้อจำกัด

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

ตัวอย่าง

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

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

เศษ

อรรถศาสตร์

แสดงเศษที่เหลือของตัวหาร lhs และตัวหาร rhs สำหรับ Tensor และ สร้าง Tensor ของ result

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

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

replica_id

อรรถศาสตร์

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

เอาต์พุต

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

ตัวอย่าง

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

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

ปรับรูปร่าง

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

กลับกัน

อรรถศาสตร์

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

  • operand_index[d] = dim(result, d) - result_index[d] - 1 หาก d ใน dimensions
  • จ่าย operand_index[d] = result_index[d]

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

Rng

อรรถศาสตร์

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

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

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

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

rng_bit_generator

อรรถศาสตร์

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

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

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

round_nearest_afz

อรรถศาสตร์

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

round_nearest_even

อรรถศาสตร์

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

rsqrt

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

แผนภูมิกระจาย

อรรถศาสตร์

สร้าง Tensor จำนวน results ซึ่งเท่ากับ Tensor จำนวน inputs ยกเว้นค่าดังกล่าว ส่วนต่างๆ ที่ scatter_indices ระบุจะได้รับการอัปเดตด้วยค่า updates กำลังใช้ update_computation

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

แผนภูมิกระจาย

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

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

ด้วยเหตุนี้ results = exec(schedule, inputs) ซึ่ง:

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

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

หาก unique_indices คือ true การใช้งานจะถือว่ามี ดัชนี result_index รายการที่กระจายอยู่เป็นดัชนีที่ไม่ซ้ำกัน หาก unique_indices คือ true แต่ดัชนีที่กระจัดกระจายอยู่นั้นซ้ำกัน ลักษณะการทำงานคือ ไม่ได้กำหนด

อินพุต

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

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
results จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว (C24-C25)

ข้อจำกัด

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

ตัวอย่าง

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

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

เลือก

อรรถศาสตร์

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

select_and_scatter

อรรถศาสตร์

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

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

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 ต่อ 1 เมตริก (C3)
(I4) window_dimensions ค่าคงที่ tensor ใน 1 มิติของประเภท si64 (C2), (C4), (C5)
(I5) window_strides ค่าคงที่ tensor ใน 1 มิติของประเภท si64 (C2), (C6), (C7)
(I6) padding ค่าคงที่ tensor แบบ 2 มิติของประเภท si64 (C2), (C8)
(I7) select ฟังก์ชัน (C9)
(I8) scatter ฟังก์ชัน (C10)

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

ส่ง

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

  • (C1) channel_type มีความหมายดังต่อไปนี้
    • DEVICE_TO_HOST หาก is_host_transfer = true
    • จ่าย DEVICE_TO_DEVICE

ตัวอย่าง

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

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

shift_left

อรรถศาสตร์

ดำเนินการ Shift ซ้ายขององค์ประกอบบน lhs tensor ตามตัวเลข rhs และสร้าง Tensor ขึ้น result

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

shift_right_arithmetic

อรรถศาสตร์

ทำการดำเนินการเลื่อนไปทางขวาแบบเลขคณิตเชิงองค์ประกอบบน Tensor ของ lhs โดยใช้ rhs จำนวนบิตและสร้าง Tensor ขนาด result

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

shift_right_logical

อรรถศาสตร์

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

เครื่องหมาย

อรรถศาสตร์

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

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

สำหรับประเภทที่เล็กลง จะดำเนินการ dequantize_op_quantize(sign, operand, type(result))

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

ไซน์

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

ส่วนแบ่ง

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

จัดเรียง

อรรถศาสตร์

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

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

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

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

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

อินพุต

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

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
results จำนวนแปรผันของ Tensor หรือ Tensor ต่อ 1 ตัว (C2), (C3)

ข้อจำกัด

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

ตัวอย่าง

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

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

SQL

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

// %operand: [[0.0, 1.0], [4.0, 9.0]]
%result = "stablehlo.sqrt"(%operand) : (tensor<2x2xf32>) -> tensor<2x2xf32>
// %result: [[0.0, 1.0], [2.0, 3.0]]

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

ลบ

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

tan

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

// %operand: [
//            [0.0, 1.57079632],       // [0, pi/2]
//            [3.14159265, 4.71238898] // [pi, 3pi/2]
//           ]
%result = "stablehlo.tan"(%operand) : (tensor<2x2xf64>) -> tensor<2x2xf64>
// %result: [
//           [0.0, 1.63312e+16],
//           [0.0, 5.44375e+15]
//          ]

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

แทนห์

อรรถศาสตร์

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

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

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

// %operand: [-1.0, 0.0, 1.0]
%result = "stablehlo.tanh"(%operand) : (tensor<3xf32>) -> tensor<3xf32>
// %result: [-0.76159416, 0.0, 0.76159416]

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

สลับตำแหน่ง

อรรถศาสตร์

เรียงสับเปลี่ยนมิติข้อมูลของ tensor ของ operand โดยใช้ permutation และสร้างพารามิเตอร์ result Tensor อย่างเป็นทางการเพิ่มเติม result[result_index] = operand[operand_index] โดยมี result_index[d] = operand_index[permutation[d]]

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

  • (C1) element_type(result) ได้มาจาก
    • element_type(operand) หากเป็น !is_per_axis_quantized(operand)
    • element_type(operand) ยกเว้นquantization_dimension(operand) และ quantization_dimension(result) อาจแตกต่างออกไปหากไม่เป็นเช่นนั้น
  • (C2) permutation เป็นการเปลี่ยนลำดับ range(rank(operand))
  • (C3) shape(result) = dim(operand, permutation...)
  • (C4) หาก is_per_axis_quantized(result) แล้ว quantization_dimension(operand) = permutation(quantization_dimension(result))

ตัวอย่าง

// %operand: [
//            [[1,2], [3,4], [5,6]],
//            [[7,8], [9,10], [11,12]]
//           ]
%result = "stablehlo.transpose"(%operand) {
  permutation = array<i64: 2, 1, 0>
} : (tensor<2x3x2xi32>) -> tensor<2x3x2xi32>
// %result: [
//           [[1,7], [3,9], [5,11]],
//           [[2,8], [4,10], [6,12]]
//          ]

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

triangular_solve

อรรถศาสตร์

แก้ระบบสมการเชิงเส้นกลุ่มต่างๆ ที่มีสามเหลี่ยมมุมล่างหรือสามเหลี่ยมด้านบน เมทริกซ์สัมประสิทธิ์

อย่างเป็นทางการมากขึ้น หากกำหนด a และ b แล้ว result[i0, ..., iR-3, :, :] คือโซลูชัน เป็น op(a[i0, ..., iR-3, :, :]) * x = b[i0, ..., iR-3, :, :] เมื่อ left_side คือ trueหรือx * op(a[i0, ..., iR-3, :, :]) = b[i0, ..., iR-3, :, :]เมื่อ left_side มีค่า false กำลังแก้โจทย์เพื่อหาตัวแปร x เมื่อระบุ op(a) โดย transpose_a ซึ่งอาจเป็นอย่างใดอย่างหนึ่งต่อไปนี้

  • NO_TRANSPOSE: ดำเนินการโดยใช้ a ตามที่เป็น
  • TRANSPOSE: ดำเนินการสลับตำแหน่ง a
  • ADJOINT: ดำเนินการกับการสับเปลี่ยนสังยุคของ a

จะอ่านข้อมูลอินพุตจากสามเหลี่ยมด้านล่างของ a เท่านั้น หาก lower คือ true หรือ สามเหลี่ยมมุมบนของ a มิเช่นนั้น ข้อมูลเอาต์พุตจะส่งกลับมาในสามเหลี่ยมเดียวกัน ค่าในสามเหลี่ยมอีกรูปหนึ่งจะกำหนดการติดตั้งใช้งาน

หาก unit_diagonal เป็นจริง การติดตั้งใช้งานจะถือว่าเส้นทแยงมุม องค์ประกอบของ a จะเท่ากับ 1 มิเช่นนั้นจะไม่สามารถระบุลักษณะการทำงาน

สำหรับประเภทที่เล็กลง จะดำเนินการ dequantize_op_quantize(lambda x, y: triangular_solve(x, y, left_side, lower, unit_diagonal, transpose_a), a, b, type(result))

อินพุต

ป้ายกำกับ ชื่อ ประเภท ข้อจำกัด
(I1) a เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน (C1-C3)
(I2) b เทรลของจุดลอยตัวหรือประเภทเชิงซ้อนหรือ Tensor ที่แปลงค่าเป็น 1 ส่วน (C1-C4)
(I3) left_side ค่าคงที่ของประเภท i1 (C3)
(I4) lower ค่าคงที่ของประเภท i1
(I5) unit_diagonal ค่าคงที่ของประเภท i1
(I6) transpose_a enum ของ NO_TRANSPOSE, TRANSPOSE และ ADJOINT

เอาต์พุต

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

ข้อจำกัด

  • (C1) baseline_element_type(a) = baseline_element_type(b)
  • (C2) 2 <= rank(a) = rank(b) = R
  • (C3) ความสัมพันธ์ระหว่าง shape(a) กับ shape(b) กำหนดไว้ดังต่อไปนี้
    • shape(a)[:-3] = shape(b)[:-3]
    • dim(a, -2) = dim(a, -1) = dim(b, left_side ? -2 : -1)
  • (C4) baseline_type(b) = baseline_type(result)

ตัวอย่าง

// %a = [
//       [1.0, 0.0, 0.0],
//       [2.0, 4.0, 0.0],
//       [3.0, 5.0, 6.0]
//      ]
// %b = [
//       [2.0, 0.0, 0.0],
//       [4.0, 8.0, 0.0],
//       [6.0, 10.0, 12.0]
//      ]
%result = "stablehlo.triangular_solve"(%a, %b) {
  left_side = true,
  lower = true,
  unit_diagonal = false,
  transpose_a = #stablehlo<transpose NO_TRANSPOSE>
} : (tensor<3x3xf32>, tensor<3x3xf32>) -> tensor<3x3xf32>
// %result: [
//           [2.0, 0.0, 0.0],
//           [0.0, 2.0, 0.0],
//           [0.0, 0.0, 2.0]
//          ]

Tuple

อรรถศาสตร์

สร้าง Tuple result จากค่า val

อินพุต

ป้ายกำกับ ชื่อ ประเภท ข้อจำกัด
(I1) val จำนวนค่าแปรผัน (C1)

เอาต์พุต

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

ข้อจำกัด

  • (C1) result มีประเภท tuple<E0, ..., EN-1> โดยที่ Ei = type(val[i])

ตัวอย่าง

// %val0: [1.0, 2.0]
// %val1: (3)
%result = "stablehlo.tuple"(%val0, %val1) : (tensor<2xf32>, tuple<tensor<i32>>) -> tuple<tensor<2xf32>, tuple<tensor<i32>>>
// %result: ([1.0, 2.0], (3))

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

uniform_dequantize

อรรถศาสตร์

ทำการแปลงเชิงปริมาณของ Tensor จำนวน operand เป็น tensor จุดลอยตัว result ตามพารามิเตอร์การแปลงค่าตัวเลขที่กําหนดไว้ ตามประเภท operand

หรือ result = dequantize(operand) อย่างเป็นทางการ

อินพุต

ป้ายกำกับ ชื่อ ประเภท ข้อจำกัด
(I1) operand Tensor (C1), (C2)

เอาต์พุต

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

ข้อจำกัด

  • (C1) shape(operand) = shape(result)
  • (C2) element_type(result) = expressed_type(operand)

ตัวอย่าง

// %operand: [10, 10]
%result = "stablehlo.uniform_dequantize"(%operand) : (tensor<2x!quant.uniform<i8:f32:0, {0.1:-30,0.5:-20}>>) -> tensor<2xf32>
// %result: [4.0, 15.0]

uniform_quantize

อรรถศาสตร์

ดำเนินการแปลง Tensor จุดลอยตัวหรือ Tensor ที่วัดปริมาณด้วยองค์ประกอบ operand ไปยัง Tensor ที่เล็กลง result ตามการวัดปริมาณ พารามิเตอร์ที่กำหนดโดยประเภท result

อย่างเป็นทางการ

  • หาก is_float(operand):
    • result = quantize(operand, type(result))
  • หาก is_quantized(operand):
    • float_result = dequantize(operand)
    • result = quantize(float_result, type(result))

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

  • (C1) shape(operand) = shape(result)
  • (C2) expressed_type(result) = is_float(operand) ? element_type(operand) : expressed_type(operand)

ตัวอย่าง

// %operand: [4.0, 15.0]
%result = "stablehlo.uniform_quantize"(%operand) : (tensor<2xf32>) -> tensor<2x!quant.uniform<i8:f32:0, {0.1:-30,0.5:-20}>>
// %result: [10, 10]

// %operand: [10, 10]
%result = "stablehlo.uniform_quantize"(%operand) : (tensor<2x!quant.uniform<i8:f32:0, {0.1:-30,0.5:-20}>>) -> tensor<2x!quant.uniform<i8:f32:0, {0.1:-20,0.2:-30}>>
// %result: [20, 45]

ฟังขณะ

อรรถศาสตร์

สร้างเอาต์พุตจากการเรียกใช้ฟังก์ชัน body 0 ครั้งขึ้นไปขณะที่ฟังก์ชัน ฟังก์ชัน cond จะเอาต์พุต true ยิ่งเป็นทางการ ก็สามารถอธิบายความหมาย โดยใช้ไวยากรณ์ Python ดังนี้

internal_state = operand
while cond(*internal_state):
  internal_state = body(*internal_state)
results = internal_state

ลักษณะการทำงานของลูปอนันต์จะมีการกำหนดภายหลัง (#383)

อินพุต

ป้ายกำกับ ชื่อ ประเภท ข้อจำกัด
(I1) operand จำนวนแปรผันของ Tensor, Tensor ที่เล็กลง หรือโทเค็น (C1-C3)
(I2) cond ฟังก์ชัน (C1)
(I3) body ฟังก์ชัน (C2)

เอาต์พุต

ชื่อ ประเภท ข้อจำกัด
results จำนวนแปรผันของ Tensor, Tensor ที่เล็กลง หรือโทเค็น (C3)

ข้อจำกัด

  • (C1) cond เป็นประเภท (T0, ..., TN-1) -> tensor<i1> โดยที่ Ti = type(operand[i])
  • (C2) body เป็นประเภท (T0, ..., TN-1) -> (T0, ..., TN-1) โดยที่ Ti = type(operand[i])
  • (C3) type(results...) = type(operand...)

ตัวอย่าง

// %init_i: 1
// %init_sum: 0
// %one: 1
// %ten: 10
%results0, %results1 = "stablehlo.while"(%init_i, %init_sum) ({
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %cond = "stablehlo.compare"(%arg0, %ten) {
      comparison_direction = #stablehlo<comparison_direction LT>
    } : (tensor<i64>, tensor<i64>) -> tensor<i1>
    stablehlo.return %cond : tensor<i1>
  }, {
  ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
    %new_sum = stablehlo.add %arg1, %one : tensor<i64>
    %new_i = stablehlo.add %arg0, %one : tensor<i64>
    stablehlo.return %new_i, %new_sum : tensor<i64>, tensor<i64>
}) : (tensor<i64>, tensor<i64>) -> (tensor<i64>, tensor<i64>)
// %results0: 10
// %results1: 10

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

Xor

อรรถศาสตร์

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

  • สำหรับบูลีน: ตรรกะ XOR
  • สำหรับจำนวนเต็ม: Bitwise XOR

อินพุต

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

เอาต์พุต

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

ข้อจำกัด

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

ตัวอย่าง

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

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

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

การทำงานร่วมกันของภาษาถิ่น

ในขณะนี้ โปรแกรม StableHLO ในป่านี้บางครั้งมีการดำเนินงานที่ ไม่ได้กำหนดโดย StableHLO

โมดูล ฟังก์ชัน การโทรและส่งคืน

StableHLO ใช้การดำเนินการอัปสตรีม MLIR สำหรับ ModuleOp, FuncOp, CallOp และ ReturnOp. ทำให้สามารถทำงานร่วมกับเครื่องจักร MLIR ที่มีอยู่ได้ดียิ่งขึ้น บัตรผ่านที่มีประโยชน์คือการเขียน ที่กำหนดเป้าหมาย FuncOp และ ModuleOp และการรวบรวม คาดหวังว่าจะมีการดำเนินการเหล่านี้ด้วย การรับประกันความเข้ากันได้อย่างสมบูรณ์คือ ที่ใช้กับการดำเนินการเหล่านี้ หากมีการเปลี่ยนแปลงใดๆ เกี่ยวกับการดำเนินการเหล่านี้ใน วิธีที่เข้ากันไม่ได้ (เช่น การนำออก) ระบบจะเพิ่มค่าเทียบเท่าของ StableHLO เพื่อเก็บรักษา ความสามารถในการใช้งานร่วมกัน

CHLO

ฝั่งตรงข้ามของ CHLO มีการดำเนินการระดับสูงกว่าซึ่งย่อยสลายเป็น StableHLO ปัจจุบันยังไม่มีการรับประกันความเข้ากันได้สำหรับ CHLO สำหรับความเข้ากันได้ การรับประกัน, บัตร chlo-legalize-to-stablehlo ต้องใช้ก่อนการเรียงอันดับ

การดำเนินการรูปร่าง

ชุมชนใช้การดำเนินการบางอย่างจากระบบหลักเป็นกรณีการใช้งานทั่วไป ภาษาถิ่นของ MLIR ในโปรแกรม StableHLO แบบไดนามิกเพื่อคำนวณรูปร่าง โดยส่วนใหญ่ได้แก่ภาษาถิ่น shape เช่น shape_of หรือ num_elements, tensor ภาษา เช่น dim หรือ from_elements และประเภท index ในตัว

Dynamism RFC > O2 แสดงว่ารายการเหล่านี้อยู่นอกขอบเขต แต่การสนับสนุน index ประเภท รวมไว้เพื่อการทำงานร่วมกัน ไม่มีการรับประกันความเข้ากันได้สำหรับแอปเหล่านี้ การดำเนินการหรือประเภท shape-legalize-to-stablehlo สามารถใช้เพื่อแปลงการดำเนินการเหล่านี้เป็น Ops ของ StableHLO ที่สนับสนุนอย่างสมบูรณ์

การดำเนินการที่เลิกใช้งานแล้ว

มีการดำเนินการ StableHLO หลายรายการที่รับช่วงมาจาก MHLO ซึ่งเลิกใช้งานแล้วและกำลังออกจาก StableHLO รายละเอียดทั้งหมดเกี่ยวกับเรื่องเหล่านี้ การนำออกจะอยู่ใน StableHLO v1.0 Cleanup #2283 ปัญหาเครื่องมือติดตามสำหรับการเลิกใช้งานเหล่านี้คือ #2340

โดยการดำเนินการเหล่านี้แบ่งออกเป็น 2-3 หมวดหมู่ ดังนี้

  • "ไม่ได้อยู่ใน HLO" หมวดหมู่การดำเนินงาน StableHLO - ในตอนแรกมันเป็นส่วนหนึ่งของ ตัวเลือก StableHLO แต่ภายหลังมีการพิจารณาได้ไม่ดีนัก: broadcast, create_token, cross-replica-sum, dot, einsum torch_index_select unary_einsum (#3)
  • การดำเนินการที่ไม่ได้ใช้ - การดำเนินการเหล่านี้อาจมีประโยชน์ในช่วงหนึ่ง แต่การดำเนินการ ด้อยพัฒนา หรือไปป์ไลน์ที่ใช้การดำเนินการเหล่านี้ เปลี่ยนโครงสร้างภายในโค้ดเพื่อไม่ให้จำเป็นต้องใช้อีกต่อไป ซึ่งรวมถึง map, tuple (#598) การเปรียบเทียบ get_tuple_element, rng, complex #560, และ 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 และการคำนวณค่าเอาต์พุต ค่าเอาต์พุตของฟังก์ชันจะคำนวณตาม การเรียกใช้กราฟของการดำเนินการที่รูทในการดำเนินการ return ที่เกี่ยวข้อง

ลำดับการดำเนินการจะได้รับการกำหนดการใช้งาน ตราบใดที่สอดคล้องกับ โฟลว์ข้อมูล นั่นคือเมื่อมีการเรียกใช้การดำเนินการก่อนการใช้งาน ใน 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 พร้อมกันได้โดยจัดแบ่งเป็นตารางกริดกระบวนการแบบ 2 มิติ ของ num_replicas ตาม num_partitions ซึ่งทั้งคู่เป็นประเภท ui32

ในตารางกระบวนการ StableHLO num_replicas * num_partitions ของ StableHLO ดำเนินการในเวลาเดียวกัน แต่ละกระบวนการจะมี process_id = (replica_id, partition_id) โดยที่ replica_idในreplica_ids = range(num_replicas)และ partition_id ใน partition_ids = range(num_partitions) ซึ่งทั้งคู่มี พิมพ์ ui32

ขนาดของตารางกริดประมวลผลเป็นที่รับรู้กันโดยทั่วไปสำหรับทุกโปรแกรม (ใน ในอนาคต เรามีแผนที่จะทำให้ฟีเจอร์นี้กลายเป็นส่วนหนึ่งของโปรแกรม StableHLO #650) และตำแหน่ง ภายในตารางกริดของกระบวนการจะมีชื่อที่คงที่สำหรับทุกกระบวนการ โดยแต่ละกระบวนการจะมี สิทธิ์เข้าถึงตำแหน่งภายในตารางกระบวนการผ่าน replica_id และ partition_id การดำเนินการ

ภายในตารางกระบวนการ โปรแกรมทั้งหมดสามารถเหมือนกันได้ (ใน โปรแกรม ข้อมูลที่หลากหลาย" ) ที่ใช้แตกต่างกันได้ (ใน "หลายโปรแกรม ข้อมูลหลายรายการ" ) หรืออะไรบางอย่างคั่นกลาง ในอนาคตเรากำลังวางแผน ที่จะมีการสนับสนุนสำนวนอื่นๆ ในการกำหนดโปรแกรม StableHLO คู่ขนาน รวมถึง GSPMD (#619)

ภายในตารางกระบวนการนั้น กระบวนการส่วนใหญ่จะเป็นอิสระจากกัน มีสถานะการดำเนินการแตกต่างกัน รวมถึงมีค่าอินพุต/กลาง/เอาต์พุตแยกกัน และการดำเนินการส่วนใหญ่จะถูกดำเนินการแยกกันในระหว่างกระบวนการ ยกเว้นการดำเนินการรวมจำนวนเล็กน้อยที่อธิบายด้านล่าง

เนื่องจากการดำเนินการของ Ops ส่วนใหญ่จึงใช้เพียงค่าจาก ส่วนใหญ่แล้ว การอ้างอิงค่าเหล่านี้ด้วยชื่อมักจะไม่ชัดเจน อย่างไรก็ตาม เมื่ออธิบายความหมายของการทำงานรวม นั่นถือว่าไม่เพียงพอ และ ที่เป็นสาเหตุของเครื่องหมาย name@process_id เพื่ออ้างถึงค่า name ภายในกระบวนการหนึ่งๆ โดยเฉพาะ (จากมุมมองนี้ name ที่ไม่มีสิทธิ์อาจ ซึ่งถือเป็นชวเลขสำหรับ name@(replica_id(), partition_id()))

ลำดับการดำเนินการในกระบวนการต่างๆ มีการกำหนดการใช้งานแล้ว ยกเว้น การซิงค์ที่นำมาใช้โดยการสื่อสารแบบจุดต่อจุดและการดำเนินการร่วมกัน ตามที่อธิบายไว้ด้านล่าง

การสื่อสารแบบจุดต่อจุด

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

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

การสื่อสารแบบสตรีมมิง

ทุกกระบวนการของ StableHLO จะสามารถเข้าถึงอินเทอร์เฟซสตรีมมิง 2 แบบ ได้แก่

  • Infeed ที่สามารถอ่านได้
  • โฆษณานอกฟีดที่เขียนถึงได้

ต่างจากช่องทางที่ใช้เพื่อสื่อสารระหว่างกระบวนการ และด้วยเหตุนี้ มีกระบวนการทั้ง 2 ด้าน ขณะที่ในฟีดและนอกฟีดมีกระบวนการอื่นๆ สิ้นสุดการใช้งานที่กำหนดโดย

รูปแบบที่เป็นทางการเพิ่มเติม เช่น การสื่อสารแบบสตรีมมิงส่งผลต่อการดำเนินการอย่างไร ลำดับและประเภทการซิงค์ที่จะนำมาใช้งาน จะมีการกำหนดในภายหลัง (#484)

การดำเนินการร่วมกัน

ทีมปฏิบัติงานร่วม 6 กลุ่มใน StableHLO ได้แก่ all_gather, all_reduce all_to_all, collective_broadcast, collective_permute และ reduce_scatter การดำเนินการทั้งหมดนี้แยกกระบวนการในกระบวนการ StableHLO เป็นกลุ่มกระบวนการ StableHLO และดำเนินการคำนวณร่วมกันภายใน แต่ละกลุ่มกระบวนการ โดยไม่ขึ้นอยู่กับกลุ่มกระบวนการอื่นๆ

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

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

การคำนวณที่ดำเนินการโดยหน่วยงานปฏิบัติการร่วมจะเป็นข้อมูลเฉพาะสำหรับการดำเนินการของแต่ละบุคคล และได้อธิบายไว้ในส่วนการดำเนินการด้านบน อย่างไรก็ตาม กลยุทธ์โดย ซึ่งระบบจะแบ่งตารางกระบวนการออกเป็นกลุ่มกระบวนการที่มีการแชร์ระหว่างการดำเนินการเหล่านี้ และอธิบายไว้ในส่วนนี้ อย่างเป็นทางการมากขึ้น StableHLO สนับสนุน ต่อไปนี้ 4 กลยุทธ์

cross_replica

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

def cross_replica(replica_groups: List[List[ReplicaId]]) -> List[List[ProcessId]]:
  for replica_group in replica_groups:
    for partition_id in partition_ids:
      process_group = []
      for replica_id in replica_group:
        process_group.append((replica_id, partition_id))
      yield process_group

ตัวอย่างเช่น สำหรับ replica_groups = [[0, 1], [2, 3]] และ num_partitions = 2 cross_replica จะสร้างและ [[(0, 0), (1, 0)], [(0, 1), (1, 1)], [(2, 0), (3, 0)], [(2, 1), (3, 1)]]

cross_partition

เฉพาะการสื่อสารข้ามพาร์ติชันจะเกิดขึ้นภายในแต่ละกลุ่มกระบวนการ ช่วงเวลานี้ กลยุทธ์ใช้เวลา partition_groups ซึ่งเป็นรายการรหัสพาร์ติชัน และ คำนวณผลคูณคาร์ทีเซียนของ partition_groups ด้วย replica_ids partition_groups ต้องมีองค์ประกอบที่ไม่ซ้ำกันและครอบคลุม partition_ids ทั้งหมด อย่างเป็นทางการมากขึ้น โดยใช้ไวยากรณ์ Python ดังนี้

def cross_partition(partition_groups: List[List[PartitionId]]) -> List[List[ProcessId]]:
  for partition_group in partition_groups:
    for replica_id in replica_ids:
      process_group = []
      for partition_id in partition_group:
        process_group.append((replica_id, partition_id))
      yield process_group

ตัวอย่างเช่น สำหรับ partition_groups = [[0, 1]] และ num_replicas = 4 cross_partition จะสร้างและ [[(0, 0), (0, 1)], [(1, 0), (1, 1)], [(2, 0), (2, 1)], [(3, 0), (3, 1)]]

cross_replica_and_partition

ทั้งการสื่อสารแบบข้ามพาร์ติชันและข้ามพาร์ติชันอาจเกิดขึ้นภายในแต่ละรายการ กลุ่มการประมวลผลข้อมูล กลยุทธ์นี้ใช้เวลา replica_groups ซึ่งเป็นลิสต์รายการของ รหัสแบบจำลอง - และคำนวณผลคูณคาร์ทีเซียนของ replica_group แต่ละรายการโดย partition_ids replica_groups ต้องมีองค์ประกอบที่ไม่ซ้ำกันและครอบคลุมทั้งหมด replica_ids อย่างเป็นทางการมากขึ้น โดยใช้ไวยากรณ์ Python ดังนี้

def cross_replica_and_partition(replica_groups: List[List[ReplicaId]]) -> List[List[ProcessId]]:
  for replica_group in replica_groups:
    process_group = []
    for partition_id in partition_ids:
      for replica_id in replica_group:
        process_group.append((replica_id, partition_id))
    yield process_group

ตัวอย่างเช่น สำหรับ replica_groups = [[0, 1], [2, 3]] และ num_partitions = 2 cross_replica_and_partition จะสร้างและ [[(0, 0), (1, 0), (0, 1), (1, 1)], [(2, 0), (3, 0), (2, 1), (3, 1)]]

flattened_ids

กลยุทธ์นี้ใช้เวลา flattened_id_groups ซึ่งเป็นลิสต์รายการ "แบ่งเป็นหลายรายการ" รหัสกระบวนการในรูปแบบ replica_id * num_partitions + partition_id - และ เพื่อเปลี่ยนให้เป็นรหัสกระบวนการ flattened_id_groups ต้องมีองค์ประกอบที่ไม่ซ้ำกัน และครอบคลุมทั้ง process_ids อย่างเป็นทางการมากขึ้น โดยใช้ไวยากรณ์ Python ดังนี้

def flattened_ids(flattened_id_groups: List[List[ui32]]) -> List[List[ProcessId]]:
  for flattened_id_group in flattened_id_groups:
    process_group = []
    for flattened_id in flattened_id_group:
      replica_id = flattened_id // num_partitions
      partition_id = flattened_id % num_partitions
      process_group.append((replica_id, partition_id))
    yield process_group

ตัวอย่างเช่น สำหรับ flattened_id_groups = [[0, 1, 2, 3], [4, 5, 6, 7]] num_replicas = 4 และ num_partitions = 2, flattened_ids จะสร้าง [[(0, 0), (0, 1), (1, 0), (1, 1)], [(2, 0), (2, 1), (3, 0), (3, 1)]]

ความแม่นยำ

ในขณะนี้ StableHLO ไม่รับประกันความถูกต้อง ของตัวเลข แต่อาจมีการเปลี่ยนแปลงในอนาคต (#1156)

ความหมายของการดำเนินการของการดำเนินการเชิงปริมาณ

การตีความการดำเนินการ StableHLO ที่วัดปริมาณอาจแตกต่างกันไปขึ้นอยู่กับ ข้อกำหนดและความสามารถของฮาร์ดแวร์ ตัวอย่างเช่น ฮาร์ดแวร์อาจเลือกใช้ ตีความการดำเนินการที่แปลงค่าเป็นเชิงปริมาณโดยใช้ฟังก์ชัน "ทำให้จำนวนที่ลอยอยู่ ดำเนินการจุดลอยตัว และสุดท้ายคือปริมาณ" ของคุณ ผู้อื่นอาจดำเนินการทั้งหมด การคำนวณด้วยเลขคณิตจำนวนเต็ม ดังนั้น การตีความ การดำเนินการ StableHLO ที่วัดปริมาณได้จะกำหนดโดย การใช้งานของคุณ การตีความการวัดปริมาณแบบผสม (#1575) ควรอิงตาม เป็นอรรถศาสตร์ตามที่ระบุไว้ในข้อกำหนด (ผ่าน 1792)

ข้อผิดพลาด

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

ข้อยกเว้นจุดลอยตัว

ข้อยกเว้นสำหรับกฎนี้คือข้อยกเว้นจุดลอยตัวในโปรแกรม StableHLO มีลักษณะการทำงานที่กำหนดไว้แล้ว การดำเนินการซึ่งส่งผลให้เกิดข้อยกเว้นที่กำหนดโดย มาตรฐาน IEEE-754 (การดำเนินการไม่ถูกต้อง, การแบ่งตามศูนย์, ไม่มากเกินไป, มากเกินไป, หรือ ข้อยกเว้นที่ไม่เหมือนกัน) จะสร้างผลลัพธ์เริ่มต้น (ตามที่ให้คำนิยามไว้ในมาตรฐาน) และ ดำเนินการต่อไปโดยไม่ต้องเพิ่มธงสถานะที่เกี่ยวข้อง คล้ายกับ มีการจัดการข้อยกเว้น raiseNoFlag รายการจากมาตรฐาน ข้อยกเว้นสำหรับโฆษณาที่ไม่เป็นมาตรฐาน การดำเนินการ (เช่น เลขคณิตที่ซับซ้อนและฟังก์ชันทรูปัญญาประดิษฐ์) ที่กำหนดโดยการติดตั้งใช้งาน

รูปร่างไม่ตรงกัน

StableHLO รองรับ Tensor ที่มีการจัดรูปแบบแบบไดนามิก อย่างไรก็ตาม รูปร่างต้องยอมรับที่ รันไทม์ มิฉะนั้นจะทำงานไม่ได้ StableHLO จะไม่แสดง จะมีการดำเนินการที่สามารถยืนยันได้ว่า Tensor มีรูปร่างที่กำหนดในระหว่างรันไทม์ การสร้างโค้ดที่ถูกต้องถือเป็นความรับผิดชอบของผู้สร้าง

โปรแกรมด้านล่างนี้ถูกต้องตามตัวอย่าง แต่ในระหว่างรันไทม์ รูปทรงที่แน่นอนของ %arg0 และ %arg1 จะต้องเหมือนกัน มิฉะนั้น ลักษณะการทำงานของโปรแกรมที่ไม่ได้กำหนด:

func.func @foo(%arg0: tensor<?xi32>, %arg1: tensor<?xi32>) -> tensor<?xi32> {
    %0 = stablehlo.add %arg0, %arg1 : tensor<?xi32>
    return %0 : tensor<?xi32>
}

เครื่องหมาย

สำหรับการอธิบายไวยากรณ์ เอกสารนี้ใช้เวอร์ชัน ISO ที่แก้ไขแล้วของ EBNF (ISO/IEC 14977:1996, วิกิพีเดีย) โดยมีการแก้ไข 2 รายการ ได้แก่ 1) กำหนดกฎโดยใช้ ::= แทนที่จะเป็น =

2) การต่อกันแสดงโดยใช้การอยู่ต่อกันแทนที่จะเป็น ,

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

สูตร

มาดูวิธีการทำงานของสูตรตามตัวอย่างจาก dot_general หนึ่งในข้อจำกัดสำหรับการดำเนินการนี้มีดังนี้ dim(lhs, lhs_batching_dimensions...) = dim(rhs, rhs_batching_dimensions...)

ชื่อที่ใช้ในสูตรนี้มาจากแหล่งที่มา 2 แหล่ง ได้แก่ 1) ฟังก์ชันส่วนกลาง เช่น dim, 2) คำจำกัดความสมาชิกขององค์ประกอบโปรแกรมที่เกี่ยวข้อง เช่น อินพุต lhs, lhs_batching_dimensions, rhs และ rhs_batching_dimensions ที่กำหนดไว้ใน "อินพุต" ของ dot_general

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

ตอบ) ในสูตรเหล่านี้ เราใช้ = เพื่อแสดงความเท่าเทียม ดังนั้นขั้นแรก เพื่อรับไวยากรณ์ Python จะแทนที่ = ด้วย == ดังนี้ dim(lhs, lhs_batching_dimensions...) == dim(rhs, rhs_batching_dimensions...)

ข) และสูตรเหล่านี้ยังรองรับจุดไข่ปลา (...) ซึ่งเปลี่ยนนิพจน์สเกลาร์ เป็นนิพจน์ Tensor โดยสรุปแล้ว f(xs...) จะหมายถึง "สำหรับแต่ละผลิตภัณฑ์" สเกลาร์ x ใน tensor xs คำนวณสเกลาร์ f(x) แล้วแสดงผลทั้งหมด ผลลัพธ์สเกลาร์เหล่านี้รวมกันเป็นผลลัพธ์ Tensor" ในไวยากรณ์ Python เวอร์ชันวานิลลา สูตรตัวอย่างของเราจะเปลี่ยนเป็น [dim(lhs, dim1) for dim1 in lhs_batching_dimensions] == [dim(rhs, dim2) for dim2 in rhs_batching_dimensions]

ด้วยจุดไข่ปลา ทำให้สามารถหลีกเลี่ยงการทำงานได้ในระดับ สเกลาร์แต่ละรายการ อย่างไรก็ตาม ในบางกรณีที่ยุ่งยาก ระดับล่างจะเป็นข้อมูลกึ่งทางการ อาจมีการใช้ไวยากรณ์ เช่น ในสูตร start_indices[bi0, ..., :, ..., biN] จากข้อกำหนด gather ในการให้บริการกระชับ เราจึงไม่ มีรูปแบบที่แน่นอนสำหรับการแปลไวยากรณ์ดังกล่าวให้เป็นวานิลลา Python ใน หวังว่าเนื้อหานี้จะยังคงเข้าใจได้ง่ายโดยพิจารณาเป็นรายกรณีไป โปรดแจ้งให้เราทราบหากมีสูตรบางสูตรที่ทึบแสง และเราจะพยายามดำเนินการ เพื่อปรับปรุงให้ดีขึ้น

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

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

หากต้องการดำเนินการต่อตามตัวอย่าง dot_general มีข้อจำกัดอื่นดังนี้ 0 <= lhs_batching_dimensions < rank(lhs) ตามที่ระบุไว้ใน dot_general lhs_batching_dimensions จะเป็น Tensor อย่างไรก็ตามทั้ง 0 และ rank(lhs) เป็นสเกลาร์ หลังจากเราใช้การออกอากาศโดยนัยแล้ว สูตรจะ เปลี่ยนเป็น [0, ..., 0] <= lhs_batching_dimensions < [rank(lhs), ..., rank(lhs)]

เมื่อใช้กับการดำเนินการ dot_general โดยเฉพาะ สูตรนี้จะ ประเมินเป็น tensor ของบูลีน เมื่อใช้สูตรเป็นข้อจำกัด ค่า จะมีการคงไว้ชั่วคราวหากสูตรประเมินเป็น true หรือ tensor ที่ มีองค์ประกอบ true เท่านั้น

ชื่อ

ในสูตร ขอบเขตคำศัพท์ประกอบด้วย 1) ฟังก์ชันส่วนกลาง 2) คำนิยามสมาชิก

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

  • สำหรับการดำเนินการ คำนิยามสมาชิกจะรวมถึงชื่อที่ใช้ใน "อินพุต" และ "เอาต์พุต"
  • สำหรับสิ่งอื่นๆ คำนิยามสมาชิกจะรวมถึงส่วนต่างๆ เชิงโครงสร้างของ องค์ประกอบของโปรแกรม ซึ่งตั้งชื่อตามรายการที่ไม่ใช่เทอร์มินัลของ EBNF ที่เกี่ยวข้อง ส่วนใหญ่ของ ชื่อของชิ้นส่วนโครงสร้างเหล่านี้จะได้จากการแปลงค่า ชื่อของกรณีที่ไม่ใช่เทอร์มินัลที่จะงู (เช่น IntegerLiteral =>) integer_literal) แต่บางครั้งชื่ออาจถูกตัดให้สั้นลงในกระบวนการนี้ (เช่น QuantizationStorageType => storage_type) ซึ่งในกรณีนี้ชื่อคือ มีลักษณะคล้ายกับ "อินพุต" / "เอาต์พุต" ส่วนที่ดำเนินการอยู่
  • นอกจากนี้ คําจํากัดความของสมาชิกจะใส่ self เสมอเพื่ออ้างถึง ที่เกี่ยวข้องของโปรแกรม

ค่า

เมื่อประเมินสูตรแล้ว สูตรจะทำงานกับค่าประเภทต่อไปนี้ 1) Value (ค่าจริง เช่น dense<[[1, 2], [3, 4]]> : tensor<2x2xi32>; เด็กๆ รู้ประเภทคอนเทนต์ของตัวเองเสมอ) 2) Placeholder (ค่าในอนาคต เช่น lhs, rhs หรือ result ค่าตามจริง ระบบยังไม่รู้จักค่าเหล่านี้ รู้เฉพาะประเภทเท่านั้น) 3) Type (ประเภทตามที่กำหนดไว้ในส่วน "ประเภท") 4) Function (ฟังก์ชันส่วนกลางตามที่กำหนดไว้ในส่วน "ฟังก์ชัน")

ชื่ออาจอ้างอิงถึงค่าที่แตกต่างกัน ขึ้นอยู่กับบริบท เพิ่มเติม โดยเฉพาะอย่างยิ่ง "ความหมาย" สำหรับการดำเนินการ (และเทียบเท่ากับโปรแกรมอื่น) ) จะกำหนดตรรกะรันไทม์ ดังนั้นอินพุตทั้งหมดจะพร้อมใช้งานเป็น Value ในทางกลับกัน "ข้อจำกัด" สำหรับการดำเนินการ (และรายการเทียบเท่า) "เวลาคอมไพล์" คือสิ่งที่มักจะดำเนินการก่อนรันไทม์ จึงมีเฉพาะอินพุตคงที่เท่านั้นที่จะแสดงเป็น Value ส่วนอินพุตอื่นๆ จะมีค่า พร้อมให้ใช้งานในรูปแบบ Placeholder เท่านั้น

ชื่อ ใน "ความหมาย" ใน "ข้อจำกัด"
ฟังก์ชันส่วนกลาง Function Function
อินพุตแบบคงที่ Value Value
อินพุตที่ไม่คงที่ Value Placeholder
เอาต์พุต Value Placeholder
คำจำกัดความในภาษาท้องถิ่น ขึ้นอยู่กับคำจำกัดความ ขึ้นอยู่กับคำจำกัดความ

ดูตัวอย่างการดำเนินการ transpose

%result = "stablehlo.transpose"(%operand) {
  permutation = dense<[2, 1, 0]> : tensor<3xi64>
} : (tensor<2x3x2xi32>) -> tensor<2x3x2xi32>

สำหรับการดำเนินการนี้ permutation เป็นค่าคงที่ ดังนั้นจึงใช้ได้เป็น Value ทั้งในความหมายและข้อจำกัด ในทางตรงกันข้าม operandและresult ใช้เป็น Value ในอรรถศาสตร์ แต่เป็น Placeholder ในข้อจำกัดเท่านั้น

ฟังก์ชัน

การก่อสร้างประเภท

ไม่มีฟังก์ชันที่สามารถใช้สร้างประเภทได้ แต่เราโดยตรง ใช้ไวยากรณ์ประเภทเนื่องจากโดยทั่วไปมีความกระชับมากกว่า เช่น (tensor<E>, tensor<E>) -> (tensor<E>) แทนที่จะเป็น function_type( [tensor_type([], E), tensor_type([], E)], [tensor_type([], E)])

ฟังก์ชันในประเภท

  • element_type กำหนดสำหรับประเภท tensor และประเภท tensor ที่เล็กลงและ TensorElementType หรือ QuantizedTensorElementType ตามลำดับ ของ TensorType หรือ QuantizedTensorType ที่เกี่ยวข้อง
def element_type(x: Value | Placeholder | Type):
 if type(x) == TensorType:
    return tensor_element_type(x)
  if type(x) == QuantizedTensorType:
    return quantized_tensor_element_type(x)
  if type(x) is not Type:
    return element_type(type(x))
  • is_per_axis_quantized(x: Value | Placeholder | Type) -> Value เป็นทางลัด สำหรับ is_quantized(x) and quantization_dimension(x) is not None

  • is_per_tensor_quantized(x: Value | Placeholder | Type) -> Value เป็น แป้นพิมพ์ลัดสำหรับ is_quantized(x) and quantization_dimension(x) is None

  • is_promotable(x: Type, y: Type) -> bool ตรวจสอบว่าสามารถโปรโมตประเภท x ได้หรือไม่ เพื่อพิมพ์ y เมื่อ x และ y มีราคา QuantizedTensorElementType จะมีผลกับ storage_type เท่านั้น โปรโมชันเวอร์ชันเฉพาะนี้ ที่ใช้ในบริบทของการคำนวณการลดทอน (ดู RFC เพื่อดูรายละเอียดเพิ่มเติม)

def is_promotable(x: Type, y: Type) -> Value:
  is_same_type = (is_bool(x) and is_bool(y)) or
    (is_integer(x) and is_integer(y)) or (is_float(x) and is_float(y)) or
    (is_complex(x) and is_complex(y)) or
    (is_quantized(x) and is_quantized(y) and expressed_type(x) = expressed_type(y))

  if is_same_type == False:
    return False

  if is_integer(x) or is_float(x):
    return bitwidth(x) <= bitwidth(y)

  if is_complex(x):
    return bitwidth(element_type(x)) <= bitwidth(element_type(y))

  if is_quantized(x):
    return bitwidth(storage_type(x)) <= bitwidth(storage_type(y))

  return false
  • is_quantized(x: Value | Placeholder | Type) -> Value เป็นทางลัดสำหรับ is_quantized_tensor_element_type(x)

  • is_type_name(x: Value | Placeholder | Type) -> Value พร้อมใช้งานสำหรับทุกคน ประเภทต่างๆ เช่น is_float(x) จะแสดงผล true หาก x เป็น FloatType หาก x เป็นค่าหรือตัวยึดตำแหน่ง ฟังก์ชันนี้จะเป็นทางลัดสำหรับ is_type_name(type(x))

  • max_value(x: Type) -> Value แสดงผลค่าสูงสุดของ TensorElementType หาก x ไม่ใช่ TensorElementType จะแสดงผล None

  • min_value(x: Type) -> Value แสดงผลค่าต่ำสุดที่เป็นไปได้ของ TensorElementType หาก x ไม่ใช่ TensorElementType จะแสดงผล None

  • member_name(x: Value | Placeholder | Type) -> Any พร้อมให้บริการสำหรับสมาชิกทุกคน คำจำกัดความ member_name ทุกประเภท เช่น tensor_element_type(x) แสดงผลส่วน TensorElementType ของ TensorType ที่เกี่ยวข้อง หาก x เป็นค่าหรือตัวยึดตำแหน่ง ฟังก์ชันนี้จะเป็นทางลัดสำหรับ member_name(type(x)) หาก x ไม่ใช่ประเภทที่มีสมาชิกที่เหมาะสม หรือ ค่าหรือตัวยึดตำแหน่งของประเภทดังกล่าวจะแสดง None

  • is_empty_algorithm(*args: Type) ตรวจสอบว่าได้ตั้งค่าฟิลด์อัลกอริทึมของจุดทั้งหมดหรือไม่ ไปยัง None ซึ่งจำเป็นต้องมีเนื่องจากอัลกอริทึมของจุดมีการกำหนดการใช้งาน พฤติกรรมที่เป็นค่าเริ่มต้น ดังนั้นการระบุค่าเริ่มต้นจึงไม่ถูกต้อง

การสร้างมูลค่า

  • operation_name(*xs: Value | Type) -> Value ใช้ได้สำหรับการดำเนินงานทั้งหมด ตัวอย่างเช่น add(lhs, rhs) ใช้ค่า Tensor 2 ค่า lhs และ rhs และ แสดงผลเอาต์พุตของการประเมินการดำเนินการ add ด้วยข้อมูลเหล่านี้ สำหรับการดำเนินการบางอย่าง เช่น broadcast_in_dim ประเภทของเอาต์พุตคือ "รับน้ำหนักบรรทุก" กล่าวคือ จำเป็นสำหรับการประเมินการดำเนินการ ในกรณีนี้ ฟังก์ชัน จะใช้ประเภทเหล่านี้เป็นอาร์กิวเมนต์

ฟังก์ชันสำหรับค่า

  • โอเปอเรเตอร์และฟังก์ชันทั้งหมดของ Python จะพร้อมใช้งาน เช่น ทั้งคู่ การสมัครใช้บริการ และการแบ่งส่วน หมายเหตุจาก Python พร้อมสำหรับการจัดทำดัชนีเป็น Tensor, Tensor ที่เล็กลง และ Tuples

  • to_destination_type(x: Value, destination_type: Type) -> Value กำหนดไว้เมื่อ tensor แสดงผลค่าที่แปลงของ x ตาม type(x) และ destination_type ดังนี้

def to_destination_type(x: Value, destination_type: Type) -> Value:
  if type(x) == destination_type:
    return x

  if is_quantized(destination_type):
    if is_quantized(type(x)):
      return quantize(x, destination_type)
    assert is_float(type(x))
    return quantize(x, destination_type)

  if is_quantized(type(x)):
    assert destination_type = expressed_type(type(x))
    return dequantize(type(x))

  return convert(x, destination_type)

มีการพูดคุยกันล่วงหน้าเกี่ยวกับการผสานรวม convert, uniform_quantize กับ การดำเนินการ uniform_dequantize (#1576) หลังจากการผสาน เราไม่ต้องใช้ฟังก์ชันข้างต้นและสามารถใช้ชื่อการดำเนินการ ในราคา convert แทน

  • is_nan(x: Value) -> Value กำหนดไว้ใน tensor และแสดงค่า true หาก องค์ประกอบทั้งหมดของ x จะเป็น NaN หรือ false หาก x ไม่ใช่ Tensor แสดงผล None

  • is_sorted(x: Value) -> Value กำหนดไว้ใน tensor และแสดงค่า true หาก องค์ประกอบของ x จะได้รับการจัดเรียงตามจากน้อยไปหามาก เรียงลำดับแบบพจนานุกรมของดัชนีหรือ false ในกรณีอื่นๆ หาก x ไม่ใช่ tensor แสดงผล None

  • is_unique(x: Value) -> Value กำหนดไว้ใน tensor และแสดงค่า true หากเป็น x ไม่มีองค์ประกอบที่ซ้ำกันหรือไม่มี false หาก x ไม่ใช่ Tensor แสดงผล None

  • คำจำกัดความของ member_name(x: Value) -> Any คือคำจำกัดความของสมาชิกทั้งหมด member_name ของค่าทั้งหมด เช่น real_part(x) จะแสดงผล RealPart ของ ComplexConstant ที่เกี่ยวข้อง หาก x ไม่ใช่ค่าที่มี สมาชิกที่เหมาะสม แสดงผล None

  • same(x: Value) -> Value กำหนดไว้ใน tensor และแสดงค่า true หาก องค์ประกอบของ x ทั้งหมดจะต้องเท่ากัน หรือ false ในกรณีอื่นๆ หาก Tensor ไม่มีองค์ประกอบที่นับว่า "เท่าเทียมกันทั้งหมด" เช่น แสดงผล true หาก x ไม่ใช่ Tensor จะแสดงผล None

  • split(x: Value, num_results: Value, axis: Value) -> Value กำหนดไว้เมื่อ tensor และแสดงส่วน num_results ของ x ตามแกน axis หาก x ไม่ใช่ Tensor หรือ dim(x, axis) % num_results != 0 ให้แสดงผล None

  • มีการกำหนด is_defined_in_parent_scope(x: Value) -> Value ในสตริง และแสดงผล true หาก x เป็นชื่อฟังก์ชันที่กำหนดไว้ในขอบเขตเดียวกัน เป็นฟังก์ชันหลักของการดำเนินการที่เกี่ยวข้อง

  • มีการกำหนด is_namespaced_op_name(x: Value) -> Value สำหรับสตริงและการคืนสินค้า true หาก x เป็นชื่อ Op ที่ถูกต้อง ก็หมายความว่าเป็นไปตามลักษณะการทำงานปกติต่อไปนี้ นิพจน์: [a-zA-Z][a-zA-Z0-9_]*([.][a-zA-Z0-9_$]+)+

การคำนวณรูปร่าง

  • axes(x: Value | Placeholder | Type) -> Value เป็นทางลัดสำหรับ range(rank(x))

  • dim(x: Value | Placeholder | Type, axis: Value) -> Value เป็นทางลัดสำหรับ shape(x)[axis]

  • dims(x: Value | Placeholder | Type, axes: List) -> List เป็นทางลัดสำหรับ list(map(lambda axis: dim(x, axis), axes))

  • กำหนด index_space(x: Value | Placeholder | Type) -> Value ใน Tensor แล้ว และแสดงผลดัชนี size(x) รายการสำหรับ TensorType ที่จัดเรียงใน เรียงลำดับแบบพจนานุกรมจากน้อยไปมาก เช่น [0, ..., 0], [0, ..., 1], ..., shape(x) - 1 หาก x ไม่ใช่ประเภท Tensor, ประเภท Tensor ที่เล็กลง หรือค่า หรือตัวยึดตำแหน่งของหนึ่งในประเภทเหล่านี้แสดงผล None

  • rank(x: Value | Placeholder | Type) -> Value เป็นทางลัดสำหรับ size(shape(x))

  • shape(x: Value | Placeholder | Type) -> Value ได้รับการกําหนดไว้ในส่วน "ฟังก์ชัน ตามประเภท" ผ่าน member_name

  • size(x: Value | Placeholder | Type) -> Value เป็นทางลัดสำหรับ reduce(lambda x, y: x * y, shape(x))

การคำนวณหาปริมาณ

  • def baseline_element_type(x: Value | Placeholder | Type) -> Type เป็น แป้นพิมพ์ลัดสำหรับ element_type(baseline_type(x))

  • baseline_type กำหนดสำหรับประเภท tensor และประเภท tensor ที่เล็กลงและ เปลี่ยนเป็น "เกณฑ์พื้นฐาน" ซึ่งก็คือประเภทที่มีรูปทรงเดียวกันแต่มี พารามิเตอร์การวัดปริมาณของประเภทองค์ประกอบรีเซ็ตเป็นค่าเริ่มต้น นี่คือ ใช้เป็นเคล็ดลับที่มีประโยชน์ในการเปรียบเทียบทั้ง Tensor และ Tensor ประเภทที่เล็กลง อย่างเท่าเทียมกัน ซึ่ง จำเป็นค่อนข้างบ่อยครั้ง สำหรับประเภทที่เล็กลง จะเป็นการเปิดใช้ การเปรียบเทียบประเภทโดยไม่คํานึงถึงพารามิเตอร์การวัดปริมาณ ซึ่งก็คือ shape storage_type, expressed_type, storage_min, storage_max และ quantization_dimension (สำหรับประเภทต่อแกน) ต้องตรงกันทั้งหมด แต่ scales และ zero points อาจแตกต่างออกไป

def baseline_type(x: Value | Placeholder | Type) -> Type:
  if type(x) == TensorType:
    return x
  if type(x) == QuantizedTensorType:
    element_type = quantized_tensor_element_type(x)
    baseline_element_type = QuantizedTensorElementType(
      storage_type = storage_type(element_type),
      storage_min = storage_min(element_type),
      storage_max = storage_max(element_type),
      expressed_type = expressed_type(element_type),
      quantization_dimension = quantization_dimension(element_type),
      scales = [constant(1.0, expressed_type(element_type))] * dim(x, quantization_dimension(element_type)),
      zero_points = [constant(0, storage_type(element_type))] * dim(x, quantization_dimension(element_type)))
    return QuantizedTensorType(shape(x), baseline_element_type)
  if type(x) is not Type:
    return baseline_element_type(type(x))
  • dequantize กำหนดไว้ในประเภท Tensor และเปลี่ยนให้เป็น ประเภท Tensor จุดลอยตัว ซึ่งเกิดขึ้นผ่านการแปลงองค์ประกอบที่เล็กลง ซึ่งจะแสดงค่าจำนวนเต็มของประเภทพื้นที่เก็บข้อมูลให้สอดคล้องกับ ค่าจุดลอยตัวของประเภทที่แสดงโดยใช้จุดเป็นศูนย์และมาตราส่วน ที่เชื่อมโยงกับประเภทองค์ประกอบที่เล็กลง
def compute_zero_points(quantized_type, result_type):
  if is_per_tensor_quantized(quantized_type):
    return broadcast_in_dim(constant(zero_point(quantized_type), storage_type(quantized_type)), [], result_type)
  if is_per_axis_quantized(quantized_type):
    for i in index_space(result_type):
      d = quantization_dimension(quantized_type)
      zero_points[i] = zero_points(quantized_type)[i[d]]
    return zero_points

def compute_scales(quantized_type, result_type):
  if is_per_tensor_quantized(quantized_type):
    return broadcast_in_dim(constant(scale(quantized_type), expressed_type(quantized_type)), [],
            type(result_type))
  if is_per_axis_quantized(quantized_type):
    for i in index_space(result_type):
      d = quantization_dimension(quantized_type)
      scales[i] = scales(quantized_type)[i[d]]
    return scales

def dequantize(x: Value) -> Value:
  assert is_quantized(x)
  x_storage = bitcast_convert(x, storage_type(x))
  x_storage_sub = x_storage - compute_zero_points(type(x), type(x_storage))
  x_expressed_sub = convert(x_storage_sub, expressed_type(x))
  return x_expressed_sub * compute_scales(type(x), type(x_expressed_sub))
  • quantize กำหนดไว้ในประเภท Tensor จุดลอยตัวและเปลี่ยนให้เป็น ประเภท Tensor ที่เล็กลง ซึ่งเกิดขึ้นผ่านการแปลงค่าทศนิยม ของประเภทที่ระบุให้เป็นค่าจำนวนเต็มที่สอดคล้องของประเภทพื้นที่เก็บข้อมูล โดยใช้จุดเป็นศูนย์และมาตราส่วนที่เชื่อมโยงกับประเภทองค์ประกอบที่เล็กลง
def quantize(x: Value, result_type: Type) -> Value:
  assert is_float(x) and is_quantized(result_type)
  zero_points = compute_zero_points(result_type, TensorType(shape(x), storage_type(result_type)))
  converted_zero_points = convert(zero_points, expressed_type(result_type))
  converted_min = convert(storage_min(result_type), expressed_type(result_type))
  converted_max = convert(storage_max(result_type), expressed_type(result_type))

  x_scaled = x / compute_scales(result_type, type(x))
  x_scaled_add_zp = x_scaled + converted_zero_points
  x_clamped = clamp(converted_min, x_scaled_add_zp, converted_max)
  x_rounded = round_nearest_even(x_clamped)
  return convert(x_rounded, result_type)
  • dequantize_op_quantize ใช้เพื่อระบุการคำนวณระดับองค์ประกอบใน Tensor วัดปริมาณค่า กล่าวคือ เปลี่ยนธาตุที่เป็นจำนวนมหาศาลให้เป็นหน่วยวัด ประเภทที่แสดง แล้วดำเนินการ จากนั้นจึงวัดปริมาณ ซึ่งก็คือการเลี้ยว ผลลัพธ์กลับเข้าไปในประเภทพื้นที่เก็บข้อมูล ตอนนี้ ฟังก์ชันนี้เท่านั้น เหมาะสำหรับการวัดปริมาณแบบต่อ Tensor การวัดขนาดต่อแกนอยู่ระหว่างดำเนินการ (#1574)
def dequantize_op_quantize(op, *inputs_and_output_type):
  inputs = inputs_and_output_type[:-1]
  output_type = inputs_and_output_type[-1]

  float_inputs = map(dequantize, inputs)
  float_result = op(*float_inputs)
  return quantize(float_result, output_type)

def dequantize_batch_norm_grad_or_training_quantize(op, *inputs_and_output_types):
  inputs = inputs_and_output_type[:-3]
  float_inputs = map(dequantize, inputs)
  float_results = op(*float_inputs)
  return map(quantize, float_results, inputs_and_output_type[-3:])

def dequantize_compare(lhs, rhs, comparison_direction):
  float_lhs = dequantize(lhs)
  float_rhs = dequantize(rhs)
  return compare(float_lhs, float_rhs, comparison_direction, FLOAT)

def dequantize_select_quantize(pred, on_true, on_false, output_type):
  float_on_true = dequantize(on_true)
  float_on_false = dequantize(on_false)
  float_result = select(pred, float_on_true, float_on_false)
  return quantize(float_result, output_type)
  • hybrid_dequantize_then_op ใช้เพื่อระบุการแปลงค่าตามน้ำหนักเท่านั้นสำหรับ ตัวเลือกแบบผสมที่ยอมรับ lhs ในจุดลอยตัวและ rhs ในประเภทที่เล็กลง ทั้งนี้ วัดปริมาณอินพุตที่แปลงแล้วให้เป็นประเภทที่แสดงผล และดำเนินการคำนวณ แบบลอย ประเภทองค์ประกอบของ Float lhs tensor และประเภท rhs แบบควอนไทล์ที่แสดง Tensor ควรเหมือนกัน
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 โปรดดู &quot;cross_replica_and_partition&quot; ที่ด้านบน

  • flattened_ids(replica_groups: Value) -> Value ดู "flattened_ids" ที่ด้านบน

ความคิดวิพากษ์วิจารณ์

ค่า HLO เวอร์ชันเสถียรอาจมีขนาดมิติข้อมูลแบบไดนามิกได้ เช่น 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
}

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

รูปร่างไม่ตรงกันสำหรับการดำเนินการที่นำรูปร่างเอาต์พุตเป็นโอเปอแรนด์

ลองพิจารณาโปรแกรมของเล่นต่อไปนี้

func.func @foo(%arg0: tensor<2xi32>) {
  %0 = stablehlo.dynamic_iota %arg0, dim = 0 : (tensor<2xi32>) -> tensor<3x4xi64>
  return
}

ค่าในตัวถูกดำเนินการรูปร่างขณะรันไทม์ต้องตรงกับรูปร่างของผลลัพธ์ มิเช่นนั้น ระบบจะไม่ระบุลักษณะการทำงาน กล่าวคือ ในระหว่างรันไทม์ %arg0 ต้องมีแอตทริบิวต์ เป็น dense<[3, 4]> : tensor<2xi32> ถ้าตัวถูกดำเนินการรูปร่างคงที่ สามารถยืนยันแบบคงที่ได้ หากรูปทรงของผลลัพธ์เป็นแบบไดนามิกเต็มรูปแบบ จะต้องไม่ใช่ข้อมูลที่ไม่ตรงกัน