残差网络的介绍
如果你接触过深度学习中的图像任务,一定听过 “残差网络”(Residual Network,简称 ResNet)这个名字。作为 2015 年 ImageNet 图像分类竞赛的冠军模型,ResNet 彻底解决了 “深层网络难训练” 的痛点,将网络层数从几十层提升到上千层,也成为了如今目标检测、图像分割等任务的 “骨干网络” 基石。
一、ResNet 诞生的背景:深层网络的 “梯度困境”
在 ResNet 出现之前,研究者们普遍认为 “网络层数越深,性能越好”—— 毕竟更深的网络能提取更复杂的特征。但实际训练中却遇到了两个致命问题:
1. 梯度消失 / 梯度爆炸
当网络层数超过 20 层后,反向传播时梯度会不断乘以 “小于 1 的权重”(或 “大于 1 的权重”),导致梯度逐渐趋近于 0(消失)或无限增大(爆炸)。最终浅层网络的参数无法更新,模型训练陷入停滞。
虽然当时已有 ReLU 激活函数、批归一化(Batch Normalization)等方法缓解,但当层数突破 50 层后,问题依然无法解决。
2. 退化问题(Degradation)
即使梯度没有完全消失,深层网络的性能也会 “不升反降”—— 比如一个 50 层的网络,测试准确率反而比 20 层的网络更低。这并非过拟合,而是深层网络的特征表达能力出现了 “退化”,简单来说:深层网络连 “复制” 浅层网络的性能都做不到。
正是在这样的背景下,何凯明团队在 2015 年发表了《Deep Residual Learning for Image Recognition》,提出了 “残差连接”(Residual Connection)的设计,一举将网络层数提升到 152 层,同时在 ImageNet 上实现了当时的最高准确率。
二、ResNet 的核心:残差块与跳跃连接
ResNet 的精髓只有一个 ——残差块(Residual Block)。它通过 “跳跃连接”(Skip Connection)的设计,让梯度能 “畅通无阻” 地回传,同时解决了退化问题。
1. 残差块的核心思想:“绕路” 的特征融合
我们先思考一个问题:如果深层网络的某一层 “没有学习到更好的特征”,能不能让它直接 “复用” 前一层的特征,而不是强行学习新特征?
ResNet 的答案是:可以。
传统卷积层的目标是学习一个 “映射函数” \(H(x)\)(输入x经过卷积、激活后得到输出\(H(x)\));而残差块则将目标拆分为两部分:
学习一个 “残差映射” \(F(x) = H(x) - x\)(即 “新特征与原始特征的差异”);
最终输出为 \(H(x) = F(x) + x\)(将原始输入x直接 “跳” 过卷积层,与残差\(F(x)\)相加)。
这个 “跳过卷积层直接相加” 的操作,就是跳跃连接(也叫恒等映射连接)。
2. 残差块的两种经典结构
根据网络层数和计算效率,ResNet 设计了两种残差块,分别对应不同深度的模型:
(1)基础残差块(Basic Block):适用于 ResNet-18/34
结构简单,由 2 个 3×3 卷积层组成,配合跳跃连接实现残差融合。其流程如下:
输入 x → 3×3卷积(ReLU激活)→ 3×3卷积 → 与输入x相加 → ReLU激活 → 输出
关键细节:卷积层的padding
会设置为 1,确保卷积后的特征图尺寸与输入x一致(比如 28×28 的输入,卷积后仍为 28×28),这样才能与x直接相加。
就像我们之前在 MNIST 任务中实现的残差块:
class ResBlock(nn.Module):def __init__(self, channels_in):super().__init__()self.conv1 = nn.Conv2d(channels_in, 30, kernel_size=5, padding=2) # 保持尺寸self.conv2 = nn.Conv2d(30, channels_in, kernel_size=3, padding=1) # 恢复输入通道数def forward(self, x):out = self.conv1(x)out = self.conv2(out)return F.relu(out + x) # 跳跃连接:out(残差)+ x(原始输入)
(2)瓶颈残差块(Bottleneck Block):适用于 ResNet-50/101/152
当网络层数超过 50 层时,基础残差块的计算量会急剧增加。瓶颈块通过 “1×1 卷积降维→3×3 卷积提特征→1×1 卷积升维” 的设计,在保证性能的同时减少计算量:
输入 x → 1×1卷积(降维,减少通道数)→ ReLU → 3×3卷积(提特征)→ ReLU → 1×1卷积(升维,恢复通道数)→ 与输入x相加 → ReLU → 输出
举个例子:输入通道数为 256,瓶颈块会先通过 1×1 卷积将通道数降到 64(降维),再用 3×3 卷积处理(计算量仅为直接处理 256 通道的 1/16),最后用 1×1 卷积恢复到 256 通道,与输入 x 相加。
三、ResNet 的整体架构:从输入到输出
ResNet 的整体架构非常规整,以经典的 ResNet-50 为例,分为 5 个阶段(Stage 0 到 Stage 4),每个阶段由多个残差块组成,最后通过全连接层输出分类结果:
阶段(Stage) | 网络层 | 输出通道数 | 特征图尺寸 | 残差块数量 |
---|---|---|---|---|
Stage 0 | 7×7 卷积(步长 2)+ 池化 | 64 | 112×112 | - |
Stage 1 | 瓶颈块(Bottleneck) | 256 | 56×56 | 3 |
Stage 2 | 瓶颈块 | 512 | 28×28 | 4 |
Stage 3 | 瓶颈块 | 1024 | 14×14 | 6 |
Stage 4 | 瓶颈块 | 2048 | 7×7 | 3 |
最终层 | 全局平均池化 + 全连接 | 1000 | 1×1 | - |
关键流程:
输入图像(如 224×224×3)先经过 7×7 大卷积和最大池化,缩小尺寸并提取初步特征;
然后进入 4 个阶段的残差块,每个阶段的残差块数量逐渐增加,通道数翻倍、尺寸减半(通过步长为 2 的卷积实现);
最后通过全局平均池化将特征图压缩为 1×1×2048 的向量,再用全连接层输出 1000 类(对应 ImageNet 的 1000 个类别)的预测结果。
四、ResNet 的优势与影响:不止于图像分类
ResNet 的出现不仅解决了深层网络的训练问题,更深刻影响了后续所有计算机视觉任务,其核心优势包括:
1. 可训练的深层网络
首次实现了上千层网络的稳定训练,比如 ResNet-1000 在 ImageNet 上仍能收敛,打破了 “层数越深性能越差” 的魔咒。
2. 特征复用能力
跳跃连接让浅层特征能直接传递到深层,避免了深层网络 “遗忘” 浅层的基础特征(如边缘、纹理),提升了特征表达的丰富性。
3. 泛化能力强
ResNet 在小数据集(如 MNIST、CIFAR)和大数据集(如 ImageNet)上都表现优异,且不易过拟合,成为迁移学习的首选骨干网络。
ResNet 的衍生应用
如今 ResNet 已不是一个单一模型,而是一个 “家族”,并广泛应用于各类计算机视觉任务:
目标检测:Faster R-CNN、YOLOv5 等模型用 ResNet 作为骨干网络,提取高质量的图像特征;
图像分割:U-Net 的变体(如 ResUNet)加入残差块,解决分割任务中深层梯度消失的问题;
人脸识别:ArcFace 等算法用 ResNet 提取人脸特征,提升识别准确率;
迁移学习:预训练的 ResNet 模型(如 ResNet-50)可快速微调适配自定义任务,减少数据需求和训练时间。
五、实践建议:如何用 ResNet 解决你的任务?
如果你想在自己的项目中使用 ResNet,不需要从零实现 ——PyTorch、TensorFlow 等框架已内置了预训练的 ResNet 模型,直接调用即可:
示例:PyTorch 调用预训练 ResNet-50
import torch
from torchvision import models# 加载预训练的ResNet-50(权重来自ImageNet)
model = models.resnet50(pretrained=True) # 或 torch.hub.load(...)# 微调:修改最后一层全连接层,适配自定义分类任务(如10类)
num_classes = 10
model.fc = torch.nn.Linear(model.fc.in_features, num_classes)# 移动到GPU(如果有)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = model.to(device)
新手入门建议
- 先理解残差块:从简单的基础残差块入手,用 MNIST 或 CIFAR-10 数据集实现一个 18 层的 ResNet,观察训练过程中梯度的变化;
- 尝试微调预训练模型:对于自定义任务(如自己的图像分类),优先使用预训练的 ResNet-50/101,仅微调最后几层,效率更高;
- 注意通道匹配:如果自己设计残差块,务必确保跳跃连接的两端(输入 x 和残差 F (x))的通道数和尺寸一致,否则会报错。
六、总结:ResNet 为何能成为 “常青树”?
ResNet 的成功,本质上是 “简单有效” 的设计哲学 —— 没有复杂的理论创新,只是通过一个巧妙的 “跳跃连接”,解决了深度学习领域长期存在的 “深层网络难训练” 问题。
它不仅是一个模型,更提供了一种 “特征融合” 的思路:在设计深层网络时,不要让每一层都 “从零学习”,而是让它们 “学习差异”,通过复用浅层特征提升效率。这种思路也影响了后续的 DenseNet、EfficientNet 等模型,成为深度学习的重要设计范式。