From 1c0ca0e47b11f9a35b30b3c67da961b4f757ecb5 Mon Sep 17 00:00:00 2001 From: Georgy Krivoruchko Date: Thu, 21 Mar 2024 11:14:35 +0400 Subject: [PATCH] [ONNX] Extended ReduceMax by opsets 13,18,20 (#23475) ### Details: - Extended ReduceMax by opsets 13,18,20 - Updated a using opset for ONNX to 20 - Added tests for additional supported types - Enabled backend tests ### Tickets: - Closes #20555 --- src/frontends/onnx/frontend/CMakeLists.txt | 2 +- src/frontends/onnx/frontend/src/op/reduce.cpp | 46 ++++++++++++- src/frontends/onnx/frontend/src/op/reduce.hpp | 9 +++ .../onnx/frontend/src/ops_bridge.cpp | 3 + src/frontends/onnx/tests/__init__.py | 2 - .../onnx/tests/models/reduce_max_18.prototxt | 68 +++++++++++++++++++ .../models/reduce_wrong_type_v3.prototxt | 48 +++++++++++++ .../models/reduce_wrong_type_v4.prototxt | 48 +++++++++++++ src/frontends/onnx/tests/onnx_import.in.cpp | 22 ++++++ .../onnx/tests/onnx_import_exceptions.cpp | 21 ++++++ .../onnx/tests/tests_python/test_backend.py | 17 ----- 11 files changed, 265 insertions(+), 21 deletions(-) create mode 100644 src/frontends/onnx/tests/models/reduce_max_18.prototxt create mode 100644 src/frontends/onnx/tests/models/reduce_wrong_type_v3.prototxt create mode 100644 src/frontends/onnx/tests/models/reduce_wrong_type_v4.prototxt diff --git a/src/frontends/onnx/frontend/CMakeLists.txt b/src/frontends/onnx/frontend/CMakeLists.txt index e53ee551f07063..681fa778e2be12 100644 --- a/src/frontends/onnx/frontend/CMakeLists.txt +++ b/src/frontends/onnx/frontend/CMakeLists.txt @@ -10,7 +10,7 @@ ov_add_frontend(NAME onnx FILEDESCRIPTION "FrontEnd to load and convert ONNX file format" LINK_LIBRARIES openvino_onnx_common openvino::core::dev) -set(ONNX_OPSET_VERSION 18 CACHE INTERNAL "Supported version of ONNX operator set") +set(ONNX_OPSET_VERSION 20 CACHE INTERNAL "Supported version of ONNX operator set") target_compile_definitions(${TARGET_NAME} PRIVATE ONNX_OPSET_VERSION=${ONNX_OPSET_VERSION}) ov_ncc_naming_style(FOR_TARGET ${TARGET_NAME} diff --git a/src/frontends/onnx/frontend/src/op/reduce.cpp b/src/frontends/onnx/frontend/src/op/reduce.cpp index 9a8c1cd4ec3ea2..d9108c8b6fcf30 100644 --- a/src/frontends/onnx/frontend/src/op/reduce.cpp +++ b/src/frontends/onnx/frontend/src/op/reduce.cpp @@ -8,6 +8,7 @@ #include "identity.hpp" #include "openvino/frontend/exception.hpp" #include "openvino/op/constant.hpp" +#include "openvino/op/convert.hpp" #include "openvino/op/exp.hpp" #include "openvino/op/log.hpp" #include "openvino/op/multiply.hpp" @@ -94,6 +95,27 @@ const std::set supported_types_v1 = {element::u32, element::u64, element::i32, element::i64, element::f16, element::f32, element::f64}; const std::set supported_types_v2 = {element::u32, element::u64, element::i32, element::i64, element::f16, element::f32, element::f64, element::bf16}; +const std::set supported_types_v3 = {element::u32, + element::u64, + element::i32, + element::i64, + element::f16, + element::f32, + element::f64, + element::bf16, + element::i8, + element::u8}; +const std::set supported_types_v4 = {element::u32, + element::u64, + element::i32, + element::i64, + element::f16, + element::f32, + element::f64, + element::bf16, + element::i8, + element::u8, + element::boolean}; template std::shared_ptr make_ov_reduction_op(const Node& node, @@ -177,11 +199,33 @@ namespace set_13 { ov::OutputVector reduce_sum(const ov::frontend::onnx::Node& node) { return {make_ov_reduction_op(node, node.get_ov_inputs().at(0), supported_types_v2, false)}; } +ov::OutputVector reduce_max(const ov::frontend::onnx::Node& node) { + return {make_ov_reduction_op(node, node.get_ov_inputs().at(0), supported_types_v3)}; +} } // namespace set_13 namespace set_18 { -// Placeholder +ov::OutputVector reduce_max(const ov::frontend::onnx::Node& node) { + return {make_ov_reduction_op(node, node.get_ov_inputs().at(0), supported_types_v3, false)}; +} } // namespace set_18 + +namespace set_20 { +ov::OutputVector reduce_max(const ov::frontend::onnx::Node& node) { + auto data = node.get_ov_inputs().at(0); + if (data.get_element_type() != element::boolean) { + return {make_ov_reduction_op(node, data, supported_types_v3, false)}; + } else { + // Handling boolean as a uint8 + return {std::make_shared( + make_ov_reduction_op(node, + std::make_shared(data, element::u8), + supported_types_v4, + false), + element::boolean)}; + } +} +} // namespace set_20 } // namespace op } // namespace onnx } // namespace frontend diff --git a/src/frontends/onnx/frontend/src/op/reduce.hpp b/src/frontends/onnx/frontend/src/op/reduce.hpp index defa7c4e33dce2..3acdc3677e77da 100644 --- a/src/frontends/onnx/frontend/src/op/reduce.hpp +++ b/src/frontends/onnx/frontend/src/op/reduce.hpp @@ -29,6 +29,15 @@ ov::OutputVector reduce_l2(const ov::frontend::onnx::Node& node); namespace set_1 { ov::OutputVector reduce_max(const ov::frontend::onnx::Node& node); } // namespace set_1 +namespace set_13 { +ov::OutputVector reduce_max(const ov::frontend::onnx::Node& node); +} // namespace set_13 +namespace set_18 { +ov::OutputVector reduce_max(const ov::frontend::onnx::Node& node); +} // namespace set_18 +namespace set_20 { +ov::OutputVector reduce_max(const ov::frontend::onnx::Node& node); +} // namespace set_20 namespace set_1 { ov::OutputVector reduce_mean(const ov::frontend::onnx::Node& node); diff --git a/src/frontends/onnx/frontend/src/ops_bridge.cpp b/src/frontends/onnx/frontend/src/ops_bridge.cpp index 2e4d60d87e60ab..6350c902ba5761 100644 --- a/src/frontends/onnx/frontend/src/ops_bridge.cpp +++ b/src/frontends/onnx/frontend/src/ops_bridge.cpp @@ -484,6 +484,9 @@ OperatorsBridge::OperatorsBridge() { REGISTER_OPERATOR("ReduceL1", 1, reduce_l1); REGISTER_OPERATOR("ReduceL2", 1, reduce_l2); REGISTER_OPERATOR("ReduceMax", 1, reduce_max); + REGISTER_OPERATOR("ReduceMax", 13, reduce_max); + REGISTER_OPERATOR("ReduceMax", 18, reduce_max); + REGISTER_OPERATOR("ReduceMax", 20, reduce_max); REGISTER_OPERATOR("ReduceMean", 1, reduce_mean); REGISTER_OPERATOR("ReduceMin", 1, reduce_min); REGISTER_OPERATOR("ReduceProd", 1, reduce_prod); diff --git a/src/frontends/onnx/tests/__init__.py b/src/frontends/onnx/tests/__init__.py index 1a66a0624cf8e0..a7d8744262f106 100644 --- a/src/frontends/onnx/tests/__init__.py +++ b/src/frontends/onnx/tests/__init__.py @@ -59,7 +59,6 @@ def xfail_test(reason="Mark the test as expected to fail", strict=True): xfail_issue_99954 = xfail_test(reason="Constant Pad - RuntimeError: Shape inference of Reference node with name y failed") xfail_issue_99955 = xfail_test(reason="GroupNorm is not supported") xfail_issue_99957 = xfail_test(reason="LayerNorm - RuntimeError: While validating node ''") -xfail_issue_99958 = xfail_test(reason="LogSoftmax - Results mismatch") xfail_issue_99960 = xfail_test(reason="MVN - Results mismatch") xfail_issue_99961 = xfail_test(reason="Optional has/get element operators are not supported)'") xfail_issue_99962 = pytest.mark.skip(reason="ReduceL1/L2 - Unrecognized attribute: axes for operator ReduceL1/L2") @@ -71,7 +70,6 @@ def xfail_test(reason="Mark the test as expected to fail", strict=True): xfail_issue_99970 = xfail_test(reason="Scatter and ScatterND - RuntimeError: Check '(reduction == none)' failed at " "src/frontends/onnx/frontend/src/op/scatter_elements.cpp OR at " "src/frontends/onnx/frontend/src/op/scatter_nd") -xfail_issue_99972 = xfail_test(reason="Softmax - Results mismatch") xfail_issue_99973 = xfail_test(reason="Split - RuntimeError: While validating ONNX node " "''") xfail_issue_38710 = xfail_test(reason="RuntimeError: data has zero dimension which is not allowed") diff --git a/src/frontends/onnx/tests/models/reduce_max_18.prototxt b/src/frontends/onnx/tests/models/reduce_max_18.prototxt new file mode 100644 index 00000000000000..f08aae650c54c6 --- /dev/null +++ b/src/frontends/onnx/tests/models/reduce_max_18.prototxt @@ -0,0 +1,68 @@ +ir_version: 3 +producer_name: "OpenVINO ONNX Frontend" +graph { + node { + input: "A" + input: "axes" + output: "B" + op_type: "ReduceMax" + } + name: "compute_graph" + initializer { + data_type: 6 + dims: 1 + name: "axes" + raw_data: "\002\000\000\000" + } + input { + name: "A" + type { + tensor_type { + elem_type: 2 + shape { + dim { + dim_value: 1 + } + dim { + dim_value: 1 + } + dim { + dim_value: 4 + } + dim { + dim_value: 4 + } + } + } + } + } + input { + name: "axes" + type { + tensor_type { + elem_type: 6 + shape { + dim { + dim_value: 1 + } + } + } + } + } + output { + name: "B" + type { + tensor_type { + elem_type: 2 + shape { + dim { + dim_value: 1 + } + } + } + } + } +} +opset_import { + version: 18 +} diff --git a/src/frontends/onnx/tests/models/reduce_wrong_type_v3.prototxt b/src/frontends/onnx/tests/models/reduce_wrong_type_v3.prototxt new file mode 100644 index 00000000000000..8e9110bd532ad9 --- /dev/null +++ b/src/frontends/onnx/tests/models/reduce_wrong_type_v3.prototxt @@ -0,0 +1,48 @@ +ir_version: 3 +producer_name: "OpenVINO ONNX Frontend" +graph { + node { + input: "A" + output: "B" + op_type: "ReduceMax" + } + name: "compute_graph" + input { + name: "A" + type { + tensor_type { + elem_type: 9 + shape { + dim { + dim_value: 1 + } + dim { + dim_value: 1 + } + dim { + dim_value: 4 + } + dim { + dim_value: 4 + } + } + } + } + } + output { + name: "B" + type { + tensor_type { + elem_type: 9 + shape { + dim { + dim_value: 1 + } + } + } + } + } +} +opset_import { + version: 13 +} diff --git a/src/frontends/onnx/tests/models/reduce_wrong_type_v4.prototxt b/src/frontends/onnx/tests/models/reduce_wrong_type_v4.prototxt new file mode 100644 index 00000000000000..a36fafc7ab66f0 --- /dev/null +++ b/src/frontends/onnx/tests/models/reduce_wrong_type_v4.prototxt @@ -0,0 +1,48 @@ +ir_version: 3 +producer_name: "OpenVINO ONNX Frontend" +graph { + node { + input: "A" + output: "B" + op_type: "ReduceMax" + } + name: "compute_graph" + input { + name: "A" + type { + tensor_type { + elem_type: 9 + shape { + dim { + dim_value: 1 + } + dim { + dim_value: 1 + } + dim { + dim_value: 4 + } + dim { + dim_value: 4 + } + } + } + } + } + output { + name: "B" + type { + tensor_type { + elem_type: 9 + shape { + dim { + dim_value: 1 + } + } + } + } + } +} +opset_import { + version: 20 +} diff --git a/src/frontends/onnx/tests/onnx_import.in.cpp b/src/frontends/onnx/tests/onnx_import.in.cpp index b02d3a1116131c..b515fd1cb78799 100644 --- a/src/frontends/onnx/tests/onnx_import.in.cpp +++ b/src/frontends/onnx/tests/onnx_import.in.cpp @@ -974,6 +974,28 @@ OPENVINO_TEST(${BACKEND_NAME}, onnx_model_reduce_max) { test_case.run(); } +OPENVINO_TEST(${BACKEND_NAME}, onnx_model_reduce_max_18) { + // TEMPLATE plugin has an issue with evaluation for u8 type + if (std::string("${BACKEND_NAME}") == std::string("INTERPRETER")) { + GTEST_SKIP(); + } + + auto model = convert_model("reduce_max_18.onnx"); + + // input data shape (1, 1, 4, 4) + std::vector> inputs{ + ov::test::NDArray({{{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16}}}}) + .get_vector()}; + + // output data shape (1,) + auto expected_output = ov::test::NDArray({13, 14, 15, 16}).get_vector(); + + auto test_case = ov::test::TestCase(model, s_device); + test_case.add_multiple_inputs(inputs); + test_case.add_expected_output(expected_output); + test_case.run(); +} + OPENVINO_TEST(${BACKEND_NAME}, onnx_model_reduce_max_invalid_axes) { EXPECT_THROW(convert_model("reduce_max_invalid_axes.onnx"), ov::Exception); } diff --git a/src/frontends/onnx/tests/onnx_import_exceptions.cpp b/src/frontends/onnx/tests/onnx_import_exceptions.cpp index 586f5bbc3d4d2f..28c0d9aaec1ca2 100644 --- a/src/frontends/onnx/tests/onnx_import_exceptions.cpp +++ b/src/frontends/onnx/tests/onnx_import_exceptions.cpp @@ -92,3 +92,24 @@ TEST(onnx_importer, exception_msg_onnx_reduce_wrong_type_v2) { FAIL() << "The ONNX model importer failed for unexpected reason"; } } + +TEST(onnx_importer, exception_msg_onnx_reduce_wrong_type_v3) { + try { + convert_model("reduce_wrong_type_v3.onnx"); + // Should have thrown, so fail if it didn't + FAIL() << "ONNX Importer did not detected incorrect model!"; + } catch (const ::ov::Exception& e) { + EXPECT_HAS_SUBSTRING(e.what(), std::string("Unsupported input type boolean")); + } + // On MacOS after we re-throw ov::Exception exception, we couldn't catch it as is, + // thus below workaround. + catch (const std::exception& e) { + EXPECT_HAS_SUBSTRING(e.what(), std::string("Unsupported input type boolean")); + } catch (...) { + FAIL() << "The ONNX model importer failed for unexpected reason"; + } +} + +TEST(onnx_importer, no_exception_onnx_reduce_wrong_type_v4) { + EXPECT_NO_THROW(convert_model("reduce_wrong_type_v4.onnx")); +} diff --git a/src/frontends/onnx/tests/tests_python/test_backend.py b/src/frontends/onnx/tests/tests_python/test_backend.py index 2307b5282c235c..229b88b39b31a8 100644 --- a/src/frontends/onnx/tests/tests_python/test_backend.py +++ b/src/frontends/onnx/tests/tests_python/test_backend.py @@ -51,13 +51,11 @@ xfail_issue_99954, xfail_issue_99955, xfail_issue_99957, - xfail_issue_99958, xfail_issue_99960, xfail_issue_99961, xfail_issue_99968, xfail_issue_99969, xfail_issue_99970, - xfail_issue_99972, xfail_issue_99973, xfail_issue_101965, xfail_issue_113506, @@ -453,10 +451,6 @@ def expect_fail(test_case_path, xfail): # type: (str) -> None "OnnxBackendNodeModelTest.test_layer_normalization_4d_axis_negative_3_expanded_ver18_cpu", "OnnxBackendNodeModelTest.test_layer_normalization_default_axis_expanded_ver18_cpu", ), - ( - xfail_issue_99958, - "OnnxBackendNodeModelTest.test_logsoftmax_large_number_expanded_ver18_cpu", - ), ( xfail_issue_99960, "OnnxBackendNodeModelTest.test_mvn_expanded_ver18_cpu", @@ -499,12 +493,6 @@ def expect_fail(test_case_path, xfail): # type: (str) -> None "OnnxBackendNodeModelTest.test_reduce_log_sum_exp_negative_axes_keepdims_example_cpu", "OnnxBackendNodeModelTest.test_reduce_log_sum_exp_keepdims_random_cpu", "OnnxBackendNodeModelTest.test_reduce_log_sum_negative_axes_cpu", - "OnnxBackendNodeModelTest.test_reduce_max_do_not_keepdims_example_cpu", - "OnnxBackendNodeModelTest.test_reduce_max_do_not_keepdims_random_cpu", - "OnnxBackendNodeModelTest.test_reduce_max_keepdims_example_cpu", - "OnnxBackendNodeModelTest.test_reduce_max_keepdims_random_cpu", - "OnnxBackendNodeModelTest.test_reduce_max_negative_axes_keepdims_example_cpu", - "OnnxBackendNodeModelTest.test_reduce_max_negative_axes_keepdims_random_cpu", "OnnxBackendNodeModelTest.test_reduce_mean_do_not_keepdims_example_cpu", "OnnxBackendNodeModelTest.test_reduce_log_sum_exp_negative_axes_keepdims_random_cpu", "OnnxBackendNodeModelTest.test_reduce_mean_do_not_keepdims_random_cpu", @@ -552,10 +540,6 @@ def expect_fail(test_case_path, xfail): # type: (str) -> None "OnnxBackendNodeModelTest.test_scatternd_max_cpu", "OnnxBackendNodeModelTest.test_scatternd_min_cpu", ), - ( - xfail_issue_99972, - "OnnxBackendNodeModelTest.test_softmax_large_number_expanded_ver18_cpu", - ), ( xfail_issue_99973, "OnnxBackendNodeModelTest.test_split_1d_uneven_split_opset18_cpu", @@ -732,7 +716,6 @@ def expect_fail(test_case_path, xfail): # type: (str) -> None ), ( xfail_issue_125495, - "OnnxBackendNodeModelTest.test_reduce_max_bool_inputs_cpu", "OnnxBackendNodeModelTest.test_reduce_min_bool_inputs_cpu", ), (