deep learning笔记:记首次ResNet实战

实践出真知。在之前的博文deep-learning笔记:使网络能够更深——ResNet简介与pytorch实现中,我对何恺明大神的CVPR最佳论文中提出的残差网络做了简单介绍。而就在第二年(2016年),何恺明的团队就发表了“Identity Mappings in Deep Residual Networks”这篇文章,分析了ResNet成功的关键因素——residual block背后的算法,并对residual block以及after-addition activation进行改进,通过一系列的ablation experiments验证了,在residual block和after-addition activation上都使用identity mapping(恒等映射)时,能对模型训练产生很好的效果。不知道为什么,我今天从arXiv上download这篇paper的时候发现上不去了,莫非现在上arXiv也要科学上网了?
本次实战主要是基于之前的ResNet实现和flyAI平台,并结合上面提到的何恺明团队分析ResNet的论文做出一些改进,并检验效果。

References

电子文献:
https://blog.csdn.net/Sandwichsauce/article/details/89162570
https://www.jianshu.com/p/184799230f20
https://blog.csdn.net/wspba/article/details/60572886
https://www.cnblogs.com/4991tcl/p/10395574.html
https://blog.csdn.net/DuinoDu/article/details/80435127

参考文献:
[1]Identity Mappings in Deep Residual Networks


ablation experiments

在上面我提到了这个名词,中文翻译是“消融实验”。或许在阅读论文的过程中会接触到这个名词,如果仅根据字面翻译的话或许会很纳闷。
在查找了一定的资料后,我对这种方法有了大致地了解。
ablation的原本释义是通过机械方法切除身体组织,如手术,从身体中去除尤指器官以及异常生长的有害物质。
事实上,这种方法类似于物理实验中的控制变量法,即当在一个新提出的模型中同时改变了多个条件或者参数,那么为了分析和检验,在接下去的消融实验中,会一一控制每个条件或者参数不变,来根据结果分析到底是哪个条件或者参数对模型的优化、影响更大。
在机器学习、特别是复杂的深度神经网络的背景下,科研工作者们已经采用“消融研究”来描述去除网络的某些部分的过程,以便更好地理解网络的行为。


ResNet的分析与改进

  1. 残差单元

    在2015年ResNet首次发布的时候,设计的残差单元在最后的输出之前是要经过一个激活函数的。而在2016年新提出的残差单元中,去掉了这个激活函数,并通过实验证明新提出的残差单元训练更简单。 这种新的构造的关键在于不仅仅是在残差单元的内部,而是在整个网络中创建一个“直接”的计算传播路径来分析深度残差网络。通过构造这样一个“干净”的信息通路,可以在前向和反向传播阶段,使信号能够直接的从一个单元传递到其他任意一个单元。实验表明,当框架接近于上面的状态时,训练会变得更加简单。
  2. shortcut

    对于恒等跳跃连接$h(x_{l})=x_{l}$,作者设计了5种新的连接方式来与原本的方式作对比,设计以及实验结果如下所示: 其中fail表示测试误差超过了20%。实验结果表明,原本的连接方式误差衰减最快,同时误差也最低,而其他形式的shortcut都产生了较大的损失和误差。
    作者认为,shortcut连接中的操作 (缩放、门控、1×1的卷积以及dropout) 会阻碍信息的传递,以致于对优化造成困难。
    此外,虽然1×1的卷积shortcut连接引入了更多的参数,本应该比恒等shortcut连接具有更加强大的表达能力。但是它的效果并不好,这表明了这些模型退化问题的原因是优化问题,而不是表达能力的问题。
  3. 激活函数

    对于激活函数的设置,作者设计了如下几种方式进行比较: 在这里,作者将激活项分为了预激活(pre-activation)和后激活(post-activation)。通过实验可以发现,将ReLU和BN都放在预激活中,即full pre-activation最为有效。

ResNet实战

