手动修补大语言模型权重

我仅使用 torchtransformers,从头实现了 ROME——秩-1 模型编辑。目标是:通过一次矩阵加法,在 GPT-2 Medium 内部改写一个事实,然后观察模型所知道的其他一切会发生什么。

我进行了四次编辑。三次精准无误。第四次暴露出一个问题:ROME 的"精准性"对那些你事先未必会想到的实现细节极为敏感。

四次编辑

我挑选了 GPT-2 Medium 确实以较高置信度(正确答案的概率 P > 0.5)知晓的事实,涵盖四个不同领域:

主体原始事实修改为
哈佛大学位于马萨诸塞州加利福尼亚州
谷歌位于加利福尼亚州德克萨斯州
墨西哥卷饼来自墨西哥日本
自由女神像位于纽约拉斯维加斯

四次编辑全部命中目标。更新后,模型对精确编辑提示的新答案预测概率均达到 ≥ 0.98。所以 ROME 本身是有效的。变化在于其他的一切。

三次干净的编辑

四次编辑中,有三次的表现大致符合 ROME 论文的预测。以下是每次编辑后,不相关事实的变化情况:

墨西哥卷饼 → 日本(更新范数:权重范数的 9%)

对照项编辑后
寿司来自日本✓ 未变
披萨来自意大利✓ 未变
拉面来自日本✓ 未变
墨西哥卷 来自墨西哥→ 日本

只有玉米卷(Burritos)——在墨西哥食物语义空间中最近的邻居——被带偏了。

哈佛 → 加利福尼亚州(更新范数:13%)

对照项编辑后
MIT 位于马萨诸塞州✓ 未变(仍然模糊)
马萨诸塞州首府 = 波士顿✓ 未变
波士顿位于马萨诸塞州✓ 未变
耶鲁 位于康涅狄格州→ 加利福尼亚州

耶鲁——哈佛在常春藤联盟语义空间中最近的邻居——被带偏了。其他一切没有变动。

自由女神像 → 拉斯维加斯(更新范数:16%)

对照项编辑后
时代广场位于纽约✓ 未变
纽约市位于纽约✓ 未变
帝国大厦有争议(纽约 0.49 vs 拉斯维加斯 0.26)
自由钟 位于费城→ 拉斯维加斯

两个地标出现了摇摆。自由钟(Liberty Bell)特别有趣——它并不在纽约,但它和"Liberty"这个词共享,GPT-2 将两者混淆了。

总结:直接编辑干净,附带损伤范围窄,更新幅度合理(9–16%)。

模型还欣然编造了与之匹配的替代历史。我最喜欢的一个:将哈佛迁至加利福尼亚州后,当被问及哈佛的创建年份时,模型回答道:“1776 年由法国耶稣会神父查尔斯·德·孟德斯鸠创建。” 完整的句子,内部自洽,完全错误。这就是模型的先验知识(“哈佛是名校,著名的地方有著名的创始人”)在填补原有事实消失后留下的空洞。

混乱的那次:谷歌

谷歌的编辑很糟糕。我的第一次运行报告的更新范数为 117%——秩-1 变化比权重矩阵的范数本身还要大——整个加利福尼亚科技集群就此崩溃:

我原本打算以这个发现作为博客文章的头条结论。后来我多想了一会儿,意识到 117% 这个数字很可疑。秩-1 编辑的幅度不应该比被编辑对象本身还大。

调试谷歌

有两个地方出了问题。

问题 1:我的协方差估计不足

ROME 的更新公式依赖于 C——目标层中间(post-GELU)向量的协方差:

u = torch.linalg.solve(C + lambda * I, h_star)
delta_W = (u / (h_star @ u)).unsqueeze(1) @ (v_star - W @ h_star).unsqueeze(0)

方向 C⁻¹ @ h* 使编辑具有选择性——它与 h* 对齐,同时与典型的键向量正交。如果 C 的条件数很差,C⁻¹ @ h* 就会在低特征值方向上爆炸,导致更新变得巨大。

