From 0e36cafcf4ec80988955162bcdbdb35eeae7a5a8 Mon Sep 17 00:00:00 2001 From: Yang Guanyuhan <1523543870@qq.com> Date: Tue, 28 Jul 2026 00:13:40 +0800 Subject: [PATCH] dnn: preserve Cast semantics after ONNX Gather --- .../dnn/src/onnx/onnx_graph_simplifier.cpp | 69 ------------------- modules/dnn/test/test_layers.cpp | 28 ++++++++ 2 files changed, 28 insertions(+), 69 deletions(-) diff --git a/modules/dnn/src/onnx/onnx_graph_simplifier.cpp b/modules/dnn/src/onnx/onnx_graph_simplifier.cpp index 3fc8309110..c359c32751 100644 --- a/modules/dnn/src/onnx/onnx_graph_simplifier.cpp +++ b/modules/dnn/src/onnx/onnx_graph_simplifier.cpp @@ -1402,74 +1402,6 @@ public: } }; -class GatherCastSubgraph : public Subgraph -{ -public: - GatherCastSubgraph() - { - int input = addNodeToMatch(""); - int index = addNodeToMatch("Constant"); - gather = addNodeToMatch("Gather", input, index); - cast = addNodeToMatch("Cast", gather); - setFusedNode("Gather", input, index); - } - - virtual bool match(const Ptr& net, int nodeId, - std::vector& matchedNodesIds) CV_OVERRIDE - { - bool retVal = Subgraph::match(net, nodeId, matchedNodesIds); - size_t matchedNodesNum = matchedNodesIds.size(); - // Now we check if merging can be made for these Gather and Cast nodes - if (!retVal || matchedNodesNum < 2) - return retVal; - else { - int nodeToMatch = matchedNodesIds[cast]; - const Ptr node = net->getNode(nodeToMatch); - if (node->getType() == "Cast") { - int inpNodeId = matchedNodesIds[gather]; - const Ptr inpNode = net->getNode(inpNodeId); - if (inpNode->getType() == "Gather") { - int numNodes = net->getNumNodes(); - std::string inpNodeName = node->getInputName(0); - for (int i = 0; i < numNodes; ++i) { - const Ptr node_to_check = net->getNode(i); - int numInp = node_to_check->getNumInputs(); - for (int inp = 0; inp < numInp; ++inp) { - if (i != nodeToMatch && inpNodeName == node_to_check->getInputName(inp)) { - // Another node has the same input node, so it cannot be merged. - return false; - } - } - } - // extract axis from original Gather node - axis = 0; - opencv_onnx::NodeProto* origGatherNode = - inpNode.dynamicCast()->node; - for (int i = 0; i < origGatherNode->attribute_size(); i++) { - opencv_onnx::AttributeProto attr = origGatherNode->attribute(i); - if (attr.name() == "axis") - axis = attr.i(); - } - } - } - } - return retVal; - } - - virtual void finalize(const Ptr& net, - const Ptr& fusedNode, - std::vector >& /*inputs*/) CV_OVERRIDE - { - opencv_onnx::NodeProto* node = fusedNode.dynamicCast()->node; - opencv_onnx::AttributeProto* new_attr = node->add_attribute(); - new_attr->set_name("axis"); - new_attr->set_i(axis); - } - -private: - int cast, gather, axis; -}; - /* Constant folding shape for Expand. Before fusion: @@ -1922,7 +1854,6 @@ void simplifySubgraphs(opencv_onnx::GraphProto& net, const std::string& basePath subgraphs.push_back(makePtr()); subgraphs.push_back(makePtr()); subgraphs.push_back(makePtr()); - subgraphs.push_back(makePtr()); subgraphs.push_back(makePtr()); subgraphs.push_back(makePtr()); subgraphs.push_back(makePtr()); diff --git a/modules/dnn/test/test_layers.cpp b/modules/dnn/test/test_layers.cpp index 7c8968d66e..e5a098c1b1 100644 --- a/modules/dnn/test/test_layers.cpp +++ b/modules/dnn/test/test_layers.cpp @@ -2347,6 +2347,34 @@ TEST(Layer_Size, onnx_0d_scalar) EXPECT_EQ(outs[0].at(0), 1); } +TEST(Layer_GatherCast, preserves_float_cast) +{ + auto engine_forced = static_cast( + cv::utils::getConfigurationParameterSizeT("OPENCV_FORCE_DNN_ENGINE", cv::dnn::ENGINE_AUTO)); + if (engine_forced == cv::dnn::ENGINE_ORT) + { + applyTestTag(CV_TEST_TAG_DNN_SKIP_PARSER); + return; + } + + const std::string modelname = findDataFile("dnn/onnx/models/gather_cast_float.onnx", true); + Net net = readNetFromONNX(modelname, ENGINE_OPENCV); + ASSERT_FALSE(net.empty()); + ASSERT_TRUE(net.getMainGraph()); + + int inputShape[] = {2, 3}; + Mat input(2, inputShape, CV_32F, Scalar(0)); + net.setInput(input, "input"); + + std::vector outputs; + net.forward(outputs, std::vector{"output"}); + + ASSERT_EQ(outputs.size(), 1u); + EXPECT_EQ(outputs[0].total(), (size_t)1); + EXPECT_EQ(outputs[0].type(), CV_32F); + EXPECT_FLOAT_EQ(outputs[0].ptr()[0], 2.f); +} + TEST(ConvolutionWinograd, Accuracy) { Mat weights({2, 1, 3, 3}, CV_32F);