本篇博文主要讲YOLOv1-YOLOv3的进化历程。
论文名称:You only look once unified real-time object detection
论文链接
YOLOv1是典型的目标检测one stage方法,在YOLO算法中,核心思想 就是把物体检测(object detection)问题处理成回归问题,用一个卷积神经网络结构就可以从输入图像直接预测bounding box和类别概率。用回归的方法去做目标检测,执行速度快,达到非常高效的检测,其背后的原理和思想也非常简单。
如上图所示,YOLOv1的算法思想就是把一张图片,首先reshape成448x448大小(由于网络中使用了全连接层,所以图片的尺寸需固定大小输入到CNN中),然后将划分成SxS个单元格(原文中S=7),以每个格子所在位置和对应内容为基础,来预测:
1)检测框,包含物体框中心相对其所在网格单元格边界的偏移(一般是相对于单元格左上角坐标点的位置偏移,以下用x,y表示)和检测框真实宽高相对于整幅图像的比例(注意这里w,h不是实际的边界框宽和高),每个格子预测B个检测框(原文中是2),如下图;
2)每个框的Confidence,这个confidence代表了预测框含有目标的置信度和这个预测框预测的有多准2重信息,公式和说明如下:
3)每个格子预测一共C个类别的概率分数,并且这个分数和物体框是不相关的,只是基于这个格子。
注意(重要细节):
综上所述:每个格子需要输出的信息维度是Bx(4+1)+C=Bx5+C。在YOLO的论文中,S=7,B=2,C是PASCAL VOC的类别数20,所以最后得到的关于预测的物体信息是一个7x7x30的张量。最后从这7x7x30的张量中提取出来的预测框和类别预测的信息经过NMS,就得到了最终的物体检测结构。
网络方面主要采用GoogLeNet,卷积层主要用来提取特征,全连接层主要用来预测类别概率和坐标。并且,作者将GoogleNet中的Inception模块换成了1x1卷积后接3x3卷积,最终网络结构由24个卷积层和4个最大池化层和2个全连接层组成。
两个小细节:1、作者先在ImageNet数据集上预训练网络,而且网络只采用fig3的前面20个卷积层,输入是224224大小的图像。然后在检测的时候再加上随机初始化的4个卷积层和2个全连接层,同时输入改为更高分辨率的448448。2、Relu层改为pRelu,即当x<0时,激活值是0.1*x,而不是传统的0。
Loss Function公式详细介绍:
在loss function中,前面两行表示localization error(即坐标误差),第一行是box中心坐标(x,y)的预测,第二行为宽和高的预测。这里注意用宽和高的开根号代替原来的宽和高,这样做主要是因为相同的宽和高误差对于小的目标精度影响比大的目标要大。举个例子,原来w=10,h=20,预测出来w=8,h=22,跟原来w=3,h=5,预测出来w1,h=7相比,其实前者的误差要比后者小,但是如果不加开根号,那么损失都是一样:4+4=8,但是加上根号后,变成0.15和0.7。
第三、四行表示bounding box的confidence损失,就像前面所说的,分成grid cell包含与不包含object两种情况。这里注意下因为每个grid cell包含两个bounding box,所以只有当ground truth 和该网格中的某个bounding box的IOU值最大的时候,才计算这项。
第五行表示预测类别的误差,注意前面的系数只有在grid cell包含object的时候才为1。
所以具体实现的时候是什么样的过程呢?
训练的时候: 输入N个图像,每个图像包含M个objec,每个object包含4个坐标(x,y,w,h)和1个label。然后通过网络得到7730大小的三维矩阵。每个1*30的向量前5个元素表示第一个bounding box的4个坐标和1个confidence,第6到10元素表示第二个bounding box的4个坐标和1个confidence。最后20个表示这个grid cell所属类别。注意这30个都是预测的结果。然后就可以计算损失函数的第一、二 、五行。至于第二三行,confidence可以根据ground truth和预测的bounding box计算出的IOU和是否有object的0,1值相乘得到。真实的confidence是0或1值,即有object则为1,没有object则为0。 这样就能计算出loss function的值了。
测试的时候:输入一张图像,跑到网络的末端得到7730的三维矩阵,这里虽然没有计算IOU,但是由训练好的权重已经直接计算出了bounding box的confidence。然后再跟预测的类别概率相乘就得到每个bounding box属于哪一类的概率。
1、位置精确性差,并且,由于每个单元格只预测2个bbox,然后每个单元格最后只取与gt_bbox的IOU高的那个最为最后的检测框,也只是说每个单元格最多只预测一个目标,若单个单元格有多个目标时,只能检测出其他的一个,导致小目标漏检,因此YOLOv1对于小目标物体以及物体比较密集的检测不是很好。
2、YOLO虽然可以降低将背景检测为物体的概率,但同时导致召回率较低。
3、由于输出层为全连接层,因此在检测时,YOLO 训练模型只支持与训练图像相同的输入分辨率的图片。
YOLOv2又叫YOLO9000,其能检测超过9000种类别的物体,在VOC2007数据集中在76FPS的速度下,能达到76.8%的mAP,在40FPS的速度下,能达到78.6%的mAP,很好的达到速度与精度的平衡。
论文链接
Anchor: 引入了Faster R-CNN中使用的Anchor,注意这里作者在YOLOv2中设计的Anchor并不是像Faster R-CNN中人为事先设计的尺寸和高宽比一级个数,作者通过在所有训练图像的所有边界框上运行k-means聚类来选择锚的个数和形状(k = 5,因此它找到五个最常见的目标形状)。因此,YOLO的锚是特定于您正在训练(和测试)的数据集的。k-means算法找到了将所有数据点划分聚类的方法。这里的数据点是数据集中所有真实边界框的宽度和高度。但5个锚是否最佳选择?我们可以在不同数量的聚类上多次运行k-means,并计算真实标签框与它们最接近的锚框之间的平均IOU。毫无疑问,使用更多质心(k值越大)平均IOU越高,但这也意味着我们需要在每个网格单元中使用更多的检测器,并使模型运行速度变慢。对于YOLO v2,他们选择了5个锚作为召回率和模型复杂度之间的良好折衷。
坐标预测: 在这里作者虽然引入了Faster R-CNN中类似的anchor,但是作者并没有像其意义,对bbox中心坐标的预测是基于anchor坐标的偏移量得到的,而是采用了v1中预测anchor中心点相对于对于单元格左上角位置的偏移,如下图:
Batch Normalization: 使用Batch Normalization对网络进行优化,让网络提高了收敛性,同时还消除了对其他形式的正则化(regularization)的依赖。 通过对YOLO的每一个卷积层增加Batch Normalization,最终使得mAP提高了2%,同时还使model正则化。使用Batch Normalization可以从model中去掉Dropout,而不会产生过拟合。
High Resolution Classifier : 首先fine-tuning的作用不言而喻,现在基本跑个classification或detection的模型都不会从随机初始化所有参数开始,所以一般都是用预训练的网络来finetuning自己的网络,而且预训练的网络基本上都是在ImageNet数据集上跑的,一方面数据量大,另一方面训练时间久,而且这样的网络都可以在相应的github上找到。
原来的YOLO网络在预训练的时候采用的是224 * 224的输入(这是因为一般预训练的分类模型都是在ImageNet数据集上进行的),然后在detection的时候采用448 * 448的输入,这会导致从分类模型切换到检测模型的时候,模型还要适应图像分辨率的改变。而YOLOv2则将预训练分成两步:先用224 * 224的输入从头开始训练网络,大概160个epoch(表示将所有训练数据循环跑160次),然后再将输入调整到448448,再训练10个epoch。注意这两步都是在ImageNet数据集上操作。最后再在检测的数据集上fine-tuning,也就是detection的时候用448448的图像作为输入就可以顺利过渡了。作者的实验表明这样可以提高几乎4%的MAP。
Convolutional With Anchor Boxes : 原来的YOLO是利用全连接层直接预测bounding box的坐标,而YOLOv2借鉴了Faster R-CNN的思想,引入anchor。 首先将原网络的全连接层和最后一个pooling层去掉,使得最后的卷积层可以有更高分辨率的特征;然后缩减网络,用416416大小的输入代替原来448448。这样做的原因在于希望得到的特征图都有奇数大小的宽和高,奇数大小的宽和高会使得每个特征图在划分cell的时候就只有一个center cell(比如可以划分成77或99个cell,center cell只有一个,如果划分成88或1010的,center cell就有4个)。为什么希望只有一个center cell呢?因为大的object一般会占据图像的中心,所以希望用一个center cell去预测,而不是4个center cell去预测。网络最终将416416的输入变成1313大小的feature map输出,也就是缩小比例为32。
我们知道原来的YOLO算法将输入图像分成77的网格,每个网格预测两个bounding box,因此一共只有98个box,但是在YOLOv2通过引入anchor boxes,预测的box数量超过了1千(以输出feature map大小为1313为例,每个grid cell有9个anchor box的话,一共就是13139=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%)。
论文:YOLOv3: An Incremental Improvement
论文链接
YOLO算法的基本思想是: 首先通过特征提取网络对输入图像提取特征,得到一定size的feature map,比如1313,然后将输入图像分成1313个grid cell,接着如果ground truth中某个object的中心坐标落在哪个grid cell中,那么就由该grid cell来预测该object,因为每个grid cell都会预测固定数量的bounding box(YOLO v1中是2个,YOLO v2中是5个,YOLO v3中是3个,这几个bounding box的初始size是不一样的),那么这几个bounding box中最终是由哪一个来预测该object?答案是:这几个bounding box中只有和ground truth的IOU最大的bounding box才是用来预测该object的。可以看出预测得到的输出feature map有两个维度是提取到的特征的维度,比如1313,还有一个维度(深度)是B(5+C),注:YOLO v1中是(B*5+C),其中B表示每个grid cell预测的bounding box的数量,比如YOLO v1中是2个,YOLO v2中是5个,YOLO v3中是3个,C表示bounding box的类别数(没有背景类,所以对于VOC数据集是20),5表示4个坐标信息和一个置信度(objectness score)。
分类损失:在YOLOv3中,每个框用多标签分类来预测边界框可能包含的类。该算法将v2中的softmax替换成了逻辑回归loss,在训练过程中使用二原交叉熵损失来进行类别预测。对于重叠的标签,多标签方法可以更好的模拟数据。
跨尺度预测:YOLOv3采用多个尺度融合的方式做预测。原来YOLOv2中有一个层叫:passthrough layer,假设最后提取的特征图尺度是1313,那么这个层的作用就是将前面一层的2626的特征图和本层1313的特征图进行连接,有点像ResNet。这样的操作是为了加强YOLO算法对小目标检测的精度。在YOLOv3中,作者采用了类似与FPN的上采样和融合做法(最后融合了3个尺度,其他2个尺度分别是2626和52*52),在多给尺度的特征图上做预测,对于小目标的提升效果还是非常明显的。虽然在YOLOv3中每个网格预测3个边界框,比v2中的5个要少,但v3采用了多个尺度的特征融合,所以边界框的数量也比之前多很多。
Darknet53与其他backbone对比(256×256的图片,并进行单精度测试。运行环境为Titan X)
尝试,但效果不好的工作
Anchor box坐标的偏移预测。 作者尝试了常规的Anchor box预测方法,比如利用线性激活将坐标x、y的偏移程度预测为边界框宽度或高度的倍数。但发现这种做法降低了模型的稳定性,且效果不佳。 用线性方法预测x,y,而不是使用逻辑方法。我们尝试使用线性激活来直接预测x,y的offset,而不是逻辑激活,还降低了mAP。
focal loss。我们尝试使用focal loss,但使我们的mAP降低了2%。 对于focal loss函数试图解决的问题,YOLOv3从理论上来说已经很强大了,因为它具有单独的对象预测和条件类别预测。因此,对于大多数例子来说,类别预测没有损失?或者其他的东西?我们并不完全确定。
双IOU阈值和真值分配。在训练期间,Faster RCNN用了两个IOU阈值,如果预测的边框与ground truth的IoU>0.7,那它是个正样本;如果在[0.3,0.7]之间,则忽略;如果和ground truth的IoU<0.3,那它就是个负样本。作者尝试了这种思路,但效果并不好。
YOLO系列算法不断吸收目标检测同类算法的优点,如FPN,Faster-RCNN,ResNet,,将其应用与自身,不断进步,取得了较高的检测速度和检测精度,相比于其他算法更符合工业界对目标检测算法实时性的要求,简单易实现,对于嵌入式很友好,期待下一代的YOLO算法!