原文链接:https://zhuanlan.zhihu.com/p/47575929 本文比原论文写的详细的多,再结合上另外一篇Anchor box的理解,即可做到全面了解YOLOv2。 引用部分为本人心得。

YOLOv2 相对 v1 版本,在继续保持处理速度的基础上,从预测更准确(Better),速度更快(Faster),识别对象更多(Stronger)这三个方面进行了改进。其中识别更多对象也就是扩展到能够检测 9000 种不同对象,称之为 YOLO9000。

本文讨论 YOLOv2 的内容,关于 YOLO v1 和 v3 的内容,请参考 YOLO v1 深入理解YOLO v3 深入理解。下面具体看下 YOLO2 都做了哪些改进。

预测更准确(Better)

论文[1]中给出了下面的改进项目列表,列出各项改进对 mAP 的提升效果。

YOLO v2 / YOLO9000 深入理解 - 图1

图 1 YOLOv1 到 YOLOv2

1)batch normalization(批归一化)

批归一化使 mAP 有 2.4 的提升。

批归一化有助于解决反向传播过程中的梯度消失和梯度爆炸问题,降低对一些超参数(比如学习率、网络参数的大小范围、激活函数的选择)的敏感性,并且每个 batch 分别进行归一化的时候,起到了一定的正则化效果(YOLO2 不再使用 dropout),从而能够获得更好的收敛速度和收敛效果。

通常,一次训练会输入一批样本(batch)进入神经网络。批规一化在神经网络的每一层,在网络(线性变换)输出后和激活函数(非线性变换)之前增加一个批归一化层(BN),BN 层进行如下变换:①对该批样本的各特征量(对于中间层来说,就是每一个神经元)分别进行归一化处理,分别使每个特征的数据分布变换为均值 0,方差 1。从而使得每一批训练样本在每一层都有类似的分布。这一变换不需要引入额外的参数。②对上一步的输出再做一次线性变换,假设上一步的输出为 Z,则 Z1=γZ + β。这里γ、β是可以训练的参数。增加这一变换是因为上一步骤中强制改变了特征数据的分布,可能影响了原有数据的信息表达能力。增加的线性变换使其有机会恢复其原本的信息。

关于批规一化的更多信息可以参考 Batch Normalization 原理与实战

2)使用高分辨率图像微调分类模型

mAP 提升了 3.7。

图像分类的训练样本很多,而标注了边框的用于训练对象检测的样本相比而言就比较少了,因为标注边框的人工成本比较高。所以对象检测模型通常都先用图像分类样本训练卷积层,提取图像特征。但这引出的另一个问题是,图像分类样本的分辨率不是很高。所以 YOLO v1 使用 ImageNet 的图像分类样本采用 224224 作为输入,来训练 CNN 卷积层。然后在训练对象检测时,检测用的图像样本采用更高分辨率的 448448 的图像作为输入。但这样切换对模型性能有一定影响。

所以 YOLO2 在采用 224224 图像进行分类模型预训练后,再采用 448448 的高分辨率样本对分类模型进行微调(10 个 epoch),使网络特征逐渐适应 448448 的分辨率。然后再使用 448448 的检测样本进行训练,缓解了分辨率突然切换造成的影响。

3)采用先验框(Anchor Boxes)

召回率大幅提升到 88%,同时 mAP 轻微下降了 0.2。

借鉴 Faster RCNN 的做法,YOLO2 也尝试采用先验框(anchor)。在每个 grid 预先设定一组不同大小和宽高比的边框,来覆盖整个图像的不同位置和多种尺度,这些先验框作为预定义的候选区在神经网络中将检测其中是否存在对象,以及微调边框的位置。

同时 YOLO2 移除了全连接层。另外去掉了一个池化层,使网络卷积层输出具有更高的分辨率。

之前 YOLO1 并没有采用先验框,并且每个 grid 只预测两个 bounding box,整个图像 98 个。YOLO2 如果每个 grid 采用 9 个先验框,总共有 13139=1521 个先验框。所以,相对 YOLO1 的 81% 的召回率,YOLO2 的召回率大幅提升到 88%。同时 mAP 有 0.2% 的轻微下降。

不过 YOLO2 接着进一步对先验框进行了改良。

