StableHLO-Spezifikation

StableHLO ist ein Operation-Set für High-Level-Operationen (HLO) in Maschinen, Lernmodelle (ML). StableHLO dient als Portabilitätsebene zwischen verschiedenen ML-Frameworks und ML-Compiler: ML-Frameworks, die StableHLO-Programme erstellen sind mit ML-Compilern kompatibel, die StableHLO-Programme nutzen.

Unser Ziel ist es, die ML-Entwicklung zu vereinfachen und zu beschleunigen, Interoperabilität zwischen verschiedenen ML-Frameworks (wie TensorFlow, JAX und PyTorch) und ML-Compiler (wie XLA und IREE). Gegen dieses Ende enthält eine Spezifikation für die Programmiersprache StableHLO.

Diese Spezifikation enthält drei Hauptabschnitte. Zunächst sollte der Im Abschnitt Programme wird die Struktur von StableHLO-Programmen beschrieben. die aus StableHLO-Funktionen bestehen, die wiederum aus StableHLO-Operationen bestehen. Innerhalb dieser Struktur gibt der Abschnitt Ops die Semantik der für einzelne Vorgänge. Der Abschnitt Ausführung enthält Semantik für alle die diese Vorgänge gemeinsam in einem Programm ausführen. Die Funktion Im Abschnitt Notation wird die im gesamten Dokument verwendete Notation erläutert. Spezifikation zu ändern.

Um die Spezifikation einer früheren StableHLO-Version anzuzeigen, öffnen Sie das Repository im getaggte Freigabe von Interesse. Beispiel: StableHLO v0.19.0 Spec Informationen zum Anzeigen von Änderungen, die bei jedem Nebenversions-Bump von StableHLO vorgenommen wurden, finden Sie unter das Versionsprotokoll in VhloDialect.td

Programme

Program ::= {Func}

StableHLO-Programme bestehen aus einer beliebigen Anzahl von StableHLO-Funktionen. Unten sehen Sie ein Beispielprogramm mit der Funktion @main mit 3 Eingaben (%image, %weights und %bias) und 1 Ausgabe. Der Hauptteil der Funktion hat 6 Vorgänge.

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

Funktionen

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

StableHLO-Funktionen, die auch als benannte Funktionen bezeichnet werden, haben eine Kennung, Ein-/Ausgaben und einen Textkörper. Für die Zukunft planen wir, Es werden zusätzliche Metadaten für Funktionen eingeführt, um eine bessere Kompatibilität zu erreichen. mit HLO (#425, #626 Nr. 740 #744).

IDs

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

StableHLO-Kennungen ähneln Kennungen in vielen Programmiersprachen. Sprachen, mit zwei Besonderheiten: 1) Alle Kennungen haben Sieigzeichen, die verschiedene Arten von Kennungen unterscheiden, 2) Wertkennungen vollständig numerisch, um die Generierung von StableHLO-Programmen zu vereinfachen.

Typen

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

StableHLO-Typen werden in Werttypen kategorisiert, die auch als First-class-Typen), die StableHLO-Werte und Nicht-Werttypen darstellen. die andere Programmelemente beschreiben. StableHLO-Typen ähneln Typen in viele Programmiersprachen, wobei die größte Besonderheit die Funktionen von StableHLO sind. domainspezifischen Charakter, der zu ungewöhnlichen Ergebnissen führt (z.B. skalare Typen) sind keine Werttypen).

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

Tensor-Typen stellen Tensoren dar, also mehrdimensionale Arrays. Sie haben eine Form und einen Unterelementtyp, wobei eine Form für nicht negative oder unbekannte Dimensionsgrößen in aufsteigender Reihenfolge der zugehörigen Dimensionen (auch Achsen genannt) von 0 bis R-1 nummeriert. Die Anzahl der Dimensionen R wird als Rang bezeichnet. Beispiel: tensor<2x3xf32> ist einen Tensortyp mit der Form 2x3 und dem Elementtyp f32. Es hat zwei Dimensionen. (oder, mit anderen Worten, zwei Achsen) – die 0. Dimension und die erste Dimension, deren Größen 2 und 3 sind. Sein Rang ist 2.

Formen können teilweise oder vollständig unbekannt (dynamisch) sein, z.B. tensor<?x2xf64> ist teilweise unbekannt und tensor<?x?xf64> ist vollständig unbekannt. Dynamisch Dimensionsgrößen durch ? dargestellt. Die Rangfolge von Formen kann nicht aufgehoben werden.

Zukünftig möchten wir die Tensortypen Größen und Elementtypen beispielsweise, um Layouts (#629) und Datendichte (#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
Name Typ Einschränkungen
storage_type Ganzzahltyp (C1–C3), (C8)
storage_min Ganzzahlkonstante (C1), (C3), (C7)
storage_max Ganzzahlkonstante (C2), (C3), (C7)
expressed_type Gleitkommatyp (C4)
quantization_dimension optionale Ganzzahlkonstante (C10–C12)
scales variadische Anzahl von Gleitkommakonstanten (C4-C6), (C9), (C10), (C13)
zero_points variadische Anzahl ganzzahliger Konstanten (C7–C9)

Quantisierte Elementtypen stehen für ganzzahlige Werte eines Speichertyps in den Bereich von storage_min bis storage_max (einschließlich), die sich auf Gleitkommawerte eines ausgedrückten Typs. Für einen gegebenen ganzzahligen Wert i kann der entsprechende Gleitkommawert f als f = (i - zero_point) * scale, wobei scale und zero_point aufgerufen werden Quantisierungsparametern. storage_min und storage_max sind optional in der Grammatik, aber haben die Standardwerte min_value(storage_type) und max_value(storage_type). Quantisierte Elementtypen haben die folgenden Einschränkungen:

  • (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) Wenn is_empty(quantization_dimension), dann size(scales) = 1.
  • (C11) 0 <= quantization_dimension.

Derzeit ist QuantizationScale eine Gleitkommakonstante, es gibt jedoch starkes Interesse an ganzzahlbasierten Skalen, dargestellt durch Multiplikatoren und Schichten. Wir möchten dies in naher Zukunft untersuchen (#1404)

Die Semantik von QuantizationZeroPoint wird derzeit diskutiert. einschließlich Typ, Werten und ob es nur eine oder in einem quantisierten Tensortyp. Basierend auf den zum Ergebnis dieser Diskussion kann sich die Spezifikation um Nullpunkte in der Zukunft erfolgen (#1405).

Eine weitere laufende Diskussion zur Semantik von QuantizationStorageMin und QuantizationStorageMax, um zu bestimmen, ob Einschränkungen auf diese Werte und die Werte von quantisierten Tensoren angewendet. (#1406)

Schließlich wollen wir erkunden, wie unbekannte Skalen und Nullen Ähnlich wie die Darstellung von unbekannten Dimensionsgrößen (#1407)

Quantisierte Tensortypen stellen Tensoren mit quantisierten Elementen dar. Diese Tensoren sind genau die gleichen wie reguläre Tensoren, mit der Ausnahme, dass ihre Elemente quantisierte Elementtypen anstelle von regulären Elementtypen haben.

In quantisierten Tensoren kann die Quantisierung per-Tensor erfolgen, was bedeutet, Ein scale und zero_point für den gesamten Tensor oder kann pro Achse sein, Dies bedeutet, dass bei mehreren scales und zero_points ein Paar pro Segment von um eine bestimmte Dimension quantization_dimension zu erhalten. Formals in einem Tensor-t Mit der Quantisierung pro Achse gibt es dim(t, quantization_dimension) Slices der quantization_dimension: t[:, ..., 0, ..., :], t[:, ..., 1, ..., :], Alle Elemente im i. Segment verwenden scales[i] und zero_points[i] als ihre Quantisierungsparameter. Quantisierte Tensortypen haben Folgendes: Einschränkungen:

  • Für die Quantisierung pro Tensor: <ph type="x-smartling-placeholder">
      </ph>
    • Keine zusätzlichen Einschränkungen.
  • Für die Quantisierung pro Achse: <ph type="x-smartling-placeholder">
      </ph>
    • (C12) quantization_dimension < rank(self).
    • (C13) dim(self, quantization_dimension) = size(scales).
TokenType ::= 'token'

Tokentypen stellen Tokens dar, d. h. intransparente Werte, die erzeugt und verbraucht werden. durch einige Operationen. Tokens werden zum Festlegen der Ausführungsreihenfolge für Vorgänge verwendet wie im Abschnitt Ausführung beschrieben.

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

Tupeltypen stehen für Tupel, also heterogene Listen. Tupel sind ein Vermächtnis die nur aus Gründen der Kompatibilität mit HLO besteht. In HLO werden Tupel zur Darstellung variadischer Ein- und Ausgaben. In StableHLO werden variadische Eingaben und Ausgaben werden nativ unterstützt und die einzige Verwendung von Tupeln in StableHLO besteht darin, umfassende Darstellung von HLO ABI, wo z.B. T, tuple<T> und tuple<tuple<T>> kann je nach Implementierung. Wir planen, in Zukunft Änderungen am HLO ABI vorzunehmen. mit der wir Tupeltypen aus StableHLO entfernen können, (#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'

Elementtypen stellen Elemente von Tensortypen dar. Anders als bei vielen Programmen Sprachen sind, sind diese Typen in StableHLO nicht an erster Stelle. Das bedeutet, dass StableHLO-Programme können Werte dieser Typen nicht direkt darstellen (daher Es ist idiomatisch, Skalarwerte des Typs T mit einem 0-dimensionalen Tensor darzustellen. Werte des Typs tensor<T>) enthält.

  • Der Boolesche Typ steht für die booleschen Werte true und false.
  • Ganzzahltypen können entweder vorzeichen (si) oder unvorzeichent (ui) sein und haben eine der unterstützten Bitbreiten (2, 4, 8, 16, 32 oder 64). Vorzeichenbehaftete siN-Typen stellen ganzzahlige Werte von -2^(N-1) bis 2^(N-1)-1 dar einschließlich und vorzeichenlose uiN-Typen stellen Ganzzahlwerte von 0 bis 2^N-1 einschließlich.
  • Es gibt folgende Gleitkommatypen: <ph type="x-smartling-placeholder">
  • Komplexe Typen stehen für komplexe Werte, die einen reellen Teil haben und einem imaginären Teil desselben Elementtyps. Unterstützt, komplex Typen sind complex<f32> (beide Teile sind vom Typ f32) und complex<f64> (beide Teile sind vom Typ f64).
FunctionType ::= '(' InputTypes ')' '->' '(' OutputTypes ')'
InputTypes ::= [ValueType {',' ValueType}]
OutputTypes ::= [ValueType {',' ValueType}]

Funktionstypen stellen sowohl benannte als auch anonyme Funktionen dar. Sie haben Eingabetypen (die Liste der Typen auf der linken Seite von ->) und Ausgabetypen (die Liste der Typen rechts von ->). In vielen Programmierungen sind Funktionstypen erstklassig, aber in StableHLO nicht.

StringType ::= 'string'

Der Stringtyp steht für Bytesequenzen. Anders als bei vielen Programmen ist der Zeichenfolgentyp in StableHLO nicht die erste Klasse und wird nur verwendet, geben statische Metadaten für Programmelemente an.

Vorgänge

StableHLO-Operationen (auch Ops genannt) stellen eine geschlossene Menge dar. übergeordneten Abläufen in ML-Modellen. Wie bereits erwähnt, StableHLO-Syntax ist stark von MLIR inspiriert, was nicht unbedingt die am stärksten eine ergonomische Alternative, ist aber wohl am besten für das Ziel von StableHLO geeignet, und mehr Interoperabilität zwischen ML-Frameworks und ML-Compilern schaffen.

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

StableHLO-Operationen (auch Operations genannt) haben einen Namen, Ein-/Ausgaben und eine Signatur. Der Name besteht aus dem Präfix stablehlo. und Eine mnemonische Kennzeichnung, die einen der unterstützten Vorgänge eindeutig identifiziert. Siehe unten für eine umfassende Liste aller unterstützten Operationen.

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

Betriebsabläufe verbrauchen Eingaben und erzeugen Ausgaben. Eingaben sind kategorisiert in Eingabewerte (berechnet während der Ausführung), Eingabefunktionen (bereitgestellt statisch, da StableHLO-Funktionen keine First-Class-Werte sind) und Eingabeattribute (auch statisch bereitgestellt). Die Art der Ein- und Ausgaben von einem Opaion konsumiert und produziert wird, hängt von seiner Eselsbrücke ab. Beispiel: add op verbraucht 2 Eingabewerte und erzeugt 1 Ausgabewert. Im Vergleich dazu Der Vorgang select_and_scatter verbraucht 3 Eingabewerte, 2 Eingabefunktionen und 3 Eingabeattribute.

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

Eingabefunktionen (auch anonyme Funktionen genannt) sind sehr ähnlich wie benannte Funktionen, mit dem Unterschied, dass sie keine Kennung haben (daher der Name „anonymous“), 2) es werden keine Ausgabetypen deklariert (Ausgabetypen sind aus dem return-Vorgang in der Funktion abgeleitet wird).

Die Syntax für Eingabefunktionen enthält einen derzeit nicht verwendeten Teil (siehe Unused-Produktion oben), das aus Gründen der MLIR-Kompatibilität gedacht ist. In MLIR gibt es ein allgemeineres Konzept von „Regionen“, die mehrere „Blöcke“ haben kann, der Operationen sind über Jump Ops miteinander verbunden. Die IDs dieser Blöcke entsprechen an die Unused-Produktion, damit sie voneinander unterschieden werden können. StableHLO hat keine Jump Ops, sodass der entsprechende Teil der MLIR-Syntax nicht verwendet werden (aber noch vorhanden ist).

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

Eingabeattribute haben einen Namen und einen Wert. Dies ist einer der unterstützten Werte. Konstanten. Sie sind die primäre Möglichkeit, statische Metadaten für das Programm anzugeben. Elemente. Beim Vorgang concatenate wird beispielsweise das Attribut dimension verwendet, gibt die Dimension an, mit der die Eingabewerte verkettet werden. In ähnlicher Weise Der Vorgang slice verwendet mehrere Attribute wie start_indices und limit_indices , um die Grenzen anzugeben, die zum Aufteilen des Eingabewerts verwendet werden.

Derzeit enthalten StableHLO-Programme, die derzeit frei sind, manchmal Attribute die in diesem Dokument nicht beschrieben sind. Für die Zukunft planen wir, diese Attribute entweder in das StableHLO-Opset aufnehmen oder sie StableHLO-Programmen. In der Zwischenzeit finden Sie hier eine Liste mit diesen Attribute:

  • layout (#629)
  • mhlo.frontend_attributes (#628)
  • mhlo.sharding (#619)
  • output_operand_aliases (#740)
  • Standortmetadaten (#594)
OpSignature ::= '(' [ValueType {',' ValueType}] ')' '->' '(' [ValueType {',' ValueType}] ')'

Die Vorgangssignatur besteht aus den Typen aller Eingabewerte (der Liste der Typen der linken Seite von ->) und die Typen aller Ausgabewerte (die Liste der auf der rechten Seite von ->. Genau genommen sind Eingabetypen redundant sind und Ausgabetypen fast immer redundant sind. Bei den meisten StableHLO-Operationen lassen sich Ausgabetypen aus Eingaben ableiten). Trotzdem Signatur ist absichtlich Teil der StableHLO-Syntax für die Kompatibilität mit MLIR.

Unten sehen Sie ein Beispiel für eine Operation mit der mnemonischen Kennzeichnung select_and_scatter. Es verbraucht 3 Eingabewerte (%operand, %source und %init_value), 2 Eingabefunktionen und 3 Eingabeattribute (window_dimensions, window_strides und padding). Beachten Sie, dass die Signatur des Vorgangs nur die Typen der Eingabewerte enthält. Dies gilt jedoch nicht für die Art der Eingabefunktionen und Attribute, die inline bereitgestellt werden.

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

Konstanten

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

StableHLO-Konstanten haben ein Literal und einen Typ, die zusammen für einen StableHLO-Wert. Im Allgemeinen ist der Typ Teil der konstanten Syntax, außer wenn sie eindeutig ist (z.B. hat eine boolesche Konstante eindeutig den Typ i1, während eine ganzzahlige Konstante mehrere mögliche Typen haben kann).

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

Boolesche Konstanten stellen die booleschen Werte true und false dar. Boolescher Wert haben Konstanten den Typ i1.

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

Ganzzahlkonstanten stellen Ganzzahlwerte über Strings dar, die Dezimalzahlen oder Hexadezimalschreibweise. Andere Basen, z.B. binär oder oktal, werden nicht unterstützt. Für Ganzzahlkonstanten gelten die folgenden Einschränkungen:

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

Gleitkommakonstanten stellen Gleitkommawerte über Strings dar, die Dezimalschreibweise oder wissenschaftliche Schreibweise verwenden. Außerdem kann die hexadezimale Notation werden die zugrunde liegenden Bits direkt im Gleitkommaformat eines mit dem entsprechenden Typ aus. Für Gleitkommakonstanten gelten die folgenden Einschränkungen:

  • (C1) Wenn die Hexadezimalschreibweise nicht verwendet wird, is_wellformed(float_literal, float_type)
  • (C2) Bei Verwendung der Hexadezimalschreibweise size(hexadecimal_digits) = num_bits(float_type) / 4
ComplexConstant ::= ComplexLiteral ':' ComplexType
ComplexLiteral  ::= '(' RealPart ',' ImaginaryPart ')'
RealPart        ::= FloatLiteral
ImaginaryPart   ::= FloatLiteral

Komplexe Konstanten stellen komplexe Werte mithilfe von Listen eines reellen Teils dar. (kommt an erster Stelle) und ein imaginärer Teil (an zweiter Stelle). Beispiel: (1.0, 0.0) : complex<f32> steht für 1.0 + 0.0i und (0.0, 1.0) : complex<f32> repräsentiert 0.0 + 1.0i. Die Reihenfolge, in der diese werden -Teile dann im Arbeitsspeicher gespeichert. Komplexe Konstanten haben folgende Einschränkungen:

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

Tensor-Konstanten stellen Tensor-Werte mithilfe verschachtelter Listen dar, die über NumPy-Notation. Beispiel: dense<[[1, 2, 3], [4, 5, 6]]> : tensor<2x3xi32> stellt einen Tensorwert mit der folgenden Zuordnung von Indexen zu Elementen dar: {0, 0} => 1, {0, 1} => 2, {0, 2} => 3, {1, 0} => 4, {1, 1} => 5, {1, 2} => 6 Die Reihenfolge, in der diese Elemente dann im Arbeitsspeicher gespeichert werden, Implementierung definiert. Für Tensorkonstanten gelten die folgenden Einschränkungen:

  • (C1) has_syntax(tensor_literal, element_type(tensor_type)), wobei gilt: <ph type="x-smartling-placeholder">
      </ph>
    • 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)), wobei gilt: <ph type="x-smartling-placeholder">
      </ph>
    • 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:]).
    • Andernfalls false.
QuantizedTensorConstant ::= QuantizedTensorLiteral ':' QuantizedTensorType
QuantizedTensorLiteral  ::= 'dense' '<' (DenseLiteral | ElementLiteral) '>'

Quantisierte Tensorkonstanten stellen quantisierte Tensorwerte mit denselben Werten Notation als Tensorkonstanten, wobei Elemente als Konstanten ihrer Speichertyp. Quantisierte Tensorkonstanten haben die folgenden Einschränkungen:

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

Stringliterale bestehen aus Byte, die mithilfe von ASCII-Zeichen und Escapesequenzen verwenden. Da sie unabhängig von der Codierung sind, Bytes ist implementierungsdefiniert. Stringliterale haben den Typ string.

Operativer Betrieb

Bauchmuskeln

Semantik

Führt eine elementweise abs-Operation für den operand-Tensor durch und erzeugt einen result-Wert Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für vorzeichenbehaftete Ganzzahlen: Modulus ganzzahl.
  • Für Gleitkommazahlen: abs aus IEEE-754.
  • Für komplexe Zahlen: komplexer Modulus.
  • Für quantisierte Typen: dequantize_op_quantize(abs, operand, type(result)).

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor eines vorzeichenbehafteten Ganzzahl-, Gleitkomma- oder komplexer Typ oder eines quantisierten Tensors pro Tensor (C1–C2)

Ausgaben

Name Typ Einschränkungen
result Tensor des vorzeichenbehafteten Ganzzahl- oder Gleitkommatyps oder quantisierter Tensor pro Tensor (C1–C2)

Einschränkungen

  • (C1) shape(result) = shape(operand).
  • (C2) baseline_element_type(result) ist definiert als: <ph type="x-smartling-placeholder">
      </ph>
    • complex_element_type(element_type(operand)) wenn is_complex(operand).
    • Andernfalls baseline_element_type(operand).

Beispiele

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

Weitere Beispiele

Hinzufügen

Semantik

Führt eine elementweise Addition der beiden Tensoren lhs und rhs durch und erzeugt einen result-Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für boolesche Werte: logisches ODER.
  • Für Ganzzahlen: Addition von Ganzzahlen.
  • Für Gleitkommazahlen: addition aus IEEE-754.
  • Für komplexe Zahlen: komplexe Addition
  • Für quantisierte Typen: dequantize_op_quantize(add, lhs, rhs, type(result)).

Eingaben

Label Name Typ Einschränkungen
(I1) lhs Tensor oder quantisierter Tensor (C1–C6)
(I2) rhs Tensor oder quantisierter Tensor (C1–C5), (C7)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor (C1–C7)

Einschränkungen

  • Wenn die Operation nicht quantisierte Tensoren verwendet: <ph type="x-smartling-placeholder">
      </ph>
    • (C1) type(lhs) = type(rhs) = type(result).
  • Wenn die Operation quantisierte Tensoren verwendet: <ph type="x-smartling-placeholder">
      </ph>
    • (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) Wenn is_per_axis_quantized(lhs), dann quantization_dimension(lhs) = quantization_dimension(result).
    • (C7) Wenn is_per_axis_quantized(rhs), dann quantization_dimension(rhs) = quantization_dimension(result).

Beispiele

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

Weitere Beispiele

after_all

Semantik

Stellt sicher, dass die Vorgänge, die die inputs erzeugen, vor jeder Ausführung ausgeführt werden Vorgänge, die von result abhängig sind. Bei der Ausführung dieses Vorgangs passiert nichts. Er existiert nur zum Einrichten von Datenabhängigkeiten von result bis inputs.

Eingaben

Label Name Typ
(I1) inputs variadische Zahl von token

Ausgaben

Name Typ
result token

Beispiele

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

Weitere Beispiele

all_gather

Semantik

Verkettet innerhalb jeder Prozessgruppe im StableHLO-Prozessraster die Werte der operands-Tensoren aus jedem Prozess entlang von all_gather_dim und erzeugt results-Tensoren.

Der Vorgang teilt das StableHLO-Prozessraster in process_groups auf, wie folgt definiert:

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

Danach gilt in jeder process_group Folgendes:

  • operands...@receiver = [operand@sender for sender in process_group] für alle receiver in process_group.
  • results...@process = concatenate(operands...@process, all_gather_dim) für alle process in process_group.

Eingaben

Label Name Typ Einschränkungen
(I1) operands variadische Anzahl von Tensoren oder quantisierte Tensoren pro Tensor (C1), (C6)
(I2) all_gather_dim Konstante vom Typ si64 (C1), (C6)
(I3) replica_groups 2-dimensionale Tensorkonstante vom Typ si64 (C2–C4)
(I4) channel_id Konstante vom Typ si64 (C5)
(I5) use_global_device_ids Konstante vom Typ i1 (C5)

Ausgaben

Name Typ Einschränkungen
results variadische Anzahl von Tensoren oder quantisierte Tensoren pro Tensor (C6)

Einschränkungen

  • (C1) 0 <= all_gather_dim < rank(operands...).
  • (C2) is_unique(replica_groups).
  • (C3) size(replica_groups) ist definiert als: <ph type="x-smartling-placeholder">
      </ph>
    • num_replicas, wenn cross_replica verwendet wird.
    • num_replicas, wenn cross_replica_and_partition verwendet wird.
    • num_processes, wenn flattened_ids verwendet wird.
  • (C4) 0 <= replica_groups < size(replica_groups).
  • (C5) Wenn use_global_device_ids = true, dann channel_id > 0.
  • (C6) type(results...) = type(operands...) mit Ausnahme von: <ph type="x-smartling-placeholder">
      </ph>
    • dim(results..., all_gather_dim) = dim(operands..., all_gather_dim) * dim(process_groups, 1).

Beispiele

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

Weitere Beispiele

all_reduce

Semantik

Wendet innerhalb jeder Prozessgruppe im StableHLO-Prozessraster eine Reduzierung an Funktion computation zu den Werten der operands-Tensoren aus jedem Prozess und erzeugt results-Tensoren.

Der Vorgang teilt das StableHLO-Prozessraster in process_groups auf, wie folgt definiert:

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

Danach gilt in jeder process_group Folgendes:

  • results...@process[result_index] = exec(schedule) für einen binären Baum schedule, wobei gilt: <ph type="x-smartling-placeholder">
      </ph>
    • exec(node) = computation(exec(node.left), exec(node.right)).
    • exec(leaf) = leaf.value.
  • schedule ist eine implementierungsdefinierte binäre Baumstruktur, deren Reihenfolge Durchlauf ist to_destination_type(operands...@process_group...[result_index], type(func_inputs(computation)[0])).

Eingaben

Label Name Typ Einschränkungen
(I1) operands variadische Anzahl von Tensoren oder quantisierte Tensoren pro Tensor (C5), (C6)
(I2) replica_groups Variadische Anzahl der eindimensionalen Tensorkonstanten vom Typ si64 (C1–C3)
(I3) channel_id Konstante vom Typ si64 (C4)
(I4) use_global_device_ids Konstante vom Typ i1 (C4)
(I5) computation Funktion (C5)

Ausgaben

Name Typ Einschränkungen
results variadische Anzahl von Tensoren oder quantisierte Tensoren pro Tensor (C6–C7)

Einschränkungen

  • (C1) is_unique(replica_groups).
  • (C2) size(replica_groups) ist definiert als: <ph type="x-smartling-placeholder">
      </ph>
    • num_replicas, wenn cross_replica verwendet wird.
    • num_replicas, wenn cross_replica_and_partition verwendet wird.
    • num_processes, wenn flattened_ids verwendet wird.
  • (C3) 0 <= replica_groups < size(replica_groups).
  • (C4) Wenn use_global_device_ids = true, dann channel_id > 0.
  • (C5) computation hat den Typ (tensor<E>, tensor<E>) -> (tensor<E>), wobei is_promotable(element_type(operand), E)
  • (C6) shape(results...) = shape(operands...).
  • (C7) element_type(results...) = E.

Beispiele

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

Weitere Beispiele

all_to_all

Semantik

all_to_all

Innerhalb jeder Prozessgruppe im StableHLO-Prozessraster werden die Werte der die operands-Tensoren entlang von split_dimension in Teile, verteilt die zwischen Prozessen und verkettet die verstreuten Teile entlang concat_dimension und erzeugt results-Tensoren. Der Vorgang teilt das StableHLO-Prozessraster in process_groups auf, wie folgt definiert:

  • cross_replica(replica_groups) wenn channel_id <= 0.
  • cross_partition(replica_groups) wenn channel_id > 0.

Danach gilt in jeder process_group Folgendes:

  • split_parts...@sender = split(operands...@sender, split_count, split_dimension) für alle sender in process_group.
  • scattered_parts...@receiver = [split_parts...@sender[receiver_index] for sender in process_group], wobei receiver_index = process_group.index(receiver).
  • results...@process = concatenate(scattered_parts...@process, concat_dimension).

Eingaben

Label Name Typ Einschränkungen
(I1) operands variadische Anzahl von Tensoren oder quantisierte Tensoren pro Tensor (C1–C3), (C9)
(I2) split_dimension Konstante vom Typ si64 (C1), (C2), (C9)
(I3) concat_dimension Konstante vom Typ si64 (C3), (C9)
(I4) split_count Konstante vom Typ si64 (C2), (C4), (C8), (C9)
(I5) replica_groups 2-dimensionale Tensorkonstante vom Typ si64 (C5–C8)
(I6) channel_id Konstante vom Typ si64

Ausgaben

Name Typ Einschränkungen
results variadische Anzahl von Tensoren oder quantisierte Tensoren pro Tensor (C9)

Einschränkungen

  • (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) ist definiert als: <ph type="x-smartling-placeholder">
      </ph>
    • num_replicas, wenn cross_replica verwendet wird.
    • num_partitions, wenn cross_partition verwendet wird.
  • (C7) 0 <= replica_groups < size(replica_groups).
  • (C8) dim(replica_groups, 1) = split_count.
  • (C9) type(results...) = type(operands...) mit Ausnahme von split_dimension != concat_dimension: <ph type="x-smartling-placeholder">
      </ph>
    • dim(results..., split_dimension) = dim(operands..., split_dimension) / split_count.
    • dim(results..., concat_dimension) = dim(operands..., concat_dimension) * split_count.

Beispiele

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

Weitere Beispiele

und

Semantik

Führt das elementweise UND der zwei Tensoren lhs und rhs durch und erzeugt eine result Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für boolesche Werte: logisches UND.
  • Für Ganzzahlen: bitweises UND.

Eingaben

Label Name Typ Einschränkungen
(I1) lhs Tensor des booleschen oder Ganzzahltyps (C1)
(I2) rhs Tensor des booleschen oder Ganzzahltyps (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des booleschen oder Ganzzahltyps (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

atan2

Semantik

Führt eine elementweise atan2-Operation für den Tensor lhs und rhs durch und erzeugt einen result-Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für Gleitkommazahlen: atan2 aus IEEE-754.
  • Für komplexe Zahlen: komplexe atan2.
  • Für quantisierte Typen: dequantize_op_quantize(atan2, lhs, rhs, type(result)).

Eingaben

Label Name Typ Einschränkungen
(I1) lhs Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)
(I2) rhs Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

batch_norm_grad

Semantik

Berechnet Gradienten mehrerer Eingaben der Rückpropagierung von batch_norm_training aus grad_output und produziert grad_operand, grad_scale und grad_offset Tensoren. Formal kann diese Operation als eine Zerlegung in vorhandene StableHLO-Vorgänge mit der folgenden Python-Syntax:

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

Führt für quantisierte Typen durch 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))

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkommatyps oder quantisierter Tensor pro Tensor (C1–C3), (C5)
(I2) scale 1-dimensionaler Tensor eines Gleitkomma- oder pro Tensor quantisierten Typs (C2), (C4), (C5)
(I3) mean 1-dimensionaler Tensor eines Gleitkomma- oder pro Tensor quantisierten Typs (C2), (C4)
(I4) variance 1-dimensionaler Tensor eines Gleitkomma- oder pro Tensor quantisierten Typs (C2), (C4)
(I5) grad_output Tensor des Gleitkommatyps oder quantisierter Tensor pro Tensor (C2), (C3)
(I6) epsilon Konstante vom Typ f32
(I7) feature_index Konstante vom Typ si64 (C1), (C5)

Ausgaben

Name Typ Einschränkungen
grad_operand Tensor des Gleitkommatyps oder quantisierter Tensor pro Tensor (C2), (C3)
grad_scale 1-dimensionaler Tensor eines Gleitkomma- oder pro Tensor quantisierten Typs (C2), (C4)
grad_offset 1-dimensionaler Tensor eines Gleitkomma- oder pro Tensor quantisierten Typs (C2), (C4)

Einschränkungen

  • (C1) 0 <= feature_index < rank(operand).
  • (C2) operand, scale, mean, variance, grad_output, grad_operand, grad_scale und grad_offset haben dieselbe baseline_element_type.
  • (C3) operand, grad_output und grad_operand haben die gleiche Form.
  • (C4) scale, mean, variance, grad_scale und grad_offset haben die dieselbe Form haben.
  • (C5) size(scale) = dim(operand, feature_index).

Beispiele

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

Semantik

Normalisiert den Tensor operand für alle Dimensionen mit Ausnahme der feature_index-Dimension und erzeugt einen result-Tensor. Formell gesprochen Operation kann als Zerlegung vorhandener StableHLO-Vorgänge ausgedrückt werden. mit der folgenden Python-Syntax:

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)

Führt für quantisierte Typen durch 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))

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkommatyps oder quantisierter Tensor pro Tensor (C1–C7)
(I2) scale 1-dimensionaler Tensor eines Gleitkomma- oder pro Tensor quantisierten Typs (C2), (C3)
(I3) offset 1-dimensionaler Tensor eines Gleitkomma- oder pro Tensor quantisierten Typs (C2), (C4)
(I4) mean 1-dimensionaler Tensor eines Gleitkomma- oder pro Tensor quantisierten Typs (C5)
(I5) variance 1-dimensionaler Tensor eines Gleitkomma- oder pro Tensor quantisierten Typs (C2), (C6)
(I6) epsilon Konstante vom Typ f32
(I7) feature_index Konstante vom Typ si64 (C1), (C3–C6)

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkommatyps oder quantisierter Tensor pro Tensor (C2), (C7)

Einschränkungen

  • (C1) 0 <= feature_index < rank(operand).
  • (C2) operand, scale, offset, mean, variance und result haben die Gleiche baseline_element_type.
  • (C3) size(scale) = dim(operand, feature_index).
  • (C4) size(offset) = dim(operand, feature_index).
  • (C5) size(mean) = dim(operand, feature_index).
  • (C6) size(variance) = dim(operand, feature_index).
  • (C7) baseline_type(operand) = baseline_type(result).

Beispiele

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

Semantik

Berechnet den Mittelwert und die Varianz für alle Dimensionen mit Ausnahme von feature_index Dimension und normalisiert den Tensor operand, der output, batch_mean erzeugt und batch_var-Tensoren. Formal kann dieser Vorgang als Zerlegung in vorhandene StableHLO-Vorgänge unter Verwendung der Python-Syntax als folgt:

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

Führt für quantisierte Typen durch 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))

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkommatyps oder quantisierter Tensor pro Tensor (C1)
(I2) scale 1-dimensionaler Tensor von Gleitkomma oder pro Tensor quantisiert (C2), (C3)
(I3) offset 1-dimensionaler Tensor von Gleitkomma oder pro Tensor quantisiert (C2), (C4)
(I4) epsilon Konstante vom Typ f32 (C1), (C3–C6)
(I5) feature_index Konstante vom Typ si64 (C1), (C3–C6)

