Layer Normalization(层归一化)是一种用于深度学习神经网络的归一化方法,它通过对神经元的输入进行归一化,使每一层的输入保持稳定,从而减缓梯度消失或梯度爆炸问题。与批量归一化(Batch Normalization)不同,LayerNorm 不依赖于 mini-batch,而是对每一个样本的每一层神经元进行归一化,这使其在序列建模、深层网络和小批量训练中表现出色。

1. Layer Normalization(层归一化)

(1) Layer Normalization 的定义

Layer Normalization 的目标是在神经网络的每一层中,对该层所有神经元的激活值进行归一化。具体来说,LayerNorm 将每一层的激活值转换为均值为 0、标准差为 1 的分布,然后对结果进行缩放和偏移。

给定神经网络中某一层的输入向量 z = ( z 1 , z 2 , … , z H ) \mathbf{z} = (z_1, z_2, \dots, z_H) z=(z1,z2,,zH),其中 H H H 是该层的神经元个数,LayerNorm 的计算公式如下:

z ^ i = z i − μ σ \hat{z}_i = \frac{z_i - \mu}{\sigma} z^i=σziμ

其中:

  • μ \mu μ 是该层所有神经元激活值的均值: μ = 1 H ∑ i = 1 H z i \mu = \frac{1}{H} \sum_{i=1}^{H} z_i μ=H1i=1Hzi
  • σ \sigma σ 是该层所有神经元激活值的标准差: σ = 1 H ∑ i = 1 H ( z i − μ ) 2 + ϵ \sigma = \sqrt{\frac{1}{H} \sum_{i=1}^{H} (z_i - \mu)^2 + \epsilon} σ=H1i=1H(ziμ)2+ϵ ,其中 ϵ \epsilon ϵ 是一个小的正数,用于防止除零错误。

经过归一化后,每个归一化后的激活值 z ^ i \hat{z}_i z^i 会进行缩放和偏移操作,以保持模型的表达能力。这个过程通过引入可学习的参数 γ \gamma γ β \beta β 来完成:
y i = γ z ^ i + β y_i = \gamma \hat{z}_i + \beta yi=γz^i+β
其中:

  • γ \gamma γ 是缩放系数,用于控制归一化后的尺度(可学习参数)。
  • β \beta β 是偏移系数,用于控制归一化后的位移(可学习参数)。

(2) Layer Normalization 的完整过程

  1. 计算每一层所有神经元激活值的均值 μ \mu μ 和标准差 σ \sigma σ
  2. 通过公式 z ^ i = z i − μ σ \hat{z}_i = \frac{z_i - \mu}{\sigma} z^i=σziμ 对每个激活值进行归一化。
  3. 通过可学习参数 γ \gamma γ β \beta β 对归一化后的激活值进行缩放和偏移:
    y i = γ z ^ i + β y_i = \gamma \hat{z}_i + \beta yi=γz^i+β
  4. 输出归一化后的激活值 y i y_i yi

LayerNorm 的作用

Layer Normalization 通过对每一层神经元的激活值进行归一化,使得激活值保持在一个稳定的范围内,防止了激活值过大或过小导致的梯度消失或梯度爆炸问题。相比 Batch Normalization,LayerNorm 更适用于小批量训练、序列建模(如 RNN)等场景,因为它不依赖于 mini-batch 的统计信息。

2. Layer Normalization 解决梯度消失问题举例

假设我们有一个三层的神经网络,每层有 3 个神经元,激活函数为 sigmoid。为了更好理解,我们给每一层起特定的名称:

  • 输入处理层:接收输入并进行初步处理。
  • 特征提取层:提取更高层次的特征。
  • 输出预测层:根据提取到的特征进行最终的预测。

由于 sigmoid 激活函数的导数在接近 0 或 1 时非常小,梯度在反向传播时容易逐层衰减,尤其在深层网络中,靠近输入处理层的梯度最容易消失

1. 使用 LayerNorm 之前的情况

1.1 前向传播

  • 输入处理层:对于输入 x = [ 1 , 2 , 3 ] x = [1, 2, 3] x=[1,2,3],假设初始权重矩阵 W 1 W_1 W1 和偏置项 b 1 b_1 b1 是随机的,得到该层的输出:
    z 处理层 = W 1 ⋅ x + b 1 = [ 4 , 5 , 6 ] z_{\text{处理层}} = W_1 \cdot x + b_1 = [4, 5, 6] z处理层=W1x+b1=[4,5,6]
    对每个神经元应用 sigmoid 激活函数:
    a 处理层 = σ ( z 处理层 ) = [ 0.98 , 0.99 , 0.997 ] a_{\text{处理层}} = \sigma(z_{\text{处理层}}) = [0.98, 0.99, 0.997] a处理层=σ(z处理层)=[0.98,0.99,0.997]
    因为 sigmoid 的输出接近 1,导数将非常小。

  • 特征提取层:使用上一层的输出作为输入,计算输出:
    z 提取层 = W 2 ⋅ a 处理层 + b 2 = [ 6.5 , 7 , 7.5 ] z_{\text{提取层}} = W_2 \cdot a_{\text{处理层}} + b_2 = [6.5, 7, 7.5] z提取层=W2a处理层+b2=[6.5,7,7.5]
    激活函数输出:
    a 提取层 = σ ( z 提取层 ) = [ 0.9985 , 0.999 , 0.9994 ] a_{\text{提取层}} = \sigma(z_{\text{提取层}}) = [0.9985, 0.999, 0.9994] a提取层=σ(z提取层)=[0.9985,0.999,0.9994]

  • 输出预测层:计算最终的输出:
    z 预测层 = W 3 ⋅ a 提取层 + b 3 = 8 z_{\text{预测层}} = W_3 \cdot a_{\text{提取层}} + b_3 = 8 z预测层=W3a提取层+b3=8
    激活函数输出:
    a 预测层 = σ ( z 预测层 ) = 0.9997 a_{\text{预测层}} = \sigma(z_{\text{预测层}}) = 0.9997 a预测层=σ(z预测层)=0.9997

