【目标检测实战】Darknet—yolov3模型训练(VOC数据集)

19.jpg

0.前言

本文为Darknet框架下,利用官方VOC数据集的yolov3模型训练,训练环境为: Ubuntu18.04下的GPU训练,cuda版本10.0;cudnn版本7.6.5。经过一晚上的训练,模型20个类别的mAP达到74%+。

主要模块:

  • 概述
  • 源码编译
  • 功能测试
  • 模型训练
  • 模型验证

【概述】部分主要介绍yolo系列模型和darknet框架的关系、资源网站和数据集下载
【源码编译】主要是用官方源码和make命令编译出Linux下可执行文件,包括cuda+cudnn的设置
【功能测试】主要是用官网给出的demo和与训练模型来进行图片测试
【模型训练】主要是用darknet+yolov3模型训练VOC图像数据集(VOC2007+VOC2012)
【模型验证】即用训练好的模型,检测模型训练效果.

1.概述

官网:https://pjreddie.com/

1.1 Yolo

Yolo系列模型(v1~v3)在近年些来的目标检测领域,非常火热!Yolo为:You only look once的缩写,同时也表明了其特点,只需要一次即可完成从图像分割到检测,故其被称为one-stage系列模型的鼻祖。

two-stage类目标检测模型如Fast R-CNN、Faster R-CNN

屏幕截图_1.png

1.2 Darknet

yolo系列就是深度学习领域中用于目标检测的模型(yolov1~v3),那么darknet是什么?两者关系如何?
darknet是作者用c和cuda编写的用于深度学习模型训练的框架,支持CPU和GPU训练,是个非常简单轻量级框架,就和Tensorflow,Mxnet,Pytorch,Caffe一样,虽然功能没有它们多,不过小也有小的优势,如果你会c语言,可以对其进行充分地利用和改造,或者读读源码看一下其实现,也会收货满满!
So,总结一下:Darknet是深度学习框架,yolov1~v3是yolo系列的目标检测模型

1.3 资源下载

官网

https://pjreddie.com/

源码

Darknet源码:
https://github.com/pjreddie/darknet

Darknet是用纯c和cuda编写的,要想用darknet来训练模型,最好用Linux/Unix系统,官方也提供了python的接口,如果是Windows系统,可以利用网友开源实现:https://github.com/AlexeyAB/darknet

可以直接下载zip包📎darknet-master.zip也可直接执行
git clonehttps://github.com/pjreddie/darknet将源码下载到本地

权重文件

yolov3-tiny.weights
yolov2.weights
yolov3.weights
darknet53.conv.74

VOC数据集

VOCtrainval_11-May-2012.tar
VOCtrainval_06-Nov-2007.tar
VOCtest_06-Nov-2007.tar

其他:

YOLO-V3可视化训练过程中的参数,绘制loss、IOU、avg Recall等的曲线图:https://blog.csdn.net/qq_34806812/article/details/81459982
AlexyAB大神总结的优化经验:
https://www.cnblogs.com/pprp/p/10204480.html

2.源码编译

2.1 编辑Makefile

指定是否使用GPU

在执行make指令编译之前,需要编辑一下makefile,来指定是否需要用GPU(cuda),如果用cuda,是否需要用cudnn加速;是否需要用opencv等。我这里是用GPU且需要用CUDNN加速的,不使用OpenCV。

Makefile的前5行如下,这5项内容0表示不启用,1表示启用,可根据需求自己配置。

  • GPU 是否启用GPU1
  • CUDNN 是否启用CUDNN加速,若GPU = 1则CUDNN可选1或0;GPU=0则CUDNN=0
  • OPENCV 是否启用OpenCV,启用的话需先编译安装好,启用可支持对视频和图像流文件处理
  • OPENMP 是否启动多核CPU来加速Yolo,如果是用CPU训练,建议开启=1
  • DEBUG 表示编译的Yolo版本为是否为DEBUG版

屏幕截图_14.png

如果不使用GPU则GPU=0,CUDNN=0;还有一点需注意,如果在shell执行nvcc找不到命令(没有添加到环境变量),则需要将nvcc命令的全路径写出来

指定cuda的路径

如果不使用GPU,则此步可忽略,如果使用GPU,则需要指定cuda路径。官方的Makefile默认的cuda路径为:/usr/local/cuda,如果你装了多个cuda,但是有软连接指向正确的cuda文件夹路径:即/usr/local/cuda软连接到你需要的cuda文件夹,那么无需修改,保持/usr/local/cuda即可;否则需要指定你的cuda路径,这里需要改两处:51行的COMMON和53行的LDFAGS。

屏幕截图_15.png

2.2 执行make

屏幕截图_16.png

执行make编译完成后,在项目主目录下生成可执行的darknet文件。然后我们就可以用这个可执行文件来进行模型训练和测试了!

3.功能测试

将下载好的权重文件放入主目录下,然后cd到该目录下执行:

./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg

如果你看到如下输出,且在主目录下找到一张predictions.jpg的图片,则执行成功,表明上一步骤中编译的darknet可以正常使用。

屏幕截图_17.png

你也可以指定一个阈值,yolo默认输出置信度>0.25的预测框,你也可以自行指定:

./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg -thresh 0.45

-thresh 0.45表示:置信度低于45%的预测框都不会被输出。

除了使用经典的yolov3模型外,你还可以换一个模型尝试,譬如yolov3-tiny.weights

./darknet detect cfg/yolov3-tiny.cfg yolov3-tiny.weights data/dog.jpg

当然,也可以通过连接摄像头实现实时视频画面预测。(需要编译时添加opencv)

./darknet detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights <video file>

4.模型训练

4.1 数据准备

模型训练前首先准备数据集,我们用VOC数据集,将VOC数据集解压,解压后共同存放在VOCevkit文件夹中,我将VOCevkit放在了darknet主文件夹/data/VOC/下。

cd到/VOC目录下,下载📎voc_label.py ,并运行:

python voc_label.py

可以将该脚本复制到/scripts下留作备份

文件夹下会生成7个.txt文件:

屏幕截图_17.png

如果你的voc_label.py脚本是从官网wget https://pjreddie.com/media/files/voc_label.py下载的,则需要在脚本57行处额外加上如下两行内容:

os.system("cat 2007_train.txt 2007_val.txt 2012_train.txt 2012_val.txt > train.txt") os.system("cat 2007_train.txt 2007_val.txt 2007_test.txt 2012_train.txt 2012_val.txt > train.all.txt")

目的:将2007年的训练和验证图像+2012年的图像都放入了train.txt用于集中训练

4.2 修改配置文件voc.data

配置cfg/voc.data,来确定你需要检测的目标类别数量和名称;修改train和valid的图片资源路径。训练资源指向train.txt测试/验证资源指向2007_test.txt

屏幕截图_23.png

VOC数据集默认的类别数量为20个,名称在data/voc.names中:

屏幕截图_19.png

我这里使用默认的20个类别,所以无需修改;如果,你只想检测其中的几个类别,譬如person和car,那么可以设置voc.data中classes=2,names只保留person和car这两种,不过后面相应的需要更改yolov3-voc.cfg里的卷积层配置等。

4.3 修改yolov3-voc.cfg

yolov3-voc.cfg文件定义了yolo的卷积神经网络模型,和超参数配置等。这里需要注意,训练时需要将#Testing区块下的batch和subvisions注释掉;测试和验证时则放开注释,同时注释掉#Training区块下的内容。

训练时,可以根据自己GPU的内存来设置批的大小batch,可设为16、32、64、128
验证时,batch和subvisions同时设为1即可。

屏幕截图_22.png

4.4 开始训练

cd回项目主目录,将darknet53.conv.74权重放入主目录下,运行:

./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg darknet53.conv.74

如果报错提示cuda内存溢出,可以降低batch,再次运行;运行过程中可以通过nvidia-smi查看显存占用情况:

屏幕截图_24.png

训练过程中会持续往backup/下生成权重文件,如:yolov3-voc_100.weights、yolov3-voc_200.weights....

5.模型验证

检验生成的模型权重文件、测试准确率和map等指标。验证前需要将yolov3-voc.cfg中的batch和subdivisions都改成1。然后找到需要测试的权重文件,默认权重文件保存在:项目目录/bakcup/下,我选择这个yolov3-voc_10000.weights,训练大约一个晚上12小时左右,loss在0.6多。

