YOLO有两个缺点:一个缺点在于定位不准确,另一个缺点在于和基于region proposal的方法相比召回率较低。因此YOLOv2主要是要在这两方面做提升。另外YOLOv2并不是通过加深或加宽网络达到效果提升,反而是简化了网络。
以下博文讲的比较好:
一文看懂YOLO v2_litt1e的博客-CSDN博客_yolov2
l)较低。YOLOv2共提出了几种改进策略来提升YOLO模型的定位准确度和召回率,从而提高mA YOLOv1虽然检测速度很快,但是在检测精度上却不如R-CNN系检测方法,YOLOv1在物体定位方面(localization)不够准确,并且召回率(recalP,YOLOv2在改进中遵循一个原则:保持检测速度,这也是YOLO模型的一大优势。YOLOv2的改进策略如图1所示,可以看出,大部分的改进方法都可以比较显著提升模型的mAP。下面详细介绍各个改进策略。
图1 YOLOv2的改进策略
1、Batch Normalization
BN(Batch Normalization)层简单讲就是对网络的每一层的输入都做了归一化,这样网络就不需要每层都去学数据的分布,收敛会快点。原来的YOLO算法(采用的是GoogleNet网络提取特征)是没有BN层的,因此在YOLOv2中作者为每个卷积层都添加了BN层。另外由于BN可以规范模型,所以本文加入BN后就把dropout去掉了。实验证明添加了BN层可以提高2%的mAP。
先建立这样一个观点: 对数据进行预处理(统一格式、均衡化、去噪等)能够大大提高训练速度,提升训练效果。批量规范化 正是基于这个假设的实践,对每一层输入的数据进行加工。示意图:
BN 的做法是 在卷积池化之后,激活函数之前,对每个数据输出进行规范化(均值为 0,方差为 1),公式如下图所示。
第一部分是 Batch内数据归一化(其中 E为Batch均值,Var为方差),Batch数据近似代表了整体训练数据。
第二部分是亮点,即引入 附加参数 γ 和 β(Scale & Shift),Why? 因为简单的归一化 相当于只使用了激活函数中近似线性的部分,破坏了原始数据的特征分布,这会降低模型表达能力。所以引入参数 γ 和 β(Scale & Shift)。
2、High Resolution Classifier
首先fine-tuning(微调)的作用不言而喻,现在基本跑个classification或detection的模型都不会从随机初始化所有参数开始,所以一般都是用预训练的网络来finetuning自己的网络,而且预训练的网络基本上都是在ImageNet数据集上跑的,一方面数据量大,另一方面训练时间久,而且这样的网络都可以在相应的github上找到。
原来的YOLO网络在预训练的时候采用的是224*224的输入(这是因为一般预训练的分类模型都是在ImageNet数据集上进行的),然后在detection的时候采用448*448的输入,这会导致从分类模型切换到检测模型的时候,模型还要适应图像分辨率的改变。而YOLOv2则将预训练分成两步:先用224*224的输入从头开始训练网络,大概160个epoch(表示将所有训练数据循环跑160次),然后再将输入调整到448*448,再训练10个epoch。注意这两步都是在ImageNet数据集上操作。最后再在检测的数据集上fine-tuning,也就是detection的时候用448*448的图像作为输入就可以顺利过渡了。作者的实验表明这样可以提高几乎4%的MAP。
3、Convolutional With Anchor Boxes
原来的YOLO是利用全连接层直接预测bounding box的坐标,而YOLOv2借鉴了Faster R-CNN的思想,引入anchor。首先将原网络的全连接层和最后一个pooling层去掉,使得最后的卷积层可以有更高分辨率的特征;然后缩减网络,用416*416大小的输入代替原来448*448。这样做的原因在于希望得到的特征图都有奇数大小的宽和高,奇数大小的宽和高会使得每个特征图在划分cell的时候就只有一个center cell(比如可以划分成7*7或9*9个cell,center cell只有一个,如果划分成8*8或10*10的,center cell就有4个)。为什么希望只有一个center cell呢?因为大的object一般会占据图像的中心,所以希望用一个center cell去预测,而不是4个center cell去预测。网络最终将416*416的输入变成13*13大小的feature map输出,也就是缩小比例为32。如下图,是yolov1的结构,特征图并不是都是奇数特征图(包含28*28,14*14)。
我们知道原来的YOLO算法将输入图像分成7*7的网格,每个网格预测两个bounding box,因此一共只有98个box,但是在YOLOv2通过引入anchor boxes,预测的box数量超过了1千(以输出feature map大小为13*13为例,每个grid cell有9个anchor box的话,一共就是13*13*9=1521个,当然由后面第4点可知,最终每个grid cell选择5个anchor box)。顺便提一下在Faster RCNN在输入大小为1000*600时的boxes数量大概是6000,在SSD300中boxes数量是8732。显然增加box数量是为了提高object的定位准确率。
作者的实验证明:虽然加入anchor使得MAP值下降了一点(69.5降到69.2),但是提高了recall(81%提高到88%)。
YOLOv2中引入anchor boxes,输出feature map大小为13×13,每个cell有5个anchor box预测得到5个bounding box,一共有13×13×5=845个box。增加box数量是为了提高目标的定位准确率。
4. Dimension Clusters(维度的集群)
Faster R-CNN中anchor box的大小和比例是按经验设定的,然后网络会在训练过程中调整anchor box的尺寸。但是如果一开始就能选择到合适尺寸的anchor box,那肯定可以帮助网络越好地预测detection。所以作者采用k-means的方式对训练集的bounding boxes做聚类,试图找到合适的anchor box。
另外作者发现如果采用标准的k-means(即用欧式距离来衡量差异),在box的尺寸比较大的时候其误差也更大,而我们希望的是误差和box的尺寸没有太大关系。所以通过IOU定义了如下的距离函数,使得误差和box的大小无关:
如下图,左边是聚类的簇个数核IOU的关系,两条曲线分别代表两个不同的数据集。在分析了聚类的结果并平衡了模型复杂度与recall值,作者选择了K=5,这也就是Figure2中右边的示意图是选出来的5个box的大小,这里紫色和黑色也是分别表示两个不同的数据集,可以看出其基本形状是类似的。而且发现聚类的结果和手动设置的anchor box大小差别显著。聚类的结果中多是高瘦的box,而矮胖的box数量较少。
Table1中作者采用的5种anchor(Cluster IOU)的Avg IOU是61,而采用9种Anchor Boxes的Faster RCNN的Avg IOU是60.9,也就是说本文仅选取5种box就能达到Faster RCNN的9中box的效果。
什么是k-means算法
K-Means算法的思想很简单,对于给定的样本集,按照样本之间的距离大小,将样本集划分为K个簇。让簇内的点尽量紧密的连在一起,而让簇间的距离尽量的大。
K-Means采用的启发式方式很简单,用下面一组图就可以形象的描述。
上图a表达了初始的数据集,假设k=2。在图b中,我们随机选择了两个k类所对应的类别质心,即图中的红色质心和蓝色质心,然后分别求样本中所有点到这两个质心的距离,并标记每个样本的类别为和该样本距离最小的质心的类别,如图c所示,经过计算样本和红色质心和蓝色质心的距离,我们得到了所有样本点的第一轮迭代后的类别。此时我们对我们当前标记为红色和蓝色的点分别求其新的质心,如图4所示,新的红色质心和蓝色质心的位置已经发生了变动。图e和图f重复了我们在图c和图d的过程,即将所有点的类别标记为距离最近的质心的类别并求新的质心。最终我们得到的两个类别如图f。
当然在实际K-Mean算法中,我们一般会多次运行图c和图d,才能达到最终的比较优的类别。算法流程如下图所示:
5. New Network:Darknet-19
YOLOv2采用了一个新的基础模型(特征提取器),称为Darknet-19,包括19个卷积层和5个maxpooling层,如下图所示。Darknet-19与VGG16模型设计原则是一致的,主要采用3*3卷积,采用2*2的maxpooling层之后,特征图维度降低2倍,而同时将特征图的channles增加两倍。与NIN(Network in Network)类似,Darknet-19最终采用global avgpooling做预测,并且在3*3卷积之间使用1*1卷积来压缩特征图channles以降低模型计算量和参数。Darknet-19每个卷积层后面同样使用了batch norm层以加快收敛速度,降低模型过拟合。在ImageNet分类数据集上,Darknet-19的top-1准确度为72.9%,top-5准确度为91.2%,但是模型参数相对小一些。使用Darknet-19之后,YOLOv2的mAP值没有显著提升,但是计算量却可以减少约33%。
网络包含19个卷积层和5个max pooling层,而在YOLOv1中采用的GooleNet,包含24个卷积层和2个全连接层,因此Darknet-19整体上卷积卷积操作比YOLOv1中用的GoogleNet要少,这是计算量减少的关键。最后用average pooling层代替全连接层进行预测。整体预测速度及训练速度会比yolov1提升。
6. Direct location prediction(直接位置预测)
YOLOv2中没有采用这种预测方式,而是沿用了YOLOv1的方法,就是预测边界框中心点相对于对应cell左上角位置的相对偏移值。
网络在最后一个卷积层输出13*13的feature map,有13*13个cell,每个cell有5个anchor box来预测5个bounding box,每个bounding box预测得到5个值。
分别为:tx、ty、tw、th和to(类似YOLOv1的confidence)
为了将bounding box的中心点约束在当前cell中,使用sigmoid函数将tx、ty归一化处理,将值约束在0~1,这使得模型训练更稳定。
其实这与BBR回归本质上差不多,BBR回归(相关内容点此链接)的参数是offset偏移值,而YOLO v2回归的是tx,ty,tw,th。它们都需要编码解码的过程来得到最终的坐标信息,差别只是已知信息的不同。
7. Fine-Grained Features(passthrough)
YOLOv2的输入图片大小为416×416,经过5次maxpooling之后得到13×13大小的特征图,并以此特征图采用卷积做预测。13×13大小的特征图对检测大物体是足够了,但是对于小物体还需要更精细的特征图(Fine-Grained Features)。因此SSD使用了多尺度的特征图来分别检测不同大小的物体,前面更精细的特征图可以用来预测小物体。YOLOv2提出了一种passthrough层来利用更精细的特征图。YOLOv2所利用的Fine-Grained Features是26×26大小的特征图(最后一个maxpooling层的输入),对于Darknet-19模型来说就是大小为26×26×512的特征图。passthrough层与ResNet网络的shortcut类似,以前面更高分辨率的特征图为输入,然后将其连接到后面的低分辨率特征图上。前面的特征图维度是后面的特征图的2倍,passthrough层抽取前面层的每个2×2的局部区域,然后将其转化为channel维度,对于26×26×512的特征图,经passthrough层处理之后就变成了13×13×2048的新特征图(特征图大小降低4倍,而channles增加4倍,图6为一个实例),这样就可以与后面的13×13×1024特征图连接在一起形成13×13×3072的特征图,然后在此特征图基础上卷积做预测。
8.Multi-Scale Training
YOLOv2中只有卷积层和池化层,因此不需要固定的输入图片的大小。
为了让模型更有鲁棒性,作者引入了多尺度训练。就是在训练过程中,每迭代一定的次数,改变模型的输入图片大小。
注意:这一步是在检测数据集上fine-tuning时候采用的,不要跟前面在Imagenet数据集上的两步预训练分类模型混淆。
网络输入是416×416,经过5次max pooling之后会输出13×13的feature map,也就是下采样32倍,因此作者采用32的倍数作为输入的size,具体采用320、352、384、416、448、480、512、544、576、608共10种size。
输入图片大小为320×320时,特征图大小为10×10,输入图片大小为608×608时,特征图大小为19×19。
每次改变输入图片大小还需要对最后检测层进行处理,然后开始训练。
这种网络训练方式使得相同网络可以对不同分辨率的图像做检测。
在输入size较大时,训练速度较慢,在输入size较小时,训练速度较快,而multi-scale training又可以提高准确率,因此算是准确率和速度都取得一个不错的平衡。
第一阶段就是先在ImageNet分类数据集上预训练Darknet-19,此时模型输入为224×224,共训练160个epochs。
第二阶段将网络的输入调整为448*448,继续在ImageNet数据集上finetune分类模型,训练10个epochs,此时分类模型的top-1准确度为76.5%,而top-5准确度为93.3%。
第三个阶段就是修改Darknet-19分类模型为检测模型,并在检测数据集上继续finetune网络。
(检测数据集,可以用来学习预测物体的边界框、置信度以及为物体分类,而对于分类数据集可以仅用来学习分类,但是其可以大大扩充模型所能检测的物体种类。)
引申:检测和分类的区别
识别的意义比较广泛,囊括了其他所有类型,包括但不限于以下常用任务:二分类(单纯的逻辑回归)、多分类(也可以看作单标签多分类问题)、检测(也可以看作多标签多分类逻辑回归)、语义分割、边框回归(bounding box)、看图说话(show and tell)。
二分类
顾名思义,对于每一张输入照片,都有两个标签与之对应——通常是有某物和无某物。其中有某物是正类,无某物是负类。
这一类任务通常是输出层只有一个神经元,该神经元的激活函数是Sigmoid,通常规定输出大于0.5是正类,小于0.5是负类。
训练损失函数采用交叉熵公式,。其中a是期望输出(正样本对应1,负样本对应0),x为网络实际输出。
多分类
与二分类相对应,目标类有n类,如鼠、猫、狗、狼、虎、象等标签,有时可能会有一个“空白”或者“背景”标签来表征除这些正类之外的负类。此时末层神经元有n个,每个神经元代表是对应类别的概率。
网络末层输出层通常是softmax层将结果规约为概率。将概率最大的类别作为预测结果。
训练过程依然采用交叉熵公式作为损失函数。不过由于期望输出中只有一个1,其他都是0,所以可以去掉反向概率项。
LOSS
(1)和YOLOv1一样,对于训练图片中的ground truth,若其中心点落在某个cell内,那么该cell内的5个先验框所对应的边界框负责预测它,具体是哪个边界框预测它,需要在训练中确定,即由那个与ground truth的IOU最大的边界框预测它,而剩余的4个边界框不与该ground truth匹配。YOLOv2同样需要假定每个cell至多含有一个grounth truth,而在实际上基本不会出现多于1个的情况。与ground truth匹配的先验框计算坐标误差、置信度误差(此时target为1)以及分类误差,而其它的边界框只计算置信度误差(此时target为0)。
(2)YOLOv2和YOLOv1的损失函数一样,为均方差函数。但是看了YOLOv2的源码(训练样本处理与loss计算都包含在文件region_layer.c中),并且参考国外的blog以及allanzelener/YAD2K(Ng深度学习教程所参考的那个Keras实现)上的实现,发现YOLOv2的处理比原来的v1版本更加复杂。
loss计算公式: