卷 V · 当助手CH 19深度 19/20

从 GPT-2 到今天:骨架没变

这本书拆了十八章的 GPT-2,一台 2019 年的模型。一个合理的担心是:这些东西放到今天还算数吗?这一章不靠印象回答,直接去 Hugging Face 上下载几个当下主流开源模型的配置文件(config.json,几 KB 的文本,写着模型每一个结构参数),和 GPT-2 的那份逐行对照。你会看到一副没变的骨架,和五个被换掉的零件。

五个零件KV 缓存 64 → 16 GiB256 个专家里挑 8 个
◉ 这一章在 GPT-2 的哪一段

▷ 先猜一下

Meta 在 2024 年发布的 Llama 3.1 8B,上下文窗口是 131072 个 token(128K)。第 15 章说过,生成时每个 token 都要在每一层存一份键和值(KV 缓存)。

问:把 128K 的窗口用满,一段对话的 KV 缓存大约多大?(按常用的半精度,每个数 2 字节。)

A 16 MB 左右 B 1.6 GB 左右 C 16 GB 左右 D 160 GB 左右

答案在本章末尾。

五份配置文件

下面是五份真实的 config.json 里读出来的数(GPT-2 是 OpenAI 2019 年发布的;Llama 3.1 8B 是 Meta 2024 年;Qwen3 两个是阿里巴巴 2025 年;DeepSeek-V3 是深度求索 2024 年底):

GPT-2 smallLlama 3.1 8BQwen3-8BQwen3-30B-A3BDeepSeek-V3
层数1232364861
总线宽度7684096409620487168
注意力头 / 键值头12 / 1232 / 832 / 832 / 4128(压缩)
词表50257128256151936151936129280
最长上下文10241310724096040960163840
位置编码学出来的表RoPERoPERoPERoPE
归一化LayerNormRMSNormRMSNormRMSNormRMSNorm
MLP 的激活GELUSiLU(门控)SiLU(门控)SiLU(门控)SiLU(门控)
专家———128 选 8256 选 8

把 Llama 3.1 8B 的配置代进去,按它的结构一个矩阵一个矩阵地数参数:词嵌入和输出层各 128256 × 4096,每层的注意力(4096 × 4096 的查询和输出、4096 × 1024 的键和值)加 MLP(三个 4096 × 14336 的矩阵),一共 8030261248 个——正好是它名字里的「8B」(官方说 8.03B)。从 GPT-2 small 的 1.24 亿到这里,是 65 倍。

没变的:那副骨架

先看什么没变。这五个模型,前向计算的流程一模一样:

文字 → 分词(第 2 章)→ 查嵌入表(第 5 章)
     → [ 注意力(第 9 章)+ MLP(第 11 章)] × 层数,全部加在同一条总线上(第 10 章)
     → 最后一次归一化 → 乘回词表 → 一张候选表(第 1 章)→ 抽一个(第 14 章)→ 接到末尾,再来

训练目标也一样:在海量文本上猜下一个 token,压低交叉熵(第 4 章);然后做后训练(第 17 章)。这本书里拆出来的现象——总线上的加法、在中间层读出答案、归纳头、叠加、复读、校准——在这些大模型上都被研究者反复观察到了。你在 GPT-2 上建立的直觉,在今天的模型上几乎全部成立。

Attention is all you ▍ Attention ␣is ␣all ␣you 下一个 token 概率 意外 ' need' 46.50% 1.10 比特 ' have' 17.15% 2.54 比特 ' can' 6.90% 3.86 比特 ' get' 4.09% 4.61 比特 ' want' 2.21% 5.50 比特 ''ve' 2.04% 5.62 比特 熵 3.52 比特

(GPT-2 知道 2017 年那篇论文的标题:Attention is all you 后面,␣need 46.50%。那篇论文定下的这副骨架,至今没有被换掉。)

换掉的五个零件

一、位置:从「查表」到「旋转」

GPT-2 给每个位置学一个向量(第 9 章),学了 1024 个,所以它最多只能看 1024 个 token,第 1025 个位置根本没有向量。今天的模型几乎都用 RoPE(旋转位置编码):不再往向量上加东西,而是把查询和键的每两维当成一个平面,按位置旋转一个角度,位置越靠后转得越多,不同的维度对用不同的转速。两个向量做点积时,旋转角度一相减,留下的就只是它们之间的相对距离。没有「第几个位置」的表,所以也就没有硬性的长度上限——配置里那个 rope_theta(Llama 是 500000,Qwen3 是 1000000)就是最慢那一档的转速,调大它是把窗口撑长的常用手段之一。

