点上方蓝字计算机视觉联盟获取更多干货

在右上方 ··· 设为星标 ★,与你不见不散

仅作学术分享,不代表本公众号立场,侵权联系删除

转载于:作者丨刘昕宸@知乎

来源丨https://zhuanlan.zhihu.com/p/268308900

AI博士笔记系列推荐

周志华《机器学习》手推笔记正式开源!可打印版本附pdf下载链接

通过堆叠神经网络层数(增加深度)可以非常有效地增强表征,提升特征学习效果,但是会出现深层网络的性能退化问题,ResNet的出现能够解决这个问题。本文用论文解读的方式展现了ResNet的实现方式、分类、目标检测等任务上相比SOTA更好的效果。

论文标题:Deep Residual Learning for Image Recognition

1 motivation

通过总结前人的经验,我们常会得出这样的结论:通过堆叠神经网络层数(增加深度)可以非常有效地增强表征,提升特征学习效果。

为什么深度的网络表征效果会好?
深度学习很不好解释,大概的解释可以是:网络的不同层可以提取不同抽象层次的特征,越深的层提取的特征越抽象。因此深度网络可以整合low-medium-high各种层次的特征,增强网络表征能力。

那好,我们就直接增加网络深度吧!

但是事情好像并没有那么简单!

梯度优化问题:

我们不禁发问:Is learning better networks as easy as stacking more layers?

首先,深度网络优化是比较困难的,比如会出现梯度爆炸/梯度消失等问题。不过,这个问题已经被normalized initialization和batch normalization等措施解决得差不多了。

退化问题:

好,那就直接上deeper network吧!

但是新问题又来了:deeper network收敛是收敛了,却出现了效果上的degradation

deeper network准确率饱和后,很快就退化了

为什么会这样呢?网络更深了,参数更多了,应该拟合能力更强了才对啊!噢,一定是过拟合了。

但似乎也不是过拟合的问题:

因为56-layer网络(红线)的training error(左图)也比20-layer网络(黄线)要高,这就应该不是过拟合了啊!

那么究竟是什么原因导致了deeper network degradation问题呢?

现在,我们换一种思路来构建deeper network:

the added layers are identity mapping, and the other layers are copied from the learned shallower model.(在原始的浅层网络基础上增加的层视为是identity mapping)

也就是假设浅层网络已经可以得到一个不错的结果了,那我接下来新增加的层啥也不干,只是拟合一个identity mapping,输出就拟合输入,这样总可以吧。

这样的话,我们觉得:这样构建的深层网络至少不应该比它对应的浅层training error要高。对吧。

但是实验又无情地表明:这样却又不能得到(与浅层网络)一样好的结果,甚至还会比它差!

看来,深度网络的优化并不容易的!

总结一下:直觉上深度网络应该会有更好的表征能力,但是事实却是深度网络结果会变差,由此我们认为深度网络的优化部分出了问题,深度网络的参数空间变得更复杂提升了优化的难度。

那么,ResNet来了。

我们就想啊,与其直接拟合一个desired underlying mapping  ,不如让网络尝试拟合一个residual mapping  。

也就是:

原先的映射  ,被转换为了 

我们在这里假设优化残差映射(residual mapping)  是比优化原映射  要容易的。
比如如果现在恒等映射(identity mapping)是最优的,那么似乎通过堆叠一些非线性层的网络将残差映射为0,从而拟合这个恒等映射,最种做法是更容易的。

 可以通过如上图所示的短路连接(shortcut connection)结构来实现。

shortcut就是设计的可以skip几层的结构,在ResNet中就是起到了相当于一个最最简单的identity mapping,其输出被加到了stacked layers的输出上。这样做既没有增加新的参数,也没有增加计算复杂性。

ResNet的具体结构,后面会详细介绍。

接下来,本文在ImageNet和CIFAR-10等数据集上做实验,主要是想验证2个问题:

  1. deep residual nets比它对应版本的plain nets更好优化,training error更低。

  2. deep residual nets能够从更深的网络中获得更好的表征,从而提升分类效果。

2 solution

ResNet想做什么?

learning residual functions with reference to the layer inputs, instead of learning unreferenced functions.

