JOVANA
Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

对抗样本与鲁棒性

对图像做一个微小、肉眼看不见的扰动,就能让一个信心十足的模型把熊猫认成长臂猿。本文带你认识对抗样本、制造它们的攻击手段、抵御它们的防御方法,以及为什么鲁棒性是一种必须去争取的性质。

一只熊猫、一点噪声、一只长臂猿

这是现代机器学习里最令人不安的画面之一。拿一张熊猫的照片,一个训练良好的图像分类器会以 58% 的置信度标注为「熊猫」。再叠加一层淡淡的噪声——淡到你的眼睛根本看不出任何变化——同一个模型现在却以 99% 的置信度说这是「长臂猿」。在你看来,这张图依然百分之百是熊猫。这就是对抗样本:一个被刻意(往往是不可察觉地)修改过的输入,目的就是让模型出错。

在上一篇里你见过「无声的失败」:当输入来自一个发生了偏移的分布时,模型会栽跟头。对抗样本是这个故事里最坏的情形——它不是分布偏移带来的意外,而是攻击者故意制造出来的失败。它们不是你偶然碰上的随机故障,而是攻击者通过搜索模型最脆弱之处,精确找出来的输入。这种区别——随机的坏运气,与有智能的对手——正是为什么对抗鲁棒性是一个安全问题,而不仅仅是一个质量问题。

攻击是怎么造出来的

这个配方在复用你已知的知识时,几乎带着一种诗意。训练模型时,我们用梯度去微调*权重*,让损失下降。攻击则把这件事反过来:它冻住权重,用同样的梯度去微调*输入*,让损失上升——把模型推向错误答案。换句话说,正是让学习得以运转的那套微积分,反向作用到像素上,就把模型给打破了。这就是为什么:一个你能对它求梯度的模型,也是一个攻击者能对它下手的模型。

# normal training: change WEIGHTS to lower loss
W <- W - lr * d(loss)/d(W)

# attack: freeze W, change the INPUT to RAISE loss
x_adv <- x + eps * sign( d(loss)/d(x) )
# eps is kept tiny, so x_adv looks identical to x
一行写完的快速梯度符号法(FGSM):让输入沿梯度的符号方向走一步,步幅被一个极小的预算 eps 限制住。

攻击也分不同口味。白盒攻击能看到模型的权重和梯度,因此可以直接精心炮制扰动。黑盒攻击只能看到模型的输出——但它依然可能成功,因为对抗样本常常会*迁移*:为骗过一个模型而造出来的样本,往往也能骗过另一个在相似数据上训练的模型。扰动可以是熊猫身上那种不可察觉的噪声,也可以是物理的、看得见的——几张精心摆放的贴纸就能让停车标志被读成限速标志,或者 T 恤上印一个图案就能让检测器看不见这个人。

防御,以及那场军备竞赛

最强、也最诚实的防御是对抗训练:在训练过程中生成攻击,并把它们加进数据里,让模型在自己最糟糕的样本上学习。它确实有用,是当今对抗防御的中流砥柱。但它绝非免费的午餐——训练成本要高得多,而且一个针对某个攻击预算加固过的模型,仍可能败给一个更大的、或形状不同的攻击。针对今天的攻击赢来的鲁棒性,并不能保证挡得住明天的攻击。

还有一整片更廉价防御的「坟场」,曾试图绕开那份成本——模糊输入、遮蔽梯度、检测「奇怪的」像素。其中很多被发表、被赞誉,然后在几个月内就被那些干脆见招拆招的攻击者攻破了。反复出现的教训叫*梯度遮蔽*:一个仅仅把梯度藏起来的防御,纸面上看着很鲁棒,可一旦碰上用别的办法估计梯度的攻击者,就垮了。这个领域学会了对任何没有经受过「自适应、且了解防御机制的攻击者」检验的防御,保持冷酷的怀疑。

把鲁棒性当作一种性质

退一步,把鲁棒性看作模型的一种*性质*,区别于准确率,是很值得的。一个测试准确率出众的模型,可能极其脆弱,因为准确率问的是「它在平均情况下答对了吗?」,而鲁棒性问的是「当输入在某个邻域内被扰动时,它还能答对吗?」这是两个不同的问题,一个模型完全可能在其中一个上拿满分,而在另一个上不及格。鲁棒性其实关乎一个预测的*稳定性*,而不只是它在干净测试集上的正确性。

模型一开始为什么会这么脆弱?一种主流解释是:它们抓住了那些预测性很强、却并不鲁棒的特征——一些细微的纹理和统计上的怪癖,它们在整个训练集里与标签相关,却不承载任何真正的含义。这和虚假相关属于同一类失败:模型答对了,但答对的理由很脆弱。攻击者要做的,不过是利用这些脆弱的理由,去精准扰动那些模型依赖、而人类忽略的特征。

这里甚至潜伏着一个令人不舒服的取舍:用今天的方法,把模型推向更强的对抗鲁棒性,往往会降低它在干净数据上的普通准确率。鲁棒性不是免费的,也不是一个一拨就开的开关——它是一种你要专门去设计、去仔细测量,并以算力、有时还以准确率为代价去换取的性质。

为何重要:安全,以及一张更大的网

只要一个模型挡在攻击者和他们想要的东西之间,对抗样本就会变成一个真实的攻击面。垃圾邮件和恶意软件过滤器,会被喂入专门调过、能溜过去的输入。人脸识别和内容审核系统,会被精心炮制的图案骗过。自动驾驶汽车的感知,可以在物理世界里被针对。防御方的活儿比攻击方更难:攻击者只需要一个能奏效的输入,而防御者必须挡住对手能想出来的*每一个*输入。这种不对称,正是为什么鲁棒性是一门两用的安全学科,而不是一个整整齐齐的基准测试。

同样的思路在语言模型身上又出现了。所谓*越狱*或*提示注入*,就是文本形式的对抗输入——一段精心构造、要把模型推过其安全护栏的字符串——而那种猫捉老鼠的节奏,和图像研究者们多年来经历的一模一样。要在第一步就察觉一个输入可疑,就把鲁棒性和分布外检测联系了起来:一个能标记出「这个输入和我训练时见过的任何东西都不像」的系统,才有机会去拒绝或上报,而不是自信地犯错。

  1. 先建立威胁模型:写清楚攻击者是谁、他们能看到什么(白盒还是黑盒),以及在你的领域里多大的扰动才算「小」。
  2. 在别人动手之前,用强大的、自适应的攻击去打你自己的模型——把它当作红队演练,而不是走过场。
  3. 在关键处加固(对抗训练、输入校验),并加上检测机制,让异常输入被标记出来,而不是被默默信任。
  4. 假定防御只是局部的:在高风险决策上保留人类参与,并在生产环境中持续监控,因为攻击者会不断适应。

这一切都不构成什么世界末日。对抗脆弱性是一个具体的、已被深入研究的工程问题——它并不意味着模型暗地里心怀恶意,或者快要挣脱束缚了。更诚实的表述其实更简单、也更有用:这些系统是强大的模式匹配器,带着锋利、可被利用的边缘,而鲁棒性就是这样一门持续的功夫——在对手之前找到那些边缘,并把那些要紧的磨钝。把它当作安全工程来对待,用对抗的方式去度量它,并对任何单一防御所能承诺的东西保持谦逊。