二、归一化:更简单的 RMSNorm

GPT-2 每层用 LayerNorm 把向量拉回标准尺度(减均值、除标准差、再缩放平移)。今天普遍换成 RMSNorm:不减均值、不加平移,只除以均方根再缩放。少算一点,效果几乎一样,训练还更稳。

三、MLP:加一道门

GPT-2 的 MLP 是「乘矩阵 → GELU → 乘矩阵」。今天普遍用门控的版本(叫 SwiGLU):三个矩阵,一个算「值」,一个算「门」,门过一个平滑的激活函数(SiLU)之后和值逐个相乘,再乘第三个矩阵回到总线。第 11 章说 MLP 是一张键值表;这道门让每个神经元在「要不要写」和「写多少」之间多了一层控制。配置里 Llama 的 intermediate_size 是 14336,是总线宽度的 3.5 倍(GPT-2 是 4 倍),因为三个矩阵比两个多出一份。

四、注意力:很多个头共用一套键值

这是对推理成本影响最大的一处。GPT-2 的 12 个头各有自己的键和值;Llama 3.1 8B 有 32 个查询头,却只有 8 组键和值,每 4 个查询头共用一组。这叫分组查询注意力(GQA)。查询头可以多,因为它们不用存;键和值要存进 KV 缓存,越少越好。算一下它省了多少(半精度,每个数 2 字节):

模型每个 token 的 KV 缓存用满 128K 窗口
GPT-2 small(12 层 × 12 组 × 64 维)36 KiB(窗口只有 1024)
Llama 3.1 8B,假如 32 个头各存一组512 KiB64 GiB
Llama 3.1 8B,实际(8 组)128 KiB16 GiB
Qwen3-8B(36 层 × 8 组)144 KiB—
Qwen3-30B-A3B(48 层 × 4 组)96 KiB—
DeepSeek-V3(压缩成 512 + 64 维)68.6 KiB—

GQA 让同一段 128K 对话的缓存从 64 GiB 降到 16 GiB。DeepSeek-V3 走得更远:它有 128 个头、总线宽 7168,却不存完整的键值,只存一个压缩后的 512 维向量加 64 维的位置部分(叫 MLA,多头潜在注意力),每层每个 token 576 个数,61 层下来每个 token 只要 70272 字节——比一台小它几十倍的 Llama 3.1 8B 还少。这些改动不让模型更聪明,让它更便宜——尤其是让「长」变得便宜。

五、混合专家:参数很多,每次只用一小部分

Qwen3-30B-A3B 和 DeepSeek-V3 的配置里多了几行:num_experts: 128 / n_routed_experts: 256,num_experts_per_tok: 8。意思是:每一层的 MLP 不是一块,而是 128 块(或 256 块)较小的「专家」,加上一个小小的路由器;每个 token 来了,路由器只挑其中 8 块去算。

于是总参数和「每个 token 实际动用的参数」分了家。Qwen3-30B-A3B 名字里写得明白:总共约 300 亿,每个 token 只激活约 30 亿(「A3B」)。DeepSeek-V3 的技术报告给的数字是总共 6710 亿、每个 token 激活 370 亿。知识可以存得很多(第 11 章:MLP 是知识的主要存放处),而每一步的计算量只按激活的那部分付钱。代价是所有专家都得放在内存里——它省的是算力,不是内存。

还有两样不在配置文件里的

  • 数据。GPT-2 用了约 40 GB 的网页文本;Llama 3 的训练数据超过 15 万亿个 token。第 8 章的幂律在这里起作用:参数和数据一起往上推,损失一起往下走。
  • 后训练。今天的「助手」和 GPT-2 之间最大的体感差距——听懂指令、会停、会拒绝、会调用工具——主要来自第 17 章那一段,而那一段在配置文件里一个字都看不到。
⌨ 自己跑一遍

读配置文件不需要下载模型权重,几 KB 而已:

from transformers import AutoConfig

