当前位置:   article > 正文

使用YOLOv3 训练行人检测模型_yolo行人检测

yolo行人检测

使用YOLO进行目标检测在保证速度的前提下能有较好的准确性,这篇文章是在yolov3的代码基础上进行修改为行人检测,由原来的20个分类改为识别person,使用tiny-yolo的进行训练和检测,最后能达到还不错的效果。

1.数据集制作

收集图片并标注,这是一件工作量较大的事情,所以我们直接使用了PASCAL VOC2007的数据集,抽取其中带有行人的图片。

具体过程如下:

1.1 创建相应的文件夹

  • 在yolo代码里的scripts/目录下创建VOC_person文件夹,在其文件夹下创建Annotations、ImageSets、JPEGImages文件夹,在ImageSets文件夹下建立Main文件夹。这里顺便说下这三个文件夹的作用:

Annotations -- Annotations文件夹中存放的是xml格式的标签文件,每一个xml文件都对应于JPEGImages文件夹中的一张图片;

ImageSets -- ImageSets存放的是每一种类型的challenge对应的图像数据。在ImageSets下有Main文件夹,存放的是图像物体识别的数据,总共分为20类;

JPEGImages -- JPEGImages文件夹中包含了PASCAL VOC所提供的所有的图片信息,包括了训练图片和测试图片。

1.2 拷贝相应的文件

  • 提取VOC2007/ImageSets/Main/文件夹里的person_test.txt,person_trainval.txt,person_train.txt  person_val.txt 这四个文件到VOC_person/ImageSets/Main/目录下;
  • 拷贝VOC2007/Annotations/ 目录下的所有的文件到VOC_person/Annotations/ 目录下;
  • 拷贝VOC2007/JPEGImages/ 目录下的所有的文件到VOC_person/JPEGImages/ 目录下;

1.3 生成训练集,测试集和开发集文件

  • 我们需要生成VOC_person/ImageSets/Main/目录下的test.txt,train.txt,trainval.txt,val.txt 这四个文件。

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 代码如下:

  1. %注意修改下面四个值
  2. xmlfilepath='E:\Image Sets\VOC_person\Annotations';
  3. txtsavepath='E:\Image Sets\VOC_person\ImageSets\Main\';
  4. trainval_percent=0.8;%trainval占整个数据集的百分比,剩下部分就是test所占百分比
  5. train_percent=0.8;%train占trainval的百分比,剩下部分就是val所占百分比
  6. xmlfile=dir(xmlfilepath);
  7. numOfxml=length(xmlfile)-2;%减去.和.. 总的数据集大小
  8. trainval=sort(randperm(numOfxml,floor(numOfxml*trainval_percent)));
  9. test=sort(setdiff(1:numOfxml,trainval));
  10. trainvalsize=length(trainval);%trainval的大小
  11. train=sort(trainval(randperm(trainvalsize,floor(trainvalsize*train_percent))));
  12. val=sort(setdiff(trainval,train));
  13. ftrainval=fopen([txtsavepath 'trainval.txt'],'w');
  14. ftest=fopen([txtsavepath 'test.txt'],'w');
  15. ftrain=fopen([txtsavepath 'train.txt'],'w');
  16. fval=fopen([txtsavepath 'val.txt'],'w');
  17. for i=1:numOfxml
  18. if ismember(i,trainval)
  19. fprintf(ftrainval,'%s\n',xmlfile(i+2).name(1:end-4));
  20. if ismember(i,train)
  21. fprintf(ftrain,'%s\n',xmlfile(i+2).name(1:end-4));
  22. else
  23. fprintf(fval,'%s\n',xmlfile(i+2).name(1:end-4));
  24. end
  25. else
  26. fprintf(ftest,'%s\n',xmlfile(i+2).name(1:end-4));
  27. end
  28. end
  29. fclose(ftrainval);
  30. fclose(ftrain);
  31. fclose(fval);
  32. fclose(ftest);
  • 将数据转换成YOLO训练所需的标注各色,并生成训练/验证/测试图片路径文件

1)打开yolo代码下的scripts目录,拷贝voc_label.py文件并重命名为person_voc_label.py 文件:

cp voc_label.py person_voc_label.py

