From f04f1d8aedf3441c6bb3fffb1b965872d2936797 Mon Sep 17 00:00:00 2001 From: vatsalas <vatsala.shanubhag@intel.com> Date: Tue, 18 Mar 2025 14:06:05 +0530 Subject: [PATCH 1/2] implement qlinear softmax --- .../op/com.microsoft/qlinear_activation.cpp | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/frontends/onnx/frontend/src/op/com.microsoft/qlinear_activation.cpp b/src/frontends/onnx/frontend/src/op/com.microsoft/qlinear_activation.cpp index 850c24fab2ccc6..ae926e52d1cc94 100644 --- a/src/frontends/onnx/frontend/src/op/com.microsoft/qlinear_activation.cpp +++ b/src/frontends/onnx/frontend/src/op/com.microsoft/qlinear_activation.cpp @@ -12,9 +12,13 @@ #include "openvino/op/divide.hpp" #include "openvino/op/maximum.hpp" #include "openvino/op/multiply.hpp" +#include "openvino/op/reshape.hpp" +#include "openvino/op/shape_of.hpp" #include "openvino/op/sigmoid.hpp" +#include "openvino/op/softmax.hpp" #include "openvino/op/subtract.hpp" #include "utils/common.hpp" +#include "utils/reshape.hpp" using namespace ov::op; @@ -102,10 +106,32 @@ ov::OutputVector qlinear_avg_pool(const ov::frontend::onnx::Node& node) { }); } +ov::OutputVector qlinear_softmax(const ov::frontend::onnx::Node& node) { + return qlinear_activation(node, [&](const std::shared_ptr<ov::Node>& input_dequantized) { + auto axis = node.get_attribute_value<int64_t>("axis", -1); + auto opset = node.get_attribute_value<int64_t>("opset"); + + auto shape = std::make_shared<v3::ShapeOf>(input_dequantized); + + std::shared_ptr<ov::Node> softmax_result; + if (opset <= 12) { + const auto coerced_data = ov::op::util::flatten(input_dequantized, static_cast<int>(axis)); + softmax_result = std::make_shared<v8::Softmax>(coerced_data, 1); + softmax_result = std::make_shared<v1::Reshape>(softmax_result, shape, false); + } else { + softmax_result = std::make_shared<v8::Softmax>(input_dequantized, axis); + } + + return softmax_result; + }); +} + bool register_multiple_operators(void) { ONNX_OP_M("QLinearSigmoid", OPSET_SINCE(1), com_microsoft::opset_1::qlinear_sigmoid, MICROSOFT_DOMAIN); ONNX_OP_M("QLinearLeakyRelu", OPSET_SINCE(1), com_microsoft::opset_1::qlinear_leaky_relu, MICROSOFT_DOMAIN); ONNX_OP_M("QLinearAveragePool", OPSET_SINCE(1), com_microsoft::opset_1::qlinear_avg_pool, MICROSOFT_DOMAIN); + ONNX_OP_M("QLinearSoftmax", OPSET_SINCE(1), com_microsoft::opset_1::qlinear_softmax, MICROSOFT_DOMAIN); + return true; } From aa22bfa15e564083bec090e3b9c5c0eaa48d396c Mon Sep 17 00:00:00 2001 From: vatsalas <vatsala.shanubhag@intel.com> Date: Tue, 18 Mar 2025 14:07:20 +0530 Subject: [PATCH 2/2] test qlinear softmax --- .../qlinear_softmax_opset12.prototxt | 101 +++++++++++++++++ .../qlinear_softmax_opset13.prototxt | 106 ++++++++++++++++++ .../tests/onnx_import_com_microsoft.in.cpp | 45 ++++++++ 3 files changed, 252 insertions(+) create mode 100644 src/frontends/onnx/tests/models/com.microsoft/qlinear_softmax_opset12.prototxt create mode 100644 src/frontends/onnx/tests/models/com.microsoft/qlinear_softmax_opset13.prototxt diff --git a/src/frontends/onnx/tests/models/com.microsoft/qlinear_softmax_opset12.prototxt b/src/frontends/onnx/tests/models/com.microsoft/qlinear_softmax_opset12.prototxt new file mode 100644 index 00000000000000..466746708ea937 --- /dev/null +++ b/src/frontends/onnx/tests/models/com.microsoft/qlinear_softmax_opset12.prototxt @@ -0,0 +1,101 @@ +ir_version: 3 +producer_name: "OpenVINO ONNX Frontend" +producer_version: "" +model_version: 0 +graph { + name: "test_qlinear_softmax_opset12" + + node { + input: "X" + input: "X_scale" + input: "X_zero_point" + input: "Y_scale" + input: "Y_zero_point" + output: "Y" + op_type: "QLinearSoftmax" + attribute { + name: "opset" + i: 12 + type: INT + } + domain: "com.microsoft" + } + + input { + name: "X" + type { + tensor_type { + elem_type: 3 + shape { + dim { dim_value: 4 } + dim { dim_value: 5 } + } + } + } + } + + input { + name: "X_scale" + type { + tensor_type { + elem_type: 1 + shape { + dim { dim_value: 1 } + } + } + } + } + + input { + name: "X_zero_point" + type { + tensor_type { + elem_type: 3 + shape { + dim { dim_value: 1 } + } + } + } + } + + input { + name: "Y_scale" + type { + tensor_type { + elem_type: 1 + shape { + dim { dim_value: 1 } + } + } + } + } + + input { + name: "Y_zero_point" + type { + tensor_type { + elem_type: 3 + shape { + dim { dim_value: 1 } + } + } + } + } + + output { + name: "Y" + type { + tensor_type { + elem_type: 3 + shape { + dim { dim_value: 4 } + dim { dim_value: 5 } + } + } + } + } +} + +opset_import { + version: 1 +} diff --git a/src/frontends/onnx/tests/models/com.microsoft/qlinear_softmax_opset13.prototxt b/src/frontends/onnx/tests/models/com.microsoft/qlinear_softmax_opset13.prototxt new file mode 100644 index 00000000000000..64b0e3ed4eb07d --- /dev/null +++ b/src/frontends/onnx/tests/models/com.microsoft/qlinear_softmax_opset13.prototxt @@ -0,0 +1,106 @@ +ir_version: 3 +producer_name: "OpenVINO ONNX Frontend" +producer_version: "" +model_version: 0 +graph { + name: "test_qlinear_softmax" + + node { + input: "X" + input: "X_scale" + input: "X_zero_point" + input: "Y_scale" + input: "Y_zero_point" + output: "Y" + op_type: "QLinearSoftmax" + attribute { + name: "axis" + i: -1 + type: INT + } + attribute { + name: "opset" + i: 12 + type: INT + } + domain: "com.microsoft" + } + + input { + name: "X" + type { + tensor_type { + elem_type: 3 + shape { + dim { dim_value: 2 } + dim { dim_value: 3 } + } + } + } + } + + input { + name: "X_scale" + type { + tensor_type { + elem_type: 1 + shape { + dim { dim_value: 1 } + } + } + } + } + + input { + name: "X_zero_point" + type { + tensor_type { + elem_type: 3 + shape { + dim { dim_value: 1 } + } + } + } + } + + input { + name: "Y_scale" + type { + tensor_type { + elem_type: 1 + shape { + dim { dim_value: 1 } + } + } + } + } + + input { + name: "Y_zero_point" + type { + tensor_type { + elem_type: 3 + shape { + dim { dim_value: 1 } + } + } + } + } + + output { + name: "Y" + type { + tensor_type { + elem_type: 3 + shape { + dim { dim_value: 2 } + dim { dim_value: 3 } + } + } + } + } +} + +opset_import { + version: 1 +} diff --git a/src/frontends/onnx/tests/onnx_import_com_microsoft.in.cpp b/src/frontends/onnx/tests/onnx_import_com_microsoft.in.cpp index 170476aae05dd3..ee89750871481f 100644 --- a/src/frontends/onnx/tests/onnx_import_com_microsoft.in.cpp +++ b/src/frontends/onnx/tests/onnx_import_com_microsoft.in.cpp @@ -1740,3 +1740,48 @@ OPENVINO_TEST(${BACKEND_NAME}, onnx_com_microsoft_bias_add) { test_case.run(); } + +OPENVINO_TEST(${BACKEND_NAME}, onnx_com_microsoft_qlinearsoftmax) { + const auto model = convert_model("com.microsoft/qlinear_softmax_opset13.onnx"); + auto test_case = ov::test::TestCase(model, s_device); + + const std::vector<int8_t> data_X{-50, -25, 0, 25, 50, 75}; + const std::vector<float> x_scale{0.1f}; + const std::vector<int8_t> x_zero_point{0}; + const std::vector<float> y_scale{0.03f}; + const std::vector<int8_t> y_zero_point{5}; + + const std::vector<int8_t> expected_output{5, 7, 35, 5, 7, 35}; + + test_case.add_input<int8_t>(Shape{2, 3}, data_X); + test_case.add_input<float>(Shape{1}, x_scale); + test_case.add_input<int8_t>(Shape{1}, x_zero_point); + test_case.add_input<float>(Shape{1}, y_scale); + test_case.add_input<int8_t>(Shape{1}, y_zero_point); + + test_case.add_expected_output<int8_t>(Shape{2, 3}, expected_output); + test_case.run(); +} + +OPENVINO_TEST(${BACKEND_NAME}, onnx_com_microsoft_qlinearsoftmax_opset12) { + const auto model = convert_model("com.microsoft/qlinear_softmax_opset12.onnx"); + auto test_case = ov::test::TestCase(model, s_device); + + const std::vector<int8_t> data_X{-60, -40, -20, 0, 20, 40, 60, 80, 100, 120, + -10, -5, 0, 5, 10, -80, -60, -40, -20, 0}; + const std::vector<float> x_scale{0.15f}; + const std::vector<int8_t> x_zero_point{0}; + const std::vector<float> y_scale{0.05f}; + const std::vector<int8_t> y_zero_point{3}; + + const std::vector<int8_t> expected_output{3, 3, 3, 3, 22, 3, 3, 3, 3, 22, 3, 4, 5, 8, 13, 3, 3, 3, 3, 22}; + + test_case.add_input<int8_t>(Shape{4, 5}, data_X); + test_case.add_input<float>(Shape{1}, x_scale); + test_case.add_input<int8_t>(Shape{1}, x_zero_point); + test_case.add_input<float>(Shape{1}, y_scale); + test_case.add_input<int8_t>(Shape{1}, y_zero_point); + + test_case.add_expected_output<int8_t>(Shape{4, 5}, expected_output); + test_case.run(); +}