理解不了没关系,接着往下看。

2.1 Residual Learning

前提:如果假设多个非线性层能够渐近一个复杂的函数,那么多个非线性层也一定可以渐近这个残差函数。

令  表示目标拟合函数。

所以与其考虑拟合  ,不如考虑拟合其对应的残差函数  .这两种拟合难度可能是不同的。

回到上面的讨论,如果被增加层能够被构建成identity mapping,那么深层网络的性能至少不应该比其对应的浅层版本要差。

这个表明:网络是在使用多层非线性网络趋近identity mapping做优化这里出了问题。

残差学习的这种方式,使得“如果identity mapping是最优的,网络的优化器直接将残差学习为0”就可以了,这样做是比较简单的。

但其实在真实情况下,identity mapping不一定是最优的映射啊!原文说这种设计仍有意义,这种设计help to precondition the problem.

也就是如果optimal function更接近identity mapping的话,优化器应该能够比较容易找到残差,而不是重新学习一个新的。

后面实验也表明了:残差网络各层输出的标准差是比较低的(如上图,后面会解释),这也验证了在identity mapping的基础上学习残差,确实是会更容易(identity mappings provide reasonable preconditioning.).

这里解释得还是比较含糊,但总结来说就是作者想解释,训练学习残差会有效降低学习的难度,可能据此来解决深层网络的性能退化问题。

2.2 Identity Mapping by Shortcuts

再回顾一下这个著名的残差块图片:

identity mapping实现得非常之简单,直接就用了个shortcut

形式化就是:

 表示residual mapping,比如上图,实际上就是2层网络,也就是 

然后直接将  与  element-wise相加。

最后,给  套一个激活函数  .

这么设计(shortcut)有个巨大的好处,就是没有引入任何新的参数,也没有增加计算复杂度。

下面还有2个小问题:

问题1:关于 

因为  是element-wise相加,那么如果  和  维度不一样怎么办?

方案一:直接对  补0.

方案二:增加一个网络层(参数为  ),改变  的维度。即:

事实上,每个shortcut我们都可以加一个映射层  (实现起来可以就是个感知机)。不需要做维度转化时,  就是个方阵。但是后面实验表明,直接shortcut就已经足够好了,不需要再加那么多参数浪费计算资源。

问题2:关于 

 的结构应该是什么样的呢?

 可以是2层或者3层,也可以是更多;但是不要是1层,效果会不好。

最后,shortcut设计不仅针对全连接网络,卷积网络当然也是没问题的!

2.3 网络架构

受VGGNet(左边)启发,设计了34层的plain network(中间),以及其对应的residual network版本(右边)。

注意:中间plain network和右边residual network层数一致,网络参数也可以设计得完全一样(element-wise相加维度不match时直接补0就不会增加任何learnable parameters)。

34-layer plain network设计原则(遵循VGGNet):

  1. for the same output feature map size, the layers have the same number of filters

  2. if the feature map size is halved, the number of filters is doubled so as to preserve the time complexity per layer

3 dataset and experiments

3.1 ImageNet on Classification

3.1.1 与plain network的对比实验

这个实验是核心,为了说明residual network能够非常完美地解决“深度增加带来的degradation”问题!!!

左边是plain network,右边是ResNet;细线是train error,加粗线是val error

Plain network会出现网络的层数增加,train error和val error都会升高

什么原因呢???
首先排除过拟合,因为train error也会升高
其次排除梯度消失,网络中使用了batch normalization,并且作者也做实验验证了梯度的存在
事实上,34-layers plain network也是可以实现比较好的准确率的,这说明网络在一定程度上也是work了的。
作者猜测:We conjecture that the deep plain nets may have exponentially low convergence rates. 层数的提升会在一定程度上指数级别影响收敛速度。

下面是Residual Network与plain network的量化对比:

观察上面两张图,我们可以得出结论:

  1. 而ResNet却真正实现了网络层数增加,train error和val error都降低了,证明了网络深度确实可以帮助提升网络的性能。degradation problem在一定程度上得到了解决。

  2. 相对于plain 34-layers,ResNet 34-layers的top-1 error rate也降低了3.5%。resnet实现了在没有增加任何参数的情况下,获得了更低error rate,网络更加高效。

  3. 从plain/residual 18-layers的比较来看,两者的error rate差不多,但是ResNet却能够收敛得更快。

