Zgodność ze StableHLO

StableHLO to zgodna wstecznie operacja obliczeniowa ML inspirowana HLO/MHLO. W tym dokumencie opisujemy rodzaje i zakres gwarancji zgodności zapewnianych przez StableHLO na podstawie procesu opisanego w specyfikacji zgodności.

Wersje

Aktualną wersję StableHLO znajdziesz w Version.h.

Wersja podrzędna jest napotykana przy każdej zmianie w ustawieniu StableHLO lub formacie serializacji StableHLO, a wersja poprawki jest ponawiana za każdym razem, gdy integrujemy StableHLO w dół strumienia, tj. do repozytorium openxla/xla.

Gwarancje

Według specyfikacji StableHLO w wersji 1.0 okno zgodności zawiera te elementy:

5 lat zgodności wstecznej: przenośne artefakty zserializowane przez starszą wersję biblioteki libStablehlo mają tę samą semantykę* po deserializacji za pomocą nowej wersji biblioteki libStablehlo, pod warunkiem, że te wersje zostały utworzone na podstawie zgłoszeń openxla/stablehlo, które są tworzone w odstępach krótszych niż 5 lat.

Zgodność wsteczna o 2 lata: przenośne artefakty zserializowane przez nową wersję libStablehlo mają tę samą semantykę* po deserializacji za pomocą starej wersji libStablehlo, pod warunkiem że wersje te zostały utworzone na podstawie zgłoszeń openxla/stablehlo, w odstępach mniej niż 2 lat, chyba że program korzysta z nowych funkcji wprowadzonych od poprzedniej wersji.

* Programy StableHLO są konwertowane na przenośne artefakty za pomocą interfejsów API zgodności. Semantyka tych programów jest określona w specyfikacji StableHLO. Więcej przykładów znajdziesz w sekcji „Poza zakresem”.

Interfejsy API

Przenośne artefakty można tworzyć za pomocą narzędzia stablehlo-translate albo bezpośrednio w interfejsach API C++ lub Pythona. Serializacja wymaga docelowej wersji StableHLO do zapisania artefaktu napisanego w formacie #.#.# (bieżącą wersję znajdziesz w sekcji Version.h). Wersje poprawek nie mają wpływu na zgodność, dlatego podczas serializacji każdy cel z inną wersją poprawki jest domyślnie ustawiany na 0. Deserializacja używa bieżącej wersji StableHLO do odczytu artefaktu.

stablehlo-translate

To najprostszy sposób na utworzenie i odczytanie artefaktu przenośnego.

# Write a StableHLO program to a portable artifact
$ stablehlo-translate --serialize file.mlir --target=0.9.0 > portable_artifact.mlir.bc

# Read StableHLO portable artifact
$ stablehlo-translate --deserialize portable_artifact.mlir.bc

C++

W przypadku zautomatyzowanych przepływów pracy StableHLO udostępnia te interfejsy API zgodności:

// From: #include "stablehlo/api/PortableApi.h"

// Get the current StableHLO version.
//
// This value can be used as the `targetVersion` argument to
// `serializePortableArtifact`.
std::string getCurrentVersion();

// Get the minimum supported StableHLO version.
//
// This value can be used as the `targetVersion` argument to
// `serializePortableArtifact`.
std::string getMinimumVersion();

// From: #include "stablehlo/dialect/Serialization.h"

// Write a StableHLO program to a portable artifact
// Writes a stable payload for `module` to `os`. If compatibility with a
// previous version of StableHLO is required, provide the required version
// string `#.#.#` for `targetVersion`.
//
// Can fail if `module` cannot be expressed in the `targetVersion` version of
// StableHLO, e.g. if it's using new or removed features, or if it involves
// unsupported dialects.
LogicalResult serializePortableArtifact(ModuleOp module,
                                        StringRef targetVersion,
                                        raw_ostream& os);

// Read StableHLO portable artifact
//
// Can fail if `sourceStr` cannot be expressed in the current version of
// StableHLO, e.g. if it's using incompatible features. Returns nullptr if
// `sourceStr` is invalid or fails to deserialize.
OwningOpRef<ModuleOp> deserializePortableArtifact(StringRef sourceStr,
                                                  MLIRContext* context);

