Windows ML útmutató

Ez a rövid oktatóanyag bemutatja, hogy Windows ML használatával futtathatja a ResNet-50 rendszerképbesorolási modellt Windows, részletezve a modellek beszerzésének és előfeldolgozásának lépéseit. Az implementáció magában foglalja a végrehajtási szolgáltatók dinamikus kiválasztását az optimalizált következtetési teljesítmény érdekében.

A ResNet-50 modell egy képosztályozásra szánt PyTorch-modell.

Ebben az útmutatóban a ResNet-50 modellt a Hugging Face-ről fogja hozzáférni, és a Foundry Toolkit használatával QDQ ONNX formátumba konvertálja.

Ezután betölti a modellt, előkészíti a bemeneti tenzorokat, és következtetést futtat az Windows ML API-k használatával, beleértve a softmax alkalmazásának utófeldolgozási lépéseit, és lekéri a legfontosabb előrejelzéseket.

A modell beszerzése és az előfeldolgozás

A ResNet-50-et az Hugging Face-ból szerezheti be (az a platform, ahol az ML-közösség modelleken, adatkészleteken és alkalmazásokon együttműködik). A ResNet-50-et QDQ ONNX formátumra konvertálja az Foundry Toolkit használatával (további információért tekintse meg a modellek ONNX formátumra konvertálását ).

Ennek a példakódnak a célja, hogy a Windows ML futtatókörnyezetet használja a legjelentősebb feladatok elvégzéséhez.

A Windows ML-futtatókörnyezet a következő lesz:

  • A modellt töltse be.
  • Dinamikusan válassza ki a modellhez az IHV által biztosított végrehajtási szolgáltatót (EP), és szükség esetén töltse le az EP-t a Microsoft Store-ból.
  • Futtassa a következtetést a modellen az EP használatával.

Az API-ra vonatkozó referencia: OrtSessionOptions és ExecutionProviderCatalog osztály.

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

Megjegyzés:

Ez az oktatóanyag egy egyhívásos beállítási útvonalat használ a végrehajtási szolgáltatók számára. Ha az alkalmazásnak meg kell vizsgálnia az elérhető szolgáltatókat, kezelnie kell a letöltéseket, vagy regisztrálnia kell egy adott szolgáltatót, lásd: Windows ML EP-k telepítése és Windows ML EP-k regisztrálása.

EP-összeállítás

Ha a modell még nincs lefordítva az EP-hez (ami az eszköztől függően változhat), a modellt először az adott EP-hez kell lefordítani. Ez egy egyszeri folyamat. Az alábbi példakód úgy kezeli, hogy az első futtatáskor összeállítja a modellt, majd helyben tárolja. A kód későbbi futtatásai felveszik a lefordított verziót, és futtatják azt; optimalizált gyors következtetést eredményez.

Api-referenciaként lásd : Ort::ModelCompilationOptions struct, Ort::Status struct és 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;

A következtetés futtatása

A bemeneti kép tenzoros adatformátummá lesz konvertálva, majd a következtetés fut rajta. Bár ez az ONNX Runtime-ot használó összes kódra jellemző, a különbség ebben az esetben az, hogy az ONNX Runtime közvetlenül a Windows ML-en keresztül van használva. Az egyetlen követelmény, hogy a #include <winml/onnxruntime_cxx_api.h> elemet hozzáadjuk a kódhoz.

Lásd még : Modell konvertálása a VS Code-hoz készült Foundry Toolkittel

API-referenciához lásd a Ort::Session struct, Ort::MemoryInfo struct, Ort::Value struct, Ort::AllocatorWithDefaultOptions struct, Ort::RunOptions struct dokumentációkat.

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

Utófeldolgozás

A rendszer a softmax függvényt alkalmazza a visszaadott nyers kimenetre, a címkeadatok pedig az öt legnagyobb valószínűségű nevek leképezésére és nyomtatására szolgálnak.

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

Kimenet

Íme egy példa a várható kimenet típusára.

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

Teljes kódminták

A teljes kódminták az WindowsAppSDK-Samples GitHub adattárban érhetők el. Lásd: WindowsML.