Nasazení modelu v aplikaci pro Windows pomocí rozhraní WINDOWS ML API

Poznámka:

Pro větší funkčnost lze PyTorch použít také s DirectML ve Windows.

V předchozí části tohoto kurzu jste se naučili, jak sestavit a exportovat model ve formátu ONNX. Teď vám ukážeme, jak vložit exportovaný model do aplikace pro Windows a spustit ho místně na zařízení zavoláním rozhraní API WinML.

Až to dokončíme, budete mít funkční aplikaci pro klasifikaci obrázků.

Informace o ukázkové aplikaci

V tomto kroku kurzu vytvoříte aplikaci, která dokáže klasifikovat obrázky pomocí modelu ML. Základní uživatelské rozhraní umožňuje vybrat obrázek z místního zařízení a pomocí klasifikačního modelu ONNX, který jste vytvořili a vytrénovali v předchozí části, jej klasifikovat. Značky vrácené modelem se pak zobrazí vedle obrázku.

Tady vás provedeme tímto procesem.

Poznámka:

Pokud se rozhodnete použít předdefinovanou ukázku kódu, můžete naklonovat soubor řešení. Naklonujte úložiště, přejděte do této ukázky a otevřete soubor classifierPyTorch.sln v sadě Visual Studio. Přejděte na část Spustit aplikaci na této stránce, abyste ho viděli v akci.

Níže vás provedeme vytvořením aplikace a přidáním kódu Windows ML.