总结来说就是,ResNet在不增加任何参数的情况下,仅使用shortcuts and zero-padding for matching dimensions结构,就实现了:

解决了degradation problem,更高的准确率,更快的收敛速度

简直太强了!!!

3.1.2 Identity v.s. Projection shortcuts

所谓projection shortcuts,就是:shortcuts包括了一个可学习参数(可以用来对齐维度,使得element-wise相加可以实现):

设计了A,B,C三种实验:

A:单纯使用identity shortcuts:

维度不能对齐时使用zero padding来提升维度

此方案没有增加任何参数

B:仅仅在维度需要对齐时使用projection shortcuts,其余均使用parameter-free的identity shortcuts

C:全部使用projection shortcuts

下面是三种方案的实验结果:

ABC三种方案均明显好于plain版本

C虽然结果稍微优于B、C,但是却引入了大量的参数,增加了时空计算复杂度。

作者认为:projection shortcuts are not essential for addressing the degradation problem.

因此后面的实验仍然采用A或者B结构。

3.1.3 Deeper Bottleneck Architectures.

为了探索更深层的网络,保证训练时间在可控范围内,作者重又设计了bottleneck版本的building block

左边是原版本,右边是bottleneck版本

bottleneck版本是将卷积核换成了1*1,3*3,1*1的size,虽然层数增加到了3层,但是降低了参数量。
作者在这里是想探索深度的真正瓶颈,而不是追求很低的error rate,因此在这里使用了更加精简的bottleneck building block

50-layers:将34-layers的每个2-layer block换成了3-layers bottleneck block

101-layers/152-layers:增加更多的3-layers bottleneck block

网络具体参数可参考如下图:

实验结果如下所示:

网络越深,确实取得了更好的结果。Plain network的degradation problem似乎消失了。

3.2 CIFAR-10实验与分析

实线是test error,虚线是train error

左边是plain network,中间是ResNet,右边是ResNet with 110 layers and 1202 layers.

结论基本与之前一致,但在1202层时,ResNet还是出现了degradation现象(结果比110层差),作者认为是过拟合。

另外:Analysis of Layer Responses

关于response:The responses are the outputs of each  layer, after BN and before other nonlinearity (ReLU/addition).

从上图我们可以直接看出:ResNet较于plain network,一般来说response std更小。

并且:deeper ResNet has smaller magni- tudes of responses

这就说明了:

  1. residual functions(即  ) might be generally closer to zero than the non-residual functions.

  2. When there are more layers, an individual layer of ResNets tends to modify the signal less.(也就是后面逐渐就接近identity mapping,要拟合的残差越来越小,离目标越来越近)

4 code review

ResNet实现非常简单,网上各种实现多如牛毛,这里仅随意找了个实现版本作为对照:

代码基于CIFAR-10的:

2层的BasicBlock:

