Windows ML ランタイム API の概念

Important

Windows ML ランタイム API は現在試験段階であり、運用環境での使用はサポートされていません。 この API を試しているアプリは、Microsoft Store に公開すべきではありません。

Windows ML ランタイム API は、Windows専用に構築されたネイティブのローカル AI 推論フレームワークです。 Windows ML Runtime API を使用すると、モデルの読み込み、ハードウェアへの配置、テンソルの所有権、パイプラインの構成、コンパイル、診断を明示的に制御できます。

Windowsで最適なモデル推論パフォーマンスを得るためにランタイム API を使用することをお勧めしますが、アプリを他のプラットフォームで実行する必要がある場合や、クロスプラットフォームの ONNX ランタイム コードを既に使用している場合は、Windows ML 経由で ONNX ランタイムを使用することもできます。

オブジェクトの組み合わせ方

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

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

すべてのメソッドは HRESULTを返し、すべてのインターフェイス ポインターは通常の COM 参照カウントに従います。 オプションの機能は、 QueryInterfaceで検出されます。使用できない機能は E_NOINTERFACEを返します。

Runtime

IWinMLRuntimeを使用してWinMLCreateRuntimeを作成します。 これを使用して、モデル成果物の読み込み、実行ターゲットの作成、パイプライン ビルダーの作成を行います。

モデルとスキーマ

IWinMLModel は不変で内部構造が隠蔽されたモデル成果物です。 LoadModelFromFile には、アプリが読み取れる任意の絶対パスまたは相対パスが指定できます。モデルの保存場所は、アプリのパッケージ構成によって決まります。

読み込みによって、成果物が認識され、構造的に読み取り可能であることが確認されます。 ターゲット互換性は、パイプライン ビルダーの Build メソッドが成功した後でコミットされます。

IWinMLModelSchemaを使用して、モデルの宣言された序数スキーマを反映します。 一部の ONNX アーティファクトでは、オプションの IWinMLOrtModelSchemaを介して名前も公開されますが、実行時の識別は位置指定のままです。

図形と演算子

宣言されたモデル スキーマには、 UINT64_MAXで表される自由ディメンションを含めることができます。 具体的な IWinMLTensor には、常に確定した寸法が設定されています。 ORT ベースのパイプラインでは、自由ディメンションに対して具象値をバインドして実行できます。

固定された、あるいは明示的に境界が定められた形状は、Build が互換性を検証し、安定したリソースを割り当て、リプレイまたはデバイス常駐型のイテレーションが有効であるかどうかを判断できるため、最適化設計の中心であり続けています。 また、実行バックエンド間で最も広範な互換性も提供します。 これは最適化と移植性の区別であり、宣言された ONNX スキーマに自由ディメンションが含まれるモデルの一括拒否ではありません。

標準の ONNX 演算子も同様に、バックエンドの移植性を向上させます。 モデルの読み込みが成功しても、すべてのターゲットがすべての演算子を実行できるわけではありません。 Build は互換性チェックです。

Backends

モデル ファイルによってバックエンドが選択されます。 アプリでは、どちらの方法でも同じランタイム オブジェクト (モデル、実行ターゲット、パイプライン ビルダー、ステージ、バインド、および Run) が使用されます。

モデルファイル Backend ハードウェアアクセラレーション
.onnx、.ort ONNX ランタイム Windows が Windows ML EP カタログを通じてインストールし、最新の状態に保つ実行プロバイダー (EP)
.gguf llama.cpp アプリと共にデプロイされたllama.cppモジュール: パッケージ内の CPU モジュールと、NVIDIA GPU 用のオプションの CUDA モジュール。 CPU と CUDA は、Windows ML がこのリリースで検証する唯一の llama.cpp バックエンドです。

バックエンドは、ステージで表現できる内容が異なります。

能力 ONNX ランタイム llama.cpp
ステージの形状 任意の ONNX グラフ。複数のステージを 1 つのパイプラインに接続できます GGUF ファイルごとに 1 つのデコーダー ステージ: トークン ID は (入力 0) に入り、logits は (出力 0) から出力される
シーケンス状態 (KV キャッシュ) IWinMLStatefulStageOptionsを使用して状態テンソル ペアを宣言します。ランタイムがそれらを管理します バックエンドが所有している、宣言すべき事項なし
コンテキストの長さ Build の前の SetSequenceCapacityHint、またはモデルの宣言された容量 SetSequenceCapacityHint を Build の前に置くと、llama.cpp のコンテキスト長が設定されます
プロバイダーのピン留めと ORT ステージ オプション サポート対象 (WinMLRuntimeOrt.h) サポートされていません、HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED) は Build を返します
Build 後の配置レポート IWinMLOrtStageDiagnostics は、要求されたプロバイダーと選択されたプロバイダーに名前を付けます IWinMLStage::GetExecutionTarget は CPU または GPU を報告します