4)聚类提取先验框尺度

聚类提取先验框尺度,结合下面的约束预测边框的位置,使得 mAP 有 4.8 的提升。

之前先验框都是手工设定的,YOLO2 尝试统计出更符合样本中对象尺寸的先验框,这样就可以减少网络微调先验框到实际位置的难度。YOLO2 的做法是对训练集中标注的边框进行聚类分析,以寻找尽可能匹配样本的边框尺寸。

聚类算法最重要的是选择如何计算两个边框之间的 “距离”,对于常用的欧式距离,大边框会产生更大的误差,但我们关心的是边框的 IOU。所以,YOLO2 在聚类时采用以下公式来计算两个边框之间的 “距离”。 YOLO v2 / YOLO9000 深入理解 - 图2
centroid 是聚类时被选作中心的边框,box 就是其它边框,d 就是两者间的 “距离”。IOU 越大,“距离” 越近。YOLO2 给出的聚类分析结果如下图所示:

YOLO v2 / YOLO9000 深入理解 - 图3
图 2 边框聚类分析

上图左边是选择不同的聚类 k 值情况下,得到的 k 个 centroid 边框,计算样本中标注的边框与各 centroid 的 Avg IOU。显然,边框数 k 越多,Avg IOU 越大。YOLO2 选择 k=5 作为边框数量与 IOU 的折中。对比手工选择的先验框,使用 5 个聚类框即可达到 61 Avg IOU,相当于 9 个手工设置的先验框 60.9 Avg IOU。

上图右边显示了 5 种聚类得到的先验框,VOC 和 COCO 数据集略有差异,不过都有较多的瘦高形边框。

5)约束预测边框的位置

借鉴于 Faster RCNN 的先验框方法,在训练的早期阶段,其位置预测容易不稳定。其位置预测公式为: YOLO v2 / YOLO9000 深入理解 - 图4

其中, YOLO v2 / YOLO9000 深入理解 - 图5
是预测边框的中心, YOLO v2 / YOLO9000 深入理解 - 图6
是先验框(anchor)的中心点坐标, YOLO v2 / YOLO9000 深入理解 - 图7
是先验框(anchor)的宽和高, YOLO v2 / YOLO9000 深入理解 - 图8
是要学习的参数。 注意,YOLO 论文中写的是 YOLO v2 / YOLO9000 深入理解 - 图9
,根据 Faster RCNN,应该是 “+”。

由于 YOLO v2 / YOLO9000 深入理解 - 图10
的取值没有任何约束,因此预测边框的中心可能出现在任何位置,训练早期阶段不容易稳定。YOLO 调整了预测公式,将预测边框的中心约束在特定 gird 网格内。 YOLO v2 / YOLO9000 深入理解 - 图11

其中, YOLO v2 / YOLO9000 深入理解 - 图12
是预测边框的中心和宽高。 YOLO v2 / YOLO9000 深入理解 - 图13
是预测边框的置信度,YOLO1 是直接预测置信度的值,这里对预测参数 YOLO v2 / YOLO9000 深入理解 - 图14
进行σ变换后作为置信度的值。 YOLO v2 / YOLO9000 深入理解 - 图15
是当前网格左上角到图像左上角的距离,要先将网格大小归一化,即令一个网格的宽 = 1,高 = 1。 YOLO v2 / YOLO9000 深入理解 - 图16
是先验框的宽和高。 σ是 sigmoid 函数。 YOLO v2 / YOLO9000 深入理解 - 图17
是要学习的参数,分别用于预测边框的中心和宽高,以及置信度。

