1. 对抗样本攻击的底层逻辑与整体分类框架搞机器学习安全这块的人迟早会碰到对抗样本这个绕不开的坎。我第一次接触这个概念是在做一个图像分类的小项目时模型在测试集上准确率跑到98%以上结果把一张熊猫照片加上一层肉眼几乎看不出来的噪声模型就斩钉截铁地把它认成了长臂猿置信度还高达99.3%。当时我就意识到模型的“聪明”和人类的“聪明”完全是两回事。对抗样本攻击方法总结这件事本质上是在梳理一个核心问题如何用最小的扰动让模型做出最离谱的判断。这篇文章我会把主流攻击方法从原理到实现逐层拆开包括梯度类、优化类、迁移类、物理世界攻击等方向适合有一定深度学习基础、想系统理解对抗攻防的读者。先说清楚对抗样本的定义。给定一个原始输入 ( x ) 和真实标签 ( y )以及一个目标模型 ( f )对抗样本 ( x x \delta ) 满足两个条件一是 ( f(x) \neq y )非目标攻击或 ( f(x) y_{target} )目标攻击二是扰动 ( |\delta|p \leq \epsilon ) 足够小人眼不可察觉。这里的 ( p ) 通常是 ( L\infty )、( L_2 ) 或 ( L_0 ) 范数。( L_\infty ) 限制每个像素的最大变化量( L_2 ) 限制整体能量( L_0 ) 限制被修改的像素个数。理解这三种范数的区别非常关键因为它直接决定了攻击的视觉隐蔽性和实现难度。为什么对抗样本会存在目前学界比较公认的解释有几个方向。一个是线性假设在高维空间中即使每个维度的扰动很小累加起来的内积变化也足以让决策边界翻转。另一个是决策边界曲率模型学到的决策边界在某些区域非常接近数据点稍微推一下就越界了。还有一个是特征脆弱性模型依赖的某些特征和人类感知的特征不一致攻击者恰好可以利用这种错位。这些解释各有道理实际做攻击时不需要纠结哪个对但理解它们有助于你设计更有效的攻击策略。从攻击者掌握的信息来看对抗攻击分为三大类。白盒攻击是攻击者完全知道模型结构、参数、梯度这类攻击通常效果最好扰动最小代表方法有FGSM、PGD、CW等。黑盒攻击是攻击者只能查询模型的输入输出不知道内部细节又分为基于查询的和基于迁移的两种。灰盒攻击介于两者之间比如知道模型结构但不知道参数。实际场景中黑盒攻击更贴近真实威胁模型因为攻击者通常拿不到目标模型的权重。从攻击目标来看分为非目标攻击和目标攻击。非目标攻击只要让模型分类错误就行难度较低目标攻击要让模型输出指定的错误类别难度明显更高通常需要更大的扰动或更多的迭代步数。还有一个维度是有目标类别 vs 无目标类别以及定向 vs 非定向这些术语在不同论文里叫法不太统一但核心意思就这两类。从扰动范数约束来看( L_\infty ) 攻击最常用因为它实现简单用clip操作就能控制( L_2 ) 攻击生成的扰动更分散视觉上更自然( L_0 ) 攻击只改少量像素适合研究稀疏攻击。选择哪种范数取决于你的应用场景如果是研究图像分类的鲁棒性( L_\infty ) 是标配如果要做物理世界攻击( L_2 ) 或 ( L_0 ) 可能更合适因为物理扰动往往不是均匀分布的。下面这张表是我自己整理的攻击方法分类速查后面每个方法都会展开讲。分类维度类别代表方法特点信息掌握白盒FGSM, PGD, CW效果好扰动小信息掌握黑盒-查询ZOO, NES需要大量查询信息掌握黑盒-迁移MI-FGSM, DI-FGSM无需查询依赖迁移性攻击目标非目标FGSM, PGD难度低攻击目标目标Targeted-PGD, CW难度高范数约束L∞FGSM, PGD像素级限制范数约束L2CW, DeepFool整体能量限制范数约束L0JSMA, SparseFool稀疏像素修改理解了这些分类你在读论文或做实验时就能快速定位一个方法的位置知道它解决的是什么问题代价是什么。接下来我会按攻击方法的发展脉络从最经典的FGSM开始一路讲到最新的迁移攻击和物理攻击。2. 白盒攻击方法逐层拆解与实操要点2.1 FGSM一行代码就能跑通的入门攻击FGSM全称Fast Gradient Sign Method是Goodfellow在2014年提出的可以说是对抗攻击领域的“Hello World”。它的核心思想极其简单沿着损失函数对输入的梯度方向取符号函数乘以步长 ( \epsilon )就得到了扰动。公式就一行[ x x \epsilon \cdot \text{sign}(\nabla_x J(f(x), y)) ]其中 ( J ) 是损失函数通常是交叉熵。为什么取sign因为我们要在 ( L_\infty ) 约束下最大化损失而 ( L_\infty ) 球面上的最优方向就是梯度的符号方向。这个推导用到了Holder不等式简单说就是在每个维度上梯度绝对值最大的方向就是符号方向。我用PyTorch写一个最小实现你可以直接抄import torch import torch.nn as nn def fgsm_attack(model, x, y, epsilon): x_adv x.clone().detach().requires_grad_(True) output model(x_adv) loss nn.CrossEntropyLoss()(output, y) model.zero_grad() loss.backward() grad_sign x_adv.grad.data.sign() x_adv x epsilon * grad_sign x_adv torch.clamp(x_adv, 0, 1) return x_adv.detach()这段代码有几个细节要注意。第一x_adv需要requires_grad_(True)否则拿不到梯度。第二model.zero_grad()要放在backward()之前清掉之前的梯度。第三最后要clamp到合法像素范围否则生成的图片可能超出[0,1]区间保存时会出现奇怪的颜色。FGSM的优点是快一次前向一次反向就搞定适合大规模生成对抗样本做对抗训练。缺点是扰动不够精细同样的 ( \epsilon ) 下它的攻击成功率通常低于迭代方法。我实测下来在CIFAR-10上( \epsilon8/255 ) 时FGSM的非目标攻击成功率大概在60%到70%之间而PGD能到95%以上。注意FGSM对 ( \epsilon ) 非常敏感。( \epsilon ) 太小攻击无效太大则肉眼可见。做实验时建议从 ( \epsilon1/255 ) 开始试逐步增加到 ( 8/255 )、( 16/255 )观察攻击成功率和视觉质量的变化。还有一个变体叫FGSM with random start就是在原始输入上先加一个小的随机扰动再做FGSM。这个技巧能提升攻击成功率因为随机起点让攻击者有机会跳出损失函数的局部平坦区域。实现上就是在FGSM之前加一行x x torch.empty_like(x).uniform_(-epsilon, epsilon)然后clamp。2.2 PGD迭代攻击的标杆方法PGD全称Projected Gradient Descent也叫I-FGSMIterative FGSM是目前白盒攻击里最常用的基准方法。它的思路是把FGSM的单步变成多步每步走小一点走完后再投影回 ( \epsilon ) 球内。算法流程是这样的初始化 ( x_0 x \text{random_noise} )噪声在 ( [-\epsilon, \epsilon] ) 内均匀采样对 ( t 1 ) 到 ( T )计算梯度 ( g_t \nabla_x J(f(x_{t-1}), y) )更新 ( x_t x_{t-1} \alpha \cdot \text{sign}(g_t) )投影 ( x_t \text{clip}(x_t, x - \epsilon, x \epsilon) )再clip到[0,1]返回 ( x_T )这里的 ( \alpha ) 是每步步长通常取 ( \epsilon / 4 ) 或 ( \epsilon / 10 )( T ) 是迭代次数常见取10、20、40、100。步长和迭代次数的关系是( \alpha \cdot T ) 要略大于 ( \epsilon )这样才有足够的“探索空间”让攻击找到好的解。def pgd_attack(model, x, y, epsilon, alpha, num_iter): x_adv x.clone().detach() x_adv x_adv torch.empty_like(x_adv).uniform_(-epsilon, epsilon) x_adv torch.clamp(x_adv, 0, 1) for i in range(num_iter): x_adv.requires_grad_(True) output model(x_adv) loss nn.CrossEntropyLoss()(output, y) model.zero_grad() loss.backward() grad_sign x_adv.grad.data.sign() x_adv x_adv.detach() alpha * grad_sign x_adv torch.min(torch.max(x_adv, x - epsilon), x epsilon) x_adv torch.clamp(x_adv, 0, 1) return x_adv.detach()PGD为什么比FGSM强直观理解是FGSM只走一步容易走到损失函数的“沟壑”里出不来PGD走多步每步都重新计算梯度能更充分地探索 ( \epsilon ) 球内的空间。理论上PGD可以近似求解 ( L_\infty ) 约束下的最优扰动所以它常被用作评估模型鲁棒性的“最强白盒攻击”。实操中有几个坑我踩过。第一随机初始化很重要。如果不用随机起点PGD可能陷入某个局部最优攻击成功率会下降。第二步长不要设太大。( \alpha ) 太大时每步更新会“跳过”好的解反而降低效果。我一般用 ( \alpha \epsilon / 10 )迭代20到50次。第三目标攻击需要改损失函数。非目标攻击是最大化真实标签的损失目标攻击是最小化目标标签的损失代码上就是把loss -CrossEntropy(output, target_label)。提示PGD的攻击成功率随迭代次数增加而提升但边际收益递减。迭代20次和迭代100次的差距可能只有2到3个百分点但计算时间差5倍。做对抗训练时通常用7到10次迭代做鲁棒性评估时用20到50次。2.3 CW攻击优化视角下的精细扰动CW攻击是Carlini和Wagner在2017年提出的它的出发点不是“快速生成”而是“最小扰动”。FGSM和PGD优化的是 ( L_\infty ) 范数下的攻击成功率CW直接优化扰动大小目标是找到最小的 ( \delta ) 使得模型分类错误。CW的原始形式是一个约束优化问题[ \min_{\delta} |\delta|_p c \cdot f(x \delta) ]其中 ( f ) 是一个自定义的损失函数设计目标是让模型把 ( x\delta ) 分类到目标类别。CW提出了7种 ( f ) 的候选形式最常用的是[ f(x) \max(\max_{i \neq t} Z(x)_i - Z(x)_t, -\kappa) ]这里 ( Z ) 是logits输出( t ) 是目标类别( \kappa ) 是一个置信度参数控制攻击的“强度”。( \kappa ) 越大攻击越强但扰动也越大。CW的厉害之处在于它生成的对抗样本在视觉上几乎完美而且对防御方法如对抗训练、防御蒸馏有很强的穿透力。但代价是计算量大需要对每个样本单独优化通常用Adam或L-BFGS求解一个样本可能要跑几百到几千次迭代。def cw_attack(model, x, target, c1e-4, kappa0, num_iter1000, lr0.01): delta torch.zeros_like(x, requires_gradTrue) optimizer torch.optim.Adam([delta], lrlr) for i in range(num_iter): x_adv torch.clamp(x delta, 0, 1) output model(x_adv) target_logit output[0, target] other_logits output.clone() other_logits[0, target] -1e10 max_other other_logits.max() f_loss torch.clamp(max_other - target_logit, min-kappa) l2_loss torch.norm(delta.view(delta.size(0), -1), p2) loss l2_loss c * f_loss optimizer.zero_grad() loss.backward() optimizer.step() return torch.clamp(x delta, 0, 1).detach()CW的调参经验( c ) 是最关键的超参数太小则攻击无效太大则扰动过大。实践中常用二分搜索找合适的 ( c )从 ( 10^{-4} ) 开始如果攻击失败就乘10如果扰动太大就除以10。( \kappa ) 一般设0表示只要分类错误就行如果要更强的攻击可以设 ( \kappa20 ) 或 ( \kappa40 )。注意CW攻击对 ( L_2 ) 范数的优化效果最好对 ( L_\infty ) 需要改一下损失函数把 ( L_2 ) 范数换成 ( L_\infty ) 范数的近似。另外CW的计算成本很高不适合大规模生成对抗样本更适合做小规模的精调攻击或防御评估。2.4 DeepFool寻找最近决策边界DeepFool的思路很优雅它想找到从原始样本到最近决策边界的最短路径。对于二分类问题这个最短路径就是到超平面的垂线对于多分类问题DeepFool用迭代的方式每次找最近的决策边界走一小步直到分类翻转。算法核心是在每个迭代步对每个非真实类别 ( k )计算把样本推到类别 ( k ) 的决策边界所需的最小扰动然后选最小的那个更新样本。重复直到分类错误。DeepFool生成的扰动通常比FGSM小但比CW略大。它的优点是无需调参除了迭代次数和过冲系数而且对 ( L_2 ) 范数有理论保证。缺点是只适用于白盒且对复杂模型可能不收敛。def deepfool_attack(model, x, num_classes10, max_iter50, overshoot0.02): x_adv x.clone().detach().requires_grad_(True) for i in range(max_iter): output model(x_adv) pred output.argmax().item() if pred ! x.argmax().item(): break grad_orig torch.autograd.grad(output[0, pred], x_adv, retain_graphTrue)[0] min_dist float(inf) min_grad None for k in range(num_classes): if k pred: continue grad_k torch.autograd.grad(output[0, k], x_adv, retain_graphTrue)[0] diff grad_k - grad_orig dist abs(output[0, k] - output[0, pred]) / (diff.norm() 1e-8) if dist min_dist: min_dist dist min_grad diff r (min_dist 1e-4) * min_grad / (min_grad.norm() 1e-8) x_adv (x_adv (1 overshoot) * r).detach().requires_grad_(True) return x_adv.detach()DeepFool的过冲系数overshoot一般设0.02作用是让样本稍微越过决策边界避免在边界上震荡。迭代次数50通常够用如果模型很深可以加到100。3. 黑盒攻击与迁移攻击的实战策略3.1 迁移攻击不查模型也能打迁移攻击是黑盒场景下最实用的方法。核心思想是在一个替代模型surrogate model上生成对抗样本然后直接拿去攻击目标模型。之所以有效是因为不同模型在相似数据上训练时学到的决策边界有相似性对抗样本的“攻击方向”可以跨模型迁移。迁移攻击的关键是提升对抗样本的迁移性。早期直接用FGSM或PGD在替代模型上生成迁移成功率通常只有20%到40%。后来一系列工作通过改进梯度计算方式把迁移成功率提升到了80%以上。MI-FGSMMomentum Iterative FGSM是第一个重要改进。它在PGD的基础上引入了动量项让梯度更新更稳定避免陷入替代模型的局部最优。公式是[ g_{t1} \mu \cdot g_t \frac{\nabla_x J(f(x_t), y)}{|\nabla_x J(f(x_t), y)|_1} ][ x_{t1} x_t \alpha \cdot \text{sign}(g_{t1}) ]动量系数 ( \mu ) 通常取1.0。归一化用 ( L_1 ) 范数而不是 ( L_2 )是因为 ( L_1 ) 归一化后每个像素的梯度贡献更均匀迁移性更好。DI-FGSMDiverse Inputs FGSM是另一个重要改进。它在每次迭代时对输入做随机resize和padding让攻击者看到的输入有变化从而生成对输入变换更鲁棒的对抗样本。实现上就是在计算梯度前对 ( x_t ) 做一次随机变换def random_transform(x, prob0.5): if torch.rand(1) prob: return x # 随机resize到不同尺寸再resize回来 scale torch.randint(200, 260, (1,)).item() / 256 new_size int(x.size(2) * scale) x_t torch.nn.functional.interpolate(x, size(new_size, new_size), modebilinear) # 随机padding pad_top torch.randint(0, 20, (1,)).item() pad_left torch.randint(0, 20, (1,)).item() x_t torch.nn.functional.pad(x_t, (pad_left, 20-pad_left, pad_top, 20-pad_top), modeconstant, value0) x_t torch.nn.functional.interpolate(x_t, size(x.size(2), x.size(3)), modebilinear) return x_tTI-FGSMTranslation-Invariant FGSM用高斯核卷积梯度让梯度在空间上更平滑提升对平移变换的鲁棒性。SI-FGSMScale-Invariant FGSM在多个尺度上计算梯度并平均提升对尺度变化的鲁棒性。NI-FGSMNesterov Iterative FGSM用Nesterov加速梯度提升收敛速度。实际做迁移攻击时我通常把MI、DI、TI、SI组合起来用效果比单用好很多。组合方式是在每次迭代时先对输入做DI变换计算梯度然后用TI的高斯核卷积梯度再用MI的动量更新最后用SI的多尺度平均。这套组合拳在ImageNet上能把迁移成功率从30%提升到90%以上。提示迁移攻击的替代模型选择很关键。通常用多个模型集成ensemble效果更好比如同时用ResNet、VGG、Inception生成对抗样本然后平均梯度。集成时每个模型的损失要归一化避免某个模型的损失主导梯度方向。3.2 基于查询的黑盒攻击如果攻击者可以查询目标模型但不知道内部细节可以用基于查询的方法。这类方法把攻击建模成优化问题通过查询来估计梯度或直接搜索扰动。ZOOZeroth Order Optimization用有限差分估计梯度。对每个像素分别加一个小扰动 ( h ) 和减一个小扰动 ( h )用输出变化除以 ( 2h ) 估计梯度。这个方法精度高但查询次数是像素数的两倍对于224x224的图像一次梯度估计要查询10万次以上实际不可行。改进方法是用坐标下降每次只优化一个像素查询次数降到几千次。NESNatural Evolution Strategies用随机方向采样估计梯度。每次采样一个随机方向 ( u )计算 ( f(x \sigma u) - f(x - \sigma u) )用这个差值乘以 ( u ) 作为梯度的无偏估计。查询次数比ZOO少但方差大需要多次采样平均。Bandits方法把攻击建模成多臂老虎机问题每次选择一个像素或一个区域进行扰动根据反馈更新策略。这类方法查询效率高但实现复杂调参困难。基于查询的攻击在实际中受限于查询次数。很多线上模型有查询频率限制或者每次查询有成本。所以这类方法更多用于研究场景实际攻击更常用迁移攻击。3.3 物理世界攻击从数字到现实的跨越物理世界攻击是对抗样本最“出圈”的方向因为它能影响现实系统比如让自动驾驶误判停车标志或者让人脸识别系统认错人。物理攻击的难点在于数字扰动经过打印、拍摄、光照变化后可能完全失效。EOTExpectation Over Transformation是物理攻击的核心技术。它的思想是在生成对抗样本时不是优化单个数字图像而是优化一个变换分布上的期望。具体来说对原始图像做随机旋转、缩放、亮度调整、噪声添加然后在这些变换后的图像上计算损失反向传播时把梯度累加回原始图像。这样生成的对抗样本对变换更鲁棒。def eot_attack(model, x, y, epsilon, num_iter, num_samples10): x_adv x.clone().detach().requires_grad_(True) optimizer torch.optim.Adam([x_adv], lr0.01) for i in range(num_iter): total_loss 0 for j in range(num_samples): # 随机变换 angle torch.empty(1).uniform_(-15, 15).item() scale torch.empty(1).uniform_(0.9, 1.1).item() brightness torch.empty(1).uniform_(0.8, 1.2).item() x_t transform(x_adv, angle, scale, brightness) output model(x_t) loss nn.CrossEntropyLoss()(output, y) total_loss loss total_loss / num_samples optimizer.zero_grad() total_loss.backward() optimizer.step() # 投影到epsilon球 with torch.no_grad(): x_adv.data torch.clamp(x_adv.data, x - epsilon, x epsilon) x_adv.data torch.clamp(x_adv.data, 0, 1) return x_adv.detach()物理攻击的另一个关键是可打印性。数字扰动可以是任意浮点数但打印机只能打印有限色域。所以生成对抗样本时要限制颜色在可打印范围内或者用CMYK色彩空间优化。另外打印后的图像会有墨点扩散、纸张纹理、光照不均等问题EOT的变换分布要覆盖这些因素。我做过一个简单的物理攻击实验在停车标志上贴几个黑白贴纸让分类器把它认成限速标志。数字环境下攻击成功率95%打印出来贴在墙上用手机拍照测试成功率降到60%左右。后来增加了EOT的变换种类加了透视变换和运动模糊成功率回到80%以上。这个实验让我深刻体会到物理攻击的难度比数字攻击高一个数量级。注意物理世界攻击涉及现实系统安全做实验时务必在受控环境下进行不要影响公共设施或他人财产。学术研究用模拟场景即可不要真的去攻击生产系统。4. 常见问题排查与防御视角的攻防对抗4.1 攻击失败的原因排查做对抗攻击实验时最常见的问题就是“攻击不成功”。我整理了一个排查清单按可能性从高到低排列。问题现象可能原因排查方法解决方案攻击成功率极低epsilon太小打印epsilon和扰动范数增大epsilon到8/255或16/255攻击成功率极低梯度计算错误检查requires_grad和zero_grad确保输入需要梯度梯度清零攻击成功率低迭代次数不够增加迭代次数到50或100用PGD替代FGSM攻击成功率低步长不合适尝试epsilon/4, epsilon/10调整alpha目标攻击失败损失函数方向错检查是最大化还是最小化目标攻击用负损失扰动肉眼可见epsilon太大计算PSNR或SSIM减小epsilon或改用CW迁移攻击失败替代模型太弱换更强的替代模型用集成模型物理攻击失败变换不够增加EOT变换种类加透视、模糊、噪声还有一个隐蔽的坑是模型预处理。很多模型在推理时会做归一化比如把[0,1]的像素转到[-1,1]或减去均值除以标准差。如果你在攻击时没有复现这个预处理梯度方向就是错的攻击自然失败。我踩过这个坑调了一下午才发现是归一化没对齐。另一个坑是batch normalization。如果模型在训练时用了BN推理时用的是running mean和var攻击时如果模型处于train模式BN会用当前batch的统计量导致梯度不稳定。攻击前一定要model.eval()。4.2 对抗防御的常见思路了解攻击方法后自然要问怎么防目前主流的防御思路有几类。对抗训练是最有效的防御方法。核心思想是在训练时把对抗样本加入训练集让模型学会抵抗攻击。最经典的方案是用PGD生成对抗样本然后最小化对抗样本上的损失。对抗训练能显著提升鲁棒性但代价是标准准确率会下降几个百分点而且训练成本高每步都要生成对抗样本。输入预处理是在推理前对输入做变换比如JPEG压缩、位深度降低、随机resize、总变差最小化等。这些变换能破坏对抗扰动但对正常图像的准确率也有影响。而且攻击者如果知道预处理方法可以针对性地生成对抗样本所以这类防御通常不够鲁棒。梯度掩码是让攻击者拿不到有用的梯度比如用非可微的预处理、随机化、或者梯度正则化。但这类防御容易被“梯度-free”攻击绕过比如迁移攻击或基于查询的攻击。** certified defense**是提供数学保证的防御比如随机平滑、区间 bound propagation。这类方法能证明在某个扰动范围内模型输出不变但通常只适用于小模型或小扰动实用性有限。从攻防对抗的角度看目前没有“完美”的防御。对抗训练虽然有效但计算成本高而且对未见过的攻击类型可能失效。实际部署时通常是多种防御组合使用比如对抗训练加输入预处理再加异常检测。4.3 实操心得与避坑指南最后分享几个我在做对抗攻击实验时总结的经验。第一固定随机种子。对抗攻击涉及随机初始化、随机变换、dropout等随机因素不固定种子的话实验结果不可复现。我一般在代码开头加import torch import numpy as np import random def set_seed(seed42): torch.manual_seed(seed) torch.cuda.manual_seed_all(seed) np.random.seed(seed) random.seed(seed) torch.backends.cudnn.deterministic True torch.backends.cudnn.benchmark False第二保存对抗样本时注意格式。对抗样本的像素值可能超出[0,1]保存为图片时会被截断导致攻击失效。保存前一定要clamp或者保存为npy文件保留原始浮点值。第三评估攻击成功率时要用正确的指标。非目标攻击的成功率是“分类错误的比例”目标攻击的成功率是“分类到目标类别的比例”。不要混淆。另外如果原始样本本身就被分类错误应该从分母中排除。第四注意计算资源。PGD迭代50次每个样本要50次前向反向1000个样本就是5万次。用GPU跑CIFAR-10上大概几分钟ImageNet上可能要几小时。做大规模实验前先在小批量上验证代码正确性。第五多读论文的官方实现。对抗攻击的论文很多但细节往往在代码里。比如FGSM的随机起点、PGD的投影方式、CW的二分搜索不同实现有差异。建议直接看作者的开源代码或者用成熟的库如Foolbox、Adversarial Robustness Toolbox避免重复造轮子。第六理解攻击的局限性。对抗攻击在数字世界很有效但物理世界受限于拍摄条件、光照、角度等因素。而且防御方法在不断进化今天有效的攻击明天可能就失效了。做研究时要关注最新的攻防进展不要停留在几年前的基准上。这个领域变化很快每年都有新的攻击和防御方法出来。我个人的体会是与其追求“最强攻击”不如深入理解攻击背后的原理这样才能在防御端设计出更鲁棒的方案。对抗样本本质上是模型决策边界在高维空间中的脆弱性体现只要模型还是用梯度下降训练的这个问题就不会完全消失。