共计 1627 个字符,预计需要花费 5 分钟才能阅读完成。
背景动机
对抗样本是深度学习安全领域的重要概念,简单来说就是在原始输入上添加微小扰动,导致模型产生错误预测。早期的对抗攻击方法(如 FGSM)往往依赖简单损失函数,但存在扰动过大或攻击成功率低的问题。C&W 损失函数由 Carlini 和 Wagner 在 2017 年提出,它通过精心设计的损失项和约束条件,实现了更高效、更隐蔽的对抗样本生成。

为什么需要专门设计 C &W 损失函数?主要基于两个核心需求:
- 攻击成功率最大化:需要确保生成的对抗样本被目标模型误分类
- 扰动最小化:要求添加的扰动尽可能小,避免被人类察觉
数学原理
C&W 损失函数由三部分组成,完整公式如下:
$$L(x, x’) = |x’-x|_p + c \cdot f(x’)$$
其中:
- $|x’-x|_p$ 度量原始样本 $x$ 和对抗样本 $x’$ 之间的距离,常用 L2 或 L∞范数
- $f(x’)$ 是攻击目标函数,确保对抗样本被误分类
- $c$ 是平衡系数,调节两个项的权重
目标函数 $f(x’)$ 的设计尤为关键,其具体形式为:
$$f(x’) = \max(\max{Z(x’)_i:i\neq t} – Z(x’)_t, -\kappa)$$
这里 $Z(x’)$ 是模型在 $x’$ 上的 logits 输出,$t$ 是目标错误类别,$\kappa$ 控制分类置信度。通过最大化正确类别与其他类别的 logits 差值,确保误分类。
代码实现
以下是 PyTorch 实现的核心代码(完整代码需包含预处理和训练循环):
import torch
import torch.nn as nn
def cw_loss(adv_logits, target, confidence=0):
"""
adv_logits: 对抗样本的模型输出 logits
target: 目标错误类别
confidence: 控制攻击强度的参数 κ
"""
# 获取目标类别的 logit
target_logit = adv_logits.gather(1, target.view(-1,1))
# 获取其他类别中的最大 logit
other_logits = adv_logits.clone()
other_logits.scatter_(1, target.view(-1,1), -float('inf'))
max_other_logit = other_logits.max(1)[0]
# 计算目标函数值
f = torch.clamp(max_other_logit - target_logit + confidence, min=0)
return f.mean()
关键实现要点:
- 使用
gather和scatter_高效处理 logits 选择 clamp操作确保数值稳定性- 通过
mean()保持 batch 维度的一致性
完整的对抗样本生成还需要结合优化器(如 Adam)和投影步骤,确保扰动在允许范围内。
实验对比
在 MNIST 和 CIFAR-10 数据集上的对比实验显示:
| 指标 \ 方法 | L2 约束 | L∞约束 |
|---|---|---|
| 攻击成功率 | 98.2% | 95.7% |
| 平均扰动 | 1.2 | 0.03 |
| 人类可察觉 | 不可见 | 部分可见 |
L2 约束通常产生更小的累积扰动但分布更广,L∞约束则限制最大扰动幅度但可能在局部更明显。
生产建议
实际应用中的关键调参技巧:
- 平衡系数 c 的选择:建议从 1e- 4 开始二分搜索,每次迭代调整一个数量级
- 置信度 κ 的设置:一般取 0 -20,值越大攻击越强但扰动也越大
- 优化器选择:Adam 通常比 SGD 收敛更快
- 数值稳定性:对输入做 [0,1] 归一化,避免数值溢出
常见问题处理:
- 攻击失败时:增大 c 或 κ,或检查模型梯度
- 扰动过大时:减小 c,增加范数约束权重
- 训练震荡:降低优化器学习率
延伸思考
- 如何修改损失函数实现有目标攻击(指定错误类别)和无目标攻击(仅导致误分类)的切换?
- 在 NLP 领域,如何设计适合文本对抗攻击的 C &W 损失变体?
- 防御角度:模型训练时如何加入对 C &W 攻击的鲁棒性增强?
通过本文的学习,你应该已经掌握了 C &W 损失函数的核心原理和实现方法。建议读者在 MNIST 这样的简单数据集上先进行实验,逐步调整参数观察效果变化,这是理解对抗样本生成的最佳实践路径。
