Windows ML では、特定の実行プロバイダー (IP) が Windows ML ExecutionProviderCatalog API を介してシステム全体で動的にダウンロード、インストール、共有され、 自動的に更新されます。 使用可能な IP を確認するには、「 サポートされている実行プロバイダー」を参照してください。
このページでは、ユーザーのデバイスに EP をインストールする方法について説明します。 インストールが完了したら、 実行プロバイダー を使用する前に ONNX Runtime に登録する必要があります。
互換性のあるすべての拡張パックをインストールする
初期開発では、 EnsureAndRegisterCertifiedAsync()を呼び出すだけで、ユーザーのデバイスで使用できるすべての IP をダウンロードしてインストールし、1 回の呼び出しですべての EP を ONNX ランタイムに登録することができます。 初回実行時には、ダウンロードする必要があるネットワーク速度と IP によっては、この方法に数秒または数分かかる場合があることに注意してください。
// Get the default ExecutionProviderCatalog
var catalog = ExecutionProviderCatalog.GetDefault();
// Ensure execution providers compatible with device are present (downloads if necessary)
// and then registers all present execution providers with ONNX Runtime
await catalog.EnsureAndRegisterCertifiedAsync();
// Get the default ExecutionProviderCatalog
winrt::Microsoft::Windows::AI::MachineLearning::ExecutionProviderCatalog catalog =
winrt::Microsoft::Windows::AI::MachineLearning::ExecutionProviderCatalog::GetDefault();
// Ensure execution providers compatible with device are present (downloads if necessary)
// and then registers all present execution providers with ONNX Runtime
catalog.EnsureAndRegisterCertifiedAsync().get();
C API は、1 つの EnsureAndRegisterCertifiedAsync() 呼び出しをサポートしていません。 代わりに、さらに下の手順に従って、特定の EP をダウンロードして登録します。
# Please DO NOT use this API. It won't register EPs to the python ort env.
互換性のあるすべての EP を見つける
FindAllProviders() メソッドを呼び出すと、ユーザーのデバイスで使用できる IP (インストールされていない IP を含む) を確認できます。
ExecutionProviderCatalog catalog = ExecutionProviderCatalog.GetDefault();
// Find all available EPs (including non-installed EPs)
ExecutionProvider[] providers = catalog.FindAllProviders();
foreach (var provider in providers)
{
Console.WriteLine($"{provider.Name}: {provider.ReadyState}");
}
auto catalog = ExecutionProviderCatalog::GetDefault();
// Find all available EPs (including non-installed EPs)
auto providers = catalog.FindAllProviders();
for (auto const& provider : providers)
{
std::wcout << provider.Name() << L": " << static_cast<int>(provider.ReadyState()) << std::endl;
}
#include <WinMLEpCatalog.h>
// Context structure to track enumeration state
struct EnumContext
{
bool needsDownload;
};
// Callback to check if any providers need downloading
BOOL CALLBACK CheckDownloadNeededCallback(
WinMLEpHandle ep,
const WinMLEpInfo* info,
void* context)
{
if (info == nullptr) return TRUE; // Skip invalid entries
EnumContext* ctx = static_cast<EnumContext*>(context);
if (info->readyState == WinMLEpReadyState_NotPresent)
{
ctx->needsDownload = true;
return FALSE; // Stop enumeration early
}
return TRUE; // Continue enumeration
}
void DiscoverProviders()
{
WinMLEpCatalogHandle catalog = nullptr;
HRESULT hr = WinMLEpCatalogCreate(&catalog);
if (FAILED(hr)) return;
EnumContext ctx = { false };
// Check if any providers need to be downloaded
WinMLEpCatalogEnumProviders(catalog, CheckDownloadNeededCallback, &ctx);
if (ctx.needsDownload)
{
// There are new EPs available; decide how your app wants to handle that.
// See "Install a specific EP" below for download and registration.
}
WinMLEpCatalogRelease(catalog);
}
# winml: winui3.microsoft.windows.ai.machinelearning
catalog = winml.ExecutionProviderCatalog.get_default()
# Find all available EPs (including non-installed EPs)
providers = catalog.find_all_providers()
for provider in providers:
print(f"{provider.name}: {provider.ready_state}")
返される実行プロバイダーは、ユーザーのデバイスと使用可能な実行プロバイダーによって異なります。 現在実行プロバイダーがインストールされていない互換性のある Qualcomm デバイスでは、上記のコードによって次の出力が出力されます。
QNNExecutionProvider: NotPresent
各 ExecutionProvider には、デバイス上の現在の状態を示す ReadyState プロパティがあります。 これらの状態を理解することは、アプリで実行する必要があるアクションを決定するのに役立ちます。
| ReadyState |
Definition |
次のステップ |
NotPresent |
EP はクライアント デバイスにインストールされていません。 |
EnsureReadyAsync()を呼び出して EP をダウンロードしてインストールし、アプリのランタイム依存関係グラフに追加します。 |
NotReady |
EP はクライアント デバイスにインストールされますが、アプリのランタイム依存関係グラフには追加されていません。 |
EnsureReadyAsync()を呼び出して、EP をアプリのランタイム依存関係グラフに追加します。 |
Ready |
EP はクライアント デバイスにインストールされ、アプリのランタイム依存関係グラフに追加されています。 |
TryRegister() を呼び出して、EP を ONNX Runtime に登録します。 |
特定の EP をインストールする
アプリで使用する特定の ExecutionProvider があり、その ReadyState が NotPresent場合は、 EnsureReadyAsync()を呼び出してダウンロードしてインストールできます。
最初に、FindAllProviders()を使用して互換性のあるすべての IP を取得します。その後、特定の EnsureReadyAsync() でを呼び出して特定の実行プロバイダーをダウンロードし、TryRegister()を呼び出して特定の実行プロバイダーを登録します。
// Download and install a NotPresent EP
var result = await provider.EnsureReadyAsync();
// Check that the download and install was successful
bool installed = result.Status == ExecutionProviderReadyResultState.Success;
最初に、FindAllProviders()を使用して互換性のあるすべての IP を取得します。その後、特定の EnsureReadyAsync() でを呼び出して特定の実行プロバイダーをダウンロードし、TryRegister()を呼び出して特定の実行プロバイダーを登録します。
// Download and install a NotPresent EP
auto result = provider.EnsureReadyAsync().get();
// Check that the download and install was successful
bool installed = result.Status() == ExecutionProviderReadyResultState::Success;
WinMLEpCatalogFindProvider メソッドを使用して特定の実行プロバイダーを要求し、WinMLEpEnsureReady で渡すを呼び出して特定の実行プロバイダーをダウンロードし、WinMLEpGetLibraryPathSizeとWinMLEpGetLibraryPathを使用して実行プロバイダーへのパスを取得し、RegisterExecutionProviderLibraryを使用して ONNX Runtime に登録できます。
#include <WinMLEpCatalog.h>
#include <onnxruntime_cxx_api.h>
#include <filesystem>
#include <string>
// Assumes an Ort::Env has already been created
// Ort::Env env(ORT_LOGGING_LEVEL_ERROR, "MyApp");
WinMLEpCatalogHandle catalog = nullptr;
HRESULT hr = WinMLEpCatalogCreate(&catalog);
if (FAILED(hr)) return;
// Find the QNN provider
WinMLEpHandle qnnProvider = nullptr;
hr = WinMLEpCatalogFindProvider(catalog, "QNN", nullptr, &qnnProvider);
if (SUCCEEDED(hr) && qnnProvider != nullptr)
{
// Ensure it's ready (download if necessary)
hr = WinMLEpEnsureReady(qnnProvider);
if (SUCCEEDED(hr))
{
// Get the library path for registration
size_t pathSize = 0;
WinMLEpGetLibraryPathSize(qnnProvider, &pathSize);
std::string libraryPathUtf8(pathSize, '\0');
WinMLEpGetLibraryPath(qnnProvider, pathSize, libraryPathUtf8.data(), nullptr);
// Register with ONNX Runtime
std::filesystem::path libraryPath(libraryPathUtf8);
env.RegisterExecutionProviderLibrary("QNN", libraryPath.wstring());
}
}
WinMLEpCatalogRelease(catalog);
最初に、find_all_providers()を使用して互換性のあるすべての IP を取得します。次に、特定の ensure_ready_async() でを呼び出して特定の実行プロバイダーをダウンロードし、ONNX Runtime のregister_execution_provider_libraryを使用して特定の実行プロバイダーを登録します。
# Download and install a NotPresent EP
result = provider.ensure_ready_async().get()
# Check that the download and install was successful
installed = result.status == winml.ExecutionProviderReadyResultState.SUCCESS
インストール進行中
AP をダウンロードしてインストールするための API には、進行状況の更新プログラムを提供するコールバックが含まれているため、進行状況インジケーターを表示してユーザーに通知することができます。
// Start the download and install of a NotPresent EP
var operation = provider.EnsureReadyAsync();
// Listen to progress callback
operation.Progress = (asyncInfo, progressInfo) =>
{
// Dispatch to UI thread (varies based on UI platform)
_dispatcherQueue.TryEnqueue(() =>
{
// progressInfo is out of 100, convert to 0-1 range
double normalizedProgress = progressInfo / 100.0;
// Display the progress to the user
Progress = normalizedProgress;
};
};
// Await for the download and install to complete
var result = await operation;
// Check that the download and install was successful
bool installed = result.Status == ExecutionProviderReadyResultState.Success;
// Start the download and install of a NotPresent EP
auto operation = provider.EnsureReadyAsync();
// Listen to progress callback
operation.Progress([this](auto const& asyncInfo, double progressInfo)
{
// Dispatch to UI thread (varies based on UI platform)
dispatcherQueue.TryEnqueue([this, progressInfo]()
{
// progressInfo is out of 100, convert to 0-1 range
double normalizedProgress = progressInfo / 100.0;
// Display the progress to the user
Progress(normalizedProgress);
});
});
// Await for the download and install to complete
auto result = operation.get();
// Check that the download and install was successful
bool installed = result.Status() == ExecutionProviderReadyResultState::Success;
#include <WinMLEpCatalog.h>
#include <WinMLAsync.h>
#include <iostream>
#include <format>
// Progress callback — called periodically during download
void CALLBACK OnProgress(WinMLAsyncBlock* async, double progress)
{
// progress is out of 100, convert to 0-1 range
double normalizedProgress = progress / 100.0;
// Display the progress to the user
std::cout << std::format("Progress: {:.0f}%\n", normalizedProgress * 100);
}
// Completion callback — called when the download finishes
void CALLBACK OnComplete(WinMLAsyncBlock* async)
{
HRESULT hr = WinMLAsyncGetStatus(async, FALSE);
if (SUCCEEDED(hr))
{
std::cout << "Download complete!\n";
}
else
{
std::cout << std::format("Download failed: 0x{:08X}\n", static_cast<uint32_t>(hr));
}
}
// Start the async download with progress
WinMLAsyncBlock async = {};
async.callback = OnComplete;
async.progress = OnProgress;
HRESULT hr = WinMLEpEnsureReadyAsync(ep, &async);
if (SUCCEEDED(hr))
{
// Wait for the async operation to complete
WinMLAsyncGetStatus(&async, TRUE);
}
WinMLAsyncClose(&async);
# Start the download and install of a NotPresent EP
operation = provider.ensure_ready_async()
# Listen to progress callback
def on_progress(async_info, progress_info):
# progress_info is out of 100, convert to 0-1 range
normalized_progress = progress_info / 100.0
# Display the progress to the user
print(f"Progress: {normalized_progress:.0%}")
operation.progress = on_progress
# Await for the download and install to complete
result = operation.get()
# Check that the download and install was successful
installed = result.status == winml.ExecutionProviderReadyResultState.SUCCESS
次のステップ
実行プロバイダーをインストールしたので、「 実行プロバイダーの登録 」を参照して、ONNX Runtime で使用するために実行プロバイダーを登録する方法を確認してください。
運用アプリの例
実稼働アプリケーションの場合、ダウンロードがいつ行われるかを自分とユーザーが制御できるように、アプリが実行する可能性のある操作の例を次に示します。 登録する前に、新しい実行プロバイダーが使用可能かどうかを確認し、条件付きでダウンロードできます。
using Microsoft.Windows.AI.MachineLearning;
var catalog = ExecutionProviderCatalog.GetDefault();
// Filter to the EPs our app supports/uses
var providers = catalog.FindAllProviders().Where(p =>
p.Name == "MIGraphXExecutionProvider" ||
p.Name == "VitisAIExecutionProvider" ||
p.Name == "OpenVINOExecutionProvider" ||
p.Name == "QNNExecutionProvider" ||
p.Name == "NvTensorRtRtxExecutionProvider"
);
if (providers.Any(p => p.ReadyState == ExecutionProviderReadyState.NotPresent))
{
// Show UI to user asking if they want to download new execution providers
bool userWantsToDownload = await ShowDownloadDialogAsync();
if (userWantsToDownload)
{
// Download all EPs
foreach (var p in providers)
{
if (p.ReadyState == ExecutionProviderReadyState.NotPresent)
{
// Ignore result handling here; production code could inspect status
await p.EnsureReadyAsync();
}
}
// And register all EPs
await catalog.RegisterCertifiedAsync();
}
else
{
// Register only already-present EPs
await catalog.RegisterCertifiedAsync();
}
}
using namespace winrt::Microsoft::Windows::AI::MachineLearning;
auto catalog = ExecutionProviderCatalog::GetDefault();
auto allProviders = catalog.FindAllProviders();
// Filter to the EPs our app supports/uses
std::vector<ExecutionProvider> targetProviders;
for (auto const& p : allProviders)
{
auto name = p.Name();
if (name == L"VitisAIExecutionProvider" ||
name == L"OpenVINOExecutionProvider" ||
name == L"QNNExecutionProvider" ||
name == L"NvTensorRtRtxExecutionProvider")
{
targetProviders.push_back(p);
}
}
bool needsDownload = false;
for (auto const& p : targetProviders)
{
if (p.ReadyState() == ExecutionProviderReadyState::NotPresent)
{
needsDownload = true;
break;
}
}
if (needsDownload)
{
// Show UI to user or check application settings to confirm download
bool userWantsToDownload = ShowDownloadDialog();
if (userWantsToDownload)
{
// Download only the missing target providers
for (auto const& p : targetProviders)
{
if (p.ReadyState() == ExecutionProviderReadyState::NotPresent)
{
// Ignore result handling here; production code could inspect status
p.EnsureReadyAsync().get();
}
}
// Register all (both previously present and newly downloaded) providers
catalog.RegisterCertifiedAsync().get();
}
else
{
// User deferred download; register only already-present providers
catalog.RegisterCertifiedAsync().get();
}
}
else
{
// All target EPs already present
catalog.RegisterCertifiedAsync().get();
}
#include <WinMLEpCatalog.h>
#include <onnxruntime_cxx_api.h>
#include <filesystem>
#include <string>
#include <cstring>
// List of provider names our app supports
const char* targetProviderNames[] = {
"VitisAIExecutionProvider",
"OpenVINOExecutionProvider",
"QNNExecutionProvider",
"NvTensorRtRtxExecutionProvider"
};
const size_t targetProviderCount = sizeof(targetProviderNames) / sizeof(targetProviderNames[0]);
bool IsTargetProvider(const char* name)
{
for (size_t i = 0; i < targetProviderCount; i++)
{
if (strcmp(name, targetProviderNames[i]) == 0)
return true;
}
return false;
}
// Context for enumeration callbacks
struct ProductionContext
{
bool needsDownload;
bool userWantsToDownload;
Ort::Env* env;
};
// Check if any target providers need downloading
BOOL CALLBACK CheckTargetProvidersCallback(
WinMLEpHandle ep,
const WinMLEpInfo* info,
void* context)
{
if (info == nullptr || info->name == nullptr) return TRUE; // Skip invalid entries
ProductionContext* ctx = static_cast<ProductionContext*>(context);
if (IsTargetProvider(info->name) && info->readyState == WinMLEpReadyState_NotPresent)
{
ctx->needsDownload = true;
}
return TRUE; // Continue to check all providers
}
// Download missing and register ready target providers
BOOL CALLBACK ProcessTargetProvidersCallback(
WinMLEpHandle ep,
const WinMLEpInfo* info,
void* context)
{
if (info == nullptr || info->name == nullptr) return TRUE; // Skip invalid entries
ProductionContext* ctx = static_cast<ProductionContext*>(context);
if (!IsTargetProvider(info->name))
return TRUE; // Skip non-target providers
// Download if user agreed and provider is not present
if (ctx->userWantsToDownload && info->readyState == WinMLEpReadyState_NotPresent)
{
WinMLEpEnsureReady(ep);
}
// Re-check state and register if ready
WinMLEpReadyState currentState;
WinMLEpGetReadyState(ep, ¤tState);
if (currentState == WinMLEpReadyState_Ready)
{
// Get the library path
size_t pathSize = 0;
WinMLEpGetLibraryPathSize(ep, &pathSize);
std::string libraryPathUtf8(pathSize, '\0');
WinMLEpGetLibraryPath(ep, pathSize, libraryPathUtf8.data(), nullptr);
// Register with ONNX Runtime
std::filesystem::path libraryPath(libraryPathUtf8);
ctx->env->RegisterExecutionProviderLibrary(info->name, libraryPath.wstring());
}
return TRUE;
}
void ProductionAppExample(Ort::Env& env, bool userWantsToDownload)
{
WinMLEpCatalogHandle catalog = nullptr;
HRESULT hr = WinMLEpCatalogCreate(&catalog);
if (FAILED(hr)) return;
ProductionContext ctx = { false, userWantsToDownload, &env };
// First pass: check if any target providers need downloading
WinMLEpCatalogEnumProviders(catalog, CheckTargetProvidersCallback, &ctx);
if (ctx.needsDownload && !userWantsToDownload)
{
// TODO: Show UI to user asking if they want to download
// ctx.userWantsToDownload = ShowDownloadDialog();
}
// Second pass: download (if requested) and register target providers
WinMLEpCatalogEnumProviders(catalog, ProcessTargetProvidersCallback, &ctx);
WinMLEpCatalogRelease(catalog);
}
# remove the msvcp140.dll from the winrt-runtime package.
# So it does not cause issues with other libraries.
from pathlib import Path
from importlib import metadata
site_packages_path = Path(str(metadata.distribution('winrt-runtime').locate_file('')))
dll_path = site_packages_path / 'winrt' / 'msvcp140.dll'
if dll_path.exists():
dll_path.unlink()
from winui3.microsoft.windows.applicationmodel.dynamicdependency.bootstrap import (
InitializeOptions,
initialize
)
import winui3.microsoft.windows.ai.machinelearning as winml
import onnxruntime as ort
with initialize(options=InitializeOptions.ON_NO_MATCH_SHOW_UI):
catalog = winml.ExecutionProviderCatalog.get_default()
# Filter EPs that the app supports
providers = [provider for provider in catalog.find_all_providers() if provider.name in [
'VitisAIExecutionProvider',
'OpenVINOExecutionProvider',
'QNNExecutionProvider',
'NvTensorRtRtxExecutionProvider'
]]
# Download and make ready missing EPs if the user wants to
if any(provider.ready_state == winml.ExecutionProviderReadyState.NOT_PRESENT for provider in providers):
# Ask the user if they want to download the missing packages
if user_wants_to_download:
for provider in [provider for provider in providers if provider.ready_state == winml.ExecutionProviderReadyState.NOT_PRESENT]:
provider.ensure_ready_async().get()
# Make ready the existing EPs
for provider in [provider for provider in providers if provider.ready_state == winml.ExecutionProviderReadyState.NOT_READY]:
provider.ensure_ready_async().get()
# Register all ready EPs
for provider in [provider for provider in providers if provider.ready_state == winml.ExecutionProviderReadyState.READY]:
ort.register_execution_provider_library(provider.name, provider.library_path)
こちらも参照ください