深度学习之---yolov1,v2,v3详解及实践

(写在前面:如果你想 run 起来,立马想看看效果,那就直接跳转到最后一张,动手实践,看了结果再来往前看吧,开始吧······)

一、YOLOv1 简介
这里不再赘述,之前的我的一个 GitChat 详尽的讲述了整个代码段的含义,以及如何一步步的去实现它,可参照这里手把手实践YOLO深度残差神经网络拐点检测

二、YOLOv2 简介
V1 版本的缺陷和不足,就是 V2 版本出现的源泉与动力,而 V1 版本究竟在哪些地方是它的短板之处呢:

V1 缺陷之处:

输入尺寸固定:由于输出层为全连接层,因此在检测时,YOLO 训练模型只支持与训练图像相同的输入分辨率。其它分辨率需要缩放成此固定分辨率;
占比较小的目标检测效果不好:虽然每个格子可以预测 B 个 bounding box,但是最终只选择只选择 IOU 最高的 bounding box 作为物体检测输出,即每个格子最多只预测出一个物体。当物体占画面比例较小,如图像中包含畜群或鸟群时,每个格子包含多个物体,但却只能检测出其中一个。

2.1 anchor box 的思想引入

为提高物体定位精准性和召回率,YOLO 作者提出了 《YOLO9000: Better, Faster, Stronger》 (Joseph Redmon, Ali Farhadi, CVPR 2017, Best Paper Honorable Mention),也就是 YOLOv2 的论文全名,相比 v1 提高了训练图像的分辨率;引入了 faster rcnn 中 anchor box 的思想,对网络结构的设计进行了改进,使得模型更易学习。

什么是(候选区域框)anchor box?

假设特征可以看做一个尺度 6448 像素的 256 通道图像,对于该图像的每一个位置,考虑 9 个可能的候选窗口:三种面积三种比例。这些候选窗口称为 anchors。下图示出 6448 图像 anchor 中心,在每个面积尺寸下,取三种不同的长宽比例(1:1,1:2,2:1),这样一来,我们得到了一共 9 种面积尺寸各异的 anchor。示意图如下:
深度学习之---yolov1,v2,v3详解及实践_第1张图片
以一个点 9 种尺寸来取 proposal,重复区域多。而且 feature map 相邻两个点对应原图的 9 个 proposal 也是很多重复区域。只是整个 faster RCNN 中的第一步,只是对候选区域进行提取 (RPN, region proposal networks, 候选区域生成网络)。这个过程只是希望能够得到覆盖目标的候选区域,所以有不同尺寸不同比例的 proposal(这样才有最大可能可以在一个候选框中包括完整的目标)。而在这之后,确实会有很多重复区域,而这其实是候选区域生成之后的下一个问题。针对这个问题,一般会采用非极大值抑制算法进行去重 (NMS, non maximum suppression)。

至于这个 anchor 到底是怎么用的,这个是理解整个问题的关键。

下面是整个 faster RCNN 结构的示意图:深度学习之---yolov1,v2,v3详解及实践_第2张图片
输入图像无论是什么大小的样本,都要转化为 224*224(可根据情况自己设定)大小的图片,送进网络进行训练。( 为什么要固定输入网络图片尺寸呢?后面解释。)

对于每个 3x3 的窗口,作者就计算这个滑动窗口的中心点所对应的原始图片的中心点。然后作者假定,这个 3x3 窗口,是从原始图片上通过 SPP 池化 得到的,而这个池化的区域的面积以及比例,就是一个个的 anchor。换句话说,对于每个 3x3 窗口,作者假定它来自 9 种不同原始区域的池化,但是这些池化在原始图片中的中心点,都完全一样。这个中心点,就是刚才提到的,3x3 窗口中心点所对应的原始图片中的中心点。如此一来,在每个窗口位置,我们都可以根据 9 个不同长宽比例、不同面积的 anchor,逆向推导出它所对应的原始图片中的一个区域,这个区域的尺寸以及坐标,都是已知的。而这个区域,就是我们想要的 proposal。所以我们通过滑动窗口和 anchor,成功得到了 51x39x9 个原始图片的 proposal。接下来,每个 proposal 我们只输出 6 个参数:每个 proposal 和 ground truth 进行比较得到的前景概率和背景概率 (2 个参数)(对应图上的 clsscore);由于每个 proposal 和 ground truth 位置及尺寸上的差异,从 proposal 通过平移放缩得到 ground truth 需要的 4 个平移放缩参数(对应图上的 bboxpred)。

