Windows ML-Runtime-API-Konzepte

Important

Die Windows ML-Runtime-API ist derzeit experimentell und wird für die Verwendung in Produktionsumgebungen nicht unterstützt. Apps, die diese API ausprobieren, sollten nicht im Microsoft Store veröffentlicht werden.

Die Windows ML-Runtime-API ist ein systemeigenes lokales KI-Inferencing-Framework, das speziell für Windows erstellt wurde. Mit der Windows ML-Runtime-API haben Sie explizite Kontrolle über das Laden von Modellen, Hardwareplatzierung, Tensorbesitz, Pipelinekomposition, Kompilierung und Diagnose.

Es wird empfohlen, die Laufzeit-API für die beste Inferenzleistung des Modells unter Windows zu verwenden. Wenn Ihre App jedoch auf anderen Plattformen ausgeführt werden muss oder Sie bereits plattformübergreifenden ONNX-Runtime-Code haben, können Sie auch ONNX-Runtime über Windows ML verwenden.

Zusammenpassen der Objekte

IWinMLRuntime
  |-- loads --> IWinMLModel
  |-- creates -> IWinMLExecutionTarget
  `-- creates -> IWinMLPipelineBuilder
                   |-- adds/connects -> IWinMLStage
                   `-- Build() ------> IWinMLPipeline

IWinMLExecutionTarget -- creates --> IWinMLTensor
IWinMLStage ----------- binds -----> IWinMLTensor
IWinMLPipeline -------- Run() -----> stage outputs

Jede Methode gibt HRESULT zurück, und jeder Schnittstellenzeiger folgt der normalen COM-Referenzzählung. Optionale Funktionen werden mit QueryInterface ermittelt; eine nicht verfügbare Funktion gibt E_NOINTERFACE zurück.

Runtime

Erstellen Sie IWinMLRuntime mit WinMLCreateRuntime. Verwenden Sie es, um Modellartefakte zu laden, Ausführungsziele zu erstellen und Pipeline-Builder zu erstellen.

Modelle und Schemata

IWinMLModel ist ein unveränderliches, opakes Modellartefakt. LoadModelFromFile akzeptiert einen absoluten oder relativen Dateipfad, den Ihre App lesen kann; der Speicherort des Modells hängt von der Paketierung Ihrer App ab.

Beim Laden wird überprüft, ob das Artefakt erkannt und strukturell lesbar ist. Die Zielkompatibilität wird später zugesichert, wenn die Methode des Build Pipeline-Builders erfolgreich abgeschlossen wird.

Spiegeln Sie das deklarierte ordinale Schema eines Modells über IWinMLModelSchema wider. Einige ONNX-Artefakte machen auch Namen über die optionale IWinMLOrtModelSchema verfügbar, aber die Ausführungsidentität bleibt positionsbasiert.

Formen und Operatoren

Ein deklariertes Modellschema kann freie Dimensionen enthalten, dargestellt durch UINT64_MAX. Ein konkretes IWinMLTensor hat immer aufgelöste Dimensionen. Auf ORT basierende Pipelines können eine freie Dimension an konkrete Werte binden und mit diesen ausführen.

Feste oder explizit gebundene Shapes bleiben der Optimierungsschwerpunkt, da sie Build die Kompatibilität validieren lassen, stabile Ressourcen zuordnen und bestimmen können, ob die Wiedergabe oder die geräteinterne Iteration legal ist. Sie bieten auch die größtmögliche Kompatibilität über Ausführungs-Back-Ends hinweg. Dies ist ein Unterschied in Bezug auf Optimierung und Portabilität, keine allgemeine Ablehnung von Modellen, deren deklariertes ONNX-Schema freie Dimensionen enthält.

Standardmäßige ONNX-Operatoren verbessern ebenfalls die Back-End-Portabilität. Ein erfolgreiches Laden eines Modells garantiert nicht, dass jedes Ziel jeden Operator ausführen kann; Build ist die Kompatibilitätsprüfung.

Backends

