Skip to content

LLM 基础:跟着一个 token 走完全程

这份文档不按字母排序,按数据流排序。 每个名词只出现在它真正被用到的位置上——如果一个概念放不进下面这条链,它就不属于本文。

每个条目固定三行:是什么 / 一个可验证的数字 / 没有它会坏在哪。第三行才是理解的地方,前两行只是记忆。

🔗 相关:ReAct 论文笔记


0. 骨架

先看全貌。下面 12 行是一个现代 decoder-only LLM 的全部推理逻辑,剩下的都是细节:

python
# 输入:"猫吃鱼"
ids = tokenizer.encode(text)              # → [1234, 5678, 91011]        §1
x   = embedding[ids]                      # → [T, d_model]  残差流起点    §1 §2

for layer in range(L):                    # L 个结构完全相同的 block      §2
    x = x + attn(rmsnorm(x))              # token 之间交换信息            §3
    x = x + ffn (rmsnorm(x))              # 80% 的参数在这一行            §4

logits = lm_head(rmsnorm(x))              # → [T, vocab]                 §5
next   = sample(logits[-1], temp, top_p)  # 只取最后一个位置              §5
# 把这一步的 K,V 存进 cache,把 next 接到序列末尾,回到第 3 行            §6

三件事看完这段就该记住:

  1. 模型是 L 个相同 block 的堆叠,不是一个巨大的黑箱。看懂一层就看懂了全部。
  2. 每层只做两件事:attention 混 token,FFN 存知识。
  3. 生成是一个循环,每次只产出一个 token,然后把自己的输出接回输入。

速查表(当字典用)

名词在哪名词在哪
Token / 分词 / Tokenizer§1FFN / MLP / SwiGLU§4
词表 Vocabulary§1MoE / 激活参数§4
Embedding / input_ids§1logits / lm_head§5
残差流 / RMSNorm§2温度 / Top-p / 采样§5
参数 / 权重 / 模型尺寸§2自回归生成§6
Attention / QKV / 多头§3KV Cache§6
GQA / MQA / MLA§3上下文窗口 / RoPE 外推§6
位置编码 / RoPE§3Prefill / Decode / TTFT§6
Causal Mask§3基座 / Instruct 模型§7
预训练 / SFT / RLHF / RLVR§7Loss / 梯度 / 反向传播§7
蒸馏 Distillation§7GPU / HBM / 量化§8

1. 入口:从文本到向量

Token / 分词(Tokenization)

  • 是什么:模型不吃字符,吃 token——通常是子词(subword)。英文里 tokenization 可能切成 token|ization;中文一个常用字往往就是一个 token,生僻字会被拆成多个字节 token。
  • 数字:英文约 1 token ≈ 0.75 词,中文约 1 token ≈ 1~1.5 字。算 API 成本和上下文占用都靠这个换算。
  • 没有它会坏在哪:退化到字符级建模,同一段文本的序列长度涨 4~5 倍——KV Cache(§6)和注意力算力同比膨胀,而 attention 是 O(T²)。分词首先是一个压缩手段。

分词器(Tokenizer:BPE / SentencePiece)

  • 是什么:执行分词的算法。主流是 BPE(byte-level,从字节开始反复合并高频对);SentencePiece 是它的一种工程封装。关键性质:byte-level 意味着任何字节串都能被编码,永远不会 OOV
  • 数字:Tokenizer 是独立训练的,且训完就冻结。换 tokenizer 等于换词表,等于整个 embedding 矩阵作废、必须重训。
  • 没有它会坏在哪:这一层的怪癖会一路渗透到模型行为。经典案例:数字被切得乱七八糟(1234 可能是 12|34),所以 LLM 做算术天生吃亏;SolidGoldMagikarp 这类词表里存在但训练时几乎没出现的 token,会触发彻底失控的输出。很多看起来像"模型笨"的现象,根因在 tokenizer。

词表(Vocabulary)

  • 是什么:模型认识的全部 token 的集合。生成时"下一个词"只能从这张表里选。

  • 数字现在是 10 万~26 万,不是"几万"。

    模型vocab_size
    Llama 2 / Mistral(旧世代)32,000
    GPT-4(cl100k)100,256
    Llama 3 / 3.1128,256
    DeepSeek V3 / R1129,280
    Qwen3151,936
    GPT-4o / o1 / o3(o200k)~200,000
    Llama 4 Scout202,048
    Gemma 3262,208
  • 没有它会坏在哪:词表大小是一个真实的成本项,不是无关参数。它同时决定 embedding 矩阵和 lm_head 的宽度:Gemma 3 27B 光 embedding 就 417M 参数。词表变大 → 序列变短(省算力)但矩阵变宽(费显存),是一个权衡而非免费改进。