根据论文中的实验结果,我使用了新的残差模块进行实践。并结合在deep-learning笔记:学习率衰减与批归一化中的分析总结对BN层的位置选取作了简单调整。在本次实验中,我尝试使用了StepLR阶梯式衰减和连续衰减两种学习率衰减方式,事实证明,使用StepLR阶梯式衰减的效果在这里要略好一些(连续衰减前期学得太快,后面大半部分都学不动了…)。
首次训练的结果并不理想,于是我加大了学习率每次衰减的幅度,即让最后阶段的学习率更小,这使我的模型的评分提高了不少。
由于训练资源有限,我没能进行更深(仅设置了10层左右)、更久(每次仅进行20个epoch)的训练,但在每个batch中,最高的accuracy也能达到65%左右,平均大约能超过50%。相比之前使用浅层网络仅能达到20%左右的accuracy,这已经提升不少了。然而最终的打分还是没有显著提高,因此我思考是否存在过拟合的问题。为此我尝试着在全连接层和捷径连接中加入dropout正则化来提高在测试集中的泛化能力,结果最终打分仅提高了0.1,而训练时间稍短。由于我除了dropout之外并没有改变网络的层数等影响参数量的因素,因此似乎与何大神在论文中original版和dropout版shortchut的比较有一些矛盾,但的确还是说明了dropout在这里的作用微乎其微,优化模型时可以排除至考虑范围之外了。


遇到的问题

  1. TabError: inconsistent use of tabs and spaces in indentation

    当我在flyAI提供的窗口中修改代码并提交GPU训练时,就出现了这个报错。它说我在缩进时错误的使用了制表符和空格。于是我只好把报错处的缩进删除并重敲tab缩进,问题就得到了解决。
    如果使用PyCharm等IDE的话,这个错误会直接显示出来,即在缩进处会有灰色的颜色警告,将光标移过去就会有具体报错。这就省得提交GPU之后才能收到报错,所以以后写代码、改代码能用IDE还是用起来好啦。
  2. RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation

    这是在shortcut残差连接时遇到的一个报错,上网后发现原因很简单:版本问题。在新版的pytorch中,由于0.4.0之后把Varible和Tensor融合为一个Tensor,因此inplace操作在之前对Varible时还能用,但现在只有Tensor,就会出错了。
    解决的办法是将x += self.shortcut(x1)替换成x = x + self.shortcut(x1)
    若网络很大,找起来很麻烦,可以在网络的中间变量加一句x.backward(),看会不会报错,如果不会的话,那就说明至少这之前是没毛病的。
  3. 张量第一维是batch size

    起初,我根据输入的torch.Size([64, 1, 128, 128]),使用如下函数将输出拍平成1维的:

    1
    2
    3
    4
    5
    6
    def num_flat_features(self, x):
    size = x.size()[0:]
    num_features = 1
    for s in size:
    num_features *= s
    return num_features

    同时,为了匹配,我将第一个全连接层的输入乘上了64。其实这个时候我已经开始怀疑这个64是哪来的了,为什么这个张量第一维尺度有64。
    直到后来平台报错,我才意识到这个表示的不是数据的维度,而是我设计的batch size。
    为此我将上面的代码调整如下:

    1
    2
    3
    4
    5
    6
    def num_flat_features(self, x):
    size = x.size()[1:]
    num_features = 1
    for s in size:
    num_features *= s
    return num_features

    如此,问题得到解决,最终的输出应该是batch size乘上总类别数的一个张量。


arXiv

文前提到了上arXiv下论文要科学上网的事情,后来我发现了一个中科院理论物理所的一个备选镜像,但是好像不是特别稳定,不过还是先留在这里吧,万一的话可以拿来试试。
一般一些科研工作者会在论文发布之前上传到arXiv以防止自己的idea被别人用了。估计主要是为了防止类似牛顿莱布尼兹之争这种事吧。


碰到底线咯 后面没有啦

本文标题:deep learning笔记:记首次ResNet实战

文章作者:高深远

发布时间:2020年01月13日 - 17:47

最后更新:2020年02月15日 - 22:10

原始链接:https://gsy00517.github.io/deep-learning20200113174731/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

0%