Die Modelldatei legt das Back-End fest. Ihre App verwendet in beiden Fällen dieselben Runtime-Objekte: Modell, Ausführungsziel, Pipeline-Generator, Phasen, Bindungen und Run.

Modelldatei Backend Hardwarebeschleunigung
.onnx, .ort ONNX Runtime Ausführungsanbieter (EPs), die Windows installiert und über den Windows ML EP-Katalog aktuell hält
.gguf llama.cpp llama.cpp Module, die mit Ihrer App bereitgestellt werden: ein CPU-Modul im Paket und ein optionales CUDA-Modul für NVIDIA GPUs. CPU und CUDA sind die einzigen llama.cpp-Backends, die Windows ML für diese Version validiert.

Die Back-Ends unterscheiden sich darin, was eine Stufe ausdrücken kann:

Fähigkeit ONNX Runtime llama.cpp
Bühnenform Beliebiger ONNX-Graph; mehrere Stufen können in einer Pipeline verbunden werden Eine Decoderstufe pro GGUF-Datei: Token-IDs in (Eingabe 0), Logits aus (Ausgabe 0)
Sequenzstatus (KV-Cache) Deklarieren Sie Zustands-Tensorpaare mit IWinMLStatefulStageOptions; die Runtime verwaltet sie. Vom Backend verwaltet; nichts zu deklarieren
Kontextlänge SetSequenceCapacityHint vor Build oder der deklarierten Kapazität des Modells SetSequenceCapacityHint bevor Build die llama.cpp-Kontextlänge festlegt
Optionen für Provider-Pinning und ORT-Phasenoptionen Unterstützt (WinMLRuntimeOrt.h) Nicht unterstützt; Build gibt HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED) zurück
Platzierungsreport nach Build IWinMLOrtStageDiagnostics benennt die angeforderten und ausgewählten Anbieter IWinMLStage::GetExecutionTarget meldet CPU oder GPU

Eine Pipeline kann Back-Ends kombinieren. Beispielsweise kann eine Whisper-Stufe auf der ONNX Runtime ein GGUF-Sprachmodell in llama.cpp einspeisen.

Ausführungsziele

IWinMLExecutionTarget ist ein unveränderliches Platzierungstoken, das eine Hardwareklasse und optional einen bestimmten Adapter anfordert. Jedes Back-End löst es beim Build Ausführen auf:

Stufenziel ONNX Runtime llama.cpp
nullptr übergeben an AddModelStage Die automatische Platzierung wählt ein kompatibles GPU-EP aus, wenn verfügbar, mit CPU-Fallback. Lagert an das CUDA-Modul aus, wenn ein CUDA-Modul verfügbar ist und das Modell passt; andernfalls wird auf der CPU ausgeführt.
CreateCpuExecutionTarget Wählt ein kompatibles CPU-EP mit dem CPU-Provider von ORT als Basis aus. Wird auf der CPU ausgeführt.
CreateExecutionTarget mit dem GPU-Typ, CreateExecutionTargetFromAdapter oder CreateExecutionTargetFromD3D12 Ordnet die Adapteridentität einem kompatiblen GPU-EP-Gerät zu. Wenn kein Anbietergerät übereinstimmt, Build schlägt fehl. Erfordert mindestens eine teilweise Auslagerung auf das CUDA-Modul. Build gibt HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED) zurück, wenn kein CUDA-Modul bereitgestellt wird, und HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY), wenn das Modell nicht passt. Das Modul wählt die GPU aus; die Adapteridentität wird nicht verwendet.
CreateExecutionTarget mit dem NPU-Typ oder einem NPU-Adapter Wird einem kompatiblen NPU-EP-Gerät zugeordnet. Nicht unterstützt; Build gibt zurück HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED).
IWinMLOrtCompatibility::CreateExecutionTarget(provider, kind, hardwareTarget) Fixiert ein registriertes EP. Bei Festlegung von hardwareTarget auf nullptr koppelt die Runtime den Provider mit einem seiner eigenen Geräte. Auf einem PC mit zwei GPUs verhindert dies die Kopplung des Providers mit einem Adapter, den der Provider nicht unterstützt. Nicht unterstützt; Build gibt zurück HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED).

