数学基础:标准化公式与缩放平移参数
好,咱们进入正题。LayerNorm 的核心,说白了就是两件事:标准化和仿射变换。很多同学一开始就被公式吓住了,其实拆开看,每个部分都很简单。
我记得刚接触 LayerNorm 那会儿,第一反应是「这不就是中学学的标准化吗?」。嗯,本质上确实如此,只不过我们把它搬到了神经网络里,还加了两个可学习的参数。
标准化公式
先看标准化的数学表达。对于一个输入向量 x = [x₁, x₂, ..., xₙ],LayerNorm 的第一步是计算均值和方差:
μ = (1/n) * Σᵢ xᵢ
σ² = (1/n) * Σᵢ (xᵢ - μ)²
然后对每个元素做标准化:
x̂ᵢ = (xᵢ - μ) / √(σ² + ε)
这里有个小细节——ε 是个很小的常数,比如 1e-5。为什么要加它?
我曾经在训练一个深层 Transformer 时,因为忘记加这个 epsilon,结果梯度直接爆炸了。你想想看,如果方差恰好为 0,分母就是 0,整个训练就崩了。所以这个 epsilon 虽然小,但它是保命用的。
缩放与平移参数
标准化之后,数据被拉到了均值为 0、方差为 1 的分布。但问题来了——神经网络有时候需要保留原始的分布特征,或者学习一个新的分布。这时候就需要 仿射变换。
LayerNorm 引入了两个可学习参数:
- γ(gamma):缩放参数,控制输出的方差
- β(beta):平移参数,控制输出的均值
最终输出为:
yᵢ = γ * x̂ᵢ + β
说白了,就是先标准化,再「反标准化」——只不过这个反标准化的参数是网络自己学出来的。我习惯把 γ 和 β 理解成「可调节的均值和方差」。网络可以根据任务需要,决定要不要恢复原来的分布。
关键点:γ 和 β 的维度与输入 x 的最后一维相同。比如输入形状是 [batch_size, seq_len, hidden_dim],那么 γ 和 β 的形状就是 [hidden_dim]。
为什么需要这两个参数?
你可能会问:既然标准化已经让数据分布统一了,为什么还要加 γ 和 β?
嗯,这个问题我当初也困惑过。后来在实践中才明白:标准化虽然稳定了训练,但也可能限制了模型的表达能力。比如某些任务中,原始数据的方差本身就携带了重要信息,强行归一化反而会丢失这些信息。
举个例子。我在做语音识别时,不同说话人的音量差异很大。如果 LayerNorm 没有 γ 和 β,模型就很难区分「大声说话」和「小声说话」——因为标准化后它们都变成了均值为 0 的分布。有了可学习的参数,模型就能根据上下文决定要不要保留这种差异。
实际使用中的小技巧
这里分享几个我踩过的坑:
- 初始化问题:γ 通常初始化为 1,β 初始化为 0。这样一开始相当于不做仿射变换,让网络慢慢学。
- 梯度流动:标准化操作会引入全局依赖——每个元素的梯度都依赖于所有元素。这意味着反向传播时,梯度计算会稍微复杂一些。不过别担心,下一章我会详细推导。
- 数值稳定性:计算方差时,建议用
torch.var(x, unbiased=False),也就是有偏估计。因为 LayerNorm 是对整个特征维度做标准化,不需要贝塞尔校正。
我的习惯:在实现 LayerNorm 时,我会把 epsilon 加到方差里再开根号,而不是先开根号再加。即 torch.rsqrt(var + eps)。这样数值更稳定,梯度也不会出现奇怪的问题。
公式总结
最后,把整个 LayerNorm 的前向过程整理成一张表:
| 步骤 | 公式 | 说明 |
|---|---|---|
| 计算均值 | μ = (1/n) Σ xᵢ | 沿特征维度求平均 |
| 计算方差 | σ² = (1/n) Σ (xᵢ - μ)² | 同样沿特征维度 |
| 标准化 | x̂ᵢ = (xᵢ - μ) / √(σ² + ε) | 得到零均值单位方差 |
| 仿射变换 | yᵢ = γ * x̂ᵢ + β | 可学习的缩放和平移 |
好了,这一章的内容就到这里。标准化公式和缩放平移参数是 LayerNorm 的基石,理解透了,后面的反向传播推导就会轻松很多。下一章我们正式进入梯度计算,我会手把手带你推一遍。