Informacje o pełnych interfejsach API znajdziesz w sekcjach stablehlo/api/PortableApi.h i stablehlo/dialect/Serialization.h.

Przykład zastosowania tych interfejsów API znajdziesz w sekcji StablehloTranslateMain.cpp.

Python

StableHLO udostępnia też powiązania Pythona z interfejsami API zgodności C++:

def get_current_version() -> str: ...
def get_minimum_version() -> str: ...
def serialize_portable_artifact(module: ir.Module, target_version: str) -> bytes: ...
def serialize_portable_artifact(module: str, target_version: str) -> bytes: ...
def deserialize_portable_artifact(context: ir.Context, artifact: bytes) -> ir.Module: ...
def deserialize_portable_artifact(artifact: bytes) -> str: ...

Pełną listę interfejsów API Pythona znajdziesz w sekcji StablehloModule.cpp.

W sekcji stablehlo.py > test_serialization_apis znajdziesz przykłady użycia interfejsów API do serializacji w Pythonie w obie strony.

Testy

W stablehlo/tests/vhlo mamy pakiet zgodności, który obejmuje kompleksowy kompendium operacji StableHLO zserializowany na potrzeby wszystkich obsługiwanych wersji StableHLO. W przypadku każdego żądania pull testujemy zgodność wsteczną i przyszłą, tj. czy można zdezorientować pakiet HEAD (zgodność wsteczną), czy kompendium może być zserializowane i kierowane na wszystkie obsługiwane wersje StableHLO (zgodność z wyprzedzeniem), a wyniki są składniowo identyczne z pierwotnymi programami StableHLO.

Praca w przyszłości

Utworzenie pakietu zgodności w projekcie MLIR: na podstawie wniosków z ustalania i utrzymywania gwarancji StableHLO zamierzamy udostępnić pakiet zgodności dla starszych wersji MLIR, aby zapewnić wczesne wykrywanie przypadkowych awarii zgodności w infrastrukturze kodu bajtowego MLIR (#1632).

Użycie implementacji referencyjnej: obecnie testowanie zgodności polega na deserializacji pakietu zgodności zserializowanego za pomocą starszych wersji biblioteki libStablehlo i upewnieniu się, że deserializacja generuje programy o identycznej składni. W tych testach planujemy też zastosować wdrożenie referencyjne, co pozwoli łagodzić nadmiernie uciążliwe wymaganie związane z tożsamością składniową i dokładnie przetestować implementację referencyjną (#1245).

Wykracza poza zakres

Nieprzenośne artefakty: gwarancja zgodności jest zapewniana tylko w przypadku artefaktów przenośnych, które zostały utworzone w określony sposób. Inne rodzaje artefaktów, takie jak stylowa reprezentacja dialektu StableHLO czy nawet reprezentacja dialektu StableHLO za pomocą kodu bajtowego, nie są gwarantowane.

Nieokreślone funkcje: możemy wprowadzać niezgodne zmiany w funkcjach, które były wcześniej obsługiwane w programach StableHLO, ale nie były jeszcze uwzględnione w specyfikacji StableHLO. Na przykład nie udzielamy gwarancji zgodności niezarejestrowanych atrybutów.

Zgodność błędu: możemy wprowadzić niezgodne zmiany, jeśli implementacja w libStablehlo jest sprzeczna ze specyfikacją StableHLO, np. jeśli definicja w dialekcie VHLO jest nieprawidłowa lub weryfikator w dialekcie StableHLO nie pasuje do specyfikacji.

Dokładność liczbowa: StableHLO ma wiele operacji ze zdefiniowaną dokładnością wdrożenia dla różnych klientów, a nawet w ramach tego samego klienta w różnych wersjach. W rezultacie StableHLO nie gwarantuje dokładności liczb, chociaż w przyszłości może się to zmienić (#1156).

Zależy nam na zgodności źródeł interfejsów API w językach C, C++ i Python w libStablehlo. Obecnie nie gwarantujemy zgodności źródeł, ale daj nam znać, jeśli jest to ważny przypadek użycia, abyśmy mogli porozmawiać o jego wspieraniu (#1247).