Conceitos da API do Windows ML Runtime

Importante

A API do Windows ML Runtime está atualmente experimental e não é suportada para utilização em ambientes de produção. As aplicações que testam esta API não devem ser publicadas na Microsoft Store.

A API do Windows ML Runtime é um framework nativo de inferência de IA local construído especificamente para o Windows. Com a API do Windows ML Runtime, tens controlo explícito sobre o carregamento dos modelos, posicionamento do hardware, propriedade dos tensores, composição do pipeline, compilação e diagnóstico.

Recomendamos usar a API de Runtime para o melhor desempenho de inferência de modelos no Windows, mas se a sua aplicação precisar de correr noutras plataformas, ou se já tiver código ONNX Runtime multiplataforma a funcionar, também pode usar o ONNX Runtime via Windows ML.

Como os objetos se encaixam

IWinMLRuntime
  |-- loads --> IWinMLModel
  |-- creates -> IWinMLExecutionTarget
  `-- creates -> IWinMLPipelineBuilder
                   |-- adds/connects -> IWinMLStage
                   `-- Build() ------> IWinMLPipeline

IWinMLExecutionTarget -- creates --> IWinMLTensor
IWinMLStage ----------- binds -----> IWinMLTensor
IWinMLPipeline -------- Run() -----> stage outputs

Cada método devolve HRESULT, e cada ponteiro de interface segue a contagem normal de referências COM. Capacidades opcionais são descobertas com QueryInterface; uma capacidade indisponível devolve E_NOINTERFACE.

Runtime

Criar IWinMLRuntime com WinMLCreateRuntime. Use isto para carregar artefactos de modelo, criar alvos de execução e criar construtores de pipelines.

Modelos e esquemas

IWinMLModel é um artefacto de modelo imutável e opaco. LoadModelFromFile aceita qualquer caminho de ficheiro absoluto ou relativo que a sua aplicação possa ler; a localização do modelo é a decisão de embalagem da sua aplicação.

O carregamento confirma que o artefacto é reconhecido e estruturalmente legível. A compatibilidade de alvo é efetivada mais tarde, quando o método Build do construtor de pipeline é bem-sucedido.

Reflete o esquema ordinal declarado de um modelo através de IWinMLModelSchema. Alguns artefactos ONNX também expõem nomes através do opcional IWinMLOrtModelSchema, mas a identidade de execução mantém-se posicional.

Formas e operadores

Um esquema de modelo declarado pode conter dimensões livres, representadas por UINT64_MAX. Um betão IWinMLTensor tem sempre dimensões definidas. Os pipelines suportados por ORT podem associar e executar valores concretos para uma dimensão livre.

Formas fixas ou explicitamente limitadas continuam a ser o centro de design otimizado porque permitem Build validar compatibilidade, alocar recursos estáveis e determinar se a replay ou a iteração residente no dispositivo é legal. Também proporcionam a maior compatibilidade entre backends de execução. Trata-se de uma distinção entre otimização e portabilidade, não de uma rejeição generalizada de modelos cujo esquema ONNX declarado contém dimensões livres.

Os operadores ONNX padrão também melhoram a portabilidade do backend. Uma carga de modelo bem-sucedida não garante que todos os alvos possam executar todos os operadores; Build é a verificação de compatibilidade.

Backends

O ficheiro do modelo seleciona o backend. A sua aplicação utiliza os mesmos objetos de Runtime: model, execution target, pipeline builder, stages, bindings, e Run.

Ficheiro de modelo Backend Aceleração de hardware
.onnx, .ort Tempo de execução do ONNX Fornecedores de execução (EPs) que o Windows instala e mantém atualizados através do catálogo de EPs do Windows ML
.gguf llama.cpp llama.cpp módulos implementados com a tua aplicação: um módulo CPU no pacote e um módulo CUDA opcional para GPUs NVIDIA. CPU e CUDA são os únicos backends de llama.cpp que o Windows ML valida para esta versão.

Os backends diferem no que uma fase pode expressar:

