用foolbox快速运行pgd攻击:先确保模型输出logits、输入归一化到[0,1],调用fb.pytorchmodel(model,bounds=(0,1))和fb.attacks.projectedgradientdescent(),再执行attack(fmodel,images,labels,epsilons=8/255)。

怎么用 foolbox 快速跑一个对抗样本攻击
直接上手最常用的白盒攻击,比如 ProjectedGradientDescent(PGD),它对 PyTorch/TensorFlow 模型兼容好、收敛稳,适合快速验证鲁棒性缺口。
关键不是调参多精细,而是先让攻击“动起来”,确认模型真能被扰动误导。
- 确保模型输出是未归一化的 logits(不是 softmax 后概率),
foolbox默认按 logits 计算梯度 - 输入张量必须是
[0, 1]归一化范围(不是 [-1, 1] 或 ImageNet 标准化),否则攻击方向会偏 - 别跳过
model.eval()和torch.no_grad()—— 训练模式下 BatchNorm/ Dropout 会导致攻击结果不可复现 - 示例片段:
import foolbox as fb<br>fmodel = fb.PyTorchModel(model, bounds=(0, 1))<br>attack = fb.attacks.ProjectedGradientDescent()<br>_, advs, success = attack(fmodel, images, labels, epsilons=8/255)
FGSM 为什么经常“打不中”,以及什么时候该换别的攻击
FGSM 是单步攻击,只走一次梯度方向,对很多现代模型(尤其是加了 BN 或用了 ReLU6 的)几乎无效——不是你写错了,是它本身太弱。
- 如果
success返回全是False,先别怀疑数据预处理,直接换PGD或DeepFool -
FGSM对 ResNet 类模型的攻击成功率常低于 5%,但对浅层 CNN 可能达 40%+,说明它测的是“最粗粒度脆弱性”,不是真实鲁棒下限 - 它不迭代、不裁剪中间扰动,所以
eps设大了容易溢出(如16/255导致像素值超 [0,1]),必须手动 clip
测试时要不要关掉 Dropout 和 BatchNorm
要,而且必须显式关。对抗攻击依赖确定性梯度,而 Dropout 和训练态 BatchNorm 会让每次前向结果抖动,导致攻击失败或扰动不收敛。
-
model.eval()能关Dropout和BatchNorm的训练行为,但注意:有些自定义 BN 层可能没遵循这个协议,得手动设bn.training = False - 如果模型里嵌了
torch.nn.functional.dropout这种函数式调用,eval()不起作用,得临时 patch 或重构 - 漏关
BatchNorm的典型现象:同一张图多次攻击,生成的advs完全不同,且success波动剧烈
对抗样本保存后加载再测,准确率突然回升?
大概率是图像读写过程破坏了扰动精度——PNG 压缩、PIL 默认转 uint8 再读回 float,会四舍五入丢掉 1~2 个 LSB,而对抗扰动本身就在 1~3/255 量级。
立即学习“Python免费学习笔记(深入)”;
- 保存时用
np.save或torch.save存原始 tensor,别用cv2.imwrite或PIL.Image.save - 如果非得存图片,用无损格式(TIFF)、禁用压缩,并指定
dtype=np.float32保存,读取时也保持 float 精度 - 加载后立刻检查:
torch.allclose(saved_advs, loaded_advs, atol=1e-5),不通过就说明精度已失
对抗测试真正难的不是跑通攻击,而是确保每一步数值路径都可控——从模型 forward 的确定性,到 tensor 保存加载的 bit 级一致,漏掉任何一环,测出来的“鲁棒性”就是假阳性。








