Compilar e armazenar em cache modelos ONNX no Windows ML

A compilação é o passo que transforma o seu modelo ONNX no binário específico de hardware que um fornecedor de execução (EP) realmente executa. Em NPUs e GPUs, esse passo pode demorar desde alguns segundos até vários minutos para modelos grandes — e se a sua aplicação não armazenar o resultado em cache, os utilizadores pagam esse custo sempre que a sua aplicação inicia.

Esta página explica o que envolve a compilação, quando pré-compilar e como validar um modelo compilado em cache antes de o reutilizar.

Pré-requisitos

As APIs de compatibilidade de modelos compilados requerem Windows ML 2.3 ou posterior. No upstream ONNX Runtime, GetModelCompatibilityForEpDevices() está disponível na versão 1.23 e GetCompatibilityInfoFromModel() na versão 1.24.

Dois tipos de compilação

"Compilação" pode significar duas coisas diferentes. Separá-los torna o resto desta página mais fácil de compreender:

  • Otimização de grafos — Trabalhos de fusão, dobra constante e layout que o ONNX Runtime realiza na criação da sessão. É barato, independente do EP e funciona sempre que crias uma sessão.
  • Compilação EP — Conversão do grafo ONNX para o próprio formato de um EP, seguida de compilação para um binário específico de hardware. Os EPs de hardware (QNN, OpenVINO, VitisAI, NvTensorRtRtx, MIGraphX) fazem isto, e é o passo mais caro. Em NPUs pode demorar dezenas de segundos a minutos para modelos maiores.

O Windows ML evita voltar a incorrer no custo da compilação do EP, recorrendo ao mecanismo EPContext do ONNX Runtime. A primeira compilação serializa um binário pronto para o hardware num modelo *_ctx.onnx (ou num ficheiro sidecar .bin); as sessões posteriores carregam o binário pré-gerado e saltam a conversão por completo.

Porquê pré-compilar?

O Windows ML recomenda fortemente a pré-compilação ao utilizar fornecedores de execução. A pré-compilação converte um arranque a frio de vários segundos — por vezes, de vários minutos — num custo único e proporciona à sua aplicação:

  • Arranques rápidos a frio — os arranques subsequentes ignoram a conversão do grafo e a compilação para o hardware.
  • Comportamento previsível — a plataforma suporta verificar se um modelo compilado é ótimo para os dispositivos que a sua aplicação seleciona antes de criar uma sessão de inferência.
  • Menor consumo de CPU e bateria — deixa de recompilar o mesmo gráfico em cada lançamento.

Sem pré-compilação, a sua aplicação repete a conversão e compilação de EP em cada criação de sessão, e os utilizadores sentem o atraso a cada vez.

Quando pré-compilar

Efetua a pré-compilação sempre que a tua aplicação tiver como destino um EP de hardware. Estão disponíveis duas opções de temporização:

Strategy Melhor para Trade-offs
Ahead-of-time (AOT) — compilar durante a fase de construção ou de instalação e disponibilizar o artefacto compilado. Parques controlados de hardware e controladores, ou instaladores por dispositivo. Requer ferramentas de compilação cruzada para plataformas-alvo que a sua máquina de compilação não consegue executar. Valide o artefacto no dispositivo alvo e forneça um recurso de recompilação.
Compila na primeiraexecução (recomendado para distribuição ampla) — verifica se há um artefacto compilado, compila-o se estiver em falta, depois cache e reutiliza-o. Armazene aplicações e distribuição geral para consumidores numa base de hardware diversificada. Os utilizadores pagam o custo de compilação uma vez, no primeiro lançamento.

O guia do Windows ML demonstra a mecânica básica de compilação na primeira execução, verificando se existe um artefacto compilado. Não é um exemplo completo de gestão de cache. Antes de reutilizar um modelo compilado existente numa aplicação, aplique a verificação de compatibilidade descrita neste artigo. Para a API de compilação em contexto, veja Modelos de compilação.

Validar um modelo compilado antes de a reutilizar

Um modelo compilado pode depender do EP e da configuração do dispositivo que o produziu. O EP determina se um modelo armazenado em cache permanece compatível e ideal para um conjunto de dispositivos.

Durante a compilação, um EP pode gerar uma cadeia de compatibilidade UTF-8 com terminação nula que o ONNX Runtime escreve nas propriedades de metadados do modelo compilado. O formato e o conteúdo da string são definidos pelo EP. A tua aplicação não deve analisar ou interpretar isso.

A sua aplicação passa a cadeia de caracteres e os dispositivos EP de destino para GetModelCompatibilityForEpDevices(). O ONNX Runtime chama a implementação de validação da fábrica do EP e devolve um estado OrtCompiledModelCompatibility. Para os contratos de código-fonte, veja GetModelCompatibilityForEpDevices() e ValidateCompiledModelCompatibilityInfo() no repositório ONNX Runtime.

Cenários de verificação de compatibilidade

Pode usar a mesma API de validação em dois cenários:

  • Valide um modelo que já esteja no dispositivo. Chamada GetCompatibilityInfoFromModel() para extrair a cadeia de um ficheiro de modelo compilado. Se o modelo já estiver em memória, chame GetCompatibilityInfoFromModelBytes(). Depois, passe a cadeia de caracteres para GetModelCompatibilityForEpDevices().
  • Valide antes de descarregar um modelo compilado. Publique a cadeia opaca como metadados leves juntamente com o modelo compilado. A sua aplicação pode obter primeiro a cadeia de caracteres, validá-la com GetModelCompatibilityForEpDevices() e transferir o modelo potencialmente grande apenas quando o estado devolvido satisfizer a sua política de cache ou de implementação.

