ResNet v2论文笔记

ResNet v2分析了深度残差网络的信号传播,强调了恒等映射(identity mappings)在跳跃连接中的重要性,指出其在前向和反向传播中促进了信息的直接传递。实验表明,使用恒等映射的ResNet-1001在CIFAR-10/100和ImageNet上表现优异,而其他类型的跳跃连接或激活函数改变会导致训练困难和泛化能力下降。预激活残差单元提高了模型的正则化效果,使得更深网络的训练和优化变得更加容易。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ResNet v2:Identity Mappings in Deep Residual Networks

摘要:
ResNets v1作为一种极深的网络框架,在精度和收敛等方面都展现出了很好的特性。在本文,我们分析了残差块(residual building blocks)背后的信号传播公式(数学表达式),公式表明,当使用恒等映射(identity mappings)作为跳跃连接(skip connections)及信号加合后的激活函数时,前向、反向传播的信号能直接从一个残差块传递到其他任意一个残差块。一系列的“ablation”实验也验证了这些恒等映射的重要性。这促使我们提出了一个新的残差单元,它使得训练变得更容易(更容易收敛),同时也提高了网络的泛化能力。我们报告了1001层的ResNet在CIFAR-10(4.62% error) 和CIFAR-100上的结果,以及200层的ResNet在ImageNet上的结果。代码可在 https://github.com/KaimingHe/resnet-1k-layers上下载。

1.简介

ResNets v1堆叠了很多残差单元,每一个单元(图1a)能够写为下面的通用形式:

yl=h(xl)+F(xl,Wl) y l = h ( x l ) + F ( x l , W l )
xl+1=f(yl) x l + 1 = f ( y l )

这里 xl x l xl+1 x l + 1 是第 l l 个单元的输入和输出, F 是一个残差函数。在ResNet中, h(xl)=xl h ( x l ) = x l 是一个identity mapping, f f 是一个ReLU函数。

超过100层的ResNets在ImageNet和MS COCO竞赛的许多识别挑战任务中展现出了极高的精度(state of art)。ResNets的核心思想是去学习加到 h ( x l ) 上的残差函数 F F ,这个思想的关键是恒等映射的使用。这种思想可以通过附加一个恒等跳跃连接(shortcut)来实现。

在本文中,我们致力于创建一个全局(整个网络)的直接信息传播路径来分析深度残差网络(而不是仅仅在残差单元内部)。我们的推导揭示了:如果 h(xl) h ( x l ) f(yl) f ( y l ) 都采用恒等映射,那么在正向传播和反向传播中,信号总能从一个残差块传播到其它的任何一个残差块。我们的实验经验性地说明,当架构接近上面两种情况时,通常训练变得更加容易。

为了理解跳跃连接(skip connections)的作用,我们分析并对比了各种类型的 h(xl) h ( x l ) 。我们发现,在所有研究的类型中,ResNet v1中选择的恒等映射 h(xl)=xl h ( x l ) = x l 误差下降最快,训练误差最低。而使用缩放(scaling)、门控(gating)以及1×1 卷积的跳跃连接都产生了更高的训练损失和误差。这些实验表明,保持一个干净的(“clean”)信息通道(图1,2,4中灰色箭头)对于简化训练是十分有帮助的。
图1
为了建立一个恒等映射 f(yl)=yl f ( y l ) = y l ,我们将激活函数(ReLU和BN)看作有权重的层(weight layer)的“pre-activation”。这个观点产生了一个新的残差单元设计(图1b)。基于这个单元设计设计的ResNet-1001在CIFAR-10/100上表现出了更优的结果,并且与原始的ResNet-1001相比,也更容易训练,泛化能力更强。原始的ResNet-200在ImageNet上出现了过拟合现象,我们进一步展示了改进后网络的结果。这些结果表明,深度作为深度学习陈工的关键,仍有很大的研究空间。

2.深度残差网络的分析

ResNet-v1是一个由很多残差块堆叠的模块化架构。本文中,我们称这些块为“残差单元”,ResNet-v1的残差单元进行以下的计算:

yl=h(xl)+F(xl,Wl)         (1) y l = h ( x l ) + F ( x l , W l )                   ( 1 )
xl+1=f(yl)         (2) x l + 1 = f ( y l )                   ( 2 )
这里 xl x l 是第 l l 个残差单元的输。入特征。 W = { W l , k | 1 k K } 是一个与第 l l 个残差单元相关的权重和偏差的集合, K 是残差单元内部的层的数量(图1种K分别为2和3)。 F F 是残差函数。函数 f f 是元素加和后的操作(ResNet-v1中采用的是ReLU)。函数 h 是恒等映射 h(xl)=xl h ( x l ) = x l

