Idioma

Gerar texto com seu próprio modelo de idioma usando Windows ML

Importante

As APIs de geração de texto e runtime de Windows ML atualmente são experimentais e não têm suporte para uso em ambientes de produção. Os aplicativos que testam essas APIs não devem ser publicados na Microsoft Store.

Importante

As APIs de Geração de Texto e Runtime do Windows ML estão disponíveis no momento em C++ e Python; Atualmente, não há suporte para C#. Informe-nos se você está interessado em usar essas APIs do C# abrindo uma issue no repositório GitHub do Windows ML!

A API de Geração de Texto do Windows ML simplifica a execução da geração de texto em seu próprio modelo de linguagem. Ele manipula a tokenização, a decodificação autoregressiva, a saída por streaming e o cancelamento para você, além da Windows ML Runtime API, de forma semelhante a como o ONNX Runtime GenAI simplifica esse loop sobre o ONNX Runtime. O Windows não inclui um modelo para essa API; você escolhe, empacota e distribui o modelo — um arquivo ONNX ou GGUF, além de um tokenizador — com seu aplicativo.

Dica

Se você não precisar de um modelo específico e quiser apenas a geração de texto no dispositivo com um modelo gerenciado pela Microsoft, use uma das LLMs locais prontas para uso em vez disso.

Você ainda cria os objetos de Runtime subjacentes – o modelo, o destino de execução e o pipeline – e os passa para a sessão. A API não oculta o posicionamento de hardware; ela só remove a necessidade de escrever seu próprio loop de token.

Modelos com suporte

A API de geração de texto aceita:

  • Modelos ONNX (.onnx) ou no formato ORT (.ort), executados por meio do ONNX Runtime. O modelo deve expor uma entrada de ID de token, uma saída de logits e um par de tensores de estado de capacidade fixa que contém o cache de chave/valor e a posição da sequência. Você fornece uma origem do tokenizador separada (por exemplo, um tokenizer.json).
  • Modelos GGUF (.gguf) executados por meio do back-end llama.cpp. O tokenizador é incorporado ao modelo, portanto, nenhuma fonte do tokenizador separada é necessária.

As amostras validam esse contrato em relação à família de modelos Qwen2.5-0.5B-Instruct, exportada com um grafo específico da tarefa que empacota o cache de chave/valor e a posição da sequência em um único par de estado. Outros modelos de linguagem somente decodificador que expõem a mesma entrada de token, a saída de logits e o contrato de estado também devem funcionar.

Gerar texto

Uma sessão de geração de texto encapsula um tokenizador e um pipeline com estado (o modelo que possui o cache de chave/valor). Carregue o modelo e o tokenizador, descreva a entrada de token do modelo, a saída de logits e o contrato de estado e compile a sessão:

// Create the runtime and an execution target (CPU here; GPU/NPU also available).
ComPtr<IWinMLRuntime> runtime;
THROW_IF_FAILED(WinMLCreateRuntime(IID_PPV_ARGS(runtime.GetAddressOf())));
ComPtr<IWinMLExecutionTarget> target;
THROW_IF_FAILED(runtime->CreateCpuExecutionTarget(target.GetAddressOf()));

// Load your ONNX model and its tokenizer.
ComPtr<IWinMLModel> model;
THROW_IF_FAILED(runtime->LoadModelFromFile(
    L"C:\\models\\qwen2.5-0.5b-instruct\\task_model.onnx",
    nullptr,
    model.GetAddressOf()));
ComPtr<IWinMLTokenizer> tokenizer;
THROW_IF_FAILED(WinMLCreateTokenizerFromFile(
    L"C:\\models\\qwen2.5-0.5b-instruct\\tokenizer.json",
    tokenizer.GetAddressOf()));

// Describe the model's token input, logits output, and KV-cache state pair.
winml::tasks::text_generation::onnx::StateTensorPair stateTensorPairs[] = {{1, 1}};
winml::tasks::text_generation::Options options;
options.values = winml::tasks::MakeTextGenerationOptions(/* maxNewTokens */ 64);

winml::tasks::text_generation::onnx::BuildTextGenerationArguments arguments;
arguments.runtime = runtime.Get();
arguments.model = model.Get();
arguments.target = target.Get();
arguments.tokenizer = tokenizer.Get();
arguments.tokenInputName = L"input_ids";
arguments.outputName = L"logits";
arguments.debugName = L"my-text-generation";
arguments.stateTensorPairs = stateTensorPairs;
arguments.sequenceCapacityHint = 128;
arguments.outputKind = WINML_TEXT_GENERATION_OUTPUT_KIND_LOGITS;
arguments.eosPolicy = WINML_TEXT_GENERATION_EOS_POLICY_TOKENIZER_DEFAULT;
arguments.options = &options;

winml::tasks::text_generation::TextGeneration textGeneration;
THROW_IF_FAILED(winml::tasks::text_generation::onnx::BuildTextGeneration(
    arguments, textGeneration));

Chame GenerateText com um prompt para iniciar uma operação de streaming e, em seguida, efetue pull de fragmentos do fluxo retornado até que o fluxo informe a conclusão:

ComPtr<IWinMLCancellationSource> cancellation;
THROW_IF_FAILED(textGeneration.tasks->CreateCancellationSource(
    cancellation.GetAddressOf()));

ComPtr<IWinMLTextGenerationPullStream> stream;
THROW_IF_FAILED(textGeneration.session->GenerateText(
    L"The sky is often",
    textGeneration.options.Get(),
    cancellation.Get(),
    stream.GetAddressOf()));

// Pull generated text one fragment at a time until the stream completes.
WINML_TEXT_GENERATION_READ_STATUS status{};
UINT32 tokenId = 0;
LPCWSTR fragment = nullptr;
while (SUCCEEDED(stream->ReadNext(&status, &tokenId, &fragment)) &&
    status == WINML_TEXT_GENERATION_READ_STATUS_UPDATE)
{
    std::wprintf(L"%ls", fragment);
}

// The terminal result is the authoritative text, token counts, and finish reason.
ComPtr<IWinMLTextGenerationResult> result;
THROW_IF_FAILED(stream->GetResult(result.GetAddressOf()));

O relatório de resultado concluído:

  • O texto gerado completo e os IDs de tokens
  • Contagens de prompt e token gerado
  • Um motivo de término : um token de fim de sequência, um token de parada, o limite de token solicitado, a capacidade de sequência, o cancelamento ou um erro

C++ e Python

A API nativa é exposta por meio de WinMLTasks.h, e os auxiliares tipados em C++ em winml/tasks/text_generation/TextGeneration.hpp. Aplicativos Python usam a projeção windowsml.tasks junto com windowsml.runtime.

Os exemplos do Windows ML incluem um exemplo de geração de texto em C++ e Python. O exemplo mostra a configuração completa do Runtime ao lado da configuração de geração de texto para que você possa ver onde a abstração começa e como personalizar o fluxo de trabalho subjacente.

Consulte também