You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PyTorch中实现对抗样本?复现指定论文的实现疑问

嘿,关于复现这篇经典对抗样本论文的问题,我来给你理清楚——你的核心思路其实是对的,但还有几个关键细节得补上,才能完美对齐论文里的实现:

核心修改验证与细节补充

1. 损失函数的正确性

你提到的损失修改逻辑完全契合论文里基于优化的L2约束对抗样本生成方法,对应论文里的目标函数:

最小化「模型对扰动后样本的交叉熵损失 + c × 扰动r的L2范数」
这里的c是权衡分类损失和扰动大小的超参数,论文里用了0.01、0.1这类量级,你可以先从小值试起,根据任务调整。

代码上的标准实现应该是这样:

# 初始化可学习的扰动r,和输入同形状,开启梯度追踪
r = torch.zeros_like(inputs, requires_grad=True)
# 给r单独配优化器,选Adam或者SGD都可以,学习率建议从小值开始
optimizer = torch.optim.Adam([r], lr=1e-3)

# 生成扰动后的输入
perturbed_inputs = inputs + r

# 计算总损失
outputs = model(perturbed_inputs)
ce_loss = torch.nn.CrossEntropyLoss()(outputs, labels)
l2_reg = c * torch.norm(r, p=2)
total_loss = ce_loss + l2_reg

# 反向传播更新r
optimizer.zero_grad()
total_loss.backward()
optimizer.step()

2. 必须加上的扰动约束

论文里隐含了一个关键要求:扰动后的样本必须在合理的输入范围内(比如图像的01或0255像素值),所以每次更新r后,一定要做裁剪,不然生成的对抗样本可能完全脱离真实数据分布:

# 用torch.no_grad()避免计算裁剪步骤的梯度
with torch.no_grad():
    # 假设你的输入是归一化到0~1的图像
    clamped_perturbed = torch.clamp(inputs + r, 0.0, 1.0)
    # 更新r,确保扰动后输入合法
    r.copy_(clamped_perturbed - inputs)

3. 别搞混:论文里还有FGSM快速方法

如果你想复现论文里更知名的FGSM(快速梯度符号法),那方法就完全不同了——它不需要迭代优化r,直接用损失对输入的梯度符号乘以步长ε就能生成扰动:

# 开启输入的梯度追踪
inputs.requires_grad = True
outputs = model(inputs)
loss = torch.nn.CrossEntropyLoss()(outputs, labels)
loss.backward()

# 生成FGSM扰动,ε是步长,论文里用0.1左右
epsilon = 0.1
r_fgsm = epsilon * torch.sign(inputs.grad.data)
# 裁剪到合法范围
perturbed_inputs_fgsm = torch.clamp(inputs + r_fgsm, 0.0, 1.0)

这种方法速度快,不需要迭代,也是论文里的核心方法之一,你可以根据需求选。

4. 容易踩坑的小细节

  • 确保r是可学习参数(设置requires_grad=True),并且被正确加入优化器——这就是你说的“纳入优化器相关流程”的核心。
  • 如果是做对抗训练(用对抗样本训练模型),要注意不要把r的梯度传到模型参数上,可以用perturbed_inputs.detach()切断梯度;如果只是生成对抗样本测试鲁棒性,固定模型参数只优化r就行。
  • 论文是在MNIST上做的实验,换其他数据集的话,记得调整超参数(比如c、学习率、ε)。

内容的提问来源于stack exchange,提问作者Charlie Parker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:37:13