Lecture 12 · 机制可解释性:逆向工程 Transformer 学到的算法 · Mechanistic Interpretability

Advances in Foundation Models · Lecture 12。个人学习讲义与配套实验,按主题整理并持续修订。

课程源码 ZIP ↓

个人整理的学习笔记,非官方讲义;课程来源与整理说明见课程介绍。配套示例未逐一运行验证。

本篇目录

对应 Maps to:Stanford CS324 Winter 2023 Advances in Foundation Models,1/30 客座报告 Stella Biderman(EleutherAI):Mechanistic Interpretability – Reverse Engineering Learned Algorithms from Transformers。 依据说明:课程网站没有提供 slides 或录像,报告的具体内容不可考。本讲依据报告题目所指的研究方向和讲者的公开工作来写:Elhage et al. 2021(A Mathematical Framework for Transformer Circuits)、Olsson et al. 2022(In-context Learning and Induction Heads)、Nanda et al. 2023(Progress Measures for Grokking via Mechanistic Interpretability)、Elhage et al. 2022(Toy Models of Superposition);Biderman 本人参与的 Pythia(Biderman et al. 2023)、tuned lens(Belrose et al. 2023)和关于记忆的研究。§6 的稀疏自编码器补充了 Bricken et al. 2023(Towards Monosemanticity)。这些都是 2022–2023 年机制可解释性的代表性工作,但我不能确定报告讲了其中哪些。文献里的数字都是我在原文里读到的;§9”2023 年之后”是我补充的。 配套代码 Code:code/lecture12/(PyTorch;5 个脚本 + 1 个模块。代码 01 约 3 秒,02 第一次约 45 秒,03 约 1 秒,04 约 60 秒,05 约 15 秒) 预计阅读时间:3.5 小时(含运行代码)


0. 本讲导航 · How to read this lecture

0.1 学习目标 Learning goals

学完这一讲,你应该能够:

  1. 说清”行为上的”理解和”机制上的”理解的区别,以及机制可解释性想做的事:像反编译一个程序那样,读出网络执行的算法。
  2. 用残差流的视角描述 Transformer:每个部件从残差流读、往残差流写,最后的输出是所有部件的和;会用 logit lens 和直接 logit 归因,并知道它们看不到什么。
  3. 解释只有注意力的 Transformer 里的 QK 电路和 OV 电路,以及 0 层、1 层、2 层模型分别能实现什么(二元组、跳跃三元组、通过组合实现 induction)。
  4. 描述 induction head 的算法 [A][B] … [A] → [B]、它在训练中的相变,并用三类证据(训练动态、消融与修补、直接读权重)论证”它就是复制能力的来源”。
  5. 解释 grokking:先背诵、后泛化;Nanda et al. 发现的傅里叶算法;“顿悟”背后平稳变化的进度指标;权重衰减的作用。
  6. 解释叠加(superposition)和多义神经元,以及稀疏自编码器为什么能把叠加的特征拆开。
  7. 说出 Pythia 一类”开放的训练过程”对可解释性研究的意义,以及机制可解释性目前的局限。

0.2 先修与本讲范围 Prerequisites & scope

默认你已经会 Assumed本讲只给直觉,后面几讲再展开 Previewed only
第 3 讲 §3:Transformer 的每个部件(嵌入、q / k / v、多头、残差、LayerNorm、MLP)记忆与训练数据提取(第 16 讲)
第 5 讲 §4:上下文学习,以及”第 1 讲的 base model 没有形成 induction head”可解释性在安全中的用途(第 17、18 讲)
第 6 讲 §6:因果追踪(激活修补的一种)
第 11 讲 §6.3:base model 不会”回去抄”;§5:最小描述长度

0.3 本讲地图 Map

§1  为什么要打开黑盒:行为 vs 机制;反编译的比喻
§2  残差流、logit lens 与归因:第 1 讲的 base model 怎样"想起"一个人住在哪里      ← 代码 01
§3  Transformer 电路的数学框架:只有注意力的模型、QK 与 OV、组合
§4  induction head:形成的相变、1 层对照、消融、修补、读权重                        ← 代码 02、03
§5  grokking:背诵、顿悟、傅里叶算法与进度指标                                    ← 代码 04
§6  叠加与稀疏自编码器                                                           ← 代码 05
§7  Pythia:把训练过程本身变成研究对象(Biderman 的工作)
§8  局限与争论
§9  2023 年之后:大规模 SAE、归因图、自动化可解释性
§10–14  小结、常见误区、练习、延伸阅读、下一讲预告

0.4 记号 Notation(只列本讲新增的,其余见第 1 讲 §0.4)

符号含义例子
残差流 xℓx_\ell第 ℓ\ell 层之后、每个位置上的那个 dd 维向量xfinal=x_{\text{final}} = 嵌入 + Σ 各部件输出
WEW_E,WPW_P,WUW_Utoken 嵌入、位置嵌入、反嵌入(unembedding)logits =xWU= x W_U
WQK=WQ⊤WKW_{QK} = W_Q^\top W_KQK 电路:决定”哪个位置看哪个位置”
WOV=WOWVW_{OV} = W_O W_VOV 电路:决定”看到之后往残差流里写什么”
K / Q / V-composition后一层的头在算键 / 查询 / 值时,读了前一层某个头写下的东西induction head 靠 K-composition
消融(ablation)把一个部件的输出置零(零消融)或换成平均值(均值消融)
激活修补(activation patching)在”被破坏”的输入上运行,把某个部件的输出换成”干净”输入上的值第 6 讲的因果追踪是一种
SAE稀疏自编码器(sparse autoencoder)

0.5 关于数字 · About the numbers

讲义里的实验数字都来自 code/lecture12/ 的实际输出(固定种子、PyTorch 单线程,同一台机器上重复运行逐字相同;代码 02 训练的模型缓存在本目录的 checkpoints/,删掉后重新训练得到逐位相同的结果)。代码 01 打开的是第 1 讲的 base model;代码 02–05 用的是专门设计的极小模型(只有注意力的 2 层 Transformer、模加法的 MLP、5 维的玩具模型),因为机制可解释性目前只在这样的规模上能做到”完全讲清楚”。有几处结果和我写代码前的预想不一样(完整清单在代码 README 的”关于实验结果”里),最重要的是:base model 里注意力头的直接贡献几乎为 0,它们的作用要靠消融才看得出来(§2.4);以及 K-composition 的信号比我预想的弱(§4.6)。


1. 为什么要打开黑盒 · Why open the black box

1.1 行为 vs 机制

前面十一讲大多是从外面研究模型:给它输入,看它输出——它的损失(第 4 讲)、它能做什么任务(第 5 讲)、它压缩得多好(第 11 讲)。这叫行为上的理解。它能告诉我们模型”会什么”,但不能告诉我们模型”怎样做到的”,也就无法回答一些关键的问题:模型在新的情况下会不会用同样的方式工作?它给出某个答案,是因为”理解”了,还是因为碰巧记住了一个相似的例子?它有没有在做我们不希望它做的事?

