一.下载yolov3工程项目
git clone https://github.com/pjreddie/darknet
cd darknet
将makefile的相应部分参数改为1,
#如果使用GPU设置为1,CPU设置为0,GPU=0
#如果使用CUDNN设置为1,否则为0,CUDNN=0
#如果使用OPENCV设置为1,否则为0,OPENCV=1
修改后保存,再make一下。
将官网的预训练权重先下载到darknet下
二.准备训练数据集
按照下面文件夹的结构,将训练数据集放到各个文件夹下面,生成2个文件一个train.txt,一个是val.txt。这里使用到的脚本为getfile.py,
VOCdevkit
—VOC2012
——Annotations
——ImageSets
———Layout
———Main
———Segmentation
——JPEGImages
注意:其中Annotations中是所有的xml文件
JPEGImages中是所有的训练文件
Main中是2个txt文件:train.txt与val.txt文件(前一个用来验证,后一个用来测试)
三.生成2007_train.txt和2007_val.txt文件
下载voc_label.py,或者直接在scripts中找到voc_labels.py将该文件与VOCdevkit数据集放到同一级路径下。
首先修改voc_label.py里面的值:
修改sets为自己训练样本集的名称,以及classes为训练样本集的类标签
文件最后两行注释掉。
在当前终端运行 python voc_label.py
生成
① 训练和验证的文件列表(2007_train.txt和2007_val.txt)主要存储的是图片位置信息;
② 生成与Annotations等同级的label文件,label里面的文件是每张图片位置坐标以及类别的标签信息。
四.修改cfg/voc.data文件
#classes为训练样本集的类别总数:classes= 1
#train的路径为训练样本集所在的路径
train = /home/njust/darknet_model/darknet_person/2007_train.txt
#valid的路径为验证样本集所在的路径
valid = /home/njust/darknet_model/darknet_person/2007_val.txt
#names的路径为data/voc.names文件所在的路径
names = data/voc.names
backup = backup
五.在darknet文件夹下面新建文件夹backup
六.修改voc.name为样本集的标签名
七.修改cfg/yolov3-voc.cfg
这里我只是以一类目标检测为例,主要有4处地方调整:
[net]
# Testing
# batch=1
# subdivisions=1
# Training
batch=64
subdivisions=16
......
[convolutional]
size=1
stride=1
pad=1
filters=18###75
activation=linear
[yolo]
mask = 6,7,8
anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326
classes=1###20
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=0###1
......
[convolutional]
size=1
stride=1
pad=1
filters=18###75
activation=linear
[yolo]
mask = 3,4,5
anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326
classes=1###20
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=0###1
......
[convolutional]
size=1
stride=1
pad=1
filters=18###75
activation=linear
[yolo]
mask = 0,1,2
anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326
classes=1###20
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=0###1
A.filters数目是怎么计算的:3x(classes数目+5),和聚类数目分布有关,论文中有说明;
B.如果想修改默认anchors数值,使用k-means即可;
C.如果显存很小,将random设置为0,关闭多尺度训练;
D.其他参数基本与V2一致,不再说明;
E.前100次迭代loss较大,后面会很快收敛;
八.开始训练
./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg darknet53.conv.74
九.识别
./darnket detector test cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc.backup data/test.jpg
常见问题解决:
- 1. 什么时候停止训练:
通常每个类(对象)有足够的2000次迭代。但是,当你应该停止训练时,为了更准确的定义,请使用以下指标:
9002:是迭代次数
0.060730:是平均损失,当看到平均损失0.xxxxx avg在许多吃迭代不再减少时,应该停止训练。一旦停止训练,可以得到最后的.weights文件,可以在backup里面找到最佳的文件,也可以使用yolov3-voc.backup这个文件。
***利用YOLOv2训练数据---https://blog.csdn.net/echoKangYL/article/details/79445587
1.下载YOLO
yolo的官网:https://pjreddie.com/darknet/yolo/
2.数据预处理(该处理方法与参考博客中的方法相同)该阶段建立的文件夹的名称最好与该文档中的相同,否则需要改动图片处理等python脚本中的文件名。a.建立文件夹"Image",并在其下存放所有图片样本(jpg、png均可)b.利用labelImg工具进行标注c.与Image文件件同级建立"xml"文件夹,存放利用labelImg标注后得到的所有图片的xml文件d.下载脚本,放在Image、xml文件夹的同级脚本下载地址:http://pan.baidu.com/s/1hs22I7U 密码:wdv0(该下载地址在参考博客中有提供,十分感谢原作者的帮助)在运行脚本之前,先做几处改动:a.将traindata.py中大概在65行和71行的:shutil.copy(xmlolddir, newdir1);shutil.copy(xmlolddir, newdir2);两句删掉(或前面加‘#’)否则在训练过程中报类似这样的error:“Cannot load image "/home/ts/tensorflow/objectRecognition/Augmentation/KNIFE/Getdata/trainImage/000018.png"STB Reason: unknown image type”b.若之前建立文件夹时文件夹名称并非Image和xml,那么在traindata.py中的对应文件夹名称处将其改为自己的文件夹名称改动之后,运行脚本运行traindata.py:生成trainImage文件夹,存放训练图片;生成trainImageXML文件夹,存放训练图片xml标签;生成validateImage文件夹,存放验证集图片;生成validateImageXML文件夹,存放验证集图片的xml标签;生成trainImageId.txt、validateImageId.txt,存放训练、验证集图片索引(一般为文件名)。运行trans.py,生成trainImageLabelTxt文件夹,存放训练图片通过xml标签转化得到的txt文件(若在训练过程提示txt文件找不到,则把此文件夹下的txt文件夹移动到trainImage文件夹);生成validateImageLabelTxt文件夹,道理一样。另外,得到的trainImagePath.txt和validateImagePath.txt存放着训练图片和验证图片的路径。此后,将生成的validateImageLabelTxt文件夹中的所有txt文件复制到validateImage文件夹中;同理,将trainImageLabelTxt文件夹中的所有txt文件复制到trainImage文件夹中。否则会在训练过程中报类似这样的error:“cannot open file xxxxxx.txt”
3.修改配置文件a.cfg/voc.data文件中:classes= 3train = /home/ts/tensorflow/objectRecognition/YOLOv2/YOLOtraining/trainImagePath.txtvalid = /home/ts/tensorflow/objectRecognition/YOLOv2/YOLOtraining/validateImagePath.txtnames = data/knifes.namesbackup = backupclasses存放类别总数(这里有knife、swissknife、jackknife三种,根据使用者不同的需要进行改动),train 和valid 中存的是训练图片集和验证图片集的路径;在data文件夹中新建文件knifes.names,存放的是方框注释,本例中有三行(根据使用者不同的需要进行改动):knifeswissknifejackknifeb.yolo-voc.cfg文件中:将[region]中的classes改为3(这里有knife、swissknife、jackknife三类,根据使用者不同的需要进行改动);将最后一个[convolutional](紧挨着[region]的前一个)中的filter改为40(filter的公式filters=(classes+coords+1)*(NUM),这里是(3+4+1)*5=30,根据使用者不同的需要进行改动)。 c.knifes.names:具体见a4.下载预训练文件cfg/darknet19_448.conv.23以在其他数据集上pretrain的模型做为初值。下载地址:http://pan.baidu.com/s/1dFgUk4x 密码:ynhg(该下载地址为参考博客原文作者提供,再次感谢原作者的帮助)下载之后将其放在darknet文件夹下。在训练之前,要先在darknet文件夹下新建backup文件夹,在backup文件夹中新建一个以yolo-voc.backup为文件名的文件,以保存训练参数。否则将在训练过程中报类似这样的error:“cannot open backup/yolo-voc.backup”5.训练在darknet文件夹路径下运行命令:./darknet detector train cfg/voc.data cfg/yolo-voc.cfg darknet19_448.conv.23系统默认会迭代45000次batch,如果需要修改训练次数,进入cfg/yolo_voc.cfg修改max_batches的值。6.测试训练完成后,模型成功保存,输入命令测试模型:./darknet detector test cfg/voc.data cfg/yolo-voc.cfg backup/yolo-voc_final.weights testpicture/001.jpg在该步骤中,将最后一个参数 testpicture/001.jpg 改为自己想要测试的图片路径;若提前终止训练,则将倒数第二个参数 backup/yolo-voc_final.weights 改为backup文件夹下的最新权重备份文件名称,例如:我提前终止后,最新权重备份文件为 backup/yolo-voc_900.weights。否则将提示error:“Couldn't open file: backup/yolo-voc_final.weights”参考原文中训练类别为1,本文中的训练类别为3,相互比较之下可以知道所有类别的情况下配置文件应该如何改动。
原文:https://blog.csdn.net/echoKangYL/article/details/79445587
***YOLO训练自己的数据集---https://blog.csdn.net/qq_34484472/article/details/73135354#reply
1.yolo
yolo的官网:https://pjreddie.com/darknet/yolo/
yolo的官网介绍了yolo的安装与测试。建议大家多看看英文官网,因为中文网更新的慢,而且有部分内容省略了。按照官网的步骤就不会有错。(建议先跑一下Pscal VOC)
2.数据的预处理
yolo的数据包括训练数据和验证数据(训练数据用来训练模型,验证数据用来调整模型)。训练数据和验证数据都包括:a.图片;b.标签。需要说明的是,如果采用VCC的话,标签需要特定xml格式,还要转化为txt。下面以我目标检测“猫”为例讲解。
a.在“Image”文件夹下存放所有的图片样本(包括训练数据和验证数据,而且最好是jpg格式)
b.下载labelImg(一种图像标记工具,给图像中的目标打上标签,且可以生成训练需要的xml格式),具体的使用方法可以百度,操作起来很简单。
c.与“Image”文件夹同级新建“xml”文件夹,“xml”文件夹存放labelImg得到的所有图片样本的标签。
标注工具labelImg在Ubuntu系统的安装和使用--- https://blog.csdn.net/learning_tortosie/article/details/80947301
若是标中文则要进行整改--- https://www.cnblogs.com/datou-swag/articles/10658822.html
d.现在就是要将所有的样本分成训练集和验证集,而且要将训练集和验证集对应的xml也分开。这里下载python脚本,直接放在“Image”和“xml”文件夹同级路径。
下载:
链接:http://pan.baidu.com/s/1hs22I7U 密码:wdv0
在运行脚本之前,先做几处改动:a.将traindata.py中大概在65行和71行的:shutil.copy(xmlolddir, newdir1);shutil.copy(xmlolddir, newdir2);两句删掉(或前面加‘#’)否则在训练过程中报类似这样的error:“Cannot load image
运行traindata.py:生成trainImage文件夹,存放训练图片;生成trainImageXML文件夹,存放训练图片xml标签;生成validateImage文件夹,存放验证集图片;生成validateImageXML文件夹,存放验证集图片的xml标签。
运行trans.py(改一下自己的类别),生成trainImageLabelTxt文件夹,存放训练图片通过xml标签转化得到的txt文件(若在训练过程提示txt文件找不到,则把此文件夹下的txt文件夹移动到trainImage文件夹);生成validateImageLabelTxt文件夹,道理一样。
另外得到的trainImagePath.txt和validateImagePath.txt存放着训练图片和验证图片的路径。
3.修改配置文件
接下来就是修改配置文件了:
a.cfg/voc.data文件中:
classes= 1
train = /home/pdd/pdwork/darknet2/darknet/VOC/cat/trainImagePath.txt
valid = /home/pdd/pdwork/darknet2/darknet/VOC/cat/validateImagePath.txt
names = data/cats.names
classes存放类别总数(这里只有cat一种),train 和valid 放着的是训练图片和验证图片的路径,cats.names存放的是方框注释,这里只有cat一行:
b.yolo-voc.cfg
将[region]中的classes改为1(这里只有cat一类),将最后一个[convolutional](紧挨着[region]的前一个)中的filter改为30(filter的公式filters=(classes+ coords+ 1)* (NUM) ,我的是(1+4+1)* 5=30)。
c.cats.names
在data文件夹下新建cats.names,具体见a。
4.下载预训练文件cfg/darknet19_448.conv.23
以在其他数据集上pretrain的模型做为初值,下载地址:
链接:http://pan.baidu.com/s/1dFgUk4x 密码:ynhg。放在darknet文件夹下。
(最新的预训练权中参数darknet53.conv.74--- wget https://pjreddie.com/media/files/darknet53.conv.74)
5.训练
在darknet文件夹路径下运行命令:
./darknet detector train cfg/voc.data cfg/yolo-voc.cfg cfg/darknet19_448.conv.23
系统默认会迭代45000次batch,如果需要修改训练次数,进入cfg/yolo_voc.cfg修改max_batches的值。
6.测试
训练完成后,模型成功保存,输入命令测试一下这个模型吧:
./darknet detector test cfg/voc.data cfg/yolo-voc.cfg backup/yolo-voc_final.weights testpicture/001.jpg
darknet detector train cfg/chinese.data cfg/chinese-voc.cfg darknet53.conv.74
./darknet detector test cfg/chinese.data cfg/chinese-voc.cfg chinese_output/chinese-voc_final.weights chinese_data/Image/6420.jpg
---------------------
作者:Panda_Peng
来源:CSDN
原文:https://blog.csdn.net/qq_34484472/article/details/73135354
版权声明:本文为博主原创文章,转载请附上博文链接!
yolo v2使用总结---http://www.cnblogs.com/shepherd2015/p/8671646.html
【Darknet 】Darknet 源码理解---https://zhuanlan.zhihu.com/p/37726435
【YOLO】训练voc数据集没有框??解决方法
https://blog.csdn.net/shangpapa3/article/details/76277869
如果你想保存输出的结果,在后面加句 | tee yolo-voc.txt
./darknet detector train cfg/voc.data cfg/yolo-voc.cfg darknet19_448.conv.23 | tee yolo-voc.txt
./darknet detector test cfg/voc.data cfg/yolo-voc.2.0.cfg yolo-voc_final.weights data/dog.jpg -thresh 0.25
./darknet detector train plate_12651/plate_12651.data plate_12651/p3-voc.cfg darknet53.conv.74
###traindata.py### # -*- coding: utf-8 -*- import os; import shutil; def rename_by_count(path): #按序号命名 count = 1000; filelist = os.listdir(path) # 该文件夹下所有的文件(包括文件夹) for files in filelist: # 遍历所有文件 Olddir = os.path.join(path, files); # 原来的文件路径 if os.path.isdir(Olddir): # 如果是文件夹则跳过 continue; filename = os.path.splitext(files)[0]; # 文件名 filetype = os.path.splitext(files)[1]; # 文件扩展名 Newdir = os.path.join(path, str(count) + filetype); # 新的文件路径 os.rename(Olddir, Newdir); # 重命名 count += 1; def listname(path,idtxtpath): filelist = os.listdir(path); # 该文件夹下所有的文件(包括文件夹) f = open(idtxtpath, 'w'); for files in filelist: # 遍历所有文件 Olddir = os.path.join(path, files); # 原来的文件路径 if os.path.isdir(Olddir): # 如果是文件夹则跳过 continue; filename = os.path.splitext(files)[0]; # 文件名 filetype = os.path.splitext(files)[1]; # 文件扩展名 #Newdir = os.path.join(path, "1000" + filetype); # 新的文件路径: path+filename+type f.write(filename); f.write('\n'); f.close(); def imgid_list(imgpath, savepath, num): #rename_by_count(imgpath); path1 = savepath + "/validateImage"; path2 = savepath + "/trainImage"; if os.path.exists(path1)== False: os.mkdir(path1); if os.path.exists(path2) == False: os.mkdir(path2); xmlpath1 = savepath + "/validateImageXML"; xmlpath2 = savepath + "/trainImageXML"; if os.path.exists(xmlpath1)== False: os.mkdir(xmlpath1); if os.path.exists(xmlpath2) == False: os.mkdir(xmlpath2); filelist = os.listdir(imgpath); count = 0; for files in filelist: olddir = os.path.join(imgpath, files); newdir1 = os.path.join(path1, files); newdir2 = os.path.join(path2, files); filename = os.path.splitext(files)[0]; # 文件名 xmldir = savepath + "/xml"; xmldir1 = savepath + "/validateImageXML"; xmldir2 = savepath + "/trainImageXML"; if count<num: shutil.copy(olddir, newdir1); #validate xmlolddir = os.path.join(xmldir, filename + ".xml"); xmlnewdir = os.path.join(xmldir1,filename+".xml"); shutil.copy(xmlolddir,xmlnewdir); #shutil.copy(xmlolddir, newdir1); else: shutil.copy(olddir, newdir2); xmlolddir = os.path.join(xmldir, filename + ".xml"); xmlnewdir = os.path.join(xmldir2, filename + ".xml"); shutil.copy(xmlolddir, xmlnewdir); #shutil.copy(xmlolddir, newdir2); count=count+1; imgidtxtpath1 = savepath + "/validateImageId.txt"; imgidtxtpath2 = savepath + "/trainImageId.txt"; listname(path1, imgidtxtpath1); listname(path2, imgidtxtpath2); #rename_by_count; # 给图片按序号给名字 savepath = os.getcwd()#取得当前工作目录 imgpath = savepath+"/Image" val_num=16 #验证集数量,可修改 imgid_list(imgpath,savepath,val_num);
###trans.py import xml.etree.ElementTree as ET import pickle import string import os import shutil from os import listdir, getcwd from os.path import join sets=[('2012', 'train')] classes = ["plate"] #分类集,我这里是识别猫,所以是一个cat def convert(size, box): dw = 1./size[0] dh = 1./size[1] x = (box[0] + box[1])/2.0 y = (box[2] + box[3])/2.0 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(image_id,flag,savepath): #s = '\xef\xbb\xbf' #nPos = image_id.index(s) #if nPos >= 0: # image_id = image_id[3:] if flag == 0: in_file = open(savepath+'/trainImageXML/%s.xml' % (image_id)) labeltxt = savepath+'/trainImageLabelTxt'; if os.path.exists(labeltxt) == False: os.mkdir(labeltxt); out_file = open(savepath+'/trainImageLabelTxt/%s.txt' % (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) elif flag == 1: in_file = open(savepath+'/validateImageXML/%s.xml' % (image_id)) labeltxt = savepath + '/validateImageLabelTxt'; if os.path.exists(labeltxt) == False: os.mkdir(labeltxt); out_file = open(savepath+'/validateImageLabelTxt/%s.txt' % (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: #savepath = "/home/wurui/CAR/wrz/pillar"; savepath = os.getcwd(); idtxt = savepath + "/validateImageId.txt"; pathtxt = savepath + "/validateImagePath.txt"; image_ids = open(idtxt).read().strip().split() list_file = open(pathtxt, 'w') s = '\xef\xbb\xbf' for image_id in image_ids: nPos = image_id.find(s) if nPos >= 0: image_id = image_id[3:] list_file.write('%s/validateImage/%s.jpg\n' % (wd, image_id)) print(image_id) convert_annotation(image_id, 1, savepath) list_file.close() idtxt = savepath + "/trainImageId.txt"; pathtxt = savepath + "/trainImagePath.txt" ; image_ids = open(idtxt).read().strip().split() list_file = open(pathtxt, 'w') s = '\xef\xbb\xbf' for image_id in image_ids: nPos = image_id.find(s) if nPos >= 0: image_id = image_id[3:] list_file.write('%s/trainImage/%s.jpg\n'%(wd,image_id)) print(image_id) convert_annotation(image_id,0,savepath) list_file.close()