mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-07-13 18:08:13 +00:00
[WebNN EP] Support LpPool, GlobalLpPool, and Log ops (#16954)
BTW, reset minimal supported opset to 1, because with minimal supported opset 7 will ignore all ops that have last since version less than 7. e.g. GlobalLpPool, it only has two opset versions: 1, 2.
This commit is contained in:
parent
4a2a248dd7
commit
ba49d64f67
6 changed files with 56 additions and 23 deletions
|
|
@ -153,6 +153,7 @@ static const InlinedHashMap<std::string, std::string> op_map = {
|
|||
{"Gemm", "gemm"},
|
||||
{"GlobalAveragePool", "averagePool2d"},
|
||||
{"GlobalMaxPool", "maxPool2d"},
|
||||
{"GlobalLpPool", "l2Pool2d"},
|
||||
{"Greater", "greater"},
|
||||
{"GroupNormalization", "meanVarianceNormalization"},
|
||||
{"HardSigmoid", "hardSigmoid"},
|
||||
|
|
@ -162,6 +163,8 @@ static const InlinedHashMap<std::string, std::string> op_map = {
|
|||
{"LayerNormalization", "meanVarianceNormalization"},
|
||||
{"LeakyRelu", "leakyRelu"},
|
||||
{"Less", "lesser"},
|
||||
{"Log", "log"},
|
||||
{"LpPool", "l2Pool2d"},
|
||||
{"MatMul", "matmul"},
|
||||
{"Max", "max"},
|
||||
{"MaxPool", "maxPool2d"},
|
||||
|
|
|
|||
|
|
@ -100,8 +100,9 @@ bool BaseOpBuilder::HasSupportedOpSet(const Node& node,
|
|||
const logging::Logger& logger) const {
|
||||
auto since_version = node.SinceVersion();
|
||||
if (since_version < GetMinSupportedOpSet(node) || since_version > GetMaxSupportedOpSet(node)) {
|
||||
LOGS(logger, VERBOSE) << "Current opset is " << since_version << ", "
|
||||
<< node.OpType() << " is only supported for opset ["
|
||||
LOGS(logger, VERBOSE) << "Current opset since version of "
|
||||
<< node.OpType() << " is " << since_version
|
||||
<< ", WebNN EP only supports for its opset ["
|
||||
<< GetMinSupportedOpSet(node) << ", "
|
||||
<< GetMaxSupportedOpSet(node) << "]";
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -41,7 +41,11 @@ class BaseOpBuilder : public IOpBuilder {
|
|||
|
||||
// ONNX Runtime only *guarantees* support for models stamped
|
||||
// with opset version 7 or above for opset domain 'ai.onnx'.
|
||||
virtual int GetMinSupportedOpSet(const Node& /* node */) const { return 7; }
|
||||
// WebNN EP ignores node support for opset less than 7 by
|
||||
// default as which will be fallback earlier by ONNX Runtime.
|
||||
// We still set the mininal supported opset to 1 as we couldn't
|
||||
// get the model opset version at this stage.
|
||||
virtual int GetMinSupportedOpSet(const Node& /* node */) const { return 1; }
|
||||
virtual int GetMaxSupportedOpSet(const Node& /* node */) const { return 19; }
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -38,15 +38,22 @@ Status PoolOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder,
|
|||
emscripten::val input = model_builder.GetOperand(input_defs[0]->Name());
|
||||
|
||||
bool is_global_pooling = false;
|
||||
bool is_average_pool = false;
|
||||
std::string webnn_op_name;
|
||||
if (op_type == "GlobalAveragePool") {
|
||||
is_global_pooling = true;
|
||||
is_average_pool = true;
|
||||
webnn_op_name = "averagePool2d";
|
||||
} else if (op_type == "GlobalMaxPool") {
|
||||
is_global_pooling = true;
|
||||
webnn_op_name = "maxPool2d";
|
||||
} else if (op_type == "GlobalLpPool") {
|
||||
is_global_pooling = true;
|
||||
webnn_op_name = "l2Pool2d";
|
||||
} else if (op_type == "AveragePool") {
|
||||
is_average_pool = true;
|
||||
webnn_op_name = "averagePool2d";
|
||||
} else if (op_type == "MaxPool") {
|
||||
webnn_op_name = "maxPool2d";
|
||||
} else if (op_type == "LpPool") {
|
||||
webnn_op_name = "l2Pool2d";
|
||||
} else {
|
||||
return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "PoolOpBuilder, unknown op: ", op_type);
|
||||
}
|
||||
|
|
@ -97,12 +104,7 @@ Status PoolOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder,
|
|||
options.set("roundingType", ceil_mode == 0 ? emscripten::val("floor")
|
||||
: emscripten::val("ceil"));
|
||||
|
||||
emscripten::val output = emscripten::val::object();
|
||||
if (is_average_pool) {
|
||||
output = model_builder.GetBuilder().call<emscripten::val>("averagePool2d", input, options);
|
||||
} else {
|
||||
output = model_builder.GetBuilder().call<emscripten::val>("maxPool2d", input, options);
|
||||
}
|
||||
emscripten::val output = model_builder.GetBuilder().call<emscripten::val>(webnn_op_name.c_str(), input, options);
|
||||
model_builder.AddOperand(node.OutputDefs()[0]->Name(), std::move(output));
|
||||
return Status::OK();
|
||||
}
|
||||
|
|
@ -127,21 +129,36 @@ bool PoolOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* initializer
|
|||
return false;
|
||||
}
|
||||
|
||||
if (op_type == "AveragePool" || op_type == "MaxPool") {
|
||||
NodeAttrHelper helper(node);
|
||||
const auto storage_order = helper.Get("storage_order", 0);
|
||||
if (storage_order == 1) {
|
||||
LOGS(logger, VERBOSE) << "storage_order == 1 is not supported";
|
||||
return false;
|
||||
}
|
||||
|
||||
NodeAttrHelper helper(node);
|
||||
if (op_type == "AveragePool" || op_type == "LpPool" || op_type == "MaxPool") {
|
||||
if (helper.Get("kernel_shape", std::vector<int32_t>{1, 1}).size() != 2) {
|
||||
LOGS(logger, VERBOSE) << "Only pooling 2d is supported";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (op_type == "AveragePool") {
|
||||
if (helper.Get("count_include_pad", 0) != 0) {
|
||||
LOGS(logger, VERBOSE) << "AveragePool only supports count_include_pad == 0";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (op_type == "MaxPool") {
|
||||
if (helper.Get("storage_order", 0) == 1) {
|
||||
LOGS(logger, VERBOSE) << "MaxPool storage_order == 1 is not supported";
|
||||
return false;
|
||||
}
|
||||
if (node.OutputDefs().size() != 1) {
|
||||
LOGS(logger, VERBOSE) << "Argmax in maxpooling is not supported";
|
||||
LOGS(logger, VERBOSE) << "MaxPool only supports one output";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (op_type == "GlobalLpPool" || op_type == "LpPool") {
|
||||
// WebNN only supports l2Pool2d.
|
||||
if (helper.Get("p", 2) != 2) {
|
||||
LOGS(logger, VERBOSE) << op_type << " only supports p == 2";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -155,9 +172,11 @@ void CreatePoolOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_
|
|||
|
||||
static std::vector<std::string> op_types =
|
||||
{
|
||||
"AveragePool",
|
||||
"GlobalAveragePool",
|
||||
"GlobalMaxPool",
|
||||
"AveragePool",
|
||||
"GlobalLpPool",
|
||||
"LpPool",
|
||||
"MaxPool",
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ Status UnaryOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const
|
|||
output = model_builder.GetBuilder().call<emscripten::val>("floor", input);
|
||||
} else if (op_type == "Identity") {
|
||||
output = model_builder.GetBuilder().call<emscripten::val>("identity", input);
|
||||
} else if (op_type == "Log") {
|
||||
output = model_builder.GetBuilder().call<emscripten::val>("log", input);
|
||||
} else if (op_type == "Neg") {
|
||||
output = model_builder.GetBuilder().call<emscripten::val>("neg", input);
|
||||
} else if (op_type == "Not") {
|
||||
|
|
@ -77,6 +79,7 @@ void CreateUnaryOpBuilder(const std::string& op_type, OpBuilderRegistrations& op
|
|||
"Exp",
|
||||
"Floor",
|
||||
"Identity",
|
||||
"Log",
|
||||
"Neg",
|
||||
"Not",
|
||||
"Reciprocal",
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ static OpBuilderRegistrations CreateOpBuilderRegistrations() {
|
|||
CreateUnaryOpBuilder("Exp", op_registrations);
|
||||
CreateUnaryOpBuilder("Floor", op_registrations);
|
||||
CreateUnaryOpBuilder("Identity", op_registrations);
|
||||
CreateUnaryOpBuilder("Log", op_registrations);
|
||||
CreateUnaryOpBuilder("Neg", op_registrations);
|
||||
CreateUnaryOpBuilder("Not", op_registrations);
|
||||
CreateUnaryOpBuilder("Reciprocal", op_registrations);
|
||||
|
|
@ -117,9 +118,11 @@ static OpBuilderRegistrations CreateOpBuilderRegistrations() {
|
|||
}
|
||||
|
||||
{ // Pool
|
||||
CreatePoolOpBuilder("AveragePool", op_registrations);
|
||||
CreatePoolOpBuilder("GlobalAveragePool", op_registrations);
|
||||
CreatePoolOpBuilder("GlobalMaxPool", op_registrations);
|
||||
CreatePoolOpBuilder("AveragePool", op_registrations);
|
||||
CreatePoolOpBuilder("GlobalLpPool", op_registrations);
|
||||
CreatePoolOpBuilder("LpPool", op_registrations);
|
||||
CreatePoolOpBuilder("MaxPool", op_registrations);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue