Dela via


Distribuera din ML.NET-modell i en Windows-app med Windows Machine Learning-API:er

I föregående del av den här självstudien lärde du dig hur du skapar och exporterar en ML.NET modell i ONNX-format. Nu när du har den modellen kan du bädda in den i ett Windows-program och köra den lokalt på en enhet genom att anropa WinML-API:er.

När vi är klara har du en fungerande WinML UWP-app för bildklassificerare (C#).

Om exempelappen

Med hjälp av vår modell skapar vi en app som kan klassificera bilder av mat. Med den kan du välja en bild från din lokala enhet och bearbeta den med en lokalt lagrad ONNX-klassificeringsmodell som du skapade och tränade i föregående del. Taggarna som returneras visas bredvid bilden samt klassificeringens sannolikhet för konfidens.

Om du har följt den här självstudien hittills bör du redan ha de nödvändiga förutsättningarna för apputveckling på plats. Om du behöver en uppdatering kan du läsa den första delen av den här självstudien.

Anmärkning

Om du föredrar att ladda ned den fullständiga exempelkoden kan du klona lösningsfilen. Klona förvaret, gå till det här exemplet och öppna sedan classifierMLNETModel.sln-filen med Visual Studio. Sedan kan du gå vidare till steget [Starta programmet](#Launch the application).

Skapa en WinML UWP (C#)

Nedan visar vi hur du skapar din app och WinML-kod från grunden. Du får lära dig att:

  • Läs in en maskininlärningsmodell.
  • Läs in en bild i det format som krävs.
  • Binda modellens indata och utdata.
  • Utvärdera modellen och visa meningsfulla resultat.

Du använder också grundläggande XAML för att skapa ett enkelt GUI, så att du kan testa bildklassificeraren.

Skapa appen

  1. Öppna Visual Studio och välj create a new project.

Skapa ett nytt Visual Studio-projekt

  1. I sökfältet skriver du UWP och väljer Blank APP (Universal Windowssedan ). Detta öppnar ett nytt C#-projekt för en enkelsidig UWP-app (Universal Windows Platform) som inte har några fördefinierade kontroller eller layout. Välj Next för att öppna ett konfigurationsfönster för projektet.

Skapa en UWP-app

  1. I konfigurationsfönstret:
  • Välj ett namn för projektet. Här använder vi klassificerarenMLNETModel.
  • Välj platsen för projektet.
  • Om du använder VS 2019, kontrollera att Place solution and project in the same directory är avmarkerad.
  • Om du använder VS 2017 kontrollerar du att Create directory for solution är markerad.

Konfigurera din app

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 build 17763 eller senare.

Om du vill skapa en app och distribuera en modell med en WinML-app behöver du följande:

  1. När projektet har skapats går du till projektmappen, öppnar mappen assets [....\classifierMLNETModel\Assets] och kopierar bestModel.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. Om du har skapat en UWP-app tidigare bör dessa filer vara mycket bekanta för dig.

Skapa program-GUI

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

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

  2. Byt ut koden MainPage.xaml mot följande.

<Page
    x:Class="classifierMLNETModel.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:classifierMLNETModel"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

       <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>
            <!--Dispaly 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> 
</Page>

Lägg till modellen i projektet med hjälp av Windows Machine Learning Code Generator

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. 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 ImageClassifierAppUWP [….\ImageClassifierAppUWP\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 (namn: "klassificerare") i mappen assets i Solution Explorer i VS bör projektet nu ha två nya filer:

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

Projektstruktur med ONNX-modell tillagd

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

Nu ska vi utforska den nyligen genererade koden i bestModel.cs filen.

Den genererade koden innehåller tre klasser:

  • bestModelModel: 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.
  • bestModelInput: Den här klassen initierar de indatatyper som modellen förväntar sig. Modellindata beror på modellkraven för indata.
  • bestModelOutput: Den här klassen initierar de typer som modellen ska mata ut. Modellutdata beror på hur den definieras av modellen.

Nu ska du använda dessa klasser för att läsa in, binda och utvärdera modellen i vårt projekt.

Tensor-konvertering

Om du vill göra det enklare att hantera tensorization ändrar du indataklassen TensorFloat till ImageFeatureValue.

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

Koden:

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

Kommer att bli:

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

Läs in modellen och indata

Läs in modellen

  1. Dubbelklicka på MainPage.xaml.cs kodfilen för att öppna programkoden.

  2. Ersätt "using"-uttrycken med följande 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 you'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 efter användningsinstruktionerna i MainPage klassen under namnområdet classifierMLNETModel.
		// All the required fields declaration
		private bestModelModel modelGen;
		private bestModelInput image = new bestModelInput();
		private bestModelOutput results;
		private StorageFile selectedStorageFile;
		private string label = "";
		private float probability = 0;
		private Helper helper = new Helper();

		public enum Labels
		{
			desert,
			soup,
			vegetable_fruit,
		}

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 bestModel.cs som genereras av mlgen.

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. Nu ska vi definiera huvudmetoden.
// The main page to initialize and execute the model.
public MainPage()
{
	this.InitializeComponent();
	loadModel();
}
  1. Lägg till implementeringen av loadModel metoden i din MainPage.xaml.cs kodfil 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/bestModel.onnx"));
// Instantiate the model. 
	modelGen = await bestModelModel.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. Om du vill skapa en hjälpfil, högerklickar du på lösningsnamnet (ClassifierPyTorch) och väljer 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 bestModelInput 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. Om du vill skapa enImageFeatureValue, 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 klassen ImageFeatureValue i stä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 bind 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 224x224 
              	inputImage=await helper.CropAndDisplayInputImageAsync(inputImage);
              	// Bind the model input with image
              	ImageFeatureValue imageTensor = ImageFeatureValue.CreateFromVideoFrame(inputImage);
				image.input1 = 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 bestModel.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ärderingsmetoder för att köra modellen kan du kontrollera 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.

För att testa vår app ska vi använda bilden nedan av soppa. 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å lägga till andra relevanta avbildningar från din lokala enhet i ett .jpg eller .png -format.

  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å Pick Image och väljer avbildningen från den lokala enheten.

Programgränssnitt

Resultatet visas på skärmen direkt. Som du ser klassificerade vår Windows ML-app bilden som en soppa.

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: