在本教程中,我们将构建一个简单的通用 Windows 平台应用程序,该应用程序使用经过训练的机器学习模型来识别用户绘制的数字数字。 本教程主要介绍如何在 UWP 应用程序中加载和使用 Windows ML。
以下视频逐步讲解本教程基于的示例。
如果只想查看已完成教程的代码,可以在 WinML GitHub 存储库中找到它。 它还可在 C++/CX 中使用。
先决条件
- Windows 10(版本 1809 或更高版本)
- Windows 10 SDK (内部版本 17763 或更高版本)
- Visual Studio 2019 (或 Visual Studio 2017 版本 15.7.4 或更高版本)
- 适用于 Visual Studio 2019 或 2017 的 Windows 机器学习代码生成器扩展
- 一些基本的 UWP 和 C# 知识
1.在 Visual Studio 中打开项目
从 GitHub 下载项目后,启动 Visual Studio 并打开 MNIST_Demo.sln 文件(该文件应位于 <存储库>路径\Windows-Machine-Learning\Samples\MNIST\Tutorial\cs)。 如果解决方案显示为不可用,则需要右键单击 解决方案资源管理器 中的项目,然后选择 “重新加载项目”。
我们提供了一个模板,其中包含实现的 XAML 控件和事件,包括:
- 一个 InkCanvas,用于绘制数字。
- 按钮用于识别数字和清除画布。
- 用于将 InkCanvas 输出转换为 VideoFrame 的帮助程序例程。
在 解决方案资源管理器中,项目有三个主要代码文件:
- MainPage.xaml - 用于为 InkCanvas、按钮和标签创建 UI 的所有 XAML 代码。
- MainPage.xaml.cs - 应用程序代码所在的位置。
- Helper.cs - 帮助程序例程,用于裁剪和转换图像格式。
2.生成并运行项目
在 Visual Studio 工具栏中,将 解决方案平台 更改为 x64 ,以在本地计算机上运行项目(如果设备为 64 位)或 x86 (如果为 32 位)。 (可以在 Windows 设置中检查:系统 > 关于 > 设备规格 > 系统类型。)
若要运行项目,请单击工具栏上的 “开始调试 ”按钮,或按 F5。 应用程序应显示 InkCanvas,用户可以在其中写入数字、解释数字的“识别”按钮、将解释的数字显示为文本的空标签字段,以及清除 InkCanvas 的“清除数字”按钮。
注释
如果项目不能构建,您可能需要更改项目的部署目标版本。 右键单击 解决方案资源管理器 中的项目,然后选择 “属性”。 在 “应用程序 ”选项卡中,将 目标版本 和 最小版本 设置为与 OS 和 SDK 匹配。
注释
如果收到已安装应用程序的警告,只需选择 “是 ”以继续部署。 如果 Visual Studio 仍然不起作用,可能需要关闭 Visual Studio 并重新打开。
3. 下载模型
接下来,让我们获取一个机器学习模型来添加到应用程序。 在本教程中,我们将使用预先训练的 MNIST 模型,该模型使用 Microsoft认知工具包(CNTK) 训练 并导出到 ONNX 格式。
MNIST 模型已包含在 Assets 文件夹中,需要将其作为现有项添加到应用程序。 还可以从 GitHub 上的 ONNX 模型动物园 下载预先训练的模型。
4.添加模型
右键单击解决方案资源管理器中的“资产”文件夹,然后选择“添加>现有项”。 将文件选取器指向 ONNX 模型的位置,然后单击“ 添加”。
项目现在应有两个新文件:
- mnist.onnx - 已训练的模型。
- mnist.cs - Windows ML 生成的代码。
若要确保模型在编译应用程序时生成,请右键单击 mnist.onnx 文件,然后选择“ 属性”。 对于生成操作,请选择内容。
现在,让我们看看 mnist.cs 文件中新生成的代码。 我们有三个类:
- mnistModel 创建机器学习模型表示形式,在系统默认设备上创建会话,将特定输入和输出绑定到模型,并异步评估模型。
- mnistInput 初始化模型所需的输入类型。 在本例中,输入需要是 ImageFeatureValue。
- mnistOutput 初始化模型将输出的类型。 在这种情况下,输出将是一个名为 tensorFloat 类型的Plus214_Output_0的列表。
现在,我们将使用这些类来加载、绑定和评估项目中的模型。
5. 加载、绑定和评估模型
对于 Windows ML 应用程序,我们要遵循的模式是:加载 > 绑定 > 评估。
- 加载机器学习模型。
- 将输入和输出绑定到模型。
- 评估模型并查看结果。
我们将使用 mnist.cs 中生成的接口代码来加载、绑定和评估应用程序中的模型。
首先,在 MainPage.xaml.cs中,让我们实例化模型、输入和输出。 将以下成员变量添加到 MainPage 类:
private mnistModel ModelGen;
private mnistInput ModelInput = new mnistInput();
private mnistOutput ModelOutput;
然后,在 LoadModelAsync 中,我们将加载模型。 在使用模型的任何方法之前(即在 MainPage 的 Loaded 事件中或 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 的更多示例,请查看 GitHub 上的 Windows-Machine-Learning 存储库。
注释
使用以下资源获取有关 Windows ML 的帮助:
- 若要询问或回答有关 Windows ML 的技术问题,请使用 Stack Overflow 上的 windows-machine-learning 标记。
- 若要报告 bug,请在 GitHub 上提出问题。