Thông số kỹ thuật của StableHLO

StableHLO là một tập hợp thao tác cho các hoạt động cấp cao (HLO) trong máy mô hình học máy (ML). StableHLO hoạt động như một lớp di chuyển giữa các cấu hình Khung học máy và trình biên dịch học máy: các khung học máy tạo ra chương trình ổn định HLO tương thích với các trình biên dịch ML sử dụng các chương trình StableHLO.

Mục tiêu của chúng tôi là đơn giản hoá và đẩy nhanh quá trình phát triển công nghệ học máy bằng cách tạo ra Khả năng tương tác giữa nhiều khung máy học (chẳng hạn như TensorFlow, JAX và PyTorch) và trình biên dịch ML (chẳng hạn như XLA và IREE). Để đạt được mục tiêu này, cung cấp thông số kỹ thuật cho ngôn ngữ lập trình StableHLO.

Bản đặc tả này bao gồm ba phần chính. Đầu tiên, Phần Programs (Chương trình) mô tả cấu trúc của các chương trình StableHLO bao gồm các hàm StableHLO mà bản thân nó bao gồm các hoạt động ổn định HLO. Trong cấu trúc đó, phần Ops chỉ định ngữ nghĩa của hoạt động riêng lẻ. Phần Execution (Thực thi) cung cấp ngữ nghĩa cho tất cả các hoạt động này thực thi cùng nhau trong một chương trình. Cuối cùng, Phần Ký hiệu thảo luận về ký hiệu được sử dụng trong toàn bộ phần đặc điểm kỹ thuật.

Để xem thông số kỹ thuật của bản phát hành StableHLO trước, hãy mở kho lưu trữ tại bản phát hành được gắn thẻ mà bạn quan tâm. Ví dụ: StableHLO v0.19.0 Spec. Để xem những thay đổi xảy ra ở mỗi lần tăng phiên bản nhỏ của StableHLO, hãy tham khảo nhật ký phiên bản trong VhloDialect.td.

Chương trình

Program ::= {Func}

Chương trình ổn định HLO bao gồm một số lượng hàm ổn định HLO tuỳ ý. Dưới đây là một chương trình mẫu có hàm @main có 3 dữ liệu đầu vào (%image, %weights%bias) và 1 đầu ra. Phần nội dung của hàm có 6 hoạt động.

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>) -> ()
}

Hàm

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

Các hàm ổn định (còn được gọi là hàm được đặt tên) có giá trị nhận dạng, đầu vào/đầu ra và nội dung. Trong tương lai, chúng tôi dự định giới thiệu siêu dữ liệu bổ sung cho các hàm để đạt được khả năng tương thích tốt hơn với HLO (#425, #626, #740 #744).

Giá trị nhận dạng

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

Giá trị nhận dạng ổn địnhHLO tương tự như giá trị nhận dạng trong nhiều chương trình ngôn ngữ, với hai đặc điểm: 1) tất cả các giá trị nhận dạng đều có các dấu hiệu phân biệt các loại mã nhận dạng khác nhau, 2) mã nhận dạng giá trị hoàn toàn bằng số để đơn giản hoá việc tạo chương trình StableHLO.

Loại

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

Loại HLO ổn định được phân loại thành các loại giá trị (còn được gọi là loại đầu tiên) đại diện cho giá trị ổn định HLO và loại không có giá trị mô tả các yếu tố khác của chương trình. Các kiểu ổn địnhHLO tương tự như các kiểu trong nhiều ngôn ngữ lập trình, với đặc điểm chính là tính chất đặc thù theo miền, dẫn đến một số kết quả bất thường (ví dụ: các kiểu vô hướng không phải là loại giá trị).

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

Các loại tensor đại diện cho tensor, tức là mảng đa chiều. Họ có hình dạngloại phần tử, trong đó một hình dạng đại diện cho không âm hoặc kích thước thứ nguyên không xác định theo thứ tự tăng dần của kích thước tương ứng kích thước (còn được gọi là trục) được đánh số từ 0 đến R-1. Chiến lược phát hành đĩa đơn số lượng phương diện R được gọi là thứ hạng. Ví dụ: tensor<2x3xf32> là loại tensor có hình dạng 2x3 và loại phần tử f32. Nó có hai chiều (hoặc, nói cách khác là hai trục) - chiều thứ 0 và chiều thứ 1 - có kích thước là 2 và 3. Thứ hạng của nó là 2.

Hình dạng có thể không xác định được một phần hoặc hoàn toàn (động), ví dụ: tensor<?x2xf64> chưa xác định được một phần và tensor<?x?xf64> hoàn toàn không xác định. Động kích thước kích thước được biểu thị bằng ?. Không thể huỷ xếp hạng hình dạng.

Trong tương lai, chúng tôi dự định khám phá việc mở rộng các loại tensor ngoài kích thước kích thước và loại phần tử, ví dụ: để bao gồm bố cục (#629) và độ thưa (#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
Tên Loại Giới hạn
storage_type kiểu số nguyên (C1–C3), (C8)
storage_min hằng số nguyên (C1), (C3), (C7)
storage_max hằng số nguyên (C2), (C3), (C7)
expressed_type loại dấu phẩy động (C4)
quantization_dimension hằng số nguyên không bắt buộc (C10–C12)
scales số đại lượng hằng số dấu phẩy động (C4-C6), (C9), (C10), (C13)
zero_points số đại lượng của hằng số nguyên (C7–C9)

Các loại phần tử được định lượng biểu thị các giá trị số nguyên của một loại bộ nhớ trong phạm vi từ storage_min đến storage_max (bao gồm) tương ứng với giá trị dấu phẩy động thuộc một kiểu được biểu thị. Đối với một giá trị số nguyên đã cho i, giá trị dấu phẩy động tương ứng f có thể được tính là f = (i - zero_point) * scale, trong đó scalezero_point được gọi tham số lượng tử. storage_minstorage_max là không bắt buộc trong ngữ pháp, nhưng có các giá trị mặc định là min_value(storage_type)max_value(storage_type). Các loại phần tử lượng tử hoá có những hạn chế sau:

  • (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) Nếu là is_empty(quantization_dimension), thì size(scales) = 1.
  • (C11) 0 <= quantization_dimension.

Hiện tại, QuantizationScale là hằng số dấu phẩy động, nhưng có rất quan tâm đến thang đo số nguyên, được thể hiện bằng hệ số nhân và ca. Chúng tôi dự định sẽ khám phá tính năng này trong thời gian sắp tới (#1404).

Hiện đang có một cuộc thảo luận về ngữ nghĩa của QuantizationZeroPoint, bao gồm loại, giá trị và liệu có thể chỉ có một hoặc có khả năng có nhiều điểm 0 trong loại tensor lượng tử hoá. Dựa trên kết quả của cuộc thảo luận này, quy cách về điểm 0 có thể thay đổi trong tương lai (#1405).

Một cuộc thảo luận đang diễn ra khác liên quan đến ngữ nghĩa của QuantizationStorageMinQuantizationStorageMax để xác định xem có bất kỳ điều kiện ràng buộc nào hay không đặt lên các giá trị này và trên các giá trị tensor lượng tử hoá (#1406).

Cuối cùng, chúng tôi dự định khám phá đại diện cho các thang đo chưa biết và số không tương tự như cách chúng ta dự định khám phá cách đại diện cho những giá trị chưa biết kích thước kích thước (#1407).

Các loại tensor lượng tử hoá biểu thị các tensor với các phần tử lượng tử hoá. Các tensor này hoàn toàn giống như tensor thông thường, ngoại trừ các phần tử của chúng có loại phần tử lượng tử hoá, thay vì loại phần tử thông thường.

Trong tensor lượng tử hoá, lượng tử hoá có thể theo mỗi tensor, nghĩa là có một scalezero_point cho toàn bộ tensor hoặc có thể là mỗi trục, tức là có nhiều scaleszero_points, một cặp trên mỗi lát cắt của một tham số cụ thể quantization_dimension. Trang trọng hơn khi dùng tensor t với lượng tử hoá theo mỗi trục, có dim(t, quantization_dimension) lát cắt trong quantization_dimension: t[:, ..., 0, ..., :], t[:, ..., 1, ..., :], Tất cả các phần tử trong lát i sử dụng scales[i]zero_points[i] làm các tham số lượng tử của chúng. Sau đây là các loại tensor lượng tử hoá quy tắc ràng buộc:

  • Đối với lượng tử mỗi tensor:
    • Không có hạn chế bổ sung.
  • Đối với lượng tử trên mỗi trục:
    • (C12) quantization_dimension < rank(self).
    • (C13) dim(self, quantization_dimension) = size(scales).
TokenType ::= 'token'

Loại mã thông báo đại diện cho mã thông báo, tức là các giá trị mờ được tạo ra và tiêu thụ thực hiện một số phép toán. Mã thông báo được dùng để áp đặt thứ tự thực thi cho các thao tác như được mô tả trong phần Thực thi.

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

Loại bộ dữ liệu đại diện cho bộ dữ liệu, tức là danh sách không đồng nhất. Cặp đôi là di sản chỉ tồn tại để tương thích với HLO. Trong HLO, các bộ dữ liệu là được dùng để biểu thị nhiều giá trị đầu vào và đầu ra. Trong StableHLO, dữ liệu đầu vào đa dạng và đầu ra được hỗ trợ nguyên gốc và việc sử dụng duy nhất các bộ dữ liệu trong StableHLO là thể hiện toàn diện ABI HLO, ví dụ: T, tuple<T>tuple<tuple<T>> có thể khác nhau đáng kể tuỳ thuộc vào một trong quá trình triển khai. Trong tương lai, chúng tôi dự định sẽ thay đổi ABI HLO tính năng này có thể cho phép chúng ta xoá các loại bộ dữ liệu khỏi 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'

Loại phần tử đại diện cho phần tử thuộc loại tensor. Không giống như trong nhiều chương trình các loại này không phải là lớp đầu tiên trong StableHLO. Điều này có nghĩa là Các chương trình ổn định HLO không thể biểu diễn trực tiếp giá trị của các loại này (do đó, thì gọi là biểu diễn các giá trị vô hướng thuộc loại T bằng tensor 0 chiều thuộc loại tensor<T>).

  • Kiểu Boolean biểu thị các giá trị boolean truefalse.
  • Loại số nguyên có thể là đã ký (si) hoặc chưa ký (ui) và có một trong các độ rộng bit được hỗ trợ (2, 4, 8, 16, 32 hoặc 64). Loại siN đã ký biểu thị các giá trị số nguyên từ -2^(N-1) đến 2^(N-1)-1 các loại uiN không dấu biểu thị các giá trị số nguyên từ 0 đến 2^N-1.
  • Loại dấu phẩy động có thể là một trong các loại sau:
  • Kiểu phức tạp biểu thị các giá trị phức có phần thực và một phần ảo thuộc cùng một loại phần tử. Khu phức hợp được hỗ trợ loại là complex<f32> (cả hai phần đều thuộc loại f32) và complex<f64> (cả hai phần đều thuộc loại f64).
FunctionType ::= '(' InputTypes ')' '->' '(' OutputTypes ')'
InputTypes ::= [ValueType {',' ValueType}]
OutputTypes ::= [ValueType {',' ValueType}]

Loại hàm đại diện cho cả hàm được đặt tên và hàm ẩn danh. Chúng có loại đầu vào (danh sách các loại ở bên trái của ->) và loại đầu ra (danh sách các loại ở bên phải ->). Trong nhiều chương trình ngôn ngữ, loại hàm là lớp đầu tiên, nhưng không phải trong StableHLO.

StringType ::= 'string'

Loại chuỗi biểu thị chuỗi byte. Không giống như trong nhiều chương trình ngôn ngữ, loại chuỗi không phải là lớp đầu tiên trong StableHLO và chỉ được dùng để chỉ định siêu dữ liệu tĩnh cho các phần tử của chương trình.

Hoạt động tính toán

Hoạt động ổn định HLO (còn được gọi là hoạt động) biểu thị một tập hợp khép kín các thao tác cấp cao trong các mô hình học máy. Như đã thảo luận ở trên, Cú pháp StableHLO chủ yếu lấy cảm hứng từ MLIR, không nhất thiết là giải pháp thay thế công thái học, nhưng được cho là phù hợp nhất cho mục tiêu của StableHLO là tăng khả năng tương tác giữa các khung ML và trình biên dịch ML.

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

Hoạt động ổn địnhHLO (còn được gọi là hoạt động) đều có tên, đầu vào/đầu ra và chữ ký. Tên này bao gồm tiền tố stablehlo. và một ký tự xác định duy nhất một trong các hoạt động được hỗ trợ. Xem bên dưới để biết danh sách đầy đủ tất cả hoạt động được hỗ trợ.

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

Các hoạt động sử dụng đầu vào và tạo ra đầu ra. Dữ liệu đầu vào được phân loại thành giá trị đầu vào (được tính trong quá trình thực thi), hàm đầu vào (được cung cấp tĩnh, vì trong các hàm StableHLO không phải là giá trị hạng nhất) và đầu vào (cũng được cung cấp cố định). Loại dữ liệu đầu vào và đầu ra được tiêu thụ và sản xuất bởi một op phụ thuộc vào khả năng ghi nhớ của nó. Ví dụ: add op sử dụng 2 giá trị đầu vào và tạo ra 1 giá trị đầu ra. So với, Hoạt động select_and_scatter sử dụng 3 giá trị đầu vào, 2 hàm đầu vào và 3 thuộc tính đầu vào.

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

Các hàm đầu vào (còn được gọi là hàm ẩn danh) rất tương tự như các hàm được đặt tên, ngoại trừ: 1) chúng không có giá trị nhận dạng (do đó có tên "anonymous"), 2) thẻ không khai báo loại đầu ra (loại đầu ra là suy ra từ hoạt động return trong hàm).

Cú pháp cho các hàm đầu vào bao gồm một phần hiện chưa được sử dụng (xem Unused chính thức ở trên), có khả năng tương thích với MLIR. Trong MLIR, có một khái niệm chung hơn là "khu vực" có thể có nhiều "chặn" gồm các hoạt động được kết nối với nhau thông qua hoạt động nhảy. Các khối này có mã nhận dạng tương ứng đối với phiên bản chính thức Unused để có thể phân biệt chúng với nhau. StableHLO không có hoạt động nhảy, vì vậy, phần tương ứng của cú pháp MLIR là chưa được sử dụng (nhưng vẫn còn đó).

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

Thuộc tính đầu vào có tên và giá trị là một trong những thuộc tính được hỗ trợ hằng số. Thẻ Google là phương thức chính để chỉ định siêu dữ liệu tĩnh cho chương trình phần tử. Ví dụ: hoạt động concatenate sử dụng thuộc tính dimension để chỉ định phương diện nối các giá trị đầu vào của phương diện đó. Tương tự, hoạt động slice sử dụng nhiều thuộc tính như start_indiceslimit_indices để chỉ định các giới hạn dùng để cắt giá trị đầu vào.

Hiện tại, các chương trình StableHLO trong môi trường tự nhiên đôi khi có chứa các thuộc tính không được mô tả trong tài liệu này. Trong tương lai, chúng tôi dự định hấp thụ các thuộc tính này vào hệ thống StableHLO hoặc cấm chúng xuất hiện trong chương trình StableHLO. Trong lúc đó, đây là danh sách thuộc tính:

  • layout (#629).
  • mhlo.frontend_attributes (#628).
  • mhlo.sharding (#619).
  • output_operand_aliases (#740).
  • Siêu dữ liệu vị trí (#594).
OpSignature ::= '(' [ValueType {',' ValueType}] ')' '->' '(' [ValueType {',' ValueType}] ')'

Chữ ký Op bao gồm các loại của tất cả giá trị đầu vào (danh sách các loại trên phần bên trái của ->) và loại của tất cả giá trị đầu ra (danh sách ở bên phải ->). Nói một cách chính xác, các loại dữ liệu đầu vào dư thừa và các loại đầu ra hầu như cũng luôn thừa (vì đối với hầu hết các hoạt động ổn định HLO, loại đầu ra có thể được suy ra từ dữ liệu đầu vào). Tuy nhiên, vận hành chữ ký là một phần có chủ ý của cú pháp StableHLO để tương thích với MLIR.

Dưới đây là một ví dụ về op có ghi nhớ là select_and_scatter. Chiến dịch này tiêu thụ 3 giá trị đầu vào (%operand, %source%init_value), 2 hàm đầu vào và 3 thuộc tính đầu vào (window_dimensions, window_stridespadding). Lưu ý rằng chữ ký của op chỉ bao gồm các loại giá trị đầu vào của nó (nhưng không phải là loại hàm và thuộc tính đầu vào được cung cấp cùng dòng).

%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>

Hằng số

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

Hằng số ổn địnhHLO có một giá trị cố định và một kiểu cùng biểu thị giá trị StableHLO. Thông thường, kiểu dữ liệu này là một phần của cú pháp hằng số, ngoại trừ khi không rõ ràng (ví dụ: hằng số boolean rõ ràng có loại i1, trong khi hằng số nguyên có thể có nhiều kiểu).

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

Hằng số boolean biểu thị các giá trị boolean truefalse. Boolean (logic) hằng số có kiểu i1.

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

Hằng số số biểu thị giá trị số nguyên thông qua các chuỗi sử dụng số thập phân hoặc ký hiệu thập lục phân. Các cơ sở khác, ví dụ: nhị phân hoặc bát phân, không được hỗ trợ. Hằng số nguyên có các hạn chế sau:

  • (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]

Hằng số dấu phẩy động biểu thị các giá trị dấu phẩy động thông qua các chuỗi sử dụng ký hiệu thập phân hoặc khoa học. Ngoài ra, ký hiệu thập lục phân có thể là được dùng để chỉ định trực tiếp các bit cơ bản ở định dạng dấu phẩy động của loại tương ứng. Hằng số dấu phẩy động có các hạn chế sau:

  • (C1) Nếu sử dụng ký hiệu không phải thập lục phân, is_wellformed(float_literal, float_type).
  • (C2) Nếu sử dụng ký hiệu thập lục phân, size(hexadecimal_digits) = num_bits(float_type) / 4.
ComplexConstant ::= ComplexLiteral ':' ComplexType
ComplexLiteral  ::= '(' RealPart ',' ImaginaryPart ')'
RealPart        ::= FloatLiteral
ImaginaryPart   ::= FloatLiteral

Hằng số phức tạp biểu thị các giá trị phức tạp bằng cách sử dụng danh sách phần thực (đến trước) và phần tưởng tượng (đến sau). Ví dụ: (1.0, 0.0) : complex<f32> đại diện cho 1.0 + 0.0i(0.0, 1.0) : complex<f32> đại diện cho 0.0 + 1.0i. Thứ tự trong đó sau đó các phần được lưu trữ trong bộ nhớ sẽ được triển khai xác định. Hằng số phức tạp có những hạn chế sau:

  • (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

Hằng số tensor biểu thị các giá trị tensor bằng cách sử dụng các danh sách lồng nhau được chỉ định qua Ký hiệu NumPy. Ví dụ: dense<[[1, 2, 3], [4, 5, 6]]> : tensor<2x3xi32> biểu thị một giá trị tensor với ánh xạ sau từ chỉ mục đến các phần tử: {0, 0} => 1, {0, 1} => 2, {0, 2} => 3, {1, 0} => 4, {1, 1} => 5, {1, 2} => 6. Sau đó, thứ tự lưu trữ các phần tử này trong bộ nhớ là do triển khai xác định. Hằng số Tensor có các hạn chế sau:

  • (C1) has_syntax(tensor_literal, element_type(tensor_type)), trong đó:
    • 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)), trong đó:
    • 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:]).
    • nếu không thì false.
QuantizedTensorConstant ::= QuantizedTensorLiteral ':' QuantizedTensorType
QuantizedTensorLiteral  ::= 'dense' '<' (DenseLiteral | ElementLiteral) '>'

Hằng số tensor lượng tử hoá biểu thị các giá trị tensor lượng tử hoá bằng cách sử dụng cùng ký hiệu dưới dạng hằng số tensor, với các phần tử được chỉ định là hằng số loại bộ nhớ. Hằng số tensor lượng tử hoá có các hạn chế sau:

  • (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))

Hằng chuỗi bao gồm các byte được chỉ định bằng ký tự ASCII và chuỗi ký tự thoát. Các thuật ngữ này không phụ thuộc vào mã hoá, nên việc diễn giải những thuật ngữ này byte sẽ được triển khai xác định. Hằng chuỗi có kiểu string.

Hoạt động

bụng

Ngữ nghĩa

Thực hiện phép toán abs đa dạng trên tensor operand và tạo ra một result tensor. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với số nguyên có dấu: mô-đun số nguyên.
  • Đối với số thực độ chính xác đơn: abs từ IEEE-754.
  • Đối với số phức: mô-đun phức.
  • Đối với các kiểu lượng tử hoá: dequantize_op_quantize(abs, operand, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor của số nguyên có dấu, dấu phẩy động hoặc kiểu phức hoặc tensor lượng tử hoá mỗi tensor (C1–C2)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của loại số nguyên có dấu hoặc dấu phẩy động hoặc tensor lượng tử hoá mỗi tensor (C1–C2)

Giới hạn

  • (C1) shape(result) = shape(operand).
  • (C2) baseline_element_type(result) được định nghĩa là:
    • complex_element_type(element_type(operand)) nếu is_complex(operand).
    • baseline_element_type(operand).

Ví dụ

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

Ví dụ khác

thêm

Ngữ nghĩa

Thực hiện phép cộng theo từng phần tử của hai tensor lhsrhs và tạo ra một Tensor result. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với boolean: logic OR.
  • Đối với số nguyên: phép cộng số nguyên.
  • Đối với số thực độ chính xác đơn: addition từ IEEE-754.
  • Đối với số phức: phép cộng phức.
  • Đối với các kiểu lượng tử hoá: dequantize_op_quantize(add, lhs, rhs, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) lhs tensor hoặc tensor lượng tử hoá (C1–C6)
(I2) rhs tensor hoặc tensor lượng tử hoá (C1–C5), (C7)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá (C1–C7)

Giới hạn

  • Nếu phép toán sử dụng tensor không lượng tử hoá:
    • (C1) type(lhs) = type(rhs) = type(result).
  • Nếu thao tác này sử dụng tensor lượng tử hoá:
    • (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) Nếu là is_per_axis_quantized(lhs), thì quantization_dimension(lhs) = quantization_dimension(result).
    • (C7) Nếu là is_per_axis_quantized(rhs), thì quantization_dimension(rhs) = quantization_dimension(result).

Ví dụ

// %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]]

Ví dụ khác

after_all

Ngữ nghĩa

Đảm bảo rằng các thao tác tạo ra inputs được thực thi trước khi bất kỳ các toán tử phụ thuộc vào result. Việc thực thi thao tác này không ảnh hưởng gì đến nó chỉ tồn tại để thiết lập các phần phụ thuộc dữ liệu từ result đến inputs.

Thông tin đầu vào

Hãng nhạc Tên Loại
(I1) inputs số biến thiên token

Kết quả đầu ra

Tên Loại
result token

Ví dụ

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

Ví dụ khác

all_gather

Ngữ nghĩa

Trong mỗi nhóm quy trình ở lưới quy trình StableHLO, hãy nối các giá trị trong số tensor operands từ mỗi quá trình dọc theo all_gather_dim và tạo ra Các tensor results.

Thao tác này sẽ chia lưới quy trình StableHLO thành process_groups, tức là được xác định như sau:

  • cross_replica(replica_groups) nếu channel_id <= 0 and use_global_device_ids = false.
  • cross_replica_and_partition(replica_groups) nếu channel_id > 0 and use_global_device_ids = false.
  • flattened_ids(replica_groups) nếu channel_id > 0 and use_global_device_ids = true.

Sau đó, trong mỗi process_group:

  • operands...@receiver = [operand@sender for sender in process_group] cho tất cả receiver trong process_group.
  • results...@process = concatenate(operands...@process, all_gather_dim) cho tất cả process trong process_group.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operands số biến thiên của tensor hoặc tensor lượng tử hoá mỗi tensor (C1), (C6)
(I2) all_gather_dim hằng số loại si64 (C1), (C6)
(I3) replica_groups Hằng số tensor 2 chiều thuộc loại si64 (C2–C4)
(I4) channel_id hằng số loại si64 (C5)
(I5) use_global_device_ids hằng số loại i1 (C5)

Kết quả đầu ra

Tên Loại Giới hạn
results số biến thiên của tensor hoặc tensor lượng tử hoá mỗi tensor (C6)

Giới hạn

  • (C1) 0 <= all_gather_dim < rank(operands...).
  • (C2) is_unique(replica_groups).
  • (C3) size(replica_groups) được định nghĩa là:
    • num_replicas nếu dùng cross_replica.
    • num_replicas nếu dùng cross_replica_and_partition.
    • num_processes nếu dùng flattened_ids.
  • (C4) 0 <= replica_groups < size(replica_groups).
  • (C5) Nếu là use_global_device_ids = true, thì channel_id > 0.
  • (C6) type(results...) = type(operands...) ngoại trừ:
    • dim(results..., all_gather_dim) = dim(operands..., all_gather_dim) * dim(process_groups, 1).

Ví dụ

// 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]]

Ví dụ khác

all_reduce

Ngữ nghĩa

Trong mỗi nhóm quy trình ở lưới quy trình StableHLO, hãy áp dụng mức giảm hàm computation thành các giá trị của tensor operands trong mỗi tiến trình và tạo ra tensor results.

Thao tác này sẽ chia lưới quy trình StableHLO thành process_groups, tức là được xác định như sau:

  • cross_replica(replica_groups) nếu channel_id <= 0 and use_global_device_ids = false.
  • cross_replica_and_partition(replica_groups) nếu channel_id > 0 and use_global_device_ids = false.
  • flattened_ids(replica_groups) nếu channel_id > 0 and use_global_device_ids = true.

Sau đó, trong mỗi process_group:

  • results...@process[result_index] = exec(schedule) cho một số cây nhị phân schedule trong đó:
    • exec(node) = computation(exec(node.left), exec(node.right)).
    • exec(leaf) = leaf.value.
  • schedule là cây nhị phân do triển khai xác định có theo thứ tự truyền tải là to_destination_type(operands...@process_group...[result_index], type(func_inputs(computation)[0])).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operands số biến thiên của tensor hoặc tensor lượng tử hoá mỗi tensor (C5), (C6)
(I2) replica_groups số biến thiên của hằng số tensor 1 chiều thuộc loại si64 (C1–C3)
(I3) channel_id hằng số loại si64 (C4)
(I4) use_global_device_ids hằng số loại i1 (C4)
(I5) computation hàm (C5)

Kết quả đầu ra

Tên Loại Giới hạn
results số biến thiên của tensor hoặc tensor lượng tử hoá mỗi tensor (C6–C7)

Giới hạn

  • (C1) is_unique(replica_groups).
  • (C2) size(replica_groups) được định nghĩa là:
    • num_replicas nếu dùng cross_replica.
    • num_replicas nếu dùng cross_replica_and_partition.
    • num_processes nếu dùng flattened_ids.
  • (C3) 0 <= replica_groups < size(replica_groups).
  • (C4) Nếu là use_global_device_ids = true, thì channel_id > 0.
  • (C5) computation có loại (tensor<E>, tensor<E>) -> (tensor<E>) trong đó is_promotable(element_type(operand), E).
  • (C6) shape(results...) = shape(operands...).
  • (C7) element_type(results...) = E.

Ví dụ

// 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]

Ví dụ khác

all_to_all

Ngữ nghĩa

all_to_all

Trong mỗi nhóm quy trình ở lưới quy trình StableHLO, chia tách các giá trị của các tensor operands dọc theo split_dimension thành các phần, phân tán phần phân tách các phần giữa các quy trình, nối các phần nằm rải rác dọc theo concat_dimension và tạo ra tensor results. Thao tác này sẽ chia lưới quy trình StableHLO thành process_groups, tức là được xác định như sau:

  • cross_replica(replica_groups) nếu channel_id <= 0.
  • cross_partition(replica_groups) nếu channel_id > 0.

Sau đó, trong mỗi process_group:

  • split_parts...@sender = split(operands...@sender, split_count, split_dimension) cho tất cả sender trong process_group.
  • scattered_parts...@receiver = [split_parts...@sender[receiver_index] for sender in process_group] trong đó receiver_index = process_group.index(receiver)
  • results...@process = concatenate(scattered_parts...@process, concat_dimension).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operands số biến thiên của tensor hoặc tensor lượng tử hoá mỗi tensor (C1–C3), (C9)
(I2) split_dimension hằng số loại si64 (C1), (C2), (C9)
(I3) concat_dimension hằng số loại si64 (C3), (C9)
(I4) split_count hằng số loại si64 (C2), (C4), (C8), (C9)
(I5) replica_groups Hằng số tensor 2 chiều thuộc loại si64 (C5–C8)
(I6) channel_id hằng số loại si64

Kết quả đầu ra

Tên Loại Giới hạn
results số biến thiên của tensor hoặc tensor lượng tử hoá mỗi tensor (C9)

Giới hạn

  • (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) được định nghĩa là:
    • num_replicas nếu dùng cross_replica.
    • num_partitions nếu dùng cross_partition.
  • (C7) 0 <= replica_groups < size(replica_groups).
  • (C8) dim(replica_groups, 1) = split_count.
  • (C9) type(results...) = type(operands...) ngoại trừ nếu split_dimension != concat_dimension:
    • dim(results..., split_dimension) = dim(operands..., split_dimension) / split_count.
    • dim(results..., concat_dimension) = dim(operands..., concat_dimension) * split_count.

Ví dụ

// 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]]

Ví dụ khác

Ngữ nghĩa

Thực hiện cấu trúc phần tử AND của hai tensor lhsrhs và tạo ra một result tensor. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với boolean: logic AND.
  • Đối với số nguyên: thao tác bit AND.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) lhs tensor của boolean hoặc kiểu số nguyên (C1)
(I2) rhs tensor của boolean hoặc kiểu số nguyên (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của boolean hoặc kiểu số nguyên (C1)

Giới hạn

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

Ví dụ

// %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]]

Ví dụ khác

atan2

Ngữ nghĩa

Thực hiện toán tử atan2 thông minh trên tensor lhsrhs và tạo ra một Tensor result. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với số thực độ chính xác đơn: atan2 từ IEEE-754.
  • Đối với số phức: phức atan2.
  • Đối với các kiểu lượng tử hoá: dequantize_op_quantize(atan2, lhs, rhs, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) lhs tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)
(I2) rhs tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]

Ví dụ khác

batch_norm_grad

Ngữ nghĩa

Tính toán độ dốc của một số đầu vào của batch_norm_training lan truyền ngược từ grad_output và tạo grad_operand, grad_scalegrad_offset tensor. Một cách chính thức hơn, thao tác này có thể được biểu thị dưới dạng quá trình phân tách để các hoạt động ổn định hiện có bằng cú pháp Python như sau:

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

Đối với các kiểu lượng tử hoá, 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)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor loại dấu phẩy động hoặc tensor lượng tử hoá mỗi tensor (C1–C3), (C5)
(I2) scale Tensor 1 chiều của loại lượng tử hoá theo dấu phẩy động hoặc mỗi tensor (C2), (C4), (C5)
(I3) mean Tensor 1 chiều của loại lượng tử hoá theo dấu phẩy động hoặc mỗi tensor (C2), (C4)
(I4) variance Tensor 1 chiều của loại lượng tử hoá theo dấu phẩy động hoặc mỗi tensor (C2), (C4)
(I5) grad_output tensor loại dấu phẩy động hoặc tensor lượng tử hoá mỗi tensor (C2), (C3)
(I6) epsilon hằng số loại f32
(I7) feature_index hằng số loại si64 (C1), (C5)

Kết quả đầu ra

Tên Loại Giới hạn
grad_operand tensor loại dấu phẩy động hoặc tensor lượng tử hoá mỗi tensor (C2), (C3)
grad_scale Tensor 1 chiều của loại lượng tử hoá theo dấu phẩy động hoặc mỗi tensor (C2), (C4)
grad_offset Tensor 1 chiều của loại lượng tử hoá theo dấu phẩy động hoặc mỗi tensor (C2), (C4)

Giới hạn

  • (C1) 0 <= feature_index < rank(operand).
  • (C2) operand, scale, mean, variance, grad_output, grad_operand, grad_scalegrad_offset có cùng baseline_element_type.
  • (C3) operand, grad_outputgrad_operand có cùng hình dạng.
  • (C4) scale, mean, variance, grad_scalegrad_offset có cùng một hình dạng.
  • (C5) size(scale) = dim(operand, feature_index).

Ví dụ

// %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

Ngữ nghĩa

Chuẩn hoá tensor operand trên tất cả các chiều, ngoại trừ chiều feature_index và tạo ra một tensor result. Chính thức hơn, đây là có thể được biểu thị dưới dạng quá trình phân ly đối với các toán tử ổn định hiện có sử dụng cú pháp Python như sau:

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)

Đối với các kiểu lượng tử hoá, 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)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor loại dấu phẩy động hoặc tensor lượng tử hoá mỗi tensor (C1–C7)
(I2) scale Tensor 1 chiều của loại lượng tử hoá theo dấu phẩy động hoặc mỗi tensor (C2), (C3)
(I3) offset Tensor 1 chiều của loại lượng tử hoá theo dấu phẩy động hoặc mỗi tensor (C2), (C4)
(I4) mean Tensor 1 chiều của loại lượng tử hoá theo dấu phẩy động hoặc mỗi tensor (C5)
(I5) variance Tensor 1 chiều của loại lượng tử hoá theo dấu phẩy động hoặc mỗi tensor (C2), (C6)
(I6) epsilon hằng số loại f32
(I7) feature_index hằng số loại si64 (C1), (C3–C6)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor loại dấu phẩy động hoặc tensor lượng tử hoá mỗi tensor (C2), (C7)

