diff --git a/js/web/docs/webnn-operators.md b/js/web/docs/webnn-operators.md index 7c2f10a034..f060109b31 100644 --- a/js/web/docs/webnn-operators.md +++ b/js/web/docs/webnn-operators.md @@ -6,7 +6,7 @@ operators and the supported opset domain/versions in **WebNN EP** by ONNX Runtim (**Note**: ONNX Runtime only *guarantees* support for models stamped with opset version 7 or above for opset domain 'ai.onnx'.) -[WebNN API](https://webmachinelearning.github.io/webnn) provides two device types `cpu` and `gpu` to leverage different on-device accelerators. WebNN API implementation in Chromium uses XNNPack backend for `cpu` device type and DirectML backend for `gpu` device type. [The op support status](https://webmachinelearning.github.io/webnn-status/) behind these two backends is inconsistent since XNNPack backend currently supports limited op scope. +[WebNN API](https://webmachinelearning.github.io/webnn) provides two device types `cpu` and `gpu` to leverage different on-device accelerators. WebNN API implementation in Chromium uses TFLite XNNPack delegate backend for `cpu` device type and DirectML backend for `gpu` device type. [The op support status](https://webmachinelearning.github.io/webnn-status/) behind these two backends is inconsistent. | Operator | Opset | WebNN API | WebNN CPU | WebNN GPU | Comments | @@ -22,33 +22,33 @@ operators and the supported opset domain/versions in **WebNN EP** by ONNX Runtim | Clip | ai.onnx(7-10, 11, 12, 13+) | clamp | ✓ | ✓ | WebNN CPU backend only supports 3 specific ranges: [0.0, infinity], [-1.0, 1.0], [0.0, 6.0] (Chromium issue: https://issues.chromium.org/issues/326156496) | | Concat | ai.onnx(7-10, 11-12, 13+) | concat | ✓ | ✓ | | | Conv | ai.onnx(7-10, 11+) | conv2d | ✓ | ✓ | Only supports 3-D or 4-D input and 'W' (weight). WebNN CPU requires the 'W' (weight) input to be a constant | -| ConvTranspose | ai.onnx(7-10, 11+) | convTranspose2d | ✓ | ✗ | Only supports 3-D or 4-D input and 'W' (weight). | -| Cos | ai.onnx(7+) | cos | ✗ | ✓ | | +| ConvTranspose | ai.onnx(7-10, 11+) | convTranspose2d | ✗ | ✓ | Only supports 3-D or 4-D input and 'W' (weight). | +| Cos | ai.onnx(7+) | cos | ✓ | ✓ | | | Div | ai.onnx(7-12, 13, 14+) | div | ✓ | ✓ | | | Elu | ai.onnx(7+) | elu | ✓ | ✓ | WebNN CPU backend only supports 'alpha' value is 1.0 | -| Equal | ai.onnx(7-10, 11-12, 13-18, 19+) | equal | ✗ | ✓ | | +| Equal | ai.onnx(7-10, 11-12, 13-18, 19+) | equal | ✓ | ✓ | | | Erf | ai.onnx(7-9, 10-12, 13+) | erf | ✗ | ✓ | | -| Exp | ai.onnx(7-12, 13+) | exp | ✗ | ✓ | | +| Exp | ai.onnx(7-12, 13+) | exp | ✓ | ✓ | | | Expand | ai.onnx(8-12, 13+) | expand | ✗ | ✓ | 'shape' input should be a constant | | Flatten | ai.onnx(7-8, 9-10, 11-12, 13-20, 21+) | reshape | ✓ | ✓ | | | Floor | ai.onnx(7-12, 13+) | floor | ✓ | ✓ | | -| Gather | ai.onnx(7-10, 11-12, 13+) | gather | ✗ | ✓ | | +| Gather | ai.onnx(7-10, 11-12, 13+) | gather | ✓ | ✓ | | | Gelu | ai.onnx(20+) | gelu | ✗ | ✓ | | | Gemm | ai.onnx(7-8, 9-10, 11-12, 13+) | gemm | ✓ | ✓ | Only supports 1-D 'C' input | | GlobalAveragePool | ai.onnx(7+) | averagePool2d | ✓ | ✓ | Only supports 4-D input | | GlobalMaxPool | ai.onnx(7+) | maxPool2d | ✓ | ✓ | Only supports 4-D input | | GlobalLpPool| ai.onnx(7+) | l2Pool2d | ✗ | ✓ | Only supports 4-D input, 'p' value is 2 | -| Greater | ai.onnx(7-8, 9-12, 13+) | greater | ✗ | ✓ | | -| GreaterOrEqual | ai.onnx(12-15, 16+) | greaterOrEqual | ✗ | ✓ | | -| HardSigmoid | ai.onnx(7+) | hardSigmoid | ✗ | ✓ | | +| Greater | ai.onnx(7-8, 9-12, 13+) | greater | ✓ | ✓ | | +| GreaterOrEqual | ai.onnx(12-15, 16+) | greaterOrEqual | ✓ | ✓ | | +| HardSigmoid | ai.onnx(7+) | hardSigmoid | ✓ | ✓ | | | HardSwish | ai.onnx(14+) | hardSwish | ✓ | ✓ | | -| Identity | ai.onnx(7-13, 14-15, 16-18, 19-20, 21+) | identity | ✗ | ✓ | | +| Identity | ai.onnx(7-13, 14-15, 16-18, 19-20, 21+) | identity | ✓ | ✓ | | | InstanceNormalization | ai.onnx(7+) | instanceNormalization | ✗ | ✓ | | | LayerNormalization | ai.onnx(7-16, 17+) | layerNormalization | ✗ | ✓ | | | LeakyRelu | ai.onnx(7-15, 16+) | leakyRelu | ✓ | ✓ | | -| Less | ai.onnx(7-8, 9-12, 13+) | lesser | ✗ | ✓ | | -| LessOrEqual | ai.onnx(12-15, 16+) | lesserOrEqual | ✗ | ✓ | | -| Log | ai.onnx(7-12, 13+) | log | ✗ | ✓ | | +| Less | ai.onnx(7-8, 9-12, 13+) | lesser | ✓ | ✓ | | +| LessOrEqual | ai.onnx(12-15, 16+) | lesserOrEqual | ✓ | ✓ | | +| Log | ai.onnx(7-12, 13+) | log | ✓ | ✓ | | | LpPool | ai.onnx(7-10, 11-17, 18+) | l2Pool2d | ✗ | ✓ | Only supports 4-D input, 2-D 'kernel_shape', 'p' value is 2 | | MatMul | ai.onnx(7-8, 9-12, 13+) | matmul | ✓ | ✓ | | | Max | ai.onnx(7, 8-11, 12, 13+) | max | ✓ | ✓ | | @@ -56,38 +56,38 @@ operators and the supported opset domain/versions in **WebNN EP** by ONNX Runtim | Min | ai.onnx(7, 8-11, 12, 13+) | min | ✓ | ✓ | | | Mul | ai.onnx(7-12, 13, 14+) | mul | ✓ | ✓ | | | Neg | ai.onnx(7-12, 13+) | neg | ✓ | ✓ | | -| Not | ai.onnx(7+) | logicalnot | ✗ | ✓ | | +| Not | ai.onnx(7+) | logicalnot | ✓ | ✓ | | | Pad | ai.onnx(7-10, 11-12, 13-17, 18, 19-20, 21+) | pad | ✓ | ✓ | modes == 'wrap' is not supported | -| Pow | ai.onnx(7-11, 12, 13-14, 15+) | pow | ✗ | ✓ | | +| Pow | ai.onnx(7-11, 12, 13-14, 15+) | pow | ✓ | ✓ | | | PRelu | ai.onnx(7-8, 9-15, 16+) | prelu | ✓ | ✓ | WebNN CPU restricts slope to be a static value | | Reciprocal | ai.onnx(7-12, 13+) | reciprocal | ✗ | ✓ | | | ReduceL1 | ai.onnx(7-10, 11-12, 13-17, 18+) | reduceL1 | ✗ | ✓ | Input 'axes' if present should be a constant | | ReduceL2 | ai.onnx(7-10, 11-12, 13-17, 18+) | reduceL2 | ✗ | ✓ | Input 'axes' if present should be a constant | | ReduceLogSum| ai.onnx(7-10, 11-12, 13-17, 18+) | reduceLogSum| ✗ | ✓ | Input 'axes' if present should be a constant | | ReduceLogSumExp | ai.onnx(7-10, 11-12, 13-17, 18+) | reduceLogSumExp | ✗ | ✓ | Input 'axes' if present should be a constant | -| ReduceMax | ai.onnx(7-10, 11, 12, 13-17, 18-19, 20+) | reduceMax | ✗ | ✓ | Input 'axes' if present should be a constant | +| ReduceMax | ai.onnx(7-10, 11, 12, 13-17, 18-19, 20+) | reduceMax | ✓ | ✓ | Input 'axes' if present should be a constant | | ReduceMean | ai.onnx(7-10, 11-12, 13-17, 18+) | reduceMean | ✓ | ✓ | Input 'axes' if present should be a constant | -| ReduceMin | ai.onnx(7-10, 11, 12, 13-17, 18-19, 20+) | reduceMin | ✗ | ✓ | Input 'axes' if present should be a constant | -| ReduceProd | ai.onnx(7-10, 11-12, 13-17, 18+) | reduceProduct | ✗ | ✓ | Input 'axes' if present should be a constant | -| ReduceSum | ai.onnx(7-10, 11-12, 13+) | reduceSum | ✗ | ✓ | Input 'axes' if present should be a constant | +| ReduceMin | ai.onnx(7-10, 11, 12, 13-17, 18-19, 20+) | reduceMin | ✓ | ✓ | Input 'axes' if present should be a constant | +| ReduceProd | ai.onnx(7-10, 11-12, 13-17, 18+) | reduceProduct | ✓ | ✓ | Input 'axes' if present should be a constant | +| ReduceSum | ai.onnx(7-10, 11-12, 13+) | reduceSum | ✓ | ✓ | Input 'axes' if present should be a constant | | ReduceSumSquare | ai.onnx(7-10, 11-12, 13-17, 18+) | reduceSumSquare | ✗ | ✓ | Input 'axes' if present should be a constant | | Relu | ai.onnx(7-12, 13, 14+) | relu | ✓ | ✓ | | | Reshape | ai.onnx(7-12, 13, 14-18, 19-20, 21+) | reshape | ✓ | ✓ | Input 'shape' should be a constant, 0 dimension value in 'shape' is not supported | | Resize | ai.onnx(11-12, 13-17, 18, 19+) | resample2d | ✓ | ✓ | Only supports 4-D input, exclude_outside != 0, input 'scales' and 'sizes' if present must be a constant, 'linear' and 'nearest' modes | | Shape | ai.onnx(7-12, 13-14, 15-18, 19-20, 21+) | slice | ✓ | ✓ | | | Sigmoid | ai.onnx(7-12, 13+) | sigmoid | ✓ | ✓ | | -| Softplus | ai.onnx(7+) | softplus | ✗ | ✓ | | +| Softplus | ai.onnx(7+) | softplus | ✓ | ✓ | | | Softsign | ai.onnx(7+) | softsign | ✗ | ✓ | | -| Sin | ai.onnx(7+) | sin | ✗ | ✓ | | +| Sin | ai.onnx(7+) | sin | ✓ | ✓ | | | Slice | ai.onnx(7-9, 10, 11-12, 13+) | slice | ✓ | ✓ | Input 'starts', 'ends', 'axes', and 'steps' if present must be a constant, only supports 'steps' value 1 | | Softmax | ai.onnx(7-10, 11-12, 13+) | softmax | ✓ | ✓ | | | Split | ai.onnx(7-10, 11-12, 13-17, 18+) | split | ✓ | ✓ | Input 'split' if present should be a constant | | Sqrt | ai.onnx(7-12, 13+) | sqrt | ✓ | ✓ | | | Squeeze | ai.onnx(7-10, 11-12, 13-20, 21+) | reshape | ✓ | ✓ | Input 'axes' if present should be a constant | | Sub | ai.onnx(7-12, 13, 14+) | sub | ✓ | ✓ | | -| Tan | ai.onnx(7+) | tan | ✗ | ✓ | | +| Tan | ai.onnx(7+) | tan | ✓ | ✓ | | | Tanh | ai.onnx(7-12, 13+) | tanh | ✓ | ✓ | | | Transpose | ai.onnx(7-12, 13-20, 21+) | transpose | ✓ | ✓ | | | Trilu | ai.onnx(14+) | triangular | ✗ | ✓ | Input 'k' (option 'diagonal' for WebNN) if present should be a constant | | Unsqueeze | ai.onnx(7-10, 11-12, 13-20, 21+) | reshape | ✓ | ✓ | | -| Where | ai.onnx(7-8, 9-15, 16+) | where | ✗ | ✓ | | +| Where | ai.onnx(7-8, 9-15, 16+) | where | ✓ | ✓ | | diff --git a/onnxruntime/core/providers/webnn/builders/helper.h b/onnxruntime/core/providers/webnn/builders/helper.h index 7c84a14ba7..daecfcf457 100644 --- a/onnxruntime/core/providers/webnn/builders/helper.h +++ b/onnxruntime/core/providers/webnn/builders/helper.h @@ -168,34 +168,34 @@ static const InlinedHashMap op_map = { {"Conv", {"conv2d", true}}, {"ConvInteger", {"conv2dInteger", false}}, {"ConvTranspose", {"convTranspose2d", false}}, - {"Cos", {"cos", false}}, + {"Cos", {"cos", true}}, {"Div", {"div", true}}, {"DequantizeLinear", {"dequantizeLinear", false}}, {"DynamicQuantizeLinear", {"dynamicQuantizeLinear", false}}, {"Elu", {"elu", true}}, - {"Equal", {"equal", false}}, + {"Equal", {"equal", true}}, {"Erf", {"erf", false}}, - {"Exp", {"exp", false}}, + {"Exp", {"exp", true}}, {"Expand", {"expand", false}}, {"Flatten", {"reshape", true}}, {"Floor", {"floor", true}}, - {"Gather", {"gather", false}}, + {"Gather", {"gather", true}}, {"Gelu", {"gelu", false}}, {"Gemm", {"gemm", true}}, {"GlobalAveragePool", {"averagePool2d", true}}, {"GlobalMaxPool", {"maxPool2d", true}}, {"GlobalLpPool", {"l2Pool2d", false}}, - {"Greater", {"greater", false}}, - {"GreaterOrEqual", {"greaterOrEqual", false}}, - {"HardSigmoid", {"hardSigmoid", false}}, + {"Greater", {"greater", true}}, + {"GreaterOrEqual", {"greaterOrEqual", true}}, + {"HardSigmoid", {"hardSigmoid", true}}, {"HardSwish", {"hardSwish", true}}, - {"Identity", {"identity", false}}, + {"Identity", {"identity", true}}, {"InstanceNormalization", {"instanceNormalization", false}}, {"LayerNormalization", {"layerNormalization", false}}, {"LeakyRelu", {"leakyRelu", true}}, - {"Less", {"lesser", false}}, - {"LessOrEqual", {"lesserOrEqual", false}}, - {"Log", {"log", false}}, + {"Less", {"lesser", true}}, + {"LessOrEqual", {"lesserOrEqual", true}}, + {"Log", {"log", true}}, {"LpPool", {"l2Pool2d", false}}, {"MatMul", {"matmul", true}}, {"MatMulInteger", {"matmulInteger", false}}, @@ -204,41 +204,41 @@ static const InlinedHashMap op_map = { {"Min", {"min", true}}, {"Mul", {"mul", true}}, {"Neg", {"neg", true}}, - {"Not", {"logicalNot", false}}, + {"Not", {"logicalNot", true}}, {"Pad", {"pad", true}}, - {"Pow", {"pow", false}}, + {"Pow", {"pow", true}}, {"PRelu", {"prelu", true}}, {"Reciprocal", {"reciprocal", false}}, {"ReduceL1", {"reduceL1", false}}, {"ReduceL2", {"reduceL2", false}}, {"ReduceLogSum", {"reduceLogSum", false}}, {"ReduceLogSumExp", {"reduceLogSumExp", false}}, - {"ReduceMax", {"reduceMax", false}}, + {"ReduceMax", {"reduceMax", true}}, {"ReduceMean", {"reduceMean", true}}, - {"ReduceMin", {"reduceMin", false}}, - {"ReduceProd", {"reduceProduct", false}}, - {"ReduceSum", {"reduceSum", false}}, + {"ReduceMin", {"reduceMin", true}}, + {"ReduceProd", {"reduceProduct", true}}, + {"ReduceSum", {"reduceSum", true}}, {"ReduceSumSquare", {"reduceSumSquare", false}}, {"Relu", {"relu", true}}, {"Reshape", {"reshape", true}}, {"Resize", {"resample2d", true}}, {"Shape", {"slice", true}}, {"Sigmoid", {"sigmoid", true}}, - {"Softplus", {"softplus", false}}, + {"Softplus", {"softplus", true}}, {"Softsign", {"softsign", false}}, - {"Sin", {"sin", false}}, + {"Sin", {"sin", true}}, {"Slice", {"slice", true}}, {"Softmax", {"softmax", true}}, {"Split", {"split", true}}, {"Sqrt", {"sqrt", true}}, {"Squeeze", {"reshape", true}}, {"Sub", {"sub", true}}, - {"Tan", {"tan", false}}, + {"Tan", {"tan", true}}, {"Tanh", {"tanh", true}}, {"Transpose", {"transpose", true}}, {"Trilu", {"triangular", false}}, {"Unsqueeze", {"reshape", true}}, - {"Where", {"where", false}}, + {"Where", {"where", true}}, }; inline bool CheckSingleOp(const std::string& op_type, const emscripten::val& wnn_builder_, @@ -251,10 +251,10 @@ inline bool CheckSingleOp(const std::string& op_type, const emscripten::val& wnn if (!wnn_builder_[op_map.find(op_type)->second.opName].as()) { return false; } - // The current WebNN CPU (XNNPack) backend supports a limited op list, and we'd rather + // The current WebNN CPU (TFLite) backend supports a limited op list, and we'd rather // fall back early to the ORT CPU EP rather than fail in the WebNN "cpu" deviceType. // This is a workaround because the op may be included in MLGraphBuilder for DirectML - // backend but without XNNPack implementation in Chromium. + // backend but without TFLite implementation in Chromium. if (!op_map.find(op_type)->second.isCpuSupported && device_type == WebnnDeviceType::CPU) { return false; }