Embedding(词嵌入)/ input_ids

  • 是什么input_ids 是 token 在词表里的整数下标;embedding 是一张 [vocab, d_model] 的查找表,把下标换成向量。注意这是查表,不是矩阵乘。
  • 数字d_model(隐藏维度)现在典型 2048~8192。Llama 3 70B 是 8192。
  • 没有它会坏在哪:不查表就得直接拿整数进网络,那样 id=1234 和 id=1235 在数值上相邻——而词表里相邻的两个 token 毫无语义关系。embedding 的作用是把"任意编号"变成"可学习的几何位置",语义近的词向量才可能近。

2. 主干:残差流

这一节是原文档完全缺失的部分,也是最该先补的部分。不理解残差流,Transformer 就只是一堆零件。

残差流(Residual Stream)

  • 是什么:贯穿全模型的一条 [T, d_model] 的"主干道"。每个子层都不是替换它,而是往上加一笔x = x + sublayer(norm(x))。可以把它想成一块共享白板,每一层读一遍、往上写一点。
  • 数字:Llama 3 70B 有 80 层 × 2 个子层 = 160 次读写,全都作用在同一条 8192 维的流上。
  • 没有它会坏在哪梯度传不回去,深网络根本训不动。 加法让反向传播有一条恒等短路(∂x/∂x = 1),梯度可以直达第一层。ResNet 解决的就是这个问题,Transformer 继承了它。这也是为什么"深"是免费的——每层只需要学一个小增量。

RMSNorm / Pre-Norm

  • 是什么:进子层之前先把向量归一化。现代模型用 RMSNorm(只除以均方根,不减均值),比 LayerNorm 少一半操作。位置在子层之前(pre-norm),不是之后。
  • 数字x / sqrt(mean(x²) + eps) * weight——每层只有 d_model 个可学习参数,可以忽略不计。
  • 没有它会坏在哪:残差流是一路相加的,激活值会逐层放大直到溢出,或坍缩到 0。归一化把每次进子层的输入拉回可控尺度。Pre-norm 而非 post-norm 是让大模型训练稳定的关键工程细节之一——原始 2017 Transformer 用的是 post-norm,深层时不加 warmup 就发散。

参数 / 权重 / 模型尺寸

  • 是什么权重是学出来的数字(矩阵乘的系数),偏置是加性项,参数 = 两者统称。现代 LLM 里偏置基本被去掉了(Llama 系全无 bias),所以"权重"和"参数"在实践中同义。模型 = 固定架构(代码)+ 参数(数字)。
  • 数字:一个 block 的参数分布(Llama 3 70B):attention 17.6%,FFN 82.4%。跨模型都在 16~20% / 80~84%
  • 没有它会坏在哪:把参数当成一坨无结构的数字,就会漏掉最重要的事实——知识主要不在注意力里,在 FFN 里§4)。MoE、剪枝、LoRA 该往哪下手,全由这个分布决定。
  • ⚠️ 参数量已经不再直接代表能力:"7B / 70B" 这套刻度在 MoE 时代断了。DeepSeek V3 是 671B 总参 / 37B 激活。规则:激活参数预测算力和延迟,总参数预测显存

3. Attention 子层

一层里的第一个子层。它是模型中唯一让不同位置的 token 互相看见的地方。

注意力(Attention)/ QKV

  • 是什么:每个位置从残差流里投影出三个向量——Q(我在找什么)、K(我能提供什么)、V(我实际携带的内容)。用 Q·Kᵀ 算出每个位置对其他位置的关注权重,softmax 归一化,再对 V 加权求和写回残差流。四个矩阵:W_q, W_k, W_v, W_o
  • 数字softmax(Q Kᵀ / sqrt(head_dim)) V。那个 sqrt(head_dim) 不是装饰——不除,点积方差随维度线性增长,softmax 会饱和成 one-hot,梯度消失。
  • 没有它会坏在哪:没有 attention,每个位置就是独立的,模型退化成对每个 token 单独做变换的 MLP,无法利用上下文。这是"上下文"这个词的物理来源。

