VHLO-Dialekt

Was ist der VHLO-Dialekt?

Der VHLO-Dialekt (versioned StableHLO) wird für die Serialisierung und Stabilität verwendet. Sie bietet einen Snapshot des StableHLO-Dialekts zu einem bestimmten Zeitpunkt, indem einzelne Programmelemente versioniert werden.

VHLO ist ein nur zum Hinzufügen einzelner Dialekt mit versionierten Vorgängen, Typen und Attributen. Das bedeutet, dass ein Feature, das dem Dialekt einmal hinzugefügt wurde, in keiner Weise mehr geändert werden kann, die sich auf die Semantik auswirkt.

Alle Änderungen an einem Vorgang, Typ oder Attribut erfordern eine neue Version, die dem Dialekt hinzugefügt wird. Wenn beispielsweise eine hypothetische my_op zu StableHLO in 0.9.0 hinzugefügt, aber in 0.11.0 geändert wurde, ergibt sich in VHLO Folgendes:

// This represents the StableHLO version of the op from 0.9.0 -> 0.10.0
// Both the lower and the upper bound of versions are inclusive
def VHLO_MyOpV1 : VHLO_Op<"my_op_v1", "0.9.0", "0.10.0"> {
  let arguments = (ins
    VHLO_AnyType:$operand
  );
  let results = (outs VHLO_AnyType:$result);
}

// This represents the StableHLO version of the op from 0.11.0 -> current
def VHLO_MyOpV2 : VHLO_Op<"my_op_v2", "0.11.0", "current"> {
  let arguments = (ins
    VHLO_AnyType:$operand,
    VHLO_AnyAttr:$attr  // New attribute added to StableHLO in 0.11.0
  );
  let results = (outs VHLO_AnyType:$result);
}

Der StableHLO-Dialekt hat nur die neueste Version des Vorgangs. Im laufenden Beispiel hätte der StableHLO-Dialekt bei v0.11.0 nur den StableHLO_MyOp mit operand und attr, während VHLO jede Phase der Entwicklung des Vorgangs erfasst.

Warum ist VHLO nützlich?

Ein versionierter Dialekt ermöglicht es uns, frühere Versionen des StableHLO-Vorgangs anzusteuern. Dies schließt die Vorwärts- und Abwärtskompatibilität bei Konvertierungen zwischen Vorgängen im VHLO-Dialekt ein.

Aufwärtskompatibilität: Die Aufwärtskompatibilität wird durch eine Konvertierung in eine VHLO und ein Downgrade von Vorgängen auf eine Zielversion bereitgestellt. Wenn jeder Vorgang/Typ/Attr in einem VHLO-Programm auf die Zielversion herabgestuft werden kann, ist diese garantiert deserialisierbar und in StableHLO für einen Nutzer, der eine Version verwendet, die größer oder gleich der Zielversion ausgeführt wird, da VHLO zu diesem Zeitpunkt einen Snapshot des Vorgangs hat.

Bild zur Aufwärtskompatibilität

Diese Downgrade-Konvertierung schlägt fehl, wenn Vorgänge oder Funktionen verwendet werden, die in der vorherigen Version des Vorgangs nicht vorhanden waren. Das bedeutet, dass die Aufwärtskompatibilität beim Producer und nicht zur Laufzeit erkannt wird.

Abwärtskompatibilität: Die Abwärtskompatibilität wird bereitgestellt, indem VHLO-Vorgänge auf ihre neueste Version (falls erforderlich) aktualisiert und dann ein Vorgang wieder in StableHLO konvertiert wird. Alle VHLO-Programme innerhalb des Kompatibilitätsfensters können auf StableHLO aktualisiert werden. Das bedeutet, dass verschiedene Versionen von Nutzern dieselbe VHLO-Nutzlast aus einer früheren Version deserialisieren können.

Bild zur Abwärtskompatibilität

Noch wichtiger ist, dass VHLO hinter der Serialisierung abstrahiert ist. Das bedeutet, dass ML-Frameworks (Produzenten) nur StableHLO-Vorgänge ansprechen müssen und Compiler-Back-Ends (Nutzer) nur die neueste Version unterstützen müssen, also den StableHLO-Vorgangssatz. Konvertierungen zu und von VHLO werden mit Maschinen durchgeführt, die im StableHLO-Repository verwaltet werden.

Versionen des MLIR-Bytecode-Formats

