分数怎么变成「关注多少」的权重?
本课一问:分数怎么变成「关注多少」的权重?
这一课先不碰:谁能看谁(第 4 课);权重拿去乘什么(第 5 课)。
从已有出发
上一课得到的是一行分数:「给了」对 5 个 token 各有一个 q·k。我们想要的是一组权重:都不小于 0、加起来正好 100%,这样才能拿去对 token 们的信息做加权平均。从「分数」到「权重」,要一个转换。
先自己设计:按分数占比分
最直接的:第 j 个 token 分到 sj ÷ Σs。分数高的多拿,分数低的少拿。
- ① 朴素方案
- ② 它在哪失败
- ③ 改进方案
改进第一轮:softmax
softmax 先把每个分数变成 es,再除以总和:wj = esj ÷ Σk esk。它一次解决了上面所有问题 证据等级 · 数学可证明 在写明的前提下可以严格推导出来,不依赖实验。只要前提成立,换数据、换规模仍然成立。 本条e^x 恒为正;除以总和后和为 1;分子分母同乘 e^c 后不变;w_a/w_b = e^(s_a − s_b) 出处待补 :
- 永远为正:es 对任何实数都大于 0,负分也只是分得少。
- 和恰为 1:除以总和。
- 只看分差:整行加一个常数 c,每一项都乘 ec,相除后抵消。
- 两个 token 之间怎么分,只由它俩的分差决定:wa ÷ wb = esa − sb,别的 token 来不来都不影响。「先减最小值」做不到这一点。
纠正对话样本里的一处示意数。样本 L1795 给了分数 8、7、9,写的权重是 40% / 30% / 30%。真算 softmax:e8 ≈ 2981,e7 ≈ 1097,e9 ≈ 8103,合计 12181,权重是 24.5% / 9.0% / 66.5%(在上面「改进方案」里切到「8 / 7 / 9」核对)。分差只有 1,权重却差 e ≈ 2.72 倍——softmax 会把分差放大成比例差,编一组「好看」的数正好把这个性质抹掉了。
把前三课合起来,权重矩阵就是这一行公式。点每一项看它是什么、为什么在那:
改进第二轮:为什么要除以 √d
softmax 只看分差。那分差有多大?假设 q、k 的每一维都是独立的、均值 0、方差 1 的随机数(初始化附近大致如此)。点积 q·k = Σi qiki 是 d 个独立项相加,每一项的方差是 1,所以
Var(q·k) = d,标准差 = √d 证据等级 · 数学可证明 在写明的前提下可以严格推导出来,不依赖实验。只要前提成立,换数据、换规模仍然成立。 本条前提:q、k 各分量独立、均值 0、方差 1。独立随机变量之和的方差等于方差之和 出处Vaswani et al. 2017 脚注 4 ↗ 。
锚点模型每头 256 维,点积的标准差就是 √256 = 16:同一行里随手两个分数差上十几二十是常态。e20 ≈ 4.9 亿——softmax 会把几乎全部权重交给最大的那个。
「几乎 one-hot」为什么是坏事?softmax 的梯度是雅可比矩阵 J = diag(w) − w·wT。当某个 w 接近 1、其余接近 0 时,J 的每一项都接近 0 证据等级 · 数学可证明 在写明的前提下可以严格推导出来,不依赖实验。只要前提成立,换数据、换规模仍然成立。 本条J_ij = w_i(δ_ij − w_j);w 为 one-hot 时每一项都为 0 出处待补 :分数怎么变,权重几乎不动,loss 的梯度传不回 WQ、WK。原文的说法是「我们怀疑(we suspect)大 dk 时点积量级变大,把 softmax 推进梯度极小的区域」 证据等级 · 有理论动机 有数学或机制上的理由说明它可能有效,但没有证明它一定更好。最后是否采用,仍然要看实验。 本条「方差变大 → softmax 饱和 → 训练变差」这条因果链,原文用的是 we suspect,是理论动机 出处Vaswani et al. 2017 §3.2.1 ↗ 。
除以 √d,方差回到 1,不管 d 是 4 还是 256,分数都落在同一个尺度上。下面用固定种子的随机向量真算一遍。
试三件事:① 看上面一排直方图:三张图共用同一条横轴,d 越大分布越宽,宽度按 √d 增长;② 看下面一排:除以 √d 之后三张图一样宽——这就是「方差拉回 1」;③ 看表里 d = 256 那一行,对比「不缩放」和「÷√d」的最大权重、熵和梯度大小,想一想:如果不缩放,训练初期哪一个量会让模型学不动?
⚠ 常见误解
「除以 √d 是个经验技巧,换成别的常数也差不多。」不对。√d 是有来由的:在「分量独立、方差为 1」的前提下,它恰好把点积的方差变回 1,与维数无关——这一步是推导出来的。真正属于经验的是另一半:「方差为 1 时训练最好」、以及训练中途前提不再成立时怎么办。后一件事现代模型用 QK-Norm 来管(锚点 Qwen3.8 就开着),C8 讲。
「softmax 的权重就是概率,66.5% 表示模型有 66.5% 的把握关注它。」这组权重是加权平均的系数,不是某个随机事件的概率:它不描述「关注谁」的不确定性,模型每次都按这组比例把所有 V 混在一起(第 5 课)。
注意力的演进,你在这里
① 训练时:一个 token 怎么从别的 token 那里取信息
- 解决了能读任意长的序列,参数与长度无关;手里只带一个固定大小的状态 h。卡在ht 要等 ht−1 算完:T = 4,096 时每层 4,096 步不能并行,第 1 个 token 的信息要经过 4,095 次更新才到最后;翻译时整句还得挤进一个定长向量——Bahdanau 2014 说的瓶颈。展开岔路 B1
- 解决了解码器每一步回头给源句的每个位置打分、加权取回,不再只靠那一个定长向量:score = vT·tanh(W1q + W2k)。卡在每一对都要单独过 tanh,交不给矩阵乘单元;朴素实现要先落一个 T×T×da 的中间张量:T = 4,096、da = 256 时单头单层 8.0 GiB(BF16),点积只留 T×T 个分数,32 MiB。它还长在 RNN 翻译模型里,串行没解决。展开第 2 课
- 解决了直接比 embedding 时「给了」最像的是它自己(余弦 1.000),小明、苹果、小王排在最后;投影成 Q、K 再点积,它自己排到最后、前三名是苹果、小王、小明,全部配对一次矩阵乘 QKT;取回用单独的 V——两个人名的 K 余弦 0.995,取回 K 分不清是谁。卡在不缩放:锚点每头 256 维,点积标准差 √256 = 16,同一行分差十几二十是常态(e20 ≈ 4.9 亿),softmax 几乎独占,梯度传不回 WQ、WK。
- 解决了softmax 把分数变成正的、和为 1 的权重,只看分差(按占比分,对话样本的 10、3、−4 会给「汽车」−44.4%);除以 √dk = 16,点积方差回到 1。卡在训练时整句一次喂进去:不加掩码,「给了」一行有 32.5% 的注意力直接落在它要预测的答案「小王」上,loss 低得虚假。展开第 3 课
- 解决了旋转后 q·k 只依赖距离 j − i;V 不参与打分,不转(转了会把绝对位置混进取回的内容)。锚点每头 256 维里只转 64 维。卡在旋转矩阵随位置变,夹在展开矩阵和缓存之间就没法事先并进 Q:MLA 因此把 RoPE 单独拆出 64 维另存(DeepSeek-V2 config,第 10 课)。
- 解决了标准 softmax 逼每行分完 100%:「苹果」一行 3 个分数只差零点几(0.04、0.36、0.00),照样分成 30% / 41% / 29%;分母加可学习的 sink logit,或在输出上乘门,这个头就能「这次不取」——锚点开着输出门(attn_output_gate = true)。卡在出口的效果只有实验证据:Gated Attention 原文说门控「缓解」sink,不是消除;DeepSeek-V4 没给 sink logit 的单独消融。展开岔路 B4
② 生成时:K、V 怎么越存越少
- 解决了缓存直接除以头数:锚点形状下每 token 16 KiB,262,144 上下文 4 GiB。卡在质量会掉、训练可能不稳:GQA 论文表 1(T5-XXL,七个任务平均)MHA 47.2 → MQA 46.6。展开第 9 课
- 解决了24 个 Q 头分 4 组、每组 6 个共用 1 个 KV 头(组数 = KV 头数):每 token 64 KiB、262,144 上下文 16 GiB;T5-XXL 上 GQA-8 平均 47.1、推理 0.28 s,质量接近 MHA(47.2、1.51 s),速度接近 MQA(0.24 s)。卡在再减 KV 头就回到 MQA:DeepSeek LLM 67B 已是 GQA-8,每 token 仍要 389,120 B(每头一份的 MHA 是 3,112,960 B),1M token 单条请求 380 GiB。展开第 9 课
- 解决了不存 K、V,每层每 token 只存 512 维潜向量 + 64 维 RoPE = 576 个数,用时再展开:DeepSeek-V2(60 层)每 token 69,120 B、V3(61 层)70,272 B;相对 67B 按 BF16 降 82.2%,官方「−93.3%」还含约 6 bit 的 KV 量化。卡在仍随长度线性增长,打分仍是 T²:GLM-5.3 同是 576 个数、78 层,每 token 89,856 B,原生 1,048,576 上下文时单条请求只算潜向量就要 87.75 GiB。展开第 10 课
- 解决了换掉「按长度存」本身:锚点 64 层里 48 层不存 KV,只存固定大小的状态(FP32 共 144 MiB),与上下文长度无关(这些层是什么、怎么更新,C11 第 4 课揭晓);DeepSeek-V4.1 叠加压缩、稀疏与低精度,官方报告全局 KV 890 B/token。卡在固定状态装不下任意多对键值,锚点仍留 16 层全注意力;稀疏注意力每步只读挑出来的一部分,挑本身也有代价——各自省了什么、没省什么,C11 讲。
证据三问
- 它解决什么问题?把任意实数分数变成正的、和为 1 的权重;并让不同 head_dim 的分数落在同一尺度,不至于一开训就饱和。
- 数学上为什么可能有效?softmax 的四条性质可证明;Var(q·k) = d 在给定前提下可证明;饱和时雅可比趋于 0 可证明 证据等级 · 数学可证明 在写明的前提下可以严格推导出来,不依赖实验。只要前提成立,换数据、换规模仍然成立。 本条见上文三处推导 出处待补 。「饱和会让训练变差」是理论动机 证据等级 · 有理论动机 有数学或机制上的理由说明它可能有效,但没有证明它一定更好。最后是否采用,仍然要看实验。 本条原文 we suspect 出处Vaswani et al. 2017 §3.2.1 ↗ 。
- 实验上为什么最后选了它?原文引用的对比:dk 较大时,不缩放的点积注意力不如加性注意力;缩放后点积成为 Transformer 的默认做法 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条当时的机器翻译设置 出处Vaswani et al. 2017 §3.2.1 引 Britz et al. 2017 ↗ 。
一句话
softmax 把任意分数变成正的、和为 1 的权重,只看分差;除以 √d,是为了让分差不至于大到 softmax 饱和、梯度消失。
下一个缺口
到这里,「给了」这一行对 5 个 token 都有权重——包括排在它后面的「小王」。可是训练「预测下一个 token」时,「给了」后面那个 token 正是它要预测的答案。一次喂进整句,怎么保证它看不到答案?→ 第 4 课:训练时怎么防止模型偷看答案?
你可能会问
这一课还没有收到真实提问;你的提问会记到 05-问答记录/C3-L3.md。
🔍 为什么偏偏是 e 为底?用 2 行不行?
行,而且等价。2s = es·ln2,换底只相当于把所有分数乘一个常数 ln2 ≈ 0.693,也就是换了一个「温度」;模型会用 WQ、WK 的尺度把它吸收掉。选 e 是惯例:导数最简单(d ex/dx = ex),和交叉熵的自然对数配套。
🔍 √d 和生成时调的「温度」是一回事吗?
数学上是同一件事:都是「分数先除以一个数,再 softmax」。√dk 是训练时固定的、写死在注意力里的温度;生成时你手里的温度 T 作用在输出层的 logits 上,改的是下一个 token 的采样分布(C13 讲)。除以大的数 → 分布更平;除以小的数 → 更尖。
🔍 除以 √d 之后就一劳永逸了吗?
不是。推导的前提是 q、k 各分量方差为 1,只在初始化附近大致成立。训练中 WQ、WK 的尺度会长,点积会重新变大,严重时注意力 logit 爆炸、loss 突然飙升。这就是为什么 Qwen3.8 等模型还要对 q、k 做 RMSNorm(QK-Norm),以及 Kimi K2 的 QK-Clip 这类办法——C8 稳定性一章专门讲。