对抗样本与鲁棒评估:从 FGSM 公式到 scikit-learn 数字分类实验
对抗样本与鲁棒评估:从 FGSM 公式到 scikit-learn 数字分类实验
站内搜索
直接问 AI

对抗样本与鲁棒评估:从 FGSM 公式到 scikit-learn 数字分类实验

给一张图片加上人眼完全看不出的扰动,分类器就会把熊猫判成长臂猿——这个例子被引用了无数次,但它真正说明的事情常常被忽略:那个扰动不是随机噪声,是算出来的。攻击者沿着模型自己的梯度方向走,找的正是让损失上升最快的那个方向,所以很小的改动就能造成很大的影响。

本文解构了基于梯度的攻击(FGSM 和 PGD)的数学框架,为红队提供了基于 PyTorch 的实现脚本,并详细探讨了对抗防御所需的生产级流水线架构。

一、威胁模型的数学边界

如果不定义攻击者的可行集,对抗性评估在数学上毫无意义。威胁模型由以下参数定义:

  • 攻击者知识:白盒(完全访问 \( \theta \)、架构以及梯度 \( \nabla_x J \))对比 黑盒(通过查询进行零阶优化)。
  • 扰动约束(\( L_p \) 范数):扰动 \( \delta \) 受到 \( \|\delta\|_p \le \epsilon \) 的限制。常见的范数包括 \( L_\infty \)(最大像素变化)和 \( L_2 \)(欧几里得距离)。
  • 目标函数:无目标攻击(\( \arg\max_\delta J(\theta, x+\delta, y) \))对比 有目标攻击(\( \arg\min_\delta J(\theta, x+\delta, y_{target}) \))。

二、快速梯度符号法 (FGSM)

FGSM 是一种基于梯度的单步攻击,它在输入 \( x \) 附近对损失函数 \( J \) 进行线性化。利用一阶泰勒展开,攻击者在 \( L_\infty \) 约束下最大化损失。

数学公式如下:

\[ \delta = \epsilon \cdot \text{sign}(\nabla_x J(\theta, x, y)) \]

\[ x_{adv} = \text{clip}(x + \delta, x_{min}, x_{max}) \]

PyTorch FGSM 实现

import torch
import torch.nn as nn

def fgsm_attack(model, images, labels, epsilon, criterion):
    images.requires_grad = True
    outputs = model(images)
    loss = criterion(outputs, labels)
    
    # 计算关于输入的雅可比矩阵/梯度
    model.zero_grad()
    loss.backward()
    data_grad = images.grad.data
    
    # 构建扰动
    sign_data_grad = data_grad.sign()
    perturbed_images = images + epsilon * sign_data_grad
    
    # 投影回有效的输入域 (例如 [0, 1])
    perturbed_images = torch.clamp(perturbed_images, 0, 1)
    return perturbed_images

三、投影梯度下降 (PGD)

虽然 FGSM 计算效率高,但它对对抗目标的拟合不足。投影梯度下降(PGD)是一种通用的一阶对抗攻击。它通过迭代的梯度步长解决约束优化问题,并在每一步后将扰动投影回 \( \epsilon \)-球内。

第 \( t+1 \) 步的更新规则为:

\[ x^{t+1} = \Pi_{x+\mathcal{S}} \left( x^t + \alpha \cdot \text{sign}(\nabla_x J(\theta, x^t, y)) \right) \]

其中 \( \alpha \) 是步长,\( \Pi_{x+\mathcal{S}} \) 是向 \( L_p \) 球的投影算子。

PyTorch PGD 实现

def pgd_attack(model, images, labels, epsilon, alpha, iters, criterion):
    perturbed_images = images.clone().detach()
    # 在 epsilon 球内随机初始化
    perturbed_images = perturbed_images + torch.empty_like(perturbed_images).uniform_(-epsilon, epsilon)
    perturbed_images = torch.clamp(perturbed_images, 0, 1)
    
    for _ in range(iters):
        perturbed_images.requires_grad = True
        outputs = model(perturbed_images)
        loss = criterion(outputs, labels)
        
        model.zero_grad()
        loss.backward()
        
        with torch.no_grad():
            adv_images = perturbed_images + alpha * perturbed_images.grad.sign()
            eta = torch.clamp(adv_images - images, min=-epsilon, max=epsilon)
            perturbed_images = torch.clamp(images + eta, 0, 1)
            
    return perturbed_images

四、红蓝对抗复盘:生产架构防御

在生产流水线中,基础的“随机噪声”防御会被 EOT(Expectation Over Transformation)完全击溃。现实世界中的缓解措施依赖于架构级集成:

  • 对抗训练逻辑 (Adversarial Training):经验风险最小化被修改为一个极小极大(min-max)鞍点问题:

    \[ \min_\theta \mathbb{E}_{(x,y)\sim \mathcal{D}} \left[ \max_{\|\delta\|_p \le \epsilon} J(\theta, x+\delta, y) \right] \]
    模型使用 PGD 生成的样本进行连续训练。这降低了损失表面的曲率,但代价是“准确率-鲁棒性权衡”(降低了干净样本的准确率)。
  • 梯度掩码与混淆 (Gradient Masking):蓝队经常无意中引入破碎的梯度(例如不可导的预处理)。红队可以使用反向传播可导近似(BPDA)绕过这种防御。真正的防御需要通过黑盒迁移攻击来验证鲁棒性。
  • 推理拒答与 OOD 检测:在深层特征表示上部署马哈拉诺比斯距离(Mahalanobis distance)度量,以检测远离干净训练流形的输入。

五、鲁棒性评估的报告标准

生产级的安全审计必须产出一份评估矩阵:

  • 在不同 \( \epsilon \) 预算谱下的 干净准确率 与 PGD-100(100 次迭代)准确率对比。
  • 对无梯度攻击(如 SPSA)的评估,以证明防御不仅仅依赖于梯度混淆。
  • 动态 OOD 检测模块引入的系统延迟开销。

六、鲁棒性评估矩阵

为了让结果可复查,建议把每一次鲁棒性测试写成矩阵,而不是只给一段“模型对抗鲁棒”的结论。

测试项 固定参数 记录指标 失败信号
FGSM sweep \(\epsilon\) 从小到大扫描 clean acc, adv acc 极小扰动下准确率断崖式下降
PGD-k 固定 \(\epsilon\),改变迭代次数 adv acc, attack success rate 迭代数增加后防御迅速失效
Black-box transfer 替代模型生成样本 迁移攻击成功率 白盒防御有效但黑盒迁移仍高
Latency overhead 开启检测/拒答模块 P50/P95/P99 延迟 鲁棒性提升但线上延迟不可接受

七、如何避免虚假的安全感

如果某个防御让 FGSM 攻击失败,但 PGD 或黑盒迁移攻击仍然成功,很可能只是梯度被遮蔽,而不是真正鲁棒。报告中应同时包含白盒、黑盒和无梯度攻击结果,并说明输入预处理是否可导。对抗评估的目标不是证明模型“安全”,而是明确在给定扰动预算和攻击知识下,模型还能承受多少风险。

八、参考文献

发表回复

向下探索