第 12 篇 我们把 hidden 变成 logits,再用交叉熵衡量「下一个 token 猜得准不准」。但还有一条硬规则没写进公式:位置 $t$ 不许看见未来的 token——否则训练会作弊、推理也无法自回归。

这一篇把 因果掩码(Causal Mask) 讲清楚,并和 第 11 篇 的 Prefill / Decode、第 12 篇 的并行 CE 收成一张对照表。

这是「大模型数学速成」续篇第 13 篇。建议先读 第 05 篇 Attention第 11 篇 KV Cache第 12 篇 交叉熵。下一篇讲 采样(Temperature / top-k / top-p)

一、为什么需要因果掩码?

Self-Attention 默认是双向的:每个 query 可以和所有 key 算分(第 05 篇)。
对语言模型来说这会出问题:

场景 若允许看见未来 后果
训练 位置 $t$ 的预测能「偷看」$t{+}1,t{+}2,\ldots$ 的真实词 损失虚低,模型学不到接龙
推理 生成第 $t$ 个词时,后面的词还不存在 根本没有未来可看

所以 GPT 类自回归 LM 使用 因果注意力(Causal / Autoregressive Attention)

位置 $i$ 的 query 只能 attend 到位置 $j \le i$ 的 key/value。

编码器式双向模型(如部分 BERT、ViT)不需要这条规则;解码器式 LLM 必须要。

二、Mask 加在哪里?

回顾缩放点积注意力(单头示意):

\[\mathbf{S} = \frac{Q^\top K}{\sqrt{d}}, \qquad \mathbf{P} = \mathrm{softmax}(\mathbf{S}), \qquad \mathbf{O} = V \mathbf{P}^\top\]

因果约束作用在 Softmax 之前的分数矩阵 $\mathbf{S}$ 上:对非法的 $(i,j)$($j > i$)设为「负无穷」,Softmax 后权重变为 0。

\[\tilde{S}_{i,j} = \begin{cases} S_{i,j} & \text{if } j \le i \\ -\infty & \text{if } j > i \end{cases}\]

\[P_{i,j} = \frac{e^{\tilde{S}_{i,j}}}{\sum_{k=1}^{T} e^{\tilde{S}_{i,k}}}\]

实现上常用一个很大的负数(如 $-10^{4}$ 或 dtype 允许的最小值)代替真正的 $-\infty$,避免 NaN。

下三角示意图($T=4$)

行 = query 位置 $i$,列 = key 位置 $j$; 可见, 被 mask:

1
2
3
4
5
        j=0   j=1   j=2   j=3
i=0 ✓ ✗ ✗ ✗ ← 第 0 个 token 只能看自己
i=1 ✓ ✓ ✗ ✗
i=2 ✓ ✓ ✓ ✗
i=3 ✓ ✓ ✓ ✓ ← 最后一个能看全文(到自己为止)

对应 下三角(含对角线) 为 1、上三角为 0 的布尔掩码——所以常叫 causal lower-triangular mask

三、手算:mask 怎样改变 Softmax?

设 $T=3$,某 query 行($i=1$,只能看 $j=0,1$)的原始分数:

\[\mathbf{s} = [1.0,\ 2.0,\ 3.0]\]

无 mask(非法)

\[\mathrm{softmax}(\mathbf{s}) \approx [0.090,\ 0.245,\ 0.665]\]

最大权重落在未来位置 $j=2$。

有因果 mask($s_2 \leftarrow -\infty$)

\[\mathbf{s}' = [1.0,\ 2.0,\ -\infty]\]

\[\mathrm{softmax}(\mathbf{s}') \approx [0.269,\ 0.731,\ 0]\]

未来位置权重精确为 0;概率在合法前缀上重新归一化。

四、训练:教师强制 + 因果 mask = 整句并行

训练时输入一整句 token(长度 $T$),目标是每个位置预测下一个真实 token(第 12 篇 的 CE)。

步骤 做什么
1 嵌入 + 各层 Transformer,Attention 带因果 mask
2 每个位置 $i$ 的 hidden 经 lm_head 得 logits
3 位置 $i$ 的标签通常是 token $i{+}1$(边界与特殊符依实现)
4 对有效位置平均交叉熵,一次反传

关键:有了因果 mask,位置 $i$ 的表示数学上不依赖 $i$ 之后的输入,因此可以整句一次前向,而不必像推理那样逐步生成——这叫 teacher forcing(教师强制):标签来自真实下一词,不是模型自己滚出来的词。

1
2
3
4
输入:  [BOS]  今  天  气  不错
预测: 今 天 气 不错 [EOS] ← 每位预测「下一个」
↑ 并行算 5 个 CE(示意)
Attention: 下三角 mask,今天看不见「不错」

五、推理:Prefill 与 Decode 里的 mask

第 11 篇 对齐:

Prefill(prompt 一次算完)

  • 输入长度 $S_0$ 的 prompt
  • 做一次 $S_0 \times S_0$ 的因果 Attention(下三角)
  • 把各层 K/V 写入 Cache
  • 通常用最后一个位置的 logits 采出第 1 个新 token

Decode(每次 1 个新 token)

  • 只算新位置的 Q(以及新 K/V)
  • 与 Cache 中全部历史 K 做点积——历史天然都是 $\le$ 当前时刻,不必再拼一块上三角未来
  • 新 K/V 追加进 Cache
阶段 序列长度 Mask 形态 Cache
训练 整句 $T$ 完整下三角 $T\times T$ 一般不长期缓存
Prefill prompt $S_0$ 下三角 $S_0\times S_0$ 初始化
Decode 历史 $S$ + 1 新 query 对 $1..S{+}1$ 全可见(无未来) 追加 1 列

Decode 时「因果」体现在:根本没有未来 token 参与计算;Prefill/训练则靠显式 mask 禁止偷看。

六、和双向注意力差在哪?(一眼表)

因果(LLM 解码) 双向(如部分 Encoder / ViT)
可见范围 $j \le i$ 全体 $j$
典型任务 语言建模、聊天生成 理解、分类、部分编码
训练并行 可以(+ teacher forcing) 可以
生成方式 自回归逐步 通常不逐步「接龙出词」

多模态里:图像 patch 往往在 prompt 侧一次编进序列,文本侧仍对文本位置保持因果;图像 token 之间是否双向取决于具体架构——读代码时看 mask 构造即可。

七、实现时容易踩的坑(概念级)

  1. Off-by-one:标签是「当前词」还是「下一个词」必须与 shift 一致,否则 CE 对不齐。
  2. Padding:pad 位置既不当 query 有效位,也不应被 attend(额外 padding mask,与因果 mask 按位组合)。
  3. 数值:用有限大负数代替 $-\infty$ 时,极端长度下仍可能 underflow;框架融合 kernel 一般已处理。
  4. 和 RoPE第 07 篇 的位置旋转与因果 mask 正交——一个改 Q/K 相位,一个改可见集合。

八、小结

概念 要点
因果 位置 $i$ 只看 $j\le i$
做法 Softmax 前把未来 score 置 $-\infty$
形状 下三角可见
训练 整句并行 + teacher forcing + CE
Prefill 对 prompt 做下三角 Attention,填 Cache
Decode 无未来 token;Cache 追加,自然因果

大模型数学速成续篇第 13 篇完。下一篇 采样:Temperature / top-k / top-p——有了 logits,如何从分布里「抽出」下一个 token。

系列导航

篇号 标题 状态
12 输出层、Logits 与交叉熵
13 因果掩码与解码循环(本篇)
14 采样:Temperature / top-k / top-p

完整大纲见工作区 docs/MATH_SERIES_OUTLINE_V2.md