From ed4ab5a5180fd1184254bccb9d98d783e0f2e371 Mon Sep 17 00:00:00 2001 From: Patrick To Date: Tue, 8 Oct 2024 23:46:13 -0700 Subject: [PATCH] WebNN: Add IDL and mojo definitions for `logical[And|Or|Xor]` operators The `logicalAnd`, `logicalOr`, and `logicalXor` operators are proposed by the WebNN WG [1]. These operators are required to support models that are commonly used. [1]: https://github.com/webmachinelearning/webnn/issues/375#issuecomment-2292466613 Bug: 368085623 Change-Id: I765e4f6787d01907c09e9c067426174a8f0cd240 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5883679 Reviewed-by: Weizhong Xia Reviewed-by: ningxin hu Commit-Queue: Patrick To Reviewed-by: Alex Gough Cr-Commit-Position: refs/heads/main@{#1365998} --- .../logical_and.https.any.js | 422 ++++++++++++++++++ .../conformance_tests/logical_or.https.any.js | 422 ++++++++++++++++++ .../logical_xor.https.any.js | 422 ++++++++++++++++++ .../elementwise-logical.https.any.js | 3 + 4 files changed, 1269 insertions(+) create mode 100644 webnn/conformance_tests/logical_and.https.any.js create mode 100644 webnn/conformance_tests/logical_or.https.any.js create mode 100644 webnn/conformance_tests/logical_xor.https.any.js diff --git a/webnn/conformance_tests/logical_and.https.any.js b/webnn/conformance_tests/logical_and.https.any.js new file mode 100644 index 00000000000000..be379de157c5d0 --- /dev/null +++ b/webnn/conformance_tests/logical_and.https.any.js @@ -0,0 +1,422 @@ +// META: title=test WebNN API element-wise logicalAnd operation +// META: global=window,dedicatedworker +// META: variant=?cpu +// META: variant=?gpu +// META: variant=?npu +// META: script=../resources/utils.js +// META: timeout=long + +'use strict'; + +// MLOperand logicalAnd(MLOperand a, MLOperand b, optional MLOperatorOptions options = {}); + +const logicalAndTests = [ + { + 'name': 'logicalAnd uint8 0D scalar', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [1], + 'descriptor': {shape: [], dataType: 'uint8'} + }, + 'inputB': { + 'data': [1], + 'descriptor': {shape: [], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalAnd', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': {'data': [1], 'descriptor': {shape: [], dataType: 'uint8'}} + } + } + }, + { + 'name': 'logicalAnd uint8 1D constant tensors', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [24], dataType: 'uint8'}, + 'constant': true + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [24], dataType: 'uint8'}, + 'constant': true + } + }, + 'operators': [{ + 'name': 'logicalAnd', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, + 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 + ], + 'descriptor': {shape: [24], dataType: 'uint8'} + } + } + } + }, + { + 'name': 'logicalAnd uint8 1D tensors', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [24], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [24], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalAnd', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, + 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 + ], + 'descriptor': {shape: [24], dataType: 'uint8'} + } + } + } + }, + { + 'name': 'logicalAnd uint8 2D tensors', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [4, 6], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [4, 6], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalAnd', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, + 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 + ], + 'descriptor': {shape: [4, 6], dataType: 'uint8'} + } + } + } + }, + { + 'name': 'logicalAnd uint8 3D tensors', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [2, 3, 4], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [2, 3, 4], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalAnd', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, + 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 + ], + 'descriptor': {shape: [2, 3, 4], dataType: 'uint8'} + } + } + } + }, + { + 'name': 'logicalAnd uint8 4D tensors', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalAnd', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, + 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + } + } + }, + { + 'name': 'logicalAnd uint8 5D tensors', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [2, 2, 1, 2, 3], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [2, 2, 1, 2, 3], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalAnd', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, + 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 + ], + 'descriptor': {shape: [2, 2, 1, 2, 3], dataType: 'uint8'} + } + } + } + }, + { + 'name': 'logicalAnd uint8 broadcast 0D to 4D', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [1], + 'descriptor': {shape: [], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalAnd', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + } + } + }, + { + 'name': 'logicalAnd uint8 broadcast 1D to 4D', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [1], + 'descriptor': {shape: [1], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalAnd', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + } + } + }, + { + 'name': 'logicalAnd uint8 broadcast 2D to 4D', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 255, 255 + ], + 'descriptor': {shape: [2, 3], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalAnd', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + } + } + }, + { + 'name': 'logicalAnd uint8 broadcast 3D to 4D', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 255 + ], + 'descriptor': {shape: [2, 2, 1], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalAnd', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, + 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + } + } + }, + { + 'name': 'logicalAnd uint8 broadcast 4D to 4D', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [1], + 'descriptor': {shape: [1, 1, 1, 1], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalAnd', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + } + } + } +]; + +if (navigator.ml) { + logicalAndTests.forEach((test) => { + webnn_conformance_test( + buildGraphAndCompute, getPrecisionTolerance, test); + }); +} else { + test(() => assert_implements(navigator.ml, 'missing navigator.ml')); +} diff --git a/webnn/conformance_tests/logical_or.https.any.js b/webnn/conformance_tests/logical_or.https.any.js new file mode 100644 index 00000000000000..f5eb21de7295af --- /dev/null +++ b/webnn/conformance_tests/logical_or.https.any.js @@ -0,0 +1,422 @@ +// META: title=test WebNN API element-wise logicalOr operation +// META: global=window,dedicatedworker +// META: variant=?cpu +// META: variant=?gpu +// META: variant=?npu +// META: script=../resources/utils.js +// META: timeout=long + +'use strict'; + +// MLOperand logicalOr(MLOperand a, MLOperand b, optional MLOperatorOptions options = {}); + +const logicalOrTests = [ + { + 'name': 'logicalOr uint8 0D scalar', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [1], + 'descriptor': {shape: [], dataType: 'uint8'} + }, + 'inputB': { + 'data': [1], + 'descriptor': {shape: [], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalOr', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': {'data': [1], 'descriptor': {shape: [], dataType: 'uint8'}} + } + } + }, + { + 'name': 'logicalOr uint8 1D constant tensors', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [24], dataType: 'uint8'}, + 'constant': true + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [24], dataType: 'uint8'}, + 'constant': true + } + }, + 'operators': [{ + 'name': 'logicalOr', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 + ], + 'descriptor': {shape: [24], dataType: 'uint8'} + } + } + } + }, + { + 'name': 'logicalOr uint8 1D tensors', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [24], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [24], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalOr', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 + ], + 'descriptor': {shape: [24], dataType: 'uint8'} + } + } + } + }, + { + 'name': 'logicalOr uint8 2D tensors', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [4, 6], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [4, 6], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalOr', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 + ], + 'descriptor': {shape: [4, 6], dataType: 'uint8'} + } + } + } + }, + { + 'name': 'logicalOr uint8 3D tensors', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [2, 3, 4], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [2, 3, 4], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalOr', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 + ], + 'descriptor': {shape: [2, 3, 4], dataType: 'uint8'} + } + } + } + }, + { + 'name': 'logicalOr uint8 4D tensors', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalOr', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + } + } + }, + { + 'name': 'logicalOr uint8 5D tensors', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [2, 2, 1, 2, 3], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [2, 2, 1, 2, 3], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalOr', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 + ], + 'descriptor': {shape: [2, 2, 1, 2, 3], dataType: 'uint8'} + } + } + } + }, + { + 'name': 'logicalOr uint8 broadcast 0D to 4D', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [1], + 'descriptor': {shape: [], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalOr', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + } + } + }, + { + 'name': 'logicalOr uint8 broadcast 1D to 4D', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [1], + 'descriptor': {shape: [1], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalOr', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + } + } + }, + { + 'name': 'logicalOr uint8 broadcast 2D to 4D', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 255, 255 + ], + 'descriptor': {shape: [2, 3], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalOr', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + } + } + }, + { + 'name': 'logicalOr uint8 broadcast 3D to 4D', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 255 + ], + 'descriptor': {shape: [2, 2, 1], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalOr', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + } + } + }, + { + 'name': 'logicalOr uint8 broadcast 4D to 4D', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [1], + 'descriptor': {shape: [1, 1, 1, 1], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalOr', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + } + } + } +]; + +if (navigator.ml) { + logicalOrTests.forEach((test) => { + webnn_conformance_test( + buildGraphAndCompute, getPrecisionTolerance, test); + }); +} else { + test(() => assert_implements(navigator.ml, 'missing navigator.ml')); +} diff --git a/webnn/conformance_tests/logical_xor.https.any.js b/webnn/conformance_tests/logical_xor.https.any.js new file mode 100644 index 00000000000000..b678b04065b2cf --- /dev/null +++ b/webnn/conformance_tests/logical_xor.https.any.js @@ -0,0 +1,422 @@ +// META: title=test WebNN API element-wise logicalXor operation +// META: global=window,dedicatedworker +// META: variant=?cpu +// META: variant=?gpu +// META: variant=?npu +// META: script=../resources/utils.js +// META: timeout=long + +'use strict'; + +// MLOperand logicalXor(MLOperand a, MLOperand b, optional MLOperatorOptions options = {}); + +const logicalXorTests = [ +{ + 'name': 'logicalXor uint8 0D scalar', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [1], + 'descriptor': {shape: [], dataType: 'uint8'} + }, + 'inputB': { + 'data': [1], + 'descriptor': {shape: [], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalXor', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': {'data': [1], 'descriptor': {shape: [], dataType: 'uint8'}} + } + } +}, +{ + 'name': 'logicalXor uint8 1D constant tensors', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [24], dataType: 'uint8'}, + 'constant': true + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [24], dataType: 'uint8'}, + 'constant': true + } + }, + 'operators': [{ + 'name': 'logicalXor', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0 + ], + 'descriptor': {shape: [24], dataType: 'uint8'} + } + } + } +}, +{ + 'name': 'logicalXor uint8 1D tensors', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [24], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [24], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalXor', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0 + ], + 'descriptor': {shape: [24], dataType: 'uint8'} + } + } + } +}, +{ + 'name': 'logicalXor uint8 2D tensors', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [4, 6], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [4, 6], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalXor', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0 + ], + 'descriptor': {shape: [4, 6], dataType: 'uint8'} + } + } + } +}, +{ + 'name': 'logicalXor uint8 3D tensors', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [2, 3, 4], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [2, 3, 4], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalXor', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0 + ], + 'descriptor': {shape: [2, 3, 4], dataType: 'uint8'} + } + } + } +}, +{ + 'name': 'logicalXor uint8 4D tensors', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalXor', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + } + } +}, +{ + 'name': 'logicalXor uint8 5D tensors', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [2, 2, 1, 2, 3], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [2, 2, 1, 2, 3], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalXor', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0 + ], + 'descriptor': {shape: [2, 2, 1, 2, 3], dataType: 'uint8'} + } + } + } +}, +{ + 'name': 'logicalXor uint8 broadcast 0D to 4D', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [1], + 'descriptor': {shape: [], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalXor', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + } + } +}, +{ + 'name': 'logicalXor uint8 broadcast 1D to 4D', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [1], + 'descriptor': {shape: [1], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalXor', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + } + } +}, +{ + 'name': 'logicalXor uint8 broadcast 2D to 4D', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 255, 255 + ], + 'descriptor': {shape: [2, 3], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalXor', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, + 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + } + } +}, +{ + 'name': 'logicalXor uint8 broadcast 3D to 4D', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 8, 8, + 0, 0, 8, 8, 0, 0, 255, 255, 0, 0, 255, 255 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 255 + ], + 'descriptor': {shape: [2, 2, 1], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalXor', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + } + } +}, +{ + 'name': 'logicalXor uint8 broadcast 4D to 4D', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [1], + 'descriptor': {shape: [1, 1, 1, 1], dataType: 'uint8'} + }, + 'inputB': { + 'data': [ + 0, 1, 0, 1, 0, 2, 0, 2, 0, 8, 0, 8, + 0, 2, 0, 2, 0, 255, 0, 255, 0, 8, 0, 8 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + }, + 'operators': [{ + 'name': 'logicalXor', + 'arguments': [{'a': 'inputA'}, {'b': 'inputB'}], + 'outputs': 'output' + }], + 'expectedOutputs': { + 'output': { + 'data': [ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'} + } + } + } +} +]; + +if (navigator.ml) { +logicalXorTests.forEach((test) => { + webnn_conformance_test( + buildGraphAndCompute, getPrecisionTolerance, test); +}); +} else { +test(() => assert_implements(navigator.ml, 'missing navigator.ml')); +} diff --git a/webnn/validation_tests/elementwise-logical.https.any.js b/webnn/validation_tests/elementwise-logical.https.any.js index bada9e7648b1eb..3db25c106246cf 100644 --- a/webnn/validation_tests/elementwise-logical.https.any.js +++ b/webnn/validation_tests/elementwise-logical.https.any.js @@ -13,6 +13,9 @@ const kElementwiseLogicalBinaryOperators = [ 'greaterOrEqual', 'lesser', 'lesserOrEqual', + 'logicalAnd', + 'logicalOr', + 'logicalXor', ]; const label = 'elementwise_logic_op';