Dela via


Genomgång av Windows ML

I den här korta självstudien går vi igenom hur du använder Windows ML för att köra resNet-50-bildklassificeringsmodellen i Windows, med information om steg för modellförvärv och förbearbetning. Implementeringen innebär att dynamiskt välja exekveringsleverantörer för optimerad prestanda vid inferenser.

ResNet-50-modellen är en PyTorch-modell avsedd för bildklassificering.

I den här självstudien skaffar du ResNet-50-modellen från Hugging Face och konverterar den till QDQ ONNX-format med hjälp av AI Toolkit.

Sedan läser du in modellen, förbereder indata-tensorer och kör inferens med hjälp av Windows ML-API:er, inklusive efterprocessningssteg för att tillämpa softmax och hämta topprediktionerna.

Hämta modellen och förbearbeta

Du kan hämta ResNet-50 från Hugging Face (plattformen där ML-communityn samarbetar om modeller, datauppsättningar och appar). Du konverterar ResNet-50 till QDQ ONNX-format med hjälp av AI Toolkit (se konvertera modeller till ONNX-format för mer information).

Målet med den här exempelkoden är att använda Windows ML-körmiljön för att utföra tunga lyft.

Windows ML-körsystemet kommer att:

  • Läs in modellen.
  • Välj den IHV-tillhandahållna körningsprovidern (EP) dynamiskt för modellen och ladda ned dess EP från Microsoft Store på begäran.
  • Kör slutsatsdragning för modellen med hjälp av EP:n.

Api-referens finns i OrtSessionOptions och klassen 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);

EP-kompilering

Om din modell inte redan är kompilerad för EP:n (som kan variera beroende på enhet) måste modellen först kompileras mot den EP:n. Det här är en engångsprocess. Exempelkoden nedan hanterar den genom att kompilera modellen vid den första körningen och sedan lagra den lokalt. Efterföljande körningar av koden hämtar den kompilerade versionen och kör den. vilket resulterar i optimerade snabba slutsatsdragningar.

Api-referens finns i Ort::ModelCompilationOptions struct, Ort::Status struct och 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;

Köra slutsatsdragningen

Indatabilden konverteras till tensor-dataformat och sedan körs slutsatsdragningen på den. Detta är typiskt för all kod som använder ONNX Runtime, men skillnaden i det här fallet är att det är ONNX-körning direkt via Windows ML. Det enda kravet är att lägga #include <winml/onnxruntime_cxx_api.h> till koden.

Se även Konvertera en modell med AI Toolkit för VS Code

Api-referens finns i 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);

Efterbearbetning

Funktionen softmax tillämpas på returnerade råutdata och etikettdata används för att mappa och skriva ut namnen med de fem högsta sannolikheterna.

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

Utgång

Här är ett exempel på vilken typ av utdata som ska förväntas.

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

Fullständiga kodexempel

De fullständiga kodexemplen är tillgängliga på WindowsAppSDK-Samples GitHub-lagringsplats. Se WindowsML.