Partilhar via


Implante seu modelo de ML.NET em um aplicativo do Windows com as APIs do Windows Machine Learning

Na parte anterior deste tutorial, você aprendeu como criar e exportar um modelo de ML.NET no formato ONNX. Agora que você tem esse modelo, você pode incorporá-lo em um aplicativo do Windows e executá-lo localmente em um dispositivo chamando APIs WinML.

Quando terminarmos, você terá um aplicativo WinML UWP (C#) do classificador de imagens em funcionamento.

Sobre o aplicativo de exemplo

Usando nosso modelo, criaremos um aplicativo que pode classificar imagens de alimentos. Ele permite que você selecione uma imagem do seu dispositivo local e processe-a por um modelo ONNX de classificação armazenado localmente que você construiu e treinou na parte anterior. As tags retornadas são exibidas ao lado da imagem, bem como a probabilidade de confiança da classificação.

Se tens acompanhado este tutorial até agora, já deves ter os pré-requisitos necessários para o desenvolvimento de aplicativos prontos. Se precisar de uma atualização, consulte a primeira parte deste tutorial.

Observação

Se preferir baixar o código de exemplo completo, você pode clonar o arquivo de solução. Clone o repositório, navegue até este exemplo e abra o ficheiro com o classifierMLNETModel.sln no Visual Studio. Em seguida, você pode pular para a etapa [Iniciar o aplicativo](#Launch o aplicativo).

Criar uma aplicação WinML UWP (C#)

Abaixo, mostraremos como criar seu aplicativo e código WinML do zero. Você aprenderá a:

  • Carregue um modelo de aprendizado de máquina.
  • Carregue uma imagem no formato necessário.
  • Vincule as entradas e saídas do modelo.
  • Avalie o modelo e exiba resultados significativos.

Você também usará XAML básico para criar uma GUI simples, para que possa testar o classificador de imagem.

Criar a aplicação

  1. Abra o Visual Studio e escolha create a new project.

Criar um novo projeto do Visual Studio

  1. Na barra de pesquisa, digite UWP e selecione Blank APP (Universal Windows). Isso abre um novo projeto C# para um aplicativo da Plataforma Universal do Windows (UWP) de página única que não tem controles ou layout predefinidos. Selecione Next para abrir uma janela de configuração para o projeto.

Criar um aplicativo UWP

  1. Na janela de configuração:
  • Escolha um nome para o seu projeto. Aqui, usamos classificadorMLNETModel.
  • Escolha a localização do seu projeto.
  • Se estiver a utilizar o VS 2019, certifique-se de que Place solution and project in the same directory está desmarcado.
  • Se estiver a utilizar o VS 2017, certifique-se de que Create directory for solution está marcado.

Configurar seu aplicativo

Pressione create para criar seu projeto. A janela da versão de destino mínima pode aparecer. Certifique-se de que a sua versão mínima está definida como Windows 10 build 17763 ou posterior.

Para criar um aplicativo e implantar um modelo com um aplicativo WinML, você precisará do seguinte:

  1. Depois que o projeto for criado, navegue até a pasta do projeto, abra a pasta assets [....\classifierMLNETModel\Assets] e copie o bestModel.onnx arquivo para esse local.

Explore a solução do projeto

Vamos explorar a solução do seu projeto.

O Visual Studio criou automaticamente vários arquivos de código cs, dentro do Gerenciador de Soluções. MainPage.xaml contém o código XAML para sua GUI e MainPage.xaml.cs contém o código do aplicativo. Se você já criou um aplicativo UWP antes, esses arquivos devem ser muito familiares para você.

Criar a GUI do aplicativo

Primeiro, vamos criar uma GUI simples para seu aplicativo.

  1. Clique duas vezes no MainPage.xaml arquivo. Em seu aplicativo em branco, o modelo XAML para a GUI do seu aplicativo está vazio, portanto, precisaremos adicionar alguns recursos da interface do usuário.

  2. Substitua o código de MainPage.xaml pelo seguinte.

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

Adicionar o modelo ao projeto usando o Gerador de Código do Windows Machine Learning

O Gerador de Código do Windows Machine Learning, ou mlgen, é uma extensão do Visual Studio para ajudá-lo a começar a usar APIs WinML em aplicativos UWP. Ele gera código de modelo quando você adiciona um arquivo ONNX treinado ao projeto UWP.

O gerador de código mlgen do Windows Machine Learning cria uma interface (para C#, C++/WinRT e C++/CX) com classes wrapper que chamam a API do Windows ML para você. Isso permite que você carregue, vincule e avalie facilmente um modelo em seu projeto. Vamos usá-lo neste tutorial para lidar com muitas dessas funções para nós.

O gerador de código está disponível para o Visual Studio 2017 e posterior. Por favor, esteja ciente de que no Windows 10, versão 1903 e posterior, mlgen não está mais incluído no SDK do Windows 10, então você deve baixar e instalar a extensão. Se você tem acompanhado este tutorial desde a introdução, você já terá lidado com isso, mas se não, você deve baixar para VS 2019 ou VS 2017.

Observação

Para saber mais sobre mlgen, consulte a documentação mlgen

  1. Se ainda não o fez, instale o mlgen.

  2. Clique com o botão direito do mouse na pasta Assets no Gerenciador de Soluções no Visual Studio e selecione Add > Existing Item.

  3. Navegue até a pasta assets dentro ImageClassifierAppUWP [….\ImageClassifierAppUWP\Assets], encontre o modelo ONNX que você já copiou lá e selecione add.

  4. Depois de adicionar um modelo ONNX (nome: "classificador") à pasta assets no gerenciador de soluções no VS, o projeto agora deve ter dois novos arquivos:

  • bestModel.onnx - este é o seu modelo em formato ONNX.
  • bestModel.cs – arquivo de código WinML gerado automaticamente.

Estrutura do projeto com modelo ONNX adicionado

  1. Para se certificar de que o modelo é construído ao compilar a nossa aplicação, selecione o ficheiro bestModel.onnx e escolha Properties. Para Build Action, selecione Content.

Agora, vamos explorar o código recém-gerado no bestModel.cs arquivo.

O código gerado inclui três classes:

  • bestModelModel: Esta classe inclui dois métodos para instanciação de modelo e avaliação de modelo. Isso nos ajudará a criar a representação do modelo de aprendizado de máquina, criar uma sessão no dispositivo padrão do sistema, vincular as entradas e saídas específicas ao modelo e avaliar o modelo de forma assíncrona.
  • bestModelInput: Esta classe inicializa os tipos de entrada esperados pelo modelo. A entrada do modelo depende dos requisitos do modelo para os dados de entrada.
  • bestModelOutput: Esta classe inicializa os tipos que o modelo irá produzir. A saída do modelo depende de como ela é definida pelo modelo.

Agora você usará essas classes para carregar, vincular e avaliar o modelo em nosso projeto.

Conversão de tensores

Para facilitar o tratamento da tensorização, altere a classe de entrada TensorFloat para ImageFeatureValue.

  1. Faça as seguintes alterações no bestModel.cs arquivo:

O código:

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

Tornar-se-á:

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

Carregue o modelo e dados de entrada

Carregue o modelo

  1. Clique duas vezes no arquivo de MainPage.xaml.cs código para abrir o código do aplicativo.

  2. Substitua as instruções "usando" pelo seguinte, para obter acesso a todas as APIs necessárias.

// 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. Adicione as seguintes declarações de variável após as instruções using dentro de sua MainPage classe, sob o namespace 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,
		}

Agora, você implementará o LoadModel método. O método irá acessar o modelo ONNX e armazená-lo na memória. Em seguida, você usará o CreateFromStreamAsync método para instanciar o modelo como um LearningModel objeto. A LearningModel classe representa um modelo de aprendizagem de máquina treinado. Uma vez instanciado, o LearningModel é o objeto inicial utilizado para interagir com o Windows ML.

Para carregar o modelo, você pode usar vários métodos estáticos na LearningModel classe. Nesse caso, você usará o CreateFromStreamAsync método.

O CreateFromStreamAsync método foi criado automaticamente com mlgen, então você não precisa implementar esse método. Você pode revisar este método clicando duas vezes no bestModel.cs arquivo gerado pelo mlgen.

Para saber mais sobre a LearningModel classe, consulte a documentação da classe LearningModel.

Para saber mais sobre formas adicionais de carregar o modelo, consulte a documentação Carregar um modelo

  1. Vamos definir o método principal.
// The main page to initialize and execute the model.
public MainPage()
{
	this.InitializeComponent();
	loadModel();
}
  1. Adicione a loadModel implementação do método ao seu MainPage.xaml.cs arquivo de código dentro da MainPage classe.
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);
}

Carregue a imagem

  1. Precisamos definir um evento de clique para iniciar a sequência de quatro chamadas de método para a execução do modelo – conversão, vinculação e avaliação, extração de saída e exibição dos resultados. Adicione o seguinte método ao seu MainPage.xaml.cs arquivo de código dentro da MainPage classe.
        // 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. Agora, você implementará o getImage() método. Este método irá selecionar um arquivo de imagem de entrada e salvá-lo na memória. Adicione o seguinte método ao seu MainPage.xaml.cs arquivo de código dentro da MainPage classe.
        // 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;
        }

