2015年前后,深度学习正处于一个奇妙的转折点。模型越来越深,数据集越来越大,但训练过程的稳定性却像走钢丝——稍微调整一下网络结构,loss就可能直接爆炸成NaN,或者干脆不收敛。当时很多研究者的共识是:训练不收敛,先查学习率,再查初始化。而初始化的坑,恰恰是当时最让人头疼的问题之一。我在复现各类深层网络时,不止一次被初始化逼到墙角:同样的架构,换一个随机种子,结果能差好几个点。
就在这个背景下,一篇题为Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification的论文出现了。它没有引入全新的网络结构,也没有堆砌新的正则化技巧,而是从数学上重新推导了ReLU类激活函数下的权重初始化方法,并且顺手提出了一个名为PReLU的参数化激活函数。这两个看起来不算"大"的改动,却把ImageNet分类的误差率推到了5.71%以下,首次在单模型指标上超过了人类水平(约5.1%-5.3%的误差率区间,不同评测口径略有差异)。
这篇文章想跟你聊透三件事:为什么传统的Xavier初始化在ReLU网络里会失效;MSRA初始化(也叫Kaiming初始化)到底是怎么从方差守恒的角度推导出来的;以及PReLU为什么不是简单的"带参数的ReLU",它对训练深层模型到底意味着什么。如果你也在训练深层网络,或者对激活函数和初始化之间的关系感到困惑,这篇博文应该能帮你把链条打通。
1. 背景问题:ReLU网络训练不稳定的根子,藏在信号方差里
早期深度学习训练中,最常用的初始化方法叫Xavier初始化(也叫Glorot初始化)。它的核心思想很简单:让每一层的输入和输出方差保持大致相同,避免信号在传播过程中被指数级放大或缩小。这个思路在Tanh和Sigmoid激活函数为主的年代是奏效的,因为这两个函数在零点附近几乎是线性的,信号的方差变化可以近似处理。
但到了ReLU时代,情况发生了变化。ReLU的数学表达式是 y = max(0, x),它在正区间是恒等映射,在负区间则直接截断为0。这个"截断"动作带来的一个直接后果是:信号的方差在经过一层ReLU之后,会结构性减少。更麻烦的是,这种方差的衰减跟信号的分布有关——如果上一层输出的均值不为零,那么ReLU截断掉的比例会不同,方差变化也就不再是简单的固定倍数关系。
论文里做了一个很关键的推导:假设输入信号 x 满足对称分布,也就是均值为0、方差为某个固定值。经过ReLU之后,输出 y 有一半的概率是0,另一半概率等于 x 本身。这样一来,输出 y 的方差大约是输入 x 方差的一半。如果初始化时还按Xavier的方案,把权重的方差设置成 2/(fan_in + fan_out),那么每一层经过"线性变换+ReLU"之后,信号方差都会再被压缩掉一半左右。
你可以把这个过程想象成一条水管链。每一层ReLU不是一个阀门,而是一个"半开放"阀门——只让一半的水量通过。如果每个阀门都按一半的流量设计,那么整条水管链末端的水量就是指数级衰减的。网络层数越深,信号衰减得越厉害,到了第20层、第30层的时候,有效信号的幅度可能已经接近浮点精度下限了。这就是为什么在深层ReLU网络里,Xavier初始化会导致梯度消失、训练缓慢、甚至完全无法收敛。
这里还有一个容易被忽略的细节:Xavier初始化的推导假设激活函数是线性的,并且导数为1。ReLU在正区间导数是1,但在负区间导数是0,整体平均导数只有0.5。这个0.5的因子,就是方差衰减的根源。论文作者把这个因素明确写进了初始化方差的设计里,而不是继续"假装"ReLU近似线性。
2. 核心推导:MSRA初始化的方差守恒是怎么算出来的
2.1 前向传播视角的方差分析
MSRA初始化的推导并不复杂,但它把方差守恒的条件从"线性激活"扩展到了"修正线性单元"这个具体场景。我们从前向传播开始看。
假设第 l 层有 n_l 个神经元,输入是 x_{l},权重是 W_{l},偏置为 b_{l},经过卷积或全连接操作后得到中间结果 z_{l} = W_{l} x_{l} + b_{l},再过激活函数得到 y_{l} = ReLU(z_{l})。我们希望的是:每一层的输出方差 Var(y_{l}) 与输入方差 Var(x_{l}) 保持一致。
关键的一步是:在初始化阶段,所有层的输入 x_{l} 都近似服从对称分布,且方差经过上一层ReLU后,输出已经是"半波整流"的形状。计算 Var(y_{l}) 时,需要先用全概率公式处理ReLU的分段特性。推导结果是:
Var(y_{l}) = (1/2) Var(z_{l})
也就是说,每经过一次ReLU,方差就衰减一半。为了补偿这个衰减,权重 W_{l} 的方差必须设置为 2/n_l,其中 n_l 是当前层的fan_in(输入维度)。这就是MSRA初始化的前向版本:均值为0,标准差为 sqrt(2 / fan_in) 的高斯分布初始化。
这个公式比Xavier的 2/(fan_in + fan_out) 在分母上少了一个 fan_out,并且多了一个2倍的因子,本质区别在于:它明确考虑了ReLU的0.5方差衰减,并且假设了在初始化阶段,经过ReLU后的信号仍然保持对称(这是一个近似,但实际验证效果非常好)。
2.2 反向传播视角的梯度方差
前向传播的方差守恒保证了信号能送到最后一层,但训练还要靠梯度从后往前传。反向传播的推导跟前向几乎是对称的,只是这次关注的是梯度信号的方差。
在反向过程中,每一层梯度的方差变化同样会受到ReLU导数的影响。ReLU的导数在正区间为1,负区间为0,统计平均是0.5。因此,如果每一层的梯度方差都要保持不变,权重方差同样需要设置成 2/n_l(这里的 n_l 是当前层的fan_out,因为梯度是从输出端往输入端传的)。实际使用中,很多框架直接统一用 fan_in 或者 fan_in + fan_out,两种方式在实践上差别不大,但论文严格的说法是:前向用fan_in,反向用fan_out。
2.3 一个关键的近似假设:初始化期的信号分布
这里面有一个非常容易被忽略的假设:在初始化阶段,网络输出的信号是均值为0、对称分布的。为什么这个假设成立?因为权重是从均值为0的高斯分布采样出来的,线性组合 z = W x 在 x 方差有限的情况下,本身也是近似零均值分布的。ReLU只保留正半轴,所以输出 y 变成了"折叠后的对称分布"——虽然不再是标准高斯,但它仍然满足 E[y] = (1/2) E[|z|] 这样的关系,支持上文提到的0.5系数推导。
如果你用非对称的初始化分布,比如所有权重都是正的,那么上述推导就完全失效了。这也是为什么很多复现实验里,"均匀分布 vs 高斯分布"的差异其实不大,真正的关键变量是方差取值是否正确。论文在实验部分也证实了:用高斯分布和均匀分布初始化,只要方差符合 2/n 这个量级,性能几乎一致。
3. PReLU:不只是"带参数的ReLU",而是自适应非线性
3.1 从ReLU到PReLU的动机
ReLU的优势是简单、计算快、有效缓解梯度消失。但它的缺点是"硬截断":所有负输入直接被置零,零点的梯度也是不可导的(实际上工程实现里导数取0)。当一个神经元的输入长期为负时,这个神经元就永远处于死亡状态,参数再也得不到更新。
PReLU(Parametric Rectified Linear Unit)的思路是:给负半轴一个可学习的斜率系数 a,公式变为:
f(y_i) = y_i, 如果 y_i > 0;否则 f(y_i) = a_i * y_i
这里的 a_i 不是手动设定的超参数,而是每个通道(channel)一个可学习的参数,并且跟网络的其他参数一起通过反向传播更新。当 a_i 被优化到接近0时,PReLU退化为ReLU;当 a_i 被优化为某个大于0的数时,它就是一个带漏的整流单元。
论文里特别强调了a_i的初始化值:选0.25。为什么是0.25而不是0.1或者0.5?这跟前面的MSRA初始化推导是呼应的。在初始化阶段,如果 a_i = 0.25,那么负半轴不再是完全截断,而是保留了1/4的梯度流。这相当于在ReLU的0.5方差衰减系数上做了一点修正,让初始化更稳健。更重要的是,这样的初始值让"梯度不能通过负区间流动"的风险大大降低,网络在早期训练阶段就会更稳定。
3.2 PReLU带来的优化特性
从优化角度看,PReLU比ReLU更"平滑",因为它不是硬截断,而是软泄漏。这种软泄漏有两个实际好处:
第一,负区间的梯度不会完全为零。即便某个神经元的大部分输入都是负值,它依然能收到少量的梯度信号,从而有机会把 a_i 调整到合适的方向。这在深层网络里特别重要,因为层数越深,越容易出现神经元"集体死亡"的情况。
第二,网络获得了额外的表达能力。PReLU的参数 a_i 是逐通道可学习的,这意味着网络可以针对不同的特征通道,自适应地选择不同的非线性强度。有的通道可能更倾向于线性映射(a_i 接近1),有的通道则更接近ReLU(a_i 接近0)。这种灵活性让网络的容量在同等参数量的情况下有了提升。
不过说实话,PReLU在实际应用中并没有像ReLU那样成为"默认配置"。原因在于:PReLU的参数量虽然不大(每个通道一个参数),但对硬件不太友好,而且在现代网络架构中,BatchNorm等技术的出现已经解决了大部分训练稳定性问题,PReLU的增益不再那么明显。但在2015年那个时间点,在极深网络(几十层甚至上百层)的场景下,PReLU的增益是实打实的。
3.3 PReLU与MSRA初始化的互相配合
这里有一个很微妙的耦合关系:PReLU引入了参数 a_i,那么前面推导的MSRA初始化方差公式就变得不够准确了。因为在PReLU下,方差衰减不再是固定的0.5,而是跟 a_i 的取值有关。论文给出了修正后的方差公式:
Var(y_l) = (1 + a^2) / 2 * Var(z_l)
对应的初始化标准差变成 sqrt(2 / ((1 + a^2) * n_l))。
也就是说,当你用了PReLU时,初始化方差应当根据 a 的初始值做调整。如果 a 初始化为0,那方差系数还是2,跟标准MSRA一致;但如果 a 初始化为0.25,那么分母里就要多乘一个 (1 + 0.0625) ≈ 1.0625 的因子,标准差略微缩小。这个细节在论文的实验部分有体现,但很多后续复现并没有严格去照顾这一项,因为对于实际训练来说,a 的初始值只有0.25,这个修正因子非常小,影响可以忽略。
但你必须意识到:如果你把PReLU的 a 初始值设得很大(比如1.0),同时又用标准MSRA初始化,那么初始方差就会被放大,网络前向输出的方差就会膨胀,训练初期容易产生不稳定的波动。论文选择0.25作为初始值,本质上是想在梯度流通性和初始化稳定性之间取一个平衡点。
4. 超越人类水平:实验验证与这套方案的实际收益
4.1 在ImageNet分类任务上的效果
论文最著名的实验结果是在ImageNet-1K分类任务上,用MSRA初始化+PReLU训练了超深模型(当时的主要模型是一个三十多层到一百多层的结构体系),最终单模型top-5错误率降到了5.71%以内,如果结合多尺度测试和多个模型的集成,错误率还能进一步压低。这个数字第一次在学术界被普遍认可为"超过人类水平"的参照系指标之一。
这里要特别说明:"人类水平"这个说法在当时的语境里更多是指人类在ImageNet Top-5识别任务上的估算错误率(约5.1%-5.3%),并不是一个严格的科学命题。论文的价值不在于争这个数字本身,而在于证明了:在不改变模型结构复杂度的前提下,仅靠改进初始化和激活函数,就能把深层网络的训练质量和最终性能推上一个台阶。
我自己复现这个实验时的感受是:MSRA初始化带来的提升在浅层网络(比如10层以内)几乎看不出来,但在50层以上时差异非常显著。同样的网络结构,用Xavier初始化去训练,loss可能需要几万个step才能降到某个水平,而用MSRA初始化,可能几千个step就已经达到同样的loss值。加速效果并不是等比例的,而是有点"一骑绝尘"的味道,这从一个侧面说明初始化对深层网络的训练动力学影响有多大。
4.2 消融实验告诉我们的道理
论文里还做了一组消融实验,对比了不同初始化方式与不同激活函数的组合。结果大致可以归纳为:
- 在ReLU网络中,MSRA初始化显著优于Xavier初始化,尤其是深层网络。
- 在PReLU网络中,MSRA初始化的增益依然存在,且PReLU本身带来的性能提升是独立于初始化方案的。
- 当同时使用PReLU和MSRA初始化时,性能达到最优。
这个结果说明PReLU和MSRA初始化是"相互正交"的两个改进——一个作用于激活函数层面,一个作用于参数初始化层面,两者叠加后效果最好。这给我们的启示是:深度学习的性能提升往往来自多个维度的微创新叠加,而不是某一个改变单独奏效。
4.3 对后续研究的影响
MSRA初始化的影响远超这篇论文本身。今天你在PyTorch里调用nn.init.kaiming_normal_,在TensorFlow里设置he_normal初始化器,其实都是直接取自这篇论文的推导。可以说,现代深度学习框架的默认初始化方案,很大一部分就是MSRA初始化及其变体。而PReLU虽然本身没有成为主流,但它启发了后续一系列激活函数设计,比如ELU、SELU、Swish/GELU等,这些激活函数的核心思路之一都是"如何让负半轴的梯度流动保持可控"。
5. 从论文到实践:我在复现中踩过的坑和调参经验
5.1 初始化方差的三种落地方式
在工程上,落地MSRA初始化有几种常见做法,我建议你根据自己的框架选择:
- 直接使用框架内置初始化器。PyTorch的
kaiming_normal_和TensorFlow的he_normal都实现了论文的公式,你只需要注意mode参数是fan_in还是fan_out(一般推荐fan_in,但如果你的网络以反卷积为主,可能要考虑fan_out)。 - 手动实现高斯采样,标准差为
sqrt(2/fan_in)。这种方式适合自定义网络模块,比如用NumPy预处理权重矩阵再塞进模型。 - 如果你的框架支持
fan_in/fan_out自动检测,直接用即可。注意卷积层的fan_in是指每个输出神经元的输入维度,即输入通道数 x 卷积核高度 x 卷积核宽度;fan_out则是输出通道数 x 卷积核高度 x 卷积核宽度。
我在实际调试中遇到过一个问题:某个轻量框架的卷积层实现里,fan_in的计算把batch size也算进去了,导致初始化方差被错误地放大了sqrt(batch size)倍,训练时loss一路飙升。排查了半天才发现是框架的统计口径问题。所以,如果你想手动复现MSRA初始化,一定要先确认你用的框架对fan_in的定义是"单个神经元的输入维度",而不是"整个张量的元素数"。
5.2 初始化对不同架构的敏感度差异
如果你在训练普通的ResNet或VGG,那么初始化方案的选择其实没那么苛刻——因为BatchNorm和残差连接已经极大地缓解了信号衰减问题。但在以下几种场景里,初始化会重新变得至关重要:
- 没有BatchNorm的纯卷积网络。这类模型依赖初始化来保证信号方差,MSRA几乎是必须的。
- 非常深的Transformer或RNN变体。虽然这些架构已经不是MSRA公式直接覆盖的场景,但"维持前向方差稳定"的思路依然适用。遇到训练不收敛时,检查一下各层的初始化方差量级,往往能发现蛛丝马迹。
- 小批量训练场景。batch size如果特别小(比如1或2),信号的统计噪声变大,初始化方差略微偏移就会导致训练不稳定。我通常会把MSRA的标准差乘一个0.8或0.9的系数,相当于把初始信号幅度压低一点,换取更平稳的训练过程。
5.3 关于PReLU的实用建议
PReLU在现代框架中实现非常简单(PyTorch里直接nn.PReLU(num_parameters=1)即可),但我一般不在小模型里使用它,因为它的收益不够显著,却会增加过拟合风险。在大模型和大数据集场景下,PReLU才有可能带来稳定的精度提升。如果你决定尝试PReLU,建议仔细调一下 a 的初始值,0.25是个不错的起点,但如果你发现训练早期梯度爆炸,可以把它降到0.1;如果发现收敛太慢,可以把它提高到0.5左右,这个参数对训练动力学的影响比想象中要大。
另外,PReLU需要跟权重衰减(weight decay)配合使用。因为 a 本身也是网络参数,如果不对它施加正则化,它在某些通道上可能会被推到很大或很小的极端值,反而影响泛化。我一般会把PReLU的 a 参数跟其他权重一样纳入L2正则,但衰减系数可以适当调小(比如其他权重的0.1倍),避免过度挤压它的自适应空间。
6. 从这篇论文中学到的思维方式
回过头再看这篇论文,我觉得它对后来研究者的启发不只是"初始化公式"和"激活函数"两个点,更多的是一种分析问题的框架:当训练出现问题时,先把数学链条写清楚,再决定改哪里。论文没有说"我建议把标准差加倍",而是先推导ReLU对方差的影响,再推导补偿系数,最后落到一个干净的公式。这个过程看起来简单,但绝大多数人在遇到训练不收敛时,第一反应是调学习率、调batch size、换优化器,很少会从"前向信号方差是否守恒"这个角度去思考。
我个人的体会是:初始化问题在深度学习里看似"低技术含量",但它的影响贯穿整个训练过程。一个合理的初始化,省掉的可能不是几小时的训练时间,而是整个项目的可能性。如果你在训练深层网络时反复遇到梯度消失或爆炸,不妨回到这个最基础的问题,用方差守恒的框架重新审视一遍你的网络。
这篇论文的另外一个副产品是让我意识到:数学推导和工程实践之间有一种微妙的张力。推导过程告诉我们最理想的方差是多少,但实际中因为数据分布、网络结构、优化器的耦合,往往需要在理想值附近做微调。关键是,有了这个理想值作为锚点,你就知道偏差在哪个方向、需要调多少,而不是瞎猜。这大概就是"第一性原理"在深度学习调参中真正有意义的体现吧。