Manter os metadados de compatibilidade remota associados ao artefacto compilado exato que os produziu. Se o artefacto mudar, atualize a string de compatibilidade associada.

Em qualquer dos cenários:

  1. Chame GetEpDevices() para enumerar os dispositivos EP disponíveis, depois aplique a mesma política EP ou de dispositivo que usa para configurar a sessão de inferência.
  2. Obtenha a cadeia de compatibilidade do modelo local ou dos metadados associados a um modelo remoto.
  3. Passe a cadeia de caracteres e o grupo de dispositivos correspondente para GetModelCompatibilityForEpDevices().
  4. Aplique a sua política de cache ou de transferência ao estado devolvido. Os exemplos de Windows ML usam uma política conservadora e aceitam o modelo compilado apenas para EP_SUPPORTED_OPTIMAL.

GetCompatibilityInfoFromModel() Analisa o ONNX ModelProto completo a partir do disco. Usa o padrão de metadados remotos quando precisares de tomar uma decisão de compatibilidade antes de descarregar o próprio modelo.

As APIs retornam um valor OrtCompiledModelCompatibility:

Situação Meaning Ação recomendada
EP_SUPPORTED_OPTIMAL O modelo compilado é suportado e ótimo para os dispositivos EP. Reutilize o modelo compilado.
EP_SUPPORTED_PREFER_RECOMPILATION O modelo compilado é suportado, mas o EP recomenda a recompilação para melhor desempenho. O modelo pode executar-se, mas uma política de cache apenas otimizada recompila-o.
EP_UNSUPPORTED O modelo compilado não é suportado pelos dispositivos EP atuais. Não carregues o modelo compilado. Recompilar ou usar o modelo original.
EP_NOT_APPLICABLE O EP não fornecia uma determinação de compatibilidade para os dispositivos fornecidos. Este é também o padrão quando o EP não implementa validação de compatibilidade. Não trate este estado como prova de que a cache é compatível. Use o modelo original, a menos que a sua aplicação tenha outra política de validação.

Sob uma política de cache exclusiva de ideal, trate a ausência de metadados de compatibilidade relativos ao EP preferido como uma falha de cache. Se a avaliação de compatibilidade devolver um erro, usa o modelo original para essa execução e não promovas um artefacto recém-compilado porque a tua aplicação não o consegue validar.

Eventos que podem exigir uma nova entrada de cache incluem:

  • É instalado um novo EP.
  • O driver da GPU ou NPU é atualizado.
  • O hardware do utilizador muda.
  • O modelo ONNX de origem muda.
  • A sua aplicação altera as definições de ONNX Runtime, EP ou compilação utilizadas para produzir o artefacto.

As APIs de compatibilidade validam um artefacto compilado existente contra dispositivos EP; não determinam se o artefacto foi produzido a partir do modelo de origem atual. Inclua uma versão ou hash do modelo de origem na chave de cache, e invalide a cache quando as entradas de compilação mudarem.

Se a sua aplicação estiver distribuída por vários dispositivos, armazene artefactos compilados numa localização de cache local para que cada dispositivo produza e reutilize o seu próprio binário.

Verificação básica de compatibilidade

As seguintes funções auxiliares verificam um modelo compilado para um EP. Antes de chamar um ajudante, aplique a mesma política de EP ou dispositivo que usa para configurar a sessão de inferência. A coleção de dispositivos deve ser não vazia e conter dispositivos do mesmo EP.

static bool IsCompiledModelOptimal(
    OrtEnv ortEnv,
    string compiledModelPath,
    string epName,
    IReadOnlyList<OrtEpDevice> epDevices)
{
    string compatibilityInfo =
        ortEnv.GetCompatibilityInfoFromModel(compiledModelPath, epName);

    return !string.IsNullOrWhiteSpace(compatibilityInfo) &&
        ortEnv.GetModelCompatibilityForEpDevices(
            epDevices,
            compatibilityInfo) ==
        OrtCompiledModelCompatibility.EP_SUPPORTED_OPTIMAL;
}

Use a verificação antes da criação da sessão:

  • Se o resultado cumprir a política de compatibilidade da sua aplicação, utilize o modelo compilado.
  • Caso contrário, use ou recompile o modelo original.

Os exemplos de ML do Windows usam uma política conservadora e aceitam apenas EP_SUPPORTED_OPTIMAL. A tua aplicação determina como armazenar, atualizar e substituir os modelos compilados.

Compilar modelos

Antes de usar um modelo ONNX em uma sessão de inferência, ele geralmente deve ser compilado em uma representação otimizada que pode ser executada de forma eficiente no hardware subjacente do dispositivo.

A partir do ONNX Runtime 1.22, há novas APIs que encapsulam melhor as etapas de compilação. Mais detalhes estão disponíveis na documentação de compilação do ONNX Runtime (consulte OrtCompileApi struct).

// Prepare compilation options
OrtModelCompilationOptions compileOptions = new(sessionOptions);
compileOptions.SetInputModelPath(modelPath);
compileOptions.SetOutputModelPath(compiledModelPath);

// Compile the model
compileOptions.CompileModel();

Note

A compilação pode levar vários minutos para ser concluída. Para que qualquer interface de utilizador se mantenha responsiva, considere fazer isto como uma operação em segundo plano na sua aplicação ou alertar o utilizador de que um modelo está a ser preparado.

Consulte também