YOLO(You Only Look Once)是一种基于深度神经网络的对象识别和定位算法,其最大的特点是运行速度很快,可以用于实时系统。现在YOLO已经发展到v3版本,不过新版本也是在原有版本基础上不断改进演化的,所以本文先分析YOLO v1版本。
输入一张图片,要求输出其中所包含的对象,以及每个对象的位置(包含该对象的矩形框)。
对象识别和定位,可以看成两个任务:找到图片中某个存在对象的区域,然后识别出该区域中具体是哪个对象。对象识别这件事(一张图片仅包含一个对象,且基本占据图片的整个范围),最近几年基于CNN卷积神经网络的各种方法已经能达到不错的效果了。所以主要需要解决的问题是,对象在哪里。
最简单的想法,就是遍历图片中所有可能的位置,地毯式搜索不同大小,不同宽高比,不同位置的每个区域,逐一检测其中是否存在某个对象,挑选其中概率最大的结果作为输出。显然这种方法效率太低。
RCNN/Fast RCNN/Faster RCNN
RCNN开创性的提出了候选区(Region Proposals)的方法,先从图片中搜索出一些可能存在对象的候选区Selective Search,大概2000个左右,然后对每个候选区进行对象识别。大幅提升了对象识别和定位的效率。不过RCNN的速度依然很慢,其处理一张图片大概需要49秒。因此又有了后续的Fast RCNN 和 Faster RCNN,针对RCNN的神经网络结构和候选区的算法不断改进,Faster RCNN已经可以达到一张图片约0.2秒的处理速度。
YOLO
YOLO创造性的将候选区和对象识别这两个阶段合二为一,看一眼图片(不用看两眼哦)就能知道有哪些对象以及它们的位置。实际上,YOLO并没有真正去掉候选区,而是采用了预定义的候选区(准确说应该是预测区,并不是Faster RCNN所采用的Anchor)。也就是将图片划分为 77=49 个网格(grid),每个网格允许预测出2个边框(bounding box,包含某个对象的矩形框),总共 492=98 个bounding box。可以理解为98个候选区,它们很粗略的覆盖了图片的整个区域。
RCNN:我们先来研究一下图片,嗯,这些位置很可能存在一些对象,你们对这些位置再检测一下看到底是哪些对象在里面。
YOLO:我们把图片大致分成98个区域,每个区域看下有没有对象存在,以及具体位置在哪里。
RCNN:你这么简单粗暴真的没问题吗?
YOLO:当然没有…咳,其实是有一点点问题的,准确率要低一点,但是我非常快!快!快!
RCNN:为什么你用那么粗略的候选区,最后也能得到还不错的bounding box呢?
YOLO:你不是用过边框回归吗?我拿来用用怎么不行了。
RCNN虽然会找到一些候选区,但毕竟只是候选,等真正识别出其中的对象以后,还要对候选区进行微调,使之更接近真实的bounding box。这个过程就是边框回归:将候选区bounding box调整到更接近真实的bounding box。既然反正最后都是要调整的,干嘛还要先费劲去寻找候选区呢,大致有个区域范围就行了,所以YOLO就这么干了。
下面具体看下YOLO的实现方案。
1)结构
去掉候选区这个步骤以后,YOLO的结构非常简单,就是单纯的卷积、池化最后加了两层全连接。最大的差异是最后输出层用线性函数做激活函数,因为需要预测bounding box的位置(数值型),而不仅仅是对象的概率。YOLO网络结构由24个卷积层与2个全连接层构成,网络入口为448x448(v2为416x416),图片进入网络先经过resize,网络的输出结果为一个张量,维度为:
其中,S为划分网格数,B为每个网格负责的边框个数,C为类别个数。每个小格会对应B个边界框,边界框的宽高范围为全图,表示以该小格为中心寻找物体的边界框位置。每个边界框对应一个分值,代表该处是否有物体及定位准确度:,每个小格会对应C个概率值,找出最大概率对应的类别P(Class|object),并认为小格中包含该物体或者该物体的一部分。
2)输入和输出的映射关系
3)输入
输入就是原始图像,唯一的要求是缩放到448*448的大小。主要是因为YOLO的网络中,卷积层最后接了两个全连接层,全连接层是要求固定大小的向量作为输入,所以倒推回去也就要求原始图像有固定的尺寸。那么YOLO设计的尺寸就是448*448。
4)输出是一个 7730 的张量(tensor)。
输入图像被划分为 7*7 的网格(grid),输出张量中的 7*7 就对应着输入图像的 7*7 网格。或者我们把 7*7*30 的张量看作49个30维的向量,也就是输入图像中的每个网格对应输出一个30维的向量。参考上图,比如输入图像左上角的网格对应到输出张量中左上角的向量。
要注意的是,并不是说仅仅网格内的信息被映射到一个30维向量。经过神经网络对输入图像信息的提取和变换,网格周边的信息也会被识别和整理,最后编码到那个30维向量中。具体来看每个网格对应的30维向量中包含了哪些信息?
① 20个对象分类的概率
YOLO支持识别20种不同的对象(人、鸟、猫、汽车、椅子等),所以这里有20个值表示该网格位置存在任一种对象的概率。可以记为 P(C_1|Object), ......, P(C_i|Object),......P(C_{20}|Object),之所以写成条件概率,意思是如果该网格存在一个对象Object,那么它是C_i的概率是P(C_i|Object)。
② 2个bounding box的位置
每个bounding box需要4个数值来表示其位置,(Center_x,Center_y,width,height),即(bounding box的中心点的x坐标,y坐标,宽度,高度),2个bounding box共需要8个数值来表示其位置。其中坐标的 x, y 用对应网格的 offset 归一化到 0-1 之间,w, h 用图像的 width 和 height 归一化到 0-1 之间。
③ 2个bounding box的置信度
bounding box的置信度 = 该bounding box内存在对象的概率 * 该bounding box与该对象实际bounding box的IOU,公式:
Confidence = Pr(Object) * IOU_{pred}^{truth}
Pr(Object)是bounding box内存在对象的概率,区别于 P(C_i|Object)。Pr(Object)并不管是哪个对象,它体现的是有或没有对象的概率。第①点中的P(C_i|Object)意思是假设已经有一个对象在网格中了,这个对象具体是哪一个。
IOU_{pred}^{truth}是 bounding box 与对象真实bounding box 的IOU。要注意的是,现在讨论的30维向量中的bounding box是YOLO网络的输出,也就是预测的bounding box。所以IOU_{pred}^{truth}体现了预测的bounding box与真实bounding box的接近程度。还要说明的是,虽然有时说"预测"的bounding box,但这个IOU是在训练阶段计算的。等到了测试阶段(Inference),这时并不知道真实对象在哪里,只能完全依赖于网络的输出,这时已经不需要(也无法)计算IOU了。
综合来说,一个bounding box的置信度Confidence意味着它是否包含对象且位置准确的程度。置信度高表示这里存在一个对象且位置比较准确,置信度低表示可能没有对象 或者 即便有对象也存在较大的位置偏差。
总的来说,30维向量 = 20个对象的概率 + 2个bounding box * 4个坐标 + 2个bounding box的置信度
注意:class 信息是针对每个网格的,confidence 信息是针对每个 bounding box 的。
4.2)讨论
① 一张图片最多可以检测出49个对象。每个30维向量中只有一组(20个)对象分类的概率,也就只能预测出一个对象。所以输出的 7*7=49个30维向量,最多表示出49个对象。
② 总共有 49*2=98 个候选区(bounding box),每个30维向量中有2组bounding box,所以总共是98个候选区。
③ YOLO的bounding box并不是Faster RCNN的Anchor
Faster RCNN等一些算法采用每个grid中手工设置n个Anchor(先验框,预先设置好位置的bounding box)的设计,每个Anchor有不同的大小和宽高比。YOLO的bounding box看起来很像一个grid中2个Anchor,但它们不是。YOLO并没有预先设置2个bounding box的大小和形状,也没有对每个bounding box分别输出一个对象的预测。它的意思仅仅是对一个对象预测出2个bounding box,选择预测得相对比较准的那个。
我们需要事先根据样本给出一个正确的bounding box作为回归的目标。YOLO的2个bounding box事先并不知道会在什么位置,只有经过前向计算,网络会输出2个bounding box,这两个bounding box与样本中对象实际的bounding box计算IOU。这时才能确定,IOU值大的那个bounding box,作为负责预测该对象的bounding box。
训练开始阶段,网络预测的bounding box可能都是乱来的,但总是选择IOU相对好一些的那个,随着训练的进行,每个bounding box会逐渐擅长对某些情况的预测(可能是对象大小、宽高比、不同类型的对象等)。所以,这是一种进化或者非监督学习的思想。
另外就是一个Object只由一个grid来进行预测,不要多个grid都抢着预测同一个Object。更具体一点说,就是在设置训练样本的时候,样本中的每个Object归属到且仅归属到一个grid,即便有时Object跨越了几个grid,也仅指定其中一个。具体就是计算出该Object的bounding box的中心位置,这个中心位置落在哪个grid,该grid对应的输出向量中该对象的类别概率是1(该gird负责预测该对象),所有其它grid对该Object的预测概率设为0(不负责预测该对象)。
还有:虽然一个grid中会产生2个bounding box,但我们会选择其中一个作为预测结果,另一个会被忽略。下面构造训练样本的部分会看的更清楚。
④ 可以调整网格数量、bounding box数量
7*7网格,每个网格2个bounding box,对448*448输入图像来说覆盖粒度有点粗。我们也可以设置更多的网格以及更多的bounding box。设网格数量为 S*S,每个网格产生B个边框,网络支持识别C个不同的对象。这时,输出的向量长度为:C + B * (4+1),整个输出的tensor就是:S * S * (C + B * (4+1))
YOLO选择的参数是 7*7网格,2个bounding box,20种对象,因此输出向量长度 = 20 + 2 * (4+1) = 30。整个输出的tensor就是 7*7*30。因为网格和bounding box设置的比较稀疏,所以这个版本的YOLO训练出来后预测的准确率和召回率都不是很理想,后续的v2、v3版本还会改进。当然,因为其速度能够满足实时处理的要求,所以对工业界还是挺有吸引力的。
5)训练样本构
作为监督学习,我们需要先构造好训练样本,才能让模型从中学习。对于一张输入图片,其对应输出的7*7*30张量(也就是监督学习所说的标签label)应该填写什么数据呢?首先,输出的 7*7维度对应于输入的 7*7 网格。然后具体看下30维向量的填写。
① 20个对象分类的概率
对于输入图像中的每个对象,先找到其中心点。比如图中的自行车,其中心点在黄色圆点位置,中心点落在黄色网格内,所以这个黄色网格对应的30维向量中,自行车的概率是1,其它对象的概率是0。所有其它48个网格的30维向量中,该自行车的概率都是0。这就是所谓的"中心点所在的网格对预测该对象负责"。狗和汽车的分类概率也是同样的方法填写。
② 2个bounding box的位置
训练样本的bounding box位置应该填写对象实际的bounding box,但一个对象对应了2个bounding box参数,应该把实际的bounding box填在哪一个里面?上面讨论过,需要根据网络输出的bounding box与对象实际bounding box的IOU来选择,所以要在训练过程中动态决定到底填哪一个bounding box。参考下面第③点。
③ 2个bounding box的置信度
上面讨论过置信度公式:
Confidence = Pr(Object) * IOU_{pred}^{truth}
IOU_{pred}^{truth}可以直接计算出来,就是用网络输出的2个bounding box与对象真实bounding box一起计算出IOU。然后看2个bounding box的IOU,哪个比较大(更接近实际的bounding box),就由哪个bounding box来负责预测该对象是否存在,即该bounding box的Pr(Object) =1,同时把对象真实的bounding box参数填入到这个bounding box位置向量处。另一个不负责预测的bounding box的Pr(Object) =0。
总的来说就是,与对象实际bounding box最接近的那个bounding box,其Confidence=IOU_{pred}^{truth},该网格的其它bounding box的Confidence=0。
举个例子,比如上图中自行车的中心点位于4行3列网格中,所以输出tensor中4行3列位置的30维向量如下图所示。
4行3列网格位置有一辆自行车,它的中心点在这个网格内,把自行车的实际边框参数填入样本标签向量中的bounding box1位置。注意,图中将自行车实际边框参数放在bounding box1,但实际上是在训练过程中,等网络输出以后,比较两个bounding box1和bounding box2与自行车实际bounding box的IOU,发现输出的bounding box1与实际边框的IOU最大,所以把自行车的实际bounding box参数放置在图中bounding box1位置,且该bounding box1的置信度设为1,bounding box2正常存入,同时置信度置0.
6)损失函数
损失就是网络实际输出值与样本标签值之间的偏差。
(我们输出 预测边框坐标1和 预测边框坐标2,然后计算与实际对象边框的IOU,最大的那个预测边框对应的位置处,把样本标签对应的位置填入实际对象边框)
YOLO的损失函数:
损失函数的设计目标就是让坐标(x,y,w,h)8维,confidence 2维,classification 20维这个三个方面达到很好的平衡。简单的全部采用了sum-squared error loss来做这件事会有以下不足:
a) 8维的localization error和20维的classification error同等重要显然是不合理的。
b) 如果一些格子中没有object(一幅图中这种格子很多),那么就会将这些栅格子中的bounding box的confidence 置为0,相比于较少数量的有object的格子,这些不包含物体的格子对梯度更新的贡献会远大于包含物体的格子对梯度更新的贡献,这会导致网络不稳定甚至发散。
对不同大小的bbox预测中,相比于大bbox预测偏一点,小box预测偏相同的尺寸对IOU的影响更大。而sum-square error loss中对同样的偏移loss是一样。 为了缓和这个问题,作者用了一个巧妙的办法,就是将box的width和height取平方根代替原本的height和width。 如下图:small bbox的横轴值较小,发生偏移时,反应到y轴上的loss(下图绿色)比big box(下图红色)要大。
1_i^{obj}意思是网格i中存在对象;1_{ij}^{obj}意思是网格i的第j个bounding box中存在对象。1_{ij}^{noobj}意思是网格i的第j个bounding box中不存在对象,C_i表示存在对象的概率。
总的来说,就是用网络输出与样本标签的各项内容的误差平方和作为一个样本的整体误差。损失函数中的几个项是与输出的30维向量中的内容相对应的。
① 对象分类的误差
公式第5行类别预测,1_i^{obj}意味着存在对象的网格才计入误差。
② bounding box的位置误差
上图蓝色框有错误,以下图为准:
a)都带有1_{ij}^{obj}意味着只有"负责"(IOU比较大)预测的那个bounding box的数据才会计入误差。
b)第2行宽度和高度先取了平方根,因为如果直接取差值的话,大的对象对差值的敏感度较低,小的对象对差值的敏感度较高,所以取平方根可以降低这种敏感度的差异,使得较大的对象和较小的对象在尺寸误差上有相似的权重。
c)给这些损失前面赋予更大的loss weight, 记为 λcoord ,乘以 \lambda_{coord} 调节bounding box位置误差的权重(相对分类误差和置信度误差)。YOLO设置 \lambda_{coord} = 5,即调高位置误差的权重。
③ bounding box的置信度误差
a)第3行是存在对象的bounding box的置信度误差。带有1_{ij}^{obj}意味着只有"负责"(IOU比较大)预测的那个bounding box的置信度才会计入误差。
b)第4行是不存在对象的bounding box的置信度误差。因为不存在对象的bounding box应该老老实实的说"我这里没有对象",也就是输出尽量低的置信度。如果它不恰当的输出较高的置信度,会与真正"负责"该对象预测的那个bounding box产生混淆。其实就像对象分类一样,正确的对象概率最好是1,所有其它对象的概率最好是0。有object的bbox的confidence loss (上图红色框) 的loss weight正常取1。
c)对没有object的bbox的confidence loss,赋予小的loss weight,记为 λnoobj ,乘以 \lambda_{noobj} 调节不存在对象的bounding box的置信度的权重(相对其它误差)。YOLO设置 \lambda_{noobj} = 0.5,即调低不存在对象的bounding box的置信度误差的权重。
7)训练
YOLO先使用ImageNet数据集对前20层卷积网络进行预训练,然后使用完整的网络,在PASCAL VOC数据集上进行对象识别和定位的训练和预测。YOLO的网络结构如下图所示:
YOLO的最后一层采用线性激活函数,其它层都是Leaky ReLU。训练中采用了drop out和数据增强(data augmentation)来防止过拟合。
8)预测(inference)
训练好的YOLO网络,输入一张图片,将输出一个 7*7*30 的张量(tensor)来表示图片中所有网格包含的对象(概率)以及该对象可能的2个位置(bounding box)和置信度。YOLO采用NMS(Non-maximal suppression,非极大值抑制)算法,从中提取出最有可能的那些对象和位置。
9)NMS(非极大值抑制)
NMS其核心思想是:选择得分最高的作为输出,与该输出重叠的去掉,不断重复这一过程直到所有备选处理完。YOLO的NMS计算方法如下。
网络输出的7730的张量,在每一个网格中,对象C_i位于第j个bounding box的得分:
Score_{ij} = P(C_i|Object) * Confidence_j
它代表着某个对象C_i存在于第j个bounding box的可能性。每个网格有:20个对象的概率*2个bounding box的置信度,共40个得分(候选对象)。49个网格共1960个得分。对每种对象分别进行NMS,那么每种对象有1960/20=98个得分。
NMS步骤如下:
1)设置一个Score的阈值,低于该阈值的候选对象排除掉(将该Score设为0)
2)遍历每一个对象类别
2.1)遍历该对象的98个得分
2.1.1)找到Score最大的那个对象及其bounding box,添加到输出列表
2.1.2)对每个Score不为0的候选对象,计算其与上面2.1.1输出对象的bounding box的IOU
2.1.3)根据预先设置的IOU阈值,所有高于该阈值(重叠度较高)的候选对象排除掉(将Score设为0)
2.1.4)如果所有bounding box要么在输出列表中,要么Score=0,则该对象类别的NMS完成,返回步骤2处理下一种对象
3)输出列表即为预测的对象
10)小结YOLO的检测流程:
2.将图片放到网络里面进行处理。
3.进行非极大值抑制处理得到结果。
YOLO不同于传统的检测算法,采用滑动窗口来寻找目标。YOLO直接采用单个卷积神经网络来预测多个bounding boxes和类别概率。
YOLO存在的优点是:
1.速度快,处理速度可以达到45fps,其快速版本(网络较小)甚至可以达到155fps。这得益于其识别和定位合二为一的网络设计,而且这种统一的设计也使得训练和预测可以端到端的进行,非常简便。
3.背景预测错误率低,因为是整张图片放到网络里面进行预测。
YOLO存在的缺点是:
精度低,小目标和邻近目标检测效果差,小对象检测效果不太好(尤其是一些聚集在一起的小对象),对边框的预测准确度不是很高,总体预测精度略低于Fast RCNN。主要是因为网格设置比较稀疏,而且每个网格只预测两个边框,另外Pooling层会丢失一些细节信息,对定位存在影响。
YOLO与Fast R-CNN相比有较大的定位误差,与基于region proposal的方法相比具有较低的召回率。但是,YOLO在定位识别背景时准确率更高,而 Fast-R-CNN 的假阳性很高。基于此作者设计了 Fast-R-CNN + YOLO 检测识别模式,即先用R-CNN提取得到一组bounding box,然后用YOLO处理图像也得到一组bounding box。对比这两组bounding box是否基本一致,如果一致就用YOLO计算得到的概率对目标分类,最终的bouding box的区域选取二者的相交区域。这种组合方式将准确率提高了3个百分点。
论文下载地址:https://pjreddie.com/media/files/papers/yolo.pdf
caffe代码下载地址:https://github.com/yeahkun/caffe-yolo
二、YOLOv2
V1 缺陷之处:
输入尺寸固定:由于输出层为全连接层,因此在检测时,YOLO 训练模型只支持与训练图像相同的输入分辨率。其它分辨率需要缩放成此固定分辨率;
占比小的目标检测效果不好:虽然每个格子可以预测 B 个 bounding box,但是最终只选择只选择 IOU 最高的bbox作为物体检测输出,即每个格子最多只预测出一个物体。当物体占画面比例较小,如图像中包含畜群或鸟群时,每个格子包含多个物体,但却只能检测出其中一个。
为提高物体定位精准性和召回率,YOLO 作者提出了 《YOLO9000: Better, Faster, Stronger》 (Joseph Redmon, Ali Farhadi, CVPR 2017, Best Paper Honorable Mention),也就是 YOLOv2 的论文全名,相比 v1 提高了训练图像的分辨率;引入了 faster rcnn 中 anchor box 的思想,对网络结构的设计进行了改进,使得模型更易学习。YOLOv2的结构示意图如下:
在这里插入图片描述
分类网络
Fine-Grained Features细粒度特征
这里添加了一个直通层(passthrough layer),即就是源码中的reorg layer,将前面一层的26*26的特征图和本层13*13的特征图进行连接,与ResNet网络的shortcut类似,以前面更高分辨率的特征图为输入,然后将其连接到后面的低分辨率特征图上。
在1313的特征图上做预测,虽然对于大目标已经足够了,但对小目标不一定足够好,这里合并前面大一点的特征图可以有效的检测小目标。
具体操作:对于2626512的特征图,经passthrough层处理之后就变成了13132048的新特征图(特征图大小变为1/4,而通道数变为以前的4倍),然后与后面的13131024特征图连接在一起形成1313*3072的特征图,最后在该特征图上卷积做预测。
1、Anchor Boxes:v1中直接在卷积层之后使用全连接层预测bbox的坐标。v2借鉴Faster R-CNN的思想预测bbox的偏移.
为了引入anchor boxes来预测bounding boxes,作者在网络中果断去掉了全连接层。剩下的具体怎么操作呢?首先,作者去掉了后面的一个池化层以确保输出的卷积特征图有更高的分辨率。然后,通过缩减网络,让图片输入分辨率为416 * 416,这一步的目的是为了让后面产生的卷积特征图宽高都为奇数,这样就可以产生一个center cell(yolo使用pooling来下采样,有5个size=2, stride=2的max pooling,而卷积层没有降低大小,因此最后的特征是416/(2^5)=13).。作者观察到,大物体通常占据了图像的中间位置, 就可以只用中心的一个cell来预测这些物体的位置,否则就要用中间的4个cell来进行预测,这个技巧可稍稍提升效率。最后,YOLOv2输入卷积网络的416 * 416图片最终得到13 * 13的卷积特征图(416/32=13)。
2、输出层使用卷积层替代 YOLOv1 的全连接层
YOLOv2提出了一种新的分类模型Darknet-19。主要使用3x3卷积并在pooling之后channel数加倍(VGG);global average pooling替代全连接做预测分类,并在3x3卷积之间使用1x1卷积压缩特征表示(Network in Network);使用 batch normalization 来提高稳定性,加速收敛,对模型正则化。Darknet-19的结构如下表:
darknet-19
包含 19 conv + 5 maxpooling.用 1x1 卷积层替代 YOLOv1 的全连接层。1x1 卷积层( 为了跨通道信息整合)如上图的红色矩形框部分。
3、高分辨率分类器:目前大部分的检测模型都会在先在ImageNet分类数据集上预训练模型的主体部分(CNN特征提取器),ImageNet分类模型基本采用大小为 224\times224 的图片作为输入,分辨率相对较低,不利于检测模型。所以YOLOv1在采用 224\times224 分类模型预训练后,将分辨率增加至 448\times448 ,并使用这个高分辨率在检测数据集上finetune。但是直接切换分辨率,检测模型可能难以快速适应高分辨率。所以YOLOv2增加了在ImageNet数据集上使用 448\times448 输入来finetune分类网络这一中间过程(10 epochs),这可以使得模型在检测数据集上finetune之前已经适用高分辨率输入。
v1使用224 × 224训练分类器网络,扩大到448用于检测网络。v2将ImageNet以448×448 的分辨率微调最初的分类网络,迭代10 epochs。
4、卷积层全部使用 Batch Normalization
v1 中也大量用了 Batch Normalization,同时在定位层后边用了 dropout,v2 中取消了 dropout,在卷积层全部使用 Batch Normalization。
5、K-Means 算法
Faster R-CNN中anchor box 的大小和比例是按经验设定的,YOLOv2 对其做了改进,采用 k-means 在训练集 bbox 上进行聚类产生合适的先验框. 由于使用采用标准的 k-means欧氏距离会使较大的 bbox 比小的 bbox 产生更大的误差,而 IOU 与 bbox 尺寸无关, 因此使用 IOU 参与距离计算, 使得通过这些 anchor boxes 获得好的 IOU 分值。距离公式:
k-means
使用聚类进行选择的优势是达到相同的IOU结果时所需的anchor box数量更少,使得模型的表示能力更强,任务更容易学习。算法过程是:将每个bbox的宽和高相对整张图片的比例(wr,hr)进行聚类,得到k个anchor box,将这个比例值乘上卷积层的输出特征的大小.如输入是416x416,那么最后卷积层的特征是13x13.
6、Multi-Scale Training:
和YOLOv1训练时网络输入的图像尺寸固定不变不同,YOLOv2(在cfg文件中random=1时)每隔几次迭代后就会微调网络的输入尺寸。训练时每迭代10次,就会随机选择新的输入图像尺寸。因为YOLOv2的网络使用的downsamples倍率为32,所以使用32的倍数调整输入图像尺寸{320,352,…,608}。训练使用的最小的图像尺寸为320 x 320,最大的图像尺寸为608 x 608。这使得网络可以适应多种不同尺度的输入。
7、Direct location prediction(直接位置预测)
作者在使用anchor boxes时发现的第二个问题就是:模型不稳定,尤其是在早期迭代的时候。大部分的不稳定现象出现在预测box的 (x,y)坐标上了。在区域建议网络中,预测 (x,y) 以及 tx,ty 使用的是如下公式:
这里写图片描述
公式中,x 是坐标预测值,xa 是anchor坐标(预设固定值),x∗是坐标真实值(标注信息),其他变量 y,w,h 以此类推,t变量是偏移量。然后把前两个公式变形,
这个公式的理解为:当预测 tx=1,就会把box向右边移动一定距离(具体为anchor box的宽度),预测 tx=−1,就会把box向左边移动相同的距离。这个公式没有任何限制,使得无论在什么位置进行预测,任何anchor boxes可以在图像中任意一点结束(我的理解是,tx没有数值限定,可能会出现anchor检测很远的目标box的情况,效率比较低。正确做法应该是每一个anchor只负责检测周围正负一个单位以内的目标box)。
在此,作者就没有采用预测直接的偏移量的方法,而使用了预测相对于grid cell的坐标位置的办法,作者又把ground truth限制在了0到1之间,利用logistic回归函数来进行这一限制。
现在,神经网络在特征图(13 *13 )的每个cell上预测5个bounding boxes(聚类得出的值),同时每一个bounding box预测5个坐值,分别为 tx,ty,tw,th,to,其中前四个是坐标,to是置信度。该cell对应box(bounding box prior)的长和宽分别为 (pw,ph),这个cell距离图像左上角的边距为 (cx,cy),(折磨说的话:每个cell都对应不同的(cx,cy))那么预测值可以表示为:
bx表示预测的坐标值,tx表示偏移量,cx是预设的固定值(类似anchor坐标)
tx,ty经sigmod函数处理过,取值限定在了0~1,就是把偏移量控制在0到1之间。实际意义就是使anchor只负责周围的box,有利于提升效率和网络收敛。σ 函数的意义没有给,但估计是把归一化值转化为图中真实值,因此,σ(tx)是bounding box的中心相对栅格左上角的横坐标,σ(ty)是纵坐标,σ(to)是bounding box的confidence score。定位预测值被归一化后,参数就更容易得到学习,模型就更稳定。
YOLO v3 简介
yolo v3代码是qwe的keras版本,复现比较容易,代码相对来说比较容易理解。同学们可以结合代码和博文共同理解v3的精髓。
github地址:https://github.com/qqwweee/keras-yolo3
基于tensorflow的实现代码可以参考:https://github.com/wizyoung/YOLOv3_TensorFlow
yolo_v3作为yolo系列目前最新的算法,对之前的算法既有保留又有改进。先分析一下yolo_v3上保留的东西:
从yolo_v1开始,yolo算法就是通过划分单元格来做检测,只是划分的数量不一样。采用"leaky ReLU"作为激活函数。端到端进行训练。一个loss function搞定训练,只需关注输入端和输出端。
从yolo_v2开始,yolo就用batch normalization作为正则化、加速收敛和避免过拟合的方法,把BN层和leaky relu层接到每一层卷积层之后。
多尺度训练。在速度和准确率之间tradeoff。想速度快点,可以牺牲准确率;想准确率高点儿,可以牺牲一点速度。yolo每一代的提升很大一部分决定于backbone网络的提升,从v2的darknet-19到v3的darknet-53。yolo_v3还提供替换backbone——tiny darknet。要想性能牛叉,backbone可以用Darknet-53,要想轻量高速,可以用tiny-darknet。总之,yolo就是天生“灵活”,所以特别适合作为工程算法。
DBL: 如图左下角所示,也就是代码中的Darknetconv2d_BN_Leaky,是yolo_v3的基本组件。就是卷积+BN+Leaky relu。对于v3来说,BN和leaky relu已经是和卷积层不可分离的部分了(最后一层卷积除外),共同构成了最小组件。
res_n:n代表数字,有res1,res2, … ,res8等等,表示这个res_block里含有多少个res_unit。这是yolo_v3的大组件,yolo_v3开始借鉴了ResNet的残差结构,使用这种结构可以让网络结构更深(从v2的darknet-19上升到v3的darknet-53,前者没有残差结构)。对于res_block的解释,可以在图右下角直观看到,其基本组件也是DBL。
concat:张量拼接。将darknet中间层和后面的某一层的上采样进行拼接。拼接的操作和残差层add的操作是不一样的,拼接会扩充张量的维度,而add只是直接相加不会导致张量维度的改变。
整个yolo_v3_body包含252层,包括add层23层(主要用于res_block的构成,每个res_unit需要一个add层,一共有1+2+8+8+4=23层)。除此之外,BN层和LeakyReLU层数量完全一样(72层),在网络结构中的表现为:每一层BN后面都会接一层LeakyReLU。卷积层一共有75层,其中有72层后面都会接BN+LeakyReLU的组合构成基本组件DBL。看结构图,可以发现上采样和concat都有2次,和表格分析中对应上。每个res_block都会用上一个零填充,一共有5个res_block.
layers
darknet-53 模型
v3
1、backbone
整个v3结构里面,是没有池化层和全连接层的。前向传播过程中,张量的尺寸变换是通过改变卷积核的步长来实现的,在yolo_v2中, yolo_v2中对于前向过程中张量尺寸变换,都是通过最大池化来进行,一共有5次,经历5次缩小,会将特征图缩小到原输入尺寸的1/32。输入为416x416,则输出为13x13(416/32=13)。yolo_v3也和v2一样,backbone都会将输出特征图缩小到输入的1/32。所以,通常都要求输入图片是32的倍数,而v3是通过卷积核增大步长来进行,也是5次。(darknet-53最后面有一个全局平均池化,在yolo-v3里面没有这一层,所以张量维度变化只考虑前面那5次)。
darknet-19是不存在残差结构(resblock,从resnet上借鉴过来)的,和VGG是同类型的backbone(属于上一代CNN结构),而darknet-53是可以和resnet-152正面刚的backbone.darknet-19在速度上仍然占据很大的优势。其实在其他细节也可以看出(比如bounding box prior采用k=9),yolo_v3并没有那么追求速度,而是在保证实时性(fps>36)的基础上追求performance。
2、Output
yolo v3输出了3个不同尺度的feature map,如上图所示的y1, y2, y3。这也是v3论文中提到的为数不多的改进点:predictions across scales.这个借鉴了FPN(feature pyramid networks),采用多尺度来对不同size的目标进行检测,越精细的grid cell就可以检测出越精细的物体。y1,y2和y3的深度都是255,边长的规律是13:26:52
对于COCO类别而言,有80个种类,所以每个box应该对每个种类都输出一个概率。yolo v3设定的是每个网格单元预测3个box,所以每个box需要有(x, y, w, h, confidence)五个基本参数,然后还要有80个类别的概率。所以3*(5 + 80) = 255。这个255就是这么来的。(还记得yolo v1的输出张量吗? 7x7x30,只能识别20类物体,而且每个cell只能预测2个box,和v3比起来就像老人机和iphoneX一样)
v3用上采样的方法来实现这种多尺度的feature map,concat连接的两个张量是具有一样尺度的(两处拼接分别是26x26尺度拼接和52x52尺度拼接,通过(2, 2)上采样来保证concat拼接的张量尺度相同)。作者并没有像SSD那样直接采用backbone中间层的处理结果作为feature map的输出,而是和后面网络层的上采样结果进行一个拼接之后的处理结果作为feature map。为什么这么做呢? 我感觉是有点玄学在里面,一方面避免和其他算法做法重合,另一方面这也许是试验之后并且结果证明更好的选择,再者有可能就是因为这么做比较节省模型size的。
3、Bounding Box Prediction
对于v3而言,在prior这里的处理有明确解释:选用的b-box priors 的k=9,对于tiny-yolo的话,k=6。priors都是在数据集上聚类得来的,有确定的数值,如下:
10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326
每个anchor prior(名字叫anchor prior,但并不是用anchor机制)就是两个数字组成的,一个代表高度另一个代表宽度。v3对b-box进行预测的时候,采用了logistic regression。这一波操作sao得就像RPN中的线性回归调整b-box。v3每次对b-box进行预测时,输出和v2一样都是,然后通过公式1计算出绝对的(x, y, w, h, c)。
其中cx,cy是网格的坐标偏移量,pw,ph是预设的anchor box的边长.最终得到的预测边框坐标值是bx,by,bw,bh而网络学习目标是tx,ty,tw,th。作者使用了logistic回归来对每个anchor包围的内容进行了一个目标性评分(objectness score),即这块位置是目标的可能性有多大。这一步是在predict之前进行的,可以去掉不必要anchor,可以减少计算量.根据目标性评分来选择anchor prior进行predict,而不是所有anchor prior都会有输出。
不同于faster R-CNN的是,yolo_v3只会对1个prior进行操作,也就是那个最佳prior。而logistic回归就是用来从9个anchor priors中找到objectness score(目标存在可能性得分)最高的那一个。logistic回归就是用曲线对prior相对于objectness score映射关系的线性建模。
多尺度预测:
9个anchor会被三个输出张量平分的。根据大中小三种size各自取自己的anchor。每种尺度预测3个box, anchor的设计方式仍然使用聚类,得到9个聚类中心,将其按照大小均分给3中尺度.
尺度1: 在基础网络之后添加一些卷积层再输出box信息.
尺度2: 从尺度1中的倒数第二层的卷积层上采样(x2)再与最后一个16x16大小的特征图相加,再次通过多个卷积后输出box信息.相比尺度1变大两倍.
尺度3: 与尺度2类似,使用了32x32大小的特征图.
每个输出y在每个自己的网格都会输出3个预测框,这3个框是9除以3得到的,这是作者设置的,我们可以从输出张量的维度来看,13x13x255。255是怎么来的呢,3*(5+80)。80表示80个种类,5表示位置信息和置信度,3表示要输出3个prediction。在代码上来看,3*(5+80)中的3是直接由num_anchors//3得到的。
分类器-类别预测:
YOLOv3不使用Softmax对每个框进行分类,主要考虑因素有两个:
Softmax使得每个框分配一个类别(score最大的一个),而对于Open Images这种数据集,目标可能有重叠的类别标签,因此Softmax不适用于多标签分类。
Softmax可被独立的多个logistic分类器替代,且准确率不会下降。分类损失采用binary cross-entropy loss.
yolov3较yolov2的改进
从Darknet-53网络结构看出yolov3较yolov2网络深度推至106层,其中引用ResNet、FPN网络结构思想,同时采用多尺度预测来弥补初始划分13*13网格细粒度不够问题,同时yolov3网络仍然采用yolov2中数据增强、批归一化等操作。
YOLOv2网络结构中有一个特殊的转换层(Passthrough Layer),假设最后提取的特征图的大小是13*13,转换层的作用就是将前面的26*26的特征图和本层的13*13的特征图进行堆积(扩充特征维数据量),而后进行融合,再用融合后的特征图进行检测。这么做是为了加强算法对小目标检测的精确度。为达更好效果,YOLOv3将这一思想进行了加强和改进。
YOLO v3采用(类似FPN)上采样(Upsample)和融合做法,融合了3个尺度(13*13、26*26和52*52),在多个尺度的融合特征图上分别独立做检测,最终对于小目标的检测效果提升明显。(有些算法采用多尺度特征融合的方式,比如YOLOv2一般是采用融合后的单一特征图做预测,FPN不一样的地方在于其预测是在不同特征层进行的)
有效的改进策略:
1 使用逻辑回归来预测每个bounding boxes的对象分数,每个bounding box与ground truth的匹配策略为1 vs 1。
2 每个bounding boxes使用多标签分类法预测包含的类,采用二元交叉熵(sigmoid)取代softmax进行类别预测。
3 采取金字塔网络来进行预测多尺度的boxes(多层feature map[13 26 52]),同时提取网络较早的feature map(特征图),与之前经过两倍上采样的feature map进行element-wise addition合并,进行更精确细粒度预测(类似SSD思想)。但是v2并不是这种SSD思想,虽然它也用到多层的featuremap,但是v2是通过Passthrough Layer将2626特征图转化为1313特征图,依次增加特征的维度
from:https://blog.csdn.net/donkey_1993/article/details/81481833
from :https://www.jianshu.com/p/cad68ca85e27
from:https://blog.csdn.net/zxyhhjs2017/article/details/83013297
from:https://www.cnblogs.com/makefile/p/YOLOv3.html
from:https://blog.csdn.net/leviopku/article/details/82660381
总结:
1、YOLOv1会把图像看成一个sxs的栅格,这里的s是等于7,每个栅格预测2个bounding boxes以及栅格含有对象的置信度,同时每个栅格还是预测栅格所属的对象类别;YOLOv1由24层卷积层,4个最大池化层和2个全连接层组成,常规操作,我们关注最后的输出是7x7x30,这里是7x7代表输入图像的7x7栅格,一一对应,30的前十个代表2个bounding boxes的坐标以及对象的置信度,后20个代表VOC数据集的20个类别。
2、YOLOv2:批量归一化,高分辨分类器,锚盒,维度聚类,细粒度特征以及多尺度训练。YOLOv2采用了一个新的基础模型(特征提取器),称为Darknet-19,包括19个卷积层和5个maxpooling层。改进使精度高了,速度方面依然比YOLOv1还要快。
Batch Normalization将数据分布映射到相对紧凑的分布,让网络可以更快以及更好地学习,避免过拟合,使用批归一化这一操作提升了2%mAP。
v1使用224 × 224训练分类器网络,扩大到448用于检测网络。v2将ImageNet以448×448 的分辨率微调最初的分类网络,迭代10 epochs。
YOLOv1使用全连接层来生成bounding box的坐标,丢失了特征图的空间信息,造成定位不准,YOLOv2利用锚框直接在卷积特征图滑窗采样,与YOLOv1不同的是,YOLOv2是预测的是坐标相对于栅格左顶点的偏移量,通过变换公式得到最后的预测坐标。YOLOv1只能预测98个边界框,而YOLOv2使用anchor boxes之后可以预测上千个边界框。
YOLOv2采用k-means聚类方法对训练集中的边界框做了聚类分析,通过K-means聚类算法将数据集中的ground truth进行了聚类。最后对模型复杂度和召回率的平衡,选择5个聚类中心,挑选了5个最具代表性的bounding box。
细粒度特征对于检测小物体是有很大的影响,引入了一个Passthrough Layer,把浅层特征图连接到深层特征图,也就是图中这个26x26x512的特征图通过隔行隔列采样,变换成13x13x2048的特征图,然后和13x13x1024的特征图进行按通道concat。
让YOLOv2对不同尺寸图片的具有鲁棒性,引入了多尺寸的训练,每10batch,选择新的图像尺寸对网络进行训练。
3、YOLOv3在保持实时性的基础上,对YOLOv2进行了几点改进,主要有三点:
使用了残差网络;采用逻辑回归预测置信度和进行分类,从三个尺度上预测b-box的坐标以及特征提取器发生变化。
在分类上,没有使用softmax多分类,作者也指出softmax最终对性能也没有提升,而且softmax假设是每个box只有一个类,这对迁移到更大有多种类别标签的数据集是没有好处的,对于Open Images这种数据集,目标可能有重叠的类别标签,因此Softmax不适用于多标签分类。所以作者使用多个逻辑回归来预测分类,使用二元交叉熵计算分类损失。
借由FPN的思想,用中间层的输出与后层输出进行融合,进行三个尺度预测,每个尺度的每个cell预测3个坐标,以上面为例,下采样32倍,最后一起的输出是8x8x1024,通过卷积层和逻辑回归得到8x8x255(255=3x(5+80),5是坐标加置信度,80是coco类别),这就是第一个尺度的预测输出,第二个尺度是8x8x1024通过上采样与卷积通过缩放变成16x16x512,然后与上一个stage的16x16x512进行concat,然后通过相似的方式生成16x16x255,类似的操作得到,得到32x32x255。