最近这段时间学习了YOLO系列原理,也跑了pytorch_yolov4、darknet框架yolov4、pytorch_yolov3、dakrnet框架yolov3等模型。这里要感谢网上大佬们的博文,没有你们,自己要走很多弯路。
本篇博客主要是记录自己学习YOLO系列的历程,方便以后自己需要时及时地查询与巩固,内容包括YOLO的原理、windows系统下的yolo模型搭建、用yolov3和yolov4训练自己的数据集去检测目标以及网上我认为不错的博文。
推荐一个CV领域的相关论文下载网址:https://github.com/hoya012/deep_learning_object_detection
在YOLO出来之前,常见的目标检测算法:
1.滑窗检测算法
①将目标检测的问题转化为图像识别的问题
②物体的位置是根据滑窗的位置确定的
③缺点:a.从图上可以看出,滑窗之间存在着很大部分的重叠,即存在大量的冗余,导致该方法效率低下。
b.滑窗算法最大的问题是只能看到滑窗部分里面的内容,不能看到整个目标。
这里推荐一篇论文,虽然时间比较早,但很经典,论文的下载可以去最上面的CV领域相关论文下载的网址。
为了解决滑窗算法的低效,引入了卷积神经网络
2.区域检测算法:采用某些算法,先从图像中找出可能存在目标的区域,然后只对这些区域进行目标检测。如select search
3.理解下神经网络解决对象分类和定位问题——边界框(bounding box)
https://blog.csdn.net/litt1e/article/details/87729884
4.目标检测进阶一(窗口滑动卷积算法)
https://blog.csdn.net/litt1e/article/details/87786398
(Yolo算法)
https://blog.csdn.net/litt1e/article/details/87820879
YOLOv1
https://blog.csdn.net/litt1e/article/details/88814417
YOLO v1深入理解
https://www.jianshu.com/p/cad68ca85e27
一文看懂YOLO v2
https://blog.csdn.net/litt1e/article/details/88852745
一文看懂YOLO v3
https://blog.csdn.net/litt1e/article/details/88907542
1.其中在YOLO中有好几种框,分别是:
2.对于目标的框选,也有几种框选的方式,如下:
①AABB——轴对齐的边界框
②RBOX——带旋转角度的边界框
③QUAD——圆形框
3.边界框的位置表示方式:
绝对坐标:缺点:当图像进行缩放之后,绝对坐标便不起作用了。
尺度归一化:将坐标压缩到0——1之间,即使图像缩放也能表示目标的位置。
4.YOLO:将目标检测的问题当成回归来做(object detection -> regression),像之前的Fast-CNN采用的是将目标检测的问题转化为分类。
5.Yolov1
对上述图片中的中间部分进一步分析,如下:
①将图像分成7×7、13×13或S×S,判断每个格子中是否有要检测的目标,假设是7×7,则有49个格子,相比于滑窗中的大量重叠,明显这种效率高了许多。缺点:对于一些很小的目标,不能很好的识别出来,这也是YOLO v1的一个缺陷。
②如何知道哪个格子判断哪个目标?
假设以狗为例,以狗的中心点格子,判断这是狗(中心点是用来训练的),训练的过程中,物体的中心点落在哪个格子中就由哪个中心点预测,中心点的确定是由我们训练集中的标签决定的,这是设定好了的,由ground truth(格子的真值)生成,即训练时,只有中心的格子才有标签真值。
但到了测试集预测阶段中,就没有这种限制了,每个格子都有其他目标的可能性,上述图片展示的是测试推断的过程,而不是训练过程,所以看上去每个格子似乎都预测了东西,预测后出来的一个值,就是结果,该结果不需要ground truth再进行比较了。上述操作完成后,再进行NMS处理,最终得到结果。
6.在YOLOv1中,神经网络最后是全连接层,之后YOLO就改成了全卷积层 (FCN):
YOLOv1的缺点:
①与基于区域检测的方法相比,召回率相对较低;
②大量的定位错误;
7.YOLO v3的多尺度问题:
上图图解:
①图中的数字指的是当前层的序号
②假设输入图像是3×608×608,先将其缩小至原图的1/32,608/32 = 19
③④表示上采样,即放大图像,这里的上采样用的是最近邻插值
⑤通过上采样扩大尺度,将其缩小至原图的/16
⑥通过上采样扩大尺度,将其缩小至原图的/8
可以发现,随着层数的增加,划分图像的格子越来越小
8.YOLOv3一共使用了9个anchor的框,它分了3个不同的尺度,每个尺度上又分了3个不同的框,(如YOLO v3的多尺度问题,分别缩小至原图的1/32、1/16、1/8)。
上图中的anchor是作者通过他的数据集聚类得到的anchor大小,具有一定的通用性,我们训练自己的模型时,可以通过自己的数据集Kmeans聚类得出属于适合自己数据集的anchor大小。
9.Yolov3原论文中有一个图
上图中的Cx,Cy那里表达不清楚,容易产生误解,这里的Cx,Cy是从图像的左上角顶点开始的,改成如下这种就行了,且Cx,Cy是根据网格的个数决定的,这里的值是1。
相对于网格单元:
换成上面这张图可以更好的理解,这里的Cx和Cy的大小为3。σ(tx)和σ(ty)通过σ(sigmoid)函数将预测到的点控制在那个小格子中,比如假设这里预测到的位置是(0.5,0.7),则该点的实际坐标是(3.5,3.7)。(预测的点、预测的黑色框是根据anchor的位置和大小决定的。)
1.yolov3.cfg
Darknet构建网络架构不是通过代码直接堆叠,而是通过解析cfg文件进行生成的。
2.在yolov3.cfg文件中,一些参数的解释(配合yolov3的网络体系结构图理解):
下图表示网络结构图中的卷积层
下图表示网络结构图中的yolo层,即对应②⑤⑥操作
参数解释:
mask:因为anchor有9个,所以编号为0——8,这里的6,7,8表示的是第7、8、9个anchor,对应上图中的②,3、4、5anchor对应图中的⑤,0、1、2对应图中的⑥
anchors:对应图上的②⑤⑥操作,每次需要3个anchor,且这里9个anchor的大小是由Kmeans聚类得到的
classes:表示你要检测的目标种类
num:表示anchor的数量
jitter:用来数据增强时候的参数
ignore_thresh:在做交并比的时候用来判断你的anchor是正样本还是负样本,IOU的阈值
表示特征融合层
其中①:layers = -4 表示将前面的第4层带过来,如果layers有1层表示将那1层引过来
其中②:layers = -1,36表示将前面1层和后面的第36层融合起来,如果layers有两层表示将那两层相加
表示上采样层
https://github.com/eriklindernoren/PyTorch-YOLOv3
(这个版本的yolov3源码比较贴切于原论文)
https://github.com/ultralytics/yolov3
(该代码虽然是yolov3的,但其中有些部分已经做了改动,初学yolo源码的话不建议看这个,这会和论文中的很多地方对不上)
比如:下图中的一个个小格子是用来划分责任的,即表示这个格子到底用来划分什么物体,真正的看到的东西是anchor。每个格子中都会放anchor,anchor是我们的样本,
步骤一:anchor是通过聚类得到的,首先为Anchor分配GT(ground truth)
上图中,Anchor表示的序号0——4(彩色的方框),黑色的方框表示的是GT(我们自己标的标签)。然后为每个anchor分配GT,即每个anchor要不有一个GT对应,要不就是background,可以根据IOU来判定。
关于IOU的阈值,在yolov3.cfg文件中的ignore_thresh即表示IOU阈值。ignore_thresh设置的越大,留下的anchor越少。(留下来的anchor就是正样本)
以上图为例,计算anchor-0和anchor-1与黑色方框GT的IOU值,可以发现anchor-0小于我们设定的IOU阈值,则判断为background,anchor-1判断为GT。
步骤二:标注每个anchor,根据GT的值,是猫的话就判断为猫,是狗的话就判断为狗,即为每个anchor分类别。
步骤三:计算每个anchor的偏移量,根据下面的图进行逆推
步骤四:以上步骤是设置类别,计算偏移量。注意样本是anchor。这样一来anchor的类别和偏移量都有了,tx’,ty’,tw’,th’。
在yolov3的源码中,关于yolo层即YOLOLayer是预测出来的tx,ty,tw,th。和上面步骤计算出来的tx’,ty’,tw’,th’进行比较,可以计算loss函数,然后就可以使用反向传播了。
推断预测的时候,直接使用YOLOLayer,虽然没有真值GT了,但也是要生成anchor的,因为这里得到的结果是相对于anchor的。
附上大佬的博文:
https://blog.csdn.net/weixin_44791964/article/details/106214657
非极大抑制NMS与Soft-NMS
https://blog.csdn.net/weixin_44791964/article/details/106222846
YoloV4当中的Mosaic数据增强方法
https://blog.csdn.net/weixin_44791964/article/details/105996954
补充:
①因为传统的IOU中计算的是两个方框相交的情况,如果不相交就无法处理,所以引入了GIOU、DIOU。
上图中第二项相当于是惩罚项。
Pytorch的yolov4(力推这个博主,我就是按照他的博文配置成功的):
windows下的torch=1.2.0与CUDA环境配置:
https://blog.csdn.net/weixin_44791964/article/details/106037141
相关资源下载:
链接:https://pan.baidu.com/s/1fUKk4JFNZmk2BbQKghnRrg
提取码:y0mx
Pytorch搭建YoloV4目标检测平台
https://blog.csdn.net/weixin_44791964/article/details/106214657
配套的视频介绍:
https://www.bilibili.com/video/BV1Q54y1D7vj?p=2
准备过程:
①按照VOC数据集存放图像和xml文件
②运行…yolov4-pytorch-master\VOCdevkit\VOC2007中的voc2yolo4.py文件,然后进入到Image/Main中查看,分成了test.txt,train.txt(并不是所有数据参加训练过程),val.txt,trainval.txt文件
③修改…\yolov4-pytorch-master目录下的voc_annotation.py,将类别classes换成你检测的类别。
运行…\yolov4-pytorch-master目录下的voc_annotation.py,会在此目录下生成2007_test.txt,2007_train.txt,2007_val.txt文件(打开txt文件其中存放的是图像的绝对路径和目标的参数,每个目标有5个参数,前4个是目标的位置,第五个是目标的种类)
④train.py中:先把main中的输入图像大小改成input_shape=608x608
smoooth_label平滑标签改为0.001
classes_path中改为你需要训练的类别
anchors_path中需要kmeans聚类后的先验框大小,运行kmeans_for_anchors.py文件
model_path
相关资源下载(里面的步骤很详细):
链接:https://pan.baidu.com/s/1WbsSSPJ_vBcJSBVtlc6L8w
提取码:gf4w
配套的视频:
https://www.bilibili.com/video/BV1kt4y1C7YC?t=1183
快速入手YoloV4 编译+使用+训练
视频链接:https://www.bilibili.com/video/BV1oi4y1x7gn
yolov4仓库github地址: https://github.com/AlexeyAB/darknet
关于VS2017、OPENCV的配置: https://www.cnblogs.com/Songyiqing/p/12824557.html
这里参考我之前写的博客:
https://blog.csdn.net/qq_45445740/article/details/104801631
Pytorch搭建yolo3目标检测平台
https://blog.csdn.net/weixin_44791964/article/details/105310627
配套视频:
https://www.bilibili.com/video/BV1Hp4y1y788
①如果是Pytorch框架的yolo,用xml文件就可以,LabelImage中直接就可以输出PascalVOC格式的标签
②如果是Darknet框架的yolo,是需要txt文件的,更新下LabelImage,就可以直接将打标签的图像转为yolo的形式。
参考博文:https://blog.csdn.net/qq_45445740/article/details/106521620
但如果你的xml文件已经有了,若再去打一遍标签,相信肯定会崩溃,有的Darknet框架中提供将xml文件转为txt的程序,有的没有,这里我贴出一个我实测过的xml文件转txt文件的源程序。
'''xml转txt'''
import os
import sys
import xml.etree.ElementTree as ET
import glob
def xml_to_txt(indir,outdir):
os.chdir(indir)
annotations = os.listdir('.')
annotations = glob.glob(str(annotations)+'*.xml')
for i, file in enumerate(annotations):
file_save = file.split('.')[0]+'.txt'
file_txt=os.path.join(outdir,file_save)
f_w = open(file_txt,'w')
# actual parsing
in_file = open(file)
tree=ET.parse(in_file)
root = tree.getroot()
for obj in root.iter('object'):
current = list()
name = obj.find('name').text
xmlbox = obj.find('bndbox')
xn = xmlbox.find('xmin').text
xx = xmlbox.find('xmax').text
yn = xmlbox.find('ymin').text
yx = xmlbox.find('ymax').text
#print xn
f_w.write(xn+' '+yn+' '+xx+' '+yx+' ')
f_w.write(str(name.encode("utf-8")+ b"\n"))
indir= r'C:\Users\ps\Desktop\transform\Annotations' #xml目录
outdir= r'C:\Users\ps\Desktop\transform\txt' #txt目录
xml_to_txt(indir,outdir)
③在给xml文件转为txt文件时,我报了一个错,大概意思是除数不能为0,后经过排查,是因为有些xml文件中是这样:
后将这些出错的xml文件重新打标签保存就可以了。
最近学习Yolo是因为老师布置的一个项目需要,刚开始接手的时候,心里第一想法就是拿刚出来的yolov4网络,因为数据集比较小,分4个类只有700多张数据集,抱着试一试的想法,跑了一下Pytorch搭建的yolov4,随便测试了几张,准确率高达90%,不得不佩服yolov4的强大。
起初是想用PyQt做一个交互式界面,最后却发现Pytho的运行速度实在是太低效,于是想到了用C++的QT写界面,然而在调用模型的时候,却总是出错,因为我用Pytorch的yolov4跑出来的权重文件后缀是pth,查了下资料,大概原因是readNetFromDarknet()函数不支持.pth权重的读取;
opencv用dnn.readNet加载caffe/torch/darknet/tensorflow的模型和权重
https://blog.csdn.net/qq_31375855/article/details/103784160
突然发现Opencv中有readNetFromTorch这个函数,但网上搜了之后发现他们调用的文件后缀都是.t7格式,而我自己Pytorch训练出来的是后缀为.pth,
http://ddrv.cn/a/197161
https://blog.csdn.net/juebai123/article/details/86545556
然后我又想到了Darknet框架的yolov4,因为那样跑出来的权重文件后缀是weights,是支持的,一顿操作搭建好了环境,开始跑模型的时候,突然想到,因为yolov4刚出来不久,里面有一些新的网络层,去C++里面调用时,Opencv会不会不支持,请教了师兄,也提出了这样的顾虑,于是我放弃了yolov4,改用yolov3.
PS:windows环境下配darknet的yolov3过程实属曲折,不是这个报错就是那个报错,没办法了试了下Linux系统的环境配置,还是以失败告终。
如果用Pytorch的yolov3跑模型,最终出来的权重文件又是.pth,还是绕不过这个问题。
最后还是师兄给了我一个Pytorch_yolov3的版本,输出.pt格式权重,然后再转为.weights格式权重。
①相关资料下载:
链接:https://pan.baidu.com/s/1sCfiOl7A5BAH0opdNAaIHA
提取码:9f00
②训练过程参考博客:
https://blog.csdn.net/weixin_37889356/article/details/104313153?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
③训练好了之后,先进行预测:
在这个文件夹下放待检测的图像:
在这个路径下输出预测的结果:
④.pt转为.weights文件
模型跑完后输出的权重文件在这个路径下,
修改上面两张图的路径
最后输出weights文件
⑤C++、opencv下调用weights权重
源码链接:
链接:https://pan.baidu.com/s/1Y7O_iAFLKyy2wOkirHvJlw
提取码:z6bf
若有大佬在C++、opencv中调用过yolov4或者调用过.pth的权重,望告知,非常感谢!!!