资讯动态

对抗样本引发AI事故?攻防实战与防御策略全解析

发布时间:2026/10/21 5:32:41 来源:尧图企业网站定制
去年有一次线上事故让我印象特别深。某公司一个图像审核系统上线了大半年各项指标都稳得让人放松警惕直到测试团队拿着几张肉眼看起来完全正常的照片在系统面前晃了一圈——审核结果全部出错有人脸被误判成另一个人有张压根就没识别出来。后来排查发现这几张照片上都叠加了一层极其轻微的、人眼注意不到的点状噪声就是这层噪声让一个成熟模型瞬间“失明”。这类噪声在AI安全领域里有一个专门的名字对抗样本。这篇文章我想从一次攻防复盘的角度把对抗攻击的核心原理、主流攻击手法、防御策略以及落地时踩过的坑一条线讲清楚。如果你正在做模型上线前的安全评估或者正在为业务场景挑防御方案这篇文章应该能帮你少走不少弯路。先说明白一点讲攻击不是为了制造恐慌而是只有搞懂了刀往哪儿砍才知道盾该怎么铸。1. 对抗攻击到底是什么从一次事故聊起1.1 一次“看不见的噪声”引发的上线风波那次事故排查到后面整个技术团队都有点懵。原始图片是完整的人脸照片分类器在干净数据上测试准确率一直维持在99%以上可一旦图片经过某个细微扰动系统就像换了个人一样乱猜。问题不在于模型本身漂移而在于输入数据被刻意“污染”了。这类操作在学术界的定义很明确给定一个原本能被模型正确分类的样本 x攻击者可以构造一个微小的扰动 δ使得 xδ 在人类看来和原图几乎没有区别但模型给出的预测结果彻底改变。这个经过扰动的样本就叫对抗样本δ 则是对抗扰动。放到实际业务里这意味着什么内容审核模型可以被绕过、人脸识别门禁可以被伪装、自动驾驶的路牌识别可以被欺骗。最头疼的是这类攻击不依赖任何漏洞不需要对目标系统做任何物理侵入攻击者只需要“喂”给模型一张精心构造的图片或者一段文字模型自己就会犯错。所以安全团队面对的不是传统意义上的漏洞修复而是一个更底层的问题深度模型本身有着结构性的弱点。1.2 对抗样本的底层原理模型学的是特征不是概念为什么微小扰动会造成如此大的误判我自己的理解是深度学习模型在高维空间里学到的是统计特征而不是人类意义上的“语义概念”。人在看一张猫的照片时关注的是耳朵、眼睛、毛发的整体形态但模型实际上是在数千维的特征空间里做划分它的决策边界是跟着训练数据分布走出来的。高维空间有一个反直觉的特性维度越高同样大小的扰动向量在空间中的“影响范围”就越大。你可以把模型的输入空间想象成一个铺满决策边界的迷宫干净样本在迷宫里处于正确区域只要沿着某个特定方向轻轻推一下它就可能越过边界滑进错误区域而这个方向人不敏感模型却极其敏感。一张图的像素值通常有上万个维度每个像素只需改动很小的数值累积起来就足以把样本推出正确区域。FGSM这个经典攻击方法本质上就是沿着损失函数对输入梯度上升的方向一次性加一个固定大小的扰动。公式写出来很简洁x_adv x ε * sign(∇x L(θ, x, y))x是原始输入θ是模型参数y是真实标签L是损失ε是扰动强度。sign表示取梯度的符号方向相当于只保留“往哪个方向推最有效”这个信息然后以ε为步长推一下。这就是对抗攻击最底层的思想把模型的梯度当成一份“导航地图”梯度方向就是模型最容易犯错的方向。2. 主流攻击手法知道刀怎么砍才知道盾怎么造2.1 白盒攻击家族从FGSM到PGD再到CWFGSM是最容易理解也最容易实现的攻击类型但它有个明显短板只做一步更新扰动方向不一定足够精确。很多防御方法稍微做点输入平滑FGSM就失效了。真正让安全团队头疼的是它的迭代版本——PGD。PGD的思想也简单一步推不动那就多推几步。每一步沿着梯度符号方向走一个小步长 α走完一步就把结果裁剪回原始样本的 ε 邻域内防止扰动超出预算。公式长这样x^{t1} clip(x^t α * sign(∇x L(θ, x^t, y)), x-ε, xε)这个循环迭代的“投影梯度下降”方法在数学上可以理解为一个寻找最坏情况扰动的过程。我实测下来的感受是PGD做攻击时收敛速度很快通常在10到20步迭代之后就能稳定地把一个原本预测正确的样本打到错误分类。正因为PGD足够强它后来也成了对抗训练里最常用的攻击基准。再往后是CW攻击一个思路完全不同但同样硬核的方法把“制造对抗样本”建模成一个优化问题目标函数分成两项一项希望扰动尽可能小另一项希望模型输出目标错误类别然后用优化器去平衡这两项。CW的白盒版本攻击成功率很高而且它生成的扰动通常比FGSM和PGD隐蔽得多。过去很多防御方案号称能抵御攻击结果在CW面前一测就原形毕露。下面这段PyTorch代码是我在项目里常用的一套FGSM攻击实现方便你快速上手理解整个流程import torch import torch.nn as nn def fgsm_attack(model, x, y, eps): model.eval() x.requires_grad True loss_fn nn.CrossEntropyLoss() loss loss_fn(model(x), y) model.zero_grad() loss.backward() # 取梯度符号方向叠加扰动 grad_sign x.grad.data.sign() x_adv x eps * grad_sign # 裁剪到合法像素范围 x_adv torch.clamp(x_adv, 0, 1) return x_adv这段代码里最关键的一行是x.requires_grad True。没有它PyTorch不会对输入做梯度计算整个攻击就没法生效。做防御实验时我建议把eps从0.01开始逐步加大看看模型准确率和扰动强度的关系曲线这样能对模型的鲁棒性有个直观认知。2.2 黑盒攻击与物理世界攻击现实威胁升级白盒攻击的前提是攻击者能拿到目标模型的结构和参数。现实业务里这不现实。于是就有了黑盒攻击它分两大类基于迁移性的攻击和基于查询的攻击。基于迁移性的思路是攻击者先自己训练一个替代模型在这个替代模型上生成对抗样本再拿去攻击目标系统。因为同类任务上不同模型的决策边界往往有相似性在替代模型上有效的扰动经常也能骗过目标模型。这个特性叫攻击的迁移性。我在测试中就遇到过这样的情况用一个公开数据上训出来的小型替代模型生成的对抗样本直接就让线上另一个完全不同架构的模型出现明显错误。所以哪怕你的模型参数没泄露也不能觉得自己就安全了。基于查询的攻击更“笨”一点但也更直接攻击者反复向目标模型发送输入观察输出的置信度或者预测标签通过大量查询反向推断出模型的敏感方向。比如边界攻击这类方法连梯度都不用算只需要知道模型在某个输入下给出的预测类别就能逐步逼近对抗样本。这类攻击对部署在API里的模型威胁很大因为API天然给了攻击者无限次的查询机会。更麻烦的是物理世界攻击。研究者已经做过很多实验在眼镜框上贴对抗花纹让人脸识别系统认错人在停车标志上贴几块黑白贴纸让自动驾驶模型把它识别成限速牌。这类攻击不再局限于数字世界里改像素而是把扰动打印到实物上通过摄像头进入系统。物理世界攻击意味着AI安全不只是线上安全团队要考虑的事凡是摄像头能拍到的地方都可能是攻击面。3. 防御策略全景先搞清楚你防的是谁3.1 按攻击者能力分级白盒、灰盒、黑盒聊防御方案之前一定要先明确一个东西威胁模型。所谓威胁模型就是假设攻击者对你的系统了解多少、能施加什么样的操作。不同威胁模型对应的防御策略完全不一样。如果攻击者对模型结构和参数一清二楚白盒那么绝大多数启发式防御都靠不住因为攻击者可以利用梯度信息针对性地绕过你的防御这也就是后面要讲的“梯度掩盖”问题的来源。如果攻击者只有模型输入输出接口黑盒那么输入预处理、随机化这些偏工程的手段就有实际意义虽然不能彻底阻断攻击但能显著抬高攻击成本。还有一种灰盒场景攻击者可能知道你的模型结构但不知道参数这种情况下可以综合用迁移性评估和输入变化检测来防御。业务侧最常见的问题是一上来就追求“万能防御”。我跟不少团队聊过大家的期待是找一个方案装上去之后所有攻击都进不来。但现在的技术现状是不存在这样的方案。理性的做法是先根据业务场景定义攻击者的能力上限再选择性价比最高的防御组合。3.2 训练侧防御对抗训练与它的代价在目前所有防御手段里对抗训练是理论依据最扎实、实践效果最稳定的一个。它的核心思想特别直接把对抗样本当成训练数据的一部分让模型在训练阶段就见过这些“坏样本”从而学会抵抗它们。数学上是一个典型的Min-Max问题min_θ [ max_δ L(θ, xδ, y) ]内层max是在寻找最能让模型出错的数据分布外层min是让模型在这个最坏情况下仍然把损失降到最低。换句话说就是在一场模拟攻防中训练模型内层是攻击者拼命构造扰动外层是模型拼命抵抗。工程实现上最经典的做法是用PGD生成对抗样本然后放进训练循环。我在PyTorch里写过一段简化版对抗训练逻辑核心代码大致是这样def pgd_attack(model, x, y, eps, alpha, iters): x_adv x.clone().detach() for _ in range(iters): x_adv.requires_grad True loss nn.CrossEntropyLoss()(model(x_adv), y) grad torch.autograd.grad(loss, x_adv)[0] x_adv x_adv alpha * grad.sign() x_adv torch.clamp(x_adv, x - eps, x eps) x_adv torch.clamp(x_adv, 0, 1) return x_adv.detach() # 训练循环片段 for x, y in trainloader: x_adv pgd_attack(model, x, y, eps0.03, alpha0.01, iters10) loss nn.CrossEntropyLoss()(model(x_adv), y) optimizer.zero_grad() loss.backward() optimizer.step()这段代码跑起来不难但真正用到生产环境时有两个问题要注意。一是计算开销巨大每个训练batch都要做一次完整的PGD迭代等于训练成本翻了10倍甚至20倍。二是对抗训练往往会让模型在干净数据上的准确率下降也就是“鲁棒性与准确率不可兼得”这个困境。针对这个问题学术界做了很多改进最著名的是TRADES算法它在损失函数里显式加入了一项衡量“干净样本和对抗样本预测差异”的正则项让模型在提升鲁棒性的同时尽量少牺牲精度。我实践下来的体验是TRADES在中小规模数据集上的平衡效果好于朴素对抗训练但超参数调整更费工夫。具体到业务里你是选PGD对抗训练还是TRADES取决于你容忍多少精度损失通常要在验证集上做一轮网格搜索才能定下来。3.3 输入与输出侧防御预处理、检测与拒答训练侧防御成本高、周期长很多人就想着在输入输出侧加一些“便宜”的防御对输入做预处理或者对输出做检测发现可疑样本就直接拒绝。这类方案能不能用能用但要有清醒的预期。输入预处理的思路是给输入“洗个澡”比如JPEG压缩、图像缩放、中值滤波、随机裁剪、加随机噪声等。原理是这些操作能破坏对抗扰动精心构造的结构让扰动失效。我在早期项目里试过对这些方法做过一轮对比表面上看起来有一定效果但后来用白盒攻击一测很多预处理方案在自适应攻击面前基本不堪一击。所谓自适应攻击就是攻击者知道你做了预处理之后把预处理函数也纳入梯度的计算范围专门绕过它。这条经验算是我踩过最深的坑之一任何防御方案如果评估时没有考虑自适应攻击得出的安全结论都可能是幻觉。输出侧检测是另一种思路不改变模型本身而是加一个哨兵模块判断当前输入是不是对抗样本。常见方法有用局部内在维度LID来度量样本周围空间结构的异常程度也有用随机平滑做多次预测一致性检查的。原理是对抗样本在特征空间里的分布和正常样本有明显差异检测器可以把这个差异识别出来。这类方法的优点是部署灵活不需要重训主模型缺点是检测器本身也可能被绕过而且检测器的误报率在生产环境里可能造成不少正常请求被拒掉。这里必须提一下防御蒸馏。它曾经在业界很火思路是让模型输出“软化”的概率分布从而平滑损失面、让小梯度攻击失效。但后来有研究者证明防御蒸馏可以被CW这类基于优化的攻击轻松绕过关键原因是蒸馏并没有真正消除模型对扰动的敏感性只是隐藏了梯度信息。这个案例提醒我判断防御方案是否有效不能只看它在某些攻击下稳不稳还要看它是不是只是在“掩盖”问题。4. 一次防御实战从评估基到部署总结4.1 第一步建立攻击基准量化模型“受伤”程度我每次接一个新模型的AI安全评估第一件事不是急着上防御而是先测出模型在攻击下的“受伤基线”。没有基线后面做的所有防御都说不清楚有没有效果。实际操作上我一般固定三四种代表性攻击方法覆盖单步攻击、迭代攻击和优化攻击三个梯度然后在不同攻击强度下跑一遍模型记录一堆指标。下表是一个比较典型的评估基线样例用的是我在某个图像分类Demo里的测试结果四舍五入一下大概是这样攻击方法扰动强度干净准确率攻击后准确率攻击成功率FGSMε0.0398.2%43.6%55.6%PGD-10ε0.0398.2%18.4%81.2%PGD-20ε0.0398.2%11.7%88.1%CW-L2自动优化98.2%4.8%95.1%这张表一眼就能看出几个关键信息FGSM虽然好实现但攻击效果在迭代攻击面前不算强PGD迭代次数增加带来的准确率下降非常明显CW攻击几乎能把模型打穿。如果你的模型连FGSM都扛不住那线上环境肯定存在很大风险如果评估时只用FGSM又容易高估模型的安全性。我在评估时还习惯把同一套方案在不同随机种子上跑三遍取均值把方差也记录下来防止某一次评估结果有偶然性。4.2 第二步对抗训练的工程化落地拿到基线之后我开始分层推进防御方案。对抗训练永远放在第一位因为它能真正改变模型的决策边界而不是在外部做遮掩。工程落地时有几个细节值得专门讲一下。第一个细节是数据比例。不是生成多少对抗样本就无脑塞进训练集我建议一开始从20%-30%的比例试起。对抗样本是“硬样本”数量一多模型很容易训练不稳干净准确率掉得厉害。先用小比例热热身再逐步往上加稳定性和鲁棒性之间往往能找到一个可接受的平衡点。第二个细节是扰动强度和迭代步数。训练用的攻击强度内置的eps直接决定模型能扛住的扰动上限一般选测试时攻击强度上限的80%作为训练强度就够了。迭代步数方面训练阶段其实不建议用特别大的步数通常5到7步就行。步数太大训练慢而且过强的训练攻击反而会让模型收敛到很差的局部最优。我试过用10步迭代做训练效果反而不如7步稳定。第三个细节是优化器与学习率。对抗训练本身是一个偏对抗的动态过程损失面往往更陡峭学习率要相对保守一些。我用SGD配动量的经验是学习率设为普通训练的0.5到0.7倍比较稳。另外对抗训练的过程需要更长的热身阶段让模型先对“干净数据”有一个稳定的拟合基础再逐步引入对抗样本不然一开始模型可能根本收不拢。经历几次失败后我把热身策略定为前5个epoch纯用干净数据训练之后再混合对抗样本收敛稳定性明显改善。4.3 第三步评估不能光看准确率还要揭穿“假防御”防御训练做完最后一个环节是重新评估。最忌讳的是拿和防御时同一种攻击、同一个参数去评估那样做的结果往往“好看”但不可靠。我复盘过不少防御方案凡是只报“防御后准确率从20%提升到90%”的结论十有八九是评估幻觉。正确的做法是引入更强、更全面的攻击来交叉验证。具体来说我会同时跑这几类测试一是用多种白盒攻击FGSM、PGD、CW、AutoAttack等交叉验证二是测试对抗样本在不同初始化条件下的攻击成功率看模型的防御效果是否稳定三是做迁移性测试看黑盒场景下的防御表现。在这些测试里AutoAttack是一个很值得用的标准评估库因为它集成了多种强攻击策略能自动组合出当前模型最容易中招的攻击方式。我用AutoAttack跑过好几个号称“已经很稳”的模型结果不少都明显高估了自己的防御能力。评估结果的表现形式我通常画一条鲁棒性-准确率曲线横轴是攻击强度纵轴是模型准确率。这条曲线能直观看出模型的鲁棒性边界在哪里。还有一个关键检查项验证防御是否引入了“梯度掩盖”。最简单的方法是检查模型在输入上的梯度是否出现大量饱和或几乎为0的情况因为如果梯度消失了攻击虽然暂时失败但同时也说明模型把敏感信息藏起来了攻击者换一种不求梯度的攻击方式就可能重新攻破。这种状态下的“防御成功”靠不住一定要在评估报告里明确标注。5. 常见问题与避坑清单5.1 对抗训练不收敛先查这一项对抗训练最让人崩溃的问题就是loss死活不降。我遇到过几次排查到最后发现同一个元凶对抗样本生成过程中扰动没有做范围裁剪或者裁剪顺序错了。扰动超出合法范围模型在训练时接收到了一堆完全畸形的输入拟合难度剧增自然不收敛。排错方法其实很直接单独写一段测试脚本把生成的对抗样本可视化出来看一眼图像是不是还保持基本语义。如果图像看起来已经像纯粹噪声说明裁剪逻辑有问题。另外一个常见的坑是把对抗样本的梯度传回了原输入图导致训练时输入本身的像素被改动模型永远也学不到稳定特征。正确做法是确保输入图requires_gradFalse只让对抗样本生成过程内部传播梯度训练阶段用detach后的对抗样本算损失。5.2 防御后干净样本掉点严重从正则项和数据比例找平衡对抗训练掉点几乎是必然的但掉点幅度有讲究。我见过有人做完对抗训练干净准确率从97%掉到70%那基本等于模型被练废了。出现这种问题的原因通常有两个一是对抗样本比例太高模型被“硬样本”带偏了二是训练攻击强度太高相当于你要模型在所有方向上都有很强的鲁棒性最终顾此失彼。解决的路径我记得很清楚第一步降低对抗样本混入比例从50%降到25%看看掉点是否缓解第二步尝试TRADES这类显式带正则项的损失函数它的调节参数能直接控制精度与鲁棒性的取舍第三步降低对抗扰动强度把训练时用的eps从一个较大的值减下来具体情况要根据业务对鲁棒性和精度的容忍度来权衡没有统一答案。5.3 越防越危险梯度掩盖与评估幻觉这一条是很多团队在防御评估中容易忽略的通过某种防御手段把梯度弄得特别粗糙或者特别平缓攻击者用梯度类方法确实打不穿于是团队宣判防御生效。但换个黑盒攻击一测防线瞬间瓦解。这就是梯度掩盖问题。怎么判断自己的防御是否在掩盖梯度我通常做一个简单实验在更大的扰动预算下用基于边界搜寻的攻击不需要梯度测试模型比如边界攻击或者基于决策的黑盒攻击。如果原先用FGSM能防住、换黑盒攻击后防御效果大幅缩水基本可以断定存在梯度掩盖。这类防御不仅没有提升安全性还会给业务方制造虚假的安全感潜在风险更大。我整理了一份很常用的排查速查表放在下面供你参考现象可能原因检查动作对抗训练loss不降扰动裁剪错误 / 输入梯度泄漏可视化对抗样本检查detach逻辑干净准确率大幅下降对抗样本比例过高 / 训练扰动过大降低比例尝试TRADES正则FGSM防住了但黑盒攻击失败梯度掩盖用不需要梯度的攻击重新测试防御后攻击成功率反而更高防御诱导模型产生新的脆弱方向用AutoAttack做多攻击交叉验证不同随机种子评估差异大评估样本量不足 / 攻击初始化影响扩大测试集多种子求均值这个表看起来简单但我每次做项目评审时都会逐条过一遍能拦住大部分“看似安全实则裸奔”的情况。最后再分享一个我个人的体会。做AI安全防御这几年我最深的感受是安全不是一个结果而是一个持续的过程。对抗攻击技术在演进防御方案也在迭代今天有效的防线明天可能就被新的攻击手法绕过。所以我现在做任何项目都会在交付文档里附上一份“持续评估计划”约定每隔一段时间重新跑一次攻击基线监测模型鲁棒性是否有漂移。这套做法虽然不起眼但在生产环境里带来的安全感远高于任何“装上就不用管”的防御方案。如果你正准备给自己的模型做安全加固我建议你也从建立基线评估开始先搞清楚模型到底有多脆弱再决定要花多大力气去防守。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