Vytvoření Windows ML UWP (C#)

Pokud chcete vytvořit funkční aplikaci Windows ML, musíte udělat toto:

  • Načtěte model strojového učení.
  • Načtěte obrázek v požadovaném formátu.
  • Spojte vstupy a výstupy modelu.
  • Vyhodnoťte model a zobrazte smysluplné výsledky.

Také budete muset navrhnout základní uživatelské rozhraní, protože je obtížné vytvořit uspokojivou aplikaci využívající obrazy v příkazové řádce.

Otevření nového projektu v sadě Visual Studio

  1. Pojďme začít. Otevřete Visual Studio a zvolte vytvořit nový projekt.

Vytvoření nového projektu sady Visual Studio

  1. Do vyhledávacího panelu zadejte UWPa pak vyberte Blank APP (Universal Windows). Tím se otevře projekt jazyka C# pro jednostráňovou aplikaci univerzální platformy Windows (UPW) s předdefinovanými ovládacími prvky nebo rozložením. Výběrem next otevřete okno konfigurace projektu.

Vytvoření nové aplikace pro UPW

  1. V okně konfigurace postupujte takto:
  • Pojmenujte projekt. Tady ji nazýváme classifierPyTorch.
  • Zvolte umístění projektu.
  • Pokud používáte VS2019, zkontrolujte, jestli Create directory for solution je zaškrtnuté.
  • Pokud používáte VS2017, ujistěte se, že Place solution and project in the same directory není zaškrtnuto.

Nové nastavení aplikace pro UPW

Stisknutím create vytvoříte projekt. Může se objevit okno minimální cílové verze. Ujistěte se, že je minimální verze nastavená na Windows 10 verze 1809 (10.0; build 17763) nebo vyšší.

  1. Po vytvoření projektu přejděte do složky projektu, otevřete složku [….\classifierPyTorch \Assets] a zkopírujte ImageClassifier.onnx soubor do tohoto umístění.

Prozkoumání projektového řešení

Pojďme prozkoumat řešení projektu.

Visual Studio automaticky vytvořilo několik souborů cs-code v Průzkumníku řešení. MainPage.xaml obsahuje kód XAML pro vaše grafické uživatelské rozhraní a MainPage.xaml.cs obsahuje kód vaší aplikace, označovaný také jako kód za kódem. Pokud jste předtím vytvořili aplikaci pro UPW, měly by vám tyto soubory být velmi známé.

Řešení aplikací pro UPW

Vytvoření grafického uživatelského rozhraní aplikace

Nejprve vytvoříme pro vaši aplikaci jednoduché grafické uživatelské rozhraní.

  1. Poklikejte na MainPage.xaml kódový soubor. V prázdné aplikaci je šablona XAML pro grafické uživatelské rozhraní prázdná, takže budeme muset přidat některé funkce uživatelského rozhraní.

  2. Přidejte následující kód do MainPage.xaml, nahraďte značky <Grid> a </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> 

Přidání modelu do projektu pomocí generátoru kódu Windows ML (mlgen)

Windows Machine Learning Code Generator nebo mlgen je rozšíření sady Visual Studio, které vám pomůže začít používat rozhraní API WinML v aplikacích pro UPW. Generuje kód šablony při přidání trénovaného souboru ONNX do projektu UPW.

Generátor kódu služby Windows Machine Learning mlgen vytvoří rozhraní (pro C#, C++/WinRT a C++/CX) s obálkovými třídami, které za vás volají rozhraní WINDOWS ML API. To vám umožní snadno načíst, svázat a vyhodnotit model v projektu. V tomto kurzu ji použijeme ke zpracování mnoha těchto funkcí.

Generátor kódu je k dispozici pro Visual Studio 2017 a novější. Doporučujeme používat Visual Studio. Mějte na paměti, že ve Windows 10 verze 1903 a novějším už není mlgen součástí sady Windows 10 SDK, takže je nutné stáhnout a nainstalovat rozšíření. Pokud jste postupovali podle tohoto kurzu z úvodu, už to zvládnete, ale pokud ne, měli byste si stáhnout verzi VS 2019 nebo VS 2017.

Poznámka:

Další informace o mlgen najdete v dokumentaci k mlgenu.

  1. Pokud jste to ještě neudělali, nainstalujte mlgen.

  2. Klikněte pravým tlačítkem myši na Assets složku v Průzkumníku řešení v sadě Visual Studio a vyberte Add > Existing Item.

  3. Přejděte do složky assets uvnitř classifierPyTorch [….\classifierPyTorch \Assets], vyhledejte model ONNX, který jste tam dříve zkopírovali, a vyberte add.

  4. Po přidání modelu ONNX do složky assets v Průzkumníku řešení ve VS by teď měl mít projekt dva nové soubory:

  • ImageClassifier.onnx - toto je váš model ve formátu ONNX.
  • ImageClassifier.cs – automaticky vygenerovaný soubor kódu WinML.

Soubory ONNX v řešení aplikace pro UPW

  1. Pokud chcete mít jistotu, že se model sestaví při kompilaci naší aplikace, vyberte ImageClassifier.onnx soubor a zvolte Properties. Pro Build Action vyberte Content.

Kód souboru ONNX

Teď se podíváme na nově vygenerovaný kód v ImageClassifier.cs souboru.

Vygenerovaný kód obsahuje tři třídy:

  • ImageClassifierModel: Tato třída obsahuje dvě metody pro vytvoření instance modelu a vyhodnocení modelu. Pomůže nám vytvořit reprezentaci modelu strojového učení, vytvořit relaci na výchozím systémovém zařízení, svázat konkrétní vstupy a výstupy s modelem a asynchronně vyhodnotit model.
  • ImageClassifierInput: Tato třída inicializuje vstupní typy, které model očekává. Vstup modelu závisí na požadavcích modelu pro vstupní data.
  • ImageClassifierOutput: Tato třída inicializuje typy, které bude model generovat. Výstup modelu závisí na tom, jak ho model definuje.

V tomto kurzu nechceme řešit tensorizaci. Mírně změníme ImageClassifierInput třídu, změníme vstupní datový typ a usnadníme život.

  1. Proveďte v ImageClassifier.cs souboru následující změny:

Změňte proměnnou input z TensorFloat na ImageFeatureValue.

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

Načtení modelu

  1. Poklikáním na MainPage.xaml.cs soubor otevřete kód aplikace.

  2. Nahraďte následující příkazy using, abyste získali přístup ke všem rozhraním API, která budete potřebovat:

// 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. Uvnitř vaší MainPage třídy nad funkci public MainPage(), přidejte následující deklarace proměnných.
        // 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
        } 

Teď implementujete metodu LoadModel . Metoda získá přístup k modelu ONNX a uloží ho do paměti. Pak použijete metodu CreateFromStreamAsync k vytvoření instance modelu jako objektu LearningModel . Třída LearningModel představuje trénovaný model strojového učení. Po vytvoření instance je počátečním objektem, LearningModel který používáte k interakci s Windows ML.

K načtení modelu můžete ve LearningModel třídě použít několik statických metod. V tomto případě použijete metodu CreateFromStreamAsync .

Metoda CreateFromStreamAsync byla automaticky vytvořena pomocí mlgen, takže tuto metodu nemusíte implementovat. Tuto metodu můžete zkontrolovat dvojitým kliknutím na soubor classifier.cs vygenerovaný nástrojem mlgen.

Poznámka:

Další informace o LearningModel třídě najdete v dokumentaci k třídě LearningModel. Chcete-li se dozvědět více o dalších způsobech načítání modelu, podívejte se na dokumentaci "Načtení modelu."

  1. Přidejte do konstruktoru hlavní třídy volání metody loadModel.
        // The main page to initialize and execute the model.
        public MainPage()
        {
            this.InitializeComponent();
            loadModel();
        }
  1. Přidejte implementaci loadModel metody uvnitř této MainPage třídy.
        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);
        }

Načtení obrázku

  1. Potřebujeme definovat událost kliknutí, abychom zahájili posloupnost čtyř volání metod pro provádění modelu – převod, vazbu a vyhodnocení, extrakci výstupu a zobrazení výsledků. Do souboru kódu MainPage.xaml.cs uvnitř třídy MainPage přidejte následující metodu.
        // 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. Teď implementujete metodu getImage() . Tato metoda vybere vstupní soubor obrázku a uloží ho do paměti. Do souboru kódu MainPage.xaml.cs uvnitř třídy MainPage přidejte následující metodu.
        // 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ále implementujete metodu obrázku Bind() , která získá reprezentaci souboru ve formátu rastrového obrázku BGRA8. Nejprve ale vytvoříte pomocnou třídu pro změnu velikosti obrázku.

  1. Chcete-li vytvořit pomocný soubor, klikněte pravým tlačítkem myši na název řešení (ClassifierPyTorch) a zvolte Add a new item. V otevřeném okně vyberte Class a pojmenujte ho. Tady tomu Helperříkáme .

Přidání pomocného souboru

  1. V projektu se zobrazí nový soubor třídy. Otevřete tuto třídu a přidejte následující kód:
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; 
        } 
    } 
} 

Teď převedeme obrázek na příslušný formát.

Třída ImageClassifierInput inicializuje vstupní typy, které model očekává. V našem případě jsme nakonfigurovali kód tak, aby očekával ImageFeatureValue.

Třída ImageFeatureValue popisuje vlastnosti obrázku použitého k předání do modelu. K vytvoření ImageFeatureValue použijte metodu CreateFromVideoFrame. Konkrétnější podrobnosti o tom, proč tomu tak je a jak tyto třídy a metody fungují, najdete v dokumentaci ke třídě ImageFeatureValue.

Poznámka:

V tomto kurzu použijeme ImageFeatureValue třídu místo tensoru. Pokud Window ML nepodporuje barevný formát modelu, nebude to možnost. Pro příklad práce s převody obrázků a tensorizací se podívejte na ukázku vlastní tensorizace.

  1. Přidejte implementaci convert() metody do MainPage.xaml.cs souboru kódu uvnitř Třídy MainPage. Metoda convert nám získá reprezentaci vstupního souboru ve formátu BGRA8.
// 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) 
    {
    }
} 

Vytvoření vazby a vyhodnocení modelu

Dále vytvoříte relaci založenou na modelu, vytvoříte vazbu vstupu a výstupu z relace a vyhodnotíte model.

Vytvořte relaci pro svázání modelu.

K vytvoření relace použijete LearningModelSession třídu. Tato třída se používá k vyhodnocení modelů strojového učení a vytvoří vazbu modelu na zařízení, které pak model spustí a vyhodnotí. Můžete vybrat zařízení, když vytvoříte relaci pro spuštění svého modelu na konkrétním zařízení vašeho počítače. Výchozím zařízením je procesor.

Poznámka:

Další informace o tom, jak zvolit zařízení, najdete v dokumentaci Vytvořit relaci.

Vytvoření vazby vstupů a výstupů modelu:

Pro vázání vstupu a výstupu použijte třídu LearningModelBinding. Model strojového učení má vstupní a výstupní funkce, které předávají informace do a z modelu. Mějte na paměti, že rozhraní API služby Windows ML musí podporovat požadované funkce. Třída LearningModelBinding se aplikuje na LearningModelSession k přiřazení hodnot pojmenovaným vstupním a výstupním vlastnostem.

Implementace vazby se automaticky vygeneruje nástrojem mlgen, takže se o ni nemusíte starat. Vazba je implementována voláním předdefinovaných metod LearningModelBinding třídy. V našem případě používá metodu Bind k vytvoření vazby hodnoty na pojmenovaný typ funkce.

