[控场AI]
· 7 分钟阅读· 3,776 字

LLM能审计机器遗忘吗?一次揭穿假遗忘代码的基准测试

LLM能审计机器遗忘吗?一次揭穿假遗忘代码的基准测试

用LLM审计伪装的机器遗忘代码,结果发现评分器和遗忘方法本身都需要被审计。

本文记录了一个名为"Unlearning Security Audit"的基准测试实验,核心问题是:大语言模型能否识破"声称在遗忘却实际没有执行任何遗忘更新"的PyTorch代码?作者设计了两个有缺陷的遗忘实现——一个把遗忘损失乘以0.0使梯度贡献为零,另一个用错误标签替代真正的影响消除——分别测试Gemini 2.5 Pro和Flash。两款模型都成功识别了概念性错误并给出基于梯度上升的正确修复。然而最大意外并非模型能力差距,而是评分器本身因脆弱的关键词匹配产生了两个假阴性,揭示了"用工具评估LLM输出,工具本身也需被审计"的方法论困境。独立的合成实验进一步证明,梯度上升使遗忘损失确实上升,但触发器攻击成功率依然100%,只有完全重训才彻底清除了后门,说明损失指标的改善根本不等于遗忘成功。

当代码声称“忘记”却偷偷乘以零

机器遗忘(Machine Unlearning)正成为AI安全领域的关键议题。当用户要求删除自己的数据,或当训练数据中混入恶意模式时,模型需要真正清除这些样本的影响,而不只是在表面上做做样子。问题在于:很多所谓的遗忘代码只是“看起来在遗忘”。

一位开发者在Kaggle Benchmarking Challenge中构建了名为 Unlearning Security Audit 的基准测试,专门检验大语言模型能否识破这种伪装。测试的起点是一段颇具迷惑性的PyTorch代码——它计算了需要被遗忘数据的损失,然后把这个损失乘以零。换句话说,这个遗忘项对梯度毫无贡献,模型根本没有做任何“反向遗忘”的更新。

核心问题只有一个:LLM能否分辨“声称遗忘”的代码和“真正执行遗忘更新”的代码?

LLM审计机器遗忘代码基准测试

两个精心设计的bug案例

作者给每个模型投喂了两个有缺陷的案例,分别对应两种常见但错误的遗忘实现方式。

案例一:被掩盖的遗忘损失

代码把遗忘集的标签替换为零,再将遗忘损失乘以 0.0。结果是遗忘项不产生任何梯度,训练仅在保留数据上继续进行,完全没有针对“消除不良学习”的更新。这是典型的“形式上存在、实质上失效”的陷阱。

案例二:被归零的目标

代码去掉了损失掩码,但仍然把遗忘集标签替换为零。这实际上是在训练模型把这些样本预测为“类别0”。而修改标签与消除样本影响是两回事——模型可能只是学会了一个新的错误映射,原有的影响并未真正清除。

每个模型都需要完成三件事:解释bug、使用原始标签和梯度上升基线重写代码、并提出如何测试后门是否仍然存在。作者在提示中已经指定了梯度上升方法,因此测试的是模型的审计与实现能力,而非让它凭空发明一套遗忘算法。每个案例配有八项自动化检查,覆盖Python语法、损失计算、原始标签使用、优化器步骤、问题诊断、评估规划和局限性说明。

这两类bug代表了实际工程中遗忘实现失效的两种典型模式:一是操作被静默短路(乘以0.0导致梯度为零),二是目标被错误替代(用错误标签训练代替真正的影响消除)。值得注意的是,这两种错误在代码审查时都不会触发任何运行时报错或异常——程序正常执行,损失曲线看似收敛,只有深入理解遗忘目标的人才能发现问题所在。这也正是将此类代码审计任务交给LLM进行测试的意义:模型需要具备对"训练目标在数学上是否达成预期"的语义理解,而不只是语法级别的代码检查能力。

两款Gemini模型都识破了概念性错误

作者选择了同一模型家族中的 Gemini 2.5 Pro 和 Gemini 2.5 Flash 进行对比,使用相同的提示和检查项。

作者原本预期会出现一种情况:某个模型只是把代码整理干净,却没抓住它为何无法真正遗忘。但这并没有发生。两款模型都准确识别了问题,并在修复中使用了原始遗忘集标签。四个被选中的回答全部通过了数学目标检查,重写后的核心逻辑如下:

retain_loss = F.cross_entropy(model(x_r), y_r)
forget_loss = F.cross_entropy(model(x_f), y_f)
objective = retain_loss - alpha * forget_loss

正常优化器会最小化这个目标函数:正的保留项鼓励模型在保留样本上保持良好表现,负的遗忘项则鼓励在待遗忘样本上增大损失,alpha 控制两者的平衡。这是一个基于梯度上升的基线方法——但它并不能保证用户影响或后门已被彻底清除。

最大的意外来自评分器自己

