知识存在哪
注意力负责在位置之间搬东西。可是「Michael Jordan 是打篮球的」这种事,不在这句话的任何一个位置上——它得是模型自己「知道」的。这一章去找它知道的地方:先看参数都花在了哪,再追踪 GPT-2 想起「篮球」的全过程,最后拿刀去删。结论会让习惯了数据库的人不太舒服:你找不到那一条记录。
喂给 GPT-2 Michael Jordan plays the sport of,它给 ␣basketball 13.53%,排第一。
假设「Jordan → 篮球」是存在某一层 MLP 里的一条记录。我们在 ␣Jordan 这个词的位置上,一次删掉一层的 MLP(12 层轮流删),看 basketball 的概率掉到多少。问:删掉影响最大的那一层,basketball 最低会降到多少?
答案在本章末尾。
参数都花在哪了
把 GPT-2 的 124439808 个参数按部件分一分:
| 部件 | 参数 | 占比 | 做什么 |
|---|---|---|---|
| 词嵌入表 | 38597376 | 31.0% | token 编号 → 坐标(第 5 章);最后还拿来把总线翻译回候选表 |
| 位置表 | 786432 | 0.6% | 第几个位置 → 一个向量(第 9 章) |
| 注意力(12 层) | 28348416 | 22.8% | 在位置之间搬信息 |
| MLP(12 层) | 56669184 | 45.5% | 在每个位置上就地加工 |
| LayerNorm | 38400 | 0.0% | 把向量的尺度拉回来 |
MLP 是最大的一块:每一层的 MLP 有 472 万个参数,是同一层注意力的整整两倍。它的结构很朴素:把总线上的 768 维向量乘一个矩阵,变成 3072 个数(每个数叫一个神经元),过一个弯曲函数(GELU,大致是「负的压成接近 0,正的留着」),再乘一个矩阵变回 768 维,加回总线。12 层一共 36864 个神经元。
MLP 是一张键值表
有一种看待 MLP 的方式很好用(2021 年 Geva 等人的论文《Transformer Feed-Forward Layers Are Key-Value Memories》把它说透了):
- 第一个矩阵的每一行是一个键:一个「模式探测器」。总线上的向量和它越像,对应的那个神经元就越亮。
- 第二个矩阵的每一列是一个值:这个神经元亮了之后,要往总线上写的那个方向。
所以每个神经元都是一条「如果看到 X,就写下 Y」的规则,3072 条规则同时检查、按亮度加权写回去。和第 9 章的注意力比:注意力的「键」来自上下文里别的位置,是临时的;MLP 的键和值是训练时刻进权重里的,是永久的。如果模型有「常识」,它最可能以这种形式存在:一大堆「看到这个模式,就往那个方向推一把」的规则。
看它想起篮球
最终 basketball 13.53%,football 8.59%,golf 5.62%——它确实「知道」Jordan 和篮球有关,但没什么把握。用上一章的 logit lens 看这个答案是怎么长出来的:
| 在哪里截下来读 | basketball 名次 | basketball 概率 | football 名次 |
|---|---|---|---|
| 第 0 层之后 | 1254 | 0.003% | 937 |
| 第 4 层之后 | 54 | 0.06% | 26 |
| 第 5 层之后 | 13 | 0.68% | 4 |
| 第 7 层之后 | 4 | 9.19% | 3 |
| 第 8 层之后 | 1 | 26.51% | 3 |
| 第 9 层之后 | 1 | 61.88% | 2 |
| 第 10 层之后 | 1 | 41.67% | 2 |
| 第 11 层之后(最终) | 1 | 13.53% | 2 |
前半段,football 一直走在 basketball 前面——「the sport of」后面接 football 本来就更常见。到第 7、8 层,basketball 追上并反超;第 9 层之后,它一度拿到 61.88%。然后最后两层又把它压回到 13.53%。这个「先冲高、再回落」的形状后面还会解释。
再用上一章的拆账法,把最终「basketball 胜过 football」的 1.45 拆回各部件:
第 7 层 MLP +0.42 ← 单个部件里最大的一笔,占 29% 第 10 层注意力 +0.34 第 11 层注意力 +0.24 第 9 层注意力 +0.24 第 8 层 MLP +0.23 第 10 层 MLP ⟦−0.16⟧ 第 3 层 MLP ⟦−0.14⟧ ……(其余 18 笔各自不到 ±0.13)
没有哪个部件是「那个答案」。最大的一笔是第 7 层的 MLP,也只占 29%;其余的分散在好几层的注意力和 MLP 里,还有几层在往反方向写。
拿刀去删:没有那一条记录
2022 年有一篇很有影响的论文(Meng 等人的 ROME)提出:关于一个人的事实,主要是在读到这个人名字的最后一个 token 时,由中间几层的 MLP「取出来」的;他们还据此去改写 MLP 的权重,让模型相信「埃菲尔铁塔在罗马」。照这个思路,在 ␣Jordan 这个位置上,一层一层地删 MLP:
删掉第 0 层影响最大,basketball 降到 5.72%——但第 10 章说过,第 0 层的 MLP 实际上是在给词嵌入补课,删掉它等于把「Jordan」这个词本身弄模糊了。删第 1 到第 10 层中的任何一层,basketball 都还在 9.00% 到 12.55% 之间。没有任何一层是「存着 Jordan 打篮球的那一格」:它被分散地写在很多层里,彼此冗余,删一处,其余的还能凑出个大概。
这件事在研究界至今有争论。ROME 在更大的模型上找到了相当集中的位置;可是 2023 年另一篇论文(Hase 等人,《Does Localization Inform Editing?》)发现:「删哪里影响最大」和「改哪里最有效」之间几乎没有关系——你以为找到了存储位置,改别的层照样能改掉这个事实。这里能带走的判断是:在这台模型里,「一条知识」不是一个可以指着说「就在这」的东西。
最后两层在泼冷水
回到那个「冲高再回落」:第 9 层之后 basketball 是 61.88%,最终只有 13.53%。是谁把它压下去的?在最后一个位置上分别删掉第 10、11 层的 MLP:
正常 basketball 13.53% 删掉最后一个位置的第 10 层 MLP ⟪25.73%⟫ 删掉最后一个位置的第 11 层 MLP ⟪32.47%⟫
删掉它们,模型反而更确定了。最后两层的一部分工作,是把前面层过于集中的判断摊开——给其他可能的续写留一点概率。这不奇怪:第 4 章说过,交叉熵会狠狠惩罚「信誓旦旦地错」,一个总是过度自信的模型损失会很高。于是训练在网络的末端长出了一个「降温器」。模型最终给出的把握,是一个被特意校准过的数,不是它内部最强的那个信号。第 18 章会看到,后续的训练怎样把这个降温器弄坏。
参数账本,八行:
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("gpt2")
groups = dict.fromkeys(["词嵌入 wte", "位置 wpe", "注意力", "MLP", "LayerNorm"], 0)
for name, p in model.transformer.named_parameters():
key = ("词嵌入 wte" if "wte" in name else "位置 wpe" if "wpe" in name else
"注意力" if ".attn." in name else "MLP" if ".mlp." in name else "LayerNorm")
groups[key] += p.numel()
total = sum(groups.values())
for k, v in groups.items():
print(f"{k:10} {v:>12,} {v / total:6.1%}")
print(f"{'合计':10} {total:>12,}")
本机输出:
词嵌入 wte 38,597,376 31.0% 位置 wpe 786,432 0.6% 注意力 28,348,416 22.8% MLP 56,669,184 45.5% LayerNorm 38,400 0.0% 合计 124,439,808
把第 10 章那段 logit lens 的代码里的句子和两个候选换成 Michael Jordan plays the sport of / ␣basketball / ␣football,就能复现上面那张逐层表。
pip install torch transformers && python 11.py
ROME 的作者把他们的方法做成了在线演示和代码(搜「rome.baulab.info」),能亲手把一个事实「改」进 GPT-2 里,然后看看还有哪些别的东西被一起改坏了。
- 「让模型忘掉某件事」比想象中难。个人信息被训进了模型,按隐私法规要求删除——可是没有一条记录可删。这个方向叫机器遗忘(machine unlearning),至今没有既彻底又不伤及其他能力的通用办法。
- 会变的事实,最好别指望写进权重。公司的价格表、本周的值班表、最新的 API 版本——与其靠微调把它们「教」给模型,不如在提问时把它们放进上下文(这就是 RAG 的出发点)。第 17 章会看到,微调连格式都学得比事实快得多。
- 同一个事实,问法一变,答案就可能变。因为它不是一条记录,而是很多层规则合力推出来的方向;换一种问法,参与合力的规则就换了一批。
「模型里的知识就像数据库里的记录:找到存它的那一格,就能读出来、改掉或删掉。」
在 ␣Jordan 的位置上逐层删 MLP,basketball 最低只降到 5.72%(而且那一层是嵌入的延伸);最终答案拆开来,最大的一笔也只占 29%。知识是分散的、冗余的、按方向叠加的——它更像一种倾向,而不是一行数据。
所以「编辑一个事实」总会带来副作用(改了 A,相关的 B 可能跟着变或者没跟着变),「删除一个事实」很难删干净。对于要准确、要更新、要能撤回的信息,别把它存进权重里。
正确答案是 C:删掉第 0 层的 MLP,basketball 从 13.53% 降到 5.72%;删其他任何一层,都还在 9.00% 到 12.55% 之间(删第 11 层不影响,因为那里写的东西已经没有人再读)。
A 「删掉存它的那一层就没了」——这是数据库的直觉。这台模型里没有「那一层」,删任何一处,其余各层写的那些笔还在。 B 「几乎忘光」——要做到这个程度,得同时删好几层;而那样一来,被一起删掉的就不只是这一条知识了。 D 「删哪一层都几乎没影响」——对大多数层来说接近事实(第 9、10 层删掉后还有 12.5%)。只是第 0 层删掉伤得比较重,因为它在给「Jordan」这个词的表示本身补课。《当真》讲的是一种把每一条数据都「当真」的系统:每一行有主键,能精确地增删改查。这一章的模型是它的反面——没有主键、没有行。《拨动》的干预方法论在这里又用了一次:想知道一个部件起什么作用,就把它拿掉,看下游怎么变。
这一章的一句话
MLP 占了模型近一半的参数,是一张「看到某个模式,就往总线上推某个方向」的键值表;知识以分散、冗余、叠加的方式存在于很多层里,找不到「那一条记录」。而模型最终说出口的把握,是末端几层特意降过温的结果。
下一章是全书的招牌实验。给 GPT-2 一串它从没见过的随机 token,50 个,然后原样再来一遍。第一遍它每个都猜不中:平均 17.36 比特,比在 50257 个里闭眼瞎猜(15.62 比特)还差。第二遍,平均 0.63 比特,97.1% 一猜就中。它是怎么「现学」的?答案是两个注意力头搭成的一个小电路——而且可以亲手把它关掉。