为什么之前的 CNN 要固定输入网络图片尺寸呢?

CNN 大体包含 3 部分:卷积、池化、全连接

卷积层。卷积操作对图片输入的大小会有要求吗?比如一个 5 * 5 的卷积核,我输入的图片是 30 * 81 的大小,可以得到 (26,77) 大小的图片,并不会影响卷积操作。我输入 600 * 500,它还是照样可以进行卷积,也就是卷积对图片输入大小没有要求,只要你喜欢,任意大小的图片进入,都可以进行卷积。
池化层。池化对图片大小会有要求吗?比如我池化大小为(2,2)我输入一张 30 * 40 的,那么经过池化后可以得到 15 * 20 的图片。输入一张 53 * 22 大小的图片,经过池化后,我可以得到 26 * 11 大小的图片。因此池化这一步也没对图片大小有要求。只要你喜欢,输入任意大小的图片,都可以进行池化。
全连接层。既然池化和卷积都对输入图片大小没有要求,那么就只有全连接层对图片结果又要求了。因为全连接层我们的连接劝值矩阵的大小 W,经过训练后,就是固定的大小了,比如我们从卷积到全连层,输入和输出的大小,分别是 50、30 个神经元,那么我们的权值矩阵(50,30)大小的矩阵了。因此空间金字塔池化,要解决的就是从卷积层到全连接层之间的一个过度。
这里插入卷积、池化层的输入输出计算方法:
在这里插入图片描述
深度学习之---yolov1,v2,v3详解及实践_第3张图片
怎么改变这个现状呢,也就是无论输入图片是什么大小,不需要都转化为统一大小的图片,再送入网络的预处理过程。这就出现了大神何凯明的 CNN 应用之 SPP。空间金字塔池化的卷积神经网络物体检测,很详细,能看懂其中原因和机理,不赘述。

2.2 YOLOv2 多处改进

2.2.1 输出层使用卷积层替代 YOLOv1 的全连接层

附 darknet-19 的结构表:
深度学习之---yolov1,v2,v3详解及实践_第4张图片
包含 19 conv + 5 maxpooling。用 1x1 卷积层替代 YOLOv1 的全连接层。

1x1 卷积层(此处 1x1 卷积层的存在是为了跨通道信息整合)如上图的红色矩形框部分。

引入一点:YOLO,YOLOv2、YOLO9000,Darknet-19,Darknet-53,YOLOv3 分别是什么关系?

YOLOv2 是 YOLO 的升级版,但并不是通过对原始加深或加宽网络达到效果提升,反而是简化了网络。
YOLO9000 是 CVPR2017 的最佳论文提名。首先讲一下这篇文章一共介绍了 YOLOv2 和 YOLO9000 两个模型,二者略有不同。前者主要是 YOLO 的升级版,后者的主要检测网络也是 YOLOv2,同时对数据集做了融合,使得模型可以检测 9000 多类物体。而提出 YOLO9000 的原因主要是目前检测的数据集数据量较小,因此利用数量较大的分类数据集来帮助训练检测模型。
YOLOv2 使用了一个新的分类网络作为特征提取部分,参考了前人的先进经验,比如类似于 VGG,作者使用了较多的 3 * 3 卷积核,在每一次池化操作后把通道数翻倍。借鉴了 network in network 的思想,网络使用了全局平均池化(global average pooling),把 1 * 1 的卷积核置于 3 * 3 的卷积核之间,用来压缩特征。也用了 batch normalization(前面介绍过)稳定模型训练。最终得出的基础模型就是 Darknet-19,如上图,其包含 19 个卷积层、5 个最大值池化层(maxpooling layers )
2.2.2 卷积层全部使用 Batch Normalization

