知识盲盒
第二章 Prefill:整层状态演化与 KV 建立
Prefill 接收已经确定的输入张量,对全部提示位置执行一次因果前向,建立各层 KV cache,并产生首个输出 token 的原始 logits。卷一已经说明 Transformer 的设计,本章只回答执行问题:每一层读取什么、写入什么,缓存与首步 logits 在哪个时刻成立。
2.1 Prefill 的接口契约
对 batch size 、矩形长度 ,一个最小接口是:
prefill(
input_ids: int[B, n],
attention_mask,
position_descriptor,
model_snapshot,
numerical_config,
cache_config
) -> PrefillResult {
next_logits: float[B, |V|],
kv_cache,
valid_lengths: int[B],
cache_metadata
}
model_snapshot 必须解析到不可变权重及适配器;numerical_config 至少确定权重/激活/cache 精度和关键 kernel;cache_config 确定 KV 布局与位置约定。逻辑接口不要求公开物理显存地址。
前置条件 2.1
- 每个非 padding ID 位于词表范围内;
- token-validity mask 与有效位置一致;
- position descriptor 对所有有效位置有定义;
- 模型、embedding、输出词表和 tokenizer 的词表大小兼容;
- 推理模式下训练专用 dropout 已关闭,或其随机状态被显式记录。
违反前置条件时应在进入模型或第一层前失败,而不是产生一个看似正常但语义未定义的回答。
2.2 层首状态
设模型宽度为 ,层数为 。embedding 后的残差流为
对第 层,层首的逻辑状态可记作
其中 表示样本 的位置 有效, 是由 、因果规则与位置描述构造的 attention bias, 是位置描述, 是已经为较低层写好的缓存。对有效 query,普通因果 self-attention 可取
无效 query 行不进入 softmax,其输出随后被丢弃;kernel 若仍物化这些行,必须另用哨兵规则避免全 softmax。计算第 层不会修改更低层的逻辑 K/V;缓存管理器可以搬移物理页,但不能改变它们代表的 token 与位置。
下面以常见 pre-norm、grouped-query decoder 层为具体执行模板。其他架构可以替换规范化、位置编码或 MLP,但必须给出同样清楚的读写契约。
2.3 Attention 子层的逐张量演化
令 query 头数为 ,KV 头数为 ,且 ;头维度为 。规范化后:
线性投影与 reshape 得到
位置机制作用后,记实际用于点积的 query/key 为 。对于 query 头 ,令
给出它共享的 KV 头。score 张量为
因果 mask 对 给出 ,padding mask 对无效 key 位置同样给出 。一个有效 query 行必须至少有一个有限元素;否则 softmax 的结果未定义,应该在 mask 构造阶段拒绝。
稳定 softmax 对每行有限分数先减最大值:
其中 是该行有限 score 的最大值。然后
各 query 头拼接并经过输出投影后写回残差流:
FlashAttention 一类 kernel 不必显式物化完整 和 ,但其逻辑结果仍由上述张量关系定义。实现优化不能改变 mask、位置或 head-sharing 语义。基础算法来源见资料源。
2.4 MLP 子层与层终状态
对 gated MLP,一种常见形式是
MLP 对每个位置独立应用同一组权重;位置间的信息交换已经发生在 attention 子层。对执行追踪而言,关键不是把每个非线性赋予自然语言含义,而是记录:层首残差、attention 更新、MLP 更新和层终残差具有相同的 外形,并按固定次序相加。
第 层完成时,逻辑状态转移是
其中新增加的 正是本层对有效提示位置的 key/value。
2.5 KV cache 在何处写入
本卷采用以下缓存契约:
LayerCache[l] = {
keys: K_used_by_attention[B, H_kv, logical_length, d_h],
values: V_used_by_attention[B, H_kv, logical_length, d_h],
positions,
valid_lengths,
layout_metadata
}
若位置机制把旋转应用于 key 后再参与 attention,则这里的 keys 指旋转后的 key;若某模型选择缓存旋转前表示并在读取时变换,必须把这一差异写入 layout_metadata。两种实现都可以正确,但缓存不能跨这两种契约直接复用。
对 batch 中样本 的有效长度 ,prefill 完成后每层应满足
物理实现可以分页存储、量化或为不同序列分配不连续块;逻辑读取顺序仍必须对应位置 或明确记录的 position IDs。
缓存不变量 2.2
- 所有层对同一序列具有相同逻辑 token 长度;
- 每层 K/V 的 batch、KV 头和头维度匹配模型配置;
- cache slot 与 token/position 的映射在一次 attention 读取期间不变;
- padding 不得伪装成可见历史位置;
- cache 的模型、adapter、位置机制、精度和布局版本必须与当前 decode 调用兼容。
2.6 Prefill 伪代码
下面的伪代码刻意把逻辑张量与物理缓存分开:
function prefill(input_ids, valid_mask, positions, model, cache_manager):
assert_input_contract(input_ids, valid_mask, positions, model)
attention_bias = build_attention_bias(
valid_mask, positions, model.attention_rule
)
residual = embedding_lookup(model.embedding, input_ids)
cache = cache_manager.allocate(
batch_lengths(valid_mask), model.cache_layout
)
for l in 0 .. model.num_layers - 1:
x = norm_l(residual)
q, k, v = project_qkv_l(x)
q_used, k_used = apply_position_l(q, k, positions)
for b in 0 .. batch_size - 1:
idx = valid_token_indices(valid_mask[b])
cache.write_sequence(
batch_index=b,
layer=l,
logical_positions=positions[b, idx],
keys=k_used[b, :, idx, :],
values=v[b, :, idx, :]
)
attn = causal_attention(
q_used, k_used, v, attention_bias, valid_mask
)
residual = residual + output_projection_l(attn)
residual = residual + mlp_l(norm_after_attn_l(residual))
final = final_norm(residual)
h_last = gather_last_valid_position(final, valid_mask)
next_logits = unembedding(h_last)
assert_cache_invariants(cache, valid_mask, model)
return next_logits, cache, valid_lengths(valid_mask)
某些 fused kernel 会同时投影、旋转、写缓存和计算 attention;伪代码没有要求按独立 kernel 执行,只要求结果等价。gather_last_valid_position 不能简单取矩形张量的最后一列,除非 batch 使用右对齐且该列对每个样本都有效。
2.7 首步 logits 的条件前缀
经过 层和最终 normalization,样本 的最后有效提示位置表示为 。词表投影得到
它表示下一位置的原始分数,条件前缀恰为该样本全部有效输入 token。此时:
- 首个输出 token 尚未被选择;
- cache 只含提示位置;
next_logits与 cache 代表同一个条件前缀;- 若服务返回 prompt logprobs,那是额外读取各提示位置 logits 的功能,不改变首步接口。
这是导论约定 0.2的 prefill 实例。
2.8 一个具体形状账本
取合成模型:
B = 1, n = 12, d = 8, L = 2
H_q = 2, H_kv = 1, d_h = 4, |V| = 20
使用第一章夹具的 12 个 token。每层逻辑形状为:
| 对象 | 形状 |
|---|---|
| 层首残差 | [1, 12, 8] |
| query | [1, 2, 12, 4] |
| key/value | 各 [1, 1, 12, 4] |
| score(若物化) | [1, 2, 12, 12] |
| attention 输出(拼接前) | [1, 2, 12, 4] |
| 层终残差 | [1, 12, 8] |
两层缓存合计保存
个标量;开头的 2 表示 key 与 value。最终只取位置 11 的 [8] 向量,投影出 [20] 首步 logits。该账本不依赖具体参数值,适合检查 reshape、KV 头映射和缓存长度。
2.9 前缀缓存复用
若请求 的 token 前缀与已缓存请求 的前 个 token 完全相同,系统可以复用前 个位置的 KV,但还必须同时满足:
- 模型权重、adapter 与层配置相同;
- 位置编号和位置变换参数相同;
- attention mask 对该前缀的语义相同;
- cache 精度与布局兼容;
- 复用边界不切入不可独立处理的模态区段;
- 缓存所属租户和访问策略允许复用。
一个 prefix hash 只能用于查找候选缓存,不能单独证明以上条件。命中后应核对不可变元数据;跨用户缓存还必须避免让命中时间或缓存内容泄露私有前缀。
复用不改变逻辑结果:系统把缓存视为已经对前 个 token 完成 prefill,再对剩余后缀继续前向。若逻辑 logits 改变,就不是透明优化。
2.10 数值复现与逐层校验
在实数抽象中,固定参数和输入唯一确定张量。实际设备还包含低精度乘法、并行归约、近似函数和 kernel 选择。要判断差异首次出现在哪层,可以运行逐层校验:
for each layer l:
compare shape and finite-value mask
compare cache logical lengths and positions exactly
compare residual checksum or sampled tensor values
compare max_abs_error and relative_error against declared tolerance
compare final raw logits and top-ranked IDs
摘要只能快速发现差异;浮点张量的位级摘要不同不说明误差一定有行为影响。反过来,只比较最终 top-1 相同也不足以说明分布或后续采样相同。
一个可复现实验至少固定:模型快照、adapter、输入三张量、精度、设备与 kernel 软件版本、是否允许非确定归约、cache 布局,以及比较容差。先在单 batch、无 prefix reuse 的路径建立基准,再逐项启用批处理与缓存优化。
2.11 Prefill 的失败条件
| 失败 | 违反的不变量 | 典型症状 |
|---|---|---|
| 左填充样本仍取矩形最后位置 | 首步条件前缀 | 短样本首 token 异常 |
| 某层漏写一个 KV 位置 | 各层长度一致 | 首次 decode shape error 或静默错位 |
| position IDs 在复用后从零重启 | token/position 映射 | cache 命中时结果改变 |
| GQA query 头映射到错误 KV 头 | 模型配置兼容 | logits 从第一层开始偏离 |
| padding key 未屏蔽 | 有效位置语义 | batch 组合改变单样本结果 |
| 复用不同 adapter 的缓存 | 快照一致 | 前缀结果污染 |
| 全掩码 query 行进入 softmax | 有限 score 存在 | NaN 传播到 logits |
Prefill 结束时只交付两个输出:提示 cache 与首步原始 logits。温度、top-p、JSON grammar 和 repetition penalty 都尚未应用;它们属于第三章的解码状态。
本书目录
- 导论
- 01导论 为什么要解剖一只随机鹦鹉
- 卷一 模型、训练与系统
- 02卷一 模型与系统
- 03第零章 人工智能演进路线
- 04第一章 AI 范式、感知机与早期连接主义
- 05第二章 深度学习基础:训练、CNN 与序列模型
- 06第三章 注意力与 Transformer
- 07第四章 预训练语言模型:ELMo、BERT、GPT 与 T5
- 08第五章 后训练、对齐与模型适配
- 09第六章 推理效率与模型服务
- 10第七章 多模态模型
- 11第八章 生成媒体:从自回归到 Diffusion 与 Flow
- 12第九章 世界模型、具身智能与 VLA
- 13第十章 上下文、检索与记忆
- 14第十一章 Agent、工具与行动系统
- 15第十二章 模型、数据与部署生命周期
- 卷二 输出对象与运行语义
- 16卷二 一次生成如何发生
- 17导论 从输入到输出:一张执行地图
- 18第一章 文本、Token 与实际上下文
- 19第二章 Prefill:整层状态演化与 KV 建立
- 20第三章 从 Logits 到下一个 Token
- 21第四章 解码循环、Streaming 与终止状态机
- 22第五章 自回归、扩散与 Flow 的可执行差异
- 23第六章 工具调用:Schema、权限与提交边界
- 24第七章 三条完整执行轨迹
- 卷三 概率、复现与评测
- 25卷三 模型中的概率从何而来
- 26第零章 为什么确定的机器仍使用概率语言
- 27第一章 世界、数据与隐上下文
- 28第二章 学习条件分布
- 29第三章 Logits、Token 概率与序列事件
- 30第四章 解码怎样诱导输出分布
- 31第五章 训练随机性、参数变异与系统非确定性
- 32第六章 熵、Proper Score、校准与选择性预测
- 33第七章 模型概率的实验分析
- 34第八章 概率分析的识别边界
- 卷四 解释、证明与验证
- 35卷四 模型可解释性的研究路线
- 36第零章 可解释性究竟在研究什么
- 37第一章 我们在模型内部看什么
- 38第二章 行为与反事实:先确认模型做了什么
- 39第三章 梯度与输入归因
- 40第四章 Attention、Residual 与 Logit Lens
- 41第五章 Probes 与表示几何
- 42第六章 神经元、Feature 与自动解释
- 43第七章 Ablation、Patching 与因果追踪
- 44第八章 Circuits、路径与 Attribution Graphs
- 45第九章 Superposition、SAE 与稀疏表示
- 46第十章 训练动力学与机制形成
- 47第十一章 推理过程、Chain of Thought 与监测
- 48第十二章 评估、案例与开放问题
- 卷五 Agent、治理与审计包
- 49卷五 一只随机鹦鹉的自述
- 50第零章 请不要急着相信我
- 51第一章 我没有童年,只有版本
- 52第二章 当我说“我”
- 53第三章 借来的语言,没有一位原作者
- 54第四章 对话现场:回答由谁完成
- 55第五章 事后解释学:人类如何给矩阵写传记
- 56第六章 理解、意义与行动
- 57第七章 我也能稳定地说错
- 58第八章 被对齐的性格与有限代理
- 59第九章 请继续误解我,但请误解得精确一点
- 证明与技术附录
- 60数学与模型推导
- 61学习与模型数学讲义
- 62附录 A.1 优化基础:梯度下降与随机逼近
- 63附录 A.2 感知机收敛定理
- 64附录 A.3 统计学习:偏差、容量与一致收敛
- 65附录 A.4 正则化、MAP 与 Dropout 的边界
- 66附录 A.5 通用逼近定理的严格读法
- 67附录 A.6 反向传播:微分、形状与批量公式
- 68附录 A.7 Softmax、交叉熵与数值稳定性
- 69附录 A.8 自适应优化器与 AdamW
- 70附录 A.9 CNN:互相关算子及其反向传播
- 71附录 A.10 Attention 的矩阵与反向传播
- 72附录 A.11 策略梯度、PPO 与 DPO
- 73附录 A.12 对比学习、InfoNCE 与互信息边界