ResNet论文笔记

本文探讨了神经网络深度增加导致的退化现象,焦点在于ResNet如何通过恒等映射和残差模块避免这一问题。通过介绍身份映射和ResNet结构,展示了如何构建深层网络并提升性能。提及了VGG和ResNet的区别,以及bottleneck结构的应用。

神经网络退化(degradation) 现象的提出

在这里插入图片描述
上面的图片指示的是在 CIFAR-10 这个小型的数据集上,56 层的神经网络的表现比不过 20 层的神经网络。也就是层数加深,网络却反而退化了。

堆叠网络的缺点:
1.网络难以收敛,梯度消失/爆炸在一开始就阻碍网络的收敛。
(传统解决办法:通过标准初始化和中间标准化层在很大程度上解决。这使得数十层的网络能通过具有反向传播的随机梯度下降(SGD)开始收敛。)

2.当更深层次的网络能够开始收敛时,一个退化问题就暴露出来了:随着网络深度的增加,精确度趋于饱和(这可能并不奇怪),然后迅速退化。

如何构建更深层的网络?

一个解决方案是:
在一个常规的比较浅的模型上添加新的层,而新的层是基于 identity mapping 的。identity mapping :恒等变换,也就是输入与输出是相等的映射关系。

通俗来讲,就是在一个浅层的网络模型上进行改造,然后将新的模型与原来的浅层模型相比较,这里有个底线就是,改造后的模型至少不应该比原来的模型表现要差。因为新加的层可以让它的结果为 0,这样它就等同于原来的模型了。这个假设是 ResNet 的出发点。

在这里插入图片描述
ResNet将输入分为两条路:
右边:恒等映射,不对输入做任何处理,直接传给输出
左边:两层神经网络,不去拟合原始的底层分布,直接拟合残差(保证这个神经网络至少不会比什么都不加时更差,大不了为0,这时输出等于输入)
最后将左边和右边相加(逐元素求和)

ResNet是将很多个残差模块堆叠
在这里插入图片描述
在这里插入图片描述
VGG里使用池化进行下采样,ResNet使用步长为2的卷积来下采样(右图中虚线),使得残差分支和恒等映射分支的数据大小一致
VGG的最后是全连接层,产生了大量的参数(1亿左右),ResNet使用全局平均池化代替全连接,大大减少了参数和计算量
VGG19的所有卷积都是3*3的卷积

当输入和输出维度一致时, identity shortcuts分支可以直接运用
维度不一致(右图中虚线处)时,匹配维度的方式:
1.shortcut仍然执行恒等映射,为增加维度填充额外的零项,此方案不产生额外参数
2.对shortcut分支做1*1的卷积进行升维
B站论文详解

bottleneck

bottleneck算是原残差分支的进阶版,更关注对通道数的缩放处理,输入和输出都是高维的,1*1卷积先降维再升维。这个结构在Inception模块也用到了。
在这里插入图片描述

补充

ResNet没有使用dropout,因为dropout和batch normalization不适合同时存在,关于这个现象,有专门的论文从方差偏移的现象去解释
weight decay L2正则化,论文设置为0.0001; momentum 动量0.9
fully-convolutional form 不是指全卷积,指的是多尺度裁剪和特征融合,把多尺度的结果进行汇总融合

虽然给定的引用未涉及ResNet论文的精读内容、翻译、学习笔记及PyTorch代码复现相关信息,但下面为你提供关于ResNet论文的一些通用信息。 ### ResNet论文翻译 ResNet(Deep Residual Learning for Image Recognition)是何恺明等人在2015年发表于CVPR的论文论文核心是提出了残差块(Residual Block)的概念来解决深度神经网络中的梯度消失和梯度爆炸问题。 例如残差块的基本公式 $y = F(x) + x$,其中 $x$ 是输入,$F(x)$ 是残差函数,$y$ 是输出。在翻译中,“Deep Residual Learning for Image Recognition”可译为“用于图像识别的深度残差学习” 。 ### 学习笔记 - **背景**:传统的深度神经网络在增加网络深度时,会出现训练误差和测试误差增大的情况,即退化问题。ResNet提出残差学习的方法解决该问题。 - **残差块**:通过引入跳跃连接(skip connection),使得网络可以学习残差映射。残差块可以更容易地学习到恒等映射,让网络专注于学习输入和输出之间的差异。 - **网络结构**:ResNet有不同的版本,如ResNet18、ResNet34、ResNet50等,数字代表网络的层数。不同版本在残差块的堆叠数量上有所不同。 ### PyTorch代码复现 ```python import torch import torch.nn as nn # 定义残差块 class BasicBlock(nn.Module): expansion = 1 def __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) self.shortcut = nn.Sequential() if stride != 1 or in_channels != self.expansion * out_channels: self.shortcut = nn.Sequential( nn.Conv2d(in_channels, self.expansion * out_channels, kernel_size=1, stride=stride, bias=False), nn.BatchNorm2d(self.expansion * out_channels) ) def forward(self, x): out = self.relu(self.bn1(self.conv1(x))) out = self.bn2(self.conv2(out)) out += self.shortcut(x) out = self.relu(out) return out # 定义ResNet class ResNet(nn.Module): def __init__(self, block, num_blocks, num_classes=10): super(ResNet, self).__init__() self.in_channels = 64 self.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 = [] for stride in strides: layers.append(block(self.in_channels, out_channels, stride)) self.in_channels = out_channels * block.expansion return nn.Sequential(*layers) def forward(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) return out # 创建ResNet18模型 def ResNet18(): return ResNet(BasicBlock, [2, 2, 2, 2]) # 测试模型 model = ResNet18() x = torch.randn(1, 3, 32, 32) y = model(x) print(y.shape) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值