3. 权重初始化策略:零初始化、随机初始化、Xavier初始化、He初始化

权重初始化这事儿,看着简单,其实坑特别多。我刚开始做深度学习那会儿,觉得不就是给参数赋个初值嘛,随便搞搞就行。结果呢?模型要么不收敛,要么loss直接炸掉。后来才明白——初始化策略选不对,后面再怎么调优都是白费力气。

说白了,权重初始化决定了你的网络在训练起点处的状态。起点选得好,梯度传播顺畅,收敛快;起点选得烂,梯度消失或爆炸,模型根本学不动。

核心观点:权重初始化的本质是控制前向传播和反向传播过程中,信号的方差保持稳定。不让它越传越小,也不让它越传越大。

权重初始化策略知识体系 权重初始化 零初始化 随机初始化 Xavier初始化 He初始化 所有权重=0 对称性问题 几乎不用 小随机数 方差不可控 简单但脆弱 方差=1/n_in 适合tanh/sigmoid 信号方差稳定 方差=2/n_in 适合ReLU 当前最常用 核心原则:根据激活函数选择匹配的初始化策略 目标:保持前向/反向传播的方差稳定

3.1 零初始化——最直观但最坑的方法

把所有权重设成0,听起来很合理对吧?对称初始化嘛。但实际跑起来,你会发现一个严重问题:所有神经元在每一层学到的东西完全一样。

为什么会这样?因为如果权重都是0,那么所有神经元的输入相同、梯度相同、更新量也相同。无论网络多深,每一层内的神经元都在做完全相同的计算。这就是所谓的对称性问题。

我曾经踩过的坑:刚入行时用零初始化训练一个3层全连接网络做分类,跑了100个epoch,loss纹丝不动。我还以为是学习率太小,调大之后直接炸了。后来才发现——所有神经元都在学同样的特征,模型根本没有表达能力。

零初始化唯一的适用场景是偏置项(bias)。我个人习惯把偏置初始化为0,权重则用其他策略。

3.2 随机初始化——简单但需要技巧

既然全0不行,那就随机给值呗。最朴素的做法是从一个小的正态分布或均匀分布中采样:

# 从正态分布采样
W = np.random.randn(n_in, n_out) * 0.01

# 从均匀分布采样
W = np.random.uniform(-0.01, 0.01, (n_in, n_out))

这里乘0.01是为了让初始值足够小。但问题来了——这个0.01怎么来的?为什么不是0.1或0.001?

我告诉你,这个系数其实很敏感。系数太大,深层网络的激活值会爆炸;系数太小,激活值会趋近于0。你想想看,一个100层的网络,每层乘一个0.01的系数,到最后一层信号早就消失得无影无踪了。

我的经验:随机初始化只适合浅层网络(3层以内)。一旦网络深度超过5层,建议直接上Xavier或He初始化,别在随机系数上浪费时间调参。

3.3 Xavier初始化——让信号方差稳定传播

Xavier初始化(也叫Glorot初始化)是2010年提出的。它的核心思想很简单:让每一层的输出方差等于输入方差。

数学上,它要求权重的方差满足:

Var(W) = 2 / (n_in + n_out)

# 均匀分布版本
W = np.random.uniform(-np.sqrt(6/(n_in+n_out)), np.sqrt(6/(n_in+n_out)), (n_in, n_out))

# 正态分布版本
W = np.random.randn(n_in, n_out) * np.sqrt(2/(n_in+n_out))

这个公式考虑了输入神经元数n_in和输出神经元数n_out。为什么?因为前向传播时信号从n_in个输入来,反向传播时梯度从n_out个输出回去,两边都要照顾到。

特性 Xavier初始化
适用激活函数 tanh、sigmoid、softmax
方差公式 2 / (n_in + n_out)
前向方差 保持稳定
反向方差 保持稳定
对ReLU效果 较差(信号衰减)

我记得第一次用Xavier初始化训练一个10层的tanh网络,收敛速度比随机初始化快了将近3倍。当时就觉得——嗯,数学推导出来的东西确实靠谱。

3.4 He初始化——专为ReLU设计

Xavier初始化在tanh上表现很好,但到了ReLU时代就不太行了。原因很简单:ReLU会把一半的神经元置0,实际传递的信号方差只有理论值的一半。

He初始化(也叫Kaiming初始化)就是针对这个问题提出的。它把方差调整为:

Var(W) = 2 / n_in

# 正态分布版本(最常用)
W = np.random.randn(n_in, n_out) * np.sqrt(2/n_in)

# 均匀分布版本
W = np.random.uniform(-np.sqrt(6/n_in), np.sqrt(6/n_in), (n_in, n_out))

注意看,这里只除以n_in,没有n_out。而且系数是2,不是Xavier的1。为什么?因为ReLU会丢弃一半的信号,所以需要把初始方差放大一倍来补偿。

实战建议:如果你用ReLU或它的变体(Leaky ReLU、PReLU等),直接用He初始化。这是目前最主流的做法,PyTorch和TensorFlow的默认初始化策略就是He。

3.5 四种策略对比总结

策略 方差公式 适用激活函数 深度适用性 我的推荐度
零初始化 0 无(仅偏置) ❌ 不适用 ⭐
随机初始化 手动指定 任意(需调参) 浅层(≤3层) ⭐⭐
Xavier初始化 2/(n_in+n_out) tanh、sigmoid 中等深度 ⭐⭐⭐⭐
He初始化 2/n_in ReLU及其变体 深层(50+层) ⭐⭐⭐⭐⭐

3.6 实际项目中的选择策略

说了这么多理论,到底怎么选?我直接给结论:

  • 用ReLU系列激活函数 → He初始化(无脑选这个)
  • 用tanh或sigmoid → Xavier初始化
  • 偏置项 → 零初始化
  • Batch Normalization后面 → 可以适当放宽初始化要求,但我个人习惯还是用He

一个小技巧:如果你不确定用哪个,先跑一个mini-batch看看各层激活值的分布。如果深层激活值越来越小,说明初始化方差不够大;如果越来越大甚至出现NaN,说明方差太大了。He初始化在大多数情况下都能直接work。

嗯,权重初始化就这些内容。记住一句话:初始化策略要和激活函数匹配。选对了,训练事半功倍;选错了,后面再怎么调学习率、加正则化都救不回来。