Ausgaben

Name Typ Einschränkungen
output Tensor des Gleitkommatyps oder quantisierter Tensor pro Tensor (C7)
batch_mean 1-dimensionaler Tensor von Gleitkomma oder pro Tensor quantisiert (C2), (C5)
batch_var 1-dimensionaler Tensor von Gleitkomma oder pro Tensor quantisiert (C2), (C6)

Einschränkungen

  • (C1) 0 <= feature_index < rank(operand).
  • (C2) Für operand, scale, offset, batch_mean, batch_var und output wurden denselben baseline_element_type.
  • (C3) size(scale) = dim(operand, feature_index).
  • (C4) size(offset) = dim(operand, feature_index).
  • (C5) size(batch_mean) = dim(operand, feature_index).
  • (C6) size(batch_var) = dim(operand, feature_index).
  • (C7) baseline_type(output) = baseline_type(operand).

Beispiele

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

Semantik

Führt einen Bitcast-Vorgang für den operand-Tensor aus und erzeugt einen result-Tensor wobei die Bits des gesamten operand-Tensors mit der Methode Typ des result-Tensors.

Formeller gesprochen: E = element_type(operand), E' = element_type(result), und R = rank(operand):

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

bits gibt eine speicherinterne Darstellung eines bestimmten Werts und sein Verhalten zurück. ist implementierungsdefiniert, da die genaue Darstellung von Tensoren Implementierung definiert. Die genaue Darstellung von Elementtypen ist Implementierung definiert werden.

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor oder quantisierter Tensor (C1–C2)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor (C1–C2)

