一、前言
本文内含YOLOv10网络结构图 + 各个创新模块手撕结构图 + 训练教程 + 推理教程 + 参数解析 + 环境搭建 + 数据集获取等一些有关YOLOv10的内容!
目录
一、 前言
二、整体网络结构图
三、空间-通道分离下采样
3.1 SCDown介绍
3.2 C2fUIB介绍
3.3 PSA介绍
4.4 更多YOLOv10内容介绍
四、环境搭建
五、数据集获取
六、模型获取
七、模型训练
7.1 训练的三种方式
7.1.1 方式一
7.1.2 方式二(推荐)
7.1.3 方式三
八、模型验证/测试
九、模型推理
十、模型输出
十一、全文总结
论文地址:官方论文地址点击此处即可跳转
代码地址:官方代码地址点击此处即可跳转
二、整体网络结构图
三、空间-通道分离下采样
论文中主要提出了三个创新的结构分别是C2fUIB、PSA、SCDown,下面分别来介绍一下这三个主要的创新模块
3.1 SCDown介绍
YOLO通常利用带有步幅2的常规3×3标准卷积,同时实现空间下采样(从H×W到H/2×W/2)和通道变换(从C到2C)。这引入了不可忽视的计算成本和参数数量相反,我们提出分离空间减少和通道增加操作,进行更高效的下采样。具体而言,我们首先利用点卷积调整通道维度,然后利用深度卷积进行空间下采样。这将计算成本减少到和参数数量减少到。同时,这最大限度地保留了下采样过程中的信息,从而在减少延迟的同时实现竞争性性能。
3.2 C2fUIB介绍
YOLO通常为所有阶段使用相同的基本构建块,例如YOLOv8中的瓶颈块。为全面检查这种同质设计的冗余,我们利用内在秩分析各阶段的冗余。具体而言,我们计算每个阶段最后一个基本块的最后一个卷积的数值秩,表示超过阈值的奇异值数量。图3.(a)展示了YOLOv8的结果,表明深层阶段和大模型往往表现出更多冗余。此观察表明,简单地为所有阶段应用相同的块设计对于最佳的容量-效率权衡来说是次优的。为此,我们提出了一种基于秩的块设计方案,旨在通过紧凑的架构设计减少冗余阶段的复杂性。我们首先提出了一种紧凑的倒置块(CIB)结构,它采用廉价的深度卷积进行空间混合,并采用成本效益高的点卷积进行通道混合,如图3.(b)所示。它可以作为高效的基本构建块,例如嵌入ELAN结构中。然后,我们倡导一种基于秩的块分配策略,以在保持竞争性容量的同时实现最佳效率。具体而言,给定一个模型,我们按内在秩从低到高排序其所有阶段。我们进一步检查用CIB替换领先阶段的基本块的性能变化。如果与给定模型相比没有性能下降,我们继续替换下一个阶段,否则停止该过程。这样,我们可以在各个阶段和模型规模中实现自适应紧凑块设计,在不影响性能的情况下实现更高的效率(这个结构外部结构是和C2f一样只是用CIB结构替换了C2f的Bottleneck结构)。
class CIB(nn.Module):
"""Standard bottleneck."""
def __init__(self, c1, c2, shortcut=True, e=0.5, lk=False):
"""Initializes a bottleneck module with given input/output channels, shortcut option, group, kernels, and
expansion.
"""
super().__init__()
c_ = int(c2 * e) # hidden channels
self.cv1 = nn.Sequential(
Conv(c1, c1, 3, g=c1),
Conv(c1, 2 * c_, 1),
Conv(2 * c_, 2 * c_, 3, g=2 * c_) if not lk else RepVGGDW(2 * c_),
Conv(2 * c_, c2, 1),
Conv(c2, c2, 3, g=c2),
)
self.add = shortcut and c1 == c2
def forward(self, x):
"""'forward()' applies the YOLO FPN to input data."""
return x + self.cv1(x) if self.add else self.cv1(x)
class C2fCIB(nn.Module):
"""Faster Implementation of CSP Bottleneck with 2 convolutions."""
def __init__(self, c1, c2, n=1, shortcut=False, lk=False, g=1, e=0.5):
"""Initialize CSP bottleneck layer with two convolutions with arguments ch_in, ch_out, number, shortcut, groups,
expansion.
"""
super().__init__()
self.c = int(c2 * e) # hidden channels
self.cv1 = Conv(c1, 2 * self.c, 1, 1)
self.cv2 = Conv((2 + n) * self.c, c2, 1) # optional act=FReLU(c2)
self.m = nn.ModuleList(CIB(self.c, self.c, shortcut, e=1.0, lk=lk) for _ in range(n))
def forward(self, x):
"""Forward pass through C2f layer."""
y = list(self.cv1(x).chunk(2, 1))
y.extend(m(y[-1]) for m in self.m)
return self.cv2(torch.cat(y, 1))
def forward_split(self, x):
"""Forward pass using split() instead of chunk()."""
y = list(self.cv1(x).split((self.c, self.c), 1))
y.extend(m(y[-1]) for m in self.m)
return self.cv2(torch.cat(y, 1))
3.3 PSA介绍
自注意力在各种视觉任务中得到了广泛应用,因为它具有显著的全局建模能力。然而,自注意力机制表现出较高的计算复杂度和内存占用。为了解决这个问题,鉴于注意力头冗余的普遍存在,我们提出了一种高效的部分自注意力(PSA)模块设计,如图3(c)所示。
具体来说,我们通过1×1卷积将特征均匀地划分为两部分。然后,我们仅将其中一部分输入到由多头自注意力模块(MHSA)和前馈网络(FFN)组成的NPSA块中。两部分特征随后被连接并通过1×1卷积融合。此外,我们遵循将MHSA中查询和键的维度分配为值的一半,并将LayerNorm替换为BatchNorm以加快推理速度。
PSA仅在分辨率最低的Stage 4之后放置,以避免自注意力二次复杂性带来的过多开销。通过这种方式,可以在低计算成本下将全局表示学习能力引入YOLO模型,从而增强模型能力并提高性能。
通过这些精度驱动的设计,我们能够在不显著增加计算成本的情况下提升YOLO模型的性能。
class Attention(nn.Module):
def __init__(self, dim, num_heads=8,
attn_ratio=0.5):
super().__init__()
self.num_heads = num_heads
self.head_dim = dim // num_heads
self.key_dim = int(self.head_dim * attn_ratio)
self.scale = self.key_dim ** -0.5
nh_kd = nh_kd = self.key_dim * num_heads
h = dim + nh_kd * 2
self.qkv = Conv(dim, h, 1, act=False)
self.proj = Conv(dim, dim, 1, act=False)
self.pe = Conv(dim, dim, 3, 1, g=dim, act=False)
def forward(self, x):
B, _, H, W = x.shape
N = H * W
qkv = self.qkv(x)
q, k, v = qkv.view(B, self.num_heads, -1, N).split([self.key_dim, self.key_dim, self.head_dim], dim=2)
attn = (
(q.transpose(-2, -1) @ k) * self.scale
)
attn = attn.softmax(dim=-1)
x = (v @ attn.transpose(-2, -1)).view(B, -1, H, W) + self.pe(v.reshape(B, -1, H, W))
x = self.proj(x)
return x
class PSA(nn.Module):
def __init__(self, c1, c2, e=0.5):
super().__init__()
assert(c1 == c2)
self.c = int(c1 * e)
self.cv1 = Conv(c1, 2 * self.c, 1, 1)
self.cv2 = Conv(2 * self.c, c1, 1)
self.attn = Attention(self.c, attn_ratio=0.5, num_heads=self.c // 64)
self.ffn = nn.Sequential(
Conv(self.c, self.c*2, 1),
Conv(self.c*2, self.c, 1, act=False)
)
def forward(self, x):
a, b = self.cv1(x).split((self.c, self.c), dim=1)
b = b + self.attn(b)
b = b + self.ffn(b)
return self.cv2(torch.cat((a, b), 1))
4.4 更多YOLOv10内容介绍
由于篇幅内容不宜太多,更多有关YOLOv10的内容介绍可以看我的另一篇文章介绍的十分详细!
YOLOv10详细解读 | 一文带你深入了解yolov10的创新点(附网络结构图 + 举例说明) | 点击即可跳转
四、环境搭建
大家如果没有搭建环境可以看我的另一篇博客,里面讲述了如何搭建pytorch环境。
Win11上Pytorch的安装并在Pycharm上调用PyTorch最新超详细过程并附详细的系统变量添加过程,可解决pycharm中pip不好使的问题
五、数据集获取
在我们开始训练之前,我们需要一份数据集,如何获取一个YOLOv10的数据集大家可以看我的另一篇博客从YOLO官方指定的数据集网站Roboflow下载数据模型训练
超详细教程YoloV8官方推荐免费数据集网站Roboflow一键导出Voc、COCO、Yolo、Csv等格式
我在上面随便下载了一个 数据集用它导出yolov8的数据集,以及自动给转换成txt的格式yaml文件也已经配置好了,我们直接用就可以。
六、模型获取
模型获取的方式,我们需要去Github上面下载压缩包,
我们需要打开如下的网址点击此处即可跳转YOLOv10官方代码网址,我们会出现如下界面!
我们下载完YOLOv10压缩包利用我们自己的IDEA工具打开即可!
在我们配置好环境之后,模型获取完成之后,我们可以进行配置的安装我们可以在命令行下输入如下命令进行环境的配置。
pip install -r requirements.txt
输入如上命令之后我们就可以看到命令行在安装模型所需的库了。
七、模型训练
我们来看一下主要的ultralytics目录结构,
我门打开cfg目录下的default.yaml文件可以配置模型的参数,
在其中和模型训练有关的参数及其解释如下:
参数名 | 输入类型 | 参数解释 | |
---|---|---|---|
0 | task | str | YOLO模型的任务选择,选择你是要进行检测、分类等操作 |
1 | mode | str | YOLO模式的选择,选择要进行训练、推理、输出、验证等操作 |
2 | model | str/optional | 模型的文件,可以是官方的预训练模型,也可以是训练自己模型的yaml文件 |
3 | data | str/optional | 模型的地址,可以是文件的地址,也可以是配置好地址的yaml文件 |
4 | epochs | int | 训练的轮次,将你的数据输入到模型里进行训练的次数 |
5 | patience | int | 早停机制,当你的模型精度没有改进了就提前停止训练 |
6 | batch | int | 我们输入的数据集会分解为多个子集,一次向模型里输入多少个子集 |
7 | imgsz | int/list | 输入的图片的大小,可以是整数就代表图片尺寸为int*int,或者list分别代表宽和高[w,h] |
8 | save | bool | 是否保存模型以及预测结果 |
9 | save_period | int | 在训练过程中多少次保存一次模型文件,就是生成的pt文件 |
10 | cache | bool | 参数cache 用于控制是否启用缓存机制。 |
11 | device | int/str/list/optional | GPU设备的选择:cuda device=0 or device=0,1,2,3 or device=cpu |
12 | workers | int | 工作的线程,Windows系统一定要设置为0否则很可能会引起线程报错 |
13 | name | str/optional | 模型保存的名字,结果会保存到'project/name' 目录下 |
14 | exist_ok | bool | 如果模型存在的时候是否进行覆盖操作 |
15 | prepetrained | bool | 参数pretrained用于控制是否使用预训练模型。 |
16 | optimizer | str | 优化器的选择choices=[SGD, Adam, Adamax, AdamW, NAdam, RAdam, RMSProp, auto] |
17 | verbose | bool | 用于控制在执行过程中是否输出详细的信息和日志。 |
18 | seed | int | 随机数种子,模型中涉及到随机的时候,根据随机数种子进行生成 |
19 | deterministic | bool | 用于控制是否启用确定性模式,在确定性模式下,算法的执行将变得可重复,即相同的输入将产生相同的输出 |
20 | single_cls | bool | 是否是单标签训练 |
21 | rect | bool | 当 rect 设置为 True 时,表示启用矩形训练或验证。矩形训练或验证是一种数据处理技术,其中在训练或验证过程中,输入数据会被调整为具有相同宽高比的矩形形状。 |
22 | cos_lr | bool | 控制是否使用余弦学习率调度器 |
23 | close_mosaic | int | 控制在最后几个 epochs 中是否禁用马赛克数据增强 |
24 | resume | bool | 用于从先前的训练检查点(checkpoint)中恢复模型的训练。 |
25 | amp | bool | 用于控制是否进行自动混合精度 |
26 | fraction | float | 用于指定训练数据集的一部分进行训练的比例。默认值为 1.0 |
27 | profile | bool | 用于控制是否在训练过程中启用 ONNX 和 TensorRT 的性能分析 |
28 | freeze | int/list/optinal | 用于指定在训练过程中冻结前 n 层或指定层索引的列表,以防止它们的权重更新。这对于迁移学习或特定层的微调很有用。 |
7.1 训练的三种方式
7.1.1 方式一
我们可以通过命令直接进行训练在其中指定参数,但是这样的方式,我们每个参数都要在其中打出来。命令如下:
yolo task=detect mode=train model=yolov10n.yaml data=替换你数据集的yaml文件地址 batch=16 epochs=100 imgsz=640 workers=0 device=0
需要注意的是如果你是Windows系统的电脑其中的Workers最好设置成0否则容易报线程的错误。
7.1.2 方式二(推荐)
通过指定cfg直接进行训练,我们配置好ultralytics/cfg/default.yaml这个文件之后,可以直接执行这个文件进行训练,这样就不用在命令行输入其它的参数了。
yolo cfg=ultralytics/cfg/default.yaml
7.1.3 方式三
我们可以通过创建py文件来进行训练,这样的好处就是不用在终端上打命令,这也能省去一些工作量,我们在根目录下创建一个名字为run.py的文件,在其中输入代码
from ultralytics import YOLO
model = YOLO("权重的地址 or 模型配置文件的地址")
data = "数据集文件Yaml文件的地址"
model.train(data=data, epochs=100, batch=16)
无论通过上述的哪一种方式在控制台输出如下图片的内容就代表着开始训练成功了!
八、模型验证/测试
参数名 | 类型 | 参数讲解 | |
---|---|---|---|
1 | val | bool | 用于控制是否在训练过程中进行验证/测试。 |
2 | split | str | 用于指定用于验证/测试的数据集划分。可以选择 'val'、'test' 或 'train' 中的一个作为验证/测试数据集 |
3 | save_json | bool | 用于控制是否将结果保存为 JSON 文件 |
4 | save_hybird | bool | 用于控制是否保存标签和附加预测结果的混合版本 |
5 | conf | float/optional | 用于设置检测时的目标置信度阈值 |
6 | iou | float | 用于设置非极大值抑制(NMS)的交并比(IoU)阈值。 |
7 | max_det | int | 用于设置每张图像的最大检测数。 |
8 | half | bool | 用于控制是否使用半精度(FP16)进行推断。 |
9 | dnn | bool | ,用于控制是否使用 OpenCV DNN 进行 ONNX 推断。 |
10 | plots | bool | 用于控制在训练/验证过程中是否保存绘图结果。 |
验证我们划分的验证集/测试集的情况,也就是评估我们训练出来的best.pt模型好与坏
yolo task=detect mode=val model=best.pt data=data.yaml device=0
九、模型推理
我们训练好自己的模型之后,都会生成一个模型文件,保存在你设置的目录下,当我们再次想要实验该模型的效果之后就可以调用该模型进行推理了,我们也可以用官方的预训练权重来进行推理。
推理的方式和训练一样我们这里就选一种来进行举例其它的两种方式都是一样的操作只是需要改一下其中的一些参数即可:
参数讲解
参数名 | 类型 | 参数讲解 | |
---|---|---|---|
0 | source | str/optinal | 用于指定图像或视频的目录 |
1 | show | bool | 用于控制是否在可能的情况下显示结果 |
2 | save_txt | bool | 用于控制是否将结果保存为 .txt 文件 |
3 | save_conf | bool | 用于控制是否在保存结果时包含置信度分数 |
4 | save_crop | bool | 用于控制是否将带有结果的裁剪图像保存下来 |
5 | show_labels | bool | 用于控制在绘图结果中是否显示目标标签 |
6 | show_conf | bool | 用于控制在绘图结果中是否显示目标置信度分数 |
7 | vid_stride | int/optional | 用于设置视频的帧率步长 |
8 | stream_buffer | bool | 用于控制是否缓冲所有流式帧(True)或返回最新的帧(False) |
9 | line_width | int/list[int]/optional | 用于设置边界框的线宽度,如果缺失则自动设置 |
10 | visualize | bool | 用于控制是否可视化模型的特征 |
11 | augment | bool | 用于控制是否对预测源应用图像增强 |
12 | agnostic_nms | bool | 用于控制是否使用无关类别的非极大值抑制(NMS) |
13 | classes | int/list[int]/optional | 用于按类别筛选结果 |
14 | retina_masks | bool | 用于控制是否使用高分辨率分割掩码 |
15 | boxes | bool | 用于控制是否在分割预测中显示边界框。 |
yolo task=detect mode=predict model=best.pt source=images device=0
这里需要需要注意的是我们用模型进行推理的时候可以选择照片也可以选择一个视频的格式都可以。支持的视频格式有
MP4(.mp4):这是一种常见的视频文件格式,通常具有较高的压缩率和良好的视频质量
AVI(.avi):这是一种较旧但仍广泛使用的视频文件格式。它通常具有较大的文件大小
MOV(.mov):这是一种常见的视频文件格式,通常与苹果设备和QuickTime播放器相关
MKV(.mkv):这是一种开放的多媒体容器格式,可以容纳多个视频、音频和字幕轨道
FLV(.flv):这是一种用于在线视频传输的流式视频文件格式
十、模型输出
当我们进行部署的时候可以进行文件导出,然后在进行部署。
YOLOv8支持的输出格式有如下
1. ONNX(Open Neural Network Exchange):ONNX 是一个开放的深度学习模型表示和转换的标准。它允许在不同的深度学习框架之间共享模型,并支持跨平台部署。导出为 ONNX 格式的模型可以在支持 ONNX 的推理引擎中进行部署和推理。
2. TensorFlow SavedModel:TensorFlow SavedModel 是 TensorFlow 框架的标准模型保存格式。它包含了模型的网络结构和参数,可以方便地在 TensorFlow 的推理环境中加载和使用。
3. PyTorch JIT(Just-In-Time):PyTorch JIT 是 PyTorch 的即时编译器,可以将 PyTorch 模型导出为优化的 Torch 脚本或 Torch 脚本模型。这种格式可以在没有 PyTorch 环境的情况下进行推理,并且具有更高的性能。
4. Caffe Model:Caffe 是一个流行的深度学习框架,它使用自己的模型表示格式。导出为 Caffe 模型的文件可以在 Caffe 框架中进行部署和推理。
5. TFLite(TensorFlow Lite):TFLite 是 TensorFlow 的移动和嵌入式设备推理框架,支持在资源受限的设备上进行高效推理。模型可以导出为 TFLite 格式,以便在移动设备或嵌入式系统中进行部署。
6. Core ML(Core Machine Learning):Core ML 是苹果的机器学习框架,用于在 iOS 和 macOS 上进行推理。模型可以导出为 Core ML 格式,以便在苹果设备上进行部署。
这些格式都提供了不同的优势和适用场景。选择合适的导出格式应该考虑到目标平台和部署环境的要求,以及所使用的深度学习框架的支持情况。
模型输出的参数有如下
参数名 | 类型 | 参数解释 | |
---|---|---|---|
0 | format | str | 导出模型的格式 |
1 | keras | bool | 表示是否使用Keras |
2 | optimize | bool | 用于在导出TorchScript模型时进行优化,以便在移动设备上获得更好的性能 |
3 | int8 | bool | 用于在导出CoreML或TensorFlow模型时进行INT8量化 |
4 | dynamic | bool | 用于在导出CoreML或TensorFlow模型时进行INT8量化 |
5 | simplify | bool | 用于在导出ONNX模型时进行模型简化 |
6 | opset | int/optional | 用于指定导出ONNX模型时的opset版本 |
7 | workspace | int | 用于指定TensorRT模型的工作空间大小,以GB为单位 |
8 | nms | bool | 用于在导出CoreML模型时添加非极大值抑制(NMS) |
命令行命令如下:
yolo task=detect mode=export model=best.pt format=onnx
到此为止本文的讲解就结束了,希望对大家对于YOLOv8模型理解有帮助,希望本文能够帮助到大家。
十一、全文总结
到此本文的正式分享内容就结束了,在这里给大家推荐我的YOLOv10改进有效涨点专栏,本专栏目前为新开的,后期我会根据各种最新的前沿顶会进行论文复现,也会对一些老的改进机制进行补充,如果大家觉得本文帮助到你了,订阅本专栏,关注后续更多的更新~
专栏目录:YOLOv10改进有效专栏 | 持续复现前沿机制