StabilerHLO-Dolmetscher

Das Hauptziel des StableHLO-Interpreters ist es, Implementierung entsprechend der Semantik des StableHLO-Opsets Spezifikation zu ändern. Sekundäres Ziel ist es, bei der Implementierung genau zu beobachten, die Lesbarkeit gegenüber der Leistung bevorzugt, um für mehr Klarheit zu sorgen. mit der Semantik selbst der verbundensten Vorgänge wie Convolution, Gather/Scatter und DotGeneral.

Derzeit unterstützt OpenXLA die Interpretation von 91 von 96 Spezifikationen StableHLO-Vorgänge Für die verbleibenden drei Vorgänge (FftOp, RngOp, RngBitGeneratorOp) wie ihre Semantik in spec.md und haben erste Untersuchungen zum weiteren Vorgehen durchgeführt (siehe status.md finden Sie eine vollständige Liste der Vorgänge mit dem aktuellen Status. Diese finalen werden bei Bedarf in der Community implementiert.

Umfang

Wir haben das StableHLO-Opset in 11 Kategorien mit 118 Operationen in (siehe Anhang). Referenzimplementierung In Workstream wird die Arbeit an der Implementierung eines Dolmetschers organisiert. für 100% der StableHLO-Vorgänge gemäß Definition in der StableHLO-Spezifikation. Wir sind Sie planen, alle oder fast alle Arbeiten in diesem Workstream in StableHLO abzuschließen. Version 1.0. Von den 96 Vorgängen, die derzeit eine Spezifikation haben, können wir 91 Vorgänge durch OpenXLA (siehe Sonderfälle für die übrigen fünf Fälle).

Spezifikation

Die wichtigste Voraussetzung für den Dolmetscher ist eine direkte Korrespondenz mit dem Spezifikation. Die Spezifikation ermöglicht die Standardisierung des Interpreters für ähnliche Vorgänge, zu einer modularen, hochwertigen Implementierung des Dolmetschers führen.

Sonderfälle

Sonstige

Diese Kategorie enthält zerlegbare Operationen, deren Zukunft noch unklar ist. Es sind drei vordefinierte Operationen in dieser Kategorie, die vom Interpreter nicht unterstützt werden. für den Moment:

  • FftOp
  • RngOp
  • RngBitGeneratorOp

FftOp ist als „Sonstiges“ kategorisiert, aber im Gegensatz zu anderen Vorgängen in dieser Kategorie Dieser Vorgang hat keinen Erweiterungs-Pass. Die Unterstützung in StableHLO ist ein In Arbeit.

RngOp und RngBitGeneratorOp können in MHLO-Vorgänge zerlegt werden, aber der der Zerlegung führt zu einem XlaRngGetAndUpdateStateOp, das ein MHLO-spezifisches Op. Eine unterstützende Interpretation dieser beiden Vorgänge ist WIP.

Das Tool zum Umwandeln der verbleibenden Operationen in dieser Kategorie in StableHLO-Operationen, die Der Interpreter befindet sich in hlo_expand_main.cc.

Nicht in HLO

Abgesehen von den spezifizierten Operationen besteht diese Kategorie aus acht nicht spezifizierten Operationen (siehe StableHLO Ops Categories), die in Zukunft aus StableHLO verschoben. Für die meisten dieser Vorgänge sind Karten/Tickets in Mhlo nach in StableHLO-Äquivalente umwandeln.

Das Tool zum Umwandeln der verbleibenden Vorgänge in dieser Kategorie in entsprechende StableHLO-Vorgänge die vom Interpreter unterstützt werden, befindet sich in mlir-hlo-opt.cc.

Quantisierung

Interpreter-Unterstützung für stablehlo.constant-Vorgänge mit quantisiertem Typ ist nicht unterstützt und erfasst über #1691.

Verwendungsanleitung

Referenzinterpreter erstellen

Der Interpreter kann über Bazel oder CMake (bevorzugt) erstellt und getestet werden. Vollständige finden Sie unter README.md.

Das ist z. B. der Fall.

bazel build //...

CMake:

mkdir -p build && cd build

cmake .. -GNinja \
  -DLLVM_ENABLE_LLD="$LLVM_ENABLE_LLD" \
  -DCMAKE_BUILD_TYPE=Release \
  -DLLVM_ENABLE_ASSERTIONS=On \
  -DMLIR_DIR=${PWD}/../llvm-build/lib/cmake/mlir

Zum Ausführen des Interpreters gibt es ein Übersetzungstool zum Interpretieren von StableHLO-Programmen. die in MLIR geschrieben sind.

stablehlo-translate --interpret <path/to/program>

Der Dolmetscherdialekt

Der Dialekt Interpreter enthält verschiedene Dienstprogrammvorgänge im Zusammenhang mit dem Dolmetscher. Konkret enthält die interpreter.run_parallel (siehe InterpreterOps.td für Vorgangssemantik und Beispielverwendung) op ermöglicht die Interpretation von Verteilungsvorgängen und mehr werden je nach Bedarf ergänzt.

Der Prüfdialekt

Der Dialekt Check wird verwendet, um die Interpreter-Laufzeitwerte mit den erwarteten Werten zu vergleichen Werte. StableHLO-Programmausgaben können über verschiedene Prüfvorgänge getestet werden (siehe CheckOps.td für die Semantik von Operationen und die Beispielverwendung).

Testprogramme schreiben

Wir verwenden das lit-Tool von LLVM, Mit der generierten Datei vergleichen, um mit der Ausgabe des Interpreters zu vergleichen (siehe stablehlo/tests/interpret) z. B. Tests).

AddOp wird getestet (Beispiel aus interpret_add.mlir):

// RUN: stablehlo-translate --interpret %s

