ONNX Runtime Web WebNN EP 算子支持指南:覆盖清单、版本区间与底层实现解析
2026/9/13 17:08:30 网站建设 项目流程

ONNX Runtime Web WebNN EP 算子支持指南:覆盖清单、版本区间与底层实现解析

【免费下载链接】onnxruntimeONNX Runtime: cross-platform, high performance ML inferencing and training accelerator项目地址: https://gitcode.com/GitHub_Trending/on/onnxruntime

本指南基于 js/web/docs/webnn-operators.md 展开,系统梳理 ONNX Runtime Web 中WebNN EP(Execution Provider)对 ONNX 算子及 opset 版本的支持范围、每条支持项背后的 WebNN API 映射,以及各算子的实际约束条件。读完本文,你将掌握:如何按表判断一个 ONNX 模型能否在 WebNN EP 上运行、每条支持记录中"版本区间/WebNN API/注释"三列的确切含义,以及 WebNN EP 在 onnxruntime/core/providers/webnn 源码中如何完成从算子注册、能力检查到模型编译的完整流程。

一、WebNN EP 与支持表的使用前提

1.1 什么是 WebNN EP

WebNN EP 是 ONNX Runtime Web 通过 WebNN(Web Neural Network API,W3C 标准,见 webmachinelearning/webnn)将模型推理卸载到浏览器底层硬件加速器(CPU/GPU/NPU)的执行提供程序。它的 C++ 侧实现位于 onnxruntime/core/providers/webnn,而 JS 侧入口在 js/web/lib/wasm/jsep/backend-webnn.ts 与 js/web/lib/wasm/session-options.ts。

WebNN API 目前在 Windows、Linux、macOS、Android 与 ChromeOS 上的最新版 Chrome 和 Edge 中可用(需在浏览器实验特性中开启"Enables WebNN API"标志)。由于不同平台对 WebNN 各算子的实现进度不一,同一算子在不同平台上的支持状态可能有差异,具体实现细节应参考 WebNN status。这也意味着:下面的支持表描述的是 WebNN EP 代码层面允许的算子集合,最终能否在某个平台上成功运行,还取决于该平台浏览器对 WebNN 对应 API 的实现程度。

1.2 支持表三列的含义

支持表每行包含三列,含义如下:

含义
OperatorONNX 算子名,来自ai.onnx域或 Microsoft 扩展域com.microsoft
Opset该算子可用的 opset 版本区间;7-12, 13+表示当前支持 opset 7 到 12,以及 13 及以上版本
WebNN API实现该算子所调用的一个或多个 WebNN 底层原语(如absconv2dmatmul

关于 opset 需要特别说明:ONNX Runtime 官方只保证ai.onnx域中 opset 7 及以上版本标注的模型提供支持(原文档中的 Note)。因此低于 opset 7 的模型即使算子出现在表中,也不能视为受支持。

1.3 从源码看能力检查流程

WebNN EP 的算子支持检查并非运行时逐个硬编码,而是由执行提供程序的GetCapability流程驱动。在 webnn_execution_provider.cc 中可以看到完整链条:

  1. 构造MLGraphBuilderemscripten::val::global("MLGraphBuilder").new_(wnn_context_));
  2. 调用 helper.cc 中的GetSupportedNodes/IsNodeSupported,按节点类型在算子构建器注册表中查找;
  3. 对查到的节点调用IsOpSupported做细粒度检查(含opSupportLimits()返回的 rank 范围校验,见 helper.cc);
  4. 最终通过CreateSupportedPartitions把支持的节点划分成子图并生成 metadef(命名形如WEBNN_<hash>_<id>)。

其中,算子构建器注册表定义在 op_builder_factory.cc,一个 ONNX 算子由对应的*_op_builder.cc实现(如conv_op_builder.ccgemm_op_builder.ccgqa_op_builder.cc)。表中有不少算子(如DynamicQuantizeLinearEinsumLRNSimplifiedLayerNormalization)的 WebNN API 列包含多个原语,正是因为它们在 builders/impl 下被分解为若干基础 WebNN 操作的组合。

