From 5c02d32ccac16885ee537ff3a10095b149a6e810 Mon Sep 17 00:00:00 2001 From: Dmitry Kurtaev Date: Thu, 13 Nov 2025 14:19:46 +0800 Subject: [PATCH] Merge pull request #28000 from dkurt:d.kurtaev:reset_winograd_impl ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request resolves https://github.com/opencv/opencv/issues/27580 - [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/convolution_layer.cpp | 11 +++-- modules/dnn/test/test_layers.cpp | 43 ++++++++++++++++++++ 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/modules/dnn/src/layers/convolution_layer.cpp b/modules/dnn/src/layers/convolution_layer.cpp index 13069f53bc..c33eda428e 100644 --- a/modules/dnn/src/layers/convolution_layer.cpp +++ b/modules/dnn/src/layers/convolution_layer.cpp @@ -253,6 +253,7 @@ public: Ptr activ; Ptr fastConvImpl; + bool canUseWinograd = false; #ifdef HAVE_OPENCL Ptr > convolutionOp; @@ -448,6 +449,13 @@ public: #ifdef HAVE_OPENCL convolutionOp.release(); #endif + + // Winograd only works when input h and w >= 12. + canUseWinograd = useWinograd && inputs[0].dims == 4 && inputs[0].size[2] >= 12 && inputs[0].size[3] >= 12; + if (fastConvImpl && (fastConvImpl->conv_type == CONV_TYPE_WINOGRAD3X3) ^ canUseWinograd) + { + fastConvImpl.reset(); + } } bool setActivation(const Ptr& layer) CV_OVERRIDE @@ -1292,9 +1300,6 @@ public: int K = outputs[0].size[1]; int C = inputs[0].size[1]; - // Winograd only works when input h and w >= 12. - bool canUseWinograd = useWinograd && conv_dim == CONV_2D && inputs[0].size[2] >= 12 && inputs[0].size[3] >= 12; - CV_Assert(outputs[0].size[1] % ngroups == 0); fastConvImpl = initFastConv(weightsMat, &biasvec[0], ngroups, K, C, kernel_size, strides, dilations, pads_begin, pads_end, conv_dim, diff --git a/modules/dnn/test/test_layers.cpp b/modules/dnn/test/test_layers.cpp index 48c968fb6a..9da907758c 100644 --- a/modules/dnn/test/test_layers.cpp +++ b/modules/dnn/test/test_layers.cpp @@ -2788,4 +2788,47 @@ INSTANTIATE_TEST_CASE_P(TestLayerFusion, ConvolutionActivationEltwiseFusion, Com TestLayerFusion::dnnBackendsAndTargetsForFusionTests() )); +TEST(ConvolutionWinograd, Accuracy) +{ + Mat weights({2, 1, 3, 3}, CV_32F); + randn(weights, 0, 1); + + // Check convolution can switch between implementations on changed shape. + auto getNet = [&]() { + Net net; + LayerParams lp; + lp.name = "conv"; + lp.type = "Convolution"; + lp.set("kernel_size", 3); + lp.set("num_output", 2); + lp.set("pad", 0); + lp.set("stride", 1); + lp.set("bias_term", false); + + lp.blobs.push_back(weights); + net.addLayerToPrev(lp.name, lp.type, lp); + return net; + }; + + Mat inpSmall({1, 1, 5, 5}, CV_32F); + Mat inpLarge({1, 1, 64, 64}, CV_32F); + randn(inpSmall, 0, 1); + randn(inpLarge, 0, 1); + + Net net1 = getNet(); + Net net2 = getNet(); + net1.setInput(inpSmall); + net2.setInput(inpLarge); + Mat refSmall = net1.forward(); + Mat refLarge = net2.forward(); + + net1.setInput(inpLarge); + net2.setInput(inpSmall); + Mat outLarge = net1.forward(); + Mat outSmall = net2.forward(); + + normAssert(outSmall, refSmall, "Small input after large", 0.0, 0.0); + normAssert(outLarge, refLarge, "Large input after small", 0.0, 0.0); +} + }} // namespace