Einschränkungen

  • (C1) Für E = is_quantized(operand) ? storage_type(operand) : element_type(operand), E' = is_quantized(result) ? storage_type(result) : element_type(result) und R = rank(operand): <ph type="x-smartling-placeholder">
      </ph>
    • Wenn num_bits(E') = num_bits(E), shape(result) = shape(operand).
    • Wenn num_bits(E') < num_bits(E):
    • rank(result) = R + 1.
    • dim(result, i) = dim(operand, i) für alle 0 <= i < R.
    • dim(result, R) * num_bits(E') = num_bits(E).
    • Wenn num_bits(E') > num_bits(E):
    • rank(result) = R - 1.
    • dim(result, i) = dim(operand, i) für alle 0 <= i < R.
    • dim(operand, R - 1) * num_bits(E) = num_bits(E').
  • (C2) Wenn is_complex(operand) or is_complex(result), dann is_complex(operand) and is_complex(result).

Beispiele

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

Weitere Beispiele

broadcast_in_dim

Semantik

Erweitert die Dimensionen und/oder den Rang eines Eingabetensors durch Duplizieren der Daten im operand-Tensor und erzeugt einen result-Tensor. Formeller gesprochen result[result_index] = operand[operand_index] – wo für alle d in axes(operand):

  • operand_index[d] = 0 wenn dim(operand, d) = 1.
  • Andernfalls operand_index[d] = result_index[broadcast_dimensions[d]].

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor oder quantisierter Tensor (C1–C2), (C5–C6)
(I2) broadcast_dimensions Eindimensionale Tensorkonstante vom Typ si64 (C2–C6)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor (C1), (C3), (C5-C6)

Einschränkungen

  • (C1) element_type(result) ist gegeben durch: <ph type="x-smartling-placeholder">
      </ph>
    • element_type(operand), wenn !is_per_axis_quantized(operand).
    • element_type(operand) mit Ausnahme von quantization_dimension(operand), scales(operand) und zero_points(operand) können abweichen von quantization_dimension(result), scales(result) und zero_points(result) oder „Sonstiges“.
  • (C2) size(broadcast_dimensions) = rank(operand).
  • (C3) 0 <= broadcast_dimensions < rank(result).
  • (C4) is_unique(broadcast_dimensions).
  • (C5) Für alle d in axes(operand): <ph type="x-smartling-placeholder">
      </ph>
    • dim(operand, d) = 1 oder
    • dim(operand, d) = dim(result, broadcast_dimensions[d]).
  • (C6) Wenn is_per_axis_quantized(result): <ph type="x-smartling-placeholder">
      </ph>
    • quantization_dimension(result) = broadcast_dimensions[quantization_dimension(operand)].
    • Wenn dim(operand, quantization_dimension(operand)) = 1, dann scales(result)[i] = scales(operand)[0] and zero_points(result)[i] = zero_points(operand)[0] for i in range(dim(result, quantization_dimension(result))).

Beispiele

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

Weitere Beispiele

Supportanfrage

Semantik

Erzeugt die Ausgabe, wenn genau eine Funktion aus branches ausgeführt wird abhängig vom Wert von index. Formeller result = selected_branch() Dabei gilt:

  • selected_branch = branches[index] wenn 0 <= index < size(branches).
  • Andernfalls selected_branch = branches[-1].

Eingaben

Label Name Typ Einschränkungen
(I1) index 0-dimensionaler Tensor vom Typ si32
(I2) branches variadische Anzahl von Funktionen (C1–C4)

Ausgaben

Name Typ Einschränkungen
results variadische Anzahl von Tensoren, quantisierte Tensoren oder Tokens (C4)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

cbrt

Semantik

Führt eine elementweise kubische Wurzeloperation für den operand-Tensor durch und erzeugt eine result-Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für Gleitkommazahlen: rootn(x, 3) aus IEEE-754.
  • Für komplexe Zahlen: komplexe kubische Wurzel.
  • Für quantisierte Typen: dequantize_op_quantize(cbrt, operand, type(result))

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

Ceil

Semantik

Führt die elementweise Obergrenze des operand-Tensors durch und erzeugt einen result-Tensor. Implementiert den roundToIntegralTowardPositive-Vorgang aus IEEE-754 Spezifikation zu ändern. Führt für quantisierte Typen durch dequantize_op_quantize(ceil, operand, type(result))

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkommatyps oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkommatyps oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

Cholesky

Semantik

Berechnet die Cholesky-Zerlegung eines Batches von Matrizen.

Formeller gesprochen: für alle i in index_space(result), result[i0, ..., iR-3, :, :] ist eine Cholesky-Zerlegung von a[i0, ..., iR-3, :, :] in Form eines unteren Dreiecks (wenn lower true ist) oder eine obere dreieckige Form (wenn lower false ist) Matrix. Die Ausgabewerte im entgegengesetzten Dreieck, d.h. dem genauen oberen Dreieck oder sind implementierungsdefiniert.

Wenn es i gibt, bei dem die Eingabematrix keine hermitische positiv-definierte ist ist das Verhalten nicht definiert.

Führt für quantisierte Typen durch dequantize_op_quantize(lambda operand: cholesky(operand, lower), a, type(result))

Eingaben

Label Name Typ Einschränkungen
(I1) a Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1–C3)
(I2) lower 0-dimensionale Tensorkonstante vom Typ i1

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

einschränken

Semantik

Fixiert jedes Element des Tensors operand zwischen einem Mindest- und einem Höchstwert und erzeugt einen result-Tensor. Formeller, result[result_index] = minimum(maximum(operand[result_index], min_element), max_element), wobei min_element = rank(min) = 0 ? min[] : min[result_index], max_element = rank(max) = 0 ? max[] : max[result_index] Bei quantisierten Typen führt dequantize_op_quantize(clamp, min, operand, max, type(result)) aus.

Komplexe Zahlen müssen mit einer überraschenden Semantik, Daher planen wir, die Unterstützung für komplexe Zahlen in Zukunft einzustellen. für diesen Vorgang (#560).

Eingaben

Label Name Typ Einschränkungen
(I1) min Tensor oder quantisierter Tensor pro Tensor (C1), (C3)
(I2) operand Tensor oder quantisierter Tensor pro Tensor (C1–C4)
(I3) max Tensor oder quantisierter Tensor pro Tensor (C2), (C3)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor pro Tensor (C4)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

collective_broadcast

Semantik

Innerhalb jeder Prozessgruppe im StableHLO-Prozessraster senden Sie den Wert des operand-Tensor vom Quellprozess zu den Zielprozessen und erzeugt einen result-Tensor.

Der Vorgang teilt das StableHLO-Prozessraster in process_groups auf, wie folgt definiert:

  • cross_replica(replica_groups) wenn channel_id <= 0.
  • cross_partition(replica_groups) wenn channel_id > 0.

Danach wird result@process folgendermaßen angegeben:

  • operand@process_groups[i, 0], wenn ein i vorhanden ist, sodass der Prozess in process_groups[i].
  • broadcast_in_dim(constant(is_quantized(result) ? quantize(0, element_type(result)) : 0, element_type(result)), [], type(result)) sonst.

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor oder quantisierter Tensor pro Tensor (C3)
(I2) replica_groups Variadische Anzahl der eindimensionalen Tensorkonstanten vom Typ si64 (C1), (C2)
(I3) channel_id Konstante vom Typ si64

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor pro Tensor (C3)

Einschränkungen

  • (C1) is_unique(replica_groups).
  • (C2) 0 <= replica_groups < N, wobei N definiert ist als: <ph type="x-smartling-placeholder">
      </ph>
    • num_replicas, wenn cross_replica verwendet wird.
    • num_partitions, wenn cross_partition verwendet wird.
  • (C3) type(result) = type(operand).

Beispiele

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

Semantik

Innerhalb jeder Prozessgruppe im StableHLO-Prozessraster wird der Wert der operand-Tensor vom Quellprozess zum Zielprozess und erzeugt einen result-Tensor.

Der Vorgang teilt das StableHLO-Prozessraster in process_groups auf, wie folgt definiert:

  • cross_replica(source_target_pairs) wenn channel_id <= 0.
  • cross_partition(source_target_pairs) wenn channel_id > 0.

Danach wird result@process folgendermaßen angegeben:

  • operand@process_groups[i, 0], wenn ein i vorhanden ist, sodass process_groups[i, 1] = process
  • broadcast_in_dim(constant(is_quantized(result) ? quantize(0, element_type(result)) : 0, element_type(result)), [], type(result)) sonst.

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor oder quantisierter Tensor pro Tensor (C5)
(I2) source_target_pairs 2-dimensionale Tensorkonstante vom Typ si64 (C1–C4)
(I3) channel_id Konstante vom Typ si64

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

  • (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, wobei N definiert ist als: <ph type="x-smartling-placeholder">
      </ph>
    • num_replicas, wenn cross_replica verwendet wird.
    • num_partitions, wenn cross_partition verwendet wird.
  • (C5) type(result) = type(operand).

Beispiele

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

Weitere Beispiele

vergleichen

Semantik

Führt einen elementweisen Vergleich von lhs- und rhs-Tensoren durch comparison_direction und compare_type und erzeugt einen result-Tensor.

Für die Werte comparison_direction und compare_type gilt Folgendes: Semantik:

Für boolesche und ganzzahlige Elementtypen:

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

Für Gleitkommaelementtypen mit compare_type = FLOAT wird durch die Operation implementiert folgende IEEE-754-Vorgänge:

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

Bei Gleitkomma-Elementtypen mit compare_type = TOTALORDER wird die Operation verwendet die Kombination aus totalOrder- und compareQuietEqual-Vorgängen aus IEEE-754.

Bei komplexen Elementtypen ist der lexikografische Vergleich von (real, imag)-Paaren wird mit den angegebenen comparison_direction und compare_type ausgeführt. Komplexe Zahlen müssen mit einer überraschenden Semantik, Daher planen wir, die Unterstützung für komplexe Zahlen in Zukunft einzustellen. wenn comparison_direction GE, GT, LE oder LT ist (#560)

Für quantisierte Typen. führt dequantize_compare(lhs, rhs, comparison_direction) aus.

Eingaben

Label Name Typ Einschränkungen
(I1) lhs Tensor oder quantisierter Tensor pro Tensor (C1–C3)
(I2) rhs Tensor oder quantisierter Tensor pro Tensor (C1–C2)
(I3) comparison_direction Aufzählung von EQ, NE, GE, GT, LE und LT
(I4) compare_type Aufzählung von FLOAT, TOTALORDER, SIGNED und UNSIGNED (C3)

Ausgaben

Name Typ Einschränkungen
result Tensor des booleschen Typs (C2)

Einschränkungen

  • (C1) baseline_element_type(lhs) = baseline_element_type(rhs).
  • (C2) shape(lhs) = shape(rhs) = shape(result).
  • (C3) compare_type ist definiert als: <ph type="x-smartling-placeholder">
      </ph>
    • SIGNED wenn is_signed_integer(element_type(lhs)).
    • UNSIGNED wenn is_unsigned_integer(element_type(lhs)) or is_boolean(element_type(lhs)).
    • FLOAT oder TOTALORDER, wenn is_float(element_type(lhs)).
    • FLOAT wenn is_complex(element_type(lhs)).

Beispiele

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

Weitere Beispiele

komplex

Semantik

Führt eine elementweise Konvertierung in einen komplexen Wert aus einem Paar aus reellen und lhs und rhs und erzeugt einen result-Tensor.

Eingaben

Label Name Typ Einschränkungen
(I1) lhs Tensor vom Typ f32 oder f64 (C1–C3)
(I2) rhs Tensor vom Typ f32 oder f64 (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des komplexen Typs (C2), (C3)

Einschränkungen

  • (C1) type(lhs) = type(rhs).
  • (C2) shape(result) = shape(lhs).
  • (C3) element_type(result) hat den Typ complex<E>, wobei E = element_type(lhs)

Beispiele

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

Weitere Beispiele

Zusammengesetzt

Semantik

Kapselt einen Vorgang ein, der aus anderen StableHLO-Vorgängen besteht, inputs und composite_attributes nehmen und dabei results produzieren. Die Die Semantik des Vorgangs wird durch das Attribut decomposition implementiert. Die composite-Op kann durch seine Zerlegung ersetzt werden, ohne das Programm zu ändern Semantik. In Fällen, in denen die Inline-Zerlegung nicht die gleichen Op-Semantik. Verwenden Sie am besten custom_call.

Mit dem Feld version (standardmäßig 0) wird angegeben, wann die eine Änderung der Semantik.

Eingaben

Label Name Typ
(I1) inputs variadische Anzahl von Werten
(I2) name Konstante vom Typ string
(I3) composite_attributes Attributwörterbuch
(I4) decomposition Konstante vom Typ string
(I5) version Konstante vom Typ si32

Ausgaben

Name Typ
results variadische Anzahl von Werten

Einschränkungen

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

Beispiele

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

Weitere Beispiele

concatenate

Semantik

Verkettet inputs entlang der Dimension dimension in derselben Reihenfolge wie bei und erzeugt einen result-Tensor. Formeller gesprochen result[i0, ..., id, ..., iR-1] = inputs[k][i0, ..., kd, ..., iR-1]. Dabei gilt:

  1. id = d0 + ... + dk-1 + kd.
  2. d ist gleich dimension und d0 sind die d. Dimensionsgrößen von inputs.

Eingaben

Label Name Typ Einschränkungen
(I1) inputs variadische Anzahl von Tensoren oder quantisierte Tensoren pro Tensor (C1–C6)
(I2) dimension Konstante vom Typ si64 (C2), (C4), (C6)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor pro Tensor (C5 bis C6)

Einschränkungen

  • (C1) same(element_type(inputs...)).
  • (C2) same(shape(inputs...)) mit Ausnahme von 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]) mit Ausnahme von: <ph type="x-smartling-placeholder">
      </ph>
    • dim(result, dimension) = dim(inputs[0], dimension) + ....

Beispiele

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

Weitere Beispiele

Konstante

Semantik

Erzeugt einen output-Tensor aus einer konstanten value.

Eingaben

Label Name Typ Einschränkungen
(I1) value Konstante (C1)

Ausgaben

Name Typ Einschränkungen
output Tensor oder quantisierter Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

eine Conversion ausführen

Semantik

Führt eine elementweise Konvertierung von einem Elementtyp in einen anderen durch operand-Tensor und erzeugt einen result-Tensor.

Für Conversions vom Typ boolean-to-any-supported-type ist der Wert false in Null und der Wert true in eins konvertiert. Für any-supported-type-to-boolean-Conversions wird der Wert Null in false und Werte ungleich null werden in true konvertiert. Unten sehen Sie, wie dies auch für komplexe Typen.

Für Konvertierungen mit integer-to-integer und integer-to-floating-point oder floating-point-to-floating-point, wenn der Quellwert genau im Zieltyp dargestellt, ist der Ergebniswert genau Darstellung. Ansonsten steht das Verhalten noch nicht fest. (#180)

Bei Konvertierungen mit floating-point-to-integer ist der Bruchteil abgeschnitten. Wenn der abgeschnittene Wert nicht im Zieltyp dargestellt werden kann, Das Verhalten steht noch nicht fest (#180).

Konvertierungen, die komplex zu komplex umfassen, folgen dem gleichen Verhalten wie floating-point-to-floating-point-Conversions, mit denen reale und imaginären Teilen.

Für Conversions vom Typ complex-to-any-other-type und complex-to-any-other-type der imaginäre Quellwert wird ignoriert oder der imaginäre Zielwert ist auf 0 gesetzt. Die Umrechnung des realen Teils folgt der Gleitkomma-Conversions.

Prinzipiell könnte diese Operation eine Dequantisierung (Konvertierung von quantisierte Tensoren in reguläre Tensoren), Quantisierung (Umwandlung von regulären Tensoren) Tensoren in quantisierte Tensoren) und Requantisierung (Umwandlung zwischen quantisierten Tensoren Tensoren), aber derzeit haben wir dafür dedizierte Operationen – uniform_dequantize für den ersten Anwendungsfall und uniform_quantize für den zweiten und dritten Anwendungsfälle. In Zukunft werden diese beiden Vorgänge möglicherweise zusammengeführt. in convert (#1576) ein.

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

Faltung

Semantik

Berechnet Punktprodukte zwischen Fenstern von lhs und Segmenten von rhs und erzeugt result Das folgende Diagramm zeigt, wie Elemente in result aus lhs und rhs anhand eines konkreten Beispiels.

Faltung

Formaler sollten Sie die folgende Neuformulierung der Eingaben in Bezug auf lhs betrachten: um Fenster von lhs ausdrücken zu können:

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

Für diese Neuausrichtung werden die folgenden Hilfsfunktionen verwendet:

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

Wenn feature_group_count = 1 und batch_group_count = 1, dann für alle output_spatial_index in index_space(dim(result, output_spatial_dimensions...)), result[result_shape(:, output_spatial_index, :)] = dot_product, wobei:

  • 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]) Diese Funktion wird offenbar noch nicht genutzt. Daher planen wir, sie in Zukunft zu entfernen. es (#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]).

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

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

Führt für quantisierte Typen 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)) aus.

Führt für hybrid quantisierte Typen 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) aus.

Eingaben

Label Name Typ Einschränkungen
(I1) lhs Tensor oder quantisierter Tensor pro Tensor (C1), (C10-C11), (C14) (C25), (C27-C28), (C31-C32), (C34)
(I2) rhs Tensor oder quantisierter Tensor (C1), (C14-C16), (C25), (C27-C29), (C31-C34)
(I3) window_strides Eindimensionale Tensorkonstante vom Typ si64 (C2–C3), (C25)
(I4) padding 2-dimensionale Tensorkonstante vom Typ si64 (C4), (C25)
(I5) lhs_dilation Eindimensionale Tensorkonstante vom Typ si64 (C5–C6), (C25)
(I6) rhs_dilation Eindimensionale Tensorkonstante vom Typ si64 (C7–C8), (C25)
(I7) window_reversal Eindimensionale Tensorkonstante vom Typ i1 (C9)
(I8) input_batch_dimension Konstante vom Typ si64 (C10), (C13), (C25)
(I9) input_feature_dimension Konstante vom Typ si64 (C11), (C13-C14)
(I10) input_spatial_dimensions Eindimensionale Tensorkonstante vom Typ si64 (C12), (C13), (C25)
(I11) kernel_input_feature_dimension Konstante vom Typ si64 (C14), (C18)
(I12) kernel_output_feature_dimension Konstante vom Typ si64 (C15-C16), (C18), (C25), (C29)
(I13) kernel_spatial_dimensions Eindimensionale Tensorkonstante vom Typ si64 (C17-C18), (C25)
(I14) output_batch_dimension Konstante vom Typ si64 (C20), (C25)
(I15) output_feature_dimension Konstante vom Typ si64 (C20), (C25), (C30)
(I16) output_spatial_dimensions Eindimensionale Tensorkonstante vom Typ si64 (C19–C20), (C25)
(I17) feature_group_count Konstante vom Typ si64 (C11), (C14), (C16), (C21), (C23)
(I18) batch_group_count Konstante vom Typ si64 (C10), (C15), (C22), (C23), (C25)
(I19) precision_config Variadische Anzahl von Enums von DEFAULT, HIGH und HIGHEST (C24)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor (C25-C28), (C30), (C32-34)

Einschränkungen

  • (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) Angegebener input_dimensions = [input_batch_dimension] + input_spatial_dimensions + [input_feature_dimension]: <ph type="x-smartling-placeholder">
      </ph>
    • 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) Angegebener kernel_dimensions = kernel_spatial_dimensions + [kernel_input_feature_dimension] + [kernel_output_feature_dimension]: <ph type="x-smartling-placeholder">
      </ph>
    • is_unique(kernel_dimensions).
    • 0 <= kernel_dimensions < N.
  • (C19) size(output_spatial_dimensions) = N - 2.
  • (C20) Angegebener output_dimensions = [output_batch_dimension] + output_spatial_dimensions + [output_feature_dimension]: <ph type="x-smartling-placeholder">
      </ph>
    • 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) ist definiert als: <ph type="x-smartling-placeholder">
      </ph>
    • dim(lhs, input_batch_dimension) / batch_group_count wenn result_dim = output_batch_dimension.
    • dim(rhs, kernel_output_feature_dimension) wenn result_dim = output_feature_dimension.
    • num_windows, andernfalls gilt:
    • 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.
  • Wenn die Operation nicht quantisierte Tensoren verwendet: <ph type="x-smartling-placeholder">
      </ph>
    • (C27) element_type(lhs) = element_type(rhs) = element_type(result).
  • Wenn die Operation quantisierte Tensoren verwendet: <ph type="x-smartling-placeholder">
      </ph>
    • (C28) is_quantized(lhs) = is_quantized(result) and is_quantized(rhs).
    • (C29) Wenn is_per_axis_quantized(rhs), danach quantization_dimension(rhs) = kernel_output_feature_dimension.
    • (C30) Wenn is_per_axis_quantized(result), dann quantization_dimension(result) = output_feature_dimension.
    • Wenn is_quantized(lhs):
    • (C31) storage_type(lhs) = storage_type(rhs).
    • (C32) expressed_type(lhs) = expressed_type(rhs) = expressed_type(result).
    • (C33) Wenn is_per_tensor_quantized(rhs), dann is_per_tensor_quantized(result).
    • Wenn !is_quantized(lhs):
    • (C34) element_type(lhs) = expressed_type(rhs) = element_type(result).

Beispiele

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

Weitere Beispiele

Kosinus

Semantik

Führt eine elementweise Kosinusoperation für den operand-Tensor durch und erzeugt einen result-Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für Gleitkommazahlen: cos aus IEEE-754.
  • Für komplexe Zahlen: komplexer Kosinus.
  • Für quantisierte Typen: dequantize_op_quantize(cosine, operand, type(result)).

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

count_leading_zeros

Semantik

Führt eine elementweise Zählung der Anzahl der führenden Null-Bits im operand durch und erzeugt einen result-Tensor.

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Ganzzahltyps (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Ganzzahltyps (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

custom_call

Semantik

Kapselt einen implementierungsdefinierten Vorgang call_target_name, der inputs und called_computations und produziert results. has_side_effect, backend_config und api_version können verwendet werden, um zusätzliche implementierungsdefinierten Metadaten.

Im Moment enthält dieser Vorgang eine ziemlich unorganisierte Sammlung von die die organische Entwicklung des entsprechenden Betriebs in den XLA-Compiler. Wir planen, diese Metadaten in Zukunft zu vereinheitlichen. (#741)

Eingaben

Label Name Typ
(I1) inputs variadische Anzahl von Werten
(I2) call_target_name Konstante vom Typ string
(I3) has_side_effect Konstante vom Typ i1
(I4) backend_config Konstante vom Typ string oder Attributwörterbuch
(I5) api_version Konstante vom Typ si32
(I6) called_computations variadische Anzahl von Konstanten vom Typ string

Ausgaben

Name Typ
results variadische Anzahl von Werten

Beispiele

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

Dividieren

Semantik

Führt die elementweise Division der Tensoren des Dividenden lhs und des Divisors rhs durch und erzeugt einen result-Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für Ganzzahlen: Ganzzahldivision, die den algebraischen Quotienten mit einer beliebigen Bruchteil verworfen.
  • Für Gleitkommazahlen: division aus IEEE-754.
  • Für komplexe Zahlen: komplexe Division.
  • Für quantisierte Typen: <ph type="x-smartling-placeholder">
      </ph>
    • dequantize_op_quantize(divide, lhs, rhs, type(result)).

Eingaben

Label Name Typ Einschränkungen
(I1) lhs Tensor von Ganzzahl, Gleitkomma oder komplexer Typ oder quantisierter Tensor pro Tensor (C1)
(I2) rhs Tensor von Ganzzahl, Gleitkomma oder komplexer Typ oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor von Ganzzahl, Gleitkomma oder komplexer Typ oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

dot_general

Semantik

Berechnet die Punktprodukte zwischen Segmenten von lhs und Segmenten von rhs und erzeugt einen result-Tensor.

Formeller result[result_index] = dot_product, wobei Folgendes gilt:

  • 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 wobei size(result_batching_index) = size(lhs_batching_dimensions), size(result_lhs_index) = size(lhs_result_dimensions) und 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))

Führt für quantisierte Typen 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)) aus.

Führt für hybrid quantisierte Typen 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) aus.

precision_config steuert den Kompromiss zwischen Geschwindigkeit und Genauigkeit auf Beschleuniger-Back-Ends. Dies kann einer der folgenden sein (im ist die Semantik dieser enum-Werte zu niedrig angegeben. wie Sie dieses Problem #755):

  • DEFAULT: Schnellste Berechnung, aber am wenigsten genaue Schätzung zum die ursprüngliche Nummer.
  • HIGH: langsamere Berechnung, aber genauere Annäherung an den Wert die ursprüngliche Nummer.
  • HIGHEST: Die langsamste Berechnung, aber die genaueste Annäherung an den Wert die ursprüngliche Nummer.

Ein DotAlgorithm definiert die Haupteigenschaften des Algorithmus, der zur Implementierung verwendet wird. die Punktoperation, die auch die Genauigkeit definiert. Wenn das Algorithmusattribut festgelegt sind, muss precision_config auf DEFAULT gesetzt sein. DotAlgorithms haben keinen Standardwert, da die Standardparameter definiert. Daher können alle Punktalgorithmusfelder auf None gesetzt werden, um ein Algorithmus mit leerem Punkt, der stattdessen den Wert precision_config verwendet.

DotAlgorithm-Felder enthalten:

  • lhs_precision_type und rhs_precision_type, die Genauigkeit, die die linke und die linke Seite und die Die RHS-Werte des Vorgangs werden auf gerundet. Genauigkeitstypen sind unabhängig vom die Speichertypen der Ein- und Ausgabe.
  • accumulation_type ist die für die Akkumulation verwendete Genauigkeit.
  • lhs_component_count, rhs_component_count und num_primitive_operations anwenden, wenn wir einen Algorithmus ausführen, der die linke und/oder rechte Seite in und führt mehrere "primitive" Punkt-Operationen auf diesen -Werte haben, um eine höhere Genauigkeit zu emulieren (z.B. Mit dem Datentyp bfloat16 „Artificial Intelligence“ für präzisere Berechnungen arbeiten: bf16_6x tf32_3x usw.). Bei Algorithmen ohne Zerlegung sind diese Werte sollte auf 1 festgelegt sein.
  • allow_imprecise_accumulation, um anzugeben, ob die Akkumulation mit geringerer Genauigkeit verwendet wird ist für einige Schritte zulässig (z.B. CUBLASLT_MATMUL_DESC_FAST_ACCUM).

Beispiele für DotAlgorithm-Attribute:

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

Es liegt an den Implementierungen, zu entscheiden, welche Kombinationen unterstützt werden. In kann nicht garantiert werden, dass jeder Algorithmus Beschleunigertyp durch den Nutzer des StableHLO. Wenn ein bestimmter Algorithmus sollte ein Fehler ausgegeben werden, anstatt auf einen als Alternative. Die StableHLO-Überprüfung ermöglicht eine bestmögliche Verifizierung, um Algorithmen zu verhindern, die bekanntermaßen auf keiner Hardware unterstützt werden.

Weitere Informationen finden Sie unter xla_data.proto > Algorithm. für einige unterstützte Algorithmuswerte. Ticket Nr. 2483 enthält den Plan zur Erstellung eines zentralisiertes Dokument zu unterstützten Algorithmen vom Back-End.

Eingaben

Label Name Typ Einschränkungen
(I1) lhs Tensor oder quantisierter Tensor pro Tensor (C5-C6), (C9-C10), (C12-C14), (C17-C18), (C20)
(I2) rhs Tensor oder quantisierter Tensor (C7-C10), (C12-C20)
(I3) lhs_batching_dimensions Eindimensionale Tensorkonstante vom Typ si64 (C1), (C3), (C5), (C9), (C12)
(I4) rhs_batching_dimensions Eindimensionale Tensorkonstante vom Typ si64 (C1), (C4), (C7), (C9)
(I5) lhs_contracting_dimensions Eindimensionale Tensorkonstante vom Typ si64 (C2), (C3), (C6), (C10)
(I6) rhs_contracting_dimensions Eindimensionale Tensorkonstante vom Typ si64 (C2), (C4), (C8), (C10), (C16)
(I7) precision_config Variadische Anzahl von Enums von DEFAULT, HIGH und HIGHEST (C11), (C21)
(I8) lhs_precision_type FloatType oder TensorFloat32 (C21)
(I9) rhs_precision_type FloatType oder TensorFloat32 (C21)
(I10) accumulation_type FloatType oder TensorFloat32 (C21)
(I11) lhs_component_count Konstante vom Typ si32 (C21), (C22)
(I12) rhs_component_count Konstante vom Typ si32 (C21), (C23)
(I13) num_primitive_operations Konstante vom Typ si32 (C21), (C24)
(I14) allow_imprecise_accumulation Konstante vom Typ bool (C21)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor (C12), (C14), (C18-C20)

Einschränkungen

  • (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).
  • Wenn die Operation nicht quantisierte Tensoren verwendet: <ph type="x-smartling-placeholder">
      </ph>
    • (C13) element_type(lhs) = element_type(rhs).
  • Wenn die Operation quantisierte Tensoren verwendet: <ph type="x-smartling-placeholder">
      </ph>
    • (C14) is_quantized(lhs) = is_quantized(result) and is_quantized(rhs).
    • (C15) zero_points(rhs) = 0.
    • (C16) Wenn is_per_axis_quantized(rhs), dann quantization_dimension(rhs) nicht in rhs_contracting_dimensions.
    • Wenn is_quantized(lhs):
    • (C17) storage_type(lhs) = storage_type(rhs).
    • (C18) expressed_type(lhs) = expressed_type(rhs) = expressed_type(result).
    • (C19) Wenn is_per_tensor_quantized(rhs), dann is_per_tensor_quantized(result).
    • Wenn !is_quantized(lhs):
    • (C20) element_type(lhs) = expressed_type(rhs) = element_type(result).
  • Wenn !is_empty_algorithm(lhs_precision_type, rhs_precision_type, accumulation_type, lhs_component_count, rhs_component_count, num_primitive_operations allow_imprecise_accumulation): <ph type="x-smartling-placeholder">
      </ph>
    • (C21) precision_config... = DEFAULT.
    • (C22) 0 < lhs_component_count.
    • (C23) 0 < rhs_component_count.
    • (C24) 0 < num_primitive_operations.

Beispiele

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

Weitere Beispiele

dynamic_broadcast_in_dim

Semantik

Funktional ist dieser Vorgang identisch mit broadcast_in_dim op, aber die Ergebnisform wird dynamisch über output_dimensions angegeben.

Für den Vorgang werden auch die optionalen Attribute known_expanding_dimensions und known_non_expanding_dimensions akzeptiert. um statisches Wissen über das Expansionsverhalten von Dimensionen auszudrücken. Wenn nicht angegeben, wird angenommen, dass alle Abmessungen möglicherweise maximiert werden.

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor oder quantisierter Tensor (C1-C2), (C5-C6), (C9)
(I2) output_dimensions Eindimensionaler Tensor vom Typ „Ganzzahl“ (C7)
(I3) broadcast_dimensions 1-dimensionaler Konstantentensor vom Ganzzahltyp (C2–C6)
(I4) known_expanding_dimensions 1-dimensionaler Konstantentensor vom Ganzzahltyp (C8–C9)
(I5) known_non_expanding_dimensions 1-dimensionaler Konstantentensor vom Ganzzahltyp (C8–C9)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor (C1), (C3), (C5-C7)

Einschränkungen

  • (C1) element_type(result) ist gegeben durch: <ph type="x-smartling-placeholder">
      </ph>
    • element_type(operand), wenn !is_per_axis_quantized(operand).
    • element_type(operand) mit Ausnahme von quantization_dimension(operand), scales(operand) und zero_points(operand) können abweichen von quantization_dimension(result), scales(result) und zero_points(result) oder „Sonstiges“.
  • (C2) size(broadcast_dimensions) = rank(operand).
  • (C3) 0 <= broadcast_dimensions < rank(result).
  • (C4) is_unique(broadcast_dimensions).
  • (C5) Für alle d in axes(operand): <ph type="x-smartling-placeholder">
      </ph>
    • dim(operand, d) = 1 oder
    • dim(operand, d) = dim(result, broadcast_dimensions[d]).
  • (C6) Wenn is_per_axis_quantized(result): <ph type="x-smartling-placeholder">
      </ph>
    • quantization_dimension(result) = broadcast_dimensions[quantization_dimension(operand)].
    • Wenn dim(operand, quantization_dimension(operand)) = 1, dann 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).

Beispiele

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

Weitere Beispiele

dynamic_conv

Semantik

Funktional ist dieser Vorgang identisch mit Faltung op, aber das Padding wird dynamisch über padding angegeben.