Em seguida, você implementará um método de imagem Bind() para obter a representação do arquivo no formato bitmap BGRA8. Mas primeiro, você criará uma classe auxiliar para redimensionar a imagem.

  1. Para criar um ficheiro auxiliar, clique com o botão direito do rato no nome da solução (ClassifierPyTorch) e, em seguida, selecione Add a new item. Na janela aberta, selecione Class e atribua-lhe um nome. Aqui, estamos chamando de Helper.

Adicionar um arquivo auxiliar

  1. Um novo arquivo de classe aparecerá em seu projeto. Abra esta classe e adicione o seguinte código:
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; 
        } 
    } 
} 

Agora, vamos converter a imagem para o formato apropriado.

A bestModelInput classe inicializa os tipos de entrada esperados pelo modelo. No nosso caso, configurámos o nosso código para esperar um ImageFeatureValue.

A ImageFeatureValue classe descreve as propriedades da imagem usada para passar para um modelo. Para criar um ImageFeatureValue, utilize o método CreateFromVideoFrame. Para obter detalhes mais específicos sobre por que esse é o caso e como essas classes e métodos funcionam, consulte a documentação da classe ImageFeatureValue.

Observação

Neste tutorial, usamos a ImageFeatureValue classe em vez de um tensor. Se o Window ML não suportar o formato de cores do seu modelo, esta não será uma opção. Para obter um exemplo de como trabalhar com conversões de imagem e tensorização, consulte o Exemplo de tensorização personalizada.

  1. Adicione a implementação do método convert() ao seu ficheiro de código MainPage.xaml.cs dentro da classe MainPage. O método convert nos dará uma representação do arquivo de entrada em um formato BGRA8.
