卷 III · 肚子里CH 11深度 11/20

知识存在哪

注意力负责在位置之间搬东西。可是「Michael Jordan 是打篮球的」这种事,不在这句话的任何一个位置上——它得是模型自己「知道」的。这一章去找它知道的地方:先看参数都花在了哪,再追踪 GPT-2 想起「篮球」的全过程,最后拿刀去删。结论会让习惯了数据库的人不太舒服:你找不到那一条记录。

MLP 占 45.5%36864 个神经元最多降到 5.72%
◉ 这一章在 GPT-2 的哪一段

▷ 先猜一下

喂给 GPT-2 Michael Jordan plays the sport of,它给 ␣basketball 13.53%,排第一。

假设「Jordan → 篮球」是存在某一层 MLP 里的一条记录。我们在 ␣Jordan 这个词的位置上,一次删掉一层的 MLP(12 层轮流删),看 basketball 的概率掉到多少。问:删掉影响最大的那一层,basketball 最低会降到多少?

A 接近 0%。删掉存它的那一层,记录就没了 B 2% 左右。几乎忘光了 C 6% 左右。少了一半多,但还记得 D 12% 左右。删哪一层都几乎没影响

答案在本章末尾。

参数都花在哪了

把 GPT-2 的 124439808 个参数按部件分一分:

部件参数占比做什么
词嵌入表3859737631.0%token 编号 → 坐标(第 5 章);最后还拿来把总线翻译回候选表
位置表7864320.6%第几个位置 → 一个向量(第 9 章)
注意力(12 层)2834841622.8%在位置之间搬信息
MLP(12 层)5666918445.5%在每个位置上就地加工
LayerNorm384000.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 的键和值是训练时刻进权重里的,是永久的。如果模型有「常识」,它最可能以这种形式存在:一大堆「看到这个模式,就往那个方向推一把」的规则。

看它想起篮球

Michael Jordan plays the sport of ▍ Michael ␣Jordan ␣plays ␣the ␣sport ␣of 下一个 token 概率 意外 ' basketball' 13.53% 2.89 比特 ' football' 8.59% 3.54 比特 ' golf' 5.62% 4.15 比特 ' hockey' 3.58% 4.80 比特 ' rugby' 2.75% 5.18 比特 ' soccer' 2.73% 5.20 比特 熵 8.11 比特

最终 basketball 13.53%,football 8.59%,golf 5.62%——它确实「知道」Jordan 和篮球有关,但没什么把握。用上一章的 logit lens 看这个答案是怎么长出来的:

在哪里截下来读basketball 名次basketball 概率football 名次
第 0 层之后12540.003%937
第 4 层之后540.06%26
第 5 层之后130.68%4
第 7 层之后49.19%3
第 8 层之后126.51%3
第 9 层之后161.88%2
第 10 层之后141.67%2
第 11 层之后(最终)113.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:

在 Jordan 的位置上删掉某一层 MLP 后,basketball 的概率(正常 13.53%) 删第 0 层 MLP 5.72% 删第 1 层 MLP 10.53% 删第 2 层 MLP 11.06% 删第 3 层 MLP 11.10% 删第 4 层 MLP 9.12% 删第 5 层 MLP 11.83% 删第 6 层 MLP 9.00% 删第 7 层 MLP 10.23% 删第 8 层 MLP 11.77% 删第 9 层 MLP 12.52% 删第 10 层 MLP 12.55% 删第 11 层 MLP 13.53%

删掉第 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% 一猜就中。它是怎么「现学」的?答案是两个注意力头搭成的一个小电路——而且可以亲手把它关掉。