屏幕截图.png

5.1 测试

测试一

我们从VOC数据集中随便找一找图片来测试一下,这里我选取000275.jpg放入主目录下

000275.jpg

运行:

./darknet detector test cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc_10000.weights 000275.jpg

屏幕截图_1.png

运行结束会在控制台打印出标注出的目标类别以及置信度、同时会在目录下生成一张标注图片:predictions.jpg

predictions.jpg

测试二

再随便找一张图片试试

>./darknet detector test cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc_10000.weights data/person.jpg

屏幕截图_2.png
predictions.jpg

5.2 验证

测试只能一张张地直观感受下模型的训练效果,看看标注出的目标是否正确,通过验证才能确定模型的整体训练效果,验证时会用模型对所有的4952张测试集图片进行预测,同时与正确结果进行比对,得出一个模型预测准确率。

验证测试集

可以运行以下脚本进行验证:

./darknet detector valid cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc_10000.weights
验证完会在results文件夹下生成20个类别的验证结果txt文件

屏幕截图_3.png

默认的文件命名规则是:'comp4_det_test_' + '类别名称' + .txt,如bird类生成comp4_det_test_bird.txt文件。

屏幕截图_4.png

如图,第一列000053表示图像编号;第二列为置信度;后4列为检测出的目标框坐标

计算map

计算map,我们需要两个python文件:

  • voc_eval.py
  • compute_mAP.py

其中voc_eval.py是github上开源项目的代码voc_eval.py;compute_mAP.py需要我们自己编写


voc_eval.py
我们为了适配darknet中voc数据集的验证,需要对源码做几处修改:
a.源码第9行:import cPickle 改为:

import _pickle as cPickle

因为源码是python2.x版本,如果python3.x版本的运行会报错,故需要修改。

b.源码103行: imagenames ``=`` [x.strip() ``for`` x ``in`` lines]改为:

imagenames = [x.strip().split('/')[-1].split('.')[0] for x in lines]

这个主要是为了方便适配2007_test.txt,因为我们验证时采用的是2007_test.txt中的测试集图片,文件中存放的是图片的全路径,而imagenames需要用的是文件名、所以需要将全路径做个转换,截取到文件名。

c.115行:with`` ``open``(cachefile, ``'w'``) ``as`` f:和 119行with`` ``open``(cachefile, ``'r'``) ``as f:改成:

with open(cachefile, 'wb') as f:
with open(cachefile, 'rb') as f:

如果不修改成‘wb’和‘rb’存储二进制格式,运行时会报错

compute_mAP.py
新建compute_mAP.py文件,用于调用voc_eval.py,内容如下:

from voc_eval import voc_eval
import os
map_ = 0
# classnames填写训练模型时定义的类别名称
classnames = ['aeroplane','bicycle','bird','boat','bottle','bus','car','cat','chair','cow','diningtable','dog','horse','motorbike','person','pottedplant','sheep','sofa','train','tvmonitor']
for classname in classnames:
    ap = voc_eval('../results/{}.txt', '../data/VOC/VOCdevkit/VOC2007/Annotations/{}.xml', '../data/VOC/2007_test.txt', classname, '.')
    map_ += ap
    #print ('%-20s' % (classname + '_ap:')+'%s' % ap)
    print ('%s' % (classname + '_ap:')+'%s' % ap)
# 删除临时的dump文件
if(os.path.exists("annots.pkl")):
    os.remove("annots.pkl")
    print("cache file:annots.pkl has been removed!")
# 打印map
map = map_/len(classnames)
#print ('%-20s' % 'map:' + '%s' % map)
print ('map:%s' % map)

我这里在项目主目录下新建了一个【yolo-compute-util】文件夹,将两个.py文件放在文件夹中,cd /yolo-compute-util,然后运行:python compute_mAP.py即可根据results中的验证结果统计出各个类别的ap,以及汇总的map。

屏幕截图_5.png

可以看见,经过1晚上的训练,我们的模型——yolov3-voc_10000.weights的mAP是0.740,虽然没有达到yolov2系列76.8+的水平,不过一晚上的训练能达到如此程度,也是挺高了。

屏幕截图_6.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容