IWinMLRuntime::CreateExecutionTarget(kind, preference) wählt einen Adapter der angeforderten Klasse aus, ohne dass Sie Geräte selbst auflisten müssen, und preference bewertet Adapter, wenn mehrere vorhanden sind, z. B. eine integrierte und eine diskrete GPU:

ComPtr<IWinMLExecutionTarget> target;
THROW_IF_FAILED(runtime->CreateExecutionTarget(
    WINML_EXECUTION_TARGET_KIND_GPU,
    WINML_EXECUTION_TARGET_PREFERENCE_PERFORMANCE,
    target.GetAddressOf()));

Die explizite Adapterauswahl erfordert einen kompatiblen ONNX-Runtime-Anbieter, um diese Hardwareidentität über ORT verfügbar zu machen. Wenn kein Anbietergerät übereinstimmt, schlägt Build fehl, anstatt stillschweigend einen anderen Adapter oder eine andere CPU auszuwählen.

CreateExecutionTargetFromD3D12 behält das Endgerät des Anrufers und die optionale Warteschlange auf dem Ziel bei, die ORT-Ausführung verwendet jedoch nur die Adapteridentität für die EP-Auswahl. Der ORT-Anbieter besitzt seine Ausführungsressourcen, und die Befehlswarteschlange des Aufrufers wird nicht für die ORT-Übermittlung verwendet.

Ein D3D12-Ziel stellt weiterhin über IWinMLD3D12ExecutionTarget bis QueryInterface bereit. Durch die Wiederverwendung eines expliziten Ziels über Stufen wird die Affinität zum selben Adapter ausgedrückt; unterschiedliche Ziele machen Übertragungsgrenzen explizit.

Ausführen eines GGUF-Modells

  1. Laden Sie die Datei mit LoadModelFromFile. Die .gguf Erweiterung verwendet llama.cpp. Behalten Sie für ein Sharded-Modell jeden Shard in einem Ordner bei, und laden Sie den ersten Shard.
  2. Fügen Sie eine Modellstufe mit einer CPU, GPU oder nullptr einem Ziel hinzu. Um die Kontextlänge festzulegen, fragen Sie IWinMLStatefulStageOptions bei der Stage ab und rufen Sie SetSequenceCapacityHint auf.
  3. Rufen Sie Buildauf. Binden Sie dann die Token-IDs der Eingabeaufforderung an Eingabe 0, fordern Sie Ausgabe 0 an und rufen Sie Run auf. Jede spätere Ausführung übernimmt das nächste Token; das Back-End hält den KV-Cache zwischen den Ausführungen.
  4. Rufen Sie ResetExecutionState vor einer eigenständigen Sequenz auf.
// Create the runtime and an execution target (CPU here; GPU also available).
ComPtr<IWinMLRuntime> runtime;
THROW_IF_FAILED(WinMLCreateRuntime(IID_PPV_ARGS(runtime.GetAddressOf())));
ComPtr<IWinMLExecutionTarget> target;
THROW_IF_FAILED(runtime->CreateCpuExecutionTarget(target.GetAddressOf()));

ComPtr<IWinMLModel> model;
THROW_IF_FAILED(runtime->LoadModelFromFile(
    L"C:\\models\\qwen2.5-0.5b-instruct.gguf", nullptr, model.GetAddressOf()));

ComPtr<IWinMLPipelineBuilder> builder;
THROW_IF_FAILED(runtime->CreatePipelineBuilder(builder.GetAddressOf()));

ComPtr<IWinMLStage> stage;
THROW_IF_FAILED(builder->AddModelStage(
    model.Get(), target.Get(), L"decoder", stage.GetAddressOf()));
THROW_IF_FAILED(stage->RequestOutput(0));

// Set the llama.cpp context length before Build.
ComPtr<IWinMLStatefulStageOptions> stateOptions;
THROW_IF_FAILED(stage->QueryInterface(IID_PPV_ARGS(stateOptions.GetAddressOf())));
THROW_IF_FAILED(stateOptions->SetSequenceCapacityHint(4096));

