手动修改LLM权重
我从头开始编写了ROME(秩一模型编辑)的实现,只使用了torch和transformers。目标:通过一次矩阵加法在GPT-2 Medium中重写单个事实,并观察模型所知的其他一切会发生什么。
我进行了四次编辑。三次是精确的外科手术式。第四次揭示了ROME的"外科精确性"对于你不一定会预先考虑到的实现细节极为敏感。
四次编辑
我在四个不同领域选择了GPT-2 Medium确实有把握知道的事实(正确答案的P > 0.5):
| 主题 | 原始事实 | 编辑为 |
|---|---|---|
| 哈佛大学 | 在马萨诸塞州 | 加利福尼亚州 |
| 在加利福尼亚州 | 德克萨斯州 | |
| 玉米饼 | 来自墨西哥 | 日本 |
| 自由女神像 | 在纽约 | 拉斯维加斯 |
四次编辑都命中了目标。更新后,模型以概率≥0.98预测了精确编辑提示的新答案。所以ROME本身是有效的。变化的是其他一切。
三次干净的编辑
四次中的三次行为与ROME论文的预测大致相符。以下是每次编辑后不相关事实发生的变化:
玉米饼 → 日本(更新范数:重量范数的9%)
| 对照 | 编辑后 |
|---|---|
| 来自日本的寿司 | ✓ 未变化 |
| 来自意大利的比萨 | ✓ 未变化 |
| 来自日本的拉面 | ✓ 未变化 |
| 墨西哥卷饼来自墨西哥 | → 日本 |
只有墨西哥卷饼,墨西哥食物空间中最近的邻居,被带着走了。
哈佛 → 加利福尼亚州(更新范数:13%)
| 对照 | 编辑后 |
|---|---|
| 马萨诸塞州的MIT | ✓ 未变化(仍然模糊) |
| 马萨诸塞州首府 = 波士顿 | ✓ 未变化 |
| 马萨诸塞州的波士顿 | ✓ 未变化 |
| 康涅狄格州的耶鲁 | → 加利福尼亚州 |
耶鲁——常春藤联盟空间中哈佛最近的邻居——跟着来了。其他什么都没动。
自由女神像 → 拉斯维加斯(更新范数:16%)
| 对照 | 编辑后 |
|---|---|
| 纽约的时代广场 | ✓ 未变化 |
| 纽约州的纽约市 | ✓ 未变化 |
| 帝国大厦 | 竞争(New 0.49 vs Las 0.26) |
| 费城的自由钟 | → 拉斯维加斯 |
两个地标摇摆了。自由钟特别有趣——它不在NY,但它共享"Liberty(自由)“这个词,GPT-2把它们混淆了。
所以:干净的直接编辑,有限的附带损害,合理的更新幅度(9–16%)。
模型也愉快地编造了相应的替代历史。我最喜欢的:把哈佛移到加利福尼亚后,问哈佛是什么时候建立的,模型回答*“1776年由法国耶稣会士夏尔·德·孟德斯鸠神父创建。"*完整的句子,内部一致,完全错误。这是模型的先验知识(“哈佛很有声望,著名的地方有著名的创始人”)填补了曾经是真实事实的空洞。
混乱的那次:Google
Google的编辑进行得很糟糕。我的第一次运行报告了117%的更新范数——秩-1变化大于权重矩阵范数本身——并使整个加利福尼亚技术集群崩溃:
- Apple → 德克萨斯州(P = 1.00)
- Microsoft → 德克萨斯州(P = 1.00)
- Silicon Valley → 德克萨斯州(P = 1.00)
- Stanford University → 德克萨斯州(P = 0.75)
- 并且:“Google于2000年由史蒂夫·乔布斯创建。”
我以此为主要发现写了一篇博客文章。然后我想了更多,意识到117%是可疑的。秩-1编辑不应该比它所编辑的东西大。
调试Google
结果有两件事是错误的。
问题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样本(约10,600个标记)估计C。对于4096×4096的协方差矩阵,每个维度约2.5个样本。矩阵严重秩亏。我有1e-4 * I的正则化,这远远不够。
修复:2000个样本(118,000个标记,每个维度29倍)和迹缩放正则化(1e-2 × mean(diag(C)))。
同一编辑的结果:**更新范数从117%降至50.5%。**更好的条件,一半的更新幅度。
但50%仍然很大,控制仍然损坏了:
| 对照 | 编辑后(修正协方差) |
|---|---|
| Apple总部 | 德克萨斯州(1.00) |
| Microsoft总部 | 德克萨斯州(0.99) |
| Silicon Valley | 德克萨斯州(0.92) |
| Stanford | 德克萨斯州(0.97) |
所以"灾难"的一部分是一个bug——但不是全部。集群泄漏是真实的。
问题2:位置很重要,非常重要
“Google"是单个BPE标记。在我的提示中——“Google is a company headquartered in the state of”——它在位置0。这意味着h*(用于编辑的中间向量)是从一个没有看到任何前置上下文的标记计算的。这是一个裸露的表示。
如果我把Google放在位置0以外的地方呢?我把提示改为"The technology company known as Google is headquartered in the state of”——现在Google在位置5,有"The technology company known as"作为前置上下文。
相同的编辑目标。相同的新协方差。结果:
- 更新范数:9.1%(从50.5%下降,从117%下降)
- Apple → 德克萨斯州(0.97)——仍然被带走
- Microsoft → 德克萨斯州(0.57)——部分被带走
- Silicon Valley → 加利福尼亚州(0.81) ✓ 保留
- Stanford → 加利福尼亚州(0.92) ✓ 保留
所以只是在计算h*之前给主题标记一些上下文,编辑就变得足够精确,让Silicon Valley和Stanford得以保留。Apple和Microsoft仍然被推动了,所以存在一些真实的Google相邻泄漏——但不像原来的那场末日灾难。
这真正教会了什么
我想让这篇文章变成"看,ROME无法编辑枢纽概念——看Google是如何毁掉一切的。“这个框架是错误的。真相更有趣,也不那么戏剧性:
**ROME对论文中看不到的实现细节很敏感。**协方差的样本数。正则化强度。主题标记在提示中的位置。弄错其中任何一个,你的"灾难性附带损害"可能就是你自己的代码。
**位置0的单标记主题是最坏的情况。**它们的
h*是最不具判别力的,C中的任何数值误差都会反转为过大的更新。如果你想要干净的编辑,给主题提供前置上下文。**枢纽概念泄漏是真实的但适度的。**即使有了适当的协方差和前置上下文,编辑Google也会轻微移动Apple和Microsoft。“Google"处于密集的语义邻域中,秩-1编辑会触及该邻域。你可以用MEMIT风格的多层分布将其减少另外2–4倍,但无法完全消除。
**更新范数是可靠的诊断工具。**低于权重范数的15%:可能没问题。高于50%:可能已损坏,要么是因为bug,要么是因为你在编辑枢纽。在相信编辑之前请检查。
虚构的内容确实存在
在每次成功的编辑中,模型都编造了相应的一致替代事实:
- 哈佛(现在在加利福尼亚州)于1776年由一位法国耶稣会士创建。
- 玉米饼(现在来自日本)配米饭上桌,与玉米饼最相关的语言是西班牙语。
- 自由女神像的渡轮服务现在从"拉斯维加斯国际机场"出发。
- Google(现在在德克萨斯州)“于2000年由史蒂夫·乔布斯创建”。
这些不是噪音——这是模型将其先验应用于修改后的事实。一旦它相信Google是德克萨斯的,“由史蒂夫·乔布斯创建"不是随机的幻觉;这是模型关于著名德克萨斯科技公司的创始人故事应该是什么样子的最佳猜测。
语言模型中的知识不是独立事实的列表。它是相互强化的事实图。编辑一个节点,图会在其周围生成一个一致的(且完全错误的)新区域。
配置
整个东西是分布在几个文件中的约500行代码:因果追踪、协方差估计、v*梯度下降、秩-1权重更新,以及四次编辑的端到端脚本。
依赖项:torch、transformers、datasets。没有ROME特定的内容。
在CPU上运行。每次编辑使用200样本协方差需要约3分钟,使用2000样本协方差需要约15分钟。适当的协方差设置值得等待。