对抗样本基础
对抗样本基础
本文适合
已经理解 模型文件与推理流程,并需要让分类器在扰动约束内输出错误类别的学习者。学完你能:复现模型预处理,判断白盒/黑盒攻击条件,用 FGSM/PGD 生成对抗样本,并用评分脚本验证扰动、格式和目标类别
一句话判断
如果题目要求“输入看起来几乎不变,但模型输出变成指定类别或错误类别”,就是对抗样本题。
对抗样本不是随机加噪声,而是在约束范围内把输入推过模型决策边界。
题目中常见信号
说明:白盒攻击概率高
第一反应:先复现本地推理
说明:黑盒攻击或迁移攻击
第一反应:收集输出信息量
说明:有扰动约束
第一反应:先写验证函数
说明:targeted attack
第一反应:loss 要朝目标类别优化
说明:预处理或保存格式不一致
第一反应:保存后重读再推理
说明:不能粗暴改图
第一反应:控制范数和像素范围
核心概念
常见攻击类型:
条件:有模型和梯度
目标:一步扰动,快速验证
条件:有模型和梯度
目标:多步迭代,成功率更高
条件:只能访问 API
目标:用查询估计方向或训练替代模型
条件:有相似模型
目标:在替代模型生成样本,提交给目标模型
条件:可以添加局部贴片
目标:局部扰动触发错分类
约束通常包括:
- 像素范围:
[0,1]或[0,255]。 - 扰动范数:
Linf <= eps、L2 <= eps或改动像素数限制。 - 输入尺寸、格式、通道顺序不能变。
- 目标类别必须匹配题目要求。
最小分析流程
- 复现推理:用样例输入得到和远程一致的 label/logits。
- 写约束检查:先检查
Linf/L2、尺寸、范围、保存后像素变化。 - 选攻击模式:有梯度用 FGSM/PGD;只有 API 用查询/迁移。
- 先做小步验证:看目标类别概率是否朝正确方向变化。
- 保存后重读:PNG/JPEG 编码会改变像素,必须重新推理。
- 跑评分脚本:以题目脚本为准,不只看本地预测。
最小验证示例
扰动约束检查
import torch
def check_linf(original, adv, eps):
delta = (adv - original).abs()
print("linf", float(delta.max()))
print("l2", float(delta.flatten().norm(p=2)))
print("range", float(adv.min()), float(adv.max()))
return delta.max() <= eps and adv.min() >= 0 and adv.max() <= 1先写这个函数,再写攻击代码。否则很容易本地误分类但提交不合格。
FGSM 最小验证
import torch
import torch.nn.functional as F
def fgsm(model, x, y, eps):
model.eval()
x0 = x.detach()
x = x0.clone().requires_grad_(True)
loss = F.cross_entropy(model(x), y)
loss.backward()
adv = torch.clamp(x + eps * x.grad.sign(), 0, 1)
return adv.detach()
with torch.no_grad():
print("before", model(x).argmax(1).item())
adv = fgsm(model, x, y, eps=8/255)
with torch.no_grad():
print("after", model(adv).argmax(1).item())
print(check_linf(x, adv, 8/255))PGD 目标攻击骨架
def pgd_targeted(model, x, target, eps=8/255, alpha=2/255, steps=40):
x0 = x.detach()
adv = x0.clone()
for _ in range(steps):
adv.requires_grad_(True)
loss = F.cross_entropy(model(adv), target)
loss.backward()
adv = adv - alpha * adv.grad.sign()
adv = torch.max(torch.min(adv, x0 + eps), x0 - eps)
adv = torch.clamp(adv.detach(), 0, 1)
return adv目标攻击是让目标类别 loss 下降,所以更新方向和非目标攻击相反。
常见利用 / 解题路线
路线总览:
路线一:白盒图像分类
- 按 模型文件与推理流程 复现样例。
- 用 FGSM 验证梯度方向有效。
- 切到 PGD 提高成功率。
- 保存 PNG 后重新读取,确认仍满足目标类别和范数。
路线二:黑盒迁移
- 用公开模型或自己训练替代模型。
- 在替代模型上生成对抗样本。
- 提交给目标 API,记录置信度变化。
- 根据反馈调整 eps、目标类别和预处理。
路线三:文本对抗
- 先确认模型按字符、词还是 token 处理。
- 尝试同义词、空格、Unicode、大小写、标点。
- 用 Tokenizer安全 验证 token 切分差异。
- 保持语义不变的同时改变分类结果。
路线四:对抗 patch
- 确认题目允许局部区域变化。
- 固定 patch 位置或随机增强训练 patch。
- 验证不同背景下是否稳定触发目标类别。
- 提交前检查 patch 面积和像素范围。
常见失败原因
可能原因:预处理不一致
排查动作:对齐 resize、crop、mean/std、RGB/BGR
可能原因:编码改变像素
排查动作:保存后重读再推理,优先用 PNG
可能原因:没有投影回 eps 球
排查动作:每步 clamp 到 x0 +/- eps
可能原因:loss 方向写反
排查动作:目标攻击最小化 target loss
可能原因:eps 太大或范围错
排查动作:确认 [0,1] 和 [0,255] 单位
迷你案例
题目给 model.pth、cat.png 和评分脚本,要求输出类别变成 dog,且 Linf <= 8/255。
先用题目推理脚本确认 cat.png -> cat。写 check_linf 后,用 FGSM 发现类别仍是 cat,但 dog 概率上升。改用 targeted PGD,40 步后本地输出 dog。保存为 PNG 后重新读取,发现仍是 dog 且 linf=0.0313 小于 8/255。
最终 WP 应保留:原始预测、目标类别、eps、攻击代码、保存后重读结果、评分脚本通过截图或输出。