YOLOv3是目标检测任务中最常用的算法之一,本文具体讲述了YOLOv3搭建——训练——测试——评估的几个步骤,顺便记录了遇到的几个坑。我用的是Ubuntu版本Darknet框架的YOLOv3,参考作者的步骤( https://pjreddie.com/darknet/yolo/)来一步步完成的,后面为了项目部署会继续学Tensorflow框架的。
基本配置
Ubuntu18.04
cuda9.0
cudnn7.3.1
opencv3.2.0
环境搭建
cuda和cudnn的配置相关具体的博文有很多,不需要过多赘述,推荐这篇博客写的比较详细(https://blog.csdn.net/weixin_41851439/article/details/88712465),一定注意Ubuntu系统与cuda、cudnn三者之间的对应关系,装cuda和cudnn是因为下面调用GPU进行训练和测试,用CPU和GPU的速度天差地别,如果显存太差建议用CPU慢慢跑。
主目录下
git clone https://github.com/pjreddie/darknet
cd darknet
make
下载预训练权重,若下载太慢则复制链接(https://pjreddie.com/media/files/yolov3.weights)到浏览器下载。
wget https://pjreddie.com/media/files/yolov3.weights
下面测试一下!
./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg
将会见到以下输出
layer filters size input output
0 conv 32 3 x 3 / 1 416 x 416 x 3 -> 416 x 416 x 32 0.299 BFLOPs
1 conv 64 3 x 3 / 2 416 x 416 x 32 -> 208 x 208 x 64 1.595 BFLOPs
.......
105 conv 255 1 x 1 / 1 52 x 52 x 256 -> 52 x 52 x 255 0.353 BFLOPs
106 detection
truth_thresh: Using default '1.000000'
Loading weights from yolov3.weights...Done!
data/dog.jpg: Predicted in 0.029329 seconds.
dog: 99%
truck: 93%
bicycle: 99%
因为还没有调用GPU,用CPU进行测试的时候会几秒到十几秒的时间,下面调用一下GPU,减少训练测试时间,修改Makefile文件
终端输入命令
gedit Makefile
修改如下
GPU=1
CUDNN=1
OPENCV=1 # 如果安装了opencv则改为1
OPENMP=0
DEBUG=0
...
NVCC=/usr/local/cuda-9.0/bin/nvcc # 原为 NVCC = nvcc,cuda后面的紧跟自己的cuda版本,如cuda-9.0,cuda-10.0等
修改完后终端重新make后重新测试
如果见到下面的情况,不要慌,有两种可能:
1.显存不够,深度学习对显卡的显存要求较高,一般至少需要4G的显存,检查一下自己显卡对应的显存,如果显存不够建议换个好一点的显卡或者租服务器,深度学习最不能省钱的就是显卡了!!!
2.cfg文件没有修改,cfg文件夹下的yolov3.cfg文件做以下修改,如果是训练状态,取消Training下面batch和subdivisions的注释,把Testing的batch和subdivisions注释掉
# Testing
batch=1
subdivisions=1
# Training
# batch=64
# subdivisions=16
...
模型训练
接下来将会以自己的数据集作为例子进行训练,文件目录如下所示,图片存储于JPEGImages文件夹下,标注的xml文件存储与
VOCdevkit
——VOC2008
————Annotations
————ImageSets
——————Main
————JPEGImages
在voc2008文件夹下建立voc_2008.py文件并运行,voc_2008.py的作用是在ImageSets 下的main文件夹产生随机分割后的训练集测试集路径文件,代码如下:
import os
import random
trainval_percent = 0.1
train_percent = 0.9
xmlfilepath = 'Annotations'
txtsavepath = 'ImageSets/Main'
total_xml = os.listdir(xmlfilepath)
num = len(total_xml)
list = range(num)
tv = int(num * trainval_percent)
tr = int(tv * train_percent)
trainval = random.sample(list, tv)
train = random.sample(trainval, tr)
ftrainval = open('ImageSets/Main/trainval.txt', 'w')
ftest = open('ImageSets/Main/test.txt', 'w')
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 trainval:
ftrainval.write(name)
if i in train:
ftest.write(name)
else:
fval.write(name)
else:
ftrain.write(name)
ftrainval.close()
ftrain.close()
fval.close()
ftest.close()
随后在darknet主目录下建立voc_label.py文件并运行,voc_label.py的作用是将所有标注的xml文件转化成txt文件,因为YOLO支持读取的数据只是txt格式,代码如下:
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
sets=[('2008', 'train'), ('2008', 'val'), ('2008', 'test')]
classes = ["knife"]
def convert(size, box):
dw = 1./(size[0])
dh = 1./(size[1])
x = (box[0] + box[1])/2.0 - 1
y =