Skip to Content
💡WebNN Origin Trial 即将到来!开发者很快将可以注册试用密钥进行体验 →
学习TutorialsVanilla JavaScriptWebNNUtils ONNX Converter

WebNNUtils/OnnxConverter

WebNNUtils/OnnxConverter  是一个 WebNN 编译器,可将 .onnx 模型编译为纯 JavaScript(JS)模型,使用 WebNN API 在网页浏览器中进行机器学习推理,且没有框架开销。

概述

虽然 JS 机器学习框架可以在浏览器中评估模型,但它们需要分发框架本身,并在加载时进行昂贵的预处理,从而影响延迟。在预处理期间,框架会确定算子的输入形状,在 CPU 与加速执行之间划分算子,并优化模型图。

使用 OnnxConverter 则没有这样的开销。在编译时,OnnxConverter 接收固定形状的 .onnx 文件,并生成用于构建等效 WebNN 图的 JS 代码。生成的 JS 代码可以直接在浏览器中使用,无需任何额外的框架依赖项。

隐私和安全

🔒 仅客户端处理

所有模型转换和 JavaScript 生成操作都只在你的本地环境中运行。任何模型数据、权重或知识产权都不会传输到任何外部服务器,也不会存储在外部服务器上。这使得该工具适用于:

  • 专有模型
  • 敏感的知识产权
  • 具有严格数据治理要求的企业环境
  • 任何需要完全数据隐私的场景

生成的输出

OnnxConverter 会生成多个文件:

  • 一个 JavaScript 文件(.js),包含 WebNN 图构建函数
  • 一个或多个二进制文件(.bin),包含模型权重
  • 可选的 JSON 元数据文件,用于调试

核心输出是一个具有以下签名的 JavaScript 函数:

