Compatibilidade com StableHLO

StableHLO é uma opset de computação de ML compatível com versões anteriores inspirada em HLO/MHLO. Este documento explica o tipo e a extensão das garantias de compatibilidade que o StableHLO fornece, com base no processo estabelecido no RFC de compatibilidade (link em inglês).

Versions

A versão atual do StableHLO pode ser encontrada em Version.h.

A versão secundária é quebrada toda vez que são feitas alterações na opset de StableHLO ou no formato de serialização de StableHLO, e a versão de patch é movida sempre que integramos o downstream de StableHLO, ou seja, no repositório openxla/xla.

Garantias

De acordo com o RFC de compatibilidade do StableHLO v1.0 (em inglês), a janela de compatibilidade inclui o seguinte:

Cinco anos de compatibilidade com versões anteriores:artefatos portáteis serializados por uma versão antiga do libStablehlo têm a mesma semântica* quando desserializados por uma nova versão do libStablehlo, se essas versões são criadas com base em confirmações openxla/stablehlo com menos de cinco anos de diferença.

Dois anos de compatibilidade com versões futuras:artefatos portáteis serializados por uma nova versão do libStablehlo têm a mesma semântica* quando desserializados por uma versão antiga do libStablehlo, caso essas versões sejam criadas com base em confirmações openxla/stablehlo com menos de dois anos de diferença, a menos que o programa use novos recursos introduzidos desde a versão antiga.

* Os programas StableHLO são convertidos de/para artefatos portáteis por meio de APIs de compatibilidade, e a semântica desses programas é definida pela especificação StableHLO (links em inglês). Consulte a seção "Fora do escopo" para conferir exemplos do que não é coberto por essa definição de compatibilidade.

APIs

Artefatos portáteis podem ser criados usando a ferramenta stablehlo-translate ou diretamente nas APIs C++ ou Python. A serialização precisa de uma versão de destino do StableHLO para gravar um artefato escrito no formato #.#.#. Consulte Version.h para conferir a versão atual. Como as versões de patch não afetam a compatibilidade, qualquer destino com uma versão de patch diferente de zero é definida como zero por padrão durante a serialização. A desserialização usa a versão atual de StableHLO para ler um artefato.

stablehlo-translate

Essa é a maneira mais fácil de criar e ler um artefato portátil.

# 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++

Para fluxos de trabalho programáticos, o StableHLO fornece as seguintes APIs de compatibilidade:

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

Consulte stablehlo/api/PortableApi.h e stablehlo/dialect/Serialization.h para ver as APIs completas.

Consulte StablehloTranslateMain.cpp para conferir um exemplo de uso dessas APIs.

Python

O StableHLO também fornece vinculações do Python às APIs de compatibilidade com 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: ...

Consulte StablehloModule.cpp para ver as APIs completas do Python.

Consulte stablehlo.py > test_serialization_apis para ver exemplos de ida e volta de como usar as APIs de serialização do Python.

Testes

Temos um pacote de compatibilidade em stablehlo/tests/vhlo que envolve um compêndio abrangente de operações do StableHLO serializadas para todas as versões do StableHLO com suporte. Para cada solicitação de envio, testamos a compatibilidade com versões anteriores e futuras, ou seja, que o pacote pode ser desserializado para HEAD (compatibilidade com versões anteriores), que o compêndio pode ser serializado para todas as versões compatíveis do StableHLO (compatibilidade avançada) e que os resultados são sintaticamente idênticos aos programas StableHLO originais.

Trabalho futuro

Criar um pacote de compatibilidade no upstream MLIR:usando os aprendizados de desenvolvimento e manutenção de garantias do StableHLO, planejamos contribuir com um pacote de compatibilidade para o upstream de MLIR para fornecer detecção precoce de falhas de compatibilidade acidentais na infraestrutura de bytecode MLIR (#1632).

Usar implementação de referência: no momento, o teste de compatibilidade consiste em desserializar o pacote de compatibilidade serializado por versões mais antigas do libStablehlo e garantir que a desserialização produza programas sintaticamente idênticos. Planejamos usar também uma implementação de referência nesses testes, relaxando o requisito excessivamente oneroso de identidade sintática e testando de forma abrangente a implementação de referência (#1245).

Fora do escopo

Artefatos não portáteis:as garantias de compatibilidade são fornecidas apenas para artefatos portáteis criados de uma forma muito específica. Outros tipos de artefatos, como a representação com estilo impresso do dialeto StableHLO ou até mesmo a representação do bytecode do dialeto StableHLO, não têm garantias de compatibilidade.

Recursos não especificados:podemos fazer alterações incompatíveis em recursos que têm suporte em programas StableHLO, mas que ainda não fazem parte da especificação StableHLO. Por exemplo, não oferecemos garantias de compatibilidade para atributos não registrados.

Compatibilidade com bugs:podemos fazer mudanças incompatíveis se a implementação no libStablehlo contradiz a especificação do StableHLO. Por exemplo, se uma definição no dialeto VHLO estiver errada ou se um verificador no dialeto StableHLO não corresponder à especificação.

Precisão numérica: o StableHLO tem várias operações com precisão definida pela implementação entre consumidores e até mesmo no mesmo consumidor em todas as versões. Como resultado, o StableHLO não pretende fazer garantias de precisão numérica, embora isso possa mudar no futuro (#1156).

A compatibilidade de origem para APIs C, C++ e Python no libStablehlo é uma meta ambiciosa. No momento, não oferecemos garantias de compatibilidade de fonte, mas avise se esse for um caso de uso importante para você para que possamos conversar sobre como oferecer suporte (#1247).