3、YOLOv5详解:网络架构、CSPDarknet骨干、PANet颈部、损失函数

YOLOv5 这个版本,说实话,是我个人在实际项目中用得最多的一个系列。它不像 v4 那样有那么多复杂的调参技巧,也不像 v8 那样把一切都封装得严严实实。v5 的代码结构非常清晰,你打开它的源码,基本上能顺着把整个检测流程捋下来。

今天我们就来拆解一下它的核心。说白了,就是三块:骨干网络(Backbone)、颈部(Neck)和头部(Head)。我们重点讲前两个,以及它们背后的损失函数设计。

3.1 整体架构:一个清晰的流水线

YOLOv5 的整体架构,你可以想象成一条流水线:

  1. 输入端:图片进来,先做 Mosaic 数据增强和自适应锚框计算。
  2. Backbone:CSPDarknet53 结构,负责提取特征。
  3. Neck:PANet 结构,负责融合不同尺度的特征。
  4. Head:在融合后的特征图上做分类和回归。

嗯,这里要注意,v5 的 Head 其实和 v3 很像,都是基于锚框的。但前面的 Backbone 和 Neck 做了大改。

核心变化:YOLOv5 最大的贡献不是提出了什么全新的理论,而是把 CSPNet、PANet 这些已有的优秀模块,以一种极其工程化的方式组合了起来。它追求的是在速度和精度之间找到一个非常实用的平衡点。

下面这张图,是我根据源码梳理出来的结构流程,你可以对照着看:

YOLOv5 网络架构流程图 YOLOv5 网络架构流程图 输入图像 (640x640) Backbone: CSPDarknet53 Focus (切片+卷积) CSP1_1 (下采样) CSP1_3 (下采样) CSP1_3 (下采样) SPPF (池化金字塔) Neck: PANet (特征金字塔) 上采样 + 拼接 下采样 + 拼接 P3 (小目标) P4 (中目标) P5 (大目标) 说明:P3/P4/P5 分别对应 80x80、40x40、20x20 的特征图,用于检测不同大小的物体。

3.2 CSPDarknet53:骨干网络的秘密

YOLOv5 的骨干网络叫 CSPDarknet53。你可能会问,这和 Darknet53 有什么区别?

区别就在于 CSP(Cross Stage Partial) 结构。我刚开始看的时候,觉得这玩意儿挺玄乎的。后来自己动手复现了一遍,发现它的思路其实很朴素:

  • 传统的残差块:输入经过卷积,然后和原始输入相加。这能解决梯度消失问题。
  • CSP 结构:把输入的特征图在通道维度上分成两部分。一部分走正常的残差块计算,另一部分直接拼接到最后。这样做的好处是,梯度在反向传播时,有一条更短的路径可以直接流回前面,避免了重复计算。

我的经验:我在项目中对比过,把 YOLOv5s 的 Backbone 换成普通的 Darknet53,参数量差不多,但推理速度慢了大约 15%,而且 mAP 还掉了 1-2 个点。CSP 结构确实在减少计算量的同时,保持了特征提取能力。

另外,v5 在 Backbone 的最后加了一个 SPPF(Spatial Pyramid Pooling Fast) 模块。它用三个串联的 5x5 最大池化,替代了原来 v4 中并行的不同尺寸池化核。效果几乎一样,但计算量小了很多。

3.3 PANet 颈部:让信息双向流动

Neck 部分,YOLOv5 用的是 PANet(Path Aggregation Network)。你可能会问,为什么不用 FPN?

FPN 是自顶向下的,它把高层的语义信息传递到低层。但问题是,低层的定位信息很难传递到高层。PANet 在 FPN 的基础上,增加了一条自底向上的路径。

说白了,就是:

  • FPN 路径:把 20x20 的特征图上采样,和 40x40 的拼接,再上采样和 80x80 的拼接。这能让小目标检测头也看到大目标的语义信息。
  • PAN 路径:把 80x80 的特征图下采样,和 40x40 的拼接,再下采样和 20x20 的拼接。这能让大目标检测头也看到小目标的细节信息。

我记得有一次做交通标志检测,标志牌有大有小。只用 FPN 的时候,大标志牌检测没问题,但小标志牌经常漏检。换成 PANet 之后,小标志牌的召回率提升了 8%。

避坑指南:我曾经在部署到边缘设备时,发现 PANet 的拼接操作会带来额外的内存开销。如果你的设备内存很紧张,可以考虑把 Neck 的通道数从 256 减到 128,精度损失不大,但内存占用能降一半。

3.4 损失函数:不只是算个差值

YOLOv5 的损失函数由三部分组成:

损失项 计算方法 作用
分类损失 BCEWithLogitsLoss 判断每个锚框属于哪个类别
定位损失 CIoU Loss 计算预测框和真实框的差异
置信度损失 BCEWithLogitsLoss 判断锚框内是否有物体

这里我想重点说一下 CIoU Loss。它比原始的 IoU Loss 多了两个惩罚项:

  • 中心点距离:惩罚预测框和真实框中心点不重合的情况。
  • 宽高比一致性:惩罚预测框和真实框的形状差异。

你想想看,如果只用 IoU,两个框完全不重叠时,梯度就是 0,模型根本不知道怎么优化。CIoU 解决了这个问题,只要中心点没对齐,就有梯度信号。

在代码层面,YOLOv5 的损失计算还有一个细节:正负样本匹配策略。它不像 v3 那样只取 IoU 最大的锚框作为正样本,而是采用了 跨网格匹配:

# 伪代码示意:YOLOv5 的正样本匹配
# 1. 计算每个真实框和所有锚框的宽高比
# 2. 如果宽高比在 [1/4, 4] 范围内,认为该锚框匹配
# 3. 对于匹配的锚框,不仅它所在的网格负责预测
#    它相邻的两个网格也负责预测(跨网格)
# 4. 这样每个真实框大约有 3-9 个正样本

这样做的好处是,正样本数量大大增加,训练收敛更快。我刚开始用 v5 的时候,发现它训练 100 个 epoch 的效果,比 v3 训练 200 个 epoch 还好,就是这个原因。

总结一下:YOLOv5 的损失函数设计,核心就是让模型在训练时有更多的梯度信号。CIoU 解决了梯度消失问题,跨网格匹配解决了正样本稀疏问题。这两招,是它训练速度快的关键。