1. 深层网络训练为什么难
把几十上百层 Transformer 堆起来,最头疼两件事:
- 梯度消失/爆炸:层数深了,梯度一层层乘下来,要么趋近 0(学不动),要么趋近 ∞(参数飞掉);
- 分布漂移:每一层的输入分布随前层参数变化而变(内部协变量偏移),学习率稍微不对就崩。
这两道关不过,深层模型根本训不起来。Transformer 用两样东西一起镇住它们:残差连接 + LayerNorm。
(见图 figure_10_1)
2. 残差连接的作用
残差连接的写法:输出 = Sublayer(x) 的残差 + x(具体放 LN 前后有 Pre/Post 之分,下节讲)。关键在于那条跳跃捷径:梯度回传时可以走x这条「高速公路」直接到达浅层,不必经过每一层子层连乘。
这让深层网络的梯度至少「有一条近路」,有效缓解梯度消失。没有残差,ResNet、Transformer 这类深模型都不可能训出来。
3. Layer Normalization
LN 对单个样本的所有特征维度做归一化:减均值、除标准差,再乘可学习参数 γ、加 β。它和 BatchNorm 不同——BN 跨 batch 维度,LN 跨特征维度,因此不依赖 batch 大小,序列任务里更稳。
LN 的作用是「把每一层的输出尺度拉回可控范围」,防止激活值越叠越大或越叠越小,给后续层一个稳定的输入分布。
(见图 figure_10_2)
4. Pre-LN vs Post-LN
LN 放哪有讲究:
- Post-LN(原始 Transformer):
LN(x + Sublayer(x)),归一化在残差之后; - Pre-LN(现代主流):
x + Sublayer(LN(x)),归一化在子层输入前。
Post-LN 训练更敏感,需要小心 warmup;Pre-LN 输出方差不易累积,训练更稳。今天的大模型(GPT-3、Llama、BERT 后续变体)基本都用 Pre-LN 或其改进(如 RMSNorm)。
(见图 figure_10_4)
5. 为什么两者要组合
残差和 LN 各管一摊,缺一不可:
- 没有LN:深层叠加后数值会越飘越大,激活饱和或溢出;
- 没有残差:梯度传不到浅层,深层等于摆设。
残差负责「梯度高速公路」,LN 负责「信号幅度稳定」。两者合体,才有了能堆到上百层的稳定 Transformer。
(见图 figure_10_3)
6. Java 侧启示
你做微调或私有化训练时,如果 loss 抖动剧烈、不收敛,别只怀疑学习率——先排查:
- 模型是不是 Pre-LN?LN 的 γ/β 有没有正确初始化;
- warmup 步数够不够(Pre-LN 也需要一定 warmup);
- 残差分支有没有被不小心「截断」(比如某子层输出没加回 x)。
架构细节决定训练能否收敛,看懂这节能省你无数调参时间。
/** LayerNorm 示意 */publicclassLayerNorm{publicdouble[]normalize(double[]x,double[]gamma,double[]beta,doubleeps){doublemean=0,var=0;for(doublev:x)mean+=v;mean/=x.length;for(doublev:x)var+=(v-mean)*(v-mean);var/=x.length;double[]y=newdouble[x.length];for(inti=0;i<x.length;i++)y[i]=gamma[i]*(x[i]-mean)/Math.sqrt(var+eps)+beta[i];returny;}}| 位置 | 公式 | 训练稳定性 | 代表 |
|---|---|---|---|
| Post-LN | LN(x + Sublayer(x)) | 较敏感 | 原始 Transformer |
| Pre-LN | x + Sublayer(LN(x)) | 更稳定 | GPT/BERT 后序/Llama |