From 46f1d2aaf24e023fba2593f422ed07b3a0934798 Mon Sep 17 00:00:00 2001 From: shiyi Date: Sun, 10 Nov 2024 10:20:52 +0800 Subject: [PATCH] [WebNN] Support steps >= 1 for slice operator (#22708) Co-authored-by: Wanming Lin --- js/web/docs/webnn-operators.md | 2 +- js/web/test/suite-test-list.jsonc | 16 +++++++------- .../webnn/builders/impl/slice_op_builder.cc | 21 ++++++++++++------- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/js/web/docs/webnn-operators.md b/js/web/docs/webnn-operators.md index b8c3b2ec8ec57..0c86845f79d48 100644 --- a/js/web/docs/webnn-operators.md +++ b/js/web/docs/webnn-operators.md @@ -93,7 +93,7 @@ operators and the supported opset domain/versions in **WebNN EP** by ONNX Runtim | Softplus | ai.onnx(7+) | softplus | ✓ | ✓ | | | Softsign | ai.onnx(7+) | softsign | ✓ | ✓ | | | 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 | +| 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 | ✓ | ✓ | | diff --git a/js/web/test/suite-test-list.jsonc b/js/web/test/suite-test-list.jsonc index 0e42a1dbcbf08..be2e0002ca748 100644 --- a/js/web/test/suite-test-list.jsonc +++ b/js/web/test/suite-test-list.jsonc @@ -2362,14 +2362,14 @@ // "test_sinh", // // "test_size_example", // // "test_size", - // "test_slice_default_axes", - // "test_slice_default_steps", - // "test_slice_end_out_of_bounds", - // "test_slice_neg_steps", - // "test_slice_neg", - // "test_slice_negative_axes", - // "test_slice_start_out_of_bounds", - // "test_slice", + "test_slice_default_axes", + "test_slice_default_steps", + "test_slice_end_out_of_bounds", + "test_slice_neg_steps", + "test_slice_neg", + "test_slice_negative_axes", + "test_slice_start_out_of_bounds", + "test_slice", // "test_softmax_axis_0_expanded", "test_softmax_axis_0", // "test_softmax_axis_1_expanded", diff --git a/onnxruntime/core/providers/webnn/builders/impl/slice_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/slice_op_builder.cc index 3f0d633ac888b..78ec0acdfbd9f 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/slice_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/slice_op_builder.cc @@ -52,6 +52,7 @@ Status SliceOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, emscripten::val inputs = model_builder.GetOperand(input_defs[0]->Name()); std::vector starts(rank); std::vector sizes(rank); + std::vector steps(rank); // Copy the data from the starts/ends/axes/steps initializers. std::vector input_starts; @@ -94,8 +95,11 @@ Status SliceOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, std::transform(compute_metadata.ends_.cbegin(), compute_metadata.ends_.cend(), compute_metadata.starts_.cbegin(), sizes.begin(), [](int64_t i, int64_t j) { return SafeInt(i - j); }); + std::transform(compute_metadata.steps_.cbegin(), compute_metadata.steps_.cend(), steps.begin(), + [](int64_t i) { return SafeInt(i); }); emscripten::val options = emscripten::val::object(); + options.set("strides", emscripten::val::array(steps)); options.set("label", node.Name()); emscripten::val output = model_builder.GetBuilder().call("slice", inputs, emscripten::val::array(starts), @@ -144,18 +148,19 @@ bool SliceOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, return false; } const auto data_type = steps_tensor.data_type(); - // WebNN doesn't support steps other than 1. + // WebNN doesn't support steps less than 1. if (data_type == ONNX_NAMESPACE::TensorProto_DataType_INT64) { - if (!std::all_of(reinterpret_cast(unpacked_tensor.data()), - reinterpret_cast(unpacked_tensor.data() + unpacked_tensor.size()), - [](int64_t i) { return i == 1; })) { + if (std::any_of(reinterpret_cast(unpacked_tensor.data()), + reinterpret_cast(unpacked_tensor.data() + unpacked_tensor.size()), + [](int64_t i) { return i < 1; })) { + LOGS(logger, VERBOSE) << "WebNN slice doesn't support steps less than 1"; return false; } } else if (data_type == ONNX_NAMESPACE::TensorProto_DataType_INT32) { - if (!std::all_of(reinterpret_cast(unpacked_tensor.data()), - reinterpret_cast(unpacked_tensor.data()) + - unpacked_tensor.size() / sizeof(int32_t), - [](int32_t i) { return i == 1; })) { + if (std::any_of(reinterpret_cast(unpacked_tensor.data()), + reinterpret_cast(unpacked_tensor.data()) + unpacked_tensor.size() / sizeof(int32_t), + [](int32_t i) { return i < 1; })) { + LOGS(logger, VERBOSE) << "WebNN slice doesn't support steps less than 1"; return false; } }