LOADING
4178 words
21 minutes
目标检测简史

发展历程#

第一阶段:R-CNN —— “蛮力穷举的开端”#

核心痛点:由于全连接层(FC)需要固定输入,导致必须对图像进行破坏性缩放;且 2000 次 CNN 计算极其冗余。

1. 工作流程与维度变化#

  1. 输入图像:一张任意大小的图。
    • Dim: (1,3,H,W)(1, 3, H, W)
  2. 生成候选框 (Proposal Generation)
    • 使用 Selective Search (CPU) 算法。
    • 得到约 2000 个候选框坐标 (x,y,w,h)(x, y, w, h)
    • 注:这时候还没进神经网络。
  3. 图像变形 (Warping) —— 你的疑问点
    • 动作:将原图中这 2000 个不同大小的框抠出来,强制缩放成固定大小(如 227×227227 \times 227)。
    • 后果:物体变形,导致特征提取不准。
    • Tensor Dim: 变成了 (2000,3,227,227)(2000, 3, 227, 227) 的一堆小图片。
  4. 特征提取 (Backbone)
    • 动作:把这 2000 张图**依次(或 Batch 并行)**送入 CNN。
    • 计算量:跑了 2000 次卷积网络。(极慢的根源)
    • Tensor Dim: 得到 (2000,4096)(2000, 4096) 的特征向量。
  5. 分类与回归
    • 使用 SVM 分类,使用线性回归器微调坐标。

总结:这一阶段的 BBox 回归和分类是分开的,不是端到端。


第二阶段:Fast R-CNN —— “共享特征的飞跃”#

核心改进:引入 RoI Pooling,让 CNN 只跑一次;解决了变形问题。

1. 共享特征提取 (Backbone)#

  • 动作:整张图进 CNN,一次性得到特征图。
  • Tensor Dim: (1,3,H,W)CNN(1,512,H/16,W/16)(1, 3, H, W) \xrightarrow{CNN} (1, 512, H/16, W/16)
  • 关键点:这里包含了全图的上下文信息(Context),虽然最后只看局部,但特征是全局感受野算出来的(回应了你关于”视野”的疑问)。

2. 候选框映射 (RoI Projection)#

  • 动作:依然用 Selective Search 在原图生成 2000 个框。
  • 映射:将坐标除以步长(Stride=16)。
    • x=x/16x' = x/16(这里会有量化误差,即坐标不准)。
  • 数据结构: 一个列表 [roi_1, roi_2, ..., roi_2000]

3. RoI Pooling —— “万能适配器”#

  • 输入
    1. 特征图 (1,512,H/16,W/16)(1, 512, H/16, W/16)
    2. 2000 个大小不一、长宽比各异 (hw)(h \neq w) 的 RoI。
  • 你的疑问:HWH \neq W 怎么办?
    • 动作:使用自适应网格(Adaptive Grid)。如果 RoI 是 10×510 \times 5,就按比例划分为 7×77 \times 7 的网格。
  • 你的疑问:维度怎么变?是一次次送吗?
    • 动作:逻辑上是串行,实现上是并行
    • RoI Pooling 层会将 2000 个区域提取并堆叠。
    • Tensor Dim: (2000,512,7,7)(2000, 512, 7, 7)
    • 注意:这里把 RoI 的数量 NN 合并到了 Batch 维度,变成了 (N,C,H,W)(N, C, H, W)

4. 分类与回归 (Head)#

  • 动作:展平 (Flatten) 后送入全连接层。
  • Tensor Dim: (2000,512×7×7)FC(2000,4096)(2000, 512 \times 7 \times 7) \xrightarrow{FC} (2000, 4096)
  • 输出分支
    1. Cls: (2000,Num_Classes+1)(2000, \text{Num\_Classes} + 1) —— 概率。
    2. Reg: (2000,4)(2000, 4) —— 坐标偏移。
  • 你的疑问:回归真值?
    • 训练时,只有和 GT IoU > 0.5 的 RoI 才算回归损失,背景忽略。

第三阶段:Faster R-CNN —— “完全端到端 (End-to-End)”#

核心改进:引入 RPNAnchor,彻底抛弃 CPU 上的 Selective Search。

1. 特征提取 (Backbone)#

  • 同上,得到特征图 (1,512,H/16,W/16)(1, 512, H/16, W/16)