Capacidade Tempo de execução do ONNX llama.cpp
Forma do palco Qualquer grafo ONNX; vários estágios podem ser ligados num único pipeline Um estágio do descodificador por ficheiro GGUF: IDs de token em (entrada 0), logits à saída (saída 0)
Estado da sequência (cache KV) Declare emparelhamentos do tensor de estado com IWinMLStatefulStageOptions; o Runtime gere-os Gerido pelo backend; nada a declarar
Comprimento do contexto SetSequenceCapacityHint antes de Build, ou da capacidade declarada do modelo SetSequenceCapacityHint antes de Build define o comprimento do contexto do llama.cpp
Opções de fixação do fornecedor e estágio ORT Suportado (WinMLRuntimeOrt.h) Não suportado; Build retorna HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)
Relatório de posicionamento após Build IWinMLOrtStageDiagnostics Lista os fornecedores solicitados e selecionados IWinMLStage::GetExecutionTarget comunica CPU ou GPU

Um pipeline pode misturar backends. Por exemplo, uma etapa Whisper em tempo de execução ONNX pode alimentar um modelo de linguagem GGUF em llama.cpp.

Alvos de execução

IWinMLExecutionTarget é um token de colocação imutável que solicita uma classe de hardware e, opcionalmente, um adaptador específico. Cada backend resolve isso quando Build é executado:

Destino do stage Tempo de execução do ONNX llama.cpp
nullptr passado a AddModelStage A seleção automática seleciona um EP compatível com GPU quando disponível, com fallback para CPU. Transfere o processamento para o módulo CUDA quando existir um e o modelo encaixa; caso contrário, corre na CPU.
CreateCpuExecutionTarget Seleciona um CPU EP compatível, tendo o fornecedor de CPU da ORT como referência. Funciona no CPU.
CreateExecutionTarget com o tipo da GPU, CreateExecutionTargetFromAdapter, ou CreateExecutionTargetFromD3D12 Mapeia a identidade do adaptador para um dispositivo GPU EP compatível. Se nenhum dispositivo do provedor corresponder, Build falha. Requer pelo menos uma transferência parcial para o módulo CUDA. Build retorna HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED) quando nenhum módulo CUDA é implantado e HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY) quando o modelo não cabe. O módulo escolhe a GPU; a identidade do adaptador não é utilizada.
CreateExecutionTarget com o tipo NPU, ou um adaptador NPU Mapeia para um dispositivo NPU EP compatível. Não é suportado; Build retorna HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED).
IWinMLOrtCompatibility::CreateExecutionTarget(provider, kind, hardwareTarget) Afixa um EP registado. Com hardwareTarget definido para nullptr, o Runtime emparelha o provider com um dos seus próprios dispositivos; num PC com duas GPUs, isto evita emparelhar o provider com um adaptador que o provider não suporta. Não suportado; Build retorna HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED).

IWinMLRuntime::CreateExecutionTarget(kind, preference) escolhe um adaptador da classe solicitada sem exigir que enumere os dispositivos por si próprio, e preference classifica os adaptadores quando há mais do que um, por exemplo, uma GPU integrada e uma discreta:

ComPtr<IWinMLExecutionTarget> target;
THROW_IF_FAILED(runtime->CreateExecutionTarget(
    WINML_EXECUTION_TARGET_KIND_GPU,
    WINML_EXECUTION_TARGET_PREFERENCE_PERFORMANCE,
    target.GetAddressOf()));

A seleção explícita de adaptadores requer que um fornecedor ONNX Runtime compatível exponha essa identidade de hardware através do ORT. Se nenhum dispositivo do fornecedor corresponder, Build falha em vez de selecionar silenciosamente outro adaptador ou CPU.

CreateExecutionTargetFromD3D12 mantém o dispositivo do chamador e a fila opcional no destino, mas a execução ORT usa apenas a identidade do adaptador para a seleção EP. O fornecedor ORT detém os seus recursos de execução, e a fila de comandos do chamador não é usada para submissão de ORT.

Um alvo D3D12 ainda expõe IWinMLD3D12ExecutionTarget através de QueryInterface. Reutilizar um destino explícito entre estágios expressa afinidade pelo mesmo adapter; destinos distintos tornam explícitos os limites de transferência.