// 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)
            {
            }
        }

Vincular e avaliar o modelo

Em seguida, você criará uma sessão com base no modelo, vinculará a entrada e a saída da sessão e avaliará o modelo.

Crie uma sessão para vincular o modelo:

Para criar uma sessão, use a LearningModelSession classe. Essa classe é usada para avaliar modelos de aprendizado de máquina e vincula o modelo a um dispositivo que, em seguida, executa e avalia o modelo. Você pode selecionar um dispositivo ao criar uma sessão para executar seu modelo em um dispositivo específico da sua máquina. O dispositivo padrão é a CPU.

Observação

Para saber mais sobre como escolher um dispositivo, consulte a documentação Criar uma sessão .

Vincular entradas e saídas do modelo:

Para vincular entrada e saída, use a LearningModelBinding classe. Um modelo de aprendizado de máquina tem recursos de entrada e saída, que passam informações para dentro e para fora do modelo. Lembre-se de que os recursos necessários devem ser suportados pelas APIs do Window ML. A LearningModelBinding classe é aplicada em um LearningModelSession para vincular valores a recursos de entrada e saída nomeados.

A implementação da ligação é gerada automaticamente pelo mlgen, para que você não precise cuidar dela. A associação é implementada chamando os métodos predefinidos da LearningModelBinding classe. No nosso caso, ele usa o Bind método para vincular um valor ao tipo de recurso nomeado.