2. RPN (Region Proposal Network) —— “猜框网络”#

这是新增的独立分支。

  • Anchor 生成:在特征图每个像素点生成 9 个 Anchor(3尺寸 ×\times 3比例)。
    • 总 Anchor 数 (H/16)×(W/16)×920,000\approx (H/16) \times (W/16) \times 9 \approx 20,000 个。
  • 正负样本分配 (Label Assignment) —— 你的核心疑问
    • 计算所有 Anchor 与 GT 的 IoU
    • 正样本:IoU > 0.7(或者是最大的那个)。
    • 负样本:IoU < 0.3。
    • 忽略:中间态。
  • Loss 计算
    • Cls Loss:正负样本都算(教它认背景)。
    • Reg Loss只算正样本(如你所悟,只有正样本有回归真值)。
  • 生成 Proposal
    • 网络输出预测偏移量 \rightarrow 修正 Anchor \rightarrow 得到粗略框。
    • NMS (非极大值抑制):从 20,000 个框里剔除重叠的,选出前 2000 个。
    • 数据流出: 2000 个 Proposals

3. RoI Pooling#

  • 输入:特征图 + 2000 个 Proposals (来自 RPN)。
  • 动作:和 Fast R-CNN 一样,统统变成 7×77 \times 7
  • Tensor Dim: (2000,512,7,7)(2000, 512, 7, 7)

4. R-CNN Head (最终精修)#

  • 输入(2000,512,7,7)(2000, 512, 7, 7)
  • 动作:再次经过 FC 层。
  • 目的
    1. 精细分类:RPN 只知道是”物体”,Head 要知道是”猫”。
    2. 二次回归:在 RPN 粗略调整的基础上,进行像素级微调。

维度与流程总结表 (Cheatsheet)#

假设输入图片 800×800800 \times 800,Backbone 是 VGG16 (Stride=16),Batch Size=1。

步骤涉及网络模块输入 Tensor 维度输出 Tensor 维度关键动作/术语你的疑问解答
1. 提特征Backbone(1,3,800,800)(1, 3, 800, 800)(1,512,50,50)(1, 512, 50, 50)卷积/下采样全局感受野在此形成。
2. 撒网RPN (Anchor)/~22500 个 Anchors生成基准框预设的,不参与计算,只做参考。
3. 初筛RPN (Pred)(1,512,50,50)(1, 512, 50, 50)Class: (1,18,50,50)(1, 18, 50, 50) Reg: (1,36,50,50)(1, 36, 50, 50)IoU分配 正负样本训练时只对正样本算回归 Loss。
4. 建议RPN (Post)上面的预测结果2000 个 Proposals (List)NMS去重,选出最好的 2000 个。
5. 统一RoI PoolingFeature Map + 2000 Proposals(2000,512,7,7)(2000, 512, 7, 7)Mapping Pooling并行处理,把 NN 融合进 Batch 维度。 处理 HWH \neq W
6. 展平Flatten(2000,512,7,7)(2000, 512, 7, 7)(2000,25088)(2000, 25088)Reshape准备喂给全连接层。
7. 结果FC Head(2000,25088)(2000, 25088)Cls: (2000,C+1)(2000, C+1) Reg: (2000,4)(2000, 4)精修对这 2000 个框做最后的裁决。

优缺点与发展评价#

  • R-CNN:
    • 优点:把深度学习引入检测,精度大增。
    • 缺点:慢(2000次CNN),缩放导致变形。
  • Fast R-CNN:
    • 优点:共享特征图(快),RoI Pooling 解决变形。
    • 缺点:候选框生成(Selective Search)还在 CPU 上,是瓶颈。
  • Faster R-CNN:
    • 优点:RPN 替代 CPU 算法,真正端到端,精度高。
    • 缺点:对于小物体(特征图下采样导致消失)效果一般;速度依然无法满足 30FPS 实时性(因为还有两阶段)。

下一步发展(给研究生的指引)

  1. 嫌慢? \rightarrow YOLO / SSD (去掉 RPN 和 RoI Pooling,直接在 Feature Map 上回归)。
  2. 嫌小物体不准? \rightarrow FPN (Feature Pyramid Networks) (融合浅层和深层特征)。
  3. 嫌 RoI Pooling 使得像素不对齐? \rightarrow Mask R-CNN (RoI Align) (用双线性插值替代取整)。