我当时用 200 个 WikiText 样本估计 C——大约 10,600 个 token。对于一个 4096×4096 的协方差矩阵,这意味着每个维度只有约 2.5 个样本。矩阵严重秩亏。我设置了 1e-4 * I 的正则化,完全不够。

修复方案:使用 2000 个样本(约 118,000 个 token,每个维度约 29 个),以及基于迹的缩放正则化(1e-2 × mean(diag(C)))。

同一次编辑的结果:更新范数从 117% 降至 50.5%。 条件数改善,更新幅度减半。

但 50% 仍然很大,对照项仍然被破坏:

对照项修复协方差后
苹果总部德克萨斯州(1.00)
微软总部德克萨斯州(0.99)
硅谷德克萨斯州(0.92)
斯坦福德克萨斯州(0.97)

因此,部分"灾难"是 bug 造成的——但并非全部。集群泄漏是真实存在的。

问题 2:位置影响极大

“Google” 是一个单独的 BPE token。在我的提示词——“Google is a company headquartered in the state of”——中,它位于位置 0。这意味着 h*(用于编辑的中间向量)是从一个没有见过任何前文语境的 token 计算得来的。这是一个裸表示。

如果我把 Google 放在位置 0 以外的地方呢?我把提示词改为 “The technology company known as Google is headquartered in the state of”——这样 Google 位于位置 5,有 “The technology company known as” 作为前文语境。

相同的编辑目标,相同的新协方差。结果:

仅仅通过在计算 h* 之前给主体 token 一些语境,编辑就变得足够精准,硅谷和斯坦福得以保全。苹果和微软仍然被波及,说明真实存在一些与谷歌相邻的泄漏——但与最初的大灾难相去甚远。

这究竟告诉了我们什么

我原本希望这篇文章的结论是"看,ROME 无法编辑枢纽概念——看谷歌是怎么把一切都炸掉的。“这个框架是错的。真相更有趣,也没那么戏剧化:

  1. ROME 对论文中看不到的实现细节十分敏感。 协方差的样本数量。正则化强度。主体 token 在提示词中的位置。这些地方任何一个出错,你所谓的"灾难性附带损伤"可能就是你自己的代码造成的。

  2. 位于位置 0 的单 token 主体是最差情况。 它们的 h* 判别性最弱,C 中的任何数值误差都会在求逆时放大为过大的更新。如果你想要干净的编辑,请用前文语境填充主体。

  3. 枢纽概念泄漏是真实的,但程度有限。 即使使用了正确的协方差和前文语境,编辑谷歌仍然会轻微影响苹果和微软。“Google” 处于一个语义密集的邻域,秩-1 编辑会触及这个邻域。你可以通过 MEMIT 式的多层分布将其再减少 2–4 倍,但无法完全消除。

  4. 更新范数是可靠的诊断指标。 低于权重范数的 15%:可能没问题。高于 50%:可能有问题,要么是因为 bug,要么是因为你在编辑一个枢纽概念。在信任编辑结果之前,先检查这个值。

幻觉是真实存在的

在每一次成功的编辑中,模型都编造了自洽的替代事实来配合:

这些不是噪声——而是模型将其先验知识应用于被修改事实的结果。一旦它相信谷歌是德克萨斯州的公司,“由史蒂夫·乔布斯创立"就不是随机的幻觉;而是模型对"一家著名的德克萨斯科技公司的创始人故事应该是什么样的"做出的最佳猜测。

语言模型内部的知识不是一列独立事实的清单,而是一张相互强化的事实图谱。编辑一个节点,图谱就会在其周围产生一个自洽(却完全错误)的新区域。

实现细节

整个实现大约 500 行代码,分布在几个文件中:因果追踪、协方差估计、v* 梯度下降、秩-1 权重更新,以及一个用于四次编辑的端到端脚本。

依赖项:torchtransformersdatasets。无需任何 ROME 专用库。

可在 CPU 上运行。使用 200 样本协方差时,每次编辑约需 3 分钟;使用 2000 样本协方差时约需 15 分钟。正确的协方差设置值得等待。