cbs:

c指conv,卷积层,当 stride=1 且 padding=k//2(如YOLOv8中常用配置)时,空间尺寸保持不变,当 stride=2 时,空间尺寸减半(如YOLOv8的下采样层)。卷积层的核心作用是提取局部特征,其空间尺寸可能保持不变缩小,但不会主动增大。        

b指bn,归一化,对每个批次的数据在通道维度上进行标准化意思是规范化,更规范,防止梯度爆炸(深度神经网络训练过程中,反向传播的梯度值变得异常大,导致参数更新幅度过大,模型无法收敛)公式为:

  • μ 和 σ2 是当前批次在通道维度上的均值和方差。
  • γ 和 β 是可学习参数,用于恢复数据分布。

 BN的作用是缓解内部协变量偏移,加速训练收敛,但不保证数值范围在[0,1]

s指激活函数,为网络引入非线性特性,帮助模型学习复杂的特征映射关系。yolov8中的默认激活函数:SiLU(Swish),

YOLOv8的骨干网络(Backbone)和特征金字塔(Neck)中的C2f模块默认使用SiLU。如果不使用激活函数,则每一层的输入直接是上一层的输出,这样就是最原始的感知机。引入激活函数,在每一层的数据传递会引入非线性变换,这样神经网络会引入众多非线性模型。

yolov8各层作用:

1. Conv 层(标准卷积层)

通俗解释
像流水线上的基础加工站,对输入的图像特征进行基础加工(提取边缘/纹理等),包含卷积、归一化和激活函数三步操作。类似用不同滤镜扫描照片提取特征。