评价指标#

第一层:基本判定单位 —— IoU 与 TP/FP/FN#

在分类任务中,预测结果只有”对/错”。但在目标检测中,预测结果是一个框,我们需要一个量化的阈值来判断这个框到底算不算”对”。

这个阈值通常是 IoU (Intersection over Union)

1. IoU (交并比)#

IoU=Area of OverlapArea of UnionIoU = \frac{\text{Area of Overlap}}{\text{Area of Union}}

2. 状态定义 (TP, FP, FN)#

假设我们设定阈值 IoU Threshold = 0.5

  • TP (True Positive / 真正例)
    • 预测框与真值框 (GT) 的 IoU0.5IoU \ge 0.5
    • 类别分类正确。
    • 注意:对于同一个 GT,只能有一个预测框算 TP。如果模型对同一个物体预测了两个高分框(没被 NMS 滤掉),第一个是 TP,第二个就是 FP(重复检测)。
  • FP (False Positive / 假正例)
    • 预测框与 GT 的 IoU<0.5IoU < 0.5(位置不准)。
    • 或者是对背景的误检(无中生有)。
    • 或者是重复检测(Duplicate)。
  • FN (False Negative / 假负例)
    • 图片里有一个 GT,但模型没有预测出任何与它 IoU 合格的框。
    • 或者预测出来了,但置信度太低被过滤掉了。
  • TN (True Negative / 真负例)
    • 在目标检测中不讨论 TN。因为图片中”背景”是无限多的,你没把背景框出来是理所当然的,无法计算。

第二层:统计指标 —— Precision (P) 与 Recall (R)#

有了 TP, FP, FN,我们就能算两个核心指标。

1. Precision (查准率)#

含义“你预测出来的这些框里,有多少是靠谱的?”

Precision=TPTP+FP=抓对的所有抓到的Precision = \frac{TP}{TP + FP} = \frac{\text{抓对的}}{\text{所有抓到的}}

2. Recall (查全率)#

含义“所有真实的物体里,你找出来了多少?”

Recall=TPTP+FN=抓对的所有该抓的Recall = \frac{TP}{TP + FN} = \frac{\text{抓对的}}{\text{所有该抓的}}

研究生视角的权衡 (Trade-off)

  • 如果你把置信度阈值设为 0.99(只输出最有把握的),Precision 会极高,但 Recall 会极低(漏检)。
  • 如果你把置信度阈值设为 0.01(是个框就输出),Recall 会极高,但 Precision 会极低(全是误报)。

第三层:综合评价 —— AP (Average Precision)#

为了不依赖某一个特定的置信度阈值,我们需要看模型在”各种置信度下”的综合表现。这就是 AP 的由来。

计算步骤(手推一遍):#

  1. 排序:把你模型对某一个类别(比如”猫”)预测出来的所有框(几千个),按置信度从高到低排序。
  2. 累积计算
    • 看第 1 个框:是 TP 吗?更新 P 和 R。
    • 看前 2 个框:更新 P 和 R。
    • 看前 N 个框:更新 P 和 R。
  3. 画图 (PR Curve):以 Recall 为横轴,Precision 为纵轴,画出一条曲线。
  4. 平滑 (Smoothing/Interpolation)
    • 实际画出来的线是锯齿状的。为了标准化,我们做一个操作:对于每一个 Recall 值 rr,其 Precision 取 rr 右侧最大的那个 Precision 值。
    • 公式:Pinterp(r)=maxrrP(r)P_{interp}(r) = \max_{r' \ge r} P(r')
    • 效果:把锯齿线拉平成单调递减的线。
  5. 算面积:这条平滑曲线下的面积,就是 AP

结论:AP = 1.0 表示完美(既不误报也不漏报);AP 越低表示效果越差。


第四层:全类平均 —— mAP (mean Average Precision)#

上面算的是”猫”的 AP。如果你的数据集有 80 个类别(COCO):

mAP=APcat+APdog++APcar80mAP = \frac{AP_{cat} + AP_{dog} + \dots + AP_{car}}{80}

注:在 COCO 的语境下,通常直接用 AP 代指 mAP。


第五层:两大标准的详细对比 (VOC vs COCO)#

这是你写论文时最需要分清的部分。

