一.首先将自制数据集制作成voc格式
1.目标检测一般采用的标注工具为labelImg,标注过程如下所示
2.标注完成会生成与图像同名的.xml文件
3.之后按照voc数据集的格式,在文件夹目录下生成JPEGImages和Annotations文件夹,将自己的数据集图片拷贝到JPEGImages目录下。将数据集label文件拷贝到Annotations目录下。也可以自己写个脚本直接建立文件夹分类,这样比较简单。
4.然后通过编写脚本将数据集分成训练集和验证集
#coding:utf-8
import os
import random
trainval_percent = 1 #训练验证数据集的百分比
train_percent = 0.9 #训练集的百分比
filepath = './JPEGImages'
txtsavepath = './ImageSets/Main'
parent_path = os.path.abspath(txtsavepath)
if not os.path.exists(parent_path):
os.mkdir(parent_path)
total_img = os.listdir(filepath)
num=len(total_img) #列表的长度
list=range(num)
tv=int(num*trainval_percent) #训练验证集的图片个数
tr=int(tv*train_percent) #训练集的图片个数 # sample(seq, n) 从序列seq中选择n个随机且独立的元素;
trainval= random.sample(list,tv)
train=random.sample(trainval,tr)
#创建文件trainval.txt,test.txt,train.txt,val.txt
ftrain = open('./ImageSets/Main/train.txt', 'w')
fval = open('./ImageSets/Main/val.txt', 'w')
for i in list:
name=total_img[i][:-4]+'\n'
if i in train:
ftrain.write(name)
else:
fval.write(name)
ftrain.close()
fval.close()
5.运行后会自动生成相应的训练集train.txt和验证集val.txt。
6.通过运行脚本文件将数据转换成darknet支持的格式
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
#源代码sets=[('2012', 'train'), ('2012', 'val'), ('2007', 'train'), ('2007', 'val'), ('2007', 'test')]
sets=[('voc', 'train'),('voc', 'val')] # 改成自己建立的数据集
classes = ["person"] # 改成自己的类别
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('voc/Annotations/%s.xml'%(image_id)) # 源代码VOCdevkit/VOC%s/Annotations/%s.xml
out_file = open('voc/labels/%s.txt'%(image_id), 'w') # 源代码VOCdevkit/VOC%s/labels/%s.txt
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('voc/labels/'): # 改成自己建立的voc
os.makedirs('voc/labels/')
image_ids = open('voc/ImageSets/Main/%s.txt'%(image_set)).read().strip().split()
list_file = open('voc/%s_%s.txt'%(year, image_set), 'w')
for image_id in image_ids:
list_file.write('%s/voc/JPEGImages/%s.jpg\n'%(wd, image_id))
convert_annotation(year, image_id)
list_file.close()
二、配置darknet文件
1.修改cfg文件中的voc.data
classes= 3 #修改为自己的类别数
train = /home/learner/darknet/data/voc/train.txt #修改为自己的路径 or /home/learner/darknet/scripts/2007_test.txt
valid = /home/learner/darknet/data/voc/2007_test.txt #修改为自己的路径 or /home/learner/darknet/scripts/2007_test.txt
names = /home/learner/darknet/data/voc.names #修改见voc.names
backup = /home/learner/darknet/backup #修改为自己的路径,输出的权重信息将存储其内
2.修改VOC.names
person #自己需要探测的类别,一行一个
3.下载预训练卷积层权重:darknet53.conv.74模型地址
4.选择anchor,由于每个数据集中的目标尺寸并不同,有的主要是大目标,有的主要是小目标,有的则是中等目标居多,故对于每一个数据集,其anchor尺寸都需要重新聚类;可以用命令行参数calc_anchors直接计算anchor了
./darknet detector calc_anchors data文件 -num_of_clusters 需要几组框 -width 宽度 -height 高度 -show
需要注意2点:
(1)yolo(v2/v3)和tiny-yolo(v2/v3)的anchor默认数目不同:tiny的6组,yolo的9组 (当然也可以根据你自己的需要改)
(2)yolov2和yolov3,anchor的值意义不一样(这个通过GITHUB上的issues来看, 算是由于darknet作者设计失误造成的)
yolov2的anchor是相对于最后一层特征图(feature map)的, 而yolov3则是相对于输入图片的,比如320*224的图片, 具体命令如下所示:
yolov3使用如下命令:
./darknet detector calc_anchors cfg/voc_dog.data -num_of_clusters 9 -width 320 -height 224 -show
而yolov2使用如下命令:
./darknet detector calc_anchors cfg/voc_dog.data -num_of_clusters 9 -width 10 -height 7 -show
具体运行结果如下所示:
5.修改cfg文件中的参数
[net]
#Testing
batch=64
subdivisions=32 #每批训练的个数=batch/subvisions,根据自己GPU显存进行修改,显存不够改大一些
#Training
#batch=64
#subdivisions=16
width=416
height=416
channels=3
momentum=0.9
decay=0.0005
angle=0
saturation = 1.5
exposure = 1.5
hue=.1
learning_rate=0.001
burn_in=1000
max_batches = 50200 #训练步数
policy=steps
steps=40000,45000 #开始衰减的步数
scales=.1,.1
..................
[convolutional]
size=1
stride=1
pad=1
filters=36 #filters = anchor_num * ( classes + 5 ) here,filters=6*(1+5)
activation=linear
[yolo]
mask =3,4,5, 6,7,8#选择每一层anchor时遵循最大特征图即52x52时,anchor应该大于60x60,26x26时,anchor应该大于30x30而小于60x60,13x13时,anchor应该小于30x30.
anchors = 21, 27, 62, 38, 41, 78, 99, 78, 75,140, 204, 75, 141,160, 255,127, 266,200
classes=1 #修改为自己的类别数
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=1
三、训练自己的模型
1 单GPU训练:
./darknet -i <gpu_id> detector train <data_cfg> <train_cfg> <weights>
./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg darknet53.conv.74 -map#加上map会在loss图上出现mAP的值
2 多GPU训练,格式为0,1,2,3:
./darknet detector train <data_cfg> <model_cfg> <weights> -gpus <gpu_list>
./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg darknet53.conv.74 -gpus 0,1,2,3
# 从某个权重快照继续训练
./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg models/yolov3_voc_150000.weights -gpus 0,1,2,3
具体训练过程如下所示:
这里由于只是演示,所以只训练了几百步,但是可以明显看到起loss值下降很快
四、测试Yolo模型
1、测试单张图片:
测试单张图片,需要编译时有OpenCV支持:
./darknet detector test <data_cfg> <test_cfg> <weights> <image_file> #本次测试无opencv支持
<test_cfg>文件中batch和subdivisions两项必须为1。
测试时还可以用-thresh和-hier选项指定对应参数。
./darknet detector test cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc_20000.weights Eminem.jpg
运行过程如下所示
2.测试视频
./darknet detector demo ./cfg/voc.data ./cfg/yolov3-voc.cfg backup/yolov3.weights test.mp4
3.测试Valid
./darknet detector valid cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3.weights -out valid_ -gpu 0 -thresh .5
需要在darknet可执行文件夹下建立voc或results文件夹用来保存数据
4.计算mAP值
./darknet.exe detector map cfg/voc.data cfg/yolov3-voc.cfg backup/yolo-voc.weights -points 11
由于只训练了几百步,所以mAP值很低,正常30000步左右的voc数据集mAP可以达到73%左右
4.计算每幅图像的recall
./darknet detector recall cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3.weights -out recall.txt -gpu 0 -thresh .5
五、使用tiny模型训练
1.获取tiny预训练模型
./darknet.exe partial cfg/yolov3-tiny.cfg darknet53.conv.74 yolov3-tiny.conv.15 15
通过darknet53.conv.74可以获取tiny预训练模型,其实主要网络结构还是由yolov3-tiny.cfg来决定其层数
后面训练测试过程与上面相同,这里不再赘述。