1 つのパイプラインでバックエンドを混在させることができます。 たとえば、ONNX Runtime の Whisper ステージは、llama.cpp 上の GGUF 言語モデルに入力を渡すことができます。

実行ターゲット

IWinMLExecutionTarget は、ハードウェア クラスと、必要に応じて特定のアダプターを要求する不変の配置トークンです。 各バックエンドは、Build が実行された際にこれを解決します:

ステージのターゲット ONNX ランタイム llama.cpp
nullptr が AddModelStage に渡される 自動配置では、CPU フォールバックを使用して、使用可能な場合は互換性のある GPU EP が選択されます。 CUDA モジュールがデプロイされ、モデルの適合が完了している場合は、処理を CUDA モジュールにオフロードします。そうでない場合は、CPU 上で実行されます。
CreateCpuExecutionTarget ORT の CPU プロバイダーをベースラインとして使用して、互換性のある CPU EP を選択します。 CPU 上で実行されます。
GPU の種類が CreateExecutionTarget の場合、CreateExecutionTargetFromAdapter または CreateExecutionTargetFromD3D12 アダプター ID を互換性のある GPU EP デバイスにマップします。 一致するプロバイダー デバイスがない場合、Build は失敗します。 CUDA モジュールへの少なくとも部分的なオフロードが必要です。 Build は、CUDA モジュールがデプロイされていない場合は HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED) を返し、モデルが適合しない場合は HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY) を返します。 モジュールは GPU を選択します。アダプターの識別情報は使用されません。
NPU 搭載モデル、または NPU アダプターを備えた CreateExecutionTarget 互換性のある NPU EP デバイスにマップされます。 サポート対象外です; Build は HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)を返します。
IWinMLOrtCompatibility::CreateExecutionTarget(provider, kind, hardwareTarget) 1 つの登録済み EP をピン留めしました。 hardwareTarget を nullptr に設定すると、ランタイムはプロバイダを自身のデバイスのいずれかとペアリングします。GPU が 2 つ搭載された PC では、これにより、プロバイダがサポートしていないアダプタとのペアリングが回避されます。 サポートされていません; Build は HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)を返します。

IWinMLRuntime::CreateExecutionTarget(kind, preference) では、デバイスを自分で列挙しなくても要求されたクラスのアダプターを選択し、 preference は、統合 GPU や個別 GPU など、複数ある場合にアダプターをランク付けします。

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

アダプタを明示的に選択するには、ORT を通じてそのハードウェア識別子を公開できる互換性のある ONNX Runtime プロバイダが必要です。 プロバイダー デバイスが一致しない場合は、別のアダプターまたは CPU を暗黙的に選択するのではなく、Build が失敗します。

CreateExecutionTargetFromD3D12 は、呼び出し元のデバイスとオプションのキューをターゲットに保持しますが、ORT の実行では EP の選択にアダプター ID のみが使用されます。 ORT プロバイダーは実行リソースを所有しており、呼び出し元のコマンド キューは ORT 送信には使用されません。

D3D12 ターゲットは引き続き QueryInterface から IWinMLD3D12ExecutionTarget までを公開します。 ある明示的なターゲットを複数のステージで再利用することで、同じアダプターへの親和性が表され、異なるターゲットを用いることで転送の境界が明確になります。

GGUF モデルを実行する

  1. LoadModelFromFileを使用してファイルを読み込みます。 .gguf 拡張子は llama.cpp を選択します。 シャード化されたモデルの場合は、すべてのシャードを 1 つのフォルダーに保持し、最初のシャードを読み込みます。
  2. CPU、GPU、または nullptr ターゲットを備えたモデル ステージを 1 つ追加します。 コンテキストの長さを設定するには、ステージから IWinMLStatefulStageOptions を取得し、SetSequenceCapacityHint を呼び出します。
  3. Buildを呼び出します。 次に、プロンプトのトークン ID を入力 0 にバインドし、出力 0 を要求し、 Runを呼び出します。 以降の各実行は、次のトークンを受け取ります。バックエンドは、実行の間に KV キャッシュを保持します。
  4. 独立したシーケンスの前に、ResetExecutionState を呼び出します。
// 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());

トークナイザーと会話の書式設定は GGUF ファイルから取得されるため、GGUF モデルでは個別のトークナイザー ファイルは必要ありません。 トークン ループをスキップするには、GGUF モデルと ONNX モデルで動作する Text Generation API を使用します。

llama.cpp バックエンドをデプロイする

llama.cpp バックエンドはアプリローカルです。 プロジェクトがオプトインすると、Windows ML NuGet パッケージによって、ランタイムの llama.cpp アダプター、llama.cpp コア、および CPU モジュールがアプリと同じディレクトリにコピーされます。 GPU アクセラレーションには、パッケージと同じllama.cppリビジョン用に構築され、アプリの横に配置されるオプションの CUDA モジュールが必要です。

