Tutorial: criar um aplicativo UWP do Windows Machine Learning (C#)
Neste tutorial, criaremos um aplicativo simples da Plataforma Universal do Windows que usa um modelo de machine learning treinado para reconhecer um dígito numérico desenhado pelo usuário. Este tutorial se concentra principalmente em como carregar e usar o Windows ML em seu aplicativo UWP.
O vídeo a seguir apresenta o exemplo no qual este tutorial se baseia.
Se você preferir simplesmente examinar o código do tutorial concluído, poderá encontrá-lo no repositório GitHub do WinML. Ele também está disponível em C++/CX.
Pré-requisitos
- Windows 10 (versão 1809 ou superior)
- SDK do Windows 10 (build 17763 ou superior)
- Visual Studio 2019 (ou Visual Studio 2017, versão 15.7.4 ou posterior)
- Extensão do gerador de código do Windows Machine Learning para Visual Studio 2019 ou 2017
- Um pouco de conhecimento básico de UWP e C#
1. Abrir o projeto no Visual Studio
Depois de baixar o projeto do GitHub, inicie o Visual Studio e abra o arquivo MNIST_Demo.sln (deve estar localizado em <demarcador para o repositório>\Windows-Machine-Learning\Samples\MNIST\Tutorial\cs). Se a solução for mostrada como não disponível, você precisará clicar com botão direito do mouse no projeto no Gerenciador de Soluções e selecionar Recarregar projeto.
Fornecemos um modelo com controles e eventos XAML implementados, incluindo:
- Uma InkCanvas para desenhar o dígito.
- Botões para interpretar o dígito e limpar a tela.
- Rotinas auxiliares para converter a saída de InkCanvas em um VideoFrame.
Dentro do Gerenciador de Soluções, o projeto tem três arquivos de código principais:
- MainPage.xaml – Todo o nosso código XAML para criar a interface do usuário para a InkCanvas, botões e rótulos.
- MainPage.xaml.cs – Onde está o código do nosso aplicativo.
- Helper.cs – Rotinas auxiliares para recortar e converter formatos de imagem.
2. Compilar e executar o projeto
Na barra de ferramentas do Visual Studio, altere a Plataforma de Solução para x64 para executar o projeto no computador local se seu dispositivo for de 64 bits ou x86 se for de 32 bits. (Confira isso no aplicativo Configurações do Windows: Sistema > Sobre > Especificações do dispositivo > Tipo de sistema.)
Para executar o projeto, clique no botão Iniciar depuração na barra de ferramentas ou pressione F5. O aplicativo deve mostrar uma InkCanvas em que os usuários podem escrever um dígito, um botão Reconhecer para interpretar o número, um campo de rótulo vazio em que o dígito interpretado será exibido como texto e um botão Limpar dígito para limpar a InkCanvas.
Observação
Se o projeto não for compilado, talvez seja necessário alterar a versão de destino de implantação do projeto. Clique com o botão direito do mouse no projeto no Gerenciador de Soluções e selecione Propriedades. Na guia Aplicativo, defina a versão de destino e a versão mínima para corresponder ao seu sistema operacional e SDK.
Observação
Se você receber um aviso de que o aplicativo já está instalado, basta selecionar Sim para continuar a implantação. Talvez seja necessário fechar o Visual Studio e abri-lo novamente se ele ainda não funcionar.
3. Baixar um modelo
Em seguida, vamos obter um modelo de machine learning para adicionar ao nosso aplicativo. Para este tutorial, usaremos um modelo MNIST previamente treinado com o Microsoft Cognitive Toolkit (CNTK) e exportado para o formato ONNX.
O modelo MNIST já foi incluído em sua pasta Ativos. Você precisará adicioná-lo ao seu aplicativo como um item existente. Você também pode baixar o modelo previamente treinado do ONNX Model Zoo no GitHub.
4. Adicionar o modelo
Clique com o botão direito do mouse na pasta Ativos no Gerenciador de Soluções e selecione Adicionar>Item Existente. Aponte o seletor de arquivos para a localização do seu modelo ONNX e clique em Adicionar.
Agora, o projeto deve ter dois novos arquivos:
- mnist.onnx – seu modelo treinado.
- mnist.cs – o código gerado do Windows ML.
Para garantir que o modelo seja compilado com o nosso aplicativo, clique com botão direito do mouse no arquivo mnist.onnx e selecione Propriedades. Para Ação de compilação, selecione Conteúdo.
Agora, vamos dar uma olhada no código recém-gerado no arquivo mnist.cs. Temos três classes:
- mnistModel cria a representação de modelo de machine learning, cria uma sessão no dispositivo padrão do sistema, associa as entradas e saídas específicas ao modelo e avalia o modelo de forma assíncrona.
- mnistInput inicializa os tipos de entrada que o modelo espera. Nesse caso, a entrada espera um ImageFeatureValue.
- mnistOutput inicializa os tipos que o modelo terá como saída. Nesse caso, a saída será uma lista chamada Plus214_Output_0 do tipo TensorFloat.
Agora, usaremos essas classes para carregar, associar e avaliar o modelo em nosso projeto.
5. Carregar, associar e avaliar o modelo
Para aplicativos do Windows ML, o padrão que queremos a seguir é: Carregar > Associar > Avaliar.
- Carregue o modelo de machine learning.
- Associe entradas e saídas ao modelo.
- Avalie o modelo e exiba os resultados.
Vamos usar o código de interface gerado em mnist.cs para carregar, associar e avaliar o modelo em nosso aplicativo.
Primeiro, em MainPage.xaml.cs, vamos instanciar o modelo, as entradas e as saídas. Adicione as variáveis de membro a seguir à classe MainPage:
private mnistModel ModelGen;
private mnistInput ModelInput = new mnistInput();
private mnistOutput ModelOutput;
Em seguida, em LoadModelAsync, carregaremos o modelo. Esse método deve ser chamado antes de usarmos qualquer um dos métodos do modelo (ou seja, no evento Loaded de MainPage, em uma substituição de OnNavigatedTo ou em qualquer lugar antes de recognizeButton_Click ser chamado). A classe mnistModel representa o modelo MNIST e cria a sessão no dispositivo padrão do sistema. Para carregar o modelo, chamamos o método CreateFromStreamAsync, passando o arquivo ONNX como o parâmetro.
private async Task LoadModelAsync()
{
// Load a machine learning model
StorageFile modelFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri($"ms-appx:///Assets/mnist.onnx"));
ModelGen = await mnistModel.CreateFromStreamAsync(modelFile as IRandomAccessStreamReference);
}
Observação
Se você vir sublinhados vermelhos sob IRandomAccessStreamReference, precisará incluir seu namespace. Coloque o cursor sobre ele, pressione Ctrl + . e selecione usando Windows.Storage.Streams no menu suspenso.
Depois disso, queremos associar nossa entradas e saídas ao modelo. O código gerado também inclui classes wrapper mnistInput e mnistOutput. A classe mnistInput representa as entradas esperadas do modelo; a classe mnistOutput representa as saídas esperadas do modelo.
Para inicializar o objeto de entrada do modelo, chame o construtor da classe mnistInput, passando os dados de aplicativos, e verifique se seus dados de entrada correspondem ao tipo de entrada que seu modelo espera. A classe mnistInput espera um ImageFeatureValue. Portanto, usamos um método auxiliar para obter um ImageFeatureValue para a entrada.
Usando nossas funções auxiliares incluídas em helper.cs, copiaremos o conteúdo da InkCanvas, o converteremos no tipo ImageFeatureValue e o associaremos ao nosso modelo.
private async void recognizeButton_Click(object sender, RoutedEventArgs e)
{
// Bind model input with contents from InkCanvas
VideoFrame vf = await helper.GetHandWrittenImage(inkGrid);
ModelInput.Input3 = ImageFeatureValue.CreateFromVideoFrame(vf);
}
Para a saída, simplesmente chamamos EvaluateAsync com a entrada especificada. Depois que suas entradas forem inicializadas, chame o método EvaluateAsync do modelo para avaliar seu modelo nos dados de entrada. EvaluateAsync associa suas entradas e saídas ao objeto do modelo e avalia o modelo nas entradas.
Como o modelo retorna um tensor de saída, primeiro desejaremos convertê-lo em um tipo de dados amigável e, em seguida, analisar a lista retornada para determinar qual dígito tinha a maior probabilidade e exibi-lo.
private async void recognizeButton_Click(object sender, RoutedEventArgs e)
{
// Bind model input with contents from InkCanvas
VideoFrame vf = await helper.GetHandWrittenImage(inkGrid);
ModelInput.Input3 = ImageFeatureValue.CreateFromVideoFrame(vf);
// Evaluate the model
ModelOutput = await ModelGen.EvaluateAsync(ModelInput);
// Convert output to datatype
IReadOnlyList<float> vectorImage = ModelOutput.Plus214_Output_0.GetAsVectorView();
IList<float> imageList = vectorImage.ToList();
// Query to check for highest probability digit
var maxIndex = imageList.IndexOf(imageList.Max());
// Display the results
numberLabel.Text = maxIndex.ToString();
}
Por fim, desejaremos limpar a InkCanvas para permitir que os usuários desenhem outro número.
private void clearButton_Click(object sender, RoutedEventArgs e)
{
inkCanvas.InkPresenter.StrokeContainer.Clear();
numberLabel.Text = "";
}
6. Iniciar o aplicativo
Depois que criarmos e iniciarmos o aplicativo (pressione F5), poderemos reconhecer um número desenhado na InkCanvas.
Isso é tudo. Você criou seu primeiro aplicativo Windows ML! Para obter mais exemplos que demonstram como usar o Windows ML, confira nosso repositório do Windows-Machine-Learning no GitHub.
Observação
Use os recursos a seguir para obter ajuda com o Windows ML:
- Para fazer perguntas ou responder a perguntas técnicas sobre o Windows ML, use a marca windows-machine-learning no Stack Overflow.
- Para relatar um bug, registre um problema no nosso GitHub.