目标检测是计算机视觉领域的基础任务,旨在通过算法自动检测图像中包含的目标类别信息和位置信息。本文将详细介绍基于锚框(Anchor)的目标检测算法,并介绍其原理和实现方法。
1. 目标检测基础
不同于图像分类任务,目标检测任务需要识别图像中的多个目标对象,并给出每个目标的类别信息和 位置信息。
1.1. 基于锚框的目标检测
如图所示,假设我们需要识别一张图片中的人脸,我们可以人为标记出图片中人脸的范围和位置(使用绿色方框),问题转化为,如何使用 CNN 来自动识别并定位图片中的人脸。
一种思路是,在图片中人为设计许多锚框(Anchor Boxes),然后使用 CNN 来识别锚框中的内容,同时想办法把锚框的位置和长宽信息预测的尽可能接近预先的标记框。可以看出,上述思想实际上是将目标检测问题转化为一个「图像分类」问题和一个「坐标回归」问题。
根据上述两个问题是「分阶段解决」还是「一步同时解决」,我们可以将目标检测方法分类为:
- 单阶段(single-stage)目标检测(YOLOv2等)
- 多阶段(multi-stage)目标检测(R-CNN等)
1.2. 非锚框的目标检测
非锚框检测方法摒弃了预设锚框的设计,直接预测目标的位置和类别,主要分为两种思路:
- 基于关键点/中心点的检测
- 思想:不预测边界框,而是预测目标的中心点或关键点
- 代表方法:CornerNet、CenterNet、ExtremeNet
- 优势:避免了锚框的超参数调优,对形状变化更鲁棒
- 基于密集预测的检测
- 思想:在特征图的每个位置直接预测边界框参数
- 代表方法:FCOS(Fully Convolutional One-Stage)、YOLOv1
- 优势:更简单的流程,避免了锚框匹配的复杂性
1.3. 目标检测的主要指标
1.3.1. 置信度阈值
和 CNN 用于图像分类类似,由于目标检测中对每一个锚框都要做分类预测,因此也需要设置一个置信度阈值,低于该阈值的锚框会被忽略。
1.3.2. 交并比(IoU)
交并比(Intersection over Union,IoU)是两个框的相似度度量,用于度量两个框之间的相似度,进而衡量两个框在位置和尺寸上的差异。其计算方式为:
\[IoU = \frac{A_1 \cap A_2}{A_1 \cup A_2}\]图示如下:
1.3.3. 平均精度(AP)和均值平均精度(mAP)
在目标检测任务中,AP(Average Precision,平均精度) 和 mAP(mean Average Precision,均值平均精度) 是衡量算法性能的核心指标,其计算基于精确率(Precision)、召回率(Recall) 和 PR 曲线(Precision-Recall Curve),且必须结合IoU 阈值和置信度阈值来判定检测结果的正负样本。
对于某个特定的类别,AP 的计算流程如下:
-
排序:对于该类别的每个预测框,都有一组
(confidence_score, predicted_box),将其按照置信度从高到低排序 -
正负样本判定:从高置信度开始,依次处理每个预测框,通过 IoU 找到与之最为匹配(交并比最大)且没被匹配过的真实框(Ground Truth, GT)
- 真正例(TP,True Positive):预测框与 GT 的 IoU ≥ 阈值(如 0.5),且类别一致;
- 假正例(FP,False Positive):预测框与所有 GT 的 IoU < 阈值,或类别不一致;
-
计算精确率与召回率
- Precision = 累计TP / (累计TP + 累计FP)
- Recall = 累计TP / 总GT数
- 随着置信度阈值降低,预测框数量增加,TP 和 FP 均会增多,Recall 单调递增,Precision 通常递减。
-
计算 AP:AP 是单类别 PR 曲线下的面积,反映该类别检测算法在所有置信度阈值下的综合性能。主流计算方法有「11 点插值法」和「积分法」两种。
- 11 点插值法(PASCAL VOC 2007):
- 将 PR 曲线的 $x$ 轴(Recall)均分 11 个点 $[0, 0.1, \cdots, 1.0]$;
- 在每个 Recall 值处,取右侧最大 Precision;
- AP = 这 11 个 Precision 值的平均值。
- 积分法(PASCAL VOC 2010+):
- 对所有不同的Recall值进行插值
- AP = P-R曲线下的面积(更精确)
- 11 点插值法(PASCAL VOC 2007):
-
计算 mAP:对所有类别的 AP 求平均,得到 mAP
注意到,上述 AP 和 mAP 计算与 IoU 阈值的设置密切相关。对于特定类别,按照不同的 IoU 阈值设置,可以进一步计算如下各类指标:
- mAP@.5:
mAP at IoU=.50PASCAL VOC 指标 - mAP@.75:
mAP at IoU=.75更严格的指标 - mAP@[.5:.95]:
mAP at IoU=.5:.05:.95MS COCO 指标 - mAP@small:
mAP for small objects: aera < 32^2MS COCO 指标(用于衡量小目标检测效果) - mAP@medium:
mAP for medium objects: 32^2 < aera < 96^2MS COCO 指标(用于衡量中等目标检测效果) - mAP@large:
mAP for large objects: aera > 96^2MS COCO 指标(用于衡量大目标检测效果)
计算出 AP 之后,对所有的类别的AP求平均就可以得出整个数据集上的 mAP(mean Average Precision)。
2. R-CNN 系列多阶段目标检测
2.1. R-CNN
其流程如下:
- 输入图像:输入一张带检测的图像;
- 候选区域生成:使用 选择性搜索算法(Selective Search),在输入图像上生成 ~2K 个候选区域(region proposal);
- 候选区域处理:对每个候选区域进行预处理,并缩放到 $227\times 227$ 的尺寸(数字是否很熟悉?);
- 特征提取:将缩放后候选区域输入 AlexNet,并最终提取得到 $4096$ 维度的特征;
- 类别判断:把提取的特征送入 $20$ 个二分类 SVM 模型,得到 $20$ 个类别的概率,判断其属于哪一类;
- 位置精修:使用回归器精细修正候选框的位置。
2.1.1. 候选区域提取
一张图像中可能存在多个物体需要分别定位和分类。显然,在训练分类器之前,需要使用一些方法将图像划分为小的区域,这些方法统称为 Region Proposal Algorithms。一张图像中包含的信息非常丰富,图像中的物体有不同的形状、尺寸、颜色、纹理,而且物体间还有层次(hierarchical)关系。下图给出了四个例子,来说明目标检测的难度。
图(a)中的场景表明图像中不同物体之间是有一定的层次关系。图(b)中给出了两只猫,通过纹理很难找出这两只猫,但是通过颜色来可以很容易区分它们。图(c)中变色龙和周边颜色接近,但可以通过纹理来区分。图(d)中的车辆,我们需要把车身和车轮看做一个整体,但它们两者之间在纹理和颜色方面差别都非常大。
- Exhaustive Search
刚开始人们想到的是穷举法(Exhaustive Search),首先设计多个尺度的窗口,在每个尺度下按照一定步长进行滑动遍历(滑动窗口目标检测方法)。对于每一个窗口都分别计算 HOG 特征,然后送入提前训练好的 SVM 分类器进行判断,如果输出结果高于阈值则认为该框中含有目标。这个方式的局限性是搜索的范围很大,需要的计算量也很大,最后产生的提议区域也很多,即使改进的穷举法依然可以产生 $100000$ 多个提议区域,这对后面的区域特征提取和分类器训练带来不小的压力,所以不合适使用复杂的特征提取算法和分类器。
1
2
3
4
5
6
7
8
9
10
11
12
# 假设图像尺寸:1000×1000像素
# 窗口大小:64×128(行人检测标准)
# 步长:8像素
# 尺度数:10个
# 单一尺度的窗口数
水平滑动次数 = (1000 - 64) / 8 ≈ 117
垂直滑动次数 = (1000 - 128) / 8 ≈ 109
单尺度窗口数 = 117 × 109 ≈ 12,753
# 多尺度(10个尺度)
总窗口数 = 12,753 × 10 ≈ 127,530
此外,这个方法的窗口形状是固定的,比如对于行人设定的 $60\times 128$ 对与非行人类目标就不适用。
- Selective Search
选择性搜索是用于目标检测的区域提议算法,它计算速度快,具有很高的召回率。Selective Search 算法的核心是基于颜色,纹理,大小和形状兼容计算相似区域的分层分组,主要包含两个内容:
- Hierarchical Grouping Algorithm
- Diversification Strategies
这个方法主要有三个优势:捕捉不同尺度(Capture All Scales)、多样化(Diversification)、快速计算(Fast to Compute)。
在 Hierarchical Grouping Algorithm 中,首先将图像划分为多个区域,然后基于区域之间的相似性进行分组,两个最相似的区域被组合在一起形成一个新的区域,并将其添加到候选区域提议(Region Proposal)的列表中,重复上述过程直到整个图像变为一个区域。
在 Diversification Strategies 中,主要计算了不同的相似性度量方式,包括颜色相似度、纹理相似度、尺度相似度、形状重合度等。最终将他们加权得到总的相似性度量。
虽然 Selective Search 算法能够大幅降低(提取~2K候选区域),但计算量仍然过高(每一个候选区域都需要过一次 CNN,且相邻区域间存在大量重复计算)。
在送入 AlexNet 之前,候选框需要扩展 16 个像素的上下文区域(避免裁剪丢失目标边缘特征),再强制缩放为 $227\times 227$ 尺寸,适配 AlexNet 的输入要求。
2.1.2. 候选框分类
对于每个候选框,输入预先训练好的 $20$ 个 SVM 分类器(只用于判断该输入候选框是该类样本还是背景),得到 $20$ 个类别的概率,然后选择概率最大的类别作为该候选框的类别,最终可以得到 $2000\times 1$ 的类别预测结果。
上述每个 SVM 分类器的训练流程严格依赖 CNN 提取的特征,且需要人工构造正负样本。
-
CNN 特征预提取
-
CNN 预训练
先在大规模分类数据集(如 ImageNet)上预训练一个 CNN(如 AlexNet),目的是让 CNN 学会提取通用的图像特征。虽然将 CNN 当作分类器去训练,但是训练完毕后只使用其前面的 5 个卷积层 + 3 个池化层作为特征提取器。
-
特征提取
对训练集的每张图像,用 Selective Search 生成约 2000 个候选框,将每个候选框裁剪、缩放为 CNN 要求的固定尺寸(如 $227\times 227$),输入预训练 CNN,输出 $4096$ 维的特征向量—— 这是 SVM 的输入特征。
-
-
正负样本构建
-
样本标注
正样本:对于当前类别 $C$,若候选框与该类的某个 GT 框的 IoU $≥ 0.5$,则标注为正样本(表示该候选框包含类别 $C$ 的目标)。注意:一个候选框只能属于一个类的正样本。
负样本:若候选框与所有类的 GT 框的 IoU $< 0.5$,则标注为负样本(表示该候选框是背景)。注意:负样本数量远大于正样本,训练时需负样本采样(避免样本不均衡),通常随机选取部分负样本,或采用难负样本挖掘(Hard Negative Mining) 提升训练效果。
-
-
SVM 训练
- 构造样本集:$S_{C} = {(x_1, y_1), (x_2, y_2), …, (x_n, y_n)}$,其中 $x_i$ 为 $4096$ 维特征向量,$y_i$ 为类别标签($+1$ 表示正样本,$-1$ 表示负样本背景)。
- 使用线性 SVM 分类器,因为计算效率高,训练目标是找到一个最优超平面,将正样本(目标)和负样本(背景)分开,同时最大化分类间隔。
- 损失函数:Hinge Loss,$L = \sum_{i}max(0, 1-y_i (w \cdot x_i+b)) + \lambda/2 \sum_i w_i^2$
2.1.3. 边界框回归
虽然已经完成了分类,但是每个候选框的坐标,也就是 Selective Search 生成的候选区域(region proposals)通常不够精确,主要体现在:
- 边界框可能只覆盖目标的一部分
- 位置可能有偏移
- 大小可能不完全匹配
R-CNN 的作者表示,CNN 提取的深层特征(pool5 层)包含目标的精准位置线索,可通过线性模型学习这种 “候选框 - 真实锚框” 的映射关系,实现框的微调(Bounding Box Regression)。
AlexNet 结构(R-CNN使用)
1 2 3 4 5 6 conv1 → relu1 → pool1 → norm1 → conv2 → relu2 → pool2 → norm2 → conv3 → relu3 → conv4 → relu4 → conv5 → relu5 → pool5 → fc6 → fc7 → fc8pool5 特征特点:
- 空间维度:6×6×256=9216(对于 227×227 输入)
- 其兼顾局部细节和全局语义,比浅层卷积特征更适合定位,比全连接层特征更具位置敏感性。
线性模型的核心是学习候选框到真实锚框(Ground Truth)的 $4$ 个变换参数。线性模型的结构、目标函数和参数求解方式如下:
- 目标参数定义
不直接预测边界框的绝对坐标,而是预测相对变换参数,以提升模型的尺度鲁棒性。设候选框$P=(P_x,P_y,P_w,P_h)$($P_x,P_y$为中心坐标,$P_w,P_h$为宽高),真实锚框$G=(G_x,G_y,G_w,G_h)$,定义4个目标变换参数:
\[\begin{cases} t_x=\frac{G_x - P_x}{P_w}\\ t_y=\frac{G_y - P_y}{P_h}\\ t_w=\ln(\frac{G_w}{P_w})\\ t_h=\ln(\frac{G_h}{P_h}) \end{cases}\]其中$t_x,t_y$描述中心坐标的相对偏移,$t_w,t_h$描述宽高的相对缩放
思考:为何宽高与中心坐标的相对变换参数形式不一样?
有如下几个考虑:为何宽高使用比值,而不是差值:
(1)尺度不变性。假设候选框宽度 $P_w=10$,真实锚框宽度 $G_w=20$,宽度差为 $10$。但如果 $P_w=100, G_w=110$,差值也是 $10$,但物理意义完全不同:第一个是宽度翻倍,第二个只是增加了 $10\%$。而使用比值可以反应不同尺度框的相对缩放关系。
(2)损失函数的公平性。在训练时,一张图像中可能同时存在大物体和小物体。如果对大物体的宽高预测误差为10像素,对小物体的误差也为10像素,数值上相同。但对小物体来说,10像素可能是巨大的相对误差(比如50%),而对大物体可能是微小误差(比如5%)。使用差值损失会导致模型偏向优化大物体的绝对误差,而忽视小物体的相对精度。使用比值(对数)后,所有尺寸的物体都在相对变化空间中进行优化,实现了尺度公平。
(3)梯度计算的稳定性。如果使用差值,对于不同尺度的物体,梯度数值范围差异很大。
(4)恢复预测时的数值合理性。如果网络预测宽度差值很不准确,比如为一个很大的负数 $t_w=-15$,在用这个差值对候选框进行纠正时会得到比如 $\hat{G_w}=10-15=-5$ 种非法数字。
为何宽高使用对数,而不是直接使用比值:
(1)放大一倍时比值为2,而缩小0.5倍时比值为0.5,二者在数值上不对称;如果使用对数,$ln(2)\approx 0.693, ln(0.5)\approx -0.693$,对数比值更适合表示缩放关系;
(2)直接比值的范围是 $(0,+\infty)$,这带来两个问题:(1)分布严重右偏,大多数比值在 $1$ 附近,但偶尔有极大值(如 $10$ 倍放大);(2)梯度不稳定,大比值导致大梯度;
(3)取对数后,范围变为 $(-\infty, +\infty)$,大多数值集中在 $0$ 附近,分布更接近正态分布,适合神经网络优化。
- 线性模型结构
线性模型为 $4$ 个独立的 Ridge 回归(带 L2 正则的线性回归)模型,分别对应 $t_x,t_y,t_w,t_h$ 的预测。每个模型的表达式为 $\hat{t}=W^T f + b$,其中 $f$ 是 pool5 层的 9216 维特征向量,$W$ 是 9216 维的权重向量,$b$ 是偏置项,$\hat{t}$ 是预测的变换参数。使用独立模型可避免参数间的相互干扰,提升预测精度。
- 损失函数与训练约束
训练的损失函数采用均方误差(MSE),即最小化
\[\sum_{i=1}^N (\hat{t}_i - t_i)^2+\lambda||W||^2\]其中 $\lambda$ 是 L2 正则化系数,用于防止过拟合。补充材料特别强调,训练样本需满足候选框与真实锚框的 IoU(交并比)大于 $0.6$,因为只有候选框与目标足够接近时,候选框到真实锚框的映射才近似线性,这是线性回归模型有效的前提。
论文指出,无需多次迭代修正,一次线性回归的调整即可满足精度要求,多次调整反而会引入累积误差,降低检测性能。
2.1.4. 非极大值抑制(NMS)
非极大值抑制(Non-Maximum Suppression,NMS)是候选框筛选阶段的核心操作,其作用是去除冗余的目标检测框,保留最精准的一个框来定位目标。
非极大值抑制作用于分类和回归之后,针对每个类别独立执行。其步骤如下:
- 排序:对当前类别下所有候选框,按照 SVM 分类器输出的概率从高到低排序,得到一个候选框列表 $B$;
- 筛选:从排序后的列表 $B$ 中,取出第一个候选框放入最终列表 $D$,并计算其与其他候选框的 IoU(交并比),如果 IoU 大于阈值(如 $0.5$),则该候选框被标记为冗余,将其从 $B$ 中删除;
- 重复上述筛选操作,直到整个候选框列表 $B$ 为空。最终列表 $D$ 中存放着该类别的所有最终检测框。
2.1.5. 总结
R-CNN 最大的问题在于:候选区域提取、目标特征分类、候选框回归,三个步骤相互独立,要分别训练,测试效率也较低。
2.2. Fast R-CNN
为了改善 R-CNN 的问题,作者提出了 Fast R-CNN。其核心改动是屏弃 SVM 分类器,改用 FC 层搭配两个不同的检测头同时完成分类和回归。那么作为 CNN 特征提取部分和 FC 层分类回归部分的连接,Fast R-CNN 的重要创新就在于提出的感兴趣区域投影(RoI Projection)和感兴趣区域池化(RoI Pooling)操作。
其主要流程如下:
- 输入图像:输入一张带检测的图像;
- 候选区域生成:使用 选择性搜索算法(Selective Search),在输入图像上生成 ~2K 个候选区域(region proposal);
- 特征提取:将整张图片传入 CNN 提取特征;
- 候选区域特征:利用 RoI Pooling 层将候选区域映射到固定大小,并提取特征(投影+池化);
- 分类和回归:把提取的特征仅分类和回归;
2.2.1. RoI 投影
感兴趣区域(Region of Interest, ROI)投影(Projection)指将原始图像坐标空间中的感兴趣区域投影到卷积特征图上的过程。
投影的核心在于坐标的线性缩放,这个缩放是由 CNN 网络的结构,或者更具体说,是由 CNN 结构中使用的 总步长(Total Stride) 决定的。总步长是网络从输入到输出特征图空间尺寸缩放的倍数。它由卷积层和池化层的 stride 乘积决定。
例如,一个经典的 VGG16 网络,在 conv5_3 之前,通常有 5 次步长为 2 的下采样($2\times 2$ 池化,默认卷积使用 stride=2),这意味着特征图在宽和高上都变成了输入的 $1/(2^5) = 1/32$。则将原图像对应的四元数组转换到 feature maps 上就是每个值都除以 32 并 取整 到最接近的整数,得到投影的坐标,即为 ROI feture map。
注意,投影过程存在 第一次量化损失。损失的信息如下图蓝色区域所示。在图中的例子中,一个 ROI 的原始大小为 $200\times145$,左上角设置为 $(296\times 192)$ 。除以 $32$(比例因子)并取整,左上角变为 $(9,6)$,宽高变为 $6\times 4$,得到的 ROI feature maps 为 $[9,6,6,4]$。
2.2.2. RoI 池化
RoI Pooling 利用特征采样,把不同空间大小的特征,变成空间大小一致的「固定大小特征」。这样做有两个好处:
- RoI pooling 后接的是 FC 层,要求输入固定的维度;
- 各个候选区域的特征大小一致,可以组成 batch 进行批处理。
假设经过 ROI 池化后的固定大小为是一个超参数 $H\times W$ ,因为输入的 ROI feature map 大小不一样,假设为 $h\times w$,需要对这个特征图进行池化来减小尺寸,那么可以计算出池化窗口的尺寸为:$(h/H)\times (w/W)$。注意,池化窗口尺寸也需要进行 取整,如上图中,左上角的池化区域区域明显小于右上角的池化区域,这导致了 第二次量化损失(后续会有 RoI Align 方法消除该量化损失)。
最后,用这个计算出的窗口对 RoI feature map 做 max pooling,Pooling 对每一个特征图通道都是独立的。
2.2.3. 损失函数
Fast R-CNN 的核心突破之一是实现分类与边界框回归的端到端联合训练,其损失函数设计兼顾了分类任务的类别判别和回归任务的框位置微调,整体为多任务损失(Multi-Task Loss),由分类损失和回归损失加权组合而成。
\[L(p,u,t^u,v) = L_{cls}(p,u) + \lambda [u\geq 1]L_{reg}(t^u,v)\]其中:
- $p$:预测的类别概率分布,维度为 $K+1$($K$ 个目标类别 + 1 个背景类别)
- $u$:类别索引,$u=0$ 表示背景类别,$u=1,2,\cdots,K$ 表示目标类别
- $t^u$:预测的对应类别 $u$ 的边界框回归参数,维度为 $4$,即 $t_x,t_y,t_w,t_h$
- $v$:真实的边界框回归目标参数,维度为 $4$,即 $v_x,v_y,v_w,v_h$
- $\lambda$:回归损失的权重系数,平衡分类与回归任务的损失量级,一般取值为 $1$
- $[u\geq 1]$:指示函数,当$u\geq 1$ (非背景类)时值为 $1$,否则为 $0$
分类损失采用交叉熵损失函数:
\[L_{cls}(p,u) = -\log p_u\]思考:如何从交叉熵损失函数的一般形式推导得到上述损失函数?
对于标签 $u$,独热编码的真实标签为 $$y = [0,0,\cdots, \underbrace{1}_{第u位},\cdots, 0,0]$$ 代入交叉熵公式 $$ \begin{aligned} H(p,y) &= - \sum_{i=0}^K y_i \log p_i = - \sum_{i=0}^K 1[i=u]\log p_i\\ &=-(0\cdot \log p_0 +\cdots + 1\cdot \log p_u + \cdots + 0\cdot \log p_K)\\ &= -\log p_u \end{aligned} $$回归损失采用平滑 $L_1$ 损失函数:
\[L_{reg}(t,v) = \sum_{i\in\{x,y,w,h\}} \text{smooth}_{L1}(t_i^u-v_i)\]其中平滑 $L_1$ 损失函数定义为:
\[L_{smoothL1}(x) = \begin{cases} 0.5x^2 & \text{if } |x| < 1\\ |x| - 0.5 & \text{otherwise} \end{cases}\]对损失函数分析如下:
- 当 $\vert x\vert<1$ 时,近似为 L2 损失,梯度随误差减小而降低,训练更稳定;
- 当 $\vert x\vert \geq 1$ 时,近似为 L1 损失,避免 L2 损失因离群点导致的梯度爆炸,提升鲁棒性。(思考:为什么?)
2.2.4. 总结
- 相比 R-CNN 速度提升 200 多倍,精度提高约 10 mAP;
- 生成候选区域的算法(Selective Search)非常慢(耗时约 2s)。
2.3. Faster R-CNN
相比 Fast R-CNN,Faster R-CNN 引入了区域提议网络(Region Proposal Network,RPN)来代替启发式搜索(Selective Search)来获得更好的锚框。
2.3.1. RPN
观察上图可以发现,RPN 的输入是特征提取骨干网络部分的最后一层输出.在 RPN 输入的特征图上,从左上角开始,通过「滑动窗口」提取对应区域的特征区域信息,然后将其送入一个小网络中(如下图所示,实际上小网络和前面的特征提取网络共同组成 RPN )。
2.3.1.1. 锚框中心确定与逆向映射
特征图的每个像素点都会作为锚框的中心,这是锚框生成的基本规则。因此,锚框会从特征图的左上角开始,通过滑动窗口开始遍历。
接着,需要把锚框的中心坐标映射回原始的输入图像。通常为了简化计算,Faster R-CNN 的特征提取网络会保证 padding 是 “same” 或经过调整,使得特征图坐标到原图坐标的映射是整数倍关系。所以我们不需要考虑卷积层会缩小特征图尺寸,只需要考虑有多少池化层(下采样)即可。因此,RPN 输入特征图上的一个像素在原始图像上的位置只与「总步长」有关。比如 VGG16 的 conv5_3,从原图到该特征图的总步长是 16,即 stride=16。
注意区分「感受野大小」与「总步长」的区别:
- 感受野大小:特征图上每个像素对应的原图理论最大视野范围;
- 总步长:特征图上每个像素对应的原图的位置,或特征图上两个相邻像素在原图感受野的间隔距离。
设特征图上的点坐标为 $[x_f, y_f]$(行和列),原图中锚框中心的坐标 $[x_o, y_o]$ 为:
\[[x_o, y_o] = [(x_f+0.5)\times\text{stride},\; (y_f+0.5)\times\text{stride}]\]2.3.1.2. 锚框尺寸设计
光有锚框中心点依然无法产生锚框,因此人们「预先设计」了 $k$ 个形状不同的候选框,然后让网络预测候选框的相对偏移量($k$ 个候选框会产生 $4k$ 个偏移量,即长宽和中心点的横纵坐标)。而每个候选框还需要额外预测两个分类概率值,用于判断该候选框是否属于背景或者目标(因此总共有 $2k$ 个分类得分)。
Faster R-CNN 按照「特定的宽高比」设置 $9$ 个候选框,其由 $128^2, 256^2, 512^2$ 三个尺度和 $1:1, 2:1, 1:2$ 三个长宽比进行组合得到。
注意,候选框的尺寸和待检测的目标特性(数据集)有关系。比如,对于 COCO 数据集,因为其包含很多小目标,候选框的尺寸就额外设置有 $64^2$ 这种偏小的尺寸。
将网络输出的所有推荐的锚框进行可视化,如下图所示:
2.3.1.3. RPN 训练
在训练(反向传播)时:我们需要为所有的锚框计算损失。为此,我们必须为每个锚框分配一个“标签”,告诉它:
-
分类标签:这个锚框应该是背景($0$)还是前景($1$)?
-
回归目标:如果它是前景,它应该向哪个真实锚框调整?(即那 $4$ 个偏移量的 “目标值” 是多少?)
因此,我们需要将 RPN 给出的候选锚框,与真实标签框进行匹配:
- 首先计算所有候选锚框与所有真实锚框的 IoU
- 然后进行正样本分配
- 对每个真实锚框,找到与它 IoU 最大的那个候选锚框(即使 IoU 很小),强制标记为前景(保证每个真实锚框至少有一个锚框对应)。
- 候选锚框与任意真实锚框的 IoU $\geq 0.7$(论文默认阈值),标记为前景。
- 接着进行负样本分配
- 与所有真实锚框 IoU $< 0.3$ 的候选框,赋予负标签
- 最后舍弃中间锚框
- IoU 在 $[0.3, 0.7]$ 之间的候选锚框,属于“模糊样本”。它们不分配标签,不参与训练。
基于上述分配,我们就可以算出每个样本的分类损失,和每个正样本的回归损失。则损失函数如下:
\[L(\{p_i\}, \{t_i\}) = \frac{1}{N_{cls}}\sum_{i} L_{cls}(p_i, p_i^\star) + \lambda \frac{1}{N_{reg}}\sum_i p_i^\star L_{reg}(t_i, t_i^\star)\]其中:
- $i$:mini-batch 中 anchor 的索引
- $p_i$:anchor $i$ 被预测包含有物体的概率
- $p_i^\star$:anchor $i$ 的真实标签(1 表示正样本,0 表示负样本)
- $t_i$:anchor $i$ 的预测锚框的回归参数向量
- $t_i^\star$:anchor $i$ 的真实锚框的回归参数向量
- $L_{cls}$:分类损失(二分类交叉熵损失函数)
- $L_{reg}$:回归损失(平滑 L1 损失函数)
- $N_{cls}$:分类损失归一化项(mini-batch 大小)
- $N_{reg}$:回归损失归一化项(论文设置为 2400,实际代码设置为 mini-batch 中正样本数量)
- $\lambda$:平衡权重(论文设置为 10, 实际代码中设置为 1)
2.3.2. 网络结构
下面给出 Faster R-CNN 的网络结构,并逐步拆解分析其前向传播过程。
- (1)特征提取
- 将输入图像缩放至固定大小
M×N,然后送入主干网络(比如VGG16)的 13 个卷积层、13 个 ReLU 激活函数、4 个池化层,得到M/16×N/16×256的特征图。注意,这个特征图包含的锚框数量是M/16×N/16×9个,即特征图上每个像素点都对应着 9 个锚框。接着,特征图分别送入两个分支:RPN 和 ROI 池化。
- 将输入图像缩放至固定大小
- (2)RPN
- 预处理
- 首先经过
3×3×256卷积和激活函数,相当于每个点又融合了周围3×3的空间信息(对于被遮挡的目标至关重要),同时通道数保持不变,特征图尺寸依然为M/16×N/16×256。接着又分为两条线,分别做分类和回归:
- 首先经过
- 分类(上一条线):
- 注意到,特征图包含的锚框数量是
M/16×N/16×9个,每个锚框又是一个(前景/背景)的二分类问题,因此分类分支中必须要将特征转变为M/16×N/16×9行2列的特征矩阵; - 首先经过
1×1×18卷积,得到M/16×N/16×18的三维矩阵,然后经过 Reshape 得到[M/16×N/16×9, 2]二维特征矩阵,即可对每一行做 softmax 激活,得到每个锚框的两个原始分数(logits),第一个分数是属于背景的概率,第二个分数是属于前景(物体)的概率,二者和为 $1$。
- 注意到,特征图包含的锚框数量是
- 回归(下一条线)
- 每个锚框需要预测 $4$ 个偏移量 $t_x, t_y, t_w, t_h$,因此一共需要
M/16×N/16×9×4维度的特征。 - 使用
1×1×36卷积即可一步得到上述维度的特征; - 根据偏移量和预设锚框宽高尺寸,计算得到预测的锚框中心位置和宽高尺寸为:
1 2 3 4
预测框中心x = 锚框中心x + tx × 锚框宽 预测框中心y = 锚框中心y + ty × 锚框高 预测框宽 = 锚框宽 × exp(tw) 预测框高 = 锚框高 × exp(th)
- 应用上述计算完成的预测候选锚框的坐标和尺寸确定。
- 每个锚框需要预测 $4$ 个偏移量 $t_x, t_y, t_w, t_h$,因此一共需要
- 生成最终的候选区域
- 在完成分类和回归两个分支后,我们得到了所有候选框的位置、尺寸、二分类概率;
- 如果不考虑背景分类,那么根据分类分支的前景概率,可先过滤掉概率低的框;
- 对剩余的框进行非极大值抑制(NMS),去除高度重叠的框;
- 最后选择选择前景概率最高的 $n$ 个框(训练时 $n=2000$,测试时 $n=300$)作为候选区域。
- 预处理
- (3)ROI Pooling
- 映射到特征图
- 将 RPN 得到的 $n$ 候选区域的坐标从原图空间映射到特征图空间
- 长宽除以 $2^{stride}$,通道数保持不变(此处为 256)
- 区域裁剪
- 从共享特征图上裁剪出对应区域
- 最大池化
- 将每个区域池化为固定大小(如
7×7)
- 将每个区域池化为固定大小(如
- 输出:
(n, 7, 7, 256)的张量n为候选区域数量7×7为每个候选区域固定池化尺寸256为共享特征图的通道数
- 映射到特征图
- (4)检测头
- 检测头对每个候选区域进行最终的分类和边界框回归。它本质是一个小型全连接网络,接收固定尺寸的特征输入,输出最终的检测结果。
- 特征展平
- 将 ROI 池化输出的
(n, 7, 7, 256)张量展平为(n, 7×7×256)的二维矩阵,其中7×7×256=12544,这是每个候选区域的固定长度特征向量。
- 将 ROI 池化输出的
- 全连接特征提取
- 经过第一个全连接层(fc6),将
12544维特征降维到4096维,后接 ReLU 激活函数和 Dropout(通常 dropout 率为0.5)以防止过拟合。 - 再经过第二个全连接层(fc7),保持
4096维,同样后接 ReLU 和 Dropout。 - 这两个全连接层进一步融合全局信息,将局部区域特征转化为高度抽象的表征,为后续分类和回归提供判别性特征。
- 经过第一个全连接层(fc6),将
- 并行输出分支
- 分类分支
- 从 fc7 输出接一个全连接层,输出维度为
K+1,其中K是目标类别数(如 VOC 数据集的 20 类),加 1 表示背景类。输出尺寸为(n, K+1) - 对该
K+1维向量应用 softmax 激活,得到每个候选区域属于每个类别的概率分布,概率最大的类别即为预测类别。
- 从 fc7 输出接一个全连接层,输出维度为
- 回归分支
- 从 fc7 输出接另一个全连接层,输出维度为
4×(K+1)。 - 每个类别都对应
4个边界框精修参数(Δx, Δy, Δw, Δh),用于对候选区域的坐标进行微调。这些参数与 RPN 中的回归参数意义类似,但此处是针对具体类别的更精细调整。输出尺寸为(n, 4×(K+1)) - 在实际预测时,仅使用预测类别对应的那 4 个偏移量对候选框进行调整,其余类别的偏移量被忽略。
- 从 fc7 输出接另一个全连接层,输出维度为
- 分类分支
2.3.3. 检测头训练
检测头的损失同样由两部分加权组成:分类损失(通常为交叉熵损失)和回归损失(通常为 Smooth L1 损失)。
回归损失仅对非背景类的候选区域计算,背景区域没有边界框真值,因此无需回归。
在端到端训练中,检测头的损失与 RPN 的损失相加,构成 Faster R-CNN 的总损失,通过反向传播同时优化 RPN 和检测头,共享的骨干网络参数也随之更新。
2.3.4. 最终输出
对于每个候选区域,检测头输出:
-
类别标签:K+1 个类别的概率分布,取最大概率对应的类别(若非背景)。
-
精修后的边界框:在原始候选框基础上,应用预测类别的 4 个偏移量,得到更精确的物体位置。
最后,通常还会对所有预测结果进行跨类别的非极大值抑制(NMS),去除重复检测,生成图像最终的检测框及类别标签。
跨类别 NMS(Class-Agnostic NMS))是目标检测后处理中的一个重要步骤,它用于消除不同类别之间可能出现的重叠检测框,生成最终的干净检测结果。
假设一张图像中:
一个检测器预测了一个”汽车”框和”卡车”框,但它们高度重叠
实际上图像中只有一个车辆,但被两个不同类别的检测框覆盖
如果不进行跨类别抑制,会输出两个重叠的检测结果
尽管有过度抑制的风险,但通过合理的阈值选择和算法改进,可以在精度和召回率之间取得良好平衡。在实际应用中,可根据具体场景和数据特性选择合适的NMS策略。
3. YOLO 系列单阶段目标检测
回顾 RCNN 虽然会找到一些候选区域,但毕竟只是候选,等真正识别出其中的对象以后,还要对候选区进行微调,使之更接近真实的 bounding box。这个过程就是边框回归:将候选区bounding box 调整到更接近真实的 bounding box。
既然反正最后都是要调整的,干嘛还要先费劲去寻找候选区呢?大致有个区域范围就行了,按照这个思想就诞生了 YOLO 系列目标检测方法。
3.1. YOLO v1
YOLO(You Only Look Once)是一种开创性的实时目标检测算法,由 Joseph Redmon 等人于2015年提出。核心思想是将目标检测任务转化为单次前向传播的回归问题,通过单个神经网络同时预测目标边界框和类别概率,显著提升了检测速度,适用于对实时性要求高的场景。
3.1.1. 网络结构
下面是 YOLO v1 的网络结构:
去掉候选区这个步骤以后,YOLO 的结构非常简单,就是单纯的卷积、池化最后加了两层全连接。单看网络结构的话,和普通的CNN对象分类网络几乎没有本质的区别,最大的差异是最后输出层用线性函数做激活函数,因为需要预测 bounding box 的位置(数值型),而不仅仅是对象的概率。所以粗略来说,YOLO 的整个结构就是输入图片经过神经网络的变换得到一个输出的张量,如下图所示。
输入就是原始图像,唯一的要求是缩放到 $448\times 448$ 的大小。因为 YOLO v1 网络中的卷积层最后接了两个全连接层,全连接层是要求固定大小的向量作为输入,倒推回去也就要求原始图像有固定的尺寸。
具体来看每个网格对应的 $7\times 7 \times 30$ 维输出向量中包含了哪些信息:
或者另一个版本:
1
2
3
4
5
6
[类别概率] [边界框1] [边界框2]
[20个值] [5个值] [5个值]
↑ ↑ ↑
│ │ └── 第二个边界框:x, y, w, h, confidence
│ └── 第一个边界框:x, y, w, h, confidence
└── 20个类别的条件概率 P(class|object)
- 类别预测:$20$ 个类别的概率向量(PASCAL VOC数据集有20类);
- 边界框预测:每个网格预测
B=2个边界框,每个框包含5个值(x,y,w,h,confidence);- 边界框中心坐标 (x, y):
- 激活函数:
Sigmoid - 作用:将输出约束在
(0, 1)之间,表示相对于该网格单元左上角的偏移比例。例如,(0.5, 0.5) 表示物体中心位于该网格的正中央。
- 激活函数:
- 边界框宽高 (w, h):
- 激活函数:在v1原文描述中,这里使用的是线性输出(未用激活函数限制),但会通过图像宽高进行归一化。
- 作用:预测边界框相对于整张图像的尺度。有些实现为了确保正值,会采用 exp() 函数处理,但原论文未明确提及,直接使用了线性输出。
- 置信度 (confidence):
- 激活函数:
Sigmoid - 作用:表示该边界框包含一个物体的概率,与类别无关。值在 (0, 1) 之间。
- 思考:反向传播时,置信度标签如何给定? 损失函数中设计两个指示函数
- 激活函数:
- 类别条件概率 (class scores):
- 激活函数:
Softmax - 作用:对每个网格单元,其 20 个类别输出通过 Softmax 激活,确保和为1。这表示 “如果这个网格里有物体,它属于各个类别的概率”。
- 激活函数:
- 边界框中心坐标 (x, y):
思考:YOLO v1 一张图片最多能识别多少个对象?
YOLO v1 默认最多可以识别 $S^2$ 个对象,其中 $S$ 是网格大小,默认为 $7$。每个网格可以预测 $B$ 个边界框,默认为 $2$。网格会从自己预测的 $B=2$ 个边界框中,挑选出与真实物体边界框交并比(IoU)更高的那一个,作为最终预测框。
3.1.2. 损失函数
YOLO v1 的损失函数为:
\[\begin{aligned} L_{\text{total}} = & \lambda_{\text{coord}} \sum_{i=0}^{S^2} \sum_{j=0}^{B} \mathbf{1}_{ij}^{\text{obj}} \left[ (x_i - \hat{x}_i)^2 + (y_i - \hat{y}_i)^2 \right] \\ &+ \lambda_{\text{coord}} \sum_{i=0}^{S^2} \sum_{j=0}^{B} \mathbf{1}_{ij}^{\text{obj}} \left[ \left( \sqrt{w_i} - \sqrt{\hat{w}_i} \right)^2 + \left( \sqrt{h_i} - \sqrt{\hat{h}_i} \right)^2 \right] \\ &+ \sum_{i=0}^{S^2} \sum_{j=0}^{B} \mathbf{1}_{ij}^{\text{obj}} (C_i - \text{IoU}_i)^2 \\ &+ \lambda_{\text{noobj}} \sum_{i=0}^{S^2} \sum_{j=0}^{B} \mathbf{1}_{ij}^{\text{noobj}} (C_i - 0)^2 \\ &+ \sum_{i=0}^{S^2} \mathbf{1}_{i}^{\text{obj}} \sum_{c \in \text{classes}} (p_i(c) - \hat{p}_i(c))^2 \end{aligned}\]其中:
- $S \times S$: 图像被划分的网格数(通常 $S=7$,共$49$个网格)。
- $B$: 每个网格预测的边界框数量(YOLOv1中 $B=2$)。
- $\mathbf{1}_{i}^{\text{obj}}$: 指示函数,当第 $i$ 个网格包含某个真实物体的中心点时,其值为1;否则为0。控制「分类损失」是否生效。
- $\mathbf{1}_{ij}^{\text{obj}}$: 指示函数,当第 $i$ 个网格的第 $j$ 个预测框被分配负责预测某个真实物体时,其值为1;否则为0。控制「坐标损失」与「前景置信度损失」是否生效。选择与真实目标边界框的 IoU 更大的那个框置为 1;
- $\mathbf{1}_{ij}^{\text{noobj}}$: 指示函数,当第 $i$ 个网格的第 $j$ 个预测框不负责任何真实物体(即背景框)时,其值为 1;否则为 0。控制「背景置信度损失」是否生效。选择与真实目标边界框的 IoU 更小的那个框置为 1;
- $(x_i, y_i, w_i, h_i)$: 预测边界框的中心坐标(相对于网格左上角)和宽高(相对于整图)。
- $(\hat{x}_i, \hat{y}_i, \hat{w}_i, \hat{h}_i)$: 真实边界框(Ground Truth)的对应值。
- $C_i$: 预测框的置信度(Confidence Score)。
- $p_i(c)$: 预测的第 $i$ 个网格属于类别 $c$ 的条件概率。
- $\hat{p}_i(c)$: 真实的类别标签(one-hot向量形式)。
- $\lambda_{\text{coord}}$: 坐标损失的权重系数(论文中设为 $5$),用于提升定位精度的重要性。
- $\lambda_{\text{noobj}}$: 背景框置信度损失的权重系数(论文中设为 $0.5$),用于减轻大量简单负样本对训练的主导。
思考:损失函数中,候选区域中心坐标损失、当第某个预测框不包含任何物体时,三个指示函数怎么设置?
均设为0。下面对损失函数的每个部分分别展开详细阐述:
- 候选区域中心坐标损失
迫使“负责”预测框的中心尽可能接近真实框中心。
- 候选区域宽高损失
对宽高取平方根再计算误差,使网络对「小物体」的尺寸误差更敏感,优化小物体检测。
- 包含物体的置信度损失
迫使“负责”框的预测置信度 $C_i$ 接近预测框与真实框的 IoU。
思考:为什么不直接使用 1 取代置信度损失中的 IoU 作为标签?
如果把标签设为 1,网络会认为所有正样本的置信度都应该接近1,无法区分定位好坏的框。我们希望网络可以学习预测定位质量,这样推理时高置信度应反映高 IoU,否则无法评判预测输出的 $B$ 个框谁好谁坏。- 不包含物体的置信度损失
迫使背景框的预测置信度 $C_i$ 接近 $0$。$\lambda_{\text{noobj}} < 1$ 防止简单负样本主导训练。
- 分类损失
迫使包含物体中心的网格预测出正确的类别概率分布。注意,
- 分类是以网格为单位,与具体是哪个边界框无关。
- 对于有对象的网格,分类的误差采用与标签的 one-hot 向量进行作差然后求平方,即把分类问题当作回归问题计算 MSE 损失。
3.1.3. 前向推理
先筛选掉低置信度的框(如 Ci < 0.25),然后对每个类别的条件概率(前 20 维特征)计算最终的类别得分(class score):
也就是说,每一个网格的 $B=2$ 个边界框都有 $K=20$ 个类别的得分。
一个常见的误区是:既然每个网格单元共享同一组20维类别概率,为何不直接把 置信度阈值 低的边界框删除,只用置信度阈值高的边界框呢?
下面举一个极例子说明:
1 2 3 4 5 class_probs=[猫:0.9, 狗:0.1] grid_A_box1: confidence=0.6 grid_A_box2: confidence=0.4 猫的得分: [0.54, 0.36] 狗的得分: [0.32, 0.04] <--highest dog at 1st value
1 2 3 4 5 class_probs=[猫:0.8, 狗:0.2] grid_A_box1: confidence=0.7 grid_A_box2: confidence=0.3 猫的得分: [0.56, 0.24] <--highest cat at 1st value 狗的得分: [0.14, 0.06]如果直接删除置信度阈值低的边界框,就会丢失最高的 狗 的得分。
最后,对于每个类别根据 类别得分 分别进行 NMS。
3.1.4. 讨论
YOLOv1 的设计哲学是:每个网格单元(grid cell)在训练阶段最多只负责预测一个物体。无论一个网格里实际有多少个物体,模型都只会为这个网格输出一组类别概率和一个最有可能的边界框(从该网格预测的 $2$ 个框中选一个)。
如果一个物体的中心点落在了某个网格内,那么这个网格就获得了预测该物体的“责任”。该网格会从自己预测的 $2$ 个边界框中,挑选出置信度(与真实物体边界框交并比)更高的那一个,作为最终预测框。该网格的类别预测则指向这个物体的类别。
因此产生根本限制:如果两个或多个物体的中心点非常接近,以至于落在了同一个网格内,那么YOLOv1就只能检测出其中一个(通常是IoU更高的,或损失函数训练后选定的那一个)。
这是YOLOv1召回率较低(即容易漏检物体)的主要原因,特别是在处理密集、小物体的场景时,这个问题会非常突出。
3.2. YOLO v2
YOLO v1 虽然实现了端到端的实时目标检测,但存在明显短板:定位精度不足、召回率低(密集小物体漏检严重)、对尺度变化敏感。针对这些问题,Joseph Redmon 团队于 2016 年提出 YOLO v2(又称 YOLO9000),核心目标是在保持实时性的前提下,提升检测精度和召回率,同时支持更多类别检测(9000 种类别)。
YOLO v2 的设计围绕 “Better、Faster、Stronger” 三大方向展开:
- Better:通过一系列网络和训练策略优化,提升检测精度;
- Faster:设计轻量级骨干网络,进一步提升推理速度;
- Stronger:提出联合训练策略,实现 9000+ 类别的通用目标检测。
- 相比 YOLO v1,改进如下表所示。
3.2.1. 网络结构改进
YOLO v2 的主干网络换成 Darknet-19,包含 19 个卷积层和 5 个最大池化层,比 VGG-16 小一些,精度不弱于它,但浮点运算减少到约 1/5,运算速度更快。
- 移除全连接层
很长一段时间以来,全连接网络一直是 CNN 分类网络的标配结构。一般在全连接后会有激活函数来做分类,假设这个激活函数是一个多分类 softmax,那么全连接网络的作用就是将最后一层卷积得到的特征图展平成向量,对这个向量做乘法,最终降低其维度,然后输入到 softmax 层中得到对应的每个类别的得分。
全连接层如此的重要,以至于全连接层过多的参数重要到会造成过拟合,所以也会有一些方法专门用来解决过拟合,比如 dropout。
YOLO v2 移除了全连接层,而是采用全局平均池化(Global Average Pooling)层对整个特征图求平均值,得到和通道数维度一致的输出向量进行分类。
移除全连接层可以:
- 摆脱了固定尺寸的 FC 对输入图像尺寸的约束,可以适应各种尺寸的输入图像。
- 剔除了 FC 的黑箱特性,直接赋予每个 channel 实际意义。
因为整个网络下采样倍数是32,作者采用了 {320,352,…,608} 等 10 种输入图像的尺寸,这些尺寸的输入图像对应输出的特征图宽和高是 {10,11,…19}。训练时每10个batch就随机更换一种尺寸,使网络能够适应各种大小的对象检测。
全局平均池化已经在 前述章节 (人工智能基础 - CNN 目标检测 - 全局平均池化)进行了介绍,此处不在赘述。
- 移除一个池化层
去掉了一个池化层,使网络卷积层输出具有更高的分辨率。
- 引入批归一化
该主干网络中的每个卷积层中还引入了 批归一化 稳定训练,加快收敛,防止过拟合。同时放弃了 dropout。批归一化有助于解决反向传播过程中的梯度消失和梯度爆炸问题,降低对一些超参数(比如学习率、网络参数的大小范围、激活函数的选择)的敏感性,并且每个 batch 分别进行归一化的时候,起到了一定的正则化效果(YOLO v2 不再使用 dropout),从而能够获得更好的收敛速度和收敛效果。
通常,一次训练会输入一批样本(batch)进入神经网络。批规一化在神经网络的每一层,在网络(线性变换)输出后和激活函数(非线性变换)之前增加一个批归一化层(BN),BN层进行如下变换:
- 对该批样本的各特征量(对于中间层来说,就是每一个神经元)分别进行归一化处理,分别使每个特征的数据分布变换为均值 0,方差 1。从而使得每一批训练样本在每一层都有类似的分布。这一变换不需要引入额外的参数。
- 对上一步的输出再做一次线性变换,假设上一步的输出为Z,则 $Z_1=\gamma Z + \beta$。这里γ、β是可以训练的参数。增加这一变换是因为上一步骤中强制改变了特征数据的分布,可能影响了原有数据的信息表达能力。增加的线性变换使其有机会恢复其原本的信息。
批归一化已经在 前述章节 (模式识别 - CNN - 批归一化层)中进行了详细介绍,此处不再赘述。
批归一化使 YOLO v2 相比于 YOLO v1 的 mAP 有 2.4% 的提升。
- 高分辨率分类器
图像分类的训练样本很多,而标注了边框的用于训练对象检测的样本相比而言就比较少了,因为标注边框的人工成本比较高。所以对象检测模型通常都先用图像分类样本训练卷积层,提取图像特征。但这引出的另一个问题是,图像分类样本的分辨率不是很高。所以YOLO v1使用ImageNet的图像分类样本采用 224 x 224 作为输入,来训练CNN卷积层。然后在训练对象检测时,检测用的图像样本采用更高分辨率的 448 x 448 的图像作为输入。但这样切换对模型性能有一定影响。
所以YOLO2在采用 224 x 224 图像进行分类模型预训练后,再采用 448 x 448 的高分辨率样本对分类模型进行微调(10个epoch),使网络特征逐渐适应 448 x 448 的分辨率。然后再使用 448 x 448 的检测样本进行训练,缓解了分辨率突然切换造成的影响。
YOLO v2 的训练主要包括两个阶段。第一阶段就是先在 ImageNet 分类数据集上预训练 Darknet-19,此时模型输入为 224 x 224 ,共训练 160 个 epochs。然后第二阶段将网络的输入调整为 448 x 448 ,继续在 ImageNet 数据集上 finetune 分类模型,训练 10 个 epochs,此时分类模型的 top-1 准确度为 76.5%,而 top-5 准确度为 93.3%。
通过使用高分辨率分类器,使得 mAP 提升了 3.7%。
3.2.2. 引入锚框并聚类改进
借鉴 Faster R-CNN 的做法,YOLO v2 也尝试采用锚框(anchor)。在每个网格预先设定一组不同大小和宽高比的边框,来覆盖整个图像的不同位置和多种尺度,这些锚框作为预定义的候选区(被称为先验眶)在神经网络中将检测其中是否存在对象,以及微调边框的位置。
之前 YOLO v1 并没有采用先验框,并且每个网格只预测两个 bounding box,整个图像 98 个。YOLO v2 如果每个网格采用 9 个先验框,总共有 $13\times 13\times 9=1521$ 个先验框。
召回率大幅提升到88%,同时mAP轻微下降了0.2%。不过 YOLO v2 接着进一步对先验框进行了改良。之前先验框都是手工设定的,YOLO2尝试统计出更符合样本中对象尺寸的先验框,这样就可以减少网络微调先验框到实际位置的难度。YOLO v2 对训练集中标注的边框进行聚类分析,以寻找尽可能匹配样本的边框尺寸。
聚类算法最重要的是选择如何计算两个边框之间的“距离”,对于常用的欧式距离,大边框会产生更大的误差,但我们关心的是边框的IoU。所以,YOLO v2 在聚类时采用以下公式来计算两个边框之间的 “距离”。
\[d(box,centroid) = 1- \text{IoU}(box, centroid)\]$centroid$ 是聚类时被选作中心的边框,$box$ 就是其它边框,$d$ 就是两者间的 “距离”。IoU 越大,“距离” 越近。聚类分析结果如下图所示:
上图左边是选择不同的聚类 k 值情况下,得到的 k 个 centroid 边框,计算样本中标注的边框与各 centroid 的 Avg IoU。显然,边框数 k 越多,Avg IoU 越大。YOLO v2 选择 k=5 作为边框数量与 IoU 的折中。对比手工选择的先验框,使用 5 个聚类框即可达到 61 Avg IoU,相当于 9 个手工设置的先验框 60.9 Avg IoU。
上图右边显示了 5 种聚类得到的先验框,VOC 和 COCO 数据集略有差异,不过都有较多的瘦高形边框。
3.2.3. 约束预测框位置
借鉴于 Faster RCNN 的先验框方法,其预测变量为:
\[\begin{cases} t_x=\frac{G_x - P_x}{P_w}\\ t_y=\frac{G_y - P_y}{P_h}\\ t_w=\ln(\frac{G_w}{P_w})\\ t_h=\ln(\frac{G_h}{P_h}) \end{cases}\]对其稍加变换并改变其中一些符号,得到位置预测公式为:
\[x = (t_x \cdot w_a) + x_a\\ y = (t_y \cdot h_a) + y_a\]其中,$P_x=x_a, P_y=y_a$ 是先验框中心,$P_w=w_a, P_h=h_a$ 是先验框宽高,$x,y$ 是预测框中心,$t_x, t_y$ 是待学习参数。
由于 $t_x, t_y$ 没有任何约束,因此预测框的中心可能出现在任何位置。训练早期阶段不容易稳定。因此 YOLO v2 调整了预测公式,将预测框中心约束在特定的网格内。
\[x = \sigma (t_x) + c_x\\ y = \sigma (t_y) + c_y\\ w = w_a e^{t_w}\\ h = h_a e^{t_h}\\ \text{Pr}(obj)\cdot \text{IoU}(b, obj) = \sigma (t_o)\]式中,$t_x, t_y, t_w, t_h, t_o$ 是待学习参数。
$c_x, x_y$ 是当前网格左上角到图像左上角的距离,要先将网格大小归一化,即令一个网格的宽=1,高=1。$\sigma$ 即 sigmoid 函数,可以将 $[-\infty,+\infty]$ 的 $t_x, t_y$ 映射到 $[0,1]$,从而约束在了当前网格内(蓝色区域)。
对于预测框的宽高,采用指数函数,将 $[-\infty,+\infty]$ 的 $t_w, t_h$ 映射到 $[0,+\infty]$,此时 $t=0$ 对应 $e^t=1$ ,则预测框宽高就等于原始宽高,相当于让参数围绕 0 附近波动,更好学习。
引入先验框和约束预测框位置,使得 mAP 有 4.8% 的提升。
对于置信度,YOLO v1 直接预测置信度的值,而 YOLO v2 预测 $t_o$,要经过 sigmoid 变换作为置信度的值。
3.2.4. pass through
为了更好的检测出一些比较小的对象,最后输出的特征图需要保留一些更细节的信息。
YOLO v2 引入一种称为 pass through 层的方法,在特征图中保留一些细节信息。具体来说,就是在最后一个 pooling 之前,特征图的大小是 26 x 26 x 512,将其 1 拆 4,直接传递(passthrough)到 pooling 后(并且又经过一组卷积)的特征图,两者叠加到一起作为输出的特征图。
由于之后的 YOLO v3 等不再运用,此处就不介绍了。
