Eingaben

Label Name Typ Einschränkungen
(I1) lhs Tensor oder quantisierter Tensor pro Tensor (C1), (C10-C11), (C14) (C25), (C26-C27), (C30-C31), (C33)
(I2) rhs Tensor oder quantisierter Tensor (C1), (C14-C16), (C26-C28), (C30-C33)
(I3) padding 2-dimensionaler Tensor vom Ganzzahltyp (C4)
(I4) window_strides Eindimensionale Tensorkonstante vom Typ si64 (C2–C3)
(I5) lhs_dilation Eindimensionale Tensorkonstante vom Typ si64 (C5 bis C6)
(I6) rhs_dilation Eindimensionale Tensorkonstante vom Typ si64 (C7–C8)
(I7) window_reversal Eindimensionale Tensorkonstante vom Typ i1 (C9)
(I8) input_batch_dimension Konstante vom Typ si64 (C10), (C13)
(I9) input_feature_dimension Konstante vom Typ si64 (C11), (C13-C14)
(I10) input_spatial_dimensions Eindimensionale Tensorkonstante vom Typ si64 (C12), (C13)
(I11) kernel_input_feature_dimension Konstante vom Typ si64 (C14), (C18)
(I12) kernel_output_feature_dimension Konstante vom Typ si64 (C15-C16), (C18), (C28)
(I13) kernel_spatial_dimensions Eindimensionale Tensorkonstante vom Typ si64 (C17–C18)
(I14) output_batch_dimension Konstante vom Typ si64 (C20)
(I15) output_feature_dimension Konstante vom Typ si64 (C20), (C29)
(I16) output_spatial_dimensions Eindimensionale Tensorkonstante vom Typ si64 (C19–C20)
(I17) feature_group_count Konstante vom Typ si64 (C11), (C14), (C16), (C21), (C23)
(I18) batch_group_count Konstante vom Typ si64 (C10), (C15), (C22), (C23)
(I19) precision_config Variadische Anzahl von Enums von DEFAULT, HIGH und HIGHEST (C24)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor (C25-C27), (C29), (C31-C33)

Einschränkungen

  • (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) Angegebener input_dimensions = [input_batch_dimension] + input_spatial_dimensions + [input_feature_dimension]: <ph type="x-smartling-placeholder">
      </ph>
    • 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) Angegebener kernel_dimensions = kernel_spatial_dimensions + [kernel_input_feature_dimension] + [kernel_output_feature_dimension]: <ph type="x-smartling-placeholder">
      </ph>
    • is_unique(kernel_dimensions).
    • 0 <= kernel_dimensions < N.
  • (C19) size(output_spatial_dimensions) = N - 2.
  • (C20) Angegebener output_dimensions = [output_batch_dimension] + output_spatial_dimensions + [output_feature_dimension]: <ph type="x-smartling-placeholder">
      </ph>
    • 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) ist definiert als: <ph type="x-smartling-placeholder">
      </ph>
    • dim(lhs, input_batch_dimension) / batch_group_count wenn result_dim = output_batch_dimension.
    • dim(rhs, kernel_output_feature_dimension) wenn result_dim = output_feature_dimension.
    • num_windows, andernfalls gilt:
    • 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.
  • Wenn die Operation nicht quantisierte Tensoren verwendet: <ph type="x-smartling-placeholder">
      </ph>
    • (C27) element_type(lhs) = element_type(rhs) = element_type(result).
  • Wenn die Operation quantisierte Tensoren verwendet: <ph type="x-smartling-placeholder">
      </ph>
    • (C28) is_quantized(lhs) = is_quantized(result) and is_quantized(rhs).
    • (C29) Wenn is_per_axis_quantized(rhs), danach quantization_dimension(rhs) = kernel_output_feature_dimension.
    • (C30) Wenn is_per_axis_quantized(result), dann quantization_dimension(result) = output_feature_dimension.
    • Wenn is_quantized(lhs):
    • (C31) storage_type(lhs) = storage_type(rhs).
    • (C32) expressed_type(lhs) = expressed_type(rhs) = expressed_type(result).
    • (C33) Wenn is_per_tensor_quantized(rhs), dann is_per_tensor_quantized(result).
    • Wenn !is_quantized(lhs):
    • (C34) element_type(lhs) = expressed_type(rhs) = element_type(result).

Beispiele

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

Weitere Beispiele

dynamic_gather

Semantik

Funktional ist dieser Vorgang identisch mit sammeln Vorgang ausführen, wobei slice_sizes dynamisch als Wert angegeben wird.

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor oder quantisierter Tensor pro Tensor (C1), (C7), (C10-C12), (C14)
(I2) start_indices Tensor des Ganzzahltyps (C2), (C3), (C13)
(I3) slice_sizes Eindimensionaler Tensor vom Typ „Ganzzahl“ (C8), (C11–C13)
(I4) offset_dims Eindimensionale Tensorkonstante vom Typ si64 (C1), (C4-C5), (C13)
(I5) collapsed_slice_dims Eindimensionale Tensorkonstante vom Typ si64 (C1), (C6-C8), (C13)
(I6) start_index_map Eindimensionale Tensorkonstante vom Typ si64 (C3), (C9), (C10)
(I7) index_vector_dim Konstante vom Typ si64 (C2), (C3), (C13)
(I8) indices_are_sorted Konstante vom Typ i1

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor pro Tensor (C5), (C13-C14)

Einschränkungen

  • (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), wobei gilt: <ph type="x-smartling-placeholder">
      </ph>
    • batch_dim_sizes = shape(start_indices) mit dem Unterschied, dass die Dimensionsgröße von start_indices, die index_vector_dim entsprechen, sind nicht enthalten.
    • offset_dim_sizes = shape(slice_sizes) mit dem Unterschied, dass die Dimensionsgrößen in slice_sizes, die collapsed_slice_dims entsprechen, sind nicht enthalten.
    • combine platziert batch_dim_sizes auf den Achsen batch_dims und offset_dim_sizes an den Achsen, die offset_dims entsprechen.
  • (C14) element_type(operand) = element_type(result).

Beispiele

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

Weitere Beispiele

dynamic_iota

Semantik

Funktional ist dieser Vorgang identisch mit IoTa op, aber die Ergebnisform wird dynamisch über output_shape angegeben.

Eingaben

Label Name Typ Einschränkungen
(I1) output_shape Eindimensionaler Tensor vom Typ „Ganzzahl“ (C1), (C2)
(I2) iota_dimension si64 (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor von Ganzzahl, Gleitkomma oder komplexer Typ oder quantisierter Tensor pro Tensor (C2)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

dynamic_pad

Semantik

Funktional ist dieser Vorgang identisch mit Pad op, aber mit edge_padding_low, edge_padding_high und interior_padding dynamisch als Werte angegeben werden.

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor oder quantisierter Tensor pro Tensor (C1), (C2), (C4)
(I2) padding_value 0-dimensionaler Tensor oder quantisierter Tensor pro Tensor (C1)
(I3) edge_padding_low Eindimensionaler Tensor vom Typ „Ganzzahl“ (C1), (C4)
(I4) edge_padding_high Eindimensionaler Tensor vom Typ „Ganzzahl“ (C1), (C4)
(I5) interior_padding Eindimensionaler Tensor vom Typ „Ganzzahl“ (C2–C4)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor pro Tensor (C3 bis C6)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

dynamic_reshape

Semantik

Funktional ist dieser Vorgang identisch mit umformen op, aber die Ergebnisform wird dynamisch über output_shape angegeben.

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor oder quantisierter Tensor (C1–C3)
(I2) output_shape Eindimensionaler Tensor vom Typ „Ganzzahl“ (C4)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor (C1–C4)

Einschränkungen

  • (C1) element_type(result) ist gegeben durch: <ph type="x-smartling-placeholder">
      </ph>
    • element_type(operand), wenn !is_per_axis_quantized(operand).
    • element_type(operand) mit dem Unterschied, dass quantization_dimension(operand) und Andernfalls kann quantization_dimension(result) abweichen.
  • (C2) size(operand) = size(result).
  • (C3) Wenn is_per_axis_quantized(operand): <ph type="x-smartling-placeholder">
      </ph>
    • 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).

Beispiele

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

Weitere Beispiele

dynamic_slice

Semantik

Extrahiert ein Segment aus dem operand mit dynamisch berechneten Startindexen und erzeugt einen result-Tensor. start_indices enthalten die Startindizes von das Segment für jede Dimension vorbehaltlich möglicher Anpassungen und slice_sizes die Größen des Segments für jede Dimension enthalten. Formeller gesprochen result[result_index] = operand[operand_index], wobei gilt:

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

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor oder quantisierter Tensor pro Tensor (C1), (C2), (C4)
(I2) start_indices Variadische Anzahl von 0-dimensionalen Tensoren vom Typ „Ganzzahl“ (C2), (C3)
(I3) slice_sizes Eindimensionale Tensorkonstante vom Typ si64 (C2), (C4), (C5)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor pro Tensor (C1), (C5)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

dynamic_update_slice

Semantik

Erzeugt einen result-Tensor, der dem operand-Tensor entspricht, mit der Ausnahme, Das Segment, das bei start_indices beginnt, wird mit den Werten in update aktualisiert. Formal ist result[result_index] so definiert:

  • update[update_index], wenn 0 <= update_index < shape(update), wobei gilt: <ph type="x-smartling-placeholder">
      </ph>
    • adjusted_start_indices = clamp(0, start_indices, shape(operand) - shape(update)).
    • update_index = result_index - adjusted_start_indices.
  • Andernfalls operand[result_index].

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor oder quantisierter Tensor pro Tensor (C1–C4), (C6)
(I2) update Tensor oder quantisierter Tensor pro Tensor (C2), (C3), (C6)
(I3) start_indices Variadische Anzahl von 0-dimensionalen Tensoren vom Typ „Ganzzahl“ (C4), (C5)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

Exponentialfunktionen

Semantik

Führt eine elementweise exponentielle Operation für den operand-Tensor durch und erzeugt einen result-Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für Gleitkommazahlen: exp aus IEEE-754.
  • Für komplexe Zahlen: komplexe Exponentialfunktionen.
  • Für quantisierte Typen: dequantize_op_quantize(exponential, operand, type(result))

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

exponential_minus_one

Semantik

Führt eine elementweise exponentielle abzüglich einer Operation mit dem Tensor operand durch und erzeugt einen result-Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für Gleitkommazahlen: expm1 aus IEEE-754.
  • Für komplexe Zahlen: komplexe Exponentialzahlen minus eins.
  • Für quantisierte Typen: dequantize_op_quantize(exponential_minus_one, operand, type(result))

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

fft

Semantik

Führt die Vorwärts- und Inversen Fourier-Transformationen für reelle und komplexe Ein- und Ausgaben.

fft_type ist einer der folgenden Werte:

  • FFT: Forward-Komplex-zu-Komplex-FFT.
  • IFFT: Umgekehrte komplexe-zu-komplexe FFT.
  • RFFT: Echtzeit-FFT (Real-to-Complexed FFT)
  • IRFFT: Inverse Real-to-Complex-FFT (d.h., nimmt komplex an und gibt reell zurück).

Formaler ist die Funktion fft, die eindimensionale Tensoren von als Eingabe nutzt, werden 1-dimensionale Tensoren derselben Typen wie Ausgabe und berechnet die diskrete Fourier-Transformation:

Für fft_type = FFT ist result als Endergebnis einer Reihe von L Berechnungen, bei denen L = size(fft_length). Zum Beispiel für 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]).

Außerdem hat die Funktion ifft dieselbe Typsignatur und berechnet den Kehrwert von fft:

Für fft_type = IFFT ist result als Kehrwert der Berechnungen definiert. für fft_type = FFT. Zum Beispiel für 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, ..., :]).

Darüber hinaus werden bei der Funktion rfft, die eindimensionale Tensoren Gleitkommatypen werden, erzeugt 1-dimensionale Tensoren von komplexen Typen des Gleitkomma-Semantik und funktioniert so:

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

(Bei der Berechnung der diskreten Fourier-Transformation für reelle Operanden wird die erste N/2 + 1-Elemente des Ergebnisses definieren den Rest des Ergebnisses eindeutig, sodass das Ergebnis von rfft abgeschnitten wird, um die Berechnung redundanter Elemente zu vermeiden.

Für fft_type = RFFT ist result als Endergebnis einer Reihe von L Berechnungen, bei denen L = size(fft_length). Zum Beispiel für 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]).

Bei der Funktion irfft, die dieselbe Typsignatur und berechnet den Kehrwert von rfft:

Für fft_type = IRFFT ist result als Kehrwert der Berechnungen definiert. für fft_type = RFFT. Zum Beispiel für 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, ..., :]).

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkomma- oder komplexen Typs (C1), (C2), (C4), (C5)
(I2) fft_type Aufzählung von FFT, IFFT, RFFT und IRFFT (C2), (C5)
(I3) fft_length Eindimensionale Tensorkonstante vom Typ si64 (C1), (C3), (C4)

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkomma- oder komplexen Typs (C2), (C4), (C5)

Einschränkungen

  • (C1) size(fft_length) <= rank(operand).
  • (C2) Die Beziehung zwischen den Elementtypen operand und result variiert: <ph type="x-smartling-placeholder">
      </ph>
    • Wenn fft_type = FFT, element_type(operand) und element_type(result) denselben komplexen Typ haben.
    • Wenn fft_type = IFFT, element_type(operand) und element_type(result) denselben komplexen Typ haben.
    • Wenn fft_type = RFFT, ist element_type(operand) ein Gleitkommatyp und element_type(result) ist ein komplexer Typ desselben Gleitkommawerts Semantik.
    • Wenn fft_type = IRFFT, ist element_type(operand) ein komplexer Typ und element_type(result) ist ein Gleitkommatyp desselben Gleitkommawerts Semantik.
  • (C3) 1 <= size(fft_length) <= 3.
  • (C4) Wenn es zwischen operand und result gibt, gibt es den Tensor real eines Gleitkommatyp, dann shape(real)[-size(fft_length):] = fft_length.
  • (C5) shape(result) = shape(operand) mit Ausnahme von: <ph type="x-smartling-placeholder">
      </ph>
    • Wenn fft_type = RFFT, dim(result, -1) = dim(operand, -1) = 0 ? 0 : dim(operand, -1) / 2 + 1.
    • Wenn fft_type = IRFFT, dim(operand, -1) = dim(result, -1) = 0 ? 0 : dim(result, -1) / 2 + 1.

Beispiele

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

Boden

Semantik

Führt die elementweisen Untergrenze des operand-Tensors durch und erzeugt einen result-Tensor. Implementiert den roundToIntegralTowardNegative-Vorgang aus IEEE-754 Spezifikation zu ändern. Führt für quantisierte Typen durch dequantize_op_quantize(floor, operand, type(result))

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkommatyps oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkommatyps oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

sammeln

Semantik

Erfasst Segmente vom Tensor operand aus den in start_indices angegebenen Offsets und erzeugt einen result-Tensor.

Das folgende Diagramm zeigt, wie Elemente in result den Elementen in operand anhand eines konkreten Beispiels. Im Diagramm finden Sie einige Beispiele result -Indizes und erläutert detailliert, welchen operand-Indizes sie entsprechen.

sammeln

Formeller result[result_index] = operand[operand_index], wobei Folgendes gilt:

  • batch_dims = [d for d in axes(result) and d not in offset_dims].
  • batch_index = result_index[batch_dims...].
  • start_index ist definiert als: <ph type="x-smartling-placeholder">
      </ph>
    • start_indices[bi0, ..., :, ..., biN], wobei bi einzelne Elemente in batch_index und : werden beim Index index_vector_dim eingefügt, wenn index_vector_dim < rank(start_indices)
    • Andernfalls [start_indices[batch_index]].
  • Für d_operand in axes(operand), <ph type="x-smartling-placeholder">
      </ph>
    • full_start_index[d_operand] = clamp(start_index[d_start], 0, dim(operand, d_operand) - slice_sizes[d_operand]) wenn d_operand = start_index_map[d_start].
    • Andernfalls full_start_index[d_operand] = 0.
  • Für d_operand in axes(operand), <ph type="x-smartling-placeholder">
      </ph>
    • full_batching_index[d_operand] = batch_index[d_start - (d_start < index_vector_dim ? 0 : 1)] wenn d_operand = operand_batching_dims[i_batching] und d_start = start_indices_batching_dims[i_batching]
    • Andernfalls full_batching_index[d_operand] = 0.
  • offset_index = result_index[offset_dims...].
  • full_offset_index = [oi0, ..., 0, ..., oiN], bei denen oi individuell sind Elemente in offset_index und 0 wird an Indexen von collapsed_slice_dims und operand_batching_dims.
  • operand_index = full_start_index + full_batching_index + full_offset_index

Wenn indices_are_sorted den Wert true hat, kann die Implementierung davon ausgehen, dass start_indices werden nach start_index_map sortiert. Andernfalls Verhalten ist nicht definiert. Formeller für alle i1 < i2 aus indices(result), full_start_index(i1) <= full_start_index(i2)

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor oder quantisierter Tensor pro Tensor (C1), (C8), (C11), (C17), (C19-C21), (C23)
(I2) start_indices Tensor des Ganzzahltyps (C2-C3), (C14), (C17), (C22)
(I3) offset_dims Eindimensionale Tensorkonstante vom Typ si64 (C1), (C4-C5), (C22)
(I4) collapsed_slice_dims Eindimensionale Tensorkonstante vom Typ si64 (C1), (C6-C9), (C22)
(I5) operand_batching_dims Eindimensionale Tensorkonstante vom Typ si64 (C1), (C6), (C10-C12), (C16-C18), (C22)
(I6) start_indices_batching_dims Eindimensionale Tensorkonstante vom Typ si64 (C13–C17)
(I7) start_index_map Eindimensionale Tensorkonstante vom Typ si64 (C3), (C18–C19)
(I8) index_vector_dim Konstante vom Typ si64 (C2-C3), (C15), (C22)
(I9) slice_sizes Eindimensionale Tensorkonstante vom Typ si64 (C9), (C12), (C20-C22)
(I10) indices_are_sorted Konstante vom Typ i1

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor pro Tensor (C5), (C22-C23)

Einschränkungen

  • (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), wobei Folgendes gilt: <ph type="x-smartling-placeholder">
      </ph>
    • batch_dim_sizes = shape(start_indices) mit dem Unterschied, dass die Dimensionsgröße von start_indices, die index_vector_dim entsprechen, sind nicht enthalten.
    • offset_dim_sizes = slice_sizes, mit dem Unterschied, dass die Dimensionsgrößen in slice_sizes entspricht collapsed_slice_dims und operand_batching_dims sind nicht enthalten.
    • combine platziert batch_dim_sizes auf den Achsen batch_dims und offset_dim_sizes an den Achsen, die offset_dims entsprechen.
  • (C23) element_type(operand) = element_type(result).

Beispiele

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

Weitere Beispiele

get_dimension_size

Semantik

Erzeugt die Größe des angegebenen dimension von operand. Formeller gesprochen result = dim(operand, dimension) Die Semantik betrifft nur die Form. -Komponente des Typs. Der Elementtyp kann beliebig sein.

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor oder quantisierter Tensor (C1)
(I2) dimension Konstante vom Typ si64 (C1)

Ausgaben

Name Typ
result 0-dimensionaler Tensor vom Typ si32

Einschränkungen

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

Beispiele

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

Weitere Beispiele

get_tuple_element

<ph type="x-smartling-placeholder">
</ph>

Semantik

Extrahiert ein Element an der index-Position des operand-Tupels und erzeugt einen result Formeller: result = operand[index].

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tupel (C1), (C2)
(I2) index Konstante vom Typ si32 (C1), (C2)

Ausgaben

Name Typ Einschränkungen
result Beliebiger unterstützter Typ (C2)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

wenn

Semantik

Erzeugt die Ausgabe, wenn genau eine Funktion aus true_branch ausgeführt wird oder false_branch abhängig vom Wert von pred. Formeller: result = pred ? true_branch() : false_branch().

Eingaben

Label Name Typ Einschränkungen
(I1) pred 0-dimensionaler Tensor vom Typ i1
(I2) true_branch Funktion (C1–C3)
(I3) false_branch Funktion (C1), (C2)

Ausgaben

Name Typ Einschränkungen
results variadische Anzahl von Tensoren, quantisierte Tensoren oder Tokens (C3)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

Bild

Semantik

Extrahiert den imaginären Teil elementweise aus dem operand und erzeugt ein result-Tensor. Formeller gesprochener Text für jedes Element x: imag(x) = is_complex(x) ? imaginary_part(x) : constant(0, element_type(result)).

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkomma- oder komplexen Typs (C1), (C2)

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkommatyps (C1), (C2)

Einschränkungen

  • (C1) shape(result) = shape(operand).
  • (C2) element_type(result) ist definiert als: <ph type="x-smartling-placeholder">
      </ph>
    • complex_element_type(element_type(operand)) wenn is_complex(operand).
    • Andernfalls element_type(operand).

Beispiele

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

Weitere Beispiele

In-Feed

Semantik

Liest Daten aus dem In-Feed und erstellt results.

Die Semantik von infeed_config ist implementierungsdefiniert.