另外值得注意:在 JS 侧启用 WebNN EP 时,session-options.ts 会自动设置session.disable_quant_qdqsession.disable_qdq_constant_folding两项会话配置,以保证 DQ/Q 节点以独立算子形式保留给 WebNN EP 处理——这正是表中ConvIntegerDequantizeLinearQuantizeLinearMatMulIntegerMatMulNBits等量化算子能被识别的前提。

二、完整算子支持表(原文档全量继承)

下表为 WebNN EP 当前支持的 ONNX 算子全集(按算子名排序),含 opset 支持区间、映射的 WebNN API 与关键约束注释。

OperatorOpsetWebNN APIComments
Absai.onnx(7-12, 13+)abs
Addai.onnx(7-12, 13, 14+)add
Andai.onnx(7+)logicalAnd
ArgMaxai.onnx(7-10, 11, 12, 13+)argMax
ArgMinai.onnx(7-10, 11, 12, 13+)argMin
AveragePoolai.onnx(7-9, 10, 11, 12-18, 19+)averagePool2dOnly supports 4-D input, 2-D 'kernel_shape'
BatchNormalizationai.onnx(7-8, 9-13, 14, 15+)batchNormalizationOnly supports 'training_mode' value is 0, one output
Castai.onnx(7-8, 9-12, 13-18, 19-20, 21+)cast
Ceilai.onnx(7-12, 13+)ceil
Clipai.onnx(7-10, 11, 12, 13+)clamp
Concatai.onnx(7-10, 11-12, 13+)concat
Convai.onnx(7-10, 11+)conv2dOnly supports 3-D or 4-D input and 'W' (weight)
ConvIntegerai.onnx(10+)cast, conv2d, dequantizeLinearOnly supports 3-D or 4-D input and 'W' (weight)
ConvTransposeai.onnx(7-10, 11+)convTranspose2dOnly supports 3-D or 4-D input and 'W' (weight)
Cosai.onnx(7+)cos
CumSumai.onnx(11-13, 14+)cumulativeSum'axis' input should be a constant
Divai.onnx(7-12, 13, 14+)div
DepthToSpaceai.onnx(7-10, 11-12, 13+)reshape, transpose
DequantizeLinearai.onnx(10-12, 13-18, 19-20, 21-22, 23+)dequantizeLinear, reshape
Dropoutai.onnx(7-9, 10-11, 12, 13-21, 22+)identityOnly supports test mode
DynamicQuantizeLinearai.onnx(11+)cast, clamp, div, div, max, min, quantizeLinear, reduceMax, reduceMin, reshape, roundEven, sub
Einsumai.onnx(12+)reshape, transpose, matmul, reduceSum, mul, triangular
Eluai.onnx(7+)elu
Equalai.onnx(7-10, 11-12, 13-18, 19+)equal
Erfai.onnx(7-9, 10-12, 13+)erf
Expai.onnx(7-12, 13+)exp
Expandai.onnx(8-12, 13+)expand'shape' input should be a constant
Flattenai.onnx(7-8, 9-10, 11-12, 13-20, 21+)reshape
Floorai.onnx(7-12, 13+)floor
Gatherai.onnx(7-10, 11-12, 13+)gather
GatherBlockQuantizedcom.microsoft(1+)dequantizeLinear, gatheruint8-packed 4-bit data (bits=4) is reinterpreted as uint4, which requires 'quantize_axis' to be the last axis and 'data' (and 'zero_points', if present) to be constant initializers
GatherElementsai.onnx(11-12, 13+)gatherElements
GatherNDai.onnx(11, 12, 13+)gatherNDOnly supports 'batch_dims' == 0
Geluai.onnx(20+)gelu
Gemmai.onnx(7-8, 9-10, 11-12, 13+)gemm
GlobalAveragePoolai.onnx(7+)averagePool2dOnly supports 4-D input
GlobalMaxPoolai.onnx(7+)maxPool2dOnly supports 4-D input
GlobalLpPoolai.onnx(7+)l2Pool2dOnly supports 4-D input, 'p' value is 2
Greaterai.onnx(7-8, 9-12, 13+)greater
GreaterOrEqualai.onnx(12-15, 16+)greaterOrEqual
GroupQueryAttentioncom.microsoft(1+)add, cast, concat, constant, cumulativeSum, div, expand, lesser, matmul, reshape, scatterND, softmax, transpose, whereOnly supports input total_sequence_length is constant and past_sequence_length of past kv equals to present_sequence_length of present kv.
GRUai.onnx(7-13, 14-21, 22+)gruOnly supports 'layout' == 0. 'clip' is not supported. The activation functions in 'activations' must be one of 'Relu', 'Tanh', 'Sigmoid'. Forward and backward activations must be the same if bidirectional. 'sequence_lens' if present should be constant with values equal to the first dimension length of input 'X'
HardSigmoidai.onnx(7+)hardSigmoid
HardSwishai.onnx(14+)hardSwish
Identityai.onnx(7-13, 14-15, 16-18, 19-20, 21+)identity
InstanceNormalizationai.onnx(7+)instanceNormalization
IsNaNai.onnx(9-12, 13-19, 20+)isNaN
IsInfai.onnx(10-19, 20+)isInfinite, equal, greater
LayerNormalizationai.onnx(7-16, 17+)layerNormalization
LeakyReluai.onnx(7-15, 16+)leakyRelu
Lessai.onnx(7-12, 13+)lesser
LessOrEqualai.onnx(12-15, 16+)lesserOrEqual
Logai.onnx(7-12, 13+)log
LpNormalizationai.onnx(7-21, 22+)div, max, reduceL1, reduceL2
LpPoolai.onnx(7-10, 11-17, 18+)l2Pool2dOnly supports 4-D input, 2-D 'kernel_shape', 'p' value is 2
LRNai.onnx(7-12, 13+)pad, averagePool2d, transpose, add, mul, pow, div
LSTMai.onnx(7-13, 14-21, 22+)lstmOnly supports 'layout' == 0, 'input_forget' == 0. 'clip' is not supported. The activation functions in 'activations' must be one of 'Relu', 'Tanh', 'Sigmoid'. Forward and backward activations must be the same if bidirectional. 'sequence_lens' if present should be constant with values equal to the first dimension length of input 'X'
MatMulai.onnx(7-8, 9-12, 13+)matmul
MatMulIntegerai.onnx(10+)cast, dequantizeLinear, matmul
MatMulNBitscom.microsoft(1+)add, dequantizeLinear, matmul, reshape, transposeInputs 'B' and 'zero_points' (if present) should be constants, input 'g_idx' is not supported, only bits=4 and bits=8 are supported
Maxai.onnx(7, 8-11, 12, 13+)max
MaxPoolai.onnx(7, 8-9, 10, 11, 12+)maxPool2dOnly supports 4-D input, 2-D 'kernel_shape', 'storage_order' != 1, one output
Minai.onnx(7, 8-11, 12, 13+)min
Mulai.onnx(7-12, 13, 14+)mul
MultiHeadAttentioncom.microsoft(1+)add, cast, concat, constant, div, matmul, reshape, softmax, transposeDoes not support inputs bias, key_padding_mask, past_sequence_length, or cache_indirection. Does not support output qk
Negai.onnx(7-12, 13+)neg
Notai.onnx(7+)logicalNot
Orai.onnx(7+)logicalOr
Padai.onnx(7-10, 11-12, 13-17, 18, 19-20, 21+)padmodes == 'wrap' is not supported
Powai.onnx(7-11, 12, 13-14, 15+)pow
PReluai.onnx(7-8, 9-15, 16+)prelu
QuantizeLinearai.onnx(10-12, 13-18, 19-20, 21-22, 23+)quantizeLinear, reshape
Reciprocalai.onnx(7-12, 13+)reciprocal
Roundai.onnx(11-21, 22+)roundEven
ReduceL1ai.onnx(7-10, 11-12, 13-17, 18+)reduceL1Input 'axes' if present should be a constant
ReduceL2ai.onnx(7-10, 11-12, 13-17, 18+)reduceL2Input 'axes' if present should be a constant
ReduceLogSumai.onnx(7-10, 11-12, 13-17, 18+)reduceLogSumInput 'axes' if present should be a constant
ReduceLogSumExpai.onnx(7-10, 11-12, 13-17, 18+)reduceLogSumExpInput 'axes' if present should be a constant
ReduceMaxai.onnx(7-10, 11, 12, 13-17, 18-19, 20+)reduceMaxInput 'axes' if present should be a constant
ReduceMeanai.onnx(7-10, 11-12, 13-17, 18+)reduceMeanInput 'axes' if present should be a constant
ReduceMinai.onnx(7-10, 11, 12, 13-17, 18-19, 20+)reduceMinInput 'axes' if present should be a constant
ReduceProdai.onnx(7-10, 11-12, 13-17, 18+)reduceProductInput 'axes' if present should be a constant
ReduceSumai.onnx(7-10, 11-12, 13+)reduceSumInput 'axes' if present should be a constant
ReduceSumSquareai.onnx(7-10, 11-12, 13-17, 18+)reduceSumSquareInput 'axes' if present should be a constant
Reluai.onnx(7-12, 13, 14+)relu
Reshapeai.onnx(7-12, 13, 14-18, 19-20, 21+)reshapeInput 'shape' should be a constant, 0 dimension value in 'shape' is not supported
Resizeai.onnx(11-12, 13-17, 18, 19+)resample2dOnly supports 4-D input, antialias == 0, exclude_outside == 0, keep_aspect_ratio_policy == 'stretch', 'linear' and 'nearest' modes, input 'scales' and 'sizes' if present must be a constant
RotaryEmbeddingai.onnx(23+), com.microsoft(1+)add, concat, gather, mul, reshape, slice, split
ScatterElementsai.onnx(11-12, 13-15, 16-17, 18+)scatterElementsOnly supports 'reduction' == 'none'
ScatterNDai.onnx(11-12, 13-15, 16-17, 18+)scatterNDOnly supports 'reduction' == 'none'
Shapeai.onnx(7-12, 13-14, 15-18, 19-20, 21+)slice
SimplifiedLayerNormalizationai.onnx(1+)pow, reduceMean, add, sqrt, div, mul
Sigmoidai.onnx(7-12, 13+)sigmoid
Signai.onnx(9-12, 13+)sign
SkipLayerNormalizationcom.microsoft(1+)add, layerNormalization
SkipSimplifiedLayerNormalizationcom.microsoft(1+)pow, reduceMean, add, sqrt, div, mul
Softplusai.onnx(7+)softplus
Softsignai.onnx(7+)softsign
Sinai.onnx(7+)sin
Sliceai.onnx(7-9, 10, 11-12, 13+)slice, reverseInput 'starts', 'ends', 'axes', and 'steps' if present must be a constant
Softmaxai.onnx(7-10, 11-12, 13+)softmax
Splitai.onnx(7-10, 11-12, 13-17, 18+)splitInput 'split' if present should be a constant
Sqrtai.onnx(7-12, 13+)sqrt
Squeezeai.onnx(7-10, 11-12, 13-20, 21+)reshapeInput 'axes' if present should be a constant
Subai.onnx(7-12, 13, 14+)sub
Tanai.onnx(7+)tan
Tanhai.onnx(7-12, 13+)tanh
Tileai.onnx(7-12, 13+)tileInput 'repeats' should be a constant
Transposeai.onnx(7-12, 13-20, 21+)transpose
Triluai.onnx(14+)triangularInput 'k' (option 'diagonal' for WebNN) if present should be a constant
Unsqueezeai.onnx(7-10, 11-12, 13-20, 21+)reshape
Whereai.onnx(7-8, 9-15, 16+)where
Xorai.onnx(7+)logicalXor

