YoLov3训练自己的数据集
工具:labelimg、MobaXterm
1.标注自己的数据集。用labelimg进行标注,保存后会生成与所标注图片文件名相同的xml文件,如图。我们标注的是井盖和路边栏,名称分了NoManholeCover、ManholeCover、WarningStick共3类标签名
2.下载yolov3项目工程。按照YoLo官网下载
- git clone https://github.com/pjreddie/darknet
- cd darknet
- make
3.修改Makefile文件(文件就在下载的darknet文件夹内)
vi Makefile #打开文件
- GPU=1#使用GPU训练,其他的没有用,所以没有置为1,可根据自己的需要调整
- CUDNN=0
- OPENCV=0
- OPENMP=0
- DEBUG=0
make #保存并退出后,进行make才可生效,如果出现错误,自行百度。
3.准备数据集。在darknet/scripts文件夹下创建文件夹VOCdevkit(因为scripts文件夹下有voc_label.py文件,它的作用下面会说,下面创建的文件也跟它有关),根据下图在VOCdevkit文件夹下创建文件,并放入相应的数据
- VOCdevkit
- ——VOC2007 #文件夹的年份可以自己取,但是要与你其他文件年份一致,看下一步就明白了
- ————Annotations #放入所有的xml文件
- ————ImageSets
- ——————Main #放入train.txt,val.txt文件
- ————JPEGImages #放入所有的图片文件
- Main中的文件分别表示test.txt是测试集,train.txt是训练集,val.txt是验证集,trainval.txt是训练和验证集,反正我只建了两个
注意:Linux环境下Annotations和IPEGImages中的文件权限一定是-rw-r--r--,不然会影响模型准确率!!!
其中Main中的txt文件是要写文件名,比如train.txt里写的是用来训练的图片的文件名(不包含后缀,只是文件名哦!!!),这个文件可以找代码生成(下面的python代码可以用),代码的话看懂他的作用,特别的文件的路径之类的,根据自己的情况修改下,就可以用
import os
import random
train_percent = 0.50
xmlfilepath = 'Annotations'
txtsavepath = 'ImageSets\Main'
total_xml = os.listdir(xmlfilepath)
num=len(total_xml)
list=range(num)
tr=int(num*train_percent)
train=random.sample(list,tr)
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 train:
ftrain.write(name)
else:
fval.write(name)
ftrain.close()
fval.close()
print ("finished")
5.修改voc_label.py,这个文件就是根据Main中txt里的文件名,生成相应的txt,里面存放的是它们的路径
- sets=[('2007', 'train'), ('2007', 'val')] #这里要与Main中的txt文件一致
- classes = ["ManholeCover","NoManholeCover","WarningStick"] #你所标注的表签名,第一步中已经说过
- #os.system("cat 2007_train.txt 2007_val.txt > train.txt") #文件最后一句,意思是要将生成的文件合并,所以很据需要修改,这里的年份都是一致的,简单理解下代码应该会懂,不要盲目修改
python voc_label.py #保存后运行
运行后会生成2007_train.txt、2007_val.txt如图
6.下载Imagenet上预先训练的权重,放到scripts目录下
wget https://pjreddie.com/media/files/darknet53.conv.74
7.修改cfg/voc.data,重命名为voc-cover.data
- classes= 3#classes为训练样本集的类别总数,第一步中说了我分了5类标签
- train = /darknet/scripts/2007_train.txt #train的路径为训练样本集所在的路径,上一步中生成
- valid = /darknet/scripts/2007_val.txt #valid的路径为验证样本集所在的路径,上一步中生成
- names = data/voc-cover.names #names的路径为data/voc-cover.names文件所在的路径
- backup = backup
8.修改data/voc.names,重命名为voc-cover.names
- NoManholeCover
- ManholeCover
- WarningStick
- #修改为自己样本集的标签名即第一步中标注的标签名
9.修改cfg/yolov3-voc-cover.cfg
- [net]
- # Testing
- # batch=1 #这里的batch跟subdivisions原来不是注释掉的,但是训练后没成功,有的blog上说为1的时候太小难以收敛,但是不知道下面训练模式的 batch=64 subdivisions=8 会不会覆盖掉,总之注释掉后就成功了,不过这个脚本不是很明白,还来不及验证
- # subdivisions=1
- # Training
- batch=64
- subdivisions=8
- ......
- [convolutional]
- size=1
- stride=1
- pad=1
- filters=24#---------------修改为3*(classes+5)即3*(3+5)=24
- 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=3#---------------修改为标签类别个数,5类
- num=9
- jitter=.3
- ignore_thresh = .5
- truth_thresh = 1
- random=0#1,如果显存很小,将random设置为0,关闭多尺度训练;(转自别的blog,还不太明白)
- ......
- [convolutional]
- size=1
- stride=1
- pad=1
- filters=24#---------------修改同上
- 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=3#---------------修改同上
- num=9
- jitter=.3
- ignore_thresh = .5
- truth_thresh = 1
- random=0
- ......
- [convolutional]
- size=1
- stride=1
- pad=1
- filters=24#---------------修改同上
- 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=3#---------------修改同上
- num=9
- jitter=.3
- ignore_thresh = .5
- truth_thresh = 1
- random=1
10.开始训练
- ./darknet detector train cfg/voc-cover.data cfg/yolov3-voc-cover.cfg scripts/darknet53.conv.74 -gpus 0,1
- #注意文件路径
- 训练默认的是前1000轮每100轮保存一次模型,1000轮后每10000轮保存一次模型。可以修改examples/detector.c文件的138行。修改完重新编译一下,在darknet目录下执行make。
11.测试识别。训练后会在backup文件夹下生成权重文件,利用生成的权重文件进行测试
./darknet detector test cfg/voc-cover.data cfg/yolov3-voc-cover.cfg backup/yolov3-voc_600.weights data/210.jpg
以上对于一些文件的理解也是多次失败的收获,可能并不全对,有误请指正,遇到问题也可以交流。
DarkNet的Python接口:
注意使用Python测试的时候必须要有GPU和安装好cuda驱动,因为作者提供的Python的接口只有GPU调用函数
作者给出的使用的Demo为:
```python
# Stupid python path shit.
# Instead just add darknet.py to somewhere in your python path
# OK actually that might not be a great idea, idk, work in progress
# Use at your own risk. or don't, i don't care
import sys, os
sys.path.append(os.path.join(os.getcwd(),'python/'))
import darknet as dn
import pdb
dn.set_gpu(0)
net = dn.load_net("cfg/yolo-thor.cfg", "/home/pjreddie/backup/yolo-thor_final.weights", 0)
meta = dn.load_meta("cfg/thor.data")
r = dn.detect(net, meta, "data/bedroom.jpg")
print r
# And then down here you could detect a lot more images like:
r = dn.detect(net, meta, "data/eagle.jpg")
print r
r = dn.detect(net, meta, "data/giraffe.jpg")
print r
r = dn.detect(net, meta, "data/horses.jpg")
print r
r = dn.detect(net, meta, "data/person.jpg")
print r
```
我们不难看出除了系统模块之外,只调用了darknet.py模块,存放在工程的python目录里。
但darknet.py中有一些路径是软地址要改一下(在47行中,仿照着注释的格式):
```python
#lib = CDLL("/home/lishukang/darknet/libdarknet.so", RTLD_GLOBAL)
lib = CDLL("libdarknet.so", RTLD_GLOBAL)
```
但这个模块是基于Python2编写,如果直接使用Python2运行的话还会有一些包存在路径问题,哪我们不如将他稍微修改一下:
在154行,即最后一行中,print需要加上括号
```python
print (r)
```
这样,我们在工程目录下进行模块导入就没有任何问题了。
我们仿照着把配置文件路径和要测试的图片地址改好就可以了。比如我的:
```python
In [10]: dn = set_gpu(0)
...: net = dn.load_net("cfg/yolov3.cfg", "/home/lishukang/darknet/backup/yolov3_400.weights", 0)
...: meta = dn.load_meta("cfg/number.data")
...: r = dn.detect(net, meta, "zhebing/pic/20171105_636454947681503257_P.jpg")
...: print (r)
```
就可以显示出测试图像啦。