当前位置: 首页 > news >正文

残差网络ResNet原理深度解读:连小学生都能看懂的近路哲学

残差网络 ResNet 原理深度解读:连小学生都能看懂的"近路"哲学

2015年,He Kaiming 等人发表了一篇论文,标题只有两个词:《Deep Residual Learning》。同年 ImageNet 挑战赛,他们用这个方法拿下了图像分类、检测、定位三项冠军,错误率低至 3.6%,首次低于人类的直观判断。

这篇解释,不需要你懂高等数学,只需要你有过这些生活体验:搬家时漏了东西怎么办、抄近路比绕路快、组队完成任务比一个人扛更稳。


一、深度学习为什么会"力不从心"

普通网络像什么:一条越来越窄的流水线

想象你在组装手机。

第1个人负责焊接零件,第2个人负责装屏幕,第3个人负责测试…流水线越来越长,每个工位都在"加工"前一个人传过来的东西。

问题来了:如果第1个人焊错了,后面所有人都在用错误零件作业,越往后错得越离谱。

这就是普通深层网络的问题:信息从第一层传到最后一层,每层都要"加工"一次,传到最后层时,原始信号已经变味了。

梯度消失像什么:老板的消息在群里传丢了

你发消息给老板:“明早9点开会”。

老板转发给主管:“明早9点开会”。

主管转发给组长:“明早开会”。

组长转发给员工:“开会”。

员工不知道几点来。

老板原始消息在传递过程中"消失"了,每层都改一点,最后面目全非。

这就是梯度消失:反向传播时,梯度信号每经过一层就衰减一点,传到第一层时几乎归零。最前面的参数根本收不到"老板的指令",不知道怎么调整。

退化问题:不是过拟合,是连拟合都做不到

有人会问:深度网络至少应该和浅层网络性能一样吧?最差的情况,我让后面的层什么都不做,把前面学好的结果直接传过去不行吗?

不行。

因为网络有非线性层。让后面的层"什么都不做"(恒等映射),比让它学一个新的变换更难

这听起来违反直觉,举个例子:

  • 你想抄近路:直接走到对面 → 你知道目的地,路径清晰,一句话的事
  • 你被迫绕路:先把地图背下来,然后在脑子里模拟走一遍路线 → 信息必须经过"理解-编码-存储"流程,多了好几层处理

网络里的非线性层就是那个"强迫你绕路的流程"。它让简单的"直接传过去"变得很麻烦。

这就是退化问题(Degradation Problem):网络越深,性能反而下降。不是因为过拟合,而是因为连"抄近路"都做不到。


二、残差连接:给信息开一条"近路"

H(x) = F(x) + x 是什么

先别被公式吓跑,我们把它翻译成人话:

  • H(x):这个残差块最终要输出的东西(最终产品)
  • x:原始输入(原材料)
  • F(x):这个残差块真正"做"的变换(加工过程)
  • + x:把加工后的东西和原材料加在一起(最终出厂)

还是搬家公司的例子:

  • 你有10个箱子,工人负责把箱子从A点搬到B点。
  • 普通做法:工人全部从A搬到B,走同样的路线,最前面的人如果搬错,后面的人都在用错的箱子继续搬。
  • 残差做法:工人先搬,同时留一个人直接拎箱子走过去(近路)。最后B点收到的是:工人搬的箱子 + 直接拎过来的箱子,两者合并。

近路(Shortcut)保证了:就算工人搬错了,最原始的箱子还是有一条通路能到B点。

F(x) + x 的直观理解

生活中找类比:老师批作业。

  • 普通网络:老师把学生作业收上来,撕掉原题,只留学生写的答案,然后从头推算学生原来做了什么。结果:你根本不知道学生原来写了什么。
  • 残差网络:老师把学生作业和标准答案一起看,只批改学生写错的部分。改完的分数 = 错的分数 + 基准分。

基准分就是 x(原始输入),改错的分数就是 F(x)(残差部分)。老师只需要专注改错,不用从头算整道题。

跳跃连接(Skip Connection)是什么

跳跃= 跳过某些层,直接把前面学到的信息传过来。

生活类比:微信群里的"回复这条消息"功能。

你在一堆聊天记录里,看到一条消息被标记为"重要回复"。你直接点进去,跳过了中间几百条废话,直接看这条重点。