三、约束条件的规律性解读

表中 Comments 列并非随意罗列,而是体现了 WebNN EP 在算子映射上的几条系统性规律:

1. 常量输入约束(Constant Input Requirement)多个算子要求某个输入必须是常量(constant initializer),原因在于 WebNN 构建图时需要把 shape、axes、split、starts/ends 等元数据在编译期确定下来。典型包括:

  • CumSumaxisExpandshapeSplitsplitTilerepeatsTriluk
  • 全部Reduce*系列算子的axes(如存在);
  • Reshapeshape(且 shape 中不允许出现 0 维)、Resizescales/sizesSlicestarts/ends/axes/stepsSqueezeaxes

这与 helper.cc 中的形状检查逻辑呼应——WebNN 不支持动态形状,动态维度需要用户通过sessionOptions.FreeDimensionOverrides预先固定。

2. 秩(Rank)与 kernel 维度限制

  • AveragePoolMaxPoolLpPool仅支持 4-D 输入和 2-Dkernel_shape,且MaxPool要求storage_order != 1、只输出一个张量;
  • Conv/ConvInteger/ConvTranspose仅支持 3-D 或 4-D 输入与权重;
  • GlobalAveragePool/GlobalMaxPool/GlobalLpPool仅支持 4-D 输入,GlobalLpPoolLpPoolp值必须为 2。