func.func @add_op_scalar() {
  %0 = stablehlo.constant dense<2> : tensor<i4>
  %1 = stablehlo.constant dense<3> : tensor<i4>
  %2 = stablehlo.add %0, %1 : tensor<i4>
  check.expect_eq_const %2, dense<5> : tensor<i4>
  func.return
}

Für Testvorgänge in der Kategorie "Verteilung" muss die Ausführung über den interpreter.run_parallel-Dienstprogrammvorgang

AllReduceOp wird getestet (Beispiel aus all_reduce.mlir):

// RUN: stablehlo-translate --interpret %s

module @cross_replica {
  func.func public @all_reduce(%operand : tensor<4xi64>) -> tensor<4xi64> {
    %result = "stablehlo.all_reduce"(%operand) ({
      ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
        %0 = stablehlo.add %arg0, %arg1 : tensor<i64>
        stablehlo.return %0 : tensor<i64>
    }) {
      replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>,
      channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
    } : (tensor<4xi64>) -> tensor<4xi64>
    return %result : tensor<4xi64>
  }
  func.func public @main() {
    %inputs0 = stablehlo.constant dense<[1, 2, 3, 4]> : tensor<4xi64>
    %inputs1 = stablehlo.constant dense<[5, 6, 7, 8]> : tensor<4xi64>
    %results:2 = "interpreter.run_parallel"(%inputs0, %inputs1) {
      programs=[[@all_reduce], [@all_reduce]]
    } : (tensor<4xi64>, tensor<4xi64>) -> (tensor<4xi64>, tensor<4xi64>)
    check.expect_eq_const %results#0, dense<[6, 8, 10, 12]> : tensor<4xi64>
    check.expect_eq_const %results#1, dense<[6, 8, 10, 12]> : tensor<4xi64>
    func.return
  }
}

Fehlerbehebung bei StableHLO

Nach den StableHLO-Build-Schritten werden die StableHLO-Binärdateien für Tools in stablehlo/tools sollte sich in /build/bin befinden. Gängige Debugging-Tools wie Mit GDB kann der Code schrittweise durchlaufen werden:

gdb --args ./build/bin/stablehlo-translate -allow-unregistered-dialect --interpret ./stablehlo/tests/interpret/<test>.mlir

Anhang

Verschiedene Vorgänge konvertieren

# batch_norm_grad
hlo-expand --batch_norm_grad_expander <path/to/hlo_module>

# batch_norm_inference
hlo-expand --batch_norm_inference_expander <path/to/hlo_module>

# batch_norm_training
hlo-expand --batch_norm_training_expander <path/to/hlo_module>

# cholesky
hlo-expand --cholesky_expander <path/to/hlo_module>

# constant
# Supported in StableHLO interpreter.

# fft
# TBD

# iota
# Supported in StableHLO interpreter.

# rng
# TBD

# rng_bit_generator
# TBD

# triangular_solve
hlo-expand --triangular_solve_expander <path/to/hlo_module>

Konvertierung nicht in HLO-Vorgänge

# broadcast
mlir-hlo-opt -mhlo-legalize-broadcast-to-broadcast-in-dim <path/to/input>

# create_token
mlir-hlo-opt -mhlo-legalize-create-token-to-after-all <path/to/input>

# cross-replica-sum
mlir-hlo-opt -mhlo-legalize-cross-replica-sum-to-all-reduce <path/to/input>

# dot
mlir-hlo-opt -mhlo-legalize-dot-to-dot-general <path/to/input>

# einsum
mlir-hlo-opt -mhlo-legalize-einsum-to-dot-general <path/to/input>

# torch_index_select
mlir-hlo-opt -mhlo-legalize-torch-index-select-to-gather <path/to/input>

# unary_einsum
mlir-hlo-opt --canonicalize -mhlo-legalize-einsum-to-dot-general <path/to/input>

StableHLO Ops-Kategorien

Kategorien Eselsbrücke Gesamt
119
Kontrollfluss nach_all, Fall, wenn, Optimierungsbarriere, während 5
Datenverschiebung Broadcast_in_dim, verketten, dynamic_slice, dynamic_update_slice, erfassen, auffüllen, umformen, umkehren, streuen, schneiden, sortieren, transponieren 12
Vertrieb all_gather, all_reduce, all_to_all, collective_permute, infeed, outfeed, partition_id, recv, reduce_scatter, reseller_id, senden 11
Dynamik dynamic_broadcast_in_dim, dynamic_conv, dynamic_gather, dynamic_iota, dynamic_pad, dynamic_reshape, get_dimension_size, real_dynamic_slice, set_dimension_size 9
Elementwise abs, add, and, atan2, bitcast_convert, cbrt, ceil, clamp, compare, complex, convert, cosine, count_leading_zeros, divide, exponential, exponential_minus_one, floor, imag, is_finite, log, log_plus_one, logistic, map, maximum, minimum, multiply, negate, not, or, popcnt, power, real, reduce_precision, remainder, round_nearest_afz, round_nearest_even, rsqrt, select, shift_left, shift_right_arithmetic, shift_right_logical, sign, sine, sqrt, subtract, tan, tanh, xor 48
Erweiterbarkeit custom_call, get_tuple_element, Tupel 3
Sonstige Batch_norm_grad, Batch_norm_inference, Batch_norm_training, Cholesky, Konstante, fft, iota, rng, rng_bit_generator, triangular_solve 10
Modularität aufrufen, Funktion, Modul, Rückgabe 4
Nicht in HLO Broadcast, create_token, Cross-Replikat-Summe, Punkt, einsum, torch_index_select, unary_einsum 8
Quantisierung uniform_dequantize, uniform_quantize 2
Reduzierung Faltung, Punkt_Allgemein, Verkleinern, Fensterverkleinern, Auswählen_und_Streuung 5