Průvodce Windows ML

Tento krátký kurz vás provede použitím nástroje Windows ML ke spuštění modelu klasifikace obrázků ResNet-50 na Windows, podrobně popisuje získání modelu a kroky předběžného zpracování. Implementace zahrnuje dynamické výběr poskytovatelů spouštění pro optimalizovaný výkon odvozování.

Model ResNet-50 je model PyTorch určený pro klasifikaci obrázků.

V tomto kurzu získáte model ResNet-50 z Hugging Face a převedete ho na formát QDQ ONNX pomocí sady Foundry Toolkit.

Pak načtete model, připravíte vstupní tensory a spustíte odvozování pomocí rozhraní API Windows ML, včetně kroků následného zpracování pro použití softmaxu a načtení hlavních předpovědí.

Získání modelu a předběžné zpracování

ResNet-50 můžete získat z Hugging Face (platforma, kde komunita ML spolupracuje na modelech, datových sadách a aplikacích). Převeďte ResNet-50 na formát QDQ ONNX pomocí sady Foundry Toolkit (další informace najdete v tématu Převod modelů do formátu ONNX ).

Cílem tohoto ukázkového kódu je využít modul runtime Windows ML k náročným operacím.

Prostředí Windows ML runtime:

  • Načtěte model.
  • Dynamicky vyberte preferovaného poskytovatele spouštění IHV (EP) pro model a stáhněte si jeho EP z Microsoft Store na vyžádání.
  • Spusťte odvození modelu pomocí EP.

Pro referenční informace k rozhraní API, viz OrtSessionOptions a třída 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);

Note

Tento návod používá postup nastavení jedním voláním pro poskytovatele spouštění. Pokud vaše aplikace potřebuje zjistit, kteří poskytovatelé jsou k dispozici, spravovat stahování nebo zaregistrovat konkrétního poskytovatele, viz Instalace EP Windows ML a Registrace EP Windows ML.

Kompilace EP

Pokud váš model ještě není zkompilovaný pro EP (který se může lišit v závislosti na zařízení), je nejprve potřeba model připravit pro tento EP. Jedná se o jednorázový proces. Níže uvedený ukázkový kód ho zpracuje kompilací modelu při prvním spuštění a jeho místním uložením. Následné spuštění kódu použije zkompilovanou verzi a spustí ji; výsledkem jsou optimalizované rychlé inference.

Referenční informace k rozhraní API viz Ort::ModelCompilationOptions struktura, Ort::Status struktura a 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;

Spuštění inferenčního procesu

Vstupní obrázek se převede do formátu tensorových dat a potom se na něm spustí inference. I když je to typické pro všechny kódy, které používají modul runtime ONNX, rozdíl v tomto případě spočívá v tom, že se jedná o modul runtime ONNX přímo prostřednictvím Windows ML. Jediným požadavkem je přidání #include <winml/onnxruntime_cxx_api.h> do kódu.

Viz Také informace o převodu modelu pomocí sady Foundry Toolkit pro VS Code

Referenční informace k rozhraní API naleznete v tématu 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);

Následné zpracování

Funkce softmax se aplikuje na vrácený surový výstup a data štítků se používají k určení a vytištění jmen s pěti nejvyššími pravděpodobnostmi.

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

Výstup

Tady je příklad očekávaného typu výstupu.

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

Kompletní ukázky kódu

Kompletní ukázky kódu jsou k dispozici v úložišti WindowsAppSDK-Samples GitHub. Viz WindowsML.