查看原文
其他

用YOLOv5实现目标检测

余柏辰 狗熊会 2023-08-15
点击“蓝字”关注我们吧!



余柏辰,华东师范大学统计学院2019级本科生,统计学专业。




1. 问题背景

在深度学习中,我们非常熟悉的一类问题是图片分类问题,我们通常的解决方案是训练一个卷积神经网络(CNN),其中最后的输出层神经元根据需要分类的图片类别进行设置,往往能取得不错的效果。而今天我们遇到的问题不太一样,我们仍然要给出目标的类别预测,但需要在一幅大图片中定位到多个目标的位置和类别。目标检测的应用范围很广,比如在超市通过视频检测消费者的进出、工业制造业领域中的异常行为检测等。另一个典型的场景是,在自动驾驶时车辆需要定位视线范围内的所有物体,并识别其类别以判断危险程度。这都给目标检测这一领域提供了丰富的应用空间。

2. 模型介绍

2.1 YOLO简介

YOLO的名字来历颇有意思,他的本意是流行语You Only Live Once的缩写,而模型的作者Joseph Redmon改了一个词将You Only Look One作为模型的名字。这是由于,相对于R-CNN系列算法将检测问题分解为划定位置和判定类别分两步做,YOLO系列算法没有显式寻找区域的过程,可以实现端到端的快速预测,即输入一幅图片,在输出中给出若干目标的位置、类别和置信度。

而相对于同样是一步到位的SSD算法,YOLO系列的特点在于算法一经发出,便有各种各样的人和团队对他进行更新迭代。通过不断地更新迭代模型版本,YOLO也得到了效果上持续的提升和更广泛的关注。但值得注意的是,YOLO模型的原作者Joseph Redmon更新到v3版本后就退出了相关的研究,而后续的版本都是其他研究人员的工作,包括我们今天介绍的YOLOv5。

2.2 YOLO模型介绍

我们首先介绍一下最原始的YOLO模型,然后简要介绍一下YOLOv5版本的改进,主要通过具体的例子一起看看怎么把YOLOv5模型用好。

YOLOv1的网络结构并没有什么特别,和我们熟悉的图像分类一样都是卷积神经网络,但它的输出向量却不太一样。如果把神经网络看作我们熟悉的回归分析问题,那YOLO做的事情就是改变了模型响应Y的结构,而这也奠定了YOLO目标检测的基础。YOLO的输出向量不仅包括目标的类别,还有边界框的坐标和预测的置信度。它的核心思想在于把图像分割成S*S的若干个小块,在每个格子中预先放置两个边界框,通过卷积神经网络预测得到每个边界框的坐标、类别和置信度,然后通过非极大值抑制获得局部唯一的预测框。

经过若干年的版本迭代,YOLOv5的网络结构博采众长,已经变得格外复杂,主要包括在Backbone中通过卷积和池化网络结构提取特征,在Neck部分不断地和之前提取的特征进行融合,Head部分则是用来进行最终的检测和输出,如下图所示。

我们今天选取YOLOv5作为介绍,一方面是因为从最终效果来看YOLOv5已经相当优秀,是发展的比较完备、使用比较广泛的一个版本;而更重要的是YOLOv5的调用、训练和预测都十分方便,为初学者提供了良好的练手工具。YOLOv5的另一个特点就是它为不同的设备需求和不同的应用场景提供了大小和参数数量不同的网络。

如图所示,大一点的模型比如YOLOv5l和YOLOv5x参数更多,在大规模的COCO数据集上有更高的预测准确率;而小模型比如YOLOv5n或YOLOv5s占空间更小,适合部署在移动设备上,且推理速度更快,适合于高帧 率视频的实时检测。

3. 数据介绍

3.1 数据准备与展示