机制可解释性(mechanistic interpretability)想做的是从里面理解:把训练好的网络当成一个编译好的程序,把它”反编译”成人能读懂的算法。权重就是机器码,我们想读出源代码。

这个比喻也说明了它为什么难。一个训练好的网络没有变量名、没有注释、没有函数边界;它的”代码”分散在几百万个浮点数里,同一个数可能参与很多件事(§6 的叠加)。所以这个领域的策略是:从极小的模型、极简单的任务开始,在能完全讲清楚的地方建立工具和概念,再一步步推向更大的模型。

1.2 这次报告的背景

Stella Biderman 是 EleutherAI 的核心成员。EleutherAI 是一个开放的研究团体,训练并公开了 GPT-Neo、GPT-J、GPT-NeoX-20B 等模型和 Pile 数据集(第 2 讲),以及专门为科学研究设计的 Pythia 模型族(§7)。这些开放的模型和训练过程,正是可解释性研究的原材料:研究一个模型的内部,你需要它的权重;研究一个能力怎样形成,你需要训练过程中的检查点。报告的题目”逆向工程 Transformer 学到的算法”,概括了 2021–2023 年这个领域最有代表性的几项成果——这一讲按它们来组织。


2. 残差流、logit lens 与归因 · The residual stream

2.1 残差流是一条”通信总线”

第 3 讲 §3.6 讲过 pre-LN Transformer 的结构:每一层都是 x←x+部件(LN(x))x \leftarrow x + \text{部件}(\mathrm{LN}(x))。Elhage et al. (2021) 建议换一个角度看这个结构:残差流(residual stream)是一条贯穿整个网络的通信总线,每个部件(每个注意力头、每个 MLP)从总线上读一些信息,处理之后再写回总线;最后,输出层从总线上读出预测。

这个视角有一个很实用的推论:最后的残差流就是所有部件输出的和。对第 1 讲的 2 层 base model:

xfinal=WE[token]+WP[位置]⏟嵌入+注意力0+MLP0+注意力1+MLP1,x_{\text{final}} = \underbrace{W_E[\text{token}] + W_P[\text{位置}]}_{\text{嵌入}} + \text{注意力}_0 + \text{MLP}_0 + \text{注意力}_1 + \text{MLP}_1 ,

而注意力的输出又可以拆成每个头的贡献之和(输出投影是线性的)。代码 01 把 base model 的前向手写了一遍,把每一项都留下来,并断言它们的和等于最后的残差流。

2.2 logit lens:如果在这里停下

既然每一层都在往同一条总线上写东西,那么中间某一层的残差流是不是已经包含了部分答案?logit lens(nostalgebraist,2020)的做法很直接:把中间层的残差流直接接到最后的 LayerNorm 和输出层上,看”如果在这里停下,模型会预测什么”。

代码 01 演示 2 用 60 个提示”<名字> lives in “(答案是这个人所住城市的首字母,8 个城市的首字母互不相同):

在这里停下正确首字母的平均概率top-1 准确率8 个城市首字母的总概率
嵌入之后0.0000.0000.000
第 0 层之后0.0140.0000.115
第 1 层之后(最终)0.8550.9330.993

只看嵌入,模型对城市一无所知。第 0 层之后,城市首字母的总概率升到 0.115,但正确的那个只有 0.014(约等于 0.115 ÷ 8)——“接下来可能是一个城市”开始出现,“是哪个城市”还完全不知道。到第 1 层之后,正确的城市才被挑出来。类别先出现,具体的事实后出现——在大模型的 logit lens 研究里也常看到这种由粗到细的过程。

logit lens 是一个粗糙的工具:中间层的残差流并不是为”直接接输出层”而训练的,它可能用一种输出层读不懂的方式编码了信息。tuned lens(Belrose et al. 2023,Biderman 是作者之一)给每一层学一个小的线性变换,再接输出层,在大模型上可靠得多。

2.3 直接 logit 归因

更进一步:既然最后的残差流是各部件之和,而输出层(忽略 LayerNorm 的非线性)是线性的,就可以把一个 logit 分解成各部件的贡献。这叫直接 logit 归因(direct logit attribution)。代码 01 演示 3 分解的是”正确首字母的 logit − 其他 7 个城市首字母 logit 的平均”(只关心”选哪个城市”,不关心”是不是城市”),LayerNorm 的除法冻结成一个常数:

部件平均贡献(logit 差)占总量
第 1 层 MLP+6.67098%
第 0 层 MLP+0.3004%
第 1 层 注意力头 3+0.0591%
其余 10 项(另 7 个头、两个注意力偏置、嵌入)−0.118 到 +0.026合计约 −4%
合计+6.777

第 1 层的 MLP 一项就占了 98%:事实是在最后一层的 MLP 里”查出来”的。这和第 6 讲 §6 的因果追踪一致:那里我们发现,把第 2 层 MLP 在最后一个位置的输出放回去,就能恢复大部分事实回忆。

2.4 直接归因看不到的东西

但演示 3 还有一个让我意外的结果:所有注意力头的直接贡献都接近 0。难道注意力在这里不重要?

代码 01 演示 4 用消融来检验:把一个头的输出置零(零消融),或者换成它在整个数据集上的平均值(均值消融——它让这个头不再携带任何关于具体输入的信息,同时不把残差流推到它从没见过的状态)。正确首字母的平均概率(不消融时 0.855):

注意力头在最后一个位置看名字的注意力零消融后均值消融后
第 0 层 头 00.190.7160.719
第 0 层 头 10.070.4740.491
第 0 层 头 20.060.3670.551
第 0 层 头 30.190.3630.558
第 1 层 头 00.850.2850.307
第 1 层 头 10.000.5530.493
第 1 层 头 20.030.7080.722
第 1 层 头 30.050.7570.766

每一个头被消融,模型都忘得更多。影响最大的是第 1 层头 0:它在最后一个位置把 85% 的注意力放在名字的字符上,把”这个人是谁”的信息搬过来;第 1 层的 MLP 再用它查出城市。第 0 层的头则在名字的最后一个字符处看名字前面的字符(0.58–0.72):先在名字内部把几个字符汇总起来。

这说明了直接归因的根本局限:它只能看到”最后一步”是谁写的,看不到”谁让这一步成为可能”。注意力头的作用是间接的——它们搬运信息,让 MLP 能查到答案。要看到间接作用,必须做因果干预(消融、修补)。同时也要看到,这个只有 2 层的模型里信息流已经是分布式的:没有哪一个头是唯一的”负责人”,还有看起来不看名字、消融后却影响很大的头(第 1 层头 1)。要完全讲清楚,需要更细的工具(路径修补),这超出了本讲的范围。

这正是为什么机制可解释性要从更简单的设定开始:去掉 MLP,去掉 LayerNorm,换一个”答案完全确定”的任务。


3. Transformer 电路的数学框架 · A mathematical framework

3.1 只有注意力的 Transformer