1. Pascal VOC 标准 (The Old School)#

通常指 mAP@0.5

  • 判定标准IoU0.5IoU \ge 0.5 就算对。
  • 计算方法
    • VOC07:使用 11点插值法。只在 Recall = [0,0.1,,1.0][0, 0.1, \dots, 1.0] 这 11 个点上取 Precision 的平均值。
    • VOC12:使用 全点插值法 (Area under curve)。这就是现代标准的雏形。
  • 特点:对定位精度要求不高,属于”入门级”指标。

2. MS COCO 标准 (The Gold Standard)#

这是目前的统治级标准。

  • 核心指标 (AP)
    • 它不只算一次。它让 IoUIoU 阈值从 0.50.5 开始,每隔 0.050.05 算一次,一直算到 0.950.95
    • IoU={0.50,0.55,0.60,,0.95}IoU = \{0.50, 0.55, 0.60, \dots, 0.95\} (共 10 个阈值)。
    • 算出 10 个 AP,然后取平均值
    • APCOCO=AP50+AP55++AP9510AP_{COCO} = \frac{AP_{50} + AP_{55} + \dots + AP_{95}}{10}
  • 含义:它奖励那些定位极准的模型。如果你的框只是勉强框住物体(IoU=0.5),在 AP50 里得分,但在 AP75、AP90 里就不得分了。

3. COCO 的其他细分指标 (尺度敏感)#

COCO 非常关注物体的大小,这对于分析模型弱点非常有用。

  • APSAP_S (Small):面积 <322< 32^2 像素的物体。
    • 通常这个分很低(比如 20%),是单阶段检测器的噩梦。
  • APMAP_M (Medium)322<32^2 < 面积 <962< 96^2
  • APLAP_L (Large):面积 >962> 96^2

总结表 (可以直接贴在笔记里)#

指标全称IoU 阈值意义评价
AP50mAP @ IoU=0.500.50只要位置大概对就算成功。传统指标,容易刷高分。
AP75mAP @ IoU=0.750.75要求位置比较精准。进阶指标,考察回归能力。
mAP (AP)COCO Primary AP0.50<0>.95综合考察从粗略到精准的所有情况。绝对权威,论文对比必看。
APSAP Small0.50<0>.95仅针对小物体。衡量对远距离/小目标的能力。
FPSFrames Per Second-推理速度。衡量是否能实时运行 (Real-time)。

常见问题解答 (Q&A)#

Q: 我的 AP50 很高 (0.9),但 COCO AP 很低 (0.4),说明什么?

A: 说明你的模型分类很准,也能找到物体,但是框画得不准(定位误差大)。

  • 改进方向:改进回归 Loss(用 CIoU/GIoU),或者增加回归分支的权重,或者提高输入分辨率。

Q: 为什么我的 APS 特别低?

A: 小物体在下采样过程中特征消失了。

  • 改进方向:使用 FPN(特征金字塔),使用 Data Augmentation(Mosaic, Mixup),或者减少下采样倍数。

NMS#

这是目标检测后处理(Post-processing)中最核心的环节。

如果不做 NMS (Non-Maximum Suppression,非极大值抑制),你的模型输出结果会像”得了帕金森”一样:对着这一只猫,画出了几十个重叠的红框。

NMS 的作用就是**“杀伐决断”**:在一堆重叠的框里,只留下那个最好的,把剩下的全砍掉。

你提到的**“置信度阈值””NMS”其实是串行关系**,它们是检测器输出结果时的两道安检门


第一道门:置信度阈值过滤 (Confidence Thresholding)#

在 NMS 开始之前,我们先要进行第一轮海选。

  • 场景:YOLO 或 Faster R-CNN 输出了成千上万个框(比如 20,000 个)。其中 19,900 个都是背景(置信度可能只有 0.001)。
  • 动作“低于这个分数的,直接滚蛋。”
    • 设定一个 conf_thres (比如 0.01 或 0.1)。
    • 所有 score < conf_thres 的框,直接丢弃。
  • 目的清除背景。这一步跟”去重”没关系,纯粹是把那些”根本不像物体”的垃圾框先清理掉,为了给后面的 NMS 减轻计算压力。

第二道门:NMS 算法 (去重)#

经过第一道门,剩下的都是”看着像物体”的框了。但问题是,针对同一只猫,模型可能预测了 5 个框,得分分别是 0.9, 0.8, 0.7…