Executar um modelo GGUF

  1. Carregue o ficheiro com LoadModelFromFile. A extensão .gguf seleciona llama.cpp. Para um modelo fragmentado, mantém todos os fragmentos numa pasta e carrega o primeiro fragmento.
  2. Adicione uma etapa de modelo com um destino de CPU, GPU ou nullptr. Para definir o comprimento do contexto, consulte IWinMLStatefulStageOptions a partir do stage e chame SetSequenceCapacityHint.
  3. Ligue para o Build. Depois, associe os IDs dos tokens do prompt à entrada 0, solicite a saída 0 e chame Run. Cada execução posterior recebe o token seguinte; o backend mantém a cache KV entre as execuções.
  4. Chama ResetExecutionState antes de uma sequência independente.
// Create the runtime and an execution target (CPU here; GPU also available).
ComPtr<IWinMLRuntime> runtime;
THROW_IF_FAILED(WinMLCreateRuntime(IID_PPV_ARGS(runtime.GetAddressOf())));
ComPtr<IWinMLExecutionTarget> target;
THROW_IF_FAILED(runtime->CreateCpuExecutionTarget(target.GetAddressOf()));

ComPtr<IWinMLModel> model;
THROW_IF_FAILED(runtime->LoadModelFromFile(
    L"C:\\models\\qwen2.5-0.5b-instruct.gguf", nullptr, model.GetAddressOf()));

ComPtr<IWinMLPipelineBuilder> builder;
THROW_IF_FAILED(runtime->CreatePipelineBuilder(builder.GetAddressOf()));

ComPtr<IWinMLStage> stage;
THROW_IF_FAILED(builder->AddModelStage(
    model.Get(), target.Get(), L"decoder", stage.GetAddressOf()));
THROW_IF_FAILED(stage->RequestOutput(0));

// Set the llama.cpp context length before Build.
ComPtr<IWinMLStatefulStageOptions> stateOptions;
THROW_IF_FAILED(stage->QueryInterface(IID_PPV_ARGS(stateOptions.GetAddressOf())));
THROW_IF_FAILED(stateOptions->SetSequenceCapacityHint(4096));

ComPtr<IWinMLPipeline> pipeline;
THROW_IF_FAILED(builder->Build(pipeline.GetAddressOf()));

// Bind token IDs to input 0 and run one token at a time; the backend keeps
// the KV cache between runs.
THROW_IF_FAILED(stage->BindInput(0, tokenIdsTensor.Get()));
THROW_IF_FAILED(pipeline->Run());

ComPtr<IWinMLTensor> logits;
THROW_IF_FAILED(stage->GetOutput(0, logits.GetAddressOf()));

// Start an independent sequence on the same pipeline.
THROW_IF_FAILED(pipeline->ResetExecutionState());

O tokenizador e a formatação de conversas vêm do ficheiro GGUF, por isso um modelo GGUF não precisa de ficheiros tokenizadores separados. Para saltar o ciclo de tokens, use a API de Geração de Texto, que funciona com os modelos GGUF e ONNX.

Configurar o backend llama.cpp

O backend llama.cpp é local por app. Quando um projeto opta por aderir, o pacote Windows ML NuGet copia o adaptador de llama.cpp do Runtime, o núcleo de llama.cpp e o módulo CPU ao lado da sua aplicação. A aceleração da GPU precisa do módulo opcional CUDA, construído para a mesma revisão do llama.cpp que o pacote e colocado ao lado da sua aplicação.

Para uma explicação de ambos os passos, veja as amostras de modelos GGUF e exemplos de llama.cpp.

Pipelines e fases

Constrói um pipeline com o one-shot IWinMLPipelineBuilder:

  1. Adicione estágios de modelo ou processador com os seus destinos de execução.
  2. Ligue portas de fase por índice ordinal.
  3. Clique em Build uma vez para congelar o gráfico, resolver a colocação e validar a compatibilidade.

Para dois estágios do modelo, adicione ambos os estágios, ligue o ordinal de saída do primeiro estágio ao ordinal de entrada do segundo estágio e construa uma vez. A tua aplicação fornece os modelos e associa quaisquer entradas externas. Não precisa de uma API de Runtime específica para o modelo: embedding, decodificador, pré-processamento de imagens e outras arquiteturas de aplicação usam as mesmas primitivas de estágio e de tensor.

