Развертывание модели в приложении Windows с помощью API Windows ML
Примечание.
Для повышения функциональности PyTorch также можно использовать с DirectML в Windows.
Из предыдущей части этого руководства вы узнали, как создавать и экспортировать модели в формате ONNX. Теперь мы продемонстрируем, как внедрить экспортированную ранее модель в приложение Windows и запустить ее на локальном устройстве с помощью вызовов к API WinML.
Когда мы закончим этот процесс, у вас будет готовое приложение для классификации изображений.
Сведения о примере приложения
На этом этапе вы создадите приложение, которое будет классифицировать изображения с использованием модели машинного обучения. Несложный пользовательский интерфейс приложения позволяет выбрать изображение на локальном устройстве и классифицировать его с помощью модели классификации ONNX, которая была создана и обучена в предыдущей части. Теги, возвращаемые этой моделью, отображаются рядом с изображением.
В этой статье мы подробно рассматриваем этот процесс.
Примечание.
Если вы предпочитаете получить готовый пример кода, клонируйте файл решения. Для этого клонируйте репозиторий, перейдите в нем к нужному примеру и откройте файл classifierPyTorch.sln
в Visual Studio. Процесс работы с ним описан далее, в разделе Запуск приложения.
Ниже показано, как создать приложение и добавить в него код Windows ML.
Создание приложения UWP (C#) для Windows ML
Чтобы получить работающее приложение Windows ML, сделайте следующее:
- Загрузите модель машинного обучения.
- Загрузите изображение в требуемом формате.
- Создайте привязки для входных и выходных данных модели.
- Оцените модели и отобразите полезные результаты.
Вам также потребуется создать несложный пользовательский интерфейс, поскольку в командной строке сложно создать хорошее приложение для работы с изображениями.
Открытие нового проекта в Visual Studio
- Итак, приступим. Откройте Visual Studio и щелкните Создать проект.
- В строке поиска введите
UWP
и выберитеBlank APP (Universal Windows)
. Откроется проект C# для одностраничного приложения универсальной платформы Windows (UWP) с предопределенными элементами управления или макетом. Выберитеnext
, чтобы открыть окно конфигурации для проекта.
- В окне конфигурации сделайте следующее:
- Присвойте проекту имя. В нашем примере это classifierPyTorch.
- Выберите расположение проекта.
- Если вы используете VS 2019, установите флажок
Create directory for solution
. - Если вы используете VS2017, снимите флажок
Place solution and project in the same directory
.
Щелкните create
, чтобы создать проект. Может появиться окно для ввода минимальной целевой версией. Убедитесь, что в качестве минимальной версии указана версия Windows 10 версии 1809 (10.0; сборка 17763) или более поздняя.
- После создания проекта перейдите в папку этого проекта, откройте папку assets (
[….\classifierPyTorch \Assets]
) и скопируйте файлImageClassifier.onnx
в это расположение.
Обзор решения проекта
Давайте изучим решение проекта.
Visual Studio автоматически создает несколько файлов cs-code в Обозревателе решений. Файл MainPage.xaml
содержит код XAML для графического пользовательского интерфейса, а файл MainPage.xaml.cs
— код приложения, или "код программной части". Если вы уже создавали приложения UWP, эти файлы должны быть вам хорошо знакомы.
Создание графического пользовательского интерфейса приложения
Сначала мы создадим простой графический пользовательский интерфейс для приложения.
Дважды щелкните файл кода
MainPage.xaml
. В пустом приложении шаблон XAML для графического пользовательского интерфейса приложения пуст, поэтому нам нужно добавить некоторые возможности пользовательского интерфейса.Добавьте в
MainPage.xaml
приведенный ниже код, заменив значения тегов<Grid>
и</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>
Добавление модели в проект с помощью генератора кода Windows ML (mlgen)
Генератор кода Windows Machine Learning (mlgen) — это расширение Visual Studio, которое поможет вам приступить к использованию API-интерфейсов WinML в приложениях UWP. Он создает код шаблона при добавлении обученного файла ONNX в проект UWP.
Генератор кода Windows Machine Learning mlgen создает интерфейс (для C#, C++/WinRT и C++/CX) с классами-оболочками, которые вызывают API Windows ML. Это позволяет легко загружать, привязывать и оценивать модель в проекте. Мы будем использовать его в этом руководстве для решения многих задач такого типа.
Генератор кода доступен для Visual Studio 2017 и более поздних версий. Рекомендуется использовать Visual Studio 2019. Имейте в виду, что в Windows 10 версии 1903 и более поздних версиях mlgen больше не входит в Windows 10 SDK, поэтому вы должны скачать и установить расширение. Если вы выполняли все инструкции из этого руководства с самого начала, то у вас уже есть это средство. Если нет, то вам следует скачать версию для Visual Studio 2019 или для Visual Studio 2017.
Примечание.
Дополнительные сведения см. в документации по mlgen.
Установите mlgen, если вы еще этого не сделали.
Щелкните правой кнопкой мыши папку
Assets
в Обозревателе решений в Visual Studio и выберитеAdd > Existing Item
.Перейдите в папку ресурсов внутри
classifierPyTorch [….\classifierPyTorch \Assets]
, найдите модель ONNX, которую вы ранее скопировали туда, и выберитеadd
.После того, как вы добавили модель ONNX в папку assets в Обозревателе решений в Visual Studio, проект теперь должен иметь два новых файла:
ImageClassifier.onnx
— это модель в формате ONNX;ImageClassifier.cs
— автоматически созданный файл кода WinML.
- Чтобы убедиться, что модель успешно компилируется вместе с приложением, выберите файл
ImageClassifier.onnx
и щелкнитеProperties
. ВBuild Action
выберитеContent
.
Код в файле ONNX
Теперь давайте рассмотрим только что созданный код в файле ImageClassifier.cs
.
Созданный код включает в себя три класса:
- Класс
ImageClassifierModel
содержит два метода: для создания экземпляра модели и оценки модели. Этот класс поможет создать представление модели машинного обучения и сеанс на системном устройстве по умолчанию, привязать к модели определенные входные и выходные данные, а также асинхронно анализировать модель. - Класс
ImageClassifierInput
инициализирует типы входных данных, которые ожидает получить модель. Входные данные модели зависят от требований модели к входным данным. - Класс
ImageClassifierOutput
инициализирует типы, которые модель выводит. Выходные данные модели зависят от того, как они определяются моделью.
В этом руководстве мы не будем рассматривать преобразование в тензор. Поэтому в класс ImageClassifierInput
мы внесем небольшое изменение, чтобы использовать другой тип входных данных и немного упростить жизнь.
- Внесите следующие изменения в файл
ImageClassifier.cs
:
Для переменной input
замените значение TensorFloat
на ImageFeatureValue
.
public sealed class ImageClassifierInput
{
public ImageFeatureValue input; // shape(-1,3,32,32)
}
Загрузка модели
Дважды щелкните файл
MainPage.xaml.cs
, чтобы открыть код программной части вашего приложения.Замените все операторы using следующим выражением, чтобы получить доступ ко всем необходимым API.
// 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;
- Добавьте следующие объявления переменных в класс
MainPage
прямо над функциейpublic MainPage()
.
// 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
}
Теперь вы реализуете метод LoadModel
. Этот метод будет обращаться к модели ONNX и хранить ее в памяти. Затем вы примените метод CreateFromStreamAsync
для создания экземпляра модели в качестве объекта LearningModel
. Класс LearningModel
представляет обученную модель машинного обучения. Созданный экземпляр LearningModel
является начальным объектом, который вы используете для взаимодействия с Windows ML.
Чтобы загрузить модель, в классе LearningModel
можно использовать несколько статических методов. В нашем примере вы будете использовать метод CreateFromStreamAsync
.
Метод CreateFromStreamAsync
был автоматически создан с помощью mlgen, поэтому вам не нужно реализовывать его. Чтобы проверить этот метод, дважды щелкните файл classifier.cs
, созданный с помощью mlgen.
Примечание.
Дополнительные сведения о классе LearningModel
см. в документации по классу LearningModel. Дополнительные сведения о способах загрузки модели см. в документации по загрузке модели.
- Добавьте вызов метода
loadModel
в конструктор класса main.
// The main page to initialize and execute the model.
public MainPage()
{
this.InitializeComponent();
loadModel();
}
- Добавьте реализацию метода
loadModel
в классMainPage
.
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);
}
Загрузка изображения
- Необходимо определить событие щелчка, которое инициирует последовательность из вызовов четырех методов для выполнения модели — преобразование, привязку и оценку, извлечение выходных данных и отображение результатов. Добавьте следующий метод в файл кода
MainPage.xaml.cs
внутри классаMainPage
.
// 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();
}
- Теперь вы реализуете метод
getImage()
. Этот метод выбирает входной файл изображения и сохраняет его в памяти. Добавьте следующий метод в файл кодаMainPage.xaml.cs
внутри классаMainPage
.
// 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;
}
Теперь вы реализуете метод изображения Bind()
, чтобы получить представление файла в формате растрового изображения BGRA8. Но сначала нужно создать вспомогательный класс для изменения размера изображения.
- Чтобы создать вспомогательный файл, щелкните имя решения (
ClassifierPyTorch
) правой кнопкой мыши, а затем выберитеAdd a new item
. В открывшемся окне выберитеClass
и присвойте ему имя. В нашем примере этоHelper
.
- В вашем проекте появится новый файл класса. Откройте этот класс и добавьте в него следующий код:
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;
}
}
}
Теперь нам нужно преобразовать изображение в подходящий формат.
Класс ImageClassifierInput
инициализирует типы входных данных, которые ожидает получить модель. В нашем примере код настроен так, чтобы ожидать ImageFeatureValue
.
Класс ImageFeatureValue
описывает свойства изображения, которое передается в модель. Для создания ImageFeatureValue
используется метод CreateFromVideoFrame
. Более подробно причины и правила использования этих классов и методов описаны в документации по классу ImageFeatureValue.
Примечание.
В этом руководстве мы вместо тензора используем класс ImageFeatureValue
. Если Window ML не поддерживает цветовой формат вашей модели, такой вариант вам не подходит. Пример работы с преобразованием изображений и преобразованием в тензор см. здесь.
- Добавьте реализацию метода
convert()
в файл кодаMainPage.xaml.cs
внутри класса MainPage. Метод convert получает представление входного файла в формате 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)
{
}
}
Привязка и оценка модели
Теперь вам нужно создать сеанс на основе модели, привязать входные и выходные данные этого сеанса, а затем оценить модель.
Создайте сеанс для привязки модели:
Чтобы создать сеанс, используйте класс LearningModelSession
. Этот класс используется для оценки моделей машинного обучения и привязки модели к устройству, которое затем запускается и оценивает модель. Вы можете выбрать устройство при создании сеанса, чтобы иметь возможность выполнять модель на определенном устройстве компьютера. В качестве устройства по умолчанию используется ЦП.
Примечание.
Дополнительные сведения о том, как выбрать устройство, см. в документации по созданию сеанса.
Привязка входных и выходных данных:
Для привязки входных и выходных данных нужно использовать класс LearningModelBinding
. Модель машинного обучения имеет выходные и выходные признаки для передачи информации в модель и из нее. Имейте в виду, что требуемые признаки должны поддерживаться API Window ML. Класс LearningModelBinding
применяется к LearningModelSession
для привязки значений к именованным входным и выходным признакам.
Реализация привязки автоматически создается с помощью mlgen, поэтому вам не нужно об этом беспокоиться. Привязка реализуется путем вызова предопределенных методов класса LearningModelBinding
. В нашем случае используется метод Bind
для привязки значения к именованному типу признака.
Оценка модели:
Создав сеанс для привязки модели и привязанные значения для входных и выходных данных модели, вы можете приступить к оценке входных данных модели и получить ее прогнозы. Чтобы запустить выполнение модели, следует вызвать любой из предопределенных методов оценки в LearningModelSession. В нашем примере мы будем использовать метод EvaluateAsync
.
Как и CreateFromStreamAsync
, метод EvaluateAsync
был автоматически создан генератором кода WinML, поэтому вам не нужно реализовывать этот метод. Этот метод можно просмотреть в файле ImageClassifier.cs
.
Метод EvaluateAsync
будет асинхронно оценивать модель машинного обучения, используя значения признаков, уже привязанные в привязках. Он создает сеанс с помощью метода LearningModelSession
, привязывает входные и выходные данные с помощью метода LearningModelBinding
, выполняет оценку модели и получает выходные признаки модели с помощью класса LearningModelEvaluationResult
.
Примечание.
Чтобы узнать о других методах оценки для запуска модели, проверьте, какие методы можно реализовать в LearningModelSession, просмотрев документацию по классу LearningModelSession.
- Добавьте следующий метод в файл кода
MainPage.xaml.cs
внутри класса MainPage, чтобы создать сеанс, привязать и оценить модель.
// A method to evaluate the model
private async Task evaluate()
{
results = await modelGen.EvaluateAsync(image);
}
Извлечение и отображение результатов
Теперь вам нужно извлечь выходные данные модели и отобразить правильный результат, что можно выполнить с помощью реализации методов extractResult
и displayResult
. Чтобы вернуть правильную метку, нужно найти наибольшую вероятность.
- Добавьте метод
extractResult
в файл кодаMainPage.xaml.cs
внутри классаMainPage
.
// 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();
}
- Добавьте метод
displayResult
в файл кодаMainPage.xaml.cs
внутри классаMainPage
.
private async Task displayResult()
{
displayOutput.Text = label;
}
Вот и все! Вы успешно создали приложение Windows Machine Learning с простым графическим интерфейсом для тестирования модели классификации. Следующий шаг — запуск приложения на локальном устройстве Windows.
Запуск приложения
После того, как вы создали интерфейс приложения, добавили модель и сгенерировали код WinML, вы можете протестировать приложение.
Включите режим разработчика и протестируйте приложение в Visual Studio. В раскрывающихся меню на верхней панели инструментов должен быть указан режим Debug
. Для запуска проекта на локальном компьютере укажите для параметра "Платформа решения" значение x64 для 64-разрядного устройства или x86 для 32-разрядного.
Наша модель была обучена классификации изображений по следующим категориям: самолет, автомобиль, птица, кошка, олень, собака, лягушка, лошадь, корабль, грузовик. Чтобы протестировать приложение, вы примените изображение автомобиля из кубиков LEGO, созданного специально для нашего проекта. Давайте посмотрим, как наше приложение классифицирует содержимое этого изображения.
Сохраните это изображение на локальном устройстве, чтобы протестировать приложение. При необходимости измените формат изображения на
.jpg
. Вы также можете использовать любое другое изображение подходящей тематики, сохраненное на локальном устройстве в формате JPG или PNG.Чтобы запустить проект, нажмите кнопку
Start Debugging
на панели инструментов или нажмите клавишуF5
.Когда приложение откроется, нажмите Pick Image (Выбрать изображение) и выберите изображение на локальном устройстве.
Результат сразу отобразится на экране. Как видите, приложение Windows ML успешно распознало автомобиль на этом изображении.
Итоги
Вы только что создали свое первое приложение для Windows Machine Learning — от этапа создания модели до этапа успешного выполнения.
Дополнительные ресурсы
Дополнительные сведения см. в следующих статьях:
- Инструменты Windows ML. Ознакомьтесь с дополнительными инструментами, такими как информационная панель Windows ML, WinMLRunner и генератор кода mglen из Windows ML.
- Модель ONNX. Дополнительные сведения о формате ONNX.
- Использование вычислительной мощности и памяти для Windows ML. Узнайте, как управлять производительностью приложений в Windows ML.нк
- Справочник по API Windows Machine Learning. Узнайте больше о трех областях API-интерфейсов Windows ML.