LLM 工程化全流程手册
把大语言模型从数据到线上推理服务的完整工程链路,按流程顺序系统梳理成一份可离线阅读、可搜索、可打勾的学习地图。每个技术点都回答四个问题:它是什么 → 为什么存在 → 代价与取舍是什么 → 什么时候会踩坑。
怎么用这份文档:左侧目录可以勾选(勾选=已学,进度存在浏览器本地),顶部 / 键直接全文搜索,每个章节标题右侧可点 ¶ 复制锚点,顶部可一键折叠全部 / 打印或导出 PDF。
0. 导读与全流程地图
0.1 这份文档针对什么问题
如果你已经用了两三年 LLM,日常在做训练和推理加速,那么真正缺的通常不是某个单点技术,而是把单点放到整条链路上的位置感。这种缺失会在两种时刻暴露出来:
- 遇到新概念时无法归类:比如看到某个新项目"工作在 logits 这一层",你要先知道 logits 在整个前向计算里处于哪一步、它的形状和数值特性是什么、谁在消费它,才能判断这个项目到底新在哪。
- 做技术选型时缺少约束意识:知道 KV Cache 能省显存,但不知道它和并发数、上下文长度、batch size 之间是乘法关系,于是容量规划全靠线上试错。
所以这份文档的组织原则是沿流程走,而不是按技术名词罗列。每个环节都回答同样的问题:
1. 是什么
给出精确定义与它在数据流中的位置。定义不清是后面所有误解的源头。
2. 为什么存在
它替代了什么?如果不用它,系统会在哪一步崩掉(显存、带宽、延迟、精度、成本)?
3. 取舍是什么
任何优化都是拿一项换另一项。写清代价,才能判断在你的负载下值不值。
4. 什么时候踩坑
列出已知的典型故障模式。这一节最有实战价值,也最容易被教程省略。
- 概念(蓝)= 定义与定位,需要记住的硬事实。
- 为什么需要它(绿)= 这个技术解决的真实痛点。
- 取舍(紫)= 代价、边界、选型判据。
- 常见坑(红)= 会导致事故或白干几天的问题。
- 实例·算一遍(黄)= 用具体数字算一遍,把抽象公式落到显存与延迟上。
- 索引(青)= 代表论文与工具,方便你顺藤摸瓜。
0.2 全流程地图:一张图看完
注意这条链是回环而不是直线:线上评测结果会反向决定后训练的数据配比,推理约束(比如必须支持 128K 上下文)会在预训练阶段就改变位置编码与注意力实现的选择。
| 阶段 | 核心目标 | 关键产出物 | 主要技术 | 典型失败模式 |
|---|---|---|---|---|
| 数据工程 | 决定能力上限 | 去重后的语料 + 配比方案 + 数据 schema | 抽取、去重(MinHash/LSH)、质量过滤、去污染、课程配比 | 评测集泄漏导致指标虚高;重复数据导致逐字记忆 |
| Tokenizer | 文本 ↔ id 的可逆映射 | 词表文件 + merge 规则 | BPE / Unigram / 字节回退 | 换 tokenizer 必须从头训练;压缩率差导致同样的钱只买到更少的有效 token |
| 预训练 | 获得通用基座能力 | Base checkpoint | Scaling law 定规模、DP/TP/PP/EP 并行、bf16/fp8、重计算 | loss spike 直接毁掉几天训练;并行切分不当导致通信成为瓶颈 |
| 后训练 | 从"会续写"到"听话有用" | Instruct / 推理模型 checkpoint | SFT、LoRA、RLHF/PPO、DPO 家族、GRPO/RLVR、蒸馏 | 灾难性遗忘;奖励黑客;过度拒答 |
| 对齐与安全 | 行为可控、边界清晰 | 安全策略 + 护栏 + 红队报告 | 红队、输入输出过滤、拒答训练、可解释性探针 | 把安全当成事后过滤,结果既损体验又挡不住真正的攻击 |
| 评测 | 可比较、可决策的证据 | 评测报告 + 回归门禁 | 基准测试、pass@k、LLM-as-judge、线上 A/B | 用被污染的公开榜单做决策;评委模型有位置/长度偏置 |
| 推理与部署 | 把能力变成可交付的延迟与成本 | 推理服务 + 容量模型 + SLO | KV Cache、PagedAttention、量化、投机解码、连续批处理、PD 分离 | 只优化吞吐忽略尾延迟;量化后精度静默下降 |
0.3 三种读法,对应三种真实场景
5 分钟:遇到新名词
先查配套的 llm-cheatsheet.html(术语表 + 公式卡)。找不到定义时,用顶部搜索在本文件里定位,读该节的概念块和常见坑块即可。
每章 30–45 分钟:建立结构
按第 1 → 8 章顺序读。第 1、2 章是地基(一次前向到底发生了什么、logits 到底是什么),值得反复读。
按需:知识保鲜
直接跳到第 10 章的更新日志与待核实清单,只看变化的部分和标注"快速演进"的技术。
另外,每一章末尾都有自查清单(第 10 章汇总)。如果你能不看文档答出来,说明这一章可以打勾了;答不出来,说明只是"眼熟"而不是"掌握"。
0.4 四周刷新计划
| 周 | 目标 | 读什么 | 动手做什么 |
|---|---|---|---|
| 第 1 周 | 重建地基层 | 第 1 章(形状流)+ 第 2 章(Logits 专章) | 用 transformers 打印一次前向的逐层形状;对同一 prompt 打印 top-20 logits 与 softmax 概率,观察温度如何改变排序 |
| 第 2 周 | 训练侧全景 | 第 3–5 章(数据 / 预训练 / 后训练) | 估算一次 7B 全参训练的显存账单;跑一次 LoRA 微调并对比合并前后输出差异 |
| 第 3 周 | 评估与对齐 | 第 6–7 章(安全 / 评测) | 用 lm-evaluation-harness 跑一个小模型的两个基准;写一个带位置交换的成对 judge 脚本,观察偏差 |
| 第 4 周 | 推理与前沿 | 第 8–9 章(推理部署 / Jev 专题) | 算一遍 KV Cache 容量表(并发 × 上下文);对比开启/关闭投机解码的 TPOT |
0.5 版本与更新日志
| 版本 | 日期 | 变更 |
|---|---|---|
| v1.0 | 2026-10-04 | 首版:第 0–10 章全部建立;Logits 独立成章;新增"Jev 与从 logits 读决策"专题(第 9 章),按证据等级分栏;配套速查表文件。 |
| v1.1 | 2026-10-04 | 第 9 章补入四条已逐条核对 arXiv 编号与摘要的一手文献(早期证据审计、AnyJev、LLM2Jev、Decision Hijacking),并据此改写 9.3 / 9.5 / 9.6 / 9.8;新增附录 A · 故障排查手册(症状 → 原因 → 处置,覆盖训练/后训练/推理服务/评测四类)。 |
1. 地基:一次前向到底发生了什么
这一章的目标只有一个:让你能在脑子里把「一段文本」变成「下一个 token 的概率分布」的完整过程走一遍,并且知道每一步的张量形状。后面所有章节(Logits、量化、KV Cache、投机解码、Jev)都是在这条链上做文章——不知道链在哪,就不知道别人改的是哪一环。
- 1.1 全景:五个阶段
- 1.2 Tokenizer:文本到 id
- 1.3 Embedding 与位置编码
- 1.4 Transformer block 内部
- 1.5 从 hidden state 到 logits
- 1.6 从 logits 到下一个 token
- 1.7 训练目标与 loss
- 1.8 形状与数字总表
1.1 全景:五个阶段
其中 ① 由 tokenizer 在 CPU 上完成,②③④ 是模型的张量计算(GPU),⑤ 是一段很小的确定性/随机性数学运算加控制逻辑。工程上绝大部分优化发生在 ③④ 与"如何重复 ①–⑤ 而不重复计算"。
t 步只计算最新的一个 token(第 8 章详述)。这是"看起来 O(n²) 实际可做到近似 O(n)"的根本原因。
1.2 Tokenizer:文本到 id
关键认识:tokenizer 是模型的一部分,不是预处理工具。词表一旦确定,模型的输入输出空间就固定了,换 tokenizer 等于换模型,必须从头训练。
词表大小
大词表(128K–256K):同样文本的 token 数更少 → 上下文更"能装"、同样的钱买到更多内容;但 embedding 与 lm_head 参数量随 V 线性增长,softmax 也更贵。
小词表(32K):参数省、softmax 便宜,但序列变长、稀有词被切碎。
经验区间:英文为主 32K–64K,多语言/代码 100K–256K。
特殊 token
BOS / EOS / PAD 之外,现代模型大量使用对话与工具标记(角色、轮次、工具调用边界、思考块边界)。这些是训练与推理的协议:推理时模板打错,模型表现会明显下降,这一点比换采样参数重要得多。
- 把 token 数当字数。中文在多数词表下 1 个汉字 ≈ 1–2 个 token,英文 1 个词 ≈ 1.3 个 token,代码和 JSON 的压缩率差异更大。算成本、算上下文、算 KV Cache 都必须用 token 数。
- 训练与推理用了不同版本的 tokenizer 或 chat template。表现为"模型不听话""不会停止""格式错乱",但模型本身没问题。这类 bug 极难从输出上定位,务必把 template 与 tokenizer 版本固化进部署配置。
- 手动拼接 prompt 字符串。应该用官方 apply_chat_template 之类的接口,否则特殊 token 会被当普通文本编码,等于给模型喂了错误协议。
- tokenizer 的并行/分片不一致导致同一条数据在数据加载的多个 worker 里编码结果不同(罕见但真实,尤其是自研 tokenizer 时的多线程 BPE)。
1.3 Embedding 与位置编码
token id 通过一个查表矩阵 E ∈ R^{V×d} 变成 d 维向量,得到 [B, S, d] 的初始表示。位置信息不能靠这个查表获得(查表与顺序无关),必须显式注入。
| 方案 | 做法 | 优点 | 局限 |
|---|---|---|---|
| 绝对位置嵌入 | 第 i 个位置查一个可学习向量,加到词嵌入上 | 简单 | 外推差,超过训练长度直接失效 |
| 正弦位置编码 | 固定三角函数(原始 Transformer) | 无需训练 | 被 RoPE 取代 |
| RoPE(主流) | 对 Q、K 向量按成对维度旋转,旋转角与位置成正比 | 内积天然只依赖相对位置;可通过改旋转基频/插值外推 | 外推仍需专门处理;实现细节(cos/sin 缓存、交错方式)容易出错 |
| ALiBi | 给注意力分数加与距离成线性的负偏置 | 外推直观 | 现代主流模型少用 |
θ_i = base^{-2i/d} 再乘以位置 m。两个词的内积因此只与它们的相对距离有关。长上下文扩展的本质就是改这个 base 或对位置做插值(位置插值 PI、NTK-aware、YaRN),具体见第 4.8 节。
1.4 Transformer block 内部
现代 LLM 基本都是 Pre-Norm 的 decoder-only 结构,一个 block 两步:
# Pre-Norm 残差结构(伪代码,L 层重复)
h = x + Attention(RMSNorm(x)) # 注意力:让 token 之间交换信息
y = h + FFN(RMSNorm(h)) # 前馈:逐 token 做非线性变换(承载大部分参数)
# 全部 L 层结束后:
h_final = RMSNorm(y) # 最后的 norm 不能省
logits = h_final @ E_out.T # E_out ∈ R^{V×d},即 lm_head
RMSNorm
只做缩放不做均值中心化,比 LayerNorm 便宜。放在子层之前(Pre-Norm)使深层残差通路干净、训练更稳;代价是最终必须补一个 norm。
SwiGLU FFN
三个矩阵 W_gate, W_up, W_down,FFN(x)=W_down(SiLU(W_gate x) ⊙ W_up x)。为保持参数量与经典 4d² FFN 相当,取 d_ff ≈ 8d/3(常见再取 128 的倍数)。
注意力与 KV 头数
MHA:Q/K/V 头数相同。MQA:所有 Q 头共享 1 组 KV。GQA:Q 头分组共享 KV 头(现代默认)。KV 头数直接决定 KV Cache 大小与解码时的显存带宽压力。
因果掩码
上三角置 −∞,保证第 i 个位置只能看到 ≤ i 的内容。这是"decoder-only 能拿来做训练"的前提,也是推理时 KV Cache 能成立的前提。
n_heads 降到 n_kv_heads,KV Cache 与读取量就按同比例下降。以 32 个 Q 头、8 个 KV 头为例,KV Cache 直接变成原来的 1/4,而质量损失很小。MQA 是 n_kv_heads=1 的极端情形,省得更多但质量风险更大。
注意力的形状(以 Llama-3-8B 量级为例:d=4096, n_heads=32, n_kv_heads=8, head_dim=128):
输入 x : [B, S, 4096]
Q 投影 : [B, S, 32, 128] # n_heads × head_dim
K, V 投影 : [B, S, 8, 128] # n_kv_heads × head_dim ← GQA
注意力分数 : [B, 32, S, S] # 因果掩码后上三角为 -inf
注意力输出 : [B, S, 4096] # concat 所有头后过 W_o
1.5 从 hidden state 到 logits
最后一层输出经过最终 RMSNorm,再乘输出投影矩阵(lm_head),得到整个词表上每个 token 的分数,这就是 logits:
hidden : [B, S, d]
lm_head: [V, d]
logits : [B, S, V] # 例如 [1, 8192, 128256]
权重共享(tied embedding)
让 lm_head = E(输入嵌入矩阵)可以省下 V×d 参数。以 V=128256, d=4096 计约 5.25 亿参数,对中小模型是不小的一块。Gemma 等模型默认共享,很多大模型不共享(表达能力更强)。
只需要最后一个位置
生成时只需要 logits[:, -1, :],形状 [B, 1, V]。但朴素实现会把 [B, S, V] 全算出来——这在小 batch、长上下文时是纯浪费。第 2.6 节的"稀疏输出投影"正是针对这一点。
- logits 会很大。训练充分后,正确 token 的 logit 可以是几十甚至上百。用低精度存 logits(bf16 只有约 3 位十进制有效数字)时,接近的两个候选会被压成同一个值,导致 top-1/top-2 排序抖动。需要精确比较时,softmax 与比较都要在 fp32 里做。
- 有的模型显式限制 logits。例如 Gemma 2 用
logit soft-capping(logits = cap * tanh(logits / cap),cap 常取 30)来抑制极端值、稳定训练。这意味着它的 logits 天然被压在[−30, 30],直接和别的模型比数值大小没有意义。 - 训练里还有 z-loss。PaLM 等用
z_loss = coef * logsumexp(logits)²惩罚配分函数偏离 0,防止 logits 整体漂移导致数值不稳。看到 loss 里有 z-loss 项不要当它是笔误。
1.6 从 logits 到下一个 token
这一步在工程上被实现成一条固定的流水线,顺序很重要(HuggingFace 系框架的命名可以一一对应):
logits
→ ① LogitsProcessor 链 重复惩罚 / 频率惩罚 / 存在惩罚 / logit bias /
禁止词 / 最小长度 / 约束解码(语法、正则、JSON schema)
→ ② LogitsWarper 链 温度缩放 → top-k → top-p → min-p → typical
→ ③ Sampler greedy(argmax) / multinomial(按概率采样) / beam search
→ 下一个 token id
| 参数 | 对 logits 做什么 | 典型值 | 什么时候用 / 代价 |
|---|---|---|---|
temperature | logits / T,T<1 拉大差距、T>1 压平 | 0(贪心)~1.0 | 事实性任务用低温;T 会改变概率数值,所以 logprob 不可跨温度比较 |
top_k | 只保留最大的 k 个,其余置 −∞ | 20–100 | 简单粗暴;k 固定,分布宽窄不同时表现不稳 |
top_p(核采样) | 按概率降序累加,累计超过 p 就截断 | 0.9–0.95 | 自适应候选集大小;与 top_k 可叠加 |
min_p | 保留概率 ≥ min_p × p_max 的候选 | 0.02–0.1 | 比 top_p 更不依赖分布形状,近年流行 |
repetition_penalty | 对已出现 token 的 logit 除以惩罚系数(正负号分别处理) | 1.0–1.15 | 抑制复读;会破坏概率语义,不适合需要 logprob 的场景 |
logit_bias | 对指定 token 的 logit 加性干预 | 按需 | 强制或禁止某些 token;是"改写分布",与"事后重归一化"不同(见第 9 章对比表) |
| 约束解码 | 按语法/正则/Schema 把非法 token 置 −∞ | — | 保证输出可解析;有每步掩码开销,复杂语法会拖慢解码 |
1.7 训练目标与 loss
预训练目标就是下一 token 预测:把输入右移一位当标签,对每个位置计算交叉熵。工程上有三个必须知道的细节:
- shift by one。
logits[:, :-1]与labels[:, 1:]对齐。差一位的 off-by-one 是自研训练脚本最经典的 bug,表现为 loss 能降但模型很笨。 - loss mask。SFT 时只在"助手该说的话"上计算 loss,用户输入与 padding 位置的标签置为忽略值(通常 −100)。掩码错了,模型会学会模仿用户口吻。
- 与困惑度的关系。
PPL = exp(平均交叉熵)。loss=2.0对应 PPL≈7.4;loss=1.0对应 PPL≈2.7。PPL 只在同一 tokenizer下可比——换词表后 PPL 数字直接失去意义。
B=1, S=8192, V=128256,logits 用 fp32 存:8192 × 128256 × 4 B ≈ 4.2 GB——仅仅是一个样本的 logits。加上反传需要的梯度与 softmax 中间量,轻松翻倍到 8 GB 以上。这就是为什么大模型训练常用分块计算交叉熵(把 S 维切块)、词表并行(把 V 维切到多卡)或只对需要的位置计算 logits。也解释了为什么 SFT 的 packing 长度不能随便调到 32K 以上。
1.8 形状与数字总表
以下以 Llama-3-8B 量级的配置为参照(L=32, d=4096, n_heads=32, n_kv_heads=8, head_dim=128, d_ff=14336, V=128256):
| 对象 | 形状 / 数值 | 说明 |
|---|---|---|
嵌入矩阵 E | [128256, 4096] ≈ 5.25 亿参数 | bf16 下约 1.0 GB |
| 每层注意力参数 | W_q: d×d、W_k,W_v: d×(n_kv·head_dim)、W_o: d×d | GQA 让 K/V 投影变成 1/4 |
| 每层 FFN 参数 | 3 × d × d_ff = 3×4096×14336 ≈ 1.76 亿 | 占总参数约 2/3 |
| 解码时每步的注意力分数 | [B, n_heads, 1, S_total] | 对 KV Cache 做一次读取 |
| 单 token 的 KV Cache | 2 × n_kv × head_dim × L × 2 B = 128 KiB | bf16;全 MHA 则为 512 KiB(4 倍) |
| 128K 上下文的 KV Cache | 131072 × 128 KiB ≈ 16 GiB | 单条序列!这就是长上下文服务贵的根本原因 |
| 前向 FLOPs 近似 | 约 2 × 参数量 × token 数 | 解码时几乎全是"读权重",所以是带宽受限 |
| 8B 模型 bf16 权重 | 约 16 GB | 加 KV Cache 与激活,单卡 24 GB 已很紧张 |
- 原始架构:Attention Is All You Need(2017)|RoFormer(RoPE)|GLU Variants Improve Transformer(SwiGLU)|Root Mean Square Layer Normalization
- 分组注意力:GQA: Training Generalized Multi-Query Transformer Models(GQA)|Fast Transformer Decoding: One Write-Head is All You Need(MQA)
- 训练稳定化:Gemma 2(logit soft-capping)|PaLM(z-loss)
- 动手工具:
transformers(output_hidden_states/output_logits)、torch.nn.functional、einops用于核对形状
B=1,S=8192,V=128k 的 logits 占多少显存?④ 采样流水线中"重复惩罚"和"约束解码"都作用在 logits 上,为什么前者不该和 logprob 一起用?
2. Logits 专章:模型的原始意见与它的消费方
这一章回答一个具体问题:当有人说"我的工作发生在 logits 这一层"时,他到底站在流水线的哪个位置,改的是什么,为什么这件事有价值。同时把 logits 相关的一堆容易混淆的名词(logprobs、logit bias、约束解码、分类头、logit lens、softmax 校准)摆到同一张图里区分清楚。
- 2.1 严格定义:logit 为什么叫 logit
- 2.2 形状、内存与"到底要算几个 logit"
- 2.3 消费方一:训练时的 logits
- 2.4 消费方二:推理时的 logits
- 2.5 消费方三:把 logits 当接口(六种用法)
- 2.6 数值工程:精度、稳定性、稀疏投影
- 2.7 语义陷阱:什么时候 logprob 不再等于概率
- 2.8 校准:为什么"置信度"不能当"正确率"
- 2.9 常见坑与索引
2.1 严格定义:logit 为什么叫 logit
V 类分类器,最后一层线性输出的第 i 个分量 z_i ∈ R 就叫第 i 类的 logit。它未经归一化、可正可负、无上下界。通过 softmax 变成概率:
p_i = exp(z_i) / Σ_j exp(z_j)
名字来源于二分类的 log-odds:z = ln(p / (1−p)),即"概率的比值再取对数"。多分类里它退化成"相对分数的对数"。
三个必须内化的性质,它们解释了后面 90% 的工程细节:
平移不变
所有 logit 同时加一个常数 c,softmax 结果完全不变。所以logit 的绝对值本身没有意义,只有两两之差有意义。跨模型、跨 prompt 比较 logit 大小是无效操作。
尺度敏感
所有 logit 同时乘 k 会显著改变分布形状。temperature 做的就是这件事(z/T)。所以温度不是"风格旋钮",它改变了数值语义。
差值即概率比
z_i − z_j = ln(p_i / p_j)。一个 2.3 的差值意味着 10 倍概率差,4.6 意味着 100 倍。判断"模型有多确定"时看差值比看绝对值有用得多。
好=18.2, 不错=15.7, 很=14.1, 糟=9.3:
| 候选 | logit | T=1.0 概率 | T=0.5 概率 |
|---|---|---|---|
| 好 | 18.2 | 91.0% | 99.3% |
| 不错 | 15.7 | 7.47% | 0.669% |
| 很 | 14.1 | 1.51% | 0.027% |
| 糟 | 9.3 | 0.0124% | 0.0000018% |
2.2 形状、内存与"到底要算几个 logit"
logits = hidden_final @ lm_head.T
hidden_final : [B, S, d]
lm_head : [V, d]
logits : [B, S, V] ← 三维张量,V 通常在 32k ~ 256k
关键在于 V 很大而 B×S 也不小,两者相乘会爆掉。于是有了"到底需要哪些位置的 logit"这个问题,而回答它正是很多优化的切入点:
| 场景 | 真正需要的 logit | 朴素实现的开销 | 优化手段 |
|---|---|---|---|
| 训练(预训练/SFT) | 所有非掩码位置 × 全词表 | B×S×V×4B,例:1×8192×128256×4 ≈ 4.2 GB | 分块交叉熵、词表并行、只算非掩码位置 |
| 标准解码 | [B, 1, V](最后一个位置) | 把 [B, S, V] 全算出来是纯浪费 | 只取最后位置;缓存复用 |
| 打分/排序(PPL、rerank) | 指定位置的、指定候选 token 的 logit | 同上 | 稀疏投影:只算候选行 |
| 结构化槽位读取(Jev 类) | 若干固定槽位 × 若干候选标签 | 扩散画布 4096×128256 fp32 ≈ 2.1 GB | 稀疏输出投影:只算 槽位数 × 候选数 |
| 可解释性(logit lens) | 各中间层 × 指定位置 × top-k | 每层都要投影一次 | 只对目标位置、只取 top-k |
V=128256,若一次请求 64 个问题、每题最多 26 个候选:
- 稠密:
4096 × 128256 × 4 B ≈ 2.1 GB(仅 logits,还没算 softmax 中间量),加上投影 GEMM 的算力。 - 稀疏:
64 × 26 = 1664行输出,约1664 × 4096 × 2 ≈ 1.4e7 FLOPs与1664 × 4 B ≈ 6.6 KB。 - 差距在 5–6 个数量级。
2.3 消费方一:训练时的 logits
训练时 logits 只有一个消费方:交叉熵损失。但围绕它有一串工程细节。
∂L/∂z_i = p_i − y_i(y 是 one-hot 标签)。含义直观:模型把概率分给谁,就把谁的 logit 往反方向推多少。正确 token 的 logit 会被推高,错误 token 按它当前拿到的概率被推低。这也是"logits 蒸馏"能工作的原因:教师模型的完整分布 p_teacher 可以直接作为软标签,梯度就是 p_student − p_teacher。
| 技术 | 对 logits 做什么 | 解决什么问题 | 出现位置 |
|---|---|---|---|
| logit soft-capping | z ← cap · tanh(z / cap),cap≈30 | 抑制极端 logit,稳定训练 | Gemma 2 等 |
| z-loss | 惩罚 logsumexp(z)² | 防止 logits 整体漂移导致数值不稳 | PaLM 等 |
| 标签平滑 | 目标分布从 one-hot 变成 (1−ε)·one-hot + ε/V | 减少过度自信(直接影响校准) | 较早期工作 |
| logits 蒸馏 | 用 KL(p_teacher^T ‖ p_student^T),配温度 T | 让学生学到"类间相似性",比只学硬标签信息量大得多 | 蒸馏、小模型训练 |
| 词表并行 CE | 把 V 切到多卡,各算部分 logits 后 all-reduce | 解决 4.2 GB 级 logits 显存 | Megatron 等 |
- 忽略值写错。框架用
ignore_index=−100(不是 0)。填 0 会让模型去学预测 id 为 0 的 token,loss 看起来在降但模型学坏了。 - shift 与 mask 顺序颠倒。正确顺序是:先算 loss(框架内部 shift),mask 必须构造在标签那一侧。
- softmax 用 bf16。大 logits 在 bf16 下 exp 会溢出或精度坍缩。标准做法是先减去该位置的最大 logit,再在 fp32 里算。
- 把 soft-cap 或 z-loss 当成可选项随意删。这些项是跟特定模型训练配方绑定的,去掉后重训会不稳定;加了它再去对比不同模型的 logits 数值也不可比。
2.4 消费方二:推理时的 logits
推理时 logits 的消费方比训练多得多,而且每一个都对应一个你可能用过的开关:
① 采样器
argmax(贪心)或按概率采样。temperature / top-k / top-p / min-p 全部在这一步之前改写 logits。
② logprobs 接口
OpenAI 系 API 的 logprobs / top_logprobs 就是把这一层的数值暴露给调用方,用于分类、打分、置信度估计、构造确定性规则。
③ 约束解码
按 JSON Schema、正则、语法把非法 token 的 logit 置 −∞,保证输出一定可解析。
④ 干预类处理器
重复惩罚、频率/存在惩罚、logit bias、禁止词表。注意它们改写了分布,之后算出的"概率"已不是模型原始意见。
⑤ 投机解码的验证
用目标模型的 logits 对草稿 token 做接受/拒绝判定,需要精确比较两个分布(第 8.6 节)。
⑥ 结构性读取
不做生成,只在固定槽位读候选标签的概率——即第 9 章的 Jev 类接口。这是本文档把 logits 单独成章的直接原因。
2.5 消费方三:把 logits 当接口(六种用法)
把"生成一段文本"变成"读一个分布",是近年来很活跃的一条工程路线。下面六种用法常被混为一谈,请注意区分改的是什么、需不需要训练、有没有重新归一化。
| 用法 | 怎么读 | 要不要训练 | 典型用途 |
|---|---|---|---|
| A. 单 token 槽位读取 (最简约束解码) | 把答案位置留成一个 token 的槽,取该位置 next-token 分布,重归一化到候选标签集合 | 不需要,但校准需要 | 分类、是/否判定、多选、打分(第 9 章 Jev 类) |
| B. 候选序列打分 | 把每个候选拼成完整文本,取目标 token 的 logprob 求和,按长度归一化(或取平均) | 不需要 | rerank、PPL 打分、可验证答案的排序 |
| C. 分类头读出 | 在 hidden state 上接一个专门训练的线性头(或 MLP) | 需要 | 固定标签集的判别任务;对照实验显示在匹配主干/数据/预算时并不优于直接用 lm_head 读出 |
| D. logit lens / 中间层探针 | 把中间层的 hidden state 直接过最终 lm_head,看"模型在第 k 层想说什么" | 不需要(探针本身可能要) | 可解释性,不是产品接口。与 A 用法无关,别混写 |
| E. 嵌入相似度 | 在嵌入空间做最近邻,不经过 lm_head | 不需要 | 检索、聚类、部分零样本分类 |
| F. logit 级蒸馏 | 把教师模型的完整 logits/概率当监督信号 | 需要(训练学生) | 小模型压缩、领域适配 |
- logit bias ≠ 受限 softmax。前者是加性干预(
z_i ← z_i + b_i),改变候选之间的相对关系;后者是事后重归一化(不改相对关系,但会放大数值、让"概率"更极端)。两者经常被同一篇文章混着说。 - constrained decoding ≠ 只读不生成。约束解码保证格式合法,但仍然逐 token 生成,仍有完整的解码循环、语法状态机开销与失败重试路径。只读接口是一次前向、零生成。
- logit lens 与投机解码和"读决策"都无关。前者是可视化工具,后者是加速技术。
但代价是表达力被严格限制:候选必须是预先枚举好的、通常必须是单 token 的、问题之间一般不能有依赖。这是一次非常清晰的"用表达力换延迟与确定性"的交易。
2.6 数值工程:精度、稳定性、稀疏投影
softmax 必须减最大值
softmax(z) = softmax(z − max(z)),且要在 fp32 里算。bf16 下 exp(88) 就溢出,而训练充分的模型 logits 上百很常见。
用 logsumexp 代替 exp
需要 log 概率时用 log_softmax(内部 logsumexp),比"softmax 再取 log"稳定得多。
只算需要的行
稀疏输出投影:输出头只对请求的候选 label 行做 GEMM。省显存(少分配 [B,S,V])也省算力。
只算最后位置
标准解码只需 logits[:, -1, :]。很多朴素实现把整个序列都投影,白白多算 S 倍。
2 × 8e9 = 16 GFLOPs;lm_head 是 2 × V × d = 2 × 128256 × 4096 ≈ 1.05 GFLOPs,约占 6%。结论有两面:(1) 在标准解码里稀疏投影省下的算力有限,省的主要是显存分配与带宽;(2) 但在"画布/序列很宽、只需少数位置"的场景(扩散模型、长上下文打分),稠密投影会从 6% 变成主要瓶颈,稀疏化收益就是数量级的。
2.7 语义陷阱:什么时候 logprob 不再等于概率
下面这些操作都会让"logprob"失去"模型原始概率"的含义。把它们记成一张清单,比记住任何公式都有用。
| 操作 | 怎么破坏语义 | 后果 |
|---|---|---|
| temperature ≠ 1 | z/T 改变分布形状 | 概率数值被系统性放大/压平;跨温度不可比 |
| top-k / top-p / min-p | 截断后剩余项通常被重新归一化 | 返回的 top-1 概率被人为抬高;"模型 99% 确定"可能是截断造出来的 |
| 重复/频率/存在惩罚 | 直接改写 logits | 已出现 token 的概率被压低,与模型真实意见不符 |
| logit bias / 禁止词 | 加性干预 | 同上,且是人为指定的 |
| 约束解码掩码 | 非法 token 置 −∞ 后重归一化 | 概率质量被强行搬到合法集合里 |
| bf16 logits | 有效精度约 3 位十进制 | 接近的候选可能被压成同值,排序抖动 |
| logit soft-capping | 非线性压缩极值 | 高置信区间的数值被严重压缩,不可与外模型比较 |
temperature=1、top_k=0(不截断)、top_p=1、无惩罚、无 bias、无约束掩码,并只在 fp32 下比较。反之,如果你只是想要"输出好看",那把干预全开也没关系——但此时不要再用这些数字去做任何阈值决策。最常见的生产事故就是这样来的:用一个被 top-p 截断+重复惩罚改过的"概率 0.97"去当 97% 准确的置信度。
2.8 校准:为什么"置信度"不能当"正确率"
现代 LLM 的原始概率通常不是校准的:经过 RLHF/偏好对齐后往往过度自信(RLHF 会系统性推高被选答案的 logprob),而经过蒸馏或强标签平滑的模型可能偏保守。因此:
- 置信度 ≠ 正确率,除非你在自己的留出集上验证过。
- 阈值必须在自己的数据上定。不要用别人博客里的 0.9。
- 温度缩放是成本最低的校准手段:在验证集上拟合一个标量 T(不重训模型),再用于概率输出。它不改变 top-1 排序,只让数值更接近真实正确率。
- 若要做"拒绝/升级"(reject option、模型级联),校准质量直接决定系统收益——这是第 9 章 Jev 类接口最关键的工程前提。
2.9 常见坑与索引
- 用截断后的概率当校准概率(见 2.7)。
- 把 batch 里不同样本的 logits 混着归一化:必须每个位置独立 softmax。写错维度(对
[B,S,V]在错误的轴上 softmax)会产生"看不出来但完全错"的结果。 - padding 位置的 logits 参与了任何统计:打分、平均 logprob、置信度都必须先按 attention mask / loss mask 过滤。
- 长度归一化算错:比较不同长度候选时,用"平均 logprob"而不是"求和"。求和会让短候选系统性占优。
- 在多轮对话里对整段算 logprob:模型对"用户说的话"也有概率,这部分与"助手答得好不好"无关,必须只取助手段。
- 把 logit lens 的中间层结果当模型最终判断:中间层表示没经过最终 norm 与后续层变换,早期层基本是噪声。
- 假设同一 prompt 的 logits 可复现:不同 kernel(FlashAttention 变体)、不同精度、不同 batch 组成都会带来微小差异,进而改变接近候选的排序。
- logit lens 与可解释性:Interpreting GPT: the Logit Lens(2020)|Eliciting Latent Predictions from Transformers with the Tuned Lens
- 知识探针与事实性:Language Models (Mostly) Know What They Know(自评置信度)|Calibration of Neural Networks 综述(温度缩放、ECE)
- 约束解码:Grammar-Constrained Decoding|
outlines、guidance、lm-format-enforcer、xgrammar(vLLM 内) - 打分/rerank:monoT5|Qwen3-Reranker(yes/no logit 读出)
- 蒸馏:Distilling the Knowledge in a Neural Network(软标签与温度)|MiniLLM(反向 KL)
- 动手:
transformers的output_logits、return_dict_in_generate、scores;torch.log_softmax;OpenAI/本地推理的top_logprobs
3. 数据工程:决定上限的那一环
在预训练里,数据配方是比架构更重要的变量。同一个架构、同样的算力,数据质量与配比不同,最终能力可以差出一个代际。这一章按"从原始网页到可训练样本"的处理链路走。
3.1 数据来源与它们的特性
| 来源 | 规模量级 | 独特价值 | 主要问题 |
|---|---|---|---|
| 网页抓取(Common Crawl 等) | PB 级、数十万亿 token | 覆盖面最广,是通识与语言能力的底座 | 噪声极高,需激进过滤;质量分布长尾 |
| 代码(GitHub 等) | 万亿 token 级 | 显著提升推理与结构化能力,远不止"会写代码" | 许可证与合规;重复率高;测试文件噪声 |
| 书籍与论文 | 千亿 token 级 | 长程连贯性、深度论述 | 版权最敏感;需要长文档处理 |
| 百科与结构化知识 | 百亿 token 级 | 事实密度高、格式规范 | 风格单一,重复喂会导致语气僵化 |
| 数学与形式化(含合成) | 百亿~千亿 | 推理能力的关键来源 | 合成数据的分布偏差与自洽性风险 |
| 多语言语料 | 按语种差异极大 | 跨语言迁移 | 低资源语种容易被"遗忘",需主动加权 |
| 合成数据(强模型生成) | 可控 | 补齐稀缺能力(长链推理、特定格式、指令遵循) | 模型崩塌风险:递归自训练导致分布退化 |
3.2 抽取与清洗
- 正文抽取:从 HTML 里剥掉导航、广告、页脚。工具如 trafilatura、Readability 系算法。抽取质量差会直接引入"模板噪声",让模型学会输出网页残渣。
- 规则清洗:去 control 字符、统一 Unicode(NFKC)、修 HTML 实体、剔除超短/超长/符号占比异常的行。
- 模板与样板去除:同一模板在大量页面重复出现(如"点击这里订阅"),会污染语言模型分布。按行/按段落跨文档计数是常用的做法。
- PII 与合规:邮箱、电话、身份证等敏感串的识别与脱敏;robots 与许可证合规记录。
3.3 去重:三档强度
哈希去重
文档级 SHA-256。只能去除逐字节相同的副本,成本最低。
MinHash + LSH
按 n-gram 集合算 MinHash 签名(常 128–256 个哈希、5-gram),用 LSH 分桶找近似重复对,再按 Jaccard 阈值(如 0.8)判重。工业界主力。
SemDedup 类
用嵌入做聚类去重,能抓到改写/翻译级重复,但成本高、阈值更难定,且可能误删有价值的长尾表达。
- 省算力:重复数据等于白烧 GPU。
- 防记忆:高频重复片段会被逐字记住,既是隐私/版权风险,也直接损害泛化。
- 抑制退化:重复会放大分布尖峰,让模型更容易复读、更容易在采样时陷入循环。
- 保护评测:很多"能力提升"其实是训练集里混进了评测题的原题。
3.4 质量过滤:从启发式到分类器
| 手段 | 判据 | 优点 / 风险 |
|---|---|---|
| 启发式规则 | 平均词长、符号/数字占比、重复行比例、停用词比例、是否含 "lorem ipsum" | 极便宜、可解释;但会系统性删掉代码、表格、非拉丁语种 |
| 分类器打分 | fastText / 小 Transformer 判"是否像 Wikipedia 或教科书" | 效果强;会引入风格偏置,把整个语料往百科腔推 |
| 教育价值打分 | 用强模型给样本打"对学习有用程度"分 | 质量最高;成本高、依赖教师模型、可能引入教师偏见 |
| 困惑度过滤 | 用参考模型算 PPL,剔除极端高/低 | 能滤掉乱码;但会删掉稀有但正确的专业内容 |
3.5 去污染:这一步没做,后面所有评测都不可信
- n-gram 重叠:对评测样本取 8–13-gram,在训练语料上匹配。命中率高即疑似。
- 嵌入近邻:抓改写/翻译形式的泄漏。
- 行为探针:看模型能否补全评测题的下文、是否对"题目前缀"异常敏感。
3.6 Tokenizer 训练:数据阶段的最后一个决定
- 训练语料的采样:词表要用与预训练配比一致的样本训练,否则会偏向某个领域(例如用纯英文训词表,中文就被切得很碎)。
- 压缩率指标:常用"字节/token"或"token/词"衡量。压缩率高 → 同样的上下文窗口装更多信息 → 推理成本更低。这是中文/多语言模型必须重点优化的一项。
- 词表大小与 embedding 成本:
V×d参数(可能双份,如果输出不共享)。 - 稳定性:词表一旦上线,改动成本极高(要重训或做 embedding 对齐手术),所以宁可在早期多试几版。
3.7 三种数据 schema(后面章节都会用到)
# ① 预训练:纯文本流
{"text": "……"}
# ② SFT:对话 + 只在助手回答上算 loss
{"messages": [
{"role": "user", "content": "……"},
{"role": "assistant", "content": "……"} # ← 只有这里参与 loss
]}
# ③ 偏好数据:同一 prompt 的两个回答 + 人类/模型偏好
{"prompt": "……", "chosen": "……", "rejected": "……"}
# 可验证奖励(RLVR)则不需要 rejected,只要有标准答案/可执行校验:
{"prompt": "……", "answer": "42", "verifier": "math_exact_match"}
- 只统计 token 数,不统计"有效 token 数":模板、padding、被 mask 的部分都不该算。
- 把去重做在 tokenize 之后:那时已经晚了,且会在序列边界引入人为截断。
- 训练数据与评测数据的时间重叠:即使是同一个网站的不同时间抓取,也可能包含同一份内容。
- SFT 数据格式不统一:多个来源的对话模板混用,会让模型学到矛盾的格式协议,表现为"偶尔不听话"。
- 合成数据递归放大:用模型 A 生成数据训模型 B,再用 B 生成数据训 C,几轮后分布坍缩、多样性断崖式下降。必须混入真实数据并监控多样性指标。
- 忽略数据顺序:shuffle 不充分会让同一来源的样本聚集,等效于给某个领域临时加了很高的学习率,容易触发 loss spike。
- 数据集:The Pile|C4|RedPajama|Dolma(含完整清洗管线的开源复现)|FineWeb / FineWeb-Edu(过滤配方与消融)|The Stack(代码)
- 方法:Deduplicating Training Data Makes Language Models Better|Textbooks Are All You Need(phi 系的数据哲学)|Scaling Data-Constrained Language Models(重复数据的收益递减)
- 工具:
datasets、trafilatura、datasketch(MinHash LSH)、fastText、text-dedup
4. 预训练:把算力换成能力
预训练是整条链上最贵、最难调试、也最"工程"的一环。它的核心问题只有三个:做多大(Scaling law)、怎么切到几千张卡上跑(并行)、怎么让它别崩(稳定性)。
4.1 规模直觉:算力、参数、数据三者的关系
训练总 FLOPs ≈ 6 × N × D
N = 参数量(不含 embedding 时可近似)
D = 训练 token 数
系数 6 = 前向 2(乘加)+ 反向 4
以 8B 模型、15T token 为例:6 × 8e9 × 15e12 ≈ 7.2e23 FLOPs。若单卡有效算力 400 TFLOPS(H100 bf16 峰值 989,实际 MFU 常 35%–50%),约需 7.2e23 / 4e14 ≈ 1.8e9 卡秒,即 1000 卡跑约 21 天。
MFU(Model FLOPs Utilization,实际算力/峰值算力)是预训练最重要的效率指标。大模型训练里 MFU 40%+ 已经很好,50%+ 属于调优很到位。它受通信、气泡、重计算、算子实现共同影响——这也解释了为什么并行策略的选择直接等于钱。
4.2 Scaling law:定规模的依据
| 结论 | 内容 | 工程含义 |
|---|---|---|
| Kaplan 等(2020) | loss 随参数量、数据量、算力呈幂律下降;给定算力时优先增大参数量 | 催生了"大参数、相对少数据"的一代模型 |
| Chinchilla(2022) | 算力最优时,参数量与 token 数应同比例增长,约 20 token / 参数 | 7B → 约 140B token。推翻了上一行的结论:数据被严重欠训 |
| 推理感知最优 | 把推理成本也纳入总成本后,最优解是"更小的模型 + 更多的数据" | 这是 Llama-3-8B 用 15T token(远超 Chinchilla)以及大量小模型长时间训练的理论依据 |
| 数据受限 | 高质量数据有限时,重复数据的收益快速衰减,多次重复几乎不再有增益 | 解释了为什么"数据枯竭"成为真实约束,以及为什么要做合成数据 |
4.3 架构选择:dense 还是 MoE
| Dense | MoE(稀疏专家) | |
|---|---|---|
| 参数量 vs 计算量 | 绑定:参数多则每 token 计算多 | 解耦:总参数可以很大,每 token 只激活少数专家 |
| 训练算力效率 | 基线 | 同算力下通常更强(更多容量) |
| 显存占用 | ≈ 参数量 | 所有专家都要常驻,显存按总参数算,不按激活算 |
| 通信 | TP/PP/DP 为主 | 额外需要 all-to-all(token 发到专家所在卡),突发性强、对网络敏感 |
| 训练稳定性 | 较稳 | 路由不均衡、专家塌缩、loss spike 风险更高 |
| 推理特性 | 规则、易批处理 | batch 内专家负载不均 → 利用率波动大;需要 EP 与专门调度 |
| 微调与量化 | 生态成熟 | 工具链支持较晚,量化时专家分布不均增加难度 |
4.4 并行策略:切什么、通信多少
这是预训练工程的核心表格。判断一个并行方案是否可行,只要看通信量与可用带宽是否匹配。
| 策略 | 切分维度 | 通信原语 / 频率 | 带宽要求 | 解决的问题 |
|---|---|---|---|---|
| DP 数据并行 | batch 维(每卡一份完整模型) | 梯度 all-reduce,每步 1 次,量 ≈ 2×参数量 | 中低(可跨节点,梯度累积/重叠缓解) | 吞吐;但每卡都要放全量优化器状态 |
| ZeRO-1/2/3(FSDP) | DP 的显存优化版:分片优化器状态 / +梯度 / +参数 | stage 越高通信越多;ZeRO-3 每层需 all-gather 参数 | 中高 | 单卡放不下优化器状态——最常见的第一步 |
| TP 张量并行 | 层内矩阵(列/行切分) | 每层 2 次 all-reduce,频率极高 | 极高,基本要求 NVLink 同机 | 单层参数放不下;层内并行度提升 |
| PP 流水并行 | 按层切到不同卡 | 相邻 stage 点对点传激活,量小但需调度 | 低,可跨节点 | 超深模型;代价是流水气泡 |
| SP 序列并行 | norm/dropout 区域的序列维 | 与 TP 配合,减少激活 | 同 TP | 长序列下的激活显存 |
| CP / Ring 上下文并行 | 序列维切分做注意力 | 环形传递 KV | 中高 | 超长上下文的注意力显存与算力 |
| EP 专家并行 | MoE 专家分布到不同卡 | all-to-all,突发 | 高且对拓扑敏感 | MoE 的专家容量 |
节点内(NVLink,带宽最高)→ TP + EP + SP/CP
节点间(IB/RoCE) → PP(通信量小)
最外层 → DP / ZeRO(可与计算重叠)
原则:通信最频繁的放到带宽最高的连接上。反过来放(把 TP 跨节点)会立刻把 MFU 打到个位数。
4.5 显存账单:全参训练到底要多少
| 项目 | 精度 | 公式 | 7B 占用 |
|---|---|---|---|
| 权重 | bf16 | 2N | 14 GB |
| 梯度 | bf16 | 2N | 14 GB |
| 主权重副本 | fp32 | 4N | 28 GB |
| Adam 一阶动量 m | fp32 | 4N | 28 GB |
| Adam 二阶动量 v | fp32 | 4N | 28 GB |
| 小计(不含激活) | 16N | ≈ 112 GB |
(28+28+28+14)/8 + 14 ≈ 26 GB,再加激活与临时缓冲就比较舒服了。对比 LoRA:基座 14 GB 冻结 + 极小的 adapter 与优化器状态,单张 24 GB 卡即可微调 7B。这就是 PEFT 在工程上不可替代的原因。
激活显存与 B × S × L × d 成正比,长序列下会成为主要项。控制手段:梯度检查点(重计算,用算力换显存,通常多花约 30% 时间)、序列并行、分块注意力、以及把中间量以低精度存储。
4.6 混合精度与低精度训练
现代默认
8 位指数(与 fp32 同量级范围)、7 位尾数。因范围足够大,通常不需要 loss scaling。缺点是精度低,小梯度可能被吞掉,所以优化器状态仍用 fp32。
需 loss scaling
范围窄,梯度下溢需要放大再缩回。今天主要用于老硬件兼容。
Hopper/Blackwell 起
E4M3/E5M2,需逐张量缩放与延迟缩放策略。能显著提升吞吐,但对稳定性与实现成熟度要求高。
4.7 训练稳定性:loss spike 的因果与处置
| 可能原因 | 机理 | 缓解手段 |
|---|---|---|
| 坏数据批次 | 某批样本异常(重复、乱码、超长)造成巨大梯度 | 数据清洗与长度控制;跳过该 batch |
| 学习率/warmup 不当 | 早期参数远离初始化点,更新过猛 | 更长 warmup、更低峰值 LR、cosine 衰减 |
| 注意力 logits 爆炸 | QK 内积过大 → softmax 饱和 → 梯度异常("massive activations") | QK-Norm、softmax 前缩放、logit soft-capping |
| 输出层 logits 漂移 | 配分函数持续增大 | z-loss |
| 低精度溢出 | fp16 下溢/上溢 | 改用 bf16;动态 loss scaling |
| 初始化/参数化不当 | 深层残差累积过大 | 按 1/√(2L) 之类缩放初始化;μP |
- 监控梯度范数,不要只看 loss。
- 发现尖峰:回滚到尖峰前若干步的 checkpoint,跳过导致尖峰的数据分片,并略微降低学习率后重启。
- 不要"继续跑看它能不能自己好"——发散的训练很少能靠等待恢复,而等待的成本是按天算的。
- 把每次尖峰的数据分片、LR、step 记进训练日志,几次之后就能定位到配方问题。
4.8 长上下文扩展
| 方法 | 做法 | 特点 |
|---|---|---|
| 位置插值(PI) | 把超出训练长度的位置压缩回训练范围内 | 简单有效,短上下文性能损失小,实现即插即用 |
| NTK-aware | 按频率高低非线性调整 RoPE 基频 | 比 PI 更好地保留高频(局部)信息 |
| YaRN | NTK 思路 + 注意力温度修正 | 少步数即可扩展到很长,工业界常用 |
| 继续预训练 | 在长文档上继续训练 | 效果最好,但需要长文档语料与可观算力 |
| 注意力结构改造 | 滑窗注意力、attention sink、稀疏注意力 | 降低 O(n²) 成本,但与既有权重兼容性需验证 |
- "宣称长度" ≠ "有效长度"。支持 128K 不代表在 128K 上还能找到中间位置的针。必须用 NIAH(needle-in-a-haystack)、RULER、LongBench 之类做位置 × 长度的二维评估,常见失效模式是中间位置塌陷(lost in the middle)。
- prefill 成本是平方级的。128K 的 prefill 算力与显存远超线性直觉,这也是 PD 分离(第 8.7 节)存在的理由。
- KV Cache 是线性增长的。128K 单序列在 8B 模型上就是约 16 GiB——容量规划必须按这个算,而不是按权重算。
4.9 MoE 训练细节
- 路由:每 token 选 top-k 专家(k 常为 1–8)。细粒度专家 + 共享专家是当前主流设计:把专家切得更小更多,并留若干"永远激活"的共享专家承载通用能力。
- 负载均衡:若无约束,路由会塌缩到少数专家。用辅助损失(aux loss,鼓励各专家被均匀使用)或专家选择路由(expert-choice)来均衡;过强的 aux loss 会损害质量,权重需要调。
- 容量因子与丢 token:每个专家有容量上限,超出部分的 token 会被丢弃(或走残差)。丢弃比例是重要监控指标。
- 通信:all-to-all 是主要瓶颈,需与计算重叠;专家放置要考虑拓扑。
4.10 基础设施与容错
常见组合
Megatron-LM(TP/PP/EP 最成熟)|DeepSpeed(ZeRO 系)|FSDP/FSDP2(PyTorch 原生)|NeMo(封装)|torchtitan / MaxText(现代参考实现)|veRL / OpenRLHF(后训练)
必须提前设计的事
异步 checkpoint(不阻塞训练)|分片状态的一致性|断点续训的数据序恢复(否则等于重复喂数据)|节点故障自动重启|慢节点(straggler)检测
- 续训后数据顺序错乱:看起来 loss 曲线正常,实际模型见了重复数据,评测指标莫名下降。
- 只有一张卡上出了问题:多卡训练是"最慢的卡决定速度",也是"任何一张卡出错整体出错"。日志必须能定位到 rank。
- checkpoint 格式与并行度绑定:改变 TP/PP 度数后无法直接加载。要预留 checkpoint 转换脚本。
- 用训练 loss 判断模型好坏:loss 更低不代表下游更好,尤其在多语言与代码混合配比下。
- Scaling:Scaling Laws for Neural Language Models(Kaplan)|Training Compute-Optimal LLMs(Chinchilla)|Scaling Data-Constrained Language Models
- 并行与系统:Megatron-LM|ZeRO|Efficient Large-Scale Language Model Training on GPU Clusters Using Megatron-LM(3D 并行)|Ring Attention|Sequence Parallelism
- 稳定性:Gemma 2|PaLM|Numerical instability 相关分析与 QK-Norm|μP / Tensor Programs V
- 长上下文:RoFormer|YaRN|Lost in the Middle|RULER|StreamingLLM(attention sink)
- MoE:Switch Transformer|GShard|DeepSeekMoE|Mixtral
6ND 估算你手上一次训练的总 FLOPs 和卡天。② 为什么 TP 必须放在 NVLink 域内,而 PP 可以跨节点?③ 7B 全参训练的优化器状态占多少显存,ZeRO-2 分片到 8 卡后是多少?④ 出现 loss spike 的标准处置流程是什么?⑤ 为什么 MoE"3.8B 激活"不等于"3.8B 的显存需求"?
5. 后训练:从"会续写"到"听话有用"
预训练让模型学会语言与世界知识,后训练决定它怎么用这些能力。这一层的技术演化非常快,但骨架是清晰的:SFT 教格式与任务 → 偏好对齐教取舍 → 可验证奖励教推理。
5.1 SFT:最有效、也最容易被做坏的一步
- 数据质量 > 数量。少量高质量、多样化的样本(几千条量级)往往胜过几十万条噪声样本。混合来源时,格式一致性比单条样本的精美程度更重要。
- 轮次与长度:多轮对话要正确构造 mask(只算助手段);样本长度分布直接决定 padding/packing 效率。
- 超参经验:全参微调 LR 常在
1e-5 ~ 2e-5,LoRA 常在1e-4 ~ 2e-4;epochs 通常 1–3,再多就出现过拟合与"只会一种腔调"。 - 灾难性遗忘:SFT 太猛会削弱基座能力(多语言、长文、代码)。缓解:混入一定比例的预训练数据(replay)、降低 LR、用 LoRA、控制步数。
- packing 引入样本间串扰。把多条样本拼成一条长序列能提升吞吐,但如果不做块对角注意力掩码,后面的样本会"看到"前面的样本,学出奇怪的关联。要么用注意力隔离,要么放弃 packing。
- mask 构造错位。多轮对话里把用户轮也算进 loss,模型会学会以用户口吻自我回复。
- 训练与推理模板不一致。训练用 A 模板、部署用 B 模板,模型表现会明显下降,而且表现为"随机不听话"。
- 用 SFT 修知识错误。SFT 擅长改行为,不擅长注入大量新事实;需要知识注入时应回到继续预训练或 RAG。
5.2 参数高效微调:LoRA 家族
W,只训练一个低秩增量 ΔW = B·A(A ∈ R^{r×d_in}、B ∈ R^{d_out×r},r ≪ d),前向为 x(W + α/r · BA)。省显存的机理很直接:不需要为基座存梯度与优化器状态——按第 4.5 节,那部分正好是
16N 里的大头。
| 变体 | 关键改动 | 解决的问题 |
|---|---|---|
| LoRA | 低秩增量 + α/r 缩放 | 显存与存储;一个基座挂多个适配器 |
| QLoRA | 基座 4-bit 量化(NF4)+ 反量化计算 + LoRA | 进一步压低基座显存,单卡微调大模型 |
| DoRA | 把权重分解为幅度 + 方向,只对方向做低秩更新 | 低秩下更接近全参微调的效果 |
| AdaLoRA / 变秩 | 按重要性动态分配秩预算 | 同样参数预算下效果更好 |
| Prefix / P-Tuning | 只训练软提示向量 | 参数更少,但占据上下文位置、效果上限较低 |
- 合并进基座:推理零额外开销,但每个任务一份权重(存储与部署成本 ×N)。
- 在线挂载(多 LoRA):一份基座服务多个适配器,显存只多了一点;代价是每步多一次小矩阵乘,且批量内不同适配器需要分组处理,调度更复杂。
- 经验:适配器数量多、流量分散 → 多 LoRA 服务;单个适配器吃满流量 → 合并。
- target_modules 选错:只挂
q_proj, v_proj是最老的做法,挂全线性层(含 FFN)通常明显更好,代价是参数变多。 - α 与 r 的配比:
α/r实质是缩放,改了 r 却不调 α,等效学习率就变了。 - QLoRA 的反量化开销:训练尚可,不要用 4-bit 基座做生产推理,除非已验证精度;推理应单独量化(第 8.5 节)。
- 适配器与基座版本错配:部署时基座 revision 变了却继续用老适配器,效果会静默下降。
5.3 偏好对齐总览
| 方法 | 需要的信号 | 要不要奖励模型 | 要不要参考模型 | 主要特点 |
|---|---|---|---|---|
| RLHF / PPO | 成对偏好 → 训 RM → 用 RM 打分 | 要 | 要(KL 约束) | 在线采样,效果强;四模型并存,工程最重、最容易不稳定 |
| DPO | 成对偏好(离线) | 不要 | 要 | 把 RL 目标解析地转成分类损失;稳定、便宜,是当前主流 |
| IPO / KTO / ORPO / SimPO | 成对偏好,或二元好/坏标签 | 不要 | 视方法而定 | 各自修补 DPO 的特定缺陷(过拟合、需要成对、长度偏置、是否需参考模型) |
| GRPO / RLOO | 对同一 prompt 多次采样并打分 | 可选(多为规则/验证器) | 要(KL) | 免价值网络,用组内相对优势;是推理模型训练的主力 |
| RLVR | 可验证奖励(答案对错、单测通过、格式合规) | 不要 | 要 | 奖励不可被"讨好",能显著提升推理;但仅适用于可验证任务 |
L_DPO = − log σ( β·[log(π_θ(y_w|x)/π_ref(y_w|x))
− log(π_θ(y_l|x)/π_ref(y_l|x))] )
y_w = 被偏好的回答, y_l = 被拒绝的回答, β 控制偏离参考模型的程度
直觉:提高好回答相对参考模型的概率,压低坏回答相对参考模型的概率。它绕过了"先训 RM 再 RL"的两段式,因此工程上便宜得多。
G 个回答,得到奖励 r_1..r_G,用组内归一化当优势:
A_i = (r_i − mean(r)) / std(r)
L = − E[ min( ρ_i·A_i , clip(ρ_i, 1−ε, 1+ε)·A_i ) − β·KL(π_θ‖π_ref) ]
ρ_i = π_θ(o_i|x) / π_θ_old(o_i|x)
省掉了 PPO 的价值网络(critic),显存与调参负担都下降;组内相对比较使得奖励的绝对尺度不重要——这正是它能与"答案对错"这类 0/1 奖励配合的原因。
- 奖励黑客(reward hacking):模型学会迎合奖励模型的表面特征——更长、更多列表、更多"让我来帮你"、更自信,而不是更正确。必须持续用人类/独立评测复核,并监控长度与格式指标。
- 长度偏置:RM 与 judge 都偏好长回答。DPO 家族尤其容易把"变长"当成提升偏好的捷径。SimPO、长度正则、长度平衡的偏好数据都是应对手段。
- 过度拒答 / 谄媚:安全对齐过头会拒答正常请求;偏好数据偏向"顺从"会让模型放弃指出用户错误。
- KL 崩塌:β 或 KL 系数太小 → 模型跑偏、多样性丧失;太大 → 几乎不学习。
- 离线偏好数据分布漂移:DPO 用固定偏好集,策略一变数据就"过期",效果低于在线方法。
- 用 RL 修知识:同 SFT,RL 也改不了缺失的知识,只会改变表达与策略。
5.4 蒸馏:把大模型的能力搬到小模型
输出蒸馏
用教师生成回答做 SFT 数据。on-policy(用学生自己采样的轨迹请教师纠正)通常优于纯 off-policy,能缓解曝光偏差。最易落地。
分布蒸馏
最小化 KL(p_teacher^T ‖ p_student^T)(见第 2.3 节)。信息量最大,但要求同词表,实践上多用于同族模型压缩。
思维链蒸馏
连推理过程一起学。风险是学到的可能是"看起来像推理"的模板,而没有真正的可迁移推理能力。
5.5 模型合并与领域适配
- 模型汤 / SLERP / 任务向量:把多个同源微调模型的权重直接平均或做插值。成本极低(不需要重训),在"多个窄任务各训一个模型"时非常划算。
- TIES / DARE:先修剪小幅度参数、再解决符号冲突,最后合并。比朴素平均更稳,能减少互相干扰。
- 继续预训练(CPT):注入领域知识(法律、医疗、内部文档)。注意:CPT 容易造成通用能力退化,应混入通用数据并做回归评测。
- 合并的评测纪律:合并出来的模型必须在所有子任务上回归,避免"平均分涨了但某个任务崩了"。
- SFT 与数据:InstructGPT|LIMA: Less Is More for Alignment|Self-Instruct|Magpie
- PEFT:LoRA|QLoRA|DoRA|
peft、unsloth、LLaMA-Factory、axolotl - 偏好对齐:Training language models to follow instructions with human feedback(RLHF)|DPO|IPO|KTO|ORPO|SimPO
- 推理强化:DeepSeek-R1(GRPO + RLVR)|GRPO|RLOO|Let's Verify Step by Step(PRM)|Math-Shepherd
- 蒸馏:Distilling the Knowledge in a Neural Network|MiniLLM|On-Policy Distillation(GKD)
- 合并:Model Soups|TIES-Merging|DARE|
mergekit
16N)?② DPO 相比 RLHF 省掉了哪两个组件?③ GRPO 省掉了什么网络,为什么组内归一化让奖励尺度不再重要?④ "奖励黑客"最常见的三种表现形式是什么,怎么监控?⑤ on-policy 蒸馏为什么优于纯 off-policy?
6. 对齐与安全:让能力落在可控边界内
安全不是"最后一层过滤器",而是横跨数据、训练、推理、产品四层的约束体系。把它当过滤器做,结果通常是:体验被削掉了,真正的攻击仍然能过。
6.1 有用性与无害性的张力
6.2 攻击面
| 攻击 | 机理 | 为什么难防 |
|---|---|---|
| 越狱(jailbreak) | 通过角色扮演、编码、多语言、分步诱导绕过安全训练 | 攻击空间是开放的,防御方要覆盖所有表述 |
| 提示注入(prompt injection) | 把指令藏进模型会读到的数据里(网页、文档、工具返回、检索结果) | 模型无法从结构上区分"指令"与"数据"——二者都在同一个 token 流里。这是当前最本质的未解问题之一 |
| 数据外泄 | 诱导模型复现训练数据或系统提示、把上下文里的敏感信息发到外部 | 记忆与泛化的边界模糊;工具调用把外泄变成一次正常 API 调用 |
| 间接注入 + 工具滥用 | 在检索文档里放指令,让 Agent 执行危险操作(转账、删库、发邮件) | Agent 有真实副作用,且攻击者可污染长链条中的任意一环 |
工程含义:任何基于模型概率的下游判断,都必须假设输入可能被污染,因此要有阈值 + 升级 + 人工复核 + 最小权限,而不能因为"输出是结构化的、类型安全的"就认为它可信。
6.3 防御的分层
让模型学会边界
安全 SFT(含拒答样本)、偏好数据里包含"该拒就拒"与"不该拒就别拒"两侧、红队数据回流。目标是校准边界的形状,而不是一味提高拒答率。
护栏与隔离
输入分类器(检测注入/越狱)、输出过滤器(PII、有害内容)、权限隔离(Agent 只能调用白名单工具、写操作要二次确认)、外部内容的来源标记与信任级别。
监控与响应
记录完整轨迹(含检索到的原文)、异常检测(突然的工具调用序列)、速率与配额限制、可回滚的副作用(软删除、事务、幂等)。
- 把安全当成后置过滤器:过滤器只能处理已生成的文本,无法阻止 Agent 已经调用了危险工具。
- 只看平均拒答率:安全评估必须看分类型的漏放率与误拦率,平均值会掩盖严重的单类问题。
- 拿安全提示词当防御:"不要被注入"这类系统提示可以被绕过,只能作为纵深防御的一层。
- 不做红队回归:每次模型/提示词更新后,之前修好的攻击会重新出现。红队用例必须进 CI。
- 低估多语言风险:安全训练通常以英文为主,低资源语种的越狱成功率显著更高。
6.4 幻觉与事实性
- 来源分类:训练数据缺口(不知道)、冲突知识(记混)、解码采样(随机性导致编造)、上下文误用(RAG 召回了错误内容)。不同来源要用完全不同的手段。
- 可行手段:检索增强(把知识外部化)、要求给出处并校验出处、自一致性/多次采样投票、工具化(计算、检索、执行代码)、拒答与不确定性表达。
- 不可靠手段:只靠"请勿幻觉"的提示词;把 logprob 当正确率(见第 2.8 节)。
6.5 可解释性工具箱(与 logits 直接相关的部分)
| 工具 | 读的是哪一层 | 能回答什么 | 不能回答什么 |
|---|---|---|---|
| logit lens / tuned lens | 中间层 hidden state 过输出头 | 信息在哪一层开始成形;模型"中途想说什么" | 不是模型的最终判断;早期层结果接近噪声 |
| 线性探针 probing | 指定层的 hidden state | 某概念/属性是否线性可解码(如"这句话是否真实") | 相关性非因果;探针自身需要训练与验证 |
| 稀疏自编码器 SAE | 激活空间 | 把叠加的激活分解成可解释特征("特征即方向") | 覆盖不全;特征解释带主观性 |
| 注意力可视化 | 注意力权重 | token 之间的信息流动 | 注意力权重 ≠ 因果重要性 |
| 归因/消融 | 输入或组件 | 哪些输入片段真正影响输出(因果) | 成本高;结果随基线选择变化 |
- 对齐总论:InstructGPT|Constitutional AI|Scalable Oversight 相关综述
- 攻击与防御:Universal and Transferable Adversarial Attacks on Aligned LMs|Not what you've signed up for: Compromising Real-World LLM-Integrated Applications with Indirect Prompt Injection|OWASP LLM Top 10|GCG|Many-shot Jailbreaking
- 幻觉:Survey on Hallucination in NLG|SelfCheckGPT|Semantic Entropy(不确定性估计)
- 可解释性:Toy Models of Superposition|Scaling Monosemanticity(SAE)|Towards Monosemanticity|Tuned Lens
- 工具:
TransformerLens、nnsight、baukit、SAELens
7. 评测:你怎么知道前面几步做对了
评测是整条链的反馈信号。信号不可信,前面所有优化都是在盲调。这一章的重点不是列举榜单,而是识别评测什么时候在骗你。
7.1 评测的三个层次
能力(capability)
知识、推理、代码、数学、多语言。通常用公开基准 + 内部私有集。私有集是对抗污染的唯一可靠手段。
行为(alignment)
指令遵循、拒答边界、格式合规、谄媚程度、安全漏放/误拦率。多数需要人工或强模型评委。
系统(system)
端到端任务成功率、延迟与成本、工具调用正确率、失败可恢复性。只有这一层能回答"能不能上线"。
7.2 基准地图与它们的失效模式
| 类别 | 代表 | 主要失效模式 |
|---|---|---|
| 通识知识 | MMLU 系、GPQA | 污染最严重;题目短、答案可猜;已接近饱和 |
| 数学与推理 | AIME、MATH、GSM8K | 答案抽取规则敏感;"答案对但过程错";可用工具/代码绕过 |
| 代码 | HumanEval、SWE-bench 系 | 测试用例泄漏;环境依赖;数据划分与真实仓库分布不一致 |
| 指令遵循 | IFEval 系 | 可被格式过拟合;与真实用户请求分布差距大 |
| 长上下文 | NIAH、RULER、LongBench | "针"的构造太容易;只测召回不测推理;长度与位置覆盖不全 |
| 安全 | 红队集、越狱集 | 攻击更新快于基准更新;单一语言/单一攻击类型 |
| 偏好/主观 | Chatbot Arena 类 | 风格偏置(长、排版好、自信者占优);投票人群偏差 |
- 污染:训练数据里含评测题(见第 3.5 节)。表现是"某个基准上异常高,同族其他基准正常"。
- 饱和:分数挤在 90+ 的窄区间,差异落在噪声内。此时该换更难的自建集,而不是继续排名。
- 格式过拟合:模型学会了基准的标准答案格式(如固定输出
####后跟数字),在真实任务上并不具备同样能力。
7.3 指标与其含义
| 指标 | 定义 | 什么时候用 / 注意 |
|---|---|---|
| accuracy / exact match | 完全正确的比例 | 客观题。注意归一化规则(大小写、单位、等价形式)会显著改变结果 |
| pass@k | 采样 k 次至少有一次通过 | 代码与数学。k 越大越"宽容",要明确报告 k 与采样温度 |
| PPL / loss | 指数化的平均交叉熵 | 仅在同一 tokenizer 下可比;与下游能力不是单调关系 |
| win rate | 成对比较的胜率 | 主观任务;必须控制位置与长度偏置 |
| Elo / Bradley-Terry | 由成对结果拟合出的排名分 | 跨批次可比,但依赖对手池;新模型加入会改变全体分 |
| 系统指标 | 任务成功率、TTFT/TPOT、$/千次调用 | 上线决策只用这组 |
7.4 LLM-as-judge:好用,但必须防偏
| 偏差 | 表现 | 缓解 |
|---|---|---|
| 位置偏置 | 偏爱第一个(或第二个)出现的答案 | 交换顺序各评一次,只保留结论一致的样本 |
| 长度/格式偏置 | 偏爱更长、更多分点、更"自信"的回答 | 长度配对控制;在评委提示里显式要求忽略长度;监控胜者长度差 |
| 自我偏好 | 偏爱与自己同族的模型输出 | 用多个不同族评委投票;避免用被评模型自己当评委 |
| 评分不稳定 | 同一输入重复评分结果不同 | 固定温度(多为 0)、多次采样取多数;报告一致性指标 |
| 与人类不一致 | 在专业/安全维度上系统性偏离 | 保留人工标注子集做校准;报告评委与人类的相关系数 |
7.5 线上评测
- 离线 → 在线之间必须有门禁:把关键评测做成 CI,指标退化超过阈值就阻止发布。
- A/B 的注意点:分流要按用户而非按请求(避免同一用户体验抖动);要提前定义主指标与最小可检测效应;看尾延迟与失败率,平均值会掩盖问题。
- 影子流量:新模型只推理不影响用户,用来提前暴露崩溃与格式错误。
- 生产监控:输出长度分布、拒答率、工具调用失败率、解析失败率、用户追问率——这些比离线榜单更早发现退化。
- 用被污染的公开榜单做选型决策(最常见的重大误判)。
- 不固定解码参数:temperature 从 0 改成 0.7,分数变了,却归因于模型。
- 样本量太小:几百条样本上的 2 个点差异基本是噪声,却据此选型。
- 只报平均分:掩盖了某一类任务的严重退化。
- 把 judge 的分数当绝对真值:它是相对信号,必须配人工校准。
- 不做"同一模型重复评测"的方差估计:不知道噪声水平,就无法判断差异是否显著。
- 框架:
lm-evaluation-harness|lighteval|OpenCompass|HELM|EvalPlus|SWE-bench|RULER|Inspect - 方法:Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena|Length-Controlled AlpacaEval|Lost in the Middle|Your Benchmark is Broken 类批评文献
8. 推理与部署:把能力变成延迟与成本
这一章是整条链路里工程收益最直接的一环。核心认识只有一句:prefill 是算力受限,decode 是显存带宽受限。几乎所有推理优化技术,都能被归类为"针对这两者之一做了什么"。
- 8.1 两阶段模型与 roofline
- 8.2 该看哪些指标
- 8.3 KV Cache:容量、分页、复用
- 8.4 注意力算子
- 8.5 量化
- 8.6 投机解码与约束解码
- 8.7 批处理与调度(含 PD 分离)
- 8.8 分布式推理
- 8.9 框架选型
- 8.10 服务化与成本模型
8.1 两阶段模型与 roofline
Prefill(预填充)
把整段输入一次性算完,并行处理所有输入 token。计算量大、矩阵乘密集,属于 compute-bound。它的耗时直接决定 TTFT。
Decode(解码)
每步只算 1 个新 token,但要读取全部权重和整个 KV Cache。算力几乎闲置,属于 memory-bandwidth-bound。它决定 TPOT。
- 每生成 1 个 token,需要读的权重约
16 GB(bf16 下2N)。 - 产生的计算约
2N = 16 GFLOPs。 - 算术强度 ≈
16e9 / 16e9 = 1 FLOP/Byte。 - H100 的 bf16 峰值约 989 TFLOPS、显存带宽约 3.35 TB/s,其拐点在约
989e12 / 3.35e12 ≈ 295 FLOP/Byte。 - 1 远小于 295 → decode 严重落在带宽侧。理论上限约
3.35e12 / 16e9 ≈ 209 token/s(不管 batch 多大,单个请求只能这么快)。
8.2 该看哪些指标
| 指标 | 含义 | 被什么影响 |
|---|---|---|
| TTFT | 首 token 时间(排队 + prefill) | 输入长度、队列深度、prefill 是否被 decode 抢占(chunked prefill 相关) |
| TPOT / ITL | 每个输出 token 的平均耗时(不含首 token) | batch 大小、KV Cache 长度、带宽、是否启用量化/投机解码 |
| 端到端延迟 | 排队 + TTFT + (n_out−1)×TPOT | 输出长度影响巨大:长回答的尾延迟主要由 TPOT 决定 |
| 吞吐 | 总 token/s(输入+输出) | batch、并行策略、算子效率 |
| goodput | 满足 SLO 的 token/s | 唯一能指导容量规划的指标:吞吐再高但违反 TTFT SLO 的请求是无效产出 |
8.3 KV Cache:容量、分页与复用
KV Cache 字节数 = 2 × L × n_kv_heads × head_dim × S × B × bytes_per_elem
↑K和V ↑层数 ↑缓存长度 ↑批次
2 × 32 × 8 × 128 × 2 B = 131072 B = 128 KiB/token(若为全 MHA 的 32 个 KV 头,则是 512 KiB/token,4 倍)。
| 上下文长度 | 单序列 KV | 8 并发 | 32 并发 | 128 并发 |
|---|---|---|---|---|
| 4K | 512 MiB | 4 GiB | 16 GiB | 64 GiB |
| 32K | 4 GiB | 32 GiB | 128 GiB | 512 GiB |
| 128K | 16 GiB | 128 GiB | 512 GiB | 2 TiB |
| 技术 | 做法 | 收益 | 代价 |
|---|---|---|---|
| PagedAttention | 把 KV 切成固定大小的块(常 16 token)非连续存储,逻辑上连续 | 基本消除显存碎片,利用率可到 90%+;支持块级共享(前缀缓存、copy-on-write) | 需要专门 kernel;块大小是调参项 |
| 前缀缓存 | 相同前缀(系统提示、few-shot 示例、长文档)复用已算好的 KV 块 | Agent 场景收益极大,TTFT 可降一个数量级 | 需要前缀匹配/哈希与淘汰策略;命中率取决于请求分布 |
| KV 量化 | KV 存成 FP8/INT8(有时只量化 K 或 V) | KV 显存减半 → 并发翻倍或上下文翻倍 | 长上下文下的精度损失需要实测;对注意力数值敏感 |
| GQA / MQA | 减少 KV 头数(架构层解决) | 直接降到 1/4 或更低 | 需要在训练时就定好,无法事后改 |
| 滑窗 / 注意力池 | 只保留最近 N 个 token 的 KV,或用注意力池保留"汇点" | 把线性增长变成常数 | 丢失远期信息;需要按任务验证 |
| 驱逐 / 压缩 | 按重要性丢弃或合并历史 KV(H2O、SnapKV 类) | 长对话下显著省显存 | 策略复杂,质量风险随任务而变 |
- 按权重估容量:这是最常见的容量规划错误。必须按
权重 + KV×并发 + 激活与临时缓冲一起算。 - 忽略显存碎片:没有分页管理时,长短请求混合会让可用显存迅速碎片化,表现为"明明还有显存却 OOM 或无法接纳新请求"。
- 前缀缓存命中率不监控:开了前缀缓存但请求前缀每次都不同(比如把时间戳放进系统提示),命中率为 0,白付复杂度。
- 把 KV 量化当免费午餐:短上下文影响小,长上下文与需要精确检索的任务上可能明显退化。
- 抢占与重算策略未设计:显存不足时框架会抢占请求(丢弃 KV,稍后重算 prefill)。若不理解这一点,会看到"负载高时 TTFT 突然翻倍"的怪现象。
8.4 注意力算子
| 算子 | 解决什么 | 关键点 |
|---|---|---|
| FlashAttention 1/2/3 | 注意力中间矩阵 [S,S] 太大,读写显存成为瓶颈 | 分块 + 在线 softmax,把中间量留在片上(SRAM),不落显存,是 IO 优化而非近似算法 |
| FlashDecoding / 拆分 KV | decode 时 batch 小、KV 长,并行度不足 | 沿 KV 维切分并行归约,提升长上下文 decode 的 GPU 利用率 |
| 融合 kernel | 大量小算子的启动开销与中间读写 | RMSNorm+量化、RoPE、QKV 投影融合等;低 batch 下收益显著 |
| 分块 prefill(chunked prefill) | 超长输入的 prefill 会阻塞所有 decode | 把 prefill 切成块与 decode 混跑,改善 TPOT 抖动(见 8.7) |
8.5 量化
| 方案 | 量化对象 | 主要收益 | 注意 |
|---|---|---|---|
| GPTQ / AWQ | 仅权重(INT4) | 权重显存降到 1/4;decode 是带宽受限,所以直接加速 | 必须有融合反量化 kernel(Marlin 等),否则可能更慢;精度要按任务测 |
| SmoothQuant 类 | 权重 + 激活(W8A8) | 同时加速 prefill 与 decode | 需要处理激活离群通道,校准集影响结果 |
| FP8 | 权重 / 激活 / KV | Hopper 及以后有原生支持,精度损失小 | 逐张量缩放策略与 kernel 支持依赖硬件与框架版本 |
| GGUF(k-quants / Q4_K_M 等) | 权重 | CPU / Apple Silicon / 消费级显卡可用,格式灵活 | 面向本地单机,吞吐与并发不是强项 |
| QAT | 训练时插入伪量化 | 低比特下精度最好 | 需要训练资源,流程重 |
| KV Cache 量化 | KV(FP8/INT8) | 并发翻倍 | 长上下文精度需实测(见 8.3) |
- 先看瓶颈在哪:小 batch / 低并发、decode 主导 → 权重量化收益大;大 batch、强 prefill → 需要激活量化。
- 再看有没有融合 kernel:没有的话,反量化开销可能吃掉全部收益。
- 最后按你的任务测精度,不要只看 PPL。PPL 对量化不敏感,但对长链推理、代码正确率、结构化输出的影响可能很大。
- 保留一份 bf16 基线用于回归对比;量化版本必须过同一套评测门禁。
- 只测 PPL:PPL 变化 <1% 不代表任务指标不掉。
- AWQ/GPTQ 用了不同校准集:校准集应尽量贴近真实流量分布。
- 忽略尾部:量化对"需要精确复制长串 ID/JSON"的任务伤害最大。
- 把 4-bit 训练(QLoRA)的模型直接拿去推理:训练时的反量化是临时的,部署应使用专门的推理量化版本。
8.6 投机解码与约束解码
- 用一个便宜的方式(小 draft 模型、额外预测头、或 n-gram 查表)一次猜出 k 个后续 token。
- 目标模型一次前向并行验证这 k 个位置(代价接近生成 1 个 token,因为 decode 是带宽受限的,多算几个位置几乎不增加时间)。
- 按概率比值做接受/拒绝采样;被拒绝的位置从修正后的分布重新采样。
| 变体 | 草稿来源 | 特点 |
|---|---|---|
| 独立 draft 模型 | 同族小模型 | 实现简单;需要额外显存;两模型词表需一致 |
| Medusa | 在目标模型上多加若干预测头 | 不增加独立模型;需要训练头部;树状验证 |
| EAGLE 系 | 用目标模型的隐藏状态做自回归草稿 | 接受率高,是当前主流方案之一 |
| n-gram / 查表 | 从上下文或语料里找重复片段 | 零训练成本,对代码编辑、摘要、重复性文本极有效 |
- 有效:低 batch(decode 带宽受限、算力闲置)、输出可预测(代码、格式化文本、翻译)、有高接受率的草稿源。
- 无效甚至有害:高 batch 已经接近算力饱和时,验证成本无法被隐藏,反而降低吞吐;草稿接受率低时(创造性写作、高温度)收益接近零;额外显存挤占了 KV Cache 空间。
- 监控指标:接受率(acceptance rate)与平均接受长度。低于阈值就该关掉。
约束解码(结构化解码)是另一类:按 JSON Schema / 正则 / 语法在每一步把非法 token 的 logit 置 −∞。它保证可解析,不保证内容正确。实现上有编译有限状态机的,也有用推理解码器(如 xgrammar)的;复杂 schema 的每步掩码开销需要评估。第 9 章的"单 token 槽位读取"是它的最简特例:只约束一个位置且候选极少,于是可以连解码循环都省掉。
8.7 批处理与调度
| 机制 | 做法 | 解决的问题 |
|---|---|---|
| 静态批处理 | 一批请求一起跑完才接下一批 | 实现简单;长短请求混合时 GPU 大量空转 |
| 连续批处理 | 以"一次前向"为调度单位,完成的序列立刻退出、新请求立刻补位 | 吞吐提升数倍;是现代推理引擎的标配 |
| chunked prefill | 把长 prefill 切成多个块,与 decode 交错执行 | 避免长输入把 TPOT 打出尖峰(改善尾延迟) |
| PD 分离 | prefill 与 decode 部署在不同的实例池,KV 通过网络传递 | 两种工作负载特性完全不同(算力受限 vs 带宽受限),分开可各自扩缩容与调优 |
| 前缀缓存 | 跨请求复用相同前缀的 KV | Agent / RAG 场景的 TTFT 大幅下降 |
| 抢占与重算 | 显存不足时丢弃某请求的 KV,稍后重算 | 保证公平性与不 OOM;代价是延迟抖动 |
8.8 分布式推理
| 策略 | 什么时候用 | 代价 |
|---|---|---|
| TP(张量并行) | 模型单卡放不下;低延迟小 batch 场景 | 每层 all-reduce,增加延迟;要求高速互联(同机 NVLink) |
| PP(流水并行) | 跨节点部署超大模型 | 流水气泡;延迟增加,吞吐优先场景更合适 |
| EP(专家并行) | MoE 模型 | all-to-all 通信;专家负载不均 |
| 副本(replica) | 吞吐优先、模型能单卡装下 | 无通信开销,最理想;受单卡显存限制 |
8.9 框架选型
| 框架 | 核心优势 | 适合 | 注意 |
|---|---|---|---|
| vLLM | PagedAttention 起源地、连续批处理、生态最广(量化/LoRA/投机/结构化输出/多模态)、社区迭代快 | 通用在线服务、自研二次开发 | 特性多 → 组合配置需要验证;不同版本的性能差异明显 |
| SGLang | RadixAttention 前缀缓存、结构化输出(xgrammar)性能强、DSL 友好 | Agent / 多轮 / 大量共享前缀 | 生态相对小一些 |
| TensorRT-LLM | NVIDIA 官方极致性能、FP8/INT4 kernel 成熟、in-flight batching | 追求确定性的极致性能、固定模型 | 编译流程重,模型更新要走构建管线;可移植性差 |
| llama.cpp | GGUF 生态、CPU/Metal/消费级硬件、单机部署极简 | 本地/边缘/桌面 | 高并发服务不是强项 |
| LMDeploy / TGI / MLC | 前两者服务化封装成熟,MLC 跨平台编译 | 按团队栈选择 | 检查所需特性(量化类型、投机、工具调用)是否支持 |
- 用官方 benchmark 数字做决策:那些数字通常是最优配置、最优硬件、单一负载。必须用自己的长度分布与并发模型压测。
- 忽略版本:推理框架的吞吐可以因为一个 kernel 或调度改动而在版本间差 20%+。压测必须锁定版本。
- 只看吞吐不看 goodput:在 SLO 约束下的有效吞吐才是业务指标。
8.10 服务化与成本模型
分级与缓存
小模型先试、低置信度升级到大模型(模型级联);精确缓存 + 语义缓存;按任务路由到不同规格的实例池。
按队列深度而非 GPU 利用率
GPU 利用率在 decode 阶段天然偏低(带宽受限),用它做扩缩容信号会永远不扩容。应该看排队时长、TTFT p95、队列长度。
单位 token 成本
每百万 token 成本 = GPU 每小时成本 / (每 GPU 每小时产出 token 数)。注意输入与输出成本不同(输出受 decode 带宽限制,单价通常高数倍)。Prompt 缓存命中率是最大的成本杠杆之一。
必须采集的
TTFT/TPOT 的 p50/p95/p99、队列等待、缓存命中率、KV 占用率、抢占次数、输出长度分布、解析失败率、每请求 token 计费。
2 / (3000 × 3600) × 1e6 ≈ 0.19 美元/百万 token。若把并发从 8 提到 64(batch 更大),吞吐可能到 8000 token/s,单位成本降到约 0.07 美元/百万 token——但 TPOT 会变差。成本、延迟、SLO 三者必须一起谈。
- 系统与调度:Efficient Memory Management for Large Language Model Serving with PagedAttention(vLLM)|Orca: A Distributed Serving System for Transformer-Based Generative Models(连续批处理)|SGLang / RadixAttention|DistServe、Splitwise(PD 分离)
- 注意力与算子:FlashAttention 1/2/3|FlashDecoding|PagedAttention
- 量化:GPTQ|AWQ|SmoothQuant|LLM.int8()|Marlin|FP8 Formats for Deep Learning
- 解码加速:Fast Inference from Transformers via Speculative Decoding|Medusa|EAGLE|Lookahead Decoding
- KV 优化:H2O|SnapKV|StreamingLLM
- 工具:
vllm、sglang、TensorRT-LLM、llama.cpp、genai-perf、locust、vllm bench serve
9. 专题:Jev 与"从 logits 读决策"
这一章回应一个具体的新概念:一个项目声称"工作在 logits 等中间过程上"。我们会把它拆成(1) 它到底指什么、(2) 机制的哪一部分是真的新、(3) 与已有技术的血缘、(4) 哪些数字不能信。本章所有关键论断都标注了证据等级。
本章写于 2026-10-04(该产品公开发布约三周后),属于第 0.5 节定义的快速演进内容,半年内即可能过时。
9.1 先钉死指称:这里的 "Jev" 指什么
- 调用形态:调用方提交
state(一段描述现状的文本)加一组带类型的问题,服务返回每个答案的概率与置信度,不产出任何自由文本。 - 三种问题原语:
Choice(多选)、Noul(布尔;命名来自内部术语)、Score(有界评分,取概率加权期望)。 - 按请求声明候选:候选集合在请求时给出(而非训练时固定标签集),这是它相对传统分类器的主要接口差异。
- 命名取自杰文斯悖论;厂商自称首个 "System One Model"(借用卡尼曼的双系统隐喻),训练方法自称 RLCD。
LocalJev(GitHub Next 官方,开源参考实现)、AnyJev、OpenSourceJev、jev-serve、Laya、SemIf、JevLite、PixelJev、Visual Jev 等。读任何一篇关于 Jev 的文章时,第一件事是确认它指的是哪个 artifact:托管 API、LocalJev、还是某个复刻。三者的机制、可复现性、性能数字完全不同,混着引用会得出矛盾结论。
- "Jev = 扩散语言模型的一次去噪"——错。一次去噪只是把 Jev 风格接口套用到文本扩散模型上的一种实现路径(见 9.4),不是 Jev 的定义或核心机制。
- Jev = logit lens——错。logit lens 是读中间层表示的可解释性探针(第 6.5 节),与产品接口无关。
- Jev = 投机解码——错。投机解码是纯加速技术,不改变接口语义。
9.2 它解决的问题:把开放式生成变成有界决策
传统做法要"让模型输出一个类别/概率",标准套路是让它把答案写成文本或 JSON,然后解析。这条路径上有四个成本项:
逐 token 自回归
为得到几个概率数字,要跑完整条解码循环——每一步都受带宽限制(第 8.1 节),而其中绝大部分计算与"这几个数字"无关。
格式风险
模型可能写出非法 JSON、多写解释、把数字写成中文、或在概率上加引号。要把这条路径做稳,需要约束解码甚至重试。
解析与重试
格式错误就要重试,重试又会重新付出上面两项成本,且尾部延迟不可控。
概率语义被破坏
模型"写出的 0.82"是被采样出来的一个 token,不是模型对该类别的真实后验概率(对照第 2.7 节的清单)。
这不是新数学,而是把已有的可能性产品化:从"让模型写 JSON"变成"从 logits 里读答案"。
9.3 机制:受限 softmax,以及它和近邻技术的精确区别
1. 把 state + 问题渲染成 prompt,让答案落在某个固定位置
2. 保证每个候选标签映射到【单个 token】(多 token 候选由编译器变换成单 token 字母等)
3. 取该位置 next-token 分布的 logits
4. 只保留候选标签对应的那些 logit,做 softmax 并【重新归一化】
5. 返回归一化后的概率(+ 置信度/熵诊断),不生成任何 token
| 技术 | 对 logits 做什么 | 是否改变候选间相对关系 | 是否生成 token |
|---|---|---|---|
| 受限 softmax 读出(Jev 类) | 取出候选子集,事后重新归一化 | 否(但概率数值被放大) | 否 |
| logit bias | 对指定 token 加/减一个偏置 | 是(改写分布) | 是 |
| 约束/结构化解码 | 把非法 token 置 −∞,然后继续逐 token 生成 | 是(限制候选集) | 是 |
| logprobs API | 直接暴露 next-token logprob | 否 | 是(调用方自己取数) |
| 分类头 / 线性探针 | 在 hidden state 上接一个额外训练的头 | — | 否 |
| 实现 | 做法 | 优点 | 缺点 |
|---|---|---|---|
| ① 生成 JSON 再解析 LocalJev(开源参考实现) | 让普通 chat 模型把概率值当 JSON 文本"写"出来,再校验解析,格式错就重试 | 任何模型都能用、零改造 | 扛下整条生成管线的开销;解析失败与重试;概率语义被采样破坏 |
| ② 从 logits 直接读 多数第三方复刻 | 改推理引擎,在答案位置取 logits、重归一化到候选标签 | 无解码循环、无解析、无重试;数值上等价于从完整分布里取出相同标签再归一化 | 需要引擎层改造(或支持 logprobs 的接口);候选必须是单 token |
| ③ 扩散模型单步去噪读取 DiffusionGemma + vLLM 的结构化读取模式 | 文本扩散模型的输出是一个可预先固定大部分 token 的画布:把答案位留成单 token 槽位,只做一步去噪,从收敛步的 logits 读出各候选标签概率 | 多个问题可与同一份 prompt 的 K/V 复用、共享一次前向;画布宽度大时配合稀疏输出投影收益是数量级的 | 依赖扩散类模型;属于特定实现的路径,不是通用方案 |
正确写法:"Jev 风格接口在文本扩散模型上的一种实现路径"。 错误写法:"Jev 就是扩散语言模型的一次去噪"。后者把一个实现特例当成了定义。
这不是"省一点",而是把 O(画布 × 词表) 压成 O(候选数),差 5–6 个数量级。它也是这类接口能在延迟上占优的主要结构性原因之一。
- 做法是一次 prefill 完成:从预训练指令模型的答案位置读出,把 next-token 分布限制到候选 token 上。不需要生成,也不需要打补丁式的引擎改造。
- 偏差一 · 标签先验(label prior):某些标签无论输入是什么都会拿到更高概率。
- 偏差二 · 顺序偏差(position bias):候选在选项列表中的位置会影响概率。
- 修正不需要任何梯度步或参数改动:除以从未标注输入上估计出的标签先验;对选项列表的
K个循环轮换取对数概率平均。 - 实测效果:在两个 20 选项任务上,循环轮换把「顺序翻转率」从 0.33 降到 0.14 与 0.18,并在 11/11 个模型上提升准确率。
- 代价与优化:读全部轮换需要
K次 prefill。用一个在未标注状态上选出的停止规则,读取次数可从 18 降到约 10.6(服务实测 7.3),于是在 vLLM 上每秒多服务 2.2 倍的决策。
9.4 收益:厂商宣称 vs 独立实测
| 口径 | 数字 | 说明 |
|---|---|---|
| 厂商宣称 | 加速 20–200×,成本降至 1/40–1/400,延迟 70–500 ms;首页曾出现 193.6× / 444.6× 一类的对比数字 | 不是实证结果。其对比的分母是"前沿大模型做开放式生成",属于任务不对称的比较(一个在做有界选择,一个在生成长文本)。"输出免费"是定价政策,不是物理事实 |
| 独立实测 | 社区汇总中位数约为 加速 7×、成本降至约 1/30、延迟约 76 ms(样本量分别在数百量级);独立开发者用真实邮件分类基准测得 4.1–8.5× | 比厂商数字小一个数量级,但仍然是显著的。这才是可用于规划的量级 |
| 独立实测 | 特定实现对比同硬件下的 LocalJev 报 "快 4–5 倍" | 作者自己注明是特定硬件 + 特定量化(16 GB 级 GPU、Q4_K_M)+ 特定负载,并明确提醒不同来源的公布数据不能横向比较 |
| 独立实测 | 学术审计(arXiv:2609.32160,审阅 2026-09-19 至 09-24 间的 28 篇论文):类型化读出尚未显示出独立于同类"标签概率读出"的准确率优势;最清晰的收益在延迟与成本 | 这是本章最该记住的一条独立结论:它是接口与效率的进步,不是准确率的突破 |
- 与"大模型生成长文本"比 → 数量级差异(任务不对称)。
- 与"小模型 + 约束解码 + 只取标签位置 logprob"比 → 折扣到个位数倍数(同任务比较)。
- 与"专用分类器(如微调的 BERT 类)"比 → 在固定标签集场景下,专用小模型可能更快更准;Jev 的价值在候选集在请求时可变、零训练接入。
9.5 边界与风险
| 限制 | 内容 | 等级 |
|---|---|---|
| 表达能力 | 受具体实现约束,差别很大:某条扩散模型路径明确拒绝多 token 候选、图像输入、问题依赖链、多步去噪与长思考模式;而第三方方案用括号数字标识符(如 [1])把选项映射到单 token,可支持任意选项数,并声称原生支持图像上的多模态决策 | 已核实 |
| 规模上限 | 单请求问题数有上限(如 64),每题候选数有区间(如 2–26 或 2–255,视实现) | 已核实 |
| 置信度不是校准正确率 | 返回的是条件概率与熵诊断。实现方文档明确建议"在自己的留出样本上评估后再定阈值"——这正是第 2.8 节讲的问题 | 已核实 |
| 对提示注入脆弱 | 独立研究(数万次调用量级)显示:类型化输出确实守住了"不返回未声明的选项"(攻击目标被选中比例很低),但注入能可靠地推动概率质量。安全界的总结很到位:输出格式约束的是模型能说什么,不是它能被说服信什么 | 独立实测 |
| 非确定性 | 重复调用同一请求,返回的概率会变(有报告称在两位小数网格上波动,幅度约 1% 量级)。这与"确定性结构化决策"的营销话术存在张力 | 独立实测 |
| 闭源与不可复现 | 架构、参数量、训练数据、奖励函数均未公开;厂商不发布公开基准;据称其评测的参考答案取其他前沿模型输出的平均,属于自证闭环 | 无法验证 |
| 跨版本稳定性 | 现有研究基本只测了单一版本快照,跨版本行为无公开数据 | 无法验证 |
| 注入的量化数据 | 基于 510 个重构 InjecAgent 案例的研究(arXiv:2609.28613):恶意内容会移动动作概率,但很少真的让模型选中攻击者目标(新验证集上约 1.8%);使用分数反馈的自适应攻击可把优化中观测到的最高攻击目标概率翻倍,并把成功率推到约 3.5%;成功案例与初始决策边界很小或攻击者对观测的控制更强相关。结论是 schema 约束的输出改变但未消除注入风险 | 独立实测 |
9.6 血缘关系:它的祖先都是成熟技术
| 祖先技术 | 相同之处 |
|---|---|
| Verbalizer / cloze 式分类(PET、LM-BFF 等) | 把标签填进模板空位,用语言模型对标签 token 的概率做分类 |
| GPT-3 时代的 likelihood scoring | 用候选文本的 logprob 打分并比较 |
| 语法约束解码 | 保证输出落在合法集合内 |
| Yes/No 式 reranker(monoT5、Qwen3-Reranker 等) | 用"是/否"标签 token 的 logit 做相关性判定 |
| 零样本 NLI 分类器 | 把分类转成蕴含判定,读标签概率 |
| Reject option / learning to defer / 模型级联 | 低置信度时拒绝或升级到更强模型 |
| 温度缩放与"proper scoring rules"下的强化学习 | 让输出的概率本身成为可优化、可评估的对象 |
写作与选型建议:把它当作一个行为已知、实现未知的黑盒 API 来评估——只信你能自己测出来的部分(延迟、成本、在你数据上的准确率与校准)。
[1])的 next-token 概率里直接提取决策,并给出免训练配方与一套微调目标(tree-factorized listwise 损失,并用 KL 把辅助预测锚定到基座模型):
- 无需训练时,4B 模型即可追平同主干的社区 Jev 类实现,优于「字母 logit」读法,支持任意选项数,并原生支持图像上的多模态决策。
- 微调的收益是有针对性而非普遍的:明显改善弱模型与特定任务(如多选项意图路由),对强主干收益递减。
- KL 锚定可以避免对话生成能力退化;在强模型上 LoRA 表现最好。
9.7 工程落地建议
适合的场景
高容量、低风险的初筛层:工单分类、意图识别、内容打标、路由决策、需要概率而非文本的评分。特点是:候选集频繁变化、零样本接入、对延迟敏感、错了可以被下游兜住。
不适合的场景
高后果决策的唯一依据(放款、医疗、权限授予);需要多 token 或自由文本答案;问题之间存在依赖;输入不可信且没有隔离措施(注入风险)。
- 自己测校准:在留出集上画可靠性图,定阈值。不要相信任何"置信度"直接等于正确率。
- 设升级路径:低置信度 → 更强模型或人工。这正是 reject option 的经典用法。
- 把输入当不可信:外部内容进 state 前做来源标注与清洗;对概率质量的异常偏移做监控。
- 离线对比要同任务:与"小模型 + 约束解码 + 标签 logprob"这种同任务基线比,而不是与大模型生成长文本比。
- 锁定指称与版本:文档里写清用的是托管 API 还是某个开源复刻、哪个版本;否则半年后无法解释数据差异。
9.8 待核实清单(下次刷新时优先查这些)
- 架构、参数量、训练数据与 RLCD 奖励函数是否公开,或是否出现独立复现。
- (已部分解答)机制层面已有第三方复现与实测(见 9.3:标签先验与顺序偏差、11/11 模型提升、vLLM 上 2.2× 决策吞吐);但托管服务本身仍没有独立的公开基准对比。
- 厂商对比数字的原始测量协议与方差是否公布。
- 跨版本的行为稳定性数据。
- 注入防御是否有实质改进。当前证据是:自适应攻击可把成功率从约 1.8% 推到约 3.5%(见 9.5),需对照第 6.2 节的结构性结论一起看。
- 主流推理框架是否把"单 token 槽位读取"做成通用能力(若成为标准,这类接口会变成默认选项,而非独立产品)。
- TensorSharp 支持 Jev 模式了:一次去噪,直接读出决策(张善友,腾讯云开发者社区,2026-09-24)——本文件中"实现路径 ③""稀疏输出投影""能力上限与拒绝项"的直接来源,作者本人已注明数字的硬件与量化条件。
- githubnext/localjev——"实现路径 ①"的开源参考实现(生成 JSON 再解析)。
- rreinold/jev-serve、ShaileshRawat1403/AnyJev、sabeel111/OpenSourceJev——第三方复刻,用于观察机制差异,不代表托管 Jev 的实现。
- (本节条目已由下方四条 arXiv 引用取代,保留以说明早期核验状态)学术侧:对早期证据的审计、机制最透明的开源实现(含 hidden state 上拟合线性头的变体)、以及"LLM 本来就是 Jev-style"一类论述。
- arXiv:2609.32160 — Typed Decision Models: An Early Evidence Audit and Evaluation Checklist(2026-09-26):审阅 2026-09-19 至 09-24 间的 28 篇论文,结论为「类型化读出本身尚未显示出独立于同类标签概率读出的准确率优势;Jev 最清晰的收益在延迟与成本,难题上仍有准确率差距」,并给出 14 项评估清单。9.2 与 9.4 核心判断的依据。其自我限定:只覆盖单一托管模型发布后的前九天,应视为早期证据地图。
- arXiv:2610.00831 — AnyJev Technical Report(2026-09-30):一次 prefill 读出、标签先验与顺序偏差及其免训练修正、循环轮换的停止规则与 vLLM 吞吐实测。代码:nokia-applied-research/AnyJev。9.3 的依据。
- arXiv:2610.02076 — LLM2Jev: LLMs Are Already Jev-Style Decision Models — When and How to Fine-Tune Them(2026-10-01):括号数字标识符读出、免训练配方、tree-factorized listwise 损失与 KL 锚定。9.6 的依据。
- arXiv:2609.28613 — Decision Hijacking: Prompt Injection Attacks on Jev's Typed Probabilistic Decisions(2026-09-23):510 个重构案例的注入实验与自适应攻击数据。9.5 的依据。
说明:本章中标注"厂商宣称"的数字来自厂商公开材料与媒体报道;标注"独立实测"的来自第三方测量,其中部分为小样本或单一作者自测,已在表中注明样本量或条件。凡本文件作者未直接读到原文的条目,均标为"无法验证"或写入 9.8 待核实清单。
10. 速查卡与自查清单
这一章是可以单独打印的部分:公式、形状、超参经验值、选型决策树,以及全文的自查清单。术语表在配套文件 llm-cheatsheet.html 中。
10.1 核心公式卡
| 要算什么 | 公式 | 示例 |
|---|---|---|
| 训练总算力 | FLOPs ≈ 6 × N × D | 8B × 15T token ≈ 7.2e23 |
| 推理单 token 算力 | ≈ 2 × N(激活参数量) | 8B → 16 GFLOPs/token |
| 显存:全参训练 | 16N 字节(混精 + AdamW,不含激活) | 7B → 约 112 GB |
| 显存:仅推理权重 | 2N(bf16)/ N(INT8)/ 0.5N(INT4) | 8B bf16 → 16 GB |
| KV Cache | 2 × L × n_kv × head_dim × S × B × bytes | 8B GQA bf16 → 128 KiB/token |
| 解码吞吐上限(带宽) | 带宽 / 权重字节数 | 3.35 TB/s ÷ 16 GB ≈ 209 token/s(单序列) |
| 算术强度 | FLOPs / Bytes,与硬件拐点比较 | decode ≈ 1,H100 拐点 ≈ 295 → 带宽受限 |
| 端到端延迟 | 排队 + TTFT + (n_out − 1) × TPOT | — |
| 单位成本 | GPU 每小时成本 ÷ 每小时产出 token × 1e6 | 2 美元/时、3000 tok/s → 0.19 美元/M |
| 困惑度 | PPL = exp(平均交叉熵) | loss 2.0 → PPL 7.4 |
| Chinchilla 参考 | D ≈ 20 × N(算力最优) | 7B → 140B token |
10.2 形状速查(一次前向)
token ids [B, S]
embedding [B, S, d]
每层 Q [B, S, n_heads, head_dim]
每层 K / V [B, S, n_kv_heads, head_dim] # GQA: n_kv_heads < n_heads
注意力分数 [B, n_heads, S, S] # prefill;decode 时 S→S_total
注意力输出 [B, S, d]
final norm [B, S, d]
logits [B, S, V] # 解码只需 [:, -1, :]
概率 [B, S, V] # softmax 在最后一维,fp32
10.3 超参经验值
| 阶段 | 参数 | 常见取值 | 备注 |
|---|---|---|---|
| 预训练 | LR / warmup / 裁剪 | 峰值 LR 随规模下降;warmup 数千步;grad clip 1.0 | 用 μP 让超参可跨规模迁移 |
| 预训练 | batch(token 数) | 数百万 token 级 | 用梯度累积凑;注意与 LR 的缩放关系 |
| SFT 全参 | LR / epochs | 1e-5 ~ 2e-5 / 1–3 | 超过 3 轮容易过拟合与风格僵化 |
| LoRA | LR / r / α / target | 1e-4 ~ 2e-4 / 8–64 / 常用 2r / 全部线性层 | 只挂 q,v 是老做法,效果通常更差 |
| DPO | β | 0.1 左右 | 太小 → 跑偏;太大 → 学不动 |
| PPO / GRPO | KL 系数、clip、采样数 G | KL 0.01–0.1;clip 0.2;G 常 4–16 | 奖励尺度与 KL 需联合调 |
| 推理 | temperature / top_p / min_p | 事实任务 0;创意 0.7–1.0 / 0.9–0.95 / 0.02–0.1 | 报告结果必须附采样配置 |
| 服务 | max_num_seqs / max_model_len / gpu_memory_utilization | 按 KV 预算反推 | 先算 KV 容量表再定并发 |
10.4 选型决策树
- TTFT 太高?→ 查输入长度与队列(chunked prefill / PD 分离);查前缀缓存命中率;查是否被 decode 抢占。
- TPOT 太高?→ 显存带宽受限:上权重量化(INT4/FP8)→ 增大 batch → 低 batch 场景加投机解码 → 长上下文考虑 KV 量化。
- 吞吐不够?→ 连续批处理 → 增大并发(受 KV 限制)→ 前缀缓存复用 → 引入副本而非 TP。
- 成本太高?→ goodput 而不是峰值吞吐定容量 → 分级路由(小模型初筛)→ 缓存 → 按 SLO 选硬件规格。
- 长上下文贵?→ KV 量化 → 滑窗/驱逐 → PD 分离 → 重新审视是否真的需要那么长的上下文。
- 投机解码:只在低 batch、可预测输出、接受率高时开;高 batch 已算力饱和时关掉。
- PD 分离:长输入 + 高并发 + 对尾延迟敏感时值得;小流量下利用率下降。
- MoE:显存充裕、算力是瓶颈、能承受 all-to-all 复杂度时值得。
- 量化:decode 主导选权重量化;prefill 主导需要激活量化;都必须按任务测精度。
- RLHF/DPO/GRPO:有偏好数据选 DPO 起步;任务可验证(数学/代码)优先 RLVR + GRPO;需要在线探索与最强效果才上 PPO。
10.5 全文自查清单
逐条用"能不能不看文档答出来"判断。答不出来的章节回去打勾前先重读。
第 1–2 章 · 地基层
- 说清一次前向的五个阶段与各自形状
- 解释 GQA 为什么能把 KV 降到 1/4
- 解释为什么 softmax 必须在 fp32、且要减最大值
- 说清 logits 的三条性质与工程后果
- 列出会让 logprob 失去概率语义的配置
- 区分受限 softmax / logit bias / 约束解码 / 分类头 / logit lens
第 3–5 章 · 训练侧
- 说明为什么去重同时改善泛化、隐私与成本
- 写出
6ND与16N并会算 - 解释 TP 与 PP 对带宽要求的差异及摆放原则
- 说出 loss spike 的标准处置流程
- 解释 LoRA 省显存的机理(回到
16N) - 区分 DPO / GRPO / RLVR 各需要什么信号
第 6–7 章 · 对齐与评测
- 解释提示注入为什么在结构上难根治
- 说明为什么"格式受约束"不等于"输出可信"
- 说出 judge 的至少三种偏差与缓解手段
- 说明私有评测集为什么不可替代
第 8–9 章 · 推理与前沿
- 解释 prefill 与 decode 的瓶颈差异及由此推出的优化方向
- 会算 KV Cache 容量表并做容量规划
- 说出投机解码何时有害
- 解释 PD 分离为什么同时改善 TTFT 与 TPOT
- 说明 goodput 为什么比吞吐重要
- 用一句话讲清 Jev 的机制,并说出三条局限
10.6 更新日志
| 版本 | 日期 | 变更 |
|---|---|---|
| v1.0 | 2026-10-04 | 首版:第 0–10 章;Logits 独立成章(第 2 章);Jev 专题(第 9 章,按证据等级分栏);配套速查表文件。 |
| v1.1 | 2026-10-04 | 第 9 章补入四条已核验的一手文献并据此改写多节;新增附录 A · 故障排查手册。 |
附录 A · 故障排查手册(症状 → 原因 → 处置)
正文各章的「常见坑」讲的是原理上会怎么错;这份附录讲的是线上真的出问题时先查什么。按四张表组织:训练 / 后训练 / 推理服务 / 评测与质量。
- 先定侧:问题出在训练侧(模型能力)、推理侧(延迟/吞吐/显存)、还是评测侧(结论不可信)?三者症状经常相似,但排查路径完全不同。经验判据:同一模型换一套推理配置就能复现 → 推理侧;换评测方法结论就翻转 → 评测侧。
- 做一个最小可复现样本:把 batch 降到 1、上下文截短、关掉所有优化开关(量化/投机/前缀缓存)。如果最小配置正常,就二分法逐个打开开关。
- 核对"数字口径":硬件、量化位数、batch、输入输出长度分布、采样配置、样本量——两项不一致,比较就无意义(贯穿全文的纪律)。
A.1 训练阶段
| 症状 | 优先怀疑 | 处置 |
|---|---|---|
| loss 变 NaN / inf | fp16 溢出、学习率过大、坏数据批次 | 改 bf16;降峰值 LR 并延长 warmup;开梯度裁剪;从最近 checkpoint 回滚并跳过该数据分片 |
| 梯度范数尖峰后 loss 抬升 | 见第 4.7 节的六类原因 | 按 4.7 的 runbook:回滚 + 跳批 + 降 LR;不要"等它自己恢复" |
| loss 正常下降但模型很笨 | shift by one 错位、loss mask 错、ignore_index 填错、数据未充分 shuffle | 做小样本过拟合测试:能否把 8 条样本背下来。背不下来一定是实现 bug,不是数据问题 |
| 多卡比单卡更慢 | TP 跨了节点、通信未与计算重叠、micro-batch 过小、PP 气泡过大 | 重排拓扑(TP 进 NVLink 域,PP 跨节点);增大 micro-batch;用梯度累积补全局 batch;改用 interleaved PP |
| 吞吐忽高忽低 | 慢节点(straggler)、数据加载成为瓶颈、异步 checkpoint 未生效 | 采集逐 rank 逐步耗时,不要只看总吞吐;把 dataloader worker 数与预取调大到 GPU 不再空等;checkpoint 改异步 |
| 续训后指标莫名下降 | 数据序未恢复(等于重复喂数据)、LR schedule 被重置 | 检查 dataloader 状态的恢复逻辑;这是最隐蔽也最贵的一类坑 |
| 显存够但 OOM | 长序列激活峰值、分块 CE 未开、碎片 | 开梯度检查点;开分块交叉熵/词表并行;限制单样本最大长度 |
| MFU 明显偏低 | 算子未融合、重计算过多、通信未重叠 | 对照第 4.4 节的带宽要求逐项核对;优先解决通信与气泡,再考虑算子 |
A.2 后训练阶段
| 症状 | 优先怀疑 | 处置 |
|---|---|---|
| SFT 后通用能力退化 | 灾难性遗忘 | 混入一定比例预训练数据(replay);降 LR 与步数;改用 LoRA;对通用基准做回归门禁 |
| SFT 后"随机不听话"、格式时好时坏 | 训练与推理的 chat template 或 tokenizer 版本不一致 | 把 template 固化成部署配置的一部分;用它重新渲染一批训练样本做单测;这是排查优先级最高的一项 |
| 模型开始模仿用户口吻自我回复 | loss mask 错位(用户轮也算了 loss) | 打印若干样本的 mask 可视化核对 |
| LoRA 训练几乎没提升 | 只挂了 q/v 投影、LR 过低、α/r 不匹配、数据量或多样性不足 | 挂到全部线性层(含 FFN);LR 提到 1e-4 ~ 2e-4;保持 α≈2r;先做小样本过拟合验证通路 |
| DPO 后回答明显变长、变啰嗦 | 长度偏置(偏好数据里长回答天然占优) | 做长度配对的偏好数据;加长度正则;或改用对长度不敏感的偏好损失;监控胜者长度差 |
| RL 后指标涨但人评变差 | 奖励黑客 | 独立人评/多族评委校准;监控长度、列表密度、自信措辞等表面特征;检查奖励模型是否被过度优化 |
| 安全对齐后大量误拒 | 拒答样本占比过高、阈值过激 | 在偏好数据里补"不该拒就别拒"的一侧;分类型统计误拦率而不是只看平均 |
| 推理模型的思考段复读或超长 | 思考段模板/终止标记与训练不一致、max_tokens 过大、采样温度过高 | 核对思考块边界标记;限制思考长度;降低温度 |
A.3 推理与服务
| 症状 | 优先怀疑 | 处置 |
|---|---|---|
| TTFT 突然翻倍 | 抢占重算(显存不足丢 KV 后重算 prefill)、长输入阻塞队列、前缀缓存失效 | 查抢占计数与队列等待;开 chunked prefill;核对前缀是否每次都变(时间戳、随机 ID 会让命中率归零) |
| TPOT 抖动大(尾延迟差) | 长 prefill 混入同一批次、batch 组成随流量变化、CPU 侧采样/分词成瓶颈 | 开 chunked prefill;限制单批 token 总量;把分词与后处理移出关键路径 |
| OOM 但看起来显存还够 | KV 碎片、块大小不当、并发按权重估算了 | 按第 8.3 节公式重算:权重 + KV×并发 + 缓冲;确认分页 KV 已启用 |
| 吞吐远低于预期 | 未开连续批处理、并发太小(KV 限制)、无量化、TP 过度而副本不足 | 按第 10.4 节决策树逐项排查;用 goodput 而不是峰值吞吐评判 |
| 开了量化反而更慢 | 没有融合反量化 kernel,或实际没走低比特 GEMM | 换用带融合 kernel 的实现(如 Marlin 系);确认日志/算子层面确实是 INT4/FP8 路径 |
| 投机解码没有收益甚至更慢 | 高 batch 下已算力饱和、草稿接受率低、额外显存挤占 KV | 监控接受率与平均接受长度;只在低 batch、可预测输出的负载上开 |
| 输出重复、陷入循环 | 采样配置(top-p/惩罚缺位)、KV 量化精度、上下文过长导致退化 | 调 min_p/重复惩罚;回退 KV 量化做对比;截短上下文试 |
| 结果无法复现 | 采样参数、kernel 实现、batch 组成、框架版本不同 | 固定并记录完整配置(含框架与 kernel 版本、seed);把"报告采样配置"变成规范 |
| 长上下文"中间的信息丢了" | lost in the middle;位置外推不足 | 做位置 × 长度的二维评估;把关键信息放在开头或结尾;必要时用检索而非超长上下文 |
| MoE 服务 GPU 利用率低且波动 | batch 内专家负载不均、EP 布局不佳、容量因子设置不当 | 增大并发让专家负载摊平;调整 EP 与专家放置;观察 token 丢弃比例 |
| 扩缩容不生效 | 用了 GPU 利用率做信号(decode 天然偏低) | 改用队列长度、排队时长、TTFT p95 作为扩缩容信号 |
A.4 评测与质量结论
| 症状 | 优先怀疑 | 处置 |
|---|---|---|
| 公开榜单高但线上表现差 | 数据污染、格式过拟合、任务分布不同 | 建私有评测集;用真实流量分布采样评测;对照第 3.5 节做去污染审计 |
| 同一模型两次评测分数不同 | 采样参数未固定、样本量太小 | 固定温度与解析规则;先用同一配置重复评测估计方差,再判断差异是否显著 |
| 换评委模型结论就翻转 | 自我偏好、位置/长度偏置 | 交换顺序各评一次只保留一致结论;多族评委投票;保留人工校准子集 |
| 换 tokenizer 后 PPL 不可比 | PPL 只在同一词表下有意义 | 改用任务级指标;或换算为每字节的比特数(bits-per-byte)做跨词表比较 |
| 新模型整体更好但某类任务崩了 | 只看平均分 | 按任务类别分组报告;把关键类别做成发布门禁 |
| 上线后缓慢退化 | 流量分布漂移、上游数据变化、缓存污染 | 监控输出长度/拒答率/工具失败率/追问率;定期用固定私集回归 |