Spuštění modelu pomocí rozhraní API Windows ML Runtime

Important

Rozhraní API modulu Windows ML Runtime jsou v současné době experimentální a nejsou podporována pro použití v produkčních prostředích. Aplikace, které si tato rozhraní API vyzkouší, by se neměly publikovat do Microsoft Storu.

Tento návod ukazuje standardní sekvenci rozhraní Runtime API, aniž by stanovoval, jak vaše aplikace získává nebo balí svůj model. Model může být kdekoli, odkud může vaše aplikace číst; předejte absolutní nebo relativní cestu k LoadModelFromFile.

Pomocník níže záměrně předpokládá model s jedním vstupem FLOAT32 s pevným tvarem. Tím se kód pro přidělování tensorů zaměřuje na rozhraní API modulu runtime a nejedná se o omezení produktu. Pokud vaše aplikace používá volné rozměry, svažte konkrétní rozměry tensoru pro každé spuštění; pokud používá jiné datové typy, vytvořte odpovídající vstupní úložiště.

Než začnete

Nastavení projektu C++ pro rozhraní API Windows ML Runtime Potřebujete také model ONNX, jehož vstupnímu kontraktu rozumíte.

Přidání pomocného nástroje pro spouštění modelu

Přidejte do projektu následující hlavičky a pomocnou rutinu 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';
}

Předejte cíl provádění jak do AddModelStage, tak do továrny tensorů, aby se zachovala příprava modelu a umístění tensoru na stejném cíli.

Lock vytvoří okno pro přístup CPU k výstupnímu tenzoru. Provede jakékoli požadované mapování nebo synchronizaci a ukazatel vrácený GetData zůstane platný pouze v době, kdy outputLock je aktivní.

Zavolejte pomocníka

Zavolejte RunModel s cestou k modelu. Například následující wmain akceptuje cestu na příkazovém řádku:

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;
}

Zkompilujte a spusťte aplikaci:

.\x64\Release\RuntimeApp.exe C:\models\model.onnx

Nahraďte cestu svým modelem. Interpretujte vrácený tensor podle výstupního schématu daného modelu; popisky klasifikace, vzorkování tokenů, předběžné zpracování obrázků a další chování specifické pro model patří do vaší aplikace.

Další kroky