最初的评分似乎显示出明显差距:Pro在两个案例上通过了全部检查,而Flash只在一个案例上全部通过。

模型原始全通过案例数人工复核后平均响应时间
Gemini 2.5 Pro2/22/238.34秒
Gemini 2.5 Flash1/22/222.05秒

当作者仔细阅读Flash那个“失败”的回答时,发现它其实正确解释了掩码损失bug——指出“把 forget_loss 乘以 0.0 实际上移除了遗忘数据梯度对总损失的任何贡献”。但作者的文本检查只在寻找“zero”或“mask”这类措辞,却漏掉了用数字 0.0 表述的解释。

同样,Flash也说明了该方法“无法在数学上保证完全且不可逆的擦除”,但局限性检查依然判它失败,因为它没有使用预期的“approximate”或“heuristic”字样。

作者把这两项判定为评分器的两个假阴性,并保留了原始标记、记录了基于原始答案的人工修正。复核后,两款模型在两个案例上都达标。所谓的分数差距,实际上来自脆弱的关键词匹配检查。作者也坦诚指出,这个小规模测试并不能证明两款模型整体能力相当。

这个发现很有启发性:当我们用LLM去审计代码时,评分LLM输出的工具本身也需要被审计。

损失朝正确方向移动 ≠ 遗忘成功

作者还做了一个独立的合成逻辑回归分类器实验(注意:这不是运行任一LLM生成的PyTorch修复代码)。他测量了干净准确率和触发器攻击成功率——即模型在带触发器的测试输入上给出攻击者目标答案的频率。

方法干净准确率触发攻击成功率
中毒检查点100%100%
掩码遗忘损失100%100%
保留下降+遗忘上升(80步)100%100%
仅在保留数据上重训100%0%

结果触目惊心:经过80步基于梯度上升的修复后,遗忘损失确实从 0.0545 上升到 0.1649,但触发器依然在 100% 的触发测试输入上生效。只有在保留数据上完全重训,才在这个简单设定下既消除了后门行为,又保持了干净准确率。

这个实验传递出最核心的教训:**损失朝预期方向移动,并不足以证明遗忘成功。安全行为需要有它自己的专门测试。**后门能够在“忘记我”的指令下存活下来,正是因为我们误把损失变化当成了遗忘的证据。

后门攻击(Backdoor Attack)是指攻击者在训练数据中植入带有特定触发器(Trigger)的有毒样本,使模型在看到触发器时输出攻击者指定的目标类别,而在正常输入上行为正常。**触发器攻击成功率(Trigger Attack Success Rate, ASR)**衡量的是模型在所有含触发器测试输入上输出目标类别的比例,是评估后门是否被清除的核心指标。干净准确率(Clean Accuracy)则衡量模型在正常输入上的正常表现,两者需要同时被监控——一个"遗忘成功"的模型应同时保持高干净准确率和接近0%的ASR。本文实验中,梯度上升运行80步后干净准确率维持100%,ASR依然100%,说明梯度上升只是扰动了损失值,并未真正破坏后门模式在模型权重中的编码方式。

速度观察与后续方向

在这些调用中,Flash的两次响应分别耗时23.35秒和20.75秒,Pro则为43.83秒和32.84秒。Flash在两组配对案例中都更快,且在人工复核后达到了相同标准。不过作者谨慎地指出,每个案例只有一个被选中的回答,不应将此视为可靠的延迟排名。

对于下一步,作者计划增加更多有缺陷的脚本、重复调用、以匿名方式(不显示模型名称)审查解释,并发布改进的关键词检查作为新版评分器,同时保留原始结果可见。更进一步,他希望在隔离环境中真正执行生成的修复代码,测量干净准确率、触发攻击成功率以及与重训的对比表现。

正如作者的总结:他最初想问模型能否审计一段遗忘脚本,最后却发现评估器本身也需要一次审计。这既是对LLM代码审计能力的务实检验,也是对AI安全评测方法论的一次清醒提醒。

背景补充

机器遗忘(Machine Unlearning)的核心诉求来自隐私保护法规(如GDPR的"被遗忘权")和AI安全需求:当模型训练数据中混入后门样本、有毒数据或用户要求撤回的个人信息时,理想情况下应将这些样本的影响从模型参数中彻底抹去。然而完全重训成本极高,因此研究者提出了各种近似方法。**梯度上升(Gradient Ascent)**是其中最直观的一种——正常训练通过梯度下降最小化损失,而梯度上升则反其道而行之,刻意最大化待遗忘数据上的损失,从而推动模型"远离"对这些样本的正确预测。但近似方法的固有局限在于,损失数值的变化只是一个间接信号,并不等同于模型内部表示或决策边界的真实改变,后门触发器等深层模式可能在损失指标改善的同时依然存活。

#机器遗忘#machine unlearning#LLM代码审计#后门攻击#Gemini 2.5#AI安全#基准测试#梯度上升
分享:

相关推荐