v1 中也大量用了 Batch Normalization,同时在定位层后边用了 dropout,v2 中取消了 dropout,在卷积层全部使用 Batch Normalization。

2.2.3 K-Means 算法

我们知道在 Faster R-CNN 中 anchor box 的大小和比例是按经验设定的,然后网络会在训练过程中调整 anchor box 的尺寸。但是如果一开始就能选择到合适尺寸的 anchor box,那肯定可以帮助网络越好地预测 detection。所以作者采用 k-means 的方式对训练集的 bounding boxes 做聚类,试图找到合适的 anchor box。

另外作者发现如果采用标准的 k-means(即用欧式距离来衡量差异),在 box 的尺寸比较大的时候其误差也更大,而我们希望的是误差和 box 的尺寸没有太大关系。所以通过 IOU 定义了如下的距离函数,使得误差和 box 的大小无关:

Faster R-CNN 采用的是手选先验框方法,YOLOv2 对其做了改进,采用 k-means 在训练集 bbox 上进行聚类产生合适的先验框. 由于使用欧氏距离会使较大的 bbox 比小的 bbox 产生更大的误差,而 IOU 与 bbox 尺寸无关, 因此使用 IOU 参与距离计算, 使得通过这些 anchor boxes 获得好的 IOU 分值。距离公式:
在这里插入图片描述
如下图 Figure2,左边是聚类的簇个数核 IOU 的关系,两条曲线分别代表两个不同的数据集。在分析了聚类的结果并平衡了模型复杂度与 recall 值,作者选择了 K=5,这也就是 Figure2 中右边的示意图是选出来的 5 个 box 的大小,这里紫色和黑色也是分别表示两个不同的数据集,可以看出其基本形状是类似的。而且发现聚类的结果和手动设置的 anchor box 大小差别显著。聚类的结果中多是高瘦的 box,而矮胖的 box 数量较少。
深度学习之---yolov1,v2,v3详解及实践_第5张图片
K-Means 算法概述:k-means 是非监督学习中的聚类算法; 基本 K-Means 算法的思想很简单,事先确定常数 K,常数 K 意味着最终的聚类类别数,首先随机选定初始点为质心,并通过计算每一个样本与质心之间的相似度 (这里为欧式距离),将样本点归到最相似的类中,接着,重新计算每个类的质心 (即为类中心),重复这样的过程,知道质心不再改变,最终就确定了每个样本所属的类别以及每个类的质心。由于每次都要计算所有的样本与每一个质心之间的相似度,故在大规模的数据集上,K-Means 算法的收敛速度比较慢。

深度学习之---yolov1,v2,v3详解及实践_第6张图片
使用聚类进行选择的优势是达到相同的 IOU 结果时所需的 anchor box 数量更少, 使得模型的表示能力更强, 任务更容易学习。

2.2.4 Multi-Scale Training

和 YOLOv1 训练时网络输入的图像尺寸固定不变不同,YOLOv2(在 cfg 文件中 random=1 时)每隔几次迭代后就会微调网络的输入尺寸。训练时每迭代 10 次,就会随机选择新的输入图像尺寸。因为 YOLOv2 的网络使用的 downsamples 倍率为 32,所以使用 32 的倍数调整输入图像尺寸 {320,352,…,608}。训练使用的最小的图像尺寸为 320 x 320,最大的图像尺寸为 608 x 608。 这使得网络可以适应多种不同尺度的输入。更多详细的资料可查看这里目标检测之 YOLOv3,YOLOv3 才是全文的的重点。

这里给出官方的 YOLOv2 与其它模型在 VOC 2007 数据集上的效果对比
深度学习之---yolov1,v2,v3详解及实践_第7张图片
三:YOLO v3 简介
本文的重点,先一张图看看 V3 版本的强大
深度学习之---yolov1,v2,v3详解及实践_第8张图片
横轴是每张图像的预测推理时间,单位 ms。纵轴是在 COCO 数据集上预测的 [email protected] 的精度。无论是在耗费时间,还是预测精度上面,v3 版本都完胜过去的一些模型。

