发展历程
第一阶段:R-CNN —— “蛮力穷举的开端”
核心痛点:由于全连接层(FC)需要固定输入,导致必须对图像进行破坏性缩放;且 2000 次 CNN 计算极其冗余。
1. 工作流程与维度变化
- 输入图像:一张任意大小的图。
- Dim:
- 生成候选框 (Proposal Generation):
- 使用 Selective Search (CPU) 算法。
- 得到约 2000 个候选框坐标 。
- 注:这时候还没进神经网络。
- 图像变形 (Warping) —— 你的疑问点:
- 动作:将原图中这 2000 个不同大小的框抠出来,强制缩放成固定大小(如 )。
- 后果:物体变形,导致特征提取不准。
- Tensor Dim: 变成了 的一堆小图片。
- 特征提取 (Backbone):
- 动作:把这 2000 张图**依次(或 Batch 并行)**送入 CNN。
- 计算量:跑了 2000 次卷积网络。(极慢的根源)
- Tensor Dim: 得到 的特征向量。
- 分类与回归:
- 使用 SVM 分类,使用线性回归器微调坐标。
总结:这一阶段的 BBox 回归和分类是分开的,不是端到端。
第二阶段:Fast R-CNN —— “共享特征的飞跃”
核心改进:引入 RoI Pooling,让 CNN 只跑一次;解决了变形问题。
1. 共享特征提取 (Backbone)
- 动作:整张图进 CNN,一次性得到特征图。
- Tensor Dim: 。
- 关键点:这里包含了全图的上下文信息(Context),虽然最后只看局部,但特征是全局感受野算出来的(回应了你关于”视野”的疑问)。
2. 候选框映射 (RoI Projection)
- 动作:依然用 Selective Search 在原图生成 2000 个框。
- 映射:将坐标除以步长(Stride=16)。
- (这里会有量化误差,即坐标不准)。
- 数据结构: 一个列表
[roi_1, roi_2, ..., roi_2000]。
3. RoI Pooling —— “万能适配器”
- 输入:
- 特征图
- 2000 个大小不一、长宽比各异 的 RoI。
- 你的疑问: 怎么办?
- 动作:使用自适应网格(Adaptive Grid)。如果 RoI 是 ,就按比例划分为 的网格。
- 你的疑问:维度怎么变?是一次次送吗?
- 动作:逻辑上是串行,实现上是并行。
- RoI Pooling 层会将 2000 个区域提取并堆叠。
- Tensor Dim: 。
- 注意:这里把 RoI 的数量 合并到了 Batch 维度,变成了 。
4. 分类与回归 (Head)
- 动作:展平 (Flatten) 后送入全连接层。
- Tensor Dim: 。
- 输出分支:
- Cls: —— 概率。
- Reg: —— 坐标偏移。
- 你的疑问:回归真值?
- 训练时,只有和 GT IoU > 0.5 的 RoI 才算回归损失,背景忽略。
第三阶段:Faster R-CNN —— “完全端到端 (End-to-End)”
核心改进:引入 RPN 和 Anchor,彻底抛弃 CPU 上的 Selective Search。
1. 特征提取 (Backbone)
- 同上,得到特征图 。
2. RPN (Region Proposal Network) —— “猜框网络”
这是新增的独立分支。
- Anchor 生成:在特征图每个像素点生成 9 个 Anchor(3尺寸 3比例)。
- 总 Anchor 数 个。
- 正负样本分配 (Label Assignment) —— 你的核心疑问:
- 计算所有 Anchor 与 GT 的 IoU。
- 正样本:IoU > 0.7(或者是最大的那个)。
- 负样本:IoU < 0.3。
- 忽略:中间态。
- Loss 计算:
- Cls Loss:正负样本都算(教它认背景)。
- Reg Loss:只算正样本(如你所悟,只有正样本有回归真值)。
- 生成 Proposal:
- 网络输出预测偏移量 修正 Anchor 得到粗略框。
- NMS (非极大值抑制):从 20,000 个框里剔除重叠的,选出前 2000 个。
- 数据流出: 2000 个 Proposals。
3. RoI Pooling
- 输入:特征图 + 2000 个 Proposals (来自 RPN)。
- 动作:和 Fast R-CNN 一样,统统变成 。
- Tensor Dim: 。
4. R-CNN Head (最终精修)
- 输入:。
- 动作:再次经过 FC 层。
- 目的:
- 精细分类:RPN 只知道是”物体”,Head 要知道是”猫”。
- 二次回归:在 RPN 粗略调整的基础上,进行像素级微调。
维度与流程总结表 (Cheatsheet)
假设输入图片 ,Backbone 是 VGG16 (Stride=16),Batch Size=1。
| 步骤 | 涉及网络模块 | 输入 Tensor 维度 | 输出 Tensor 维度 | 关键动作/术语 | 你的疑问解答 |
|---|---|---|---|---|---|
| 1. 提特征 | Backbone | 卷积/下采样 | 全局感受野在此形成。 | ||
| 2. 撒网 | RPN (Anchor) | / | ~22500 个 Anchors | 生成基准框 | 预设的,不参与计算,只做参考。 |
| 3. 初筛 | RPN (Pred) | Class: Reg: | IoU分配 正负样本 | 训练时只对正样本算回归 Loss。 | |
| 4. 建议 | RPN (Post) | 上面的预测结果 | 2000 个 Proposals (List) | NMS | 去重,选出最好的 2000 个。 |
| 5. 统一 | RoI Pooling | Feature Map + 2000 Proposals | Mapping Pooling | 并行处理,把 融合进 Batch 维度。 处理 。 | |
| 6. 展平 | Flatten | Reshape | 准备喂给全连接层。 | ||
| 7. 结果 | FC Head | Cls: Reg: | 精修 | 对这 2000 个框做最后的裁决。 |
优缺点与发展评价
- R-CNN:
- 优点:把深度学习引入检测,精度大增。
- 缺点:慢(2000次CNN),缩放导致变形。
- Fast R-CNN:
- 优点:共享特征图(快),RoI Pooling 解决变形。
- 缺点:候选框生成(Selective Search)还在 CPU 上,是瓶颈。
- Faster R-CNN:
- 优点:RPN 替代 CPU 算法,真正端到端,精度高。
- 缺点:对于小物体(特征图下采样导致消失)效果一般;速度依然无法满足 30FPS 实时性(因为还有两阶段)。
下一步发展(给研究生的指引):
- 嫌慢? YOLO / SSD (去掉 RPN 和 RoI Pooling,直接在 Feature Map 上回归)。
- 嫌小物体不准? FPN (Feature Pyramid Networks) (融合浅层和深层特征)。
- 嫌 RoI Pooling 使得像素不对齐? Mask R-CNN (RoI Align) (用双线性插值替代取整)。
评价指标
第一层:基本判定单位 —— IoU 与 TP/FP/FN
在分类任务中,预测结果只有”对/错”。但在目标检测中,预测结果是一个框,我们需要一个量化的阈值来判断这个框到底算不算”对”。
这个阈值通常是 IoU (Intersection over Union)。
1. IoU (交并比)
2. 状态定义 (TP, FP, FN)
假设我们设定阈值 IoU Threshold = 0.5。
- TP (True Positive / 真正例):
- 预测框与真值框 (GT) 的 。
- 类别分类正确。
- 注意:对于同一个 GT,只能有一个预测框算 TP。如果模型对同一个物体预测了两个高分框(没被 NMS 滤掉),第一个是 TP,第二个就是 FP(重复检测)。
- FP (False Positive / 假正例):
- 预测框与 GT 的 (位置不准)。
- 或者是对背景的误检(无中生有)。
- 或者是重复检测(Duplicate)。
- FN (False Negative / 假负例):
- 图片里有一个 GT,但模型没有预测出任何与它 IoU 合格的框。
- 或者预测出来了,但置信度太低被过滤掉了。
- TN (True Negative / 真负例):
- 在目标检测中不讨论 TN。因为图片中”背景”是无限多的,你没把背景框出来是理所当然的,无法计算。
第二层:统计指标 —— Precision (P) 与 Recall (R)
有了 TP, FP, FN,我们就能算两个核心指标。
1. Precision (查准率)
含义:“你预测出来的这些框里,有多少是靠谱的?”
2. Recall (查全率)
含义:“所有真实的物体里,你找出来了多少?”
研究生视角的权衡 (Trade-off):
- 如果你把置信度阈值设为 0.99(只输出最有把握的),Precision 会极高,但 Recall 会极低(漏检)。
- 如果你把置信度阈值设为 0.01(是个框就输出),Recall 会极高,但 Precision 会极低(全是误报)。
第三层:综合评价 —— AP (Average Precision)
为了不依赖某一个特定的置信度阈值,我们需要看模型在”各种置信度下”的综合表现。这就是 AP 的由来。
计算步骤(手推一遍):
- 排序:把你模型对某一个类别(比如”猫”)预测出来的所有框(几千个),按置信度从高到低排序。
- 累积计算:
- 看第 1 个框:是 TP 吗?更新 P 和 R。
- 看前 2 个框:更新 P 和 R。
- …
- 看前 N 个框:更新 P 和 R。
- 画图 (PR Curve):以 Recall 为横轴,Precision 为纵轴,画出一条曲线。
- 平滑 (Smoothing/Interpolation):
- 实际画出来的线是锯齿状的。为了标准化,我们做一个操作:对于每一个 Recall 值 ,其 Precision 取 右侧最大的那个 Precision 值。
- 公式:。
- 效果:把锯齿线拉平成单调递减的线。
- 算面积:这条平滑曲线下的面积,就是 AP。
结论:AP = 1.0 表示完美(既不误报也不漏报);AP 越低表示效果越差。
第四层:全类平均 —— mAP (mean Average Precision)
上面算的是”猫”的 AP。如果你的数据集有 80 个类别(COCO):
注:在 COCO 的语境下,通常直接用 AP 代指 mAP。
第五层:两大标准的详细对比 (VOC vs COCO)
这是你写论文时最需要分清的部分。
1. Pascal VOC 标准 (The Old School)
通常指 mAP@0.5。
- 判定标准: 就算对。
- 计算方法:
- VOC07:使用 11点插值法。只在 Recall = 这 11 个点上取 Precision 的平均值。
- VOC12:使用 全点插值法 (Area under curve)。这就是现代标准的雏形。
- 特点:对定位精度要求不高,属于”入门级”指标。
2. MS COCO 标准 (The Gold Standard)
这是目前的统治级标准。
- 核心指标 (AP):
- 它不只算一次。它让 阈值从 开始,每隔 算一次,一直算到 。
- (共 10 个阈值)。
- 算出 10 个 AP,然后取平均值。
- 含义:它奖励那些定位极准的模型。如果你的框只是勉强框住物体(IoU=0.5),在 AP50 里得分,但在 AP75、AP90 里就不得分了。
3. COCO 的其他细分指标 (尺度敏感)
COCO 非常关注物体的大小,这对于分析模型弱点非常有用。
- (Small):面积 像素的物体。
- 通常这个分很低(比如 20%),是单阶段检测器的噩梦。
- (Medium): 面积 。
- (Large):面积 。
总结表 (可以直接贴在笔记里)
| 指标 | 全称 | IoU 阈值 | 意义 | 评价 |
|---|---|---|---|---|
| AP50 | mAP @ IoU=0.50 | 0.50 | 只要位置大概对就算成功。 | 传统指标,容易刷高分。 |
| AP75 | mAP @ IoU=0.75 | 0.75 | 要求位置比较精准。 | 进阶指标,考察回归能力。 |
| mAP (AP) | COCO Primary AP | 0.50<0>0>.95 | 综合考察从粗略到精准的所有情况。 | 绝对权威,论文对比必看。 |
| APS | AP Small | 0.50<0>0>.95 | 仅针对小物体。 | 衡量对远距离/小目标的能力。 |
| FPS | Frames 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,我就把你当成我的分身砍掉”。
算法流程:
- 选出老大:取出当前分最高的框 A (0.9)。
- A 直接晋级,放入”最终保留列表”。
- 审判小弟:拿着 A,去跟剩下的 B 和 C 逐个比对(算 IoU)。
- A vs B:算出 。
- 判定: (阈值)。说明 B 和 A 重叠太严重了,B 肯定是 A 的重复预测(冗余)。
- 结果:砍掉 B!
- A vs C:算出 。
- 判定: (阈值)。说明 C 虽然分低点,但它离 A 很远,应该是另一个物体(旁边的狗)。
- 结果:保留 C。
- A vs B:算出 。
- 循环:
- 现在列表里只剩 C 了。
- C 自动成为这一轮的”老大”。
- C 晋级,放入”最终保留列表”。
- C 再去跟它后面的小弟比(如果没有小弟了,循环结束)。
最终输出:保留了 A 和 C。
关键点:两个”阈值”的区别
初学者最容易晕的就是代码里这两个参数,一定要分清:
| 参数名 (常见写法) | 中文名 | 作用阶段 | 作用对象 | 典型值 | 潜台词 |
|---|---|---|---|---|---|
conf_thres / score_thr | 置信度阈值 | NMS 之前 | 背景 vs 物体 | 0.001 ~ 0.5 | ”如果你连 0.1 分都拿不到,你就肯定是背景,别来沾边。“ |
iou_thres / nms_thres | NMS 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)中非常有用。
总结
- 置信度阈值:先用它把背景清理干净。
- NMS:在剩下的物体框里,用IoU阈值把重复的框清理干净。
- 结果:输出清爽、干净的最终检测结果。
Some information may be outdated