Ubuntu16+GPU环境训练yolov3-tiny
参考链接:https://www.cnblogs.com/xieqi/p/9818056.html
参考链接:https://www.cnblogs.com/shuiyj/p/13185303.html
参考链接:YOLOV3中Darknet中cfg文件说明和理解:https://www.cnblogs.com/hls91/p/10911997.html
辛辛苦苦搭载好GPU环境,环境搭载参考这个
现在要开始测试下效果
参考链接:https://pjreddie.com/darknet/yolo/
一,测试
(1),如果尚未安装Darknet,则应先进行安装
git clone https://github.com/pjreddie/darknet cd darknet make
您已经在cfg/
子目录中拥有YOLO的配置文件。您将必须在此处下载预训练重量文件(237 MB)。或只是运行此:
wget https://pjreddie.com/media/files/yolov3.weights
然后运行检测器!
./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg
你将看到以下输出:
layer filters size input output 0 conv 32 3 x 3 / 1 416 x 416 x 3 -> 416 x 416 x 32 0.299 BFLOPs 1 conv 64 3 x 3 / 2 416 x 416 x 32 -> 208 x 208 x 64 1.595 BFLOPs ....... 105 conv 255 1 x 1 / 1 52 x 52 x 256 -> 52 x 52 x 255 0.353 BFLOPs 106 detection truth_thresh: Using default '1.000000' Loading weights from yolov3.weights...Done! data/dog.jpg: Predicted in 0.029329 seconds. dog: 99% truck: 93% bicycle: 99%
这说明没有问题。
(2)更改检测阈值
默认情况下,YOLO仅显示置信度为.25或更高的对象。您可以通过将-thresh <val>
标志传递给yolo
命令来更改此设置。例如,要显示所有检测,可以将阈值设置为0:
./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg -thresh 0
(3) 训练YOLO VOC
要培训YOLO,您需要2007年至2012年的所有VOC数据。(如果你和我一样用自己的数据训练yolo,则不需要下面这一步)
要获取所有数据,请创建一个目录以存储所有数据,然后从该目录运行:
wget https://pjreddie.com/media/files/VOCtrainval_11-May-2012.tar wget https://pjreddie.com/media/files/VOCtrainval_06-Nov-2007.tar wget https://pjreddie.com/media/files/VOCtest_06-Nov-2007.tar tar xf VOCtrainval_11-May-2012.tar tar xf VOCtrainval_06-Nov-2007.tar tar xf VOCtest_06-Nov-2007.tar
现在将有一个VOCdevkit/
子目录,其中包含所有VOC培训数据。
生成VOC标签
现在我们需要生成Darknet使用的标签文件。Darknet希望.txt
为每个图像提供一个文件,并在图像中为每个地面真实对象添加一行,如下所示:
<object-class> <x> <y> <width> <height>
下载预训练的卷积权重(用自己的数据训练则可以不需要这一步)
为了进行训练,我们使用在Imagenet上预先训练的卷积权重。我们使用darknet53模型的权重。您可以在此处下载卷积层的权重(76 MB)。也可以自行选择其他权重文件。
wget https://pjreddie.com/media/files/darknet53.conv.74
训练模型
现在我们可以训练!运行命令(官方指导文件中命令):
./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg darknet53.conv.74
这上面基本上都是参考链接中有的,我把要用到的重要步骤给翻译整理了一下。
二,训练自己的数据
(1),标注图像
在标注前可以使用脚本对图像进行重命名,参考链接:https://www.cnblogs.com/gezhuangzhuang/p/10539792.html
推荐使用labelimg工具进行标注,参考我的博文链接:https://www.cnblogs.com/vincent212212/p/13262109.html
(2),制作数据集
我们可以仿照VOCdevkit的格式存储我们标注的xml文件和图像。
例如,建立traindata数据集文件夹,将VOCdevkit复制到traindata下,并且在traindata文件夹下添加voc_label.py脚本,参考如下:(你可以修改为自己的classes)
import xml.etree.ElementTree as ET import pickle import os from os import listdir, getcwd from os.path import join sets=[('2007', 'train'), ('2007', 'val'), ('2007', 'test')] classes = ["corner","tcorner","crosscorner"] def convert(size, box): dw = 1./(size[0]) dh = 1./(size[1]) x = (box[0] + box[1])/2.0 - 1 y = (box[2] + box[3])/2.0 - 1 w = box[1] - box[0] h = box[3] - box[2] x = x*dw w = w*dw y = y*dh h = h*dh return (x,y,w,h) def convert_annotation(year, image_id): in_file = open('VOCdevkit/VOC%s/Annotations/%s.xml'%(year, image_id)) out_file = open('VOCdevkit/VOC%s/labels/%s.txt'%(year, image_id), 'w') tree=ET.parse(in_file) root = tree.getroot() size = root.find('size') w = int(size.find('width').text) h = int(size.find('height').text) for obj in root.iter('object'): difficult = obj.find('difficult').text cls = obj.find('name').text if cls not in classes or int(difficult)==1: continue cls_id = classes.index(cls) xmlbox = obj.find('bndbox') b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text)) bb = convert((w,h), b) out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n') wd = getcwd() for year, image_set in sets: if not os.path.exists('VOCdevkit/VOC%s/labels/'%(year)): os.makedirs('VOCdevkit/VOC%s/labels/'%(year)) image_ids = open('VOCdevkit/VOC%s/ImageSets/Main/%s.txt'%(year, image_set)).read().strip().split() list_file = open('%s_%s.txt'%(year, image_set), 'w') for image_id in image_ids: list_file.write('%s/VOCdevkit/VOC%s/JPEGImages/%s.jpg\n'%(wd, year, image_id)) convert_annotation(year, image_id) list_file.close() os.system("cat 2007_train.txt 2007_val.txt > train.txt") os.system("cat 2007_train.txt 2007_val.txt 2007_test.txt > train.all.txt")
在VOCdevkit中建立VOC2007中添加test.py脚本,内容如下,仅供参考(你可以修改分配比例和文件路径)
import os import random trainval_percent = 0.3 train_percent = 0.7 xmlfilepath = 'Annotations' txtsavepath = 'ImageSets\Main' total_xml = os.listdir(xmlfilepath) num = len(total_xml) list = range(num) tv = int(num * trainval_percent) tr = int(tv * train_percent) trainval = random.sample(list, tv) train = random.sample(trainval, tr) ftrainval = open('ImageSets/Main/trainval.txt', 'w') ftest = open('ImageSets/Main/test.txt', 'w') ftrain = open('ImageSets/Main/train.txt', 'w') fval = open('ImageSets/Main/val.txt', 'w') for i in list: name = total_xml[i][:-4] + '\n' if i in trainval: ftrainval.write(name) if i in train: ftest.write(name) else: fval.write(name) else: ftrain.write(name) ftrainval.close() ftrain.close() fval.close() ftest.close()
将自己标注的xml文件放到Annotations文件夹下,将图像放到JPEGImages文件夹下。
1,cd到VOC2007下,运行test.py
先运行这个脚本将Annotations里的xml文件随机的分发到对应文件夹里,分发到比例是可以改的。
2,然后cd到traindata下,运行voc_label.py
这几个py文件都比较好理解,可以稍微看一下代码
运行完之后会得到2007_train.txt,2007_test.txt等txt文件。
3,修改Cfg以获取Pascal数据,(不要在windows环境中修改)
在cfg文件夹中的voc.data中,下面以我的路径举例
1 classes= 3
2 train = /home/.../mydarknet/darknet/traindata/train.txt
3 valid =/home/.../mydarknet/darknet/traindata/2007_test.txt
4 names =/home/.../mydarknet/darknet/traindata/voc.names
5 backup =/home/.../mydarknet/darknetbackup
4,修改cfg文件夹下的voc.names文件,(不要在windows环境中修改)
修改为自己分类的class名字。
比如,我这里改为:
corner
tcorner
crosscorner
5,修改cfg文件夹下的yolov3-tiny.cfg文件,如下是我的cfg文件,供大家参考(不要在windows环境中修改)
[net] # Testing #batch=1 #subdivisions=1 # Training batch=32 subdivisions=2 width=416 height=416 channels=3 momentum=0.9 decay=0.0005 angle=0 saturation = 1.5 exposure = 1.5 hue=.1 tee result/log/training.log learning_rate=0.001 burn_in=1000 max_batches = 240000 # 5200000 policy=steps steps=400000,450000 scales=.1,.1 [convolutional] batch_normalize=1 filters=16 size=3 stride=1 pad=1 activation=leaky [maxpool] size=2 stride=2 [convolutional] batch_normalize=1 filters=32 size=3 stride=1 pad=1 activation=leaky [maxpool] size=2 stride=2 [convolutional] batch_normalize=1 filters=64 size=3 stride=1 pad=1 activation=leaky [maxpool] size=2 stride=2 [convolutional] batch_normalize=1 filters=128 size=3 stride=1 pad=1 activation=leaky [maxpool] size=2 stride=2 [convolutional] batch_normalize=1 filters=256 size=3 stride=1 pad=1 activation=leaky [maxpool] size=2 stride=2 [convolutional] batch_normalize=1 filters=512 size=3 stride=1 pad=1 activation=leaky [maxpool] size=2 stride=1 [convolutional] batch_normalize=1 filters=1024 size=3 stride=1 pad=1 activation=leaky ########### [convolutional] batch_normalize=1 filters=256 size=1 stride=1 pad=1 activation=leaky [convolutional] batch_normalize=1 filters=512 size=3 stride=1 pad=1 activation=leaky [convolutional] size=1 stride=1 pad=1 filters=24 # (class+5)*3 activation=linear [yolo] mask = 3,4,5 anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 classes=3 num=6 jitter=.3 ignore_thresh = .7 truth_thresh = 1 random=1 [route] layers = -4 [convolutional] batch_normalize=1 filters=128 size=1 stride=1 pad=1 activation=leaky [upsample] stride=2 [route] layers = -1, 8 [convolutional] batch_normalize=1 filters=256 size=3 stride=1 pad=1 activation=leaky [convolutional] size=1 stride=1 pad=1 filters=24 # (class+5)*3 activation=linear [yolo] mask = 0,1,2 anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 classes= 3 num=6 jitter=.3 ignore_thresh = .7 truth_thresh = 1 random=1
几点注意:
1,训练时注销掉testing(前面添加#),同理测试时注销掉training
# Testing
#batch=1
#subdivisions=1
2,yolotiny训练过程中有两个输出层,要将输出层之前的卷积滤波修改为自己合适的,例如
filters=24 # (class+5)*3
3,在两个输出层中要把class改成合适自己的,例如,我的训练分为三类,我就改为了3
(3),开始训练
训练指令:./darknet detector train <data_cfg> <model_cfg> <weights> -gpus <gpu_list>
我的训练命令如下,(文件路径可修改为自己的)
./darknet detector train mycfg/voc.data mycfg/yolov3-tiny.cfg yolov3-tiny.conv.15
如果需要生成loss-iter曲线,在执行训练命令的时候加一下管道,tee一下log:命令如下:
./darknet detector train mycfg/voc.data mycfg/yolov3-tiny.cfg yolov3-tiny.conv.15 | tee result/log/training.log
生成的training文件需要绘制曲线的话,可以参考此链接的脚本:https://blog.csdn.net/qq_34806812/article/details/81459982
3,补充注意事项
1,在mycfg中的yolov3-tiny.cfg文件中,可以修改训练参数。
比如中的max_batches = 250000,表示最大训练步数,可以自己修改。
还可以把training下面的batch改小一点,以免报错,我这里batch=32.
2,训练中,在mycfg中的yolov3-tiny.cfg文件中,testing下面的batch和subdivisions前面要加#号注释掉。training下面的两项要保留。
测试时,在mycfg中的yolov3-tiny.cfg文件中,training下面的batch和subdivisions前面要加#号注释掉。testing下面的两项要保留。
3,在不同的环境下,还要更改darknet中的makefile文件配置,例如,用的GPU训练,可以参考如下配置。
makefile中的配置如下。
GPU=1
CUDNN=1
OPENCV=1
OPENMP=1
DEBUG=0
4,如果在训练中出现无法找到训练文件的情况,Couldn't open file: train.txt
很有可能是你的文件格式不对,很可能是因为你在windows环境下修改了这些文件。
请检查生成的几个txt文件的格式,检查方法参考链接:https://liumin.blog.csdn.net/article/details/99687482
如果txt文件没问题,请检查voc.data,cfg等文件内容格式是否有问题。
5,训练的过程中,出现部分nan是正常的,但是全部是nan的话,就是你的数据集的问题了。
6,训练过程中,什么时候训练的可以了,可以关注avg指标,训练收敛后,一般会降低到0.1一下。
不断更新ing