如何训练属于自己的目标检测模型
如何训练属于自己的目标检测模型
YOLO,You Only Look Once,是目前应用最广泛的基于深度学习的目标检测算法之一。在当前大模型逐渐成为主流时,在目标检测领域依然非常能打。目前Yolo已经被ultralytics更新到了V8,有了更先进的跟踪检测算法。但在先前项目有目标检测需求时,Yolov5还是主流,彼时也仅仅由美团更新到了v6。因此以下文章所用的版本均为Yolov5。
准备代码环境
相对于Yolov8可以之间pip安装的便捷,Yolov5则需要克隆对于的代码库并安装其依赖性。推荐使用Sudo权限来安装依赖包。
1 | git clone https://github.com/ultralytics/yolov5 |
我建议使用新的conda
或者virtualenv environment
,前者安装Anaconda3即可,后者如果你使用pycharm这一类型的ide也会自带一个虚拟环境的管理器。使用这一类型的环境虚拟化管理器可以有效的避免搞乱现有的项目依赖环境。本文这使用的Conda来运行本项目依赖。
1 | conda create -n yolov5 python=3.7 |
准备好源码仓库以及依赖后让我们来继续准备所需训练的数据集吧
准备数据集
介于本文只是简单的演示,于是数据集选取了网上公开的小数据集,将使用来自 MakeML 的道路标志目标检测数据集。包含了一些道路标志,整体数据量相对于工作中实际数据量要小很多很多。仅仅包含了4类道路提示以及877个小图像。我们可以从Kaggle获取该数据集。
下载数据集
在yolov5同目录下创建Road_Sign_Dataset
文件夹,用来存放数据集
- 登录Kaggle,在
Settings
中Create New Token
即可获得一个包含token的json文件。 - 运行
pip install kaggle
命令安装kaggle依赖,并将包含Token的json文件放置在用户目录下的.kaggle
文件夹下 - 在Road_Sign_Dataset文件夹内下载对应数据集
kaggle datasets download andrewmvd/road-sign-detection
- 解压文件
unzip road-sign-detection.zip
- 删除源文件
rm -r road-sign-detection.zip
使用labelimg查看数据集
得到数据集文件后我们可以使用一些标签标注工具比如Labelme,labelimg以及前段时间比较火的结合SAM模型分割的一些标注工具如 Label-Studio来打开数据集,可以直观的查看数据集的标注的内容。我们仅仅查看数据集,这里简单的安装一下labelimg即可.
1 | conda create --name=labelimg python=3.9 |
打开labelimg后选择对应的数据集文件夹以及标注数据的文件夹即可直观的看见标注效果
注释格式转换
现在我们以及拥有一个VOC格式(这是一种非常常见的存储在XML中文件中的注释格式)的路标数据集,但是VOC格式的数据集是无法直接提供给YOLOv5训练解析的,我们需要编写脚本将其转化为Yolo注释的格式。
首先我们先来看看上图对应的标注文件road25.xml内VOC格式的注释格式。
1 |
|
这个注释文件描述了图片的文件夹名称,文件名,图片分辨率大小。以及注释了包含的对象,以及通过坐标框选了对象的位置。而Yolo格式的注释首先是存储在TxT中。每一行都包含了一个VOC中的一个框选的对象。先贴一张来自官网的图来解释一下yolo的注释格式
注释文件具体内容如下
1 | 0 0.670 0.468 0.035 0.120 |
一共标注了三个对象(三个红绿灯)。每一行代表这些对象中的一个。规范如下。
- 每个对象一行
- 每一行 格式为 对象类别 x中心 y中心 宽的比值 高的比值(坐标必须按照图像的尺寸进行标准化)
- 对象类别是类索引下标(从0开始)。
将VOC格式数据转化为Yolo格式数据需要提取的有用信息为 标注对象类别,标注对象的坐标。我们写一个函数来从Voc注释文件中批量提取这两个信息。
1 | import xml.etree.ElementTree as ET |
该函数返回一个包含了VOC中标注的所有对象的 类别与坐标的字典。
接下来我们需要根据字典的生成Yolo格式的注释文件,现在我们编写convert_to_yolov5(info_dict)函数,转换格式并写入TXT中。
1 | # 将标注对象分别映射到id的字典(可动态获取) |
现在我们将所有 VOL转换为 YOLO 样式的 txt 注释。
1 | # 获取vol注释的文件 |
划分数据集
将VOC格式转化为Yolo格式化后,这个数据集并不能直接用来训练,我们还需要将这个数据集划分为三份。分别是训练集,验证集,与测试集,常见的会将大量的样本放在训练集,少量放在验证集或者测试集,甚至测试集合不放,所以常见比例为 7:2:1或者 8:1:1,甚至为 8:2:0接下来我们编写脚本分别数据集根据8:1:1的比例划分好数据集。划分好数据集后数据集准备工作基本完成了。这里就贴出完整代码好了。
1 | import torch |
训练
准备好数据集后接下来就是我们的重头戏,训练数据集了。数据集的训练我们可以从官方选择一个预训练模型进行训练。本文仅仅为了演示,故而选择的是对性能要求最小的n模型。
以下是各个版本官方给出的参数表格
Model | size (pixels) | mAPval 0.5:0.95 | mAPval 0.5 | Speed CPU b1 (ms) | Speed V100 b1 (ms) | Speed V100 b32 (ms) | params (M) | FLOPs @640 (B) |
---|---|---|---|---|---|---|---|---|
YOLOv5n | 640 | 28.0 | 45.7 | 45 | 6.3 | 0.6 | 1.9 | 4.5 |
YOLOv5s | 640 | 37.4 | 56.8 | 98 | 6.4 | 0.9 | 7.2 | 16.5 |
YOLOv5m | 640 | 45.4 | 64.1 | 224 | 8.2 | 1.7 | 21.2 | 49.0 |
YOLOv5l | 640 | 49.0 | 67.3 | 430 | 10.1 | 2.7 | 46.5 | 109.1 |
YOLOv5x | 640 | 50.7 | 68.9 | 766 | 12.1 | 4.8 | 86.7 | 205.7 |
YOLOv5n6 | 1280 | 36.0 | 54.4 | 153 | 8.1 | 2.1 | 3.2 | 4.6 |
YOLOv5s6 | 1280 | 44.8 | 63.7 | 385 | 8.2 | 3.6 | 12.6 | 16.8 |
YOLOv5m6 | 1280 | 51.3 | 69.3 | 887 | 11.1 | 6.8 | 35.7 | 50.0 |
YOLOv5l6 | 1280 | 53.7 | 71.3 | 1784 | 15.8 | 10.5 | 76.8 | 111.4 |
YOLOv5x6 + TTA | 1280 1536 | 55.0 55.8 | 72.7 72.7 | 3136 - | 26.2 - | 19.4 - | 140.7 - | 209.8 - |
我们使用train.py 来训练数据集,而train关于训练有如下常用参数
-
batch
: 批量处理的数目,根据训练显卡的显存来调节,最好训练时可以吃比较多的显存又不至于爆显存 -
epochs
: 需要训练的轮次,常用轮次为300轮 (次数太少效果会很差,次数太多会过拟合) -
data
: 数据 YAML 文件,包含有关数据集的信息(图像路径、标签) -
cfg
: 模型架构。有5种选择: yolo5n.yaml,yolo5s.yaml,yolov5m.yaml,yolov5l.yaml,yolov5x.yaml。这些模型的大小和复杂程度按升序增加,你可以选择一个适合你目标检测任务复杂程度的模型。如果希望使用自定义体系结构,则必须在指定网络体系结构的 model 文件夹中定义 YAML 文件。本文使用的n模型仅仅为了演示效果,实际上n模型只有在移动端上这种硬件性能极差的情况下才会考虑n模型,其他场景几乎没有遇见过使用情况,业务中常用的为Medium与Large模型。 -
weights
: 使用预训练模型,没有预训练模型可以使用官方的即可 -
hyp
: hyperparameter,超参数文件 一般不用修改 -
name
: 关于训练的各种事情,如训练日志。训练重量将存储在名为 run/train/name 的文件夹中
接下来详细的说明一些配置文件。
数据集信息
data
参数将会指向一个数据集相关配置信息的Yaml文件,必须在数据集配置文件中定义以下参数:
-
train
,test
, andval
:训练集,测试集与验证集的图片文件夹的位置 -
nc
: 数据集中的对象的数目。 -
names
: 数据集中的类的名称。此列表中的类的索引下标将用作代码中类名的标识符。因此列表的中各个类型的顺序必须与标注文件中的类索引下标一致根据本文中的road_sign_data数据集创建一个名为 road_sign_data. yaml 的配置文件,并将其放在 yolov5/data 文件夹中。内容如下
1
2
3
4
5
6
7train: ../Road_Sign_Dataset/images/train/
val: ../Road_Sign_Dataset/images/val/
test: ../Road_Sign_Dataset/images/test/
# number of classes
nc: 4
# class names
names: ["trafficlight","stop", "speedlimit","crosswalk"]
模型网络架构
Yolov5还允许您定义自己的定制架构和锚,如果预定的网络架构不适合,也可以自定义权重配置文件。本文中我们使用 yolov5n.yaml。内容如下,简单修改一下nc值为类型数量即可。训练时使用cfg指定即可
1 | # YOLOv5 🚀 by Ultralytics, AGPL-3.0 license |
超参数
超参数配置文件内容为神经网络定义超参数。一般情况下使用默认值即可,默认的配置文件在data/hyps
。
1 | # YOLOv5 🚀 by Ultralytics, AGPL-3.0 license |
训练模型
在上述的配置文件中定义了 数据集位置,类的数量与名称后,即可直接使用命令开始训练了。由于设备受限,无论是数据集的选择是少量的小图片,模型的选择也选择了n模型。这次训练批量处理的数目为32,训练轮次为100.
单卡
1 | python train.py --img 640 --cfg models/yolov5n.yaml --hyp hyp.scratch.yaml --batch 32 --epochs 100 --data data/road_sign_data.yaml --weights yolov5n.pt --workers 24 --name yolo_road_det |
多卡训练
1 | python train.py --img 640 --cfg models/yolov5n.yaml --hyp hyp.scratch.yaml --batch 32 --epochs 100 --data data/road_sign_data.yaml --weights yolov5n.pt --workers 24 --name yolo_road_det --device 0,1 |
缺点:这种方法很慢,与仅使用 1 个 GPU 相比,几乎无法加快训练速度。大部分压力依旧在GPU1上,因此仅推荐在Windows中使用
推荐:
1 | python -m torch.distributed.run --nproc_per_node 2 train.py --img 640 --cfg models/yolov5n.yaml --hyp hyp.scratch.yaml --batch 32 --epochs 100 --data data/road_sign_data.yaml --weights yolov5n.pt --workers 24 --name yolo_road_det --device 0,1 |
在训练时可以使用nvidia-smi
查看实时的显存使用情况,再适当调节batch的值,充分榨干显卡。
训练完毕后,训练好的数据会保存在.\runs\train\yolo_road_det2
中,模型在weights
文件夹下的best.pt
推理
1 | python detect.py --source 0 # webcam |