专栏链接:深度学习和论文精读
本文并非对论文直接进行翻译,增加了自己对于论文的理解,如有问题请及时指出~
前言
论文题目:《Deep Residual Learning for Image Recognition》
论文原文:https://arxiv.org/abs/1512.03385
论文来源:CVPR(CCF-A会议)
发表时间:2016
摘要
更深的神经网络更难以训练。我们提出了一个残差学习框架,以简化训练比以往使用的网络更深的网络。我们明确地将层重新表述为相对于层输入学习残差函数,而不是学习无参考的函数。我们提供全面的实证证据,显示这些残差网络更容易优化,并且可以从大幅增加的深度中获得精度提升。在ImageNet数据集上,我们评估了深度达到152层的残差网络——比VGG网络深8倍,但复杂度更低。这些残差网络的集成在ImageNet测试集上达到了3.57%的错误率。这一结果赢得了ILSVRC 2015分类任务的第一名。我们还在CIFAR-10上进行了100层和1000层的分析。
对于许多视觉识别任务来说,表示的深度至关重要。仅仅由于我们极其深的表示,我们在COCO对象检测数据集上获得了28%的相对改进。深度残差网络是我们提交给ILSVRC & COCO 2015竞赛的基础,我们还赢得了ImageNet检测、ImageNet定位、COCO检测和COCO分割任务的第一名。
1 介绍
1.1 背景
深度卷积神经网络为图像分类带来了一系列突破。深度网络自然地以端到端的多层方式集成低/中/高级特征和分类器,并且特征的“级别”可以通过堆叠层的数量(深度)来丰富。在深度意义的驱动下,一个问题出现了:学习更好的网络是否像堆叠更多层一样容易?
当更深的网络能够开始收敛时,一个退化问题就暴露出来了:随着网络深度的增加,准确性会饱和,然后迅速退化。出乎意料的是,这种退化不是由过度拟合引起的,并且向适当深度的模型添加更多的层会导致更高的训练错误,下图显示了一个典型的例子。
这里我们可以发现56层的神经网络相较于20层的训练和测试的错误率更高,这就意味着更深的网络结构不代表着更好的结果。
引起这个问题并非是以下两个问题
1.梯度消失or梯度爆炸
已经可以通过归一化(normalized initialization)和中间归一化层(intermediate normalization)解决
2.过拟合or欠拟合
过拟合结果应是训练集表现好,测试集表现差,而真实情况是训练集和测试集的表现都很差。
1.2 贡献
- 深度残差网络很容易优化,当深度增加时,对应的“普通”网络(简单地堆叠层)表现出更高的训练误差。
- 深度残差网络可以很容易地从深度的大幅增加中获得准确性增益,产生的结果比以前的网络要好得多。
2 相关工作
2.1 残差表达(Residual Representations)
对于矢量量化,编码残差矢量被证明比编码原始矢量更有效。当求解求解偏微分方程(PDE)时,多重网格方法、分层基础预处理已经证明比不知道解决方案的剩余性质的标准求解器收敛得更快。这些方法表明,一个好的重新表达或预处理可以简化优化。
2.2 短路连接(Shortcut Connections)
有些论文在一些中间层直接连接到辅助分类器,用于解决消失/爆炸梯度。有些论文提出了通过快捷连接实现的用于居中层响应、梯度和传播误差的方法。总体来说是有成效的。此外,不同于“highway networks”所提出的带有门控功能的短路连接。这些门控是数据依赖的且有参数。当一个门控快捷方式被“关闭”(接近零)时,高速网络中的层表示非残差函数。相反,我们的模型始终学习残差函数;我们的恒等快捷方式永远不会关闭,所有信息始终被传递,同时有额外的残差函数需要学习。
3 方法
3.1 残差学习(Residual Learning)
我们考虑这样一个问题,现在有一个浅层网络,通过向上堆积新层来建立深层网络,一个极端情况是这些增加的层什么也不学习,仅仅复制浅层网络的特征,这层输出=输入的操作便是恒等映射(Identity mapping),这样就有可能将已经达到最优解的权重参数继续更新为误差更多的值。
正常网络: H ( x ) = F ( x ) H(x)=F(x) H(x)=F(x),拟合 H ( x ) H(x) H(x)
残差网络: H ( x ) = F ( x ) + x H(x)=F(x)+x H(x)=F(x)+x,拟合残差 F ( x ) = H ( x ) - x F(x)=H(x)-x F(x)=H(x)-x
如果去拟合一个
H
(
x
)
=
F
(
x
)
H(x)=F(x)
H(x)=F(x)是比较困难的,而拟合
F
(
x
)
=
H
(
x
)
-
x
F(x)=H(x)-x
F(x)=H(x)-x更为容易。
这里为方便理解举个例子:
- 没有引入残差的情况:设 F ′ ( x ) F'(x) F′(x)代表原始的网络映射,没有采用残差学习。如果输入是5,输出目标是5.1,那么网络需要直接学习从5映射到5.1的函数 F ′ ( 5 ) = 1 F'(5)=1 F′(5)=1
- 引入残差的情况:设 H ( x ) H(x) H(x)代表引入残差后的映射,其中 H ( x ) = F ( x ) + x H(x)=F(x)+x H(x)=F(x)+x。在这个例子中,网络不是直接学习从5到5.1的映射,而是学习从5到5.1的残差,即 F ( 5 ) = 0.1 F(5)=0.1 F(5)=0.1。因此,最终输出是 H ( 5 ) = F ( 5 ) + 5 = 0.1 + 5 = 5.1 H(5)=F(5)+5=0.1+5=5.1 H(5)=F(5)+5=0.1+5=5.1
我们上文中提到,如果去拟合一个 H ( x ) = F ( x ) H(x)=F(x) H(x)=F(x)是比较困难的,而拟合 F ( x ) = H ( x ) - x F(x)=H(x)-x F(x)=H(x)-x更为容易。关键优势在于对输出的微小变化更敏感,例如当目标输出从5.1变成5.2时:
- 没有引入残差: F ′ F' F′的输出从5.1变到5.2,相对增加了约2%(从5.1增加到5.2,相对于原始5.1)。
- 引入残差后: F F F的输出从0.1变到0.2,相对增加了 100%。这是因为残差结构仅需要调整小量的变化(即从0.1到0.2),而非整个输出的映射,使得网络对于学习目标的微调变得更加高效和敏感。
3.2 短路连接进行恒等映射(Identity Mapping by Shortcuts)
每隔几个堆叠层采用短路连接。然而堆叠层中可能包含卷积等操作进而改变数据的形状,因此短路连接要考虑维度是否相同。
1. 维度相同
y = F ( x , { w i } ) + x y=F(x, \{w_i\})+x y=F(x,{wi})+x
F = W 2 σ ( W 1 x ) F=W_2\sigma(W_1x) F=W2σ(W1x) 其中 σ \sigma σ代表ReLU和偏差
其不引入额外参数也不引入计算复杂性。
2. 维度不同
可以通过短路连接执行线性投影 W s W_s Ws以匹配尺寸:
y = F ( x , { w i } ) + W s x y=F(x, \{w_i\})+W_sx y=F(x,{wi})+Wsx
为了简单起见,上述符号是关于全连接层的,但它们适用于卷积层。函数 F ( x , { w i } ) + W s x F(x, \{w_i\})+W_sx F(x,{wi})+Wsx可以表示多个卷积层。逐元素加法是在两个特征图上逐个通道执行的。
3.3 网络架构(Network Architectures)
在此部分作者构建了两种网络,分别为普通网络(Plain Network)和残差网络(Residual Network),具体结构见下图。
普通网络(Plain Network)
普通基线(图中)主要受到VGG网络(图左)的启发。卷积层大多有3×3滤波器,并遵循两个简单的设计规则:
1.对于相同的输出特征图大小,层具有相同数量的滤波器;
2.如果特征图大小减半,则滤波器的数量加倍,以保持每层的时间复杂度。直接通过步长为2的卷积层执行下采样。该网络以全局平均池化层和1000个输出的softmax全连接层结束。
加权层的总数为34。相较于VGG网络具有更少的过滤器和更低的复杂度。我们的34层基线具有36亿FLOP(乘加),仅为VGG-19(196亿FLOP)的18%。
残差网络(Residual Network)
残差网络。基于上述普通网络,增加了短路连接(图右)。当输入和输出的维度相同时,可以直接使用恒等快捷连接(3.2中的1),在图中以实线表示。当维度增加时(图中虚线表示),此时考虑两个选项:
(A)短路连接仍然执行恒等映射,对增加的维度进行额外的零填充。这个选项不引入额外的参数;
(B)使用3.2中的2投影快捷方式来匹配维度(通过1×1卷积完成)。
对于这两个选项,当短路连接跨越两种尺寸的特征图时,它们以步长为2执行。
3.4 实现(Implementation)
使用ImageNet数据集。图像通过将其较短的边随机采样在[256, 480]范围内进行尺度增强。从图像或其水平翻转中随机采样一个224×224的裁剪区域,并减去每个像素的均值。使用标准颜色增强。在每次卷积之后以及激活之前立即使用批归一化(BN)。使用带有256个样本的小批量的SGD。学习率从0.1开始,当错误停滞不前时除以10,并且模型训练多达 60 × 1 0 4 60×10^4 60×104次迭代。使用0.0001的权重衰减和0.9的动量。不使用dropout。在测试中,为了比较研究,我们采用了标准的10-crop测试。为了获得最佳结果,采用了特定的全卷积形式,并在多个尺度上平均得分(图像被重新调整大小,使得较短的边在{224, 256, 384, 480, 640}中)。
4 实验(仅介绍ImageNet实验部分)
4.1 普通网络和残差网络
在ImageNet 2012分类数据集由1000个类组成。模型在128万张训练图像上进行训练,并在5万张验证图像上进行评估,使用10万张测试图像得到最终结果。我们评估前1和前5错误率。
不同模型的具体结构见下图:
对18层和34层普通网络和残差进行评估(所有短路连接使用恒等映射,并对增加的维度使用零填充),结果见下图:
这里我们可以发现,增加了短路连接的网络并不会因为增加了网络层数而导致准确率降低,解决了退化问题。此外增加了短路连使得模型的收敛速度要更快。
4.2 恒等 vs 映射(Identity vs. Projection Shortcuts)
上文已经验证了无参数的恒等的短路连接是有助于训练的。接下来我们研究映射的短路连接。比较了三种情况:
(A) 对增加的维度使用0填充,所有的短路连接是无参数的
(B) 对增加的维度使用映射短路连接,其它使用恒等短路连接
(C) 所有的都是映射短路连接
由上表可以发现所有三个方法都比普通网络好得多。B略优于A,这是因为A中的零填充维度确实没有剩余学习。C略优于B,归因于许多(13个)映射短路连接引入的额外参数。但A/B/C之间的微小差异表明,映射短路连接对于解决退化问题并不重要。因此,其余部分不使用选项C,以减少内存/时间复杂度和模型大小。
4.3 更深的瓶颈架构(Deeper Bottleneck Architectures.)
此部分对于模型深度进行探究。将ResNet-34中每个残差函数
F
F
F,改为使用3层而不是2层的堆叠,见下图,进而形成ResNet-50。
50/101/152层的ResNet比34层的ResNet准确得多,见下表。且没有观察到退化问题,因此从显著增加的深度中获得了显著的精度增益。所有评价指标都证明了深度的好处。
4.4 与最先进方法的比较(Comparisons with State-of-the-art Methods)
在4.3的表中,以前的最佳单模型结果进行了比较。ResNet-34已经达到了非常有竞争力的准确性。ResNet-152具有4.49%的单模型top-5验证误差。该单一模型结果优于所有先前的结果。我们将六个不同深度的模型联合收割机组合成一个整体(提交时只有两个152层的)。这导致测试集上的前5名误差为3.57%。该作品在ILSVRC 2015中获得第一名。
Code
仅包含直接从Pytorch中直接调用以及基础的残差模块代码。详细代码可见
直接调用ResNet-50:
import torchvision.models as models
# 预定义的ResNet-50 将`pretrained`设置为True可以加载预训练的权重
resnet50 = models.resnet50(pretrained=True)
# 如果你想从头开始训练,只需要设置`pretrained=False`。
resnet50 = models.resnet50(pretrained=False)
BasicBlock模块
import torch
import torch.nn as nn
class BasicBlock(nn.Module):
"""用于resnet 18和resnet 34的基础块"""
# BasicBlock和BottleNeck块有不同的输出大小我们使用类属性expansion来区分
expansion = 1
def __init__(self, in_channels, out_channels, stride=1):
super().__init__()
# 残差函数
self.residual_function = nn.Sequential(
nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False),
nn.BatchNorm2d(out_channels),
nn.ReLU(inplace=True),
nn.Conv2d(out_channels, out_channels * BasicBlock.expansion, kernel_size=3, padding=1, bias=False),
nn.BatchNorm2d(out_channels * BasicBlock.expansion)
)
# 快捷路径
self.shortcut = nn.Sequential()
# 如果快捷路径的输出维度与残差函数的输出维度不同
# 使用1*1卷积来匹配维度
if stride != 1 or in_channels != BasicBlock.expansion * out_channels:
self.shortcut = nn.Sequential(
nn.Conv2d(in_channels, out_channels * BasicBlock.expansion, kernel_size=1, stride=stride, bias=False),
nn.BatchNorm2d(out_channels * BasicBlock.expansion)
)
def forward(self, x):
return nn.ReLU(inplace=True)(self.residual_function(x) + self.shortcut(x))
相关面试问题
答案取自互联网,如有错误请大家及时指出~
Q1:ResNet主要解决了什么问题
理论上,随着网络深度的增加,网络性能应该越来越好,或者至少保持不变。然而,更深的网络反而具有更差的训练和测试性能,这个情况我们称之为网络退化。这个问题不是由过拟合引起的,而是网络在深度增加时,额外的层学习到的仅仅是恒等映射,即输出等于输入。ResNet通过其残差连接允许这些额外的层更容易地学习到恒等映射,实际上它们只需要学习输入和输出之间的残差,这样即使网络非常深,性能也不会退化。
Q2:为什么ResNet可以解决“随着网络加深,准确率不下降”的问题?
理论上,对于“随着网络加深,准确率下降”的问题,Resnet提供了两种选择方式,也就是identity mapping和residual mapping,如果网络已经到达最优,继续加深网络,residual mapping将被push为0,只剩下identity mapping,这样理论上网络一直处于最优状态了,网络的性能也就不会随着深度增加而降低了。
Q3:ResNet为什么不用Dropout?
BN和dropout不能混合使用,单独使用效果更佳,原因为方差偏移
BN和Dropout共同使用时会出现的问题
参考
深度学习&论文精读内的参考部分
经典神经网络论文超详细解读(五)——ResNet(残差网络)学习笔记(翻译+精读+代码复现)
残差网络ResNet笔记