Elhage et al. (2021) 研究的是只有注意力层的 Transformer:没有 MLP、没有 LayerNorm(或者把它忽略)、没有偏置。这样的模型里,从输入到输出的每一步都是线性的,除了注意力的 softmax。于是整个网络可以写成一串矩阵乘积,能直接读权重。

一个注意力头做的事可以拆成两个独立的部分:

  • QK 电路 WQK=WQ⊤WKW_{QK} = W_Q^\top W_K(d×dd \times d 的矩阵):位置 qq 的残差流 xqx_q 和位置 kk 的 xkx_k,注意力分数是 xq⊤WQK xkx_q^\top W_{QK}\, x_k——它决定**“哪个位置看哪个位置”**。
  • OV 电路 WOV=WOWVW_{OV} = W_O W_V(同样是 d×dd \times d):被看到的位置 kk,往位置 qq 的残差流里写 WOV xkW_{OV}\, x_k——它决定**“看到之后写什么”**。

两者是分开的:注意力模式只由 QK 决定,写入的内容只由 OV 决定。这让分析一个头变得很清楚。

3.2 0 层、1 层、2 层能做什么

Elhage et al. 用这个框架一层一层地分析:

  • 0 层(只有嵌入和反嵌入):logits =WEWU= W_E W_U,只依赖当前 token——它只能学二元组统计(“看到 A,下一个多半是 B”)。
  • 1 层只有注意力:每个头可以”看到前面的某个 token,再提高某个 token 的概率”——这是跳跃三元组(skip-trigram):[A] … [B] → [C]。它能做”前面出现过的词更可能再出现”这一类事,但看哪里只能由当前 token 和那个位置的 token 本身决定。
  • 2 层:第 1 层的头可以读第 0 层的头写下的东西,用来算自己的查询、键或值——这叫组合(composition,Q / K / V-composition)。有了组合,就能实现更复杂的算法;其中最重要的一个是 induction head。

3.3 为什么 induction 需要两层

induction 要做的是:当前 token 是 [A],到前面找上一次出现 [A] 的地方,抄它后面的那个 token [B]。难点在于”它后面的那个”:要让位置 qq(token [A])去注意位置 kk(token [B]),注意力分数必须依赖于”位置 kk 的前一个 token 是不是 [A]“——而位置 kk 的残差流里本来只有 [B] 自己的信息。

解决办法是两步:

  1. 第 0 层的一个前一个 token 头:每个位置都注意自己的前一个位置,把”我前面是谁”写进自己的残差流。
  2. 第 1 层的 induction 头:位置 qq 用”我是 [A]“去匹配各个位置残差流里的”我前面是谁”——在算键的时候读第 0 层写下的东西(K-composition),匹配上的位置正好是 [B];然后用 OV 电路把 [B] 抄到输出。

一层注意力做不到这件事,因为它无法在同一层里既”算出前一个 token”又”用它来匹配”。这是一个可以检验的预测(§4.3)。


4. induction head

4.1 实验设定

代码 02 在最干净的设定下训练:一个只有注意力的 2 层 Transformer(每层 4 个头,宽度 64,没有 MLP、LayerNorm 和偏置),训练数据是随机的 token 片段(词表 64)重复若干遍拼成的序列(长度 64)。片段长度在 6–31 之间随机:

片段长度 L = 22:47 53  0  3 59  3 39  9 19 21 50 36 23  6 24 24 12 58  1 38 39 23 47 53  0  3 59 …
                 ·· ·· ·· ·· ·· ·· ·· ·· ·· ·· ·· ·· ·· ·· ·· ·· ·· ·· ·· ·· ·· ·· ↑↑ ↑↑ ↑↑ ↑↑ ↑↑ …

第一遍(··)是随机的,谁也预测不了(最好也要 ln⁡64=4.16\ln 64 = 4.16 nats);第二遍以后(↑↑),只要会”抄”就能预测。片段长度随机是关键:如果长度固定,模型可以学”往回数 L 步”这种只看位置的捷径;长度随机时,必须靠内容匹配。(这个设计是我在第一版实验失败后改的:第一版只有一部分位置可以靠复制预测,2000 步里 induction head 没有形成,代码 README 里有记录。)

4.2 相变

代码 02 演示 2 每 50 步记录一次:重复部分的损失,以及每个头的两个诊断分数(Olsson et al. 的定义)——前一个 token 分数(位置 ii 注意 i−1i - 1 的平均注意力)和 induction 分数(位置 ii 注意”前一个 token 等于 xix_i“的那些位置的注意力之和)。节选:

步重复部分损失第一遍损失最强的前一个 token 头最强的 induction 头
04.1794.1860.060.07
6003.5834.6010.060.08
7003.4364.6350.070.11
8002.8644.9170.090.29
9001.4105.2180.160.69
10000.8455.0120.230.85
20000.4574.6030.370.85

前 600 步,重复部分的损失和第一遍差不多:模型还不会抄。第 700–1000 步之间,重复部分的损失骤降(3.58 → 0.85),同一时刻第 1 层出现了 induction 分数约 0.85 的头,第 0 层出现了前一个 token 分数逐渐升高的头。训练结束时,第 1 层的 4 个头都成了 induction 头(0.84–0.85),第 0 层的头 1、头 3 是前一个 token 头(0.33、0.37)。

这就是 Olsson et al. 描述的相变:电路的形成和能力的出现发生在同一时刻,在损失曲线上表现为一次突然的下降(在真实语言模型的训练里,它是训练早期损失曲线上的一个小”鼓包”)。这也是第 5 讲讨论”涌现”时提到的一种”真实的跳变”。

一个有意思的细节:第一遍的损失在相变期间反而上升(第 900 步到 5.2,之后回落到 4.6)。模型开始把概率押在”前面出现过的 token”上,而在第一遍(全是新 token)里这个赌注是错的。获得一种能力,常常伴随着在别处付出一点代价。

4.3 对照:只有 1 层的模型

代码 02 演示 3 用同样的数据训练只有 1 层注意力的模型:重复部分的损失降到 2.918 就停住了,induction 分数一直在 0.1 附近。它学到的是一个更弱的策略:把注意力分散在前面出现过的 token 上,提高它们的概率——相当于”答案是前面某个 token,但不知道是哪个”。如果均匀地猜片段里出现过的 token,损失约为 ln⁡\ln(片段里不同 token 的个数)≈ ln⁡15.6=2.75\ln 15.6 = 2.75,和 1 层模型的 2.92 很接近。

这正是 §3.3 的预测:1 层注意力做不了 induction。Olsson et al. 也明确说,induction head 不会出现在 1 层模型里,因为它需要不同层的注意力头组合。

4.4 一个具体的例子

代码 02 演示 4 在一个片段长度为 7 的序列上看两个头在每个位置注意哪里(注意力最大的位置):

序列:35 14 47 61 38 54 16 35 14 47 61 38 54 16 35 14 47 …
  q  x[q]  第 0 层头 3 看  第 1 层头 0 看  它抄到的  真正的下一个
 11   38     10(61)           5           54          54
 12   54     11(38)           6           16          16
 13   16     12(54)           7           35          35
 14   35     13(16)           1           14          14

