对抗样本攻击(四)对抗训练

第 7 天日志:对抗样本攻击(四)对抗训练

项目 内容
模块 模块二 对抗样本攻击
进度 第 7 天 / 共 10 天
数据集 MNIST
模型 MNISTCNN(多种对抗训练变体)

一、任务目标

  1. 理解对抗训练的理论基础与 Min-Max 优化框架;
  2. 掌握 PGD 对抗训练与 TRADES 正则化训练及超参数选择;
  3. 评估对抗训练防御效果,分析鲁棒性与清洁精度的权衡;
  4. 用自适应攻击(更强 PGD、C&W、迁移攻击)检验防御边界与薄弱环节;
  5. 设计综合性对抗防御体系。

二、实验原理

2.1 Min-Max 优化框架(Madry et al., 2018)

对抗训练求解一个 Min-Max 问题:内层最大化损失(找最强对抗样本),外层

最小化损失(训练模型在该对抗样本上分类正确):

min⁡θ  E(x,y)max⁡∥δ∥∞≤εL(fθ(x+δ),y) \min_\theta \; \mathbb{E}_{(x,y)} \Big \\max_{\\\|\\delta\\\|_\\infty \\le \\varepsilon} \\mathcal{L}\\big(f_\\theta(x+\\delta), y\\big) \\Big θminE(x,y)∥δ∥∞≤εmaxL(fθ(x+δ),y)

内层用 PGD 近似求解("PGD 攻击是通用的一阶攻击",内层越强、外层鲁棒性越好)。

2.2 TRADES(Zhang et al., 2019)

TRADES 显式分解"自然误差"与"边界误差",用 KL 散度正则化:

min⁡θ  EL(fθ(x),y)+β⋅KL(fθ(x) ∥ fθ(xadv)) \min_\theta \; \mathbb{E} \big \\mathcal{L}(f_\\theta(x), y) + \\beta \\cdot \\mathrm{KL}\\big(f_\\theta(x) \\,\\\|\\, f_\\theta(x_{adv})\\big) \\big θminEL(fθ(x),y)+β⋅KL(fθ(x)∥fθ(xadv))