Causal Mask(因果掩码)

  • 是什么:训练时把注意力矩阵的上三角设为 -inf,让位置 t 只能看见 ≤ t 的位置。
  • 数字:一行代码,scores.masked_fill_(mask, -inf)
  • 没有它会坏在哪训练和推理会不一致。 训练时模型能看见后面的答案,学会了"抄";推理时后面还不存在,直接崩。有了 mask,一次前向对 T 个位置同时提供 T 个训练信号——这是"预测下一个词"能高效并行训练的全部原因。

多头注意力(Multi-Head Attention)

  • 是什么:把 attention 拆成 n_heads 份并行做,每份在 head_dim 维的子空间里,结果拼回再过 W_o
  • 数字:Llama 3 70B:64 头 × 128 维。注意 head_dim 现在常和 d_model / n_heads 解耦——Gemma 3 27B 是 hidden 5376、32 头、head_dim 128(32×128 = 4096 ≠ 5376)。
  • 没有它会坏在哪:单个 softmax 只能表达一种关注模式。要同时追踪句法依赖、指代、和远距离主题,需要多个独立的注意力模式并行。

GQA / MQA / MLA(KV 压缩)

  • 是什么:Q 用满头,但 K/V 共享更少的头。MHA(每头独立)→ GQA(几个 Q 头共享一组 KV)→ MQA(全部共享一组)→ MLA(DeepSeek:把 K/V 压成一个共享的低秩 latent 向量 + 一个单独的 RoPE key)。

  • 数字:Llama 3 全系 num_key_value_heads = 8

    模型Q/KV 头每 token KV@128k若用 MHA压缩
    Llama 3 8B32 / 8128 KiB17.2 GB68.7 GB
    Llama 3 70B64 / 8320 KiB42.9 GB343.6 GB
    Llama 3 405B128 / 8504 KiB67.6 GB16×
    DeepSeek V3(MLA)128 / latent68.6 KiB9.2 GB~工程等价 GQA-2.25

    DeepSeek V3 是 671B 的模型,KV Cache 却比 70B 的 Llama 3 还小 4.7 倍。MLA 论文自己的说法是"KV cache 等于 2.25 组的 GQA,但效果强于 MHA";V2 相比 MHA 版本减少 93.3% KV,生成吞吐 5.76×

  • 没有它会坏在哪:Llama 3 70B 权重 140 GB + MHA 的 343.6 GB KV,128k 上下文在任何单机上都放不下。GQA 不是微优化,它是长上下文能被商业化服务的前提。

  • 同类杠杆滑动窗口 / 局部-全局交替。Gemma 3 用 5:1 的局部:全局比例、局部窗口 1024,把 128k 的 KV 从 66.6 GB 压到 11.2 GB(~6×)。

位置编码 / RoPE(旋转位置编码)

  • 是什么RoPE 现在是事实标准。 它不往 embedding 上加任何东西——而是在每一层 attention 内部,对 Q 和 K 按位置做旋转。旋转的相对角度天然编码了相对距离。

  • 数字:唯一的关键超参是 rope_theta(base frequency),它直接决定能撑多长上下文:

    模型rope_theta
    原始 Llama 2 / DeepSeek V310,000
    Kimi K250,000
    Llama 3(从 10k 提到 500k)500,000
    Qwen3 / Gemma 31,000,000
    Qwen3-Next10,000,000
  • 没有它会坏在哪不给位置信息,attention 对输入顺序是置换等变的——「猫吃鱼」和「鱼吃猫」会得到完全相同的 logits。位置编码是唯一打破这个对称性的东西。

  • ⚠️ 别用旧框架:「给每个 token 注入位置信息」描述的是 2017 年的 sinusoidal 绝对位置编码和 BERT/GPT-2 的可学习绝对位置表。两者都已淘汰,致命缺陷是没法外推超过训练时那张表的长度。RoPE 因为是相对的、且由一个 base 参数控制,才有了 YaRN 这类外推手段(§6)。

  • 2026 趋势(值得知道名字)部分 RoPE——只旋转一部分维度(GLM-4.6 partial_rotary_factor: 0.5,Qwen3-Next 0.25),或只在一部分层用(Llama 4 的 iRoPE:每 4 层有 1 层完全不加位置编码,48 层里 12 层是 NoPE)。DeepSeek 的 MLA 本身就是部分 RoPE 设计(qk_nope_head_dim=128 + qk_rope_head_dim=64)。


