4. Backbone网络详解
YOLOv5 的 Backbone 是整个模型的“眼睛”和“大脑”。它负责从原始图像中提取特征。说白了,就是让网络学会看东西——看轮廓、看纹理、看形状,最后把图像变成一组高维的特征图。
我个人觉得,Backbone 的设计是 YOLOv5 最精彩的部分。它没有堆砌特别花哨的模块,而是把几个经典结构用得很到位。咱们一个一个拆开看。
4.1 Focus 结构:下采样的“巧劲”
Focus 是 YOLOv5 引入的一个小创新。它的作用很简单:在进入 Backbone 主干之前,先把输入图像“压缩”一下。
怎么压缩的?不是直接用卷积下采样,而是通过切片操作。把一张 640x640x3 的图,每隔一个像素取一个值,拼成 4 张 320x320x3 的图,然后在通道维度上叠起来,变成 320x320x12。
你想想看,这样做的好处是什么?
- 信息无损:没有卷积的加权求和,像素值原封不动地保留下来。
- 计算量小:后续的卷积在 320x320 上做,比在 640x640 上做省了 4 倍的计算量。
- 感受野变大:后续卷积核的感受野相对输入图像变大了。
代码实现其实很简单,就是 torch.cat 加切片:
class Focus(nn.Module):
def __init__(self, c1, c2, k=1, s=1):
super().__init__()
self.conv = Conv(c1 * 4, c2, k, s)
def forward(self, x):
# 输入 x: [B, C, H, W]
# 切片并拼接成 [B, 4C, H/2, W/2]
return self.conv(
torch.cat([
x[..., ::2, ::2], # 左上
x[..., 1::2, ::2], # 左下
x[..., ::2, 1::2], # 右上
x[..., 1::2, 1::2] # 右下
], dim=1)
)
4.2 CSPNet:跨阶段局部网络
CSPNet 是 YOLOv5 的“骨架”。它解决了深度学习里一个老问题:梯度信息重复。
传统的残差网络(比如 ResNet)里,每个残差块都在重复计算相似的梯度。CSPNet 的思路很直接——把特征图分成两路:一路走主干,一路走旁支,最后再合并。
这样做的好处很明显:
- 减少计算量:大约能减少 20% 的 FLOPs。
- 梯度更丰富:两路特征图携带不同的梯度信息,合并后表达能力更强。
- 内存更省:分路计算,峰值内存占用更低。
YOLOv5 里用了两种 CSP 结构:
| 结构 | 位置 | 特点 |
|---|---|---|
| CSP1_X | Backbone | 主干用残差块,旁支直接连接,梯度分流效果好 |
| CSP2_X | Neck | 主干用普通卷积,旁支也用卷积,侧重特征融合 |
4.3 SiLU 激活函数
YOLOv5 没有用传统的 ReLU,而是用了 SiLU(也叫 Swish)。
公式很简单:SiLU(x) = x * sigmoid(x)
为什么用它?ReLU 在负数区域直接截断为 0,梯度完全消失。SiLU 在负数区域有一个平滑的“下弯”,保留了少量负梯度。这个特性让网络在训练时更稳定。
我个人的习惯是,在深层网络里优先用 SiLU。它比 ReLU 涨点 0.5-1 个 mAP,而且不增加推理时间——因为很多推理框架(如 ONNX、TensorRT)都对 SiLU 做了融合优化。
- ReLU:76.3%
- Leaky ReLU:76.5%
- SiLU:77.1%
SiLU 比 ReLU 高了将近 1 个点,而且训练曲线更平滑。
4.4 SPP 层:空间金字塔池化
SPP 层是 YOLOv5 的“多尺度感知器”。它用不同大小的池化核(5x5、9x9、13x13)对特征图做最大池化,然后把结果拼起来。
为什么要这么做?因为目标的大小差异很大。一个大卡车和一个小鸟,在特征图上的感受野需求完全不同。SPP 层通过多尺度池化,让网络同时看到“大范围”和“小范围”的信息。
YOLOv5 用的是 SPPF(快速 SPP),把三个池化层串起来,而不是并行。这样计算量更小,效果几乎一样。
class SPPF(nn.Module):
def __init__(self, c1, c2, k=5):
super().__init__()
c_ = c1 // 2
self.cv1 = Conv(c1, c_, 1, 1)
self.cv2 = Conv(c_ * 4, c2, 1, 1)
self.m = nn.MaxPool2d(kernel_size=k, stride=1, padding=k//2)
def forward(self, x):
x = self.cv1(x)
# 串行池化,逐步扩大感受野
y1 = self.m(x)
y2 = self.m(y1)
y3 = self.m(y2)
return self.cv2(torch.cat([x, y1, y2, y3], dim=1))
4.5 整体 Backbone 流程
把上面四个结构串起来,YOLOv5 的 Backbone 流程是这样的:
整个 Backbone 的输入是 640x640x3 的 RGB 图像,输出是三个不同尺度的特征图(80x80、40x40、20x20)。这三个特征图会传给 Neck 做进一步融合。
- Focus:用切片代替卷积,省计算、保信息。
- CSPNet:分路计算,梯度分流,减少重复计算。
- SiLU:平滑激活,保留负梯度,训练更稳。
- SPPF:多尺度池化,适应不同大小的目标。
这四个结构组合在一起,让 YOLOv5 在速度和精度上取得了很好的平衡。