Dialecte VHLO

Qu'est-ce que le dialecte VHLO ?

Le dialecte VHLO (Versioned StableHLO) est utilisé pour la sérialisation et la stabilité. Elle fournit un instantané du dialecte StableHLO à un moment donné grâce à la gestion des versions des éléments individuels du programme.

VHLO est un dialecte de type "add uniquement" comportant des opérations, types et attributs avec versions gérées. Cela signifie qu'une fois qu'une caractéristique est ajoutée au dialecte, elle ne peut pas être modifiée d'une manière qui affecte la sémantique.

Toute modification apportée à une opération, à un type ou à un attribut nécessite l'ajout d'une nouvelle version au dialecte. Par exemple, si un my_op hypothétique a été ajouté à StableHLO dans la version 0.9.0, mais a été modifié dans la version 0.11.0, nous obtenons ce qui suit dans VHLO:

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

Le dialecte StableHLO ne dispose que de la dernière version des opérations. Dans l'exemple en cours d'exécution, le dialecte StableHLO de la version v0.11.0 n'aurait que le StableHLO_MyOp contenant operand et attr, tandis que VHLO capture chaque phase de l'évolution de l'opération.

Quelle est l'utilité de VHLO ?

La gestion des versions d'un dialecte nous permet de cibler les versions précédentes de l'opération StableHLO. Cela encapsule la rétrocompatibilité dans les conversions entre les opérations dans le dialecte VHLO.

Compatibilité transfert:la compatibilité ascendante est assurée par la conversion au format VHLO et la rétrogradation des opérations vers une version cible. Si chaque opération/type/attr d'un programme VHLO peut être rétrogradé vers la version cible, il est garanti qu'il est désérialisable et convertible en StableHLO sur un consommateur exécutant une version supérieure ou égale à la version cible, car VHLO dispose d'un instantané de l'opération à ce moment-là.

Image de compatibilité ascendante

Cette conversion de rétrogradation échouera si des opérations ou des fonctionnalités qui n'existent pas dans la version précédente de l'opération sont utilisées. Cela signifie que la compatibilité ascendante est découverte sur le producteur, plutôt qu'au moment de l'exécution.

Rétrocompatibilité:la rétrocompatibilité est fournie en mettant à niveau les opérations VHLO vers leur dernière version (si nécessaire), puis en convertissant une opération en StableHLO. Tous les programmes VHLO de la fenêtre de compatibilité peuvent être mis à niveau vers StableHLO, ce qui signifie que différentes versions des consommateurs peuvent désérialiser la même charge utile VHLO qu'une version précédente.

Image de rétrocompatibilité

Plus important encore, VHLO est extrait derrière la sérialisation. Autrement dit, les frameworks de ML (producteurs) ne doivent cibler que les opérations StableHLO, et les backends de compilation (utilisateurs) n'ont besoin que de la dernière version, qui est l'ensemble d'opérations StableHLO. Les conversions vers et depuis le VHLO sont assurées par les machines gérées dans le dépôt StableHLO.

Versions du format MLIR (Bytecode)

Afin de maintenir la compatibilité ascendante, les versions StableHLO sont associées à une version du format MLIR Bytecode. De plus, la dernière version de StableHLO utilise la dernière version du format MLIR Bytecode. Lorsque la version du format MLIR Bytecode est incrémentée, la prochaine version de StableHLO incrémente la version mineure et met à jour Version.cpp pour utiliser la dernière version du format MLIR Bytecode.

Pour en savoir plus sur le format MLIR Bytecode et sur ses raisons de l'utiliser dans StableHLO, consultez bytecode.md.

Contribution de modifications incompatibles

Toutes les modifications ayant des implications en termes de compatibilité doivent passer par le processus RFC. Cela inclut l'ajout, l'abandon ou le changement de nom d'un élément géographique. Une fois le document RFC approuvé, voici quelques consignes de contribution:

Compléter le numéro de version dans Version.h

Avant de mettre à jour des opérations, des attributs, des types ou des conversions VHLO, incrémentez le numéro de version mineure dans Version.h. Toute nouvelle fonctionnalité VHLO ajoutée utilisera cette version migrée. Par exemple, après avoir bouleversé 0.10.0 --> 0.11.0, une nouvelle opération dans VhloOps.td utilisera:

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

Ajouter l'implémentation et les conversions VHLO requises

Le code exact nécessaire pour intégrer une nouvelle fonctionnalité varie, mais dans la plupart des cas, les éléments suivants devront être modifiés:

Un exemple récent d'envoi lié à la compatibilité est l'ajout de deux types FP8 ainsi que leur implémentation dans VHLO à la n° 1379.

Ajouter / Mettre à jour des tests unitaires

Le contributeur d'une modification incompatible est responsable des tests unitaires positifs et négatifs de la fonctionnalité, ainsi que des tests unitaires de compatibilité.

Les tests unitaires de compatibilité impliquent la mise à jour de stablehlo_legalize_to_vhlo.mlir pour s'assurer que les allers-retours StableHLO utilisent la dernière version de VHLO, ainsi que tous les tests de compatibilité ascendante ou ascendante supplémentaires requis.

Voici quelques exemples :

Ajouter un test de sérialisation avec versions gérées

Après avoir ajouté un point de test à stablehlo_legalize_to_vhlo.mlir, créez une copie avec versions gérées du fichier nommé stablehlo_legalize_to_vhlo.0_X_0.mlir comme suit, ainsi qu'une version bytecode de ce fichier avec une extension .0_X_0.mlir.bc. Ajoutez des lignes FileCheck appropriées pour tester la rétrocompatibilité.

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

Exemple de test avec versions gérées dans la section #1430.