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
và %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ạng và loạ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 đó scale
và zero_point
được gọi
tham số lượng tử. storage_min
và storage_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)
và
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 QuantizationStorageMin
và QuantizationStorageMax
để 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 scale
và zero_point
cho toàn bộ tensor hoặc có thể là mỗi trục,
tức là có nhiều scales
và zero_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]
và 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)
.
- (C12)
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>
và
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
true
vàfalse
. - 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ặc64
). LoạisiN
đã ký biểu thị các giá trị số nguyên từ-2^(N-1)
đến2^(N-1)-1
các loạiuiN
không dấu biểu thị các giá trị số nguyên từ0
đến2^N-1
. - Loại dấu phẩy động có thể là một trong các loại sau:
- các loại
f8E4M3FN
vàf8E5M2
tương ứng với Mã hoáE4M3
vàE5M2
của định dạng FP8 được mô tả trong Các định dạng của FP8 dành cho công nghệ học sâu. - Loại
f8E4M3FNUZ
vàf8E5M2FNUZ
tương ứng vớiE4M3
vàE5M2
mã hoá các định dạng FP8 được mô tả trong Định dạng số 8 bit cho mạng nơron sâu. - Loại
f8E4M3B11FNUZ
tương ứng với mã hoáE4M3
của các định dạng FP8 được mô tả trong Chương trình đào tạo và suy luận dựa trên điểm nổi 8 bit kết hợp (HFP8) cho mạng nơron sâu. - Loại
bf16
tương ứng với định dạngbfloat16
được mô tả trong BFloat16: Bí quyết để đạt được hiệu suất cao trên Cloud TPU. - Các loại
f16
,f32
vàf64
tương ứng vớibinary16
("độ chính xác bán chính xác"),binary32
("độ chính xác đơn") và Định dạngbinary64
("độ chính xác kép") như mô tả trong tiêu chuẩn IEEE 754. - Loại
tf32
tương ứng với định dạng TensorFloat32 và chỉ hỗ trợ hạn chế trong Ổn định HLO.
- các loại
- 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ạif32
) vàcomplex<f64>
(cả hai phần đều thuộc loạif64
).
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_indices
và limit_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
và %init_value
), 2 hàm đầu vào
và 3 thuộc tính đầu vào (window_dimensions
, window_strides
và padding
).
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 true
và false
. 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
và
(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ếuis_complex(operand)
.baseline_element_type(operand)
.
Ví dụ
// %operand: [-2, 0, 2]
%result = "stablehlo.abs"(%operand) : (tensor<3xi32>) -> tensor<3xi32>
// %result: [2, 0, 2]
thêm
Ngữ nghĩa
Thực hiện phép cộng theo từng phần tử của hai tensor lhs
và rhs
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)
.
- (C1)
- 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)
.
- (C2)
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]]
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
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ếuchannel_id <= 0 and use_global_device_ids = false
.cross_replica_and_partition(replica_groups)
nếuchannel_id > 0 and use_global_device_ids = false
.flattened_ids(replica_groups)
nếuchannel_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
trongprocess_group
.results...@process = concatenate(operands...@process, all_gather_dim)
cho tất cảprocess
trongprocess_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ùngcross_replica
.num_replicas
nếu dùngcross_replica_and_partition
.num_processes
nếu dùngflattened_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]]
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ếuchannel_id <= 0 and use_global_device_ids = false
.cross_replica_and_partition(replica_groups)
nếuchannel_id > 0 and use_global_device_ids = false
.flattened_ids(replica_groups)
nếuchannel_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ânschedule
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ùngcross_replica
.num_replicas
nếu dùngcross_replica_and_partition
.num_processes
nếu dùngflattened_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]
all_to_all
Ngữ nghĩa
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ếuchannel_id <= 0
.cross_partition(replica_groups)
nếuchannel_id > 0
.
Sau đó, trong mỗi process_group
:
split_parts...@sender = split(operands...@sender, split_count, split_dimension)
cho tất cảsender
trongprocess_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ùngcross_replica
.num_partitions
nếu dùngcross_partition
.
- (C7)
0 <= replica_groups < size(replica_groups)
. - (C8)
dim(replica_groups, 1) = split_count
. - (C9)
type(results...) = type(operands...)
ngoại trừ nếusplit_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à
Ngữ nghĩa
Thực hiện cấu trúc phần tử AND của hai tensor lhs
và rhs
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]]
atan2
Ngữ nghĩa
Thực hiện toán tử atan2 thông minh trên tensor lhs
và rhs
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]
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_scale
và grad_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_scale
vàgrad_offset
có cùngbaseline_element_type
. - (C3)
operand
,grad_output
vàgrad_operand
có cùng hình dạng. - (C4)
scale
,mean
,variance
,grad_scale
vàgrad_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
,variance
vàresult
có cùngbaseline_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_mean
và batch_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_var
vàoutput
có cùng mộtbaseline_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)
và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')
.
- Nếu
- (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
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ả d
ở
axes(operand)
:
operand_index[d] = 0
nếudim(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)
vàzero_points(operand)
có thể khác vớiquantization_dimension(result)
,scales(result)
và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
trongaxes(operand)
:dim(operand, d) = 1
hoặcdim(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]
// ]
// ]
ố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ếu0 <= 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]
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]
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]
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 lower
là true
) hoặc ma trận tam giác trên (nếu lower
là false
).
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]
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ếuchannel_id <= 0
.cross_partition(replica_groups)
nếuchannel_id > 0
.
Sau đó, result@process
được cung cấp bởi:
operand@process_groups[i, 0]
nếu tồn tạii
để quá trình này trongprocess_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ùngcross_replica
.num_partitions
nếu dùngcross_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ếuchannel_id <= 0
.cross_partition(source_target_pairs)
nếuchannel_id > 0
.
Sau đó, result@process
được cung cấp bởi:
operand@process_groups[i, 0]
, nếu tồn tạii
sao choprocess_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ùngcross_replica
.num_partitions
nếu dùngcross_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]]
so sánh
Ngữ nghĩa
Thực hiện so sánh các phần tử của tensor lhs
và rhs
theo
comparison_direction
và compare_type
rồi tạo tensor result
.
Các giá trị của comparison_direction
và compare_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ử totalOrder
và compareQuietEqual
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_direction
và compare_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 , LE và LT |
|
(I4) | compare_type |
enum của FLOAT , TOTALORDER , SIGNED và UNSIGNED |
(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ếuis_signed_integer(element_type(lhs))
.UNSIGNED
nếuis_unsigned_integer(element_type(lhs)) or is_boolean(element_type(lhs))
.FLOAT
hoặcTOTALORDER
nếuis_float(element_type(lhs))
.FLOAT
nếuis_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]
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, lhs
và rhs
, đồ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ạicomplex<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)]
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 inputs
và composite_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>
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 đó:
id = d0 + ... + dk-1 + kd
.d
bằngdimension
vàd0
, ... 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]]
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]]
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-type và complex-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)]
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ừ
lhs
và rhs
trong một ví dụ cụ thể.
Để 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 = 1
và batch_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 , HIGH và HIGHEST |
(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ếuresult_dim = output_batch_dimension
.dim(rhs, kernel_output_feature_dimension)
nếuresult_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)
.
- (C27)
- 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)
.
- (C28)
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]]
// ]]
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]]
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]]
custom_call
Ngữ nghĩa
Đóng gói thao tác triển khai call_target_name
sẽ nhận
inputs
và called_computations
, đồng thời tạo results
. has_side_effect
,
backend_config
và api_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]
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)
và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_type
vàrhs_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_count
vànum_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ành1
.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 , HIGH và HIGHEST |
(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)
.
- (C13)
- 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ó trongrhs_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)
.
- (C14)
- 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
.
- (C21)
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]]
// ]
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)
vàzero_points(operand)
có thể khác vớiquantization_dimension(result)
,scales(result)
và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
trongaxes(operand)
:dim(operand, d) = 1
hoặcdim(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]
// ]
// ]
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 , HIGH và HIGHEST |
(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ếuresult_dim = output_batch_dimension
.dim(rhs, kernel_output_feature_dimension)
nếuresult_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)
.
- (C27)
- 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)
.
- (C28)
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]]
// ]]
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ồmstart_indices
tương ứng vớiindex_vector_dim
.offset_dim_sizes = shape(slice_sizes)
ngoại trừ kích thước kích thước trongslice_sizes
tương ứng vớicollapsed_slice_dims
sẽ không được đưa vào.combine
đặtbatch_dim_sizes
tại các trục tương ứng vớibatch_dims
vàoffset_dim_sizes
tại các trục tương ứng vớioffset_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]]
// ]
// ]
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]
// ]
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_high
và interior_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]
// ]
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]]
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]
// ]
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ếu0 <= 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]
// ]
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]]
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]
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 , RFFT và IRFFT |
(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ử
operand
vàresult
là khác nhau:- Nếu
fft_type = FFT
,element_type(operand)
vàelement_type(result)
có cùng kiểu phức. - Nếu
fft_type = IFFT
,element_type(operand)
và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.
- Nếu
- (C3)
1 <= size(fft_length) <= 3
. - (C4) Nếu trong số
operand
vàresult
, có một tensorreal
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
- Nếu giá trị là
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]
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.
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ẻ trongbatch_index
và:
được chèn vào chỉ mụcindex_vector_dim
, nếuindex_vector_dim
<rank(start_indices)
.[start_indices[batch_index]]
.
- Đối với
d_operand
trongaxes(operand)
,full_start_index[d_operand] = clamp(start_index[d_start], 0, dim(operand, d_operand) - slice_sizes[d_operand])
nếud_operand = start_index_map[d_start]
.full_start_index[d_operand] = 0
.
- Đối với
d_operand
trongaxes(operand)
,full_batching_index[d_operand] = batch_index[d_start - (d_start < index_vector_dim ? 0 : 1)]
nếud_operand = operand_batching_dims[i_batching]
và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ử trongoffset_index
và0
được chèn vào các chỉ mục từcollapsed_slice_dims
vàoperand_batching_dims
.operand_index = full_start_index + full_batching_index + full_offset_index
.
Nếu indices_are_sorted
là true
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ồmstart_indices
tương ứng vớiindex_vector_dim
.offset_dim_sizes = slice_sizes
ngoại trừ kích thước kích thước theoslice_sizes
tương ứng vớicollapsed_slice_dims
và Không bao gồmoperand_batching_dims
.combine
đặtbatch_dim_sizes
tại các trục tương ứng vớibatch_dims
vàoffset_dim_sizes
tại các trục tương ứng vớioffset_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]]
// ]
// ]
// ]
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
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]
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
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ếuis_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]
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ặcis_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]]
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]
// ]
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]
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]]
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]
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]]
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])
và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]]
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 lhs
và rhs
, đồ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]]
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 lhs
và rhs
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]]
nhân
Ngữ nghĩa
Thực hiện tích số phần tử của hai tensor lhs
và rhs
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]]
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]
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]
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
hoặc
Ngữ nghĩa
Thực hiện từng phần tử OR của hai tensor lhs
và rhs
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]]
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
đệ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_low
và edge_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ếuresult_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]
// ]
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>
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]
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]
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ếuis_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]
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_transfer
là true
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_DEVICE và HOST_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ếuis_host_transfer = true
,DEVICE_TO_DEVICE
.
- (C2)
0 < size(results)
. - (C3)
is_empty(result[:-1])
hoặcis_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)
giảm
Ngữ nghĩa
Áp dụng hàm rút gọn body
cho inputs
và init_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à body
và
init_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úcdimensions
.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ânschedule
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
trongindex_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ướcinputs...
tương ứng vớidimensions
. - (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]
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_bits
và mantissa_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ĩaroundToIntegralTiesToEven
. - 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ànhmantissa_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]
reduce_scatter
Ngữ nghĩa
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ếuchannel_id <= 0 and use_global_device_ids = false
.cross_replica_and_partition(replica_groups)
nếuchannel_id > 0 and use_global_device_ids = false
.flattened_ids(replica_groups)
nếuchannel_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
trongprocess_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ùngcross_replica
.num_replicas
nếu dùngcross_replica_and_partition
.num_processes
nếu dùngflattened_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]]
reduce_window
Ngữ nghĩa
Áp dụng hàm rút gọn body
cho các cửa sổ inputs
và init_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ể.
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]]
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ònroundTowardZero
- Đố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]
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>
đổ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_index
và operand_index
ở cùng vị trí trong từ điển
là index_space(result)
và 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]]
đả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
trongdimensions
.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]]
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 UNIFORM và NORMAL |
(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_FRY và PHILOX |
(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ếurng_algorithm = THREE_FRY
.2
hoặc3
nếurng_algorithm = PHILOX
.
- phương thức triển khai được xác định nếu là
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]
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]
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]]
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.
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ử trongupdate_scatter_index
và:
được chèn vào Chỉ mụcindex_vector_dim
, nếuindex_vector_dim
<rank(scatter_indices)
.[scatter_indices[update_scatter_index]]
.
- Đối với
d_input
trongaxes(inputs[0])
,full_start_index[d_input] = start_index[d_start]
nếud_input = scatter_dims_to_operand_dims[d_start]
full_start_index[d_input] = 0
.
- Đối với
d_input
trongaxes(inputs[0])
,full_batching_index[d_input] = update_scatter_index[d_start - (d_start < index_vector_dim ? 0 : 1)]
nếud_input = input_batching_dims[i_batching]
và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ử trongupdate_window_index
và0
được chèn vào các chỉ mục từinserted_window_dims
vàinput_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ủaindex_space(updates[0])
exec([update_index, ...], results) = exec([...], updated_results)
trong đó:- Nếu
result_index
nằm trong giới hạn củashape(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ủaresults
córesults...[result_index]
được đặt thànhupdated_values...
.- Hoặc
updated_results = results
.
- Nếu
exec([], results) = results
.
Nếu indices_are_sorted
là true
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_indices
là true
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_indices
là
true
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ủascatter_indices
tương ứng với Không bao gồmindex_vector_dim
.update_window_dim_sizes <= shape(inputs[0])
ngoại trừ các kích thước kích thước tronginputs[0]
tương ứng vớiinserted_window_dims
vàinput_batching_dims
không được đưa vào.combine
đặtupdate_scatter_dim_sizes
tại các trục tương ứng vớiupdate_scatter_dims
vàupdate_window_dim_sizes
tại các trục tương ứng đếnupdate_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]]
// ]
// ]
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]]
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ừ
operand
và source
trong một ví dụ cụ thể.
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_strides
vàpadding
đượ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)
và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ảnreduce
(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ếuselected_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]]
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_transfer
là true
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_DEVICE và DEVICE_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ếuis_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
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]
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]
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]
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]
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]]
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]
// ]
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ử e1
và e2
đượ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 trongresult_index
và:
được chèn tạiadjusted_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ằngcomparator_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]]
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]]
trừ
Ngữ nghĩa
Thực hiện phép trừ từng phần tử của hai tensor lhs
và rhs
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]]
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]
// ]
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]
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ủarange(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]]
// ]
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 a
và b
, result[i0, ..., iR-3, :, :]
là giải pháp
đến op(a[i0, ..., iR-3, :, :]) * x = b[i0, ..., iR-3, :, :]
khi left_side
là
true
hoặc x * op(a[i0, ..., iR-3, :, :]) = b[i0, ..., iR-3, :, :]
khi
left_side
là false
, 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ụnga
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ủaa
.
Dữ liệu đầu vào chỉ được đọc từ tam giác dưới của a
, nếu lower
là true
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 , TRANSPOSE và ADJOINT |
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)
và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ạituple<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))
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
xor
Ngữ nghĩa
Thực hiện XOR toàn phần của 2 tensor lhs
và rhs
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]]
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ánhget_tuple_element
,rng
,complex
#560, và tích chậpwindow_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
→ %2
→ return
và
%1
→ %0
→ %2
→ return
.
func.func @main() -> tensor<f64> {
%0 = stablehlo.constant dense<1.0> : tensor<f64>
%1 = stablehlo.constant dense<2.0> : tensor<f64>
%2 = stablehlo.add %0, %1 : tensor<f64>
return %2 : tensor<f64>
}
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)
và
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_permute
và
reduce_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]]
và 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]]
và 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]]
và 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 = 4
và num_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
và %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
, rhs
và rhs_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ả 0
và
rank(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, operand
và result
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ặcQuantizedTensorElementType
tương ứng. củaTensorType
hoặcQuantizedTensorType
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 trongis_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 chois_quantized(x) and quantization_dimension(x) is None
.is_promotable(x: Type, y: Type) -> bool
kiểm tra xem loạix
có thể được quảng bá hay không để nhậpy
. Khix
vày
làQuantizedTensorElementType
, chương trình khuyến mãi chỉ được áp dụng chostorage_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 chois_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ếux
làFloatType
. Nếux
là một giá trị hoặc phần giữ chỗ, thì hàm này sẽ là lối tắt chois_type_name(type(x))
max_value(x: Type) -> Value
trả về giá trị lớn nhất của mộtTensorElementType
Nếux
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ộtTensorElementType
Nếux
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ĩamember_name
thuộc mọi loại. Ví dụ:tensor_element_type(x)
trả về phầnTensorElementType
củaTensorType
tương ứng. Nếux
là một giá trị hoặc phần giữ chỗ, thì hàm này sẽ là lối tắt chomember_name(type(x))
Nếux
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 đếnNone
. Đ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ị tensorlhs
vàrhs
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ê bao và chia 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ủax
dựa trêntype(x)
và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ủax
làNaN
hoặcfalse
. Nếux
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ủax
đượ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ặcfalse
. Nếux
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ếux
không có phần tử trùng lặp hoặcfalse
. Nếux
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ầnmember_name
trong số tất cả giá trị. Ví dụ:real_part(x)
trả vềRealPart
củaComplexConstant
tương ứng. Nếux
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ủax
đều bằng nhau hoặcfalse
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ếux
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ủax
dọc theo trụcaxis
. Nếux
không phải là tensor hoặcdim(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ếux
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ếux
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 chorange(rank(x))
dim(x: Value | Placeholder | Type, axis: Value) -> Value
là lối tắt choshape(x)[axis]
dims(x: Value | Placeholder | Type, axes: List) -> List
là lối tắt cholist(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ụcsize(x)
choTensorType
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ếux
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 chosize(shape(x))
shape(x: Value | Placeholder | Type) -> Value
được định nghĩa trong phần "Hàm về các loại" quamember_name
.size(x: Value | Placeholder | Type) -> Value
là lối tắt choreduce(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 choelement_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_max
vàquantization_dimension
(đối với loại lượng tử hoá trên mỗi trục) đều phải khớp, nhưngscales
vàzero 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 "cross_replica_and_partition" 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.