Sdílet prostřednictvím


Průvodce Windows ML

Tento krátký kurz vás provede použitím Windows ML ke spuštění modelu klasifikace obrázků ResNet-50 ve 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 AI 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). Pomocí sady AI Toolkit převedete formát ResNet-50 na QDQ ONNX (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 úkolům.

Mod Runtime Windows ML bude:

  • Načtěte model.
  • Dynamicky vyberte preferovaného poskytovatele provádění IHV (EP) pro model a stáhněte si jeho EP z Microsoft Storu 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);

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

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 přes 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 AI 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 GitHubu. Viz WindowsML.