darknet-53 模型
深度学习之---yolov1,v2,v3详解及实践_第9张图片
注:YOLO Detection 层: 坐标及类别结果输出层;Region 82,Region 94,Region 106。
YOLOv3 的改进之处:多尺度预算

坐标预测:bbox 预测仍是 yolov2 的使用维度聚类(dimension clusters )作为 anchor boxes 来预测边界框. 在训练期间,我们使用平方误差损失的总和。

对象分数:YOLOv3 使用逻辑回归预测每个边界框(bounding box)的对象分数。 如果先前的边界框比之前的任何其他边界框重叠 ground truth 对象,则该值应该为 1。如果以前的边界框不是最好的,但是确实将 ground truth 对象重叠了一定的阈值以上,我们会忽略这个预测,按照 [15] 进行。我们使用阈值 0.5。与 [15] 不同,我们的系统只为每个 ground truth 对象分配一个边界框。如果先前的边界框未分配给 grounding box 对象,则不会对坐标或类别预测造成损失。

类别预测:每个框使用多标签分类来预测边界框可能包含的类。在训练过程中,使用二元交叉熵损失来进行类别预测。

补充:Darknet 框架 Darknet 由 C 语言和 CUDA 实现, 对 GPU 显存利用效率较高 (CPU 速度差一些, 通过与 SSD 的 Caffe 程序对比发现存在 CPU 较慢,GPU 较快的情况). Darknet 对第三方库的依赖较少, 且仅使用了少量 GNU linux 平台 C 接口, 因此很容易移植到其它平台, 如 Windows 或嵌入式设备.

四:动手实践篇
来开始本文的重中之重吧——

第一步:首先根据官网提示,一步步的走一遍,直到能够训练 VOC 数据集,就可以停下来歇歇了。官网点这里穿越如果一起正常,恭喜你,就可以开始之后的步骤了。当然有兴趣想了解 YOLOv3 中设计上的更多细节,可以去看下诙谐幽默的论文,点这里,看 YOLOv3: An Incremental Improvement后面也会就论文中和修改中的一些联系,做个解释。

第二步:上面做完,只是说明你可以检测和训练了官方的图片数据集,下面开始自己的数据集。
注意点: 如果你的电脑设备是有 GPU 加速图像运算的,那样在第一步中,默认的还是 CPU 下的训练,想要使用 GPU 就要改 Makefile 文件这里了
深度学习之---yolov1,v2,v3详解及实践_第10张图片这是我这一个博客中看到的,将红色框圈中的部分改为 1,修改了之后,在 darknet 文件目录下 make clean 清除之前的 make 文件,重新 make,发现速度明显提高,使用上了 GPU 训练。(其实在之前第一次我重新 make 时候报 opencv 错误,后来尽管发错 opencv 没有安装好,make 也通过了,对这个没有影响,就没有太关注这里了,有经验的求告知)。相同的命令,再来训练一次 VOC 数据试试看,速度是不是提高杠杠的。
第三步:数据集的采集,制作标签,这块还参考手把手实践 YOLO 深度残差神经网络拐点检测,一句话也就是 labelImg 标记软件工具了,具体不详述了。其中有一点就是 ImageSets/Main/ 文件夹下的 train.txt,test.txt,val.txt,这里的文件需要改为自己待训练的图片所有名字编号,在生成待训练的 train.txt 大有用处。

第四步:对待训练初始配置参数进行修改

**改动一 **

首先确定你需要做几个类别的物体检测,也就是 classes=1,还是 classes=5 或者 7,或者 20。我这里待检测的类别为一类,所以 classes=1, 如下图的 cfg 文件夹下的.data 文件:

class 为训练的类别数
train 为训练集 train.txt
valid 为验证集 val.txt(未标识添加,后期可加入)
names 为 my_target.names,里面为自己训练的目标名称
backup 为 weights 的存储位置
将 VOC 格式的 xml 文件转换成 YOLO 格式的 txt 文件。

