Поделиться через


Руководство по созданию приложения UWP для Машинного обучения Windows (C#)

В этом руководстве мы создадим простое приложение универсальной платформы Windows, которое использует обученную модель машинного обучения для распознавания числовой цифры, рисуемой пользователем. В этом руководстве основное внимание уделяется загрузке и использованию Windows ML в приложении UWP.

В следующем видео приведен пример, на основе который основан этот учебник.


Если вы предпочитаете просто посмотреть код готового руководства, его можно найти в репозитории WinML GitHub. Он также доступен в C++/CX.

Предпосылки

  • Windows 10 (версия 1809 или более поздняя)
  • Пакет SDK для Windows 10 (сборка 17763 или более поздней версии)
  • Visual Studio 2019 (или Visual Studio 2017, версия 15.7.4 или более поздней версии)
  • Расширение генератора кода машинного обучения Windows для Visual Studio 2019 или 2017
  • Некоторые базовые знания UWP и C#

1. Открытие проекта в Visual Studio

После скачивания проекта из GitHub запустите Visual Studio и откройте файл MNIST_Demo.sln (он должен находиться в <пути к репозиторию>\Windows-Machine-Learning\Samples\MNIST\Tutorial\cs). Если решение отображается как недоступное, необходимо щелкнуть проект правой кнопкой мыши в обозревателе решений и выбрать "Перезагрузить проект".

Мы предоставили шаблон с реализованными элементами управления и событиями XAML, в том числе:

  • InkCanvas для рисования цифры.
  • Кнопки для интерпретации цифры и очистки холста.
  • Вспомогательные подпрограммы для преобразования выходных данных InkCanvas в видеофрейм.

В обозревателе решений проект содержит три основных файла кода:

  • MainPage.xaml — весь код XAML для создания пользовательского интерфейса для inkCanvas, кнопок и меток.
  • MainPage.xaml.cs — где живет код приложения.
  • Helper.cs — вспомогательные подпрограммы для обрезки и преобразования форматов изображений.

Обозреватель решений Visual Studio с файлами проекта

2. Сборка и запуск проекта

На панели инструментов Visual Studio измените платформу решения на x64 , чтобы запустить проект на локальном компьютере, если устройство имеет 64-разрядную версию или x86 , если это 32-разрядная версия. (Вы можете проверить приложение параметров Windows: Система > О > Характеристики устройства > Тип системы.)

Чтобы запустить проект, нажмите кнопку "Начать отладку " на панели инструментов или нажмите клавишу F5. Приложение должно отобразить inkCanvas , где пользователи могут писать цифру, кнопку Распознать , чтобы интерпретировать число, пустое поле метки, в котором интерпретируемая цифра будет отображаться как текст, и кнопка "Очистить цифру", чтобы очистить InkCanvas.

Снимок экрана приложения

Замечание

Если проект не будет построен, может потребоваться изменить целевую версию развертывания проекта. Щелкните проект правой кнопкой мыши в обозревателе решений и выберите "Свойства". На вкладке "Приложение" задайте целевую версию и минимальную версию , чтобы она соответствовала ОС и пакету SDK.

Замечание

Если вы получите предупреждение о том, что приложение уже установлено, просто нажмите кнопку "Да ", чтобы продолжить развертывание. Возможно, потребуется закрыть Visual Studio и повторно открыть его, если он по-прежнему не работает.

3. Скачивание модели

Затем давайте получим модель машинного обучения для добавления в наше приложение. В этом руководстве мы будем использовать предварительно обученную модель MNIST, которая была обучена с помощью Microsoft Cognitive Toolkit (CNTK) и экспортирована в формат ONNX.

Модель MNIST уже включена в папку Assets, и её нужно добавить в приложение как существующий элемент. Вы также можете скачать предварительно обученную модель из зоопарка моделей ONNX на GitHub.

4. Добавление модели

Щелкните правой кнопкой мыши папку "Ресурсы " в обозревателе решений и выберите "Добавить>существующий элемент". Направьте средство выбора файлов к месту расположения модели ONNX и нажмите Добавить.

Теперь проект должен иметь два новых файла:

  • mnist.onnx — ваша обученная модель.
  • mnist.cs — созданный в Windows ML код.

Обозреватель решений с новыми файлами

Чтобы убедиться, что модель выполняет сборку при компиляции приложения, щелкните правой кнопкой мыши файл mnist.onnx и выберите "Свойства". Для действия сборки выберите "Содержимое".

Теперь давайте рассмотрим только что созданный код в файле mnist.cs . У нас есть три класса:

  • mnistModel создает представление модели машинного обучения, создает сеанс на устройстве по умолчанию системы, привязывает определенные входные и выходные данные к модели и оценивает модель асинхронно.
  • mnistInput инициализирует типы входных данных, которые ожидает модель. В этом случае входные данные ожидают ImageFeatureValue.
  • mnistOutput инициализирует типы, которые будет выводить модель. В этом случае выходные данные будут списком, называемым Plus214_Output_0 типа TensorFloat.

Теперь мы будем использовать эти классы для загрузки, привязки и оценки модели в нашем проекте.

5. Загрузка, привязка и оценка модели

Для приложений Windows ML шаблон, который мы хотим выполнить, — load > Bind > Evaluate.

  1. Загрузите модель машинного обучения.
  2. Привязка входных и выходных данных к модели.
  3. Оцените модель и просмотрите результаты.

Мы будем использовать код интерфейса, созданный в mnist.cs для загрузки, привязки и оценки модели в нашем приложении.

Во-первых, в MainPage.xaml.cs создадим экземпляр модели, входные данные и выходные данные. Добавьте следующие переменные-члены в класс MainPage :

private mnistModel ModelGen;
private mnistInput ModelInput = new mnistInput();
private mnistOutput ModelOutput;

Затем в LoadModelAsync мы загрузим модель. Этот метод следует вызывать перед использованием любого из методов модели (т. е. в событии Loaded на MainPage, при переопределении OnNavigatedTo или где-либо до вызова recognizeButton_Click). Класс mnistModel представляет модель MNIST и создает сеанс на системном устройстве по умолчанию. Чтобы загрузить модель, мы вызываем метод CreateFromStreamAsync , передавая в качестве параметра файл ONNX.

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);
}

