Skip to content

Commit f125b3d

Browse files
Honryankitm3k
authored andcommitted
[WebNN] Allow ops to handle ignoring an empty tensor as input (microsoft#22972)
### Description Some ops should allow empty tensor as input, e.g. roi, scales inputs in Resize ### Motivation and Context It avoid some unexpected fallback for optional input with empty tensor. e.g. roi and scales are both optional inputs in Resize, in some models they have non-empty name but with empty initializer presented as `[0]`, WebNN currently will fallback all nodes with 0 dimension, which is not expected. ![image](https://github.com/user-attachments/assets/599ba351-b5f6-49ac-8a1f-69fb28dbaf9b)
1 parent f94351f commit f125b3d

File tree

5 files changed

+13
-4
lines changed

5 files changed

+13
-4
lines changed

onnxruntime/core/providers/webnn/builders/helper.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ bool IsNodeSupported(const Node& node, const GraphViewer& graph_viewer, const We
6969
}
7070
}
7171

72-
bool IsTensorShapeSupported(const NodeArg& node_arg, const std::string& parent_name, const logging::Logger& logger) {
72+
bool IsTensorShapeSupported(const NodeArg& node_arg, const std::string& parent_name,
73+
const logging::Logger& logger, bool allow_empty_input) {
7374
const auto& node_arg_name = node_arg.Name();
7475
const auto* shape_proto = node_arg.Shape();
7576
// Optional tensors can be indicated by an empty name, just ignore it.
@@ -89,7 +90,7 @@ bool IsTensorShapeSupported(const NodeArg& node_arg, const std::string& parent_n
8990
<< "use sessionOptions.FreeDimensionOverrides to set a fixed shape: " << node_arg_name;
9091
return false;
9192
}
92-
if (dim.dim_value() == 0) {
93+
if (dim.dim_value() == 0 && !allow_empty_input) {
9394
LOGS(logger, VERBOSE) << "The shape of [" << node_arg_name << "] has 0 dimension which is not supported by WebNN";
9495
return false;
9596
}

onnxruntime/core/providers/webnn/builders/helper.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,8 @@ inline bool IsEmptyTensor(const InitializedTensorSet& initializers, const std::s
181181
return std::any_of(dims.begin(), dims.end(), [](auto d) { return d == 0; });
182182
}
183183

184-
bool IsTensorShapeSupported(const NodeArg& node_arg, const std::string& parent_name, const logging::Logger& logger);
184+
bool IsTensorShapeSupported(const NodeArg& node_arg, const std::string& parent_name,
185+
const logging::Logger& logger, bool allow_empty_input = false);
185186

186187
// Get a list of groups of supported nodes, each group represents a subgraph supported by WebNN EP.
187188
std::vector<std::vector<NodeIndex>> GetSupportedNodes(const GraphViewer& graph_viewer,

onnxruntime/core/providers/webnn/builders/impl/base_op_builder.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ bool BaseOpBuilder::HasSupportedInputs(const Node& node, const emscripten::val&
4545
const logging::Logger& logger) const {
4646
const auto node_name = MakeString("Node [", node.Name(), "] type [", node.OpType(), "]");
4747
for (const auto* input : node.InputDefs()) {
48-
if (!IsTensorShapeSupported(*input, node_name, logger)) {
48+
if (!IsTensorShapeSupported(*input, node_name, logger, allow_empty_tensor_as_input_)) {
4949
return false;
5050
}
5151
}

onnxruntime/core/providers/webnn/builders/impl/base_op_builder.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ class BaseOpBuilder : public IOpBuilder {
2222
const logging::Logger& logger) const override final ORT_MUST_USE_RESULT;
2323

2424
protected:
25+
explicit BaseOpBuilder(bool allow_empty_tensor_as_input = false)
26+
: allow_empty_tensor_as_input_(allow_empty_tensor_as_input) {
27+
}
2528
virtual Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node,
2629
const logging::Logger& logger) const ORT_MUST_USE_RESULT = 0;
2730

@@ -55,6 +58,8 @@ class BaseOpBuilder : public IOpBuilder {
5558
bool HasSupportedOpSet(const Node& node, const logging::Logger& logger) const;
5659
bool HasSupportedInputs(const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const;
5760
bool HasSupportedOutputs(const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const;
61+
62+
const bool allow_empty_tensor_as_input_; // Some operators can handle ignoring an empty tensor as input.
5863
};
5964

6065
} // namespace webnn

onnxruntime/core/providers/webnn/builders/impl/resize_op_builder.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ namespace webnn {
2121
class ResizeOpBuilder : public BaseOpBuilder {
2222
// Add operator related.
2323
public:
24+
// Allow roi and scales potentially being empty inputs that are ignored during processing.
25+
ResizeOpBuilder() : BaseOpBuilder(/*allow empty inputs*/ true) {}
2426
void AddInitializersToSkip(ModelBuilder& model_builder, const Node& node) const override;
2527

2628
private:

0 commit comments

Comments
 (0)