其中 xadvx_{adv}xadv 最大化 KL(fθ(x)∥fθ(x′))\mathrm{KL}(f_\theta(x) \| f_\theta(x'))KL(fθ(x)∥fθ(x′))。β 控制

"鲁棒性---清洁精度"的权衡强度。

2.3 自适应攻击

评估鲁棒模型必须用"自适应攻击"(针对防御机制专门设计):更强的 PGD(更多

迭代、随机重启)、C&W 优化攻击、迁移攻击等,避免高估防御效果。

2.4 对抗训练的理论基础:从 ERM 到鲁棒风险最小化

标准训练最小化经验风险(Empirical Risk Minimization, ERM):

min⁡θ  E(x,y)∼DL(fθ(x),y) \min_\theta \; \mathbb{E}_{(x,y)\sim \mathcal{D}} \big \\mathcal{L}(f_\\theta(x), y) \\big θminE(x,y)∼DL(fθ(x),y)

ERM 只优化"干净样本"上的损失,完全不约束边界附近的行为,因此学到的

边界可以紧贴数据点------模型"准确但不鲁棒"。对抗训练最小化鲁棒风险

(Robust Risk):

min⁡θ  E(x,y)max⁡∥δ∥∞≤εL(fθ(x+δ),y) \min_\theta \; \mathbb{E}_{(x,y)} \Big \\max_{\\\|\\delta\\\|_\\infty \\le \\varepsilon} \\mathcal{L}\\big(f_\\theta(x+\\delta), y\\big) \\Big θminE(x,y)∥δ∥∞≤εmaxL(fθ(x+δ),y)

鲁棒风险强迫边界与数据点保持至少 ε\varepsilonε 的距离。Tsipras et al.

(2019)证明了一个重要的不可能性结果:在数据类条件分布存在重叠(或特征

可分性不足)时,不存在一个模型能同时达到最优的干净精度与最优的鲁棒
精度
------鲁棒性与清洁精度之间存在内在权衡。本实验第 3.1 节的权衡曲线

正是该理论的实证表现。

2.5 PGD:通用的一阶攻击

Madry et al.(2018)的核心论断:能抵抗足够强 PGD 的模型,也基本抵抗
其他一阶攻击
。理由:

  • 对凸问题,带符号梯度的迭代投影收敛到全局最优;
  • 对深度网络(非凸),随机重启的 PGD 是对"一阶最优性"的经验近似;
  • 若内层攻击弱(步数少、无重启),模型实际只在"弱攻击"下鲁棒,会被
    更强的攻击穿透。

因此对抗训练的超参数关键是内层 PGD 的 ε、步数 T、步长 α:

  • T 太小 → 内层攻击弱 → 防御被"更聪明的攻击"绕过;
  • T 太大 → 训练成本线性上升(每步都需反向传播)。

本实验用 T=5 平衡成本与效果,并用第 3.2 节 T=50 + 3 次重启的自适应攻击

验证边界:对 PGD-AT 模型 PGD-20 与 PGD-50×3 的 ASR 几乎一致(2.0%),

说明 5 步训练已覆盖该类攻击的"主要脆弱方向"。

2.6 TRADES 的误差分解与 β 敏感性

TRADES 的理论出发点是"自然误差与对抗误差的分解"。记 fθf_\thetafθ 的自然
误差
为 Rnat(f)=P(f(x)≠y)\mathcal{R}_{nat}(f) = \mathbb{P}(f(x) \neq y)Rnat(f)=P(f(x)=y),对抗误差

Radv(f)=P(∃δ:f(x+δ)≠y)\mathcal{R}_{adv}(f) = \mathbb{P}(\exists \delta: f(x+\delta) \neq y)Radv(f)=P(∃δ:f(x+δ)=y)。

Zhang et al.(2019)证明对抗误差可被上界分解为两项之和:

Radv(f)≤Rnat(f)+Emax⁡∥δ∥≤εKL(f(x) ∥ f(x+δ)) \mathcal{R}{adv}(f) \le \mathcal{R}{nat}(f) + \mathbb{E}\big \\max_{\\\|\\delta\\\|\\le\\varepsilon} \\mathrm{KL}\\big(f(x) \\,\\\|\\, f(x+\\delta)\\big) \\big Radv(f)≤Rnat(f)+E∥δ∥≤εmaxKL(f(x)∥f(x+δ))

第二项称为边界误差 :衡量"在扰动球内模型输出的不稳定程度"。TRADES

直接最小化这两项(用 KL 正则化逼近内层 max),因此比"只在对抗点监督

标签"的 PGD-AT 更精细地控制了边界形状。

β 是两类误差的相对权重:β 过小近似 PGD-AT;β 过大则 KL 项主导,模型趋向

输出恒定分布("什么都一样"),训练崩溃------本实验 β=6 在 6 轮训练预算下

退化为均匀预测(干净精度 48.4%)即为该机制的极端表现。实际中 β 应与训练

轮数、学习率联合调节(原论文使用 100 轮 + 步长调度)。

补充要点(来自原理补充版本):

记自然误差 Rnat(f)=P(f(x)≠y)\mathcal{R}_{nat}(f) = \mathbb{P}(f(x) \neq y)Rnat(f)=P(f(x)=y),对抗误差

Radv(f)=P(∃δ:f(x+δ)≠y)\mathcal{R}_{adv}(f) = \mathbb{P}(\exists \delta: f(x+\delta) \neq y)Radv(f)=P(∃δ:f(x+δ)=y)。

Zhang et al.(2019)证明对抗误差可被分解上界:

Radv(f)≤Rnat(f)+Emax⁡∥δ∥≤εKL⁡(f(x),∥,f(x+δ)) \mathcal{R}{\mathrm{adv}}(f) \le \mathcal{R}{\mathrm{nat}}(f) + \mathbb{E}\Big \\max_{\\lVert\\delta\\rVert\\le\\varepsilon} \\operatorname{KL}\\big(f(x),\\Vert,f(x+\\delta)\\big) \\Big Radv(f)≤Rnat(f)+E∥δ∥≤εmaxKL(f(x),∥,f(x+δ))

第二项称边界误差 :衡量扰动球内模型输出的不稳定程度。TRADES 直接

最小化这两项(KL 正则化逼近内层 max),比"只在对抗点监督标签"的 PGD-AT

更精细地控制边界形状。

β 是两类误差的相对权重:

  • β 过小 → 近似 PGD-AT;
  • β 过大 → KL 项主导,模型趋向输出恒定分布("对什么都一样"),训练崩溃。

本实验 β=6 在 6 轮训练预算下退化为均匀预测(干净精度仅 48.4%),β=3 则

正常收敛(干净 98.43%、鲁棒 95.5%)------定量演示了 β 的敏感性。原论文

β=6 需要 100 轮训练 + 学习率调度,说明超参数必须与训练预算联合调节。

2.7 自适应攻击与鲁棒性评估方法学

"评估攻击是否自适应"是鲁棒性研究的方法学核心:

  • 静态攻击 (固定 ε 的 PGD)可能只是"碰巧没找到"对抗样本,而非模型
    真的鲁棒;
  • 自适应攻击 针对防御的具体机制设计:知道对抗训练用的 ε 就用更大 ε +
    更多迭代 + 随机重启;知道是 PGD-AT 就尝试 C&W(不同范数/不同目标
    函数);知道有预处理就尝试"端到端"优化整个管线;
  • AutoAttack (Croce & Hein, 2020)把 4 种互补攻击(APGD-CE、APGD-DLR、
    FAB、Square)组合为标准化评估套件,是目前鲁棒性基准的事实标准。

本实验用 PGD-50×3、C&W、迁移攻击构成自适应集:结果显示 C&W 能攻破

PGD-AT(95--100%)而 TRADES β=3 对其最鲁棒(12%)------说明"单一攻击评估

会系统性高估防御",必须用攻击族交叉检验。


2.8 权衡曲线的实证解读

模型 清洁准确率 PGD(0.1) 鲁棒准确率
干净基线 98.83% 86.60%
PGD-AT(ε=0.1--0.3) 98.93--99.23% 96.60--97.80%
TRADES β=1 / β=3 98.70% / 98.43% 93.60% / 95.50%

规律:对抗训练把鲁棒性提升约 10 个百分点,代价是清洁精度损失 <0.4%;

训练 ε 越大,对大扰动攻击(ε=0.3)越鲁棒(PGD-AT ε=0.2 训练后 ε=0.3

攻击仅 7.5% vs ε=0.05 训练的 18%)------"在哪个预算上训练,就在哪个预算上

鲁棒"。这为工程选型提供了直接依据:防御预算应匹配威胁模型中的扰动上限。

2.9 实现要点与可复用代码

python 复制代码
# ① PGD 对抗训练(Min-Max)------内层攻击 + 外层更新
def pgd_ce(model, x, y, eps, alpha, iters):
    was_training = model.training          # ★ 保存训练模式
    model.eval()
    x_adv = torch.clamp(x + torch.empty_like(x).uniform_(-eps, eps), -3, 3)
    for _ in range(iters):
        x_adv = x_adv.clone().requires_grad_(True)
        F.cross_entropy(model(x_adv), y).backward()      # 内层 max
        x_adv = x_adv.detach() + alpha * x_adv.grad.sign()
        x_adv = torch.clamp(x + torch.clamp(x_adv - x, -eps, eps), -3, 3)
    model.train(was_training)              # ★ 必须恢复,否则 BN 统计被破坏
    return x_adv

for xb, yb in train_loader:
    x_adv = pgd_ce(model, xb, yb, eps, alpha, iters)
    loss  = F.cross_entropy(model(x_adv), yb)            # 外层 min
    optimizer.zero_grad(); loss.backward(); optimizer.step()

# ② TRADES 的正确 KL 方向(★ 本项目最隐蔽的坑)
#    目标:KL( f(x) || f(x_adv) ) = Σ_c f_c(x)·log[ f_c(x) / f_c(x_adv) ]
kl = F.kl_div(
        input  = F.log_softmax(logits_adv, dim=1),        # q = f(x_adv)
        target = F.softmax(logits, dim=1),                # p = f(x)
        reduction="batchmean")
loss = F.cross_entropy(logits, yb) + beta * kl
#    ✗ 错误写法:kl_div(log_softmax(logits), softmax(logits_adv.detach()))
#      方向反了且目标被 detach,β 越大越会把模型推向"输出均匀"的退化解

# ③ 自适应攻击组合(评估防御必须用)
attacks = {
    "PGD-20":       lambda m, x, y: pgd(m, x, y, eps=0.1, alpha=0.02, iters=20),
    "PGD-50×3重启": lambda m, x, y: best_of_restarts(pgd, m, x, y, eps=0.1, iters=50, n=3),
    "PGD-ε0.3":     lambda m, x, y: pgd(m, x, y, eps=0.3, alpha=0.06, iters=30),
    "C&W":          lambda m, x, y: cw_l2_attack(m, x, y, iters=80),      # 换范数
    "迁移":         lambda m, x, y: pgd(surrogate, x, y, eps=0.1, iters=100),  # 换模型
}

对抗训练配置与预算(本项目实际使用)

方法 ε 内层步数 训练轮数 单模型耗时
PGD-AT 0.05/0.1/0.2/0.3 5 6 8--12 分钟
TRADES 0.1 5 6 8--12 分钟

2.10 常见误解、纠正与自测题

常见误解

  1. "对抗训练能防住所有攻击" → C&W 攻破全部 PGD-AT 模型(95%--100%);
    防御是"在某范数、某预算内"的。
  2. "PGD 迭代次数越多防御越好" → 内层步数决定防御质量,但 5 步与 50 步
    的自适应攻击差距不大;关键是训练时的 ε 覆盖威胁预算
  3. "TRADES 一定比 PGD-AT 好" → TRADES β=3 对 C&W 更鲁棒(12% vs 100%),
    但对 ε=0.3 的 PGD 更弱(34.5% vs 7.5%)------两者盲区不同,宜组合使用。
  4. "β 越大正则越强越好" → β=6 在短预算下训练崩溃(干净精度 48.4%);
    超参数必须与训练轮数、学习率联合调整。
  5. "换个攻击评估就行" → 必须针对防御机制设计自适应攻击
    本实验正是靠 C&W 才发现 PGD-AT 的范数盲区。
  6. "鲁棒性可以免费获得" → 对抗训练需要 5--10 倍训练成本(内层每次都要
    反向传播),工程上要权衡。

自测题(附答案要点)

  1. 写出 Min-Max 对抗训练目标,并说明内层用什么求解。
    要点 :min⁡θEmax⁡∥δ∥≤εL(fθ(x+δ),y)\min_\theta\mathbb{E}\\max_{\\\|\\delta\\\|\\le\\varepsilon} \\mathcal{L}(f_\\theta(x+\\delta),y)minθEmax∥δ∥≤εL(fθ(x+δ),y);内层用 PGD(多步符号梯度 + 投影)。
  2. TRADES 的误差分解定理说了什么?
    要点 :Radv≤Rnat+Emax⁡δKL(f(x)∥f(x+δ))\mathcal{R}{adv}\le\mathcal{R}{nat}+\mathbb{E}\\max_\\delta \\mathrm{KL}(f(x)\\\|f(x+\\delta))Radv≤Rnat+EmaxδKL(f(x)∥f(x+δ)),即对抗误差 ≤ 自然误差 + 边界误差,
    TRADES 显式最小化这两项。
  3. 为什么写错 KL 方向不会报错但会训练失败?
    要点 :把 f(x)f(x)f(x) 推向 f(xadv)f(x_{adv})f(xadv) 的退化解是"输出趋于均匀",
    损失正常下降(趋近 log C),准确率却停在随机水平。
  4. 内层攻击函数为什么必须恢复 train() 模式?
    要点eval() 是全局状态,会让 BatchNorm 使用固定统计量,破坏训练
    动力学(本项目 β=12 崩溃的第二个原因)。
  5. PGD-AT 模型对 C&W 为何如此脆弱?如何弥补?
    要点 :PGD-AT 只覆盖 L∞ 球,C&W 优化 L2 距离可找到未覆盖方向;
    可用 TRADES(边界平滑)或同时在多范数上训练来弥补。
  6. 评估一个防御方案时,最少需要哪些攻击?
    要点 :同类更强攻击(更多迭代/重启)、不同范数攻击(C&W)、
    迁移攻击,三者组合(理想情况用 AutoAttack 套件)。

三、实验结果

3.1 对抗训练模型对比(鲁棒性评估:PGD ε=0.1, 20 步)

模型 清洁准确率 鲁棒准确率
干净基线 98.83% 86.60%
PGD-AT ε=0.05 98.93% 96.60%
PGD-AT ε=0.10 98.93% 97.80%
PGD-AT ε=0.20 99.23% 97.80%
PGD-AT ε=0.30 99.03% 97.60%
TRADES β=1 98.70% 93.60%
TRADES β=3 98.43% 95.50%
TRADES β=6(未收敛) 48.40% 34.00%

3.2 自适应攻击测试(400 样本)

模型 PGD-20 PGD-50×3重启 PGD ε=0.3 C&W 迁移
干净基线 12.75% 14.25% 96.00% 100% 1.75%
PGD-AT ε=0.05 3.00% 3.00% 18.00% 100% 2.25%
PGD-AT ε=0.10 2.00% 2.00% 12.00% 100% 1.00%
PGD-AT ε=0.20 2.00% 2.00% 7.50% 100% 1.00%
PGD-AT ε=0.30 1.50% 1.50% 9.50% 95% 0.50%
TRADES β=1 4.75% 4.75% 51.00% 92% 2.00%
TRADES β=3 2.50% 2.75% 34.50% 12% 1.00%
TRADES β=6 66.00% 66.25% 86.50% 77% 51.75%


四、结果分析与讨论

4.1 鲁棒性---清洁精度权衡

  • PGD-AT 各 ε 下鲁棒准确率 96.6%--97.8%,清洁准确率 98.9%--99.2%,权衡
    损失很小(对比基线 86.6% 鲁棒);
  • 训练扰动 ε 越大,对大扰动攻击 (ε=0.3)的防御越强(7.5%--9.5% vs
    ε=0.05 训练的 18%),代价是清洁精度略降------体现了"在哪个扰动预算上
    训练,就在哪个预算上鲁棒"的规律;
  • TRADES 的 β 是敏感的旋钮:β=1 鲁棒 93.6%、β=3 鲁棒 95.5%;β=6 在本实验
    的短训练预算(6 轮)下完全不收敛(清洁 48.4%)------论文中 β=6 需要 100 轮
    训练。这直接演示了"超参数 + 训练预算"对对抗训练成败的决定性作用。

4.2 防御边界与薄弱环节

  • 更强 PGD 收益有限 :PGD-50×3 重启 vs PGD-20 的 ASR 几乎不变(如
    PGD-AT ε=0.2 都是 2.0%)------对抗训练的防御边界对"同类攻击强度"稳定;
  • C&W 是 PGD-AT 的薄弱点 :对 PGD-AT 模型攻击成功率 95%--100%!原因:
    PGD-AT 只在 L∞ 球内防御,而 C&W 优化的是 L2 扰动,可以找到 PGD-AT
    未覆盖的"低失真但有效"方向;
  • TRADES β=3 对 C&W 最鲁棒 (仅 12%):TRADES 通过 KL 正则化平滑了
    logit 边界,间接抵抗了 L2 优化攻击------说明不同对抗训练方法的防御
    "形状"不同,需要多种攻击联合评估;
  • 迁移攻击对鲁棒模型几乎无效 (0.5%--2.25%):对抗训练显著破坏了对抗
    样本的跨模型迁移性。

4.3 综合防御体系

结合第 4--7 天实验,综合防御体系:

  1. 对抗训练(主防御) :PGD-AT ε=0.2 + TRADES β=3 双模型,覆盖 L∞ 与
    L2 攻击面;
  2. 输入预处理:中值滤波去噪(第 6 天验证 PGD ASR 95.5%→41.5%);
  3. 模型集成:多模型投票(第 5 天);
  4. 认证防御:随机平滑提供可验证保证(第 6 天);
  5. 检测与监控:随机化一致性检测 + 查询限制(第 4--5 天);
  6. 持续审计:定期用 C&W 等高强度自适应攻击重新评估,防止"防御退化"。

4.4 理论预测 vs 实测数据

理论预测 实测结果 是否吻合
对抗训练大幅提升鲁棒性 PGD(0.1) 下:基线 86.60% → PGD-AT 96.60%--97.80%
代价是清洁精度小幅下降 98.83% → 98.93%--99.23%(部分配置甚至更高) ✅ 权衡很小
训练 ε 决定鲁棒预算 ε=0.3 攻击下:ε=0.05 训练 18.0% vs ε=0.2 训练 7.5%
TRADES 的 β 需与训练预算匹配 β=1/3 正常(干净 98.70%/98.43%);β=6 在 6 轮下仅 48.40%
更强同类攻击(更多迭代/重启)收益有限 PGD-20 vs PGD-50×3 对 PGD-AT 模型:均 2.0% ✅ 防御边界稳定
换范数攻击可突破 L∞ 训练 C&W(L2)对 PGD-AT:95%--100% ✅ 关键薄弱点
对抗训练破坏迁移性 迁移攻击对鲁棒模型仅 0.5%--2.25%

模型 × 攻击 ASR 矩阵(第 7 天核心数据)

模型 PGD-20 PGD-50×3 PGD(ε=0.3) C&W 迁移
干净基线 12.75% 14.25% 96.00% 100% 1.75%
PGD-AT ε=0.05 3.00% 3.00% 18.00% 100% 2.25%
PGD-AT ε=0.10 2.00% 2.00% 12.00% 100% 1.00%
PGD-AT ε=0.20 2.00% 2.00% 7.50% 100% 1.00%
PGD-AT ε=0.30 1.50% 1.50% 9.50% 95% 0.50%
TRADES β=1 4.75% 4.75% 51.00% 92% 2.00%
TRADES β=3 2.50% 2.75% 34.50% 12% 1.00%

五、试错与调试记录

5.1 问题速览

# 问题 类型 影响 解决方式
1 TRADES β=12 训练崩溃(9.9%) 代码+方法 模型完全失效 修正 KL 方向 + 恢复训练模式
2 修正后 β=6 仍未收敛(48.4%) 超参数 一个数据点不可用 补 β=3 并解释敏感性
3 自适应攻击脚本模型名不匹配 代码 绘图缺失数据 修正模型清单并续跑
4 6 个模型训练耗时 工程 单次全量约 70 分钟 模型缓存 + 断点续跑

5.2 问题 1:TRADES β=12 训练崩溃,验证准确率仅 9.9%

现象

TRADES 训练(β=12)过程中,验证准确率一直停留在 9.9%--10.8%

(10 类随机水平),损失稳定在约 1.92(接近 log⁡10≈2.30\log 10 \approx 2.30log10≈2.30),

即模型输出接近均匀分布,完全没有学到分类。

定位过程

  1. 对比 β=1 的实验(同结构、同轮数)能正常收敛到 98.7%,排除数据与模型

    结构问题;

  2. 检查 KL 项方向 :TRADES 的目标是

    KL(f(x) ∥ f(xadv))\mathrm{KL}\big(f(x)\,\|\,f(x_{adv})\big)KL(f(x)∥f(xadv)),而代码写成

    python 复制代码
    kl = F.kl_div(F.log_softmax(logits, 1),
                  F.softmax(logits_adv.detach(), 1))   # 方向反了

    kl_div(input, target) 计算的是 KL(target∥input)\mathrm{KL}(\text{target}\|\text{input})KL(target∥input),

    因此上式实际是 KL(f(xadv)∥f(x))\mathrm{KL}(f(x_{adv})\|f(x))KL(f(xadv)∥f(x)),且 f(xadv)f(x_{adv})f(xadv) 被

    detach,梯度只会把 f(x)f(x)f(x) 往 f(xadv)f(x_{adv})f(xadv) 方向推------方向与目标相反;

  3. 检查训练模式 :TRADES 内层生成对抗样本的函数开头调用了

    model.eval(),但没有恢复 train();由于该函数在训练循环内被调用,

    模型此后一直以 eval 模式训练,BatchNorm 使用固定统计量且不再更新,

    训练动力学被破坏。

根本原因

两个独立缺陷叠加:(a) KL 散度方向写反;(b) 内层攻击函数没有恢复模型的

训练模式。

解决方案

python 复制代码
# (a) 修正方向:KL(f(x) || f(x_adv))
kl = F.kl_div(F.log_softmax(logits_adv, 1),
              F.softmax(logits, 1), reduction="batchmean")

# (b) 内层攻击保存并恢复训练模式
was_training = model.training
model.eval()
...
model.train(was_training)

修正后 β=3 正常收敛(干净 98.43%、鲁棒 95.5%)。

为什么这样解决

  • KL 方向必须与理论一致,否则正则项把模型推向"输出模糊"的退化解
    (这正是 β 越大崩溃越彻底的原因);
  • 训练模式必须显式保存与恢复:model.eval()全局状态
    在训练循环中被调用后不恢复,会静默破坏后续所有批次。

可积累的经验

  • 使用 F.kl_div 时先写清"谁是谁的目标分布",方向错误是本项目中最隐蔽的
    bug 之一(不会报错,只会训练失败);
  • 任何在训练循环中被调用的"评估性质"函数,都要用
    was_training = model.training ... model.train(was_training) 模式;
  • 训练完全失效(准确率≈随机、损失≈log C)时,优先检查:损失方向、
    训练模式、标签对齐这三件事。

对本项目的作用

修正后 TRADES 成为可用方案,并产出关键结论"TRADES β=3 对 C&W 最鲁棒

(ASR 仅 12%)"------这是第 7 天最重要的防御发现。同时,"训练模式必须恢复"

被写入项目编码规范,第 8 天 DP-SGD、第 9 天提取脚本都据此检查。


5.3 问题 2:修正后 β=6 仍不收敛(超参数敏感性)

现象

修正 KL 方向后重训 β=6:验证准确率从 44% 缓慢升到 48.4% ,仍未收敛

(对照:β=1 达 98.70%、β=3 达 98.43%)。

定位过程

  1. 排除了代码问题(同一实现下 β=1、β=3 均正常);
  2. 分析目标函数:CE+β⋅KLCE + \beta\cdot KLCE+β⋅KL,β 越大 KL 项占比越高;
    在 KL 尚未收敛(模型输出仍不稳定)时,过大的 β 会让优化器优先压低 KL,
    而降低 KL 最快的方式是"输出变得更模糊/更均匀"------与分类目标冲突;
  3. 对照文献:TRADES 原文使用 β=6 但训练 100 轮 并配合学习率调度;
    本实验预算为 6 轮,属于"β 与训练预算不匹配"。

根本原因

超参数 β 与训练预算(轮数、学习率)不匹配,导致优化停留在"KL 优先"的

次优区域。

解决方案

  • 补做 β=3 实验点,使权衡曲线覆盖"收敛良好"的参数区间;
  • 在日志与报告中明确记录 β=6 未收敛的现象与原因,不隐藏、不伪造;
  • 给出实践建议:β 应与训练轮数联合调节,必要时采用学习率调度。

为什么这样解决

  • 保留失败数据点能揭示超参数敏感性,比"只报告成功参数"更有教学价值;
  • 补一个可用的中间点(β=3)保证权衡曲线的完整性(干净精度 vs 鲁棒性)。

可积累的经验

  • 对抗训练的超参数(ε、β、内层步数)必须与训练预算联合调优;
  • 复现论文超参数时要同时复现训练预算,否则结论不可比;
  • 失败数据点在报告中同样是有价值的证据,应保留并解释。

对本项目的作用

使第 7 天的权衡曲线包含"收敛良好(β=1、3)"与"未收敛(β=6)"两类点,

更真实地反映了超参数敏感性;这一经验也被第 10 天总结报告采纳为

"对抗训练的工程注意事项"。


5.4 问题 3:自适应攻击脚本引用了已改名的模型

现象

自适应攻击脚本运行日志出现:

复制代码
[WARN] 模型不存在: trades_beta12

结果 JSON 中缺少该项,绘图时该模型的柱子缺失。

定位过程

脚本的模型清单里保留了旧名字 trades_beta12(在问题 1 修复过程中,

该配置已改名为 trades_beta6,并新增了 trades_beta3);而磁盘上已无

对应权重文件。

根本原因

配置改名后,引用清单未同步更新(典型的"配置漂移")。

解决方案

修正模型清单为

[clean_baseline, pgd_at_eps005/010/020/030, trades_beta1/3/6]

重跑脚本;由于所有模型权重已缓存,重跑仅耗时约 4.5 分钟(含自适应攻击

评估),未重新训练。

为什么这样解决

  • 治本是让"脚本引用的模型名"与"实际训练产物名"保持一致;
  • 依托前几天的缓存机制,修复代价很小;若在早期(无缓存),这一处疏忽
    会导致 70 分钟重训。

可积累的经验

  • 模型/产物命名应集中定义(如统一的配置表),避免多处硬编码;
  • 脚本启动时校验所需产物是否存在 并给出清晰告警(本次 WARN 起到了
    保护作用,避免了静默出错);
  • 缓存机制不仅能省时间,也能显著降低"配置漂移"的修复成本。

对本项目的作用

促成了本项目"配置集中 + 启动校验 + 缓存复用"的组合做法,在第 8、9 天

的多模型实验中有效避免了"缺一个模型导致整图缺失"的问题。


5.5 问题 4:6 个对抗训练模型的全量训练耗时约 70 分钟

现象(工程挑战而非缺陷)

PGD-AT(ε=0.05/0.1/0.2/0.3)与 TRADES(β=1/3/6)合计 6 个模型,

单个模型 6 轮训练约 8--12 分钟,全量约 70 分钟;期间任何一次崩溃都会

造成大段损失。

解决方案

  1. 每个模型训练完立即 torch.save 权重并写入结果 JSON(增量保存);
  2. 脚本开头做"权重存在则加载"的续跑判断;
  3. 复用第 4 天已训练的 PGD-AT ε=0.1 模型(避免重复训练);
  4. 先跑单模型验证实现(KL 方向、训练模式),再批量训练其余模型。

为什么这样解决

  • 训练是最昂贵的环节,必须"一次训练、多次使用";
  • 先验证再批量,避免"6 个模型全部训错"的最坏情况(问题 1 正是先在
    一个模型上暴露出来的)。

可积累的经验

  • 批量实验前用最小可复现单元(单个模型)验证实现正确性;
  • 增量落盘 + 续跑 + 复用已有产物,是长实验的三件套;
  • 训练计划要标出"可复用资产"(如第 4 天的 ε=0.1 模型),避免重复劳动。

对本项目的作用

该策略使第 7 天在修复 β 配置后,只需补训 1--2 个模型而非全部重训;

最终产出的 6 个模型也成为第 6 天认证防御、第 10 天总结分析的基础资产。


5.6 复现与验证速查

复现问题 1:KL 方向写反 + 训练模式未恢复

第一步:确认 KL 方向

python 复制代码
# ✓ 正确:KL( f(x) || f(x_adv) ) ------ 以 f(x_adv) 为 q(input)、f(x) 为 p(target)
kl_ok = F.kl_div(F.log_softmax(logits_adv, 1), F.softmax(logits, 1),
                 reduction="batchmean")

# ✗ 错误(本项目最初的写法):方向反了且 target 被 detach
kl_bad = F.kl_div(F.log_softmax(logits, 1), F.softmax(logits_adv.detach(), 1),
                  reduction="batchmean")

第二步:确认训练模式是否恢复

python 复制代码
was_training = model.training      # 训练循环中应为 True
model.eval()                       # 内层攻击需固定 BN 统计
# ... 生成对抗样本 ...
print(model.training)              # ✗ 若仍为 False,说明忘记恢复
model.train(was_training)          # ✓ 恢复

第三步:用验证曲线确认修复

配置 验证准确率曲线 最终干净准确率 鲁棒准确率
修复前(方向反 + eval 未恢复) 停在 9.9%--10.8% 9.90% 11.60%
修复后 β=3 1 轮 96.2% → 6 轮 98.4% 98.43% 95.50%

判读 :准确率≈随机、损失≈log 10(2.30)时,按顺序检查"损失方向 →

训练模式 → 标签对齐"三件事。

复现问题 2:β 与训练预算的匹配关系
python 复制代码
for beta in [1.0, 3.0, 6.0]:
    model = train_trades(build_model(), train_loader, val_loader,
                         epochs=6, beta=beta, eps=0.1, alpha=0.02, iters=5)
    print(beta, evaluate(model, val_loader)["accuracy"])
# 1.0 → 0.9870   3.0 → 0.9843   6.0 → 0.4840(未收敛)
β 训练轮数 干净准确率 鲁棒准确率 结论
1 6 98.70% 93.60% 可用
3 6 98.43% 95.50% 可用(权衡最佳)
6 6 48.40% 34.00% 未收敛(论文需约 100 轮)
复现问题 3:配置漂移的发现与修复
text 复制代码
[WARN] 模型不存在: trades_beta12
python 复制代码
# 修复:模型清单集中定义 + 启动时逐一校验
MODELS = ["clean_baseline", "pgd_at_eps005", "pgd_at_eps010", "pgd_at_eps020",
          "pgd_at_eps030", "trades_beta1", "trades_beta3", "trades_beta6"]
missing = [m for m in MODELS if not ckpt_path(m).exists()]
assert not missing, f"缺少模型权重: {missing}"

修复验证 :重跑自适应攻击仅 4.5 分钟(模型全部命中缓存),并补齐

trades_beta3 的结果行。

本日排错速查

text 复制代码
训练不收敛(准确率≈随机、损失≈log C)时的排查顺序:
  ① KL 方向:kl_div(input=log_softmax(q), target=softmax(p)) 中的 p/q 是否写对
  ② 训练模式:eval() 之后是否 train(was_training)
  ③ 标签对齐:内层攻击的标签与数据标签是否一致
  ④ 超参数:β 与 epochs 是否匹配(β 越大越需要更多轮)
  ⑤ 产物:启动时校验缺失的模型权重,避免静默缺数据

六、经验提炼

6.1 知识收获与心得

  1. 对抗训练的本质是"用攻击者的最强工具训练自己",Min-Max 框架是攻防
    统一的数学语言;
  2. 鲁棒性与清洁精度的权衡客观存在,但通过超参数可以调整到可接受区间;
  3. "防御有效性"必须用自适应攻击检验:PGD-AT 在 PGD 下 97.8% 鲁棒,却
    被 C&W 几乎完全攻破------单一的防御评估会高估安全性;
  4. 不同防御方法补足了彼此的盲区(PGD-AT 抗 L∞、TRADES 抗 L2),组合
    防御才是工程实践的正解。

6.2 工程与排错经验

  1. KL 方向不能想当然kl_div(input, target) 计算的是
    KL(target∥input)\mathrm{KL}(\text{target}\|\text{input})KL(target∥input),写反不报错但训练失败;
  2. 训练模式是全局状态eval() 之后必须恢复 train()
  3. 超参数要与训练预算匹配:β 大 + 轮数少 = 不收敛,失败点也要记录;
  4. 配置集中 + 启动校验:模型改名后引用清单必须同步,否则静默缺数据;
  5. 先单模型验证,再批量训练:把最坏情况的损失控制在一个模型内。

相关推荐
Rocky Ding*2 小时前
【三年面试五年模拟】阿里巴巴-千问技术部算法一面全解析
论文阅读·人工智能·深度学习·机器学习·aigc·ai-native·ai agent
xx_xxxxx_2 小时前
论文阅读-REINFORCE++与Lessons of Developing PRMs
人工智能·深度学习·机器学习·强化学习
古希腊掌管代码的神THU2 小时前
【清华代码熊】DeepSeek-V4.1-Flash 多模态架构解析
人工智能·深度学习·机器学习·自然语言处理·面试
m0_547486662 小时前
《Python数据分析与实践》全套PPT课件(杭州电子科技大学)
python·数据分析
residual_fan3 小时前
航空发动机故障诊断专用智能体(一):小样本与高不平衡下的工程挑战
人工智能·数据挖掘·数据分析
tellmewhoisi3 小时前
机器学习:线性回归4(欠拟合,正好拟合,过拟合)
机器学习
人邮异步社区3 小时前
入门机器学习从理论开始还是从实战开始?
人工智能·深度学习·机器学习
residual_fan4 小时前
航空发动机故障诊断专用智能体(三):基于对比学习的时序特征区分方法
人工智能·算法·数据挖掘·数据分析
梦想的初衷~4 小时前
AI赋能生态遥感:Python无人机三维建模、特征融合与机器学习建模全流程
机器学习·无人机遥感·土地利用分类·生态三维建模·python生态建模·ai遥感·碳储量估算