想到一个有意思的问题,可以拿来当面试题。
对于 Qwen、GPT 这种 decoder only 的生成模型:
- 问题 Q 通过自回归多次前传生成 a1 a2 a3,此时生成完之后,QA 整体的 hidden state 是 Q 经过一次前传得到的 hidden state 和预测 a1 a2 a3 过程中的 hidden state 不断拼接,记为 H1;
- "Q a1 a2 a3" 作为文本序列直接拼起来一次性送入 transformer 获得的 hidden state,记为 H2;
问题是:H1 和 H2 这两个 hidden state 一样吗?
结论:完全一样
这两种方式得到的 hidden state 是数学上严格等价的。
为什么一样?
核心原因:Causal Mask(因果掩码)
Decoder-only 模型的自注意力机制使用 causal mask,确保每个 token 只能看到自己和之前的 token,看不到未来的 token。
方式一:自回归逐步生成
步骤1: 输入 [Q] → 得到 h_Q, 预测 a1
步骤2: 输入 [Q, a1] → 得到 h_Q, h_a1, 预测 a2
步骤3: 输入 [Q, a1, a2] → 得到 h_Q, h_a1, h_a2, 预测 a3
步骤4: 输入 [Q, a1, a2, a3] → 得到 h_Q, h_a1, h_a2, h_a3
在每一步中,由于 causal mask 的存在:
h_Q只依赖 Q 本身h_a1只依赖 Q 和 a1h_a2只依赖 Q、a1 和 a2h_a3只依赖 Q、a1、a2 和 a3
方式二:一次性送入
输入 [Q, a1, a2, a3] → 一次前向传播 → 得到 h_Q, h_a1, h_a2, h_a3
由于 causal mask:
- 计算
h_Q时,只 attend 到 Q → 和方式一完全一致 - 计算
h_a1时,只 attend 到 Q 和 a1 → 和方式一完全一致 - 计算
h_a2时,只 attend 到 Q、a1 和 a2 → 和方式一完全一致 - 计算
h_a3时,只 attend 到 Q、a1、a2 和 a3 → 和方式一完全一致
直观理解
Causal Mask 矩阵(1 表示可以 attend):
Q a1 a2 a3
Q [ 1 0 0 0 ]
a1 [ 1 1 0 0 ]
a2 [ 1 1 1 0 ]
a3 [ 1 1 1 1 ]
无论你是一次性算还是分步算,每个位置"能看到的信息"完全相同,因此计算结果完全相同。
这正是 KV Cache 的理论基础
实际推理中使用的 KV Cache 优化正是利用了这个等价性:
自回归生成时:
步骤1: 计算 Q 的 KV,缓存起来
步骤2: 只计算 a1 的 Q/K/V,复用 Q 的 KV cache → 得到和完整计算一样的结果
步骤3: 只计算 a2 的 Q/K/V,复用之前的 KV cache → 同样等价
...
如果两种方式的 hidden state 不一样,KV Cache 就不能用了。
唯一可能不一样的情况
在极端情况下,由于浮点数运算精度 的差异(加法顺序不同可能导致微小的舍入误差),两者可能存在 10−610^{-6}10−6 到 10−710^{-7}10−7 量级的数值差异,但这是数值计算层面 的,不是数学层面的,在逻辑上完全等价。