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

一文搞懂CNN经典架构-ResNet!

推荐直接网站在线阅读:https://aicoting.cn

在深度学习的发展过程中,人们逐渐发现:随着神经网络层数的增加,模型的表现并不一定更好。在实际训练中,深层网络往往出现 梯度消失、梯度爆炸 或 退化问题 —— 即训练误差反而比浅层网络更高。

2015 年,何恺明等人提出了 ResNet(Residual Network),首次在 ImageNet 挑战赛中使用超过 100 层的网络结构,并获得了冠军。ResNet 的关键创新是 残差连接(Residual Connection),它解决了深层网络训练困难的问题,使深度学习真正进入超深网络时代。

残差思想

在传统的网络中,每一层都试图学习一个映射函数H ( x ) H(x)H(x)

ResNet 提出的思想是,让网络学习 残差函数:
H ( x ) = F ( x ) + x H(x) = F(x) + xH(x)=F(x)+x

其中,F ( x ) = H ( x ) − x F(x) = H(x) - xF(x)=H(x)x表示残差。

这样一来,如果最优映射接近于恒等映射(Identity Mapping),则只需让F ( x ) ≈ 0 F(x) \approx 0F(x)0,训练更容易。

这种设计通过 跳跃连接(skip connection),将输入x xx直接加到卷积层的输出上,从而缓解了梯度消失问题。

网络结构

ResNet 的基本单元是 残差块(Residual Block),主要分为两类:

  • 基本残差块(Basic Block):常用于 ResNet-18 和 ResNet-34,包含两个3 × 3 3×33×3卷积层。
  • 瓶颈残差块(Bottleneck Block):常用于 ResNet-50、ResNet-101 和 ResNet-152,使用1 × 1 → 3 × 3 → 1 × 1 1×1→3×3→1×11×13×31×1三层卷积,减少计算量。

以 ResNet-34 为例,其结构大致为:

其中包含:

  1. 卷积层 + BN + ReLU + 最大池化
  2. 3 个残差块(64 通道)
  3. 4 个残差块(128 通道)
  4. 6 个残差块(256 通道)
  5. 3 个残差块(512 通道)
  6. 全局平均池化 + 全连接层

ResNet-50、101 等更深的版本采用瓶颈结构,但核心思想一致。

关键创新点

  1. 残差连接(Skip Connection):让梯度能够无障碍地传递到更早的层,缓解梯度消失。
  2. 更深的网络可训练:ResNet 首次在 ImageNet 上成功训练超过 100 层的网络。
  3. 模块化设计:残差块可以方便地堆叠,形成不同深度的模型。
  4. 恒等映射易学性:相比直接学习复杂映射,学习残差更容易收敛。

代码示例

下面我们实现一个简化版 ResNet-18,并在 CIFAR-10 上演示。

importtorchimporttorch.nnasnnimporttorch.optimasoptimfromtorchvisionimportdatasets,transformsfromtorch.utils.dataimportDataLoader# 定义残差块classBasicBlock(nn.Module):expansion=1def__init__(self,in_channels,out_channels,stride=1):super(BasicBlock,self).__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.relu=nn.ReLU(inplace=True)self.conv2=nn.Conv2d(out_channels,out_channels,kernel_size=3,stride=1,padding=1,bias=False)self.bn2=nn.BatchNorm2d(out_channels)# 如果输入和输出维度不一致,使用 1x1 卷积调整self.shortcut=nn.Sequential()ifstride!=1orin_channels!=out_channels:self.shortcut=nn.Sequential(nn.Conv2d(in_channels,out_channels,kernel_size=1,stride=stride,bias=False),nn.BatchNorm2d(out_channels))defforward(self,x):identity=self.shortcut(x)out=self.relu(self.bn1(self.conv1(x)))out=self.bn2(self.conv2(out))out+=identity out=self.relu(out)returnout# 定义 ResNetclassResNet(nn.Module):def__init__(self,block,num_blocks,num_classes=10):super(ResNet,self).__init__()self.in_channels=64self.conv1=nn.Conv2d(3,64,kernel_size=3,stride=1,padding=1,bias=False)self.bn1=nn.BatchNorm2d(64)self.relu=nn.ReLU(inplace=True)self.layer1=self._make_layer(block,64,num_blocks[0],stride=1)self.layer2=self._make_layer(block,128,num_blocks[1],stride=2)self.layer3=self._make_layer(block,256,num_blocks[2],stride=2)self.layer4=self._make_layer(block,512,num_blocks[3],stride=2)self.avgpool=nn.AdaptiveAvgPool2d((1,1))self.fc=nn.Linear(512*block.expansion,num_classes)def_make_layer(self,block,out_channels,num_blocks,stride):strides=[stride]+[1]*(num_blocks-1)layers=[]forsinstrides:layers.append(block(self.in_channels,out_channels,s))self.in_channels=out_channels*block.expansionreturnnn.Sequential(*layers)defforward(self,x):out=self.relu(self.bn1(self.conv1(x)))out=self.layer1(out)out=self.layer2(out)out=self.layer3(out)out=self.layer4(out)out=self.avgpool(out)out=torch.flatten(out,1)out=self.fc(out)returnout# ResNet-18defResNet18():returnResNet(BasicBlock,[2,2,2,2])# 数据预处理transform=transforms.Compose([transforms.Resize(224),# 调整输入大小transforms.ToTensor(),transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))])train_dataset=datasets.CIFAR10(root='./data',train=True,transform=transform,download=True)train_loader=DataLoader(train_dataset,batch_size=64,shuffle=True)# 初始化模型、损失函数和优化器device=torch.device("cuda"iftorch.cuda.is_available()else"cpu")model=ResNet18().to(device)criterion=nn.CrossEntropyLoss()optimizer=optim.SGD(model.parameters(),lr=0.01,momentum=0.9)# 简单训练循环forepochinrange(1):forbatch_idx,(data,target)inenumerate(train_loader):data,target=data.to(device),target.to(device)outputs=model(data)loss=criterion(outputs,target)optimizer.zero_grad()loss.backward()optimizer.step()ifbatch_idx%100==0:print(f"Epoch [{epoch+1}], Step [{batch_idx}], Loss:{loss.item():.4f}")