(注意:YOLOv2参考了Faster RCNN中的RPN理念,但有很大的不同,首先论文中聚类得到的仅是anchor boxes的宽高。更直白的说,聚类后知道每个格子有5个anchor boxes,你知道它们长什么样(宽高或叫尺寸)就行了,不用知道具体位置(因为我们只需要用到它们的形状)。Anchor boxes不可能完全贴合目标,所以后期你仅要根据它们的形状来进行形变缩放就可以得到合适的bounding boxes。格子左上角C点对于整张图片的坐标为(Cx,Cy),这里先假设tx,ty,tw,th为网络的输出值,它们都可以理解为bouding boxes的中心点对C的偏移值(偏移值不仅仅指简单变换如x,y轴位移等)(图上的σ定义为 sigmoid 激活函数(将函数值约束到[0,1]),这样就可以使得偏移后的 C 点也就是中心点B落在红色这一块中)。而计算bw,bh是唯一用到“anchor boxes”的地方,将exp(tw),exp(th)分别和pw,ph相乘后即可得到缩放后的款和高bw和bh,最后得到(bx,by,bw,bh),也就是 BoundingBox(预测框)的坐标信息。) 那么如何去描述bounding boxes相比ground truth 的损失呢? 首先,yolo 按照上面同样的方式先用 GroundTruth(真实框)和 anchorbox(先验框, 锚框)算出偏移和缩放比,设为 dx,dy,dh,dw,这个即标签 label,然后网络输出的 BoundingBox(预测框)是 tx,ty,th,tw 四个值,用来代表和 anchorbox(先验框, 锚框)的偏移和缩放比。

我们的目标是通过学习 (tx,ty,tw,th) 这四个值去微调 anchorbox(先验框, 锚框)得到 BoundingBox(预测框),使得 BoundingBox 不断接近 GroundTruth(真实框)也就是 (tx,ty,tw,th) 不断的接近(dx,dy,dh,dw),梯度下降的目标也就是缩小这两者的 LOSS,这就是 yolov2 中的回归方法。

Yolov1直接输出置信度,而v2置信度改为输出to,再使用sigmoid映射到(0,1)。

YOLO v2 / YOLO9000 深入理解 - 图18
图 3 边框预测

参考上图,由于σ函数将 YOLO v2 / YOLO9000 深入理解 - 图19
约束在 (0,1) 范围内,所以根据上面的计算公式,预测边框的蓝色中心点被约束在蓝色背景的网格内。约束边框位置使得模型更容易学习,且预测更为稳定。

6)passthrough 层检测细粒度特征

passthrough 层检测细粒度特征使 mAP 提升 1。

对象检测面临的一个问题是图像中对象会有大有小,输入图像经过多层网络提取特征,最后输出的特征图中(比如 YOLO2 中输入 416416 经过卷积网络下采样最后输出是 1313),较小的对象可能特征已经不明显甚至被忽略掉了。为了更好的检测出一些比较小的对象,最后输出的特征图需要保留一些更细节的信息。

YOLO2 引入一种称为 passthrough 层的方法在特征图中保留一些细节信息。具体来说,就是在最后一个 pooling 之前,特征图的大小是 2626512,将其 1 拆 4,直接传递(passthrough)到 pooling 后(并且又经过一组卷积)的特征图,两者叠加到一起作为输出的特征图。

YOLO v2 / YOLO9000 深入理解 - 图20
图 4 passthrough

具体怎样 1 拆 4,下面借用参考文章[3]中的一副图看的很清楚。图中示例的是 1 个 44 拆成 4 个 22。因为深度不变,所以没有画出来。

YOLO v2 / YOLO9000 深入理解 - 图21
图 5 passthrough 1 拆 4

另外,根据 YOLO2 的代码,特征图先用 11 卷积从 2626512 降维到 2626*64,再做 1 拆 4 并 passthrough。下面图 6 有更详细的网络输入输出结构。

7)多尺度图像训练

多尺度图像训练对 mAP 有 1.4 的提升。

因为去掉了全连接层,YOLO2 可以输入任何尺寸的图像。因为整个网络下采样倍数是 32,作者采用了 {320,352,…,608} 等 10 种输入图像的尺寸,这些尺寸的输入图像对应输出的特征图宽和高是{10,11,…19}。训练时每 10 个 batch 就随机更换一种尺寸,使网络能够适应各种大小的对象检测。

全连接层的(输入)参数shape是固定的,当改变输入图片的尺寸后,最后一个卷积层输出的特征图shape也会变,所以其flatten后的shape(数目)也会变,此时就不能输入到(旧的图片尺寸的)全连接层中了。

8)高分辨率图像的对象检测

图 1 表格中最后一行有个 hi-res detector,使 mAP 提高了 1.8。因为 YOLO2 调整网络结构后能够支持多种尺寸的输入图像。通常是使用 416416 的输入图像,如果用较高分辨率的输入图像,比如 544544,则 mAP 可以达到 78.6,有 1.8 的提升。