Giới hạn

  • (C1) 0 <= feature_index < rank(operand).
  • (C2) operand, scale, offset, mean, varianceresult có cùng 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).

Ví dụ

// %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

Ngữ nghĩa

Tính toán giá trị trung bình và phương sai trên tất cả các phương diện ngoại trừ feature_index và chuẩn hoá tensor operand tạo ra output, batch_meanbatch_var tensor. Một cách chính thức hơn, thao tác này có thể được biểu thị dưới dạng phân rã thành các hoạt động ổn định hiện có bằng cú pháp Python như sau:

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

Đối với các kiểu lượng tử hoá, 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)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor loại dấu phẩy động hoặc tensor lượng tử hoá mỗi tensor (C1)
(I2) scale Tensor 1 chiều của dấu phẩy động hoặc lượng tử hoá mỗi tensor (C2), (C3)
(I3) offset Tensor 1 chiều của dấu phẩy động hoặc lượng tử hoá mỗi tensor (C2), (C4)
(I4) epsilon hằng số loại f32 (C1), (C3–C6)
(I5) feature_index hằng số loại si64 (C1), (C3–C6)

Kết quả đầu ra

Tên Loại Giới hạn
output tensor loại dấu phẩy động hoặc tensor lượng tử hoá mỗi tensor (C7)
batch_mean Tensor 1 chiều của dấu phẩy động hoặc lượng tử hoá mỗi tensor (C2), (C5)
batch_var Tensor 1 chiều của dấu phẩy động hoặc lượng tử hoá mỗi tensor (C2), (C6)

Giới hạn

  • (C1) 0 <= feature_index < rank(operand).
  • (C2) operand, scale, offset, batch_mean, batch_varoutput có cùng một 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).

Ví dụ

// %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

Ngữ nghĩa

Thực hiện phép toán bitcast trên tensor operand và tạo ra tensor result trong đó các bit của toàn bộ tensor operand được diễn giải lại bằng cách sử dụng của tensor result.

Chính thức hơn, với E = element_type(operand), E' = element_type(result), và R = rank(operand):

  • Nếu giá trị là num_bits(E') < num_bits(E), bits(result[i0, ..., iR-1, :]) = bits(operand[i0, ..., iR-1])
  • Nếu giá trị là num_bits(E') > num_bits(E), bits(result[i0, ..., iR-2]) = bits(operand[i0, ..., iR-2, :])
  • Nếu giá trị là num_bits(E') = num_bits(E), bits(result[i0, ..., iR-1]) = bits(operand[i0, ..., iR-1])

bits trả về giá trị biểu thị trong bộ nhớ của một giá trị đã cho, kèm theo hành vi của giá trị đó được triển khai vì cách biểu diễn chính xác tensor là do triển khai xác định và cách thể hiện chính xác các loại phần tử là triển khai xác định.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor hoặc tensor lượng tử hoá (C1–C2)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá (C1–C2)

Giới hạn

  • (C1) Cho trước E = is_quantized(operand) ? storage_type(operand) : element_type(operand), E' = is_quantized(result) ? storage_type(result) : element_type(result)R = rank(operand):
    • Nếu num_bits(E') = num_bits(E), shape(result) = shape(operand).
    • Nếu giá trị là num_bits(E') < num_bits(E):
    • rank(result) = R + 1.
    • dim(result, i) = dim(operand, i) cho tất cả 0 <= i < R.
    • dim(result, R) * num_bits(E') = num_bits(E).
    • Nếu giá trị là num_bits(E') > num_bits(E):
    • rank(result) = R - 1.
    • dim(result, i) = dim(operand, i) cho tất cả 0 <= i < R.
    • dim(operand, R - 1) * num_bits(E) = num_bits(E').
  • (C2) Nếu là is_complex(operand) or is_complex(result), thì is_complex(operand) and is_complex(result)

Ví dụ

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

Ví dụ khác

broadcast_in_dim

Ngữ nghĩa

Mở rộng thứ nguyên và/hoặc thứ hạng của tensor đầu vào bằng cách sao chép dữ liệu trong tensor operand và tạo ra một tensor result. Một cách chính thức hơn, result[result_index] = operand[operand_index] cho tất cả daxes(operand):

  • operand_index[d] = 0 nếu dim(operand, d) = 1.
  • operand_index[d] = result_index[broadcast_dimensions[d]].

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor hoặc tensor lượng tử hoá (C1-C2), (C5-C6)
(I2) broadcast_dimensions Hằng số tensor 1 chiều thuộc loại si64 (C2–C6)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá (C1), (C3), (C5-C6)

Giới hạn

  • (C1) element_type(result) được cung cấp bởi:
    • element_type(operand), nếu !is_per_axis_quantized(operand).
    • element_type(operand) ngoại trừ quantization_dimension(operand) đó, scales(operand)zero_points(operand) có thể khác với quantization_dimension(result), scales(result)zero_points(result) phản hồi, nếu không.
  • (C2) size(broadcast_dimensions) = rank(operand).
  • (C3) 0 <= broadcast_dimensions < rank(result).
  • (C4) is_unique(broadcast_dimensions).
  • (C5) Đối với tất cả d trong axes(operand):
    • dim(operand, d) = 1 hoặc
    • dim(operand, d) = dim(result, broadcast_dimensions[d]).
  • (C6) Nếu is_per_axis_quantized(result):
    • quantization_dimension(result) = broadcast_dimensions[quantization_dimension(operand)].
    • Nếu là dim(operand, quantization_dimension(operand)) = 1, thì scales(result)[i] = scales(operand)[0] and zero_points(result)[i] = zero_points(operand)[0] for i in range(dim(result, quantization_dimension(result)))

Ví dụ

// %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]
//            ]
//          ]

Ví dụ khác

ốp lưng

Ngữ nghĩa

Tạo kết quả từ việc thực thi đúng một hàm từ branches tuỳ thuộc vào giá trị của index. Chính thức hơn, result = selected_branch() trong đó:

  • selected_branch = branches[index] nếu 0 <= index < size(branches).
  • selected_branch = branches[-1].

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) index Tensor 0 chiều thuộc loại si32
(I2) branches số lượng hàm thay đổi (C1–C4)

Kết quả đầu ra

Tên Loại Giới hạn
results số biến thiên của tensor, tensor lượng tử hoá hoặc mã thông báo (C4)

Giới hạn

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

Ví dụ

// %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]

Ví dụ khác

cbrt

Ngữ nghĩa

Thực hiện phép toán căn bậc ba toàn phần trên tensor operand và tạo ra một Tensor result. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với số thực độ chính xác đơn: rootn(x, 3) từ IEEE-754.
  • Đối với số phức: căn bậc ba phức.
  • Đối với các kiểu lượng tử hoá: dequantize_op_quantize(cbrt, operand, type(result))

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]

Ví dụ khác

ceil

Ngữ nghĩa

Thực hiện tensor kiểm soát phần tử của tensor operand và tạo ra tensor result. Triển khai thao tác roundToIntegralTowardPositive từ IEEE-754 đặc điểm kỹ thuật. Đối với các kiểu lượng tử hoá, dequantize_op_quantize(ceil, operand, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor loại dấu phẩy động hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor loại dấu phẩy động hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]

Ví dụ khác

cholesky

Ngữ nghĩa

Tính toán quá trình phân rã Cholesky của một lô ma trận.

Chính thức hơn, cho tất cả i trong index_space(result), result[i0, ..., iR-3, :, :] là quá trình phân huỷ Cholesky của a[i0, ..., iR-3, :, :], ở dạng tam giác dưới (nếu lowertrue) hoặc ma trận tam giác trên (nếu lowerfalse). Giá trị đầu ra trong tam giác đối diện, tức là tam giác nhọn ở trên hoặc tam giác dưới nghiêm ngặt tương ứng đều được xác định theo phương thức triển khai.

Nếu tồn tại i trong đó ma trận đầu vào không phải là xác định dương Hermitian ma trận thì hành vi là không xác định.

Đối với các kiểu lượng tử hoá, dequantize_op_quantize(lambda operand: cholesky(operand, lower), a, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) a tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1–C3)
(I2) lower Hằng số tensor 0 chiều thuộc loại i1

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]
//          ]

kẹp

Ngữ nghĩa

Gắn mọi phần tử của tensor operand từ giá trị tối thiểu đến giá trị tối đa và tạo ra tensor result. Chính thức hơn, result[result_index] = minimum(maximum(operand[result_index], min_element), max_element), trong đó min_element = rank(min) = 0 ? min[] : min[result_index], max_element = rank(max) = 0 ? max[] : max[result_index]. Đối với các loại lượng tử hoá, thực hiện dequantize_op_quantize(clamp, min, operand, max, type(result)).

Việc áp đặt một thứ tự cho số phức liên quan đến ngữ nghĩa đáng kinh ngạc, vì vậy, trong tương lai, chúng tôi sẽ có kế hoạch ngừng hỗ trợ số phức cho thao tác này (#560).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) min tensor hoặc tensor lượng tử hoá mỗi tensor (C1), (C3)
(I2) operand tensor hoặc tensor lượng tử hoá mỗi tensor (C1–C4)
(I3) max tensor hoặc tensor lượng tử hoá mỗi tensor (C2), (C3)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá mỗi tensor (C4)

Giới hạn

  • (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).

Ví dụ

// %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]

Ví dụ khác

collective_broadcast

Ngữ nghĩa

Trong mỗi nhóm quy trình ở lưới quy trình StableHLO, hãy gửi giá trị của Tensor operand từ quy trình nguồn đến các quy trình mục tiêu và tạo ra một Tensor result.

Thao tác này sẽ chia lưới quy trình StableHLO thành process_groups, tức là được xác định như sau:

  • cross_replica(replica_groups) nếu channel_id <= 0.
  • cross_partition(replica_groups) nếu channel_id > 0.

Sau đó, result@process được cung cấp bởi:

  • operand@process_groups[i, 0] nếu tồn tại i để quá trình này trong process_groups[i].
  • broadcast_in_dim(constant(is_quantized(result) ? quantize(0, element_type(result)) : 0, element_type(result)), [], type(result)) nếu không.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor hoặc tensor lượng tử hoá mỗi tensor (C3)
(I2) replica_groups số biến thiên của hằng số tensor 1 chiều thuộc loại si64 (C1), (C2)
(I3) channel_id hằng số loại si64

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá mỗi tensor (C3)

Giới hạn

  • (C1) is_unique(replica_groups).
  • (C2) 0 <= replica_groups < N trong đó N được định nghĩa là:
    • num_replicas nếu dùng cross_replica.
    • num_partitions nếu dùng cross_partition.
  • (C3) type(result) = type(operand).

Ví dụ

// 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

Ngữ nghĩa

Trong mỗi nhóm quy trình ở lưới quy trình StableHLO, hãy gửi giá trị của Tensor operand từ quá trình nguồn đến tiến trình mục tiêu và tạo ra một Tensor result.

Thao tác này sẽ chia lưới quy trình StableHLO thành process_groups, tức là được xác định như sau:

  • cross_replica(source_target_pairs) nếu channel_id <= 0.
  • cross_partition(source_target_pairs) nếu channel_id > 0.

Sau đó, result@process được cung cấp bởi:

  • operand@process_groups[i, 0], nếu tồn tại i sao cho process_groups[i, 1] = process.
  • broadcast_in_dim(constant(is_quantized(result) ? quantize(0, element_type(result)) : 0, element_type(result)), [], type(result)) nếu không.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor hoặc tensor lượng tử hoá mỗi tensor (C5)
(I2) source_target_pairs Hằng số tensor 2 chiều thuộc loại si64 (C1–C4)
(I3) channel_id hằng số loại si64

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

  • (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, trong đó N được định nghĩa là:
    • num_replicas nếu dùng cross_replica.
    • num_partitions nếu dùng cross_partition.
  • (C5) type(result) = type(operand).

Ví dụ

// 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]]

Ví dụ khác

so sánh

Ngữ nghĩa

Thực hiện so sánh các phần tử của tensor lhsrhs theo comparison_directioncompare_type rồi tạo tensor result.

Các giá trị của comparison_directioncompare_type có các giá trị sau ngữ nghĩa:

Đối với các loại phần tử boolean và số nguyên:

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

Đối với các loại phần tử dấu phẩy động có compare_type = FLOAT, hoạt động sẽ triển khai các hoạt động IEEE-754 sau đây:

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

Đối với các loại phần tử dấu phẩy động có compare_type = TOTALORDER, tuỳ chọn hoạt động sử dụng tổ hợp toán tử totalOrdercompareQuietEqual từ IEEE-754.

Đối với các loại phần tử phức tạp, phép so sánh từ điển của các cặp (real, imag) là thực hiện bằng comparison_directioncompare_type được cung cấp. Việc áp đặt một thứ tự cho số phức liên quan đến ngữ nghĩa đáng kinh ngạc, vì vậy, trong tương lai, chúng tôi sẽ có kế hoạch ngừng hỗ trợ số phức khi comparison_direction ở trạng thái GE, GT, LE hoặc LT (#560).

Đối với các loại lượng tử hoá. thực hiện dequantize_compare(lhs, rhs, comparison_direction).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) lhs tensor hoặc tensor lượng tử hoá mỗi tensor (C1–C3)
(I2) rhs tensor hoặc tensor lượng tử hoá mỗi tensor (C1–C2)
(I3) comparison_direction enum của EQ, NE, GE, GT, LELT
(I4) compare_type enum của FLOAT, TOTALORDER, SIGNEDUNSIGNED (C3)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của loại boolean (C2)

Giới hạn

  • (C1) baseline_element_type(lhs) = baseline_element_type(rhs).
  • (C2) shape(lhs) = shape(rhs) = shape(result).
  • (C3) compare_type được định nghĩa là:
    • SIGNED nếu is_signed_integer(element_type(lhs)).
    • UNSIGNED nếu is_unsigned_integer(element_type(lhs)) or is_boolean(element_type(lhs)).
    • FLOAT hoặc TOTALORDER nếu is_float(element_type(lhs)).
    • FLOAT nếu is_complex(element_type(lhs)).

Ví dụ

// %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]

Ví dụ khác

phức tạp

Ngữ nghĩa

Thực hiện chuyển đổi từng phần tử thành một giá trị phức từ một cặp giá trị thực và các giá trị ảo, lhsrhs, đồng thời tạo ra tensor result.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) lhs tensor thuộc loại f32 hoặc f64 (C1–C3)
(I2) rhs tensor thuộc loại f32 hoặc f64 (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor thuộc loại phức (C2), (C3)

Giới hạn

  • (C1) type(lhs) = type(rhs).
  • (C2) shape(result) = shape(lhs).
  • (C3) element_type(result) có loại complex<E> trong đó E = element_type(lhs).

Ví dụ

// %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)]

Ví dụ khác

tổng hợp

Ngữ nghĩa

Đóng gói một thao tác được tạo thành (bao gồm) các thao tác ổn định khác, lấy inputscomposite_attributes và tạo ra results. Chiến lược phát hành đĩa đơn ngữ nghĩa của hoạt động được triển khai bằng thuộc tính decomposition. Chiến lược phát hành đĩa đơn Có thể thay thế hoạt động composite bằng quá trình phân rã mà không cần thay đổi chương trình ngữ nghĩa. Trong trường hợp cùng dòng trong quá trình phân ly không cung cấp cùng một ngữ nghĩa op, hãy ưu tiên sử dụng custom_call.

Trường version (mặc định là 0) được dùng để biểu thị khi một thuộc tính tổng hợp ngữ nghĩa.

Thông tin đầu vào

Hãng nhạc Tên Loại
(I1) inputs số lượng giá trị biến thiên
(I2) name hằng số loại string
(I3) composite_attributes từ điển thuộc tính
(I4) decomposition hằng số loại string
(I5) version hằng số loại si32

Kết quả đầu ra

Tên Loại
results số lượng giá trị biến thiên

Giới hạn

  • (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)

Ví dụ

%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>

Ví dụ khác

nối

Ngữ nghĩa

Nối inputs dọc theo phương diện dimension theo cùng thứ tự như phương diện đã cho đối số và tạo ra một tensor result. Một cách chính thức hơn, result[i0, ..., id, ..., iR-1] = inputs[k][i0, ..., kd, ..., iR-1], trong đó:

  1. id = d0 + ... + dk-1 + kd.
  2. d bằng dimensiond0, ... là kích thước kích thước thứ d trong tổng số inputs.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) inputs số biến thiên của tensor hoặc tensor lượng tử hoá mỗi tensor (C1–C6)
(I2) dimension hằng số loại si64 (C2), (C4), (C6)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá mỗi tensor (C5–C6)

Giới hạn

  • (C1) same(element_type(inputs...)).
  • (C2) same(shape(inputs...)) ngoại trừ 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]) ngoại trừ:
    • dim(result, dimension) = dim(inputs[0], dimension) + ....

Ví dụ

// %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]]

Ví dụ khác

hằng số

Ngữ nghĩa

Tạo tensor output từ một hằng số value.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) value hằng số (C1)

Kết quả đầu ra

Tên Loại Giới hạn
output tensor hoặc tensor lượng tử hoá (C1)

Giới hạn

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

Ví dụ

%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]]