第 0 层的前一个 token 头:位置 qq 看 q−1q - 1。第 1 层的 induction 头:位置 qq 去看上一次出现 xqx_q 之后的那个位置,把那里的 token 抄过来——正好是真正的下一个。从第二遍开始的 13 个位置里,头 0 有 11 个看对了;看错的两个位置由另外 3 个 induction 头补上(下一节的消融会看到这种冗余)。

4.5 因果证据:消融与修补

训练动态只给出了相关性。代码 03 给出因果证据。

消融(演示 1):把头的输出置零,看重复部分的损失(不消融时 0.457,完全不会抄时约 4.2):

消融重复部分损失
任意一个 induction 头(第 1 层)0.804–1.065
第 1 层的 4 个头一起4.243
第 0 层头 1 和头 3(前一个 token 头)3.059
第 0 层头 0 和头 21.165

一个 induction 头被消融,其他三个能补上;4 个一起消融,模型完全不会抄了。更说明问题的是第 0 层:induction 头本身没有被碰,但消融了两个前一个 token 头,损失就升到 3.06——第 1 层的能力依赖第 0 层特定的头,这是”两层组合”的因果证据。

激活修补(演示 2):把序列第一遍的片段换成别的随机 token,于是第二遍”无处可抄”,第二遍的损失从 0.737 升到 5.320;再把某个头在原序列上的输出”修补”到这次运行里,看能找回多少:

修补哪个头找回的比例
任意一个 induction 头34%–43%
第 1 层的 4 个头一起99.9%
第 0 层的任意一个头 / 4 个一起约 0 / −7%

4 个 induction 头的输出携带了全部的复制信息。修补第 0 层的头却几乎没用:它们写下的”前一个 token 是谁”说的是被破坏之前的 token,而第 1 层的头从被破坏的位置读到的”值”已经是别的 token 了——光有”找哪里”的信息,没有”抄什么”的内容。修补比消融更精确:它告诉我们信息在哪里、以什么形式流动。

4.6 直接读权重

最后,算法能不能直接从权重里读出来?

OV 电路在复制(演示 3):把”注意到 token tt → 往输出 logits 上加什么”写成一个 64 × 64 的矩阵 M=WEWV⊤WO⊤WUM = W_E W_V^\top W_O^\top W_U(形状上的转置是实现细节),看它的特征值。复制分数 ∑λ/∑∣λ∣\sum \lambda / \sum |\lambda| 接近 +1 意味着这个头把注意到的 token 原样搬到输出。第 1 层 4 个头的复制分数都是 0.997–0.998(随机初始化的模型在 −0.234 到 +0.140 之间);对超过一半的 token,MM 的那一行里最大的正好是它自己。第 0 层的头复制分数是负的:它们不是用来直接影响输出的。

QK 电路读的是”前一个 token”(演示 4):用 Elhage et al. 的组合分数,看第 1 层的头在算键 / 查询 / 值时,读了多少第 0 层各头写下的东西:

第 0 层的头 → 第 1 层所有头K-compositionQ-compositionV-composition
头 1、头 3(前一个 token 头)0.158–0.1720.062–0.0700.063–0.087
头 0、头 20.114–0.1370.076–0.1010.115–0.136
随机初始化的模型(平均 / 最大)0.123 / 0.1440.126 / 0.1470.126 / 0.140

这正是 induction 电路的签名:前一个 token 头的输出被第 1 层的头用来算键(K-composition 高于随机的最大值),而在查询和值这两侧被”绕开”(低于随机水平)。不过差距不算大(0.17 vs 随机 0.12):分数是对整个 64 维空间的平均,而电路只用到其中几个方向。直接读权重是有用的,但在更大的模型里信号会更淡,需要和因果方法一起用。

4.7 从玩具到真实模型

Olsson et al. 的论文给出了六类证据,论证 induction head 可能是大语言模型中大部分上下文学习的机制来源:对只有注意力的小模型,证据是因果的(就像我们的消融和修补);对带 MLP 的大模型,证据是相关的(相变的时机、去掉之后的影响等)。他们定义的”上下文学习分数”——上下文里第 500 个 token 的损失减去第 50 个 token 的损失——在 induction head 形成的同一时刻急剧下降。

回到第 5 讲和第 11 讲的问题:为什么第 1 讲的 base model 没有形成 induction head?一个合理的猜想(我没有直接验证)是:迷你互联网里几乎没有”在 96 个字符的上下文里,照着前面一段新出现的内容往下写”的机会——人物介绍会重复,但重复出现在不同的行里,模型靠把它背进参数就能预测,不需要在上下文里抄。训练数据里有什么样的规律,模型才会学什么样的电路;第 2 讲 §6.3 提到的 Hernandez et al. 也发现,数据的重复方式会影响复制能力和 induction head——在那里,受伤最重的正是它们。


5. grokking:先背诵,后顿悟 · Grokking

5.1 现象

Power et al. (2022) 在一类很小的算法任务上(比如模加法 (a+b) mod p(a + b) \bmod p,只给一部分数对做训练)发现了一个奇怪的现象:网络很快就把训练集背了下来(训练准确率 100%),测试准确率却接近 0;继续训练很久之后,测试准确率突然升到接近 100%。他们把它叫做 grokking(大意是”彻底领悟”)。

代码 04 复现了它:一个小 MLP(两个数各查一个嵌入,拼起来过一层 ReLU)学 (a+b) mod 59(a + b) \bmod 59,只用 40% 的数对训练(AdamW,权重衰减 1.0,全 batch,30,000 步):

步训练准确率测试准确率参数范数最强 5 个频率占的嵌入能量
00.0190.01561.60.200
20001.0000.00071.40.222
40001.0000.00368.10.241
80001.0000.06763.60.295
120001.0000.66359.30.401
140001.0000.92057.40.465
200001.0001.00053.90.564
300001.0001.00051.80.606

训练准确率在 2000 步之内就到了 1;测试准确率在 0 附近停留了好几千步,然后爬升,20000 步时到 1。

5.2 网络学到了什么算法

Nanda et al. (2023) 打开了一个 grokking 之后的网络(1 层 Transformer,p=113p = 113,30% 的数对做训练,AdamW、权重衰减 1,全 batch,训练 40,000 个 epoch),发现它用的是离散傅里叶变换和三角恒等式:

  1. 把输入 aa 表示成若干个频率 ωk=2πk/p\omega_k = 2\pi k / p 下的 cos⁡(ωka)\cos(\omega_k a)、sin⁡(ωka)\sin(\omega_k a)——嵌入矩阵的能量集中在少数几个频率上(他们的模型用了 5 个关键频率:14、35、41、42、52)。
  2. 用三角恒等式算出 cos⁡(ωk(a+b))\cos(\omega_k (a + b)) 和 sin⁡(ωk(a+b))\sin(\omega_k (a + b))。
  3. 对每个候选答案 cc,算 cos⁡(ωk(a+b−c))\cos(\omega_k (a + b - c))——它在 c=a+b mod pc = a + b \bmod p 时最大。

