Dela via


Distribuera modellen i Windows-appen med Windows ML API

Anmärkning

För större funktioner kan PyTorch också användas med DirectML i Windows.

I föregående del av den här självstudien lärde du dig hur du skapar och exporterar en modell i ONNX-format. Nu ska vi visa dig hur du bäddar in din exporterade modell i ett Windows-program och kör den lokalt på en enhet genom att anropa WinML-API:er.

När vi är klara har du en fungerande bildklassificeringsapp.

Om exempelappen

I det här steget i självstudien skapar du en app som kan klassificera bilder med hjälp av ML-modellen. Med det grundläggande användargränssnittet kan du välja en avbildning från din lokala enhet och använda den ONNX-klassificeringsmodell som du skapade och tränade i föregående del för att klassificera den. Taggarna som returneras av modellen visas sedan bredvid bilden.

Här går vi igenom den processen.

Anmärkning

Om du väljer att använda det fördefinierade kodexemplet kan du klona lösningsfilen. Klona förvaret, gå till det här exemplet och öppna filen classifierPyTorch.sln med Visual Studio. Hoppa till delen Starta programmet för att se den i användning.

Nedan visar vi hur du skapar din app och lägger till Windows ML-kod.

Skapa en Windows ML UWP (C#)

Om du vill skapa en fungerande Windows ML-app måste du göra följande:

  • Läs in en maskininlärningsmodell.
  • Läs in en bild i ett obligatoriskt format.
  • Binda modellens indata och utdata.
  • Utvärdera modellen och visa meningsfulla resultat.

Du måste också skapa ett grundläggande användargränssnitt eftersom det är svårt att skapa en tillfredsställande bildbaserad app på kommandoraden.

Öppna ett nytt projekt i Visual Studio

  1. Nu ska vi komma igång. Öppna Visual Studio och välj skapa ett nytt projekt.

Skapa ett nytt Visual Studio-projekt

  1. I sökfältet skriver du UWPoch väljer Blank APP (Universal Windows)sedan . Då öppnas ett C#-projekt för en enkelsidig UWP-app (Universal Windows Platform) med fördefinierade kontroller eller layout. Välj next för att öppna ett konfigurationsfönster för projektet.

Skapa ny UWP-app

  1. Gör följande i konfigurationsfönstret:
  • Ge projektet ett namn. Här kallar vi det classifierPyTorch.
  • Välj platsen för projektet.
  • Om du använder VS2019 kontrollerar du att Create directory for solution är markerad.
  • Om du använder VS2017, se till att Place solution and project in the same directory är avmarkerad.

Ny UWP-appkonfiguration

Tryck create för att skapa projektet. Det lägsta målversionsfönstret kan dyka upp. Kontrollera att din lägsta version är inställd på Windows 10, version 1809 (10.0; build 17763) eller senare.

  1. När projektet har skapats navigerar du till projektmappen, öppnar mappen [….\classifierPyTorch \Assets] och kopierar ImageClassifier.onnx filen till den här platsen.

Utforska projektlösning

Nu ska vi utforska din projektlösning.

Visual Studio skapade automatiskt flera cs-code-filer i Solution Explorer. MainPage.xaml innehåller XAML-koden för ditt GUI och MainPage.xaml.cs innehåller programkoden, även kallad code-behind. Om du har skapat en UWP-app tidigare bör dessa filer vara mycket bekanta för dig.

UWP-applösning

Skapa program-GUI

Först ska vi skapa ett enkelt GUI för din app.

  1. Dubbelklicka på MainPage.xaml kodfilen. I den tomma appen är XAML-mallen för appens GUI tom, så vi måste lägga till några gränssnittsfunktioner.

  2. Lägg till koden nedan i MainPage.xamloch ersätt taggarna <Grid> och </Grid> .

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 

        <StackPanel Margin="1,0,-1,0"> 
            <TextBlock x:Name="Menu"  
                       FontWeight="Bold"  
                       TextWrapping="Wrap" 
                       Margin="10,0,0,0" 
                       Text="Image Classification"/> 
            <TextBlock Name="space" /> 
            <Button Name="recognizeButton" 
                    Content="Pick Image" 
                    Click="OpenFileButton_Click"  
                    Width="110" 
                    Height="40" 
                    IsEnabled="True"  
                    HorizontalAlignment="Left"/> 
            <TextBlock Name="space3" /> 
            <Button Name="Output" 
                    Content="Result is:" 
                    Width="110" 
                    Height="40" 
                    IsEnabled="True"  
                    HorizontalAlignment="Left"  
                    VerticalAlignment="Top"> 
            </Button> 
            <!--Display the Result--> 
            <TextBlock Name="displayOutput"  
                       FontWeight="Bold"  
                       TextWrapping="Wrap" 
                       Margin="25,0,0,0" 
                       Text="" Width="1471" /> 
            <TextBlock Name="space2" /> 
            <!--Image preview --> 
            <Image Name="UIPreviewImage" Stretch="Uniform" MaxWidth="300" MaxHeight="300"/> 
        </StackPanel> 
    </Grid> 

Lägg till modellen i projektet med hjälp av Windows ML Code Generator (mlgen)

Windows Machine Learning Code Generator, eller mlgen, är ett Visual Studio-tillägg som hjälper dig att komma igång med WinML-API:er i UWP-appar. Den genererar mallkod när du lägger till en tränad ONNX-fil i UWP-projektet.

Windows Machine Learnings kodgenerator mlgen skapar ett gränssnitt (för C#, C++/WinRT och C++/CX) med omslutningsklasser som anropar Windows ML API åt dig. På så sätt kan du enkelt läsa in, binda och utvärdera en modell i projektet. Vi använder den i den här handledningen för att hantera många av dessa funktioner åt oss.

Kodgeneratorn är tillgänglig för Visual Studio 2017 och senare. Vi rekommenderar att du använder Visual Studio. Tänk på att mlgen i Windows 10 version 1903 och senare inte längre ingår i Windows 10 SDK, så du måste ladda ned och installera tillägget. Om du har följt den här handledningen från början har du redan hanterat det, men om du inte har gjort det borde du ladda ner VS 2019 eller VS 2017.

Anmärkning

Mer information om mlgen finns i mlgen-dokumentationen

  1. Om du inte redan har gjort det installerar du mlgen.

  2. Högerklicka på Assets mappen i Solution Explorer i Visual Studio och välj Add > Existing Item.

  3. Gå till mappen assets i classifierPyTorch [….\classifierPyTorch \Assets], leta reda på DEN ONNX-modell som du tidigare kopierade där och välj add.

  4. När du har lagt till en ONNX-modell i mappen assets i Solution Explorer i VS bör projektet nu ha två nya filer:

  • ImageClassifier.onnx – det här är din modell i ONNX-format.
  • ImageClassifier.cs – Automatiskt genererad WinML-kodfil.

ONNX-filer i din UWP-applösning

  1. För att se till att modellen byggs när du kompilerar vårt program väljer du ImageClassifier.onnx filen och väljer Properties. För Build Action väljer du Content.

ONNX-filkod

Nu ska vi utforska en nygenererad kod i ImageClassifier.cs filen.

Den genererade koden innehåller tre klasser:

  • ImageClassifierModel: Den här klassen innehåller två metoder för modellinstansiering och modellutvärdering. Det hjälper oss att skapa maskininlärningsmodellens representation, skapa en session på systemets standardenhet, binda specifika indata och utdata till modellen och utvärdera modellen asynkront.
  • ImageClassifierInput: Den här klassen initierar de indatatyper som modellen förväntar sig. Modellindata beror på modellkraven för indata.
  • ImageClassifierOutput: Den här klassen initierar de typer som modellen ska mata ut. Modellutdata beror på hur den definieras av modellen.

I den här handledningen vill vi inte bekymra oss om tensorisering. Vi gör en liten ändring i ImageClassifierInput klassen för att ändra indatatypen och göra vårt liv enklare.

  1. Gör följande ändringar i ImageClassifier.cs filen:

Ändra variabeln input från en TensorFloat till en ImageFeatureValue.

public sealed class ImageClassifierInput 
    { 
        public ImageFeatureValue input; // shape(-1,3,32,32) 
    } 

Läs in modellen

  1. Dubbelklicka på MainPage.xaml.cs filen för att öppna koden bakom för appen.

  2. Ersätt "using"-instruktionerna genom att följa för att få åtkomst till alla API:er som du behöver:

// Specify all the using statements which give us the access to all the APIs that we'll need 
using System; 
using System.Threading.Tasks; 
using Windows.AI.MachineLearning; 
using Windows.Graphics.Imaging; 
using Windows.Media; 
using Windows.Storage; 
using Windows.Storage.Pickers; 
using Windows.Storage.Streams; 
using Windows.UI.Xaml; 
using Windows.UI.Xaml.Controls; 
using Windows.UI.Xaml.Media.Imaging; 
  1. Lägg till följande variabeldeklarationer i MainPage klassen ovanför public MainPage() funktionen.
        // All the required fields declaration 
        private ImageClassifierModel modelGen; 
        private ImageClassifierInput image = new ImageClassifierInput(); 
        private ImageClassifierOutput results; 
        private StorageFile selectedStorageFile; 
        private string label = ""; 
        private float probability = 0; 
        private Helper helper = new Helper(); 

        public enum Labels 
        {             
            plane,
            car,
            bird,
            cat,
            deer,
            dog,
            frog,
            horse,
            ship,
            truck
        } 

Nu ska du implementera LoadModel metoden. Metoden kommer att komma åt ONNX-modellen och lagra den i minnet. Sedan använder CreateFromStreamAsync du metoden för att instansiera modellen som ett LearningModel objekt. Klassen LearningModel representerar en tränad maskininlärningsmodell. När du har instansierat LearningModel är det det första objektet som du använder för att interagera med Windows ML.

Om du vill läsa in modellen kan du använda flera statiska metoder i LearningModel klassen. I det här fallet kommer du att använda CreateFromStreamAsync-metoden.

Metoden CreateFromStreamAsync skapades automatiskt med mlgen, så du behöver inte implementera den här metoden. Du kan granska den här metoden genom att dubbelklicka på filen classifier.cs som genereras av mlgen.

Anmärkning

Mer information om LearningModel klassen finns i dokumentationen om LearningModel-klassen. Mer information om ytterligare sätt att läsa in modellen finns i dokumentationen Läsa in en modell

  1. Lägg till ett anrop till en loadModel metod i konstruktorn för huvudklassen.
        // The main page to initialize and execute the model.
        public MainPage()
        {
            this.InitializeComponent();
            loadModel();
        }
  1. Lägg till implementeringen av loadModel-metoden i MainPage-klassen.
        private async Task loadModel()
        {
            // Get an access the ONNX model and save it in memory.
            StorageFile modelFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri($"ms-appx:///Assets/ImageClassifier.onnx"));
            // Instantiate the model. 
            modelGen = await ImageClassifierModel.CreateFromStreamAsync(modelFile);
        }

Läs in avbildningen

  1. Vi måste definiera en klickhändelse för att initiera sekvensen med fyra metodanrop för modellkörning – konvertering, bindning och utvärdering, extrahering av utdata och visning av resultaten. Lägg till följande metod i MainPage.xaml.cs kodfilen i MainPage klassen.
        // Waiting for a click event to select a file 
        private async void OpenFileButton_Click(object sender, RoutedEventArgs e)
        {
            if (!await getImage())
            {
                return;
            }
            // After the click event happened and an input selected, begin the model execution. 
            // Bind the model input
            await imageBind();
            // Model evaluation
            await evaluate();
            // Extract the results
            extractResult();
            // Display the results  
            await displayResult();
        }
  1. Nu ska du implementera getImage() metoden. Den här metoden väljer en indatabildfil och sparar den i minnet. Lägg till följande metod i MainPage.xaml.cs kodfilen i MainPage klassen.
        // A method to select an input image file
        private async Task<bool> getImage()
        {
            try
            {
                // Trigger file picker to select an image file
                FileOpenPicker fileOpenPicker = new FileOpenPicker();
                fileOpenPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
                fileOpenPicker.FileTypeFilter.Add(".jpg");
                fileOpenPicker.FileTypeFilter.Add(".png");
                fileOpenPicker.ViewMode = PickerViewMode.Thumbnail;
                selectedStorageFile = await fileOpenPicker.PickSingleFileAsync();
                if (selectedStorageFile == null)
                {
                    return false;
                }
            }
            catch (Exception)
            {
                return false;
            }
            return true;
        }

Därefter implementerar du en bildmetod Bind() för att hämta representationen av filen i bitmappens BGRA8-format. Men först skapar du en hjälpklass för att ändra storlek på avbildningen.

  1. För att skapa en hjälpfil, högerklicka på lösningsnamnet (ClassifierPyTorch), välj sedan Add a new item. I det öppna fönstret väljer du Class och ger det ett namn. Här kallar vi det Helper.

Lägga till en hjälpfil

  1. En ny klassfil visas i projektet. Öppna den här klassen och lägg till följande kod:
using System; 
using System.Threading.Tasks; 
using Windows.Graphics.Imaging; 
using Windows.Media; 

namespace classifierPyTorch 
{ 
    public class Helper 
    { 
        private const int SIZE = 32;  
        VideoFrame cropped_vf = null; 
 
        public async Task<VideoFrame> CropAndDisplayInputImageAsync(VideoFrame inputVideoFrame) 
        { 
            bool useDX = inputVideoFrame.SoftwareBitmap == null; 

            BitmapBounds cropBounds = new BitmapBounds(); 
            uint h = SIZE; 
            uint w = SIZE; 
            var frameHeight = useDX ? inputVideoFrame.Direct3DSurface.Description.Height : inputVideoFrame.SoftwareBitmap.PixelHeight; 
            var frameWidth = useDX ? inputVideoFrame.Direct3DSurface.Description.Width : inputVideoFrame.SoftwareBitmap.PixelWidth; 
 
            var requiredAR = ((float)SIZE / SIZE); 
            w = Math.Min((uint)(requiredAR * frameHeight), (uint)frameWidth); 
            h = Math.Min((uint)(frameWidth / requiredAR), (uint)frameHeight); 
            cropBounds.X = (uint)((frameWidth - w) / 2); 
            cropBounds.Y = 0; 
            cropBounds.Width = w; 
            cropBounds.Height = h; 
 
            cropped_vf = new VideoFrame(BitmapPixelFormat.Bgra8, SIZE, SIZE, BitmapAlphaMode.Ignore); 
 
            await inputVideoFrame.CopyToAsync(cropped_vf, cropBounds, null); 
            return cropped_vf; 
        } 
    } 
} 

Nu ska vi konvertera bilden till rätt format.

Klassen ImageClassifierInput initierar de indatatyper som modellen förväntar sig. I vårt fall konfigurerade vi vår kod för att förvänta oss en ImageFeatureValue.

Klassen ImageFeatureValue beskriver egenskaperna för den bild som används för att överföra till en modell. För att skapa en ImageFeatureValue använder du CreateFromVideoFrame-metoden. Mer detaljerad information om varför detta är fallet och hur dessa klasser och metoder fungerar finns i dokumentationen för Klassen ImageFeatureValue

Anmärkning

I den här självstudien använder vi ImageFeatureValue-klassen istället för en tensor. Om Window ML inte stöder modellens färgformat är detta inte ett alternativ. Ett exempel på hur du arbetar med bildkonverteringar och tensorization finns i Exemplet på anpassad tensorisering.

  1. Lägg till implementeringen av metoden convert() till kodfilen för MainPage.xaml.cs i klassen MainPage. Konverteringsmetoden ger oss en representation av indatafilen i ett BGRA8-format.
// A method to convert and bide the input image. 
private async Task imageBind () 
{
    UIPreviewImage.Source = null; 
    try
    { 
        SoftwareBitmap softwareBitmap;
        using (IRandomAccessStream stream = await selectedStorageFile.OpenAsync(FileAccessMode.Read)) 
        {
            // Create the decoder from the stream
            BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
            // Get the SoftwareBitmap representation of the file in BGRA8 format
            softwareBitmap = await decoder.GetSoftwareBitmapAsync();
            softwareBitmap = SoftwareBitmap.Convert(softwareBitmap, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
        }
        // Display the image 
        SoftwareBitmapSource imageSource = new SoftwareBitmapSource();
        await imageSource.SetBitmapAsync(softwareBitmap);
        UIPreviewImage.Source = imageSource;

        // Encapsulate the image within a VideoFrame to be bound and evaluated
        VideoFrame inputImage = VideoFrame.CreateWithSoftwareBitmap(softwareBitmap);
        // Resize the image size to 32x32  
        inputImage=await helper.CropAndDisplayInputImageAsync(inputImage); 
        // Bind the model input with image 
        ImageFeatureValue imageTensor = ImageFeatureValue.CreateFromVideoFrame(inputImage); 
        image.modelInput = imageTensor; 

        // Encapsulate the image within a VideoFrame to be bound and evaluated
        VideoFrame inputImage = VideoFrame.CreateWithSoftwareBitmap(softwareBitmap); 
        // bind the input image 
        ImageFeatureValue imageTensor = ImageFeatureValue.CreateFromVideoFrame(inputImage); 
        image.modelInput = imageTensor; 
    }
    catch (Exception e) 
    {
    }
} 

Binda och utvärdera modellen

Därefter skapar du en session baserat på modellen, binder indata och utdata från sessionen och utvärderar modellen.

Skapa en session för att binda modellen:

Om du vill skapa en session använder LearningModelSession du klassen . Den här klassen används för att utvärdera maskininlärningsmodeller och binder modellen till en enhet som sedan kör och utvärderar modellen. Du kan välja en enhet när du skapar en session för att köra din modell på en specifik enhet på datorn. Standardenheten är processorn.

Anmärkning

Mer information om hur du väljer en enhet finns i dokumentationen skapa en session .

Bind modellindata och utdata:

Om du vill binda indata och utdata använder LearningModelBinding du klassen . En maskininlärningsmodell har indata- och utdatafunktioner som skickar information till och från modellen. Tänk på att nödvändiga funktioner måste stödjas av WINDOWS ML-API:er. Klassen LearningModelBinding tillämpas på en LearningModelSession för att binda värden till namngivna indata- och utdatafunktioner.

Implementeringen av bindningen genereras automatiskt av mlgen, så du behöver inte ta hand om den. Bindningen implementeras genom att anropa de fördefinierade metoderna för LearningModelBinding klassen. I vårt fall använder den Bind metoden för att binda ett värde till den namngivna funktionstypen.

Utvärdera modellen:

När du har skapat en session för att binda modellen och avgränsade värden till en modells indata och utdata kan du utvärdera modellens indata och få dess förutsägelser. Om du vill köra modellen bör du anropa någon av de fördefinierade utvärderingsmetoderna i LearningModelSession. I vårt fall använder EvaluateAsync vi metoden.

CreateFromStreamAsync EvaluateAsync På samma sätt genererades metoden också automatiskt av WinML Code Generator, så du behöver inte implementera den här metoden. Du kan granska den här metoden i ImageClassifier.cs filen.

Metoden EvaluateAsync utvärderar asynkront maskininlärningsmodellen med hjälp av de funktionsvärden som redan är bundna i bindningar. Den skapar en session med LearningModelSession, binder indata och utdata med LearningModelBinding, kör modellutvärderingen och hämtar utdatafunktionerna i modellen med hjälp av LearningModelEvaluationResult klassen .

Anmärkning

Om du vill veta mer om andra utvärdera metoder för att köra modellen kontrollerar du vilka metoder som kan implementeras på LearningModelSession genom att läsa dokumentationen om LearningModelSession Class.

  1. Lägg till följande metod i MainPage.xaml.cs kodfilen i klassen MainPage för att skapa en session, binda och utvärdera modellen.
        // A method to evaluate the model
        private async Task evaluate()
        {
            results = await modelGen.EvaluateAsync(image);
        }

Extrahera och visa resultatet

Nu måste du extrahera modellutdata och visa rätt resultat, vilket du gör genom att implementera extractResult metoderna och displayResult . Du måste hitta den högsta sannolikheten för att returnera rätt etikett.

  1. Lägg till metoden extractResult i MainPage.xaml.cs kodfilen i MainPage klassen.
        // A method to extract output from the model 
        private void extractResult()
        {
            // Retrieve the results of evaluation
            var mResult = results.modelOutput as TensorFloat;
            // convert the result to vector format
            var resultVector = mResult.GetAsVectorView();
            
            probability = 0;
            int index = 0;
            // find the maximum probability
            for(int i=0; i<resultVector.Count; i++)
            {
                var elementProbability=resultVector[i];
                if (elementProbability > probability)
                {
                    index = i;
                }
            }
            label = ((Labels)index).ToString();
        }
  1. Lägg till metoden displayResult i MainPage.xaml.cs kodfilen i MainPage klassen.
        private async Task displayResult() 
        {
            displayOutput.Text = label; 
        }

Det var allt. Du har skapat Windows maskininlärningsapp med ett grundläggande GUI för att testa vår klassificeringsmodell. Nästa steg är att starta programmet och köra det lokalt på din Windows-enhet.

Starta programmet

När du har slutfört programgränssnittet, lagt till modellen och genererat Windows ML-koden kan du testa programmet!

Aktivera utvecklarläge och testa ditt program från Visual Studio. Kontrollera att de nedrullningsbara menyerna i det övre verktygsfältet är inställda på Debug. Ändra Solution Platform till x64 för att köra projektet på den lokala datorn om enheten är 64-bitars eller x86 om den är 32-bitars.

Vår modell tränades för att klassificera följande bilder: plan, bil, fågel, katt, hjort, hund, groda, häst, skepp, lastbil. För att testa vår app använder du bilden av Lego-bilen som skapats för det här projektet. Nu ska vi se hur vår app klassificerar innehållet i bilden.

Bild för programtestning

  1. Spara den här avbildningen på din lokala enhet för att testa appen. Ändra bildformatet till .jpg om det behövs. Du kan också ladda upp eller välja alla andra relevanta bilder från din lokala enhet i .jpg- eller .png-formatet.

  2. Om du vill köra projektet väljer du Start Debugging knappen i verktygsfältet eller trycker på F5.

  3. När programmet startar trycker du på Välj bild och väljer bilden från den lokala enheten.

Programgränssnitt

Resultatet visas på skärmen direkt. Som du ser har vår Windows ML-app klassificerat avbildningen som en bil.

Lyckad klassificering i din app

Sammanfattning

Du har precis gjort din första Windows Machine Learning-app, från att skapa modellen till att köra den framgångsrikt.

Ytterligare resurser

Mer information om ämnen som nämns i den här självstudien finns i följande resurser: