为什么 Attention 要除以 √d?
1 / √d_k 不是经验参数,而是一次数值尺度校正。它避免隐藏维度变大后,注意力分数把 Softmax 过早推入饱和区。
Transformer 的注意力通常写作:
Attention(Q, K, V) = Softmax(QKᵀ / √d_k)V
第一次看到这个式子时,很容易把 √d_k 当成论文作者加上的“小技巧”。实际上,理解它是理解训练稳定性的一条小入口:模型中很多看似细小的缩放,都是为了控制激活值、梯度或概率分布的尺度。
从点积的方差开始
先只看一个 Query 向量 q 和一个 Key 向量 k 的点积:
s = q₁k₁ + q₂k₂ + ... + q_dk_d
为了方便分析,假设每一维分量相互独立、均值为零、方差为一。每一项 qᵢkᵢ 的方差大致仍在常数尺度,那么把 d 项相加后,s 的方差会随着 d 增大。也就是说,维度从 64 提升到 256 时,点积分数的典型波动范围也会随之变大。
注意力的核心是“比较相似度”,我们并不希望仅仅因为向量维度更高,比较结果就变得更极端。除以 √d_k 后,点积的标准差重新回到相近尺度,不同 head 维度下的数值行为也更可比。
Softmax 为什么怕大数
Softmax 会把一组分数转换成概率:
pᵢ = exp(sᵢ) / Σⱼ exp(sⱼ)
指数函数对输入差异极其敏感。假如三个分数是 [1.2, 0.8, 0.5],概率会有差异但仍较平滑;若它们被放大到 [12, 8, 5],第一个位置会几乎独占全部概率。分布接近 one-hot 时,未被选中的位置梯度会非常小,模型很难继续学习更细腻的注意力模式。
这并不代表尖锐注意力一定错误。模型在某些任务中确实需要把注意力集中在极少数 token 上。问题在于:这种尖锐性应该来自数据和参数学习,而不应是隐藏维度膨胀带来的偶然数值效应。
它和 temperature 有什么区别
√d_k 和 temperature 都会改变 Softmax 前 logits 的尺度,但角色不同。
√d_k是架构层面的默认归一化,用于抵消维度变化。- temperature 是任务或采样层面的控制旋钮,用于主动调节概率分布的尖锐程度。
在语言模型生成时,较低 temperature 会让输出更确定;而注意力中的缩放,是为了让训练起点处的数值行为保持稳定。两者都作用于 Softmax,但不要混为一谈。
一个可执行的直觉实验
随机生成不同维度的 Query、Key,统计 q · k 的标准差,再统计 (q · k) / √d 的标准差。你会看到前者随维度上升,后者基本稳定。
import torch
for d in [16, 64, 256, 1024]:
q = torch.randn(10_000, d)
k = torch.randn(10_000, d)
score = (q * k).sum(dim=-1)
print(d, score.std().item(), (score / d**0.5).std().item())
这个实验不是为了证明真实网络完全符合独立同分布假设,而是建立正确的量级直觉。真实训练中,LayerNorm、参数初始化、残差连接也都在共同影响尺度。
工程上如何使用这个理解
当你遇到 attention logits 异常大、训练早期 loss 波动剧烈,或改了 hidden size 后模型难以收敛时,可以检查:
1. 注意力实现是否遗漏或重复了缩放;
2. Q/K 投影后的数值范围是否异常;
3. 是否在错误位置额外施加了 temperature;
4. 混合精度下 Softmax 前后的溢出保护是否正确。
小结
缩放点积注意力的本质很简单:点积会随维度累积,Softmax 又会放大这种累积造成的差异,因此要用 √d_k 把分数拉回稳定区间。记住这个因果链,比记住公式本身更重要。