关于深度学习各种优化器的介绍和对比在网上有很多图文并茂的讲解,比如我上一篇博文转载的文章:深度学习——优化器算法Optimizer详解(BGD、SGD、MBGD、Momentum、NAG、Adagrad、Adadelta、RMSprop、Adam)。有需要的可以移步去学习。
我们在进行深度学习模型训练时候,很容易出现过拟合现象:训练集准确率高,测试集准确率低。过拟合产生的原因可以分为两个:(1)训练数据不够,无法对整个数据分布进行评估;(2)参数学习迭代次数过多,拟合了训练数据中的噪声和训练样例中没有代表性的特征。
(1)数据集扩增
针对过拟合原因的第一种情况,当然是选择数据集扩增的方法来防止过拟合了。常见的数据集扩增方法有:
(2)Early stopping
深度学习模型如CNN对网络参数学习更新过程,会使用一些优化器(第一部分所讲)不断迭代,如梯度下降(Gradient descent)学习算法。Early stopping就是在多个连续Epoch迭代中,模型的准确率不再变化,或者微弱变化时候就停止训练,防止后面学习到与数据分布特征无关的噪声。
(3)正则化(Regularization)
正则化是机器学习中常用的防止过拟合方法,通过将权值大小加入到Cost里面,训练时候限制权值变大。模型越复杂,越容易过拟合。原先以最小化损失(经验风险最小化)为目标:
现在加入正则化后以最小化损失和模型复杂度(结构风险最小化)为目标:
通过降低复杂模型的复杂度来防止过拟合的规则称为正则化。
也就是说当我们有很多特征变量时,其中每一个变量都能对预测产生一点影响。所以要保留全部的特征变量。正如我们在房价预测的例子中看到的那样,我们可以有很多特征变量,其中每一个变量都是有用的,因此我们不希望把它们删掉,这就导致了正则化概念的发生。[4] 更通俗直观的理解如下:
如上图,如果用一个二次函数来拟合这些数据,那么能达到一个很好的拟合效果。然而,如果我们用一个更高次的多项式去拟合,最终我们可能会得到一个曲线,它能很好地拟合训练集,但却并不是一个好的结果,因为它过度拟合了数据,因此,一般性并不是很好。
因此,我们考虑在原先的损失函数中加上惩罚项,从而使参数 θ3 和 θ4 足够的小。就可以上图中X^3和X^4对预测结果的影响。
原来的代价函数(均方误差):
我们人为加入参数的惩罚项后:
这里的1000是我随意设置的值(实际是正则2的参数 λ)。在原有代价函数的基础上加上 1000 乘以 θ3 和θ4这一项后,只有将 θ3 和 θ4 的值接近于 0,才能使代价函数最小化,就像我们忽略了这两个值一样。如果我们做到这一点( θ3 和 θ4 接近 0 ),那么我们将得到一个近似的二次函数。
因此,我们最终恰当地拟合了数据,我们所使用的正是二次函数加上一些非常小,贡献很小项(因为这些项的 θ3、 θ4 非常接近于0)。显然,这是一个更好的假设。
上面仅仅是一个便于理解的例子,我们指定了只惩罚参数θ3 和 θ4 ,实际中我们不知道哪些参数重要,所以会惩罚所有的参数,即:
下面就是正则化项, λ 在这里我们称为正则化参数。
正则化有L1和L2两种,它们的具体可以在网上找到介绍,如[5]。总体来说,L1 正则化可以理解为每次从权重中减去一个常数。
L2 正则化可以理解为每次移除权重的 x%。本质都是为了降低模型的复杂度,防止过拟合。
(4)Dropout函数
我们知道如果要训练一个大型的网络,训练数据很少的话,那么很容易引起过拟合(也就是在测试集上的精度很低),可能我们会想到用L2正则化、或者减小网络规模。然而深度学习领域大神Hinton,在2012年文献中[6]提出在每次训练的时候,让一半的特征检测器停过工作,这样可以提高网络的泛化能力,Hinton又把它称之为dropout。
Hinton认为在神经网络产生过拟合主要是因为神经元之间的协同作用产生的。因此在神经网络进行训练的时候,让部分神经元失活,这样就阻断了部分神经元之间的协同作用,从而强制要求一个神经元和随机挑选出的神经元共同进行工作,减轻了部分神经元之间的联合适应性。
Dropout的实现说的简单一点就是我们让在前向传导的时候,让某个神经元的激活值以一定的概率p,让其停止工作,示意图如下。加入Dropout后,反向传播训练肯定会受影响,所以具体实现就需要仔细看看论文和源码里是怎么做的。
Keras里面的Dropout源码如下。函数中,x是本层网络的激活值。Level就是dropout就是每个神经元要被丢弃的概率。不过对于dropout后,为什么需要进行rescale(即除以retain_prob)我也不太理解,附上论文地址[7]以及此部分参考文献[8],有空再学习一下。
#dropout函数的实现
def dropout(x, level):
if level < 0. or level >= 1:#level是概率值,必须在0~1之间
raise Exception('Dropout level must be in interval [0, 1[.')
retain_prob = 1. - level
#我们通过binomial函数,生成与x一样的维数向量。binomial函数就像抛硬币一样,我们可以把每个神经元当做抛硬币一样
#硬币 正面的概率为p,n表示每个神经元试验的次数
#因为我们每个神经元只需要抛一次就可以了所以n=1,size参数是我们有多少个硬币。
sample=np.random.binomial(n=1,p=retain_prob,size=x.shape)#即将生成一个0、1分布的向量,0表示这个神经元被屏蔽,不工作了,也就是dropout了
print sample
x *=sample#0、1与x相乘,我们就可以屏蔽某些神经元,让它们的值变为0
print x
x /= retain_prob
return x
#对dropout的测试,大家可以跑一下上面的函数,了解一个输入x向量,经过dropout的结果
x=np.asarray([1,2,3,4,5,6,7,8,9,10],dtype=np.float32)
dropout(x,0.4)
(5)Batch Normalization(批标准化)[1][2]
目前BN是深度学习中较好的一种优化策略。在优化性能很大程度上超越了正则化和Dropout策略。它的优势可以总结如下三点[3]:
BN正则化模型:使用BN训练时,一个样本只与minibatch中其他样本有相互关系;对于同一个训练样本,网络的输出会发生 变化。这些效果有助于提升网络泛化能力,像dropout一样防止网络过拟合,同时BN的使用,可以减少或者去掉dropout类似的策略。
问题提出:
深度网络参数训练时内部存在协方差偏移(Internal Covariate Shift)现象:深度网络内部数据分布在训练过程中发生变化的现象。
为什么会带来不好影响:训练深度网络时,神经网络隐层参数更新会导致网络输出层输出数据的分布发生变化,而且随着层数的增加,根据链式规则,这种偏移现象会逐渐被放大。这对于网络参数学习来说是个问题:因为神经网络本质学习的就是数据分布(representation learning),如果数据分布变化了,神经网络又不得不学习新的分布。为保证网络参数训练的稳定性和收敛性,往往需要选择比较小的学习速率(learning rate),同时参数初始化的好坏也明显影响训练出的模型精度,特别是在训练具有饱和非线性(死区特性)的网络,比如即采用S或双S激活函数网络,比如LSTM,GRU。[9]
解决办法:
引入Batch Normalization,作为深度网络模型的一个层,每次先对input数据进行归一化,再送入神经网络输入层。
关于BN的实现大家可以直接看原文[1],这里有知乎的一个问题:深度学习中 Batch Normalization为什么效果好?[10],讲解的很细致,大家可以围观。这里附上两个关于BN的常见问题[11]:
关于BN的两点理解:
1.为什么它能缓解DNN训练中的梯度消失/爆炸现象?
关于梯度消失的一个简单例子是0.930≈0.040.930≈0.04,而BN通过归范化各层的输入数据使得原本会减小的data value的scale变大,这样反向求出的梯度scale应该也会相应增大。
2.为什么在normalize后还有一个scale and shift操作?
就像上面算法注释解释的,仅是简单的对网络层输入作归一化可能会改变原本的输入表示,而加入scale and shift操作,让归一化操作有机会通过对参数γ,βγ,β 的学习将其变回去,不改变输入表示。
参考文献
[1] Batch Normalization: Accelerating Deep Network Training b y Reducing Internal Covariate Shift
[2] Batch Normalization 学习笔记
[3] 深入理解Batch Normalization批标准化
[4] 机器学习之正则化(Regularization)
[5]【一看就懂】机器学习之L1和L2正则化
[6] 《Improving neural networks by preventing co-adaptation of feature detectors》
[7] Regularization of Neural Networks using DropConnect
[8] 深度学习之-Dropout的讲解(5)
[9] <深度学习优化策略-1>Batch Normalization(BN)
[10] 深度学习中 Batch Normalization为什么效果好?
[11]关于深度学习中的Batch normalization的理解