ComPtr<IWinMLPipeline> pipeline;
THROW_IF_FAILED(builder->Build(pipeline.GetAddressOf()));

// Bind token IDs to input 0 and run one token at a time; the backend keeps
// the KV cache between runs.
THROW_IF_FAILED(stage->BindInput(0, tokenIdsTensor.Get()));
THROW_IF_FAILED(pipeline->Run());

ComPtr<IWinMLTensor> logits;
THROW_IF_FAILED(stage->GetOutput(0, logits.GetAddressOf()));

// Start an independent sequence on the same pipeline.
THROW_IF_FAILED(pipeline->ResetExecutionState());

Die Tokenizer- und Unterhaltungsformatierung stammen aus der GGUF-Datei, sodass ein GGUF-Modell keine separaten Tokenizerdateien benötigt. Um die Tokenschleife zu überspringen, verwenden Sie die Textgenerierungs-API, die mit GGUF- und ONNX-Modellen funktioniert.

Llama.cpp-Backend bereitstellen

Das llama.cpp Backend ist anwendungslokal. Wenn ein Projekt sich dafür entscheidet, kopiert das Windows ML NuGet-Paket den llama.cpp-Adapter der Runtime, den llama.cpp-Kern und das CPU-Modul neben Ihre App. Die GPU-Beschleunigung benötigt das optionale CUDA-Modul, das für dieselbe llama.cpp Revision wie das Paket erstellt und neben Ihrer App platziert sein muss.

Eine exemplarische Vorgehensweise beider Schritte finden Sie in den GGUF-Modellbeispielen und llama.cpp Beispielen.

Pipelines und Stufen

Erstellen Sie eine Pipeline mit dem One-Shot IWinMLPipelineBuilder:

  1. Fügen Sie Modell- oder Prozessorphasen mit ihren Ausführungszielen hinzu.
  2. Verbinden Sie Stage-Ports nach Ordinalindex.
  3. Rufen Sie Build einmal auf, um das Diagramm zu fixieren, die Platzierung festzulegen und die Kompatibilität zu überprüfen.

Fügen Sie für zwei Modellphasen beide Phasen hinzu, verbinden Sie die Ausgabe-Ordnungszahl der ersten Modellphase mit dem Eingabe-Ordinal der zweiten Modellphase und führen Sie den Build einmal aus. Ihre App liefert die Modelle und bindet beliebige externe Eingaben. Es ist keine modellspezifische Laufzeit-API erforderlich: Einbettung, Decoder, Bildvorverarbeitung und andere Anwendungsarchitekturen verwenden die gleichen Stage- und Tensor-Primitiven.

Jede IWinMLStage besitzt positionsgebundene Eingabebindungen und macht ihre aktuellen Ausgabe-Tensoren verfügbar. Tastenbelegungen bleiben über mehrere Ausführungen hinweg bestehen. Rufen Sie BindOutput vor einem Ausführungsvorgang auf, wenn Ihre App Ausgabespeicher bereitstellt.

Optionale Stage-Funktionen umfassen aufgelöstes Ziel, materialisiertes Schema, Ausgabeaufbewahrungsrichtlinie und Sequenzstatussteuerung. Verwenden Sie QueryInterface, um jede Funktion zu testen.

Pipelineausführung

IWinMLPipeline::Run führt die vorbereitete Pipeline synchron aus. Rufen Sie ResetExecutionState zwischen unabhängigen Sequenzen auf, um den von der Laufzeit verwalteten Zustand zu löschen.

Optionale Ausführungsschnittstellen bieten die Übermittlung auf der Gerätezeitachse und die iterative Wiedergabe mit fester Anzahl, wenn der erstellte Graph und das ausgewählte Back-End diese unterstützen. Der grundlegende Run Pfad bleibt die allgemeine Basislinie.

Tensors und Locks

IWinMLTensor stellt typierte, mehrdimensionale Daten dar. Erstellen Sie Tensoren aus einer Factory, die vom Ausführungsziel abgefragt wurde, sodass die Tensorplatzierung der Zielplatzierung folgt.