速度更快(Faster)

为了进一步提升速度,YOLO2 提出了 Darknet-19(有 19 个卷积层和 5 个 MaxPooling 层)网络结构。DarkNet-19 比 VGG-16 小一些,精度不弱于 VGG-16,但浮点运算量减少到约 1/5,以保证更快的运算速度。

YOLO v2 / YOLO9000 深入理解 - 图22
图 6 Darknet-19 分类模型

YOLO2 的训练主要包括三个阶段。第一阶段就是先在 ImageNet 分类数据集上预训练 Darknet-19,此时模型输入为 224224 ,共训练 160 个 epochs。然后第二阶段将网络的输入调整为 448448 ,继续在 ImageNet 数据集上 finetune 分类模型,训练 10 个 epochs,此时分类模型的 top-1 准确度为 76.5%,而 top-5 准确度为 93.3%。第三个阶段就是修改 Darknet-19 分类模型为检测模型,移除最后一个卷积层、global avgpooling 层以及 softmax 层,并且新增了三个 331024 卷积层,同时增加了一个 passthrough 层,最后使用 11 卷积层输出预测结果,输出的 channels 数为:**num_anchors(5+num_classes)** ,和训练采用的数据集有关系。由于 anchors 数为 5,对于 VOC 数据集(20 种分类对象)输出的 channels 数就是 125,最终的预测矩阵 T 的 shape 为 (batch_size, 13, 13, 125),可以先将其 reshape 为 (batch_size, 13, 13, 5, 25) ,其中 T[:, :, :, :, 0:3] 为边界框的位置和大小 YOLO v2 / YOLO9000 深入理解 - 图23
,T[:, :, :, :, 4] 为边界框的置信度,而 T[:, :, :, :, 5:] 为类别预测值。

对象检测模型各层的结构如下(参考文章[4]):

YOLO v2 / YOLO9000 深入理解 - 图24
图 7 Darknet-19 对象检测模型

看一下 passthrough 层。图中第 25 层 route 16,意思是来自 16 层的 output,即 2626512,这是 passthrough 层的来源(细粒度特征)。第 26 层 11 卷积降低通道数,从 512 降低到 64(这一点论文在讨论 passthrough 的时候没有提到),输出 262664。第 27 层进行拆分(passthrough 层)操作,1 拆 4 分成 1313256。第 28 层叠加 27 层和 24 层的输出,得到 13131280。后面再经过 33 卷积和 11 卷积,最后输出 1313*125。

24层的特征图虽然尺寸变小了,但还是保存着原图的全局位置信息等(譬如第一个像素可能分别对应原图左上角某块格子的特征信息,其他像素亦然);passthrough层虽然抽取像素的方法也考虑到位置信息(详见上面第6点),但毕竟没有24层的特征图的位置信息这么全面,还有没有更好的方法呢?

YOLO2 输入 -> 输出

综上所述,虽然 YOLO2 做出了一些改进,但总的来说网络结构依然很简单,就是一些卷积 + pooling,从 4164163 变换到 13135*25。稍微大一点的变化是增加了 batch normalization,增加了一个 passthrough 层,去掉了全连接层,以及采用了 5 个先验框。

YOLO v2 / YOLO9000 深入理解 - 图25
图 8 YOLO2 输入 - 输出

对比 YOLO1 的输出张量,YOLO2 的主要变化就是会输出 5 个先验框,且每个先验框都会尝试预测一个对象。输出的 13135*25 张量中,25 维向量包含 20 个对象的分类概率 + 4 个边框坐标 + 1 个边框置信度。

YOLOv1每个格子只能预测一个对象,v2每个格子可以预测5个。

YOLO2 误差函数

误差依然包括边框位置误差、置信度误差、对象分类误差。

YOLO v2 / YOLO9000 深入理解 - 图26
图 9 YOLO2 误差函数

公式中:

YOLO v2 / YOLO9000 深入理解 - 图27
意思是预测边框中,与真实对象边框 IOU 最大的那个,其 IOU < 阈值 Thresh,此系数为 1,即计入误差,否则为 0,不计入误差。YOLO2 使用 Thresh=0.6。

