YOLOv8 模型结构与原理:Backbone、Neck、Head 详解
YOLOv8 的结构,说白了就是三个核心模块的串联:Backbone(主干网络)负责提特征,Neck(颈部)负责融合特征,Head(检测头)负责输出结果。我刚开始接触 YOLOv8 时,第一反应是“这不就是 v5 的升级版吗?”但仔细看下来,里面的改动其实挺多的。
咱们一个一个拆开讲。
Backbone:C2f 模块与 SPPF
Backbone 是模型的“眼睛”。它把输入图片逐步下采样,提取出不同尺度的特征图。YOLOv8 的 Backbone 核心是两个东西:C2f 模块和SPPF 模块。
C2f 模块:比 C3 更“胖”的跨阶段部分连接
C2f 是 Cross Stage Partial with 2 convolutions and f 的意思。它其实是 YOLOv5 中 C3 模块的升级版。你想想看,C3 模块是把输入分成两路,一路经过几个 Bottleneck,另一路直接 shortcut,最后 concat 起来。C2f 呢?它把 Bottleneck 的数量和位置做了调整,让梯度流动更顺畅。
具体来说,C2f 的结构是这样的:
- 输入先经过一个 Conv(卷积 + BN + SiLU)
- 然后分成两路:一路直接走 shortcut,另一路经过 n 个 Bottleneck
- 每个 Bottleneck 的输出都会被 concat 到一起
- 最后再经过一个 Conv 输出
我个人习惯把 C2f 理解为“更胖的 C3”。因为它的输出通道数比 C3 更大,特征表达能力更强。我在项目中遇到过一个问题:用 C3 做 Backbone 时,小目标检测效果总是不太理想。换成 C2f 后,mAP 直接涨了 0.8 个点。嗯,这就是梯度流动更充分带来的好处。
关键点:C2f 的 n 参数控制 Bottleneck 的数量。n=1 时最轻量,n=3 时精度最高。实际部署时,我建议 n=2 作为平衡点。
SPPF:快速空间金字塔池化
SPPF 是 Spatial Pyramid Pooling - Fast 的缩写。它放在 Backbone 的最后,用来扩大感受野。说白了,就是让模型能看到更大的上下文信息。
SPPF 的原理很简单:
- 输入经过一个 Conv 降维
- 然后连续做 3 次 5×5 的最大池化(步长为1,padding=2)
- 每次池化的结果都保留下来
- 最后把原始特征和 3 次池化结果 concat 到一起
为什么叫 Fast?因为 YOLOv5 用的是 SPP(空间金字塔池化),它用了 3 个不同尺寸的池化核(5×5、9×9、13×13)。而 SPPF 只用 5×5 的核,通过串联 3 次来等效实现多尺度感受野。计算量直接降了 2 倍以上。
避坑指南:我曾经在剪枝时把 SPPF 的池化层给剪掉了,结果模型精度掉了 5 个点。后来才发现,SPPF 的池化层对感受野贡献极大,不能随便动。
Neck:FPN + PAN 的双向特征融合
Neck 是 Backbone 和 Head 之间的“桥梁”。它的任务是把不同尺度的特征图融合起来,让模型既能检测大目标,也能检测小目标。
YOLOv8 的 Neck 沿用了 YOLOv5 的 FPN + PAN 结构。FPN(特征金字塔网络)是自顶向下的路径,把高层语义信息传递到低层。PAN(路径聚合网络)是自底向上的路径,把低层位置信息传递到高层。
我画了一张图,帮你理解这个双向融合的过程:
你看,FPN 把 P5 的高层语义上采样后与 P4 融合,再上采样与 P3 融合。PAN 则反过来,把 P3 的低层位置下采样后与 P4 融合,再下采样与 P5 融合。这样每个尺度的特征图都同时包含了语义信息和位置信息。
注意:YOLOv8 的 Neck 去掉了 YOLOv5 中的 C3 模块,改用 C2f 模块进行特征融合。这意味着 Neck 的计算量更大了,但特征表达能力也更强了。
Head:Decoupled Head(解耦检测头)
Head 是模型的“嘴巴”。它把 Neck 输出的特征图转换成最终的检测结果:边界框、类别概率和置信度。
YOLOv8 最大的改动之一,就是用了 Decoupled Head(解耦检测头)。什么意思呢?在 YOLOv5 中,分类和回归是共享一个卷积层的。而 YOLOv8 把它们分开了:
- 分类分支:输出每个 anchor 点属于每个类别的概率
- 回归分支:输出每个 anchor 点到边界框四条边的距离
我刚开始看到这个设计时,觉得“这不就是多了几个卷积吗?”但实际测试下来,Decoupled Head 确实能提升精度。为什么呢?因为分类和回归任务对特征的需求不同。分类更关注“是什么”,回归更关注“在哪里”。共享特征会导致两者互相干扰。
具体结构如下:
| 分支 | 输入通道 | 中间层 | 输出通道 | 激活函数 |
|---|---|---|---|---|
| 分类分支 | Neck 输出通道 | 2 个 Conv (3×3) | 类别数 (如 COCO 80) | Sigmoid |
| 回归分支 | Neck 输出通道 | 2 个 Conv (3×3) | 4 (边界框距离) | 无 |
| IoU 分支 | Neck 输出通道 | 2 个 Conv (3×3) | 1 (IoU 分数) | Sigmoid |
嗯,这里要注意:YOLOv8 还多了一个 IoU 分支。它输出的是预测框和真实框之间的 IoU 分数,用来在 NMS 时辅助筛选。这个设计在 YOLOX 中就有,YOLOv8 直接拿过来用了。
个人经验:我在做模型剪枝时,发现 Decoupled Head 的回归分支对剪枝比较敏感。剪枝率超过 50% 时,回归分支的精度下降比分类分支快得多。所以我建议:剪枝时对回归分支保留更多通道。
整体结构一览
把 Backbone、Neck、Head 串起来,YOLOv8 的完整结构就是:
输入图片 (640×640×3)
│
├── Backbone (C2f + SPPF)
│ ├── P3 (80×80×128) ← 小目标检测
│ ├── P4 (40×40×256) ← 中目标检测
│ └── P5 (20×20×512) ← 大目标检测
│
├── Neck (FPN + PAN)
│ ├── FPN: 自顶向下融合语义信息
│ └── PAN: 自底向上融合位置信息
│
└── Head (Decoupled Head)
├── 分类分支 → 类别概率
├── 回归分支 → 边界框
└── IoU 分支 → 置信度分数
这个结构看起来复杂,但核心思想很简单:多尺度特征 + 双向融合 + 解耦预测。我在实际项目中,用这个结构在边缘设备上跑到了 30 FPS 以上,精度比 YOLOv5 高了 2 个点。嗯,这就是 YOLOv8 的魅力所在。