演员需要自我修养,程序员也需要。
YOLO 在当时是非常不错的算法,速度极快,但明显的缺陷就是精度问题特别是小尺寸目标检测问题上。
YOLO 的作者有强调的一个事情是 YOLOv2 仍然是实时的,并且在速度和精度方面做了一定的平衡。
YOLOv2 是 YOLO 的进阶版,它没有彻底否定 YOLO,而是在 YOLOv1 的基础上,融合了很多其它论文优秀的思想做了大幅的提升。
YOLO 作者概括了从 3 个方面入手:
- 更好
- 更快
- 更强
1. 如何更好?
YOLO 作者对比了 Fast R-CNN 发现 YOLO 有一些短板,那就是比较低的召回率和比较高的定位误差。
所以,让 YOLO 变得更好指的是保持准确率的情况下:
- 提升召回率
- 降低定位误差
为此,尝试了一些手段。
1. 引入 Batch Normalization
Batch Norm 是一种很有效的正则化手段,所有的卷积层后面引入正则化之后,YOLO 表现如何呢?
- mAP 提升了 2%
- 可以去掉了 Dropout 仍然不出现过拟合
不熟悉 Batch Norm 的同学可以尝试阅读我这篇介绍文章
2. 高分辨率图像分类器
所有比较先进的目标检测网络,它的图像分类器都是在 ImageNet 做预训练的。
但从 AlexNet 开始,大多数分类器接受的图片尺寸都比较小,低于 256 * 256。
YOLOv1 训练图像分类时,图片尺寸是 224224,之后训练检测时,图片尺寸是 448 × 448,这代表模型需要同时应对学习检测和分辨率的变化。
YOLOv2 做了相应的改变。
通过对 YOLOv1 的模型进行 finetune,用 448*448 的图片尺寸训练了 10 epoches,主要目的是想让卷积核适应高分辨率。
这个步骤相当于做了减法,减轻了网络的学习任务,让它忽略图片尺寸的变化,专心应对目标检测任务。
这种尝试,让 mAP 涨了近 4 个点。
2. 引入 Anchor Box
YOLOv1 最终是通过全连接网络直接预测目标位置。
另外一个优秀的目标检测模型 Fast R-CNN 是通过 Anchor Box 的形式。
两种方法相比,Anchor Box 更容易学习,因为它是通过手选的,然后通过 RPN(Region Proposal Network) 全卷积层预测每一个位置相对于 Anchor Box 的偏移和置信度。
所以,YOLO 作者把 YOLOv1 进行了改造:
- 最后的全连接层去掉了
- 用 Anchor Box 预测 b-box
- 移除一个 pool 层,使得卷积层输出更高分辨率
- 缩放网络使其能够接受 416x416 的分辨率,目的是最终生成的 featuremap 只有一个中心 cell,方便定位。
- 将分类和空间检测解耦,跟随 YOLOv1 的思路,预测每一个 anchor box 的对象 objectness 分数,这个是 anchor box 和 groundtruth 的 IOU 分数,也是一个条件概率,针对的是某个 cell 中有无对象时的概率取值。
在论文中,作者花了很长的篇幅讲解 anchor box 相关。
引入 anchor box 后,YOLO 模型的 accuracy 发生了些许下降。
未引入 anchor box 时,YOLO 预测 98 个 bbox,引入后,总共预测的 bbox 能多达 1000 多个
代码语言:javascript复制@无anchor box @Acc=69.5 mAP @Recall = 81%
@有anchor box @Acc = 69.2 mAP @Recall = 88%
相比于精度的少许损失,召回率提升明显,文章开头说 YOLOv2 的改良有个目标就是提高召回率,而 Anchor BOX 的引入确实起了很明显的效果。
3. 尺寸聚类
在引入 Anchor BOX 到 YOLO 的过程,遇到了 2 个问题。
第一个问题就是 Anchor BOX 的尺寸是手选的。
虽然网络可以渐进学习,但是如果一开始的时候就分配好合理的先验尺寸,那么这无疑会加快学习的速度。
相比于人为指定 anchor box 的尺寸比例,YOLO 作者想到了一个自动化的手段,那就是选择 k-means 聚类手段。
在数据训练集中运行 k-means 算法,可以得到 k 个尺寸比例。
但 K 如何取值呢?
作者不是乱取的,有做很详细的对比实验。
可以看到,k 从 1 到 15 都有做过测试,最终选择了 k=5,选择 5 的原因是在模型复杂度和召回率之间过一个平衡。
经实验,效果很不错,聚类出来的 anchor box 尺寸如下图所示:
聚类选择出来的尺寸没有很短和宽的尺寸,偏向于高且瘦的尺寸。
最后,作为聚类算法,距离的度量非常重要。
YOLOv2 没有采用标准的欧式距离作为度量。
欧式距离为什么不好呢?
因为 YOLO 作者发现,大尺寸的 bbox 更容易出现定位错误,所以作者想找一个尺寸独立的距离度量,它想到了 IOU, IOU 本身就是一个比例重合的关系。
`$
d(bbox,centroid) = 1 - IOU(bbox,centroid)
$`
4. 定位预测
在引入 Anchor BOX 时还遭遇了第 2 个问题:模型的稳定性。
模型的不稳定性来源于坐标(x,y) 的预测。
在 RPN 网络中,坐标(x,y) 是这样的计算公式。
`$
x = t{x}*W{a} x_{a}
$`
`$
y = t{y}*H{a} y_{a}
$`
YOLO 论文中公式好像错了,加号变成了减号,我在这里更正过来。
W 和 H 是 anchor box a 的宽高。
t 代表预测的框和 anchor box 的偏移比例。
以 x 方向为例。
代码语言:javascript复制t = -1,x 相当于 anchor box a 左移动一个自身宽度
t = 1, x 相当于 anchor box a 右移动一个自身宽度
y 也是同样的逻辑,这里不再赘述。
上面的坐标转换很容易懂,但不好训练。因为 x,y 并没有遵守什么约束,所以可能预测的 bbox 会遍布一张图片任何角落。
所以,YOLO 作者还是想借助 YOLOv1 的做法,有别于直接预测定位,YOLOv2 继续使用 bbox 相对于 grid 的偏移。
是 logistic 函数,此函数限定了 tx 和 ty 的取值范围是 0 ~ 1.
然后,这里有个细节需要认真琢磨一下,那就是每个坐标变量的实际含义。
说实话,因为 YOLO 系列文章写得比较随性,很多细节作者没有题,所以需要自己去推断,我当时学习的时候坐标这个想了好久,好来阅读别人的笔记才意识到问题所在。1
YOLOv2 坐标预测每个 bbox 预测 5 个值:
- tx
- ty
- tw
- th
- to
- bx 和 by 是公式转换出来的,是预测的 bbox 相对于 featuremap 的中心位置偏移,YOLO 作者论文中忽略了它应当和 feature map 的 WH 相比
- bw 和 bh 也是公式转换出来的,是预测的 bbox 相对于 featuremap 的尺寸比值
- pw 和 ph 是 anchor box 先验尺寸,想对于 featuremap 的尺寸比例。
假如,featuremap 尺寸是 13x13,输入图片是 416x416
代码语言:javascript复制H=13
W=13
cx = 4
cy = 3
sigmoid(tx) = 0.3
sigmoid(ty) = 0.7
exp(tw) = 1.2
exp(th) = 1.4
pw = 3
ph = 4
那么,bbox 实际预测的值是多少呢?
代码语言:javascript复制bx = (0.3 3)/13*416=105
by = (0.7 4)/13*416=150
bw = 3*1.2/13*416=115
bh = 4*1.4/13*416=179
tx 和 ty 是偏移值,经过 sigmoid 函数可以得到 bx、by,相对于 feature map 左上角的偏移(非输入图片),是比例关系
tx 经激活函数输出后的结果是 0~1,代表了预测的bbox 的中心点相对于对应 grid 的左上角的偏移量,也是比例关系。
bw 和 by 也是偏移值,相对于 feature map 的尺寸 H 和 W,也是比例关系
cx 指的是负责预测 bbox 的那个 grid 的左上角相对于 feature map 的左上角的偏移。
YOLOv2 中 featuremap 的尺寸是 13x13,所以每个 grid 其实单位就是 1.
5. 精细化的特征图
YOLOv2 刚开始使用 13x13 的 featuremap 做预测,对于大目标来说足够应付检测了,但是小目标却不行。
像其它的目标检测算法都会利用到空间信息,会利用特征图金字塔去覆盖不同层级的尺寸信息,比如 Faster R-CNN 和 SSD 都生成了多种尺寸featuremap。
但 YOLO 作者另辟蹊径,用了一个 passthrough 手段,简单来说就是从 26x26 的featuremap 中提取信息生成新的 featuremap ,然后和最后 13x13 的 featuremap 拼接起来。
passthrough 有点类似 ResNet 的 shortcut 的思路,都是从较前面的层次获取信息,这样网络就可以应付空间上不同层次的信息。
具体做法如下:
将 26 x 26 x 512 尺寸的 featuremap 进行跨行垮列抽样,然后生成 13 x 13 x 2048 的 featuremap,参数总量没有变,但是尺寸发生了改变,所以 YOLO 源码中称这样的操作为 reorg,相当于一个宽高换深度的重组。
基于这项尝试,YOLOv2 的模型提升了 1% 的效率。
6. 多尺度训练
YOLO 作者不想让 YOLOv2 的模型只局限于 416x416 这单一尺寸的图片,所以训练过程当中,每经过 10 epoches 的训练,输入图像尺寸会发生变化。
因为 YOLOv2 的经过了 5 次下采样,缩小了 32 倍,所以,输入图像的尺寸都能被 32 整除 {320x320,352,…,608}.
多尺度训练使得 YOLOv2 可以在速度和精度上做一个很好的平衡。
低分辨率下,YOLOv2 的速度极快,228x228 的输入图片下,帧率可以到达 90 FPS,但精度和 Fast R-CNN 一致。
高分辨率下,YOLOv2 仍然可以达到实时要求,精度是当时的 state of the art.
在 VOC 2007 数据集 YOLOv2 和其他目标检测模型的对比如下图:
严密细致的验证
为了 YOLOv2 的整体表现提升,YOLO 作者做的工作很足,做了大量的工作,有些有用,有些无用,下图是作者给出来的验证记录。
这个说明,YOLO 作者虽然论文写得随性,样貌随性,但思维很严谨,不是一个浮躁的人。
2. 如何更快?
2.1 新的模型 Darknet-19
快是 YOLO 系列模型最大的优势,YOLOv2 如何在这方面精进的呢?
在 YOLOv2 的版本,作者换了一个新的分类器。
大多数目标检测模型是基于 VGG-16 的,它很简单,准确率也很高,但 YOLO 作者认为它太慢了。
处理一张 224x224 的图片,VGG-16 需要 30.69 BFLOPs。
要想快,这个地方肯定可以动刀子,YOLO 作者带来了新的模型 Darknet-19。
Darknet-19 是基于 GoogLeNet 的架构,它比 VGG-16 快,原因在于它的前向推断只要 8.52 BFLOPs。
设计 Darknet-19 参考了很多同行经验。
- 基于 GoogLeNet 架构
- 借鉴 VGG 大量运用 3x3 filter,并且在每个 pool 层之后,将卷积核的个数翻倍
- 借鉴 NIN 运用 global aveage pool,在 3x3 filter 之间插入 1x1 卷积层
- 引入 Batch Normal 层
Darknet-19 的结构如下:
19 个卷积层和 5 个 maxpool 层。
2.2 目标分类任务的训练技巧
要做好目标检测,首先就要做好目标分类。
目标分类是在 ImageNet 上做的,预测 1000 个分类。
- 随机梯度下降法做训练
- 224x224 尺寸的图片训练 160 epoches
- 初始学习率是 0.1,多项式学习率衰减策略,power 为 4
- 权重衰减系数为 0.0005,动量为 0.9
- 常见的数据增强手段
- 224x224 训练完成后,在 448x448 尺寸数据集上再训练 10 epoches ,除了初始学习率为 0.003 外,其它参数保持不变。
在高分率的数据集上,Darknet-19 Top-1 ACC 为 76.5%,Top-5 ACC 为 93.3%.
2.3 目标检测任务的训练细节
Darknet-19 是一个目标分类模型,最后一层输出了 1000 个分类的概率,需要做一些改造才能进行目标检测任务的训练。
- 去掉最后 1 个卷积层,然后用 连续 3 个 3x3 的卷积层代替。
- 每个 3x3 的卷积层卷积核数量是 1024 个。
- 每一个 3x3 的卷积层后面都跟着 n 个 1x1 的卷积核,n 是要检测目标的类别数
- 在 VOC 数据集中,类别数目是 20, 网络中每个 grid 预测 5 个 box,每一个 box 需要预测 5 个值(x,y,w,h,conf) 和 20 个类别的概率,所以需要 125 个 filter。
- 添加 passthrough 层从最后一个 3x3x512 卷积层到最后一个卷积层,目的是为了获取更精细的 feature。
训练细节:
代码语言:javascript复制epoches:160
learning rate: 0.001 在前 60 epoches,60 到 90 epoches 之间学习率除以 10
weight decay: 0.0005 动量是 0.9
数据增强:和 YOLO、SSD 一致
在 COCO 和 VOC 数据集的训练策略是一致的。
3.如何更强?
YOLOv2 的更强指的是作者提出了一种目标检测和目标分类联合训练的方法。
当遇到目标检测数据集中的图片时,模型反向传播更新整个 YOLOv2 的 loss 函数。
当遇到目标分类数据集中的图片时,反向传播只更新 YOLO 分类的那一部分结构。
另外,将分类进行层次化处理,使得 YOLO 能够识别超过 9000 种类别,这就是 YOLO9000。
由于我的兴趣在于目标检测,所以这一部分不做多讲,有兴趣的同学可以自行阅读相关文档。
总结
YOLOv2 是一个平衡了速度和准确度的模型,它通过一系列 tricks 让自己更快、更好、更强。
如果让我个人评价的话,那一个 tricks 让我眼前一亮,我会投用 k-means 去聚类数据集中的 label 尺寸从而得到 anchor box 尺寸。
这其实是一个很强的先验知识,正因为此 YOLOv2 才会变得比 YOLOv1 更棒,YOLOv2 也没有全部照抄其它模型的 tricks ,而是真正有选择性地运用,这才是真正值得我们学习的地方。
参考
- https://zhuanlan.zhihu.com/p/35325884
- https://arxiv.org/abs/1612.08242