Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В предыдущей части этого руководства вы узнали, как создать и экспортировать модель в формате ONNX. Теперь, когда у вас есть эта модель, вы можете внедрить его в приложение Windows и запустить его локально на устройстве, вызвав API WinML.
После завершения работы у вас будет приложение WinML UWP с рабочим классификатором изображений (C#).
Сведения о примере приложения
С помощью нашей модели мы создадим приложение, которое может классифицировать изображения продуктов питания. Он предоставляет возможность выбрать изображение с вашего локального устройства и обработать его классификационной моделью ONNX, которая хранится локально и была создана и обучена в предыдущей части. Возвращаемые теги отображаются рядом с изображением, а также вероятность достоверности классификации.
Если вы выполнили это руководство до сих пор, у вас уже должны быть необходимые предварительные требования для разработки приложений. Если вам нужно освежить память, ознакомьтесь с первой частью этого руководства.
Замечание
Если вы предпочитаете скачать полный пример кода, можно клонировать файл решения. Клонируйте репозиторий, перейдите к этому образцу ImageClassifierAppUWP.sln , а затем откройте файл с помощью Visual Studio. Затем можно перейти к шагу [Запустить приложение](#Launch_the_application).
Создание WinML UWP (C#)
Ниже показано, как создать приложение и код WinML с нуля. Вы узнаете, как:
- Загрузите модель машинного обучения.
- Загрузите изображение в требуемом формате.
- Свяжите входные и выходные данные модели.
- Оцените модель и отобразите значимые результаты.
Вы также будете использовать базовый КОД XAML для создания простого графического интерфейса, чтобы протестировать классификатор изображений.
Создание приложения
- Откройте Visual Studio и выберите
create a new project.
- В строке поиска введите
UWPи выберитеBlank APP (Universal Windows). Откроется новый проект C# для одностраничного приложения универсальной платформы Windows (UWP), не имеющего предопределенных элементов управления или макета. ВыберитеNext, чтобы открыть окно конфигурации для проекта.
- В окне конфигурации:
- Выберите имя проекта. Здесь мы используем ImageClassifierAppUWP.
- Выберите расположение проекта.
- Если вы используете VS 2019, убедитесь, что флажок
Place solution and project in the same directoryснят. - Если вы используете VS 2017, убедитесь, что
Create directory for solutionустановлен флажок.
Нажмите, create чтобы создать проект. Окно минимально целевой версии может появиться. Убедитесь, что минимальная версия установлена на Windows 10 сборки 17763 или более поздней.
Чтобы создать приложение и развернуть модель с помощью приложения WinML, вам потребуется следующее:
После создания проекта перейдите в папку проекта, откройте папку ресурсов [....\ImageClassifierAppUWP\Assets], а затем скопируйте модель в это расположение.
Измените имя модели с
model.onnxнаclassifier.onnx. Это делает ситуацию более понятной и приводит её в соответствие с форматом учебника.
Изучите вашу модель
Давайте познакомимся со структурой файла модели.
classifier.onnxОткройте файл модели с помощью Netron.Нажмите,
Dataчтобы открыть свойства модели.
Как видно, модель требует 32-битный тензор (многомерный массив) с плавающей запятой в качестве входных данных и возвращает два результата: первый, названный classLabel, является тензором строк, а второй, названный loss, представляет собой последовательность карт соответствий строки с числами с плавающей запятой, описывающих вероятность каждой классификации с метками. Эти сведения потребуются для успешного отображения выходных данных модели в приложении Windows.
Изучение решения проекта
Давайте рассмотрим решение проекта.
Visual Studio автоматически создал несколько файлов cs-code в обозревателе решений.
MainPage.xaml содержит код XAML для графического интерфейса MainPage.xaml.cs и содержит код приложения. Если вы создали приложение UWP раньше, эти файлы должны быть очень знакомы с вами.
Создание графического интерфейса приложения
Сначала создадим простой графический интерфейс для приложения.
Дважды щелкните файл
MainPage.xaml. В пустом приложении шаблон XAML для графического интерфейса приложения пуст, поэтому нам потребуется добавить некоторые функции пользовательского интерфейса.Добавьте приведенный ниже код в основной текст
MainPage.xaml.
<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="30,0,0,0"
Text="" Width="1471" />
<Button Name="ProbabilityResult"
Content="Probability is:"
Width="110"
Height="40"
IsEnabled="True"
HorizontalAlignment="Left"/>
<!--Display the Result-->
<TextBlock Name="displayProbability"
FontWeight="Bold"
TextWrapping="Wrap"
Margin="30,0,0,0"
Text="" Width="1471" />
<TextBlock Name="space2" />
<!--Image preview -->
<Image Name="UIPreviewImage" Stretch="Uniform" MaxWidth="300" MaxHeight="300"/>
</StackPanel>
</Grid>
Генератор кода машинного обучения Windows
Генератор кода Машинного обучения Windows или mlgen — это расширение Visual Studio, помогающее приступить к работе с API WinML в приложениях UWP. Он генерирует шаблонный код при добавлении обученного файла ONNX в проект UWP.
Генератор кода Windows Machine Learning mlgen создает интерфейс (для C#, C++/WinRT и C++/CX) с классами-оболочками, которые вызывают API машинного обучения Windows для вас. Это позволяет легко загружать, привязывать и оценивать модель в проекте. Мы будем использовать его в данном руководстве для обработки многих из этих функций для нас.
Генератор кода доступен для Visual Studio 2017 и более поздних версий. Помните, что в Windows 10 версии 1903 и более поздних версий mlgen больше не входит в пакет SDK для Windows 10, поэтому необходимо скачать и установить расширение. Если вы следовали этому руководству с самого начала, вы уже должны были это сделать; если нет, вам следует скачать для VS 2019 или VS 2017.
Замечание
Дополнительные сведения о mlgen см. в документации по mlgen
Если вы еще не сделали этого, установите mlgen.
Щелкните правой кнопкой мыши
Assetsпапку в обозревателе решений в Visual Studio и выберитеAdd > Existing Item.Перейдите в папку assets внутри
ImageClassifierAppUWP [….\ImageClassifierAppUWP\Assets], найдите модель ONNX, скопированную ранее, и выберитеadd.После добавления модели ONNX (имя: "классификатор") в папку ресурсов в обозревателе решений в VS проект должен иметь два новых файла:
-
classifier.onnx— это ваша модель в формате ONNX. -
classifier.cs— автоматически созданный файл кода WinML.
- Чтобы убедиться, что модель собирается, когда вы компилируете наше приложение, выберите файл
classifier.onnxи выполните действиеProperties. ВBuild ActionвыберитеContent.
Теперь давайте рассмотрим только что созданный код в файле classifier.cs.
Созданный код включает три класса:
-
classifierModel: этот класс включает два метода для создания экземпляра модели и оценки модели. Это поможет нам создать представление модели машинного обучения, создать сеанс на устройстве по умолчанию системы, привязать определенные входные и выходные данные к модели и асинхронно оценить модель. -
classifierInput: этот класс инициализирует типы входных данных, которые ожидает модель. Входные данные модели зависят от требований модели для входных данных. В нашем случае входные данные ожидают ImageFeatureValue, класс, описывающий свойства изображения, используемого для передачи в модель. -
classifierOutput: этот класс инициализирует типы, которые будет выводить модель. Выходные данные модели зависят от того, как она определена моделью. В нашем случае выходные данные будут последовательностью карт (словарей) типа String и TensorFloat (Float32) с именем loss.
Теперь эти классы будут использоваться для загрузки, привязки и оценки модели в нашем проекте.
Загрузка модели и входных данных
Загрузка модели
Дважды щелкните кодовый файл
MainPage.xaml.cs, чтобы открыть код приложения.Замените инструкции using на следующие, чтобы получить доступ ко всем API, которые вам понадобятся.
// 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;
- Добавьте следующие объявления переменных после инструкций using внутри класса
MainPage, в пространстве именImageClassifierAppUWP.
// All the required variable declaration
private classifierModel modelGen;
private classifierInput input = new classifierModelInput();
private classifierOutput output;
private StorageFile selectedStorageFile;
private string result = "";
private float resultProbability = 0;
Результат будет выглядеть следующим образом.
// 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;
namespace ImageClassifierAppUWP
{
public sealed partial class MainPage : Page
{
// All the required fields declaration
private classifierModel modelGen;
private classifierInput input = new classifierInput();
private classifierOutput output;
private StorageFile selectedStorageFile;
private string result = "";
private float resultProbability = 0;
Теперь вы реализуете LoadModel метод. Метод получит доступ к модели ONNX и сохранит его в памяти. Затем вы будете использовать метод CreateFromStreamAsync, чтобы создать объект модели как экземпляр LearningModel. Класс LearningModel представляет обученную модель машинного обучения. После создания экземпляра LearningModel это начальный объект, который используется для взаимодействия с Windows ML.
Для загрузки модели можно использовать несколько статических методов в LearningModel классе. В этом случае вы будете использовать метод CreateFromStreamAsync.
Метод CreateFromStreamAsync был автоматически создан с помощью mlgen, поэтому вам не нужно реализовать этот метод. Этот метод можно просмотреть, дважды щелкнув classifier.cs файл, созданный mlgen.
Дополнительные сведения о LearningModel классе см. в документации по классу LearningModel.
Дополнительные сведения о дополнительных способах загрузки модели см. в документации по загрузке модели.
- Вставьте метод
loadModelв ваш файл кодаMainPage.xaml.cs, находящийся внутри класса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/classifier.onnx"));
// Instantiate the model.
modelGen = await classifierModel.CreateFromStreamAsync(modelFile);
}
- Теперь добавьте вызов нового метода в конструктор класса.
// The main page to initialize and execute the model.
public MainPage()
{
this.InitializeComponent();
loadModel();
}
Результат будет выглядеть следующим образом.
// The main page to initialize and execute the model.
public MainPage()
{
this.InitializeComponent();
loadModel();
}
// A method to load a machine learning model.
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/classifier.onnx"));
// Instantiate the model.
modelGen = await classifierModel.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.
- Добавьте реализацию метода
convert()в ваш файл кодаMainPage.xaml.csвнутри класса MainPage. Метод convert позволит нам получить представление входного файла в формате 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);
// bind the input image
ImageFeatureValue imageTensor = ImageFeatureValue.CreateFromVideoFrame(inputImage);
input.data = imageTensor;
}
catch (Exception e)
{
}
}
Результат работы, выполненной в этом разделе, будет выглядеть следующим образом.
// 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, we begin the model execution.
// Bind the model input
await imageBind();
// Model evaluation
await evaluate();
// Extract the results
extractResult();
// Display the results
await displayResult();
}
// 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;
}
// 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);
// bind the input image
ImageFeatureValue imageTensor = ImageFeatureValue.CreateFromVideoFrame(inputImage);
input.data = imageTensor;
}
catch (Exception e)
{
}
}
Привязка и оценка модели
Затем вы создадите сеанс на основе модели, привязываете входные и выходные данные сеанса и оцените модель.
Создайте сеанс для привязки модели:
Чтобы создать сеанс, используйте LearningModelSession класс. Этот класс используется для оценки моделей машинного обучения и привязывает модель к устройству, который затем запускает и оценивает модель. Вы можете выбрать устройство при создании сеанса для выполнения модели на определенном устройстве компьютера. Устройство по умолчанию — это ЦП.
Замечание
Дополнительные сведения о выборе устройства см. в документации по созданию сеанса .
Привязка входных и выходных данных модели:
Для привязки входных и выходных данных используется LearningModelBinding класс. Модель машинного обучения имеет функции ввода и вывода, которые передают информацию в модель и из нее. Помните, что необходимые функции должны поддерживаться API Windows ML. Класс LearningModelBinding применяется к привязке значений LearningModelSession к именованным функциям ввода и вывода.
Реализация привязки автоматически генерируется mlgen, поэтому вам не нужно об этом беспокоиться. Привязка реализуется путем вызова предопределенных методов LearningModelBinding класса. В нашем случае он использует Bind метод для привязки значения к именованным типу признаков.
В настоящее время Windows ML поддерживает все типы объектов ONNX, такие как тензоры (многомерные массивы), последовательности (векторы значений), отображения (пары значений информации) и изображения (определенные форматы). Все изображения будут представлены в windows ML в тензорном формате. Tensorization — это процесс преобразования изображения в тензор и происходит во время привязки.
К счастью, вам не нужно заботиться о преобразовании тензоризации. Метод ImageFeatureValue , используемый в предыдущей части, отвечает за преобразование и тензоризацию, поэтому изображения соответствуют требуемому формату изображения модели.
Замечание
Чтобы узнать больше о том, как привязать LearningModel, и о типах функций, поддерживаемых WinML, пожалуйста, ознакомьтесь с документацией по привязке модели.
Оцените модель:
После создания сеанса для привязки модели и привязанных значений к входным и выходным данным модели можно оценить входные данные модели и получить его прогнозы. Чтобы выполнить выполнение модели, необходимо вызвать любой из предопределенных методов оценки в LearningModelSession. В нашем случае мы будем использовать метод EvaluateAsync.
CreateFromStreamAsyncАналогично тому, EvaluateAsync метод также был автоматически создан генератором кода WinML, поэтому вам не нужно реализовать этот метод. Этот метод можно просмотреть в classifier.cs файле.
Метод EvaluateAsync асинхронно оценивает модель машинного обучения с помощью значений признаков, уже привязанных в привязках. Он создаст сеанс с LearningModelSession, привязывает входные и выходные данные с LearningModelBinding, выполняет оценку модели и получает выходные функции модели с помощью LearningModelEvaluationResult класса.
Замечание
Чтобы узнать о других методах оценки для запуска модели, проверьте, какие методы можно реализовать в LearningModelSession, просмотрите документацию по классу LearningModelSession.
- Добавьте следующий метод в файл кода
MainPage.xaml.csвнутри класса MainPage, чтобы создать сеанс, привязать модель и выполнить её оценку.
// A method to evaluate the model
private async Task evaluate()
{
output = await modelGen.EvaluateAsync(input);
}
Извлечение и отображение результатов
Теперь необходимо извлечь выходные данные модели и отобразить правильные результаты. Вы сделаете это, реализовав метод extractResult и метод displayResult.
Как вы изучили ранее, модель возвращает два выходных данных: первый, именованный classLabel, это тензор строк, а второй, именованный loss, — это последовательность отображений строк в числа с плавающей запятой, которая описывает вероятность для каждой помеченной классификации. Таким образом, чтобы успешно отобразить результат и вероятность, необходимо извлечь выходные данные из выходных данных потери. Нам потребуется найти самую высокую вероятность возврата правильного результата.
- Добавьте метод
extractResultв файл кодаMainPage.xaml.csвнутри классаMainPage.
private void extractResult()
{
// A method to extract output (result and a probability) from the "loss" output of the model
var collection = output.loss;
float maxProbability = 0;
string keyOfMax = "";
foreach (var dictionary in collection)
{
foreach (var key in dictionary.Keys)
{
if (dictionary[key] > maxProbability)
{
maxProbability = dictionary[key];
keyOfMax = key;
}
}
}
result = keyOfMax;
resultProbability = maxProbability;
}
- Добавьте метод
displayResultв файл кодаMainPage.xaml.csвнутри классаMainPage.
// A method to display the results
private async Task displayResult()
{
displayOutput.Text = result.ToString();
displayProbability.Text = resultProbability.ToString();
}
Результат выполнения частей Привязки и Оценки и Извлечения и отображения результатов кода WinML нашего приложения будет выглядеть следующим образом.
// A method to evaluate the model
private async Task evaluate()
{
output = await modelGen.EvaluateAsync(input);
}
// A method to extract output (string and a probability) from the "loss" output of the model
private void extractResult()
{
var collection = output.loss;
float maxProbability = 0;
string keyOfMax = "";
foreach (var dictionary in collection)
{
foreach (var key in dictionary.Keys)
{
if (dictionary[key] > maxProbability)
{
maxProbability = dictionary[key];
keyOfMax = key;
}
}
}
result = keyOfMax;
resultProbability = maxProbability;
}
// A method to display the results
private async Task displayResult()
{
displayOutput.Text = result.ToString();
displayProbability.Text = resultProbability.ToString();
}
Вот и все! Вы успешно создали приложение машинного обучения Windows с базовым графическим интерфейсом для тестирования модели классификации. Следующим шагом является запуск приложения и его локальное запуск на устройстве Windows.
Запуск приложения
После завершения интерфейса приложения добавьте модель и создав код WinML, можно протестировать приложение. Убедитесь, что в раскрывающемся меню на верхней панели инструментов задано значение Debug. Измените Solution Platform на x64, чтобы запустить проект на локальном компьютере, если ваше устройство является 64-разрядным, или на x86, если оно 32-разрядное.
Чтобы протестировать наше приложение, вы будете использовать приведенный ниже образ фруктов. Давайте посмотрим, как наше приложение классифицирует содержимое изображения.
Сохраните этот образ на локальном устройстве, чтобы протестировать приложение. При необходимости измените формат изображения на jpg. Вы также можете добавить любое другое соответствующее изображение с локального устройства в подходящем формате — .jpg, .png, .bmpили .gif форматах.
Чтобы запустить проект, нажмите
Start Debuggingкнопку на панели инструментов или нажмите клавишуF5.При запуске приложения нажмите
Pick Imageи выберите изображение на локальном устройстве.
Результат появится на экране сразу. Как видно, наше приложение WinML успешно классифицирует изображение как фрукты или овощи, с рейтингом достоверности 99,9%.
Сводка
Вы только что сделали свое первое приложение Машинного обучения Windows, начиная с создания модели до успешного выполнения.
Дополнительные ресурсы
Дополнительные сведения о разделах, упомянутых в этом руководстве, см. в следующих ресурсах:
- Средства машинного обучения Windows: узнайте больше о таких средствах, как Windows ML Dashboard, WinMLRunner и mglen Windows ML генераторе кода.
- Модель ONNX. Дополнительные сведения о формате ONNX.
- Производительность и память Windows ML: узнайте больше, как управлять производительностью приложений с помощью Windows ML.
- Справочник по API машинного обучения Windows: дополнительные сведения о трех областях API Машинного обучения Windows.