我们采用真实公开的车辆检测UA-DETRAC数据集进行YOLOv5模型的训练和测试,数据开源于https://detrac-db.rit.albany.edu  。视频是用Cannon EOS 550D相机在北京和天津的24个不同地点拍摄的,总共10小时的视频以每秒25帧(FPS)的速度记录,分辨率为960*540像素,已经提前划分好训练集和验证集。由于这个数据集非常大,我们在这个案例中随机抽样10%进行训练。

3.2 数据标注

为了进行目标检测,一个重要的步骤是进行数据标注,即在图像上手动用矩形框来框出目标的位置并说明类别,以下面这张随意从训练集中抽出的图片为例。

支持标记的软件或网站有很多,比较常用的人工标注工具如labelImg软件和roboflow网站等。标注结果一般有VOC格式的xml文件或支持YOLO训练的txt文件,一般可以选择或通过脚本转换为需要的txt文件即可。UA-DETRAC数据集已经做好了xml类型的标注,而YOLOv5的输入格式要求txt文件,因此我们需要做一下格式的转换。

xml格式的标记文件中记录了物体的类别、标记框在像素图片上的左上角坐标 (left,top) 和标记框的像素长度 (width, height),而YOLO txt文件要求记录的是标记框中心相对图片长宽的比例,以及标记框长宽相对图片长宽的比例。由于我们已经知道图片像素大小,因此可以轻易的在实际的像素位置和YOLO txt格式之间进行换算,这里img_w、img_h指的是图片的宽和高,而(x, y)最终指的是标记框中心的相对位置:

x = left + width / 2        # 标记框中心x轴坐标
y = top + height / 2        # 标记框中心y轴
x = x / img_w            # 标记框中心x轴坐标归一化
y = y / img_h            # 标记框中心y轴坐标归一化
width = width / img_w     # 标记框宽度归一化
height = height / img_h    # 标记框高度归一化

通过上述公式换算过后,我们来看看刚才这张标记好的训练集图片的txt格式标记数据:

1 0.608021 0.277056 0.053854 0.089556
1 0.58651 0.196116 0.038958 0.060509
1 0.543646 0.15381 0.030104 0.052806
1 0.593672 0.150444 0.031719 0.039667
1 0.78026 0.2345 0.050104 0.069963
1 0.951562 0.481509 0.098958 0.170537

以这个标记文件的第一行为例,1表示类别car,0.608021是标记框中心横坐标与图像宽度比值,0.277056表示标记框中心纵坐标与图像高度比值,0.053854是标记框宽度与图像宽度比值,0.089556表示标记框高度与图像高度比值。

4. 迁移学习模型训练

接下来,本案例以一个比较小的网络YOLOv5s为例,展示如何用YOLOv5s训练一个我们自己的模型。

4.1 数据结构

在训练模型之前,为了让我们的数据能够被YOLO找到,我们需要写一个data.yaml文件存储在案例目录下,在其中记录下数据的路径和模型要识别的标记类别,文件内容如下所示。YOLO通过读取目录下的data.yaml文件,进而找到我们数据集存储的位置才能读取数据进行训练验证。

# 数据集存储位置
path: ./data_DETRAC  # 数据集根目录
train: images/train     # 训练图片相对于根目录的路径
val: images/val        # 验证图片相对于根目录的路径
# 所需要检测的类别
nc: 4
names: ['others''car''van''bus']

4.2 调优参数训练模型

训练模型通过调用模型文件夹下的train.py进行,可以通过--batch参数和--epochs参数调整训练批次大小和训练轮数。YOLOv5提供了在COCO数据集上预训练后的参数,我们可以通过参数--weights yolov5s.pt加载预训练参数进行迁移学习,或在训练大数据集(比如COCO)时用一个空的--weights ''参数从零开始训练。

YOLOv5默认的约30个超参数如随机梯度下降的学习率等默认存储在data/hyps/hyp.scratch-low.yaml文件内,我们可以根据自己的需要进行调参,或者通过选取med或high的超参数版本调节自己需要的数据增强水平。往往提高数据增强水平可以增强模型的泛化性,但有时也不尽然。比如我们这个问题里左右翻转是很有效的,但上下翻转很可能让模型学到错的东西,因为不会有车是翻着行驶的。训练开始后,我们可以在runs/train/exp目录下找到每一个批次训练样本的数据增强结果。