4. FFN 子层:80% 的参数在这里

原文档从头到尾没提过 FFN。这是最大的漏洞——它是模型里参数量最大的模块,也是知识的存放处。

FFN / MLP / SwiGLU

  • 是什么:一个逐位置(position-wise)的两层网络:升维 → 非线性 → 降维。它不跨 token,每个位置独立计算。现代模型用 SwiGLU,需要三个矩阵:gateup(都是 d_model → d_ff)、downd_ff → d_model),计算是 down(silu(gate(x)) * up(x))——那个逐元素乘就是"门控"。

  • 数字d_ff ≈ 3.5 × d_model(Llama 3 8B:4096 → 14336)。参数占比:

    模型AttentionFFN
    Llama 3 8B19.2%80.8%
    Llama 3 70B17.6%82.4%
    Qwen3-32B19.4%80.6%
    Gemma 3 27B16.0%84.0%
    Llama 2 7B(MHA,无 GQA)33.2%66.8%
  • 没有它会坏在哪:只剩 attention 的话,模型基本是一串加权平均——线性混合加一个 softmax,几乎没有存储和加工知识的容量。"巴黎是法国首都"这条事实存在 FFN 的权重里,不在注意力里。 常用的心智模型:attention 负责路由信息,FFN 负责存储和计算

  • 为什么占比比教科书还高:经典说法是 FFN 约 2/3(4h 的 FFN + MHA)。SwiGLU 用 3 个矩阵而非 2 个,GQA 又砍小了 K/V 投影,两个因素一起把 FFN 推到了 80%+。

MoE(Mixture of Experts)/ 激活参数

  • 是什么:把 FFN 换成 N 个并行的 FFN(专家),一个路由器给每个 token 只挑 top-k 个执行。MoE 只作用在 FFN 层——而 FFN 正好是 80% 的参数所在,这不是巧合。

  • 数字前沿开源模型现在基本全是 MoE。

    模型总参激活路由专家top-k共享专家
    Mixtral 8x7B(老世代)46.7B12.9B820
    DeepSeek V3 / R1671B37B25681
    Qwen3-235B-A22B235B22B12880
    Qwen3-Next-80B-A3B80B3B512101
    Kimi K21.04T32B38481
    Llama 4 Maverick400B17B12811
    gpt-oss-120b117B5.1B12840
  • 没有它会坏在哪:想要 671B 的容量就得付 671B 的算力。MoE 把容量算力解耦——V3 每 token 只算 37B(≈ 5.5%),但保有 671B 的知识量。

  • ⚠️ 但显存不省:671B 全部都得驻留在 HBM 里,即使每步只用 37B。这是 MoE 部署最反直觉的一点。

  • 趋势方向:Llama 3(2024)是最后一个大型密集前沿模型,论文明确说选密集是"为了最大化训练稳定性";一年后 Llama 4 全线转 MoE。粒度也在变细:Mixtral 的 8 专家 top-2 → 现在 256~512 专家 top-8/10 + 1 个常开的共享专家。约 35B 以下仍以密集为主(Qwen3-32B、Gemma 3 全系),因为部署简单。


5. 出口:从向量到 token

lm_head / logits

  • 是什么:最后一层 norm 之后,用一个 [d_model, vocab] 的矩阵把隐状态投影成词表上的原始分数(logits),未归一化。softmax 之后才是概率分布。
  • 数字:输出形状 [T, vocab],但生成时只用最后一行——前面 T-1 行在推理时是浪费的(训练时它们全都是有效信号,见 causal mask)。小模型常把 lm_head 和 embedding 共享同一份权重(tied embeddings)省显存。
  • 没有它会坏在哪:残差流是 d_model 维的连续向量,跟词表没有对应关系。lm_head 是唯一把它翻译回"哪个 token"的那一步。

温度 / Top-p / Top-k / 采样

  • 是什么logits / temperature → softmax → 截断 → 抽样。温度缩放分布(低 → 尖锐确定,高 → 平坦随机,temp → 0 等于贪心);top-k 只留概率最高的 k 个;top-p(nucleus) 留累计概率到 p 的最小集合。do_sample=False 就是贪心。
  • 数字:常见默认 temp=0.7, top_p=0.9。注意顺序:先温度缩放,后截断
  • 没有它会坏在哪:全贪心解码输出确定,但会陷入重复循环、文风乏味。反过来温度太高就开始胡言乱语。这一层是纯推理期的旋钮,不动一个权重——同一个模型换采样参数,表现可以差很远,很多"模型不行"其实是采样参数不对。

