先看一个我实际遇到过的画面:货架上四十瓶洗发水码得整整齐齐,算法输出的框一大半都叠在一个瓶子上,另一大半悬在两个瓶子中间。

我当时的第一反应是“模型太笨”。直到后来把中间结果可视化,我才发现模型其实看到了每一个瓶子——真正把它们“杀掉”的,是最后一步去重。
这一步叫 NMS(Non-Maximum Suppression)。它在稀疏场景里干得很好,但在人群、停车场、超市货架这种大量重叠的场景里,是灾难性的。
NMS 在密集场景下到底错在哪
先理解 NMS 在做什么。物体检测器会一次性输出成百上千个候选框,它们往往重复围绕同一个目标。NMS 的目的是:只保留最好的那个,其余删除。
- 把所有候选框按置信度从高到低排序;
- 取出分数最高的候选框,保留;
- 计算它和剩余候选框的 IoU,重叠度大于阈值(常见 0.5)的框直接删除;
- 重复,直到没有候选框。
这个机制有一个致命预设:IoU 高=同一个物体。但在密集场景里,“两个不同物体被NMS当成同一个”,是因为它们真实的重叠程度已经超过了 IoU 阈值。后面那个分数稍低一点的框,就这样被删掉了。
NMS 的问题不是压不住重复,而是把“重叠的真框”也当成“重复的假框”。
人群场景最直观:两个人并排走、互相挡住半个身子,其中一个候选框分数稍低就被删掉——明明是两个行人。停车场同理,车头紧贴的两辆车会被合并成一个框。
我原本以为换更强的模型就能解决,后来发现不是
我最早带着“数据问题”的思路去调模型:加深骨干、换大分辨率、洗数据。训练损失降了,val 指标却像卡住了。
直到把一个近景密集的样本拎出来看中间过程。网络输出的候选框其实分布得很健康——每个目标都有一个框在盯着。但 NMS 执行完之后,框数量骤减。那个瞬间我就懂了:模型已经“看见”了,是后处理把它“捂死”了。
这也是我在后来看 Soft-NMS 论文时才真正理解:检测器在拥挤场景下的召回率低,很多时候问题不在检测器,而在 NMS 这一刀切得太干净。Soft-NMS 不直接删除,而是按重叠程度给分数打折扣——一个只改后处理的工作,就能让检测结果显著变好。当时我才意识到:后处理不是“题外话”,它就是算法的一部分。
三条路线:改NMS、绕开NMS、抛弃候选框
密集检测的求解思路从这三个方向进化。
| 路线 | 核心思想 | 还需要NMS吗 | 密集场景的表现 | 代表工作 |
|---|---|---|---|---|
| 改进NMS | 把删除改为衰减,或根据密度动态调整阈值 | 仍需要,但更温和 | 提升明显,但天花板仍在 | Soft-NMS、Adaptive NMS |
| 密集预测(anchor-free) | 直接预测中心点或边界距离,不再产生冗余框 | CenterNet不需要,FCOS仍少量 | 对重叠目标相对友好,小目标仍有挑战 | CenterNet、FCOS |
| 集合预测(Transformer) | 一次预测固定数量的结果,用二分匹配配对GT | 不需要(甚至去掉NMS效果更好) | 结构上最优雅,训练敏感,密集小目标需要额外设计 | DETR |
三条路线各有取舍。改进 NMS 兼容旧模型,但本质上绕不过 IoU 先验;CenterNet 将检测变成“找峰值”,用热力图中心点代替框对多目标排序;FCOS 用逐像素预测定位,再用 centerness 打分,低质量框自然被压下去。
DETR 的做法最激进:它把目标检测定义成集合预测——网络直接输出 100 个结果,用 Hungarian 算法配对 GT,让模型自己学会输出一套不重复的结果,从目标函数上就不需要 NMS。我第一次看这个设计时想:目标检测居然还能这样定义。这也让我重新理解“后处理”和“模型”之间并非不可分离。
但这不是说 DETR 没有代价。它在 COCO 上让人眼前一亮,但在密集人群上容易表现出漏检和小目标不稳定的问题,后来很多工作其实是在给它加“先验”——比如把 anchor 重新请回来,把 DETR 变成更容易收敛的训练课题。这说明集合预测方向很自然,但还没到“万能”的程度。
为什么大家都拿人群、停车场和超市货架来“折磨”检测器
根本原因只有一个:这些场景里“重叠”不是罕见异常,而是数据常态。
CrowdHuman 数据集就专门聚焦拥挤人群,每张图里行人与行人互相遮挡频繁,检测器受遮挡影响极大。SKU110K 则是超市货架的密集商品,同类商品并排放置,大量目标紧密排列。目标检测在这些数据上的表现,才贴近真实世界。
有一个简单的判断:如果你的测试图里两个物体 IoU 超过 0.5 是常态,检测器的真实可用性往往会比 mAP 显示出来的差得多。指标好看不代表场景能过,这就是为什么做零售货架盘点、人群计数的人,都要自建更“密”的训练集。
还有一个隐藏战场:正样本分配
NMS 只是最后一道关卡,训练时还有一个问题几乎同样致命:正样本分配。
基于 anchor 的检测器会预先铺上几万个框,训练时要决定每个 anchor 负责预测哪个 GT。规则通常是算 IoU,IoU 最大的归哪个。在重叠场景里,这个分配会遇到歧义:一个 anchor 和两个人 IoU 都超过 0.6,它该学成“左半身”还是“右半身”?同一时刻,另一个 anchor 也面对完全相同的两个 GT。于是分类分支学到的标签本身就是抖动的。
所以当你看到一份密集数据集上的 miss rate 居高不下,甚至不需要指责模型差——它的训练信号从源头就不一致。近年的 ATSS、PAA 等方法,本质上是在改进这种分配原则:根据统计自适应决定正负样本,让“一个 anchor 只认一个 GT”这件事尽量稳定。
这条线给了我一个更深的理解:密集检测不只是后处理问题,而是一整条从匹配到打分再到抑制的链路在拥挤情况下同时失灵。
几个最常见的误解
“把 NMS 阈值调大,重叠的真框不就能幸存了吗?”
不行。NMS 阈值本质是“容忍重复度”的开关。调大它,两个不同但重叠的物体确实能同时保留,但同一个物体的重复框也会被放行,假阳性暴涨。如果你还要求低误检,这个方向就是死路一条。
“既然 NMS 有罪,干脆全部保留不行吗?”
把 NMS 整个删掉会让一个目标被输出三四个框,mAP 会按重复预测扣分,业务方也无法接受。所以关键是“在保留重叠目标的同时,把同一个目标的多余框消除”——这正是 Soft-NMS、DETR 这些工作存在的意义。
“换更强的骨干网络能解决吗?”
骨干增强对小目标、模糊边缘有提升,对密集场景有帮助,但后处理瓶颈依然在。网络能力越强,它反而越完整地保留重叠目标,最后一步 NMS 的误删也越“明显”。
所以密集检测真正难在哪
现在可以回答开头的问题。密集场景检测的真正难点,不是“模型看不到”,而是“模型看到了,却不知道该保留哪个实例”。
重叠物体意味着边界信息是一团绞在一起的线,检测器很难用一个候选框表达两个实例。NMS 用“重复”来解释重叠,代价是把真框判死刑。中心点方法绕开了框的排序,但对边界细节和拥挤程度更敏感。集合预测放大了表达能力,但训练不稳定。
目前真正可落地的工程方案仍然得拼装:一个主检测网络,一个精细化后处理,再加一套针对密集场景的数据增强策略。密集场景的边界取决于你的场景密度上限。如果你做自动驾驶,行人肩并肩的概率不算高;但停车场的早晨、超市的促销堆头、人群聚集的安检口,会不停提醒你:mAP 不是真正的终点,场景才是。
原创文章,作者:guanweilu,如若转载,请注明出处:https://guanweilu.cn/article/2364.html