这是因为底层 WebNN API 提供的是 2D 变体(averagePool2dmaxPool2dconv2dconvTranspose2d),WebNN EP 会把 ONNX 的 N-D 语义收缩到 WebNN 的 2D 语义上,超出范围的秩无法映射。

3. 循环网络(RNN)相关约束GRULSTM的限制高度一致:layout必须为 0,不支持clip,激活函数只能是Relu/Tanh/Sigmoid,双向时必须前后向激活一致,sequence_lens若存在须为常量且等于输入X第一维长度。此外LSTM还要求input_forget == 0。这些约束在 gru_op_builder.cc 与 lstm_op_builder.cc 中有对应的属性校验实现。

4. 量化与注意力扩展算子

  • 量化系列:ConvIntegerMatMulInteger通过cast+dequantizeLinear+conv2d/matmul组合实现;DequantizeLinear/QuantizeLinear在量化轴(axis)不是最后一维时需配合reshapeMatMulNBits仅支持 bits=4 与 bits=8,权重Bzero_points必须为常量,且不支持g_idx输入;GatherBlockQuantized要求 uint8 打包的 4-bit 数据按 uint4 重新解释,因此quantize_axis必须是最后一维、datazero_points必须为常量初始化器。
  • 注意力系列:MultiHeadAttention不支持biaskey_padding_maskpast_sequence_lengthcache_indirection输入及qk输出;GroupQueryAttention要求输入total_sequence_length为常量,且 past kv 的past_sequence_length必须等于 present kv 的present_sequence_lengthRotaryEmbedding同时支持ai.onnx(23+)com.microsoft(1+)两个域。这些算子的构建器分别位于 mha_op_builder.cc、gqa_op_builder.cc 与 rotaryEmbedding_op_builder.cc。