Factory-Methoden decken rohe Bytes, Bilddaten, Audiodaten, Token-IDs und komponierbare Tensorprozessoren ab. Optionale Tensorschnittstellen machen Mutationen, D3D12-Pufferbindungen und Synchronisierung verfügbar.

Rufen Sie IWinMLTensor::Lock auf, bevor Sie auf Tensor-Bytes auf der CPU zugreifen. Das zurückgegebene IWinMLTensorDataLock stellt das CPU-Zugriffsfenster her, führt die erforderliche Zuordnung oder Synchronisierung durch und verwaltet die Lebensdauer des von GetData zurückgegebenen Zeigers.

Zusammenstellung und externe Gewichte

Die Vorabkompilierung ist eine optionale Funktion eines Ausführungsziels, das über IWinMLModelCompiler verfügbar gemacht wird. Kompilierte Artefakte werden über die normalen Modelllademethoden neu geladen. Apps können externalisierte Gewichte über IWinMLResourceMapReader bereitstellen.

Text-Workloads

Text-Workloads verwenden die gleichen Laufzeit-, Ziel-, Pipeline-, Phasen- und Tensor-Primitiven. Ihre App kann eigene Modellpaketmetadaten, Samplings, Abbruchrichtlinien und die generierte Tokenakkumulation direkt verwenden oder die Textgenerierungs-API verwenden, um diese Vorgänge über eine kompatible Laufzeitpipeline zu koordinieren.

IWinMLTokenizer stellt niedrigstufige Kodierungs- und Dekodierungsvorgänge bereit. Ein IWinMLTokenizerDecoder betreibt einen unabhängigen inkrementellen Decodierungscursor für eine Sequenz. Die Textgenerierungs-API fügt Sitzungen zur Textgenerierung, Optionen, Streamingupdates, Abbruch, Beendigungsgründe und abgeschlossene Ergebnisse hinzu, ohne den Besitz der zugrunde liegenden Runtime-Objekte zu ändern.

ONNX-Runtime-Kompatibilität

Die optionalen Schnittstellen in WinMLRuntimeOrt.h bieten ONNX-Vorteile:

  • IWinMLOrtCompatibility wählt einen bereits registrierten ONNX-Runtime-Execution Provider aus.
  • IWinMLOrtModelSchema spiegelt Eingabe- und Ausgabenamen wider.
  • IWinMLOrtNamedBindings bindet eine ORT-gesicherte Stage anhand des Namens.
  • IWinMLOrtStageDiagnostics Berichte zu angeforderten und ausgewählten Anbietern nach Build.

Diese Schnittstellen lösen Namen und Anbieterrichtlinien während des Setups auf. Die Ausführung verwendet weiterhin den gleichen positionsbezogenen Pipeline-Vertrag.

Fragen Sie IWinMLOrtCompatibility zur Laufzeit ab, um eine ONNX-Modellphase an einen bereits registrierten Ausführungsanbieter anzuheften, anstatt Build automatisch einen auswählen zu lassen:

ComPtr<IWinMLOrtCompatibility> ortCompatibility;
THROW_IF_FAILED(runtime->QueryInterface(IID_PPV_ARGS(ortCompatibility.GetAddressOf())));

ComPtr<IWinMLExecutionTarget> target;
THROW_IF_FAILED(ortCompatibility->CreateExecutionTarget(
    L"MyRegisteredProvider",
    WINML_EXECUTION_TARGET_KIND_GPU,
    /* hardwareTarget */ nullptr,
    target.GetAddressOf()));

Wenn hardwareTarget für nullptr übergeben wird, ordnet die Runtime den Anbieter einem ihrer eigenen Geräte dieser Hardwareklasse zu; übergeben Sie stattdessen einen vorhandenen IWinMLExecutionTarget, um den Anbieter an diesen bestimmten Adapter anzuheften. Dieses Ziel wird für .gguf Phasen nicht unterstützt; Build gibt zurück HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED).

Siehe auch