
目标检测(1)----YOLOV5(王者荣耀数据集)

转眼间两年没有写博客了!
两年经历了好多,做了很多事情。
有做控制相关的学习,也学习了NLP,计算机视觉,transformer相关的深度学习的领域,我最近一边备战研究生,一边学习相关的vision transforemer的CNN的相关学习,也学习了YOLOV8与YOLOV5的对比实验。也做了相关ROS机器人操作系统的学习,今天我写一下目标检测
一.目标检测简介
目标检测项目的主要功能是识别图像或视频中的特定物体,并确定它们的位置和边界框。
目标检测是计算机视觉领域的重要任务,其应用广泛,包括但不限于自动驾驶、安防监控、医学影像分析、工业生产等领域。为了实现这一功能,项目通常涉及使用深度学习模型,如卷积神经网络(CNN)和循环神经网络(RNN),来提取图像特征并进行目标分类和定位。最常见的目标检测方法包括基于区域的卷积神经网络(R-CNN)、快速的区域卷积神经网络(Fast R-CNN)、区域提议网络(RPN)和单发多框架(SSD)等。
目标检测的挑战包括处理不同尺度的目标、遮挡、光照变化、姿态变化等情况。近年来,随着深度学习技术的快速发展,目标检测在准确性和效率上取得了显著进步,成为计算机视觉领域的研究热点之一。例如,YOLOv7在实时性和准确率上已经超过了之前的目标检测算法,而YOLOv8则在工程实践中展示了其性能。
此外,3D目标检测是一个重要的功能模块,特别是在自动驾驶车辆中,因为它可以同时预测周围物体的类别、位置和大小。这要求目标检测算法不仅能够处理2D图像数据,还能够处理3D空间信息,从而提供更准确的障碍物分布信息,确保安全驾驶。
在实现目标检测功能的过程中,数据集的选择和处理、模型的选择和训练、以及后处理步骤(如非极大值抑制NMS)等都是关键环节。通过不断优化这些步骤,可以提高目标检测模型的性能和准确性。例如,通过降低数据增强的权重、增加数据集数量、或采用特定的网络结构(如tiny-yolov2中的darknet)来提升模型的性能。
二,制作数据集
1.制作数据集文件夹
制作YOLOv5的数据集文件夹需满足一定目录格式。
首先创建一个文件夹可以取名叫dataset。
然后在这个文件夹内,再创建两个文件夹,分别叫images和labels,这两个文件夹一个用于存放数据集图像,一个用于存放标注后生成的标注文件的。
最后我们还需要再分别在这两个文件夹内创建一个train文件夹,这个代表训练文件夹,最终的图像和标注文件是在这个train文件夹内的。
2.收集图像
完成数据集文件夹创建后,这时候我们就需要收集需要目标检测的数据集图像了,这边我以王者荣耀的录屏检测为例,我需要收集的就是在王者荣耀英雄在游戏中画面的图像,然后找到相关的图像给他截图下来。
3.标注数据集
标注数据集需要用labelme标注软件,这个可以通过Python环境进行下载,下载的教程可以看其他博客,但有时候容易下载出错(注:这是别人开源的,具体来源我也不知道)步骤如下:
(1)打开终端创建虚拟环境
# 创建labelme的环境
conda create -n labelme python=3.9
- 激活虚拟环境
# 激活labelme环境
conda activate labelme
(3)安装相关依赖
# 安装
conda install pyqt
pip install labelme
- 启动labelme
# fixme: 需要在labelme的环境下
conda activate labelme
labelme
- labelme的使用
- 点击【open】,选择图片;【Edit Polygons】----> 【Create Polygons】
(2)可以选择自动保存
三 YOLOV5预处理
1.1 预处理分析
首先来看yolov5预处理部分,在目标检测中,我们的预处理通常是先对图像进行等比缩放,然后居中,多余部分填充,类似于下图所展示的,这个过程也被叫做添加灰条(即letterbox)
整个过程可以分为三个步骤:
1.等比缩放,矩阵 S \scriptsize S S实现(缩放倍数Scale为目标图像与源图像宽比值和高比值的最小值)
2.将图片中心平移到左上角坐标原点,矩阵 O \scriptsize O O实现
3.将图片平移到目标位置的中心,矩阵T实现
预处理的过程可以通过三个矩阵完成,分别为缩放矩阵S,平移矩阵 O平移矩阵 T,将这三个矩阵可以进行合并成一个矩阵 M ( M = T O S ),其中M矩阵被称为仿射变换矩阵,可以帮助我们完成图像预处理工作,后续的CUDA核函数就是基于M矩阵去进行加速的。
我们可以直接写出仿射变换矩阵 M如下式(4)所示,其中代Origin表源图像,Dst代表目标图像,(x,y)为源图像上任意像素点坐标, (x′,y′)为目标图像上任意像素点坐标。
通过上述变换可以得到源图像任意像素值的坐标对应在目标图像的位置,那么整个预处理过程也就可以通过仿射变换矩阵 M \scriptsize M M来完成。除了将源图像通过 M变换到目标图像,我们也要考虑将目标图像映射回源图像,即求M矩阵的逆矩阵 M^{-1}。要求逆变换是因为网络推理时是在目标图像上进行的,换而言之预测框是绘制在目标图像上的,而最终我们所需要的是源图像的预测框,从目标图像的预测框到源图像预测框的转换就是通过逆矩阵 M^{-1} 完成的。
YOLOv5的预处理过程:
YOLOv5的预处理部分除了上述仿射变换到一定尺寸大小的图片之外,输入到网络中的实际上是一个4个维度的Tensor(B,C,H,W),所以还需要进行如下变换:
BGR ➡ RGB(以opencv读取图片为例)
/255.0
通道数变换 H,W,C ➡ C,H,W(以opencv读取图片为例)
添加batch维度 C,H,W ➡ B,C,H,W
至此,预处理完成。
预处理代码:
import numpy as np
import cv2
def preprocess(img, dst_width=640, dst_height=640):
'''
:param img: 输入的图片
:param dst_width: 预处理后的图像宽
:param dst_height: 预处理后的图像高
:return: 预处理后的图片,仿射变换矩阵的逆变换矩阵IM
'''
scale = min((dst_width / img.shape[1]), (dst_height / img.shape[0]))
ox = (-scale * img.shape[1] + dst_width) / 2
oy = (-scale * img.shape[0] + dst_height) / 2
M = np.array([
[scale, 0, ox],
[0, scale, oy]
], dtype=np.float32)
# img_pre为仿射变换后的图即原始图像缩放到[dst_width,dst_height]
img_pre = cv2.warpAffine(img, M, dsize=[dst_width, dst_height], flags=cv2.INTER_LINEAR,
borderMode=cv2.BORDER_CONSTANT, borderValue=(114,114,114))
# cv2.imshow("img_pre", img_pre)
# cv2.waitKey(0)
IM = cv2.invertAffineTransform(M)
# -----------------------------------------------------------------------#
# 需要进行的预处理
# 1. BGR -> RGB
# 2. /255.0
# 3. 通道数变换 H,W,C -> C,H,W
# 4. 添加batch维度 C,H,W -> B,C,H,W
# -----------------------------------------------------------------------#
img_pre = (img_pre[...,::-1] / 255.0).astype(np.float32)
img_pre = img_pre.transpose(2,0,1)[None]
return img_pre, IM
YOLOv5整个预处理可以通过一个preprocess()函数完成,输入是opencv读取的图片以及仿射变换目标图片的宽高,输出是预处理后的img_pre(4维Tensor)以及仿射变换的逆矩阵M^{-1} 。我们只需要将预处理后的img_pre(4维Tensor)放入网络中进行推理得到预测结果,然后利用逆矩阵 MM^{-1}获得我们最终的结果。
至此,YOLOv5预处理讲解完成。
四 YOLOV5网络结构及核心代码分析
(1)yolov5 网络架构
上图是yolov5s的网络结构,它是yolov5系列中深度最小、特征图宽度最小的网络。后面的m、l、x都是在此基础上不断加深、加宽的。
网络主要分为输入端、Backbone、Neck、Prediction四个部分。
它和yolov3主要不同的地方:
(1)输入端:Mosaic数据增强、自适应锚框计算、自适应图片缩放
(2)Backbone:Focus结构、CSP结构
(3)Neck:FPN+PAN结构
(4)Prediction:GIOU_Loss
(2)输入端
【1】Mosaic数据增强
yolov5的输入端采用了和yolov4一样的Mosaic数据增强的方式。
Mosaic数据增强提出的作者也是来自yolov5团队的成员。它是采用4张图片,随机缩放、随机裁剪、随机排布的方式进行拼接,对于小目标的检测效果还是很不错的。
在平时项目训练时,小目标的AP一般比中目标和大目标低得多。而数据集中也包含大量的小目标,但比较麻烦的是小目标的分布并不均匀。
在整体的数据集中,小、中、大目标的占比并不均衡。上表中,coco数据集中小目标占比达到41.4%,数量比中目标和大目标都要多,但是在所有的训练集的图片中,只有52.3%的图片有小目标而中目标和大目标的分布相对来说更加均匀一些。
针对这种状况,yolov4的作者采用了Mosaic数据增强的方式。
主要有几个优点:
丰富数据集:随机使用4张图片,随机缩放,再随机分布进行拼接,大大丰富了检测数据集,特别是随机缩放增加了很多小目标,让网络的鲁棒性更好。
减少GPU:可能会有人说,随机缩放,普通的数据增强也可以做,但作者考虑到很多人可能只有一个GPU,因此Mosaic增强训练时,可以直接计算4张图片的数据,使得Mini-batch大小并不需要很大,一个GPU就可以达到比较好的效果。
【2】自适应锚框计算
在yolo算法中,针对不同的数据集,都会有初始设定长宽的锚框。
在网络训练中,网络在初始锚框的基础上输出预测框,进而和真实框groundtruth进行比对,计算两者差距,再反向更新,迭代网络参数。
因此初始锚框也是比较重要的一部分,比如yolov5在数据集上初始设定的锚框。
【3】自适应图片缩放
在常用的目标检测算法中,不同的图片长宽也不相同,因此常用的方式是将原始图片统一缩放到一个标准尺寸,在送入检测网络中。
(3)C3
C3代替了yolov5较早版本中使用的CSP,起到作用:简化了体系结构,减少了参数计数,并在推理时更好地利用fuse。这里只画了C3的结构如下(虚线框里的输入输出通道假设为64
分析一下两者区别
SPP(空间金字塔池化):
原论文解读在 SPPNet,这里的SPP是借鉴了SPPNet中的模块,使用不同kernel的池化层对featuremap进行信息提取然后concat。具体的如下:
1)先在通过一个ConvBNSiLU。
2)然后分别通过三个MaxPool2D,默认stride=1,且进行padding,如此整个过程不会改变featuremap的尺寸;
对应的kernel分别为5,9,13,对应的感受野分别为5*5,9*9,13*13。
3)然后进行concat,再通过ConvBNSiLU得到模块最后的输出。
SPPF:
与SPP不同的是MaxPool2D的堆叠方式。
对于9*9的MaxPool2D 等价与 两个5*5的MaxPoolD2D的堆叠;13*13的MaxPoolD等价于三个5*5的MaxPoolD2D的堆叠,可将SPP的结构修改成下图左图;然后对左图是对右图的pool进行了合并连接。其中左图是完全等价SPP的,右图是则SPPF,与上图右图完全一致。
如此,SPPF相较于SPP的效果精度并未改变的同时,节省了三个k=5的MaxPool2D的计算,较大的提升了运行时间
(5)neck模块
neck模块部分, 包含 FPN (Feature Pyramid Network)、PAN (Path Aggregation Network)。两者都是在解决目标检测中 多尺度检测任务上的不足,都是将高层的语义信息与低层的空间信息结合,然后再进行信息提取。换句话说就是 自上而下或自下而上地融合不同尺度信息的特征。
FPN和PAN都有对应的论文和完整的网络结构,但在后来的使用中,很少指原论文中的网络结构,而是来强调 不同特征进行融合的模块。FPN是unsample+merge,PAN是downsample+merge,其中merge有add、concat,具体为哪种形式看每个工程自己的使用情况。在yolov5中,使用的是conca
(6)PAN
Path Aggregation Network是由Megvii在2018年提出的一种处理多尺度问题的方法。与FPN类似,PAN也是一种金字塔式的特征提取网络,但是它采用的是自下而上的特征传播方式。
(7)head
对于检测头,就是一个ConvBNSiLU,然后得到神经网络的输出。
共有三个尺度的输出分别为 1x255x20x20、1x255x40x40、1x255x80x80。其中
【1】 为batch
【255】 为 (80+1+4)*3:
【80:class】 为coco数据集中目标检测的类别数,将其转换成one-hot形式;
【1:confidence】 为是否为目标;
【4:box】 为检测框对应的xywh,具体的为:xy检测框的中心下采样到某层输出上,距离grid ceil 左上角的偏移,wh为检测框的长宽与当前anchor的长宽的比值。
【3】 为在每个grid cell 上预测3个检出信息,分别对应3个anchor。
【80x80/40x40/20x20】不同降采样层的输出尺寸,80x80对应有80x80个grid cell。
- 标签的正样本分配
首先回一下 anchor的相关内容。在yolov5中会先匹配数据集中的anchor和工程中默认的anchor,如果差异较大,则启动自动计算anchor操作。
已知特征图尺寸越大,感受野相对较小。遵循“大尺寸预测小物体,小尺寸预测大物体”的原则,将9个anchor分配到3个输出层,平均每层3个anchor。
当我们有了一个标签[class, x,y,w,h],那么我们将它与网络输出矩阵的哪些维度进行loss呢?
标签的wh:决定了与网络输出的哪一层哪一个anchor对应的维度进行匹配。
标签的xy:决定了与网络输出的哪一grid_ceil进行匹配,然后再进行正样本扩充
标签的class:决定了onehot的表达
(9) 模型输出的box转换
网络的输出矩阵的元素,会经过sigmoid函数,将其范围处理到(0,1)之间。上面代码处理后,标签和匹配的anchor是的尺寸是【原图尺寸下的标签尺寸下采样到某一个输出层时的尺寸】(这里的原图尺寸 指的是图片像素级resize到神经网络输入时的尺寸,代码中备注的也是)。
两者是不对齐,是不能进行loss的。那么就需要将网络输出的xywh转换成与标签尺度一致的尺寸。
五 YOLOV5网络模型训练过程及代码分析
YOLOv5(You Only Look Once, Version 5)是一种流行的目标检测模型,其训练过程主要涉及数据准备、模型定义、损失函数设置、优化器选择以及训练和验证等步骤。以下是YOLOv5网络模型训练过程的一个概述以及相关代码分析:
1.数据准备
在训练YOLOv5之前,首先需要准备数据集,通常包括图像和相应的标注文件。标注文件包含图像中每个目标的边界框坐标和类别信息。
代码分析:
```python
# 加载数据集
dataset = LoadImagesAndLabels(path='data/train', img_size=640)
# 数据增强
augmentations = Albumentations([
RandomCrop(height=640, width=640),
RandomHorizontalFlip(p=0.5),
RandomBrightnessContrast(p=0.2),
# ... 其他数据增强操作
])
```
2.模型定义
YOLOv5模型主要由四个部分组成:Backbone、Neck、Head 和 Prediction。Backbone 用于提取特征,Neck 用于融合特征,Head 用于生成预测结果。
#### 代码分析:
```python
# 加载预训练的YOLOv5模型
model = torch.hub.load('ultralytics/yolov5', 'yolov5s', pretrained=True)
# 修改模型配置(如果需要)
model.yaml['anchors'] = 'data/anchors.yaml'
model.yaml['hyp'] = 'data/hyps/hyp.scratch.yaml'
```
3.损失函数设置
YOLOv5使用的损失函数主要包括分类损失、对象损失和边界框损失。常见的损失函数有交叉熵损失(CrossEntropyLoss)和CIoU Loss。
代码分析:
```python
# 定义损失函数
criterion = YOLOv5Loss()
# 其中YOLOv5Loss可能是一个自定义的损失函数,它组合了多个损失项
```
4.优化器选择
在训练过程中,通常使用Adam或SGD作为优化器。
#### 代码分析:
```python
# 选择优化器
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
```
5. 训练和验证
训练YOLOv5通常涉及多个epoch,每个epoch中会对数据集进行多次迭代。
#### 代码分析:
```python
# 训练模型
for epoch in range(num_epochs):
model.train()
for images, targets in dataset:
optimizer.zero_grad()
outputs = model(images)
loss = criterion(outputs, targets)
loss.backward()
optimizer.step()
# 验证模型
model.eval()
with torch.no_grad():
# ... 进行验证操作
```
6.保存和加载模型
训练完成后,模型会被保存,以便后续使用。
#### 代码分析:
```python
# 保存模型
torch.save(model.state_dict(), 'yolov5_model.pth')
# 加载模型
model.load_state_dict(torch.load('yolov5_model.pth'))
```
3.2.4 YOLOV5网络模型推理预测结果
YOLOv5网络模型是一种用于目标检测的深度学习算法,其推理预测过程主要涉及以下步骤:
1.输入处理:将输入图像或视频帧调整到模型要求的尺寸,并进行归一化处理。这一步确保输入数据符合模型的输入要求。
2.特征提取:使用模型的主干网络(Backbone),如CSP-Darknet53,提取图像的特征。主干网络负责从输入图像中学习到丰富的特征表示。
3.特征融合:通过特征融合网络(Neck),如FPN(Feature Pyramid Network)和PAN(Path Aggregation Network),将不同尺度的特征进行融合,以检测不同大小的目标。
4.预测头处理:模型的预测头部分将融合后的特征图转换成检测框的坐标、置信度和类别概率。YOLOv5使用Transformer Prediction Heads (TPH) 或其他类型的预测头来提高检测的准确性。
5.置信度计算:模型为每个预测框计算置信度,该置信度表示模型对预测框中包含目标的信任程度。
6.边界框回归:模型对预测框的坐标进行调整,以更精确地定位目标的位置。
7.阈值过滤:设置一定的置信度阈值,过滤掉置信度低于阈值的预测框,以减少误检。
8.非极大值抑制(NMS):对剩余的预测框进行非极大值抑制,以消除冗余的预测框。这一步骤确保每个目标只有一个检测框与之对应。
9.输出结果:经过上述步骤后,模型输出最终的检测结果,包括每个目标的类别、置信度以及边界框的坐标。
在YOLOv5的推理过程中,以下是我输出的一些预测结果:
(1)检测框坐标:表示目标在图像中的位置,通常以(x, y, width, height)的形式给出。
(2)置信度:表示模型对检测框中包含目标的信心水平,通常是一个0到1之间的数值。
(3)类别标签:模型的预测结果中包含的目标类别,如“人”、“车”、“动物”等。
(4)类别概率:表示模型对每个类别标签的预测概率。
通过这些输出,YOLOv5可以实现对图像或视频中的目标进行实时检测。




更多推荐
所有评论(0)