NMS 就是用来解决**“重复检测”**问题的。

1. NMS 的核心逻辑(手推版)#

假设我们现在有 3 个框(都过了置信度门槛),按得分从高到低排序:

  • A: Score 0.9 (位置最准)
  • B: Score 0.8 (和 A 重叠很大)
  • C: Score 0.7 (和 A 离得比较远,可能是旁边的一只狗)

设定一个 NMS IoU 阈值(比如 nms_iou_thres = 0.5)。

注意:这个阈值的意思是”如果咱俩重叠度超过 0.5,我就把你当成我的分身砍掉”。

算法流程:

  1. 选出老大:取出当前分最高的框 A (0.9)
    • A 直接晋级,放入”最终保留列表”。
  2. 审判小弟:拿着 A,去跟剩下的 B 和 C 逐个比对(算 IoU)。
    • A vs B:算出 IoU(A,B)=0.8IoU(A, B) = 0.8
      • 判定0.8>0.50.8 > 0.5 (阈值)。说明 B 和 A 重叠太严重了,B 肯定是 A 的重复预测(冗余)。
      • 结果砍掉 B!
    • A vs C:算出 IoU(A,C)=0.1IoU(A, C) = 0.1
      • 判定0.1<0.50.1 < 0.5 (阈值)。说明 C 虽然分低点,但它离 A 很远,应该是另一个物体(旁边的狗)。
      • 结果保留 C。
  3. 循环
    • 现在列表里只剩 C 了。
    • C 自动成为这一轮的”老大”。
    • C 晋级,放入”最终保留列表”。
    • C 再去跟它后面的小弟比(如果没有小弟了,循环结束)。

最终输出:保留了 A 和 C。


关键点:两个”阈值”的区别#

初学者最容易晕的就是代码里这两个参数,一定要分清:

参数名 (常见写法)中文名作用阶段作用对象典型值潜台词
conf_thres / score_thr置信度阈值NMS 之前背景 vs 物体0.001 ~ 0.5”如果你连 0.1 分都拿不到,你就肯定是背景,别来沾边。“
iou_thres / nms_thresNMS IoU 阈值NMS 之中重复框 vs 独立框0.4 ~ 0.6”如果你和老大的重叠度超过 0.5,我就当你是老大的影子,删掉你。“

深度思考:NMS IoU 阈值设高了会怎样?设低了会怎样?#

这是研究生答辩或面试常考题。

  • 如果 NMS IoU 阈值设得太低 (比如 0.1):
    • 现象:非常严格的”社交距离”。只要两个框稍微碰一点边(IoU > 0.1),分低的那个就被砍了。
    • 后果漏检 (Drop in Recall)
    • 例子:两个人肩并肩站着。因为重叠了一点点,分数低的那个人直接被 NMS 误删了。
  • 如果 NMS IoU 阈值设得太高 (比如 0.9):
    • 现象:非常宽容。只有两个框几乎完全重合时,才删掉一个。
    • 后果误检/重复 (Drop in Precision)
    • 例子:对着同一只猫预测了两个框,一个偏左一个偏右,IoU 是 0.8。因为没达到 0.9 的红线,结果两个框都留下了。你的图上会出现重影。

进阶:Soft-NMS (给研究生加餐)#

标准的 NMS 有个大缺点:它太暴力了,非黑即白。

比如:两只老虎真的重叠在一起(遮挡),IoU=0.6。

  • 标准 NMS (阈值0.5):直接把分低的那只老虎删了。导致漏检。
  • Soft-NMS:我不删你,我只是降低你的得分
    • 如果和你重叠很大,我就把你原本 0.8 的分降到 0.4。
    • 这样,如果后续还有更严格的阈值筛选,你可能会因为分低被筛掉,但也可能因为分还凑合被留下来。这在密集物体检测(CrowdHuman)中非常有用。

总结#

  1. 置信度阈值:先用它把背景清理干净。
  2. NMS:在剩下的物体框里,用IoU阈值重复的框清理干净。
  3. 结果:输出清爽、干净的最终检测结果。
目标检测简史
/blog/posts/科研笔记/object-detection-history/
Author
Zenfish
Published at
2026-01-30
License
CC BY-NC-SA 4.0

Some information may be outdated