LLM 可解释性(一):SAE与单语义
首先想问:神经网络里,到底什么是"一个概念"?
直觉上我们想找具体能够表征某一个概念的神经元, 但真实模型里单个神经元会对多个不同的概念/模式同时起反应,这就是 polysemanticity(多义性)。Anthropic 这篇的工作是:既然神经元本身不好直接解释,那我们就用稀疏自编码器(SAE)把激活"解混"成一组单语义特征(monosemantic features),并给出证据说这些特征才是模型真正在用的计算单元。
一、为什么单个神经元看不懂
机械可解释性(mechanistic interpretability)最早的想法很朴素:打开模型,逐个神经元看它对什么输入有反应,像生物学家找"祖母细胞"那样。但这条路撞墙了,因为绝大多数神经元是多义的,一个神经元可能同时对 DNA 序列、阿拉伯文、人名首字母大写都有反应。
为什么? Anthropic 在更早的 Toy Models of Superposition 里给了一个很干净的假设:
模型要表达的概念(features)比它拥有的维度(neurons)多得多。
于是模型把一堆概念"挤"进一个低维空间里——这就是 superposition(叠加)。直觉上,如果每个概念是高维空间里一个几乎正交的方向,那么 维空间可以塞下远多于 个几乎正交的方向(只要允许它们之间有一点干扰),代价是每个方向不再对齐到任何一根坐标轴(也就是不再等于某个神经元)。这件事不是拍脑袋--苏剑林在《n维空间下两个随机向量的夹角分布》里算过:两个随机单位向量的夹角 的密度正比于 ,关于 对称,均值就是 90°。但光有均值不够--二维、三维的均值也是 90°。真正让结论成立的是方差:文章证明方差随维度 趋于 0,近似为 (弧度²), 时标准差只有约 1.8°,夹角几乎被钉死在 90°。
另外有JL引理:塞下 个向量只需要 维空间。
高维空间里随便抓两个方向就几乎正交,所以能塞下远多于 个几乎正交的方向。
随手模拟一下:在不同维度 里各取一万个随机向量,看随机一对的夹角落在 的比例:
import numpy as np
np.random.seed(0)
for d in [2, 3, 10, 100, 1000]:
n = 10000
x = np.random.randn(n, d)
x /= np.linalg.norm(x, axis=1, keepdims=True)
i, j = np.random.randint(n, size=100000), np.random.randint(n, size=100000)
ang = np.degrees(np.arccos(np.clip((x[i] * x[j]).sum(1), -1, 1)))
print(f"d={d:5d}: 夹角落在 [80°, 100°] 的比例 = {(np.abs(ang - 90) <= 10).mean():.4f}")
输出大致是 d=2: 0.11、d=3: 0.17、d=10: 0.39、d=100: 0.92、d=1000: 1.00--维度一上来,几乎每一对都贴着 90°。
不过"塞得下"只是第一步,还得"不崩"。方向挤在一起就不再严格正交,激活一个特征会顺带蹭到别的特征一点--这是叠加付出的干扰。光靠"几乎正交"压不住它,真正让 superposition 成立的是稀疏:同时激活的特征很少,蹭到的项也少,加上每对方向本来就接近 90°,干扰才被压成可忽略的噪声。没有稀疏,这个近似就站不住,叠加也就不可行。
所以 polysemanticity 是模型在有限容量下主动选择的压缩策略:
- 神经元 = 坐标轴方向 → 因为叠加,一个轴上叠了好几个概念 → 多义。
- 特征 = 叠加后那个几乎正交的方向 → 才是"一个概念"的载体 → 单义。
另外,LLM其实是对超大规模数据的压缩,superposition可以说是压缩过程中自然的行为;对应的,我们追求可解释性就需要进行解压缩。
结论很清楚:要看懂模型,得先把叠加解开,把坐标轴换成特征方向。
二、稀疏自编码器:把混合的激活"解混"
上面说模型把概念稀疏叠加进激活,写成式子就是 :字典 过完备(),编码 稀疏()。这正是经典**字典学习(dictionary learning)**的形式,而解混它就是把这个方程反过来解--顺手的工具是 sparse autoencoder(SAE)。对模型某一层(这篇是小型 SoLU transformer 的 MLP 层)的激活向量 , 训练一个 autoencoder:
目标函数是重建误差 + 稀疏惩罚:
几个关键点,我的理解:
- 字典比原维度大很多。 MLP 宽度 ,但字典可以开到几十万甚至上百万个特征(扩张系数 expansion factor = 字典大小 / ,这篇扫到量级几百倍)。这正对应"概念数 > 神经元数"的叠加假设——故意给一个过完备(overcomplete)的字典。
- ReLU 强制非负 + L1 强制稀疏。 重建要求字典能还原 ,L1 要求每个样本只激活很少几个特征。两个约束一起,逼着字典学出稀疏组合——每个激活向量被表示成"少数几个特征方向"的叠加。( 量级在 ,具体值看模型规模。)
- L0 远小于 ,但方差解释率(FVE)很高。 这是最漂亮的结果:每个 token 的 MLP 激活,只需要几十到几百个特征稀疏激活就能重建绝大部分方差。如果神经元真是计算单元,你不可能用这么少的方向重建得这么好——这反过来支持"特征才是真实单元"。
三、特征真的是单语义的吗
光重建好不够,得证明每个特征确实对应一个可解释的概念。他们做了大量 case study,挑几个最能说明问题的:
| 特征 | 激活条件 | 为什么重要 |
|---|---|---|
| DNA 特征 | 输入是 ATGC... 这样的 DNA 序列 | 跨 token、跨上下文都稳定,甚至能拿来给文本"是否含 DNA"打标 |
| 阿拉伯文特征 | 文本里出现阿拉伯字符 | 与主题无关,纯粹认"书写系统"这个抽象 |
| 专有名词 / 缩写特征 | 首字母大写的人名、全大写缩写 | 语法-词性层面的抽象 |
| 无用 token 特征 | 模型词表里那些训练时几乎从不出现的"垃圾" token | 关键对照:这种 token 上特征的激活模式异常,说明特征不是无脑触发 |
最有说服力的是 无用 token(unuseful tokens) 实验:Anthropic 在词表里故意塞了一批训练数据里几乎不出现的 token。如果特征只是字典学习的数学产物,它对这些 token 应该也"随便"激活;但实际观察到的激活模式是有结构的、能和"这个 token 从没被真正学过"对上。这是对"特征是真实单元、不是字典 artifact"的一个反证辩护。
合起来,论文给出的画像:每一个 SAE 特征,在一个很窄但很一致的语义条件下激活——这就是 monosemantic(单语义)。和原始神经元的 polysemantic 形成鲜明对比。
四、质疑:特征会不会只是字典的产物
这一节是我觉得最该细读的部分,也是最容易被科普文章跳过的。
最自然的反对意见是:你开一个过完备字典 + L1,当然能把任何信号拆成"稀疏的零件",但这些零件是模型在用的东西,还是你强加的基?(basis dependence / 字典依赖)
他们的回应分两层:
- 特征分裂(feature splitting)是良性的。 字典开得越大,一个粗特征会"分裂"成几个更细的特征(比如"阿拉伯文" → "阿拉伯文-宗教文本""阿拉伯文-代码注释"……)。这看起来像过拟合,但分裂后每个子特征依然单义、依然可解释——只是粒度更细。所以字典大小控制的是"放大镜的倍率",不是凭空造概念。
- 行为层面的因果验证。 光说"可解释"是旁观证据,真正站住脚的是:能不能拿特征去干预模型行为。把某个特征在推理时强行激活或抑制(clamp / ablation),输出会按预期改变。(注:大规模 steering 实验——包括那个有名的"毒性特征"案例——主要在 2024 年的续作 Scaling Monosemanticity 里,本篇规模较小,但因果验证的思路已立住。)
我的看法:这两点合起来基本回应了 basis dependence,但没完全消解。特征是"字典相关的"这件事是事实,只是"字典相关"不等于"任意"——好的字典会让特征和模型的真实计算对齐。这有点像量子力学里的表象问题:换基会变,但物理不变;SAE 找的是那个让特征尽量"自然"的基。
五、延伸思考
总的来说,SAEs为Transformer的可解释性提供了可能性。我们朴素直觉(神经元=概念)被一个更准确结构(在神经元中被叠加某一方向=概念)取代。可解释性的基本单元从 neuron 让位给了 feature direction。
不过,SAE 只是"放大镜"。它给的是一个可调粒度的视图(字典大小=倍率)。模型的特征不是一个有确定数目的东西,而是依观察尺度展开的——这跟物理里"尺度决定你看到什么"是一回事。别把某一次 SAE 的特征数当成模型"真正的概念数"。SAE只是把多语义的拆分成更细的特征,便于我们解释,以及在不修改参数的情况下进行操作。
模型把比神经元多得多的概念稀疏地压进激活空间,所以神经元是多义的;稀疏自编码器通过"过完备字典 + L1 稀疏"把这个叠加解混,得到的特征在很大概率上才是模型真正在用的、单义的计算单元——而"是不是真在用",最终只能靠因果干预来回答。