赞
踩
使用YOLO进行目标检测在保证速度的前提下能有较好的准确性,这篇文章是在yolov3的代码基础上进行修改为行人检测,由原来的20个分类改为识别person,使用tiny-yolo的进行训练和检测,最后能达到还不错的效果。
收集图片并标注,这是一件工作量较大的事情,所以我们直接使用了PASCAL VOC2007的数据集,抽取其中带有行人的图片。
具体过程如下:
Annotations -- Annotations文件夹中存放的是xml格式的标签文件,每一个xml文件都对应于JPEGImages文件夹中的一张图片;
ImageSets -- ImageSets存放的是每一种类型的challenge对应的图像数据。在ImageSets下有Main文件夹,存放的是图像物体识别的数据,总共分为20类;
JPEGImages -- JPEGImages文件夹中包含了PASCAL VOC所提供的所有的图片信息,包括了训练图片和测试图片。
train.txt是训练集,test.txt是测试集,val.txt是验证集,trainval.txt是训练和验证集。VOC2007中,trainval大概是整个数据集的50%,test也大概是整个数据集的50%;train大概是trainval的50%,val大概是trainval的50%,当数据集较小时,可减少val和test的数量。
使用Matlab生成这四个txt文件,make_train_data.m 代码如下:
- %注意修改下面四个值
- xmlfilepath='E:\Image Sets\VOC_person\Annotations';
- txtsavepath='E:\Image Sets\VOC_person\ImageSets\Main\';
- trainval_percent=0.8;%trainval占整个数据集的百分比,剩下部分就是test所占百分比
- train_percent=0.8;%train占trainval的百分比,剩下部分就是val所占百分比
-
- xmlfile=dir(xmlfilepath);
- numOfxml=length(xmlfile)-2;%减去.和.. 总的数据集大小
-
- trainval=sort(randperm(numOfxml,floor(numOfxml*trainval_percent)));
- test=sort(setdiff(1:numOfxml,trainval));
-
- trainvalsize=length(trainval);%trainval的大小
- train=sort(trainval(randperm(trainvalsize,floor(trainvalsize*train_percent))));
- val=sort(setdiff(trainval,train));
-
- ftrainval=fopen([txtsavepath 'trainval.txt'],'w');
- ftest=fopen([txtsavepath 'test.txt'],'w');
- ftrain=fopen([txtsavepath 'train.txt'],'w');
- fval=fopen([txtsavepath 'val.txt'],'w');
-
- for i=1:numOfxml
- if ismember(i,trainval)
- fprintf(ftrainval,'%s\n',xmlfile(i+2).name(1:end-4));
- if ismember(i,train)
- fprintf(ftrain,'%s\n',xmlfile(i+2).name(1:end-4));
- else
- fprintf(fval,'%s\n',xmlfile(i+2).name(1:end-4));
- end
- else
- fprintf(ftest,'%s\n',xmlfile(i+2).name(1:end-4));
- end
- end
- fclose(ftrainval);
- fclose(ftrain);
- fclose(fval);
- fclose(ftest);
1)打开yolo代码下的scripts目录,拷贝voc_label.py文件并重命名为person_voc_label.py 文件:
cp voc_label.py person_voc_label.py
2)修改person_voc_label.py文件:
- import xml.etree.ElementTree as ET
- import pickle
- import os
- from os import listdir, getcwd
- from os.path import join
-
- sets=['train', 'val', 'test']
-
- 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(image_id):
- in_file = open('/home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/Annotations/%s.xml'%(image_id))
- out_file = open('/home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/labels/%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 image_set in sets:
- if not os.path.exists('/home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/labels/'):
- os.makedirs('/home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/labels/')
- image_ids = open('/home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/ImageSets/Main/%s.txt'%(image_set)).read().strip().split()
- list_file = open('person_%s.txt'%(image_set), 'w')
- for image_id in image_ids:
- list_file.write('/home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/JPEGImages/%s.jpg\n'%(image_id))
- convert_annotation(image_id)
- list_file.close()
-
- os.system("cat person_train.txt person_val.txt > my_person_train.txt")
-
3)执行person_voc_label.py脚本。
发现在scripts/VOC_person目录下生成label文件夹,里面有每张图片的标注文件(文件内容形如0 0.488888888889 0.289256198347 0.977777777778 0.429752066116),其中第一个数字表示类别标签(0表示person,也即前面写的classes的顺序),后面四个数为包围框信息。
4)生成训练文件
在上一步执行了person_voc_label.py脚本后,会在 scripts下多了person_train.txt、person_val.txt和person_test.txt这三个文件,这三个文件是数据集中图片的路径。由于yolo训练只需要一个my_person_train.txt文件,文件中包含所有你想要训练的图片的路径。因此,我们还要生成my_person_train.txt文件。
cat person_train.txt person_val.txt > my_person_train.txt
到这里数据集制作算是制作完成了。
(1)在data目录下新建文件my_person_train.names,内容为:
person
(2)在cfg目录下新建 my_person_train.data文件,内容为:
- classes= 1
- train = /home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/my_person_train.txt
- valid = /home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/person_test.txt
- names = data/my_person_train.names
- backup = backup
(3)修改examples/yolo.c文件:
char *voc_names[] = {"person"};
- char *train_images = "/home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/my_person_train.txt";
- char *backup_directory = "/home/liguiyuan/deep_learning/project/darknet/backup/";
train_images应该指向我们刚得到的my_person_train.txt;backup_directory指向的路径是训练过程中生成的weights文件保存的路径(可以在darknet-master下新建文件夹backup然后指向它)。这两个路径按自己系统修改即可。
- char *base = "results/comp4_det_test_";
- //list *plist = get_paths("data/voc.2007.test");
- list *plist = get_paths("/home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/person_test.txt");
- //list *plist = get_paths("data/voc.2012.test");
- char *base = "results/comp4_det_test_";
- list *plist = get_paths("/home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/person_test.txt");
- //draw_detections(im, l.side*l.side*l.n, thresh, boxes, probs, 0, voc_names, alphabet, 20);
- draw_detections(im, l.side*l.side*l.n, thresh, boxes, probs, 0, voc_names, alphabet, 1);
类别数改为1类。
- //demo(cfg, weights, thresh, cam_index, filename, voc_names, 20, frame_skip, prefix, avg, .5, 0,0,0,0);
- demo(cfg, weights, thresh, cam_index, filename, voc_names, 1, frame_skip, prefix, avg, .5, 0,0,0,0);
类别数改为1类。
(4)修改examples/detector.c文件
list *plist = get_paths("/home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/person_test.txt");
- //int classes = option_find_int(options, "classes", 20);
- int classes = option_find_int(options, "classes", 1);
类别数改为1类
(5)修改cfg/yolov3-voc_person.cfg文件:
复制cfg/yolov3-voc.cfg文件并命名为yolov3-voc_person.cfg,如果想用其他模型修改类似。
【yolo】层中 classes 把20改成1,因为我们检测的类别只有penson,有3个地方要改;
【yolo】层的上一层【convolutional】,即网络中的最后一层卷积,的filters改为18,也是3处地方要修改。计算方法是这样:1*1*[3*(4+1+1)]=18。[num*(coords+1+classes) ,num为3,因为yolov3预测3个boxes(yolov1为1个,yolov2为5个),coords为4个坐标(预测boundingbox的 x,y,w,h), 1表示置信度,识别1个类别。N为卷积核的size。
- [convolutional]
- size=1
- stride=1
- pad=1
- filters=18
- 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
- num=9
- jitter=.3
- ignore_thresh = .5
- truth_thresh = 1
- random=1
(6)其他的一些参数可以按自己需求修改,比如batch, subdivisions等,都是在这个cfg文件里面修改。我这里把batch改为32,要不然使用GTX1060显卡训练时会出现CUDA Error: out of memory。subdivision:这个参数意思是,让你的每一个batch不是一下子都丢到网络里,而是分成多次丢到GPU内存中,例如2,就是分成2次读入。
- [net]
- # Testing
- # batch=1
- # subdivisions=1
- # Training
- batch=32
- 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
下载预训练darknet53.conv.74的weights权重文件,下载地址为:
wget https://pjreddie.com/media/files/darknet53.conv.74
开始训练模型:
./darknet detector train cfg/my_person_train.data cfg/yolov3-voc_person.cfg darknet53.conv.74
看到开始训练了:
训练中断后从断点开始训练模型:
./darknet detector train cfg/my_person_train.data cfg/yolov3-voc_person.cfg backup/yolov3-voc_person.backup
使用GTX1060的GPU,经过30多个小时的训练,训练了10000批次,在person_backup目录下看到 yolov3-voc_person_10000.weights等训练好的模型。这里附上我训练的模型链接: https://pan.baidu.com/s/1sfeEqdR-K-9q4NZFD5FdmQ 提取码: 8n8g
修改cfg/yolov3-voc_person.cfg 文件,把Training的batch, subdivisions屏蔽掉,使用Testing的batch, subdivisions 都为1
- # Training
- #batch=32
- #subdivisions=2
- # Testing
- batch=1
- subdivisions=1
检测图片:
./darknet detect cfg/yolov3-voc_person.cfg backup/yolov3-voc_person.backup data/person.jpg
摄像头实时检测:
./darknet detector demo cfg/my_person_train.data cfg/yolov3-voc_person.cfg backup/yolov3-voc_person.backup
效果图如下:
文章到这里完成了整个训练的过程。
注:转载请注明出处!
文章里部分教程参考:https://blog.csdn.net/yudiemiaomiao/article/details/71635257
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。