“加法”变成了”在圆上转动”。他们用权重分析、激活分析和在傅里叶空间里做消融验证了这个算法:去掉 5 个关键频率之外的所有成分,模型的表现甚至略有提高。

代码 04 演示 3 在我们的小 MLP 上做了同样的因果检验:只保留嵌入里最强的几个频率(其余 20 多个频率的成分全部去掉),或者只去掉它们:

嵌入里只保留它们只去掉它们
最强的 3 个频率 [3, 17, 29]0.8560.934
最强的 5 个频率 [3, 5, 11, 17, 29]0.9960.602
最强的 8 个频率1.0000.052

(原模型 1.000;随机猜是 0.017。)只保留 5 个频率,准确率还有 0.996;去掉 8 个,掉到 0.052。我们的模型用的频率不同(pp 不同、结构不同),也更分散——只去掉最强的 3 个,准确率还有 0.934——但做的是同一类事。(我第一次只训练了 15,000 步,那时只保留 5 个频率的准确率只有 0.753:模型还没”清理”完,见下一节。)

5.3 顿悟不是突然的:进度指标

Nanda et al. 最重要的结论是:grokking 看起来是突然的,但背后是平稳的。他们定义了几个”进度指标”(例如只保留关键频率时的损失),发现这些指标在测试准确率起飞之前很久就在平稳变化。他们把训练分成三个连续的阶段:背诵(0–1.4k 个 epoch)、电路形成(1.4k–9.4k)、清理(9.4k–14k)——测试准确率的跃升发生在清理阶段,当权重衰减把用于背诵的部分去掉、让泛化电路”露出来”的时候。

我们的表格里能看到同样的东西:嵌入能量向最强 5 个频率集中的比例,从 0.20 开始一路平稳上升——测试准确率还接近 0 的时候(4000 步)已经到 0.24;测试准确率到 1 之后还在继续升(30000 步 0.61)。参数范数先升后降(71.4 → 51.8):背诵阶段权重变大,之后被权重衰减慢慢”清理”。

这对第 5 讲的”涌现”之争是一个很好的注脚:一个看起来突然出现的能力,背后可以是一个平稳形成的机制;如果我们知道该测什么,就能提前看到它。

5.4 权重衰减与数据量

代码 04 演示 4 的两个对照(同样 30,000 步):

  • 没有权重衰减:训练准确率 1,测试准确率始终是 0,参数范数一路涨到 294。背下训练集之后,网络没有动力去找更简单的解。
  • 只有 30% 的数对:30,000 步结束时测试准确率只有 0.021,似乎刚刚开始爬升。数据越少,背诵越便宜,顿悟来得越晚。

权重衰减让”用很多参数背诵”变得昂贵,“用几个频率的通用算法”变得划算——这就是第 11 讲的最小描述长度:在”描述模型的代价”和”描述数据的代价”之间,通用算法是更短的描述。grokking 对超参数非常敏感,这也是为什么它在大模型的真实训练里很少被直接看到;但”先背诵、再被更简单的通用解取代”这个过程,被认为在大模型里也以更分散的形式存在。


6. 叠加与稀疏自编码器 · Superposition and sparse autoencoders

6.1 多义神经元

如果每个神经元都对应一个清楚的概念(“这个神经元检测猫”),可解释性就容易多了。但在大模型里,研究者常常发现多义神经元(polysemantic neurons):同一个神经元对好几种毫不相干的东西都有反应——比如对学术引用、英文对话、HTTP 请求和韩文都有反应。为什么?

6.2 叠加假说

Elhage et al. (2022) 提出了叠加(superposition)假说:模型想要表示的”特征”(概念)比它的维度多;只要特征是稀疏的(大多数时候不出现),就可以把多个特征挤进同一组维度里,偶尔同时出现时的干扰可以容忍。代价是:特征不再和神经元(坐标轴)对齐,每个神经元都混着好几个特征。

他们用一个极简的玩具模型研究它:n=20n = 20 个特征(重要性递减),压到只有 m=5m = 5 维的隐藏层 h=Wxh = W x,再还原 x^=ReLU(W⊤h+b)\hat{x} = \mathrm{ReLU}(W^\top h + b)。代码 05 演示 1 改变特征的稀疏度 SS(每个特征为 0 的概率):

稀疏度 SS被表示的特征(∥Wi∥>0.5\|W_i\| > 0.5)平均干扰
050.00
0.780.72
0.990.88
0.97101.00
0.9911(另有 2 个表示了一半)1.42

特征不稀疏时,模型只表示最重要的 5 个、互相正交——就像主成分分析。特征越稀疏,被表示的特征越多,超过 5 个就是叠加;干扰也随之增大。被表示的总是最重要的那些,不重要的被完全放弃。(Elhage et al. 在更极端的稀疏度下看到几乎所有特征都被挤进去,并发现了一个相变;我们 8000 步的训练没有走那么远。)

6.3 叠加的几何

演示 2 看 S=0.97S = 0.97 时的几何:被表示的 10 个特征正好组成 5 对,每一对指向相反的方向(余弦 −1.00)。两个特征共用一条直线,一个占正方向、一个占负方向;ReLU 把负的部分截掉,所以只要两者很少同时出现,就几乎没有干扰(被表示特征的偏置几乎都是 0——不需要负偏置来压干扰)。Elhage et al. 把这种结构叫做”二角形”(digon),更稀疏时还会出现三角形、五边形等对应于正多面体的排列。

而每个隐藏维度都对 8–10 个特征有反应:如果把隐藏维度当成”神经元”去解释,它就是多义的——不是因为它”在做好几件事”,而是因为特征在叠加,没有和坐标轴对齐。

6.4 稀疏自编码器:把叠加拆开

如果特征是叠加的,能不能把它们重新找出来?稀疏自编码器(sparse autoencoder, SAE)的思路是”字典学习”:学一本比维度大得多的字典(很多个方向),要求每个激活向量都能用很少几个字典方向的组合重建:

z=ReLU(Wenc(h−bdec)+benc),h^=Wdec z+bdec,损失=∥h−h^∥2+λ∥z∥1.z = \mathrm{ReLU}(W_{\text{enc}}(h - b_{\text{dec}}) + b_{\text{enc}}), \qquad \hat{h} = W_{\text{dec}}\, z + b_{\text{dec}}, \qquad \text{损失} = \|h - \hat{h}\|^2 + \lambda \|z\|_1 .

演示 3 只给 SAE 看 S=0.97S = 0.97 的玩具模型的 5 维隐藏激活(它从来没见过真实的特征 xx),字典大小 40:每一个被模型表示的特征,都在字典里有一个几乎完全对齐的方向(余弦 0.964–0.998,10 个全部 > 0.9);每个样本平均只激活 0.83 个字典方向(真实特征平均每个样本出现 0.60 个),重建几乎完美。稀疏性约束是关键:不要求稀疏,5 维空间用任意 5 个方向就能完美重建,找不回任何有意义的东西。

