[WebNN EP] Enable several ops for WebNN CPU backend (#20847)

WebNN CPU implementation has been migrated from XNNPack to TFLite which
supports more ops. Turn on partial `cpu` supported ops which just need
the change from `false` to `true` firstly.
This commit is contained in:
Wanming Lin 2024-06-19 16:45:31 +08:00 committed by GitHub
parent 5fc60f36f2
commit 35c430a95a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 46 additions and 46 deletions

View file

@ -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 | | ✓ | |

View file

@ -168,34 +168,34 @@ static const InlinedHashMap<std::string, WebnnOpInfo> 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<std::string, WebnnOpInfo> 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<bool>()) {
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;
}