YOLO v2 / YOLO9000 深入理解 - 图28
意思是前 128000 次迭代计入误差。注意这里是与先验框的误差,而不是与真实对象边框的误差。可能是为了在训练早期使模型更快学会先预测先验框的位置。

YOLO v2 / YOLO9000 深入理解 - 图29
意思是该边框负责预测一个真实对象(边框内有对象)。

各种 YOLO v2 / YOLO9000 深入理解 - 图30
是不同类型误差的调节系数。

识别对象更多(Stronger)/ YOLO9000

VOC 数据集可以检测 20 种对象,但实际上对象的种类非常多,只是缺少相应的用于对象检测的训练样本。YOLO2 尝试利用 ImageNet 非常大量的分类样本,联合 COCO 的对象检测数据集一起训练,使得 YOLO2 即使没有学过很多对象的检测样本,也能检测出这些对象。

基本的思路是,如果是检测样本,训练时其 Loss 包括分类误差和定位误差,如果是分类样本,则 Loss 只包括分类误差。

1)构建 WordTree

要检测更多对象,比如从原来的 VOC 的 20 种对象,扩展到 ImageNet 的 9000 种对象。简单来想的话,好像把原来输出 20 维的 softmax 改成 9000 维的 softmax 就可以了,但是,ImageNet 的对象类别与 COCO 的对象类别不是互斥的。比如 COCO 对象类别有 “狗”,而 ImageNet 细分成 100 多个品种的狗,狗与 100 多个狗的品种是包含关系,而不是互斥关系。一个 Norfolk terrier 同时也是 dog,这样就不适合用单个 softmax 来做对象分类,而是要采用一种多标签分类模型。

YOLO2 于是根据 WordNet[5],将 ImageNet 和 COCO 中的名词对象一起构建了一个 WordTree,以 physical object 为根节点,各名词依据相互间的关系构建树枝、树叶,节点间的连接表达了对象概念之间的蕴含关系(上位 / 下位关系)。

YOLO v2 / YOLO9000 深入理解 - 图31
图 10 WordTree

整个 WordTree 中的对象之间不是互斥的关系,但对于单个节点,属于它的所有子节点之间是互斥关系。比如 terrier 节点之下的 Norfolk terrier、Yorkshire terrier、Bedlington terrier 等,各品种的 terrier 之间是互斥的,所以计算上可以进行 softmax 操作。上面图 10 只画出了 3 个 softmax 作为示意,实际中每个节点下的所有子节点都会进行 softmax。

2)WordTree 的构建方法。

构建好的 WordTree 有 9418 个节点(对象类型),包括 ImageNet 的 Top 9000 个对象,COCO 对象,以及 ImageNet 对象检测挑战数据集中的对象,以及为了添加这些对象,从 WordNet 路径中提取出的中间对象。

构建 WordTree 的步骤是:①检查每一个将用于训练和测试的 ImageNet 和 COCO 对象,在 WordNet 中找到对应的节点,如果该节点到 WordTree 根节点(physical object)的路径只有一条(大部分对象都只有一条路径),就将该路径添加到 WrodTree。②经过上面操作后,剩下的是存在多条路径的对象。对每个对象,检查其额外路径长度(将其添加到已有的 WordTree 中所需的路径长度),选择最短的路径添加到 WordTree。这样就构造好了整个 WordTree。

3)WordTree 如何表达对象的类别

之前对象互斥的情况下,用一个 n 维向量(n 是预测对象的类别数)就可以表达一个对象(预测对象的那一维数值接近 1,其它维数值接近 0)。现在变成 WordTree,如何表达一个对象呢?如果也是 n 维向量(这里 WordTree 有 9418 个节点(对象),即 9418 维向量),使预测的对象那一位为 1,其它维都为 0,这样的形式依然是互斥关系,这样是不合理的。合理的向量应该能够体现对象之间的蕴含关系。

比如一个样本图像,其标签是是 “dog”,那么显然 dog 节点的概率应该是 1,然后,dog 属于 mammal,自然 mammal 的概率也是 1,…… 一直沿路径向上到根节点 physical object,所有经过的节点其概率都是 1。参考上面图 10,红色框内的节点概率都是 1,其它节点概率为 0。另一个样本假如标签是 “Norfolk terrier”,则从 “Norfolk terrier” 直到根节点的所有节点概率为 1(图 10 中黄色框内的节点),其它节点概率为 0。

