mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 23:33:05 +04:00
62930a207b
dnn: skip Conv2Int8 fusion for grouped convs with Kg<8 (#28798) #28920 OpenCV Extra: https://github.com/opencv/opencv_extra/pull/1360 - [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 --- Fixes #28798. The YuNet 2023mar int8 model from opencv_zoo doesn't detect anything on 5.x. With `--score_threshold 0.05` the detector still returns no boxes, so it's not just a confidence drop — the network output is broken. After dumping intermediate tensors and comparing against onnxruntime, the `obj_*` branches collapse to ~0 (saturated int8 `-128`), and the `cls_*` branches saturate the other way. Final score is `cls * obj` so nothing ever crosses threshold. The cause is in `Conv2Int8`'s VNNI kernel. It processes `K0 = 8` output channels per SIMD iteration and writes them as one `K0`-wide block to `out + (n*K1 + k1)*planesize` with `k1 = k_base / K0`. When `ngroups > 1` and `Kg = K/ngroups < K0`, consecutive groups share the same `k1` slot and overwrite each other — only the last group's result survives. YuNet has six `1x1x3x3` depthwise conv heads (`Kg = 1`), which is exactly this case. The unfused `DequantizeLinear → Conv2 → QuantizeLinear` path is fine. The minimal fix here is to skip the rewrite to `Conv2Int8` when `Kg < 8` so we fall back to the float path. A proper depthwise int8 kernel can be added later as a separate optimization. Verified with `samples/dnn/face_detect.py` on Lena: Before: AssertionError: Cannot find a face in samples/data/lena.jpg After: Face 0, top-left coordinates: (204, 187), box width: 149, box height 212, score: 0.89 Cross-check vs onnxruntime: `cls_8` mean `0.673` (was `0.93`, ORT `0.673`), `obj_8` max `0.0039` (was `0`, ORT `0.0039`). The regression test is a single 16-group depthwise `QLinearConv` with non-zero `x_zp`, added to `Quantized_Convolution`. Test data is in opencv_extra on the matching branch (~9 KB total). <img width="1864" height="1060" alt="image" src="https://github.com/user-attachments/assets/a1b15c64-6b84-42b1-86a4-1d55474cb38c" />