class BasicBlock(nn.Module):expansion = 1def __init__(self, in_planes, planes, stride=1, option='A'):super(BasicBlock, self).__init__()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)self.shortcut = nn.Sequential()if stride != 1 or in_planes != planes:if option == 'A':"""For CIFAR10 ResNet paper uses option A."""self.shortcut = LambdaLayer(lambda x:F.pad(x[:, :, ::2, ::2], (0, 0, 0, 0, planes//4, planes//4), "constant", 0))elif option == 'B':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 = F.relu(self.bn1(self.conv1(x)))out = self.bn2(self.conv2(out))out += self.shortcut(x)out = F.relu(out)return out

ResNet骨架:

解释一下:

forward函数中定义resnet骨架:

  1. 首:1层conv

  2. 身:由BasicBlock构成layer1、layer2、layer3,个数分别为  ,因为每个BasicBlock有2层,所以总层数是 

  3. 尾:1层fc

所以总共有  层!

layer1, layer2, layer3输出维度分别是16,32,64

class ResNet(nn.Module):def __init__(self, block, num_blocks, num_classes=10):super(ResNet, self).__init__()self.in_planes = 16self.conv1 = nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1, bias=False)self.bn1 = nn.BatchNorm2d(16)self.layer1 = self._make_layer(block, 16, num_blocks[0], stride=1)self.layer2 = self._make_layer(block, 32, num_blocks[1], stride=2)self.layer3 = self._make_layer(block, 64, num_blocks[2], stride=2)self.linear = nn.Linear(64, num_classes)self.apply(_weights_init)def _make_layer(self, block, planes, num_blocks, stride):strides = [stride] + [1]*(num_blocks-1)layers = []for stride in strides:layers.append(block(self.in_planes, planes, stride))self.in_planes = planes * block.expansionreturn nn.Sequential(*layers)def forward(self, x):out = F.relu(self.bn1(self.conv1(x)))out = self.layer1(out)out = self.layer2(out)out = self.layer3(out)out = F.avg_pool2d(out, out.size()[3])out = out.view(out.size(0), -1)out = self.linear(out)return out

最后,像堆积木一样,通过设置layer1、layer2、layer3的BasicBlock个数来堆出不同层的ResNet:

def resnet20():return ResNet(BasicBlock, [3, 3, 3])def resnet32():return ResNet(BasicBlock, [5, 5, 5])def resnet44():return ResNet(BasicBlock, [7, 7, 7])def resnet56():return ResNet(BasicBlock, [9, 9, 9])def resnet110():return ResNet(BasicBlock, [18, 18, 18])def resnet1202():return ResNet(BasicBlock, [200, 200, 200])

5 conclusion

ResNet核心就是residual learning和shortcut identity mapping,实现方式极其简单,却取得了极其好的效果,在分类、目标检测等任务上均是大比分领先SOTA,这种非常general的创新是非常不容易的,这也是ResNet备受推崇的原因吧!

另外给我的启示就是:不仅仅是"talk is cheap, show me the code"了,而是"code is also relatively cheap, show me ur sense and thinking"!

end

这是我的私人微信,还有少量坑位,可与相关学者研究人员交流学习 

目前开设有人工智能、机器学习、计算机视觉、自动驾驶(含SLAM)、Python、求职面经、综合交流群扫描添加CV联盟微信拉你进群,备注:CV联盟

王博的公众号,欢迎关注,干货多多

王博的系列手推笔记(附高清PDF下载):

博士笔记 | 周志华《机器学习》手推笔记第一章思维导图

博士笔记 | 周志华《机器学习》手推笔记第二章“模型评估与选择”

博士笔记 | 周志华《机器学习》手推笔记第三章“线性模型”

博士笔记 | 周志华《机器学习》手推笔记第四章“决策树”

博士笔记 | 周志华《机器学习》手推笔记第五章“神经网络”

博士笔记 | 周志华《机器学习》手推笔记第六章支持向量机(上)

博士笔记 | 周志华《机器学习》手推笔记第六章支持向量机(下)

博士笔记 | 周志华《机器学习》手推笔记第七章贝叶斯分类(上)

博士笔记 | 周志华《机器学习》手推笔记第七章贝叶斯分类(下)

博士笔记 | 周志华《机器学习》手推笔记第八章(上)

博士笔记 | 周志华《机器学习》手推笔记第八章(下)

博士笔记 | 周志华《机器学习》手推笔记第九章

点个在看支持一下吧

重读经典:完全解析特征学习大杀器 ResNet相关推荐

  1. 重读经典:完全解析特征学习大杀器ResNet

    作者丨刘昕宸@知乎 来源丨https://zhuanlan.zhihu.com/p/268308900 编辑丨极市平台 论文标题:Deep Residual Learning for Image Re ...

  2. resnet过拟合_重读经典:完全解析特征学习大杀器ResNet

    公众号关注 "ML-CVer" 设为 "星标",DLCV消息即可送达! 作者丨刘昕宸@知乎来源丨https://zhuanlan.zhihu.com/p/268 ...

  3. 干货▍全网通俗易懂的数据竞赛大杀器XGBoost 算法详解

    前言 xgboost一直在竞赛江湖里被传为神器,比如时不时某个kaggle/天池比赛中,某人用xgboost于千军万马中斩获冠军. 而我们的机器学习课程里也必讲xgboost,如寒所说:"R ...

  4. 通俗理解kaggle比赛大杀器xgboost

    通俗理解kaggle比赛大杀器xgboost 说明:若出现部分图片无法正常显示而影响阅读,请以此处的文章为准:xgboost 题库版. 时间:二零一九年三月二十五日. 0 前言 xgboost一直在竞 ...

  5. 大杀器!攻克目标检测难点秘籍四,数据增强大法

    点击上方"AI算法修炼营",选择加星标或"置顶" 标题以下,全是干货 前面的话 在前面的秘籍一:模型加速之轻量化网络.秘籍二:非极大抑制算法和回归损失优化之路. ...

  6. 强推大杀器xgboost

    强推大杀器xgboost 1 决策树 举个例子,集训营某一期有100多名学员,假定给你一个任务,要你统计男生女生各多少人,当一个一个学员依次上台站到你面前时,你会怎么区分谁是男谁是女呢? 很快,你考虑 ...

  7. clodeblocks debug断点调试_Intellij IDEA高阶DEBUG大杀器

    前言 目前工作中由于环境复杂等客观因素,无法在本地启动项目进行 Trouble Shooting,需要打开测试环境的 DEBUG 端口,进行远程调试.为了不影响其他用户同时使用测试环境以及相关系统的正 ...

  8. 性能提升一个数量级,大杀器来了!| 文内福利

    经过多年的演进,Java语言的功能和性能都在不断地发展和提高,但是冷启动开销较大的问题长期存在,难以从根本上解决.本文先讨论冷启动问题的根本原因,然后介绍一种新近提出的彻底解决Java冷启动问题的技术 ...

  9. 结构化数据上的机器学习大杀器XGBoost

    转自: http://geek.ai100.com.cn/2017/05/26/1640 XGBoost是一个机器学习算法工具,它的原理本身就并不难理解,而且你并不需要彻底搞懂背后的原理就能把它用得呼 ...

最新文章

  1. Session丢失的解决办法小结
  2. linux fg 参数,Linux的bg和fg命令简单介绍
  3. java 应用程序的打包发行
  4. 前端if else_应该记录的一些项目代码(前端)
  5. Win10系列:VC++ 定时器
  6. eclipse没有java web,Eclipse Juno在Dynamic Web Project中没有JSP(但其他一切都很好)
  7. IntelliJ Idea学习笔记004--- idea修改格式化代码快捷键_顺带一个激活地址_以及常用快捷键
  8. SnagIt的Visual Studio Team System插件
  9. OpenStack常见命令与问题集合
  10. 【Android UI设计与开发】10:滑动菜单栏(二)SlidingMenu 动画效果的实现
  11. Avoiding GREEDYDATA for logstash'grok
  12. 多目标优化算法:多目标樽海鞘算法MOSSA(提供MATLAB源码)
  13. 几种主流的分布式定时任务
  14. 抖音是怎么做出来的?| 创业故事
  15. 中兴新支点操作系统_国产操作系统崛起之作 中兴新支点OS解析
  16. Google黑客常用搜索语法
  17. 期末前端web大作业——HTML+CSS+JavaScript仿京东购物商城网页制作(7页)
  18. 根据显示屏分辨率调试html 样式
  19. pikachu之sql注入
  20. 运动学模型(二)----轮速计 后轮速差模型

热门文章

  1. matlab meshc函数_有那些相见恨晚的MATLAB绘图命令
  2. debian9为什么默认是pip2_Debian9 安装后基本配置
  3. android工程中的软件,通过Android Studio创建Android应用程序(附带解析)
  4. hadoop mysql 安装失败_hadoop 安装问题总结
  5. 星露谷服务器一直没有空闲位置,星露谷物语小镇地图全npc住址位置 经验告诉你该这样...
  6. c盘保护软件_电脑C盘空间越来越小?简单操作这几步,可以释放大量空间
  7. Linux单系统手动分区教程,【教程贴】Linux类系统手动操作篇--标准分区硬盘和目录扩容...
  8. 来自山西机器人乐队_冰山上的机器人X三十禁放映 | 庞宽、李霄云对谈预告
  9. mysql myisam简单分表设计
  10. 配置Servlet3.0的方式和注意事项!