両方の手順の詳細は、GGUF モデルのサンプルとllama.cppサンプルを参照してください。

パイプラインとステージ

ワンショット IWinMLPipelineBuilderを使用してパイプラインを構築します。

  1. モデルまたはプロセッサステージを、その実行対象とともに追加します。
  2. ステージポートを順序番号順に接続します。
  3. Build を 1 回呼び出すと、グラフが固定され、配置が確定し、互換性が検証されます。

2 つのモデルステージがある場合は、両方のステージを結合し、第 1 ステージの出力序数を第 2 ステージの入力序数に接続して、1 回ビルドします。 アプリはモデルを提供し、外部入力をバインドします。 モデル固有のランタイム API は必要ありません。埋め込み、デコーダー、イメージの前処理、その他のアプリケーション アーキテクチャでは、同じステージおよびテンソル プリミティブが使用されます。

各 IWinMLStage は、位置ごとの入力バインディングを持ち、現在の出力テンソルを公開します。 入力バインディングは実行間でも保持されます。 アプリが出力用ストレージを提供する場合は、実行前に BindOutput を呼び出します。

オプションのステージ機能には、解決済みターゲット、マテリアライズド スキーマ、出力配置ポリシー、シーケンス状態制御が含まれます。 QueryInterfaceを使用して、各機能をテストします。

パイプラインの実行

IWinMLPipeline::Run は、準備されたパイプラインを同期的に実行します。 独立したシーケンス間で ResetExecutionState を呼び出して、ランタイムマネージド状態をクリアします。

オプションの実行インターフェイスは、ビルドされたグラフと選択したバックエンドでサポートされている場合に、デバイス タイムラインの送信と固定カウント反復再生を提供します。 基本 Run パスは、共通のベースラインのままです。

テンソルとロック

IWinMLTensor は、型指定された多次元データを表します。 実行ターゲットに照会して取得したファクトリからテンソルを作成し、テンソル配置がターゲットの配置に従うようにします。

ファクトリーは、生バイト、画像データ、オーディオ データ、トークン ID、および構成可能なテンソル プロセッサに対応します。 オプションのテンソル インターフェースでは、変更操作、D3D12 バッファのバインド、および同期機能が提供されます。

CPU 上のテンソルのバイトデータにアクセスする前に、IWinMLTensor::Lock を呼び出します。 返された IWinMLTensorDataLock は、CPU アクセス ウィンドウを確立し、必要なマッピングまたは同期を実行し、 GetDataによって返されるポインターの有効期間を所有します。

コンパイルと外部重み

事前コンパイルは、 IWinMLModelCompilerを介して公開される実行ターゲットのオプション機能です。 コンパイルされた成果物は、通常のモデル読み込みメソッドを使用して再読み込みされます。 アプリは、IWinMLResourceMapReaderを通じて外部定義の重みを提供できます。

テキスト処理の負荷

テキスト ワークロードでは、同じランタイム、ターゲット、パイプライン、ステージ、テンソル プリミティブが使用されます。 アプリは、モデル パッケージのメタデータ、サンプリング、停止ポリシー、生成されたトークンの蓄積を直接管理することも、Text Generation API を使用して互換性のあるランタイム パイプラインを介してこれらの操作を調整することもできます。

IWinMLTokenizer では、低レベルのエンコードおよびデコード操作が提供されます。 IWinMLTokenizerDecoderは、1 つのシーケンスに対して独立した増分デコード カーソルを保持します。 Text Generation API は、基になるランタイム オブジェクトの所有権を変更せずに、テキスト生成セッション、オプション、ストリーミング更新、キャンセル、完了理由、完了した結果を追加します。

ONNX ランタイムの互換性

WinMLRuntimeOrt.h のオプションのインターフェースは、ONNX の利便性を提供します:

  • IWinMLOrtCompatibility は、既に登録されている ONNX ランタイム実行プロバイダーを選択します。
  • IWinMLOrtModelSchema は入力名と出力名を反映します。
  • IWinMLOrtNamedBindings は、ORT に基づくステージを名前でバインドします。
  • IWinMLOrtStageDiagnostics は、Build 以降に要求され、選定されたプロバイダーについて報告します。

これらのインターフェイスは、セットアップ時に名前とプロバイダー ポリシーを解決します。 実行では、同じ位置指定パイプライン コントラクトが引き続き使用されます。

Build に自動的に実行プロバイダーを選ばせるのではなく、ONNX モデルのステージをすでに登録済みの実行プロバイダーに固定するには、ランタイムから IWinMLOrtCompatibility をクエリします:

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()));

hardwareTarget として nullptr を渡すと、ランタイムはそのプロバイダを、そのハードウェア クラスに属する自身のデバイスのいずれかとペアリングします。代わりに、既存の IWinMLExecutionTarget を渡すと、そのプロバイダをその特定のアダプタに固定することができます。 このターゲットは、 .gguf ステージではサポートされていません。 Build は HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)を返します。

参照