这就是 Bricken et al. 2023(Towards Monosemanticity,Anthropic)的核心想法:在一个 1 层 Transformer 的 512 个 MLP 神经元的激活上(约 80 亿个样本)训练 SAE,字典从 512 到 131,072 个特征,得到的特征比单个神经元单义得多。真实模型里我们不知道真实的特征是什么,只能靠人去看每个方向在什么输入上激活——玩具模型的好处是可以直接验证”找对了”。


7. Pythia:把训练过程变成研究对象 · Pythia and training dynamics

前面的几个现象——induction head 的相变、grokking 的进度指标——都是关于训练过程的。研究它们需要训练过程中的检查点,而大多数公开的模型只发布最终的权重。

Biderman et al. (2023) 的 Pythia 正是为此设计的:16 个模型、从 7000 万到 120 亿参数,全部在公开数据(Pile)上、以完全相同的顺序训练;每个模型公开 154 个检查点,并提供工具,可以精确重建每个模型在每一步看到的数据。这让很多以前做不了的研究变得可能:

  • 一个能力或电路在训练的哪个时刻、哪个规模上出现——比如 induction head 的相变在不同大小的模型上是否同时发生。
  • 记忆:一段训练数据是否被模型逐字记住,和它在训练中出现的时间、次数有什么关系(第 16 讲的主题)。Pythia 论文的案例研究之一就是记忆;Biderman 等人的另一项工作研究了能不能用小模型或早期检查点预测大模型会记住哪些序列。
  • 词频对能力的影响:论文发现,few-shot 算术题的表现和题目中数字在训练数据里出现的频率相关,这种相关在大模型上更明显。
  • 干预训练数据:论文还演示了在训练后期替换数据里的性别代词,可以减少模型的性别偏见——因为训练顺序完全已知,这样的对照实验才有意义。

Pythia 体现了 EleutherAI 的一个立场:理解模型需要开放——开放的权重、开放的数据、开放的训练过程。这和第 10 讲 OPT、BLOOM 公开训练日志的做法一脉相承,也是第 13 讲(像开源软件一样构建模型)的主题。


8. 局限与争论 · Limits and debates

机制可解释性在 2023 年还是一个很年轻的领域。这一讲的实验本身就暴露了它的几个难点:

  1. 规模:我们能完全讲清楚的是 2 层、8 个头、64 维的模型。真实的大模型有几十层、几千个头、几千维,加上 MLP 和叠加。在 base model 上(代码 01),连”谁记住了一个人住在哪里”都已经是分布式的。Wang et al. 2022 在 GPT-2 small 上找到的”间接宾语识别”电路就涉及 26 个注意力头、分成 7 类——而这只是一个很窄的任务。
  2. 方法的选择会影响结论:零消融和均值消融在 base model 上的结论基本一致(代码 01),但在别的情况下可能不同;零消融会把残差流推到模型从没见过的状态,让每个部件看起来都很重要。修补的结果依赖于”破坏”的方式(代码 03 用的是换掉第一遍)。不同的干预回答的是不同的问题。
  3. 直接读权重的信号会变弱:K-composition 在我们的玩具上只比随机高一点(§4.6);在大模型里,权重分析通常必须和因果方法配合。
  4. “找到一个电路”不等于”理解了模型”:一个电路可能只解释了某个行为的一部分,同一个行为可能有多条冗余的路径(我们的 4 个 induction 头就是冗余的)。怎样评价一个解释”有多完整”,本身是一个研究问题。
  5. 叠加:如果特征和神经元不对齐,“一个神经元一个概念”的分析单位就是错的;SAE 是一个有希望的修补,但它找到的特征是不是模型”真正”使用的单位,还有争论(§9)。

尽管如此,这个领域的进展说明了一件重要的事:训练出来的网络并不是无法理解的。至少在一些情况下,它们学到的是干净的、人可以读懂的算法——傅里叶变换做模加法、两个头组合实现复制。


9. 2023 年之后 · Since 2023

2023 年以后,机制可解释性的规模和关注度都迅速增长。这里只列和本讲直接相关、比较确定的几条。

  • 稀疏自编码器的规模化。 Anthropic 的 Scaling Monosemanticity(Templeton et al. 2024)把 SAE 用到了生产级的模型 Claude 3 Sonnet 上,字典最大到数千万个特征,找到了许多抽象的、多语言、多模态的特征(例如对应”金门大桥”的特征),并演示了通过放大某个特征来”操控”模型的行为。Google DeepMind 发布了在 Gemma 2 上训练的一整套开放 SAE(Gemma Scope,2024),OpenAI 也研究了 SAE 的规模定律。SAE 成了这个领域的主要工具之一。
  • 对 SAE 的反思。 研究者也发现了 SAE 的问题:用 SAE 重建的激活替换原来的激活,模型的损失会明显变差(重建误差里可能藏着重要的东西);有”死掉”的特征和特征分裂;SAE 找到的特征是否是模型计算的基本单位,并不确定。一些工作开始比较 SAE 和更简单的基线(例如线性探针)在实际任务上的用处。
  • 从特征到电路。 在 SAE 特征的基础上,出现了”归因图”一类的方法(例如 Anthropic 2025 年的电路追踪工作),尝试把一个具体的回答追溯成一张”哪些特征通过哪些路径影响了输出”的图,用来研究模型怎样做多步推理、怎样规划押韵等。
  • 自动化可解释性。 用一个大模型去解释另一个模型的神经元或特征(例如 OpenAI 2023 年用 GPT-4 给 GPT-2 的神经元写解释并打分),让”看每个特征在什么输入上激活”这一步可以规模化。
  • 表示工程与操控。 在残差流里找到对应某种性质的方向(例如真实性、拒绝),加上或减去这个方向就能改变模型的行为——“操控向量”一类的方法。这和 §2 的残差流视角、第 6 讲的模型编辑是同一个思路。
  • induction head 仍然是经典范例。 它被用来研究上下文学习的形成、数据分布对电路的影响,以及更复杂的上下文机制(第 5 讲 §7)。

哪些结论仍然成立? 残差流的视角;QK / OV 的分解;induction head 作为上下文学习的一个关键机制;grokking 背后的平稳进度;叠加作为多义性的主要解释。被修正或补充的:可解释性的基本单位从”神经元”转向了”字典学习得到的特征”;从”在玩具模型上完全讲清楚”扩展到”在生产模型上部分讲清楚”;以及对”解释是否忠实”有了更多的警惕。


