Important
Windows ML 런타임 API는 현재 실험적이며 프로덕션 환경에서 사용하도록 지원되지 않습니다. 이러한 API를 사용해보는 앱은 Microsoft Store에 게시해서는 안 됩니다.
이 자습서에서는 앱이 모델을 획득하거나 패키지하는 방법을 규정하지 않고 표준 런타임 API 시퀀스를 보여 줍니다. 모델은 앱에서 읽을 수 있는 모든 위치에 있을 수 있습니다. LoadModelFromFile에 절대 경로 또는 상대 경로를 전달합니다.
아래 도우미는 고정 셰이프 FLOAT32 입력이 하나 있는 모델을 의도적으로 가정합니다. 이로 인해 텐서 할당 코드는 런타임 API에 초점을 맞추며, 제품의 제한 사항은 아닙니다. 앱에서 자유 차원을 사용하는 경우 각 실행에 대해 구체적인 텐서 차원을 바인딩합니다. 다른 데이터 형식을 사용하는 경우 일치하는 입력 스토리지를 만듭니다.
시작하기 전 주의 사항:
Windows ML 런타임 API에 대한 C++ 프로젝트 설정을 완료하세요. 또한 입력 계약을 이해하고 있는 ONNX 모델도 필요합니다.
모델 실행 도우미 추가
프로젝트에 다음 헤더와 RunModel 도우미를 추가하세요.
// 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';
}
실행 대상을 AddModelStage와 텐서 팩터리 둘 다에 전달하여 모델 준비 및 텐서 배치를 동일한 대상에 유지합니다.
Lock 는 출력 텐서에 대한 CPU 액세스 창을 설정합니다. 필요한 매핑 또는 동기화를 수행하며, 반환된 GetData 포인터는 outputLock가 살아 있는 동안에만 유효합니다.
도우미를 호출하세요
RunModel를 모델 경로와 함께 호출합니다. 예를 들어 다음 wmain 명령은 명령줄에서 경로를 인수로 받습니다.
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;
}
앱을 빌드하고 실행합니다.
.\x64\Release\RuntimeApp.exe C:\models\model.onnx
경로를 모델로 바꾸세요. 반환된 텐서를 해당 모델의 출력 스키마에 따라 해석합니다. 분류 레이블, 토큰 샘플링, 이미지 전처리 및 기타 모델 관련 동작은 앱에서 처리해야 합니다.