4. NMS 阈值选择策略:IoU 阈值对检测结果的影响
聊到 NMS,最绕不开的就是那个 IoU 阈值。很多新手觉得这就是个固定值,设个 0.5 万事大吉。嗯,我刚开始也这么干过,结果被现实狠狠教育了一顿。
说白了,IoU 阈值决定了「两个框到底算不算重复」。阈值设高了,框就留得多,容易产生误检;设低了,框被砍得太狠,漏检就来了。这中间的平衡,才是调优的精髓。
核心观点: IoU 阈值没有万能值,它必须跟你的任务、数据、模型一起调。
4.1 IoU 阈值的工作原理
先简单回顾一下。NMS 的流程是这样的:
- 把所有检测框按置信度从高到低排序。
- 选置信度最高的框,保留它。
- 计算这个框跟剩下所有框的 IoU。
- 如果 IoU 大于你设定的阈值,就把那个框干掉。
- 重复,直到所有框都被处理过。
你看,阈值就是那个「生杀大权」的开关。阈值越大,容忍度越高,框越不容易被干掉。
我的习惯: 我一般先看数据集的标注特点。如果目标密集且相互遮挡,我会把阈值往高调;如果目标稀疏且独立,阈值可以低一些。
4.2 不同 IoU 阈值的效果对比
我在一个行人检测项目里做过对比实验,结果非常直观。这里用表格展示一下:
| IoU 阈值 | mAP@0.5 | mAP@0.75 | 误检率 | 漏检率 | 典型场景 |
|---|---|---|---|---|---|
| 0.3 | 72.1% | 45.3% | 低 | 高 | 稀疏目标、高精度要求 |
| 0.5 | 78.6% | 52.1% | 中 | 中 | 通用场景、默认值 |
| 0.7 | 81.2% | 56.8% | 高 | 低 | 密集遮挡、小目标 |
| 0.9 | 76.5% | 48.9% | 极高 | 极低 | 几乎不抑制、易误检 |
看到没?阈值从 0.3 升到 0.7,mAP 在涨,但误检率也在涨。为什么会这样?因为阈值高了,很多本该被抑制的重复框留了下来,它们虽然跟真实框重叠度高,但位置有偏差,拉低了定位精度。
我曾经踩过的坑: 在一个密集人群计数任务里,我把 IoU 阈值设到 0.8,结果一个行人被检测出五六个框,误检率直接爆炸。后来才发现,密集场景下阈值不能超过 0.65。
4.3 如何选择合适的阈值
选阈值不是拍脑袋,得看你的评价指标和业务需求。我总结了一套选择策略:
4.3.1 根据评价指标选
- 如果看重 mAP@0.5: 阈值可以设高一点(0.6-0.7),因为 mAP@0.5 对定位精度要求不高,多留几个框反而能提高召回。
- 如果看重 mAP@0.75: 阈值得设低一点(0.4-0.5),因为高 IoU 要求框必须贴得准,重复框会拉低分数。
- 如果看重 F1-Score: 建议在验证集上扫一遍阈值,从 0.3 到 0.8,步长 0.05,选 F1 最高的那个。
4.3.2 根据目标密度选
- 稀疏场景(每张图 1-5 个目标): 阈值 0.4-0.5 就够了,框少,不容易误抑制。
- 中等密度(每张图 5-20 个目标): 阈值 0.5-0.6,这是最常用的区间。
- 密集场景(每张图 20+ 个目标): 阈值 0.6-0.7,甚至更高。但要注意,阈值超过 0.7 后误检率会飙升,需要配合置信度阈值一起调。
4.3.3 根据模型能力选
- 高精度模型(mAP > 80%): 框的质量高,可以放心用低阈值(0.4-0.5),不会漏检。
- 低精度模型(mAP < 60%): 框的质量差,建议用高阈值(0.6-0.7),宁可多留几个框,也别漏掉目标。
我的建议: 别只盯着一个阈值。在实际部署中,我会在验证集上跑一个阈值扫描,画出 mAP 随阈值变化的曲线,选那个「拐点」——也就是 mAP 开始下降前的那个值。
4.4 阈值选择的完整流程
下面这张图是我自己总结的阈值选择流程,每次调参我都会走一遍:
4.5 实际调参案例
拿我最近做的一个工业缺陷检测项目来说。检测目标是 PCB 板上的微小焊点,每张图有 30-50 个目标,相互之间挨得很近。
一开始我用默认的 0.5 阈值,结果漏检率高达 15%。后来我把阈值调到 0.65,漏检率降到 5%,但误检率从 2% 升到了 8%。
怎么办?我做了两件事:
- 提高置信度阈值: 从 0.25 提到 0.4,把那些低置信度的误检框过滤掉。
- 加了一个小 trick: 对 IoU 超过 0.8 的框,直接取置信度最高的那个,其他的全部干掉。这相当于在 NMS 之后又做了一层硬过滤。
最终结果:漏检率 4%,误检率 3%,F1 从 0.82 提升到 0.91。
总结一下: IoU 阈值不是孤立的,它必须跟置信度阈值、模型能力、数据特点一起考虑。没有银弹,只有反复实验。
4.6 常见误区
- 误区一: 阈值越高越好。错!阈值高了,误检率会失控。
- 误区二: 所有类别用同一个阈值。错!不同类别的目标大小、密度不同,应该分开调。
- 误区三: 只在训练集上调。错!一定要在验证集上做阈值扫描,训练集上的结果没有参考价值。
我曾经犯过的错: 在一个多类别检测任务里,我把所有类别的 IoU 阈值都设成 0.6。结果「汽车」类表现很好,但「行人」类漏检严重。后来才发现,行人目标小且密集,需要更高的阈值。从那以后,我都是按类别单独调阈值。
好了,这一章的内容就到这里。阈值选择是个细活,多跑几次实验,多看看验证集上的可视化结果,你慢慢就会找到感觉。