10. 小结 · Summary

  1. 机制可解释性:把训练好的网络当成编译好的程序,读出它执行的算法。策略是从极小的模型、极简单的任务开始。
  2. 残差流是一条通信总线,最后的输出 = 所有部件的输出之和。logit lens 显示 base model 先确定”接下来是一个城市”、最后一层才挑出具体的城市;直接归因显示第 1 层 MLP 贡献 98%,但消融揭示注意力头的间接作用(第 1 层头 0 把名字的信息搬过来)。直接归因看不到”谁让这一步成为可能”。
  3. 数学框架:一个注意力头 = QK 电路(看哪里)+ OV 电路(写什么)。0 层只能学二元组,1 层能学跳跃三元组,2 层通过组合能实现 induction。
  4. induction head:[A][B] … [A] → [B],靠第 0 层的前一个 token 头 + 第 1 层的 induction 头(K-composition)。我们的 2 层模型在第 700–1000 步发生相变(重复部分损失 3.58 → 0.85,induction 分数 → 0.85),1 层模型停在 2.92。三类证据:消融(4 个头一起 → 4.24;前一个 token 头 → 3.06)、修补(4 个头找回 99.9%)、读权重(OV 复制分数 0.997;K-composition 高于随机、Q / V 低于随机)。
  5. grokking:训练准确率 2000 步到 1,测试准确率 20000 步才到 1。网络用傅里叶频率做模加法(只保留 5 个频率仍有 0.996);嵌入的频率集中度从一开始就平稳上升——顿悟不是突然的。没有权重衰减就不会顿悟:通用算法是更短的描述。
  6. 叠加:特征比维度多、而且稀疏时,模型把它们挤进同一组维度(10 个特征 → 5 对相反方向),神经元因此多义。稀疏自编码器只看隐藏激活就能找回全部特征方向(余弦 > 0.96)。
  7. Pythia:16 个模型、154 个检查点、相同的数据顺序,把训练过程本身变成研究对象。理解模型需要开放。
  8. 局限:规模、方法选择、信号变弱、解释的完整性、分析的基本单位。

11. 常见误区 · Common pitfalls

  1. “直接 logit 归因显示注意力头的贡献是 0,所以注意力不重要。” 直接归因只看最后一步;注意力头的作用常常是间接的(搬运信息),要靠消融或修补才看得见(代码 01)。
  2. “消融一个头,能力没有消失,所以这个头不重要。” 可能有冗余:我们的 4 个 induction 头任意一个被消融,其他三个都能补上;4 个一起消融才完全失效。
  3. “logit lens 显示的就是这一层知道的东西。” 中间层可能用输出层读不懂的方式编码信息;tuned lens 更可靠,但仍然是近似。
  4. “induction head 就是上下文学习。” 它是上下文学习的一个重要机制(在小模型上有因果证据),但大模型的上下文学习还涉及更多、更抽象的机制。
  5. “grokking 说明网络在某一刻突然理解了。” 背后的进度指标是平稳变化的;突然的只是测试准确率这一个指标(代码 04)。
  6. “多义神经元说明模型在偷懒 / 混乱。” 叠加是一种有效的压缩:特征稀疏时,挤进更多特征的收益大于偶尔干扰的代价(代码 05)。
  7. “SAE 找到的特征就是模型真正使用的概念。” 在玩具模型上可以验证;在真实模型上这仍是一个假设,SAE 的重建误差、特征分裂等问题都说明需要谨慎。
  8. “在玩具模型上找到的电路,大模型里也一模一样。” 机制(例如 induction)可能相通,但具体实现、冗余程度、和其他部件的交互都可能不同;玩具给的是假设,不是结论。

12. 练习 · Exercises

练习 1(0 层模型) 一个只有嵌入和反嵌入的”0 层 Transformer”,logits =WE[token] WU= W_E[\text{token}]\, W_U。它能学到什么?它的最优损失是什么?

参考答案

只能学”看到当前 token,下一个是什么”的条件分布,即二元组(bigram)统计;WEWUW_E W_U 这个 V×VV \times V 矩阵(的 softmax)就是一张二元组表(受低秩 dd 的约束)。最优损失是数据的二元组条件熵(在 d≥Vd \geq V 时可以达到)。在代码 02 的数据上,二元组几乎没有用(token 是随机的),0 层模型的损失约为 ln⁡64=4.16\ln 64 = 4.16。

练习 2(QK 与 OV) 一个头的 QK 电路决定”看哪里”,OV 电路决定”写什么”。如果把一个 induction 头的 OV 电路换成另一个 induction 头的 OV 电路(QK 不变),模型还会抄吗?如果换成第 0 层某个头的 OV 电路呢?

参考答案

换成另一个 induction 头的 OV:两者都是近似的”复制”矩阵(复制分数都是 0.997 左右),看到的位置不变、写的内容仍然是”被看到的 token”,所以大概率仍然会抄(可能略有损失,因为两个 OV 的细节不同)。换成第 0 层头的 OV(复制分数为负):看的位置对了,但写进去的不是被看到的 token,复制能力会消失。这说明 QK 和 OV 是两个可以分开分析的部件。

练习 3(前缀匹配分数) 序列是 [7, 3, 9, 7, 3, 9](位置 0–5)。在位置 4(token 3),哪些位置算”前一个 token 等于当前 token”的匹配位置?induction 头应该把注意力放在哪里、抄到什么?

参考答案

匹配位置 kk 满足 xk−1=x4=3x_{k-1} = x_4 = 3 且 k≤4k \leq 4:x1=3x_1 = 3,所以 k=2k = 2(以及 k=5k = 5 不算,因为在未来)。所以只有位置 2 是匹配位置,它的 token 是 9;induction 头应该注意位置 2,抄 9——正好是位置 5 的真实 token。

练习 4(为什么第一遍的损失会上升) 代码 02 里,相变期间第一遍的损失从约 4.6 升到 5.2。用”模型的赌注”解释这件事,并预测:如果训练数据里一半的序列完全不重复,相变期间第一遍的损失还会上升吗?

参考答案

induction 头形成后,模型倾向于给”前面出现过的 token 之后的那个 token”更高的概率;在第一遍里,当前 token 偶尔和前面的某个 token 相同(词表只有 64,片段里会有重复),induction 头会抄一个错误的答案,于是第一遍的损失变差。如果一半的序列完全不重复,模型会学到”复制并不总是对的”,induction 的输出会更保守,第一遍损失的上升应该更小(具体以实验为准)。这也说明一个电路的”强度”会根据数据里它有用的频率来调节。

练习 5(改一行代码,预测结果) 把 circuit_lab.repeated_batch 的片段长度固定为 16(min_len = max_len = 16),再训练 1 层的模型(代码 02 演示 3)。你预测重复部分的损失会降到多少?为什么?

参考答案

片段长度固定时,“答案在往回数 15 步的那个位置”变成了一个只依赖位置的规律:1 层模型的一个头可以学会”位置 qq 注意位置 q−15q - 15“(只需要位置嵌入的 QK 电路),然后用 OV 电路抄过来。所以 1 层模型的重复部分损失可能降到接近 0,而不是停在 2.9(具体数字以你运行的结果为准)。这就是为什么代码 02 要让片段长度随机:否则模型会找到不需要 induction 的捷径,我们就测不出”1 层做不了 induction”。

练习 6(改一行代码,预测结果) 把代码 04 的权重衰减从 1.0 改成 0.3。你预测 grokking 会更早、更晚,还是不发生?参数范数的曲线会怎样?

参考答案