train.txt 为 python voclabel.py 自动生成的,为自己的待训练样本文件位置。其中在 voclabel.py 文件我对其进行了修改,sets=[] 也进行了删减,只留下自己需要的那一部分;lasses=[" "], 里面为自己的检测类别;生成的 train.txt 也只是自己需要的部分,如下图(如有不妥或者错误,求批评指正,自己想着改的,并未看到相关材料指导)
在这里插入图片描述
<文件名>.names 文件 原始的部分为 coco.data。如果你不想惹麻烦,直接将此处更名为 coco.data 即可。如若你想将此处的.data 文件更改为自己的特有命名,如 my_yolov3.data。这就需要在 examples 里面的 darknet.c 文件的 440 行处进行修改为自己的命名,然后 cd 到 darknet 文件夹下 make clean 删除之前的 make 文件,然后重新 make 即可。
没改之前直接使用,会出现这个错误提示(训练和检测报错都有):
深度学习之---yolov1,v2,v3详解及实践_第11张图片
改动就是在这里修改:
深度学习之---yolov1,v2,v3详解及实践_第12张图片
make 命令百科

在软件开发中,make 是一个工具程序(Utility software),经由读取叫做“makefile”的文件,自动化建构软件。它是一种转化文件形式的工具,转换的目标称为“target”;与此同时,它也检查文件的依赖关系,如果需要的话,它会调用一些外部软件来完成任务。它的依赖关系检查系统非常简单,主要根据依赖文件的修改时间进行判断。大多数情况下,它被用来编译源代码,生成结果代码,然后把结果代码连接起来生成可执行文件或者库文件。它使用叫做“makefile”的文件来确定一个 target 文件的依赖关系,然后把生成这个 target 的相关命令传给 shell 去执行。

许多现代软件的开发中 (如 Microsoft Visual Studio),集成开发环境已经取代 make,但是在 Unix 环境中,仍然有许多任务程师采用 make 来协助软件开发。

/backup/ 文件夹下用于存放训练好的.weights 参数文件,源代码里面是迭代次数小于 1000 时,每 100 次保存一次,大于 1000 时,没 10000 次保存一次。自己可以根据需求进行更改,然后重新编译即可。代码位置在 examples 里面的 detector.c line 138,和上面的一样,cd 到 darknet 文件夹下 make clean 删除之前的 make 文件,然后重新 make 即可。这样.data 文件就这么些内容。
深度学习之---yolov1,v2,v3详解及实践_第13张图片
**改动二 **

cfg 文件夹下的.cfg 文件,有很多,用到的只是 yolov3-voc.cfg(现在还不知道别的.cfg 文件该怎么用,求指点,于是我把别的文件全删除了,只留下 coco.data 和 yolov3-voc.cfg)一切正常,还没发现出错。删了 – 改名,就这样了(改了名之后报错?就需要改动一处的指示了,回看改动一)
深度学习之---yolov1,v2,v3详解及实践_第14张图片
最重要的改动,是在 my_yolov3.cfg(已图片处的名字为例)下的参数,欲知详情,娓娓道来······

my_yolov3.cfg 下参数改动:Training or Testing pattern?
深度学习之---yolov1,v2,v3详解及实践_第15张图片
如图:

batch:每次迭代要进行训练的图片数量
subdivisions:batch 中的图片再产生子集,源码中的图片数量 int imgs = net.batch * net.subdivisions * ngpus (一次传入 batch 张图像,细分成 subdivisions 组行迭代训练,此时的 subdivisions=8,就会发现 train 时候,两次迭代输出之间,共输出了 8 次 Region 82,Region 94,Region 106。这里的 batch 是 16,即 8 组 2 个图像。你也可以设定 batch=64,此时的训练迭代就有 8 组 8 个图像了。)
Training pattern:注释掉 Testing 下的 batch 和 subdivisions 两个初始参数,让 Training 下的 batch 和 subdivisions 两个初始参数参与运算;
Testing pattern:反之,注释掉 Training 下的 batch 和 subdivisions 两个初始参数,让 Testing 下的 batch 和 subdivisions 两个初始参数参与运算。(上图就是在 test 下的参数模式,切记)
YOLOv3 预测 3 个不同尺度的 box

