From 03507e06b40450244a0489abba8e989d9b337d18 Mon Sep 17 00:00:00 2001 From: alexlyulkov Date: Tue, 14 May 2024 17:41:19 +0300 Subject: [PATCH] Merge pull request #25518 from alexlyulkov:al/fixed-gemm-openvino Fixed OpenVINO gemm layer #25518 Fixed OpenVINO gemm layer The problem was that our layer didn't properly handle all the possible gemm options in OpenVINO mode Fixes #25472 ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x] The feature is well documented and sample code can be built with the project CMake --- modules/dnn/src/layers/gemm_layer.cpp | 74 ++++++++++--------- ..._conformance_layer_parser_denylist.inl.hpp | 2 - 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/modules/dnn/src/layers/gemm_layer.cpp b/modules/dnn/src/layers/gemm_layer.cpp index bbbb10d2df..ac0914c2c2 100644 --- a/modules/dnn/src/layers/gemm_layer.cpp +++ b/modules/dnn/src/layers/gemm_layer.cpp @@ -289,48 +289,54 @@ public: virtual Ptr initNgraph(const std::vector >& inputs, const std::vector >& nodes) CV_OVERRIDE { - auto ieInpNode = nodes[0].dynamicCast()->node; - std::shared_ptr matmul; + ov::Output nodeA = nodes[0].dynamicCast()->node; + ov::Output nodeB; + if (const_B) + nodeB = std::make_shared(ov::element::f32, getShape(blobs[0]), blobs[0].data); + else + nodeB = nodes[1].dynamicCast()->node; - if (nodes.size() == 2) + int flatten_axis = nodeA.get_shape().size() - nodeB.get_shape().size(); + if (flatten_axis > 0) { + std::vector shape(1 + flatten_axis, 0); + shape[shape.size() - 1] = -1; + nodeA = std::make_shared( + nodeA, + std::make_shared(ov::element::i32, ov::Shape{shape.size()}, shape.data()), + true); + } + + std::shared_ptr nodeAB = std::make_shared(nodeA, nodeB, trans_a, trans_b); + if (alpha != 1.0f) { - auto& inp2 = nodes[1].dynamicCast()->node; - matmul = std::make_shared(ieInpNode, inp2, trans_a, trans_b); + nodeAB = std::make_shared( + nodeAB, + std::make_shared(ov::element::f32, ov::Shape{1}, &alpha)); + } + + if (!have_bias) + return Ptr(new InfEngineNgraphNode(nodeAB)); + + ov::Output nodeC; + if (const_C) + { + auto shape_C = blobs.back().total() == blobs.back().size[0] ? ov::Shape{blobs.back().total()} : getShape(blobs.back()); + nodeC = std::make_shared(ov::element::f32, shape_C, blobs.back().data); } else { - std::shared_ptr ieWeights = std::make_shared(ov::element::f32, getShape(blobs[0]), blobs[0].data); - - int flatten_axis = ieInpNode.get_shape().size() - ieWeights->get_shape().size(); - if (flatten_axis > 0) { - std::vector shape(1 + flatten_axis, 0); - shape[shape.size() - 1] = -1; - ieInpNode = std::make_shared( - ieInpNode, - std::make_shared(ov::element::i32, ov::Shape{shape.size()}, shape.data()), - true - ); - } - matmul = std::make_shared(ieInpNode, ieWeights, trans_a, trans_b); - } - if (alpha != 1.0f) { - matmul = std::make_shared(matmul, - std::make_shared(ov::element::f32, ov::Shape{1}, &alpha) - ); + nodeC = nodes.back().dynamicCast()->node; } - if (have_bias && const_C) { - Mat bias = blobs.back(); - auto shape = bias.total() == bias.size[0] ? ov::Shape{bias.total()} : getShape(bias); - std::shared_ptr bias_node = std::make_shared(ov::element::f32, shape, bias.data); - if (beta != 1.0f) { - bias_node = std::make_shared(bias_node, - std::make_shared(ov::element::f32, ov::Shape{1}, &beta) - ); - } - matmul = std::make_shared(matmul, bias_node, ov::op::AutoBroadcastType::NUMPY); + if (beta != 1.0f) + { + nodeC = std::make_shared( + nodeC, + std::make_shared(ov::element::f32, ov::Shape{1}, &beta)); } - return Ptr(new InfEngineNgraphNode(matmul)); + + auto nodeGemm = std::make_shared(nodeAB, nodeC, ov::op::AutoBroadcastType::NUMPY); + return Ptr(new InfEngineNgraphNode(nodeGemm)); } #endif // HAVE_DNN_NGRAPH diff --git a/modules/dnn/test/test_onnx_conformance_layer_parser_denylist.inl.hpp b/modules/dnn/test/test_onnx_conformance_layer_parser_denylist.inl.hpp index 68f49e5fa4..cb008e9670 100644 --- a/modules/dnn/test/test_onnx_conformance_layer_parser_denylist.inl.hpp +++ b/modules/dnn/test/test_onnx_conformance_layer_parser_denylist.inl.hpp @@ -121,8 +121,6 @@ "test_gemm_all_attributes", "test_gemm_alpha", "test_gemm_beta", -"test_gemm_default_matrix_bias", -"test_gemm_default_no_bias", "test_gemm_default_scalar_bias", "test_gemm_default_single_elem_vector_bias", "test_gemm_default_vector_bias",