Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Important
Interfejsy API środowiska uruchomieniowego Windows ML są obecnie eksperymentalne i nie są obsługiwane do użycia w środowiskach produkcyjnych. Aplikacje, które wypróbują te interfejsy API, nie powinny być publikowane w sklepie Microsoft Store.
W tym samouczku przedstawiono standardową sekwencję interfejsu API środowiska uruchomieniowego bez określania sposobu, w jaki aplikacja uzyskuje lub pakuje swój model. Model może znajdować się w dowolnym miejscu, które aplikacja może odczytać; przekaż ścieżkę bezwzględną lub względną do LoadModelFromFile.
Poniższy pomocnik celowo zakłada model z jednym wejściem FLOAT32 o stałym kształcie. Dzięki temu kod alokacji tensora koncentruje się na interfejsie API środowiska uruchomieniowego i nie jest ograniczeniem produktu. Jeśli aplikacja używa swobodnych wymiarów, powiąż konkretne wymiary tensorowe przy każdym uruchomieniu; jeśli używa innych typów danych, utwórz pasujący bufor wejściowy.
Zanim rozpoczniesz
Konfigurowanie projektu języka C++ dla interfejsu API środowiska uruchomieniowego Windows ML. Potrzebujesz również modelu ONNX, którego kontrakt wejściowy rozumiesz.
Dodaj pomocnika do uruchamiania modelu
Dodaj następujące nagłówki i pomocnika RunModel do projektu:
// 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';
}
Przekaż docelowy cel wykonywania do AddModelStage i fabryki tensorów, aby zachować przygotowanie modelu i umieszczanie tensorów na tym samym obiekcie docelowym.
Lock ustanawia okno dostępu procesora CPU dla tensora danych wyjściowych. Wykonuje ono dowolne wymagane mapowanie lub synchronizację, a wskaźnik zwracany przez GetData pozostaje prawidłowy tylko wtedy, gdy outputLock istnieje.
Wywołaj pomocnika
Wywołaj metodę RunModel podając ścieżkę modelu. Na przykład następujące wmain akceptuje ścieżkę w wierszu polecenia:
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;
}
Skompiluj i uruchom aplikację:
.\x64\Release\RuntimeApp.exe C:\models\model.onnx
Zastąp ścieżkę ścieżką do swojego modelu. Zinterpretuj zwrócony tensor zgodnie ze schematem danych wyjściowych tego modelu; etykiety klasyfikacji, próbkowanie tokenów, wstępne przetwarzanie obrazów i inne zachowanie specyficzne dla modelu należą do Twojej aplikacji.