5. 仅支持推理路径的算子Dropout仅支持测试模式(test mode),BatchNormalization仅支持training_mode == 0且只输出一个结果。这与 ONNX Runtime 推理引擎的定位一致,训练相关路径不会被 WebNN EP 接管。

四、算子映射的复合实现:从 ONNX 到 WebNN 原语

支持表的 WebNN API 列值得再展开一层:当某一格出现多个 API 时,说明该 ONNX 算子并非一对一映射,而是在 onnxruntime/core/providers/webnn/builders/impl 中由多个 WebNN 原语拼装而成。从源码结构看,可以归纳出以下模式:

  • 一对一直接映射Abs → absAdd → addRelu → reluMatMul → matmulConcat → concat等,是最常见的形态,构建器直接在 WebNN builder 上调用同名方法。
  • 同构替代Clip → clampRound → roundEvenReshape/Flatten/Squeeze/Unsqueeze → reshapeShape → sliceDropout(测试模式) → identity,ONNX 语义与 WebNN 原语语义一致或 WebNN 侧可用更基础的原语表达。
  • 分解组合LRN需要pad + averagePool2d + transpose + add + mul + pow + div七个原语;SimplifiedLayerNormalizationpow + reduceMean + add + sqrt + div + mul组成;DynamicQuantizeLinearcast/clamp/div/max/min/quantizeLinear/reduceMax/reduceMin/reshape/roundEven/sub展开。这类算子的实现可以在 lrn_op_builder.cc、normalization_op_builder.cc 与 dynamicQuantizeLinear_op_builder.cc 中逐行验证。

