作者:安静哒发呆 | 来源:互联网 | 2023-09-03 09:36
神经网络训练细节系列笔记:神经网络训练细节(BatchNormalization)神经网络训练细节(数据预处理、权重初始化)神经网络训练细节(训练过程,超参数优化)
神经网络训练细节系列笔记:
- 神经网络训练细节(Batch Normalization)
- 神经网络训练细节(数据预处理、权重初始化)
- 神经网络训练细节(训练过程,超参数优化)
上一篇斯坦福cs231n学习笔记(6)——神经网络初步从生物神经元角度简单的介绍了神经网络的结构,这一篇将着重介绍神经网络的训练细节,如何高效的训练神经网络。
一、追溯历史
可能女孩子都喜欢爱回忆过去,每次一讲到神经网络的历史,就特别激动,昨天在twitter上关注了Yann LeCun,内心更是激动不已,仿佛能感受到他在1998年提出CNN时的那种划时代的震撼力。AI真是一个充满挑战又激动人心的领域。就像学良老师所说,我们一直相信未来!
那么,长话短说,我们简单聊一聊a bit of history:
* 追溯到1957年,Frank Rosenblatt发明被称之为感知机的机器,就像神经网络的硬件实现,由电路和电子元件连接:
激活函数使用的是二进制阶梯函数:
由式子可以激活函数不能进行微分运算,也不能反向传播。同时,Frank Rosenblatt提出了学习法则,通过设置权值,得到好的训练结果:
在1957那个年代,没有损失函数的概念,没有反向传播的概念。
Widrow and Hoff在1960年对感知机进行改进,提出适应性神经元,将感知机整合成一个多层次的感知机网络,由下图可知,同样是由电子元件和电路组成的硬件器件,没有反向传播概念,同样也是有学习法则来评定神经网络的性能好坏。
在1986年,神经网络有了突破性的进展,源于由Rumelhart等人第一次提出的反向传播的概念(Back-propagation),摒弃了多层次感知机特定的学习法则,并提出了损失函数的公式以及梯度下降的概念,但是对于大型的神经网络,训练效果并不是很好。
在1986~2006年,神经网络的研究并没有什么实质性进展,直至2006年,神经网络开始复兴,由Hinton and Salakhutdinov 发表的论文,他们在深度学习中采用了一个无监督预训练方案,使用RBM(限制波尔兹曼机)不在单通道中对所有层使用反向传播算法,而是在第一层建立一个无监督的学习目标,第二层,第三层,第四层…….对数据集进行预训练,也就是逐层进行训练,然后将所有层整合起来进行反向传播。
在2010~2012年人们开始普遍注意到神经网络,最开始是应用在语音识别方面,是由微软提出将神经网络运用在GMM+HMM语音识别模型中,用来改善语音识别的效果。在2012年,神经网络开始应用到图像识别领域,变得愈加火热。分析原因,大概是因为有很多好的方式用来实现激活函数的初始化以及GPU硬件的发展,更重要的是数据作为驱动力的时代已经来临!
神经网络的历史就说到这里,下面我们来详解神经网络的训练细节。
二、激活函数(Activation Function)
也就是图中的f,在上一篇中斯坦福cs231n学习笔记(6)——神经网络初步简单的介绍了几种激活函数,下面将从各个函数的优缺点和特点详细的介绍每一种激活函数。
* Sigmoid
sigmoid函数在过去的一段历史中非常受欢迎,又被称为挤压函数,取值为[0,1]之间的实数。同时,sigmoid存在3个问题:
(1)一个饱和的神经元(Saturated neurons),也就是这个神经元的输出要么非常接近1要么非常接近0。这类神经元会导致在反向传播算法中出现梯度趋0的问题,这个问题叫做梯度弥散(消失)。重点解释这意味着什么,先看一下sigmoid函数的运算链路:
输入一个x,会输出一个sigmoid结果,然后进行反向传播,运用链式法则,最终得到dl/dx,可以看到,链式法则就是将这两项相乘。那我们想象一下,当sigmoid单数的输入是-10,0,10时会发生什么?
当x取-10或10时,梯度会非常小。在sigmoid图像上可以看到,在取值-10的地方,因为这点的斜率为0,梯度几乎为0;在取值为10的地方也几乎是0。那么问题来了,在输出是1或者0的时候,那么你的梯度将会趋于0,当局部梯度是一个很小的数,在进行反向传播的时候将会停止。因此可以想象我们有一个很大的sigmoid神经网络,而且很多数据都落在饱和区域,输出值不是0就是1,那么梯度将无法对网络进行反向传播,因为梯度的传播将很快停止。当很多数据落在饱和区域,梯度将只会当你的数据落在安全区域时才会变化,这一安全区域我们被称为sigmoid函数的激活区域。
(2)另一个问题是,sigmoid函数的输出不是关于远点中心对称的。假设我们有一个多层的sigmoid神经网络,如果你的输入x都是正数,然后这些不关于原点对称的输出值都集中在0和1之间,那么在反向传播中w的梯度会传播到网络的某一处,那么权值的变化是要么全正要么全负。解释下:当梯度从上层传播下来,w的梯度都是用x乘以f的梯度,因此如果神经元输出的梯度是正的,那么所有w的梯度就会是正的,反之亦然。在这个例子中,我们会得到两种权值,权值范围分别位于图中一三象限:
当输入一个值时,w的梯度要么都是正的要么都是负的,当我们想要输入一三象限区域以外的点时,我们将会得到这种并不理想的曲折路线(zig zag path),图中红色曲折路线。虽然这个理由很简单,但根据经验得出,如果我们训练的数据并不关于原点中心对称,收敛速度会非常之慢。
(3)最后一个问题就是,sigmoid函数的表达书中关于exp()的计算是很耗时的,这可能是一个小细节,但当你去训练很大的卷积网络,耗时的痛苦无法想象。
tanh(x)
tanh(x)函数是由Yann LeCun在1991年提出的,最终的输出是[-1,1]之间的实数,好比两个sigmoid函数叠在一起,由图像可以看出tanh是关于原点对称的,在这方面的做的很nice。但是tanh(x)与sigmoid函数有相同的缺点,就是梯度仍然会出现的饱和的问题,导致梯度无法传播。
ReLU(Rectified Linear Unit修正线性单元)
ReLU是Krizhevsky等人在2012年关于一篇卷积神经网络的论文中提出的一种非线性函数max(0,x)。在使用ReLU激活函数之后,神经网络收敛速度非常快,达到了之前的六倍速。简短的讲一下原因,首先因为ReLU不会饱和,至少在输入为正的时候,在正的区域内不会产生梯度弥散的问题,梯度不会突然为0,当神经元在很小的有边界的区域被激活时,才会出现梯度消失的问题。实际上,这些神经元只在反向传播的过程中才会被激活,不论正确与否,至少在一半的区域内(正区域内)反向传播不会是0。Also,ReLU有一些缺点:
(1)输出结果不是关于原点对称的;
(2)有一个很烦恼的事,当输入的神经元x<0时,梯度是怎样的?当ReLU神经元没有被激活时,会发生什么情况?答案是梯度会消散。因此,非激活的输入值无法进行反向传播,权值也不会更新,可以说,这个神经网络什么都没有做。
【Hint:这里说的梯度是指泛化的梯度,指原函数是必须可微的。】
在使用ReLU激活函数的时候,可能会发生这样的情形,如果这个神经元什么都不输出,那么说明没有任何的梯度,假如梯度弥散了,就不会有任何更新。
那么问题来了:初始化ReLU神经元时,输入数据集之后,我们可能会得到dead ReLU神经元,如果神经元在数据集的外面,那么dead ReLU将永远不会激活,参数也不会更新。
以上问题的发生,通常发生在一下两种情况:
(1)在初始化过程中,如果你非常不幸的将权重设置成不能使神经元激活的数值,神经元将不会训练Data集;
(2)在训练过程中,若学习速率太高,想象一下这些神经元在一定范围内波动,将会发生数据多样性的丢失,在这种情况下,神经元不会被激活,数据多样性的丢失也不会逆转。
在实践中,我们会看到这种情况,当训练很大的且激活函数为ReLU的神经网络,在训练过程中,看起来一切运行正常,但需要停止训练,因为当我们将整个训练集输入网络,查看所有神经元的统计状况时,我们会发现有10%或20%的神经元已经死了(不会被训练集中任何数据激活),为了解决初始化中dead ReLU问题,人们把偏置值b设置成很小的证书0.01,而不是0,这使未经初始化的ReLU更有可能输出正值,从而使参数更新,减少神经元在训练过程中不被激活的可能性。虽然这种做法会起一定作用,但是很多人还是不认可这种做法。因此,有了Leaky ReLU,PReLU,ELU等等的出现,那我们继续…
Leaky ReLU
Leaky ReLU很好的解决了dead ReLU的问题,因为Leaky ReLU保留了第三象限的曲线,分段线性并保留了ReLU的效率。以前ReLU在第三象限的区域内的梯度会消失,而Leaky ReLU给这个区间一个很小的负或正的斜率,而不会有神经元死了的问题。
PReLU(参数校正器)
PReLU对Leaky ReLU进行升级,由表达式可以看出,多了一个α参数,那么计算图中的每一个神经元都会有一个α参数,就像偏置值b一样,α参数可以由反向传播学习此参数。同时只有让αx和x不相等,计算过程才有意义。
ELU(Exponential Linear Units )
ELU是由Clevert等人在2015年提出的,使用非常普遍, 有着ReLU所有的优点,并且不会出现dead ReLU,并且有着接近0的平均输出。但是因为表达式中有exp(),所以有一定的计算成本。
In short,小心使用ReLU,ReLU是一个很好的选择!
Maxout “Neuron”(Maxout神经元)
Maxout “Neuron”是由Goodfellow等人在2013年提出的一种很有特点的神经元,它的激活函数、计算的变量、计算方式和普通的神经元完全不同,并有两组权重。先得到两个超平面,再进行最大值计算。激活函数是Generalizes ReLU和Leaky ReLU,没有ReLU函数的缺点,不会出现神经元失活(dead),仍然是分段线性和高效率。
在使用Maxout神经元时,会有2倍的参数问题。这个方法不是很理想。
Tip:有着不同的激活函数的神经元之所以优化过程不同,不单单的与损失函数有关,还与梯度反向传播的动态过程有关,我们应动态的思考问题,才能把各类参数调整得游刃有余。