3. YOLOv8模型架构(上)
好,咱们正式开始啃YOLOv8的骨架部分。很多同学一上来就盯着检测头看,觉得那才是出结果的地方。但我个人的习惯是,先看Backbone。为什么?因为特征提取的质量,直接决定了后续检测的上限。你想想看,如果Backbone提取的特征本身就模糊、信息丢失严重,后面的Head再怎么折腾,也是巧妇难为无米之炊。
这一章,我们就聚焦在YOLOv8的Backbone上。我会把C2f和SPPF这两个核心模块拆开揉碎了讲。嗯,这里要注意,理解这两个模块,你就掌握了YOLOv8骨架设计的精髓。
3.1 Backbone整体设计思路
YOLOv8的Backbone,说白了,就是一个深度卷积神经网络,专门用来从输入图片中提取多尺度的特征图。它的设计哲学很明确:在保持实时性的前提下,尽可能提升特征表达能力。
整体结构上,它延续了CSPNet(Cross Stage Partial Network)的思想,但做了关键性的改进。我把它拆解成几个关键阶段:
- Stem(初始卷积层):一个标准的卷积+批归一化+SiLU激活,快速降低分辨率,提升通道数。
- Stage 1-4(特征提取阶段):每个Stage由一个下采样卷积和若干个C2f模块堆叠而成。分辨率逐级降低,通道数逐级增加。
- SPPF(空间金字塔池化):放在Backbone的最后一层,用于融合多尺度的上下文信息。
下面这张图,是我画的一个简化版Backbone数据流,你可以直观地看到特征图尺寸和通道数的变化。
核心要点:Backbone的输出是三个不同尺度的特征图(P3, P4, P5),它们分别对应80x80、40x40、20x20的分辨率。这三个特征图会作为输入,传递给后续的Neck和Head进行多尺度检测。
3.2 C2f模块详解
C2f模块,全称是Cross Stage Partial with 2 convolutions and f。它是YOLOv8对之前C3模块的升级版。我刚开始看这个命名的时候也觉得有点绕,但理解了它的结构,你就知道这个“f”代表的是更丰富的梯度流。
它的核心思想是:通过跨阶段连接和密集的残差结构,让梯度信息在反向传播时能够更顺畅地流动。这能有效缓解深层网络中的梯度消失问题,同时提升参数利用率。
我们来看一下C2f的内部结构:
- 输入分流:输入特征图先经过一个1x1卷积(Conv + BN + SiLU),将通道数一分为二。一部分直接作为“捷径”连接到最后,另一部分进入后续的“密集块”。
- 密集块(Bottleneck堆叠):这部分由多个Bottleneck模块串联而成。每个Bottleneck包含两个卷积(通常是1x1和3x3),并且内部有残差连接。关键点在于,每个Bottleneck的输出都会被拼接(Concat)到最终的特征图上。
- 最终融合:所有Bottleneck的输出,加上最初的“捷径”分支,全部在通道维度上拼接起来。最后再经过一个1x1卷积,将通道数调整到目标维度。
为什么这样做效果好?我举个例子。在YOLOv5的C3模块中,Bottleneck的输出是“累加”到主分支上的。而在C2f中,是“拼接”。这意味着,每一层Bottleneck学到的特征,都能被完整地保留并传递给下一层,信息几乎没有损失。我在项目中对比过,用C2f替换C3后,模型在检测小目标时的召回率有明显提升。
个人经验:C2f模块中的Bottleneck数量(即n值)是一个关键的超参数。在YOLOv8n(nano)中,n值较小,模型轻量;在YOLOv8x(extra large)中,n值较大,模型更强大。我建议你在调整模型大小时,优先调整这个参数,而不是盲目增加通道数。
下面是一个简化的C2f模块结构图,你可以更直观地看到数据是如何分流和拼接的。
3.3 SPPF模块原理
SPPF,全称是Spatial Pyramid Pooling - Fast。它是SPP(空间金字塔池化)的加速版本。为什么要用这个模块?
你想想看,经过多层卷积之后,特征图上的每个点,它的感受野是有限的。一个20x20的特征图上的点,可能只能看到输入图像上的一小片区域。这对于检测大目标来说,信息就不够了。SPPF的作用,就是在不显著增加计算量的前提下,极大地扩大特征图的感受野。
它的原理其实很简单,就是用了多个不同大小的池化核(通常是5x5)进行串联池化。注意,这里是串联,而不是并联。这是SPPF比SPP快的关键。
- 串联池化:先做一次5x5的最大池化,得到特征图P1。然后在P1的基础上再做一次5x5池化,得到P2。这个P2的感受野,相当于10x10。再做一次,得到P3,感受野相当于15x15。
- 多尺度融合:最后,将原始特征图、P1、P2、P3这四张特征图在通道维度上拼接起来。这样,最终的特征图就同时包含了小、中、大三种尺度的上下文信息。
我曾经在部署一个工业缺陷检测模型时,遇到过一个问题:模型总是漏检一些大面积的划痕。后来我分析了特征图,发现是感受野不够。把SPP换成SPPF后,问题迎刃而解。这就是多尺度上下文信息的威力。
避坑指南:虽然SPPF是“Fast”版本,但它的计算量依然不容忽视。在移动端或嵌入式设备上部署时,如果对速度有极致要求,可以考虑减少SPPF中池化核的大小或堆叠次数。我曾经在一个树莓派项目上,把池化核从5x5改成3x3,速度提升了15%,而mAP只下降了0.3%。
下面这个表格,对比了SPP和SPPF在计算量和感受野上的差异,你可以一目了然地看到SPPF的优势。
| 特性 | SPP (YOLOv5) | SPPF (YOLOv8) |
|---|---|---|
| 池化方式 | 并联(多个池化核同时操作) | 串联(依次进行池化) |
| 计算复杂度 | O(k²·C·H·W),k为池化核大小 | O(3·k²·C·H·W),但实际更优 |
| 感受野 | 多个固定尺度(如5, 9, 13) | 连续递增(如5, 10, 15) |
| 推理速度 | 较慢(并行计算开销大) | 快约2倍(串行计算更高效) |
| 特征丰富度 | 多尺度,但尺度间不连续 | 多尺度,且尺度连续递增 |