print(f"{'模型':30} 层  头/KV头  词表     上下文   KV 缓存/token")
for repo in ["gpt2", "NousResearch/Meta-Llama-3.1-8B", "Qwen/Qwen3-8B", "Qwen/Qwen3-30B-A3B"]:
    c = AutoConfig.from_pretrained(repo)               # 只下载几 KB 的 config.json
    L, H = c.num_hidden_layers, c.num_attention_heads
    kv = getattr(c, "num_key_value_heads", None) or H
    hd = getattr(c, "head_dim", None) or c.hidden_size // H
    kv_bytes = 2 * L * kv * hd * 2                     # K 和 V × 层数 × KV 头 × 每头维度 × 2 字节(bf16)
    print(f"{repo:30} {L:2d}  {H:2d}/{kv:<2d}   {c.vocab_size:6d}  {c.max_position_embeddings:6d}   {kv_bytes / 1024:5.0f} KiB")

本机输出:

模型                             层  头/KV头  词表     上下文   KV 缓存/token
gpt2                           12  12/12    50257    1024      36 KiB
NousResearch/Meta-Llama-3.1-8B 32  32/8    128256  131072     128 KiB
Qwen/Qwen3-8B                  36  32/8    151936   40960     144 KiB
Qwen/Qwen3-30B-A3B             48  32/4    151936   40960      96 KiB

想亲手跑一个今天的模型:在 Apple 芯片的 Mac 上,mlx-lm 或 Ollama 都能直接跑 8B 级别的模型(4 比特量化后约 5 GB);然后用这本书的眼光去看它——它的候选表、它的复读、它的校准。

pip install transformers && python 19.py

也可以直接在浏览器里看:https://huggingface.co/Qwen/Qwen3-8B/blob/main/config.json,任何一个开源模型仓库的根目录下都有这个文件。

▸ 在现实里
  • 本地跑模型时,内存要同时装下权重和 KV 缓存。8B 模型的权重量化到 4 比特约 5 GB,可是一段长对话的缓存可能比权重还大——「能加载」和「能聊长」是两回事。
  • 「量化」是把每个权重从 16 位压成 8 位、4 位,损失一点精度换一半甚至四分之三的内存。为什么少几位精度模型照样能用、什么时候会突然不能用,《抹零》讲的是同一类问题。
  • 看一个新模型的技术报告时,先找这五样:位置怎么编、KV 怎么省、MLP 是不是专家、上下文多长、训练了多少 token。剩下的大多是规模和数据。
✗ 这个直觉是错的

「今天的大模型和 2019 年的 GPT-2 已经是完全不同的东西,拆 GPT-2 学到的那一套早就过时了。」

逐行读配置文件:切 token、查向量、几十层「注意力 + MLP」加在一条总线上、一张候选表、抽一个——这副骨架在 Llama、Qwen、DeepSeek 里原样都在。换掉的五个零件(RoPE、RMSNorm、门控 MLP、共享或压缩的键值、混合专家),主要是在让同样的事情更便宜、能更长,而不是换了一种做法。

真正拉开距离的是三样配置文件之外、或者只体现为一个数字的东西:规模(65 倍到几千倍的参数)、数据(多了上千倍),以及后训练。理解它们的直觉,前面十八章都给过了。

◇ 揭晓

正确答案是 C:每个 token 2 × 32 层 × 8 组 × 128 维 × 2 字节 = 128 KiB,乘 131072 个 token = 16 GiB。
如果 32 个头各存一组键值(像 GPT-2 那样),是 64 GiB。

A 「16 MB」——这是按 GPT-2 small 的规模在想:GPT-2 装满它的 1024 个位置是 36 MiB。今天的模型层数多、维度高、窗口长了 128 倍,三样一乘就是几百倍。 B 「1.6 GB」——低估了长度的分量。KV 缓存随上下文长度线性增长,128K 个 token,每个 128 KiB。 D 「160 GB」——高估了。如果没有 GQA,是 64 GiB;GQA 把它砍掉了四分之三。这正是那个改动存在的理由。

这一章的一句话

从 2019 年的 GPT-2 到今天的开源模型,骨架是同一副:token → 向量 → 几十层「注意力 + MLP」加在一条总线上 → 一张表 → 抽一个。换掉的五个零件主要在让它更便宜、更长;拉开距离的是规模、数据和后训练。

最后一章收尾。把前面十九个「✗ 这个直觉是错的」收成一张自查表,再按方向给出继续往下走的路——以及哪些问题至今没有定论。顺便让 GPT-2 读一下这本书的最后一句话:「This is not the end. It is only the」——它给 ␣beginning 的概率是 90.56%。