残差网络(ResNets)的残差块(Residual block)

来源:Coursera吴恩达深度学习课程

五一假期结束了,听着梁博的《日落大道》,码字中。非常非常深的神经网络是很难训练的,因为存在梯度消失和梯度爆炸问题。跳跃连接(Skip connection)可以从某一层网络层获取激活,然后迅速反馈给另外一层,甚至是神经网络的更深层。利用跳跃连接构建能够训练深度网络的ResNets,有时深度能够超过100层。ResNets是由残差块(Residual block)构建的,首先看一下什么是残差块。

上图是一个两层神经网络。回顾之前的计算过程:

在残差网络中有一点变化:

如上图的紫色部分,我们直接将a^[l]向后,到神经网络的深层,在ReLU非线性激活函数前加上a^[l],将激活值a^[l]的信息直接传达到神经网络的深层,不再沿着主路进行,因此a^[l+2]的计算公式为:

加上a^[l]后产生了一个残差块(residual block)。插入的时机是在线性激活之后,ReLU激活之前。除了捷径(shortcut),你还会听到另一个术语“跳跃连接”(skip connection),就是指a^[l]跳过一层或者好几层,从而将信息传递到神经网络的更深层。

ResNet的发明者是何恺明(Kaiming He)、张翔宇(Xiangyu Zhang)、任少卿(Shaoqing Ren)和孙剑(Jiangxi Sun),他们发现使用残差块能够训练更深的神经网络。所以构建一个ResNet网络就是通过将很多这样的残差块堆积在一起,形成一个很深神经网络。首先回忆一个普通网络(Plain network),这个术语来自ResNet论文。如下图:

变成ResNet的方法是加上所有跳跃连接,每两层增加一个捷径,构成一个残差块。如下图所示,5个残差块连接在一起构成一个残差网络。

假设使用标准优化算法(梯度下降法等)训练一个普通网络,如果没有残差,没有这些捷径或者跳跃连接,凭经验你会发现随着网络深度的加深,训练错误会先减少,然后增多。而理论上,随着网络深度的加深,应该训练得越来越好才对,网络深度越深模型效果越好。但实际上,如果没有残差网络,对于一个普通网络来说,深度越深意味着用优化算法越难训练,随着网络深度的加深,训练错误会越来越多。

但有了ResNets就不一样了,即使网络再深,训练的表现却不错,比如说训练误差减少,就算是训练深达100层的网络也不例外。对x的激活,或者这些中间的激活能够到达网络的更深层。这种方式有助于解决梯度消失和梯度爆炸问题,在训练更深网络的同时,又能保证良好的性能。

说明:记录学习笔记,如果错误欢迎指正!转载请联系我。

### Residual Block 的概念 Residual Block 是一种用于深层神经网络中的模块设计,旨在解决随着网络深度增加而导致的退化问题。通过引入跳跃连接(skip connections),使得每一层可以学习到残差映射而不是直接拟合目标输出[^1]。 这种架构允许梯度更有效地在网络中传播,从而缓解了训练非常深的卷积神经网络时遇到的梯度消失或爆炸问题。具体来说,在传统的前馈神经网络里,如果堆叠更多层次,则可能会导致性能下降;而采用残差块之后,即使增加了更多的参数量也不会造成负面影响,并且能够持续提升模型表现。 ### 实现细节 一个典型的 ResNet 中的 residual block 可以表示如下: ```python import torch.nn as nn class BasicBlock(nn.Module): expansion = 1 def __init__(self, in_planes, planes, stride=1): super(BasicBlock, self).__init__() # 定义两个连续的3x3卷积操作 self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) self.bn1 = nn.BatchNorm2d(planes) self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False) self.bn2 = nn.BatchNorm2d(planes) # 如果输入通道数与输出不同或者步幅不为1,则需要调整维度以便相加 self.shortcut = nn.Sequential() if stride != 1 or in_planes != self.expansion * planes: self.shortcut = nn.Sequential( nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False), nn.BatchNorm2d(self.expansion*planes) ) def forward(self, x): out = nn.ReLU()(self.bn1(self.conv1(x))) out = self.bn2(self.conv2(out)) out += self.shortcut(x) # 跳跃连接部分 out = nn.ReLU()(out) return out ``` 上述代码定义了一个基础版本的 `BasicBlock` 类来构建残差单元。这里包含了两次标准的二维卷积运算以及批量标准化处理(`Batch Normalization`) 和激活函数 ReLU 。当输入特征图尺寸发生变化时 (即步长 `stride>1` 或者 输入输出通道数目不一样),会利用额外的一层线性变换 (`nn.Conv2d`) 来匹配张量形状,确保最终能完成元素级别的求和操作。 ### 应用场景 除了作为图像分类任务的核心组件外,residual blocks 还被广泛应用于其他领域,比如物体检测、语义分割等视觉识别子域。此外,迁移学习也经常借助预训练好的带有残差结构的 CNNs 提取高级抽象特征并应用到新数据集上进行推理任务[^3]。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值