Wasmtime 中基于 wasi-nn 与 WinML 的图像分类示例:fixture 模型、图像与标签文件的准备与使用
【免费下载链接】wasmtimeA lightweight WebAssembly runtime that is fast, secure, and standards-compliant项目地址: https://gitcode.com/gh_mirrors/wa/wasmtime
导读
本文围绕 Wasmtime 仓库中crates/wasi-nn/examples/classification-example-winml示例的 fixture 资源目录(fixture/README.md)展开,说明该目录下三份核心素材——ONNX 分类模型、ImageNet 标签文件与测试图像——的来源、许可证及其在完整推理链路中的具体作用。读者将掌握:如何理解并复用这套 fixture 素材、如何在 Windows 上以 WinML 为后端把 wasi-nn 示例从编译一路跑到输出 Top-5 分类结果,以及如何替换为自己的模型与图片。
一、fixture 目录是什么:一份推理示例的“素材清单”
crates/wasi-nn/examples/classification-example-winml/fixture/是 WinML 分类示例的输入资源目录,目录内除 README.md 外,还包含三个被示例代码直接引用的文件:
| 文件 | 作用 | 来源 | 许可证 |
|---|---|---|---|
mobilenet.onnx | 用于推理的 MobileNetV2-7 图像分类 ONNX 模型 | 下载自 ONNX 官方模型库(onnx/models 仓库的validated/vision/classification/mobilenet路径) | onnx/models 仓库 LICENSE |
synset.txt | ImageNet 分类标签文件(共 1000 行,格式为类别ID 标签文本) | 同样下载自 onnx/models 仓库的validated/vision/classification路径 | onnx/models 仓库 LICENSE |
kitten.png | 224×224 的测试输入图像 | 下载自 onnxruntime 官方仓库 WinML 测试图片目录 | onnxruntime 仓库 LICENSE |
fixture 的 README 本质上是一份素材溯源清单:它明确记录了每个文件的下载来源与许可证归属,保证示例可复现、可合规分发。在替换素材时,这份清单也提醒使用者关注第三方模型与数据的授权边界。
说明:以上来源信息以 fixture/README.md 中的记载为准,本文不再重复给出外部链接;如需二次分发或商用,请自行核对 onnx/models 与 onnxruntime 仓库的许可证原文。
二、三份素材在推理流程中的分工(结合 main.rs)
示例程序 src/main.rs 的完整链路依次使用这三份素材:
- 模型加载:
wasi_nn::GraphBuilder::new(wasi_nn::GraphEncoding::Onnx, wasi_nn::ExecutionTarget::CPU)创建图构建器,通过build_from_files(["fixture/mobilenet.onnx"])从文件构建计算图,再init_execution_context()得到执行上下文。 - 图像读取与预处理:
fs::read("fixture/kitten.png")读入原始图像字节,随后交给preprocess函数(见下方说明),输出符合模型输入要求的张量。 - 输入张量设置:
context.set_input(0, wasi_nn::TensorType::F32, &[1, 3, 224, 224], &tensor_data)指定输入索引 0、数据类型 F32、形状 NCHW 为[1, 3, 224, 224](1 张图、RGB 三通道、224×224 分辨率)。 - 推理执行:
context.compute()触发 WinML 后端评估,代码会打印耗时毫秒数。 - 输出读取:
get_output(0, &mut output_buffer[..])读取形状为[1, 1000, 1, 1]的原始 logits(对应 ImageNet 1000 类)。 - 标签解析:读取
fixture/synset.txt,按行拆分并取第二列及之后的文本作为可读标签(例如n01440764 tench, Tinca tinca解析为tench, Tinca tinca),最终通过sort_results按概率降序输出 Top-5 结果。
图像预处理的关键参数(来自模型规范)
preprocess函数实现了 MobileNet 官方要求的预处理流程:
let tensor_data = preprocess( image_data.as_slice(), 224, 224, &[0.485, 0.456, 0.406], // mean,ImageNet 标准均值 &[0.229, 0.224, 0.225], // std,ImageNet 标准标准差 );具体步骤为:image::load_from_memory解码图像 →resize_exact(224, 224, Triangle)双线性(三角滤波)缩放 →to_rgb8()转 RGB → 逐像素执行(pixel / 255.0 - mean[channel]) / std[channel]归一化 → 按to_ne_bytes()拆成字节写入以[1, 3, 224, 224]布局的Vec<u8>。注意:图像尺寸、均值/标准差必须与模型训练时一致,否则分类精度会显著下降。
后处理:softmax 与 Top-5 排序
postprocess先对[1, 1000, 1, 1]的原始输出做 softmax(指数化后按类别轴归一),sort_results再把概率与synset.txt标签一一对应并按概率降序排序,最后打印前 5 项:
println!("Found results, sorted top 5: {:?}", &sort_results(&result, &labels)[..5]);三、端到端运行:从构建 Wasmtime 到输出分类结果
fixture 素材只有在完整示例中才有意义。按照示例目录 README.md 的说明,在Windows 10 v1803 及以上环境按以下步骤运行:
以
winml特性构建 Wasmtime(在 Wasmtime 仓库顶层目录执行):cargo build --release --features wasmtime-wasi-nn/winmlwinml特性在 crates/wasi-nn/Cargo.toml 中定义(winml = ["dep:windows"]),且属于默认特性组合default = ["openvino", "winml"]的一部分;它引入了windowscrate,使 wasi-nn 可以调用 Windows 的 WinML 机器学习 API。切换到示例目录(Wasmtime 顶层记为
%PROJECT_DIR%):set PROJECT_DIR=%CD% cd crates\wasi-nn\examples\classification-example-winml安装
wasm32-wasip1Rust 目标(示例编译为 WebAssembly,无法用宿主目标编译):rustup target add wasm32-wasip1编译示例,产物是
.wasm文件:cargo build --release --target=wasm32-wasip1该 crate 依赖(见 Cargo.toml)为
wasi-nn = "0.6.0"、image(启用png特性)与ndarray;Cargo.toml 中通过独立的[workspace]声明将其排除在 Wasmtime 主工作区之外,避免与宿主构建互相干扰。运行示例,关键是把
fixture目录映射进 WebAssembly 可见的文件空间:%PROJECT_DIR%\target\release\wasmtime.exe --dir fixture::fixture -S nn target\wasm32-wasip1\release\wasi-nn-example-winml.wasm--dir fixture::fixture:将宿主侧的fixture目录以同名路径暴露给 guest,使build_from_files(["fixture/mobilenet.onnx"])和fs::read("fixture/kitten.png")等路径可解析;-S nn:开启 wasi-nn 相关的能力开关,允许 guest 调用神经网络推理接口。
观察输出:程序依次打印“Created an execution context.”、输入张量字节数、推理耗时,最后给出按概率排序的 Top-5 分类结果。
替换模型或图像时的注意事项
示例 README 明确指出:如需换用其他图片或 ONNX 模型,只需修改fixture目录中的文件,并同步调整 src/main.rs 中可能受影响的路径。替换时还需留意:
- 新模型若输入不是 224×224,需同步修改
preprocess的目标尺寸与set_input的形状; - 新模型的类别数若不为 1000,需同步调整输出缓冲区大小与
synset.txt(或等价标签文件)的行数; - 归一化均值/标准差以模型文档为准,MobileNet 使用 ImageNet 的
[0.485, 0.456, 0.406]/[0.229, 0.224, 0.225]。
四、fixture 素材背后的 WinML 后端实现
示例之所以能在 Windows 上直接运行 ONNX 模型,靠的是 wasi-nn 的 WinML 后端 crates/wasi-nn/src/backend/winml.rs。从源码结构看,整个调用链可以概括为:
WinMLBackend::load:要求恰好一个模型构建器(builders.len() != 1时报InvalidNumberOfBuilders),将 ONNX 字节写入InMemoryRandomAccessStream,通过LearningModel::LoadFromStream加载模型;ExecutionTarget::Cpu映射为LearningModelDeviceKind::Cpu,ExecutionTarget::Gpu映射为DirectX,而Tpu目前是unimplemented!()。init_execution_context:用LearningModelDevice::Create创建设备、LearningModelSession::CreateFromModelOnDevice建立会话,封装为执行上下文。set_input/compute/get_output:按索引或名称在模型的InputFeatures/OutputFeatures中定位张量,经to_inspectable(wasi-nn 张量 → WinMLIInspectable)与to_tensor(反向转换)完成数据搬运,最后调用session.Evaluate执行推理。- 张量类型支持:
to_inspectable支持 Fp32(TensorFloat)、I64(TensorInt64Bit)以及以 f32 数组包装的 Fp16(TensorFloat16Bit),并做对齐校验;to_tensor反向支持 Float16、Float、Int64 三种TensorKind。该文件内还包含 fp16 / fp32 / i64 三组单元测试,用于验证 wasi-nn 与 WinML 之间的往返转换(winml.rs)。
换言之,guest 侧wasi-nn的 API 调用在宿主侧被翻译为 WinML 的LearningModel/LearningModelSession/LearningModelBinding操作,而mobilenet.onnx正是被LearningModel::LoadFromStream加载的那个字节流。
五、fixture 与 CI 测试
示例目录的父级 examples/README.md 提到:CI 通过ci/run-wasi-nn-example.sh测试分类示例。这说明fixture中的三份素材不仅是本地演示输入,也承担了自动化回归验证的职责——模型加载、预处理、推理与 Top-5 排序整条链路都会被持续检验,从而保证 wasi-nn API 与各后端实现(含 WinML)的行为稳定。
小结
crates/wasi-nn/examples/classification-example-winml/fixture/目录虽小,却承载了 WinML 分类示例的全部输入:ONNX 模型决定“能算什么”,synset 标签决定“结果叫什么”,测试图像决定“算的是什么”。理解这份素材清单的来源、许可证与格式约束,再结合示例 README 的构建运行步骤与 winml.rs 的后端实现,即可在 Windows 上完整复现 wasi-nn + WinML 的图像分类流程,并自如地将模型、图片替换为自有资产。
【免费下载链接】wasmtimeA lightweight WebAssembly runtime that is fast, secure, and standards-compliant项目地址: https://gitcode.com/gh_mirrors/wa/wasmtime
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考