文章目录
- 0. 前期准备(因人而异)
- 1. 试验官方模型
-
- 1.1 下载工程文件
- 1.2 转换权重文件
- 1.3 图片识别
- 2. 制作VOC数据集
-
- 2.1 格式介绍
- 2.2 准备样本及XML标记
- 2.3 生成索引
- 3. YOLO模型训练
-
- 3.1 生成训练索引
- 3.2 修改配置文件
- 3.3 执行训练
- 4. 模型验证
- 5. 常见问题
-
- 5.1 如何提高检测效果
- 5.2 Found 0 boxes for img
- 5.3 loss值异常
- 5.4 ResourceExhaustedError: OOM
- 5.5 检测时打开程序报错:Dimension 0 in both shapes must be equal, but are 1 and 24.
- 5.6 训练模型如何在OpenCV中使用?
参考:
https://blog.csdn.net/patrick_Lxc/article/details/80615433
https://blog.csdn.net/m0_37857151/article/details/81330699
0. 前期准备(因人而异)
记录一下前期的一些配置:
首先要安装好python,博主这里用的是Python 3.6 64-bit。
path环境变量中加入python36和python36/Scripts的路径。
使用管理员权限进入cmd命令提示符,运行一下代码:
pip install --upgrade pip #更新pip
pip install tensorflow #安装 tensorflow
pip install --upgrade numpy #numpy是一个基础的数组计算包,有时候版本较老会报错
pip install keras #yolo train.py文件里面要用到keras这个高层神经网络API
pip install pillow #安装 图片处理模块PIL(pillow)
pip install matplotlib #安装 2D绘图库matplotlib
pip install opencv-python #安装 opencv视觉库
中间记得测试一下tensorflow安装有没有问题:
import os
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'
import tensorflow as tf
hello = tf.constant('Hello,TensorFlow!')
sess = tf.Session()
print(sess.run(hello))
如果打算用 GPU版本 训练的话,可以参考我另外一篇文章:https://blog.csdn.net/qinchang1/article/details/90693983
给个版本建议:
Tensorflow-gpu 1.4.0 + Keras 2.2.4(我用的版本)
Tensorflow-cpu 1.13.1 + Keras2.2.4(网友提供成功的版本)
1. 试验官方模型
1.1 下载工程文件
YOLOv3下载:
1)yolov3.weights权重文件:https://pjreddie.com/media/files/yolov3.weights
2)keras-yolo3代码: https://github.com/qqwweee/keras-yolo3 (工程文件如下,记得把 .weights权重文件也放进去)
推荐:百度网盘打包下载(* ̄︶ ̄):链接:https://pan.baidu.com/s/1OIQGthndfLSfMC1ZlZH6lA 提取码:rlkd
(建议用我的网盘资源下载,因为github上面的工程文件可能会有更改,导致后续的操作出现不同或问题)
1.2 转换权重文件
这里首先要需要将 DarkNet 的
.weights
文件转换成 Keras 的
.h5
文件,在cmd中打开工程文件的路径,运行
convert.py
并告知 “.weights的输入路径 ” 和 “.h5的输出路径” ,代码如下:
python convert.py yolov3.cfg yolov3.weights model_data/yolo.h5
会在model_data文件夹中生成一个yolo.h5文件。
+注意:这个权重文件要留着,后面可能会用上。
1.3 图片识别
在工程文件中打开yolo_video.py,其用法如下:
usage: yolo_video.py [-h] [–model MODEL] [–anchors ANCHORS]
[–classes CLASSES] [–gpu_num GPU_NUM] [–image]
[–input] [–output]
positional arguments:
–input Video input path
–output Video output path
optional arguments:
-h, --help show this help message and exit
–model MODEL path to model weight file, default model_data/yolo.h5
–anchors ANCHORS path to anchor definitions, default
model_data/yolo_anchors.txt
–classes CLASSES path to class definitions, default
model_data/coco_classes.txt
–gpu_num GPU_NUM Number of GPU to use, default 1
–image Image detection mode, will ignore all positional arguments
例如:识别一张图片,则在cmd中的工程文件路径下输入:
python yolo_video.py --image
会提示你输入图片路径(这里我的图片是直接放在工程文件里面的,所以直接输入文件名):
效果如下:
2. 制作VOC数据集
VOC全称Visual Object Classes,出自The PASCAL Visual Object Classes(VOC)Challenge,这个挑战赛从2005年开始到2012年,每年主办方都会提供一些图片样本供挑战者识别分类。
PASCAL VOC官网:http://host.robots.ox.ac.uk/pascal/VOC/
2.1 格式介绍
可以在官网中下载每一年的数据集,也可以自己仿照VOC的格式制作。
其文件格式如下图:
下面是本人对每个文件功能的总结和理解:
我们可以把官方下载的VOC数据集里面的内容删除,只保留各个文件夹;或者按照这个格式建立一个文件夹集。
这个文件夹我们直接放到前面的工程文件keras-yolo3-master中(以便之后的训练不用更改路径)。
2.2 准备样本及XML标记
在JPEGImage文件夹中放入准备好的样本图片:
需要制作每张图片对应的同名xml文件,这里我们以下面这张图片为例,右边的代码是其对应的xml文件内容:
如果你有精力的话,当然可以自己一个个去写:)
不过这里我们用一个labelImg的软件进行标记,
labelImg下载链接:https://pan.baidu.com/s/1Ibenx26FaJUI_t-J3EhSLw 提取码:2gba
解压之后就两个文件,labelImg.exe运行文件,data文件夹里面有个predefined_classes.txt文件。
在predefined_classes.txt文件里面添加需要标记的类的名称。
打开软件,其实操作很简单,就是手动去标注物体,并给其选择对应的类名称:
之后保存xml文件,注意路径。
把所有xml文件都放置到VOC数据集里面的Annotations文件夹中。
打了3种标签,如下所示。
2.3 生成索引
在VOC2007文件夹中新建一个**.py文件**(名字随意)
在py文件中输入以下代码并运行,用以生成索引
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()
之后就会在ImageSets\Main文件夹中生成几个索引文件
{class}_train.txt 保存类别为 class 的训练集的所有索引
{class}_val.txt 保存类别为 class 的验证集的所有索引
{class}_trainval.txt 保存类别为 class 的训练验证集的所有索引
3. YOLO模型训练
3.1 生成训练索引
在工程文件keras-yolo3-master中,修改voc_annotation.py文件
主要是把里面classes的内容改成要训练的对象(要和前面标记的一致,这里我只有三个对象"twistlock",后两个没加上,图片是老的了)
运行这个py程序,生成三个文件"2007_test.txt", “2007_train.txt”, “2007_val.txt”,把前缀"2007_"去掉,得到 “test.txt”, “train.txt”, “val.txt”。
PS:其实这一步有个问题,仔细看过train.py代码的人估计会发现实际训练只加载了train.txt文件,然后将train.txt文件里面的索引再分成了训练集和样本集。
3.2 修改配置文件
首先要修改一下 model_data 文件夹中的coco_classes.txt和voc_classes.txt,将里面的对象改成自己要训练的对象名称
3.3 执行训练
直接将model_data文件夹中原版的yolo.h5复制,改名为yolo_weights.h5,将其作为预训练权重。
PS: 对于这个预训练权重,其实是迁移学习的方法,有些博文其实是让修改yolo3.cfg文件,然后重新生成权重文件,但是我发现这样的做法最后训练时会出现val_loss:nan的情况,所以我建议直接用原来官方的权重文件yolo.h5。还有一些博文修改了原来train.py的训练代码,不预加载训练权重,重头开始训练,但是我发现由于样本量少,这样训练出来的结果很不稳定,所以我也不推荐。
完成yolo_weights.h5文件之后,在keras-yolo3-master工程文件夹中找到train. py,根据需要,可以更改里面的迭代次数epochs 等参数。如果显存小的话,可以改小batch_size。
之后运行这个python程序,下面是我的运行效果
训练过程:
训练结束后,会生成很多过程的h5文件,最后只需要保留trained_weights_final.h5就行。
训练样本约400多张,最后两种loss都降到15左右。
4. 模型验证
参照前面1.3节内容,可以在yolo. py 中把权重文件的名字改成 trained_weights_final.h5 ,也可以直接把 trained_weights_final.h5名字改成 yolo. h5,总之就是之后要加载新的权重文件。
同样地,则在cmd中的工程文件路径下输入:
python yolo_video.py --image
输入图片路径(这里是将图片直接放在工程文件里,所以直接输入名字就行)
B站上放了一个最新的训练效果:
https://www.bilibili.com/video/av78397208
5. 常见问题
5.1 如何提高检测效果
参考:https://github.com/AlexeyAB/darknet#how-to-train-to-detect-your-custom-objects
1. 训练前
(1)在.cfg文件中设置flag
random=1
,它将通过不同分辨率来训练yolo以提高精度。
(2)提高.cfg文件中网络的分辨率,(例如
height = 608
,
width = 608
或者任意32的倍数),这样可以提高精度。
(3)确保数据集中每个类都带有标签,并且保证标签正确。(原文里面提供一个脚本工具)
(4)对于要检测的每个对象,训练数据集中必须至少有一个类似的对象,其形状、对象侧面、相对大小、旋转角度、倾斜、照明等条件大致相同。
(5)数据集中应包括对象的不同缩放、旋转、照明、不同的面、不同背景的图像,最好为每个类提供2000个不同的图像,并且训练(
2000* 类的数量
)的迭代次数或更多。
(6)确保训练的数据集中包含不想被检测的不带标签的对象,即负样本,负样本的数量最好和正样本的数量相同。
(7)对于目标物体较多的图像,在.cfg文件中最后一个[yolo]层加入
max=200
参数或者更高的值。(yolov3可以检测到的对象的全局最大数目是
0.0615234375 *(width*height)
,其中width和height是.cfg文件中[net]部分的参数)
(8)训练小物体时(图像调整到416x416后物体小于16x16),将[route]参数替换为
layers = -1, 11
,将[upsample]参数改为
stride =4
。
(9)对于都包含小对象和大对象可以使用以下的修改模型:
Full-model: 5 yolo layers: https://raw.githubusercontent.com/AlexeyAB/darknet/master/cfg/yolov3_5l.cfg
Tiny-model: 3 yolo layers: https://raw.githubusercontent.com/AlexeyAB/darknet/master/cfg/yolov3-tiny_3l.cfg
Spatial-full-model: 3 yolo layers: https://raw.githubusercontent.com/AlexeyAB/darknet/master/cfg/yolov3-spp.cfg
(10)如果要训练区分左右的对象(例如左手右手,道路上左转右转标志等),需要禁用数据翻转增强,在.cfg文件中17行左右的位置加入
flip=0
。
(11)一般规律——训练数据集应该包含一组您想要检测的对象的相对大小。简单来说,就是需要检测的对象在图像中的百分比是多少,那么训练的图像中也应该包含这个百分比的对象。例如:如果训练的时候目标在图像中都占80-90%,那检测的时候很可能就检测不出目标占0-10%情况。
(12)同一个对象在不同的光照条件、侧面、尺寸、倾斜或旋转30度的情况下,对于神经网络的内部来说,都是不同的对象。因此,如果想检测更多的不同对象,就应该选择更复杂的神经网络。
(13)在.cfg中重新计算锚(anchors)的width和height:在.cfg文件中的3个[yolo]层中的每个层中设置相同的9个锚,但是应该为每个[yolo]层更改锚点
masks=
的索引,以便[yolo]第一层的锚点大于60x60,第二层大于30x30,第三层剩余。此外,还应在每个[yolo]层之前更改过滤器
filters=(classes + 5) * <number of mask>
。如果许多计算出的锚找不到适当的层,那么只需尝试使用所有的默认锚。
2.训练后(对于检测):
通过在.cfg文件中设置(
height=608
,
width=608
)或(
height=832
,
width=832
)或(32的任意值倍数)来提高网络的分辨率,这将提高精度并使检测小对象成为可能。
这里提高了网络的分辨率,但是可以不需要重新训练(即使之前使用416*416分辨率训练的)。但是为了提高精度,还是建议使用更高的分辨率来重新训练。
注意:如果出现了
Out of memory
的错误,建议提高.cfg文件中的
subdivisions=16
参数,改成32或者64等。
5.2 Found 0 boxes for img
在检测时,减小 yolo. py 文件参数中的 score 和 iou,如下图:
(这样可以使得置信度小和交并比小的框也能显示出来)
如果这时候能出现框了,但是会发现效果不是很好,或者说置信度特别低,说明检测是成功的,但是训练做得比较差;
如果还是不能出现框,考虑有可能检测方法错了(路径设置等),或者是训练过程错误(类名称和索引没配置好等)。
不管什么情况都可以试试5.1节中提到的方法。
5.3 loss值异常
模型训练时,有两个loss值:
1)Train loss(对应本次训练中的
loss
):使用训练集的样本来计算的损失;
2)Test loss(对应本次训练中的
val_loss
):使用验证集的样本来计算的损失。
一般来说,损失函数越小,模型就越好。但要考虑过拟合情况:
过拟合:为了得到一致假设而使假设变得过度严格。
例如:训练出来的模型对训练样本检测的效果很好,但是对于验证集(也就是没有进行训练的样本)的检测效果却很差。
结果分析:( ↓ 表示 不断下降,↑ 表示 不断增加,→ 表示 趋于不变)
train loss | test loss | 说明 |
---|---|---|
↓ | ↓ | 网络正在不断学习收敛 |
↓ | → | 网络过拟合 |
→ | ↓ | 数据集有问题 |
→ | → | 此次条件下学习达到瓶颈 |
↑ | ↑ | 网络结构或设计参数有问题,无法收敛 |
5.4 ResourceExhaustedError: OOM
开始训练后有时候会报错,例如:
ResourceExhaustedError (see above for traceback): OOM when allocating tensor with shape[10,256,52,52]
这种情况通常是GPU显存被占满了,你要么清理一下,要么把程序中的
batch_size
改小
5.5 检测时打开程序报错:Dimension 0 in both shapes must be equal, but are 1 and 24.
这个是由于标明的类数量和训练的类数量对应不上,检查一下voc_classes.txt和coco_classes.txt
5.6 训练模型如何在OpenCV中使用?
参考我另一篇文章:
https://blog.csdn.net/qinchang1/article/details/105776132
如有错误,欢迎指正!