function loadModelGraph(operand_input, weights_buffers, builder) { // 生成的 WebNN 图构建代码 return output_operand; // or {output1: operand1, output2: operand2} }

其中:

  • operand_input - 模型的输入操作数
  • weights_buffers - 包含模型权重的 ArrayBuffer 数组
  • builder - MLGraphBuilder WebNN 对象

安装

安装所需的 Python 依赖项:

pip install -U onnx protobuf numpy

命令行接口

语法

python OnnxConverter.py MODEL_FILE [OPTIONS]

必需参数

ArgumentDescription
model_file输入 ONNX 模型文件的路径(.onnx)

可选参数

ArgumentDescription
--weights_file输出权重文件的路径(默认值:weights.bin)
--output_file输出 JavaScript 文件的路径(默认值:model.js)
--max_weights_size单个权重文件的最大大小,单位为 MB(默认值:1024)

基本使用方法

步骤 1:转换模型

python OnnxConverter.py mobilenetv2-12.onnx --output_file mobilenet/mobilenet.js --weights_file mobilenet/weights.bin

此命令会生成:

  • mobilenet/mobilenet.js - WebNN 图构建函数
  • mobilenet/weights0.bin - 模型权重(可能会拆分为多个文件)

步骤 2:后处理(必需)

生成的 JavaScript 需要经过后处理,以处理代码顺序和 CPU/GPU 划分:

# 重新排序操作,以确保正确解析依赖关系 python ReorderModel.py mobilenet/mobilenet.js # 在 CPU 与 GPU 执行之间划分操作 python CPUGraphPartitioner.py mobilenet/mobilenet.js

步骤 3:在浏览器中加载权重

加载权重文件并将其传递给你的 WebNN 模型:

const weights_file = 'weights0.bin'; let cache = await caches.open("weights"); let weights_response = await cache.match(weights_file); if (!weights_response) { await cache.add(weights_file); weights_response = await cache.match(weights_file); } const weights_buffer = await weights_response.arrayBuffer(); // 创建 WebNN 上下文和构建器 const context = await navigator.ml.createContext({ powerPreference: 'high-performance' }); const builder = new MLGraphBuilder(context); // 安装 CPU 操作 polyfill InstallCpuOps(builder); // 加载模型图 const model_output = loadModelGraph(input_operand, [weights_buffer], builder);

deviceType 选项已从 WebNN 规范的 MLContextOptions 中移除,因此当前的浏览器会忽略它。请改用 powerPreference 和 accelerated 提示,参见 Migrating from deviceType。

架构和处理流水线

形状推断处理

OnnxConverter 不执行传统的形状推断。相反,它会生成在运行时处理动态形状的 WebNN 图节点。WebNN 图构建器通过 polyfill 方法进行了扩展,这些方法可以处理 JavaScript 数字(而不仅仅是张量)。

例如,包含形状操作的 ONNX 图:

// 伪代码 a = tensor.shape(); b = a * 2;

会生成调用 shape() 和 mul() 操作的 WebNN 节点,其中 mul 通过 polyfill 实现,以处理 shape() 返回的 JavaScript 数字。

CPU 操作 polyfill

在调用 loadModelGraph 之前,请安装 CPU 操作 polyfill:

const context = await navigator.ml.createContext({ powerPreference: 'high-performance' }); const builder = new MLGraphBuilder(context); InstallCpuOps(builder);

该 polyfill(定义于 CpuOps.js)为 MLGraphBuilder 扩展了可处理 JavaScript 数字的算子,从而支持形状操作和常量折叠等操作。

处理流水线

完整的转换过程包括三个阶段:

  1. OnnxConverter.py - 主编译器,生成 JS 图构建代码
  2. ReorderModel.py - 修复代码生成中输入操作数在被需要之后才计算的问题
  3. CPUGraphPartitioner.py - 为需要在 CPU 上执行的操作添加 cpu_ 前缀标注

多文件权重支持

对于大型模型,权重可以自动拆分为多个文件:

python OnnxConverter.py large_model.onnx --max_weights_size 512

这会创建多个权重文件(weights0.bin、weights1.bin 等),它们必须全部加载:

const weight_files = ['weights0.bin', 'weights1.bin']; const weights_buffers = []; for (const file of weight_files) { const response = await fetch(file); weights_buffers.push(await response.arrayBuffer()); } const model_output = loadModelGraph(input_operand, weights_buffers, builder);

支持的 ONNX 操作

OnnxConverter 支持一整套 ONNX 操作,包括:

核心操作

  • 卷积:Conv(支持 groups、padding、strides、dilations)
  • 激活:Relu、Sigmoid、Softmax、LeakyRelu
  • 池化:GlobalAveragePool
  • 算术:Add、Sub、Mul、Div、Pow、Sqrt

张量操作

  • 形状操作:Reshape、Transpose、Unsqueeze、Squeeze
  • 数据移动:Concat、Gather、Slice、Expand
  • 比较:Equal、Less、Where

高级操作

  • 量化:DequantizeLinear、DynamicQuantizeLinear、MatMulInteger
  • 矩阵操作:MatMul
  • 专用操作:DepthToSpace、ConstantOfShape、ReduceMean

软件实现的操作

有些操作是用 JavaScript 实现的,而不是原生 WebNN:

  • Slice:仅对常量切片提供有限的实现
  • Squeeze:动态轴压缩
  • Range:序列生成

调试和分析

代码生成问题

如果生成的代码存在依赖问题,请使用处理流水线:

python OnnxConverter.py model.onnx --output_file model.js python ReorderModel.py model.js python CPUGraphPartitioner.py model.js

理解生成的代码

生成的 JavaScript 包含:

  • 模型权重的常量定义
  • 构建计算图的 WebNN 操作调用
  • 模型的输入/输出处理

最佳实践

  1. 始终进行后处理:对生成的代码运行 ReorderModel.py 和 CPUGraphPartitioner.py
  2. 安装 Polyfill:在加载模型之前使用 InstallCpuOps()
  3. 处理多个权重文件:为大型模型中拆分的权重文件做好处理
  4. 缓存权重:对权重文件使用浏览器缓存,以提升加载性能
  5. 本地测试:通过 HTTP 服务器提供文件,以获得正确的加载行为

限制

  • 不支持动态形状推断(形状在运行时解析)
  • 复杂模型需要后处理流水线
  • 对部分 ONNX 操作的支持有限
  • 某些操作类型需要 CPU 回退

相关 API

Last updated on