Ví dụ khác

chuyển đổi

Ngữ nghĩa

Thực hiện chuyển đổi một phần tử từ loại phần tử này sang loại phần tử khác trên Tensor operand và tạo ra một tensor result.

Đối với lượt chuyển đổi boolean-to-any-supported-type, giá trị false là chuyển đổi thành 0 và giá trị true được chuyển đổi thành 1. Cho any-supported-type-to-boolean, một giá trị bằng 0 sẽ được chuyển đổi thành false và các giá trị khác 0 được chuyển đổi thành true. Xem phần dưới đây để biết cách thực hiện phù hợp với các loại phức tạp.

Đối với các lượt chuyển đổi liên quan đến số nguyên đến số nguyên, số nguyên đến dấu phẩy động hoặc floating-point-to-floating-point, nếu giá trị nguồn có thể chính xác được biểu thị trong loại đích đến, thì giá trị kết quả là chính xác đại diện. Nếu không, hành vi sẽ được xác định sau (#180).

Đối với các lượt chuyển đổi liên quan đến floating-point-to-integer, phần phân số là bị cắt bớt. Nếu không thể biểu thị giá trị bị cắt bớt trong loại đích đến, hành vi sẽ được xác định sau (#180).

Việc chuyển đổi liên quan đến từ số phức sang số phức sẽ tuân theo hành vi tương tự của chuyển đổi floating-point-to-floating-point để chuyển đổi thực và phần ảo.

Đối với lượt chuyển đổi complex-to-any-other-typecomplex-to-any-other-type, giá trị ảo nguồn bị bỏ qua hoặc giá trị ảo đích là có giá trị tương ứng là 0. Việc chuyển đổi phần thực tuân theo chuyển đổi dấu phẩy động.

Theo nguyên tắc, thao tác này có thể thể hiện việc loại bỏ lượng tử (chuyển đổi từ tensor lượng tử hoá sang tensor thông thường), lượng tử hoá (chuyển đổi từ tensor thông thường tensor thành tensor lượng tử hoá) và lượng tử hoá (chuyển đổi giữa lượng tử hoá) tensor), nhưng hiện tại chúng tôi có hoạt động chuyên biệt cho việc đó – uniform_dequantize cho trường hợp sử dụng đầu tiên và uniform_quantize cho trường hợp sử dụng trường hợp sử dụng thứ hai và thứ ba. Trong tương lai, hai hoạt động này có thể được hợp nhất vào convert (#1576).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor (C1)

Giới hạn

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

Ví dụ

// %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)]

Ví dụ khác

tích chập

Ngữ nghĩa

Tính các tích vô hướng giữa các cửa sổ của lhs và lát cắt của rhs rồi tạo ra result. Sơ đồ dưới đây cho thấy cách các phần tử trong result được tính toán từ lhsrhs trong một ví dụ cụ thể.

tích chập

Để cụ thể hơn, hãy cân nhắc việc điều chỉnh lại khung hình sau đây của các thông tin đầu vào về mặt lhs để có thể biểu thị cửa sổ của 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).

Việc định lại khung hình này sử dụng các chức năng trợ giúp sau:

  • 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], trong đó j[d] = i[permutation[d]].

Nếu feature_group_count = 1batch_group_count = 1 thì với tất cả output_spatial_index trong index_space(dim(result, output_spatial_dimensions...)), result[result_shape(:, output_spatial_index, :)] = dot_product trong đó:

  • 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]). Tính năng này dường như không được sử dụng, vì vậy trong tương lai, chúng tôi sẽ có kế hoạch loại bỏ nó (#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]).

Nếu giá trị là 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).

Nếu giá trị là 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).

Đối với các kiểu lượng tử hoá, thực hiện 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)).

Đối với các kiểu lượng tử hoá kết hợp, thực hiện 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).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) lhs tensor hoặc tensor lượng tử hoá mỗi tensor (C1), (C10-C11), (C14) (C25), (C27-C28), (C31-C32), (C34)
(I2) rhs tensor hoặc tensor lượng tử hoá (C1), (C14-C16), (C25), (C27-C29), (C31-C34)
(I3) window_strides Hằng số tensor 1 chiều thuộc loại si64 (C2-C3), (C25)
(I4) padding Hằng số tensor 2 chiều thuộc loại si64 (C4), (C25)
(I5) lhs_dilation Hằng số tensor 1 chiều thuộc loại si64 (C5–C6), (C25)
(I6) rhs_dilation Hằng số tensor 1 chiều thuộc loại si64 (C7–C8), (C25)
(I7) window_reversal Hằng số tensor 1 chiều thuộc loại i1 (C9)
(I8) input_batch_dimension hằng số loại si64 (C10), (C13), (C25)
(I9) input_feature_dimension hằng số loại si64 (C11), (C13-C14)
(I10) input_spatial_dimensions Hằng số tensor 1 chiều thuộc loại si64 (C12), (C13), (C25)
(I11) kernel_input_feature_dimension hằng số loại si64 (C14), (C18)
(I12) kernel_output_feature_dimension hằng số loại si64 (C15-C16), (C18), (C25), (C29)
(I13) kernel_spatial_dimensions Hằng số tensor 1 chiều thuộc loại si64 (C17-C18), (C25)
(I14) output_batch_dimension hằng số loại si64 (C20), (C25)
(I15) output_feature_dimension hằng số loại si64 (C20), (C25), (C30)
(I16) output_spatial_dimensions Hằng số tensor 1 chiều thuộc loại si64 (C19-C20), (C25)
(I17) feature_group_count hằng số loại si64 (C11), (C14), (C16), (C21), (C23)
(I18) batch_group_count hằng số loại si64 (C10), (C15), (C22), (C23), (C25)
(I19) precision_config số lượng giá trị enum thay đổi là DEFAULT, HIGHHIGHEST (C24)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá (C25-C28), (C30), (C32-34)

Giới hạn

  • (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) Cho trước 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) Cho trước 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) Cho trước 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) được định nghĩa là:
    • dim(lhs, input_batch_dimension) / batch_group_count nếu result_dim = output_batch_dimension.
    • dim(rhs, kernel_output_feature_dimension) nếu result_dim = output_feature_dimension.
    • Nếu không là num_windows, trong đó:
    • 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.
  • Nếu phép toán sử dụng tensor không lượng tử hoá:
    • (C27) element_type(lhs) = element_type(rhs) = element_type(result).
  • Nếu thao tác này sử dụng tensor lượng tử hoá:
    • (C28) is_quantized(lhs) = is_quantized(result) and is_quantized(rhs).
    • (C29) Nếu is_per_axis_quantized(rhs), sau đó là quantization_dimension(rhs) = kernel_output_feature_dimension.
    • (C30) Nếu là is_per_axis_quantized(result), thì quantization_dimension(result) = output_feature_dimension
    • Nếu giá trị là is_quantized(lhs):
    • (C31) storage_type(lhs) = storage_type(rhs).
    • (C32) expressed_type(lhs) = expressed_type(rhs) = expressed_type(result).
    • (C33) Nếu là is_per_tensor_quantized(rhs), thì is_per_tensor_quantized(result)
    • Nếu giá trị là !is_quantized(lhs):
    • (C34) element_type(lhs) = expressed_type(rhs) = element_type(result).

Ví dụ

// %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]]
//          ]]

Ví dụ khác

cosin

Ngữ nghĩa

Thực hiện phép toán cosin theo phần tử trên tensor operand và tạo ra một Tensor result. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với số thực độ chính xác đơn: cos từ IEEE-754.
  • Đối với số phức: cosin phức.
  • Đối với các kiểu lượng tử hoá: dequantize_op_quantize(cosine, operand, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]]

Ví dụ khác

count_leading_zeros

Ngữ nghĩa

Thực hiện đếm số phần tử theo số phần tử số 0 ở đầu trong operand tensor và tạo ra tensor result.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor của kiểu số nguyên (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của kiểu số nguyên (C1)

Giới hạn

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

Ví dụ

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

Ví dụ khác

custom_call

Ngữ nghĩa

Đóng gói thao tác triển khai call_target_name sẽ nhận inputscalled_computations, đồng thời tạo results. has_side_effect, backend_configapi_version có thể được dùng để cung cấp thêm siêu dữ liệu do triển khai xác định.

Hiện tại, hoạt động này chứa một tập hợp khá vô tổ chức siêu dữ liệu phản ánh sự tiến hoá tự nhiên của hoạt động tương ứng của nó trong trình biên dịch XLA. Trong tương lai, chúng tôi dự định hợp nhất siêu dữ liệu này (#741).

Thông tin đầu vào

Hãng nhạc Tên Loại
(I1) inputs số lượng giá trị biến thiên
(I2) call_target_name hằng số loại string
(I3) has_side_effect hằng số loại i1
(I4) backend_config hằng số loại string hoặc từ điển thuộc tính
(I5) api_version hằng số loại si32
(I6) called_computations số lượng hằng số biến thiên thuộc loại string

Kết quả đầu ra

Tên Loại
results số lượng giá trị biến thiên

Ví dụ

%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>

chia

Ngữ nghĩa

Thực hiện phép chia từng phần tử của số bị chia lhs và tensor rhs của số chia và tạo ra tensor result. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với số nguyên: phép chia số nguyên tạo ra thương số đại số với bất kỳ đã loại bỏ phần thập phân.
  • Đối với số thực độ chính xác đơn: division từ IEEE-754.
  • Đối với số phức: phép chia phức.
  • Đối với các loại lượng tử hoá:
    • dequantize_op_quantize(divide, lhs, rhs, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) lhs tensor của số nguyên, kiểu dấu phẩy động hoặc kiểu phức hoặc tensor lượng tử hoá mỗi tensor (C1)
(I2) rhs tensor của số nguyên, kiểu dấu phẩy động hoặc kiểu phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của số nguyên, dấu phẩy động hoặc kiểu phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]

Ví dụ khác

dot_general

Ngữ nghĩa

Tính tích các chấm giữa các lát cắt lhs và lát cắt của rhs, từ đó tạo ra một Tensor result.

Chính thức hơn là result[result_index] = dot_product, trong đó:

  • 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 trong đó 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)).

Đối với các kiểu lượng tử hoá, thực hiện 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)).

Đối với các kiểu lượng tử hoá kết hợp, thực hiện 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 kiểm soát sự cân bằng giữa tốc độ và độ chính xác cho các tính toán trên chương trình phụ trợ của trình tăng tốc. Đây có thể là một trong những cách sau (ở thời điểm, ngữ nghĩa của các giá trị enum này không được chỉ định rõ, nhưng chúng tôi đang dự định giải quyết vấn đề này trong #755):

  • DEFAULT: Kết quả tính toán nhanh nhất, nhưng kém chính xác nhất so với kết quả ước tính số điện thoại ban đầu.
  • HIGH: Phép tính toán chậm hơn, nhưng giá trị ước tính chính xác hơn số điện thoại ban đầu.
  • HIGHEST: Phép tính toán chậm nhất, nhưng chính xác nhất so với số điện thoại ban đầu.

DotAlgorithm xác định các thuộc tính chính của thuật toán dùng để triển khai toán tử dấu chấm cũng xác định độ chính xác. Nếu thuộc tính thuật toán các trường được đặt, thì precision_config phải là DEFAULT. DotAlgorithms không có giá trị mặc định, vì các thông số mặc định đang được triển khai xác định. Như vậy, tất cả các trường thuật toán dấu chấm có thể được đặt thành None để chỉ định một thuật toán dấu chấm trống. Thay vào đó, thuật toán này sẽ sử dụng giá trị precision_config.

Các trường DotAlgorithm bao gồm:

  • lhs_precision_typerhs_precision_type, độ chính xác mà LHS và RHS của thao tác được làm tròn đến. Loại độ chính xác độc lập với các loại bộ nhớ đầu vào và đầu ra.
  • accumulation_type độ chính xác dùng để tích luỹ.
  • lhs_component_count, rhs_component_countnum_primitive_operations sẽ áp dụng khi chúng ta thực hiện thuật toán phân tách LHS và/hoặc RHS thành nhiều thành phần và thực hiện nhiều thao tác "gốc" trên những trang web đó giá trị – thường để mô phỏng độ chính xác cao hơn (ví dụ: Sử dụng kiểu dữ liệu trí tuệ nhân tạo bfloat16 để tính toán độ chính xác cao hơn: bf16_6x tf32_3x, v.v.). Đối với các thuật toán không phân ly, các giá trị này phải được đặt thành 1.
  • allow_imprecise_accumulation để chỉ định liệu dữ liệu tích luỹ có độ chính xác thấp hơn hay không được phép thực hiện một số bước (ví dụ: CUBLASLT_MATMUL_DESC_FAST_ACCUM).

Ví dụ về các thuộc tính 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}

Điều này phụ thuộc vào việc triển khai để quyết định kết hợp nào được hỗ trợ. Trong nói chung, không thể đảm bảo rằng mỗi thuật toán được hỗ trợ trên mỗi loại trình tăng tốc theo người tiêu dùng StableHLO. Nếu một thuật toán cụ thể không được lỗi sẽ được đưa ra thay vì quay lại sử dụng thay thế. Quy trình xác minh trên StableHLO sẽ nỗ lực xác minh một cách hiệu quả nhất, ngăn chặn các thuật toán không được hỗ trợ trên bất kỳ phần cứng nào.

Xem xla_data.proto > Algorithm đối với một số giá trị thuật toán được hỗ trợ. Phiếu yêu cầu hỗ trợ số 2483 ghi lại kế hoạch tạo tài liệu tập trung về các thuật toán được hỗ trợ theo phần phụ trợ.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) lhs tensor hoặc tensor lượng tử hoá mỗi tensor (C5-C6), (C9-C10), (C12-C14), (C17-C18), (C20)
(I2) rhs tensor hoặc tensor lượng tử hoá (C7-C10), (C12-C20)
(I3) lhs_batching_dimensions Hằng số tensor 1 chiều thuộc loại si64 (C1), (C3), (C5), (C9), (C12)
(I4) rhs_batching_dimensions Hằng số tensor 1 chiều thuộc loại si64 (C1), (C4), (C7), (C9)
(I5) lhs_contracting_dimensions Hằng số tensor 1 chiều thuộc loại si64 (C2), (C3), (C6), (C10)
(I6) rhs_contracting_dimensions Hằng số tensor 1 chiều thuộc loại si64 (C2), (C4), (C8), (C10), (C16)
(I7) precision_config số lượng giá trị enum thay đổi là DEFAULT, HIGHHIGHEST (C11), (C21)
(I8) lhs_precision_type FloatType hoặc TensorFloat32 (C21)
(I9) rhs_precision_type FloatType hoặc TensorFloat32 (C21)
(I10) accumulation_type FloatType hoặc TensorFloat32 (C21)
(I11) lhs_component_count hằng số loại si32 (C21), (C22)
(I12) rhs_component_count hằng số loại si32 (C21), (C23)
(I13) num_primitive_operations hằng số loại si32 (C21), (C24)
(I14) allow_imprecise_accumulation hằng số loại bool (C21)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá (C12), (C14), (C18-C20)

Giới hạn

  • (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).
  • Nếu phép toán sử dụng tensor không lượng tử hoá:
    • (C13) element_type(lhs) = element_type(rhs).
  • Nếu thao tác này sử dụng tensor lượng tử hoá:
    • (C14) is_quantized(lhs) = is_quantized(result) and is_quantized(rhs).
    • (C15) zero_points(rhs) = 0.
    • (C16) Nếu là is_per_axis_quantized(rhs), thì quantization_dimension(rhs) không có trong rhs_contracting_dimensions.
    • Nếu giá trị là is_quantized(lhs):
    • (C17) storage_type(lhs) = storage_type(rhs).
    • (C18) expressed_type(lhs) = expressed_type(rhs) = expressed_type(result).
    • (C19) Nếu là is_per_tensor_quantized(rhs), thì is_per_tensor_quantized(result)
    • Nếu giá trị là !is_quantized(lhs):
    • (C20) element_type(lhs) = expressed_type(rhs) = element_type(result).
  • Nếu giá trị là !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.

Ví dụ

// %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]]
//          ]

Ví dụ khác

dynamic_broadcast_in_dim

Ngữ nghĩa

Hoạt động này có chức năng giống với broadcast_in_dim , nhưng hình dạng kết quả được chỉ định một cách linh động thông qua output_dimensions.

Thao tác này cũng chấp nhận các thuộc tính không bắt buộc known_expanding_dimensions, known_non_expanding_dimensions để thể hiện kiến thức tĩnh về hành vi mở rộng của thứ nguyên. Nếu bạn không chỉ định, tất cả các phương diện đều được giả định là có thể mở rộng.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor hoặc tensor lượng tử hoá (C1-C2), (C5-C6), (C9)
(I2) output_dimensions Tensor 1 chiều thuộc kiểu số nguyên (C7)
(I3) broadcast_dimensions Tensor hằng số 1 chiều thuộc kiểu số nguyên (C2–C6)
(I4) known_expanding_dimensions Tensor hằng số 1 chiều thuộc kiểu số nguyên (C8–C9)
(I5) known_non_expanding_dimensions Tensor hằng số 1 chiều thuộc kiểu số nguyên (C8–C9)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá (C1), (C3), (C5-C7)

Giới hạn

  • (C1) element_type(result) được cung cấp bởi:
    • element_type(operand), nếu !is_per_axis_quantized(operand).
    • element_type(operand) ngoại trừ quantization_dimension(operand) đó, scales(operand)zero_points(operand) có thể khác với quantization_dimension(result), scales(result)zero_points(result) phản hồi, nếu không.
  • (C2) size(broadcast_dimensions) = rank(operand).
  • (C3) 0 <= broadcast_dimensions < rank(result).
  • (C4) is_unique(broadcast_dimensions).
  • (C5) Đối với tất cả d trong axes(operand):
    • dim(operand, d) = 1 hoặc
    • dim(operand, d) = dim(result, broadcast_dimensions[d]).
  • (C6) Nếu is_per_axis_quantized(result):
    • quantization_dimension(result) = broadcast_dimensions[quantization_dimension(operand)].
    • Nếu là dim(operand, quantization_dimension(operand)) = 1, thì 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).

Ví dụ

// %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]
//            ]
//          ]

