Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Importante
As APIs de runtime do 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.
Este tutorial mostra a sequência de API do Runtime padrão sem prescrever como seu aplicativo adquire ou empacota seu modelo. O modelo pode estar em qualquer lugar que seu aplicativo possa ler; passe um caminho absoluto ou relativo para LoadModelFromFile.
O auxiliar abaixo assume intencionalmente um modelo com uma entrada FLOAT32 de forma fixa. Isso mantém o código de alocação de tensor focado na API do Runtime e não é uma limitação do produto. Se seu aplicativo usar dimensões gratuitas, associe dimensões de tensor concretas para cada execução; se ele usar outros tipos de dados, crie um armazenamento de entrada correspondente.
Antes de começar
Conclua Configure um projeto C++ para a API Runtime ML do Windows. Você também precisa de um modelo ONNX cujo contrato de entrada você entende.
Adicionar um auxiliar de execução de modelo
Adicione esses cabeçalhos e o RunModel auxiliar ao seu projeto:
// Copyright (C) Microsoft Corporation. All rights reserved.
#include <Windows.h>
#include <cstdint>
#include <iostream>
#include <string>
#include <vector>
#include <winrt/base.h>
#include <WinMLRuntime.h>
#pragma comment(lib, "windowsapp.lib")
void RunModel(std::wstring const& modelPath)
{
winrt::com_ptr<IWinMLRuntime> runtime;
winrt::check_hresult(WinMLCreateRuntime(
__uuidof(IWinMLRuntime),
runtime.put_void()));
winrt::com_ptr<IWinMLModel> model;
winrt::check_hresult(runtime->LoadModelFromFile(
modelPath.c_str(),
nullptr,
nullptr,
model.put()));
winrt::com_ptr<IWinMLExecutionTarget> target;
winrt::check_hresult(runtime->CreateCpuExecutionTarget(target.put()));
winrt::com_ptr<IWinMLPipelineBuilder> builder;
winrt::check_hresult(runtime->CreatePipelineBuilder(builder.put()));
winrt::com_ptr<IWinMLStage> stage;
winrt::check_hresult(builder->AddModelStage(
model.get(),
target.get(),
L"model",
stage.put()));
winrt::com_ptr<IWinMLPipeline> pipeline;
winrt::check_hresult(builder->Build(pipeline.put()));
winrt::com_ptr<IWinMLModelSchema> schema;
winrt::check_hresult(model->QueryInterface(
__uuidof(IWinMLModelSchema),
schema.put_void()));
WINML_TENSOR_SCHEMA_DESC inputSchema = {};
winrt::check_hresult(schema->GetInputTensorDesc(0, &inputSchema));
if (inputSchema.dataType != WINML_TENSOR_DATA_TYPE_FLOAT32 ||
(inputSchema.dimensionCount > 0 &&
inputSchema.dimensions == nullptr))
{
winrt::throw_hresult(E_INVALIDARG);
}
UINT64 elementCount = 1;
for (UINT32 i = 0; i < inputSchema.dimensionCount; ++i)
{
const UINT64 dimension = inputSchema.dimensions[i];
if (dimension == 0 ||
dimension == UINT64_MAX ||
elementCount > UINT64_MAX / dimension)
{
winrt::throw_hresult(E_INVALIDARG);
}
elementCount *= dimension;
}
if (elementCount > SIZE_MAX)
{
winrt::throw_hresult(E_BOUNDS);
}
std::vector<float> inputData(
static_cast<size_t>(elementCount),
0.5f);
WINML_TENSOR_DESC inputDesc = {};
inputDesc.dataType = inputSchema.dataType;
inputDesc.dimensionCount = inputSchema.dimensionCount;
inputDesc.dimensions = inputSchema.dimensions;
winrt::com_ptr<IWinMLRawTensorFactory> tensorFactory;
winrt::check_hresult(target->QueryInterface(
__uuidof(IWinMLRawTensorFactory),
tensorFactory.put_void()));
winrt::com_ptr<IWinMLTensor> inputTensor;
winrt::check_hresult(tensorFactory->CreateTensor(
&inputDesc,
inputData.data(),
inputData.size() * sizeof(float),
inputTensor.put()));
winrt::check_hresult(stage->BindInput(0, inputTensor.get()));
winrt::check_hresult(pipeline->Run());
winrt::com_ptr<IWinMLTensor> outputTensor;
winrt::check_hresult(stage->GetOutput(0, outputTensor.put()));
winrt::com_ptr<IWinMLTensorDataLock> outputLock;
winrt::check_hresult(outputTensor->Lock(
WINML_TENSOR_LOCK_MODE_READ,
WINML_TENSOR_LOCK_FLAG_NONE,
outputLock.put()));
BYTE* outputBytes = nullptr;
UINT64 outputSizeInBytes = 0;
winrt::check_hresult(outputLock->GetData(
&outputBytes,
&outputSizeInBytes));
(void)outputBytes;
std::wcout << L"Output bytes: " << outputSizeInBytes << L'\n';
}
Passe o destino de execução tanto para AddModelStage quanto para a fábrica de tensores para manter a preparação do modelo e o posicionamento do tensor no mesmo destino.
Lock estabelece uma janela de acesso à CPU para o tensor de saída. Realize qualquer mapeamento ou sincronização necessária, e o ponteiro retornado por GetData permanece válido apenas enquanto outputLock estiver ativo.
Chame a função auxiliar
Chame RunModel com o caminho do modelo. Por exemplo, o seguinte wmain aceita o caminho na linha de comando:
int wmain(int argc, wchar_t** argv)
{
if (argc != 2)
{
std::wcerr << L"Usage: RuntimeApp.exe <model-path>\n";
return 1;
}
RunModel(argv[1]);
return 0;
}
Crie e execute o aplicativo:
.\x64\Release\RuntimeApp.exe C:\models\model.onnx
Substitua o caminho pelo seu modelo. Interprete o tensor retornado de acordo com o esquema de saída do modelo; rótulos de classificação, amostragem de tokens, pré-processamento de imagem e outros comportamentos específicos do modelo pertencem ao seu aplicativo.