1.2 反向传播中的梯度消失(正确的梯度衰减)

在反向传播时,梯度从输出层开始逐层向输入层传递,每一层的梯度会乘以该层激活函数的导数。

  • 输出预测层的梯度:由于输出层的激活值接近 1,但还没有完全达到极端值,sigmoid 的导数仍有一定的值。假设导数 σ ′ ( z 预测层 ) ≈ 0.3 \sigma'(z_{\text{预测层}}) \approx 0.3 σ(z预测层)0.3。此时梯度仍然较大。

  • 特征提取层的梯度:激活值接近 1,sigmoid 的导数非常小,假设 σ ′ ( z 提取层 ) ≈ 0.01 \sigma'(z_{\text{提取层}}) \approx 0.01 σ(z提取层)0.01。由于导数很小,梯度被极大缩减。

  • 输入处理层的梯度:激活值也非常接近 1,sigmoid 的导数非常小,假设 σ ′ ( z 处理层 ) ≈ 0.001 \sigma'(z_{\text{处理层}}) \approx 0.001 σ(z处理层)0.001。此时梯度几乎完全消失,导致靠近输入层的参数几乎无法更新。

通过这个过程,我们可以看到,梯度消失的现象主要发生在靠近输入处理层的地方,梯度在传播时逐层减小,最终导致输入层的梯度几乎为 0。

2. 使用 Layer Normalization 之后的情况

为了缓解梯度消失,我们在每一层后引入 LayerNorm,帮助每一层输入保持稳定的均值和方差,从而防止梯度过度衰减。

2.1 前向传播加入 LayerNorm

  • 输入处理层:对该层的输出进行 LayerNorm,假设归一化后均值为 0,标准差为 1:
    LayerNorm ( z 处理层 ) = z 处理层 − μ 1 σ 1 = [ − 1 , 0 , 1 ] \text{LayerNorm}(z_{\text{处理层}}) = \frac{z_{\text{处理层}} - \mu_1}{\sigma_1} = [-1, 0, 1] LayerNorm(z处理层)=σ1z处理层μ1=[1,0,1]
    然后应用 sigmoid 激活函数:
    a 处理层 = σ ( [ − 1 , 0 , 1 ] ) = [ 0.27 , 0.5 , 0.73 ] a_{\text{处理层}} = \sigma([-1, 0, 1]) = [0.27, 0.5, 0.73] a处理层=σ([1,0,1])=[0.27,0.5,0.73]
    激活值不再接近 0 或 1,避免了梯度过小的情况。

  • 特征提取层:对该层的输出进行 LayerNorm,假设归一化后均值和标准差为 0 和 1:
    LayerNorm ( z 提取层 ) = [ − 0.5 , 0 , 0.5 ] \text{LayerNorm}(z_{\text{提取层}}) = [-0.5, 0, 0.5] LayerNorm(z提取层)=[0.5,0,0.5]
    激活函数输出:
    a 提取层 = σ ( [ − 0.5 , 0 , 0.5 ] ) = [ 0.38 , 0.5 , 0.62 ] a_{\text{提取层}} = \sigma([-0.5, 0, 0.5]) = [0.38, 0.5, 0.62] a提取层=σ([0.5,0,0.5])=[0.38,0.5,0.62]

  • 输出预测层:可以类似处理,激活值将保持在合理范围内。

2.2 反向传播中的梯度优化

由于 LayerNorm 保持了每一层的输入在合理的范围内,sigmoid 的导数不会变得过小,梯度得以保持。

  • 输出预测层的梯度:激活值没有过度接近 1,梯度较大。

  • 特征提取层的梯度:导数值较大,假设 σ ′ ( z 提取层 ) ≈ 0.23 \sigma'(z_{\text{提取层}}) \approx 0.23 σ(z提取层)0.23,梯度得以有效传递。

  • 输入处理层的梯度:激活值也没有接近 0 或 1,导数值较大,假设 σ ′ ( z 处理层 ) ≈ 0.25 \sigma'(z_{\text{处理层}}) \approx 0.25 σ(z处理层)0.25,确保了梯度不会完全消失。

通过 LayerNorm 的归一化,每一层的输入值保持在合理范围内,防止了激活函数导数变得过小,避免了梯度消失现象

总结

通过上述例子,可以看到在引入 LayerNorm 之后,激活值的范围被控制在合理的区间,避免了梯度快速衰减的情况,最终有效缓解了梯度消失问题。LayerNorm 在深层神经网络中特别有效,能保证每一层的输入稳定,进而保证梯度能够有效传递到靠近输入层的地方。

更多推荐