次の方法で共有


Windows ML のチュートリアル

この短いチュートリアルでは、Windows ML を使用して Windows で ResNet-50 画像分類モデルを実行し、モデルの取得と前処理の手順について詳しく説明します。 実装には、推論のパフォーマンスを最適化するために実行プロバイダーを動的に選択する必要があります。

ResNet-50 モデルは、画像分類を目的とした PyTorch モデルです。

このチュートリアルでは、Hugging Face から ResNet-50 モデルを取得し、AI ツールキットを使用して QDQ ONNX 形式に変換します。

次に、モデルを読み込み、入力テンソルを準備し、Windows ML API を使用して推論を実行します。これには、softmax を適用する後処理手順を含め、上位の予測が取得されます。

モデルの取得と前処理

Hugging Face (ML コミュニティがモデル、データセット、アプリで共同作業を行うプラットフォーム) から ResNet-50 を入手できます。 AI ツールキットを使用して ResNet-50 を QDQ ONNX 形式に変換します (詳細については、 モデルを ONNX 形式に変換する を参照してください)。

このコード例の目的は、Windows ML ランタイムを利用して、負荷の高い作業を行うことです。

Windows ML ランタイムは次の動作を行います。

  • モデルを読み込みます。
  • モデルの優先 IHV 提供実行プロバイダー (EP) を動的に選択し、必要に応じて Microsoft Store からその EP をダウンロードします。
  • EP を使用してモデルで推論を実行します。

API リファレンスについては、 OrtSessionOptionsExecutionProviderCatalog クラスを参照してください。

// Create a new instance of EnvironmentCreationOptions
EnvironmentCreationOptions envOptions = new()
{
    logId = "ResnetDemo",
    logLevel = OrtLoggingLevel.ORT_LOGGING_LEVEL_ERROR
};

// Pass the options by reference to CreateInstanceWithOptions
OrtEnv ortEnv = OrtEnv.CreateInstanceWithOptions(ref envOptions);

// Use Windows ML to download and register Execution Providers
var catalog = Microsoft.Windows.AI.MachineLearning.ExecutionProviderCatalog.GetDefault();
Console.WriteLine("Ensuring and registering execution providers...");
await catalog.EnsureAndRegisterCertifiedAsync();

//Create Onnx session
Console.WriteLine("Creating session ...");
var sessionOptions = new SessionOptions();
// Set EP Selection Policy
sessionOptions.SetEpSelectionPolicy(ExecutionProviderDevicePolicy.MIN_OVERALL_POWER);

EP コンパイル

モデルがまだ EP 用にコンパイルされていない場合 (デバイスによって異なる場合があります)、まずその EP に対してモデルをコンパイルする必要があります。 これは 1 回限りのプロセスです。 次のコード例では、最初の実行時にモデルをコンパイルし、ローカルに格納することで処理します。 コードの後続の実行では、コンパイル済みのバージョンが選択され、実行されます。結果として、高速推論が最適化されます。

API リファレンスについては、 Ort::ModelCompilationOptions 構造体Ort::Status 構造体Ort::CompileModel に関するページを参照してください。

// Prepare paths
string executableFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location)!;
string labelsPath = Path.Combine(executableFolder, "ResNet50Labels.txt");
string imagePath = Path.Combine(executableFolder, "dog.jpg");
            
// TODO: Please use AITK Model Conversion tool to download and convert Resnet, and paste the converted path here
string modelPath = @"";
string compiledModelPath = @"";

// Compile the model if not already compiled
bool isCompiled = File.Exists(compiledModelPath);
if (!isCompiled)
{
    Console.WriteLine("No compiled model found. Compiling model ...");
    using (var compileOptions = new OrtModelCompilationOptions(sessionOptions))
    {
        compileOptions.SetInputModelPath(modelPath);
        compileOptions.SetOutputModelPath(compiledModelPath);
        compileOptions.CompileModel();
        isCompiled = File.Exists(compiledModelPath);
        if (isCompiled)
        {
            Console.WriteLine("Model compiled successfully!");
        }
        else
        {
            Console.WriteLine("Failed to compile the model. Will use original model.");
        }
    }
}
else
{
    Console.WriteLine("Found precompiled model.");
}
var modelPathToUse = isCompiled ? compiledModelPath : modelPath;

推論の実行

入力イメージはテンソル データ形式に変換され、その上で推論が実行されます。 これは ONNX ランタイムを使用するすべてのコードの一般的なものですが、この場合の違いは、Windows ML を介して直接 ONNX ランタイムであるということです。 唯一の要件は、コードに #include <winml/onnxruntime_cxx_api.h> を追加することです。

AI Toolkit for VS Code を使用したモデルの変換」も参照してください

API リファレンスについては、 Ort::Session 構造体Ort::MemoryInfo 構造体Ort::Value 構造体Ort::AllocatorWithDefaultOptions 構造体Ort::RunOptions 構造体を参照してください。

using var session = new InferenceSession(modelPathToUse, sessionOptions);

Console.WriteLine("Preparing input ...");
// Load and preprocess image
var input = await PreprocessImageAsync(await LoadImageFileAsync(imagePath));
// Prepare input tensor
var inputName = session.InputMetadata.First().Key;
var inputTensor = new DenseTensor<float>(
    input.ToArray(),          // Use the DenseTensor<float> directly
    new[] { 1, 3, 224, 224 }, // Shape of the tensor
    false                     // isReversedStride should be explicitly set to false
);

// Bind inputs and run inference
var inputs = new List<NamedOnnxValue>
{
    NamedOnnxValue.CreateFromTensor(inputName, inputTensor)
};

Console.WriteLine("Running inference ...");
var results = session.Run(inputs);
for (int i = 0; i < 40; i++)
{
    results = session.Run(inputs);
}

// Extract output tensor
var outputName = session.OutputMetadata.First().Key;
var resultTensor = results.First(r => r.Name == outputName).AsEnumerable<float>().ToArray();

// Load labels and print results
var labels = LoadLabels(labelsPath);
PrintResults(labels, resultTensor);

後処理

softmax 関数は返された生出力に適用され、ラベル データを使用して、5 つの確率が最も高い名前をマップして印刷します。

private static void PrintResults(IList<string> labels, IReadOnlyList<float> results)
{
    // Apply softmax to the results
    float maxLogit = results.Max();
    var expScores = results.Select(r => MathF.Exp(r - maxLogit)).ToList(); // stability with maxLogit
    float sumExp = expScores.Sum();
    var softmaxResults = expScores.Select(e => e / sumExp).ToList();

    // Get top 5 results
    IEnumerable<(int Index, float Confidence)> topResults = softmaxResults
        .Select((value, index) => (Index: index, Confidence: value))
        .OrderByDescending(x => x.Confidence)
        .Take(5);

    // Display results
    Console.WriteLine("Top Predictions:");
    Console.WriteLine("-------------------------------------------");
    Console.WriteLine("{0,-32} {1,10}", "Label", "Confidence");
    Console.WriteLine("-------------------------------------------");

    foreach (var result in topResults)
    {
        Console.WriteLine("{0,-32} {1,10:P2}", labels[result.Index], result.Confidence);
    }

    Console.WriteLine("-------------------------------------------");
}

アウトプット

期待される出力の種類の例を次に示します。

285, Egyptian cat with confidence of 0.904274
281, tabby with confidence of 0.0620204
282, tiger cat with confidence of 0.0223081
287, lynx with confidence of 0.00119624
761, remote control with confidence of 0.000487919

完全なコード サンプル

完全なコード サンプルは、WindowsAppSDK-Samples GitHub リポジトリで入手できます。 WindowsML を参照してください。