Ví dụ khác

dynamic_conv

Ngữ nghĩa

Hoạt động này có chức năng giống với tích chập , nhưng khoảng đệm được chỉ định một cách linh động thông qua padding.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) lhs tensor hoặc tensor lượng tử hoá mỗi tensor (C1), (C10-C11), (C14) (C25), (C26-C27), (C30-C31), (C33)
(I2) rhs tensor hoặc tensor lượng tử hoá (C1), (C14-C16), (C26-C28), (C30-C33)
(I3) padding Tensor 2 chiều thuộc kiểu số nguyên (C4)
(I4) window_strides Hằng số tensor 1 chiều thuộc loại si64 (C2–C3)
(I5) lhs_dilation Hằng số tensor 1 chiều thuộc loại si64 (C5–C6)
(I6) rhs_dilation Hằng số tensor 1 chiều thuộc loại si64 (C7–C8)
(I7) window_reversal Hằng số tensor 1 chiều thuộc loại i1 (C9)
(I8) input_batch_dimension hằng số loại si64 (C10), (C13)
(I9) input_feature_dimension hằng số loại si64 (C11), (C13-C14)
(I10) input_spatial_dimensions Hằng số tensor 1 chiều thuộc loại si64 (C12), (C13)
(I11) kernel_input_feature_dimension hằng số loại si64 (C14), (C18)
(I12) kernel_output_feature_dimension hằng số loại si64 (C15-C16), (C18), (C28)
(I13) kernel_spatial_dimensions Hằng số tensor 1 chiều thuộc loại si64 (C17 – C18)
(I14) output_batch_dimension hằng số loại si64 (C20)
(I15) output_feature_dimension hằng số loại si64 (C20), (C29)
(I16) output_spatial_dimensions Hằng số tensor 1 chiều thuộc loại si64 (C19–C20)
(I17) feature_group_count hằng số loại si64 (C11), (C14), (C16), (C21), (C23)
(I18) batch_group_count hằng số loại si64 (C10), (C15), (C22), (C23)
(I19) precision_config số lượng giá trị enum thay đổi là DEFAULT, HIGHHIGHEST (C24)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá (C25-C27), (C29), (C31-C33)

Giới hạn

  • (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) Cho trước 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) Cho trước 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) Cho trước 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) được định nghĩa là:
    • dim(lhs, input_batch_dimension) / batch_group_count nếu result_dim = output_batch_dimension.
    • dim(rhs, kernel_output_feature_dimension) nếu result_dim = output_feature_dimension.
    • Nếu không là num_windows, trong đó:
    • 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.
  • Nếu phép toán sử dụng tensor không lượng tử hoá:
    • (C27) element_type(lhs) = element_type(rhs) = element_type(result).
  • Nếu thao tác này sử dụng tensor lượng tử hoá:
    • (C28) is_quantized(lhs) = is_quantized(result) and is_quantized(rhs).
    • (C29) Nếu is_per_axis_quantized(rhs), sau đó là quantization_dimension(rhs) = kernel_output_feature_dimension.
    • (C30) Nếu là is_per_axis_quantized(result), thì quantization_dimension(result) = output_feature_dimension
    • Nếu giá trị là is_quantized(lhs):
    • (C31) storage_type(lhs) = storage_type(rhs).
    • (C32) expressed_type(lhs) = expressed_type(rhs) = expressed_type(result).
    • (C33) Nếu là is_per_tensor_quantized(rhs), thì is_per_tensor_quantized(result)
    • Nếu giá trị là !is_quantized(lhs):
    • (C34) element_type(lhs) = expressed_type(rhs) = element_type(result).

Ví dụ

// %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]]
//          ]]

Ví dụ khác

dynamic_gather

Ngữ nghĩa

Hoạt động này có chức năng giống với thu thập op, với slice_sizes được chỉ định một cách linh động làm giá trị.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor hoặc tensor lượng tử hoá mỗi tensor (C1), (C7), (C10-C12), (C14)
(I2) start_indices tensor của kiểu số nguyên (C2), (C3), (C13)
(I3) slice_sizes Tensor 1 chiều thuộc kiểu số nguyên (C8), (C11-C13)
(I4) offset_dims Hằng số tensor 1 chiều thuộc loại si64 (C1), (C4-C5), (C13)
(I5) collapsed_slice_dims Hằng số tensor 1 chiều thuộc loại si64 (C1), (C6-C8), (C13)
(I6) start_index_map Hằng số tensor 1 chiều thuộc loại si64 (C3), (C9), (C10)
(I7) index_vector_dim hằng số loại si64 (C2), (C3), (C13)
(I8) indices_are_sorted hằng số loại i1

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá mỗi tensor (C5), (C13-C14)

Giới hạn

  • (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) trong đó:
    • batch_dim_sizes = shape(start_indices) ngoại trừ kích thước phương diện không bao gồm start_indices tương ứng với index_vector_dim.
    • offset_dim_sizes = shape(slice_sizes) ngoại trừ kích thước kích thước trong slice_sizes tương ứng với collapsed_slice_dims sẽ không được đưa vào.
    • combine đặt batch_dim_sizes tại các trục tương ứng với batch_dimsoffset_dim_sizes tại các trục tương ứng với offset_dims.
  • (C14) element_type(operand) = element_type(result).

Ví dụ

// %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]]
//            ]
//          ]

Ví dụ khác

dynamic_iota

Ngữ nghĩa

Hoạt động này có chức năng giống với iota , nhưng hình dạng kết quả được chỉ định một cách linh động thông qua output_shape.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) output_shape Tensor 1 chiều thuộc kiểu số nguyên (C1), (C2)
(I2) iota_dimension si64 (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của số nguyên, dấu phẩy động hoặc kiểu phức hoặc tensor lượng tử hoá mỗi tensor (C2)

Giới hạn

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

Ví dụ

%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]
//          ]

Ví dụ khác

dynamic_pad

Ngữ nghĩa

Hoạt động này có chức năng giống với pad nhưng với edge_padding_low, edge_padding_highinterior_padding được chỉ định một cách linh động dưới dạng giá trị.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor hoặc tensor lượng tử hoá mỗi tensor (C1), (C2), (C4)
(I2) padding_value tensor 0 chiều hoặc tensor lượng tử hoá mỗi tensor (C1)
(I3) edge_padding_low Tensor 1 chiều thuộc kiểu số nguyên (C1), (C4)
(I4) edge_padding_high Tensor 1 chiều thuộc kiểu số nguyên (C1), (C4)
(I5) interior_padding Tensor 1 chiều thuộc kiểu số nguyên (C2–C4)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá mỗi tensor (C3–C6)

Giới hạn

  • (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.

Ví dụ

// %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]
//          ]

Ví dụ khác

dynamic_reshape

Ngữ nghĩa

Hoạt động này có chức năng giống với đổi hình , nhưng hình dạng kết quả được chỉ định một cách linh động thông qua output_shape.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor hoặc tensor lượng tử hoá (C1–C3)
(I2) output_shape Tensor 1 chiều thuộc kiểu số nguyên (C4)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá (C1–C4)

Giới hạn

  • (C1) element_type(result) được cung cấp bởi:
    • element_type(operand), nếu !is_per_axis_quantized(operand).
    • element_type(operand) ngoại trừ quantization_dimension(operand) và Nếu không thì quantization_dimension(result) có thể khác.
  • (C2) size(operand) = size(result).
  • (C3) Nếu 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).

Ví dụ

// %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]]

Ví dụ khác

dynamic_slice

Ngữ nghĩa

Trích xuất một lát cắt từ operand bằng cách sử dụng các chỉ mục khởi đầu được tính toán tự động và tạo ra tensor result. start_indices chứa các chỉ mục bắt đầu của phần của mỗi tham số có thể được điều chỉnh, và slice_sizes chứa kích thước của lát cắt cho từng kích thước. Một cách chính thức hơn, result[result_index] = operand[operand_index] trong đó:

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

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor hoặc tensor lượng tử hoá mỗi tensor (C1), (C2), (C4)
(I2) start_indices số biến thiên của tensor 0 chiều thuộc loại số nguyên (C2), (C3)
(I3) slice_sizes Hằng số tensor 1 chiều thuộc loại si64 (C2), (C4), (C5)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá mỗi tensor (C1), (C5)

Giới hạn

  • (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.

Ví dụ

// %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]
//          ]

Ví dụ khác

dynamic_update_slice

Ngữ nghĩa

Tạo một tensor result bằng với tensor operand, ngoại trừ lát cắt bắt đầu từ start_indices sẽ được cập nhật với các giá trị trong update. Chính thức hơn, result[result_index] được định nghĩa là:

  • update[update_index] nếu 0 <= update_index < shape(update) trong đó:
    • adjusted_start_indices = clamp(0, start_indices, shape(operand) - shape(update)).
    • update_index = result_index - adjusted_start_indices.
  • operand[result_index].

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor hoặc tensor lượng tử hoá mỗi tensor (C1-C4), (C6)
(I2) update tensor hoặc tensor lượng tử hoá mỗi tensor (C2), (C3), (C6)
(I3) start_indices số biến thiên của tensor 0 chiều thuộc loại số nguyên (C4), (C5)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

  • (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).

Ví dụ

// %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]
//          ]

Ví dụ khác

hàm mũ

Ngữ nghĩa

Thực hiện phép toán luỹ thừa từng phần tử trên tensor operand và tạo ra một Tensor result. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với số thực độ chính xác đơn: exp từ IEEE-754.
  • Đối với số phức: số mũ phức.
  • Đối với các loại lượng tử hoá: dequantize_op_quantize(exponential, operand, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]]

Ví dụ khác

exponential_minus_one

Ngữ nghĩa

Thực hiện luỹ thừa từng phần tử trừ một phép toán trên tensor operand và tạo ra tensor result. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với số thực độ chính xác đơn: expm1 từ IEEE-754.
  • Đối với số phức: số mũ phức trừ đi một.
  • Đối với các loại lượng tử hoá: dequantize_op_quantize(exponential_minus_one, operand, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

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

Ví dụ khác

bàn thắng

Ngữ nghĩa

Thực hiện phép biến đổi Fourier tiến và nghịch đảo cho thực và phức đầu vào/đầu ra.

fft_type là một trong những quốc gia sau:

  • FFT: Chuyển tiếp FFT từ phức tạp đến phức tạp.
  • IFFT: FFT nghịch đảo từ phức tạp đến phức tạp.
  • RFFT: Chuyển tiếp FFT từ thực đến phức tạp.
  • IRFFT: FFT nghịch đảo từ số thực đến số phức (tức là lấy số phức, trả về số thực).

Chính thức hơn, với hàm fft nhận các tensor 1 chiều của phức tạp làm đầu vào, tạo ra tensor 1 chiều cùng loại như và tính phép biến đổi Fourier rời rạc:

Đối với fft_type = FFT, result được định nghĩa là kết quả cuối cùng của một chuỗi L với L = size(fft_length). Ví dụ: đối với 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]).

Hơn nữa, với hàm ifft có cùng chữ ký loại và tính nghịch đảo của fft:

Đối với fft_type = IFFT, result được định nghĩa là nghịch đảo của các phép tính với giá fft_type = FFT. Ví dụ: đối với 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, ..., :]).

Hơn nữa, với hàm rfft sẽ nhận các tensor 1 chiều của tạo ra tensor 1 chiều thuộc các kiểu dấu phẩy động phức tạp ngữ nghĩa dấu phẩy động tương tự và hoạt động như sau:

  • rfft(real_operand) = truncated_result trong đó
  • complex_operand... = (real_operand..., 0.0).
  • complex_result = fft(complex_operand).
  • truncated_result = complex_result[:(rank(complex_result) / 2 + 1)].

(Khi tính toán biến đổi Fourier rời rạc cho các toán hạng thực, hàm đầu tiên N/2 + 1 phần tử của kết quả xác định rõ ràng phần còn lại của kết quả, vì vậy, kết quả của rfft sẽ được cắt bớt để tránh tính toán các phần tử thừa).

Đối với fft_type = RFFT, result được định nghĩa là kết quả cuối cùng của một chuỗi L với L = size(fft_length). Ví dụ: đối với 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]).

Cuối cùng, cung cấp hàm irfft có cùng chữ ký kiểu và tính nghịch đảo của rfft:

Đối với fft_type = IRFFT, result được định nghĩa là nghịch đảo của các phép tính với giá fft_type = RFFT. Ví dụ: đối với 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, ..., :]).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor của dấu phẩy động hoặc loại phức (C1), (C2), (C4), (C5)
(I2) fft_type enum của FFT, IFFT, RFFTIRFFT (C2), (C5)
(I3) fft_length Hằng số tensor 1 chiều thuộc loại si64 (C1), (C3), (C4)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của dấu phẩy động hoặc loại phức (C2), (C4), (C5)

Giới hạn

  • (C1) size(fft_length) <= rank(operand).
  • (C2) Mối quan hệ giữa các loại phần tử operandresult là khác nhau:
    • Nếu fft_type = FFT, element_type(operand)element_type(result) có cùng kiểu phức.
    • Nếu fft_type = IFFT, element_type(operand)element_type(result) có cùng kiểu phức.
    • Nếu fft_type = RFFT, element_type(operand) là loại dấu phẩy động và element_type(result) là một loại phức tạp của cùng dấu phẩy động ngữ nghĩa.
    • Nếu fft_type = IRFFT, element_type(operand) là một kiểu phức và element_type(result) là một loại dấu phẩy động của cùng một dấu phẩy động ngữ nghĩa.
  • (C3) 1 <= size(fft_length) <= 3.
  • (C4) Nếu trong số operandresult, có một tensor real của một dấu phẩy động, sau đó là shape(real)[-size(fft_length):] = fft_length.
  • (C5) shape(result) = shape(operand) ngoại trừ:
    • Nếu giá trị là fft_type = RFFT, dim(result, -1) = dim(operand, -1) = 0 ? 0 : dim(operand, -1) / 2 + 1
    • Nếu giá trị là fft_type = IRFFT, dim(operand, -1) = dim(result, -1) = 0 ? 0 : dim(result, -1) / 2 + 1

Ví dụ

// %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)]

phần nguyên gần nhất bên trái

Ngữ nghĩa

Thực hiện giá trị tầng trên các phần tử của tensor operand và tạo ra tensor result. Triển khai thao tác roundToIntegralTowardNegative từ IEEE-754 đặc điểm kỹ thuật. Đối với các kiểu lượng tử hoá, dequantize_op_quantize(floor, operand, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor loại dấu phẩy động hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor loại dấu phẩy động hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]

Ví dụ khác

thu thập

Ngữ nghĩa

Thu thập các lát cắt từ tensor operand từ các giá trị bù trừ được chỉ định trong start_indices và tạo ra tensor result.

Sơ đồ dưới đây cho thấy cách các phần tử trong result ánh xạ đến các phần tử trong operand trong một ví dụ cụ thể. Sơ đồ này chọn một số ví dụ result chỉ mục và giải thích chi tiết chúng tương ứng với chỉ mục operand nào.

thu thập

Chính thức hơn là result[result_index] = operand[operand_index], trong đó:

  • batch_dims = [d for d in axes(result) and d not in offset_dims].
  • batch_index = result_index[batch_dims...].
  • start_index được định nghĩa là:
    • start_indices[bi0, ..., :, ..., biN] trong đó bi là các phần tử riêng lẻ trong batch_index: được chèn vào chỉ mục index_vector_dim, nếu index_vector_dim < rank(start_indices).
    • [start_indices[batch_index]].
  • Đối với d_operand trong axes(operand),
    • full_start_index[d_operand] = clamp(start_index[d_start], 0, dim(operand, d_operand) - slice_sizes[d_operand]) nếu d_operand = start_index_map[d_start].
    • full_start_index[d_operand] = 0.
  • Đối với d_operand trong axes(operand),
    • full_batching_index[d_operand] = batch_index[d_start - (d_start < index_vector_dim ? 0 : 1)] nếu 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], trong đó oi là cá nhân các phần tử trong offset_index0 được chèn vào các chỉ mục từ collapsed_slice_dimsoperand_batching_dims.
  • operand_index = full_start_index + full_batching_index + full_offset_index.

Nếu indices_are_sortedtrue thì quá trình triển khai có thể giả định rằng start_indices được sắp xếp theo start_index_map, nếu không thì chưa được xác định. Chính thức hơn, cho tất cả i1 < i2 từ indices(result), full_start_index(i1) <= full_start_index(i2).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor hoặc tensor lượng tử hoá mỗi tensor (C1), (C8), (C11), (C17), (C19-C21), (C23)
(I2) start_indices tensor của kiểu số nguyên (C2-C3), (C14), (C17), (C22)
(I3) offset_dims Hằng số tensor 1 chiều thuộc loại si64 (C1), (C4-C5), (C22)
(I4) collapsed_slice_dims Hằng số tensor 1 chiều thuộc loại si64 (C1), (C6-C9), (C22)
(I5) operand_batching_dims Hằng số tensor 1 chiều thuộc loại si64 (C1), (C6), (C10-C12), (C16-C18), (C22)
(I6) start_indices_batching_dims Hằng số tensor 1 chiều thuộc loại si64 (C13 – C17)
(I7) start_index_map Hằng số tensor 1 chiều thuộc loại si64 (C3), (C18-C19)
(I8) index_vector_dim hằng số loại si64 (C2-C3), (C15), (C22)
(I9) slice_sizes Hằng số tensor 1 chiều thuộc loại si64 (C9), (C12), (C20-C22)
(I10) indices_are_sorted hằng số loại i1

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá mỗi tensor (C5), (C22-C23)

Giới hạn

  • (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) trong đó:
    • batch_dim_sizes = shape(start_indices) ngoại trừ kích thước phương diện không bao gồm start_indices tương ứng với index_vector_dim.
    • offset_dim_sizes = slice_sizes ngoại trừ kích thước kích thước theo slice_sizes tương ứng với collapsed_slice_dims và Không bao gồm operand_batching_dims.
    • combine đặt batch_dim_sizes tại các trục tương ứng với batch_dimsoffset_dim_sizes tại các trục tương ứng với offset_dims.
  • (C23) element_type(operand) = element_type(result).

Ví dụ

// %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]]
//            ]
//           ]
//          ]

Ví dụ khác

get_dimension_size

Ngữ nghĩa

Tạo kích thước của dimension đã cho của operand. Một cách chính thức hơn, result = dim(operand, dimension). Ngữ nghĩa chỉ liên quan đến hình dạng thành phần của loại. Loại phần tử có thể là bất kỳ giá trị nào.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor hoặc tensor lượng tử hoá (C1)
(I2) dimension hằng số loại si64 (C1)

Kết quả đầu ra

Tên Loại
result Tensor 0 chiều thuộc loại si32

Giới hạn

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

Ví dụ

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

Ví dụ khác

get_tuple_element

Ngữ nghĩa

Trích xuất phần tử tại vị trí index của bộ dữ liệu operand và tạo ra một result. Chính thức hơn là result = operand[index].

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand bộ dữ liệu (C1), (C2)
(I2) index hằng số loại si32 (C1), (C2)

Kết quả đầu ra

Tên Loại Giới hạn
result mọi loại được hỗ trợ (C2)

Giới hạn

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

Ví dụ

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

Ví dụ khác

nếu

Ngữ nghĩa

Tạo kết quả từ việc thực thi đúng một hàm từ true_branch hoặc false_branch tuỳ thuộc vào giá trị của pred. Chính thức hơn là result = pred ? true_branch() : false_branch().

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) pred Tensor 0 chiều thuộc loại i1
(I2) true_branch hàm (C1–C3)
(I3) false_branch hàm (C1), (C2)

Kết quả đầu ra

Tên Loại Giới hạn
results số biến thiên của tensor, tensor lượng tử hoá hoặc mã thông báo (C3)

Giới hạn

  • (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).

Ví dụ

// %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

Ví dụ khác

hình ảnh

Ngữ nghĩa

Trích xuất phần ảo, xét theo từng phần tử, từ operand và tạo ra một phần Tensor result. Chính thức hơn, đối với mỗi phần tử x: imag(x) = is_complex(x) ? imaginary_part(x) : constant(0, element_type(result))

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor của dấu phẩy động hoặc loại phức (C1), (C2)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor thuộc loại dấu phẩy động (C1), (C2)

Giới hạn

  • (C1) shape(result) = shape(operand).
  • (C2) element_type(result) được định nghĩa là:
    • complex_element_type(element_type(operand)) nếu is_complex(operand).
    • element_type(operand).

Ví dụ

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

Ví dụ khác

nguồn cấp dữ liệu

Ngữ nghĩa

Đọc dữ liệu từ nguồn cấp dữ liệu và tạo results.

Ngữ nghĩa của infeed_config được xác định khi triển khai.

results bao gồm các giá trị tải trọng xuất hiện trước và một mã thông báo đi kèm cuối cùng. Trong tương lai, chúng tôi dự định sẽ chia tải trọng và mã thông báo thành hai riêng biệt để cải thiện tính rõ ràng (#670).

Thông tin đầu vào

Hãng nhạc Tên Loại
(I1) token token
(I2) infeed_config hằng số loại string

Kết quả đầu ra

Tên Loại Giới hạn
results số biến thiên của tensor, tensor lượng tử hoá hoặc mã thông báo (C1–C3)

Giới hạn

  • (C1) 0 < size(results).
  • (C2) is_empty(result[:-1]) hoặc is_tensor(type(results[:-1])).
  • (C3) is_token(type(results[-1])).

Ví dụ

// %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]]

Ví dụ khác

Iota

Ngữ nghĩa

Điền các giá trị theo thứ tự tăng dần bắt đầu từ 0 vào một tensor output dọc theo phương diện iota_dimension. Một cách chính thức hơn,

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

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) iota_dimension si64 (C1)

Kết quả đầu ra

Tên Loại Giới hạn
output tensor của số nguyên, dấu phẩy động hoặc kiểu phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

%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]
//          ]

Ví dụ khác

is_finite

Ngữ nghĩa

Thực hiện kiểm tra từng phần tử xem giá trị trong x có hữu hạn hay không (tức là không phải là +Inf, -Inf, cũng như NaN) và tạo ra tensor y. Triển khai isFinite từ thông số kỹ thuật IEEE-754. Đối với các loại lượng tử hoá, kết quả là luôn là true.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) x tensor loại dấu phẩy động hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
y tensor của loại boolean (C1)

Giới hạn

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

Ví dụ

// 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]

Ví dụ khác

log

Ngữ nghĩa

Thực hiện phép toán logarit theo từng phần tử trên tensor operand và tạo ra một Tensor result. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với số thực độ chính xác đơn: log từ IEEE-754.
  • Đối với số phức: logarit phức.
  • Đối với các kiểu lượng tử hoá: dequantize_op_quantize(log, operand, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]]

Ví dụ khác

log_plus_one

Ngữ nghĩa

Thực hiện lôgarit các phần tử cộng với một phép toán trên tensor operand và tạo ra tensor result. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với số thực độ chính xác đơn: logp1 từ IEEE-754.
  • Đối với số phức: lôgarit phức cộng 1.
  • Đối với các loại lượng tử hoá: dequantize_op_quantize(log_plus_one, operand, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]

