Bagikan melalui


Panduan Windows ML

Tutorial singkat ini berjalan menggunakan Windows ML untuk menjalankan model klasifikasi gambar ResNet-50 di Windows, merinci akuisisi model dan langkah-langkah praproses. 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 Toolkit AI.

Kemudian Anda akan memuat model, menyiapkan tensor input, dan menjalankan inferensi menggunakan API Windows ML, 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 AI Toolkit (lihat mengonversi model ke format ONNX untuk informasi selengkapnya).

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

Akan melaksanakan runtime Windows ML:

  • Muat model.
  • Pilih secara dinamis penyedia eksekusi (EP) yang disediakan oleh IHV untuk model dan unduh EP tersebut dari Microsoft Store sesuai kebutuhan.
  • Jalankan inferensi pada model menggunakan EP.

Untuk referensi API, lihat Kelas OrtSessionOptions dan Microsoft::Windows::AI::MachineLearning::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 WinML to download and register Execution Providers
var catalog = Microsoft.Windows.AI.MachineLearning.ExecutionProviderCatalog.GetDefault();
Console.WriteLine("Ensuring and registering execution providers...");
await catalog.EnsureAndRegisterAllAsync();

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

Menjalankan inferensi

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

Lihat juga Mengonversi model dengan Toolkit AI 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 GitHub di sini.