什么是因果掩码(causal mask)?双向、因果、prefix 注意力有什么区别?
简化版
因果掩码把每个 query 对其右侧未来 token 的注意力 logits 设为负无穷,使位置 i 的隐藏状态只能读取 0…i。在常见右移训练中,位置 i 的状态用于预测 token i+1,因此看得到当前位置输入但看不到预测目标及其后内容。双向注意力允许全序列互看;因果注意力只看当前与过去;Prefix-LM 让输入前缀内部双向,生成区读取前缀及已生成位置。
详细版
因果掩码怎么实现
在注意力分数矩阵 S = QKᵀ/√d 上加一个掩码矩阵 M,再做 softmax:
S_masked[i][j] = S[i][j] + M[i][j]
M[i][j] = 0 若 j ≤ i (允许看)
M[i][j] = −∞ 若 j > i (屏蔽未来)
softmax 后,被 −∞ 的位置权重≈0
这就是一个下三角可见的模式:位置 i 只能注意到 0…i。
为什么训练时需要它
decoder-only 是「用整句话并行训练、每个位置预测下一个词」。如果不加因果掩码,位置 i 在预测第 i+1 个词时能看到答案(未来 token),就作弊了,学不到真本事。因果掩码保证「预测未来只依赖过去」,让并行训练与自回归推理行为一致。
三种注意力可见性
| 类型 | 可见范围 | 用途 | 代表 |
|---|---|---|---|
| 双向(bidirectional/full) | 全序列 | 理解、编码 | BERT 编码器 |
| 因果(causal/单向) | 只看自己及左侧 | 自回归生成 | GPT、Llama 解码器 |
| prefix-LM | 前缀双向 + 后续因果 | 单流序列中的输入理解 + 生成 | UniLM 等特定掩码架构 |
完整版教学
一、掩码的本质:在 softmax 前”屏蔽”某些位置
注意力的自由度在于「每个 token 能看谁」。掩码就是控制可见性的开关:想屏蔽哪对 (i,j),就在它们的注意力分数上加 −∞,softmax 后 exp(−∞)=0,权重归零,等于这条连接被切断。掩码不改变注意力的计算框架,只是决定信息能在哪些位置之间流动。
因果掩码是最重要的一种,它切断了「看向未来」的所有连接,形成下三角可见结构。
二、为什么自回归模型必须加因果掩码
自回归语言模型的目标是 P(x) = ∏ P(x_i | x_1…x_{i-1})——每个词的概率只依赖它前面的词。训练时为了效率,我们把整句话一次性喂进去并行计算所有位置的预测,而不是一个个来。
问题来了:并行计算时,位置 i 的表示是通过注意力聚合全序列得到的,如果不加限制,它会「看到」位置 i+1、i+2 的内容——而这些正是它要预测的答案。这叫信息泄漏,会让模型学到「抄答案」的捷径,训练 loss 很低但推理时完全不会做(因为推理时未来还不存在)。
因果掩码通过屏蔽未来,使 teacher forcing 下每个位置不会直接读取预测目标。训练与推理仍可能因真实历史 token 和模型自生成 token 不同而存在 exposure bias,所以这里的一致仅指可见性约束一致,不是输入分布完全一致。
记忆钩子:因果掩码 = 防作弊。 预测未来只准看过去,训练与推理才一致。
三、因果掩码与 KV Cache 的天然契合
因果结构还带来推理红利。因为位置 i 只依赖 0…i,且这些位置的 K/V 不会因为后面新增 token 而改变,所以历史 token 的 K/V 可以缓存复用(KV Cache):生成第 t 个 token 时,只需算新 token 的 Q/K/V,与缓存的历史 K/V 做注意力即可,无需重算历史。
如果对一个双向编码序列追加 token 并要求旧位置也看见它,旧表示就需重算,不能直接沿用同样的增量缓存语义;对固定不变的编码器输入则仍可缓存编码结果。因果结构的关键优势是追加 token 不会改变历史位置对“未来不可见”的表示。
四、三种可见性各自的适用场景
双向(BERT):每个 token 看全序列,理解最充分,适合分类、抽取、句向量等判别任务。但不能自回归生成(生成时右侧不存在)。
因果(decoder-only):每个位置看当前及左侧,天然支持逐 token 生成,是许多生成式 LLM 的基础。前面位置不能吸收后文,但最后一个 prompt 位置已经能汇聚此前全部输入;它在纯编码任务上的表现取决于训练与读出方式,不能简单断言“规模大后影响不大”。
prefix-LM(前缀语言模型):把单个序列分成前缀与生成区,前缀内部双向可见,生成区可看全部前缀与自身过去。它与 T5 这类“独立双向编码器 + 因果解码器 + 交叉注意力”在可见性效果上有相似目的,但拓扑不同,不能把 T5 直接当作同一种 Prefix-LM mask。
五、掩码还能表达更多结构
掩码不止「因果」一种,它是一个通用工具:
- Padding 掩码:屏蔽 batch 内为对齐长度而填充的 pad token,别让它们参与注意力。
- 滑动窗口掩码(sliding window):只让每个 token 看最近 W 个 token(如 Mistral),把长序列的注意力成本从 O(n²) 降到 O(n·W)。
- 文档/段掩码:训练时把多篇拼接的文档互相屏蔽,防止跨文档注意力串味。
- prefix 掩码:如上,前缀双向、后缀因果。
掌握「掩码 = 在 softmax 前用 −∞ 控制可见性」这一机制,各种变体都是它的组合。
六、用四个 token 验证掩码
设序列长度为 4,位置 2(从 0 开始)只能读取位置 0、1、2。它在 softmax 前的第 2 行分数若为 [1.2, 0.3, 2.0, 4.5],因果掩码会把最后一项改成负无穷;softmax 后未来位置的权重严格为 0,而不是“比较小”。这样训练时虽然四个位置并行计算,每一行仍只使用推理时已经存在的信息。
原始分数: [1.2, 0.3, 2.0, 4.5]
因果掩码: [0, 0, 0, -∞ ]
掩码之后: [1.2, 0.3, 2.0, -∞ ]
可见位置: 0 1 2 ×
| Mask | 屏蔽对象 | 不加时的后果 |
|---|---|---|
| Causal | 当前 token 右侧的未来位置 | 训练时偷看答案 |
| Padding | 为批处理补出的空位置 | 注意力被无效 token 稀释 |
| Document | 拼接序列中的其他文档 | 跨样本信息串扰 |
若 batch 中还存在 padding,需要再叠加 padding mask。两个 mask 都作用于 attention logits,但前者保证时间因果性,后者排除无效填充;把二者混为一种 mask,常会造成训练正常、批量推理却异常。
七、常见误区与追问
- 误区:因果掩码把未来位置的分数改成 0。 应在 softmax 前加负无穷或足够大的负数;加 0 等于不屏蔽,未来位置仍会获得概率。
- 追问:训练时为什么需要 Mask,推理时未来 token 明明不存在? 训练会并行计算整段序列的所有位置,不加 Mask 就会泄漏右侧答案;推理实现仍需正确处理批次、padding 和缓存偏移。
- 追问:Padding Mask 与 Causal Mask 如何组合? 先构造各自允许访问的布尔关系,再取交集,或把两个加法 Mask 相加后统一加到 logits 上。
- 误区:Prefix-LM 的前缀也只能单向注意。 Prefix-LM 通常让前缀内部双向可见,而生成区只能看整个前缀和已生成位置。
- 追问:序列打包时只加普通因果 Mask 够吗? 不够;后一个样本仍能看到前一个样本,必须叠加文档边界 Mask 并正确重置 position ids。
八、加强记忆
因果掩码记「防作弊、下三角」:在 softmax 前把每个 token 对未来位置的分数设 −∞,使其只能看自己及左侧,保证自回归模型「预测未来只依赖过去」,让并行训练与逐 token 推理行为一致,还天然配合 KV Cache。三种可见性简要说区分:双向=全看(BERT 理解)、因果=只看左(GPT 生成)、prefix-LM=前缀双向+生成因果(兼顾)。再记一个通用心法——掩码就是用 −∞ 控制”谁能看谁”,padding、滑动窗口、跨文档隔离都是它的变体。