Ví dụ khác

hậu cần

Ngữ nghĩa

Thực hiện toán tử logistic trên tensor operand và tạo ra một Tensor result. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với số thực độ chính xác đơn: division(1, addition(1, exp(-x))) từ IEEE-754.
  • Đối với số phức: logistic phức.
  • Đối với các loại lượng tử hoá: dequantize_op_quantize(logistic, operand, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]]

Ví dụ khác

map

Ngữ nghĩa

Áp dụng hàm ánh xạ computation cho inputs dọc theo dimensions và tạo ra tensor result.

Chính thức hơn là result[result_index] = computation(inputs...[result_index]).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) inputs số biến thiên của tensor hoặc tensor lượng tử hoá mỗi tensor (C1–C4)
(I2) dimensions Hằng số tensor 1 chiều thuộc loại si64 (C3)
(I3) computation hàm (C4)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá mỗi tensor (C1), (C4)

Giới hạn

  • (C1) shape(inputs...) = shape(result).
  • (C2) 0 < size(inputs) = N.
  • (C3) dimensions = range(rank(inputs[0])).
  • (C4) computation có loại (tensor<E0>, ..., tensor<EN-1>) -> tensor<E'> trong đó Ei = element_type(inputs[i])E' = element_type(result).

Ví dụ

// %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]]

Ví dụ khác

tối đa

Ngữ nghĩa

Thực hiện phép toán tối đa trên các phần tử trên tensor lhsrhs, đồng thời tạo ra một giá trị Tensor result. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với boolean: logic OR.
  • Đối với số nguyên: số nguyên tối đa.
  • Đối với số thực độ chính xác đơn: maximum từ IEEE-754.
  • Đối với số phức: giá trị tối đa trong từ vựng cho cặp (real, imaginary). Việc áp đặt một thứ tự cho số phức liên quan đến ngữ nghĩa đáng kinh ngạc, vì vậy, trong tương lai, chúng tôi sẽ có kế hoạch ngừng hỗ trợ số phức cho thao tác này (#560).
  • Đối với các loại lượng tử hoá:
    • dequantize_op_quantize(maximum, lhs, rhs, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) lhs tensor hoặc tensor lượng tử hoá mỗi tensor (C1)
(I2) rhs tensor hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]]

Ví dụ khác

tối thiểu

Ngữ nghĩa

Thực hiện phép toán tối thiểu trên các phần tử trên tensor lhsrhs và tạo ra một Tensor result. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với boolean: logic AND.
  • Đối với số nguyên: số nguyên tối thiểu.
  • Đối với số thực độ chính xác đơn: minimum từ IEEE-754.
  • Đối với số phức: giá trị tối thiểu trong từ điển cho cặp (real, imaginary). Việc áp đặt một thứ tự cho số phức liên quan đến ngữ nghĩa đáng kinh ngạc, vì vậy, trong tương lai, chúng tôi sẽ có kế hoạch ngừng hỗ trợ số phức cho thao tác này (#560).
  • Đối với các loại lượng tử hoá:
    • dequantize_op_quantize(minimum, lhs, rhs, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) lhs tensor hoặc tensor lượng tử hoá mỗi tensor (C1)
(I2) rhs tensor hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]]

Ví dụ khác

nhân

Ngữ nghĩa

Thực hiện tích số phần tử của hai tensor lhsrhs và tạo ra một Tensor result. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với boolean: logic AND.
  • Đối với số nguyên: nhân số nguyên.
  • Đối với số thực độ chính xác đơn: multiplication từ IEEE-754.
  • Đối với số phức: phép nhân phức.
  • Đối với các loại lượng tử hoá:
    • dequantize_op_quantize(multiply, lhs, rhs, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) lhs tensor hoặc tensor lượng tử hoá mỗi tensor (C1)
(I2) rhs tensor hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]]

Ví dụ khác

phủ định

Ngữ nghĩa

Thực hiện phép phủ định các phần tử của tensor operand và tạo ra một result tensor. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với số nguyên có dấu: số nguyên âm.
  • Đối với số nguyên chưa ký: bitcast thành số nguyên có dấu, số nguyên âm, bitcast quay lại số nguyên chưa ký.
  • Đối với số thực độ chính xác đơn: negate từ IEEE-754.
  • Đối với số phức: số phủ định phức.
  • Đối với các loại lượng tử hoá: dequantize_op_quantize(negate, operand, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor của số nguyên, dấu phẩy động hoặc kiểu phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của số nguyên, dấu phẩy động hoặc kiểu phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// 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]

Ví dụ khác

không

Ngữ nghĩa

Thực hiện NOT của tensor operand và tạo ra một tensor result. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với boolean: logic NOT.
  • Đối với số nguyên: bitwise NOT.

Đối số

Tên Loại Giới hạn
operand tensor của boolean hoặc kiểu số nguyên (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của boolean hoặc kiểu số nguyên (C1)

Giới hạn

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

Ví dụ

// 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]

Ví dụ khác

optimization_barrier

Ngữ nghĩa

Đảm bảo rằng các thao tác tạo ra operand được thực thi trước khi bất kỳ các toán tử phụ thuộc vào result và ngăn chặn việc biến đổi trình biên dịch di chuyển các hoạt động qua hàng rào. Ngoài ra, thao tác này một danh tính, chẳng hạn như result = operand.

Đối số

Tên Loại Giới hạn
operand số biến thiên của tensor, tensor lượng tử hoá trên mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result số biến thiên của tensor, tensor lượng tử hoá trên mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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

Ví dụ khác

hoặc

Ngữ nghĩa

Thực hiện từng phần tử OR của hai tensor lhsrhs và tạo ra một result tensor. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với boolean: logic OR.
  • Đối với số nguyên: thao tác bit OR.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) lhs tensor của loại số nguyên hoặc boolean (C1)
(I2) rhs tensor của loại số nguyên hoặc boolean (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của loại số nguyên hoặc boolean (C1)

Giới hạn

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

Ví dụ

// 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]]

Ví dụ khác

nguồn cấp dữ liệu ngoài

Ngữ nghĩa

Ghi inputs vào nguồn cấp dữ liệu ngoài và tạo mã thông báo result.

Ngữ nghĩa của outfeed_config được xác định khi triển khai.

Thông tin đầu vào

Hãng nhạc Tên Loại
(I1) inputs số biến thiên của tensor hoặc tensor lượng tử hoá
(I2) token token
(I3) outfeed_config hằng số loại string

Kết quả đầu ra

Tên Loại
result token

Ví dụ

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

Ví dụ khác

đệm

Ngữ nghĩa

Mở rộng operand bằng khoảng đệm xung quanh tensor cũng như giữa các phần tử của tensor với padding_value đã cho.

edge_padding_lowedge_padding_high chỉ định số lượng khoảng đệm đã thêm vào cấp thấp (bên cạnh chỉ số 0) và cấp cao cấp (bên cạnh chỉ số cao nhất) là từng phương diện tương ứng. Số lượng khoảng đệm có thể là số âm, trong đó giá trị tuyệt đối của khoảng đệm âm cho biết số phần tử cần xoá từ thứ nguyên được chỉ định.

interior_padding chỉ định khoảng đệm được thêm vào giữa hai giá trị bất kỳ trong mỗi thứ nguyên không được là số âm. Có khoảng đệm bên trong trước khoảng đệm cạnh sao cho khoảng đệm cạnh âm sẽ xoá các phần tử toán hạng có đệm trong.

Chính thức hơn, result[result_index] được định nghĩa là:

  • operand[operand_index] nếu result_index = edge_padding_low + operand_index * (interior_padding + 1)
  • padding_value.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor hoặc tensor lượng tử hoá mỗi tensor (C1), (C2), (C4)
(I2) padding_value tensor 0 chiều hoặc tensor lượng tử hoá mỗi tensor (C1)
(I3) edge_padding_low Hằng số tensor 1 chiều thuộc loại si64 (C1), (C4)
(I4) edge_padding_high Hằng số tensor 1 chiều thuộc loại si64 (C1), (C4)
(I5) interior_padding Hằng số tensor 1 chiều thuộc loại si64 (C2–C4)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá mỗi tensor (C3–C6)

Giới hạn

  • (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.

Ví dụ

// %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]
//          ]

Ví dụ khác

partition_id

Ngữ nghĩa

Tạo partition_id của quy trình hiện tại.

Kết quả đầu ra

Tên Loại
result Tensor 0 chiều thuộc loại ui32

Ví dụ

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

Ví dụ khác

popcnt

Ngữ nghĩa

Thực hiện đếm số phần tử của số bit đã đặt trong tensor operand và tạo ra tensor result.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor của kiểu số nguyên (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của kiểu số nguyên (C1)

Giới hạn

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

Ví dụ

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

Ví dụ khác

công suất

Ngữ nghĩa

Thực hiện lũy thừa phần tử của tensor lhs bằng tensor rhs và tạo ra tensor result. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với số nguyên: luỹ thừa số nguyên.
  • Đối với số thực độ chính xác đơn: pow từ IEEE-754.
  • Đối với số phức: số mũ phức.
  • Đối với các kiểu lượng tử hoá: dequantize_op_quantize(power, lhs, rhs, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) lhs tensor của số nguyên, dấu phẩy động hoặc kiểu phức hoặc tensor lượng tử hoá mỗi tensor (C1)
(I2) rhs tensor của số nguyên, dấu phẩy động hoặc kiểu phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của số nguyên, dấu phẩy động hoặc kiểu phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]

Ví dụ khác

thực

Ngữ nghĩa

Trích xuất phần thực, tương tự như các phần tử, từ operand và tạo ra một result tensor. Chính thức hơn, đối với mỗi phần tử x: real(x) = is_complex(x) ? real_part(x) : x

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor của dấu phẩy động hoặc loại phức (C1), (C2)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor thuộc loại dấu phẩy động (C1), (C2)

Giới hạn

  • (C1) shape(result) = shape(operand).
  • (C2) element_type(result) được định nghĩa là:
    • complex_element_type(element_type(operand)) nếu is_complex(operand).
    • element_type(operand).

Ví dụ

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

Ví dụ khác

bắt

Ngữ nghĩa

Nhận dữ liệu từ một kênh có channel_id và tạo results.

Nếu is_host_transfertrue thì thao tác sẽ chuyển dữ liệu từ máy chủ lưu trữ. Nếu không, ứng dụng sẽ chuyển dữ liệu từ một thiết bị khác. Ý nghĩa do triển khai xác định. Cờ này sao chép thông tin được cung cấp trong channel_type thân mến, trong tương lai, chúng tôi dự định chỉ giữ lại một trong hai (#666).

results bao gồm các giá trị tải trọng xuất hiện trước và một mã thông báo đi kèm cuối cùng. Trong tương lai, chúng tôi dự định sẽ chia tải trọng và mã thông báo thành hai riêng biệt để cải thiện tính rõ ràng (#670).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) token token (C4)
(I2) channel_id hằng số loại si64
(I3) channel_type enum của DEVICE_TO_DEVICEHOST_TO_DEVICE (C1)
(I4) is_host_transfer hằng số loại i1 (C1)

Kết quả đầu ra

Tên Loại Giới hạn
results số biến thiên của tensor, tensor lượng tử hoá hoặc mã thông báo (C2–C4)

Giới hạn

  • (C1) channel_type được định nghĩa là:
    • HOST_TO_DEVICE nếu is_host_transfer = true,
    • DEVICE_TO_DEVICE.
  • (C2) 0 < size(results).
  • (C3) is_empty(result[:-1]) hoặc is_tensor(type(results[:-1])).
  • (C4) is_token(type(results[-1])).

Ví dụ

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

Ví dụ khác

giảm

Ngữ nghĩa

Áp dụng hàm rút gọn body cho inputsinit_values dọc theo dimensions và tạo ra tensor results.

Thứ tự giảm thiểu được xác định theo phương thức triển khai, tức là bodyinit_values phải tạo một đơn từ để đảm bảo rằng toán tử tạo ra kết quả giống nhau cho tất cả dữ liệu đầu vào trên tất cả các lần triển khai. Tuy nhiên, điều kiện này không có nhiều mức giảm phổ biến. Ví dụ: phép thêm dấu phẩy động cho body và 0 cho init_values không thực sự tạo thành một đơn từ vì phép thêm dấu phẩy động không liên kết.

Chính thức hơn là results...[j0, ..., jR-1] = reduce(input_slices_converted), trong đó:

  • input_slices = inputs...[j0, ..., :, ..., jR-1], trong đó : được chèn lúc 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) cho một số cây nhị phân schedule trong đó:
    • exec(node) = body(exec(node.left), exec(node.right)).
    • exec(leaf) = leaf.value.
  • schedule là cây nhị phân đầy đủ được triển khai xác định, có thứ tự theo thứ tự truyền tải bao gồm:
    • input_slices_converted...[index] giá trị cho tất cả index trong index_space(input_slices_converted) theo thứ tự từ điển tăng dần trong tổng số index.
    • Xen kẽ với một lượng init_values_converted tại các vị trí triển khai được xác định.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) inputs số biến thiên của tensor hoặc tensor lượng tử hoá mỗi tensor (C1-C4), (C6), (C7)
(I2) init_values số biến thiên của tensor 0 chiều hoặc tensor lượng tử hoá mỗi tensor (C2), (C3)
(I3) dimensions Hằng số tensor 1 chiều thuộc loại si64 (C4), (C5), (C7)
(I4) body hàm (C6)

Kết quả đầu ra

Tên Loại Giới hạn
results số biến thiên của tensor hoặc tensor lượng tử hoá mỗi tensor (C3), (C7), (C8)

Giới hạn

  • (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 có loại (tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ..., tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>) trong đó is_promotable(element_type(inputs[i]), Ei).
  • (C7) shape(results...) = shape(inputs...) ngoại trừ phương diện không bao gồm kích thước inputs... tương ứng với dimensions.
  • (C8) element_type(results[i]) = Ei cho tất cả i trong [0,N).

Ví dụ

// %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]

Ví dụ khác

reduce_precision

Ngữ nghĩa

Thực hiện chuyển đổi toàn bộ phần tử của operand sang một loại dấu phẩy động khác sử dụng exponent_bitsmantissa_bits đồng thời quay lại phiên bản gốc dấu phẩy động và tạo ra tensor output.

Chính thức hơn:

  • Các bit mantissa của giá trị ban đầu được cập nhật để làm tròn giá trị ban đầu thành giá trị gần nhất có thể biểu thị bằng mantissa_bits sử dụng ngữ nghĩa roundToIntegralTiesToEven.
  • Sau đó, nếu mantissa_bits nhỏ hơn số bit phần tử của giá trị ban đầu, các bit mantissa được cắt ngắn thành mantissa_bits.
  • Sau đó, nếu các bit mũ của kết quả trung gian không phù hợp với dải ô do exponent_bits cung cấp, kết quả trung gian sẽ tràn sang vô cực bằng cách sử dụng dấu ban đầu hoặc trừ về 0 bằng cách sử dụng phương pháp ký hiệu ban đầu.
  • Đối với các kiểu lượng tử hoá, thực hiện dequantize_op_quantize( lambda operand: reduce_precision(operand, exponent_bits, mantissa_bits), operand, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor loại dấu phẩy động hoặc tensor lượng tử hoá mỗi tensor (C1)
(I2) exponent_bits hằng số loại si32 (C2)
(I3) mantissa_bits hằng số loại si32 (C3)

Kết quả đầu ra

Tên Loại Giới hạn
output tensor loại dấu phẩy động hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// 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]

Ví dụ khác

reduce_scatter

Ngữ nghĩa

reduce_scatter

Trong mỗi nhóm quy trình ở lưới quy trình Ổn địnhHLO, thực hiện giảm thiểu, bằng cách sử dụng computations, trên các giá trị của tensor operand trong mỗi quá trình, chia kết quả rút gọn dọc theo scatter_dimension thành nhiều phần rồi phân tán phần phân tách giữa các quy trình để tạo result.

Thao tác này sẽ chia lưới quy trình StableHLO thành process_groups, tức là được xác định như sau:

  • cross_replica(replica_groups) nếu channel_id <= 0 and use_global_device_ids = false.
  • cross_replica_and_partition(replica_groups) nếu channel_id > 0 and use_global_device_ids = false.
  • flattened_ids(replica_groups) nếu channel_id > 0 and use_global_device_ids = true.

Sau đó, trong mỗi 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] cho tất cả sender trong process_group, trong đó receiver_index = process_group.index(receiver).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor hoặc tensor lượng tử hoá mỗi tensor (C1), (C2), (C7), (C8)
(I2) scatter_dimension hằng số loại si64 (C1), (C2), (C8)
(I3) replica_groups Hằng số tensor 2 chiều thuộc loại si64 (C3–C5)
(I4) channel_id hằng số loại si64 (C6)
(I5) use_global_device_ids hằng số loại i1 (C6)
(I6) computation hàm (C7)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá mỗi tensor (C8–C9)

Giới hạn

  • (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) được định nghĩa là:
    • num_replicas nếu dùng cross_replica.
    • num_replicas nếu dùng cross_replica_and_partition.
    • num_processes nếu dùng flattened_ids.
  • (C5) 0 <= replica_groups < size(replica_groups).
  • (C6) Nếu là use_global_device_ids = true, thì channel_id > 0.
  • (C7) computation có loại (tensor<E>, tensor<E>) -> (tensor<E>) trong đó is_promotable(element_type(operand), E).
  • (C8) shape(result) = shape(operand) ngoại trừ:
    • dim(result, scatter_dimension) = dim(operand, scatter_dimension) / dim(process_groups, 1).
  • (C9) element_type(result) = E.

Ví dụ

// 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]]

Ví dụ khác

reduce_window

Ngữ nghĩa

Áp dụng hàm rút gọn body cho các cửa sổ inputsinit_values và tạo results.

Sơ đồ dưới đây cho thấy cách các phần tử trong results... được tính toán từ inputs... trong một ví dụ cụ thể.

reduce_window

Chính thức hơn, results...[result_index] = reduce(windows, init_values, axes(inputs...), body) (xem giảm) trong đó:

  • 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).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) inputs số biến thiên của tensor hoặc tensor lượng tử hoá mỗi tensor (C1-C4), (C6), (C8), (C10), (C12), (C13), (C15)
(I2) init_values số biến thiên của tensor 0 chiều hoặc tensor lượng tử hoá mỗi tensor (C1), (C13)
(I3) window_dimensions Hằng số tensor 1 chiều thuộc loại si64 (C4), (C5), (C15)
(I4) window_strides Hằng số tensor 1 chiều thuộc loại si64 (C6), (C7), (C15)
(I5) base_dilations Hằng số tensor 1 chiều thuộc loại si64 (C8), (C9), (C15)
(I6) window_dilations Hằng số tensor 1 chiều thuộc loại si64 (C10), (C11), (C15)
(I7) padding Hằng số tensor 2 chiều thuộc loại si64 (C12), (C15)
(I8) body hàm (C13)

Kết quả đầu ra

Tên Loại Giới hạn
results số biến thiên của tensor hoặc tensor lượng tử hoá mỗi tensor (C1), (C14-C16)

Giới hạn

  • (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 có loại (tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ..., tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>) trong đó is_promotable(element_type(inputs[i]), Ei).
  • (C14) same(shape(results...)).
  • (C15) shape(results[0]) = num_windows trong đó:
    • 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 cho tất cả i trong [0,N).

Ví dụ

// %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]]

Ví dụ khác

phần còn lại

Ngữ nghĩa

Thực hiện số dư phần tử tương ứng của số bị chia lhs và tensor rhs của số chia và tạo ra tensor result.

Một cách chính thức hơn, dấu hiệu của kết quả được lấy từ cổ tức, và giá trị tuyệt đối của kết quả luôn nhỏ hơn giá trị tuyệt đối của số chia. Phần còn lại được tính là lhs - d * rhs, trong đó d được tính theo:

  • Đối với số nguyên: stablehlo.divide(lhs, rhs).
  • Đối với số thực có độ chính xác đơn: division(lhs, rhs) từ IEEE-754 với thuộc tính làm tròn roundTowardZero
  • Đối với số phức: TBD (#997).
  • Đối với các loại lượng tử hoá:
    • dequantize_op_quantize(remainder, lhs, rhs, type(result)).

Đối với các loại phần tử dấu phẩy động, thao tác này trái ngược với Toán tử remainder từ quy cách của IEEE-754, trong đó d là một giá trị không thể thiếu gần giá trị chính xác nhất của lhs/rhs với mối quan hệ với số chẵn.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) lhs tensor của số nguyên, kiểu dấu phẩy động hoặc kiểu phức hoặc tensor lượng tử hoá mỗi tensor (C1)
(I2) rhs tensor của số nguyên, kiểu dấu phẩy động hoặc kiểu phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của số nguyên, kiểu dấu phẩy động hoặc kiểu phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]

Ví dụ khác

replica_id

Ngữ nghĩa

Tạo replica_id của quy trình hiện tại.

Kết quả đầu ra

Tên Loại
result Tensor 0 chiều thuộc loại ui32

Ví dụ

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

Ví dụ khác

đổi hình dạng

Ngữ nghĩa

Thực hiện việc đổi hình dạng tensor operand thành tensor result. Về mặt lý thuyết, đây là tương đương với việc giữ nguyên cách trình bày chuẩn hoá nhưng có thể thay đổi hình dạng, ví dụ: từ tensor<2x3xf32> đến tensor<3x2xf32> hoặc tensor<6xf32>.

Chính thức hơn, result[result_index] = operand[operand_index] trong đó result_indexoperand_index ở cùng vị trí trong từ điển là index_space(result)index_space(operand).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor hoặc tensor lượng tử hoá (C1–C3)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá (C1–C3)

Giới hạn

  • (C1) element_type(result) được cung cấp bởi:
    • element_type(operand), nếu !is_per_axis_quantized(operand).
    • element_type(operand) ngoại trừ quantization_dimension(operand) và Nếu không thì quantization_dimension(result) có thể khác.
  • (C2) size(operand) = size(result).
  • (C3) Nếu 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).

Ví dụ

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

Ví dụ khác

đảo ngược

Ngữ nghĩa

Đảo ngược thứ tự các phần tử trong operand dọc theo dimensions được chỉ định và tạo ra tensor result. Một cách chính thức hơn, result[result_index] = operand[operand_index] trong đó:

  • operand_index[d] = dim(result, d) - result_index[d] - 1 nếu là d trong dimensions.
  • operand_index[d] = result_index[d].

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor hoặc tensor lượng tử hoá mỗi tensor (C1), (C3)
(I2) dimensions Hằng số tensor 1 chiều thuộc loại si64 (C2), (C3)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá mỗi tensor (C1), (C3)

Giới hạn

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

Ví dụ

// %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]]

Ví dụ khác

rng

Ngữ nghĩa

Tạo số ngẫu nhiên bằng thuật toán rng_distribution rồi cho ra tensor result của một hình dạng cho trước shape.

Nếu giá trị là rng_distribution = UNIFORM, thì các số ngẫu nhiên sẽ được tạo theo phân phối đồng đều trong khoảng [a, b). Nếu giá trị là a >= b, hành vi là không xác định.

Nếu giá trị là rng_distribution = NORMAL, thì các số ngẫu nhiên sẽ được tạo tuân theo phân phối chuẩn với giá trị trung bình = a và độ lệch chuẩn = b. Nếu là b < 0, hành vi này là không xác định.

Việc triển khai xác định cách chính xác cách tạo số ngẫu nhiên. Cho ví dụ: chúng có thể hoặc không thể mang tính tất định và có thể sử dụng hoặc không sử dụng trạng thái ẩn.

Khi thảo luận với nhiều bên liên quan, cơ hội này đã đi đến hiệu quả không được dùng nữa. Vì vậy, trong tương lai, chúng tôi dự định sẽ tìm hiểu việc loại bỏ tính năng này (#597).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) a Tensor 0 chiều của kiểu số nguyên, boolean hoặc dấu phẩy động (C1), (C2)
(I2) b Tensor 0 chiều của kiểu số nguyên, boolean hoặc dấu phẩy động (C1), (C2)
(I3) shape Hằng số tensor 1 chiều thuộc loại si64 (C3)
(I4) rng_distribution enum của UNIFORMNORMAL (C2)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của loại số nguyên, boolean hoặc dấu phẩy động (C1–C3)

Giới hạn

  • (C1) element_type(a) = element_type(b) = element_type(result).
  • (C2) Nếu là rng_distribution = NORMAL, thì is_float(a).
  • (C3) shape(result) = shape.

Ví dụ

// %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

Ngữ nghĩa

Trả về một output được điền sẵn các bit ngẫu nhiên đồng nhất và trạng thái đầu ra đã cập nhật output_state sử dụng thuật toán tạo số giả ngẫu nhiên rng_algorithm với trạng thái ban đầu initial_state. Kết quả được đảm bảo hàm tất định của initial_state, nhưng không đảm bảo sẽ là mang tính quyết định giữa các lần triển khai.

rng_algorithm là một trong những quốc gia sau:

  • DEFAULT: Thuật toán do phương thức triển khai xác định.
  • THREE_FRY: Biến thể do triển khai xác định của thuật toán Threefry.*
  • PHILOX: Biến thể do thuật toán Philox xác định dựa trên việc triển khai.*

* Xem: Salmon và cộng sự. SC 2011. Số ngẫu nhiên song song: dễ dàng như 1, 2, 3.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) rng_algorithm enum DEFAULT, THREE_FRYPHILOX (C2)
(I2) initial_state Tensor 1 chiều thuộc loại ui64 (C1), (C2)

Kết quả đầu ra

Tên Loại Giới hạn
output_state Tensor 1 chiều thuộc loại ui64 (C1)
output tensor của loại số nguyên hoặc dấu phẩy động

Giới hạn

  • (C1) type(initial_state) = type(output_state).
  • (C2) size(initial_state) được định nghĩa là:
    • phương thức triển khai được xác định nếu là rng_algorithm = DEFAULT.
    • 2 nếu rng_algorithm = THREE_FRY.
    • 2 hoặc 3 nếu rng_algorithm = PHILOX.

Ví dụ

// %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

Ngữ nghĩa

Thực hiện làm tròn các phần tử về phía số nguyên gần nhất, phá vỡ các mối liên kết từ 0, trên tensor operand và tạo ra tensor result. Triển khai toán tử roundToIntegralTiesToAway từ thông số kỹ thuật IEEE-754. Cho loại lượng tử hoá, thực hiện dequantize_op_quantize(round_nearest_afz, operand, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor loại dấu phẩy động hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor loại dấu phẩy động hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]

Ví dụ khác

round_nearest_even

Ngữ nghĩa

Thực hiện làm tròn các phần tử tới số nguyên gần nhất, phá vỡ các mối liên kết về số nguyên chẵn, trên tensor operand và tạo ra giá trị result tensor. Triển khai thao tác roundToIntegralTiesToEven từ IEEE-754 đặc điểm kỹ thuật. Đối với các kiểu lượng tử hoá, dequantize_op_quantize(round_nearest_even, operand, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor loại dấu phẩy động hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor loại dấu phẩy động hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]

Ví dụ khác

rsqrt

Ngữ nghĩa

Thực hiện phép toán căn bậc hai nghịch đảo chỉ định các phần tử trên tensor operand và tạo ra tensor result. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với số thực độ chính xác đơn: rSqrt từ IEEE-754.
  • Đối với số phức: căn bậc hai nghịch đảo phức.
  • Đối với các kiểu lượng tử hoá: dequantize_op_quantize(rsqrt, operand, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]]

