残差块


以下是关于 残差块(Residual Block) 的详细解析:


1. 残差块的核心思想

残差块(Residual Block) 是ResNet(Residual Neural Network)的核心组件,由何恺明团队于2015年提出,旨在解决深度神经网络中的梯度消失网络退化问题(即网络加深后性能反而下降)。其核心思想是:
通过引入跳跃连接(Shortcut Connection),让网络直接学习输入与输出之间的残差(差值),而非直接学习目标映射
数学表达:
[ \text{输出} = F(x) + x ]
其中,( F(x) ) 为残差函数,( x ) 为输入。


2. 残差块的结构

基本残差块(Basic Block)

  • 适用场景:较浅的ResNet(如ResNet-18/34)。
  • 结构流程
  • 输入 ( x ) 经过两层卷积(3×3 → 3×3)生成残差 ( F(x) )。
  • 残差 ( F(x) ) 与原始输入 ( x ) 相加(需满足维度一致)。
  • 通过ReLU激活输出。

Basic Block

瓶颈残差块(Bottleneck Block)

  • 适用场景:更深的ResNet(如ResNet-50/101/152)。
  • 结构流程
  • 输入 ( x ) 依次通过:
    • 1×1卷积:降维(减少通道数)。
    • 3×3卷积:提取特征。
    • 1×1卷积:升维(恢复通道数)。
  • 残差 ( F(x) ) 与输入 ( x ) 相加。
  • 通过ReLU激活输出。

Bottleneck Block


3. 残差块的关键设计

  1. 跳跃连接(Shortcut Connection)
  2. 若输入 ( x ) 与残差 ( F(x) ) 维度不同,需通过 1×1卷积 调整通道数或步长调整空间尺寸。
  3. 加法操作(( F(x) + x ))使梯度可直接回传,缓解梯度消失。

  4. 批量归一化(BatchNorm)

  5. 每个卷积层后接BN层,加速训练并稳定梯度。

  6. 维度匹配规则

  7. 当残差路径改变维度时(如步长=2降采样),跳跃连接需同步调整维度。

4. 残差块的作用

  • 梯度直接传播:跳跃连接为梯度提供“高速公路”,避免因链式求导导致的梯度衰减。
  • 缓解网络退化:深层网络更容易优化残差 ( F(x) )(假设 ( F(x) ) 接近0时,网络退化为恒等映射)。
  • 特征重用:原始输入 ( x ) 直接传递,保留底层特征。

5. 残差块的PyTorch实现

基本残差块(Basic Block)

import torch.nn as nn

class BasicBlock(nn.Module):
    def __init__(self, in_channels, out_channels, stride=1):
        super().__init__()
        # 残差路径
        self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(out_channels)
        self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(out_channels)
        self.relu = nn.ReLU(inplace=True)

        # 跳跃连接(若维度变化则用1×1卷积调整)
        self.shortcut = nn.Sequential()
        if stride != 1 or in_channels != out_channels:
            self.shortcut = nn.Sequential(
                nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False),
                nn.BatchNorm2d(out_channels)
            )

    def forward(self, x):
        residual = x
        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)
        out = self.conv2(out)
        out = self.bn2(out)
        out += self.shortcut(residual)  # 残差连接
        out = self.relu(out)
        return out

瓶颈残差块(Bottleneck Block)

class Bottleneck(nn.Module):
    expansion = 4  # 输出通道数扩展倍数(如输入64 → 输出256)

    def __init__(self, in_channels, out_channels, stride=1):
        super().__init__()
        mid_channels = out_channels // self.expansion  # 中间层通道数(降维)
        # 残差路径:1×1 → 3×3 → 1×1
        self.conv1 = nn.Conv2d(in_channels, mid_channels, kernel_size=1, bias=False)
        self.bn1 = nn.BatchNorm2d(mid_channels)
        self.conv2 = nn.Conv2d(mid_channels, mid_channels, kernel_size=3, stride=stride, padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(mid_channels)
        self.conv3 = nn.Conv2d(mid_channels, out_channels, kernel_size=1, bias=False)
        self.bn3 = nn.BatchNorm2d(out_channels)
        self.relu = nn.ReLU(inplace=True)

        # 跳跃连接
        self.shortcut = nn.Sequential()
        if stride != 1 or in_channels != out_channels:
            self.shortcut = nn.Sequential(
                nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False),
                nn.BatchNorm2d(out_channels)
            )

    def forward(self, x):
        residual = x
        out = self.relu(self.bn1(self.conv1(x)))
        out = self.relu(self.bn2(self.conv2(out)))
        out = self.bn3(self.conv3(out))
        out += self.shortcut(residual)
        out = self.relu(out)
        return out

6. 残差块的变体

变体 特点
Pre-activation 将BN和ReLU放在卷积前(ResNet-v2),进一步优化梯度流。
Wide Residual Blocks 增加通道数(宽度)而非深度,提升性能且减少训练时间。
ResNeXt 引入分组卷积(Grouped Convolution),增强多分支特征融合能力。

7. 残差块的应用

  1. 图像分类:ResNet系列(18/34/50/101/152)在ImageNet上取得突破性精度。
  2. 目标检测:Faster R-CNN、Mask R-CNN等以ResNet为主干网络。
  3. 语义分割:DeepLabv3+等通过残差块捕获多尺度上下文信息。
  4. 生成对抗网络(GAN):提升生成器和判别器的稳定性。

8. 残差块的优缺点

优点

  • 训练极深网络:ResNet-152(152层)可稳定训练,而传统CNN(如VGG-19)在40层后性能下降。
  • 梯度高效传播:跳跃连接减少梯度消失风险。
  • 灵活扩展:可通过堆叠残差块轻松调整网络深度。

缺点

  • 计算开销:Bottleneck结构中的1×1卷积增加计算量。
  • 内存占用:深层网络需保存中间特征图,显存消耗较大。

总结

残差块通过引入跳跃连接,使深度神经网络的训练变得可行且高效,成为现代深度学习模型的基石。其设计思想不仅推动了计算机视觉领域的进步,还被广泛应用于自然语言处理、语音识别等任务。理解残差块的原理与实现,是掌握深度网络设计的关键一步。