所以,一个 WordTree 对应且仅对应一个对象,不过该对象节点到根节点的所有节点概率都是 1,体现出对象之间的蕴含关系,而其它节点概率是 0。

4)预测时如何确定一个 WordTree 所对应的对象

上面讲到训练时,有标签的样本对应的 WordTree 中,该对象节点到根节点的所有节点概率都是 1,其它节点概率是 0。那么用于预测时,如何根据 WordTree 各节点的概率值来确定其对应的对象呢?

根据训练标签的设置,其实模型学习的是各节点的条件概率。比如我们看 WordTree(图 10)中的一小段。假设一个样本标签是 dog,那么 dog=1,父节点 mammal=1,同级节点 cat=0,即 P(dog|mammal)=1,P(cat|mammal)=0。

既然各节点预测的是条件概率,那么一个节点的绝对概率就是它到根节点路径上所有条件概率的乘积。比如

P(Norfolk terrier) = P(Norfolk terrier|terrier) P(terrier|hunting dog) P(hunting dog|dog) …… P(animal|physical object) * P(physical object)

对于分类的计算,P(physical object) = 1。

不过,为了计算简便,实际中并不计算出所有节点的绝对概率。而是采用一种比较贪婪的算法。从根节点开始向下遍历,对每一个节点,在它的所有子节点中,选择概率最大的那个(一个节点下面的所有子节点是互斥的),一直向下遍历直到某个节点的子节点概率低于设定的阈值(意味着很难确定它的下一层对象到底是哪个),或达到叶子节点,那么该节点就是该 WordTree 对应的对象。

5)分类和检测联合训练

由于 ImageNet 样本比 COCO 多得多,所以对 COCO 样本会多做一些采样(oversampling),适当平衡一下样本数量,使两者样本数量比为 4:1。

YOLO9000 依然采用 YOLO2 的网络结构,不过 5 个先验框减少到 3 个先验框,以减少计算量。YOLO2 的输出是 13135(4+1+20),现在 YOLO9000 的输出是 13133(4+1+9418)。假设输入是 4164163。

由于对象分类改成 WordTree 的形式,相应的误差计算也需要一些调整。对一个检测样本,其分类误差只包含该标签节点以及到根节点的所有节点的误差。比如一个样本的标签是 dog,那么 dog 往上标签都是 1,但 dog 往下就不好设置了。因为这个 dog 其实必然也是某种具体的 dog,假设它是一个 Norfolk terrier,那么最符合实际的设置是从 Norfolk terrier 到根节点的标签都是 1。但是因为样本没有告诉我们这是一个 Norfolk terrier,只是说一个 dog,那么从 dog 以下的标签就没法确定了。

对于分类样本,则只计算分类误差。YOLO9000 总共会输出 13133=507 个预测框(预测对象),计算它们对样本标签的预测概率,选择概率最大的那个框负责预测该样本的对象,即计算其 WrodTree 的误差。

另外论文中还有一句话,”We also assume that the predicted box overlaps what would be the ground truth label by at least .3 IOU and we backpropagate objectness loss based on this assumption.”。感觉意思是其它那些边框,选择其中预测置信度 > 0.3 的边框,作为分类的负样本(objectness)。即这些边框不应该有那么高的置信度来预测该样本对象。具体的就要看下代码了。

小结

总的来说,YOLO2 通过一些改进明显提升了预测准确性,同时继续保持其运行速度快的优势。YOLO9000 则开创性的提出联合使用分类样本和检测样本的训练方法,使对象检测能够扩展到缺乏检测样本的对象。

最后,如果你竟然坚持看到这里,觉得还有所帮助的话,请点个赞:)๑ ๑

参考

[1]YOLO9000: Better, Faster, Stronger

[2]Batch Normalization 原理与实战

[3]目标检测 | YOLOv2 原理与实现 (附 YOLOv3)

[4]YOLO9000: Better, Faster, Stronger

[5]WordNet

[6]YOLO v1 深入理解
https://zhuanlan.zhihu.com/p/47575929