# 一、YOLOv8 的简介
YOLO(You Only Look Once)系列算法因其高效、准确等特点而备受瞩目。由 2023 年 Ultralytics 公司发布了 YOLO 的最新版本 YOLOv8 是结合前几代 YOLO 的基础上的一个融合改进版。
本文 YOLOv8 网络结构 / 环境搭建 / 数据集获取 / 训练 / 推理 / 验证 / 导出 / 部署,从网络结构的讲解从模型的网络结构讲解到模型的部署都有详细介绍,同时在本专栏中还包括 YOLOv8 模型系列的改进包括个人提出的创新点,传统卷积、注意力机制、损失函数的修改教程,能够帮助你的论文获得创新点。
# 二、YOLOv8 相对于 Yolov5 的核心改动
从 YOLOv8 的网络结构可以看出,其延用了 YOLOv5 的网络结构思想,包括基于 CSP(紧凑和分离)的骨干网络 (backbone) 和 Neck 部分的设计,以及对于不同尺度模型的考虑。
改进总结:
Backbone 的改进:使用 C2f 模块代替 C3 模块,进一步轻量化,同时保持了 CSP 的思想,同时采用了 SPPF 模块。
PAN-FPN 的改进:保留了 PAN 的思想,但删除了上采样阶段中的卷积结构,同时将 C3 模块替换为 C2f 模块。
Decoupled-Head 的引入:采用了 Decoupled-Head 的思想,使得网络的训练和推理更加高效。
Anchor-Free 的思想:抛弃了 Anchor-Base,采用了 Anchor-Free 的思想。
损失函数的改进:采用 VFL Loss 作为分类损失,同时使用 DFL Loss 和 CIOU Loss 作为回归损失。
样本匹配方式的改进:采用了 Task-Aligned Assigner 匹配方式。
这些改进使得 YOLOv8 在目标检测方面具有更高的精度和更快的速度,同时保持了轻量化的特点。
具体来说,YOLOv8 的 Backbone 部分使用了 C2f 模块来替代了 YOLOv5 中的 C3 模块,实现了进一步的轻量化。同时,它也保留了 YOLOv5 等架构中使用的 SPPF(空间金字塔池化)模块。
在 PAN-FPN(路径聚合网络 - 特征金字塔网络)部分,虽然 YOLOv8 依旧采用了 PAN 的思想,但是在结构上,它删除了 YOLOv5 中 PAN-FPN 上采样阶段中的卷积结构,并将 C3 模块替换为了 C2f 模块。
这些改进使得 YOLOv8 在保持了 YOLOv5 网络结构的优点的同时,进行了更加精细的调整和优化,提高了模型在不同场景下的性能。
# 三、YOLOv8 的网络结构
YOLOv8 的网络结构主要由以下三个大部分组成:
Backbone:它采用了一系列卷积和反卷积层来提取特征,同时也使用了残差连接和瓶颈结构来减小网络的大小和提高性能。该部分采用了 C2f 模块作为基本构成单元,与 YOLOv5 的 C3 模块相比,C2f 模块具有更少的参数量和更优秀的特征提取能力。
Neck:它采用了多尺度特征融合技术,将来自 Backbone 的不同阶段的特征图进行融合,以增强特征表示能力。具体来说,YOLOv8 的 Neck 部分包括一个 SPPF 模块、一个 PAA 模块和两个 PAN 模块。
Head:它负责最终的目标检测和分类任务,包括一个检测头和一个分类头。检测头包含一系列卷积层和反卷积层,用于生成检测结果;分类头则采用全局平均池化来对每个特征图进行分类。
下面我们来针对于 YOLOv8 的三个组成部分进行详细讲解。
# 3.1 Backbone
由最上面的 YOLOv8 网络结构图我们可以看出在其中的 Backbone 部分,由 5 个卷积模块和 4 个 C2f 模块和一个 SPPF 模块组成,
(其中浅蓝色为卷积模块,黄色为 C2f 模块深蓝色为 SPPF 模块)
如果上图看的不够直观,我们来看一下 YOLOv8 的文件中的 yaml 文件,看一下它 backbone 部分的结构组成部分,会更加直观。
1 | backbone: |
上面的部分就是 YOLOv8 的 yaml 文件的 Backbone 部分,可以看到其由 5 个 Conv 模块,四个 C2f 模块以及一个 SPPF 模块组成,下面我们来根据每个模块的组成来进行讲解。
# 3.1.1 卷积模块 (Conv)
在其中卷积模块的结构主要为下图
在其中主要结构为一个 2D 的卷积一个 BatchNorm2d 和一个 SiLU 激活函数,整个卷积模块的作用为:
- 降采样:每个卷积模块中的卷积层都采用步长为 2 的卷积核进行降采样操作,以减小特征图的尺寸并增加通道数。
- 非线性表示:每个卷积层之后都添加了 Batch Normalization(批标准化)层和 ReLU 激活函数,以增强模型的非线性表示能力。
在其中 Batch Normalization(批标准化)是深度学习中常用的一种技术,用于加速神经网络的训练。Batch Normalization 通过对每个小批量数据进行标准化,使得神经网络在训练过程中更加稳定,可以使用更高的学习率,并且减少了对初始化权重的依赖。Batch Normalization 的基本思想是:对每个小批量数据进行标准化,使得每个特征的均值为 0,方差为 1,然后再通过一个可学习的缩放因子和平移因子来调整数据的分布,从而使得神经网络更容易训练。
# 3.1.2 C2f 模块
在 YOLOv8 的网络结构中 C2f 模块算是 YOLOv8 的一个较大的改变,与 YOLOv5 的 C3 模块相比,C2f 模块具有更少的参数量和更优秀的特征提取能力。下图为 C2f 的内部网络结构图。
在 C2f 模块中我们可以看到输入首先经过一个 k=1,s=1,p=0,c=c_out 的卷积模块进行了处理,然后经过一个 split 处理 **(在这里 split 和后面的 concat 的组成其实就是所谓的残差模块处理)** 经过数量为 n 的 DarknetBottleneck 模块处理以后将残差模块和主干模块的结果进行 Concat 拼接在经过一个卷积模块处理进行输出。
在其中提到的残差连接(residual connections)是一种用于构建深层神经网络的技术。它的核心思想是通过跳过层级连接来传递残差或误差。
在传统的神经网络中,信息流通过一层层的网络层,每一层都通过非线性激活函数进行转换和提取特征。然而,随着神经网络的加深,可能会出现 "梯度消失" 或 "梯度爆炸" 的问题,导致网络收敛困难或性能下降。
残差连接通过引入跨层级的连接,将输入的原始信息直接传递到后续层级,以解决梯度消失和爆炸问题。具体而言,它将网络的输入与中间层的输出相加,形成了一个 "捷径" 或 "跳跃连接",从而允许梯度更容易地传播。
数学上,假设我们有一个输入 x,通过多个网络层进行处理后得到预测值 H (x)。那么残差连接的表达式为:
F(x) = H(x) + x
其中,F (x) 为残差块的输出,H (x) 为经过一系列网络层处理后得到的特征表示,x 为输入直接连接到残差块中的跳跃连接。
通过残差连接,网络可以更容易地学习残差或误差,从而使网络更深层次的特征表达更准确。这对于训练深层神经网络非常有用,可以提高网络的性能和收敛速度。
在 C2f 模块中用到的 DarknetBottleneck 模块其中使用多个 3x3 卷积核进行卷积操作,提取特征信息。同时其具有 add 是否进行残差链接的选项。
其实整个 C2f 模块就是一个改良版本的 Darknet
-
首先,使用 1x1 卷积核将输入通道数减少到原来的 1/2,以减少计算量和内存消耗。
-
然后,使用多个 3x3 卷积核进行卷积操作,提取特征信息。
-
接着,使用残差链接,将输入直接加到输出中,从而形成了一条跨层连接。
-
接着,再次使用 1x1 卷积核恢复特征图的通道数。
SPPF 模块
YOLOv8 的 SPPF 模块相对于 YOLOv5 的 SPPF 模块并没有任何的改变。
# 3.2 Neck
YOLOv8 的 Neck 部分是该模型中的一个关键组件,它在特征提取和融合方面起着重要作用。Neck 的详细描述如下:
Neck 部分主要起到一个特征融合的操作, YOLOv8 的 Neck 部分依然采用 PAN-FPN 的思想,下图的 a,b,c 为一个 Neck 部分的流程示意图。
整个 Neck 部分的步骤如下::将特征提取网络 (Backbone) 的输出 P3,P4,P5 输入进 PAN-FPN 网络结构,使得多个尺度的特征图进行融合;将 P5 经过上采样与 P4 进行融合得到 F1,将 F1 经过 C2f 层和一次上采样与 P3 进行融合得到 T1,将 T1 经过一次卷积层与 F1 经过融合得到 F2,将 F2 经过一次 C2f 层得到 T2,将 T2 经过一次卷积层与 P5 融合得到 F3,将 F3 经过一次 C2f 层得到 T3,最终得到 T1、T2、T3 就是整个 Neck 的产物;
上述过程可以描述为下图,我在图片上做了一些标准方便理解。
上述的过程可以在代码部分看到,我们同样看 YOLOv8 的 yaml 文件,能够更直观的看到这个步骤,大家可以看代码同时对应图片来进行分析:
1 | head: |
Neck 部分的整体功能的详细分析如下:
1. Neck 的作用:
Neck 部分在 YOLOv8 模型中负责对来自 Backbone 的特征进行进一步处理和融合,以提高目标检测的准确性和鲁棒性。它通过引入不同的结构和技术,将多尺度的特征图进行融合,以便更好地捕捉不同尺度目标的信息。
2. 特征金字塔网络(Feature Pyramid Network, FPN):
YOLOv8 的 Neck 部分通常采用特征金字塔网络结构,用于处理来自 Backbone 的多尺度特征图。FPN 通过在不同层级上建立特征金字塔,使得模型能够在不同尺度上进行目标检测。它通过上采样和下采样操作,将低层级的细节特征与高层级的语义特征进行融合,以获取更全面和丰富的特征表示。
3. 特征融合(Feature Fusion):
Neck 部分还包括特征融合的操作,用于将来自不同层级的特征进行融合。这种特征融合有助于提高模型对目标的检测准确性,尤其是对于不同尺度的目标。
4. 上采样和下采样:
Neck 部分通常会使用上采样和下采样操作,以调整特征图的尺度和分辨率。上采样操作可以将低分辨率的特征图放大到与高分辨率特征图相同的尺寸,以保留更多的细节信息。而下采样操作则可以将高分辨率的特征图降低尺寸,以减少计算量和内存消耗。
YOLOv8 的 Neck 部分通过特征金字塔网络和特征融合等操作,有效地提取和融合多尺度的特征,从而提高了目标检测的性能和鲁棒性。这使得模型能够更好地适应不同尺度和大小的目标,并在复杂场景下取得更准确的检测结果。
PAN-FPN(具有特征金字塔网络的路径聚合网络)是一种用于计算机视觉中对象检测的神经网络架构。它将特征金字塔网络(FPN)与路径聚合网络(PAN)相结合,以提高目标检测的准确性和效率。
FPN 用于从不同比例的图像中提取特征,而 PAN 用于跨网络的不同层聚合这些特征。这允许网络检测不同大小和分辨率的对象,并处理具有多个对象的复杂场景。
# 3.3 Head
如果 Backbone 和 Neck 部分可以理解为准备工作,那么 Head 部分就是收获的部分,经过前面的准备工作我们得到了 Neck 部分的输出 T1、T2、T3 分别代表不同层级的特征图,Head 部分就是对这三个特征图进行处理以产生模型的的输出结果的一个过程。
YOLOv8 的 Head 部分我们先来看一下它的网络结构。
可以看到在 YOLOv8 的 Head 部分,体现了最核心的改动 ——> 解耦头 (Decoupled-Head),顾名思义就是将原先的一个检测头分解成两个部分。
在 Head 部分的三个解耦头分别对应着 Neck 部分的特征图输出 T1、T2、T3。、
解耦头的工作流程是:
将网络得到的特征图 T1,T2,T3 分别输入解耦头头进行预测,检测头的结构如下图所示其中包含 4 个 3×3 卷积与 2 个 1×1 卷积,同时在检测头的回归分支中添加 WIOU 损失函数如图 4 所示,回归头部需要计算预测框与真实框之间的位置偏移量,然后将偏移量送入回归头部进行损失计算,然后输出一个四维向量,分别表示目标框的左上角坐标 x、y 和右下角坐标 x、y。分类头部针对于每个 Anchor Free 提取的候选框对其进行 RoI Pooling 和卷积操作得到一个分类器输出张量每个位置上的值表示该候选框属于每个类别的概率,在最后通过极大值抑制方式筛选出最终的检测结果
我们再从 YOLOv8 的 yaml 文件来看 Head 部分的作用
可以看到检测头部分的输出为 15,18,21 分别对应着 Neck 部分的三个输出特征图。
到此 YOLOv8 的网络结构部分讲解就已经完成,下面我们来看如何利用 YOLOv8 进行训练操作。
# 四、环境搭建
在我们配置好环境之后,在之后模型获取完成之后,我们可以进行配置的安装我们可以在命令行下输入如下命令进行环境的配置。
1 | pip install -r requirements.txt |
输入如上命令之后我们就可以看到命令行在安装模型所需的库了。
# 五、数据集获取
我在上面随便下载了一个 数据集用它导出 yolov8 的数据集,以及自动给转换成 txt 的格式 yaml 文件也已经配置好了,我们直接用就可以。
# 六、模型获取
到这里假设你已经搭建好了环境和有了数据集,那么我们就可以进行模型的下载,因为 yolov8 目前还存在 BUG 并不稳定随时都有可能进行更新,所以不推荐大家通过其它的途径下载,最好通过下面的方式进行下载。
我们可以直接在终端命令下
(PS:这里需要注意的是我们需要在你总项目文件目录下输入这个命令,因为他会下载到当前目录下)
1 | pip install ultralytics |
如果大家去 github 上直接下载 zip 文件到本地可能会遇到报错如下,识别不了 yolo 命令,所以推荐大家用这种方式下载,
# 七、模型训练
我们来看一下主要的 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 | ||
# 7.1 训练的三种方式
# 7.1.1 方式一
我们可以通过命令直接进行训练在其中指定参数,但是这样的方式,我们每个参数都要在其中打出来。命令如下:
1 | yolo task=detect mode=train model=yolov8n.pt data=data.yaml batch=16 epochs=100 imgsz=640 workers=0 device=0 |
需要注意的是如果你是 Windows 系统的电脑其中的 Workers 最好设置成 0 否则容易报线程的错误。
# 7.1.2 方式二(推荐)
通过指定 cfg 直接进行训练,我们配置好 ultralytics/cfg/default.yaml 这个文件之后,可以直接执行这个文件进行训练,这样就不用在命令行输入其它的参数了。
1 | yolo cfg=ultralytics/cfg/default.yaml |
# 7.1.3 方式三
我们可以通过创建 py 文件来进行训练,这样的好处就是不用在终端上打命令,这也能省去一些工作量,我们在根目录下创建一个名字为 run.py 的文件,在其中输入代码
1 | from ultralytics import YOLO model = YOLO("权重的地址") data = "文件的地址" 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 模型好与坏
1 | 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 | 用于控制是否在分割预测中显示边界框。 |
1 | 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) |
命令行命令如下:
1 | yolo task=detect mode=export model=best.pt format=onnx |