Замечание

Если вы увидите красные подчеркивания под IRandomAccessStreamReference, необходимо добавить его пространство имен. Поместите курсор над ним, нажмите Ctrl + . и выберите в раскрывающемся меню Windows.Storage.Streams.

Затем мы хотим привязать входные и выходные данные к модели. Созданный код также включает классы оболочки mnistInput и mnistOutput . Класс mnistInput представляет ожидаемые входные данные модели, а класс mnistOutput представляет ожидаемые выходные данные модели.

Чтобы инициализировать входной объект модели, вызовите конструктор класса mnistInput , передавая данные приложения, и убедитесь, что входные данные соответствуют типу входных данных, который ожидает модель. Класс mnistInput ожидает ImageFeatureValue, поэтому мы используем вспомогательный метод для получения ImageFeatureValue для входных данных.

Используя включенные вспомогательные функции в helper.cs, мы скопируйм содержимое InkCanvas, преобразуем его в тип ImageFeatureValue и привязываем его к нашей модели.

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);
}

Для выходных данных мы просто вызываем EvaluateAsync с указанными входными данными. После инициализации входных данных вызовите метод EvaluateAsync модели, чтобы оценить модель на входных данных. EvaluateAsync привязывает входные и выходные данные к объекту модели и оценивает модель на входных данных.

Так как модель возвращает выходной тензор, сначала нужно преобразовать его в понятный тип данных, а затем проанализировать возвращаемый список, чтобы определить, какая цифра имеет самую высокую вероятность и отобразить ее.

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();
}

Наконец, мы хотим очистить InkCanvas , чтобы разрешить пользователям нарисовать другое число.

private void clearButton_Click(object sender, RoutedEventArgs e)
{
    inkCanvas.InkPresenter.StrokeContainer.Clear();
    numberLabel.Text = "";
}

6. Запуск приложения

После сборки и запуска приложения (нажмите клавишу F5), мы сможем распознать число, нарисованное на inkCanvas.

полное приложение

Это так - вы сделали свое первое приложение Windows ML! Дополнительные примеры, демонстрирующие использование Windows ML, см. в репозитории Windows-Machine-Learning на сайте GitHub.

Замечание

Используйте следующие ресурсы, чтобы получить помощь по Windows ML.

  • Чтобы задать или ответить на технические вопросы о Windows ML, используйте тег windows-machine-learning в Stack Overflow.
  • Чтобы сообщить об ошибке, отправьте сообщение о проблеме на сайте GitHub.