YOLOv3使用笔记
最近使用YOLO做了一个比较简单的物体检测,途中遇到了一些问题,打算在这里写一下,方便以后参考
github地址:https://github.com/Kingqibin/EWATT_YOLO ,跟上一篇blog是统一个项目
环境
- ubuntu 16.04 LTS
- yolov3
- 等
YOLOv3的安装
安装跟着官网的历程走就可以,没有什么太大的难度。
安装并且编译darknet
git clone https://github.com/pjreddie/darknet
cd darknet
make
注意哦:如果要使用GPU要更改Makeflie文件里的一部分内容:
GPU = 1
CUDNN = 1
NVCC = /usr/local/cuda/bin/nvcc
其余的一般不需要改
下载权重集,并使用官网预带的图片进行测试
wget https://pjreddie.com/media/files/yolov3.weights
./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg
准备数据
-
使用labelimg标记数据,使用及其简单,画个框,输入名称,不建议直接保存成yolo文件,可能会有点问题,因为文件保存后的每一行的第一个数字不为0(好像为15),与后面经过转化出来的内容不太一样,具体的我没有试一下,有兴趣的同学可以自己试一下。
-
标记完成后,在自己项目目录下建一个data文件夹来保存训练使用的数据文件,data下有三个子文件夹Annotatios(将标记完成的数据文件–.xml文件全部拷到这个文件夹下)、ImageSets(再建两个子文件夹Main,Layout(这个好像没用))、labels(还有一些其它的没有什么用的文件夹),为什么这样设置,我也不是特别清楚,好像就是为了让它像voc的官方数据集?这样设置下就完事儿了
-
完成后就是生成训练集文件索引表和交叉验证集文件索引表,如我github文件目录下data/ImageSets/Main 下的antenna_train.txt 和 antenna_val.txt 文件。生成的文件内容如图所示:
即每一行保存一个训练数据图片的绝对路径(相对路径也可以,但是不是特别推荐,如果想用,请自行修改)
之后再根据文件夹下的图片名称获取为一个图片id保存到train.txt 和 val.txt文件下。如下图所示:
即只保存文件名字就可以。
以上四个文件的生成可以参考脚本如果名称不是那么有顺序,可以使用os库文件进行相应的操作,具体的可以Google。 -
索引表建好之后,就将Annotations的文件全部通过一下的一个小
脚本生成相对应的.txt文件并保存再label(data/label)文件夹下。
#coding=utf-8
import xml.etree.ElementTree as ET
#类别名称在这里修改
classes = ["antenna"]
def convert(size, box):
dw = 1./size[0]
dh = 1./size[1]
x = (box[0] + box[1])/2.0
y = (box[2] + box[3])/2.0
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):
#你的Annotations下的xml文件地址,
in_file = open('/home/kingqi/work/yolo_test/data/Annotations/%s.xml'%(image_id))
#将要保存生成txt文件的地址
out_file = open('/home/kingqi/work/yolo_test/data/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'):
cls = obj.find('name').text
if cls not in classes :
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')
#train.txt文件的路径
image_ids_train = open('/home/kingqi/work/yolo_test/data/ImageSets/Main/train.txt').read().strip().split()
#这里是val.txt文件的路径
image_ids_val = open('/home/kingqi/work/yolo_test/data/ImageSets/Main/val.txt').read().strip().split()
for image_id in image_ids_train:
convert_annotation(image_id)
for image_id in image_ids_val:
convert_annotation(image_id)
这个脚本我也是去网上找的,你也可以自己定制。
设置参数
数据准备好之后就可以开始修改一些参数,准备开始训练了
- 在开始之前,先将需要使用的预训练集下载一下,边下载,边做后面的事情:
wget https://pjreddie.com/media/files/darknet53.conv.74
- 在项目目录下新建一个.names文件,如antenna.names文件,里面每一行包含一个你需要识别的类型名称:
- 在项目目录下新建一个backup文件夹,用来保存训练生成的模型文件。
- 将darknet/cfg/yolov3-voc.cfg文件复制到项目目录下,并作相应的修改:
修改训练参数,将Testing后面的两行注释,Training 后面的两行取消注释,Testing后面的两行是用来做预测检验时使用,等到训练完成后,再将这两行取消注释,将Training后面那两行注释。
[net]
# Testing
# batch=1
# subdivisions=1
# Training
batch=64 # 批数量
subdivisions=32 # 将batch分成很多分送入网络
width=512 # 图片的宽度
height=512 # 图片的长度
channels=3
momentum=0.9
decay=0.0005
angle=90 # 图片的旋转角度,可以增加训练效果
saturation = 1.5
exposure = 1.5
hue=.1
learning_rate=0.001
burn_in=1000
max_batches = 1000
policy=steps
steps= 400,500 # steps 与 scales结合使用,前400次的learning_rate' = learning_rate * 0.1,后500次为learning_rate * 0.01
scales=.1,.01
之后就是修改yolo层的classes的大小我这里的classes=1,之后修改yolo层前一层的convolutional层的filter参数,计算公式为:filter = 3 * (classes + 5) 我这里是18,根据自己类别的多少做相应的修改。
在项目目录下,新建一个.data文件,如antenna.data文件,用来指明各个文件的路径。
# 种类数目
classes= 1
# 训练集的索引表
train = /home/kingqi/work/yolo_test/data/ImageSets/Main/antenna_train.txt
# 交叉验证集的索引表
valid = /home/kingqi/work/yolo_test/data/ImageSets/Main/antenna_val.txt
# 种类的名字
names = /home/kingqi/work/yolo_test/antenna.names
# 模型保存文件夹
backup = /home/kingqi/work/yolo_test/backup
开始训练
cd darknet
./darknet detector train ../antenna.data ../yolo-voc.cfg ../darknet53.conv.74
在darknet目录下运行,输入相应的参数即可,最后的那个参数为下载的那个预训练集。
可能遇到的问题
我在训练时遇到了两个问题报错:
- out of memory
这个的主要解决方式就是修改batch和subdivision参数。
batch=64 # 批数量
subdivisions=16 # 将batch分成很多分送入网络
- 构建时错误:
87 Layer before convolutionnal layer must output image.: Success
darknet: ./src/utils.c:256: error: Assertion '0' failed.
Aborted (core dumped)
修改图片的大小,可能你的图片太大了。
width=512 # 图片的宽度
height=512 # 图片的长度
验证
验证阶段就很简单了,只需要修改下最开始的测试命令行,修改一下参数即可。这部分略过。
训练的结果还是相当不错的~
目前为止YOLOv3的使用笔记就写完了,与之前使用的mask rcnn相比,YOLOv3的使用及其简单,不需要写太多的代码,只需要调好参数即可,所谓的调参师可能就是这样来的吧,但是,每个人应该都是从学习别人的项目,使用别人的框架开始的吧,哈哈,希望有一天能够真正的做出自己的框架。