results bestehen aus Nutzlastwerten, die an erster Stelle stehen, und einem Token, das zuletzt. In Zukunft planen wir, die Nutzlast und das Token in zwei Teile aufzuteilen. separate Ausgaben, um die Verständlichkeit zu verbessern (#670)

Eingaben

Label Name Typ
(I1) token token
(I2) infeed_config Konstante vom Typ string

Ausgaben

Name Typ Einschränkungen
results variadische Anzahl von Tensoren, quantisierte Tensoren oder Tokens (C1–C3)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

ITA

Semantik

Füllt einen output-Tensor mit Werten in aufsteigender Reihenfolge, beginnend bei null entlang der Dimension iota_dimension. Formeller gesprochen

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

Eingaben

Label Name Typ Einschränkungen
(I1) iota_dimension si64 (C1)

Ausgaben

Name Typ Einschränkungen
output Tensor von Ganzzahl, Gleitkomma oder komplexer Typ oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

is_finite

Semantik

Führt eine elementweise Prüfung durch, ob der Wert in x endlich ist (d.h. weder +Inf, -Inf oder NaN) und erzeugt einen y-Tensor. Implementiert die isFinite aus der IEEE-754-Spezifikation. Für quantisierte Typen lautet das Ergebnis: immer true.

Eingaben

Label Name Typ Einschränkungen
(I1) x Tensor des Gleitkommatyps oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
y Tensor des booleschen Typs (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

log

Semantik

Führt eine elementweise Logarithmus-Operation für den operand-Tensor durch und erzeugt einen result-Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für Gleitkommazahlen: log aus IEEE-754.
  • Für komplexe Zahlen: komplexer Logarithmus.
  • Für quantisierte Typen: dequantize_op_quantize(log, operand, type(result)).

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

log_plus_one

Semantik

Führt einen elementweisen Logarithmus plus eine Operation für den operand-Tensor durch und erzeugt einen result-Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für Gleitkommazahlen: logp1 aus IEEE-754.
  • Für komplexe Zahlen: komplexer Logarithmus plus eins.
  • Für quantisierte Typen: dequantize_op_quantize(log_plus_one, operand, type(result))

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

Logistik

Semantik

Führt eine elementweise logistische Operation am Tensor operand durch und erzeugt eine result-Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für Gleitkommazahlen: division(1, addition(1, exp(-x))) aus IEEE-754.
  • Für komplexe Zahlen: komplexe logistische Zahlen
  • Für quantisierte Typen: dequantize_op_quantize(logistic, operand, type(result))

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

Karte

<ph type="x-smartling-placeholder">
</ph>

Semantik

Wendet eine Kartenfunktion computation auf inputs entlang der dimensions und erzeugt einen result-Tensor.

Formeller: result[result_index] = computation(inputs...[result_index]).

Eingaben

Label Name Typ Einschränkungen
(I1) inputs variadische Anzahl von Tensoren oder quantisierte Tensoren pro Tensor (C1–C4)
(I2) dimensions Eindimensionale Tensorkonstante vom Typ si64 (C3)
(I3) computation Funktion (C4)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor pro Tensor (C1), (C4)

Einschränkungen

  • (C1) shape(inputs...) = shape(result).
  • (C2) 0 < size(inputs) = N.
  • (C3) dimensions = range(rank(inputs[0])).
  • (C4) computation hat den Typ (tensor<E0>, ..., tensor<EN-1>) -> tensor<E'> Dabei gilt: Ei = element_type(inputs[i]) und E' = element_type(result).

Beispiele

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

Weitere Beispiele

Maximum

Semantik

Führt eine elementweise max-Operation für die Tensoren lhs und rhs durch und erzeugt eine result-Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für boolesche Werte: logisches ODER.
  • Für Ganzzahlen: Ganzzahlhöchstwert.
  • Für Gleitkommazahlen: maximum aus IEEE-754.
  • Für komplexe Zahlen: lexikografisches Maximum für das (real, imaginary)-Paar. Komplexe Zahlen müssen mit einer überraschenden Semantik, Daher planen wir, die Unterstützung für komplexe Zahlen in Zukunft einzustellen. für diesen Vorgang (#560).
  • Für quantisierte Typen: <ph type="x-smartling-placeholder">
      </ph>
    • dequantize_op_quantize(maximum, lhs, rhs, type(result)).

Eingaben

Label Name Typ Einschränkungen
(I1) lhs Tensor oder quantisierter Tensor pro Tensor (C1)
(I2) rhs Tensor oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

Minimum

Semantik

Führt eine elementweise Min-Operation für die Tensoren lhs und rhs aus und erzeugt eine result-Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für boolesche Werte: logisches UND.
  • Für Ganzzahlen: minimale Ganzzahl.
  • Für Gleitkommazahlen: minimum aus IEEE-754.
  • Für komplexe Zahlen: lexikografisches Minimum für das (real, imaginary)-Paar. Komplexe Zahlen müssen mit einer überraschenden Semantik, Daher planen wir, die Unterstützung für komplexe Zahlen in Zukunft einzustellen. für diesen Vorgang (#560).
  • Für quantisierte Typen: <ph type="x-smartling-placeholder">
      </ph>
    • dequantize_op_quantize(minimum, lhs, rhs, type(result)).

Eingaben

Label Name Typ Einschränkungen
(I1) lhs Tensor oder quantisierter Tensor pro Tensor (C1)
(I2) rhs Tensor oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

multiplizieren

Semantik

Führt das elementweise Produkt der zwei Tensoren lhs und rhs durch und erzeugt einen result-Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für boolesche Werte: logisches UND.
  • Für Ganzzahlen: Ganzzahlmultiplikation.
  • Für Gleitkommazahlen: multiplication aus IEEE-754.
  • Für komplexe Zahlen: komplexe Multiplikation
  • Für quantisierte Typen: <ph type="x-smartling-placeholder">
      </ph>
    • dequantize_op_quantize(multiply, lhs, rhs, type(result)).

Eingaben

Label Name Typ Einschränkungen
(I1) lhs Tensor oder quantisierter Tensor pro Tensor (C1)
(I2) rhs Tensor oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

negate

Semantik

Führt eine elementweise Negation des operand-Tensors durch und erzeugt einen result-Wert Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für vorzeichenbehaftete Ganzzahlen: Ganzzahl-Negation.
  • Für vorzeichenlose Ganzzahlen: Bitcast in eine vorzeichenbehaftete Ganzzahl, Ganzzahlnegation, Bitcast zurück zur vorzeichenlosen Ganzzahl.
  • Für Gleitkommazahlen: negate aus IEEE-754.
  • Für komplexe Zahlen: komplexe Negation.
  • Für quantisierte Typen: dequantize_op_quantize(negate, operand, type(result))

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor von Ganzzahl, Gleitkomma oder komplexer Typ oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor von Ganzzahl, Gleitkomma oder komplexer Typ oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

nicht

Semantik

Führt das elementweise NOT des Tensors operand durch und erzeugt einen result-Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für boolesche Werte: logisches NOT.
  • Für Ganzzahlen: bitweises NOT.

Argumente

Name Typ Einschränkungen
operand Tensor des booleschen oder Ganzzahltyps (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des booleschen oder Ganzzahltyps (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

optimization_barrier

Semantik

Sorgt dafür, dass die Vorgänge, die den operand erzeugen, vor jedem ausgeführt werden Vorgänge, die von result abhängig sind und Compilertransformationen verhindern die Hürde zu überwinden. Ansonsten ist der Vorgang eine Identität, z.B. result = operand.

Argumente

Name Typ Einschränkungen
operand variadische Anzahl von Tensoren, quantisierte Tensoren oder Tokens pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result variadische Anzahl von Tensoren, quantisierte Tensoren oder Tokens pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

oder

Semantik

Führt das elementweise ODER der zwei Tensoren lhs und rhs durch und erzeugt eine result Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für boolesche Werte: logisches ODER.
  • Für Ganzzahlen: bitweises ODER.

Eingaben

Label Name Typ Einschränkungen
(I1) lhs Tensor des Ganzzahl- oder booleschen Typs (C1)
(I2) rhs Tensor des Ganzzahl- oder booleschen Typs (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Ganzzahl- oder booleschen Typs (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

Outfeed

Semantik

Schreibt inputs in die Ausgabe und generiert ein result-Token.

Die Semantik von outfeed_config ist implementierungsdefiniert.

Eingaben

Label Name Typ
(I1) inputs variadische Anzahl von Tensoren oder quantisierten Tensoren
(I2) token token
(I3) outfeed_config Konstante vom Typ string

Ausgaben

Name Typ
result token

Beispiele

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

Weitere Beispiele

Pad

Semantik

Erweitert operand durch ein Padding um den Tensor und zwischen den Elementen des Tensors mit dem angegebenen padding_value.

edge_padding_low und edge_padding_high geben an, wie viel Abstand hinzugefügt wurde. am unteren Rand (neben Index 0) und dem High-End-Wert (neben dem höchsten Index) von für jede Dimension auswählen. Der Abstand kann negativ sein, wobei der Der absolute Wert des negativen Paddings gibt die Anzahl der zu entfernenden Elemente an. aus der angegebenen Dimension auswählen.

interior_padding gibt den Abstand zwischen zwei beliebigen Elementen an. -Elemente in jeder Dimension, die nicht negativ sein darf. Innenabstände treten auf vor dem Randabstand, sodass durch den negativen Rand Elemente entfernt werden, den mit Innenrand versehenen Operanden.

Formal ist result[result_index] so definiert:

  • operand[operand_index] wenn result_index = edge_padding_low + operand_index * (interior_padding + 1).
  • Andernfalls padding_value.

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor oder quantisierter Tensor pro Tensor (C1), (C2), (C4)
(I2) padding_value 0-dimensionaler Tensor oder quantisierter Tensor pro Tensor (C1)
(I3) edge_padding_low Eindimensionale Tensorkonstante vom Typ si64 (C1), (C4)
(I4) edge_padding_high Eindimensionale Tensorkonstante vom Typ si64 (C1), (C4)
(I5) interior_padding Eindimensionale Tensorkonstante vom Typ si64 (C2–C4)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor pro Tensor (C3 bis C6)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

partition_id

Semantik

Erzeugt partition_id des aktuellen Prozesses.

Ausgaben

Name Typ
result 0-dimensionaler Tensor vom Typ ui32

Beispiele

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

Weitere Beispiele

Popcnt

Semantik

Führt die elementweise Zählung der Anzahl von Bits durch, die im operand-Tensor festgelegt ist. und erzeugt einen result-Tensor.

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Ganzzahltyps (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Ganzzahltyps (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

Leistung

Semantik

Führt eine elementweise Exponentierung des lhs-Tensors mit dem rhs-Tensor durch und erzeugt einen result-Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für Ganzzahlen: Ganzzahlexponentie
  • Für Gleitkommazahlen: pow aus IEEE-754.
  • Für komplexe Zahlen: komplexe Exponentie
  • Für quantisierte Typen: dequantize_op_quantize(power, lhs, rhs, type(result)).

Eingaben

Label Name Typ Einschränkungen
(I1) lhs Tensor von Ganzzahl, Gleitkomma oder komplexer Typ oder quantisierter Tensor pro Tensor (C1)
(I2) rhs Tensor von Ganzzahl, Gleitkomma oder komplexer Typ oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor von Ganzzahl, Gleitkomma oder komplexer Typ oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

real

Semantik

Extrahiert den realen Teil elementweise aus dem operand und erzeugt ein result Tensor. Formeller gesprochener Text für jedes Element x: real(x) = is_complex(x) ? real_part(x) : x.

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkomma- oder komplexen Typs (C1), (C2)

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkommatyps (C1), (C2)

Einschränkungen

  • (C1) shape(result) = shape(operand).
  • (C2) element_type(result) ist definiert als: <ph type="x-smartling-placeholder">
      </ph>
    • complex_element_type(element_type(operand)) wenn is_complex(operand).
    • Andernfalls element_type(operand).

Beispiele

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

Weitere Beispiele

Recv

Semantik

Empfängt Daten von einem Kanal mit channel_id und erstellt results.

Wenn is_host_transfer den Wert true hat, überträgt der Vorgang Daten aus der Host. Andernfalls werden Daten von einem anderen Gerät übertragen. Das bedeutet, Implementierung definiert. Dieses Flag dupliziert die in channel_type, daher planen wir, in Zukunft nur eine davon zu behalten (#666)

results bestehen aus Nutzlastwerten, die an erster Stelle stehen, und einem Token, das zuletzt. Wir planen, Nutzlast und Token in Zukunft in zwei Teile aufzuteilen. separate Ausgaben, um die Verständlichkeit zu verbessern (#670)

Eingaben

Label Name Typ Einschränkungen
(I1) token token (C4)
(I2) channel_id Konstante vom Typ si64
(I3) channel_type Aufzählung von DEVICE_TO_DEVICE und HOST_TO_DEVICE (C1)
(I4) is_host_transfer Konstante vom Typ i1 (C1)

Ausgaben

Name Typ Einschränkungen
results variadische Anzahl von Tensoren, quantisierte Tensoren oder Tokens (C2–C4)

Einschränkungen

  • (C1) channel_type ist definiert als: <ph type="x-smartling-placeholder">
      </ph>
    • HOST_TO_DEVICE, wenn is_host_transfer = true,
    • Andernfalls DEVICE_TO_DEVICE.
  • (C2) 0 < size(results).
  • (C3) is_empty(result[:-1]) oder is_tensor(type(results[:-1])).
  • (C4) is_token(type(results[-1])).

Beispiele

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

Weitere Beispiele

reduce

Semantik

Wendet eine Reduktionsfunktion body auf inputs und init_values entlang der dimensions und erzeugt results-Tensoren.

Die Reihenfolge der Reduzierungen ist implementierungsdefiniert, was bedeutet, dass body und init_values muss eine Monoid bilden, um zu gewährleisten, dass die Operation für alle Eingaben in allen Implementierungen dieselben Ergebnisse. Diese Bedingung nicht für viele beliebte Preissenkungen gilt. Beispiel: Gleitkommazahl für body und Null für init_values bilden eigentlich keine Monoide, Das Hinzufügen von Gleitkommazahlen ist nicht assoziativ.

Formeller results...[j0, ..., jR-1] = reduce(input_slices_converted), wobei Folgendes gilt:

  • input_slices = inputs...[j0, ..., :, ..., jR-1], wobei : eingefügt wird um dimensions.
  • input_slices_converted = to_destination_type(input_slices..., type(func_inputs(body)[:len(func_inputs(body))//2])...).
  • init_values_converted = to_destination_type(init_values..., type(func_inputs(body)[len(func_inputs(body))//2:])...).
  • reduce(input_slices_converted) = exec(schedule) für einen binären Baum schedule, wobei gilt: <ph type="x-smartling-placeholder">
      </ph>
    • exec(node) = body(exec(node.left), exec(node.right)).
    • exec(leaf) = leaf.value.
  • schedule ist eine implementierungsdefinierte vollständige binäre Baumstruktur, deren besteht aus: <ph type="x-smartling-placeholder">
      </ph>
    • input_slices_converted...[index] Werte für alle index in index_space(input_slices_converted) in aufsteigender lexikografischer Reihenfolge von index.
    • Dazwischen ist eine von der Implementierung definierte Menge von init_values_converted an den von der Implementierung definierten Positionen.

Eingaben

Label Name Typ Einschränkungen
(I1) inputs variadische Anzahl von Tensoren oder quantisierte Tensoren pro Tensor (C1–C4), (C6), (C7)
(I2) init_values variadische Anzahl von 0-dimensionalen Tensoren oder quantisierten Tensoren pro Tensor (C2), (C3)
(I3) dimensions Eindimensionale Tensorkonstante vom Typ si64 (C4), (C5), (C7)
(I4) body Funktion (C6)

Ausgaben

Name Typ Einschränkungen
results variadische Anzahl von Tensoren oder quantisierte Tensoren pro Tensor (C3), (C7), (C8)

Einschränkungen

  • (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 hat den Typ (tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ..., tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>), wobei is_promotable(element_type(inputs[i]), Ei).
  • (C7) shape(results...) = shape(inputs...) mit dem Unterschied, dass die Dimension Größen von inputs..., die dimensions entsprechen, sind nicht enthalten.
  • (C8) element_type(results[i]) = Ei für alle i in [0,N).

Beispiele

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

Weitere Beispiele

reduce_precision

Semantik

Führt eine elementweise Konvertierung von operand in einen anderen Gleitkommatyp durch mit exponent_bits und mantissa_bits und umgekehrt Gleitkommatyp und erzeugt einen output-Tensor.

Formeller:

  • Die Mantissenbits des ursprünglichen Werts werden aktualisiert, um das Original zu runden. Wert auf den nächsten mit mantissa_bits darstellbaren Wert unter Verwendung von roundToIntegralTiesToEven-Semantik.
  • Wenn mantissa_bits kleiner ist als die Anzahl der Mantissenbits von Originalwert, werden die Mantissenbits auf mantissa_bits gekürzt.
  • Wenn dann die Exponentenbits des Zwischenergebnisses nicht in die Bereich bereitgestellt von exponent_bits, läuft das Zwischenergebnis zu unendlich mit dem ursprünglichen Vorzeichen oder Unterflüsse auf Null mithilfe der Originalzeichen
  • Führt für quantisierte Typen dequantize_op_quantize( lambda operand: reduce_precision(operand, exponent_bits, mantissa_bits), operand, type(result)) aus.

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkommatyps oder quantisierter Tensor pro Tensor (C1)
(I2) exponent_bits Konstante vom Typ si32 (C2)
(I3) mantissa_bits Konstante vom Typ si32 (C3)

Ausgaben

Name Typ Einschränkungen
output Tensor des Gleitkommatyps oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

reduce_scatter

Semantik

reduce_scatter

Innerhalb jeder Prozessgruppe im StableHLO-Prozessraster wird eine Reduzierung durchgeführt, mit computations über die Werte des Tensors operand aus jedem Prozess teilt das Reduktionsergebnis entlang von scatter_dimension in Teile auf die aufgeteilten Teile zwischen den Prozessen, um die result zu erzeugen.

Der Vorgang teilt das StableHLO-Prozessraster in process_groups auf, wie folgt definiert:

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

Danach gilt in jeder process_group Folgendes:

  • 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] für alle sender in process_group, wobei receiver_index = process_group.index(receiver).

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor oder quantisierter Tensor pro Tensor (C1), (C2), (C7), (C8)
(I2) scatter_dimension Konstante vom Typ si64 (C1), (C2), (C8)
(I3) replica_groups 2-dimensionale Tensorkonstante vom Typ si64 (C3–C5)
(I4) channel_id Konstante vom Typ si64 (C6)
(I5) use_global_device_ids Konstante vom Typ i1 (C6)
(I6) computation Funktion (C7)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor pro Tensor (C8–C9)

Einschränkungen

  • (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) ist definiert als: <ph type="x-smartling-placeholder">
      </ph>
    • num_replicas, wenn cross_replica verwendet wird.
    • num_replicas, wenn cross_replica_and_partition verwendet wird.
    • num_processes, wenn flattened_ids verwendet wird.
  • (C5) 0 <= replica_groups < size(replica_groups).
  • (C6) Wenn use_global_device_ids = true, dann channel_id > 0.
  • (C7) computation hat den Typ (tensor<E>, tensor<E>) -> (tensor<E>), wobei is_promotable(element_type(operand), E)
  • (C8) shape(result) = shape(operand) mit Ausnahme von: <ph type="x-smartling-placeholder">
      </ph>
    • dim(result, scatter_dimension) = dim(operand, scatter_dimension) / dim(process_groups, 1).
  • (C9) element_type(result) = E.

Beispiele

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

Weitere Beispiele

reduce_window

Semantik

Wendet eine Reduktionsfunktion body auf die Fenster von inputs und init_values an und produziert results.

Das folgende Diagramm zeigt, wie Elemente in results... aus inputs... anhand eines konkreten Beispiels.

reduce_window

Formeller gesprochen results...[result_index] = reduce(windows, init_values, axes(inputs...), body) (siehe Reduzieren), wobei Folgendes gilt:

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

Eingaben

Label Name Typ Einschränkungen
(I1) inputs variadische Anzahl von Tensoren oder quantisierte Tensoren pro Tensor (C1-C4), (C6), (C8), (C10), (C12), (C13), (C15)
(I2) init_values variadische Anzahl von 0-dimensionalen Tensoren oder quantisierten Tensoren pro Tensor (C1), (C13)
(I3) window_dimensions Eindimensionale Tensorkonstante vom Typ si64 (C4), (C5), (C15)
(I4) window_strides Eindimensionale Tensorkonstante vom Typ si64 (C6), (C7), (C15)
(I5) base_dilations Eindimensionale Tensorkonstante vom Typ si64 (C8), (C9), (C15)
(I6) window_dilations Eindimensionale Tensorkonstante vom Typ si64 (C10), (C11), (C15)
(I7) padding 2-dimensionale Tensorkonstante vom Typ si64 (C12), (C15)
(I8) body Funktion (C13)

Ausgaben

Name Typ Einschränkungen
results variadische Anzahl von Tensoren oder quantisierte Tensoren pro Tensor (C1), (C14-C16)

Einschränkungen

  • (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 hat den Typ (tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ..., tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>), wobei is_promotable(element_type(inputs[i]), Ei).
  • (C14) same(shape(results...)).
  • (C15) shape(results[0]) = num_windows, wobei gilt: <ph type="x-smartling-placeholder">
      </ph>
    • 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 für alle i in [0,N).

Beispiele

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

Weitere Beispiele

Rest

Semantik

Führt den elementweisen Rest der Tensoren des Dividenden lhs und des Divisors rhs durch und erzeugt einen result-Tensor.

Formal wird das Vorzeichen des Ergebnisses von der Dividende entnommen, und das Der absolute Wert des Ergebnisses ist immer kleiner als der absolute Wert des Divisors. Der Rest wird als lhs - d * rhs berechnet, wobei d durch Folgendes gegeben ist:

  • Für Ganzzahlen: stablehlo.divide(lhs, rhs).
  • Für Gleitkommazahlen: division(lhs, rhs) aus IEEE-754 mit Rundungsattribut roundTowardZero.
  • Für komplexe Zahlen: TBD (#997)
  • Für quantisierte Typen: <ph type="x-smartling-placeholder">
      </ph>
    • dequantize_op_quantize(remainder, lhs, rhs, type(result)).

Bei Gleitkommaelementtypen steht diese Operation im Gegensatz zur remainder-Operation aus der IEEE-754-Spezifikation, wobei d ein ganzzahliger Wert ist dem Wert von lhs/rhs am nächsten ist, bei Gleichheit oder Gleichheit.

Eingaben

Label Name Typ Einschränkungen
(I1) lhs Tensor von Ganzzahl, Gleitkomma oder komplexer Typ oder quantisierter Tensor pro Tensor (C1)
(I2) rhs Tensor von Ganzzahl, Gleitkomma oder komplexer Typ oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor von Ganzzahl, Gleitkomma oder komplexer Typ oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

replica_id

Semantik

Erzeugt replica_id des aktuellen Prozesses.

Ausgaben

Name Typ
result 0-dimensionaler Tensor vom Typ ui32

Beispiele

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

Weitere Beispiele

umformen

Semantik

Führt die Umformung des operand-Tensors in einen result-Tensor durch. Konzeptionell dieselbe kanonische Darstellung beibehalten, jedoch sich möglicherweise ändert, die Form, z.B. von tensor<2x3xf32> auf tensor<3x2xf32> oder tensor<6xf32>.

Formeller gesprochen: result[result_index] = operand[operand_index], wobei result_index und operand_index haben im lexikografischen Feld dieselbe Position. von index_space(result) und index_space(operand) sortiert.

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor oder quantisierter Tensor (C1–C3)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor (C1–C3)

Einschränkungen

  • (C1) element_type(result) ist gegeben durch: <ph type="x-smartling-placeholder">
      </ph>
    • element_type(operand), wenn !is_per_axis_quantized(operand).
    • element_type(operand) mit dem Unterschied, dass quantization_dimension(operand) und Andernfalls kann quantization_dimension(result) abweichen.
  • (C2) size(operand) = size(result).
  • (C3) Wenn is_per_axis_quantized(operand): <ph type="x-smartling-placeholder">
      </ph>
    • 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).

Beispiele

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

Weitere Beispiele

reverse

Semantik

Kehrt die Reihenfolge der Elemente im operand entlang der angegebenen dimensions um und erzeugt einen result-Tensor. Formeller gesprochen result[result_index] = operand[operand_index], wobei gilt:

  • operand_index[d] = dim(result, d) - result_index[d] - 1 wenn d in dimensions.
  • Andernfalls operand_index[d] = result_index[d].

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor oder quantisierter Tensor pro Tensor (C1), (C3)
(I2) dimensions Eindimensionale Tensorkonstante vom Typ si64 (C2), (C3)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor pro Tensor (C1), (C3)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

Rng

<ph type="x-smartling-placeholder">
</ph>

Semantik

Erzeugt Zufallszahlen mit dem rng_distribution-Algorithmus und erzeugt einen Tensor result einer gegebenen Form shape.

Wenn rng_distribution = UNIFORM, werden die Zufallszahlen generiert. nach der gleichmäßigen Verteilung über das Intervall [a, b). Wenn a >= b, ist das Verhalten nicht definiert.

Wenn rng_distribution = NORMAL, werden die Zufallszahlen generiert. folgt der Normalverteilung mit Mittelwert = a und Standardabweichung = b. Wenn b < 0, ist das Verhalten nicht definiert.

Die genaue Art und Weise, wie Zufallszahlen generiert werden, ist implementierungsdefiniert. Für Sie können, müssen aber deterministisch sein, und sie verwenden ausgeblendet.

In Gesprächen mit vielen Stakeholdern hat sich diese Maßnahme ebenso effektiv wie entfernt werden. Wir planen also, es in Zukunft zu entfernen. (#597)

Eingaben

Label Name Typ Einschränkungen
(I1) a 0-dimensionaler Tensor vom Typ „Ganzzahl“, „Boolesch“ oder „Gleitkommazahl“ (C1), (C2)
(I2) b 0-dimensionaler Tensor vom Typ „Ganzzahl“, „Boolesch“ oder „Gleitkommazahl“ (C1), (C2)
(I3) shape Eindimensionale Tensorkonstante vom Typ si64 (C3)
(I4) rng_distribution Aufzählung von UNIFORM und NORMAL (C2)

Ausgaben

Name Typ Einschränkungen
result Tensor des Ganzzahl-, Boolesch- oder Gleitkommatyps (C1–C3)

Einschränkungen

  • (C1) element_type(a) = element_type(b) = element_type(result).
  • (C2) Wenn rng_distribution = NORMAL, dann is_float(a).
  • (C3) shape(result) = shape.

Beispiele

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

Semantik

Gibt ein output zurück, das mit einheitlichen zufälligen Bits und einem aktualisierten Ausgabestatus gefüllt ist output_state mit dem Algorithmus zum Pseudozufallszahlen-Generator rng_algorithm mit dem Anfangszustand initial_state. Die Ausgabe ist garantiert deterministische Funktion von initial_state, aber dies ist nicht garantiert. deterministisch ist.

rng_algorithm ist einer der folgenden Werte:

  • DEFAULT: Implementierungsdefinierter Algorithmus.
  • THREE_FRY: Implementierungsdefinierte Variante des Threefry-Algorithmus.*
  • PHILOX: Implementierungsdefinierte Variante des Philox-Algorithmus.*

* Siehe Salmon et al. SC 2011. Parallele Zufallszahlen: so einfach wie 1, 2, 3.

Eingaben

Label Name Typ Einschränkungen
(I1) rng_algorithm Aufzählung von DEFAULT, THREE_FRY und PHILOX (C2)
(I2) initial_state Eindimensionaler Tensor vom Typ ui64 (C1), (C2)

Ausgaben

Name Typ Einschränkungen
output_state Eindimensionaler Tensor vom Typ ui64 (C1)
output Tensor des Ganzzahl- oder Gleitkommatyps

Einschränkungen

  • (C1) type(initial_state) = type(output_state).
  • (C2) size(initial_state) ist definiert als: <ph type="x-smartling-placeholder">
      </ph>
    • Implementierung definiert, wenn rng_algorithm = DEFAULT.
    • 2 wenn rng_algorithm = THREE_FRY.
    • 2 oder 3, wenn rng_algorithm = PHILOX.

Beispiele

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

Semantik

Führt eine elementweise Rundung auf die nächste Ganzzahl durch, wodurch Verbindungen getrennt werden mit dem operand-Tensor und erzeugt einen result-Tensor. Implementiert Den roundToIntegralTiesToAway-Vorgang aus der IEEE-754-Spezifikation Für quantisierten Typen quantifiziert, dequantize_op_quantize(round_nearest_afz, operand, type(result))

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkommatyps oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkommatyps oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

round_nearest_even

Semantik

Führt eine elementweise Rundung auf die nächste Ganzzahl durch, wobei Gleichstände aufgehoben werden. in Richtung der geraden Ganzzahl mit dem operand-Tensor und erzeugt eine result Tensor. Implementiert den roundToIntegralTiesToEven-Vorgang aus IEEE-754 Spezifikation zu ändern. Führt für quantisierte Typen durch dequantize_op_quantize(round_nearest_even, operand, type(result))

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkommatyps oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkommatyps oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

rsqrt

Semantik

Führt eine elementweise reziproke Quadratwurzeloperation für den operand-Tensor durch und erzeugt einen result-Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für Gleitkommazahlen: rSqrt aus IEEE-754.
  • Für komplexe Zahlen: komplexe reziproke Quadratwurzel.
  • Für quantisierte Typen: dequantize_op_quantize(rsqrt, operand, type(result)).

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

Streudiagramm

Semantik

Erzeugt results-Tensoren, die inputs-Tensoren entsprechen, mit der Ausnahme, Mehrere von scatter_indices angegebene Segmente werden mit den Werten aktualisiert. updates mit update_computation.

Das folgende Diagramm zeigt, wie Elemente in updates... den Elementen in results... anhand eines konkreten Beispiels. Im Diagramm finden Sie updates...-Indexe und eine ausführliche Erläuterung der results...-Indizes die dem jeweiligen Produkt entsprechen.

Streudiagramm

Formeller für alle update_index in 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 ist definiert als: <ph type="x-smartling-placeholder">
      </ph>
    • scatter_indices[si0, ..., :, ..., siN], bei denen si individuell sind Elemente in update_scatter_index und : werden an der Index index_vector_dim, wenn index_vector_dim < rank(scatter_indices)
    • Andernfalls [scatter_indices[update_scatter_index]].
  • Für d_input in axes(inputs[0]), <ph type="x-smartling-placeholder">
      </ph>
    • full_start_index[d_input] = start_index[d_start] wenn d_input = scatter_dims_to_operand_dims[d_start].
    • Andernfalls full_start_index[d_input] = 0.
  • Für d_input in axes(inputs[0]), <ph type="x-smartling-placeholder">
      </ph>
    • full_batching_index[d_input] = update_scatter_index[d_start - (d_start < index_vector_dim ? 0 : 1)] wenn d_input = input_batching_dims[i_batching] und d_start = scatter_indices_batching_dims[i_batching]
    • Andernfalls full_batching_index[d_input] = 0.
  • update_window_index = update_index[update_window_dims...].
  • full_window_index = [wi0, ..., 0, ..., wiN], bei denen wi individuell sind Elemente in update_window_index und 0 wird an Indexen von inserted_window_dims und input_batching_dims.
  • result_index = full_start_index + full_batching_index + full_window_index.

Daher gilt: results = exec(schedule, inputs), wobei:

  • schedule ist eine implementierungsdefinierte Permutation von index_space(updates[0]).
  • exec([update_index, ...], results) = exec([...], updated_results), wobei gilt: <ph type="x-smartling-placeholder">
      </ph>
    • Wenn result_index innerhalb der Grenzen für shape(results...) liegt
    • 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 ist eine Kopie von results mit results...[result_index] auf updated_values... festgelegt.
    • Andernfalls:
    • updated_results = results.
  • exec([], results) = results.

Wenn indices_are_sorted den Wert true hat, kann die Implementierung davon ausgehen, scatter_indices werden nach scatter_dims_to_operand_dims sortiert, Andernfalls ist das Verhalten nicht definiert. Formeller für alle i1 < i2 aus indices(result), full_start_index(i1) <= full_start_index(i2).

Wenn unique_indices den Wert true hat, kann die Implementierung davon ausgehen, dass alle Die result_index-Indizes, in die verteilt werden, sind eindeutig. Wenn unique_indices gleich true aber die verteilten Indexe nicht eindeutig sind, ist das Verhalten nicht definiert.

Eingaben

Label Name Typ Einschränkungen
(I1) inputs variadische Anzahl von Tensoren oder quantisierte Tensoren pro Tensor (C1), (C2), (C4-C6), (C11), (C13), (C18), (C21), (C23-C24)
(I2) scatter_indices Tensor des Ganzzahltyps (C4), (C15), (C19), (C22)
(I3) updates variadische Anzahl von Tensoren oder quantisierte Tensoren pro Tensor (C3–C6), (C8)
(I4) update_window_dims Eindimensionale Tensorkonstante vom Typ si64 (C2), (C4), (C7-C8)
(I5) inserted_window_dims Eindimensionale Tensorkonstante vom Typ si64 (C2), (C4), (C9-C11)
(I6) input_batching_dims Eindimensionale Tensorkonstante vom Typ si64 (C2), (C4), (C9), (C12-13), (C17-18), (C20)
(I7) scatter_indices_batching_dims Eindimensionale Tensorkonstante vom Typ si64 (C14–C18)
(I8) scatter_dims_to_operand_dims Eindimensionale Tensorkonstante vom Typ si64 (C19–C21)
(I9) index_vector_dim Konstante vom Typ si64 (C4), (C16), (C19), (C22)
(I10) indices_are_sorted Konstante vom Typ i1
(I11) unique_indices Konstante vom Typ i1
(I12) update_computation Funktion (C23)

Ausgaben

Name Typ Einschränkungen
results variadische Anzahl von Tensoren oder quantisierte Tensoren pro Tensor (C24–C25)

Einschränkungen

  • (C1) same(shape(inputs...)).
  • (C2) `rank(inputs[0]) = size(update_window_dims) + size(eingefügtes_Fenster_Dims) <ph type="x-smartling-placeholder">
      </ph>
    • size(input_batching_dims)`.
  • (C3) same(shape(updates...)).
  • (C4) shape(updates[0]) = combine(update_scatter_dim_sizes, update_window_dim_sizes), wobei gilt: <ph type="x-smartling-placeholder">
      </ph>
    • update_scatter_dim_sizes = shape(scatter_indices), außer dass die Dimensionsgröße von scatter_indices für index_vector_dim ist nicht enthalten.
    • update_window_dim_sizes <= shape(inputs[0]), außer dass die Dimensionsgrößen in inputs[0] für inserted_window_dims und input_batching_dims sind nicht enthalten.
    • combine platziert update_scatter_dim_sizes auf den Achsen, die update_scatter_dims und update_window_dim_sizes an den entsprechenden Achsen an update_window_dims.
  • (C5) 0 < size(inputs) = size(updates) = N.
  • (C6) element_type(updates...) = element_type(inputs...).
  • (C7) is_unique(update_window_dims) and is_sorted(update_window_dims).
  • (C8) 0 <= update_window_dims < rank(updates[0]).
  • (C9) is_unique(concatenate(inserted_window_dims, input_batching_dims))
  • (C10) is_sorted(inserted_window_dims).
  • (C11) 0 <= inserted_window_dims < rank(inputs[0]).
  • (C12) is_sorted(input_batching_dims).
  • (C13) 0 <= input_batching_dims < rank(inputs[0])).
  • (C14) is_unique(scatter_indices_batching_dims).
  • (C15) 0 <= scatter_indices_batching_dims < rank(scatter_indices).
  • (C16) index_vector_dim not in scatter_indices_batching_dims.
  • (C17) size(input_batching_dims) == size(scatter_indices_batching_dims).
  • (C18) dim(inputs[0], input_batching_dims...) = dim(scatter_indices, scatter_indices_batching_dims...).
  • (C19) size(scatter_dims_to_operand_dims) = index_vector_dim < rank(scatter_indices) ? dim(scatter_indices, index_vector_dim) : 1.
  • (C20) is_unique(concatenate(scatter_dims_to_operand_dims, input_batching_dims)).
  • (C21) 0 <= scatter_dims_to_operand_dims < rank(inputs[0]).
  • (C22) 0 <= index_vector_dim <= rank(scatter_indices).
  • (C23) update_computation hat den Typ (tensor<E0>, ..., tensor<EN-1>, tensor<E0>, ..., tensor<EN-1>) -> (tensor<E0>, ..., tensor<EN-1>), Dabei gilt: is_promotable(element_type(inputs[i]), Ei).
  • (C24) shape(inputs...) = shape(results...).
  • (C25) element_type(results[i]) = Ei für alle i in [0,N).

Beispiele

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

Weitere Beispiele

auswählen

Semantik

Erzeugt einen result-Tensor, bei dem jedes Element aus on_true oder on_false-Tensor basierend auf dem Wert des entsprechenden Elements von pred. Formeller: result[result_index] = pred_element ? on_true[result_index] : on_false[result_index], wobei pred_element = rank(pred) = 0 ? pred[] : pred[result_index]. Führt für quantisierte Typen durch dequantize_select_quantize(pred, on_true, on_false, type(result))

Eingaben

Label Name Typ Einschränkungen
(I1) pred Tensor vom Typ i1 (C1)
(I2) on_true Tensor oder quantisierter Tensor pro Tensor (C1–C2)
(I3) on_false Tensor oder quantisierter Tensor pro Tensor (C2)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor pro Tensor (C2)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

select_and_scatter

Semantik

Streut die Werte aus dem Tensor source unter Verwendung von scatter basierend auf dem Ergebnis von reduce_window des input-Tensors mit select und erzeugt einen result-Tensor.

Das folgende Diagramm zeigt, wie Elemente in result aus operand und source anhand eines konkreten Beispiels.

select_and_scatter

Formeller:

  • selected_values = reduce_window_without_init(...) durch die folgenden Eingaben:

    • inputs = [operand].
    • window_dimensions, window_strides und padding, die unverändert verwendet werden.
    • base_dilations = windows_dilations = 1.
    • body ist definiert als:
    def body(arg0: tensor<E>, arg1: tensor<E>) -> tensor<E>:
      return select(arg0, arg1) ? arg0 : arg1;
    

    wo E = element_type(operand) und reduce_window_without_init funktionieren genau wie reduce_window, mit dem Unterschied, dass die schedule des zugrunde liegenden reduce (siehe Reduzieren) enthält keine Init-Werte. Aktuell Nicht angegeben, was passiert, wenn das entsprechende Fenster keine Werte enthält (#731)

  • result[result_index] = reduce([source_values], [init_value], [0], scatter) Dabei gilt:

    • source_values = [source[source_index] for source_index in source_indices].
    • selected_index(source_index) = operand_index wenn selected_values[source_index] hat das Element operand von operand_index.
    • source_indices = [source_index for source_index in indices(source) if selected_index(source_index) = result_index].

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor oder quantisierter Tensor pro Tensor (C1-C4), (C6), (C8-C11)
(I2) source Tensor oder quantisierter Tensor pro Tensor (C1), (C2)
(I3) init_value 0-dimensionaler Tensor oder quantisierter Tensor pro Tensor (C3)
(I4) window_dimensions Eindimensionale Tensorkonstante vom Typ si64 (C2), (C4), (C5)
(I5) window_strides Eindimensionale Tensorkonstante vom Typ si64 (C2), (C6), (C7)
(I6) padding 2-dimensionale Tensorkonstante vom Typ si64 (C2), (C8)
(I7) select Funktion (C9)
(I8) scatter Funktion (C10)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor pro Tensor (C11–C12)

Einschränkungen

  • (C1) element_type(operand) = element_type(source).
  • (C2) shape(source) = num_windows, wobei Folgendes gilt: <ph type="x-smartling-placeholder">
      </ph>
    • 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 hat den Typ (tensor<E>, tensor<E>) -> tensor<i1>, wobei E = element_type(operand)
  • (C10) scatter hat den Typ (tensor<E>, tensor<E>) -> tensor<E>, wobei is_promotable(element_type(operand), E)
  • (C11) shape(operand) = shape(result).
  • (C12) element_type(result) = E.

Beispiele

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

Weitere Beispiele

senden

Semantik

Sendet inputs an einen Kanal channel_id und generiert ein result-Token.

Wenn is_host_transfer den Wert true hat, überträgt der Vorgang Daten an den Host. Andernfalls werden Daten auf ein anderes Gerät übertragen. Das bedeutet, Implementierung definiert. Dieses Flag dupliziert die in channel_type, daher planen wir, in Zukunft nur eine davon zu behalten (#666)

Eingaben

Label Name Typ Einschränkungen
(I1) inputs variadische Anzahl von Tensoren oder quantisierten Tensoren
(I2) token token
(I3) channel_id Konstante vom Typ si64
(I4) channel_type Aufzählung von DEVICE_TO_DEVICE und DEVICE_TO_HOST (C1)
(I5) is_host_transfer Konstante vom Typ i1 (C1)

Ausgaben

Name Typ
result token

Einschränkungen

  • (C1) channel_type ist definiert als: <ph type="x-smartling-placeholder">
      </ph>
    • DEVICE_TO_HOST, wenn is_host_transfer = true,
    • Andernfalls DEVICE_TO_DEVICE.

Beispiele

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

Weitere Beispiele

shift_left

Semantik

Führt eine elementweise Linksverschiebung am lhs-Tensor um die rhs-Zahl aus und erzeugt einen result-Tensor.

Eingaben

Label Name Typ Einschränkungen
(I1) lhs Tensor des Ganzzahltyps (C1)
(I2) rhs Tensor des Ganzzahltyps (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Ganzzahltyps (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

shift_right_arithmetic

Semantik

Führt eine elementweise arithmetische Operation zur Rechtsverschiebung für den lhs-Tensor durch rhs der Anzahl von Bits und erzeugt einen result-Tensor.

Eingaben

Label Name Typ Einschränkungen
(I1) lhs Tensor des Ganzzahltyps (C1)
(I2) rhs Tensor des Ganzzahltyps (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Ganzzahltyps (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

shift_right_logical

Semantik

Führt eine elementweise logische Rechtsverschiebung für den Tensor lhs um rhs durch Anzahl von Bits und erzeugt einen result-Tensor.

Eingaben

Label Name Typ Einschränkungen
(I1) lhs Tensor des Ganzzahltyps (C1)
(I2) rhs Tensor des Ganzzahltyps (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Ganzzahltyps (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

Signieren

Semantik

Gibt das Vorzeichen von operand elementweise zurück und erzeugt einen result-Tensor. Formal kann die Semantik für jedes Element x mit Python-Syntax:

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

Führt für quantisierte Typen durch dequantize_op_quantize(sign, operand, type(result))

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor eines vorzeichenbehafteten Ganzzahl-, Gleitkomma- oder komplexer Typ oder eines quantisierten Tensors pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor eines vorzeichenbehafteten Ganzzahl-, Gleitkomma- oder komplexer Typ oder eines quantisierten Tensors pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

Sinus

Semantik

Führt eine elementweise Sinusoperation für den operand-Tensor durch und erzeugt einen result-Wert Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für Gleitkommazahlen: sin aus IEEE-754.
  • Für komplexe Zahlen: komplexer Sinus.
  • Für quantisierte Typen: dequantize_op_quantize(sine, operand, type(result)).

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

Slice

Semantik

Extrahiert ein Segment aus dem operand unter Verwendung statisch berechneter Startindexe und erzeugt einen result-Tensor. start_indices enthalten die Startindizes von das Segment für jede Dimension, limit_indices enthalten die Endindizes (ausschließlich) für das Segment für jede Dimension und strides enthalten die Schritte für jede Dimension.

Formeller gesprochen: result[result_index] = operand[operand_index], wobei operand_index = start_indices + result_index * strides.

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor oder quantisierter Tensor pro Tensor (C1–C3), (C5)
(I2) start_indices Eindimensionale Tensorkonstante vom Typ si64 (C2), (C3), (C5)
(I3) limit_indices Eindimensionale Tensorkonstante vom Typ si64 (C2), (C3), (C5)
(I4) strides Eindimensionale Tensorkonstante vom Typ si64 (C2), (C4)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor pro Tensor (C1), (C5)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

Sortieren

Semantik

Sortiert eindimensionale Segmente von inputs entlang der Dimension dimension zusammen, Laut comparator und produziert results.

Im Gegensatz zu ähnlichen Eingaben in anderen Operationen lässt dimension negative Werte zu, mit der unten beschriebenen Semantik. Künftig ist dies möglicherweise nicht mehr zulässig. aus Gründen der Einheitlichkeit (#1377)

Wenn is_stable "true" ist, ist die Sortierung stabil, d. h. die relative Reihenfolge von Elemente, die vom Vergleichsoperator als gleich eingestuft werden, werden beibehalten. Für die Schutzhülle mit einer einzigen Eingabe, werden die beiden Elemente e1 und e2 als wenn und nur wenn comparator(e1, e2) = comparator(e2, e1) = false Siehe die Formulierung unten wie dies auf mehrere Eingaben verallgemeinert wird.

Formeller für alle result_index in index_space(results[0]):

  • adjusted_dimension = dimension >= 0 ? dimension : rank(inputs[0]) + dimension.
  • result_slice = [ri0, ..., :, ..., riR-1], bei denen riN individuell sind Elemente in result_index und : wird bei adjusted_dimension eingefügt.
  • inputs_together = (inputs[0]..., ..., inputs[N-1]...).
  • results_together[result_slice] = sort(inputs_together[result_slice], comparator_together).
  • Dabei sortiert sort ein eindimensionales Segment in nicht absteigender Reihenfolge und erwartet comparator_together gibt true zurück, wenn das Argument auf der linken Seite gleich als das rechte Sekundenargument.
  • 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.

Eingaben

Label Name Typ Einschränkungen
(I1) inputs variadische Anzahl von Tensoren oder quantisierte Tensoren pro Tensor (C1–C5)
(I2) dimension Konstante vom Typ si64 (C4)
(I3) is_stable Konstante vom Typ i1
(I4) comparator Funktion (C5)

Ausgaben

Name Typ Einschränkungen
results variadische Anzahl von Tensoren oder quantisierte Tensoren pro Tensor (C2), (C3)

Einschränkungen

  • (C1) 0 < size(inputs).
  • (C2) type(inputs...) = type(results...).
  • (C3) same(shape(inputs...) + shape(results...)).
  • (C4) -R <= dimension < R, wobei R = rank(inputs[0]).
  • (C5) comparator hat Typ (tensor<E1>, tensor<E1>, ..., tensor<EN-1>, tensor<EN-1>) -> tensor<i1>, Dabei gilt: Ei = element_type(inputs[i]).

Beispiele

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

Weitere Beispiele

Quadrat

Semantik

Führt eine elementweise Quadratwurzeloperation für den operand-Tensor durch und erzeugt eine result-Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für Gleitkommazahlen: squareRoot aus IEEE-754.
  • Für komplexe Zahlen: komplexe Quadratwurzel.
  • Für quantisierte Typen: dequantize_op_quantize(sqrt, operand, type(result)).

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

subtract

Semantik

Führt eine elementweise Subtraktion der zwei Tensoren lhs und rhs durch und erzeugt einen result-Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für Ganzzahlen: Subtraktion von Ganzzahlen.
  • Für Gleitkommazahlen: subtraction aus IEEE-754.
  • Für komplexe Zahlen: komplexe Subtraktion.
  • Für quantisierte Typen: <ph type="x-smartling-placeholder">
      </ph>
    • dequantize_op_quantize(subtract, lhs, rhs, type(result)).

Eingaben

Label Name Typ Einschränkungen
(I1) lhs Tensor von Ganzzahl, Gleitkomma oder komplexer Typ oder quantisierter Tensor pro Tensor (C1)
(I2) rhs Tensor von Ganzzahl, Gleitkomma oder komplexer Typ oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor von Ganzzahl, Gleitkomma oder komplexer Typ oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

tan

Semantik

Führt eine elementweise Tangentenoperation am operand-Tensor durch und erzeugt eine result-Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für Gleitkommazahlen: tan aus IEEE-754.
  • Für komplexe Zahlen: komplexer Tangens.
  • Für quantisierte Typen: dequantize_op_quantize(tan, operand, type(result)).

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

Tanh

Semantik

Führt eine elementweise hyperbolische Tangente für den operand-Tensor und erzeugt einen result-Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für Gleitkommazahlen: tanh aus IEEE-754.
  • Für komplexe Zahlen: komplexer hyperbolischer Tangens.
  • Für quantisierte Typen: <ph type="x-smartling-placeholder">
      </ph>
    • dequantize_op_quantize(tanh, operand, type(result)).

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

Transponieren

Semantik

Permutet die Abmessungen des Tensors operand mit permutation an und erzeugt einen result-Tensor. Formeller result[result_index] = operand[operand_index] Dabei gilt: result_index[d] = operand_index[permutation[d]].

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor oder quantisierter Tensor (C1–C4)
(I2) permutation Eindimensionale Tensorkonstante vom Typ si64 (C2–C4)

Ausgaben

Name Typ Einschränkungen
result Tensor oder quantisierter Tensor (C1), (C3–C4)

Einschränkungen

  • (C1) element_type(result) ist gegeben durch: <ph type="x-smartling-placeholder">
      </ph>
    • element_type(operand), wenn !is_per_axis_quantized(operand).
    • element_type(operand) mit dem Unterschied, dass quantization_dimension(operand) und Andernfalls kann quantization_dimension(result) abweichen.
  • (C2) permutation ist eine Permutation von range(rank(operand)).
  • (C3) shape(result) = dim(operand, permutation...).
  • (C4) Wenn is_per_axis_quantized(result), dann quantization_dimension(operand) = permutation(quantization_dimension(result)).

Beispiele

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

Weitere Beispiele

triangular_solve

Semantik

Löst Batches von linearen Gleichungssystemen mit unterem oder oberem Dreieck Koeffizientenmatrizen.

Formal ist result[i0, ..., iR-3, :, :] die Lösung, basierend auf a und b. auf op(a[i0, ..., iR-3, :, :]) * x = b[i0, ..., iR-3, :, :], wenn left_side gleich true oder x * op(a[i0, ..., iR-3, :, :]) = b[i0, ..., iR-3, :, :], wenn left_side ist false, wobei die Variable x aufgelöst wird, wobei op(a) bestimmt wird. von transpose_a. Dabei kann es sich um einen der folgenden Werte handeln:

  • NO_TRANSPOSE: Vorgang mit a unverändert ausführen.
  • TRANSPOSE: Operation wird beim Transponieren von a durchgeführt.
  • ADJOINT: Operation für die konjugierte Transponierung von a ausführen.

Eingabedaten werden nur aus dem unteren Dreieck von a gelesen, wenn lower gleich true oder oberes Dreieck von a andernfalls. Ausgabedaten werden im selben Dreieck zurückgegeben. werden die Werte im anderen Dreieck implementierungsdefiniert.

Wenn unit_diagonal „true“ ist, kann die Implementierung davon ausgehen, dass die diagonale Elemente von a gleich 1 sind, ansonsten ist das Verhalten nicht definiert.

Führt für quantisierte Typen durch dequantize_op_quantize(lambda x, y: triangular_solve(x, y, left_side, lower, unit_diagonal, transpose_a), a, b, type(result))

Eingaben

Label Name Typ Einschränkungen
(I1) a Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1–C3)
(I2) b Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1–C4)
(I3) left_side Konstante vom Typ i1 (C3)
(I4) lower Konstante vom Typ i1
(I5) unit_diagonal Konstante vom Typ i1
(I6) transpose_a Aufzählung von NO_TRANSPOSE, TRANSPOSE und ADJOINT

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkomma- oder komplexen Typs oder quantisierter Tensor pro Tensor (C1)

Einschränkungen

  • (C1) baseline_element_type(a) = baseline_element_type(b).
  • (C2) 2 <= rank(a) = rank(b) = R.
  • (C3) Die Beziehung zwischen shape(a) und shape(b) ist so definiert: <ph type="x-smartling-placeholder">
      </ph>
    • 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).

Beispiele

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

Tupel

<ph type="x-smartling-placeholder">
</ph>

Semantik

Erzeugt ein result-Tupel aus den Werten val.

Eingaben

Label Name Typ Einschränkungen
(I1) val variadische Anzahl von Werten (C1)

Ausgaben

Name Typ Einschränkungen
result Tupel (C1)

Einschränkungen

  • (C1) result hat den Typ tuple<E0, ..., EN-1>, wobei Ei = type(val[i]).

Beispiele

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

Weitere Beispiele

uniform_dequantize

Semantik

Führt eine elementweise Umwandlung des quantisierten Tensors operand in einen Gleitkomma-Tensor result gemäß den definierten Quantisierungsparametern nach dem Typ operand.

Formeller: result = dequantize(operand).

Eingaben

Label Name Typ Einschränkungen
(I1) operand quantisierter Tensor (C1), (C2)

Ausgaben

Name Typ Einschränkungen
result Tensor des Gleitkommatyps (C1), (C2)

Einschränkungen

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

Beispiele

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

Semantik

Führt eine elementweise Konvertierung von Gleitkomma- oder quantisierten Tensors durch operand zu einem quantisierten Tensor result gemäß der Quantisierung Parameter, die durch den Typ result definiert sind.

Formeller gesprochen

  • Wenn is_float(operand): <ph type="x-smartling-placeholder">
      </ph>
    • result = quantize(operand, type(result)).
  • Wenn is_quantized(operand): <ph type="x-smartling-placeholder">
      </ph>
    • float_result = dequantize(operand).
    • result = quantize(float_result, type(result)).

Eingaben

Label Name Typ Einschränkungen
(I1) operand Tensor eines Gleitkomma- oder quantisierten Typs (C1), (C2)

Ausgaben

Name Typ Einschränkungen
result quantisierter Tensor (C1), (C2)

Einschränkungen

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

Beispiele

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

während

Semantik

Erzeugt die Ausgabe, wenn die Funktion body ein- oder öfter ausgeführt wird, während Die Funktion cond gibt true aus. Formal lässt sich die Semantik zum Ausdruck bringen, mit der folgenden Python-Syntax:

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

Das Verhalten einer Endlosschleife steht noch nicht fest. (#383)

Eingaben

Label Name Typ Einschränkungen
(I1) operand variadische Anzahl von Tensoren, quantisierte Tensoren oder Tokens (C1–C3)
(I2) cond Funktion (C1)
(I3) body Funktion (C2)

Ausgaben

Name Typ Einschränkungen
results variadische Anzahl von Tensoren, quantisierte Tensoren oder Tokens (C3)

Einschränkungen

  • (C1) cond hat den Typ (T0, ..., TN-1) -> tensor<i1>, wobei Ti = type(operand[i])
  • (C2) body hat den Typ (T0, ..., TN-1) -> (T0, ..., TN-1), wobei Ti = type(operand[i])
  • (C3) type(results...) = type(operand...).

Beispiele

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

Weitere Beispiele

XOR

Semantik

Führt eine elementweise XOR-Verknüpfung der beiden Tensoren lhs und rhs durch und erzeugt eine result Tensor. Gehen Sie je nach Elementtyp so vor:

  • Für boolesche Werte: logisches XOR.
  • Für Ganzzahlen: bitweises XOR.

Eingaben

Label Name Typ Einschränkungen
(I1) lhs Tensor des booleschen oder Ganzzahltyps (C1)
(I2) rhs Tensor des booleschen oder Ganzzahltyps (C1)

Ausgaben

Name Typ Einschränkungen
result Tensor des booleschen oder Ganzzahltyps (C1)

Einschränkungen

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

Beispiele

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

Weitere Beispiele

Dialekt-Interop

Derzeit enthalten StableHLO-Programme manchmal Vorgänge, die nicht durch StableHLO definiert.

Modul, Funktion, Aufruf und Rückgabe

StableHLO nutzt vorgelagerte MLIR-Vorgänge für ModuleOp, FuncOp, CallOp und ReturnOp. Dies geschah zur besseren Interoperabilität mit vorhandenen MLIR-Maschinen. nützliche Karten/Tickets enthalten, die auf FuncOp und ModuleOp ausgerichtet sind, erwarten die Pipelines, dass diese Vorgänge vorhanden sind. Vollständige Kompatibilitätsgarantien auf diese Operationen angewendet. Wenn sich an diesen Operationen in einem nicht kompatibel (d.h. entfernt), werden StableHLO-Äquivalente hinzugefügt, um Kompatibilität.

CHLO

Das CHLO-Opset enthält Vorgänge auf höherer Ebene, die in StableHLO zerlegt werden. Derzeit gibt es keine Kompatibilitätsgarantien für CHLO. Aus Gründen der Kompatibilität chlo-legalize-to-stablehlo-Pass vor der Serialisierung verwendet werden.

Formvorgänge

In der Community werden bestimmte Vorgänge häufig verwendet, MLIR-Dialekte in dynamischen StableHLO-Programmen zur Durchführung von Formberechnungen Dazu gehören am häufigsten der shape-Dialekt Operationen wie shape_of oder num_elements, Dialekt tensor Operationen wie dim oder from_elements und den integrierten Typ index an.

Der Dynamism RFC > O2 werden als ausgeschlossen gekennzeichnet. Einige index-Typen werden jedoch unterstützt. zu Interoperabilitätszwecken enthalten. Es gibt keine Kompatibilitätsgarantien für diese Operationen oder Typen. Der Parameter shape-legalize-to-stablehlo pass verwendet, um diese Vorgänge in vollständig unterstützte StableHLO-Operationen zu konvertieren.

Verworfene Vorgänge

Es gibt mehrere StableHLO-Vorgänge, die von MHLO die eingestellt wurden und aus der StableHLO entfernt werden. Alle Details zu diesen Entfernungen finden Sie im StableHLO v1.0 Cleanup #2283. Das Tracker-Problem bei diesen Einstellungen ist #2340.

Diese Vorgänge lassen sich in verschiedene Kategorien einteilen:

  • „Nicht in HLO“ StableHLO-Operationen gehört haben. Sie waren anfangs Teil StableHLO-Opset, aber später wurde davon ausgegangen, dass es nicht gut geeignet ist: broadcast, create_token, cross-replica-sum, dot, einsum torch_index_select, unary_einsum (3.)
  • Nicht verwendete Operationen: Diese Vorgänge waren vielleicht irgendwann nützlich, aber der Vorgang entweder nicht ausgereift oder die Pipelines, die diese Vorgänge nutzen, so refaktoriert, dass sie nicht mehr benötigt werden. Dazu gehören map, tuple (#598), get_tuple_element, rng, complex Vergleiche Nr. 560, und Faltung window_reversal (#1181).

Einige dieser Operationen lassen sich leicht entfernen, da sie sich mit vorhandene Vorgänge (broadcast, create_token, cross-replica-sum, dot, unary_einsum) und wird nach Ablauf des bestehenden Kompatibilitätsfensters entfernt. Pässe (6 Monate). Für andere Nutzer wird derzeit geprüft, ob sie entfernt werden sollen (einsum, get_tuple_element, map, rng torch_index_select, tuple, complex Vergleiche, window_reversal). Ausstehendes Community-Feedback, Diese Vorgänge werden entweder entfernt oder mit vollständiger Unterstützung der Spezifikation hinzugefügt. Bis diese Ops-Futures bekannt sind, sind nur 6 Monate Kompatibilität garantiert.

Ausführung

Sequenzielle Ausführung

Ein StableHLO-Programm wird ausgeführt, indem Eingabewerte für die Funktion main bereitgestellt werden und Ausgabewerte zu berechnen. Ausgabewerte einer Funktion werden berechnet durch Ausführen des Graphen von Vorgängen, der im entsprechenden return-Vorgang basiert

Die Ausführungsreihenfolge ist implementierungsdefiniert, solange sie mit Dataflow, d. h., wenn Ops vor ihrer Verwendung ausgeführt werden In StableHLO werden alle Operationen mit Nebeneffekten verbrauchen ein Token und erzeugen ein Token (mehrere Tokens können über after_all in ein Token gebündelt werden, sodass die Ausführungsreihenfolge ist auch auf Dataflow ausgerichtet. Im folgenden Programm Es gibt zwei mögliche Ausführungsaufträge: %0%1%2return und %1%0%2return.

func.func @main() -> tensor<f64> {
  %0 = stablehlo.constant dense<1.0> : tensor<f64>
  %1 = stablehlo.constant dense<2.0> : tensor<f64>
  %2 = stablehlo.add %0, %1 : tensor<f64>
  return %2 : tensor<f64>
}

Formal ist ein StableHLO-Prozess eine Kombination aus Folgendem: 1) ein StableHLO-Programm, 2) Vorgangsstatus (noch nicht ausgeführt, bereits ausgeführt) und 3) Zwischenwerte, an denen der Prozess arbeitet. Der Prozess beginnt mit Eingabewerten für die main-Funktion und läuft Diagramm der Vorgänge, bei denen Vorgangsstatus und Zwischenwerte aktualisiert werden, mit Ausgabewerten endet. Weitere Formulierung steht noch aus (#484)

Parallele Ausführung

StableHLO-Programme können parallel ausgeführt werden, in einem 2D-Prozessraster organisiert von num_replicas nach num_partitions, die beide den Typ ui32 haben.

Im StableHLO-Prozessraster, num_replicas * num_partitions von StableHLO Prozesse gleichzeitig ausgeführt werden. Jeder Prozess hat eine eigene process_id = (replica_id, partition_id), wobei replica_id in replica_ids = range(num_replicas) und partition_id in partition_ids = range(num_partitions). Beide haben Geben Sie ui32 ein.

Die Größe des Prozessrasters ist für jedes Programm (in der möchten wir dies zu einem expliziten Teil der StableHLO-Programme machen. #650) und die Position innerhalb des Prozessrasters ist für jeden Prozess statisch bekannt. Jeder Prozess hat Zugriff auf seine Position im Prozessraster über replica_id und partition_id Vorgänge

Innerhalb des Prozessrasters können die Programme alle gleich sein (in der Spalte Programm, mehrere Daten“ Stil) können alle unterschiedlich sein (im Multiple-Programm, Mehrere Daten“ Stil) oder etwas dazwischen. Für die Zukunft planen wir, um weitere Redewendungen der Definition paralleler StableHLO-Programme einzuführen, einschließlich GSPMD (#619).

Innerhalb des Prozessrasters sind die Prozesse größtenteils unabhängig voneinander – Sie haben separate Vorgangsstatus und separate Eingabe-/Zwischen-/Ausgabewerte. und die meisten Vorgänge werden getrennt zwischen Prozessen ausgeführt, wobei der Ausnahme von einer kleinen Anzahl von kollektiven Operationen (siehe unten).

Da bei der Ausführung der meisten Operationen nur Werte ist es in der Regel eindeutig, anhand der Namen auf diese Werte zu verweisen. Die Semantik kollektiver Operationen ist jedoch unzureichend. die dazu führt, dass sich die Notation name@process_id auf den Wert name bezieht. eines bestimmten Prozesses. (Aus dieser Perspektive können unqualifizierte name-Daten als Abkürzung für name@(replica_id(), partition_id()) angesehen).

Die Ausführungsreihenfolge zwischen den Prozessen ist implementierungsdefiniert, mit Ausnahme der Synchronisierung durch Punkt-zu-Punkt-Kommunikation und kollektive Operationen wie unten beschrieben.

Punkt-zu-Punkt-Kommunikation

StableHLO-Prozesse können über StableHLO-Kanäle: Ein Channel wird durch eine positive ID des Typs si64 Über verschiedene Operationen ist es möglich, Werte an Channels zu senden und von Kanälen erhalten.

Weitere formalisierung, z.B. woher diese Kanal-IDs stammen, wie erkennen Programme darauf und welche Art von Synchronisierung eingeführt wurde, steht noch aus, (#484)

Streaming-Kommunikation

Jeder StableHLO-Prozess hat Zugriff auf zwei Streaming-Schnittstellen:

  • In-Feed, aus dem gelesen werden kann.
  • Outfeed, in den geschrieben werden kann.

Im Gegensatz zu Channels, die für die Kommunikation zwischen Prozessen haben Prozesse an beiden Enden, In-Feeds und Out-Feeds haben ihre anderen und die Implementierung definieren.

Weitere formalisierung, z.B. wie Streamingkommunikation die Ausführung beeinflusst und welche Art von Synchronisierung damit eingeführt wird, steht noch nicht fest. (#484)

Kollektiv-Operationen

Es gibt sechs kollektive Operationen in StableHLO: all_gather, all_reduce, all_to_all, collective_broadcast, collective_permute und reduce_scatter All diese Operationen teilen die Prozesse im StableHLO-Prozess auf in StableHLO-Prozessgruppen umwandeln und eine gemeinsame Berechnung unabhängig von anderen Prozessgruppen.

Innerhalb jeder Prozessgruppe können gemeinsame Ops eine Synchronisierung einführen. Hindernisse zu beseitigen. Weitere formalisierung, z.B. Wir gehen noch näher darauf ein, wie genau die Prozesse diese Barriere erreichen, Und was passiert, wenn nicht, steht (#484)

Wenn die Prozessgruppe partitionsübergreifende Kommunikation umfasst, d.h., es gibt Prozessgruppe mit unterschiedlichen Partitions-IDs erstellt, der kollektiven Opa benötigt einen Kanal und die kollektive Opa muss eine positive channel_id vom Typ si64. Replikatübergreifende Kommunikation erfordert keine Kanäle.

Die von den gemeinsamen Operationen ausgeführten Berechnungen sind spezifisch für die einzelnen Operationen und werden in den einzelnen Vorgangsabschnitten weiter oben beschrieben. Die Strategien der Das Prozessraster ist in Prozessgruppen aufgeteilt. Diese Operationen werden gemeinsam genutzt. und werden in diesem Abschnitt beschrieben. Formal unterstützt StableHLO die anhand von vier Strategien.

cross_replica

Nur replikatübergreifende Kommunikation findet innerhalb jeder Prozessgruppe statt. Dieses verwendet replica_groups, eine Liste mit Replikat-IDs, und berechnet ein kartesisches Produkt von replica_groups von partition_ids. replica_groups muss eindeutige Elemente enthalten und alle replica_ids abdecken. Formeller sollte die Verwendung Python-Syntax:

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

Beispiel: Für replica_groups = [[0, 1], [2, 3]] und num_partitions = 2: cross_replica wird Folgendes produzieren: [[(0, 0), (1, 0)], [(0, 1), (1, 1)], [(2, 0), (3, 0)], [(2, 1), (3, 1)]].

cross_partition

Nur partitionsübergreifende Kommunikation erfolgt innerhalb jeder Prozessgruppe. Dieses verwendet partition_groups, eine Liste mit Partitions-IDs, berechnet ein kartesisches Produkt von partition_groups nach replica_ids. partition_groups muss eindeutige Elemente enthalten und alle partition_ids abdecken. Formal mit der Python-Syntax:

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

Beispiel: Für partition_groups = [[0, 1]] und num_replicas = 4: cross_partition wird Folgendes produzieren: [[(0, 0), (0, 1)], [(1, 0), (1, 1)], [(2, 0), (2, 1)], [(3, 0), (3, 1)]].

cross_replica_and_partition

Sowohl replikat- als auch partitionsübergreifende Kommunikation Prozessgruppe. Diese Strategie benötigt replica_groups – eine Liste mit Replikat-IDs und berechnet kartesische Produkte jeder replica_group durch partition_ids replica_groups muss eindeutige Elemente aufweisen und alle replica_ids. Formal mit der Python-Syntax:

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

Beispiel: Für replica_groups = [[0, 1], [2, 3]] und num_partitions = 2: cross_replica_and_partition wird Folgendes produzieren: [[(0, 0), (1, 0), (0, 1), (1, 1)], [(2, 0), (3, 0), (2, 1), (3, 1)]].

flattened_ids

Diese Strategie benötigt flattened_id_groups, also eine Liste der vereinfachten Listen. Prozess-IDs im Format replica_id * num_partitions + partition_id – und in Prozess-IDs. flattened_id_groups muss eindeutige Elemente enthalten und decken alle process_ids ab. Formal mit der Python-Syntax:

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

Beispiel: Für flattened_id_groups = [[0, 1, 2, 3], [4, 5, 6, 7]]: num_replicas = 4 und num_partitions = 2, flattened_ids werden [[(0, 0), (0, 1), (1, 0), (1, 1)], [(2, 0), (2, 1), (3, 0), (3, 1)]]

Genauigkeit

Derzeit gibt StableHLO keine Garantien für numerische Genauigkeit. Dies kann sich aber in Zukunft ändern. (#1156)

Ausführungssemantik eines quantisierten Vorgangs

Die Interpretation quantisierter StableHLO-Operationen kann je nach Hardwareanforderungen und -funktionen. Einige Hardwarekomponenten quantisierte Operationen mit einem „dequantize, perform floatingpoint“ und schließlich quantisieren“ . Andere führen möglicherweise die gesamte mit einer ganzzahligen Arithmetik berechnet. Folglich ist die Auslegung des Begriffs quantisierten StableHLO-Operationen ausschließlich durch die spezifische Implementierung. Die Interpretation der hybriden Quantisierung (#1575) muss auf die in der Spezifikation vorgeschrieben ist (über 1792).

Fehler

StableHLO-Programme werden durch eine Reihe von für einzelne Vorgänge, bei denen viele Fehlerklassen vor der Ausführung ausgeschlossen sind. Fehlerbedingungen sind jedoch weiterhin möglich, z.B. ganzzahlige Überläufe, oder außerhalb des Netzwerkzugriffs. Sofern nicht ausdrücklich anders angegeben, sind all diese Fehler Dies kann zu einem implementierungsdefinierten Verhalten führen. Dies kann sich jedoch Future (#1157)

Gleitkommaausnahmen

Gleitkommaausnahmen in StableHLO-Programmen ein klar definiertes Verhalten haben. Vorgänge, die zu durch den IEEE-754-Standard (ungültiger Vorgang, Division durch Null, Überlauf, Unterlauf oder ungenaue Ausnahmen), erzeugen Standardergebnisse (wie im Standard definiert) und ohne das entsprechende Status-Flag zu setzen. ähnlich wie raiseNoFlag-Ausnahmebehandlung vom Standard. Ausnahmen für nicht standardmäßige Operationen (z.B. komplexe arithmetische und bestimmte transzendentale Funktionen) Implementierung definiert.

Formen stimmen nicht überein

StableHLO unterstützt dynamisch geformte Tensoren. Die Formen müssen jedoch Andernfalls ist das Verhalten nicht definiert. StableHLO weist nicht explizit eine Operation bereitstellen, die geltend machen kann, dass ein Tensor zur Laufzeit eine bestimmte Form hat. Für die Generierung des korrekten Codes ist der Ersteller verantwortlich.

Das folgende Programm ist als Beispiel gültig. Während der Laufzeit Die genauen Formen von %arg0 und %arg1 müssen identisch sein. Andernfalls Verhalten des Programms ist nicht definiert:

func.func @foo(%arg0: tensor<?xi32>, %arg1: tensor<?xi32>) -> tensor<?xi32> {
    %0 = stablehlo.add %arg0, %arg1 : tensor<?xi32>
    return %0 : tensor<?xi32>
}

Notation

Zur Beschreibung der Syntax wird in diesem Dokument die modifizierte ISO-Variante von EBNF verwendet. Syntax (ISO/IEC 14977:1996, Wikipedia) mit zwei Änderungen: 1) Regeln werden mit ::= statt mit = definiert,

2) Die Verkettung wird durch eine Gegenüberstellung statt mit , ausgedrückt.

Zur Beschreibung der Semantik (z.B. in den Abschnitten "Typen", "Konstanten" und "Ops") Wir verwenden Formeln, die auf der um Unterstützung erweiterten Python-Syntax basieren. für prägnante Array-Operationen, wie unten beschrieben. Das funktioniert gut für kleine Code-Snippets. In seltenen Fällen können auch größere verwenden wir einfache Python-Syntax, die immer explizit eingeführt wird.

Formeln

Sehen wir uns die Funktionsweise von Formeln anhand eines Beispiels aus dem dot_general an. Spezifikation zu ändern. Eine der Einschränkungen für diesen Vorgang sieht so aus: dim(lhs, lhs_batching_dimensions...) = dim(rhs, rhs_batching_dimensions...)

Die in dieser Formel verwendeten Namen stammen aus zwei Quellen: 1) globalen Funktionen, z.B. dim, 2) Mitgliederdefinitionen des entsprechenden Programmelements, d.h. Eingaben für lhs, lhs_batching_dimensions, rhs und rhs_batching_dimensions unter „Eingaben“ Abschnitt von dot_general.

Wie bereits erwähnt, basiert die Syntax dieser Formel auf Python, prägnanten Erweiterungen. Um die Formel zu verstehen, transformieren wir in einfache Python-Syntax umwandeln.

A) In diesen Formeln verwenden wir =, um Gleichheit darzustellen. Der erste Schritt um die Python-Syntax zu erhalten, indem Sie = durch == ersetzen: dim(lhs, lhs_batching_dimensions...) == dim(rhs, rhs_batching_dimensions...)

B) Außerdem unterstützen diese Formeln Ellipsen (...), die skalare Ausdrücke umwandeln in Tensor-Ausdrücke umgewandelt. Kurz gesagt bedeutet f(xs...) in etwa „für jede die skalare x im Tensor xs, berechnen eine skalare f(x) und geben dann alle diese skalaren Ergebnisse zusammen als Tensorergebnis“. Bei der einfachen Python-Syntax verwandelt sich unsere Beispielformel in: [dim(lhs, dim1) for dim1 in lhs_batching_dimensions] == [dim(rhs, dim2) for dim2 in rhs_batching_dimensions]

Durch Auslassungspunkte ist es oft möglich, Arbeiten auf der Ebene individuelle Skalare. In einigen kniffligen Fällen können jedoch untergeordnete halbinformelle Syntax kann wie in der start_indices[bi0, ..., :, ..., biN]-Formel verwendet werden aus der Spezifikation gather. Was die Präzision angeht, einen genauen Formalismus für die Übersetzung solcher Syntax in einfaches Python, in hofft, dass sie immer noch intuitiv für jeden Fall verständlich ist. Bitte teilen Sie uns mit, wenn bestimmte Formeln undurchsichtig erscheinen. Wir werden dann versuchen, sie zu verbessern.

Außerdem werden Sie feststellen, dass in Formeln Auslassungspunkte zum Erweitern aller Arten von Listen verwendet werden. einschließlich Tensoren, Listen von Tensoren (die sich beispielsweise aus einer variadischen Anzahl der Tensoren) usw. Dies ist ein weiterer Bereich, in dem wir keine exakte Formalismus (z.B. sind Listen nicht einmal Teil des StableHLO-Typsystems) und sondern auf intuitive Verständlichkeit.

C) Das letzte wichtige notationale Instrument, das wir einsetzen, ist die Broadcasting. Zwar unterstützt das StableHLO-Opset kein implizites Broadcasting, die Formeln auch tun, auch im Dienst der Präzision. Kurz gesagt: Wenn ein Skalar in einem Kontext verwendet wird, in dem ein Tensor erwartet wird, die erwartete Form hat.

Hier ist eine weitere Einschränkung, um mit dem dot_general-Beispiel fortzufahren: 0 <= lhs_batching_dimensions < rank(lhs). Gemäß der Definition in den dot_general ist lhs_batching_dimensions ein Tensor, aber sowohl 0 als auch rank(lhs) sind Skalare. Nachdem wir implizites Broadcasting angewendet haben, [0, ..., 0] <= lhs_batching_dimensions < [rank(lhs), ..., rank(lhs)] werden.

Bei Anwendung auf einen bestimmten dot_general-Vorgang wird diese Formel mit einem booleschen Tensor auszuwerten. Wenn Formeln als Einschränkungen verwendet werden, gilt, wenn die Formel entweder als true oder als einen Tensor ausgewertet wird, enthält nur true-Elemente.

Namen

In Formeln umfasst der lexikalische Anwendungsbereich: 1) globale Funktionen, 2) Mitgliederdefinitionen,

3) lokale Definitionen. Nachfolgend finden Sie eine Liste der globalen Funktionen. Die Liste von Elementdefinitionen hängt von dem Programmelement ab, das die Notation ist. angewendet auf:

  • Bei Vorgängen enthalten Mitgliederdefinitionen die in „Eingaben“ eingeführten Namen. und „Ausgaben“ .
  • Für alles andere beinhalten die Mitgliedsdefinitionen die strukturellen Teile des Programmelement, das nach den entsprechenden EBNF-Nicht-Terminals benannt ist. Die meisten werden die Namen dieser Bauteile durch Umwandeln des Namen der nicht-terminalen Begriffe in Snake-Case-Schreibweise (z.B. IntegerLiteral => integer_literal), aber Namen werden dabei manchmal abgekürzt (z.B. QuantizationStorageType => storage_type). In diesem Fall lauten die Namen explizit ähnlich wie "Eingaben" / „Ausgaben“ Abschnitte in Betrieb Spezifikationen.
  • Darüber hinaus enthalten Mitgliederdefinitionen immer self, um auf die entsprechenden Programmelement.

Werte

Beim Auswerten von Formeln funktionieren sie mit den folgenden Arten von Werten: 1) Value (tatsächliche Werte, z.B. dense<[[1, 2], [3, 4]]> : tensor<2x2xi32>; kennen sie immer die Art) 2) Placeholder (zukünftige Werte, z.B. lhs, rhs oder result; ihre tatsächlichen Werte noch nicht bekannt sind, nur ihre Typen sind bekannt), 3) Type (Typen, wie im Abschnitt "Typen" definiert), 4) Function (globale Funktionen, wie im Abschnitt "Funktionen" definiert).

Je nach Kontext können sich Namen auf unterschiedliche Werte beziehen. Mehr insbesondere die Semantik, für Vorgänge (und Entsprechungen für andere Programme) Elemente) definiert die Laufzeitlogik, sodass alle Eingaben als Value verfügbar sind. Die „Einschränkungen“ für Vorgänge (und Entsprechungen) definiert „Compile-Zeit“ Logik, d.h. etwas, das in der Regel vor der Laufzeit ausgeführt wird, Daher sind nur konstante Eingaben als Value verfügbar, während andere Eingaben nur als Placeholder verfügbar.

Namen In „Semantics“ Gehen Sie unter „Einschränkungen“
Globale Funktionen Function Function
Konstante Eingaben Value Value
Nicht konstante Eingaben Value Placeholder
Ausgaben Value Placeholder
Lokale Definitionen Hängt von der Definition ab Hängt von der Definition ab

Hier ein Beispiel für einen transpose-Vorgang:

%result = "stablehlo.transpose"(%operand) {
  permutation = dense<[2, 1, 0]> : tensor<3xi64>
} : (tensor<2x3x2xi32>) -> tensor<2x3x2xi32>

Bei diesem Vorgang ist permutation eine Konstante und steht daher als Value zur Verfügung. sowohl in Bezug auf Semantik als auch auf Einschränkungen. Im Gegensatz dazu sind operand und result in der Semantik als Value verfügbar, aber nur als Placeholder in Einschränkungen.

Funktionen

Konstruktion von Typen

Es gibt keine Funktionen, die zum Erstellen von Typen verwendet werden können. Stattdessen haben wir direkt Typsyntax verwendet, da sie in der Regel kürzer ist. Beispiel: (tensor<E>, tensor<E>) -> (tensor<E>) statt function_type( [tensor_type([], E), tensor_type([], E)], [tensor_type([], E)]).

Funktionen für Typen

  • element_type wird für Tensortypen und quantisierte Tensortypen definiert. gibt TensorElementType bzw. QuantizedTensorElementType zurück. Teil des entsprechenden TensorType- oder QuantizedTensorType-Elements.
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 ist eine Verknüpfung für is_quantized(x) and quantization_dimension(x) is not None.

  • is_per_tensor_quantized(x: Value | Placeholder | Type) -> Value ist ein Tastenkombination für is_quantized(x) and quantization_dimension(x) is None.

  • is_promotable(x: Type, y: Type) -> bool prüft, ob der Typ x hochgestuft werden kann um y einzugeben. Wenn x und y den Wert QuantizedTensorElementType haben, wird das Angebot wird nur auf storage_type angewendet. Diese spezielle Angebotsversion ist die aktuell im Zusammenhang mit der Berechnung der Reduktion verwendet werden (siehe RFC 2018.

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 ist eine Verknüpfung für is_quantized_tensor_element_type(x).

  • is_type_name(x: Value | Placeholder | Type) -> Value Für alle verfügbar Typen. is_float(x) gibt beispielsweise true zurück, wenn x eine FloatType ist. Wenn x ein Wert oder Platzhalter ist, ist diese Funktion ein Kurzbefehl für is_type_name(type(x)).

  • max_value(x: Type) -> Value gibt den Maximalwert eines TensorElementType. Wenn x kein TensorElementType ist, wird None zurückgegeben.

  • min_value(x: Type) -> Value gibt den kleinstmöglichen Wert eines TensorElementType. Wenn x kein TensorElementType ist, wird None zurückgegeben.

  • member_name(x: Value | Placeholder | Type) -> Any Für alle Mitglieder verfügbar Definitionen member_name aller Typen. Beispiel: tensor_element_type(x) gibt den TensorElementType-Teil eines entsprechenden TensorType zurück. Wenn x ein Wert oder Platzhalter ist, ist diese Funktion ein Kurzbefehl für member_name(type(x)). Wenn x kein Typ mit einem geeigneten Mitglied ist, oder für einen Wert oder Platzhalter eines solchen Typs ist, gibt None zurück.

  • is_empty_algorithm(*args: Type) prüft, ob alle Punktalgorithmusfelder festgelegt sind an None. Dies ist erforderlich, da bei Punktalgorithmen die Implementierung definiert ist. Standardverhalten. Daher wäre es falsch, einen Standardwert festzulegen.

Konstruktion von Werten

  • operation_name(*xs: Value | Type) -> Value Für alle Vorgänge verfügbar. Beispiel: add(lhs, rhs) nimmt die beiden Tensorwerte lhs und rhs an. gibt das Ergebnis der Auswertung der add-Operation mit diesen Eingaben zurück. Bei einigen Vorgängen, z.B. broadcast_in_dim, sind die Ausgabetypen „last-bearing“, d.h. erforderlich, um einen Vorgang auszuwerten. In diesem Fall wird die Funktion verwendet diese Typen als Argumente.

Funktionen für Werte

  • Alle Operatoren und Funktionen von Python sind verfügbar. Beispiel: beides abo und Slicen Notationen aus Python stehen für die Indexierung in Tensoren, quantisierte Tensoren, zur Verfügung. und Tupeln.

  • to_destination_type(x: Value, destination_type: Type) -> Value ist definiert am Tensoren und gibt den konvertierten Wert von x basierend auf type(x) und destination_type so:

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)

Es wird im Vorfeld über das Zusammenführen von convert, uniform_quantize und uniform_dequantize-Vorgänge (#1576) Nach der Zusammenführung benötigen wir die obige Funktion nicht und können den Vorgangsnamen verwenden. für convert.

  • is_nan(x: Value) -> Value ist für Tensoren definiert und gibt true zurück, wenn Alle Elemente von x sind NaN oder false. Wenn x kein Tensor ist, gibt None zurück.

  • is_sorted(x: Value) -> Value ist für Tensoren definiert und gibt true zurück, wenn -Elemente von x in aufsteigender Reihenfolge im Hinblick auf die aufsteigende Reihenfolge lexikografische Reihenfolge der Indexe oder false auf andere Weise. Wenn x kein Tensor, gibt None zurück.

  • is_unique(x: Value) -> Value ist für Tensoren definiert und gibt true zurück, wenn x hat keine doppelten Elemente oder sonst false. Wenn x kein Tensor ist, gibt None zurück.

  • member_name(x: Value) -> Any ist für alle Mitgliederdefinitionen definiert member_name aller Werte. Beispiel: real_part(x) gibt den Wert RealPart zurück. Teil eines entsprechenden ComplexConstant. Wenn x kein Wert mit einem entsprechendes Mitglied, gibt None zurück.

  • same(x: Value) -> Value ist für Tensoren definiert und gibt true zurück, wenn Elemente von x sind alle gleich einander oder false anderenfalls. Wenn der Tensor enthält keine Elemente, wird also als "alle gleich einander" gezählt, d.h. gibt true zurück. Wenn x kein Tensor ist, wird None zurückgegeben.

  • split(x: Value, num_results: Value, axis: Value) -> Value ist definiert am Tensoren und gibt num_results-Segmente von x entlang der axis-Achse zurück. Wenn x kein Tensor oder dim(x, axis) % num_results != 0 ist, wird None zurückgegeben.

  • is_defined_in_parent_scope(x: Value) -> Value ist anhand von Strings definiert und gibt true zurück, wenn x der Name einer Funktion ist, die im selben Bereich definiert ist. als übergeordnete Funktion des entsprechenden Vorgangs ein.

  • is_namespaced_op_name(x: Value) -> Value ist für Strings definiert und gibt true, wenn x ein gültiger Vorgangsname ist, d. h., er berücksichtigt die folgende reguläre Ausdruck: [a-zA-Z][a-zA-Z0-9_]*([.][a-zA-Z0-9_$]+)+

Formberechnungen

  • axes(x: Value | Placeholder | Type) -> Value ist eine Verknüpfung für range(rank(x)).

  • dim(x: Value | Placeholder | Type, axis: Value) -> Value ist eine Verknüpfung für shape(x)[axis].

  • dims(x: Value | Placeholder | Type, axes: List) -> List ist eine Verknüpfung für list(map(lambda axis: dim(x, axis), axes)).

  • index_space(x: Value | Placeholder | Type) -> Value ist auf Tensoren definiert und gibt size(x)-Indizes für die entsprechende TensorType zurück, sortiert in aufsteigende lexikografische Reihenfolge, z.B. [0, ..., 0], [0, ..., 1], ..., shape(x) - 1 Wenn x kein Tensortyp, ein quantisierter Tensortyp oder ein Wert ist oder ein Platzhalter eines dieser Typen gibt None zurück.

  • rank(x: Value | Placeholder | Type) -> Value ist eine Verknüpfung für size(shape(x)).

  • shape(x: Value | Placeholder | Type) -> Value ist definiert in den Funktionen zu Typen“ Abschnitt über member_name.

  • size(x: Value | Placeholder | Type) -> Value ist eine Verknüpfung für reduce(lambda x, y: x * y, shape(x)).

Quantisierungsberechnungen

  • def baseline_element_type(x: Value | Placeholder | Type) -> Type ist ein Tastenkombination für element_type(baseline_type(x)).

  • baseline_type wird für Tensortypen und quantisierte Tensortypen definiert. wandelt sie in eine „Baseline“ um, d.h. einen Typ mit der gleichen Form, aber mit dem Quantisierungsparameter des Elementtyps auf Standardwerte zurückgesetzt. Dies ist als praktischer Trick verwendet, um sowohl Tensor- als auch quantisierte Tensortypen zu vergleichen was häufig erforderlich ist. Bei quantisierten Typen wird dadurch Typen ohne Quantisierungsparameter, d. h. shape, vergleichen storage_type, expressed_type, storage_min, storage_max und quantization_dimension (für pro-Achse quantisierten Typ) müssen alle übereinstimmen, aber scales und zero points können abweichen.

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 wird für quantisierte Tensortypen definiert und wandelt sie in Gleitkomma-Tensortypen. Dies geschieht durch das Konvertieren quantisierter Elemente die ganzzahlige Werte des Speichertyps in entsprechende Gleitkommawerte des ausgedrückten Typs unter Verwendung des Nullpunkts und der Skala die mit dem quantisierten Elementtyp verknüpft sind.
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 wird für Gleitkomma-Tensortypen definiert und wandelt sie in quantisierten Tensortypen spezifiziert. Dies geschieht durch die Umwandlung von Gleitkommawerten des ausgedrückten Typs in entsprechende Ganzzahlwerte des Speichertyps umwandeln mit dem Nullpunkt und der Skala des quantisierten Elementtyps.
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)
  • Mit dequantize_op_quantize werden elementweise Berechnungen für quantisierten Tensoren. Es dequantisiert, d.h. wandelt quantisierte Elemente in ihre Ausgedrückten Typen, führt dann eine Operation durch und quantisiert, d.h. die Ergebnisse in ihre Speichertypen. Derzeit kann diese Funktion nur für die Quantisierung pro Tensor. Die Quantisierung pro Achse ist in Arbeit (#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)
  • Mit hybrid_dequantize_then_op wird die Nur-Gewichtung-Quantisierung für Hybridbetrieb, der LHs in Gleitkommazahlen und rhs in quantisierten Typen akzeptiert. Es dequantisiert quantisierte Eingaben in ihre expliziten Typen und führt eine Berechnung durch als Gleitkommazahl. Elementtyp des Gleitkommazahl-Tensors und Ausdruckstyp der quantisierten rhs Tensor identisch sein.
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))

Rasterberechnungen

  • cross_partition(replica_groups: Value) -> Value "cross_Replikat" ansehen oben.

  • cross_replica(replica_groups: Value) -> Value "cross_Replikat" ansehen oben.

  • cross_replica_and_partition(replica_groups: Value) -> Value Weitere Informationen finden Sie in der &quot;cross_replica_and_partition&quot; oben.

  • flattened_ids(replica_groups: Value) -> Value Siehe den Abschnitt "Flattened_ids" oben.

Dynamik

StableHLO-Werte können dynamische Dimensionsgrößen haben, z.B. tensor<?xi64> StableHLO-Werte dürfen jedoch keine dynamische Anzahl von Dimensionen (nicht eingestuft) haben Dynamik, z.B. tensor<*xi64>. Operanden und Ergebnisse dürfen dynamische Elemente verwenden auch wenn es Beschränkungen gibt. Einschränkungen werden wenn möglich statisch überprüft. Andernfalls werden sie auf Laufzeit und Abweichungen führen zu nicht definiertem Verhalten. Siehe Beispiele unten.

Formenabweichungen bei unären elementweisen Vorgängen

Sehen Sie sich das folgende Spielzeugprogramm an:

func.func @foo(%arg0: tensor<?xf64>) {
  %0 = stablehlo.abs %arg0 : (tensor<?xf64>) -> tensor<2xf64>
  return
}

Ein solches Programm ist ungewöhnlich, da es nicht üblich ist, die Form des nicht aber die Form der Eingabe. Trotzdem ist dies ein gültiger StableHLO-Wert, . Es ist nicht möglich, den abs-Vorgang in diesem da die genaue Form des Operanden unbekannt ist. Die Formen sind jedoch sind sicherlich kompatibel, was statisch überprüft werden kann: ? könnte sich zur Laufzeit auf 2 gesetzt und es gäbe kein Problem. ? könnte jedoch auch eine andere Ganzzahl, wobei das Verhalten nicht definiert ist.

Wenn eine Dimensionsgröße im Ergebnis dynamisch ist, kann kein undefiniertes Verhalten. Tatsächlich gibt es kein „erwartetes“ kann also kein nicht übereinstimmend.

Nicht übereinstimmende Formen bei binären elementweisen Operationen

Sehen Sie sich das folgende Spielzeugprogramm an:

func.func @foo(%arg0: tensor<?xf64>, %arg1: tensor<?xf64>) {
  %0 = stablehlo.add %arg0, %arg0 : (tensor<?xf64>, tensor<?xf64>) -> tensor<?xf64>
  return
}

Bei binären elementweisen Operationen sind die Formen der Eingaben Ergebnis muss zur Laufzeit übereinstimmen. Zum Zeitpunkt der Kompilierung müssen statische Dimensionen gleich sein, sonst müssen sie nur kompatibel sein. Wenn irgendeine Dimension in den Eingaben dynamisch ist, sind möglicherweise nicht definierte Dimensionen definiert da die dynamische Größe unter Umständen nicht mit der Größe im anderen Operanden (statisch oder dynamisch) ein. Wenn alle Eingaben statisch ist, spielt es keine Rolle, ob das Ergebnis dynamisch ist oder nicht: statisch. werden bekannte Dimensionen statisch überprüft, dynamische Dimensionen nicht Einschränkungen gelten.

Nicht übereinstimmende Formen bei Vorgängen, die ihre Ausgabeform als Operanden annehmen

Sehen Sie sich das folgende Spielzeugprogramm an:

func.func @foo(%arg0: tensor<2xi32>) {
  %0 = stablehlo.dynamic_iota %arg0, dim = 0 : (tensor<2xi32>) -> tensor<3x4xi64>
  return
}

Die Werte im Formoperanden müssen zur Laufzeit der Form des Ergebnisses entsprechen. Andernfalls ist das Verhalten nicht definiert. Das heißt, zur Laufzeit muss %arg0 einen Wert von dense<[3, 4]> : tensor<2xi32> Wenn der Formoperanden konstant ist, wird dies statisch überprüft werden kann. Wenn die Ergebnisform vollständig dynamisch ist, darf nicht abweichen.