跳跃连接就是这样:后面的层可以"直接点进"前面的信息,不用一层层爬楼。


三、从代码理解残差块

最简单的残差块

importtorchimporttorch.nnasnnclassSimpleResidualBlock(nn.Module):""" 最基础的残差块:F(x) + x """def__init__(self,channels):super().__init__()self.conv1=nn.Conv2d(channels,channels,3,padding=1)self.bn1=nn.BatchNorm2d(channels)self.conv2=nn.Conv2d(channels,channels,3,padding=1)self.bn2=nn.BatchNorm2d(channels)self.relu=nn.ReLU(inplace=True)defforward(self,x):residual=x# 第一步:把原材料单独留一份(x)out=self.relu(self.bn1(self.conv1(x)))# 第二步:F(x) 第一层out=self.bn2(self.conv2(out))# 第三步:F(x) 第二层out=out+residual# 第四步:加工完的 + 原材料out=self.relu(out)# 第五步:激活,出厂returnout

这5步翻译成人话

  1. 留一份原材料
  2. 过一个非线性层
  3. 再过一个非线性层
  4. 把加工结果和原材料合并
  5. 激活出厂

核心就是第4步:把 x(原材料)和 F(x)(加工品)加在一起。

维度不匹配怎么办:近路也有"窄路"和"宽路"

有时候从A点到B点,近路是条小路,走不了大卡车。

这时候你需要投影(Projection):把大卡车的东西装到小车上,走小路运过去,再卸到卡车上。

