VHLO 言語

VHLO 言語とは

シリアル化と安定性には VHLO(バージョニングされた StableHLO)言語が使用されます。個々のプログラム要素をバージョニングすることで、特定の時点での StableHLO 言語のスナップショットを提供します。

VHLO は、バージョニングされた演算、型、属性を持つ追加専用の言語です。つまり、機能が言語に追加されると、セマンティクスに影響を与えるような方法で変更することはできません。

演算、型、属性を変更する場合は、言語に新しいバージョンを追加する必要があります。たとえば、仮の my_op が 0.9.0 で StableHLO に追加され、0.11.0 で変更された場合、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);
}

StableHLO 言語には最新バージョンの Ops のみが含まれます。実行中の例では、v0.11.0 の StableHLO 言語には operandattr を持つ StableHLO_MyOp のみがあり、VHLO は演算の進化の各フェーズをキャプチャします。

VHLO が役立つ理由

バージョニングされた言語を使用することで、StableHLO 演算セットの以前のバージョンをターゲットにできます。これにより、VHLO 言語の演算間の変換における上位互換性と下位互換性がカプセル化されます。

上位互換性: 上位互換性は、VHLO に変換し、オペレーションをターゲット バージョンにダウングレードすることで実現されます。VHLO プログラム内のすべての op、type、attr をターゲット バージョンにダウングレードできる場合、VHLO にはその時点で opset のスナップショットがあるため、直列化可能で、ターゲット バージョン以上のバージョンを実行しているコンシューマで StableHLO に変換できることが保証されます。

上位互換性の画像

以前のバージョンのオペレーションセットに存在しないオペレーションまたは機能が使用されている場合、このダウングレード変換は失敗します。つまり、上位互換性はランタイムではなくプロデューサーで検出されます。

下位互換性: 下位互換性は、VHLO 演算を最新バージョンにアップグレードし(必要に応じて)、演算を StableHLO に戻すことで実現されます。互換性ウィンドウ内のすべての VHLO プログラムは StableHLO にアップグレードできます。つまり、異なるバージョンのコンシューマーで同じ VHLO ペイロードを以前のバージョンから逆シリアル化できます。

下位互換性の画像

さらに重要なこととして、VHLO はシリアル化によって抽象化されています。つまり、ML フレームワーク(プロデューサー)は StableHLO 演算のみをターゲットにする必要があり、コンパイラ バックエンド(コンシューマ)は最新バージョン(StableHLO 演算セット)のみをサポートする必要があります。VHLO との間の変換は、StableHLO リポジトリにある機械によって処理されます。

MLIR バイトコード形式のバージョン

上位互換性を維持するため、StableHLO バージョンは MLIR バイトコード形式のバージョンに関連付けられています。また、StableHLO の最新バージョンは最新バージョンの MLIR バイトコード形式を使用します。MLIR バイトコード形式のバージョンがインクリメントされると、StableHLO の次のリリースではマイナー バージョンをインクリメントし、最新の MLIR バイトコード形式バージョンを使用するように Version.cpp を更新します。

MLIR バイトコード形式の詳細と StableHLO 内で使用する根拠については、bytecode.md をご覧ください。

互換性のない変更の投稿

互換性に影響する変更はすべて、RFC プロセスを通過する必要があります。これには、機能の追加、非推奨、名前の変更が含まれます。RFC が承認されたら、次の投稿に関するガイドラインをご覧ください。

Version.h のバージョン番号にバンプをする

VHLO オペレーション、属性、タイプ、またはコンバージョンを更新する前に、Version.h のマイナー バージョン番号をインクリメントします。追加されたすべての新しい VHLO 機能では、このバンプされたバージョンを使用します。たとえば、0.10.0 --> 0.11.0 をバンプした後、VhloOps.td の新しい op は以下を使用します。

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

必要な VHLO の実装とコンバージョンを追加する

新しい機能の統合に必要なコードは異なりますが、ほとんどの場合、以下の点を変更する必要があります。

互換性に関連する提出の最近の例としては、2 つの FP8 タイプの追加と、#1379 の VHLO でのそれらの実装が挙げられます。

単体テストの追加 / 更新

互換性のない変更の投稿者は、機能の肯定的な単体テストと否定的な単体テストの両方と、互換性の単体テストを行う責任を負います。

互換性単体テストには、stablehlo_legalize_to_vhlo.mlir を更新して、最新バージョンの VHLO で StableHLO がラウンド トリップするようにし、さらに必要な上位互換性テストまたは下位互換性テストを行う必要があります。

以下に例を示します。

バージョン付きシリアル化テストの追加

テストポイントを stablehlo_legalize_to_vhlo.mlir に追加したら、次のように stablehlo_legalize_to_vhlo.0_X_0.mlir という名前のファイルのバージョン付きコピーと、.0_X_0.mlir.bc 拡張子を持つ上記のファイルのバイトコード バージョンを作成します。上位互換性と下位互換性のテスト用に適切な FileCheck 行を追加します。

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

#1430 のバージョン対応テストの例