Udostępnij przez


Przewodnik po Windows ML

W tym krótkim samouczku przedstawiono procedurę używania usługi Windows ML do uruchamiania modelu klasyfikacji obrazów ResNet-50 w systemie Windows, szczegółowego uzyskiwania modelu i przetwarzania wstępnego. Implementacja obejmuje dynamiczne wybieranie dostawców wykonywania pod kątem zoptymalizowanej wydajności wnioskowania.

Model ResNet-50 jest modelem PyTorch przeznaczonym do klasyfikacji obrazów.

W tym samouczku uzyskasz model ResNet-50 z Hugging Face i przekonwertujesz go na format QDQ ONNX przy użyciu AI Toolkit.

Następnie załadujesz model, przygotujesz tensory wejściowe i uruchomisz wnioskowanie przy użyciu interfejsów API uczenia maszynowego systemu Windows, w tym kroków przetwarzania końcowego, aby zastosować program softmax i pobrać najlepsze przewidywania.

Uzyskiwanie modelu i wstępne przetwarzanie

ResNet-50 można zdobyć z Hugging Face (platformy, na której społeczność uczenia maszynowego współpracuje nad modelami, zestawami danych i aplikacjami). Przekonwertujesz format ResNet-50 na format QDQ ONNX przy użyciu zestawu narzędzi AI Toolkit (zobacz konwertowanie modeli na format ONNX , aby uzyskać więcej informacji).

Celem tego przykładowego kodu jest wykorzystanie środowiska wykonawczego ML Windows do wykonywania najtrudniejszej pracy.

Środowisko uruchomieniowe Windows ML będzie:

  • Załaduj model.
  • Dynamicznie wybiera preferowanego dostawcę wykonywania dostarczonego przez IHV (EP) dla modelu i pobierz jego EP ze sklepu Microsoft Store na żądanie.
  • Uruchom wnioskowanie na modelu przy użyciu EP.

Aby zapoznać się z dokumentacją interfejsu API, zobacz OrtSessionOptions oraz klasę 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);

Kompilacja EP

Jeśli model nie został jeszcze skompilowany dla EP (który może się różnić w zależności od urządzenia), najpierw należy skompilować model dla tego EP. Jest to jednorazowy proces. Poniższy przykładowy kod obsługuje go, kompilując model w pierwszym uruchomieniu, a następnie przechowując go lokalnie. Kolejne uruchomienia kodu wykorzystują skompilowaną wersję i uruchamiają ją, co prowadzi do zoptymalizowanych szybkich wnioskowań.

Aby uzyskać informacje o interfejsie API, zobacz Ort::ModelCompilationOptions, Ort::Status struct i 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;

Uruchamianie wnioskowania maszynowego

Obraz wejściowy jest przekształcany na format danych tensora, a następnie przeprowadzany jest proces wnioskowania na tym obrazie. Chociaż jest to typowe dla wszystkich kodów korzystających ze środowiska uruchomieniowego ONNX, różnica w tym przypadku polega na tym, że jest to środowisko uruchomieniowe ONNX bezpośrednio za pośrednictwem systemu Windows ML. Jedynym wymaganiem jest dodanie #include <winml/onnxruntime_cxx_api.h> do kodu.

Zobacz również Konwertowanie modelu za pomocą zestawu narzędzi AI Toolkit for VS Code

Aby uzyskać informacje o interfejsie API, zobacz 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);

Przetwarzanie końcowe

Funkcja softmax jest stosowana do zwracanych nieprzetworzonych danych wyjściowych, a dane etykiet są używane do mapowania i drukowania nazw z pięcioma najwyższymi prawdopodobieństwami.

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

Wynik

Oto przykład oczekiwanego rodzaju danych wyjściowych.

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

Pełne przykłady kodu

Pełne przykłady kodu są dostępne w repozytorium WindowsAppSDK-Samples GitHub. Zobacz WindowsML.