如果 f f 是一个恒等映射: x l + 1 x l ,我们可以把公式2带入公式1,得到:

xl+1=xl+F(xl,Wl)         (3) x l + 1 = x l + F ( x l , W l )                   ( 3 )
递归地, xl+2=xl+1+F(xl+1,Wl+1)=x
### ResNet V2 模型架构 ResNet V2 是基于原始 ResNet 的改进版本,主要通过调整激活函数的位置来优化网络性能。具体来说,在传统的 ResNet 中,ReLU 和 Batch Normalization (BN) 被放置在卷积层之后;而在 ResNet V2 中,这些操作被移动到残差连接之前[^1]。 这种设计的主要目的是为了缓解梯度消失问题并加速训练过程。此外,ResNet V2 还引入了一种称为 **pre-activation** 的结构,即 BN-ReLU 卷积顺序被修改为 ReLU-BN 或者直接省略某些 BN 层的操作[^2]。 以下是 ResNet V2 的核心特点: #### 核心特性 1. **Pre-Activation 结构**: 在每一层的输入端应用 BN 和 ReLU,然后再执行卷积操作。 2. **更深层次的支持**: 由于 Pre-Activation 设计减少了梯度消失的影响,因此可以支持更深的网络层数。 3. **简化后的跳跃连接**: 原始 ResNet 使用的是 `F(x) + x` 形式的跳跃连接,而 ResNet V2 则改为先对输入数据进行 BN 和 ReLU 处理后再加回原输入。 --- ### ResNet V2 实现细节 ResNet V2 的实现主要包括以下几个部分: 1. **基础模块定义**: 定义基本的残差单元(Residual Unit),其中包含多个卷积层以及 pre-activation 操作。 2. **整体网络构建**: 将若干个残差单元堆叠起来形成完整的网络结构。 3. **初始化参数设置**: 对权重矩阵采用特定方法初始化以促进收敛速度。 下面是一个简单的 PyTorch 版本 ResNet V2 的代码示例: ```python import torch.nn as nn import torch class BasicBlockV2(nn.Module): expansion = 1 def __init__(self, in_channels, out_channels, stride=1, downsample=None): super(BasicBlockV2, self).__init__() # Pre-activation layers self.bn1 = nn.BatchNorm2d(in_channels) self.relu = nn.ReLU(inplace=True) # Convolutional layer without activation at start self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False) # Second batch normalization before second convolution self.bn2 = nn.BatchNorm2d(out_channels) self.conv2 = nn.Conv2d(out_channels, out_channels * self.expansion, kernel_size=3, stride=1, padding=1, bias=False) self.downsample = downsample def forward(self, x): identity = x out = self.bn1(x) out = self.relu(out) if self.downsample is not None: identity = self.downsample(out) out = self.conv1(out) out = self.bn2(out) out = self.relu(out) out = self.conv2(out) out += identity return out class ResNetV2(nn.Module): def __init__(self, block, layers, num_classes=1000): super(ResNetV2, self).__init__() self.inplanes = 64 self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=7, stride=2, padding=3, bias=False) self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) self.layer1 = self._make_layer(block, 64, layers[0]) self.layer2 = self._make_layer(block, 128, layers[1], stride=2) self.layer3 = self._make_layer(block, 256, layers[2], stride=2) self.layer4 = self._make_layer(block, 512, layers[3], stride=2) self.bn_final = nn.BatchNorm2d(512 * block.expansion) self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) self.fc = nn.Linear(512 * block.expansion, num_classes) def _make_layer(self, block, planes, blocks, stride=1): downsample = None if stride != 1 or self.inplanes != planes * block.expansion: downsample = nn.Sequential( nn.Conv2d(self.inplanes, planes * block.expansion, kernel_size=1, stride=stride, bias=False), ) layers = [] layers.append(block(self.inplanes, planes, stride, downsample)) self.inplanes = planes * block.expansion for _ in range(1, blocks): layers.append(block(self.inplanes, planes)) return nn.Sequential(*layers) def forward(self, x): x = self.conv1(x) x = self.maxpool(x) x = self.layer1(x) x = self.layer2(x) x = self.layer3(x) x = self.layer4(x) x = self.bn_final(x) x = self.relu(x) x = self.avgpool(x) x = torch.flatten(x, 1) x = self.fc(x) return x ``` 上述代码展示了如何利用 PyTorch 来搭建一个标准的 ResNet V2 网络框架。 --- ### 总结 ResNet V2 主要通过对传统 ResNet 的激活位置进行了重新安排,从而提升了模型的表现力和稳定性。其预激活机制使得深层神经网络更容易训练,并显著改善了梯度传播效率。以上提供的 Python 代码片段可以帮助快速上手该模型的实际开发工作。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值