Avalie o modelo:

Depois de criar uma sessão para vincular o modelo e os valores limitados às entradas e saídas de um modelo, você pode avaliar as entradas do modelo e obter suas previsões. Para executar a execução do modelo, você deve chamar qualquer um dos métodos de avaliação predefinidos no LearningModelSession. No nosso caso, usaremos o EvaluateAsync método.

Semelhante ao CreateFromStreamAsync, o EvaluateAsync método também foi gerado automaticamente pelo WinML Code Generator, então você não precisa implementar esse método. Você pode revisar esse método no bestModel.cs arquivo.

O EvaluateAsync método avaliará de forma assíncrona o modelo de aprendizado de máquina usando os valores de recurso já vinculados em associações. Ele criará uma sessão com LearningModelSession, vinculará a entrada e a saída com LearningModelBinding, executará a avaliação do modelo e obterá os recursos de saída do modelo usando a LearningModelEvaluationResult classe.

Observação

Para saber mais sobre outros métodos de avaliação para executar o modelo, verifique quais métodos podem ser implementados no LearningModelSession examinando a documentação da Classe LearningModelSession.

  1. Adicione o seguinte método ao seu MainPage.xaml.cs arquivo de código dentro da classe MainPage para criar uma sessão, vincular e avaliar o modelo.
        // A method to evaluate the model
        private async Task evaluate()
        {
            results = await modelGen.EvaluateAsync(image);
        }

Extrair e exibir os resultados

Agora você precisará extrair a saída do modelo e exibir o resultado certo, o que será feito implementando os extractResult métodos e displayResult . Você precisará encontrar a maior probabilidade de retornar o rótulo correto.

  1. Adicione o extractResult método ao seu MainPage.xaml.cs arquivo de código dentro da MainPage classe.
        // 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. Adicione o displayResult método ao seu MainPage.xaml.cs arquivo de código dentro da MainPage classe.
        private async Task displayResult() 
        {
            displayOutput.Text = label; 
        }

Está feito! Você criou com sucesso o aplicativo de aprendizado de máquina do Windows com uma GUI básica para testar nosso modelo de classificação. O próximo passo é iniciar o aplicativo e executá-lo localmente em seu dispositivo Windows.

Inicie o aplicativo

Depois de concluir a interface do aplicativo, adicionar o modelo e gerar o código de ML do Windows, você pode testar o aplicativo!

Habilite o modo de desenvolvedor e teste seu aplicativo do Visual Studio. Verifique se os menus suspensos na barra de ferramentas superior estão definidos como Debug. Altere a plataforma de solução para x64 para executar o projeto em sua máquina local se o dispositivo for de 64 bits ou x86 se for de 32 bits.

Para testar nosso aplicativo, vamos usar a imagem abaixo da sopa. Vamos ver como nosso aplicativo classifica o conteúdo da imagem.

Imagem para teste de aplicação

  1. Guarde esta imagem no seu dispositivo local para testar a aplicação. Altere o formato da imagem para .jpg se necessário. Você também pode adicionar qualquer outra imagem relevante do seu dispositivo local em formato .jpg ou .png.

  2. Para executar o projeto, selecione o Start Debugging botão na barra de ferramentas ou pressione F5.

  3. Quando o aplicativo for iniciado, pressione Pick Image e selecione a imagem do seu dispositivo local.

Interface de aplicação

O resultado aparecerá na tela imediatamente. Como você pode ver, nosso aplicativo Windows ML classificou com sucesso a imagem como uma sopa.

Classificação bem-sucedida em seu aplicativo

Resumo

Você acabou de criar seu primeiro aplicativo de Aprendizado de Máquina do Windows, desde a criação do modelo até a execução bem-sucedida.

Recursos adicionais

Para saber mais sobre os tópicos mencionados neste tutorial, visite os seguintes recursos: