如果我们在进行视觉模式识别,那么在第一层的神经元可能学会识别边,在第二层的神经元可以在边的基础上学会识别出更加复杂的形状,例如三角形或者矩形。第三层将能够识别更加复杂的形状。依此类推。这些多层的抽象看起来能够赋予深度网络一种学习解决复杂模式识别问题的能力。然后,正如线路的示例中看到的那样,存在着理论上的研究结果告诉我们深度网络在本质上比浅层网络更加强大。
消失的梯度问题
用MNIST,这个网络拥有 784 个输入层神经元,对应于输入图片的 28∗28=784 个像素点。我们设置隐藏层神经元为 30 个,输出层为 10 个神经元,对应于 MNIST 数字 (0,1,…,9)。 让我们训练 30 轮,使用 mini batch 大小为 10, 学习率 η=0.1,正规化参数 λ=5.0。【784,30,10】。分类的准确率为 96.48,当再加一层隐藏层时,分类准确度提升了一点,96.90。当再加一层时,分类准确度又下降了,96.53。
这里表现出来的现象看起非常奇怪。直觉地,额外的隐藏层应当让网络能够学到更加复杂的分类函数,然后可以在分类时表现得更好吧。假设额外的隐藏层的确能够在原理上起到作用,问题是我们的学习算法没有发现正确地权值和偏差。那么现在就要好好看看学习算法本身有哪里出了问题,并搞清楚如何改进了。
为了获得一些关于这个问题直觉上的洞察,我们可以将网络学到的东西进行可视化。下面,我画出了一部分 [784,30,30,10] 的网络,也就是包含两层各有 30 个隐藏神经元的隐藏层。图中的每个神经元有一个条形统计图,表示这个神经元在网络进行学习时改变的速度。更大的条意味着更快的速度,而小的条则表示变化缓慢。更加准确地说,这些条表示了 每个神经元上的∂C/∂b,也就是代价函数关于神经元的偏差更变的速率。回顾第二章(Chapter 2),我们看到了这个梯度的数值不仅仅是在学习过程中偏差改变的速度,而且也控制了输入到神经元权重的变量速度。如果没有回想起这些细节也不要担心:目前要记住的就是这些条表示了每个神经元权重和偏差在神经网络学习时的变化速率。
为了让图里简单,我只展示出来最上方隐藏层上的 6 个神经元。这里忽略了输入层神经元,因为他们并不包含需要学习的权重或者偏差。同样输出层神经元也忽略了,因为这里我们做的是层层之间的比较,所以比较相同数量的两层更加合理啦。在网络初始化后立即得到训练前期的结果如下:
该网络是随机初始化的,因此看到了神经元学习的速度差异其实很大。而且,我们可以发现,第二个隐藏层上的条基本上都要比第一个隐藏层上的条要大。所以,在第二个隐藏层的神经元将学习得更加快速。如果我们添加更多的隐藏层呢?如果我们有三个隐藏层,比如说在一个 [784,30,30,10] 的网络中,那么对应的学习速度就是 0.012,0.060,0.283。这里前面的隐藏层学习速度还是要低于最后的隐藏层。假设我们增加另一个包含 30 个隐藏神经元的隐藏层。那么,对应的学习速度就是:0.003,0.017,0.070,0.285。还是一样的模式:前面的层学习速度低于后面的层。
这里,第一层的学习速度和最后一层要差了两个数量级,也就是比第四层慢了100倍。难怪我们之前在训练这些网络的时候遇到了大麻烦!
现在我们已经有了一项重要的观察结果:至少在某些深度神经网络中,在我们在隐藏层 BP 的时候梯度倾向于变小。这意味着在前面的隐藏层中的神经元学习速度要慢于后面的隐藏层。这儿我们只在一个网络中发现了这个现象,其实在多数的神经网络中存在着更加根本的导致这个现象出现的原因。这个现象也被称作是消失的梯度问题(vanishing gradient problem)。
为何消失的梯度问题会出现呢?我们可以通过什么方式避免它?还有在训练深度神经网络时如何处理好这个问题?实际上,这个问题是可以避免的,尽管替代方法并不是那么有效,同样会产生问题——在前面的层中的梯度会变得非常大!这也叫做爆炸的梯度问题(exploding gradient problem),这也没比消失的梯度问题更好处理。更加一般地说,**在深度神经网络中的梯度是不稳定的,在前面的层中或会消失,或会爆炸。这种不稳定性才是深度神经网络中基于梯度学习的根本问题。
这里,w1,w2,… 是权重,而 b1,b2,… 是偏差,C 则是某个代价函数。回顾一下,从第 j 个神经元的输出 aj=σ(zj),其中 σ 是通常的 sigmoid 函数,而 zj=wj∗aj−1+bj是神经元的带权输入。我已经在最后表示出了代价函数 C 来强调代价是网络输出 a4 的函数:如果实际输出越接近目标输出,那么代价会变低;相反则会变高。
现在我们要来研究一下关联于第一个隐藏神经元梯度 ∂C/∂b1。我们将会计算出∂C/∂b1 的表达式,通过研究表达式来理解消失的梯度发生的原因。
表达式结构如下:对每个神经元有一个 σ′(zj) 项;对每个权重有一个 wj 项;还有一个 ∂C/∂a4项,表示最后的代价函数。注意,我已经将表达式中的每个项置于了对应的位置。所以网络本身就是表达式的解读。
先看看下面的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)。比如说,我们希望 z1=w1∗a0+b1。我们只要把 b1=−100∗a0 即可。我们使用同样的方法来获得其他的偏差。这样我们可以发现所有的项 wj∗σ′(zj) 都等于 100∗1/4=25。最终,我们就获得了爆炸的梯度。
不稳定的梯度问题:根本的问题其实并非是消失的梯度问题或者爆炸的梯度问题,而是在前面的层上的梯度是来自后面的层上项的乘积。当存在过多的层次时,就出现了内在本质上的不稳定场景。唯一让所有层都接近相同的学习速度的方式是所有这些项的乘积都能得到一种平衡。如果没有某种机制或者更加本质的保证来达成平衡,那网络就很容易不稳定了。简而言之,真实的问题就是神经网络受限于不稳定梯度的问题。所以,如果我们使用标准的基于梯度的学习算法,在网络中的不同层会出现按照不同学习速度学习的情况。
消失的梯度问题普遍存在:我们已经看到了在神经网络的前面的层中梯度可能会消失也可能会爆炸。实际上,在使用 sigmoid 神经元时,梯度通常会消失。为什么?再看看表达式 |wσ′(z)|。为了避免消失的梯度问题,我们需要 |wσ′(z)|>=1。你可能会认为如果 w 很大的时候很容易达成。但是这比看起来还是困难很多。原因在于,σ′(z) 项同样依赖于 w:σ′(z)=σ′(w∗a+b),其中 a 是输入的激活函数。所以我们在让 w 变大时,需要同时不让 σ′(wa+b) 变小。这将是很大的限制了。原因在于我们让 w 变大,也会使得 wa+b 变得非常大。看看 σ′ 的图,这会让我们走到 σ′ 的两翼,这里会去到很小的值。唯一避免发生这个情况的方式是,如果输入激活函数掉入相当狭窄的范围内(这个量化的解释在下面第一个问题中进行)。有时候,有可能会出现。但是一般不大会发生。所以一般情况下,会遇到消失的梯度。
##总结:
1 梯度消失和梯度爆炸的根本原因
在于前层上的梯度的计算来自于后层上梯度的乘积(链式法则)。当层数很多时,就容易出现不稳定。
如果激活函数求导后与权重相乘的积大于1,那么层数增多的时候,最终的求出的梯度更新信息将以指数形式增加,即发生梯度爆炸,如果此部分小于1,那么随着层数增多,求出的梯度更新信息将会以指数形式衰减,即发生了梯度消失。
2 sigmoid函数最容易发生梯度消失还是梯度爆炸
因为 sigmoid 导数最大为1/4,故只有当 abs(w)>4 时才可能出现梯度爆炸,而最普遍发生的是梯度消失问题。
3 如何解决梯度消失和梯度爆炸问题
常用的用于解决梯度消失和梯度爆炸的方法如下所示:
1)使用 ReLU、LReLU、ELU、maxout 等激活函数
sigmoid函数的梯度随着x的增大或减小和消失,而ReLU不会。
2)使用批规范化
通过规范化操作将输出信号x规范化到均值为0,方差为1保证网络的稳定性.从上述可看到,反向传播中有w的存在,所以w的大小影响了梯度的消失和爆炸,Batch Normalization 就是通过对每一层的输出规范为均值和方差一致的方法,消除了w带来的放大缩小的影响,进而解决梯度消失和爆炸的问题。