Zur Aufrechterhaltung der Aufwärtskompatibilität haben StableHLO-Versionen eine zugehörige MLIR-Bytecode-Format-Version. Darüber hinaus verwendet die neueste Version von StableHLO die neueste Version von MLIR Bytecode Format. Wenn die MLIR Bytecode Format-Version erhöht wird, erhöht der nächste StableHLO-Release die Nebenversion und aktualisiert Version.cpp, um die neueste MLIR-Bytecode-Format-Version zu verwenden.

Weitere Informationen zum MLIR-Bytecodeformat und zu den Gründen für seine Verwendung in StableHLO finden Sie unter bytecode.md.

Nicht kompatible Änderungen

Alle Änderungen mit Auswirkungen auf die Kompatibilität müssen den RFC-Prozess durchlaufen. Dies gilt auch für das Hinzufügen, Verwerfen oder Umbenennen eines Elements. Sobald der RFC genehmigt wurde, findest du hier einige Beitragsrichtlinien:

Erhöhen Sie die Versionsnummer in Version.h.

Erhöhen Sie vor dem Aktualisieren von VHLO-Vorgängen, Attributen, Typen oder Conversions die Nebenversionsnummer in Version.h. Alle neuen VHLO-Features würden diese erweiterte Version verwenden, z. B. nach dem Überschreiben von 0.10.0 --> 0.11.0, würde ein neuer Vorgang in VhloOps.td Folgendes verwenden:

VHLO_Op<"abs_v2", "0.11.0", "current">

Erforderliche VHLO-Implementierung und -Conversions hinzufügen

Der genaue Code, der zum Einbinden einer neuen Funktion erforderlich ist, kann variieren, aber zum größten Teil muss Folgendes geändert werden:

Ein aktuelles Beispiel für eine kompatibilitätsbezogene Einreichung war das Hinzufügen von zwei FP8-Typen sowie deren Implementierung in VHLO in #1379.

Einheitentests hinzufügen / aktualisieren

Der Mitwirkende einer inkompatiblen Änderung ist sowohl für positive als auch negative Einheitentests der Funktion sowie für Kompatibilitätseinheitentests verantwortlich.

Zum Testen der Kompatibilitätseinheiten muss stablehlo_legalize_to_vhlo.mlir aktualisiert werden, um sicherzustellen, dass StableHLO-Umläufe mit der neuesten Version von VHLO durchgeführt werden. Außerdem werden alle erforderlichen zusätzlichen Vorwärts- und Abwärtskompatibilitätstests durchgeführt.

Einige Beispiele:

Versionierten Serialisierungstest hinzufügen

Nachdem Sie stablehlo_legalize_to_vhlo.mlir einen Testpunkt hinzugefügt haben, erstellen Sie eine versionierte Kopie der Datei mit dem Namen stablehlo_legalize_to_vhlo.0_X_0.mlir wie folgt und eine Bytecode-Version dieser Datei mit der Erweiterung .0_X_0.mlir.bc. Fügen Sie geeignete FileCheck-Zeilen für Tests zur Aufwärts- und Abwärtskompatibilität hinzu.

$ export TARGET_VERSION=0.X.0
$ export TARGET_FILENAME=${TARGET_VERSION//./_}
$ cp stablehlo/tests/stablehlo_legalize_to_vhlo.mlir stablehlo/tests/stablehlo_legalize_to_vhlo.$TARGET_FILENAME.mlir
$ build/bin/stablehlo-translate --serialize --target=$TARGET_VERSION --strip-debuginfo stablehlo/tests/stablehlo_legalize_to_vhlo.$TARGET_FILENAME.mlir > stablehlo/tests/stablehlo_legalize_to_vhlo.$TARGET_FILENAME.mlir.bc

# Replace RUN commands in stablehlo/tests/stablehlo_legalize_to_vhlo.0_X_0.mlir with the following for 0.X.0:
// RUN: stablehlo-opt --mlir-print-op-generic %s.bc | FileCheck %s
// RUN: stablehlo-translate --deserialize %s.bc | stablehlo-translate --serialize --target=0.X.0 | stablehlo-opt --mlir-print-op-generic | FileCheck %s
// RUN: diff <(stablehlo-translate --deserialize %s.bc | stablehlo-opt) <(stablehlo-opt --strip-debuginfo %s)
// RUN: diff %s.bc <(stablehlo-translate --serialize --target=0.X.0 --strip-debuginfo %s)

Beispiel für einen versionierten Test in #1430.