Ví dụ khác

tán xạ

Ngữ nghĩa

Tạo ra tensor results tương đương với inputs tensor, ngoại trừ một số lát cắt do scatter_indices chỉ định được cập nhật bằng các giá trị updates sử dụng update_computation.

Sơ đồ dưới đây cho thấy cách các phần tử trong updates... ánh xạ đến các phần tử trong results... trong một ví dụ cụ thể. Biểu đồ này chọn một vài ví dụ updates... lập chỉ mục và giải thích chi tiết results... lập chỉ mục chúng tương ứng với.

tán xạ

Chính thức hơn, cho tất cả update_index trong 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 được định nghĩa là:
    • scatter_indices[si0, ..., :, ..., siN], trong đó si là cá nhân các phần tử trong update_scatter_index: được chèn vào Chỉ mục index_vector_dim, nếu index_vector_dim < rank(scatter_indices).
    • [scatter_indices[update_scatter_index]].
  • Đối với d_input trong axes(inputs[0]),
    • full_start_index[d_input] = start_index[d_start] nếu d_input = scatter_dims_to_operand_dims[d_start]
    • full_start_index[d_input] = 0.
  • Đối với d_input trong axes(inputs[0]),
    • full_batching_index[d_input] = update_scatter_index[d_start - (d_start < index_vector_dim ? 0 : 1)] nếu 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], trong đó wi là cá nhân các phần tử trong update_window_index0 được chèn vào các chỉ mục từ inserted_window_dimsinput_batching_dims.
  • result_index = full_start_index + full_batching_index + full_window_index.

Do đó, results = exec(schedule, inputs), trong đó:

  • schedule là hoán vị do triển khai xác định của index_space(updates[0])
  • exec([update_index, ...], results) = exec([...], updated_results) trong đó:
    • Nếu result_index nằm trong giới hạn của 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 là bản sao của resultsresults...[result_index] được đặt thành updated_values....
    • Hoặc
    • updated_results = results.
  • exec([], results) = results.

Nếu indices_are_sortedtrue thì quá trình triển khai có thể giả định rằng scatter_indices được sắp xếp theo scatter_dims_to_operand_dims, nếu không thì hành vi là không xác định. Trang trọng hơn, cho tất cả i1 < i2 từ indices(result), full_start_index(i1) <= full_start_index(i2).

Nếu unique_indicestrue thì quá trình triển khai có thể giả định rằng tất cả Chỉ mục result_index được phân tán là duy nhất. Nếu unique_indicestrue nhưng các chỉ mục được phân tán đến không phải là duy nhất thì hành vi là chưa xác định.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) inputs số biến thiên của tensor hoặc tensor lượng tử hoá mỗi tensor (C1), (C2), (C4-C6), (C11), (C13), (C18), (C21), (C23-C24)
(I2) scatter_indices tensor của kiểu số nguyên (C4), (C15), (C19), (C22)
(I3) updates số biến thiên của tensor hoặc tensor lượng tử hoá mỗi tensor (C3-C6), (C8)
(I4) update_window_dims Hằng số tensor 1 chiều thuộc loại si64 (C2), (C4), (C7-C8)
(I5) inserted_window_dims Hằng số tensor 1 chiều thuộc loại si64 (C2), (C4), (C9-C11)
(I6) input_batching_dims Hằng số tensor 1 chiều thuộc loại si64 (C2), (C4), (C9), (C12-13), (C17-18), (C20)
(I7) scatter_indices_batching_dims Hằng số tensor 1 chiều thuộc loại si64 (C14–C18)
(I8) scatter_dims_to_operand_dims Hằng số tensor 1 chiều thuộc loại si64 (C19–C21)
(I9) index_vector_dim hằng số loại si64 (C4), (C16), (C19), (C22)
(I10) indices_are_sorted hằng số loại i1
(I11) unique_indices hằng số loại i1
(I12) update_computation hàm (C23)

Kết quả đầu ra

Tên Loại Giới hạn
results số biến thiên của tensor hoặc tensor lượng tử hoá mỗi tensor (C24–C25)

Giới hạn

  • (C1) same(shape(inputs...)).
  • (C2) `thứ hạng(đầu vào[0]) = kích thước(update_window_dims) + kích thước(inserted_window_dims)
    • size(input_batching_dims)`.
  • (C3) same(shape(updates...)).
  • (C4) shape(updates[0]) = combine(update_scatter_dim_sizes, update_window_dim_sizes) trong đó:
    • update_scatter_dim_sizes = shape(scatter_indices) ngoại trừ kích thước kích thước của scatter_indices tương ứng với Không bao gồm index_vector_dim.
    • update_window_dim_sizes <= shape(inputs[0]) ngoại trừ các kích thước kích thước trong inputs[0] tương ứng với inserted_window_dimsinput_batching_dims không được đưa vào.
    • combine đặt update_scatter_dim_sizes tại các trục tương ứng với update_scatter_dimsupdate_window_dim_sizes tại các trục tương ứng đến 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 có loại (tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ..., tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>), trong đó is_promotable(element_type(inputs[i]), Ei).
  • (C24) shape(inputs...) = shape(results...).
  • (C25) element_type(results[i]) = Ei cho tất cả i trong [0,N).

Ví dụ

// %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]]
//           ]
//          ]

Ví dụ khác

chọn

Ngữ nghĩa

Tạo một tensor result trong đó mỗi phần tử được chọn từ on_true hoặc Tensor on_false dựa trên giá trị của phần tử pred tương ứng. Chính thức hơn là result[result_index] = pred_element ? on_true[result_index] : on_false[result_index], trong đó pred_element = rank(pred) = 0 ? pred[] : pred[result_index]. Đối với các kiểu lượng tử hoá, dequantize_select_quantize(pred, on_true, on_false, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) pred tensor thuộc loại i1 (C1)
(I2) on_true tensor hoặc tensor lượng tử hoá mỗi tensor (C1–C2)
(I3) on_false tensor hoặc tensor lượng tử hoá mỗi tensor (C2)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá mỗi tensor (C2)

Giới hạn

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

Ví dụ

// %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]]

Ví dụ khác

select_and_scatter

Ngữ nghĩa

Phân tán các giá trị từ tensor source bằng cách sử dụng scatter dựa trên kết quả của reduce_window của tensor input sử dụng select và tạo ra tensor result.

Sơ đồ dưới đây cho thấy cách các phần tử trong result được tính toán từ operandsource trong một ví dụ cụ thể.

select_and_scatter

Chính thức hơn:

  • selected_values = reduce_window_without_init(...) với các giá trị nhập sau:

    • inputs = [operand].
    • window_dimensions, window_stridespadding được sử dụng nguyên trạng.
    • base_dilations = windows_dilations = 1.
    • body được định nghĩa là:
    def body(arg0: tensor<E>, arg1: tensor<E>) -> tensor<E>:
      return select(arg0, arg1) ? arg0 : arg1;
    

    nơi E = element_type(operand)reduce_window_without_init hoạt động giống hệt như reduce_window, ngoại trừ schedule của phần tử cơ bản reduce (xem giảm) không bao gồm giá trị khởi tạo. Hiện tại không chỉ định điều gì sẽ xảy ra nếu cửa sổ tương ứng không có giá trị (#731).

  • result[result_index] = reduce([source_values], [init_value], [0], scatter) trong đó:

    • source_values = [source[source_index] for source_index in source_indices].
    • selected_index(source_index) = operand_index nếu selected_values[source_index] có phần tử operand từ operand_index.
    • source_indices = [source_index for source_index in indices(source) if selected_index(source_index) = result_index].

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor hoặc tensor lượng tử hoá mỗi tensor (C1-C4), (C6), (C8-C11)
(I2) source tensor hoặc tensor lượng tử hoá mỗi tensor (C1), (C2)
(I3) init_value tensor 0 chiều hoặc tensor lượng tử hoá mỗi tensor (C3)
(I4) window_dimensions Hằng số tensor 1 chiều thuộc loại si64 (C2), (C4), (C5)
(I5) window_strides Hằng số tensor 1 chiều thuộc loại si64 (C2), (C6), (C7)
(I6) padding Hằng số tensor 2 chiều thuộc loại si64 (C2), (C8)
(I7) select hàm (C9)
(I8) scatter hàm (C10)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá mỗi tensor (C11–C12)

Giới hạn

  • (C1) element_type(operand) = element_type(source).
  • (C2) shape(source) = num_windows trong đó:
    • 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 có loại (tensor<E>, tensor<E>) -> tensor<i1> trong đó E = element_type(operand).
  • (C10) scatter có loại (tensor<E>, tensor<E>) -> tensor<E> trong đó is_promotable(element_type(operand), E).
  • (C11) shape(operand) = shape(result).
  • (C12) element_type(result) = E.

Ví dụ

// %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]]

Ví dụ khác

gửi

Ngữ nghĩa

Gửi inputs đến kênh channel_id và tạo mã thông báo result.

Nếu is_host_transfertrue thì thao tác này sẽ truyền dữ liệu đến máy chủ lưu trữ. Nếu không, thiết bị này sẽ chuyển dữ liệu sang một thiết bị khác. Ý nghĩa do triển khai xác định. Cờ này sao chép thông tin được cung cấp trong channel_type thân mến, trong tương lai, chúng tôi dự định chỉ giữ lại một trong hai (#666).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) inputs số biến thiên của tensor hoặc tensor lượng tử hoá
(I2) token token
(I3) channel_id hằng số loại si64
(I4) channel_type enum của DEVICE_TO_DEVICEDEVICE_TO_HOST (C1)
(I5) is_host_transfer hằng số loại i1 (C1)

Kết quả đầu ra

Tên Loại
result token

Giới hạn

  • (C1) channel_type được định nghĩa là:
    • DEVICE_TO_HOST nếu is_host_transfer = true,
    • DEVICE_TO_DEVICE.

Ví dụ

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

Ví dụ khác

shift_left

Ngữ nghĩa

Thực hiện thao tác chuyển dịch trái sang trái trên tensor lhs theo số rhs bit và tạo ra tensor result.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) lhs tensor của kiểu số nguyên (C1)
(I2) rhs tensor của kiểu số nguyên (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của kiểu số nguyên (C1)

Giới hạn

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

Ví dụ

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

Ví dụ khác

shift_right_arithmetic

Ngữ nghĩa

Thực hiện phép dịch chuyển sang phải số học từng phần tử trên tensor lhs bằng rhs số bit và tạo ra một tensor result.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) lhs tensor của kiểu số nguyên (C1)
(I2) rhs tensor của kiểu số nguyên (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của kiểu số nguyên (C1)

Giới hạn

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

Ví dụ

// %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]

Ví dụ khác

shift_right_logical

Ngữ nghĩa

Thực hiện thao tác dịch chuyển sang phải logic các phần tử trên tensor lhs bằng rhs số bit và tạo ra tensor result.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) lhs tensor của kiểu số nguyên (C1)
(I2) rhs tensor của kiểu số nguyên (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của kiểu số nguyên (C1)

Giới hạn

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

Ví dụ

// %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]

Ví dụ khác

biển báo

Ngữ nghĩa

Trả về dấu của phần tử operand và tạo ra một tensor result. Chính thức hơn, đối với mỗi phần tử x, ngữ nghĩa có thể được biểu thị bằng cách sử dụng Cú pháp Python như sau:

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)))

Đối với các kiểu lượng tử hoá, dequantize_op_quantize(sign, operand, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor của số nguyên có dấu, dấu phẩy động hoặc kiểu phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của số nguyên có dấu, dấu phẩy động hoặc kiểu phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// 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]

Ví dụ khác

sin

Ngữ nghĩa

Thực hiện phép toán sin toàn phần trên tensor operand và tạo ra một result tensor. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với số thực độ chính xác đơn: sin từ IEEE-754.
  • Đối với số phức: sin phức.
  • Đối với các kiểu lượng tử hoá: dequantize_op_quantize(sine, operand, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]]

Ví dụ khác

lát cắt

Ngữ nghĩa

Trích xuất một lát cắt từ operand bằng cách sử dụng các chỉ mục khởi đầu tính toán cố định và tạo ra tensor result. start_indices chứa các chỉ mục bắt đầu của lát cắt cho từng phương diện, limit_indices chứa chỉ mục kết thúc (không bao gồm) cho phần của mỗi phương diện và strides chứa các sải chân cho từng phương diện.

Chính thức hơn, result[result_index] = operand[operand_index] trong đó operand_index = start_indices + result_index * strides

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor hoặc tensor lượng tử hoá mỗi tensor (C1–C3), (C5)
(I2) start_indices Hằng số tensor 1 chiều thuộc loại si64 (C2), (C3), (C5)
(I3) limit_indices Hằng số tensor 1 chiều thuộc loại si64 (C2), (C3), (C5)
(I4) strides Hằng số tensor 1 chiều thuộc loại si64 (C2), (C4)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá mỗi tensor (C1), (C5)

Giới hạn

  • (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).

Ví dụ

// %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]
//           ]

Ví dụ khác

sắp xếp

Ngữ nghĩa

Sắp xếp các lát cắt 1 chiều của inputs dọc theo chiều dimension với nhau, theo comparator và tạo ra results.

Không giống như dữ liệu đầu vào tương tự trong các thao tác khác, dimension cho phép các giá trị âm, với ngữ nghĩa được mô tả bên dưới. Trong tương lai, nội dung này có thể không được phép để đảm bảo tính nhất quán (#1377).

Nếu is_stable là đúng thì cách sắp xếp sẽ ổn định, tức là thứ tự tương đối của các phần tử được xem là bằng nhau của đối tượng so sánh vẫn được giữ nguyên. Đối với trường hợp trong đó chỉ có một đầu vào duy nhất, thì hai phần tử e1e2 được coi là bằng với phương pháp so sánh khi và chỉ khi comparator(e1, e2) = comparator(e2, e1) = false. Hãy xem nội dung chính thức dưới đây về cách khái quát hoá cho nhiều dữ liệu đầu vào.

Chính thức hơn, cho tất cả result_index trong index_space(results[0]):

  • adjusted_dimension = dimension >= 0 ? dimension : rank(inputs[0]) + dimension.
  • result_slice = [ri0, ..., :, ..., riR-1], trong đó riN là cá nhân trong result_index: được chèn tại adjusted_dimension.
  • inputs_together = (inputs[0]..., ..., inputs[N-1]...).
  • results_together[result_slice] = sort(inputs_together[result_slice], comparator_together).
  • trong đó sort sắp xếp một lát cắt 1 chiều theo thứ tự không giảm dần. rằng comparator_together trả về true nếu đối số bên trái là nhỏ hơn đối số giây bên phải.
  • 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.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) inputs số biến thiên của tensor hoặc tensor lượng tử hoá mỗi tensor (C1–C5)
(I2) dimension hằng số loại si64 (C4)
(I3) is_stable hằng số loại i1
(I4) comparator hàm (C5)

Kết quả đầu ra

Tên Loại Giới hạn
results số biến thiên của tensor hoặc tensor lượng tử hoá mỗi tensor (C2), (C3)

Giới hạn

  • (C1) 0 < size(inputs).
  • (C2) type(inputs...) = type(results...).
  • (C3) same(shape(inputs...) + shape(results...)).
  • (C4) -R <= dimension < R, trong đó R = rank(inputs[0]).
  • (C5) comparator có loại (tensor<E1>, tensor<E1>, ..., tensor<EN-1>, tensor<EN-1>) -> tensor<i1>, trong đó Ei = element_type(inputs[i]).

Ví dụ

// %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]]

Ví dụ khác

sqrt

Ngữ nghĩa

Thực hiện phép toán căn bậc hai của các phần tử trên tensor operand và tạo ra một Tensor result. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với số thực độ chính xác đơn: squareRoot từ IEEE-754.
  • Đối với số phức: căn bậc hai phức.
  • Đối với các kiểu lượng tử hoá: dequantize_op_quantize(sqrt, operand, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]]

Ví dụ khác

trừ

Ngữ nghĩa

Thực hiện phép trừ từng phần tử của hai tensor lhsrhs và tạo ra một Tensor result. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với số nguyên: phép trừ số nguyên.
  • Đối với số thực độ chính xác đơn: subtraction từ IEEE-754.
  • Đối với số phức: phép trừ phức.
  • Đối với các loại lượng tử hoá:
    • dequantize_op_quantize(subtract, lhs, rhs, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) lhs tensor của số nguyên, dấu phẩy động hoặc kiểu phức hoặc tensor lượng tử hoá mỗi tensor (C1)
(I2) rhs tensor của số nguyên, dấu phẩy động hoặc kiểu phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của số nguyên, dấu phẩy động hoặc kiểu phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]]

Ví dụ khác

tan

Ngữ nghĩa

Thực hiện phép toán tiếp tuyến của các phần tử trên tensor operand và tạo ra một Tensor result. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với số thực độ chính xác đơn: tan từ IEEE-754.
  • Đối với số phức: tan phức.
  • Đối với các kiểu lượng tử hoá: dequantize_op_quantize(tan, operand, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %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]
//          ]

Ví dụ khác

tanh

Ngữ nghĩa