这一设计使 WebNN EP 能用有限的标准 WebNN 原语覆盖远超其原生算子集的 ONNX 算子面,代价是部分复合算子在精度、速度与内存占用上不如原生实现,这也是为何支持表中会为复合算子标注出若干"不支持"的属性组合。

五、在 ONNX Runtime Web 中启用 WebNN EP 的配置方式

支持表是"能不能跑"的判据,而"怎么让它跑"涉及执行提供程序的注册参数。在 webnn_provider_factory.cc 中,WebNNProviderFactoryCreator::Create从 ProviderOptions 中读取deviceType;在 helper.cc 中,DeviceTypeFromString支持"gpu""cpu""npu"三种取值,非法值会抛出Unknown WebNN deviceType.

在 JS 侧(如 js/web/lib/wasm/session-options.ts 所示),通过executionProviders传入webnn并可选指定deviceType

import * as ort from 'onnxruntime-web'; const session = await ort.InferenceSession.create('./model.onnx', { executionProviders: [{ name: 'webnn', deviceType: 'gpu', // 可选:'gpu' | 'cpu' | 'npu' }], });

要点:

  • 选择webnnEP 时,ORT 会自动追加session.disable_quant_qdq=1session.disable_qdq_constant_folding=1,以保留 DQ/Q 节点供 WebNN EP 处理(见 session-options.ts)。
  • deviceType会以会话配置的形式传递到 C++ 层,最终由WebNNExecutionProvider解析;在 webnn_execution_provider.cc 中,provider 还会调用 WebNN 的opSupportLimits()获取当前实现对各算子的支持上限,用于更精确的能力判定。
  • 如果模型含有动态维度,需要预先通过sessionOptions.freeDimensionOverrides固定形状,否则对应节点可能无法被 WebNN EP 接受(参考 helper.cc 中的日志提示)。

六、使用支持表的实操建议

  1. 先对照 opset,再对照算子:模型导出的 opset 版本决定了检查哪一行。例如 opset 13 的模型,Reshape使用ai.onnx(13, 14-18, 19-20, 21+)段;opset 12 及以下则需检查对应旧段。低于 7 的 opset 不在官方保证范围内。
  2. 逐条核对 Comments 列:即使算子名与 opset 命中,仍需检查属性与输入形态是否满足注释中的约束(如Conv的 3-D/4-D 输入、GatherNDbatch_dims == 0Pad不支持wrap模式、ScatterElements/ScatterND仅支持reduction == 'none')。
  3. 结合平台差异评估:表内支持不等于当前浏览器可运行。Chrome/Edge 各平台对 WebNN 的实现进度不同,最终以浏览器实际行为为准;排查失败时留意 WebNN 侧的opSupportLimits()返回值(WebNN EP 已在代码中用它做 rank 范围预检)。
  4. 关注com.microsoft扩展域GatherBlockQuantizedGroupQueryAttentionMatMulNBitsMultiHeadAttentionRotaryEmbeddingSkipLayerNormalizationSkipSimplifiedLayerNormalization来自 Microsoft 扩展域(com.microsoft(1+)),只有包含这些扩展算子的模型(多为 LLM/Transformer 结构)才会用到,普通 CNN 模型通常不涉及。

七、小结

WebNN EP 的算子支持表本质上回答了三个问题:哪些 ONNX 算子能被 WebNN 接管(Operator)、哪些 opset 版本区间可用(Opset)、底层用什么 WebNN API 实现(WebNN API)。配合 op_builder_factory.cc 的注册表、helper.cc 的能力检查逻辑,以及 builders/impl 下的逐算子实现,开发者可以在模型落地前准确预判兼容性,并在遇到节点下沉失败时快速定位是哪一类约束(常量输入、秩、属性、平台实现)导致的拒绝。需要继续深入算子级细节时,建议以 js/web/docs/webnn-operators.md 为总览,配合 WebNN status 与各*_op_builder.cc源文件交叉验证。

【免费下载链接】onnxruntimeONNX Runtime: cross-platform, high performance ML inferencing and training accelerator项目地址: https://gitcode.com/GitHub_Trending/on/onnxruntime

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询