panduan ML Windows

Tutorial singkat ini berjalan menggunakan ML Windows untuk menjalankan model klasifikasi gambar ResNet-50 pada Windows, merinci langkah-langkah akuisisi dan praproses model. Implementasi ini melibatkan pemilihan penyedia eksekusi secara dinamis untuk performa inferensi yang dioptimalkan.

Model ResNet-50 adalah model PyTorch yang ditujukan untuk klasifikasi gambar.

Dalam tutorial ini, Anda akan memperoleh model ResNet-50 dari Hugging Face, dan mengonversinya ke format QDQ ONNX dengan menggunakan Foundry Toolkit.

Kemudian Anda akan memuat model, menyiapkan tensor input, dan menjalankan inferensi menggunakan API ML Windows, termasuk langkah-langkah pasca-pemrosesan untuk menerapkan softmax, dan mengambil prediksi teratas.

Memperoleh model, dan pra-pemrosesan

Anda dapat memperoleh ResNet-50 dari Hugging Face (platform tempat komunitas ML berkolaborasi pada model, himpunan data, dan aplikasi). Anda akan mengonversi ResNet-50 ke format QDQ ONNX dengan menggunakan Foundry Toolkit (lihat mengonversi model ke format ONNX untuk informasi selengkapnya).

Tujuan dari kode contoh ini adalah untuk memanfaatkan runtime Windows ML untuk melakukan pengangkatan berat.

Runtime Windows ML akan:

  • Muat model.
  • Pilih secara dinamis penyedia eksekusi (EP) yang disediakan IHV yang diinginkan untuk model dan unduh EP-nya dari Microsoft Store, sesuai permintaan.
  • Jalankan inferensi pada model menggunakan EP.

Untuk referensi API, lihat OrtSessionOptions dan kelas ExecutionProviderCatalog .

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

Kompilasi EP

Jika model Anda belum dikompilasi untuk EP (yang mungkin bervariasi tergantung pada perangkat), model tersebut pertama-tama perlu dikompilasi untuk EP tersebut. Ini adalah proses satu kali. Contoh kode di bawah ini menanganinya dengan mengkompilasi model pada eksekusi pertama, lalu menyimpannya secara lokal. Eksekusi kode berikutnya mengambil versi yang dikompilasi, dan menjalankannya; menghasilkan inferensi cepat yang dioptimalkan.

Untuk referensi API, lihat Ort::ModelCompilationOptions struct, Ort::Status struct, dan 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");
            
// Set the paths to your converted ONNX model
// Use Foundry Toolkit to download and convert ResNet-50 to ONNX format: https://code.visualstudio.com/docs/intelligentapps/modelconversion
string modelPath = Path.Combine(executableFolder, "resnet50-v2-7.onnx");
string compiledModelPath = Path.Combine(executableFolder, "resnet50-v2-7-compiled.onnx");

// 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;

Menjalankan inferensi

Gambar input dikonversi ke format data tensor, lalu inferensi berjalan di atasnya. Meskipun ini adalah khas dari semua kode yang menggunakan ONNX Runtime, perbedaannya dalam hal ini adalah penggunaan ONNX Runtime secara langsung melalui Windows ML. Satu-satunya persyaratan adalah menambahkan #include <winml/onnxruntime_cxx_api.h> ke kode.

Lihat juga Mengonversi model dengan Foundry Toolkit untuk Visual Studio Code

Untuk referensi API, lihat Ort::Session struct, Ort::MemoryInfo struct, Ort::Value struct, Ort::AllocatorWithDefaultOptions struct, Ort::RunOptions struct.

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

Pemrosesan Lanjutan

Fungsi softmax diterapkan ke output mentah yang dikembalikan, dan data label digunakan untuk memetakan dan mencetak nama dengan lima probabilitas tertinggi.

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

Keluaran

Berikut adalah contoh jenis output yang diharapkan.

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

Sampel kode lengkap

Sampel kode lengkap tersedia di repositori WindowsAppSDK-Samples GitHub. Lihat WindowsML.