2)修改person_voc_label.py文件:

  1. import xml.etree.ElementTree as ET
  2. import pickle
  3. import os
  4. from os import listdir, getcwd
  5. from os.path import join
  6. sets=['train', 'val', 'test']
  7. classes = ["person"]
  8. def convert(size, box):
  9. dw = 1./(size[0])
  10. dh = 1./(size[1])
  11. x = (box[0] + box[1])/2.0 - 1
  12. y = (box[2] + box[3])/2.0 - 1
  13. w = box[1] - box[0]
  14. h = box[3] - box[2]
  15. x = x*dw
  16. w = w*dw
  17. y = y*dh
  18. h = h*dh
  19. return (x,y,w,h)
  20. def convert_annotation(image_id):
  21. in_file = open('/home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/Annotations/%s.xml'%(image_id))
  22. out_file = open('/home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/labels/%s.txt'%(image_id), 'w')
  23. tree=ET.parse(in_file)
  24. root = tree.getroot()
  25. size = root.find('size')
  26. w = int(size.find('width').text)
  27. h = int(size.find('height').text)
  28. for obj in root.iter('object'):
  29. difficult = obj.find('difficult').text
  30. cls = obj.find('name').text
  31. if cls not in classes or int(difficult)==1:
  32. continue
  33. cls_id = classes.index(cls)
  34. xmlbox = obj.find('bndbox')
  35. b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text))
  36. bb = convert((w,h), b)
  37. out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
  38. wd = getcwd()
  39. for image_set in sets:
  40. if not os.path.exists('/home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/labels/'):
  41. os.makedirs('/home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/labels/')
  42. image_ids = open('/home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/ImageSets/Main/%s.txt'%(image_set)).read().strip().split()
  43. list_file = open('person_%s.txt'%(image_set), 'w')
  44. for image_id in image_ids:
  45. list_file.write('/home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/JPEGImages/%s.jpg\n'%(image_id))
  46. convert_annotation(image_id)
  47. list_file.close()
  48. 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

到这里数据集制作算是制作完成了。

 

2.修改代码训练

(1)在data目录下新建文件my_person_train.names,内容为:

person

(2)在cfg目录下新建 my_person_train.data文件,内容为:

  1. classes= 1
  2. train = /home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/my_person_train.txt
  3. valid = /home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/person_test.txt
  4. names = data/my_person_train.names
  5. backup = backup

(3)修改examples/yolo.c文件:

  • 检测目标类别改成自己的数据集类别:
char *voc_names[] = {"person"};
  • train_yolo函数:
  1. char *train_images = "/home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/my_person_train.txt";
  2. char *backup_directory = "/home/liguiyuan/deep_learning/project/darknet/backup/";

train_images应该指向我们刚得到的my_person_train.txt;backup_directory指向的路径是训练过程中生成的weights文件保存的路径(可以在darknet-master下新建文件夹backup然后指向它)。这两个路径按自己系统修改即可。

  • validate_yolo函数:
  1. char *base = "results/comp4_det_test_";
  2. //list *plist = get_paths("data/voc.2007.test");
  3. list *plist = get_paths("/home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/person_test.txt");
  4. //list *plist = get_paths("data/voc.2012.test");
  • validate_yolo_recall函数:
  1. char *base = "results/comp4_det_test_";
  2. list *plist = get_paths("/home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/person_test.txt");
  • test_yolo函数:
  1. //draw_detections(im, l.side*l.side*l.n, thresh, boxes, probs, 0, voc_names, alphabet, 20);
  2. draw_detections(im, l.side*l.side*l.n, thresh, boxes, probs, 0, voc_names, alphabet, 1);

类别数改为1类。

  • run_yolo函数:
  1. //demo(cfg, weights, thresh, cam_index, filename, voc_names, 20, frame_skip, prefix, avg, .5, 0,0,0,0);
  2. demo(cfg, weights, thresh, cam_index, filename, voc_names, 1, frame_skip, prefix, avg, .5, 0,0,0,0);

类别数改为1类。

(4)修改examples/detector.c文件

  • validate_detector_recall函数:
list *plist = get_paths("/home/liguiyuan/deep_learning/project/darknet/scripts/VOC_person/person_test.txt");
  • run_detector函数:
  1. //int classes = option_find_int(options, "classes", 20);
  2. 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。

  1. [convolutional]
  2. size=1
  3. stride=1
  4. pad=1
  5. filters=18
  6. activation=linear
  7. [yolo]
  8. mask = 3,4,5
  9. anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326
  10. classes=1
  11. num=9
  12. jitter=.3
  13. ignore_thresh = .5
  14. truth_thresh = 1
  15. random=1

(6)其他的一些参数可以按自己需求修改,比如batch, subdivisions等,都是在这个cfg文件里面修改。我这里把batch改为32,要不然使用GTX1060显卡训练时会出现CUDA Error: out of memory。subdivision:这个参数意思是,让你的每一个batch不是一下子都丢到网络里,而是分成多次丢到GPU内存中,例如2,就是分成2次读入。

  1. [net]
  2. # Testing
  3. # batch=1
  4. # subdivisions=1
  5. # Training
  6. batch=32
  7. subdivisions=16
  8. width=416
  9. height=416
  10. channels=3
  11. momentum=0.9
  12. decay=0.0005
  13. angle=0
  14. saturation = 1.5
  15. exposure = 1.5
  16. hue=.1
  17. learning_rate=0.001
  18. burn_in=1000
  19. max_batches = 50200
  20. policy=steps
  21. steps=40000,45000
  22. scales=.1,.1

 

3.训练模型

下载预训练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 

 

4.检测模型的结果

修改cfg/yolov3-voc_person.cfg 文件,把Training的batch, subdivisions屏蔽掉,使用Testing的batch, subdivisions 都为1

  1. # Training
  2. #batch=32
  3. #subdivisions=2
  4. # Testing
  5. batch=1
  6. 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

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/73162
推荐阅读
  

闽ICP备14008679号