专业解释
实现特征的空间维度变换和通道维度变换。通过卷积核权重学习局部特征,BatchNorm 加速收敛并提升泛化能力,SiLU 激活函数引入非线性。公式:
Output = SiLU( BatchNorm( Conv(Input) )

源码:

class Conv(nn.Module):
    def __init__(self, c1, c2, k=3, s=1):  # 输入通道, 输出通道, 卷积核, 步长
        super().__init__()
        self.conv = nn.Conv2d(c1, c2, k, s, padding=k//2, bias=False)
        self.bn = nn.BatchNorm2d(c2)
        self.act = nn.SiLU()  # 激活函数
    
    def forward(self, x):
        return self.act(self.bn(self.conv(x)))

示例
输入 224x224x3 的图片,经过 Conv(3, 64, k=7, s=2) 后输出 112x112x64 的特征图。

各组件解析

  1. self.conv:PyTorch 的 2D 卷积层

    • nn.Conv2d(c1, c2, k, s):创建卷积核

    • c1:输入通道数(如RGB图像为3)

    • c2:输出通道数(特征图数量)

    • k:卷积核尺寸(默认3×3)

    • s:步长(默认1)

    • padding=k//2:填充保证尺寸不变(如k=3时填充1)

    • bias=False:禁用偏置(因BatchNorm已有偏移参数)

  2. self.bn:批标准化层

    • nn.BatchNorm2d(c2):对每个通道独立标准化

    • 作用:加速收敛,减少内部协变量偏移

    • 公式:$y = \frac{x - \mu}{\sqrt{\sigma^2 + \epsilon}} \times \gamma + \beta$

  3. self.act:激活函数

    • nn.SiLU():Sigmoid Linear Unit

    • 公式:$SiLU(x) = x \cdot \sigma(x)$

    • 特点:平滑非饱和激活,优于ReLU

2. C2f 层(梯度分流瓶颈层)

通俗解释
分叉-合并的流水线

  1. 将输入特征拆成两份(如原料分两路)

  2. 主路直接传输(保留原始特征)

  3. 支路通过多个Bottleneck加工(深度加工)

  4. 最后合并两路结果,获得更丰富的特征

专业解释
CSPNet 的改进版,通过特征分流缓解梯度消失

  • 输入特征拆分为两部分(split(1, dim=1)

  • 主路保留浅层特征(Identity)

  • 支路经 n 个 Bottleneck 模块提取深层特征

  • 拼接后融合(增强特征复用)

源码:

class C2f(nn.Module):
    def __init__(self, c1, c2, n=1):  # 输入/输出通道, Bottleneck数量
        super().__init__()
        self.c = c2 // 2  # 拆分通道数
        self.cv1 = Conv(c1, 2 * self.c, 1)  # 拆分前的1x1卷积
        self.cv2 = Conv((2 + n) * self.c, c2, 1)  # 合并后的1x1卷积
        self.m = nn.ModuleList(Bottleneck(self.c, self.c) for _ in range(n))
    
    def forward(self, x):
        y = list(self.cv1(x).chunk(2, 1)  # 拆分为两部分 [A, B]
        y.extend(m(y[-1]) for m in self.m)  # B通过n个Bottleneck
        return self.cv2(torch.cat(y, 1))  # 拼接[A, B, Bottleneck输出]

执行流程

  1. 特征拆分

    • self.cv1(x):1×1卷积将通道扩展为2c

    • .chunk(2, 1):沿通道维度拆分为两个c通道张量[A, B]

  2. Bottleneck处理

    • B分支通过n个串联的Bottleneck

    • 每个Bottleneck处理前一个的输出

    • 结果保存到列表y中

  3. 特征融合

    • torch.cat(y, 1):拼接所有特征(原始A + 原始B + n个Bottleneck输出)

    • self.cv2:1×1卷积调整通道数到c2

维度变化示例
输入:56×56×128 (c1=128)

  1. cv1:56×56×256 (2c, c=c2//2=64)

  2. 拆分:两个56×56×64张量

  3. 3个Bottleneck:生成3个56×56×64张量

  4. 拼接:56×56×(64×5)=56×56×320

  5. cv2:56×56×128 (c2=128)

3. SPPF 层(空间金字塔快速池化)

通俗解释
三种不同尺寸的筛子同时筛选特征:

  1. 对同一特征图分别做 5x5/9x9/13x13 的池化

  2. 将不同尺度的池化结果与原图拼接

  3. 融合后获得多尺度特征(适应不同大小物体)

专业解释
SPP 的加速版,通过重复使用池化层减少计算量:

  • 单次最大池化(kernel=5, padding=2)等效于多尺度池化

  • 级联三次池化输出:[原始特征, 池化1次, 池化2次, 池化3次]

  • 融合多尺度信息提升感受野

源码:

class SPPF(nn.Module):
    def __init__(self, c1, c2, k=5):  # 输入/输出通道, 池化核
        super().__init__()
        self.cv1 = Conv(c1, c1//2, 1)  # 通道压缩
        self.cv2 = Conv(c1*2, c2, 1)  # 通道恢复
        self.pool = nn.MaxPool2d(k, stride=1, padding=k//2)
    
    def forward(self, x):
        x = self.cv1(x)
        y1 = self.pool(x)
        y2 = self.pool(y1)
        y3 = self.pool(y2)
        return self.cv2(torch.cat([x, y1, y2, y3], 1))

关键点解析

  1. 池化层重用

    • 单池化层重复使用3次(而非SPP的3个独立池化层)

    • 计算量减少约50%,速度提升

  2. 多尺度融合

    • 原始特征:感受野1×1

    • 1次池化:感受野5×5

    • 2次池化:感受野9×9

    • 3次池化:感受野13×13

  3. 通道控制

    • cv1:压缩通道减少计算量

    • cv2:恢复通道整合特征

4.Bottleneck 模块解析

 源码:

class Bottleneck(nn.Module):
    def __init__(self, c1, c2, shortcut=True, g=1, e=0.5):
        super().__init__()
        c_ = int(c2 * e)  # 中间层通道数
        self.cv1 = Conv(c1, c_, 1, 1)  # 1×1卷积压缩
        self.cv2 = Conv(c_, c2, 3, 1, g=g)  # 3×3卷积
        self.add = shortcut and c1 == c2  # 是否使用残差连接

    def forward(self, x):
        return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))

核心设计

  1. 通道压缩:1×1卷积减少通道数($c_2 \times e$)

  2. 特征提取:3×3卷积处理压缩后的特征

  3. 残差连接:当输入输出通道相同时,添加跳跃连接

输入 x (n×c1×h×w)
  │
  ↓
[1×1卷积] → 降维到 c_ 通道
  │
  ↓
[3×3卷积] → 恢复 c2 通道
  │
  ├──────────────┐ (当 add=True 且 c1=c2)
  ↓              ↓
[元素级加法] → 输出 

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