ARTICLE · 1256424
ResNet 源码精读:跳过一层再相加,CVPR 2016 最佳论文怎么把网络做到 152 层
ResNet 源码精读:跳过一层再相加,CVPR 2016 最佳论文怎么把网络做到 152 层paper-2 今天回到源头:CVPR 2016 最佳论文 ResNet。它是已收名单之外、视觉基础研究里绕不开的那一篇——没有它,后面的 DenseNet、Transformer 里的残差连接、乃至今天所有超过十层的网络都要重新发明。九年后重读这份源码,重点不是怀旧,是看清那个设计为什么能赢,以及它今天还留在哪些你可能天天用的模型里。 
2015 年之前的主流认知:网络越深,表达能力越强,但训练会先崩掉。二十几层的网络堆上去,训练误差不降反升——这不是过拟合(测试集才有的现象),是优化本身失败了。批归一化缓解了一部分,但上百层的网络依然训不动。 ResNet 的答案异常简单:让每层学「残差」而不是学「完整映射」。把恒等映射抄一条捷径(shortcut),堆叠层只学 F(x) = H(x) − x,输出变成 F(x) + x。如果某一层没用,它只需把 F 学成零,恒等捷径保证信息无损通过——深层网络退化成浅层网络,最坏不输,好了就赚。公式 y = F(x, {Wi}) + x 里三个量:x 是输入,F 是残差分支学到的修正,y 是输出。梯度经加法直接回流,上百层也不会消失。 结果:152 层的 ResNet 拿下 ImageNet 2015 分类冠军,top-5 错误率 3.57%,首次在人机大战里超过人类水平(约 5.1%)。这个数字直接改写了行业对「深度」上限的想象。 官方 Torch 仓库(facebookarchive 上)加社区 PyTorch 移植版(pytorch/vision 的 resnet.py)对照读,三处值得停留。 第一,BasicBlock 与 Bottleneck 的分工。50 层以内用 BasicBlock:两个 3×3 卷积加一条捷径,结构朴素。50 层以上换 Bottleneck:1×1 降维、3×3 卷积、1×1 升维的三明治——先降通道数再卷积,计算量压下来,152 层才训得动。今天推理框架里 resnet50/101/152 的默认结构就锁在这两个类的实现里。算一笔账就明白 Bottleneck 的意义:resnet50 的一个瓶颈块,3×3 卷积在 256 通道(而非 2048)上进行,单块计算量约是朴素结构的十分之一——深度上去了,算力账还能算平。 第二,downsample 分支的条件触发。当 stride 变化或通道数扩展时,捷径上要挂一个 1×1 卷积对齐维度(代码里 self.downsample),没有这个分支的张量和捷径直接相加会形状不匹配。读代码时盯住 forward 里 identity = x 与 out += identity 的位置,残差结构一目了然。这个细节还有个工程副产品:1×1 卷积的捷径会带来轻微性能损失,所以后续研究(如 ResNet-D、Identity Mappings)都在琢磨怎么把捷径保持「干净」——一条捷径的纯洁性,养活了好几篇论文。 第三,训练配方的份量不亚于结构。论文写的超参:batch 256、动量 0.9、权重衰减 1e-4,学习率从 0.1 起每 30 轮除以 10;数据增强用了当时激进的 scale augmentation(短边随机缩放到 [256, 480])。很多复现失败不是结构抄错,是这些训练细节没对齐——这也是为什么读原论文和官方配置仍然重要。 ResNet 本体作为分类器仍在工业界大量服役:嵌入式视觉、质检、边缘设备上的特征提取,50 层版本是「够用且便宜」的默认选项。但更深的遗产是那条捷径:Transformer 每个块的 x + Attention(x)、x + FFN(x),diffusion 模型 UNet 的跳连,图网络的消息传递残差——全是这个思想的变体。 有个常被忽略的行业事实:CLIP 的视觉编码器、Stable Diffusion 的 UNet 骨架、目标检测的 FPN 结构——这些今天仍在生产环境跑的模型,骨架里都留着 ResNet 的残差连接。深度学习框架把「加一条捷径」做成了默认组件,后来者甚至意识不到这曾是拦住整个领域四年的墙。 何恺明后来拿 Marr 奖的工作里提到,ResNet 的成功有一部分来自「把问题简化到不能再简」:不加门控、不加注意力、不加深路径交互,纯加法。后来的大量研究证明,加门控、加权捷径确实能再涨一点,但那一点远不如原始设计的简洁和鲁棒值钱。工程上这是反复出现的教训:能用加法解决的地方,别急着上乘法。 还有一段值得记的历史:ResNet 论文 2015 年 12 月挂 arXiv 时,何恺明在微软亚洲研究院,团队里还有张祥雨、任少卿、孙剑——这个名单后来撑起了国内半边 CV 工业界。孙剑 2022 年离世时,业界悼念的正是这条从 ResNet 延伸出去的谱系。一份源码连着一段人才史,这也是读经典仓库的额外收获。 想跑:torchvision 一行加载预训练权重,CIFAR 或 ImageNet 子集微调即可感受训练动态;想读:从 pytorch/vision 的 resnet.py 进去,BasicBlock.forward 二十行看完残差的全部实现,再对照 Bottleneck 看通道压缩怎么省算力。容易看错的一点:论文表格里的 152 层把卷积层计数到全连接前,捷径层不计入——自己数层数对不上时先想这条。 给入门者一个读码顺序建议:先跑通 resnet18(BasicBlock,最简),对照论文图 5 的左图确认每个算子的位置;再切 resnet50 看 Bottleneck,对照图 5 右图数一遍 1×1→3×3→1×1 的通道变化(256→64→64→256);最后看 _make_layer 怎么用 stride 控制下采样和 downsample 的触发条件。三步走完,残差网络的骨架就长在脑子里了——后面读 Transformer 实现时,看到 x = x + attn(x) 那行,你会认出它的血统。 判断部分留给一句评价:这是那种「解决了自己领域最核心矛盾,然后顺便改写了所有其它领域」的工作。九年后每个做深度学习的人仍在它的延长线上,值得每个新入门的人完整读一遍源码——很短,短得配得上它的优雅。
















































