ResNet 的出现解决了深层网络训练难的问题,它通过 残差连接 提供了一条捷径,使梯度能够顺利传播。

ResNet 在 ImageNet 上取得了巨大成功,也成为后续网络(如 DenseNet、ResNeXt、EfficientNet)的基础。可以说,没有 ResNet,就没有今天的超深网络。

最新的文章都在公众号aicoting更新,别忘记关注哦!!!

📚推荐阅读

一文搞懂深度学习中的池化!

面试官:给我讲一下卷积吧!

一文搞懂卷积神经网络!

面试官:正则化都有哪些经典的方法?

面试官:你在训模型的时候经常使用的学习率策略有哪些?

面试官:深度学习中经典的优化算法都有哪些?

一文搞懂深度学习中的通用逼近定理!

一文搞懂深度学习中的表征学习理论!

一文搞懂深度学习中的信息论!

一文搞懂深度学习的反向传播与优化理论!

最新的文章都在公众号aicoting更新,别忘记关注哦!!!

作者:aicoting

分享是一种信仰,连接让成长更有温度。

我们下次不见不散!

http://www.jsqmd.com/news/563291/

相关文章:

  • Vue3+Cesium实战:解决404报错与Webpack配置优化指南
  • 如何安全升级Doris集群:从元数据备份到节点重启的完整步骤
  • $http_x_forwarded_for和$remote_addr对比
  • 速腾Helios雷达+fast-LIO2实战:如何将XYZIRT点云数据高效喂给算法并评估建图效果
  • 从Animal Pose到YOLOv8-Pose:手把手教你训练一个动物姿态估计模型
  • 解决Ubuntu远程桌面连接黑屏问题:无显示器环境下的完整配置指南
  • 2026文旅景观亮化厂家靠谱性深度评测:文旅亮化、旅游景区亮化、景观亮化、景观泛光照明、标识标牌、桥梁河道亮化选择指南 - 优质品牌商家
  • 深入MTK DRM显示框架:LK阶段compare_id与Kernel DTS的‘握手’协议详解
  • Minecraft 1.12.2 彩色渐变字体模组:打造个性化聊天与物品命名
  • Whisky:让macOS高效运行Windows程序的跨平台解决方案
  • Nrfr免Root终极指南:如何轻松解决国际漫游兼容性问题
  • 2026年比较好的小型分散机多家厂家对比分析 - 品牌宣传支持者
  • Python 正则表达式详解:从原理到实践
  • 2026年热门的装饰板UV光固化涂料/覆膜亮光UV光固化涂料公司对比推荐 - 品牌宣传支持者
  • Alpamayo-R1-10B惊艳案例:暴雨天气下通过多帧图像融合提升轨迹预测置信度
  • mysql技巧(十二):Buffer Pool 缓冲池-MySQL为何能“亿级数据”查得快
  • PapaParse实战:如何在Node.js中高效处理百万级CSV数据(附性能优化技巧)
  • 2026MBA辅导机构推荐榜高性价比选品指南:管综数学培训/管综数学辅导/管综笔试辅导/MPA培训/MPA笔试培训/选择指南 - 优质品牌商家
  • 2026年比较好的小型分散机厂家精选合集 - 品牌宣传支持者
  • nginx传递真实客户端ip
  • StructBERT模型轻量化探索:知识蒸馏与模型压缩实践
  • 为什么你的Gradle构建这么慢?可能是依赖配置用错了!implementation vs api深度解析
  • 后端服务架构演进:从单体到微服务的转型之路
  • CPUDoc:基于动态CpuSet掩码与自适应电源管理的Windows CPU性能优化架构设计原理
  • 嵌入式系统处理器选型与应用指南
  • 新手必看:红日靶场信息收集实战指南(含Nmap扫描与MySQL弱口令破解)
  • 数字人视频生成利器:HeyGem批量版快速部署与效果展示
  • 保姆级教程:在YOLOv7上部署GradCAM++可视化(避坑指南+效果对比)
  • STM32软硬件协同工作原理与程序运行机制
  • 2026跑腿系统多站点可靠服务商推荐:外卖系统多站点/外卖系统开发/外卖系统搭建/外卖系统独立部署/选择指南 - 优质品牌商家