6. 循环:KV Cache 与上下文

自回归生成(Autoregressive Generation)

  • 是什么:一次一个 token,每一步都把自己刚生成的接回输入,重跑一遍前向。
  • 数字:生成 500 token = 500 次完整前向,串行,无法并行。
  • 没有它会坏在哪:这是 LLM 延迟的根本来源。也是幻觉会自我放大的机制来源——一旦第 10 个 token 错了,后面 490 个都在这个错误的条件下生成,模型会努力让错误显得自洽。

KV Cache

  • 是什么:注意力只需要历史 token 的 K 和 V,而它们不随后续 token 改变。所以算一次就缓存,新 token 只算自己的 QKV 再去查缓存。

  • 数字公式必须用 num_kv_heads,不是 hidden_dim

    KV bytes = 2(K,V) × num_layers × num_kv_heads × head_dim × bytes_per_elem × seq_len × batch

    hidden_size 的话会高估整整一个 GQA 倍数(Llama 3 70B 是 8 倍)。核对一遍 Llama 3 70B:2 × 80 × 8 × 128 × 2 = 327,680 B = 320 KiB/token

  • 没有它会坏在哪:每步都重算全部历史的注意力,单步 O(T²),生成整段变成 O(T³)。KV Cache 把单步降到 O(T)它是用显存换算力——这一笔交易直接把上下文长度变成了显存问题(§8)。

Prefill vs Decode

  • 是什么Prefill 一次性并行处理整段输入 prompt(算力受限 / compute-bound),对应首 token 延迟 TTFTDecode 之后逐 token 生成,每步只算一个(带宽受限 / memory-bound),对应每 token 延迟 TPOT
  • 数字:这解释了"长 prompt 开头卡一下、之后稳定吐字"。也解释了为什么两个阶段的优化手段完全不同——prefill 拼 FLOPS,decode 拼带宽和 batch size。
  • 没有它会坏在哪:不区分这两个阶段,就无法理解任何推理性能数据。"这个模型多快"这个问题本身是没定义的,得问 TTFT 还是 TPOT。

上下文窗口(Context Window)

  • 是什么:模型能处理的最大 token 数(输入 + 已生成)。
  • ⚠️ 这是主要由训练决定的属性,不是由显存决定的。 原文档把它写成"本质受 HBM 容量约束",这个因果颠倒了。真正决定它的是:
    1. 训练序列长度 + 长上下文续训。Llama 3 405B 从 8K 起步,分六个阶段升到 128K,烧掉约 800B token 的长上下文数据,每一阶段都要求短上下文评测不掉、needle-in-a-haystack 全对才推进。
    2. rope_theta§3)。
    3. 外推方法YaRN、NTK-aware scaling、位置插值。DeepSeek V3 用 YaRN factor: 40,把 4096 扩到 163,840;Kimi K2-Thinking 用 factor: 64 到 262,144。
  • HBM 决定的是"这个窗口里你能经济地服务多长",两件事分开看。两个干净的证据:(a) 同样的权重换更大显存的机器,不用重训就能吃更长上下文;(b) Gemma 3 论文明说模型能泛化到 128K,但再往上"迅速退化"——那是固定硬件下的质量悬崖,是训练边界不是内存边界。
  • 第三个常被混同的概念:有效上下文。声称 128k、实际检索质量在多少 token 之后开始掉,通常远低于标称值。标称长度、可服务长度、有效长度,是三个不同的数。

7. 权重从哪来:训练流水线

前面六节讲的是权重已经存在时会发生什么。这一节讲那些数字怎么来的。

推理 vs 训练

  • 推理(Inference):拿固定权重跑前向,产出结果。就是 §0 那 12 行。
  • 训练(Training):跑前向 → 算 loss → 反向传播 → 更新权重。显存开销约是推理的 3~4 倍(要额外存激活值、梯度、优化器状态)。