YOLOv5默认的设置在迁移学习时优化了每一层网络的参数,这可能导致过大的计算量和缓慢的计算速度,因此我们也可以通过--freeze参数冻结若干层网络,比如使用--freeze 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14表示冻结了YOLO25个块中的前15个,包括卷积和batch normalization的部分。保持其他设定不变仅仅在fine-tune的时候优化模型头部的参数。超参数和冻结模型参数可以自定义设置,这里我们采用默认的超参数来优化模型参数,且不冻结网络参数,这是由于我们这里有足够多的样本量。

! python train.py --batch 32 --epochs 100 --data data.yaml --weights yolov5s.pt --hyp data/hyps/hyp.scratch-med.yaml --cache

部分训练过程如图所示:

4.3 训练结果

在深度学习中,我们通常通过损失函数下降的曲线来观察模型训练的情况。而YOLOv5训练时主要包含三个方面的损失:矩形框损失(box_loss)、置信度损失(obj_loss)和分类损失(cls_loss),在训练结束后,我们也可以在runs/train目录下找到生成对若干训练过程统计图。

我们可以发现,除了验证集的置信度损失外,训练集和验证集的损失函数都在不断下降。而通过观察验证集的混淆矩阵,发现类别others和van的预测结果相对较差,这可能是由于抽样后样本量减少导致的标签不平衡影响的,因此使用全样本训练模型可能会有所提升。此外,在三四十轮过后模型的损失函数基本稳定,可以考虑减少训练轮数避免过拟合。

针对目标检测模型的评价,一个常用的指标是IoU(Intersection over Union),它描述了我们模型预测的边界框和真实的物体定位框之间的差距。字如其名,IoU函数通过计算这两个边界框的交集区域面积和并集区域面积之比来反映这一差距。一般来说,通常约定如果IoU>0.5就说明这个预测是靠谱的。如果预测的边界框和真实边界框完全重合,那IoU就是1,因此IoU是一个0~1之间的评估变量。

当然,IoU并不能直接用来衡量多目标检测问题的算法精度,因此我们需要引入mAP(mean Average Precision),它指的是在特定的IoU阈值下计算每一类的所有图片的平均准确率。比如这里的mAP@0.5(或者记作mAP@50),就是描述了把IoU阈值设为0.5时计算每一类的所有图片的AP,再对所有类别求平均。

我们发现也对每一轮训练后的模型给出了mAP@50指标,但往往很快就达到了很高的水平,这说明仅仅考虑IoU阈值为0.5可能有些粗糙,因此YOLOv5的另一个评价指标用的是mAP@0.5:0.95,指的就是考虑把从0.5到0.95之间步长0.05的一串数(0.5、0.55、0.6、0.65、0.7、0.75、0.8、0.85、0.9、0.95)分别作为IoU阈值计算出的mAP再进行平均。

在我们的训练过程中,mAP50作为一种常用的目标检测评估指标很快达到了较高的0.6以上,而mAP50:95也在训练的过程中不断提升,说明我们模型从训练-验证的角度表现良好。

5. 模型应用

最后,我们读入一个测试集文件夹进行预测,通过--weight runs/train/exp/weights/best.pt选取验证集上效果最好的权重best.pt进行实验,其中--conf 0.5表示只显示推理置信度大于0.5的目标。由于DETRAC数据集提供的均是图片格式的数据,因此我们这里将其文件夹目录作为--source的参数,对这个目录下的所有图片进行检测,如果条件允许也可以选择一个视频对他的每一帧进行检测。然后,我们采用图像处理的opencv库将预测的结果拼接到一起成为视频,现在一起来看看模型的效果吧。 


点击此处“阅读全文”查看更多内容


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存