W przypadku Windows ML niektórzy dostawcy wykonawczy (EPs) są dynamicznie pobierani, instalowani i współużytkowani w całym systemie za pośrednictwem interfejsów API Windows ML i są automatycznie aktualizowani. Aby zobaczyć, jakie dostawcy wykonania są dostępni, zobacz Dostawcy wykonawcze systemu Windows ML.
Na tej stronie opisano sposób instalowania Windows ML EP na urządzeniu użytkownika przy użyciu katalogu EP. Aby zapoznać się z alternatywnym podejściem pakowania EP bezpośrednio w aplikacji, zobacz Bring your own EPs. Aby wybrać między tymi opcjami, zobacz Windows ML EPs vs. bring-your-own.
Po zainstalowaniu należy zarejestrować EP Windows ML w środowisku uruchomieniowym ONNX przed ich użyciem.
Uwaga / Notatka
Windows EPs uczenia maszynowego są pobierane przez Windows, gdy aplikacja wywołuje EnsureReadyAsync() lub EnsureAndRegisterCertifiedAsync(). W przypadku środowisk offline, z ograniczonym dostępem do sieci, zarządzanych lub ze ściśle przypiętymi wersjami zobacz Własne EP i EP Windows ML a własne EP.
Zainstaluj wszystkie zgodne EPs
Najprostszą opcją jest wywołanie EnsureAndRegisterCertifiedAsync(), które pobiera i instaluje wszystkie EP-y dostępne na urządzeniu użytkownika, a następnie rejestruje je wszystkie w ONNX Runtime w ramach jednego wywołania. Jeśli aplikacja wymaga większej kontroli nad wykrywaniem dostawców, pobieraniem lub rejestracją, zobacz poniżej Znajdź wszystkie zgodne EP i Zainstaluj konkretne EP.
Uwaga / Notatka
Przy pierwszym uruchomieniu ta metoda może potrwać kilka sekund, a nawet minut, w zależności od szybkości sieci i liczby EP-ów, które trzeba pobrać.
// 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();
Interfejsy API języka C nie obsługują pojedynczego EnsureAndRegisterCertifiedAsync() wywołania. Zamiast tego postępuj zgodnie z instrukcjami, aby pobrać i zarejestrować konkretny EP.
# Please DO NOT use this API. It won't register EPs to the python ort env.
Znajdź wszystkie zgodne EPs
Aby zobaczyć, które punkty końcowe (w tym nieinstalowane punkty końcowe) są dostępne dla urządzenia użytkownika, wywołaj metodę FindAllProviders().
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}")
Zwróconi dostawcy wykonywania będą się różnić w zależności od urządzenia użytkownika i dostępnych dostawców wykonywania. Na zgodnym urządzeniu Qualcomm bez zainstalowanych obecnie dostawców wykonywania powyższy kod generuje następujące dane wyjściowe...
QNNExecutionProvider: NotPresent
Każdy obiekt ExecutionProvider ma właściwość ReadyState , która wskazuje jego bieżący stan na urządzeniu. Zrozumienie tych stanów pomaga określić, jakie działania należy wykonać w aplikacji.
| ReadyState |
Definicja |
Dalsze kroki |
NotPresent |
EP nie jest zainstalowany na urządzeniu klienckim. |
Wywołaj metodę EnsureReadyAsync() , aby pobrać i zainstalować EP i dodać ją do grafu zależności środowiska uruchomieniowego aplikacji. |
NotReady |
Ep jest zainstalowany na urządzeniu klienckim, ale nie został dodany do grafu zależności środowiska uruchomieniowego aplikacji. |
Wywołaj metodę EnsureReadyAsync() , aby dodać EP do grafu zależności środowiska uruchomieniowego aplikacji. |
Ready |
EP jest zainstalowany na urządzeniu klienckim i został dodany do grafu zależności w czasie działania aplikacji. |
Wywołaj TryRegister() w celu zarejestrowania EP w środowisku uruchomieniowym ONNX. |
Instalowanie określonego EP
Jeśli istnieje określony element ExecutionProvider , którego aplikacja chce użyć, a jej element ReadyState to NotPresent, możesz pobrać i zainstalować go, wywołując polecenie EnsureReadyAsync().
Najpierw użyjesz FindAllProviders() do uzyskania wszystkich zgodnych providerów wykonania, a następnie możesz wywołać EnsureReadyAsync() na określonym ExecutionProvider w celu pobrania konkretnego providera wykonania i wywołać TryRegister() w celu zarejestrowania konkretnego providera wykonania.
// 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;
Najpierw użyjesz FindAllProviders() do uzyskania wszystkich zgodnych providerów wykonania, a następnie możesz wywołać EnsureReadyAsync() na określonym ExecutionProvider w celu pobrania konkretnego providera wykonania i wywołać TryRegister() w celu zarejestrowania konkretnego providera wykonania.
// 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;
Użyjesz metody WinMLEpCatalogFindProvider, aby poprosić o określonego dostawcę wykonywania, a następnie wywołać WinMLEpEnsureReady, przekazując WinMLEpHandle, aby pobrać określonego dostawcę wykonywania, a następnie użyć WinMLEpGetLibraryPathSize i WinMLEpGetLibraryPath, aby uzyskać ścieżkę do dostawcy wykonywania i zarejestrować go w środowisku uruchomieniowym ONNX za pomocą RegisterExecutionProviderLibrary.
#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);
Najpierw użyjesz find_all_providers() do uzyskania wszystkich zgodnych dostawców wykonywania, a następnie możesz wywołać ensure_ready_async() na określonym ExecutionProvider, aby pobrać tego konkretnego dostawcę wykonywania, a środowisko uruchomieniowe ONNX register_execution_provider_library posłuży do zarejestrowania tego konkretnego dostawcy wykonywania.
# 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
Obsługa wyników instalacji
EnsureReadyAsync() zwraca obiekt ExecutionProviderReadyResult. Sprawdź jego Stan przed utworzeniem sesji lub zarejestrowaniem dostawcy. Jeśli stan to Failure, sprawdź ExtendedError (HRESULT) i DiagnosticText, i zobacz Rozwiązywanie problemów z pobieraniem dostawcy wykonywania. Jeśli stan to InProgress, operacja nie została ukończona; przed kontynuowaniem poczekaj na wynik.
Instalacja z postępem
API do pobierania i instalowania EPs obejmują wywołania zwrotne, które zapewniają aktualizacje postępu, dzięki czemu można wyświetlać wskaźniki postępu, aby informować użytkowników.
// 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
Dalsze kroki
Po zainstalowaniu dostawców wykonywania, zobacz Rejestrowanie dostawców wykonywania Windows ML, aby dowiedzieć się, jak zarejestrować ich do użycia z środowiskiem uruchomieniowym ONNX.
Przykład aplikacji produkcyjnej
W przypadku aplikacji produkcyjnych oto przykład tego, co aplikacja może zrobić, aby dać sobie i użytkownikom kontrolę nad tym, kiedy nastąpi pobieranie. Przed zarejestrowaniem można sprawdzić, czy są dostępni nowi dostawcy wykonywania i warunkowo je pobrać:
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)
Zobacz także