使用 Windows Machine Learning 加载 ONNX 模型并推理
Windows 平台提供了强大的机器学习推理引擎,允许开发者在 Windows 应用程序中直接加载并使用训练好的机器学习模型。本文将详细介绍如何在 UWP (Universal Windows Platform) 项目中集成 Windows Machine Learning 功能,加载 ONNX 格式的模型文件,并进行图像分类推理。
环境要求
Windows 10 从版本 10.0.17763.0 开始正式提供这套推理引擎(Windows ML)。因此,开发环境需要满足以下要求:
- 操作系统:必须运行在 Windows 10 版本 1809 (Build 17763) 或更高版本的设备上。
- 开发工具:推荐使用 Visual Studio 2017 Update 3 或更高版本(Visual Studio 2019/2022 亦可),确保安装了通用 Windows 平台 (UWP) 工作负载。
- SDK:安装 Windows 10 SDK 17763 或更新版本,以便访问相关的 API 和头文件。
- 硬件加速:虽然 CPU 可以运行推理,但为了获得最佳性能,建议设备支持 GPU 加速(DirectML 后端)。
创建 UWP 项目
- 打开 Visual Studio,选择'创建新项目'。
- 在模板搜索框中输入'空白应用',选择'空白应用 (通用 Windows)'模板。
- 填写项目名称为
ClassifyBear,点击确定。
- 在弹出的配置对话框中,设置目标版本和最低版本均为 17763 (Windows 10 1809),以确保兼容性。
- 点击'创建'完成项目初始化。
添加模型文件到项目中
模型文件通常以 .onnx 格式存在。我们需要将其添加到项目的资源目录中。
- 在解决方案资源管理器中,右键点击项目根目录下的
Assets 文件夹。
- 选择'添加' -> '现有项',找到你的模型文件(例如
BearModel.onnx)并导入。
- 选中该模型文件,在属性窗口中修改以下设置:
- 生成操作:设置为
内容
- 复制到输出目录:设置为
如果较新则复制
这确保了模型文件在编译时会被复制到应用的运行时目录中。
自动生成模型封装代码
Windows ML 提供了一个命令行工具 mlgen.exe,可以根据 ONNX 模型自动生成 C# 封装类,简化输入输出的处理。
- 打开'VS 2017 的开发人员命令提示符'或对应的 VS Developer Command Prompt。
- 运行以下命令生成代码(注意路径不要包含中文或空格):
mlgen.exe -i d:\BearModel.onnx -o d:\BearModel.cs -l CS -n BearModel
-i:指定 ONNX 模型路径。
-o:指定生成的 C# 代码文件路径。
-l:指定代码语言,此处为 CS (C#)。
-n:指定生成的命名空间。
- 将生成的
BearModel.cs 文件添加到项目中。
- 如果自动生成功能失败,请检查模型文件是否合法,路径是否包含特殊字符,并根据错误信息排查。
生成的 BearModel.cs 文件包含了模型的元数据、输入输出定义以及推理入口方法,极大地降低了集成难度。
设计界面
我们需要一个简单的用户界面来上传图片并显示识别结果。打开 MainPage.xaml,替换 Grid 内容如下:
<Grid>
<StackPanel Margin="12">
<TextBlock Text="输入要识别的图片地址:" Margin="12"/>
<TextBox x:Name="tbImageUrl" Margin="12" PlaceholderText="请输入图片 URL"/>
<Button x:Name="tbRun" Content="识别" Tapped="TbRun_Tapped" Margin="12"/>
<TextBlock x:Name="tbBearType" Margin="12" TextWrapping="Wrap"/>
<Grid BorderBrush="Gray" BorderThickness="1" Margin="12" Width="454" Height="454">
<Image x:Name="imgBear" Stretch="Fill" ImageOpened="ImgBear_ImageOpened" ImageFailed="ImgBear_ImageFailed"/>
</Grid>
</StackPanel>
</Grid>
界面说明:
tbImageUrl:用于输入待识别图片的网络 URL。
tbRun:触发加载图片和推理的按钮。
tbBearType:显示模型推理结果的文本块。
imgBear:预览图片的控件。设置为正方形且 Stretch 属性为 Fill,确保图片拉伸填充,匹配模型期望的 227x227 输入尺寸。
添加按钮的事件响应
在 MainPage.xaml.cs 中实现按钮点击事件,负责从输入框读取 URL 并加载图片。
private void TbRun_Tapped(object sender, TappedRoutedEventArgs e)
{
tbBearType.Text = string.Empty;
Uri imageUri = null;
try
{
imageUri = new Uri(tbImageUrl.Text);
}
catch (Exception)
{
tbBearType.Text = "URL 不合法,请检查网络地址";
return;
}
tbBearType.Text = "正在加载图片...";
imgBear.Source = new BitmapImage(imageUri);
}
添加图片控件的事件响应
当图片加载完成或失败时,触发相应逻辑。图片加载完成后,我们调用推理函数。
private void ImgBear_ImageOpened(object sender, RoutedEventArgs e)
{
RecognizeBear();
}
private void ImgBear_ImageFailed(object sender, ExceptionRoutedEventArgs e)
{
tbBearType.Text = "图片加载失败,请检查网络连接或图片有效性";
}
处理模型的输入
Windows ML 模型对输入数据有特定格式要求。通过查看 BearModel.cs 中的 BearModelInput 类,我们可以得知输入需要一个 ImageFeatureValue 类型的数据。
系统会自动处理像素格式转换和缩放,目前支持的像素格式包括 Gray8、Rgb8 和 Bgr8。我们需要将 UI 上的图片控件渲染为位图,再转换为模型所需的格式。
private async Task<BearModelInput> GetInputData()
{
RenderTargetBitmap rtb = new RenderTargetBitmap();
await rtb.RenderAsync(imgBear);
var pixelBuffer = await rtb.GetPixelsAsync();
SoftwareBitmap softwareBitmap = SoftwareBitmap.CreateCopyFromBuffer(
pixelBuffer,
BitmapPixelFormat.Bgra8,
rtb.PixelWidth,
rtb.PixelHeight);
VideoFrame videoFrame = VideoFrame.CreateWithSoftwareBitmap(softwareBitmap);
ImageFeatureValue imageFeatureValue = ImageFeatureValue.CreateFromVideoFrame(videoFrame);
BearModelInput bearModelInput = new BearModelInput();
bearModelInput.data = imageFeatureValue;
return bearModelInput;
}
加载模型并推理
这是核心步骤。利用自动生成的 BearModelModel 类,我们可以方便地加载模型流并执行评估。
private async void RecognizeBear()
{
try
{
StorageFile modelFile = await StorageFile.GetFileFromApplicationUriAsync(
new Uri("ms-appx:///Assets/BearModel.onnx"));
BearModelModel model = await BearModelModel.CreateFromStreamAsync(modelFile);
BearModelInput bearModelInput = await GetInputData();
BearModelOutput output = await model.EvaluateAsync(bearModelInput);
if (output.classLabel != null)
{
var labels = output.classLabel.GetAsVectorView().ToList();
tbBearType.Text = $"识别结果:{labels.FirstOrDefault()}";
}
else
{
tbBearType.Text = "未获取到有效结果";
}
}
catch (Exception ex)
{
tbBearType.Text = $"推理出错:{ex.Message}";
}
}
测试与调试
- 编译并运行项目。
- 在输入框中填入一张公开可访问的图片 URL(确保是图片直链,而非网页链接)。
- 点击'识别'按钮。
- 观察图片加载情况及下方显示的识别结果。
常见问题排查:
- 模型加载失败:检查
Assets 文件夹下是否有 .onnx 文件,且'复制到输出目录'设置正确。
- 推理结果为空:检查输入图片尺寸是否符合模型要求(如 227x227),虽然系统会自动缩放,但极端比例可能导致精度下降。
- 权限问题:UWP 应用访问网络图片需要声明 Internet (Client) 能力,在
Package.appxmanifest 中确认。
性能优化建议
在实际生产环境中,除了保证功能可用,还需关注推理性能:
- 模型量化:使用 TensorRT 或其他优化工具对 ONNX 模型进行 INT8 量化,可显著提升推理速度并减少内存占用。
- 异步处理:始终使用
async/await 模式,避免阻塞 UI 线程,保持应用流畅度。
- 缓存机制:对于频繁使用的模型,可以考虑在应用启动时预加载,避免每次请求都重新加载权重。
- 资源释放:虽然 .NET GC 会处理大部分内存,但在长时间运行的应用中,注意及时释放不再使用的
StorageFile 或 VideoFrame 对象。
总结
本文详细演示了如何在 Windows UWP 应用中集成 Windows Machine Learning 框架。通过 mlgen.exe 工具自动生成代码,开发者可以快速将 ONNX 模型嵌入应用,无需深入底层 C++ API。结合 XAML 界面和 C# 异步编程,能够构建出响应迅速、体验良好的智能应用。随着 Windows ML 生态的完善,未来将支持更多模型格式和更复杂的推理场景,为 Windows 平台的 AI 应用开发提供了坚实基础。