训练机制

  • 损失函数 / 交叉熵(Cross-entropy):衡量预测分布离真实下一个 token 有多远。loss = -log P(正确token)数字直觉:随机猜的 loss ≈ ln(vocab) ≈ 11.7(词表 128k);训好的模型在 2 以下。
  • 梯度 / 反向传播(Backpropagation):对 loss 求每个权重的偏导,得到"往哪调、调多少",从输出层逐层回传。没有残差流(§2)的恒等短路,这个回传在几十层深度上就会消失。

① 预训练(Pretraining)——最贵的一步

  • 数据:万亿级 token 的无标注文本(网页 / 书 / 代码)。数据质量是这一步的全部——去重、过滤、配比比架构调参重要得多。
  • 任务:自监督"预测下一个词"。没有人工标注,文本自己当标签。
  • 产出基座模型(Base / Pretrained Model)——只会续写。你问它"法国首都是哪",它可能续一句"?德国首都是哪?意大利首都是哪?",因为在互联网语料里这才是常见的接下去写法。它不是不知道答案,是不知道你在提问。

② 监督微调(SFT)

  • 数据:人工写的(指令,理想回答)对。量少质精——通常几万到几十万条,不是几亿。
  • 产出指令微调模型(Instruct Model)。base 和 instruct 的分水岭就在这。它主要学的是"格式和角色",不是新知识——知识在预训练里就装完了。
  • 附带效应:这一步引入了 chat template<|im_start|>user 之类的特殊 token)。用错模板,instruct 模型表现会断崖下跌,这是本地部署最常见的坑。

③ 偏好对齐(RLHF / DPO)

  • 数据:人类对"哪个回答更好"的成对比较。
  • 做法RLHF 先训一个奖励模型打分,再用 PPO 让策略往高分走;DPO 跳过奖励模型和 RL 循环,直接在偏好对上做优化。
  • 目标:有用、无害、诚实。
  • ⚠️ 别再写"DPO 现在更主流":2024 年是对的(Llama 3 就是 DPO 的高点,论文明确说 DPO 比 PPO 省算力且效果更好)。R1 之后翻过去了——DeepSeek V3 论文里 "DPO" 出现 0 次,用 GRPO;Qwen3 也是 0 次,用 GRPO 后来换 GSPO;Llama 4 把 DPO 降级成最后一道轻量抛光,并明确说"SFT 和 DPO 会过度约束模型,限制 online RL 阶段的探索"。DPO 在 2026 年的准确定位:小规模社区微调的便宜稳定选项 + 最后的轻量打磨,不是前沿主线。轨迹是 PPO/RLHF (2022) → DPO (2023-24) → GRPO/RLVR (2025-26)

④ 推理训练(RLVR:RL with Verifiable Rewards)

  • 数据:能自动判对错的题——数学、代码、单元测试。"可验证"是关键词:奖励来自编译器和测试,不来自人类打分,所以能无限扩展。
  • 做法:用 GRPO 及其后继(GSPO、DAPO)奖励正确答案,长链思考是被逼出来的副产品,不是被教的。
  • 产出:推理模型(o1/o3、DeepSeek-R1、Qwen3 thinking)。R1-Zero 最惊人的地方是纯 RL、不做 SFT 就涌现出了反思和自我纠错。
  • 和 CoT 的关系:CoT(§9)原本是提示技巧——你要求模型一步步想。RLVR 之后它变成了训练进权重的行为——模型自己就会想,不需要你提示。

附:蒸馏(Distillation)

  • 是什么:两种不同的东西,别混:
    1. 经典 logit 蒸馏:学生模型拟合教师的完整输出分布(软标签),比拟合硬标签信息量大。distilgpt2DistilBERT 是这一类。
    2. "R1-distill" 式:拿大模型生成的推理轨迹去做学生的 SFT。本质是 SFT,只是数据由模型产出。今天说"蒸馏"多半指这个。
  • 没有它会坏在哪:小模型直接从原始数据训,效果远不如从大模型的输出学。这也是 2025 年后小模型能力猛涨的主因——它们不是学得更好,是有了更好的老师。

各类模型走到了哪一步

模型走过的阶段行为特征
distilgpt2① 预训练 + 蒸馏只会续写,不听指令
Llama-3-8B(base)同上
Qwen3-0.5B-Instruct① → ② → ③能听懂并回答问题
DeepSeek-R1① → ② → ③ → ④先输出长思考链再答

8. 硬件账本

顺序很重要:硬件放在软件链之后。它是前面那条链的后果,不是原因。

