YOLOv1到YOLOv3的演变过程及每个算法详解
1,YOLOv1算法的简介
YOLO算法使用深度神经网络进行对象的位置检测以及分类,主要的特点是速度够快,而且准确率也很高,采用直接预测目标对象的边界框的方法,将候选区和对象识别这两个阶段合二为一,
与faster rcnn区分开来,是一刀流的检测方法。
Yolo算法不再是窗口滑动了,而是直接将原始图片分割成互不重合的小方块,然后通过卷积最后生产这样大小的特征图,基于上面的分析,可以认为特征图的每个元素也是对应原始图片的一个小
方块,然后用每个元素来可以预测那些中心点在该小方格内的目标,这就是Yolo算法的朴素思想,
最新的YOLOv3算法再以往的结构上做出了改进,增加了多尺度检测,以及更深的网络结构darknet53,这是比较主要的改进,还有某些细节上的变动。
2,YOLOv1算法的原理
实际操作如图所示,分为7*7个小格子,每个格子预测两个bounding box。
如果一个目标的中心落入一个网格单元中,该网格单元负责检测 该目标。
对每一个切割的小单元格预测(置信度,边界框的位置),每个bounding box需要4个数值来表示其位置,(Center_x,Center_y,width,height),即(bounding box的中心点的x坐标,y坐标,bounding box的宽度,高度)
置信度定义为是否存在目标与iou值的乘积,
还要得到分类的概率结果;20个分类每个类别的概率。
7*7*30中的30=(20类概率+2*5(置信度,边框位置))
2.1 YOLOv1的网络结构
YOLO采用单个的卷积神经网络进行预测,YOLO的整个结构就是输入图片经过神经网络的变换得到一个输出的张量 。 步骤如下:
(1)将输入图像调整为448×448,(2)在图像 上运行单个卷积网络,以及(3)由模型的置信度对所得到的检测进行阈值处理
首先,YOLO速度非常快。由于我们将检测视为回归问题,所以不需要复杂的流程。测试时在一张新图像 上简单的运行我们的神经网络来预测检测
其次,YOLO在进行预测时,会对图像进行全面地推理。与基于滑动窗口和区域提出的技术不同,YOLO在训练期间和测试时会看到整个图像,所以它隐式地编码了
关于类的上下文信息以及它们的外观。快速R-CNN是一种顶级的检测方法,但是它看不到更大的上下文信息,所以在图像中会将背景块误检为目标。与快速R-CNN相比,YOLO的背景误检数量少了一半
然后,由于YOLO具有高度泛化能力,因此在应用于新领域或碰到意外的输入时不太可能出故障。
所使用的卷积结构如图所示:受到GoogLeNet图像分类模型的启发。网络有24个卷积层,后面是2个全连接层,最后输出层用线性函数做激活函数,其它层激活函数都是Leaky ReLU。
我们 只使用1*1降维层,后面是3*3卷积层,
3, YOLOv1的损失函数和训练过程
YOLO的损失函数定义如下:
YOLO在ImageNet分类任务上以一半的分辨率(224*224的输入图像)预训练卷积层,然后将分辨 率加倍来进行检测。
训练中采用了drop out和数据增强(data augmentation)来防止过拟合.
4. 预测过程以及结果的处理
直接把训练好的YOLO网络模型输入一张图片,得到一个7*7*30的结果向量,通过NMS(非极大值抑制)来选择最终的结果;
NMS就是通过打分来选出最好的结果,与这个结果重叠的对象去掉,是一个不断迭代的过程。
score = 某个对象的概率 * 置信度
所以对于每个网格有20*2个得分,每个对象有49*2个得分;这里的2是bounding box的个数;
具体的过程是:
1,设置一个分数阈值,低于的直接置为0;
2,遍历对于每个对象:
选出分数最高的那个及其bounding box放到输出列表中;
将其他的与上面选出的分数最高的那个计算IOU,设置一个阈值,大于阈值的表示重叠度较高,把分数置为0;
如果所有的bounding box都在输出列表中或者分数为0,那么这个对象的NMS就结束
对接下来的对象执行此过程
3.得出输出结果;
4. YOLOv1的特点总结
YOLO的一个贡献是将检测问题转化为了回归问题,相信这句话很多人见过很多次了。那到底是什么意思呢?指的就是之前faster RCNN是先分两步,
先提取region proposal,也就是判断是前景还是背景的问题,之后再分类,具体看前景是什么东西。而YOLO直接通过regression一次既产生坐标,又产生每种类别的概率。
YOLO的特点在于快,其中一方面来源于regression机制,还有一个原因就在于region proposal的提取过程了。再YOLO中很少提region proposal的概念,
但是为了类比faster RCNN我们可以这样理解,YOLO中粗暴地分成了7X7的网格,每个位置默认可能属于2个object,那么事实上就是提取了98个region proposal,
而faster RCNN是一种滑动窗口机制,每个feature map上都回归出9个anchor,大约一共20k个anchor,在通过非极大值抑制等方法最终会得到300个region proposal。
两者之间候选框差别巨大,因此,faster RCNN会准一点也是情理之中,而既然每个位置都要精修,当然效率就会低很多,也就不能满足实时性要求了。另外,YOLO
精简了网络,比VGG要稍微计算量小一些,可能也会加快一些速度,但这些计算量比起前面提到的两点已经不足为道。
YOLO对边界框预测强加空间约束,因为每个网格单元只预测两个盒子,只能有一个类别。这个空间约束限制了我 们的模型可以预测的邻近目标的数量。我们的模型与群组中出现的小物体(比如鸟群)进行斗争。
YOLOV2和YOLO9000(持续更新,未完善,对于world tree部分不是很明白)
YOLO9000主要是在保持速度和准确率的情况下继续增强对识别类别的能力,经过在IMAGE NET上的分类库上进行预训练分类模块之后,整个yolo可以对9000类物体进行识别检测。
YOLOv2所做的改进主要如下表格:
下面把主要的改进解释一下:
本部分直接参考:https://zhuanlan.zhihu.com/p/47575929
1)batch normalization(批归一化)
批归一化使mAP有2.4的提升。
批归一化有助于解决反向传播过程中的梯度消失和梯度爆炸问题,降低对一些超参数(比如学习率、网络参数的大小范围、激活函数的选择)的敏感性,并且每个batch分别进行归一化的时候,起到了一定的正则化效果(YOLO2不再使用dropout),从而能够获得更好的收敛速度和收敛效果。
2)使用高分辨率图像微调分类模型
mAP提升了3.7。
图像分类的训练样本很多,而标注了边框的用于训练对象检测的样本相比而言就比较少了,因为标注边框的人工成本比较高。所以对象检测模型通常都先用图像分类样本训练卷积层,提取图像特征。但这引出的另一个问题是,图像分类样本的分辨率不是很高。所以YOLO v1使用ImageNet的图像分类样本采用 224*224 作为输入,来训练CNN卷积层。然后在训练对象检测时,检测用的图像样本采用更高分辨率的 448*448 的图像作为输入。但这样切换对模型性能有一定影响。
所以YOLO2在采用 224*224 图像进行分类模型预训练后,再采用 448*448 的高分辨率样本对分类模型进行微调(10个epoch),使网络特征逐渐适应 448*448 的分辨率。然后再使用 448*448 的检测样本进行训练,缓解了分辨率突然切换造成的影响。
3)采用先验框(Anchor Boxes)
召回率大幅提升到88%,同时mAP轻微下降了0.2。
借鉴Faster RCNN的做法,YOLO2也尝试采用先验框(anchor)。在每个grid预先设定一组不同大小和宽高比的边框,来覆盖整个图像的不同位置和多种尺度,这些先验框作为预定义的候选区在神经网络中将检测其中是否存在对象,以及微调边框的位置。
同时YOLO2移除了全连接层。另外去掉了一个池化层,使网络卷积层输出具有更高的分辨率。
之前YOLO1并没有采用先验框,并且每个grid只预测两个bounding box,整个图像98个。YOLO2如果每个grid采用9个先验框,总共有13*13*9=1521个先验框。所以,相对YOLO1的81%的召回率,YOLO2的召回率大幅提升到88%。同时mAP有0.2%的轻微下降。
不过YOLO2接着进一步对先验框进行了改良。
4)聚类提取先验框尺度
聚类提取先验框尺度,结合下面的约束预测边框的位置,使得mAP有4.8的提升。
之前先验框都是手工设定的,YOLO2尝试统计出更符合样本中对象尺寸的先验框,这样就可以减少网络微调先验框到实际位置的难度。YOLO2的做法是对训练集中标注的边框进行聚类分析,以寻找尽可能匹配样本的边框尺寸。
聚类算法最重要的是选择如何计算两个边框之间的“距离”,对于常用的欧式距离,大边框会产生更大的误差,但我们关心的是边框的IOU。所以,YOLO2在聚类时采用以下公式来计算两个边框之间的“距离”。 centroid是聚类时被选作中心的边框,box就是其它边框,d就是两者间的“距离”。IOU越大,“距离”越近。
YOLO2给出的聚类分析结果如下图所示:
上图左边是选择不同的聚类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的先验框方法,在训练的早期阶段,其位置预测容易不稳定。其位置预测公式为:
其中, 是预测边框的中心, 是先验框(anchor)的中心点坐标, 是先验框(anchor)的宽和高, 是要学习的参数。 注意,YOLO论文中写的是 ,根据Faster RCNN,应该是"+"。
由于 的取值没有任何约束,因此预测边框的中心可能出现在任何位置,训练早期阶段不容易稳定。YOLO调整了预测公式,将预测边框的中心约束在特定gird网格内。
其中, 是预测边框的中心和宽高。 是预测边框的置信度,YOLO1是直接预测置信度的值,这里对预测参数 进行σ变换后作为置信度的值。 是当前网格左上角到图像左上角的距离,要先将网格大小归一化,即令一个网格的宽=1,高=1。 是先验框的宽和高。 σ是sigmoid函数。 是要学习的参数,分别用于预测边框的中心和宽高,以及置信度。
图3 边框预测
参考上图,由于σ函数将 约束在(0,1)范围内,所以根据上面的计算公式,预测边框的蓝色中心点被约束在蓝色背景的网格内。约束边框位置使得模型更容易学习,且预测更为稳定。
YOLO 一代包含有全连接层,从而能直接预测 Bounding Boxes 的坐标值。 Faster R-CNN 的方法只用卷积层与 Region Proposal Network 来预测 Anchor Box 偏移值与置信度,
而不是直接预测坐标值。作者发现通过预测偏移量而不是坐标值能够简化问题,让神经网络学习起来更容易
所以最终 YOLO 去掉了全连接层,使用 Anchor Boxes 来预测 Bounding Boxes。(后来又去掉了anchor box,因为使网络不稳定)
网络使用一个 Logistic Activation 来对于网络预测结果进行限制,让结果介于 0 到 1 之间, 因为使用了限制让数值变得参数化,也让网络更容易学习、更稳定
似于 VGG。YOLO v2 使用 3*3 的 filter,每次池化之后都增加一倍 Channels 的数量
1×1 filters to compress the feature representation between 3×3 convolutions
联合检测集和分类集训练网络,
Using this joint training, YOLO9000 learns to find objects in images using the detection data in COCO and it learns to classify a wide variety of these objects using data from ImageNet.
YOLOV3
YOLO3主要的改进有:调整了网络结构;利用多尺度特征进行对象检测;对象分类用Logistic取代了softmax。
新的网络结构Darknet -53
darknet-53借用了resnet的思想,在网络中加入了残差模块,这样有利于解决深层次网络的梯度问题,每个残差模块由两个卷积层和一个shortcut connections,
1,2,8,8,4代表有几个重复的残差模块,整个v3结构里面,没有池化层和全连接层,网络的下采样是通过设置卷积的stride为2来达到的,每当通过这个卷积层之后
图像的尺寸就会减小到一半。而每个卷积层的实现又是包含 卷积+BN+Leaky relu ,每个残差模块之后又要加上一个zero padding,具体实现可以参考下面的一张图。
具体的全部模型结构可以从这个网站的工具进行可视化分析:
https://lutzroeder.github.io/netron/
从Yolo的官网上下载yolov3的权重文件,然后通过官网上的指导转化为H5文件,然后可以再这个浏览器工具里直接看yolov3的每一层是如何分布的;类似下边截图是一部分网络(最后的拼接部分);
论文中所给的大致结果如下,由卷积结构和残差模块组成;
多尺度检测:
对于多尺度检测来说,采用多个尺度进行预测,具体形式是在网络预测的最后某些层进行上采样拼接的操作来达到;对于分辨率对预测的影响如下解释:
分辨率信息直接反映的就是构成object的像素的数量。一个object,像素数量越多,它对object的细节表现就越丰富越具体,也就是说分辨率信息越丰富。这也就是为什么大尺度feature map提供的是分辨率信息了。语义信息在目标检测中指的是让object区分于背景的信息,即语义信息是让你知道这个是object,其余是背景。在不同类别中语义信息并不需要很多细节信息,分辨率信息大,反而会降低语义信息,因此小尺度feature map在提供必要的分辨率信息下语义信息会提供的更好。(而对于小目标,小尺度feature map无法提供必要的分辨率信息,所以还需结合大尺度的feature map)
YOLO3更进一步采用了3个不同尺度的特征图来进行对象检测。能够检测的到更加细粒度的特征。
网络的最终输出有3个尺度分别为1/32,1/16,1/8;
在第79层之后经过几个卷积操作得到的是1/32 (13*13) 的预测结果,下采样倍数高,这里特征图的感受野比较大,因此适合检测图像中尺寸比较大的对象。
然后这个结果通过上采样与第61层的结果进行concat,再经过几个卷积操作得到1/16的预测结果;它具有中等尺度的感受野,适合检测中等尺度的对象。
91层的结果经过上采样之后在于第36层的结果进行concat,经过几个卷积操作之后得到的是1/8的结果,它的感受野最小,适合检测小尺寸的对象。
concat:张量拼接。将darknet中间层和后面的某一层的上采样进行拼接。拼接的操作和残差层add的操作是不一样的,拼接会扩充张量的维度,而add只是直接相加不会导致张量维度的改变。
使用Kmeans聚类的方法来决定anchors的尺寸大小:
logistic回归用于对anchor包围的部分进行一个目标性评分(objectness score),(用于NMS),即这块位置是目标的可能性有多大。
公式一:
yolo_v3只会对1个prior进行操作,也就是那个最佳prior。而logistic回归就是用来从9个anchor priors中找到objectness score(目标存在可能性得分)最高的那一个。
对象分类softmax改成logistic
预测对象类别时不使用softmax,改成使用logistic的输出进行预测。这样能够支持多标签对象(比如一个人有Woman 和 Person两个标签)。
YOLO的LOSS函数:
1 # K.binary_crossentropy is helpful to avoid exp overflow. 2 xy_loss = object_mask * box_loss_scale * K.binary_crossentropy(raw_true_xy, raw_pred[...,0:2], from_logits=True) 3 wh_loss = object_mask * box_loss_scale * 0.5 * K.square(raw_true_wh-raw_pred[...,2:4]) 4 confidence_loss = object_mask * K.binary_crossentropy(object_mask, raw_pred[...,4:5], from_logits=True)+ \ 5 (1-object_mask) * K.binary_crossentropy(object_mask, raw_pred[...,4:5], from_logits=True) * ignore_mask 6 class_loss = object_mask * K.binary_crossentropy(true_class_probs, raw_pred[...,5:], from_logits=True) 7 8 xy_loss = K.sum(xy_loss) / mf 9 wh_loss = K.sum(wh_loss) / mf 10 confidence_loss = K.sum(confidence_loss) / mf 11 class_loss = K.sum(class_loss) / mf 12 loss += xy_loss + wh_loss + confidence_loss + class_loss 13 if print_loss: 14 loss = tf.Print(loss, [loss, xy_loss, wh_loss, confidence_loss, class_loss, K.sum(ignore_mask)], message='loss: ') 15 return loss
yolov3再keras中定义的Loss函数如上,基本可以看出,对于回归预测的部分是采用多个mse均方差相加来进行的(类似于上边所提到的v1中的Loss函数),对于分类部分和置信度是采用K.binary_crossentropy来进行的,最后把两种Loss相加得出最终的loss
整体来看Yolov3的输入与输出形式如下:
输入416*416*3的图像,通过darknet网络得到三种不同尺度的预测结果,每个尺度都对应N个通道,包含着预测的信息;
每个网格每个尺寸的anchors的预测结果。
代码解释部分未完善;
return model, bottleneck_model, last_layer_model
249 3
Freeze the first 249 layers of total 252 layers.
对输入图片的要求,因为yolov3要把图片下采样到原图的1/32,所以,图片尺寸要是32的倍数,采用416*416
尺寸变换是通过改变卷积核的步长来实现的这里设置为stride = 2;
训练过程先
Train with frozen layers first, to get a stable loss.
然后再训练整个Model
Unfreeze and continue training, to fine-tune.
参考博文:
https://www.jianshu.com/p/d13ae1055302
https://zhuanlan.zhihu.com/p/46691043
https://blog.csdn.net/leviopku/article/details/82660381
https://blog.csdn.net/chandanyan8568/article/details/81089083
https://zhuanlan.zhihu.com/p/47575929
源码地址:
https://github.com/qqwweee/keras-yolo3