Deep Residual Learning for Image Recognition
为什么这篇论文重要
2015 年这篇论文解决了一个看似简单却致命的问题:
神经网络越深,效果应该越好——但 2014 年大家发现,超过 30 层后,效果反而变差。
这违反直觉——更多参数怎么会更糟?
ResNet 给了答案,让神经网络从 20 层暴涨到 1000 层。残差连接(Residual Connection)从此成为深度学习的”基础设施”。
你今天用的 ChatGPT、Stable Diffusion、AlphaFold——全部都用残差连接。
论文核心:一个简单到惊讶的修改
传统神经网络:
input → Layer 1 → Layer 2 → Layer 3 → output
ResNet 改成:
input → Layer 1 → (+)→ Layer 2 → (+)→ Layer 3 → output
└─────────────┘ └─────────────┘
"残差连接" "残差连接"
数学上:每一层学的不是 ,而是 ,输出是 。
这个”加 x”——就是革命。
为什么这个改动能解决问题
直觉 1:梯度有”快速通道”反传
反向传播时,梯度可以通过 skip connection 直接传回浅层,不被深层吃掉。
没有残差:100 层后 grad ≈ 0(每层导数 < 1,连乘消失) 有残差:grad 沿着 skip 直达——浅层仍然能学
直觉 2:网络可以”选择性”不学
如果某一层学不到任何有用的——它学的 , 输出 ——等于直接跳过这一层。
深网络再也不怕”加层让性能下降”。
直觉 3:让 identity mapping 容易
ML 中经常发现”恒等映射”比”复杂映射”难学。 残差结构默认就是 identity + 修正项—— 让模型只需学”修正”,不学完整变换。
ImageNet 实验
| 模型 | 深度 | Top-5 错误率 |
|---|---|---|
| AlexNet (2012) | 8 | 16.4% |
| VGG (2014) | 16-19 | 7.3% |
| GoogLeNet (2014) | 22 | 6.7% |
| ResNet-152 | 152 | 3.57% |
152 层在 ImageNet 上拿下当时 SOTA。 作者还训了 1202 层 的版本——证明这个架构能极深。
那年视觉领域所有人都意识到:残差连接是必备。
没用残差连接前的”plain network”
论文里做了一个关键对比:
20 层 plain network: 训练 loss 0.2, test 错误率 11%
56 层 plain network: 训练 loss 0.5, test 错误率 13%(更差!)
20 层 ResNet: 训练 loss 0.2, test 错误率 11%
56 层 ResNet: 训练 loss 0.1, test 错误率 9%(更好)
这一组数据让残差连接的价值无可争议。
论文的”工程细节”
Bottleneck 设计
为了让深层网络更高效,每个 block 用:
1×1 卷积(降维)
3×3 卷积(处理)
1×1 卷积(升维)
+ skip connection
这让计算量大幅下降。当代 Transformer 的 FFN 也是类似的”先降再升”思路。
BatchNorm
ResNet 也是首批大量使用 BatchNorm 的——和残差连接一起让深网络可训。
它对后续 AI 的影响
今天所有现代神经网络都用残差连接:
- Transformer:每个 attention + FFN 都套了残差
- U-Net(Diffusion 的核心):encoder-decoder 之间的 skip connection
- AlphaFold:处理蛋白质的几十层都用残差
- CNN 系列(EfficientNet, ConvNeXt, MobileNet):全部基于 ResNet
没有残差连接,今天的深度学习几乎没法工作。这一个”+ x”的小修改影响了整个领域 10 年。
一些有趣的事
Kaiming He
第一作者 何凯明 —— 华人科学家,后来去了 Meta,2024 年回 MIT。 他是当代 AI 最高产的研究者之一,单独凭”残差连接”就是教科书人物。
Skip Connection 的”出处”
虽然 ResNet 让残差火了——但类似想法在 1980-90 年代就有 LSTM 的”门”机制。 2015 年另一项工作 Highway Networks 也独立提出类似想法。
科学突破常常是”在恰当的时刻汇总过去想法”——而不是凭空发明。
名字由来
“Residual” 来自数学——拟合的 是 和 之间的”残差项”。 残差学习”= 学剩下的差。
代码实现
import torch.nn as nn
class ResidualBlock(nn.Module):
def __init__(self, in_channels, out_channels, stride=1):
super().__init__()
self.conv1 = nn.Conv2d(in_channels, out_channels, 3, stride=stride, padding=1)
self.bn1 = nn.BatchNorm2d(out_channels)
self.conv2 = nn.Conv2d(out_channels, out_channels, 3, padding=1)
self.bn2 = nn.BatchNorm2d(out_channels)
self.relu = nn.ReLU()
# 残差连接(如果尺寸不一致需要转换)
self.shortcut = nn.Identity()
if in_channels != out_channels or stride != 1:
self.shortcut = nn.Sequential(
nn.Conv2d(in_channels, out_channels, 1, stride=stride),
nn.BatchNorm2d(out_channels),
)
def forward(self, x):
residual = self.shortcut(x)
out = self.relu(self.bn1(self.conv1(x)))
out = self.bn2(self.conv2(out))
out += residual # ← 关键
return self.relu(out)
就这么简单——但改变了整个领域。
推荐配套阅读
- HelloAI: L3-06 CNN 卷积原理
- Deep Residual Learning 原论文(CVPR 2016 best paper)
- 后续重要论文:DenseNet(密集连接)、ResNeXt(“split-transform-merge”)
ResNet 在 CVPR 2016 拿了最佳论文。 5 年后,凯明 He 又在 CVPR 2022 拿了一次(Masked Autoencoders)。 8 年后,他又在 ICCV 2023 拿了一次(Diffusion 相关)。
一些人改变了一次领域,一些人持续改变。
想要更多论文精读
订阅每周精选 —— 下一篇论文笔记直接送邮箱。
讨论区
· 用 GitHub 账号登录评论src/components/Comments.astro 顶部填入
仓库 ID 和分类 ID(见组件注释里的配置步骤)。