Thực hiện phép toán tang hyperbol theo các phần tử trên tensor operand và tạo ra tensor result. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với số thực độ chính xác đơn: tanh từ IEEE-754.
  • Đối với số phức: tan hyperbol phức.
  • Đối với các loại lượng tử hoá:
    • dequantize_op_quantize(tanh, operand, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

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

Ví dụ

// %operand: [-1.0, 0.0, 1.0]
%result = "stablehlo.tanh"(%operand) : (tensor<3xf32>) -> tensor<3xf32>
// %result: [-0.76159416, 0.0, 0.76159416]

Ví dụ khác

hoán vị

Ngữ nghĩa

Bật tiếng các chiều của tensor operand bằng cách sử dụng permutation và tạo ra một Tensor result. Chính thức hơn, result[result_index] = operand[operand_index] trong đó result_index[d] = operand_index[permutation[d]].

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor hoặc tensor lượng tử hoá (C1–C4)
(I2) permutation Hằng số tensor 1 chiều thuộc loại si64 (C2–C4)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor hoặc tensor lượng tử hoá (C1), (C3–C4)

Giới hạn

  • (C1) element_type(result) được cung cấp bởi:
    • element_type(operand), nếu !is_per_axis_quantized(operand).
    • element_type(operand) ngoại trừ quantization_dimension(operand) và Nếu không thì quantization_dimension(result) có thể khác.
  • (C2) permutation là hoán vị của range(rank(operand)).
  • (C3) shape(result) = dim(operand, permutation...).
  • (C4) Nếu là is_per_axis_quantized(result), thì quantization_dimension(operand) = permutation(quantization_dimension(result))

Ví dụ

// %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]]
//          ]

Ví dụ khác

triangular_solve

Ngữ nghĩa

Giải các lô hệ phương trình tuyến tính có tam giác dưới hoặc trên ma trận hệ số.

Chính thức hơn, với ab, result[i0, ..., iR-3, :, :] là giải pháp đến op(a[i0, ..., iR-3, :, :]) * x = b[i0, ..., iR-3, :, :] khi left_sidetrue hoặc x * op(a[i0, ..., iR-3, :, :]) = b[i0, ..., iR-3, :, :] khi left_sidefalse, giải quyết biến x trong đó op(a) được xác định của transpose_a. Đó có thể là một trong những điều sau:

  • NO_TRANSPOSE: Thực hiện thao tác bằng cách sử dụng a nguyên trạng.
  • TRANSPOSE: Thực hiện thao tác khi hoán vị a.
  • ADJOINT: Thực hiện thao tác hoán vị liên hợp của a.

Dữ liệu đầu vào chỉ được đọc từ tam giác dưới của a, nếu lowertrue hoặc tam giác trên của a, nếu không. Dữ liệu đầu ra được trả về trong cùng một tam giác; các giá trị trong tam giác khác được triển khai xác định.

Nếu unit_diagonal là đúng, thì quá trình triển khai có thể giả định rằng đường chéo các phần tử của a bằng 1, nếu không thì hành vi là không xác định.

Đối với các kiểu lượng tử hoá, dequantize_op_quantize(lambda x, y: triangular_solve(x, y, left_side, lower, unit_diagonal, transpose_a), a, b, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) a tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1–C3)
(I2) b tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1–C4)
(I3) left_side hằng số loại i1 (C3)
(I4) lower hằng số loại i1
(I5) unit_diagonal hằng số loại i1
(I6) transpose_a enum NO_TRANSPOSE, TRANSPOSEADJOINT

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của dấu phẩy động hoặc loại phức hoặc tensor lượng tử hoá mỗi tensor (C1)

Giới hạn

  • (C1) baseline_element_type(a) = baseline_element_type(b).
  • (C2) 2 <= rank(a) = rank(b) = R.
  • (C3) Mối quan hệ giữa shape(a)shape(b) được định nghĩa như sau:
    • 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).

Ví dụ

// %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]
//          ]

bộ dữ liệu

Ngữ nghĩa

Tạo một bộ dữ liệu result từ các giá trị val.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) val số lượng giá trị biến thiên (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result bộ dữ liệu (C1)

Giới hạn

  • (C1) result có loại tuple<E0, ..., EN-1> trong đó Ei = type(val[i]).

Ví dụ

// %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))

Ví dụ khác

uniform_dequantize

Ngữ nghĩa

Thực hiện chuyển đổi phần tử thông minh của tensor lượng tử hoá operand thành tensor dấu phẩy động result theo tham số lượng tử hoá đã xác định theo loại operand.

Chính thức hơn là result = dequantize(operand).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor lượng tử hoá (C1), (C2)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor thuộc loại dấu phẩy động (C1), (C2)

Giới hạn

  • (C1) shape(operand) = shape(result).
  • (C2) element_type(result) = expressed_type(operand).

Ví dụ

// %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

Ngữ nghĩa

Thực hiện chuyển đổi từng phần tử của tensor dấu phẩy động hoặc tensor lượng tử hoá operand sang tensor lượng tử hoá result theo lượng tử hoá tham số do loại result xác định.

Một cách chính thức hơn,

  • Nếu giá trị là is_float(operand):
    • result = quantize(operand, type(result)).
  • Nếu giá trị là is_quantized(operand):
    • float_result = dequantize(operand).
    • result = quantize(float_result, type(result)).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand tensor của loại dấu phẩy động hoặc lượng tử hoá (C1), (C2)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor lượng tử hoá (C1), (C2)

Giới hạn

  • (C1) shape(operand) = shape(result).
  • (C2) expressed_type(result) = is_float(operand) ? element_type(operand) : expressed_type(operand).

Ví dụ

// %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]

trong khi

Ngữ nghĩa

Tạo kết quả từ việc thực thi hàm body từ 0 lần trở lên trong khi Hàm cond đầu ra true. Chính thức hơn, ngữ nghĩa có thể được biểu thị sử dụng cú pháp Python như sau:

internal_state = operand
while cond(*internal_state):
  internal_state = body(*internal_state)
results = internal_state

Hành vi của vòng lặp vô hạn sẽ được xác định sau (#383).

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) operand số biến thiên của tensor, tensor lượng tử hoá hoặc mã thông báo (C1–C3)
(I2) cond hàm (C1)
(I3) body hàm (C2)

Kết quả đầu ra

Tên Loại Giới hạn
results số biến thiên của tensor, tensor lượng tử hoá hoặc mã thông báo (C3)

Giới hạn

  • (C1) cond có loại (T0, ..., TN-1) -> tensor<i1>, trong đó Ti = type(operand[i]).
  • (C2) body có loại (T0, ..., TN-1) -> (T0, ..., TN-1), trong đó Ti = type(operand[i]).
  • (C3) type(results...) = type(operand...).

Ví dụ

// %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

Ví dụ khác

xor

Ngữ nghĩa

Thực hiện XOR toàn phần của 2 tensor lhsrhs rồi tạo result tensor. Tuỳ thuộc vào loại phần tử, hãy thực hiện các thao tác sau:

  • Đối với boolean: XOR logic.
  • Đối với số nguyên: bitwise XOR.

Thông tin đầu vào

Hãng nhạc Tên Loại Giới hạn
(I1) lhs tensor của boolean hoặc kiểu số nguyên (C1)
(I2) rhs tensor của boolean hoặc kiểu số nguyên (C1)

Kết quả đầu ra

Tên Loại Giới hạn
result tensor của boolean hoặc kiểu số nguyên (C1)

Giới hạn

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

Ví dụ

// 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]]

Ví dụ khác

Khả năng tương tác phương ngữ

Hiện tại, các chương trình StableHLO trong môi trường tự nhiên đôi khi có chứa các hoạt động không được StableHLO xác định.

Mô-đun, chức năng, cuộc gọi và trả lại

StableHLO sử dụng các thao tác MLIR ngược dòng cho ModuleOp, FuncOp, CallOp, và Trả lại hàng Điều này được thực hiện để tương tác tốt hơn với máy móc MLIR hiện có, các thẻ và vé hữu ích được viết nhắm mục tiêu đến FuncOp và ModuleOp, cùng với nhiều cấu hình biên dịch quy trình nào cũng mong đợi sẽ có các hoạt động này. Đảm bảo khả năng tương thích đầy đủ áp dụng cho các hoạt động này. Nếu có bất cứ thay đổi nào về các hoạt động này trong theo cách không tương thích (tức là xoá bỏ), thì phiên bản tương đương của StableHLO sẽ được thêm vào để duy trì khả năng tương thích.

CHLO

Cơ chế hoạt động CHLO chứa các toán tử cấp cao hơn được phân rã thành StableHLO. Hiện tại, chúng tôi không đảm bảo khả năng tương thích cho CHLO. Để đảm bảo khả năng tương thích đảm bảo, thẻ chlo-legalize-to-stablehlo phải được sử dụng trước khi chuyển đổi tuần tự.

Phép toán về hình dạng

Đây là một trường hợp sử dụng phổ biến trong cộng đồng khi người dùng sử dụng một số thao tác từ Phương ngữ MLIR trong các chương trình ổn định động để thực hiện việc tính toán hình dạng. Các ngôn ngữ này phổ biến nhất bao gồm shape phương ngữ hoạt động như shape_of hoặc num_elements, tensor phương ngữ các hoạt động như dim hoặc from_elements và loại index tích hợp.

RFC về động lực > O2 biểu thị những thao tác này nằm ngoài phạm vi hỗ trợ, tuy nhiên, một số hỗ trợ cho các loại index là được đưa vào cho mục đích tương tác. Không có đảm bảo về khả năng tương thích cho các định dạng này hoạt động hoặc loại hoạt động cụ thể. shape-legalize-to-stablehlo (hình dạng hợp pháp hoá thành ổn định) có thể dùng để chuyển đổi các thao tác này thành hoạt động ổn định được hỗ trợ đầy đủ.

Hoạt động không dùng nữa

Có một số thao tác ổn định HLO được kế thừa từ MHLO không được dùng nữa và sắp được rời khỏi StableHLO. Thông tin đầy đủ về Bạn có thể xem các yêu cầu xoá trong phần StableHLO v1.0 Cleanup #2283. Vấn đề về trình theo dõi đối với những trường hợp ngừng sử dụng này là #2340.

Những thao tác này thuộc một số loại:

  • "Không có trong HLO" loại hoạt động ổn định – ban đầu chúng là một phần của hoạt động của StableHLO nhưng sau đó bị cho là không phù hợp: broadcast, create_token, cross-replica-sum, dot, einsum, torch_index_select, unary_einsum (#3).
  • Hoạt động không sử dụng – Các thao tác này có thể hữu ích ở một thời điểm nào đó, nhưng hoạt động chưa phát triển hoặc đường ống sử dụng các hoạt động này đã bị được tái cấu trúc để không yêu cầu chúng nữa. Các nội dung này bao gồm map, tuple (#598), Các phép so sánh get_tuple_element, rng, complex #560, và tích chập window_reversal (#1181).

Một số hoạt động này có thể được loại bỏ dễ dàng vì chúng có thể được biểu thị bằng hoạt động hiện tại (broadcast, create_token, cross-replica-sum, dot, unary_einsum) và sẽ bị xoá sau khoảng thời gian tương thích hiện tại thẻ và vé (6 tháng). Vẫn đang tìm hiểu các mục khác để xoá (einsum, get_tuple_element, map, rng torch_index_select, tuple, complex phép so sánh, window_reversal). Đang chờ ý kiến phản hồi của cộng đồng, các hoạt động này sẽ bị xóa hoặc được thêm vào quy cách với sự hỗ trợ đầy đủ. Cho đến đã biết các hoạt động tương lai này, chúng chỉ được đảm bảo khả năng tương thích trong 6 tháng.

Thực thi

Thực thi tuần tự

Chương trình StableHLO được thực thi bằng cách cung cấp các giá trị đầu vào cho hàm main và tính toán các giá trị đầu ra. Giá trị đầu ra của một hàm được tính bằng thực thi biểu đồ của hoạt động bị can thiệp vào hệ thống return tương ứng.

Thứ tự thực thi sẽ được xác định khi triển khai, miễn là thứ tự đó phù hợp với luồng dữ liệu, tức là nếu hoạt động được thực thi trước khi sử dụng. Trong StableHLO, tất cả hoạt động tác dụng phụ sử dụng một mã thông báo và tạo một mã thông báo (nhiều mã thông báo có thể được ghép thành một mã thông báo qua after_all), do đó thứ tự thực thi của bên cũng được điều chỉnh cho phù hợp với luồng dữ liệu. Ví dụ: trong chương trình dưới đây có thể có hai thứ tự thực thi: %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>
}

Một cách chính thức hơn, quy trình ổn định HLO là sự kết hợp của: 1) chương trình ổn địnhHLO, 2) trạng thái hoạt động (chưa được thực thi, đã được thực thi) và 3) các giá trị trung gian mà quy trình đang xử lý. Quá trình này bắt đầu bằng các giá trị đầu vào cho hàm main, rồi diễn ra tiếp theo biểu đồ hoạt động cập nhật trạng thái hoạt động, các giá trị trung gian và kết thúc bằng các giá trị đầu ra. Chưa chính thức hoá thêm (#484).

Thực thi song song

Các chương trình ổn định HLO có thể được thực thi song song và được sắp xếp thành lưới quy trình 2D của num_replicas của num_partitions, cả hai đều có loại ui32.

Trong lưới quy trình ổn địnhHLO, num_replicas * num_partitions của ổn địnhHLO đang thực thi đồng thời. Mỗi quy trình có một giá trị riêng biệt process_id = (replica_id, partition_id), trong đó replica_id trong replica_ids = range(num_replicas)partition_id trong partition_ids = range(num_partitions), cả hai đều có nhập ui32.

Kích thước của lưới quy trình được xác định theo phương thức tĩnh đối với mọi chương trình (trong trong tương lai, chúng tôi đang lên kế hoạch đưa tính năng này vào các chương trình ổn định #650) và vị trí trong lưới quy trình được xác định theo cách tĩnh cho mọi quy trình. Mỗi quá trình có quyền truy cập vào vị trí của nó trong lưới quy trình thông qua replica_id và Hoạt động partition_id

Trong lưới quy trình, tất cả các chương trình đều có thể giống nhau (trong cột "Đơn Chương trình, Nhiều dữ liệu" kiểu), tất cả đều có thể khác nhau (trong báo cáo "Nhiều chương trình, Nhiều dữ liệu" kiểu) hoặc yếu tố nào đó ở giữa. Trong tương lai, chúng tôi dự định để hỗ trợ các thành ngữ khác nhằm xác định các chương trình ổn định song song, bao gồm GSPMD (#619).

Trong lưới quy trình, các quy trình gần như độc lập với nhau – chúng có trạng thái hoạt động riêng biệt, có các giá trị đầu vào/trung gian/đầu ra riêng biệt và hầu hết hoạt động được thực thi riêng biệt giữa các quy trình, với ngoại lệ với một số ít hoạt động tập thể được mô tả dưới đây.

Vì việc thực thi hầu hết hoạt động chỉ sử dụng các giá trị từ cùng một hoạt động thường rõ ràng khi tham chiếu đến các giá trị này theo tên của chúng. Tuy nhiên, khi mô tả ngữ nghĩa của hoạt động tập thể thì như vậy là chưa đủ và từ đó làm phát sinh ký hiệu name@process_id để tham chiếu đến giá trị name trong một quy trình cụ thể. (Từ đó, name không đủ điều kiện có thể được xem là viết tắt của name@(replica_id(), partition_id())).

Thứ tự thực thi trên các quy trình được triển khai theo quy định, ngoại trừ đồng bộ hoá bằng giao tiếp điểm này đến điểm khác và hoạt động tập thể như mô tả bên dưới.

Giao tiếp giữa các điểm

Các quy trình ổn định HLO có thể giao tiếp với nhau thông qua Kênh ổn địnhHLO. Kênh được biểu thị bằng một mã nhận dạng dương của loại si64. Thông qua nhiều hoạt động, bạn có thể gửi giá trị đến các kênh và nhận được từ các kênh.

Chính thức hoá hơn nữa, ví dụ: các mã nhận dạng kênh này đến từ đâu, các chương trình xử lý chúng biết về chúng và loại đồng bộ hoá nào là do họ giới thiệu, sẽ được xác định sau (#484).

Giao tiếp qua luồng phát

Mỗi quy trình StableHLO đều có quyền truy cập vào 2 giao diện truyền trực tuyến:

  • Infeed có thể được đọc.
  • Nguồn cấp dữ liệu ngoài có thể được ghi vào.

Không giống như các kênh dùng để giao tiếp giữa các quy trình và do đó có các quy trình ở cả hai đầu, nguồn cấp dữ liệu đầu vào và nguồn cấp dữ liệu ngoài đều có quy trình riêng kết thúc triển khai được xác định.

Chính thức hoá hơn nữa, ví dụ: việc trao đổi trực tuyến ảnh hưởng như thế nào đến việc thực thi và loại đồng bộ hoá nào được đưa vào, sẽ được xác định sau (#484).

Hoạt động tập thể

Có 6 hoạt động tập thể trong StableHLO: all_gather, all_reduce, all_to_all, collective_broadcast, collective_permutereduce_scatter. Tất cả các hoạt động này phân tách các quy trình trong quy trình Ổn địnhHLO lưới vào các nhóm quy trình HLO ổn định và thực hiện phép tính chung trong mỗi nhóm quá trình, độc lập với các nhóm quá trình khác.

Trong mỗi nhóm quy trình, hoạt động tập thể có thể tạo ra sự đồng bộ rào cản. Chính thức hoá hơn nữa, ví dụ: giải thích chi tiết về thời điểm chính xác quá trình đồng bộ hoá diễn ra như thế nào, chính xác các quy trình gặp phải rào cản này như thế nào, và điều gì sẽ xảy ra nếu không (#484).

Nếu nhóm quy trình liên quan đến hoạt động giao tiếp giữa nhiều phân vùng, tức là có các quy trình trong nhóm quy trình có mã phân vùng khác nhau, sau đó thực thi nhóm hoạt động tập thể cần có một kênh, và nhóm hoạt động tập thể phải cung cấp channel_id dương thuộc loại si64. Không cần phải giao tiếp trên nhiều bản sao các kênh.

Các phép tính do nhóm điều hành tập thể thực hiện là riêng cho từng hoạt động và được mô tả trong từng mục vận hành ở trên. Tuy nhiên, các chiến lược của lưới quy trình được chia thành các nhóm quy trình được chia sẻ giữa các hoạt động này và được mô tả trong phần này. Một cách chính thức hơn, StableHLO hỗ trợ sau 4 chiến lược.

cross_replica

Chỉ có hoạt động giao tiếp sao chép chéo mới xảy ra trong từng nhóm quy trình. Chiến dịch này chiến lược sẽ lấy replica_groups – danh sách danh sách mã bản sao - và tính toán một sản phẩm Descartes của replica_groups của partition_ids. replica_groups phải có các phần tử riêng biệt và bao gồm tất cả replica_ids. Trang trọng hơn, sử dụng Cú pháp 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

Ví dụ: đối với replica_groups = [[0, 1], [2, 3]]num_partitions = 2, cross_replica sẽ sản xuất [[(0, 0), (1, 0)], [(0, 1), (1, 1)], [(2, 0), (3, 0)], [(2, 1), (3, 1)]].

cross_partition

Hoạt động giao tiếp giữa các phân vùng chỉ diễn ra trong mỗi nhóm quy trình. Chiến dịch này chiến lược sẽ lấy partition_groups – danh sách danh sách mã phân vùng - và tính một tích Descartes của partition_groups cho replica_ids. partition_groups phải có các phần tử riêng biệt và bao gồm tất cả partition_ids. Chính thức hơn, sử dụng cú pháp 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

Ví dụ: đối với partition_groups = [[0, 1]]num_replicas = 4, cross_partition sẽ sản xuất [[(0, 0), (0, 1)], [(1, 0), (1, 1)], [(2, 0), (2, 1)], [(3, 0), (3, 1)]].

cross_replica_and_partition

Cả giao tiếp sao chép chéo lẫn giao tiếp phân vùng đều có thể xảy ra trong mỗi nhóm tiến trình. Chiến lược này sẽ lấy replica_groups - một danh sách gồm các danh sách id bản sao - và tính các sản phẩm Descartes của mỗi replica_group bằng cách partition_ids. replica_groups phải có các phần tử riêng biệt và bao gồm tất cả replica_ids Chính thức hơn, sử dụng cú pháp 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

Ví dụ: đối với replica_groups = [[0, 1], [2, 3]]num_partitions = 2, cross_replica_and_partition sẽ sản xuất [[(0, 0), (1, 0), (0, 1), (1, 1)], [(2, 0), (3, 0), (2, 1), (3, 1)]].

flattened_ids

Chiến lược này sẽ lấy flattened_id_groups – một danh sách các danh sách "đã làm phẳng" các mã nhận dạng quy trình ở dạng replica_id * num_partitions + partition_id - và chuyển chúng thành mã nhận dạng quy trình. flattened_id_groups phải có các phần tử riêng biệt và bao gồm tất cả process_ids. Chính thức hơn, sử dụng cú pháp 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

Ví dụ: đối với flattened_id_groups = [[0, 1, 2, 3], [4, 5, 6, 7]], num_replicas = 4num_partitions = 2, flattened_ids sẽ sản xuất [[(0, 0), (0, 1), (1, 0), (1, 1)], [(2, 0), (2, 1), (3, 0), (3, 1)]].

Độ chính xác

Hiện tại, StableHLO không đảm bảo về độ chính xác về số liệu, nhưng điều này có thể thay đổi trong tương lai (#1156).

Ngữ nghĩa thực thi của phép toán lượng tử

Việc diễn giải các toán tử ổn định lượng tử hóa có thể thay đổi tùy thuộc vào yêu cầu và khả năng về phần cứng. Ví dụ: một số phần cứng có thể chọn diễn giải các phép toán lượng tử hoá bằng cách sử dụng thuật toán "bỏ lượng tử, thực hiện dấu phẩy động" và cuối cùng là định lượng" chiến lược. Một số khác có thể thực hiện toàn bộ tính toán với số học nguyên. Do đó, việc diễn giải các toán tử ổn định lượng tử hoá được xác định riêng bằng trong quá trình triển khai. Diễn giải lượng tử hoá kết hợp (#1575) phải dựa trên cơ sở đó là ngữ nghĩa theo quy định trong thông số kỹ thuật (thông qua 1792).

Lỗi

Các chương trình ổn định HLO được xác thực thông qua một tập hợp các ràng buộc mở rộng đối với mỗi hoạt động riêng lẻ, loại bỏ nhiều loại lỗi trước thời gian chạy. Tuy nhiên, vẫn có thể xảy ra lỗi, ví dụ: thông qua tràn số nguyên, truy cập vượt quá giới hạn, v.v. Trừ phi được gọi rõ ràng, tất cả các lỗi này đều có dẫn đến hành vi do triển khai xác định, nhưng điều này có thể thay đổi trong tương lai (#1157).

Ngoại lệ dấu phẩy động

Ngoại lệ đối với quy tắc này là các trường hợp ngoại lệ dấu phẩy động trong các chương trình StableHLO có hành vi được xác định rõ ràng. Các thao tác dẫn đến ngoại lệ được xác định bởi Tiêu chuẩn IEEE-754 (hoạt động không hợp lệ, chia cho 0, tràn, luồng, hoặc ngoại lệ không chính xác) tạo ra kết quả mặc định (như được xác định trong tiêu chuẩn) và tiếp tục thực thi mà không nâng cờ trạng thái tương ứng; tương tự với Xử lý ngoại lệ raiseNoFlag theo chuẩn. Trường hợp ngoại lệ đối với các sản phẩm không theo tiêu chuẩn các phép tính (ví dụ: số học phức tạp và một số hàm cấp tiến nhất định) là do triển khai xác định.

Hình dạng không khớp

StableHLO hỗ trợ các tensor có hình dạng động. Tuy nhiên, các hình dạng phải thống nhất với nhau thời gian chạy, nếu không thì hành vi không được xác định. StableHLO không thể hiện rõ ràng cung cấp một hoạt động có thể xác nhận rằng một tensor có một hình dạng nhất định trong thời gian chạy. Nhà sản xuất có trách nhiệm tạo mã chính xác.

Ví dụ cụ thể là chương trình bên dưới là hợp lệ. Tuy nhiên, trong thời gian chạy, hình dạng chính xác của %arg0%arg1 phải giống nhau, nếu không hành vi của chương trình là chưa xác định:

func.func @foo(%arg0: tensor<?xi32>, %arg1: tensor<?xi32>) -> tensor<?xi32> {
    %0 = stablehlo.add %arg0, %arg1 : tensor<?xi32>
    return %0 : tensor<?xi32>
}

Ký hiệu

Để mô tả cú pháp, tài liệu này sử dụng phiên bản ISO đã sửa đổi của EBNF (ISO/IEC 14977:1996, Wikipedia), có hai sửa đổi: 1) các quy tắc được xác định bằng cách sử dụng ::= thay vì =,

2) việc nối được biểu thị bằng cách đặt vị trí cạnh nhau thay vì ,.

Để mô tả ngữ nghĩa (ví dụ: trong các phần "Types", "Constants" và "Ops"), chúng tôi đang sử dụng các công thức dựa trên cú pháp Python được mở rộng với sự hỗ trợ để thể hiện chính xác các thao tác mảng như được mô tả dưới đây. Cách này hiệu quả cho các đoạn mã nhỏ, nhưng trong một số ít trường hợp khi các đoạn mã lớn hơn nếu cần, chúng tôi sử dụng cú pháp vanilla Python luôn được giới thiệu rõ ràng.

Công thức

Hãy cùng tìm hiểu cách hoạt động của các công thức dựa trên ví dụ trong dot_general đặc điểm kỹ thuật. Một trong các quy tắc ràng buộc của thao tác này có dạng như sau: dim(lhs, lhs_batching_dimensions...) = dim(rhs, rhs_batching_dimensions...).

Tên được dùng trong công thức này đến từ 2 nguồn: 1) hàm toàn cục, tức là dim, 2) các định nghĩa thành phần của thành phần tương ứng trong chương trình, tức là Đầu vào lhs, lhs_batching_dimensions, rhsrhs_batching_dimensions được xác định trong cột "Đầu vào" trên dot_general.

Như đã đề cập ở trên, cú pháp của công thức này dựa trên Python với một số tiện ích định hướng tính súc tích. Để hiểu rõ công thức, hãy biến đổi thành cú pháp vanilla Python.

A) Trong các công thức này, chúng ta sử dụng = để biểu diễn đẳng thức, do đó bước đầu tiên để lấy cú pháp Python sẽ thay thế = bằng == như sau: dim(lhs, lhs_batching_dimensions...) == dim(rhs, rhs_batching_dimensions...).

B) Ngoài ra, các công thức này còn hỗ trợ dấu ba chấm (...) biến các biểu thức vô hướng thành biểu thức tensor. Tóm lại, f(xs...) đại khái có nghĩa là "đối với mỗi đại lượng vô hướng x trong tensor xs, tính một đại lượng vô hướng f(x) rồi trả về tất cả các kết quả vô hướng này lại với nhau thành một kết quả tensor". Trong cú pháp vanilla Python, công thức mẫu của chúng ta biến thành: [dim(lhs, dim1) for dim1 in lhs_batching_dimensions] == [dim(rhs, dim2) for dim2 in rhs_batching_dimensions].

Nhờ dấu ba chấm, bạn thường có thể tránh làm việc ở cấp độ đại lượng vô hướng riêng lẻ. Tuy nhiên, trong một số trường hợp phức tạp, chỉ mang tính bán không chính thức ở cấp độ thấp hơn có thể sử dụng cú pháp như trong công thức start_indices[bi0, ..., :, ..., biN] từ thông số kỹ thuật gather. Để đảm bảo tính súc tích, chúng tôi không đưa ra một quy tắc hình thức chính xác để dịch cú pháp như vậy sang vanilla Python, trong hy vọng rằng quy trình này vẫn dễ hiểu theo từng trường hợp. Vui lòng cho chúng tôi biết nếu một số công thức cụ thể có vẻ không rõ ràng và chúng tôi sẽ cố gắng để cải thiện chúng.

Ngoài ra, bạn sẽ nhận thấy rằng các công thức sử dụng dấu ba chấm để mở rộng tất cả các loại danh sách, bao gồm tensor, danh sách tensor (ví dụ: có thể phát sinh từ một biến số lượng tensor), v.v. Đây là một lĩnh vực khác mà chúng tôi không cung cấp số liệu chính xác chủ nghĩa hình thức (ví dụ: danh sách thậm chí không thuộc hệ thống loại StableHLO) và mà hãy dựa vào tính dễ hiểu.

C) Phương tiện ký hiệu đáng chú ý cuối cùng mà chúng tôi sử dụng là phương tiện ngầm ẩn đang phát sóng. Mặc dù chế độ StableHLO không hỗ trợ phát sóng ngầm, các công thức cũng giúp đảm bảo tính súc tích. Tóm lại, nếu một đại lượng vô hướng được dùng trong ngữ cảnh khi mong đợi một tensor, đại lượng vô hướng được truyền đến hình dạng mong muốn.

Để tiếp tục ví dụ về dot_general, hãy thiết lập một quy tắc ràng buộc khác: 0 <= lhs_batching_dimensions < rank(lhs) Như được xác định trong dot_general lhs_batching_dimensions là một tensor, tuy nhiên cả 0rank(lhs) là đại lượng vô hướng. Sau khi chúng ta áp dụng tính năng truyền tin ngầm, công thức sẽ trở thành [0, ..., 0] <= lhs_batching_dimensions < [rank(lhs), ..., rank(lhs)].

Khi áp dụng cho một toán tử dot_general cụ thể, công thức này sẽ đánh giá cho một tensor của boolean. Khi công thức được dùng làm điều kiện ràng buộc, ràng buộc sẽ được duy trì nếu công thức có giá trị là true hoặc cho một tensor chỉ có phần tử true.

Tên

Trong các công thức, phạm vi từ vựng bao gồm: 1) hàm toàn cục, 2) các định nghĩa liên kết,

