3、YOLOv8基础与模型架构:网络结构解析、Backbone/Neck/Head详解、配置文件解读
YOLOv8 是 Ultralytics 在 2023 年初推出的目标检测模型。说实话,它并不是一个颠覆性的创新,而是把之前 YOLOv5、YOLOX、YOLOv6 等版本里被验证有效的技巧,整合到了一个干净、高效的框架里。
我个人习惯把 YOLOv8 看作一个「模块化工具箱」。你不需要从零造轮子,只需要理解每个模块的作用,就能快速搭出适合自己业务的检测模型。这一章,我们就把它拆开来看。
3.1 整体网络结构:三件套
YOLOv8 延续了经典的 Backbone → Neck → Head 三段式设计。说白了,就是:
- Backbone(骨干网络):负责提取图像特征。输入一张图,输出多个尺度的特征图。
- Neck(颈部):负责融合特征。把 Backbone 输出的不同尺度特征图,通过上下采样和拼接,让信息流通起来。
- Head(头部):负责预测。在融合后的特征图上,输出目标的类别、位置和置信度。
下面这张图是我自己画的 YOLOv8 结构简图,你可以对照着看:
3.2 Backbone 详解:C2f 与 SPPF
YOLOv8 的 Backbone 核心是两个模块:C2f 和 SPPF。
3.2.1 C2f 模块
C2f 是 YOLOv8 对之前版本 C3 模块的改进。C3 是「跨阶段局部网络」,C2f 则是「跨阶段局部网络 + 更多梯度流」。说白了,C2f 把输入的特征图分成两路,一路直接走捷径,另一路经过多个 Bottleneck 处理,最后再拼起来。
这样做的好处是:梯度可以更顺畅地回传到浅层网络,训练时不容易梯度消失。我在项目中遇到过,用 C2f 替换 C3 后,小目标的召回率提升了大概 2 个点。
3.2.2 SPPF 模块
SPPF(快速空间金字塔池化)是 YOLOv8 的标配。它用多个不同尺寸的池化核并行处理特征图,然后把结果拼在一起。这样模型就能同时看到「大范围」和「小范围」的上下文信息。
嗯,这里要注意:SPPF 比之前的 SPP 计算量更小,但效果几乎一样。如果你在部署时对速度有极致要求,可以考虑把 SPPF 的池化核尺寸调小一点。
3.3 Neck 详解:FPN + PAN 结构
Neck 部分,YOLOv8 沿用了 FPN(特征金字塔网络)+ PAN(路径聚合网络)的组合。FPN 负责把高层语义信息传递到低层,PAN 负责把低层位置信息传递到高层。两者结合,信息就双向流通了。
| 组件 | 作用 | 方向 |
|---|---|---|
| FPN | 将深层语义信息上采样,与浅层特征融合 | 自顶向下 |
| PAN | 将浅层位置信息下采样,与深层特征融合 | 自底向上 |
YOLOv8 在 Neck 里用了大量的拼接操作(Concat),而不是加法。拼接能保留更多原始信息,但也会增加通道数。所以后面通常会跟一个 1x1 卷积来降维。
3.4 Head 详解:解耦头与 DFL 损失
YOLOv8 的 Head 是它和 YOLOv5 最大的区别之一。它采用了 解耦头 和 DFL 损失。
3.4.1 解耦头
之前的 YOLO 版本,分类和回归任务共享同一个卷积层。YOLOv8 把它们分开了:一个分支负责分类,另一个分支负责回归。这样做的好处是,两个任务可以各自学习更专一的特征,互不干扰。
说白了,就是让分类的归分类,回归的归回归。我在实际部署中发现,解耦头对密集场景下的检测效果提升很明显。
3.4.2 DFL 损失
DFL(分布焦点损失)是 YOLOv8 在回归分支上用的新损失函数。传统的回归是直接预测一个坐标值,DFL 则是预测坐标值的概率分布。举个例子,传统方法直接预测 x=100,DFL 则预测 x 在 98、99、100、101、102 上的概率分布,然后取期望。
这样做的好处是:模型能知道自己的不确定性。如果分布很集中,说明模型很确定;如果分布很分散,说明模型在犹豫。这个信息在后处理时非常有用。
3.5 配置文件解读:yolov8n.yaml
YOLOv8 的配置文件是 YAML 格式的。我个人习惯,拿到一个新模型,第一件事就是看它的配置文件。下面以 yolov8n.yaml 为例,逐段解读。
# Ultralytics YOLOv8n
# 参数
nc: 80 # 类别数
scales: # 模型缩放系数
n: [0.33, 0.25, 1024] # depth, width, max_channels
# Backbone
backbone:
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
- [-1, 3, C2f, [128, True]]
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
- [-1, 6, C2f, [256, True]]
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
- [-1, 6, C2f, [512, True]]
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
- [-1, 3, C2f, [1024, True]]
- [-1, 1, SPPF, [1024, 5]] # 9
# Head
head:
- [-1, 1, nn.Upsample, [None, 2, "nearest"]]
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
- [-1, 3, C2f, [512]] # 12
- [-1, 1, nn.Upsample, [None, 2, "nearest"]]
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
- [-1, 3, C2f, [256]] # 15 (P3/8-small)
- [-1, 1, Conv, [256, 3, 2]]
- [[-1, 12], 1, Concat, [1]] # cat head P4
- [-1, 3, C2f, [512]] # 18 (P4/16-medium)
- [-1, 1, Conv, [512, 3, 2]]
- [[-1, 9], 1, Concat, [1]] # cat head P5
- [-1, 3, C2f, [1024]] # 21 (P5/32-large)
- [[15, 18, 21], 1, Detect, [nc]] # Detect(P3, P4, P5)
解读几个关键点:
- scales:定义了模型的深度、宽度和最大通道数。n 代表 nano,是最小的版本。你可以把 [0.33, 0.25, 1024] 理解为「把标准模型的层数乘以 0.33,通道数乘以 0.25,最大通道数限制在 1024」。
- backbone 中的 [-1, 1, Conv, [64, 3, 2]]:-1 表示输入来自上一层,1 表示重复 1 次,Conv 是操作名,[64, 3, 2] 是参数:输出通道 64,卷积核 3x3,步长 2。
- head 中的 [[-1, 6], 1, Concat, [1]]:[-1, 6] 表示把当前层的输出和第 6 层的输出拼接起来。这就是 FPN + PAN 的体现。
- 最后的 Detect:[[15, 18, 21], 1, Detect, [nc]] 表示从第 15、18、21 层取特征图,分别对应小、中、大三个尺度的检测头。
3.6 不同版本对比:n/s/m/l/x
YOLOv8 提供了 5 个预训练版本,从 nano 到 xlarge。它们的区别主要体现在深度和宽度上。
| 版本 | 深度系数 | 宽度系数 | 参数量 (M) | FLOPs (G) | mAP50-95 |
|---|---|---|---|---|---|
| n (nano) | 0.33 | 0.25 | 3.2 | 8.7 | 37.3 |
| s (small) | 0.33 | 0.50 | 11.2 | 28.6 | 44.9 |
| m (medium) | 0.67 | 0.75 | 25.9 | 78.9 | 50.2 |
| l (large) | 1.00 | 1.00 | 43.7 | 165.2 | 52.9 |
| x (xlarge) | 1.00 | 1.25 | 68.2 | 257.8 | 53.9 |
从表格可以看出,nano 版本参数量只有 3.2M,非常适合边缘设备部署。而 xlarge 版本虽然精度最高,但计算量也最大。我在工业项目里,通常先用 nano 或 small 版本做快速验证,确认方案可行后,再根据硬件资源选择 larger 版本。
好了,这一章的内容就到这里。YOLOv8 的结构其实不复杂,关键是把 Backbone、Neck、Head 这三个部分理解透,再学会看配置文件,后面做模型修改和部署就会顺手很多。