做卷积神经网路方面的研究。大抵是:
1、复现别人的网络,得不到相同的表现。
2、自己的网络调参,结果调不上去。
所以有一些调参的tricks,在这里学习记录一下,然后加上一些自己的理解。
影像神经网络效果的因素可能有但不限于以下几点:
(1)学习率调节 (2)优化器 (3)初始化方法 (4)标签平滑 (5)归一化
好的学习率可以让调参过程事半功倍,那么什么是好的学习率呢,
source:https://sgugger.github.io/how-do-you-find-a-good-learning-rate.html
好的学习率应该是有利于网络学习到参数的,或者说损失函数能够得到有效的降低。对于这幅示意图来说就是,需要函数能够快速的到达谷底。如果学习率太大,就可能会直接错过最低点。如果学习率太小,就可能学得太慢,同样也不可取。
那么应该如何选取初始值呢?
source:https://sgugger.github.io/how-do-you-find-a-good-learning-rate.html
像这幅图一样,你可以去尝试不同的初始学习率,然后可以以5-10轮的训练为标准,比较最终的学习效果。这一点在吴恩达的深度学习专项课程中也有提到过,就是如何去寻找超参数的合适值。一般学习率可以从0.1-10-8或者更大的范围去搜索,可以每次 缩小十倍。
这样做的好处有,你可能会找到一个能够快速收敛的学习率。
但请注意,快速并不等于最终结果最优。
一些流行的学习率调整方法有:
循环学习率
从图中可以看到,我们可以选取获得较好学习效果阶段的学习率,进行循环的调整,有一点多尺度学习的意思。
热启动的随机梯度下降(SGD)
循环学习率是讲述的总体学习率调节技巧,然而如果我们不使用预训练的网络,我们应该如何开始我们的网络学习过程呢,就有 学者提出热启动的概念1.
没有仔细读论文,但是大致的意思就是刚开始网络经过初始化之后,需要经过一定的调整之后才能达到一个快速学习的状态(当然这是实验结论),需要经过一些柔性的学习率调节之后就能达到一个更加好的初始化状态,这可以看作是对网络初始化的一个 补充。
超级收敛(super convergence)
这里的超级意思是,学习率超级大,比以往研究中证明出来可用的学习率更大。在这种学习率下,网络仍然可以收敛的现象2, 比如:
不过对我的影响太大,数据集没那么大,总的训练时间最多也就30h, 可能在大数据下这种快速收敛有奇效。
不过论文里也指出,这种现象只针对部分的学习器和部分的网络结构,不过看起来确实很快收敛了。
批大小(mini-batch)
批大小如何影响网络学习的呢?第一印象就是我们可以选取任意大的批大小,最好就是full batch,这样理所当然应该有更好的效果。因为这样梯度会更加的符合实际损失函数的梯度,减少噪音。然而实验表明,梯度是一方面,损失函数的实际情况是一个方面,大批量更新梯度的方法容易让损失函数陷入到局部最优解3,而小批量的话就给模型的梯度更新引入了一些不确定性,就使 得网络有可能跳出局部最优解,这样和模拟退火有点相似。
那么办法还是有的,既然你想要又快,又好,那么肯定要动点脑筋了,那么从哪个点下手呢,结论还是学习率,看来学习率还真 是强大呀。
使用小批量调整学习率
在训练的初始阶段使用较低的学习率,我想这应该也是要让网络能够获得一个更好的初始化
以上是在认真检查过数据的输入和输出的情况下的方法。因为又一次我遇到了训练一个分割模型,分割的dice系数到了0.6,怎么也上不去。最后可视化之后才发现,原来是数据处理有问题,训练的label和测试的label不一致。还有就是对数据进行augmentation时,一是要选择增强的方法,有些能用,有些不能用。另外就是对增强后的图像进行可视化,检查增强后的训练数 据和测试数据是否一致。
在生物意义上的神经元中,只有前面的树突传递的信号的加权和值大于某一个特定的阈值的时候,后面的神经元才会被激活。简单的说激活函数的意义在于判定每个神经元的输出
有没有达到阈值。
放在人脸识别卷积神经网络中来思考,卷积层的激活函数的意义在于这一块区域的特征强度如果没有达到一定的标准,就输出0,表明这种特征提取方式(卷积核w)不能在该块区域提取到特征,或者说这块区域的这种特征很弱。由于输出0时,激活函数梯度几乎都为0,所以在特征很弱的区域,梯度几乎不下降,也就是说,和该特征无关的区域不会影响到该特征提取方式的训练。
反过来说,如果没有激活函数,就算特征很弱时,仍然可以得到输出,后面的层次继续把这个输出当成一个特征使用,这是不合理的。为了形象起见,我们做个比喻,本来我们可能希望在这个区域看到一个圆形,但是这里却是一个三角形,如果该三角形和我们期望看到的圆形形状相差很大的时候神经元的输出WX+B很小,我们就不希望输出值去衡量这个三角形有多不圆,而是希望输出这里没有一个圆形(对于分类问题而言,有多不圆对于我们的分类没有意义,因为我们是通过了解到形状的组合来判定人脸 属于哪一类,验证问题同理)。
个人理解这也是激活函数要非线性的意义。
Sigmoid.
Sigmoid 非线性激活函数的形式是σ(x)=1/(1+e−x),其图形如上图左所示。之前我们说过,sigmoid函数输入一个实值的数,然后将其压缩到0~1的范围内。特别地,大的负数被映射成0,大的正数被映射成1。sigmoid function在历史上流行过一段时间因为它能够很好的表达“激活”的意思,未激活就是0,完全饱和的激活则是1。而现在sigmoid已经不怎么常用了,主要是因为 它有两个缺点:
1、Sigmoid**容易饱和,并且当输入非常大或者非常小的时候,神经元的梯度就接近于0了,从图中可以看出梯度的趋势。这就使得我们在反向传播算法中反向传播接近于0的梯度,导致最终权重基本没什么更新**,我们就无法递归地学习到输入数据了。另外,你需要尤其注意参数的初始值来尽量避免这一情况。如果你的初始值很大的话,大部分神经元可能都会处在饱和的状态而把 梯度kill掉,这会导致网络变的很难学习。
对于这一点,我个人的理解就是对于数据特别小的时候,梯度确实应该接近0(等于0就不好了),理由如上所述,数据特别大的 时候,梯度不应该接近0。就像Relu函数做的那样。
2、Sigmoid 的输出不是0均值的,这是我们不希望的,因为这会导致后层的神经元的输入是非0均值的信号,这会对梯度产生影响:假设后层神经元的输入都为正(e.g. x>0 elementwise in f=wTx+b),那么对w求局部梯度则都为正,这样在反向传播的过程中w 要么都往正方向更新,要么都往负方向更新,导致有一种捆绑的效果,使得收敛缓慢。
当然了,如果你是按batch去训练,那么每个batch可能得到不同的符号(正或负),那么相加一下这个问题还是可以缓解。因此,非0均值这个问题虽然会产生一些不好的影响,不过跟上面提到的 kill gradients 问题相比还是要好很多的。
(个人认为,如果使用SGD,则Batch训练仍然不能达到上面说的效果,所以sigmod使用SGD效果不好。)
Tanh.
Tanh和Sigmoid是有异曲同工之妙的,它的图形如上图右所示,不同的是它把实值得输入压缩到-1~1的范围,因此它基本是0均值的,也就解决了上述Sigmoid缺点中的第二个,所以实际中tanh会比sigmoid更常用。但是它还是存在梯度饱和的问题。Tanh是 sigmoid的变形:tanh(x)=2σ(2x)−1。
它的数学表达式是:
f(x)=max(0,x)
ReLU的优缺点如下:
优点1:Krizhevsky et al.在ImageNet Classification with Deep Convolutional
Neural Networks 提出使用 ReLU 得到的SGD的收敛速度会比 sigmoid/tanh 快很多(如上图右)。有人说这是因为它是linear,而且梯度不会饱和。
为什么线性不饱和,就会收敛的快?反向传播算法中,下降梯度等于敏感度乘以前一层的输出值,所以前一层输出越大,下降的 梯度越多。该优点解决了sigmod的问题1的一部分
优点2:相比于 sigmoid/tanh需要计算指数等,计算复杂度高,ReLU 只需要一个阈值就可以得到激活值。
缺点1: ReLU在训练的时候很”脆弱”,一不小心有可能导致神经元”坏死”。举个例子:由于ReLU在x<0时梯度为0,这样就导致负的梯度在这个ReLU被置零,而且这个神经元有可能再也不会被任何数据激活。如果这个情况发生了,那么这个神经元之后的梯度就永远是0了,也就是ReLU神经元坏死了,不再对任何数据有所响应。实际操作中,如果你的learning rate 很大,那么很有可能你网络中的40%的神经元都坏死了。 当然,如果你设置了一个合适的较小的learning rate,这个问题发生的情况其实也不会太频繁。
这个缺点类似sigmod问题1的另一部分,也就是说,如果在训练中某一次下降的太快,会导致该卷积核对要提取的特征要求过 高,形象的说,就是变成了一个“完美主义”卷积核,所有形状都入不了它的眼,这样这个神经元就没用了,坏死了。
Leaky ReLU.
Leaky ReLUs 就是用来解决ReLU坏死的问题的。和ReLU不同,当x\<0时,它的值不再是0,而是一个较小斜率(如0.01等)的函数。也就是说f(x)=1(x\<0)(ax)+1(x>=0)(x),其中a是一个很小的常数。这样,既修正了数据分布,又保留了一些负轴的值,使得负轴信息不会全部丢失。关于Leaky ReLU 的效果,众说纷纭,没有清晰的定论。有些人做了实验发现 Leaky ReLU 表现的很好;有 些实验则证明并不是这样。
Leaky ReLU相当于对sigmod问题2有一定改善,更主要的是解决了ReLu的坏死问题,让坏了的神经元可以自我慢慢恢复,但是 坏处就是,如果a过大,会丢失作为激活函数的原意。
我认为,Leaky ReLu的作用肯定是有的,但是既有好处也有坏处,关键在于a值的把握。
PReLU.
对于 Leaky ReLU 中的a,通常都是通过先验知识人工赋值的。然而可以观察到,损失函数对a的导数我们是可以求得的,可不可以将它作为一个参数进行训练呢? Kaiming He 2015的论文《Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification》指出,不仅可以训练,而且效果更好。原文说使用了Parametric ReLU后,最终效果 比不用提高了1.03%.
Randomized Leaky ReLU. Randomized Leaky ReLU 是 leaky ReLU 的random 版本, 其核心思想就是,在训练过程中,a是从 一个高斯分布中随机出来的,然后再在测试过程中进行修正。
假设我们网络第i层有2个神经元x1、x2,第i+1层的神经元个数为1个,如下图所示:
(1)以前MLP的方法。我们要计算第i+1层,那个神经元的激活值的时候,传统的MLP计算公式就是:
z=W*X+b
out=f(z)
其中f就是我们所谓的激活函数,比如Sigmod、Relu、Tanh等。
(2)Maxout 的方法。如果我们设置maxout的参数k=5,maxout层就如下所示:
相当于在每个输出神经元前面又多了一层。这一层有5个神经元,此时maxout网络的输出计算公式为:
z1=w1*x+b1
z2=w2*x+b2
z3=w3*x+b3
z4=w4*x+b4
z5=w5*x+b5
out=max(z1,z2,z3,z4,z5)
所以这就是为什么采用maxout的时候,参数个数成k倍增加的原因。本来我们只需要一组参数就够了,采用maxout后,就需要有 k组参数。
我的理解是,本来只能提取一类特征,现在提供五类特征提取方式,选择其中最符合一类。
那么可以分析得知:
优势是具有上述的恢复能力,而且恢复的是最接近的一个特征提取方式,由于有五个备选,那么虽然是线性,但是对整体系统影响不那么大。