O que é o dialeto VHLO?
O dialeto VHLO (StableHLO com controle de versão) é usado para serialização e estabilidade. Ele fornece um resumo do dialeto StableHLO em um determinado momento pelo controle de versões de elementos individuais do programa.
VHLO é um dialeto somente para adição com operações, tipos e atributos com controle de versão, o que significa que, depois que um elemento é adicionado ao dialeto, ele não pode ser modificado de nenhuma maneira que afete a semântica.
Qualquer mudança em uma op, tipo ou atributo exige que uma nova versão seja adicionada ao
dialeto. Por exemplo, se um my_op
hipotético foi adicionado ao StableHLO na
versão 0.9.0, mas alterado na 0.11.0, teríamos o seguinte na 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);
}
O dialeto StableHLO tem apenas a versão mais recente do ops. No exemplo em execução, o dialeto StableHLO na v0.11.0 teria apenas o StableHLO_MyOp
que tem operand
e attr
, enquanto a VHLO captura cada fase da evolução da operação.
Por que a VHLO é útil?
Ter um dialeto com controle de versão nos permite segmentar versões anteriores do conjunto de opset StableHLO. Isso encapsula a compatibilidade com versões anteriores e posteriores em conversões entre operações no dialeto VHLO.
Compatibilidade futura:a compatibilidade com versões futuras é fornecida pela conversão para VHLO e downgrade das operações para uma versão de destino. Se cada op/tipo/attr em um programa VHLO puder ser rebaixado para a versão de destino, será garantido que ele será desserializável e conversível para StableHLO em um consumidor que estiver executando uma versão maior ou igual à versão de destino, já que a VHLO tem um snapshot do opset naquele momento.
Essa conversão de downgrade falhará se operações ou recursos que não existem na versão anterior da opset forem usados. Isso significa que a compatibilidade com versões futuras é descoberta no produtor, e não durante a execução.
Compatibilidade com versões anteriores:a compatibilidade com versões anteriores é fornecida ao fazer o upgrade das operações de VHLO para a versão mais recente (se necessário) e, em seguida, converter uma operação de volta para o StableHLO. Todos os programas VHLO na janela de compatibilidade podem ser atualizados para StableHLO, o que significa que diferentes versões de consumidores podem desserializar o mesmo payload de VHLO de uma versão anterior.
Mais importante, a VHLO é abstraída por trás da serialização. Isso significa que os frameworks de ML (produtores) só precisam segmentar operações StableHLO, e os back-ends do compilador (consumidores) só precisam oferecer suporte à versão mais recente, que é o conjunto de operações StableHLO. As conversões de e para VHLO são processadas com máquinas mantidas no repositório StableHLO.
Versões do formato Bytecode MLIR
Para manter a compatibilidade com versões futuras, as versões StableHLO têm uma versão associada do formato MLIR Bytecode Format. Além disso, a versão mais recente do StableHLO usará a versão mais recente do formato Bytecode MLIR. Quando a versão do formato MLIR Bytecode Format for incrementada, a próxima versão do StableHLO incrementará a versão secundária e atualizará o Version.cpp para usar a versão mais recente do formato MLIR Bytecode Format.
Para detalhes sobre o formato Bytecode MLIR e a lógica para usá-lo em StableHLO, consulte bytecode.md.
Contribuição de alterações incompatíveis
Todas as mudanças com implicações de compatibilidade precisam passar pelo processo de RFC. Isso inclui adicionar, descontinuar ou renomear um recurso. Depois que o RFC for aprovado, veja algumas diretrizes de contribuição:
Melhore o número da versão em Version.h
Antes de atualizar as operações, os atributos, os tipos ou as conversões da VHLO, incremente o
número da versão secundária em Version.h.
Qualquer novo recurso de VHLO adicionado usaria essa versão aprimorada. Por exemplo, depois
de atingir 0.10.0 --> 0.11.0
, uma nova operação em VhloOps.td
usaria:
VHLO_Op<"abs_v2", "0.11.0", "current">
Adicione a implementação e as conversões necessárias da VHLO
O código exato necessário para integrar um novo recurso varia, mas, na maior parte, será necessário mudar o seguinte:
- Para todas as mudanças:
- Atualize o registro da versão em VhloDialect.td
- Para novas operações:
- Adicione a operação em VhloOps.td.
- Adição da conversão de StableHLO → VHLO em StablehloLegalizeToVhlo.cpp
- Adicione a conversão VHLO → StableHLO em VhloLegalizeToStablehlo.cpp
- Para novas versões de operações atuais:
- Adicione a operação em VhloOps.td.
- O mapeamento de StableHLO para VHLO em MapStablehloToVhlo.h foi atualizado.
- Adicione uma conversão entre as versões novas e antigas das operações em VhloToVersion.cpp.
- Para novos tipos ou atributos:
- Adicione o tipo em VhloTypes.td ou o atributo em VhloAttrs.td.
- Adição da conversão de StableHLO → VHLO em StablehloLegalizeToVhlo.cpp
- Adicione a conversão VHLO → StableHLO em VhloLegalizeToStablehlo.cpp
Um exemplo recente de um envio relacionado à compatibilidade foi a adição de dois tipos FP8, bem como a implementação deles na VHLO em #1379 (link em inglês).
Adicionar / atualizar testes de unidade
O colaborador de uma mudança incompatível é responsável por testes de unidade positivos e negativos do recurso, bem como testes de unidade de compatibilidade.
O teste de unidade de compatibilidade envolve a atualização de stablehlo_legalize_to_vhlo.mlir para garantir que o StableHLO use a versão mais recente da VHLO, bem como todos os outros testes de compatibilidade necessários.
Alguns exemplos:
- Compatibilidade com versões anteriores, testes positivos: vhlo_to_version_upgrade.mlir
- Compatibilidade com versões futuras e testes positivos: vhlo_to_version_downgrade.mlir
- Compatibilidade com versões futuras, testes negativos: vhlo_to_version_downgrade_invalid.0_9_0.mlir
Adicionar teste de serialização com controle de versões
Depois de adicionar um ponto de teste a stablehlo_legalize_to_vhlo.mlir
, crie uma
cópia com controle de versão do arquivo chamado stablehlo_legalize_to_vhlo.0_X_0.mlir
, conforme
a seguir, junto com uma versão de bytecode desse arquivo com uma extensão
.0_X_0.mlir.bc
. Adicione linhas adequadas do FileCheck
para testes de compatibilidade com versões anteriores e futuras.
$ 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)
Exemplo de teste com controle de versão em #1430.