随着我们构建更深的神经网络,给网络权重赋予初始值这项看似简单的任务变得格外重要。不良的初始化会显著减慢训练速度,甚至完全阻碍网络学习。这是因为激活值和梯度的尺度在通过各层传播时可能呈指数级增长或收缩,分别导致梯度爆炸或梯度消失。恰当的权重初始化旨在通过设定初始权重,以维持信号传播并促进稳定的梯度流动,从而减轻这些问题。问题:激活值和梯度消失与爆炸想象一个输入信号通过多层。在每一层中,激活值是根据前一层输出的加权和计算的,然后应用激活函数。如果权重一直过小,激活值的方差将层层指数级下降,最终变得微不足道。这就是激活值消失问题。反向传播过程中计算的梯度也会消失,这意味着靠前的层的权重学习速度极慢,甚至完全不学习。相反,如果权重一直过大,激活值的方差可能指数级增长,导致数值巨大。这可能导致数值溢出问题,并在反向传播期间引发梯度爆炸问题,此时梯度变得非常大,导致更新不稳定和发散。一个简单的线性网络,经过 $L$ 层后,其输出方差大致与每层权重方差的乘积成比例。如果权重方差持续偏离1,输出方差将要么消失要么爆炸。非线性激活函数会使情况复杂化,但主要问题不变。digraph G { rankdir=LR; node [shape=box, style=filled, color="#ced4da"]; edge [color="#495057"]; subgraph cluster_poor { label = "不良初始化"; style=dashed; color="#adb5bd"; Input -> L1_poor [label=" 信号输入"]; L1_poor -> L2_poor [label=" 信号收缩/爆炸"]; L2_poor -> L3_poor [label=" 进一步收缩/爆炸"]; L3_poor -> Output_poor [label=" 接近零 / 溢出"]; } subgraph cluster_good { label = "良好初始化"; style=dashed; color="#adb5bd"; Input -> L1_good [label=" 信号输入", style=invis]; L1_good -> L2_good [label=" 稳定信号"]; L2_good -> L3_good [label=" 稳定信号"]; L3_good -> Output_good [label=" 有用信号"]; } Input [shape=ellipse, style=filled, color="#a5d8ff"]; L1_poor [label="层 1"]; L2_poor [label="层 2"]; L3_poor [label="层..."]; Output_poor [label="输出", style=filled, color="#ffc9c9"]; L1_good [label="层 1"]; L2_good [label="层 2"]; L3_good [label="层..."]; Output_good [label="输出", style=filled, color="#b2f2bb"]; }信号传播的示意图。良好的初始化有助于在网络层中保持信号方差。Xavier (Glorot) 初始化由 Glorot 和 Bengio 于 2010 年提出,Xavier 初始化旨在使激活值和梯度的方差在各层之间大致相等,前提是使用线性或对称饱和激活函数,例如 tanh 或 sigmoid。其主要思想是根据给定层的输入 ($n_{in}$) 和输出 ($n_{out}$) 单元数量来调整权重。对于均匀分布:权重从 $U[-limit, limit]$ 中采样,其中 $$limit = \sqrt{\frac{6}{n_{in} + n_{out}}}$$对于正态分布:权重从 $\mathcal{N}(0, \sigma^2)$ 中采样,其中 $$\sigma^2 = \frac{2}{n_{in} + n_{out}}$$该策略平衡了前向传播期间的信号方差和反向传播期间的梯度方差。这对于使用对称激活函数训练深度网络是一个显著的改进。He (Kaiming) 初始化尽管 Xavier 初始化适用于 tanh 和 sigmoid,但它对于修正线性单元 (ReLU) 及其变体 (Leaky ReLU, PReLU) 而言并不那么理想。ReLU 将所有负输入设为零,这与对称函数对方差统计数据的影响不同。He 初始化由 He 等人于 2015 年提出,专门考虑了 ReLU 的特性。由于 ReLU 有效地消除了约一半的激活值(负数部分),因此方差需要相应调整。He 初始化仅根据输入单元数量 ($n_{in}$) 来调整权重,以在前向传播中保持方差。对于均匀分布:权重从 $U[-limit, limit]$ 中采样,其中 $$limit = \sqrt{\frac{6}{n_{in}}}$$对于正态分布:权重从 $\mathcal{N}(0, \sigma^2)$ 中采样,其中 $$\sigma^2 = \frac{2}{n_{in}}$$这种方法有助于防止通过由 ReLU 单元组成的层时方差下降过快,使其成为主要使用 ReLU 或其变体的现代深度 CNN 的标准选择。{"layout": {"title": "初始化中的方差缩放因子", "xaxis": {"title": "输入单元数量 (n_in)", "range": [10, 1024]}, "yaxis": {"title": "标准差 (sigma)", "type": "log"}, "legend": {"title": "初始化(正态)"}, "template": "plotly_white"}, "data": [{"x": [16, 32, 64, 128, 256, 512, 1024], "y": [0.3535, 0.25, 0.1767, 0.125, 0.0883, 0.0625, 0.0441], "mode": "lines+markers", "name": "He (ReLU)", "line": {"color": "#40c057"}, "marker": {"color": "#40c057"}}, {"x": [16, 32, 64, 128, 256, 512, 1024], "y": [0.25, 0.1767, 0.125, 0.0883, 0.0625, 0.0441, 0.0312], "mode": "lines+markers", "name": "Xavier (Tanh/Sigmoid,假设 n_out=n_in)", "line": {"color": "#228be6"}, "marker": {"color": "#228be6"}}]}比较 He 和 Xavier 正态初始化中使用的标准差 ($\sigma$),其中 Xavier 假设 $n_{out} = n_{in}$。He 初始化使用更大的初始权重,以补偿 ReLU 对方差的影响。实际实施和偏置初始化大多数深度学习框架都易于使用这些初始化器。PyTorch 示例:import torch import torch.nn as nn # 使用 He 初始化对 Conv2d 层进行示例 conv_layer = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3) nn.init.kaiming_normal_(conv_layer.weight, mode='fan_in', nonlinearity='relu') # 使用 Xavier 初始化对 Linear 层进行示例 linear_layer = nn.Linear(in_features=512, out_features=256) nn.init.xavier_uniform_(linear_layer.weight) # 偏置初始化(常见做法:设为零) if conv_layer.bias is not None: nn.init.constant_(conv_layer.bias, 0) if linear_layer.bias is not None: nn.init.constant_(linear_layer.bias, 0)TensorFlow/Keras 示例:import tensorflow as tf from tensorflow.keras import layers # 使用 He 初始化对 Conv2D 层进行示例(Conv2D/Dense 层使用 ReLU 时的默认值) conv_layer = layers.Conv2D( filters=128, kernel_size=3, activation='relu', # 在 Keras 中,ReLU 默认暗示使用 HeNormal kernel_initializer=tf.keras.initializers.HeNormal(), bias_initializer='zeros' # 默认偏置初始化器 ) # 使用 Glorot (Xavier) 初始化对 Dense 层进行示例 dense_layer = layers.Dense( units=256, activation='tanh', # Tanh 激活函数通常与 Glorot 配合良好 kernel_initializer=tf.keras.initializers.GlorotUniform(), bias_initializer='zeros' )请注意 PyTorch kaiming_normal_ 中的 mode 参数(或 fan_in 与 fan_out 的选择)。fan_in 对应于标准的 He 初始化 ($n_{in}$),而 fan_out ($n_{out}$) 有时也会使用。对于 ReLU 的前向传播稳定性,通常更推荐 fan_in。Keras 通常会根据层类型和激活函数选择合适的默认初始化器。关于偏置初始化,最常见的做法是将偏置设为零。这通常是安全有效的。有时,特别是对于 ReLU 单元,建议将偏置初始化为小的正数常数(例如 0.01 或 0.1),以确保 ReLU 最初能够激活,但在恰当的权重初始化和批归一化等技术下,零初始化通常足够。总结选择恰当的权重初始化策略是成功训练深度神经网络的基本步骤。虽然简单的初始化可能适用于浅层网络,但深度架构需要 Xavier/Glorot(用于对称激活)或 He/Kaiming(用于基于 ReLU 的激活)等方法来维持信号方差并防止梯度问题。现代框架使得实施这些策略变得直接,显著提高了稳定高效训练的可能性。请记住选择与网络主要激活函数匹配的初始化器。