原文链接地址:http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/chapter5.html
我选取了原文的部分内容进行转载。之前我搜索”梯度消失和梯度爆炸“的相关博客,发现很多都解释的不是很好,然后看到了 极客学院 的这篇介绍,感觉介绍的挺详细,转载一下,大家一起分享一下~
到现在为止,本书讲神经网络看作是疯狂的客户。几乎我们遇到的所有的网络就只包括一层隐含神经元(另外还有输入输出层):
这些简单的网络已经非常有用了:在前面的章节中,我们使用这样的网络可以进行准确率高达 98% 的手写数字的识别!而且,直觉上看,我们期望拥有更多隐含层的神经网络能够变的更加强大:
这样的网络可以使用中间层构建出多层的抽象,正如我们在布尔线路中做的那样。例如,如果我们在进行视觉模式识别,那么在第一层的神经元可能学会识别边,在第二层的神经元可以在边的基础上学会识别出更加复杂的形状,例如三角形或者矩形。第三层将能够识别更加复杂的形状。依此类推。这些多层的抽象看起来能够赋予深度网络一种学习解决复杂模式识别问题的能力。然后,正如线路的示例中看到的那样,存在着理论上的研究结果告诉我们深度网络在本质上比浅层网络更加强大。
对某些问题和网络结构,Razvan Pascanu, Guido Montúfar, and Yoshua Bengio 在2014年的这篇文章Learning deep architectures for AI 的第二部分。
那我们如何训练这样的深度神经网络呢?在本章中,我们尝试使用基于 BP 的随机梯度下降的方法来训练。但是这会产生问题,因为我们的深度神经网络并不能比浅层网络性能好太多。
这个失败的结果好像与上面的讨论相悖。这就能让我们退缩么,不,我们要深入进去试着理解使得深度网络训练困难的原因。仔细研究一下,就会发现,在深度网络中,不同的层学习的速度差异很大。尤其是,在网络中后面的层学习的情况很好的时候,先前的层次常常会在训练时停滞不变,基本上学不到东西。这种停滞并不是因为运气不好。而是,有着更加根本的原因是的学习的速度下降了,这些原因和基于梯度的学习技术相关。
当我们更加深入地理解这个问题时,发现相反的情形同样会出现:先前的层可能学习的比较好,但是后面的层却停滞不变。实际上,我们发现在深度神经网络中使用基于梯度下降的学习方法本身存在着内在不稳定性。这种不稳定性使得先前或者后面的层的学习过程阻滞。
这个的确是坏消息。但是真正理解了这些难点后,我们就能够获得高效训练深度网络的更深洞察力。而且这些发现也是下一章的准备知识,我们到时会介绍如何使用深度学习解决图像识别问题。
(消失的恋人,哦不)消失的梯度问题
那么,在我们训练深度网络时究竟哪里出了问题?
为了回答这个问题,让我们重新看看使用单一隐藏层的神经网络示例。这里我们也是用 MNIST 数字分类问题作为研究和实验的对象。
MNIST 问题和数据在(这里).
这里你也可以在自己的电脑上训练神经网络。或者就直接读下去。如果希望实际跟随这些步骤,那就需要在电脑上安装 python 2.7,numpy和代码,可以通过下面的命令复制所需要的代码
git clone https://github.com/mnielsen/neural-networks-and-deep-learning.git
如果你不使用
为了让图里简单,我只展示出来最上方隐藏层上的
这个程序给出了计算梯度的方法该表达式如何关联于小时的梯度问题的。这对理解没有影响,因为实际上上面的表达式只是前面对于<a rel="nofollow" href="http://neuralnetworksanddeeplearning.com/chap2.html#the_four_fundamental_equations_behind_backpropagation" "="" style="padding: 0px; margin: 0px; background-color: transparent; color: rgb(45, 133, 202);">BP 的讨论的特例。但是也包含了一个表达式正确的解释,所以去看看那个解释也是很有趣的(也可能更有启发性吧)。
假设我们对偏差
b1进行了微小的调整Δb1。这会导致网络中剩下的元素一系列的变化。首先会对第一个隐藏元输出产生一个Δa1的变化。这样就会导致第二个神经元的带权输入产生Δz2的变化。从第二个神经元输出随之发生Δa2的变化。以此类推,最终会对代价函数产生ΔC的变化。这里我们有:
∂C∂b1≈ΔCΔb1这表示我们可以通过仔细追踪每一步的影响来搞清楚
∂C/∂b1的表达式。 现在我们看看Δb1如何影响第一个神经元的输出a1的。我们有a1=σ(z1)=σ(w1∗a0+b1),所以有Δa1≈∂σ(w1a0+b1)∂b1Δb1=σ′(z1)Δb1
σ′(z1)这项看起很熟悉:其实是我们上面关于∂C/∂b1的表达式的第一项。直觉上看,这项将偏差的改变Δb1转化成了输出的变化Δa1。Δa1随之又影响了带权输入z2=w2∗a1+b2:Δz2≈∂z2∂a1Δa1=w2Δa1将
Δz2和Δa1的表达式组合起来,我们可以看到偏差b1中的改变如何通过网络传输影响到z2的:Δ≈σ′(z1)w2Δb1现在,又能看到类似的结果了:我们得到了在表达式
∂C/∂b1的前面两项。以此类推下去,跟踪传播改变的路径就可以完成。在每个神经元,我们都会选择一个σ′(zj)的项,然后在每个权重我们选择出一个wj项。最终的结果就是代价函数中变化ΔC的相关于偏差Δb1的表达式:
ΔC≈σ′(z1)w2σ′(z2)...σ′(z4)∂C∂a4Δb1除以
Δb1,我们的确得到了梯度的表达式:
∂C/∂b1=σ′(z1)w2σ′(z2)...σ′(z4)∂C∂a4为何出现梯度消失:现在把梯度的整个表达式写下来:
∂C/∂b1=σ′(z1)w2σ′(z2)w3σ′(z3)σ′(z4)∂C∂a4除了最后一项,该表达式是一系列形如
wjσ′(zj)的乘积。为了理解每个项的行为,先看看下面的sigmoid 函数导数的图像:
该导数在
σ′(0)=1/4时达到最高。现在,如果我们使用标准方法来初始化网络中的权重,那么会使用一个均值为0标准差为1的高斯分布。因此所有的权重通常会满足|wj|<1。有了这些信息,我们发现会有wjσ′(zj)<1/4。并且在我们进行了所有这些项的乘积时,最终结果肯定会指数级下降:项越多,乘积的下降的越快。**这里我们敏锐地嗅到了消失的梯度问题的合理解释。更明白一点,我们比较一下
∂C/∂b1和一个更后面一些的偏差的梯度,不妨设为∂C/∂b3。当然,我们还没有显式地给出这个表达式,但是计算的方式是一样的。
两个表示式有很多相同的项。但是
∂C/∂b1还多包含了两个项。由于这些项都是<1/4的。所以∂C/∂b1会是∂C/∂b3的 1/16 或者更小。 这其实就是消失的梯度出现的本质原因了。 当然,这里并非严格的关于消失的梯度微调的证明而是一个不太正式的论断。还有一些可能的产生原因了。特别地,我们想要知道权重wj在训练中是否会增长。如果会,项wjσ′(zj)会不会不在满足之前wjσ′(zj)<1/4的约束。事实上,如果项变得很大——超过 1,那么我们将不再遇到消失的梯度问题。实际上,这时候梯度会在我们 BP 的时候发生指数级地增长。也就是说,我们遇到了 梯度爆炸的问题。 梯度爆炸问题:现在看看梯度爆炸如何出现的把。这里的例子可能不是那么自然:固定网络中的参数,来确保产生爆炸的梯度。但是即使是不自然,也是包含了确定会产生爆炸梯度(而非假设的可能)的特质的。共两个步骤:首先,我们将网络的权重设置得很大,比如
w1=w2=w3=w4=100。然后,我们选择偏差使得σ′(zj)项不会太小。这是很容易实现的:方法就是选择偏差来保证每个神经元的带权输入是zj=0(这样sigma′(zj)=1/4)。比如说,我们希望 $$z_1 = w_1 a_0 + b_1。我们只要把b_1 = -100 a_0即可。我们使用同样的方法来获得其他的偏差。这样我们可以发现所有的项w_j \sigma'(z_j)都等于1001/4 = 25$$。最终,我们就获得了爆炸的梯度。不稳定的梯度问题:根本的问题其实并非是消失的梯度问题或者爆炸的梯度问题,而是在前面的层上的梯度是来自后面的层上项的乘积。当存在过多的层次时,就出现了内在本质上的不稳定场景。唯一让所有层都接近相同的学习速度的方式是所有这些项的乘积都能得到一种平衡。如果没有某种机制或者更加本质的保证来达成平衡,那网络就很容易不稳定了。简而言之,真实的问题就是神经网络受限于不稳定梯度的问题。所以,如果我们使用标准的基于梯度的学习算法,在网络中的不同层会出现按照不同学习速度学习的情况。
练习
- 在我们对于消失的梯度问题讨论中,使用了
|σ′(z)<1/4|这个结论。假设我们使用一个不同的激活函数,其导数值是非常大的。这会帮助我们避免不稳定梯度的问题么?消失的梯度问题普遍存在:我们已经看到了在神经网络的前面的层中梯度可能会消失也可能会爆炸。实际上,在使用 sigmoid 神经元时,梯度通常会消失。为什么?再看看表达式
|wσ′(z)|。为了避免消失的梯度问题,我们需要|wσ′(z)|>=1。你可能会认为如果w很大的时候很容易达成。但是这比看起来还是困难很多。原因在于,σ′(z)项同样依赖于w:σ′(z)=σ′(w∗a+b),其中a是输入的激活函数。所以我们在让w变大时,需要同时不让σ′(wa+b)变小。这将是很大的限制了。原因在于我们让w变大,也会使得wa+b变得非常大。看看σ′的图,这会让我们走到σ′的两翼,这里会去到很小的值。唯一避免发生这个情况的方式是,如果输入激活函数掉入相当狭窄的范围内(这个量化的解释在下面第一个问题中进行)。有时候,有可能会出现。但是一般不大会发生。所以一般情况下,会遇到消失的梯度。问题
- 考虑乘积
|wσ′(wa+b)|。假设有|wσ′(wa+b)|>=1。
- 这种情况只有在
|w|>=4的时候才会出现。- 假设
|w|>=4,考虑那些满足|wσ′(wa+b)|>=1的输入激活a集合。证明:满足上述条件的该集合能够充满一个不超过2|w|ln(|w|(1+1−4/|w|−−−−−−−−√)2−1)宽度的区间。- 数值上说明上述表达式在
|w| =6.9时候去的最高值约0.45。所以即使每个条件都满足,我们仍然有一个狭窄的输入激活区间,这样来避免消失的梯度问题。- 幺神经元:考虑一个单一输入的神经元,
x,对应的权重w1,偏差b,输出上的权重w2。证明,通过合理选择权重和偏差,我们可以确保 $$w_2 \sigma(w_1x +b)~=x其中x \in [0, 1]。这样的神经元可用来作为幺元试用,输出和输入相同(成比例)。提示:可以重写x = 1/2 + \Delta,可以假设w_1很小,和在w_1 \Delta$$使用 Taylor 级数展开。在更加复杂网络中的不稳定梯度
现在已经研究了简单的网络,每一层只包含一个神经元。那么那些每层包含很多神经元的更加复杂的深度网络呢?
实际上,在这样的神经网络中,同样的情况也会发生。在前面关于 BP 的章节中,我们看到了在一个共
L层的第l层的梯度:
δl=Σ′(zl)∗(wl+1)TΣ′(zl+1)(wl+2)T...Σ′(zL)∇aC这里
Σ′(zl)是一个对角矩阵,每个元素是对第l层的带权输入σ′(z)。而wl是对不同层的权值矩阵。∇aC是对每个输出激活的偏导数向量。这是更加复杂的表达式。不过,你仔细看,本质上的形式还是很相似的。主要是包含了更多的形如
(wj)TΣ′(zj)的对 (pair)。而且,矩阵Σ′(zj)在对角线上的值挺小,不会超过1/4。由于权值矩阵wj不是太大,每个额外的项(wj)Tσ′(zl)会让梯度向量更小,导致梯度消失。更加一般地看,在乘积中大量的项会导致不稳定的梯度,和前面的例子一样。实践中,一般会发现在 sigmoid 网络中前面的层的梯度指数级地消失。所以在这些层上的学习速度就会变得很慢了。这种减速不是偶然现象:也是我们采用的训练的方法决定的。深度学习其他的障碍
本章我们已经聚焦在消失的梯度上,并且更加一般地,不稳定梯度——深度学习的一大障碍。实际上,不稳定梯度仅仅是深度学习的众多障碍之一,尽管这一点是相当根本的。当前的研究集中在更好地理解在训练深度神经网络时遇到的挑战。这里我不会给出一个详尽的总结,仅仅想要给出一些论文,告诉你人们正在寻觅探究的问题。
首先,在
2010年 Glorot 和 Bengio 发现证据表明 sigmoid 函数的选择会导致训练网络的问题。特别地,他们发现 sigmoid 函数会导致最终层上的激活函数在训练中会聚集在0,这也导致了学习的缓慢。他们的工作中提出了一些取代 sigmoid 函数的激活函数选择,使得不会被这种聚集性影响性能。第二个例子,在
2013年 Sutskever, Martens, Dahl 和 Hinton 研究了深度学习使用随机权重初始化和基于momentum的SGD方法。两种情形下,好的选择可以获得较大的差异的训练效果。 这些例子告诉我们,“什么让训练深度网络非常困难”这个问题相当复杂。本章,我们已经集中于深度神经网络中基于梯度的学习方法的不稳定性。结果表明了激活函数的选择,权重的初始化,甚至是学习算法的实现方式也扮演了重要的角色。当然,网络结构和其他超参数本身也是很重要的。因此,太多因子影响了训练神经网络的难度,理解所有这些因子仍然是当前研究的重点。尽管这看起来有点悲观,但是在下一章中我们会介绍一些好的消息,给出一些方法来一定程度上解决和迂回所有这些困难。