我们的系统使用类似的概念以金字塔网络(SPP)从这些量表中提取特征。最后一层网络预测一个 3D 张量编码的边界框,对象和类的预测(classes)。COCO 试验中,我们预测每个尺度上的 3 个盒子,所以这个张量是 NN3(4+1+80)的 4 个边界框偏移量,1 个目标预测,和 80 个类的预测。如果 classes=1,也就是上面的 my_yolov3.data,文件里面定义的,此时的最后一层 filters=3*(4+1+1)=18。

论文对最后一层网络的解释如下
深度学习之---yolov1,v2,v3详解及实践_第16张图片
第五步:Now we can train my target_yolo!

参考这个官方提示来做对应的修改,改为自己的命名形式,如果还是不行,恐怕就是你的 make 步骤没有做。make clean-- --make
深度学习之---yolov1,v2,v3详解及实践_第17张图片
红色框:cfg 文件夹下的.data 文件
绿色框:cfg 文件夹下的.cfg 文件
黄色框:darknet-53 的预训练参数作为整个 train 的初始参数

深度学习之---yolov1,v2,v3详解及实践_第18张图片
具体的输出详解在这里插入图片描述
Region Avg IOU: ----0.326577 is the average of the IOU of every image in the current subdivision. A 32,66% overlap in this case, this model still requires further training. Class: -----0.742537 still figuring this out Obj: -----0.033966 still figuring this out No Obj:----- 0.000793 still figuring this out The Avg Recall:------ 0.12500 is defined in code as recall/count, and thus a metric for how many positives YOLOv2 detected out of the total amount of positives in this subdivision. In this case only one of the eight positives was correctly detected. count: -----8 is the amount of positives (objects to be detected) present in the current subdivision of images (subdivision with size 8 in our case). Looking at the other lines in the log, you’ll see there are also subdivision that only have 6 or 7 positives, indicating there are images in that subdivision that do not contain an object to be detected.
如果不幸,输出的是这个样子
深度学习之---yolov1,v2,v3详解及实践_第19张图片
就是你在 2.1.1 节时候,把 Training or Testing 注释错了,更改下,再试试。

如果成功了,那就出去溜溜等着吧,记得回来看看 loss 参数,迭代输出像这样
在这里插入图片描述
9798----- indicates the current training iteration/batch. 0.370096 -----is the total loss. 0.451929 ------avg is the average loss error, which should be as low as possible. As a rule of thumb, once this reaches below 0.060730 avg, you can stop training. 0.001000----- rate represents the current learning rate, as defined in the .cfg file. 3.300000 -----seconds represents the total time spent to process this batch. The 627072 -----images at the end of the line is nothing more than 9778 * 64, the total amount of images used during training so far.
序列测试,这里将 cfg/myyolov3.data 进行修改,加入 valid 的测试序列地址,重新 python voclabel.py
深度学习之---yolov1,v2,v3详解及实践_第20张图片
valid 测试

./darknet detector valid cfg/myyolov3.data cfg/myyolov3.cfg backup/yolo-voc_final.weights

/在终端只返回用时,在./results/comp4dettest_[类名].txt 里保存测试结果/

打开查看内容
深度学习之---yolov1,v2,v3详解及实践_第21张图片
依次表示的是:文件名;每个框中存在该分类物体的概率;框框坐标 xmin;框框坐标 ymin;框框坐标 xmax;框框坐标 ymax,代码区如下截图,位置 examples/detector.c
深度学习之---yolov1,v2,v3详解及实践_第22张图片
当然也有别的测试方式,并返回评价指标,如图,可自己尝试
深度学习之---yolov1,v2,v3详解及实践_第23张图片
参考资料:

https://timebutt.github.io/static/understanding-yolov2-training-output/
https://www.zhihu.com/question/42205480
https://blog.csdn.net/qq_30401249/article/details/51694298
转载:https://gitbook.cn/books/5aceab0afafeca4b1a33e7b4/index.html

你可能感兴趣的:(深度学习,yoloV1,yoloV2,yolov3)