权重衰减越弱,“背诵”越便宜,从背诵转向通用算法的压力越小,grokking 大概率会更晚(在 30,000 步之内可能发生,也可能不发生);参数范数下降得更慢(具体以你运行的结果为准)。演示 4 的两个极端(wd = 1 时 20,000 步到 1,wd = 0 时始终为 0)给出了这个趋势的两端。

练习 7(傅里叶频率) 模 59 的问题里,为什么只有 29 个”不同的”频率?频率 kk 和 59−k59 - k 有什么关系?

参考答案

cos⁡(2π(59−k)a/59)=cos⁡(2πa−2πka/59)=cos⁡(2πka/59)\cos(2\pi (59 - k) a / 59) = \cos(2\pi a - 2\pi k a / 59) = \cos(2\pi k a / 59),sin⁡\sin 只差一个符号,所以频率 kk 和 59−k59 - k 张成的是同一个二维子空间。去掉常数项(k=0k = 0)之后,1 到 58 两两配对,一共 29 个不同的频率——代码 04 的 fourier_power 正是只算 k=1…29k = 1 \ldots 29。

练习 8(改一行代码,预测结果) 把代码 05 的隐藏维度 N_HID 从 5 改成 10。在 S=0S = 0(不稀疏)时,你预测会表示几个特征?在 S=0.97S = 0.97 时,会出现什么样的几何?

参考答案

S=0S = 0 时应该表示最重要的 10 个特征、互相正交(维度够 10 个,没有叠加)。S=0.97S = 0.97 时,按 5 维时”每一维放两个相反方向的特征”的规律,可能表示约 20 个特征——也就是全部——组成 10 对相反方向(具体以你运行的结果为准)。这个练习说明叠加的程度由”特征数 / 维度”和稀疏度共同决定。

练习 9(概念:零消融 vs 均值消融) 为什么零消融可能高估一个部件的重要性?构造一个例子:一个头的输出几乎是常数(不携带关于输入的信息),零消融和均值消融会给出什么不同的结论?

参考答案

零消融把输出换成 0,如果这个头平时总是输出一个不为 0 的常数向量 cc,那么去掉它会让残差流整体平移 −c-c,后面的部件看到的是从没见过的输入,表现变差——看起来这个头很重要,但它其实不携带任何关于具体输入的信息。均值消融把输出换成它的平均值(就是 cc),模型不受影响,正确地判断这个头”不携带信息”。在代码 01 里两种消融的结论基本一致,说明那些头确实携带了信息;但在别的模型里两者可能差别很大。

练习 10(概念:修补第 0 层为什么没用) 代码 03 演示 2 中,修补第 0 层的前一个 token 头几乎找不回能力,而消融它们却能让 induction 失效(演示 1)。这两个结果矛盾吗?

参考答案

不矛盾。消融说明 induction 需要第 0 层提供”前一个 token 是谁”的信息(必要性)。修补问的是另一个问题:在第一遍被换掉的序列里,把第 0 层头在原序列上的输出放回来,够不够恢复能力?不够——因为第 1 层的头还要从那个位置读”值”(要抄的 token),而那个位置的 token 已经被换掉了;第 0 层的信息只能告诉它”去哪里找”,不能告诉它”抄什么”(不充分)。必要但不充分:这正是不同干预回答不同问题的例子。

练习 11(概念:SAE 的稀疏惩罚) 如果把代码 05 演示 3 的 L1 系数设成 0,SAE 还能找回特征方向吗?如果设得很大呢?

参考答案

L1 = 0 时,40 个字典方向可以随便组合来重建 5 维的 hh,没有任何压力让单个方向对齐到某个特征上,找回的方向大概率没有意义(重建误差可以很小)。L1 很大时,SAE 会尽量少用字典方向,甚至宁愿不重建(把 zz 压成 0),重建误差变大、很多特征”死掉”。实践中要在重建误差和稀疏性之间调节 λ——这是训练 SAE 的主要超参数(具体以你运行的结果为准)。

练习 12(概念:为什么需要 Pythia) 假设你想研究”一个 70 亿参数的模型里,induction head 是在训练的哪个时刻形成的,它的形成和数据里重复文本的比例有没有关系”。为什么只有最终权重的开放模型不够?Pythia 提供了哪些必要的东西?

参考答案

只有最终权重,你看不到训练过程,无法知道电路何时形成;也不知道模型在每一步看到了哪些数据,无法把形成时刻和数据联系起来。Pythia 提供:同一模型的 154 个检查点(看形成的时刻)、多个规模(看是否随规模变化)、完全相同且可重建的数据顺序(把检查点和”到这一步为止看过的数据”精确对应,甚至做干预实验)。


13. 延伸阅读 · Further reading

原课相关(1/30 Mechanistic Interpretability)

  • Elhage et al. A Mathematical Framework for Transformer Circuits. Transformer Circuits Thread, 2021. transformer-circuits.pub/2021/framework
  • Olsson et al. In-context Learning and Induction Heads. 2022. arXiv:2209.11895
  • Nanda et al. Progress Measures for Grokking via Mechanistic Interpretability. ICLR 2023. arXiv:2301.05217
  • Elhage et al. Toy Models of Superposition. 2022. arXiv:2209.10652
  • Biderman et al. Pythia: A Suite for Analyzing Large Language Models Across Training and Scaling. ICML 2023. arXiv:2304.01373

补充

  • Power et al. Grokking: Generalization Beyond Overfitting on Small Algorithmic Datasets. 2022. arXiv:2201.02177
  • nostalgebraist. interpreting GPT: the logit lens. 2020(LessWrong 博客)。
  • Belrose et al. Eliciting Latent Predictions from Transformers with the Tuned Lens. 2023. arXiv:2303.08112
  • Wang et al. Interpretability in the Wild: a Circuit for Indirect Object Identification in GPT-2 small. 2022. arXiv:2211.00593
  • Bricken et al. Towards Monosemanticity: Decomposing Language Models With Dictionary Learning. Transformer Circuits Thread, 2023. transformer-circuits.pub/2023/monosemantic-features
  • Templeton et al. Scaling Monosemanticity: Extracting Interpretable Features from Claude 3 Sonnet. 2024. transformer-circuits.pub/2024/scaling-monosemanticity

14. 下一讲预告 · Next lecture

Part IV(理解基础模型)到这里结束。两讲从两个方向理解模型:第 11 讲从外面看它压缩数据压得多好,这一讲从里面看它执行了什么算法。两者都依赖同一个前提:模型、数据和训练过程是开放的——Pythia 之所以有用,是因为每一个检查点、每一批数据都公开。

第 13 讲:像开源软件一样构建模型——协作、合并与持续更新(2/8 客座 Colin Raffel)进入 Part V(生态与应用)。今天的大模型是由一家机构一次性训练出来、然后冻结发布的;开源软件则是成千上万人持续地贡献、合并、修复、更新。模型能不能也这样被构建?怎样把两个分别微调过的模型”合并”成一个?怎样只更新一个模型的一小部分?怎样让社区贡献的改进可以组合、可以回溯?代码会在第 1 讲的模型上做模型合并(权重平均、任务向量)和模块化的更新。

← 返回课程目录