YoloV5入门学习
鸣谢https://blog.csdn.net/m0_53392188/article/details/119334634以及https://blog.csdn.net/qq_45104603/article/details/121783848
一、 Yolov5的配置与安装
1、电脑配置
联想小新Air 14
设备名称 LAPTOP-US83D2VC
处理器 Intel® Core™ i7-1065G7 CPU @ 1.30GHz 1.50 GHz
机带 RAM 16.0 GB (15.8 GB 可用)
系统类型 64 位操作系统, 基于 x64 的处理器
下面是显卡驱动版本,如下,最高支持CUDA11.2版本。
2、Anaconda环境配置
Anaconda所有版本链接(清华源镜像版)
选择合适版本安装即可,注意勾选添加到环境变量。
3、Pytorch环境配置
注意关闭代理或者检查防火墙!!!(后面由于我有些问题会问gpt,简单关闭代理服务没有退出代理,导致ssh错误,真是头大)
conda create -n pytorch python=3.8
在Anaconda终端的base环境执行该命令,即可创建一个新的pytorch虚拟环境,位置在D:\Anaconda\envs。(这取决于Anaconda的安装位置)执行过程中选择安装基础包,如下:
输入指令:conda env list ,如下图即为安装成功。
激活该环境并安装pytorch-gup版的环境。
conda activate pytorch
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/
conda config --set show_channel_urls yes
由于显卡支持cuda版本太低,所以降低PyTorch和CUDA Toolkit的版本,安装了PyTorch 1.9.0,它支持CUDA 11.1版本。
conda install pytorch=1.9.0 torchvision torchaudio torchaudio
安装一个特定版本的PyTorch,以及相关的图像和音频处理库,并确保它们能够与CUDA 11.1一起正常工作。
conda install pytorch torchvision torchaudio cudatoolkit=11.1
4、Yolov5的安装
下载地址:https://github.com/ultralytics/yolov5,命令行直接克隆。
5、依赖库安装及测试
在Anaconda Prompt中进入YoloV5位置:cd Yolov5,运行当中一种,下面的清华源会快些:
pip install -r requirements.txt
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/
其中需要注意的是torchaudio与torch可能存在版本冲突问题,此时可以运行:pip uninstall torch torchaudio,而后重新下载兼容版本。此时就可以运行detect.py进行初步测试了:
python -u "d:\Yolov5\detect.py
按照提示路径 runs\detect\exp查看图片如下,成功!
6、简单样例的运行
6.1数据集处理
数据集可以使用labelme自行对图片标注,笔者在这里选取了别人制作好的数据集wzry(王者荣耀),数据集内容如图:
数据集需要修改配置文件,可以分别粘贴yolov5/data/coco128.yaml以及yolov5/models/yolov5x.yaml,而后修改nc:标签名个数 names:标签名以及相关路径即可。
6.2训练
在train.py中找到parse_opt函数,调整对应参数:
运行后的结果保存在D:\Yolov5\runs\train\
,如下:
6.3识别
在detect.py中找到parse_opt函数,同样调整对应参数:
运行完成如下,结果在runs/detect/exp查看:
运行识别视频如下:
yolov5初步识别结果
二、Yolov5原理
1、单阶段检测
与两阶段检测器(如Faster R-CNN)不同,它在一个前向传递中直接生成目标边界框和类别预测,不需要提取候选区域和对候选区域进行分类。它的基本检测原理如下:
import torch
from models.experimental import attempt_load
from utils.datasets import letterbox
from utils.general import non_max_suppression, scale_coords
from utils.torch_utils import select_device
# 1. 加载预训练模型
weights = 'yolov5s.pt'
device = select_device('')
model = attempt_load(weights, map_location=device)
model.eval()
# 2. 处理输入图像
img = 'path_to_your_image.jpg'
img_size = 640 # 设定输入图像大小
img = letterbox(img, new_shape=img_size)[0] #将输入图像调整到模型需要的大小
# 3. 将图像转化为 PyTorch Tensor
img = torch.from_numpy(img).to(device)
img = img.float() # 转换为浮点数
img /= 255.0 # 像素值归一化到 [0, 1]
# 4. 前向传递,得到预测结果
img = img.unsqueeze(0) # 添加 batch 维度
pred = model(img)[0]
# 5. 后处理
pred = non_max_suppression(pred, conf_thres=0.4, iou_thres=0.5, classes=None, agnostic=False) #对预测结果进行非极大值抑制,去除重叠的边界框。
# 6. 缩放检测结果坐标
pred[0][:, :4] = scale_coords(img.shape[2:], pred[0][:, :4], img.shape).round()
# 7. 输出检测结果
for det in pred[0]:
print(f'类别 {int(det[5])}, 置信度 {det[4]:.2f}, 位置 {det[:4]}')
2、网格单元
在 YOLOv5 中,网格单元是指将输入图像分割成一个个小方块,每个方块对应网络输出中的一个位置。例如上述简化代码,在整个过程中,pred 中的每一行都对应着一个网格单元,其中包含了对目标的预测信息(边界框坐标、类别概率等),在每个网格单元中进行预测,从而实现了Yolov5单阶段目标检测。
3、Anchor Boxes(锚定框)
Anchor Boxes(锚定框)是用于在每个网格单元中检测不同尺寸的目标的一组预定义框,它们用于提高模型对不同尺度物体的检测能力。Anchor Boxes 的定义和调整通常在模型的配置文件中进行,比如yolov5/models/yolov5.yaml。在实际项目中,可以选取对应的Model并更改参数,例如上文中的wzry_model:
# yolov5x6.yaml
# Parameters
nc: 10 # 修改处 number of classes
depth_multiple: 1.33 # model depth multiple
width_multiple: 1.25 # layer channel multiple
anchors:
- [19,27, 44,40, 38,94] # P3/8
- [96,68, 86,152, 180,137] # P4/16
- [140,301, 303,264, 238,542] # P5/32
- [436,615, 739,380, 925,792] # P6/64
# YOLOv5 v6.0 backbone
backbone:
# [from, number, module, args]
[[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[-1, 3, C3, [128]],
[-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[-1, 6, C3, [256]],
[-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[-1, 9, C3, [512]],
[-1, 1, Conv, [768, 3, 2]], # 7-P5/32
[-1, 3, C3, [768]],
[-1, 1, Conv, [1024, 3, 2]], # 9-P6/64
[-1, 3, C3, [1024]],
[-1, 1, SPPF, [1024, 5]], # 11
]
# YOLOv5 v6.0 head
head:
[[-1, 1, Conv, [768, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1, 8], 1, Concat, [1]], # cat backbone P5
[-1, 3, C3, [768, False]], # 15
[-1, 1, Conv, [512, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1, 6], 1, Concat, [1]], # cat backbone P4
[-1, 3, C3, [512, False]], # 19
[-1, 1, Conv, [256, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1, 4], 1, Concat, [1]], # cat backbone P3
[-1, 3, C3, [256, False]], # 23 (P3/8-small)
[-1, 1, Conv, [256, 3, 2]],
[[-1, 20], 1, Concat, [1]], # cat head P4
[-1, 3, C3, [512, False]], # 26 (P4/16-medium)
[-1, 1, Conv, [512, 3, 2]],
[[-1, 16], 1, Concat, [1]], # cat head P5
[-1, 3, C3, [768, False]], # 29 (P5/32-large)
[-1, 1, Conv, [768, 3, 2]],
[[-1, 12], 1, Concat, [1]], # cat head P6
[-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge)
[[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6)
]
4、预测输出
每个网格单元的预测输出包括:
边界框坐标(Bounding Box Coordinates):用于确定检测到的目标的位置,如上述代码中的det[:4],是边界框的坐标信息,通常是左上角和右下角的 (x, y) 坐标。
目标得分(Object Confidence):表示该位置是否包含目标,如det[4]。
类别概率(Class Probabilities):预测目标属于每个类别的概率,如det[5]。
5、类别预测
类别预测是模型对每个边界框预测目标所属的类别的过程,它基于模型在训练阶段学到的特征来决定每个边界框可能对应的对象类别。例如det[5] 对应着模型预测的目标类别,这个值通常是一个浮点数,表示模型对每个可能类别的得分。YOLOv5 通常用softmax激活函数来预测每个类别的概率,激活函数可以自己更换调整。
6、非极大值抑制(NMS)
非极大值抑制(Non-Maximum Suppression,NMS)是一种用于目标检测和边界框回归任务中的重要技术,它的目的是消除冗余的边界框,保留最具代表性的边界框,从而提高模型的输出质量。
在目标检测中,模型通常会产生多个重叠的边界框,这些边界框可能对同一个目标进行检测。例如,一个目标可能会被多个不同尺寸和位置的锚框检测到。NMS则可以较好解决这种情况,它的工作步骤简单描述如下:
- 根据预测框的置信度(confidence score)排序,将得分高的框排在前面。
- 选择得分最高的框作为基准框,并将其加入最终输出的结果中。
- 遍历剩余的框,计算它们与基准框的重叠度(IoU,Intersection over Union)。
- 如果某个框的 IoU 大于设定的阈值(通常是一个较小的值,如0.5),则将其舍弃,否则保留。
这样NMS可以消除多余的边界框,使得模型输出的结果更加干净和精确,它可以确保最终的检测结果中每个目标只被检测到一次。
Yolov5中NMS相关代码在utils/general.py,如下为部分代码示例:
def non_max_suppression(predictions, conf_thres=0.25, iou_thres=0.45, classes=None, agnostic=False):
"""
对预测框进行非极大值抑制(NMS)。
Args:
predictions (torch.Tensor): 预测框的信息,维度为 (N, 6),包括 (x1, y1, x2, y2, conf, class)。
conf_thres (float): 置信度阈值,低于此阈值的预测框将被忽略。
iou_thres (float): IoU 阈值,用于控制保留哪些重叠较小的边界框。
classes (int or list): 指定要保留的类别。
agnostic (bool): 是否进行类别不可知的 NMS。
Returns:
torch.Tensor: 经过非极大值抑制后保留的预测框。
"""
使用NMS,可以在代码中导入相应的函数并调用即可:
from utils.general import non_max_suppression
# 在适当的地方使用 non_max_suppression 函数
selected_boxes = non_max_suppression(predictions, conf_thres=0.25, iou_thres=0.45, classes=None, agnostic=False)
7、Backbone 网络
在 YOLOv5 中,Backbone 网络采用了一种称为 CSPDarknet53 的网络架构,这是一个专门为目标检测任务设计的 Backbone。它有如下主要几点:
1. CSPNet 结构:
- CSPDarknet53 使用了一个名为 CSPNet(Cross Stage Partial Network)的结构,它将输入特征图分成两部分,然后将其中一部分送入一个小型的网络(CSPNet)中进行处理,这种结构可以提高特征的传播和信息交流。
2. 特征金字塔:
- YOLOv5 使用了 PANet(Path Aggregation Network)结构来构建特征金字塔,以便在不同尺度上检测目标。
3. 预训练模型:
- CSPDarknet53 在 YOLOv5 中通常会使用预训练的权重来初始化网络参数,这些权重是在大规模图像数据集上进行预训练的。
from models.common import Conv, CSPDarknet
# 创建 CSPDarknet53 实例
backbone = CSPDarknet(depth=53)
# 打印网络结构
print(backbone)
上述代码中,我导入了 YOLOv5 中的 CSPDarknet53 模型,并创建了一个实例,可以根据需要调整 depth
参数来选择不同深度的网络,相关具体代码位于models/common.py。
8、训练策略
YOLOv5 使用自监督训练方法,利用大量的已标记数据进行训练,包括:
- 数据预处理:
YOLOv5 在训练之前会对输入数据进行预处理,将图像调整到模型能够接受的大小,同时进行归一化等操作。
# 在 YOLOv5 中,数据预处理由datasets工具完成
from utils.datasets import LoadImagesAndLabels
# 加载图像并进行预处理
dataset = LoadImagesAndLabels(train_path, img_size=640, batch_size=16, augment=True)
- 损失函数:
YOLOv5 使用了一种组合损失函数,包括了目标分类损失、目标位置损失和置信度损失,这些损失函数共同衡量了模型在目标检测任务上的性能。
# YOLOv5中的损失函数实现在models/yolo.py中
from models.yolo import compute_loss
# 在训练循环中计算损失
loss, loss_items = compute_loss(pred, targets, model)
- 学习率调整:
YOLOv5 采用了学习率调整策略,通常会在训练的不同阶段逐渐减小学习率,以帮助模型收敛到更好的解。
# YOLOv5中的学习率调整策略在utils/general.py中
from utils.general import adjust_learning_rate
# 在训练循环中调整学习率
adjust_learning_rate(optimizer, epoch, total_epochs)
- 数据增强:
在训练过程中,YOLOv5 会通过数据增强技术来扩充训练集,包括随机变换、缩放、裁剪等操作,以提升模型的泛化能力。
# 数据增强在datasets工具中实现
from utils.datasets import LoadImagesAndLabels
# 在加载数据时应用数据增强
dataset = LoadImagesAndLabels(train_path, img_size=640, batch_size=16, augment=True)
- 类别平衡:
YOLOv5 通常会采用一些方法来处理类别不平衡的问题,例如使用权重调整或采样技巧。
# 在 YOLOv5 中,可以使用权重调整来处理类别不平衡
# 例如在损失函数中为每个类别设置不同的权重
class_weights = [1.0, 2.0, 0.5, ...]
- 模型初始化:
YOLOv5 通常会使用预训练的权重来初始化模型的参数,这可以加速训练过程并提升模型性能。
# YOLOv5模型的初始化通常在train.py中完成
# 可以使用预训练的权重来初始化模型
model = Model(cfg)
model.load_state_dict(torch.load(weights))
- 监控与评估:
训练过程中,通常会使用验证集来监控模型的性能,并在必要时进行调整。
# 在训练循环中,可以使用验证集来监控模型性能
# 例如计算验证集上的损失或其他指标
val_loss = validate(model, val_dataloader)
- 批量训练:
YOLOv5 通常会使用小批量训练技巧,这可以加速训练过程并降低内存消耗。
# YOLOv5中通常会使用小批量训练技巧
# 在训练循环中使用适当的批量大小
for i, (imgs, targets, paths, _) in enumerate(dataloader):
...
- 终止条件:
训练会在满足一定的停止条件后结束,例如达到最大训练轮数或者验证集性能不再提升。
# 训练过程中,可以设置终止条件来控制训练的停止
# 例如达到最大训练轮数或者验证集性能不再提升时终止训练
if epoch > max_epochs or early_stopping(val_loss):
break