3) định nghĩa cục bộ. Danh sách hàm toàn cục được cung cấp dưới đây. Danh sách của định nghĩa phần tử phụ thuộc vào phần tử chương trình mà ký hiệu đó đã áp dụng cho:

  • Đối với thao tác, các định nghĩa thành phần bao gồm tên được giới thiệu trong "Đầu vào" và "Kết quả đầu ra" .
  • Đối với những yếu tố khác, định nghĩa về thành phần bao gồm các phần cấu trúc của phần tử chương trình, được đặt tên theo phần không phải của EBNF tương ứng. Hầu hết thời gian, tên của các bộ phận cấu trúc này bằng cách chuyển đổi tên của các phần không phải đầu cuối và viết hoa con rắn (ví dụ: IntegerLiteral => integer_literal), nhưng đôi khi tên được viết tắt trong quá trình này (ví dụ: QuantizationStorageType => storage_type) trong trường hợp đó tên là được giới thiệu tương tự như "Đầu vào" / "Kết quả" chuyên mục đang hoạt động thông số kỹ thuật.
  • Ngoài ra, các định nghĩa về thành phần luôn bao gồm self để tham chiếu đến phần tử chương trình tương ứng.

Giá trị

Khi được đánh giá, các công thức sẽ hoạt động với các loại giá trị sau: 1) Value (giá trị thực tế, ví dụ: dense<[[1, 2], [3, 4]]> : tensor<2x2xi32>; họ luôn biết loại hình của mình), 2) Placeholder (các giá trị tương lai, ví dụ: lhs, rhs hoặc result; thực tế của chúng các giá trị chưa được xác định mà chỉ biết loại của chúng), 3) Type (các loại được xác định trong phần "Loại"), 4) Function (các hàm chung như được định nghĩa trong phần "Hàm").

Tuỳ thuộc vào ngữ cảnh, tên có thể tham chiếu đến các giá trị khác nhau. Xem thêm cụ thể, "Ngữ nghĩa" dành cho hoạt động (và các phần tương đương cho các chương trình khác) phần tử) xác định logic thời gian chạy, vì vậy, tất cả dữ liệu đầu vào đều có sẵn dưới dạng Value. Ngược lại, "Hạn chế" dành cho hoạt động (và các quy tắc tương đương) sẽ xác định "thời gian biên dịch" logic, tức là nội dung nào đó thường được thực thi trước thời gian chạy, vì vậy, chỉ có dữ liệu đầu vào không đổi là Value và các dữ liệu đầu vào khác là chỉ có sẵn dưới dạng Placeholder.

Tên Trong "Ngữ nghĩa" Trong phần "Hạn chế"
Hàm toàn cục Function Function
Giá trị đầu vào không đổi Value Value
Giá trị đầu vào không cố định Value Placeholder
Kết quả đầu ra Value Placeholder
Định nghĩa theo địa phương Phụ thuộc vào định nghĩa Phụ thuộc vào định nghĩa

Hãy xem xét một toán tử transpose mẫu:

%result = "stablehlo.transpose"(%operand) {
  permutation = dense<[2, 1, 0]> : tensor<3xi64>
} : (tensor<2x3x2xi32>) -> tensor<2x3x2xi32>

Đối với thao tác này, permutation là hằng số nên có sẵn dưới dạng Value cả về ngữ nghĩa và ràng buộc. Ngược lại, operandresult là có sẵn dưới dạng Value trong ngữ nghĩa nhưng chỉ ở dạng Placeholder trong các điều kiện ràng buộc.

Hàm

Cấu trúc các loại

Không có hàm nào có thể dùng để tạo kiểu. Thay vào đó, chúng tôi trực tiếp sử dụng cú pháp kiểu vì cú pháp này thường ngắn gọn hơn. Ví dụ: (tensor<E>, tensor<E>) -> (tensor<E>) thay vì function_type( [tensor_type([], E), tensor_type([], E)], [tensor_type([], E)]).

Hàm trên các kiểu

  • element_type được xác định trên các loại tensor và các loại tensor lượng tử hoá và sẽ trả về TensorElementType hoặc QuantizedTensorElementType tương ứng. của TensorType hoặc QuantizedTensorType tương ứng.
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 là lối tắt trong is_quantized(x) and quantization_dimension(x) is not None.

  • is_per_tensor_quantized(x: Value | Placeholder | Type) -> Value là một phím tắt cho is_quantized(x) and quantization_dimension(x) is None.

  • is_promotable(x: Type, y: Type) -> bool kiểm tra xem loại x có thể được quảng bá hay không để nhập y. Khi xyQuantizedTensorElementType, chương trình khuyến mãi chỉ được áp dụng cho storage_type. Phiên bản cụ thể của chương trình khuyến mãi này hiện đang được sử dụng trong ngữ cảnh tính toán rút gọn (tham khảo RFC để biết thêm chi tiết).

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 là lối tắt cho is_quantized_tensor_element_type(x)

  • is_type_name(x: Value | Placeholder | Type) -> Value. Dành cho tất cả loại. Ví dụ: is_float(x) trả về true nếu xFloatType. Nếu x là một giá trị hoặc phần giữ chỗ, thì hàm này sẽ là lối tắt cho is_type_name(type(x))

  • max_value(x: Type) -> Value trả về giá trị lớn nhất của một TensorElementType Nếu x không phải là TensorElementType, hàm sẽ trả về None.

  • min_value(x: Type) -> Value trả về giá trị tối thiểu có thể có của một TensorElementType Nếu x không phải là TensorElementType, hàm sẽ trả về None.

  • member_name(x: Value | Placeholder | Type) -> Any. Dành cho tất cả thành viên định nghĩa member_name thuộc mọi loại. Ví dụ: tensor_element_type(x) trả về phần TensorElementType của TensorType tương ứng. Nếu x là một giá trị hoặc phần giữ chỗ, thì hàm này sẽ là lối tắt cho member_name(type(x)) Nếu x không phải là loại có thành viên thích hợp, hoặc một giá trị hoặc phần giữ chỗ thuộc loại như vậy, sẽ trả về None.

  • is_empty_algorithm(*args: Type) sẽ kiểm tra xem bạn đã đặt tất cả các trường thuật toán dấu chấm hay chưa đến None. Điều này là cần thiết vì thuật toán dấu chấm đã xác định cách triển khai do đó việc chỉ định giá trị mặc định sẽ không chính xác.

Xây dựng giá trị

  • operation_name(*xs: Value | Type) -> Value. Áp dụng cho mọi hoạt động. Ví dụ: add(lhs, rhs) nhận hai giá trị tensor lhsrhs và sẽ trả về kết quả đánh giá toán tử add với những dữ liệu đầu vào này. Đối với một số thao tác, ví dụ: broadcast_in_dim, các loại dữ liệu đầu ra là "mang tải", tức là cần thiết để đánh giá một hoạt động. Trong trường hợp này, hàm lấy các loại này làm đối số.

Hàm trên giá trị

  • Bạn có thể sử dụng mọi toán tử và hàm của Python. Ví dụ: cả hai gói thuê baochia nhỏ ký hiệu từ Python có sẵn để lập chỉ mục thành tensor, tensor lượng tử hoá và bộ dữ liệu.

  • to_destination_type(x: Value, destination_type: Type) -> Value được xác định trên tensor và trả về giá trị đã chuyển đổi của x dựa trên type(x)destination_type như sau:

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)

Sẽ có cuộc thảo luận sớm về việc hợp nhất convert, uniform_quantize và Toán tử uniform_dequantize (#1576). Sau khi hợp nhất, chúng ta không cần chức năng trên và có thể sử dụng tên hoạt động cho convert.

  • is_nan(x: Value) -> Value được xác định trên tensor và trả về true nếu tất cả các phần tử của xNaN hoặc false. Nếu x không phải là tensor, sẽ trả về None.

  • is_sorted(x: Value) -> Value được xác định trên tensor và trả về true nếu các phần tử của x được sắp xếp theo thứ tự tăng dần thứ tự từ điển của chỉ mục của họ hoặc false. Nếu x không phải là một tensor, trả về None.

  • is_unique(x: Value) -> Value được xác định trên tensor và trả về true nếu x không có phần tử trùng lặp hoặc false. Nếu x không phải là tensor, sẽ trả về None.

  • member_name(x: Value) -> Any được định nghĩa cho mọi định nghĩa thành phần member_name trong số tất cả giá trị. Ví dụ: real_part(x) trả về RealPart của ComplexConstant tương ứng. Nếu x không phải là một giá trị có thành phần phù hợp sẽ trả về None.

  • same(x: Value) -> Value được xác định trên tensor và trả về true nếu các phần tử của x đều bằng nhau hoặc false bằng nhau. Nếu tensor không có phần tử nào được tính là "tất cả đều bằng nhau", tức là hàm trả về true. Nếu x không phải là một tensor, trả về None.

  • split(x: Value, num_results: Value, axis: Value) -> Value được xác định trên tensor và trả về num_results lát cắt của x dọc theo trục axis. Nếu x không phải là tensor hoặc dim(x, axis) % num_results != 0, trả về None.

  • is_defined_in_parent_scope(x: Value) -> Value được xác định trên các chuỗi và trả về true nếu x là tên của một hàm được xác định trong cùng phạm vi làm hàm mẹ của cơ chế phù hợp.

  • is_namespaced_op_name(x: Value) -> Value được xác định trên chuỗi và trả về true nếu x là tên vận hành hợp lệ, thì tên này sẽ tuân theo quy tắc chính quy sau biểu thức: [a-zA-Z][a-zA-Z0-9_]*([.][a-zA-Z0-9_$]+)+

Các phép tính hình dạng

  • axes(x: Value | Placeholder | Type) -> Value là lối tắt cho range(rank(x))

  • dim(x: Value | Placeholder | Type, axis: Value) -> Value là lối tắt cho shape(x)[axis]

  • dims(x: Value | Placeholder | Type, axes: List) -> List là lối tắt cho list(map(lambda axis: dim(x, axis), axes))

  • index_space(x: Value | Placeholder | Type) -> Value được định nghĩa trên tensor và trả về các chỉ mục size(x) cho TensorType tương ứng được sắp xếp theo thứ tự từ điển tăng dần, ví dụ: [0, ..., 0], [0, ..., 1], ..., shape(x) - 1. Nếu x không phải là một loại tensor, một loại tensor lượng tử hoá hoặc một giá trị hoặc phần giữ chỗ thuộc một trong các loại này, sẽ trả về None.

  • rank(x: Value | Placeholder | Type) -> Value là lối tắt cho size(shape(x))

  • shape(x: Value | Placeholder | Type) -> Value được định nghĩa trong phần "Hàm về các loại" qua member_name.

  • size(x: Value | Placeholder | Type) -> Value là lối tắt cho reduce(lambda x, y: x * y, shape(x))

Tính toán lượng tử hoá

  • def baseline_element_type(x: Value | Placeholder | Type) -> Type là một phím tắt cho element_type(baseline_type(x)).

  • baseline_type được xác định trên các loại tensor và các loại tensor lượng tử hoá và biến chúng thành "đường cơ sở", tức là một loại có cùng hình dạng nhưng có tham số lượng tử hoá của loại phần tử được đặt lại về giá trị mặc định. Đây là được sử dụng như một thủ thuật tiện lợi để so sánh cả loại tensor và tensor lượng tử hoá một cách thống nhất. Đây là việc cần thiết khá thường xuyên. Đối với các loại lượng tử hoá, điều này cho phép so sánh các kiểu bỏ qua tham số lượng tử hoá, tức là shape, storage_type, expressed_type, storage_min, storage_maxquantization_dimension (đối với loại lượng tử hoá trên mỗi trục) đều phải khớp, nhưng scaleszero points có thể khác nhau.

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 được xác định trên các loại tensor lượng tử hoá và biến chúng thành tensor dấu phẩy động. Điều này xảy ra thông qua việc chuyển đổi các phần tử lượng tử các giá trị số nguyên của loại hình lưu trữ thành các giá trị tương ứng giá trị dấu phẩy động thuộc loại đã biểu diễn bằng cách sử dụng điểm không và tỷ lệ liên kết với loại phần tử lượng tử hoá.
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 được xác định trên các loại tensor dấu phẩy động và chuyển chúng thành các loại tensor lượng tử hoá. Điều này xảy ra bằng cách chuyển đổi các giá trị dấu phẩy động của loại đã biểu thị thành các giá trị số nguyên tương ứng của loại hình lưu trữ bằng cách sử dụng điểm 0 và tỷ lệ được liên kết với loại phần tử lượng tử hoá.
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 dùng để chỉ định các phép tính theo phần tử trên tensor lượng tử hoá. Phương pháp này khử lượng tử, tức là biến các nguyên tố lượng tử hoá thành các loại được biểu thị, sau đó thực hiện một phép toán và sau đó lượng tử hoá, tức là lượt quay các kết quả trở lại loại bộ nhớ của họ. Hiện tại, chức năng này chỉ dùng để định lượng mỗi tensor. Đang tiến hành định lượng trên mỗi trục (#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 dùng để chỉ định lượng tử chỉ trọng số cho op kết hợp chấp nhận lh trong dấu phẩy động và rhs trong các loại lượng tử hoá. Nó khử lượng tử đầu vào lượng tử thành các loại đã biểu thị và thực hiện tính toán có độ chính xác đơn. Loại phần tử của số thực độ chính xác đơn lhs tensor và loại phần tử lượng tử hoá rhs tensor phải giống hệt nhau.
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))

Tính toán lưới

  • cross_partition(replica_groups: Value) -> Value. Xem "cross_replica" phần bên trên.

  • cross_replica(replica_groups: Value) -> Value. Xem "cross_replica" phần bên trên.

  • cross_replica_and_partition(replica_groups: Value) -> Value. Xem &quot;cross_replica_and_partition&quot; phần bên trên.

  • flattened_ids(replica_groups: Value) -> Value. Xem thuộc tính "flattened_ids" phần bên trên.

Tính năng động

Các giá trị ổn địnhHLO có thể có kích thước phương diện động, ví dụ: tensor<?xi64>. Tuy nhiên, giá trị StableHLO không được có số lượng phương diện động (không được xếp hạng động lực, ví dụ: tensor<*xi64>). Toán hạng và kết quả được phép sử dụng động kích thước kích thước, ngay cả khi có hạn chế về kích thước. Các quy tắc ràng buộc sẽ là được xác minh tĩnh nếu có thể, nếu không thì chúng sẽ được trì hoãn đến thời gian chạy và thông tin không khớp sẽ dẫn đến hành vi không xác định. Hãy xem ví dụ dưới đây.

Hình dạng không khớp đối với các toán tử đơn phần tử

Hãy xem xét chương trình đồ chơi sau:

func.func @foo(%arg0: tensor<?xf64>) {
  %0 = stablehlo.abs %arg0 : (tensor<?xf64>) -> tensor<2xf64>
  return
}

Một chương trình như vậy rất bất thường, vì ít khi biết hình dạng của kết quả nhưng không phải hình dạng của đầu vào. Tuy nhiên, đây là một StableHLO hợp lệ . Không thể xác thực tĩnh hoạt động abs trong trường hợp này vì hình dạng chính xác của toán hạng là chưa xác định. Tuy nhiên, hình dạng hoàn toàn tương thích và điều này có thể được kiểm tra tĩnh: ? có thể xảy ra 2 trong thời gian chạy nên sẽ không có vấn đề gì. Tuy nhiên, ? có thể trở thành số nguyên khác, trong trường hợp đó thì hành vi không thể xác định.

Lưu ý rằng nếu kích thước thứ nguyên là động trong kết quả, thì không thể có hành vi không xác định. Thực tế, không có điều gì "có thể dự kiến" nên không thể có một không khớp.

Hình dạng không khớp đối với các toán tử phần tử nhị phân

Hãy xem xét chương trình đồ chơi sau:

func.func @foo(%arg0: tensor<?xf64>, %arg1: tensor<?xf64>) {
  %0 = stablehlo.add %arg0, %arg0 : (tensor<?xf64>, tensor<?xf64>) -> tensor<?xf64>
  return
}

Khi nói đến các phép toán phần tử nhị phân, hình dạng của đầu vào và kết quả phải thống nhất trong thời gian chạy. Tại thời điểm biên dịch, các chiều tĩnh phải bằng nhau, nếu không chúng chỉ cần tương thích. Nếu bất kỳ phương diện nào là phương diện động trong dữ liệu đầu vào, thì có thể có giá trị không xác định trong thời gian chạy, vì kích thước động có thể không khớp với kích thước trong toán hạng khác (tĩnh hoặc động). Nếu tất cả thông tin đầu vào đều là tĩnh, thì cho dù kết quả có động hay không không quan trọng: tĩnh thứ nguyên đã biết sẽ được kiểm tra tĩnh, còn thứ nguyên động thì không áp đặt mọi ràng buộc.

Hình dạng không khớp đối với hoạt động nhận hình dạng đầu ra làm toán hạng

Hãy xem xét chương trình đồ chơi sau:

func.func @foo(%arg0: tensor<2xi32>) {
  %0 = stablehlo.dynamic_iota %arg0, dim = 0 : (tensor<2xi32>) -> tensor<3x4xi64>
  return
}

Giá trị trong toán hạng hình dạng trong thời gian chạy phải khớp với hình dạng của kết quả, nếu không thì hành vi là không xác định. Tức là trong thời gian chạy, %arg0 phải có một giá trị dense<[3, 4]> : tensor<2xi32>. Nếu toán hạng hình dạng không đổi, có thể được xác minh tĩnh. Nếu hình dạng kết quả hoàn toàn động, thì khi đó không thể trùng khớp.