classResidualBlockWithProjection(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(inplace=True)# 近路(Shortcut):维度不同时,需要"投影"成一样大self.shortcut=nn.Sequential()ifstride!=1orin_channels!=out_channels:self.shortcut=nn.Sequential(nn.Conv2d(in_channels,out_channels,1,stride=stride),nn.BatchNorm2d(out_channels))defforward(self,x):residual=self.shortcut(x)# 近路先过一遍,把尺寸对齐out=self.relu(self.bn1(self.conv1(x)))out=self.bn2(self.conv2(out))out=out+residualreturnself.relu(out)

什么时候维度会变:下采样时(图片从224×224缩小到112×112),通道数通常会增加。就像搬家时把所有小箱子合并成几个大箱子,近路必须跟着调整。


四、梯度高速公路:为什么残差网络不会"失联"

普通网络的梯度传播:爬楼梯停电了

想象你在一栋100层的楼里,电梯坏了,楼梯停电了。

你要从100层往下走,每走一层手机就掉一格电。走到第50层,电没了,你困在中间,上不去下不来。

普通深层网络的梯度传播就是这样:经过100层,每层衰减一点,传到第1层时梯度几乎归零,第一层的参数"困"住了,不知道该往哪个方向调。

残差网络的梯度传播:有备用电源

同样是100层楼,残差网络在每10层留了一条直接到地面的滑梯

就算走到第20层没电了,你可以滑到10层,继续往下走,滑到地面。梯度也是同样的道理:

梯度 = 主路梯度 + 近路梯度(恒为1)

就算主路梯度衰减到接近零,近路梯度永远等于1,直接传回去。

数学上:∂L/∂x = ∂L/∂H · (∂H/∂F · ∂F/∂x + 1)

不管 ∂H/∂F · ∂F/∂x 多小,+1保证梯度不会消失。

为什么加法能让梯度"跳过"层

生活类比:老板让你做报告,你不是一个人写完交差,而是:

  • 你先写初稿
  • 秘书帮你校对格式
  • 财务帮你核实数据
  • 法务帮你检查合规

每一步都有**“原始需求”**作为参照,不是每个人从零理解老板的意思。

残差连接就是那个让每层都能看到"老板原始需求"的机制——原始输入 x 作为"基准"始终存在,梯度可以顺着这个基准快速回传。


五、ResNet 的整体结构:4个"车间",层层递进

ResNet 像一条工厂流水线

ResNet-50 的结构可以这样理解:

图片进来 → 粗加工车间(conv1) → 细加工车间1(stage1,3个残差块) → 细加工车间2(stage2,4个残差块) → 细加工车间3(stage3,6个残差块) → 细加工车间4(stage4,3个残差块) → 打包出厂(fc)

每个车间之间会发生什么:图片尺寸缩小(从224→112→56→28→14→7),通道数增加(从64→128→256→512)。这就是下采样。工厂需要把原材料逐步缩小、压缩、提纯。

瓶颈残差块(Bottleneck):先压缩再加工

ResNet-50 和 ResNet-101 用的不是基础残差块,而是瓶颈块

类比:你要把一张高清照片压缩成表情包。

  • 普通做法:原图 → 模糊化 → 压缩 → 表情包(直接压缩,信息损失大)
  • 瓶颈块做法:原图 → 压缩成小图(1×1降维)→ 精细处理(3×3卷积)→ 放大回原尺寸(1×1升维)→ 表情包
瓶颈块结构:1×1卷积(压缩)→ 3×3卷积(加工)→ 1×1卷积(还原)

这样可以用更少的计算量达到同样的效果,所以 ResNet-50 可以有50层,而 ResNet-18 只有18层(18层用基础块就够了)。

各型号 ResNet 对比

模型层数残差块数参数量ImageNet top-1 错误率
ResNet-18188 (基础块)11.7M~30%
ResNet-343416 (基础块)21.8M~26%
ResNet-505016 (瓶颈块)25.6M~24%
ResNet-10110133 (瓶颈块)44.5M~23%
ResNet-15215250 (瓶颈块)60.2M~22%

规律:层数越深 → 错误率越低,但参数量也在涨。


六、训练 ResNet 的踩坑指南

坑1:BatchNorm 和 ReLU 的顺序

错误做法Conv → ReLU → BN

正确做法Conv → BN → ReLU

类比:工厂质量检测应该在发货前做,而不是发货后做。BN 放在激活函数前面,让激活函数在归一化后的分布上工作,减少信息损失。

# ✅ 正确out=self.bn1(self.conv1(x))out=self.relu(out)# ❌ 错误out=self.relu(out)out=self.bn1(self.conv1(x))

坑2:学习率别照抄普通网络

普通网络训练时,学习率 0.1 可能合适。

ResNet 因为梯度流动更强,参数更新幅度更大,如果用同样的学习率,容易震荡

建议:用余弦退火,让学习率平缓下降,不要断崖式跌落。

optimizer=torch.optim.SGD(model.parameters(),lr=0.05,# ResNet 建议从 0.05 开始momentum=0.9,weight_decay=1e-4)scheduler=torch.optim.lr_scheduler.CosineAnnealingLR(optimizer,T_max=90)

坑3:权重初始化用 He 初始化

普通网络可以用 Xavier 初始化。

ResNet 用 He 初始化(Kaiming Normal),专门针对 ReLU 设计:

definit_weights(m):ifisinstance(m,nn.Conv2d):nn.init.kaiming_normal_(m.weight,mode='fan_out',nonlinearity='relu')elifisinstance(m,nn.BatchNorm2d):nn.init.constant_(m.weight,1)nn.init.constant_(m.bias,0)model.apply(init_weights)

七、ResNet 之后发生了什么

残差连接的思想催生了后续一整套模型进化:

路线1:让残差更"密集" → DenseNet

残差连接是 Add(加法),信息是融合

DenseNet 是 Concat(拼接),信息是堆叠

类比:

  • ResNet:把A同学做的笔记和B同学批注加在一起 → 两人合作的产出
  • DenseNet:把A的笔记、B的笔记、C的笔记全部钉在一起 → 三本笔记的完整集合
classDenseBlock(nn.Module):"""DenseNet 的密集连接:每一层的输出都和所有前面的层拼接"""def__init__(self,in_channels,growth_rate,num_layers):super().__init__()self.layers=nn.ModuleList()foriinrange(num_layers):self.layers.append(self._make_layer(in_channels+i*growth_rate,growth_rate))def_make_layer(self,in_channels,growth_rate):returnnn.Sequential(nn.BatchNorm2d(in_channels),nn.ReLU(inplace=True),nn.Conv2d(in_channels,growth_rate,3,padding=1))defforward(self,x):features=[x]forlayerinself.layers:new_feature=layer(torch.cat(features,dim=1))features.append(new_feature)returntorch.cat(features,dim=1)

DenseNet 的优势:参数利用率更高,相同性能下参数量更少。缺点是显存占用大(所有层输出都堆在一起)。

路线2:让残差关注"重要通道" → SE-ResNet

Squeeze-and-Excitation(SE)模块:让网络学会判断哪些通道重要、哪些可以忽略。

类比:老师在批改作业时,有些学生字迹清晰(重要通道),有些学生写得很潦草(噪声通道)。SE 模块就是那个帮老师"快速识别重点"的工具。

classSEBlock(nn.Module):"""通道注意力:让网络自己决定哪些通道值得重点关注"""def__init__(self,channels,reduction=16):super().__init__()self.avg_pool=nn.AdaptiveAvgPool2d(1)self.fc=nn.Sequential(nn.Linear(channels,channels//reduction),nn.ReLU(inplace=True),nn.Linear(channels//reduction,channels),nn.Sigmoid())defforward(self,x):b,c,_,_=x.size()# 全局压缩:把每个通道的信息压成一个数y=self.avg_pool(x).view(b,c)# 重新赋权:每个通道的重要性打分y=self.fc(y).view(b,c,1,1)returnx*y.expand_as(x)

路线3:Transformer 里的残差 → ViT

2020 年,Vision Transformer(ViT)把残差连接带入了 Transformer 架构。

在 Transformer 里,残差连接以LayerNorm + Add的形式存在:

classTransformerBlock(nn.Module):"""Transformer 中的残差:LayerNorm → 算子 → Add → LayerNorm → FFN → Add"""def__init__(self,embed_dim,num_heads):super().__init__()self.norm1=nn.LayerNorm(embed_dim)self.attn=nn.MultiheadAttention(embed_dim,num_heads)self.norm2=nn.LayerNorm(embed_dim)self.ffn=nn.Sequential(nn.Linear(embed_dim,embed_dim*4),nn.GELU(),nn.Linear(embed_dim*4,embed_dim))defforward(self,x):# 残差连接:原始 x 和注意力输出相加x=x+self.attn(self.norm1(x))[0]# 残差连接:原始 x 和 FFN 输出相加x=x+self.ffn(self.norm2(x))returnx

ResNet 的跳跃连接思想,在 Transformer 时代以 LayerNorm + Add 的形式继续发光发热。


八、生产环境实战:用 PyTorch 跑起来

加载预训练模型,5行代码

importtorchvision.modelsasmodels# 加载 ResNet-50,用 ImageNet 预训练的权重model=models.resnet50(weights='IMAGENET1K_V2')# 替换最后的分类头(原来分1000类,我们分10类)model.fc=nn.Linear(model.fc.in_features,10)

微调(Fine-tune):只训练最后几层

# 冻结前面的层,只训练分类头forparaminmodel.parameters():param.requires_grad=False# 只解冻分类头forparaminmodel.fc.parameters():param.requires_grad=Trueoptimizer=torch.optim.Adam(model.fc.parameters(),lr=1e-3)

完整训练流程

importtorchvision.transformsasT# 数据增强(这步很关键,决定了模型泛化能力)train_transform=T.Compose([T.RandomResizedCrop(224),T.RandomHorizontalFlip(),T.ColorJitter(0.3,0.3,0.2),# 颜色抖动:让模型不"认颜色"T.ToTensor(),T.Normalize([0.485,0.456,0.406],[0.229,0.224,0.225])])train_ds=torchvision.datasets.ImageFolder('data/train',train_transform)train_loader=torch.utils.data.DataLoader(train_ds,batch_size=64,shuffle=True,num_workers=4)# 训练forepochinrange(90):model.train()forimages,labelsintrain_loader:images,labels=images.cuda(),labels.cuda()optimizer.zero_grad()loss=nn.CrossEntropyLoss()(model(images),labels)loss.backward()optimizer.step()scheduler.step()

九、总结:残差的本质是什么

ResNet 的核心公式只有一行:

H(x) = F(x) + x

但这个简单的加法,解决了一个根本问题:把"学什么"变成了"改什么"

  • 普通网络:学习完整的 H(x)(从零画一幅画)
  • 残差网络:学习 H(x) - x(只画错了的部分)

近路的价值:让梯度有了"高速公路",100+层的训练成为可能

残差思想的影响:从 ResNet 到 DenseNet、SE-Net、ViT,跳跃连接无处不在。

记住这个比喻:老师批作业,不是从头重做一遍,而是只改错的地方。近路(Shortcut)保证了:就算改错了,原文还在。

参考资料

  • He Kaiming et al., “Deep Residual Learning for Image Recognition”, CVPR 2016
  • He Kaiming et al., “Identity Mappings in Deep Residual Networks”, ECCV 2016
  • Gao Huang et al., “Densely Connected Convolutional Networks”, CVPR 2017
  • Jie Hu et al., “Squeeze-and-Excitation Networks”, CVPR 2018
http://www.jsqmd.com/news/861192/

相关文章:

  • 吉他初学者音阶怎么弹?吉他音阶怎么练效果最好? - 雨林谷
  • Godot 4.3+生产级3D反向运动学(IK)系统实战指南
  • 手写一个AI代码审查员:Claude Agent SDK + MCP 深度实战
  • 2025-2026年国内北京国际小学推荐:五校口碑好的评测 课后活动避免兴趣培养不足注意事项 - 品牌推荐
  • 2026年5月天津国际高中推荐:五所排名学校评测夜读防焦虑 - 品牌推荐
  • 一文讲透|盘点2026年标杆级的AI论文网站
  • 2026正规空投平台怎么选:空投加盟/空投孵化/空投扶持/轻资产创业/链上光年加盟/链上光年孵化/链上光年工作室/选择指南 - 优质品牌商家
  • 毕业设计 深度学习车道线检测(源码+论文)
  • Cursor Pro免费激活工具终极指南:如何绕过限制无限使用AI编程助手
  • 2026年4月,这些无缝方管厂家不容错过,冷拔精密无缝钢管/冷拔无缝钢管/20# 精密钢管,方管生产厂家有哪些 - 品牌推荐师
  • 2026触摸互动软件怎么选:查询触摸软件、触控查询软件、触摸屏一体机软件、触摸屏查询机软件、触摸屏查询系统软件选择指南 - 优质品牌商家
  • AI正在重写数据库的规则:为什么未来十年最重要的基础设施是给AI用的
  • 2026现阶段,成都塑胶管道行业为何聚焦宥镁科技这家直销工厂? - 2026年企业推荐榜
  • DeepSeek正在做一件大事:做一个能写代码的AI Agent,对标Claude Code
  • 茂名当地方管厂家哪家口碑不错?看这里,无缝钢管/精密钢管/冷拔精密钢管/冷拔精密无缝钢管/合金无缝管,方管供应商最近报价 - 品牌推荐师
  • AI广告投放Agent:从Demo到实战的半年进化
  • 使用Taotoken后Keil5项目代码审查效率的直观提升
  • 2026年5月新消息:成都PE给水管制造厂的技术革新与市场格局分析 - 2026年企业推荐榜
  • 【限时解密】ElevenLabs未开放的客家话语音fine-tuning沙箱环境:如何用不到200条标注语句,在72小时内将模型MOS分从3.1提升至4.4(附私有化微调checklist)
  • 2026年4月米线加盟品牌选哪家:小吃加盟什么好、小吃加盟品类推荐、小吃加盟店什么好、小吃加盟推荐什么品牌、小吃店加盟联系方式选择指南 - 优质品牌商家
  • 标准化封装国产电源:钡特电源 VB50-24S24LD 与金升阳 URB2424LD-50WR3 同属工业高可靠
  • 德州2026年05月无缝钢管推荐:这些厂家值得一看,合金无缝管/冷拔精密钢管,无缝钢管厂商最近报价 - 品牌推荐师
  • GitHub史诗级泄露:3800个核心仓库被窃,TeamPCP如何通过VS Code扩展攻破全球最大代码平台
  • 2026宝鸡装修避坑全攻略:宝鸡现代简约装修公司/宝鸡装修公司免费设计/宝鸡装修公司全包价格/宝鸡装修公司别墅装修/选择指南 - 优质品牌商家
  • 2026年Q2南充广安区域租赁服务商排行及联系方式:四川鼎全机械租赁有限公司联系电话、南充吊车租赁电话、南充施工垫路铁板租赁选择指南 - 优质品牌商家
  • [智能体-7]:业务数据序列化为 JSON 字符串 完整示例
  • 物理标签退场,视觉原生上位:UWB vs 镜像视界无感定位・空间智能重构
  • 2026年全国商用制冷设备厂家TOP5:四川医药制冷设备、四川大型冷冻库安装、四川小型冷冻库安装、四川气调冷库选择指南 - 优质品牌商家
  • 2025-2026年国内新中式实木全屋定制推荐:五大品牌排行评测解决客厅显暗致压抑 - 品牌推荐
  • 如何在Mac上优雅的配置stm32开发环境?