【机器学习】反向传播与梯度消失/爆炸
【机器学习】反向传播与梯度消失/爆炸
在深度学习中,反向传播和梯度下降是优化神经网络的核心算法。然而,在实际应用中,梯度消失和梯度爆炸问题常常影响模型的训练效果。本文将深入探讨反向传播的基本原理,梯度下降的具体实现方法,以及梯度消失和梯度爆炸问题的成因和影响。
1. 反向传播
目前优化神经网络的方法都是基于反向传播的思想,即根据损失函数计算的误差通过梯度反向传播的方式,指导深度网络权值的更新优化。
这样做是有一定原因的,首先,深层网络由许多非线性层堆叠而来,每一层非线性层都可以视为是一个非线性函数f(x)(非线性来自于非线性激活函数),因此整个深度网络可以视为是一个复合的非线性多元函数:
F(x) = f_n(...f_3(f_2(f_1(x)\theta_1+b)\theta_2+b)*\theta_3+b...)
我们最终的目的是希望这个多元函数可以很好地完成输入到输出之间的映射,假设不同的输入,输出的最优解是g(x),那么,优化深度网络就是为了寻找到合适的权值,满足Loss = L(g(x), F(x))取得极小值点,比如最简单的损失函数:
Loss = ||g(x) - f(x)||^2_2
我们最优的权值就是为了寻找Loss的最小值点,对于这种数学寻找最小值问题,采用梯度下降的方法再适合不过了。
2. 梯度下降
梯度下降是一种用于优化目标函数的迭代算法,其核心目标是通过不断调整模型参数,找到使目标函数达到最小值的参数配置。它通过计算目标函数相对于参数的梯度(即偏导数),然后沿着梯度的反方向以一定的步长(称为学习率)更新参数,从而逐步接近极小值。梯度下降被广泛用于深度学习和机器学习中,用于最小化损失函数,优化模型的性能。
示例:线性回归中的梯度下降
假设我们正在训练一个简单的线性回归模型,模型的形式是:
y = w \cdot x + b
其中,w和b是模型的参数,x是输入,y是预测值。
为了衡量预测结果和真实结果之间的误差,我们引入一个损失函数,通常使用均方误差(Mean Squared Error, MSE):
Loss(w, b) = \frac{1}{n} \sum_{i=1}^{n} \left( y_i - (\hat{y_i}) \right)^2 = \frac{1}{n} \sum_{i=1}^{n} \left( y_i - (w \cdot x_i + b) \right)^2
其中,y_i是真实值,\hat{y_i} = w \cdot x_i + b是预测值,n是样本数。
我们的目标是通过梯度下降优化w和b,使损失函数最小化。
梯度计算:求偏导数
为了找到w和b的最优值,我们需要分别对损失函数关于w和b求偏导数,也就是计算损失函数相对于每个参数的梯度。
对w的偏导数是:
\frac{\partial \text{Loss}}{\partial w} = \frac{2}{n} \sum_{i=1}^{n} \left( w \cdot x_i + b - y_i \right) \cdot x_i
对b的偏导数是:
\frac{\partial \text{Loss}}{\partial b} = \frac{2}{n} \sum_{i=1}^{n} \left( w \cdot x_i + b - y_i \right)
这些偏导数告诉我们损失函数关于参数w和b的变化率,它们用于指导参数更新的方向。
参数更新:梯度下降步骤
根据梯度下降的原理,我们使用学习率η来更新参数w和b:
w = w - \eta \cdot \frac{\partial \text{Loss}}{\partial w}
b = b - \eta \cdot \frac{\partial \text{Loss}}{\partial b}
通过不断迭代上述更新步骤,我们可以逐渐找到使损失函数最小的w和b的值。
具体的梯度下降过程
假设我们有以下几个样本:
- 样本1:x_1 = 1,y_1 = 2
- 样本2:x_2 = 2,y_2 = 4
- 样本3:x_3 = 3,y_3 = 6
我们从随机初始化参数w_0 = 0和b_0 = 0开始,并设定学习率η = 0.1。
第一次迭代:
- 计算损失函数的梯度:
- 对w的偏导数:
\frac{\partial \text{Loss}}{\partial w} = \frac{2}{3} \left[ (0 \cdot 1 + 0 - 2) \cdot 1 + (0 \cdot 2 + 0 - 4) \cdot 2 + (0 \cdot 3 + 0 - 6) \cdot 3 \right] = -28
- 对b的偏导数:
\frac{\partial \text{Loss}}{\partial b} = \frac{2}{3} \left[ (0 \cdot 1 + 0 - 2) + (0 \cdot 2 + 0 - 4) + (0 \cdot 3 + 0 - 6) \right] = -12
- 更新参数:
- 更新w:
w_1 = 0 - 0.1 \times (-28) = 2.8
- 更新b:
b_1 = 0 - 0.1 \times (-12) = 1.2
第二次迭代:
- 计算新的梯度:
使用w_1 = 2.8和b_1 = 1.2,计算新的梯度:
- 对w的偏导数:
\frac{\partial \text{Loss}}{\partial w} = \frac{2}{3} \left[ (2.8 \cdot 1 + 1.2 - 2) \cdot 1 + (2.8 \cdot 2 + 1.2 - 4) \cdot 2 + (2.8 \cdot 3 + 1.2 - 6) \cdot 3 \right] = 3.6
- 对b的偏导数:
\frac{\partial \text{Loss}}{\partial b} = \frac{2}{3} \left[ (2.8 \cdot 1 + 1.2 - 2) + (2.8 \cdot 2 + 1.2 - 4) + (2.8 \cdot 3 + 1.2 - 6) \right] = 1.6
- 更新参数:
- 更新w:
w_2 = 2.8 - 0.1 \times 3.6 = 2.44
- 更新b:
b_2 = 1.2 - 0.1 \times 1.6 = 1.04
后续迭代:
通过不断迭代,梯度下降会使w和b逐渐收敛到接近于最优值(w = 2,b = 0),此时损失函数达到最小值。
对于具有复杂网络(多个隐藏层)的梯度下降
从输出层开始,逐层向前计算每一层参数对损失函数的偏导数(即梯度)。通过链式法则,损失对每一层的梯度是通过将后面层的梯度乘以前面层的导数得到的。这就是反向传播的核心。
3. 梯度消失/爆炸
梯度消失(Vanishing Gradient)
梯度消失通常发生在深度神经网络中,尤其是当网络层数较深时,梯度在通过反向传播过程中逐渐变得非常小,最终接近于零。这导致在训练过程中,模型参数的更新速度极慢,甚至根本无法有效更新。
原因
在深度网络中,梯度是通过反向传播算法逐层传递回来的。假设一个网络的每一层都具有一个激活函数(如 sigmoid 或 tanh),这些函数的导数值在某些输入范围内会非常小(例如 sigmoid 的导数最大为 0.25,且在远离 0 的地方导数接近 0)。当我们通过链式法则计算梯度时,每一层的梯度都会乘以这些导数值。
因此,如果网络有很多层,随着反向传播逐层进行,梯度的值可能会逐渐缩小到接近 0,导致早期层的梯度消失,参数更新停滞。
示例
这个例子基于一个深层神经网络中的sigmoid激活函数。我们将通过一个具体的计算,展示梯度在多层网络中如何逐渐变小,导致梯度消失的现象。
假设我们有一个简单的 3 层神经网络(输入层、隐藏层、输出层),每一层的神经元都使用 sigmoid 作为激活函数。我们用梯度下降来优化这个网络的参数。
隐藏层是位于输入层和输出层之间的神经网络层。隐藏层的主要作用是学习输入数据的特征,并通过一系列的非线性变换,将输入数据映射到更高的特征空间。
隐藏层是由多个神经元组成的,隐藏层中的每一个神经元独立处理输入,并将处理结果传递到下一层。因此,隐藏层本质上是由一组神经元构成的一个层次,每个神经元负责计算不同的特征或模式。
- 激活函数:sigmoid 函数
sigmoid 函数的定义是:
\sigma(x) = \frac{1}{1 + e^{-x}}
sigmoid 函数的导数:
\sigma'(x) = \frac{e^{-x}}{(1 + e^{-x})^2}= \sigma(x) \cdot (1 - \sigma(x))
对于大部分输入,sigmoid 函数的导数值会非常小。例如,当\sigma(x)接近 0 或 1 时,导数值接近 0;当\sigma(x) = 0.5时,导数的最大值为 0.25。
- 网络层数及权重初始化
我们假设每层有 1 个神经元,且每个神经元的初始权重为 1,偏置为 0。
- 反向传播和梯度消失
当我们在进行反向传播时,梯度会逐层向后传递,每层的梯度由链式法则计算,逐步乘上每一层的激活函数的导数。我们来看一下 3 层网络中的梯度传播:
第一步:前向传播计算输出
假设输入x_0 = 1,我们计算每一层的输出:
- 第一层:
z_1 = w_1 \cdot x_0 + b_1 = 1 \cdot 1 + 0 = 1
a_1 = \sigma(z_1) = \frac{1}{1 + e^{-1}} \approx 0.73
- 第二层:
z_2 = w_2 \cdot a_1 + b_2 = 1 \cdot 0.73 + 0 = 0.73
a_2 = \sigma(z_2) = \frac{1}{1 + e^{-0.73}} \approx 0.68
- 第三层:
z_3 = w_3 \cdot a_2 + b_3 = 1 \cdot 0.68 + 0 = 0.68
a_3 = \sigma(z_3) = \frac{1}{1 + e^{-0.68}} \approx 0.66
第二步:反向传播计算梯度
现在我们进行反向传播,逐层计算梯度。
- 输出层-第三层的激活函数导数:
\sigma'(z_3) = \sigma(z_3) \cdot (1 - \sigma(z_3)) = 0.66 \cdot (1 - 0.66) \approx 0.224
反向传播的梯度通过该层传播。
- 第二层的激活函数导数:
\sigma'(z_2) = \sigma(z_2) \cdot (1 - \sigma(z_2)) = 0.68 \cdot (1 - 0.68) \approx 0.217
再将上一层的梯度乘以这一层的激活函数导数,继续传播。
- 第一层的激活函数导数:
\sigma'(z_1) = \sigma(z_1) \cdot (1 - \sigma(z_1)) = 0.73 \cdot (1 - 0.73) \approx 0.197
最终,梯度在这一层乘上这个导数后,返回到输入层。
梯度逐步消失:
在这个过程中,梯度在每一层的传播都会被相应的导数缩小。可以看到,sigmoid 函数的导数在每一层都小于 1,且数值非常接近 0.2,这意味着梯度会被逐层缩小。对于 3 层的网络,最终的梯度为:
最终梯度 = 0.224 \times 0.217 \times 0.197 \approx 0.0096
经过 3 层网络后,梯度已经变得非常小。如果网络有更多的层(例如 10 层),梯度会迅速接近 0,使得网络前面的层几乎无法更新参数,导致网络无法有效学习。
2. 梯度爆炸(Exploding Gradient)
梯度爆炸是与梯度消失相反的问题,它通常发生在深度神经网络中,尤其是循环神经网络(RNN)中。梯度爆炸现象指的是,梯度在反向传播的过程中逐渐变得非常大,导致参数更新剧烈,使得模型无法有效训练,甚至出现参数溢出。
原因
同样在反向传播过程中,梯度会逐层传递。如果每一层的梯度导数大于 1,经过多层网络之后,梯度会指数级增长,导致最后的梯度非常大。这会导致参数更新幅度过大,使模型无法收敛。
总结
从深层网络角度来讲,不同的层学习的速度差异很大,表现为网络中靠近输出的层学习的情况很好,靠近输入的层学习的很慢,有时甚至训练了很久,前几层的权值和刚开始随机初始化的值差不多。因此,梯度消失、爆炸,其根本原因在于反向传播训练法则,属于先天不足。