Vyhodnocení modelu:

Po vytvoření relace, která vytvoří vazbu modelu a ohraničovaných hodnot na vstupy a výstupy modelu, můžete vyhodnotit vstupy modelu a získat jeho předpovědi. Pokud chcete spustit provádění modelu, měli byste volat některou z předdefinovaných metod vyhodnocení v LearningModelSession. V našem případě použijeme metodu EvaluateAsync .

CreateFromStreamAsyncPodobně jako , EvaluateAsync metoda byla také automaticky generována WinML Code Generator, takže nemusíte implementovat tuto metodu. Tuto metodu ImageClassifier.cs můžete zkontrolovat v souboru.

Metoda EvaluateAsync asynchronně vyhodnotí model strojového učení pomocí hodnot funkcí, které jsou již vázány ve vazbách. Vytvoří relaci s LearningModelSession, sváže vstup a výstup s LearningModelBinding, spustí vyhodnocení modelu a získá výstupní funkce modelu pomocí třídy LearningModelEvaluationResult.

Poznámka:

Další informace o dalších metodách vyhodnocení spuštění modelu najdete v dokumentaci ke třídě LearningModelSession a zkontrolujte, které metody je možné implementovat ve třídě LearningModelSession.

  1. Do souboru kódu uvnitř třídy MainPage přidejte následující metodu MainPage.xaml.cs pro vytvoření relace, vytvoření vazby a vyhodnocení modelu.
        // A method to evaluate the model
        private async Task evaluate()
        {
            results = await modelGen.EvaluateAsync(image);
        }

Extrahování a zobrazení výsledků

Teď budete muset extrahovat výstup modelu a zobrazit správný výsledek, který provedete implementací extractResult a displayResult metod. Abyste mohli správně vrátit označení, budete muset najít nejvyšší pravděpodobnost.

  1. Přidejte metodu extractResult do MainPage.xaml.cs souboru kódu uvnitř MainPage třídy.
        // 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. Přidejte metodu displayResult do MainPage.xaml.cs souboru kódu uvnitř MainPage třídy.
        private async Task displayResult() 
        {
            displayOutput.Text = label; 
        }

A je to. Úspěšně jste vytvořili aplikaci strojového učení pro Windows se základním grafickým uživatelským rozhraním pro testování našeho klasifikačního modelu. Dalším krokem je spuštění aplikace a jeho místní spuštění na zařízení s Windows.

Spuštění aplikace

Jakmile dokončíte rozhraní aplikace, přidáte model a vygenerujete kód Windows ML, můžete aplikaci otestovat.

Povolte vývojářský režim a otestujte aplikaci ze sady Visual Studio. Ujistěte se, že jsou rozevírací nabídky na horním panelu nástrojů nastavené na Debug. Změňte platformu řešení na x64 a spusťte projekt na místním počítači, pokud je vaše zařízení 64bitové, nebo x86, pokud je 32bitová.

Náš model byl natrénován tak, aby klasifikoval následující obrázky: letadlo, auto, pták, kočka, jelen, pes, žába, kůň, loď, nákladní vůz. K otestování naší aplikace použijete obrázek lego auta vytvořeného pro tento projekt. Pojďme se podívat, jak naše aplikace klasifikuje obsah obrázku.

Obrázek pro testování aplikací

  1. Uložte tento obrázek na místní zařízení a otestujte aplikaci. V případě potřeby změňte formát obrázku..jpg Můžete také nahrát libovolný relevantní obrázek z místního zařízení ve formátu .jpg nebo .png.

  2. Pokud chcete projekt spustit, vyberte Start Debugging tlačítko na panelu nástrojů nebo stiskněte F5.

  3. Po spuštění aplikace stiskněte vybrat obrázek a vyberte obrázek z místního zařízení.

Aplikační rozhraní

Výsledek se hned zobrazí na obrazovce. Jak vidíte, naše aplikace Windows ML úspěšně klasifikuje obrázek jako auto.

Úspěšná klasifikace v aplikaci

Shrnutí

Právě jste vytvořili svou první aplikaci Windows Machine Learning od vytvoření modelu po úspěšné spuštění.

Další zdroje

Další informace o tématech uvedených v tomto kurzu najdete v následujících zdrojích informací: