Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
As APIs do Windows ML podem ser aproveitadas para interagir facilmente com modelos de machine learning em aplicativos win32 (área de trabalho) do C++. Usando as três etapas de carregamento, associação e avaliação, seu aplicativo pode se beneficiar do poder do aprendizado de máquina.

Criaremos uma versão um pouco simplificada do exemplo de Detecção de Objetos SqueezeNet, que está disponível no GitHub. Você pode baixar o exemplo completo se quiser ver como será quando terminar.
Usaremos C++/WinRT para acessar as APIs WinML. Consulte C++/WinRT para obter mais informações.
Neste tutorial, você aprenderá a:
- Carregar um modelo de machine learning
- Carregar uma imagem como VideoFrame
- Associar entradas e saídas do modelo
- Avaliar o modelo e imprimir resultados significativos
Pré-requisitos
- Visual Studio 2019 (ou Visual Studio 2017, versão 15.7.4 ou posterior)
- Windows 10, versão 1809 ou posterior
- SDK do Windows, build 17763 ou posterior
- Extensão do Visual Studio para C++/WinRT
- No Visual Studio, selecione Extensões e Atualizações das Ferramentas>.
- Selecione Online no painel esquerdo e pesquise "WinRT" usando a caixa de pesquisa à direita.
- Selecione C++/WinRT, clique em Baixar e feche o Visual Studio.
- Siga as instruções de instalação e, em seguida, abra novamente o Visual Studio.
- Repositório Github do WindowsMachine-Learning (você pode baixá-lo como um arquivo ZIP ou clonar em seu computador)
Criar o projeto
Primeiro, criaremos o projeto no Visual Studio:
- Selecione Arquivo > Novo > Projeto para abrir a janela Novo Projeto.
- No painel esquerdo, selecione Instalado > Visual C++ > Windows Desktop e, no meio, selecione Aplicativo do Console do Windows (C++/WinRT).
- Dê um nome e um local ao projeto e clique em OK.
- Na janela Novo Projeto da Plataforma Universal do Windows, defina a versão de Destino e a versão Mínima ambas para 17763 ou posterior e clique em OK.
- Verifique se os menus suspensos na barra de ferramentas superior estão definidos como Depurar e x64 ou x86, dependendo da arquitetura do seu computador.
- Pressione Ctrl+F5 para executar o programa sem depuração. Um terminal deve ser aberto com um texto "Olá, mundo". Pressione qualquer tecla para fechá-la.
Carregar o modelo
Em seguida, carregaremos o modelo ONNX em nosso programa usando LearningModel.LoadFromFilePath:
No pch.h (na pasta Arquivos de Cabeçalho ), adicione as instruções a seguir
include(elas nos dão acesso a todas as APIs que precisaremos):#include <winrt/Windows.AI.MachineLearning.h> #include <winrt/Windows.Foundation.Collections.h> #include <winrt/Windows.Graphics.Imaging.h> #include <winrt/Windows.Media.h> #include <winrt/Windows.Storage.h> #include <string> #include <fstream> #include <Windows.h>Em main.cpp (na pasta Arquivos de Origem ), adicione as seguintes
usinginstruções:using namespace Windows::AI::MachineLearning; using namespace Windows::Foundation::Collections; using namespace Windows::Graphics::Imaging; using namespace Windows::Media; using namespace Windows::Storage; using namespace std;Adicione as seguintes declarações de variável após as
usinginstruções:// Global variables hstring modelPath; string deviceName = "default"; hstring imagePath; LearningModel model = nullptr; LearningModelDeviceKind deviceKind = LearningModelDeviceKind::Default; LearningModelSession session = nullptr; LearningModelBinding binding = nullptr; VideoFrame imageFrame = nullptr; string labelsFilePath; vector<string> labels;Adicione as seguintes declarações de encaminhamento após suas variáveis globais:
// Forward declarations void LoadModel(); VideoFrame LoadImageFile(hstring filePath); void BindModel(); void EvaluateModel(); void PrintResults(IVectorView<float> results); void LoadLabels();Em main.cpp, remova o código "Olá, mundo" (tudo da função
mainapósinit_apartment).Localize o arquivo SqueezeNet.onnx no clone local do repositório Windows-Machine-Learning . Ele deve estar localizado em \Windows-Machine-Learning\SharedContent\models.
Copie o caminho do arquivo e atribua-o à variável
modelPathem que o definimos na parte superior. Lembre-se de prefixar a cadeia de caracteres com umLpara torná-la uma cadeia de caracteres larga que funcione corretamente comhstringe para o escape das barras invertidas (\) com uma barra invertida extra. Por exemplo:hstring modelPath = L"C:\\Repos\\Windows-Machine-Learning\\SharedContent\\models\\SqueezeNet.onnx";Primeiro, implementaremos o
LoadModelmétodo. Adicione o método a seguir após omainmétodo. Esse método carrega o modelo e gera quanto tempo levou:void LoadModel() { // load the model printf("Loading modelfile '%ws' on the '%s' device\n", modelPath.c_str(), deviceName.c_str()); DWORD ticks = GetTickCount(); model = LearningModel::LoadFromFilePath(modelPath); ticks = GetTickCount() - ticks; printf("model file loaded in %d ticks\n", ticks); }Por fim, chame esse método no método
main:LoadModel();Execute o programa sem depuração. Você verá que o modelo foi carregado com êxito!
Carregar a imagem
Em seguida, carregaremos o arquivo de imagem em nosso programa:
Adicione o método a seguir. Esse método carregará a imagem do caminho fornecido e criará um VideoFrame a partir dele:
VideoFrame LoadImageFile(hstring filePath) { printf("Loading the image...\n"); DWORD ticks = GetTickCount(); VideoFrame inputImage = nullptr; try { // open the file StorageFile file = StorageFile::GetFileFromPathAsync(filePath).get(); // get a stream on it auto stream = file.OpenAsync(FileAccessMode::Read).get(); // Create the decoder from the stream BitmapDecoder decoder = BitmapDecoder::CreateAsync(stream).get(); // get the bitmap SoftwareBitmap softwareBitmap = decoder.GetSoftwareBitmapAsync().get(); // load a videoframe from it inputImage = VideoFrame::CreateWithSoftwareBitmap(softwareBitmap); } catch (...) { printf("failed to load the image file, make sure you are using fully qualified paths\r\n"); exit(EXIT_FAILURE); } ticks = GetTickCount() - ticks; printf("image file loaded in %d ticks\n", ticks); // all done return inputImage; }Adicione uma chamada a esse método no
mainmétodo:imageFrame = LoadImageFile(imagePath);Localize a pasta de mídia no clone local do repositório Windows-Machine-Learning . Ele deve estar localizado em \Windows-Machine-Learning\SharedContent\media.
Escolha uma das imagens nessa pasta e atribua seu caminho de arquivo à
imagePathvariável em que a definimos na parte superior. Lembre-se de prefixá-la com umLpara torná-la uma cadeia de caracteres larga e fazer o escape das barras invertidas com outra barra invertida. Por exemplo:hstring imagePath = L"C:\\Repos\\Windows-Machine-Learning\\SharedContent\\media\\kitten_224.png";Execute o programa sem depuração. Você deve ver a imagem carregada com êxito!
Associar a entrada e a saída
Em seguida, criaremos uma sessão com base no modelo e associaremos a entrada e a saída da sessão usando LearningModelBinding.Bind. Para obter mais informações sobre associação, consulte Associar um modelo.
Implemente o método
BindModel. Isso cria uma sessão com base no modelo e no dispositivo e uma associação com base nessa sessão. Em seguida, associamos as entradas e saídas a variáveis que criamos usando seus nomes. Sabemos antecipadamente que o recurso de entrada é chamado de "data_0" e o recurso de saída é chamado de "softmaxout_1". Você pode ver essas propriedades para qualquer modelo abrindo-as no Netron, uma ferramenta de visualização de modelo online.void BindModel() { printf("Binding the model...\n"); DWORD ticks = GetTickCount(); // now create a session and binding session = LearningModelSession{ model, LearningModelDevice(deviceKind) }; binding = LearningModelBinding{ session }; // bind the intput image binding.Bind(L"data_0", ImageFeatureValue::CreateFromVideoFrame(imageFrame)); // bind the output vector<int64_t> shape({ 1, 1000, 1, 1 }); binding.Bind(L"softmaxout_1", TensorFloat::Create(shape)); ticks = GetTickCount() - ticks; printf("Model bound in %d ticks\n", ticks); }Adicione uma chamada para
BindModelno métodomain:BindModel();Execute o programa sem depuração. As entradas e saídas do modelo devem ser associadas com êxito. Estamos quase lá!
Avaliar o modelo
Agora estamos na última etapa do diagrama no início deste tutorial, Avaliar. Avaliaremos o modelo usando LearningModelSession.Evaluate:
Implemente o método
EvaluateModel. Esse método usa nossa sessão e a avalia usando nossa associação e uma ID de correlação. A ID de correlação é algo que poderíamos usar posteriormente para corresponder a uma chamada de avaliação específica aos resultados de saída. Mais uma vez, sabemos antecipadamente que o nome da saída é "softmaxout_1".void EvaluateModel() { // now run the model printf("Running the model...\n"); DWORD ticks = GetTickCount(); auto results = session.Evaluate(binding, L"RunId"); ticks = GetTickCount() - ticks; printf("model run took %d ticks\n", ticks); // get the output auto resultTensor = results.Outputs().Lookup(L"softmaxout_1").as<TensorFloat>(); auto resultVector = resultTensor.GetAsVectorView(); PrintResults(resultVector); }Agora vamos implementar
PrintResults. Esse método obtém as três principais probabilidades de qual objeto poderia estar na imagem e as imprime:void PrintResults(IVectorView<float> results) { // load the labels LoadLabels(); // Find the top 3 probabilities vector<float> topProbabilities(3); vector<int> topProbabilityLabelIndexes(3); // SqueezeNet returns a list of 1000 options, with probabilities for each, loop through all for (uint32_t i = 0; i < results.Size(); i++) { // is it one of the top 3? for (int j = 0; j < 3; j++) { if (results.GetAt(i) > topProbabilities[j]) { topProbabilityLabelIndexes[j] = i; topProbabilities[j] = results.GetAt(i); break; } } } // Display the result for (int i = 0; i < 3; i++) { printf("%s with confidence of %f\n", labels[topProbabilityLabelIndexes[i]].c_str(), topProbabilities[i]); } }Também precisamos implementar
LoadLabels. Esse método abre o arquivo de rótulos que contém todos os diferentes objetos que o modelo pode reconhecer e o analisa:void LoadLabels() { // Parse labels from labels file. We know the file's entries are already sorted in order. ifstream labelFile{ labelsFilePath, ifstream::in }; if (labelFile.fail()) { printf("failed to load the %s file. Make sure it exists in the same folder as the app\r\n", labelsFilePath.c_str()); exit(EXIT_FAILURE); } std::string s; while (std::getline(labelFile, s, ',')) { int labelValue = atoi(s.c_str()); if (labelValue >= labels.size()) { labels.resize(labelValue + 1); } std::getline(labelFile, s); labels[labelValue] = s; } }Localize o arquivo Labels.txt em seu clone local do repositório Windows-Machine-Learning . Ele deve estar em \Windows-Machine-Learning\Samples\SqueezeNetObjectDetection\Desktop\cpp.
Atribua esse caminho de arquivo à
labelsFilePathvariável em que o definimos na parte superior. Faça o escape das barras invertidas com outra barra invertida. Por exemplo:string labelsFilePath = "C:\\Repos\\Windows-Machine-Learning\\Samples\\SqueezeNetObjectDetection\\Desktop\\cpp\\Labels.txt";Adicione uma chamada ao
EvaluateModelno métodomain:EvaluateModel();Execute o programa sem depuração. Agora ele deve reconhecer corretamente o que está na imagem! Aqui está um exemplo do que ele pode gerar:
Loading modelfile 'C:\Repos\Windows-Machine-Learning\SharedContent\models\SqueezeNet.onnx' on the 'default' device model file loaded in 250 ticks Loading the image... image file loaded in 78 ticks Binding the model...Model bound in 15 ticks Running the model... model run took 16 ticks tabby, tabby cat with confidence of 0.931461 Egyptian cat with confidence of 0.065307 Persian cat with confidence of 0.000193
Próximas etapas
Parabéns, você fez a detecção de objetos funcionar em um aplicativo da área de trabalho C++! Em seguida, você pode tentar usar argumentos de linha de comando para inserir os arquivos de modelo e imagem em vez de codificar, semelhante ao que o exemplo no GitHub faz. Você também pode tentar executar a avaliação em um dispositivo diferente, como a GPU, para ver como o desempenho difere.
Jogue com os outros exemplos no GitHub e estenda-os como quiser!
Consulte também
Observação
Use os seguintes recursos 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 em nosso GitHub.