深度学习之目标检测(七)YOLOv2理论介绍
本章学习 YOLO v2 相关理论知识,学习视频源于 Bilibili,部分参考叙述源自 知乎 。
1. YOLO v2
YOLO v2 论文为发表于 2017 CVPR 的 YOLO9000:Better,Faster,Stronger。为什么叫 YOLO9000?因为作者通过 YOLOv2 使用 PASCAL 数据集和 ImageNet 联合训练,最终能够检测的类别可以超过 9000。 相较于 YOLOv1 能达到的 45 FPS 以及 63.4 mAP,YOLOv2 在 PASCAL VOC 数据集上达到了 78.6 的 mAP 以及 40 FPS,其中输入为 $544 \times 544$。比较常用的还是 YOLOv2 $416 \times 416$ 输入。
YOLOv2 在 YOLO v1 的基础上进行的各种尝试包括(原论文 Better 章节),在改进中遵循一个原则:保持检测速度,这也是YOLO模型的一大优势。:
- Batch Normalization
- High Resolution Classifier
- Convolutional with Anchor Boxes
- Dimension Clusters
- Direct location prediction
- Fine-Grained Features
- Multi-Scale Training
接下来依次讲解这七点尝试带来的效果。
1.1 Batch Normalization
在 YOLOv1 中作者搭建网络时没有用 BN 层,在 YOLOv2 中每个卷积层后使用 BN 层,对于训练收敛有很大帮助,也减少了所需正则化处理,达到了 2% mAP 的提升,帮助模型取得了正则化的效果,还能移除掉 Dropout 层了。
1.2 High Resolution Classifier
目前大部分的检测模型都会在先在 ImageNet 分类数据集上预训练模型的 backbone(CNN特征提取器),由于历史原因,ImageNet 分类模型基本采用大小为 $224 \times 224$ 的图片作为输入,分辨率相对较低,不利于检测模型。所以YOLOv1在采用 $224 \times 224$ 输入预训练后,将分辨率增加至 $448 \times 448$ ,并使用这个高分辨率在检测数据集上 finetune。但是直接切换分辨率,检测模型可能难以快速适应高分辨率。所以 YOLOv2 采用更高分辨率的分类器,这个思想也很自然。在 YOLOv1 中作者最开始训练 backbone 的时候是在 ImageNet 上使用 $224 \times 224$ 的图像输入,而在 YOLOv2 中,作者使用更大的输入尺寸 $448 \times 448$ 在 ImageNet 上预训练。采用更大分辨率的分类器为我们带来了 4% mAP 提升。
1.3 Convolutional with Anchor Boxes
在 YOLOv1 中直接预测宽度高度和中心坐标,由于各个图片中存在不同尺度和长宽比(scales and ratios)的物体,YOLOv1 在训练过程中学习适应不同物体的形状是比较困难的,这导致定位效果差。这里作者尝试使用基于 Anchor 的目标边界框的预测方式。采用基于 Anchor 偏移的预测比直接预测坐标而言更简单,也能使得网络更加容易学习和收敛。YOLOv2 移除了 YOLOv1 中的全连接层而采用了卷积和 anchor boxes 来预测边界框。为了使检测所用的特征图分辨率更高,移除其中的一个 pool 层。在检测模型中,YOLOv2 不是采用 $448 \times 448$ 大小的图片作为输入,而是采用 $416 \times 416$ 大小。因为 YOLOv2 模型下采样的总步长为 32,对于 $416 \times 416$ 大小的图片,最终得到的特征图大小为 $13 \times 13$ ,维度是奇数,这样特征图恰好只有一个中心位置。对于一些大物体,它们中心点往往落入图片中心位置,此时使用特征图的一个中心点去预测这些物体的边界框相对容易些。所以在 YOLOv2 设计中要保证最终的特征图有奇数个位置。对于YOLOv1,每个 cell 都预测 2 个 bounding boxes,每个 bounding boxes 包含5个值:(x, y, w, h, confidence),前 4 个值是边界框位置与大小,最后一个值是置信度(包含两部分:含有物体的概率以及预测框与 ground truth 的 IOU 的乘积)。然而每个 cell 只预测一套分类概率值(class predictions,其实是置信度下的条件概率值),由两个 bounding boxes 共享。YOLOv2 使用了 Anchor boxes 之后,每个位置的各个 anchor box 都单独预测一套分类概率值,这和 SSD 比较类似(但 SSD 没有预测置信度,而是把 background 作为一个类别来处理)。
在没有使用 Anchor 的时候,模型取得了 69.5 mAP 的结果和 81% 的召回率。使用 Anchor 之后得到的模型取得了 69.2 mAP 以及 88% 的召回率。虽然 mAP 有略微下降,但是模型的召回率有了 7% 的提升,这意味着模型有了更大的进步空间。实际上,YOLOv1 只能预测 $7 \times 7 \times 2 = 98$ 个 bounding box,而 YOLOv2 则使用 Anchor boxes 之后能预测上千个边界框($13 \times 13 \times$ num_anchors),所以召回率大大提升咯。为什么 mAP 下降暂时不太清楚?
1.4 Dimension Clusters
Anchor 的聚类。 之前在讲解 Faster R-CNN 以及 SSD 的时候,作者并没有明确地给出我们为什么要采用那些作者给定的 Anchor 或者 Default Box。虽然在 SSD 中给了公式,但是意义似乎并不是特别明确。在 Faster R-CNN 中也是说根据工程经验给定的。其实这个经验对于一般人而言是没有的。这里作者使用 k-means 的方法从训练集中进行聚类得到所谓的 priors(其实就是 Anchor 或者 Default box)。
因为设置先验框的主要目的是为了使预测框与 ground truth 的 IoU 更好,所以聚类分析时选用 box 与聚类中心 box 之间的 IoU 值作为距离指标:
下图为在 VOC 和 COCO 数据集上的聚类分析结果,随着聚类中心数目的增加,平均 IoU 值(各个边界框与聚类中心的IoU的平均值)是增加的,但是综合考虑模型复杂度和召回率,作者最终选取 5 个聚类中心作为先验框,其相对于图片的大小如右边图所示。对于两个数据集,5 个先验框的 width 和 height 如下所示(来源:YOLO源码的 cfg文件):
COCO anchors = (0.57273, 0.677385), (1.87446, 2.06253), (3.33843, 5.47434), (7.88282, 3.52778), (9.77052, 9.16828)
VOC anchors = (1.3221, 1.73145), (3.19275, 4.00944), (5.05587, 8.09892), (9.47112, 4.84053), (11.2364, 10.0071)
尽管先验框的大小具体指什么作者并没有说明,但肯定不是像素点,从代码实现上看,应该是相对于预测的特征图大小( $13 \times 13$ )
通过对比两个数据集的 Anchor 尺寸可见,COCO 数据集上的物体相对小点,Pascal VOC 数据集的物体相对大点。这个策略作者并没有单独做实验,但是作者对比了采用聚类分析得到的先验框与手动设置的先验框在平均 IOU 上的差异,发现前者的平均 IOU 值更高,因此模型更容易训练学习。
1.5 Direct location prediction
作者谈到基于 Anchor 的训练过程中,网络初期出现不稳定的情况,主要是由于坐标偏移量 x 和 y 的预测导致的。x 和 y 没有增加任何约束,预测的边界框很容易向任何方向偏移,如当 $t_x = 1$ 时边界框将向右偏移先验框的一个宽度大小,而当 $t_x = -1$ 时边界框将向左偏移先验框的一个宽度大小,这使得可以将一个 Anchor 预测到图片的任何一个地方,例如下图中左上角的 Anchor 被回归参数调整到了右下角去。事实上右下角根本轮不到这个 Anchor 来进行预测。为此在训练时需要很长时间来学习预测出正确的 offsets。(注意,原论文的公式使用减号是错误的,和 Faster R-CNN 以及 SSD 中描述的公式不符合,应该是加号才对) \(\begin{array}{c} x=\left(t_{x} \times w_{a}\right)+x_{a} \\ y=\left(t_{y} \times h_{a}\right)+y_{a} \end{array}\)
在 YOLOv2 中作者就为了改善这种情况,于是弃用了这种预测方式,而是沿用 YOLOv1 的方法,就是预测边界框中心点相对于对应 cell 左上角位置的相对偏移值,为了将边界框中心点约束在当前 cell 中,使用 sigmoid 函数处理偏移值,这样预测的偏移值在 (0,1) 范围内(每个 cell 的尺度看做 1)。保证每个 anchor(prior) 去预测目标中心落在某个 grid cell 区域的目标。总结来看,根据边界框预测的 4 个 offsets $t_x, t_y, t_w, t_h$,可以按如下公式计算出边界框实际位置和大小: \(\begin{array}{c} b_{x}=\sigma\left(t_{x}\right)+c_{x} \\ b_{y}=\sigma\left(t_{y}\right)+c_{y} \\ b_{w}=p_{w} e^{t_{w}} \\ b_{h}=p_{h} e^{t_{h}} \end{array}\) 其中 $(c_x, c_y)$ 为 cell 的左上角坐标,如下图所示,在计算时每个 cell 的尺度为 1,所以当前 cell 的左上角坐标为 。由于 sigmoid 函数的处理,边界框的中心位置会约束在当前 cell 内部,防止偏移过多。而 $p_w$ 和 $p_h$ 是先验框的宽度与长度,前面说过它们的值也是相对于特征图大小的,在特征图中每个 cell 的长和宽均为1。这里记特征图的大小为(W, H),在文中是(13, 13),这样我们可以将边界框相对于整张图片的位置和大小计算出来( 4 个值均在 0 和 1 之间): \(\begin{array}{c} b_{x}=\left(\sigma\left(t_{x}\right)+c_{x}\right) / W \\ b_{y}=\left(\sigma\left(t_{y}\right)+c_{y}\right) / H \\ b_{w}=p_{w} e^{t_{w}} / W \\ b_{h}=p_{h} e^{t_{h}} / H \end{array}\) 如果再将上面的 4 个值分别乘以图片的宽度和长度就可以得到边界框的最终位置和大小了。这就是 YOLOv2 边界框的整个解码过程。约束了边界框的位置预测值使得模型更容易稳定训练,结合聚类分析得到先验框与这种预测方法,YOLOv2 获得了的约 5% mAP 的提升。
补充一句:预测得到的 confidence 值 $t_o$ 也需要经过 sigmoid 进行范围限制: \(Pr(\text{object}) * IOU(b, \text{object}) = \sigma(t_o)\) 最终 predictor 的个数是 $(5 + 20) \times 5$,这最后的 5 就是 5 个 Anchor(prior)。
1.6 Fine-Grained Features
YOLOv2 的输入图片大小为 $416 \times 416$ ,经过 5 次 maxpooling 之后得到 $13 \times 13$ 大小的特征图,并以此特征图采用卷积做预测。 $13 \times 13$ 大小的特征图对检测大物体是足够了,但是对于小物体还需要更精细的特征图(Fine-Grained Features),也就是更低层的特征图。在之前讲解的 SSD 中使用了多尺度的特征图来分别检测不同大小的物体,前面更精细的特征图可以用来预测小物体,后面的更高级语意的特征图用来预测大物体。
YOLOv2 提出了一种 passthrough 层来利用更精细的特征图。具体而言,YOLOv2 所利用的 Fine-Grained Features是 $26 \times 26$ 大小的特征图(即最后一个 maxpooling 层的输入),对于 Darknet-19 模型来说就是大小为 $26 \times 26 \times 512$ 尺寸的特征图。passthrough 层以前面更高分辨率的特征图为输入,然后将其连接到后面的低分辨率特征图上。前面的特征图维度是后面的特征图的 2 倍,passthrough 层抽取前面层的每个 $2 \times 2$ 的局部区域,然后将其转化为 channel 维度,对于 $26 \times 26 \times 512$ 尺寸的特征图,经 passthrough 层处理之后就变成了 $13 \times 13 \times 2048$ 的新特征图(特征图大小降低 4 倍,而 channles 增加 4 倍,下图为一个实例),这样就可以与后面的 $13 \times 13 \times 1024$ 特征图连接在一起形成 $13 \times 13 \times 3072$ 大小的特征图,然后在此特征图基础上卷积做预测。
此外,作者在后期的实现中借鉴了 ResNet 网络,不是直接对高分辨特征图处理,而是增加了一个中间卷积层,先采用 64 个 $1 \times 1$ 卷积核进行卷积,然后再进行 passthrough 处理,这样 $26 \times 26 \times 512$ 的特征图首先得到 $26 \times 26 \times 64$ 再得到 $13 \times 13 \times 256$ 的特征图,与后面的 $13 \times 13 \times 1024$ 特征图连接在一起形成 $13 \times 13 \times 1280$ 大小的特征图。这在原论文中没有提到,也算是实现上的一个小细节。使用 Fine-Grained Features 之后 YOLOv2 的性能有 1% 的提升。
1.7 Multi-Scale Training
采用多尺度训练方法,替换固定尺寸训练。作者认为采用固定尺寸网络的鲁棒性是受限的,所以作者在训练中将图片缩放到不同尺度来训练模型。每迭代 10 个 batches,就将输入尺寸进行随机选择。由于 YOLOv2 的缩放因子为 32,所以尺寸为 32 的倍数,采用了从 320 到 608 的尺寸。 注意到,当输入图片为 $320 \times 320$ 时,特征图大小为 $10 \times 10$ 不是奇数了,有点尴尬….
采用 Multi-Scale Training 策略,YOLOv2 可以适应不同大小的图片,并且预测出很好的结果。在测试时,YOLOv2 可以采用不同大小的图片作为输入,在 VOC 2007 数据集上的效果如下图所示。可以看到采用较小分辨率时,YOLOv2 的 mAP 值略低,但是速度更快,而采用高分辨输入时,mAP 值更高,但是速度略有下降,对于 $544 \times 544$ 的输入图,mAP 高达 78.6%。值得注意的是,这只是测试时输入图片大小不同,而实际上用的是同一个采用Multi-Scale Training训练得到的模型。
2. Darknet-19
作者在 Faster 章节提到了新的 backbone 网络,即 Darknet-19。·19 其实是说该网络有 19 个卷积层,然后还有 5 个 maxpooling 层。Darknet-19 与 VGG16 模型设计原则是一致的,主要采用 $3 \times 3$ 卷积,采用 $2 \times 2$ 的maxpooling层之后,特征图维度降低 2 倍,而同时将特征图的 channles 增加两倍。与 NIN(Network in Network) 类似,Darknet-19 最终采用 global avgpooling 做预测,并且在 $3 \times 3$ 卷积之间使用 $1 \times 1$ 卷积来压缩特征图 channles 以降低模型计算量和参数。Darknet-19 每个卷积层后面同样使用了 BN 层以加快收敛速度,降低模型过拟合。在 ImageNet 分类数据集上,Darknet-19 的 top-1 准确度为 72.9%,top-5 准确度为 91.2%,但是模型参数相对小一些。
使用 Darknet-19 之后,YOLOv2 的 mAP 值没有显著提升,但是计算量却可以减少约 33%。最终 predictor 的个数是 $(5 + 20) \times 5$,这最后的 5 就是 5 个 Anchor(prior),前面的 20 是类别分数,还有个 5 是 $t_x, t_y, t_w, t_h, t_o$。
3. 训练细节
如何匹配正负样本?论文没有讲。
如何计算误差?论文没有讲。
可能作者想让我们膜拜代码……
总有人膜拜代码后嚼烂了喂给我们吃……
知乎专栏 详细介绍了 YOLOv2 的训练。YOLOv2 的训练主要包括三个阶段。第一阶段就是先在 ImageNet 分类数据集上预训练 Darknet-19,此时模型输入为 $224 \times 224$,共训练 160 个epochs。然后第二阶段将网络的输入调整为 $448 \times 448$,继续在 ImageNet 数据集上finetune分类模型,训练 10 个epochs,此时分类模型的 top-1 准确度为 76.5%,而 top-5 准确度为 93.3%。第三个阶段就是修改Darknet-19 分类模型为检测模型,并在检测数据集上继续 finetune 网络。网络修改包括:移除最后一个卷积层、global avgpooling 层以及 softmax 层,并且新增了三个 $3 \times 3 \times 1024$ 的卷积层,同时增加了一个 passthrough层 ,最后使用 $1 \times 1$ 卷积层输出预测结果。由于 anchors 数为 5,对于 VOC 数据集输出的channels数就是 125 ,而对于COCO数据集则为 425。这里以 VOC 数据集为例,最终的预测矩阵为 T(shape为(batchsize, 13, 13, 125)),可以先将其 reshape 为(batchsize, 13, 13, 5, 25) ,其中 T[:,:,:,:,0:4] 为边界框的位置和大小 $(t_x, t_y, t_w, t_h)$,T[:,:,:,:,4] 为边界框的置信度 $t_o$,而 T[:,:,:,:,5:] 为类别预测值。
基于 YOLOv2 在 TensorFlow 上的实现 darkflow(见 yolov2/train.py),发现它就是如此处理的:和 YOLOv1 一样,对于训练图片中的ground truth,若其中心点落在某个 cell 内,那么该 cell 内的 5 个先验框所对应的边界框负责预测它,具体是哪个边界框预测它,需要在训练中确定,即由那个与 ground truth 的 IOU 最大的边界框预测它,而剩余的 4 个边界框不与该 ground truth 匹配。YOLOv2 同样需要假定每个 cell 至多含有一个 grounth truth,而在实际上基本不会出现多于 1 个的情况 (稠密小目标问题依然没有解决)。与 ground truth 匹配的先验框计算坐标误差、置信度误差(此时 target 为 1)以及分类误差,而其它的边界框只计算置信度误差(此时 target 为0)。基本上 YOLOv2 和 YOLOv1的损失函数一样,为均方差函数。
参考国外的 blog 以及 allanzelener/YAD2K(Ng深度学习教程所参考的那个Keras实现)上的实现,发现 YOLOv2 的处理比原来的 v1 版本更加复杂。先给出loss计算公式:
我们来一点点解释(此处参考YOLO v2 损失函数源码分析),首先 W,H 分别指的是特征图($13 \times 13$)的宽与高,而 A 指的是先验框数目(这里是5),各个 $\lambda$ 值是各个 loss 部分的权重系数。
- 第一项 loss 是计算 background 的置信度误差,但是哪些预测框来预测背景呢,需要先计算各个预测框和所有ground truth 的 IOU 值,并且取最大值 Max_IOU,如果该值小于一定的阈值(YOLOv2 使用的是 0.6,即与所有的 ground truth 的IOU 都小于 0.6),那么这个预测框就标记为 background,需要计算 noobj 的置信度误差。
- 第二项是计算先验框与预测宽的坐标误差,但是只在前 12800 个 iterations 间计算,这项应该是在训练前期使预测框快速学习到先验框的形状。
- 第三项计算与某个 ground truth 匹配的预测框各部分 loss 值,包括坐标误差、置信度误差以及分类误差。
- 匹配原则是对于某个 ground truth,首先要确定其中心点要落在哪个 cell 上,然后计算这个 cell 的 5 个先验框与 ground truth 的 IOU 值(YOLOv2 中 bias_match=1),计算 IOU 值时不考虑坐标,只考虑形状,所以先将先验框与 ground truth 的中心点都偏移到同一位置(原点),然后计算出对应的 IOU 值,IOU 值最大的那个先验框与 ground truth 匹配,对应的预测框用来预测这个 ground truth。
- 在计算 obj 置信度时,target=1,但与 YOLOv1 一样而增加了一个控制参数 rescore,当其为 1 时,target 取预测框与 ground truth 的真实 IOU 值(cfg文件中默认采用这种方式)。对于那些没有与 ground truth 匹配的先验框(与预测框对应),除去那些 Max_IOU 低于阈值的,其它的就全部忽略,不计算任何误差。这点在 YOLOv3 论文中也有相关说明:YOLO 中一个 ground truth 只会与一个先验框匹配(IOU值最好的),对于那些 IOU 值超过一定阈值的先验框,其预测结果就忽略了。这和 SSD 与 RPN 网络的处理方式有很大不同,因为它们可以将一个 ground truth 分配给多个先验框。尽管 YOLOv2 和 YOLOv1 计算 loss 处理上有不同,但都是采用均方差来计算 loss。
- 另外需要注意的一点是,在计算 boxes 的 w 和 h 误差时,YOLOv1 中采用的是平方根以降低 boxes 的大小对误差的影响,而YOLOv2 是直接计算,但是根据 ground truth 的大小对权重系数进行修正:l.coord_scale * (2 - truth.w*truth.h)(这里 w 和 h 都归一化到 (0,1)),这样对于尺度较小的 boxes 其权重系数会更大一些,可以放大误差,起到和 YOLOv1 计算平方根相似的效果。
4. YOLO 9000
YOLO9000 是在 YOLOv2 的基础上提出的一种可以检测超过 9000 个类别的模型,其主要贡献点在于提出了一种分类和检测的联合训练策略。众多周知,检测数据集的标注要比分类数据集打标签繁琐的多,所以 ImageNet 分类数据集比 VOC 等检测数据集高出几个数量级。在 YOLO 中,边界框的预测其实并不依赖于物体的标签,所以YOLO可以实现在分类和检测数据集上的联合训练。对于检测数据集,可以用来学习预测物体的边界框、置信度以及为物体分类,而对于分类数据集可以仅用来学习分类,但是其可以大大扩充模型所能检测的物体种类。在训练时,如果是检测样本,按照 YOLOv2 的 loss 计算误差,而对于分类样本,只计算分类误差。通过联合训练策略,YOLO9000 可以快速检测出超过 9000 个类别的物体,总体 mAP 值为 19.7%。觉得这是作者在这篇论文作出的最大的贡献,因为YOLOv2 的改进策略亮点并不是很突出,但是 YOLO9000 算是开创之举。