原创不易,转载标明出处:https://www.jianshu.com/p/4eab78a46241
因为项目升级,有想法把之前图像识别的工具升级一下(毕竟faster—rcnn是2015年的产品现在都2019年了现在比较新的工具就是yolo v3)以下是我在使用yolo v3的使用的记录,供后来人参考。
工欲善其事,必先利其器 首先我们需要下载yolov3 和一个标图工具
下载yolov3:
git clone https://github.com/pjreddie/darknet
cd darknet
修改makefile配置:
make 因为是本地cpu版本所以不用修改什么直接make
如果是gpu版本需要修改如下文件:darknet/MakeFile
- 将GPU=0 --> GPU=1
- CUDNN=0 --> CUDNN=1
- DEBUG=0 --> DEBUG=1
- NVCC=/usr/local/cuda/cuda/bin/nvcc
-->NVCC=/usr/local/cuda-8.0/bin/nvcc(这里nvcc所在位置注意修改成自己的) - COMMON+= -DGPU -I/usr/local/cuda/include
-->COMMON+= -DGPU -I/usr/local/cuda-8.0/include - LDFLAGS+= -L/usr/local/cuda/lib64-lcuda -lcudart -lcublas -lcarand
--> LDFLAGS+= -L/usr/local/cuda-8.0/lib64-lcuda -lcudart -lcublas -lcarand
这些搞定后我们还需要准备数据集,因为官方推荐了labelimg,所以我们就进行第二步:
下载labelimg
因为直接pip,安装不上去,所以我采用了源码的安装方式,下面是mac的源码安装步骤:
git clone https://github.com/tzutalin/labelImg
brew install qt
brew install libxml2
pip3 install pyqt5 lxml
make qt5py3
python3 labelImg.py
开始进行标图
工具打开后效果如下:
几个很简单的操作,将右上角使用预设标签点上,输入你的标签名称:这个根据你需要做的内容进行自定义。
记住几个快捷键就好了
A 上张图片
D 下张图片
command+s存贮
ok开始你无聊有冗长的标注工作,中间累的话起身喝一杯卡布奇诺。
。。。。。。。n小时过后。。。。。。
打开你下载好的yolo的代码
在scripts文件夹下建立如下文件格式:
—VOCdevkit
——VOC2019
———Annotations
———ImageSets
————Main
———JPEGImages
———labels
其中:Annotations用于存放xml文件,JPEGImages用于存放图片原图
ImageSets下的Main文件夹用于放两个文件train.txt和val.txt分别是指训练的图和测试的图 记住这里只有名字,路径啥的都没有,文件后缀也没有。就像这样:
这里有一个网上找的代码可以直接用
if __name__ == '__main__':
source_folder = 'darknet/scripts/VOCdevkit/VOC2019/JPEGImages/'
dest = 'darknet/scripts/VOCdevkit/VOC2019/ImageSets/Main/train.txt'
dest2 = 'darknet/scripts/VOCdevkit/VOC2019/ImageSets/Main/val.txt'
file_list = os.listdir(source_folder)
train_file = open(dest, 'a')
val_file = open(dest2, 'a')
file_num = 0
for file_obj in file_list:
file_path = os.path.join(source_folder, file_obj)
file_name, file_extend = os.path.splitext(file_obj)
file_num += 1
if (file_num < 40000):
train_file.write(file_name + '\n')
else:
val_file.write(file_name + '\n')
train_file.close()
val_file.close()
这个代码的作用就是将40000张图片作为训练集,其他的图片作为测试集合来使用。
接下来是我们很重要环节:
代码修改
以下三个代码是需要修改的:
- scripts下的voc_label.py这一步的目的是将xml文件的位置做一个再处理,生成到对应的labels文件夹下,修改内容:
sets=[('2019', 'train'), ('2019', 'val')]
classes = ['XXX'] 这里是你在lableimg中自定义的东西
这里的set=[('2019', 'train'), ('2019', 'val’)]是指你后面要读的文件的位置,和你main文件夹下的两个文件的路径保持一致。
classes = ['XXX’]是指你的分类方式,和你在lableimg中自定义的内容保持一致。
运行完成之后你的文件会多出这样几个文件
同时你的labels里也有东西了。 - 修改cfg/voc.data文件
classes= 1#分类的类别数目
train = darknet/scripts/2019_train.txt#上一步生成的文件
valid = darknet/scripts/2019_val.txt
names = data/voc.names
backup = backup
上面的代码我们其实看到了一个叫做names = data/voc.names这一行,好我们就去修改这个文件
- 修改data/voc.names
很简单就是你的imagelabe里自定义的内容 - 最重要的一步,修改你的隐藏层结构cfg/yolov3-voc.cfg
打开你的文件如下所示:
[net]
# Testing
batch=1 #批次,显存不够可减小,但会出现Nan问题(解决办法:增大batch。。。)
subdivisions=1 #训练迭代包含16组,每组4张图片
# 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=18 #3*(类别+5)
activation=linear
[yolo]
mask = 6,7,8
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
...
修改里面所有的yolo标签和跟它连接的那个[convolutional]标签中的filters 修改思路是3*(类别+5)。因为我的类别是1,所以我的filter是18
然后就可以开始训练了
训练
./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg darknet53.conv.74
多gpu下的训练
./darknet detector train cfg/coco.data cfg/yolov3.cfg darknet53.conv.74 -gpus 0,1,2,3
测试
./darknet detect cfg/yolov3.cfg yolov3.weights data/one.jpg
训练过程中的内容解析:
Region 94 Avg IOU: 0.078053, Class: 0.423860, Obj: 0.004782, No Obj: 0.083954, .5R: 0.000000, .75R: 0.000000, count: 1
Region Avg IOU: 表示在当前subdivision内的图片的平均IOU,代表预测的矩形框和真实目标的交集与并集之比。
Class: 标注物体分类的正确率,期望该值趋近于1。
Obj: 越接近1越好。
No Obj: 期望该值越来越小,但不为零。
count: count后的值是所有的当前subdivision图片中包含正样本的图片的数量。
148: 60.560833, 97.261108 avg, 0.000000 rate, 8.694288 seconds, 9472 images
148是总体loss,97是平均loss,一般到0.几的时候就可以退出训练了,0.000000 rate代表学习率,在cfg文件中定义
8.694288 seconds 是这一批次的训练花费总时间,9472 images表示到目前为止参与训练的图片的总量
异常以及处理方式
- cuda内存报错
CUDA Error: out of memory
darknet: ./src/cuda.c:36: check_error: Assertion `0' failed.
处理方式:
修改cfg/yolov3-voc.cfg中的batch 将这个值变小 甚至设置为1,上面的代码是修改过的
注:设置为1很容易出现不收敛且iou为nan情况 也可以将batch=64,subversion=16,跑起来试试效果
参考博客:https://blog.csdn.net/lixiaoyu101/article/details/86537128