Xavier 初始化
为什么初始化重要
权重的初始值直接影响梯度的流动。两种经典问题:
- 梯度消失:权重初始化太小 → 激活值逐层缩小 → 梯度趋近于 0 → 无法学习
- 梯度爆炸:权重初始化太大 → 激活值逐层放大 → 梯度趋近于无穷 → 参数溢出
理想的初始化应当保持各层激活值和梯度的方差稳定。
Xavier (Glorot) 初始化的动机
2010 年,Glorot 和 Bengio 提出:对于使用对称激活函数(如 Tanh, Sigmoid)的网络,应在初始化时保持:
即相邻层的输出方差相等。
方差推导
假设条件
- 权重
独立同分布,均值为 0,方差为 - 输入
独立同分布,均值为 0,方差为 - 激活函数在原点附近近似线性(如 Tanh 在
时)
前向传播方差
对线性层的第
忽略偏置(通常初始化为 0),计算方差:
要维持方差稳定(
反向传播梯度方差
反向传播时对输入梯度进行类似分析,得到:
Xavier 折中方案
取两者的调和平均:
均匀分布的边界
Xavier 使用该方差的均匀分布
令方差等于
最终公式
其中:
:输入神经元数( inputDim):输出神经元数( outputDim)
代码实现
src/nn/layers/linearLayer.py:55-62:
python
rng = np.random.default_rng(randomSeed)
# limit = sqrt(6 / (n_in + n_out))
limit = np.sqrt(6.0 / (inputDim + outputDim))
# 从均匀分布采样
self.weights = rng.uniform(
low=-limit,
high=limit,
size=(inputDim, outputDim),
).astype(np.float64)每一步对应数学推导:
np.sqrt(6.0 / (inputDim + outputDim))计算rng.uniform(low=-limit, high=limit, ...)从采样 .astype(np.float64)确保双精度浮点
偏置初始化
偏置统一初始化为零:
python
self.bias = np.zeros(shape=(1, outputDim), dtype=np.float64)偏置通常初始化为 0,因为:
- 零初始值不会破坏对称性(权重已随机)
- 偏置的梯度计算不依赖偏置本身,不会阻止学习
不同初始化方法对比
| 方法 | 方差 | 适用场景 |
|---|---|---|
| Xavier 均匀 | Tanh / Sigmoid 激活 | |
| He (Kaiming) 均匀 | ReLU 激活 | |
| LeCun 均匀 | 线性 / SELU |
本项目使用 Xavier,因为默认激活函数是 Tanh。若切换到 ReLU,可以考虑 He 初始化(只考虑