GPU

  • 是什么:海量核心的并行处理器。LLM 的前向几乎全是大矩阵乘。CPU 核少但单核快、擅长串行分支;GPU 核多且规整、擅长并行数值计算。
  • 数字:H100 的 bf16 算力约 1000 TFLOPS(稀疏),HBM 带宽约 3.35 TB/s。记住这两个数的比例。

HBM(高带宽显存)

  • 是什么:堆叠在 GPU 芯片旁的高速显存。带宽极高,容量有限(H100 是 80 GB)。权重、激活、KV Cache 全住在这里。
  • 数字:一张显存预算表(70B,bf16):
    权重          70B × 2 B  = 140 GB   ← 已经超过单张 H100 的 80 GB
    KV Cache @128k          =  42.9 GB  ← 见 §6
    激活值 + 碎片            ≈  几 GB
    ────────────────────────────────────
    合计                    ≈ 185 GB    → 至少 3~4 张卡
  • 为什么"带宽"比"算力"更常成为瓶颈:decode 阶段每生成 1 个 token,要把全部权重从 HBM 读进计算单元一遍。70B bf16 = 140 GB,除以 3.35 TB/s → 理论上限约 24 token/s(batch=1),跟算力毫无关系。这就是 decode 是 memory-bound 的意思,也是为什么提高 batch size 几乎免费提升总吞吐:读一次权重,服务多个请求。

量化(Quantization)

  • 是什么:用更少的位表示权重(和可选的激活/KV Cache)。⚠️ 起点是 bf16,不是 fp32——早就没人用 fp32 做推理了,DeepSeek V3 甚至原生 FP8 训练。
  • 数字:70B 的体积:
    bf16  →  140 GB   (2 张 80G 卡)
    fp8   →   70 GB   (1 张,刚好)
    int4  →   35 GB   (1 张,宽裕;常见质量损失 1~3%)
    常见方案名:GPTQ、AWQ、GGUF(llama.cpp)。
  • 没有它会坏在哪:70B 在单卡上根本跑不起来。而且量化不只省容量——它同时减少要搬的字节数,所以直接提升 decode 速度(回到上面那个带宽账)。这是"省显存"之外更容易被忽略的收益。

三者关系链

                  算力(FLOPS)  ← prefill 卡在这里

   ┌───────────────────┴───────────────────┐
   │      GPU 计算单元:矩阵乘(权重 × 激活)   │
   └───────────────────┬───────────────────┘

              每步都要把权重整个读一遍
              带宽 3.35 TB/s  ← decode 卡在这里

   ┌───────────────────┴───────────────────┐
   │  HBM 80 GB:权重 + 激活 + KV Cache     │
   └───────────────────┬───────────────────┘

              KV Cache 随上下文线性膨胀,挤占容量
              (GQA / MLA / 滑动窗口 就是压这一项,见 §3)

一句话:prefill 拼算力,decode 拼带宽;容量决定"装不装得下",带宽决定"跑多快"。上下文长度由训练决定,能不能负担得起由 HBM 决定。


9. 不在本文范围

下面这些不属于"一次前向传播"这条链,硬塞进来只会让文档退回成词汇表。它们各自应该是独立的一篇:

已经写了的

还没写的

  • 提示技巧:Prompt Engineering、CoT、few-shot、ReAct ⚠️ 但注意 §7④——CoT 已经从提示技巧变成了训进权重的行为。这一篇真要写,主轴应该是时间线(《哪些提示技巧被训进了权重》),而不是技巧清单。
  • 安全:提示注入、越狱、护栏、对齐税 最好的切入点是把攻击点标在 §0 那张骨架图上。提示注入之所以无法用 prompt 修复,是因为"指令"和"数据"进的是同一张 embedding 表——模型在架构层面就分不开
  • 评测:MMLU / GPQA / SWE-bench、污染问题、LLM-as-judge 固定格式该是「测什么 / 满分多少、蒙分基线多少 / 怎么被刷」。MMLU 四选一的蒙分基线是 25%,这个数一放,一半的榜单叙事就自己塌了。
  • 模型选型:开源 vs 闭源、许可证、API 定价 这个不该写成文章——价格三个月变一次,写死就是负债。它该是一张定期更新的表加一个成本函数,而成本函数的料在 §1(token 换算)、§8(显存账)和 agent-loop §1(上下文预算)里已经齐了。

Released under the MIT License.