Cada um IWinMLStage possui associações de entrada posicionais e expõe os seus tensores de saída correntes. As associações de entrada persistem ao longo das execuções. Invoque BindOutput antes da execução quando a sua aplicação fornece armazenamento de saída.

As capacidades opcionais da fase incluem alvo resolvido, esquema materializado, política de residência da saída e controlo do estado da sequência. Utilize QueryInterface para testar cada capacidade.

Execução do pipeline

IWinMLPipeline::Run executa o pipeline preparado de forma síncrona. Chame ResetExecutionState entre sequências independentes para limpar o estado gerido em tempo de execução.

Interfaces de execução opcionais fornecem submissão na timeline do dispositivo e repetição iterativa com contagem fixa quando o grafo construído e o backend selecionado as suportam. O caminho básico Run mantém-se como referência comum.

Tensores e trincos

IWinMLTensor representa dados tipados e multidimensionais. Criar tensores a partir de uma factory consultada a partir do alvo de execução para que o posicionamento dos tensores siga o posicionamento do alvo.

As fábricas abrangem bytes brutos, dados de imagem, dados de áudio, IDs de token e processadores tensoriais componíveis. Interfaces tensoriais opcionais expõem mutação, ligações de buffer D3D12 e sincronização.

Chame IWinMLTensor::Lock antes de aceder aos bytes tensoriais do CPU. O IWinMLTensorDataLock devolvido estabelece a janela de acesso à CPU, realiza o mapeamento ou sincronização necessário e é responsável pelo tempo de vida do ponteiro devolvido por GetData.

Compilação e pesos externos

A compilação antecipada é uma capacidade opcional de um alvo de execução, exposta através de IWinMLModelCompiler. Os artefactos compilados são recarregados através dos métodos normais de carregamento do modelo. As aplicações podem fornecer pesos externalizados através de IWinMLResourceMapReader.

Cargas de trabalho de texto

As cargas de trabalho de texto utilizam o mesmo runtime, target, pipeline, stage e primitivas de tensor. A sua aplicação pode possuir diretamente metadados do pacote de modelo, amostragem, política de paragem e acumulação de tokens gerados, ou usar a API de Geração de Texto para coordenar essas operações num pipeline de Runtime compatível.

IWinMLTokenizer fornece operações de codificação e decodificação de baixo nível. Um(a) IWinMLTokenizerDecoder mantém um cursor de descodificação incremental independente para uma sequência. A API de Geração de Texto adiciona sessões de geração de texto, opções, atualizações de streaming, cancelamento, razões de finalização e resultados concluídos sem alterar a propriedade dos objetos de Runtime subjacentes.

Compatibilidade com o ONNX Runtime

As interfaces opcionais em WinMLRuntimeOrt.h oferecem conveniências do ONNX:

  • IWinMLOrtCompatibility seleciona um fornecedor de execução do ONNX Runtime já registado.
  • IWinMLOrtModelSchema reflete os nomes de entrada e saída.
  • IWinMLOrtNamedBindings liga uma fase suportada por ORT pelo nome.
  • IWinMLOrtStageDiagnostics comunica os relatórios solicitados e os prestadores selecionados após Build.

Estas interfaces resolvem nomes e política do fornecedor durante a configuração. A execução continua a usar o mesmo contrato de pipeline posicional.

Consulte IWinMLOrtCompatibility do runtime para fixar um estágio de modelo ONNX num fornecedor de execução que já registou, em vez de deixar Build escolher um automaticamente:

ComPtr<IWinMLOrtCompatibility> ortCompatibility;
THROW_IF_FAILED(runtime->QueryInterface(IID_PPV_ARGS(ortCompatibility.GetAddressOf())));

ComPtr<IWinMLExecutionTarget> target;
THROW_IF_FAILED(ortCompatibility->CreateExecutionTarget(
    L"MyRegisteredProvider",
    WINML_EXECUTION_TARGET_KIND_GPU,
    /* hardwareTarget */ nullptr,
    target.GetAddressOf()));

Passar nullptr como hardwareTarget permite ao Runtime associar o fornecedor a um dos seus próprios dispositivos dessa classe de hardware; passar um IWinMLExecutionTarget existente para fixar o fornecedor a esse adaptador específico. Este destino não é suportado para .gguf etapas; Build retorna HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED).

Ver também