在将AI模型投入生产环境(特别是安全敏感领域,如自动驾驶或金融欺诈检测)之前,模型的鲁棒性是部署成功的关键因素。近年来,对抗性攻击(Adversarial Attacks)的威胁日益凸显,攻击者通过对输入数据添加人眼难以察觉的微小扰动(Perceptual Distortion),就能使模型做出错误的判断。在部署前进行鲁棒性微调(Robustness Fine-Tuning)是解决这一问题的最有效手段之一。
本文将聚焦于对抗训练(Adversarial Training, AT)技术,并提供基于PyTorch的可实操代码示例,指导您如何将鲁棒性作为模型质量的核心指标进行优化。
什么是对抗训练?
对抗训练是一种正则化技术,它通过在训练过程中动态生成对抗样本并将其纳入训练集,迫使模型学习更平滑、更鲁棒的决策边界。最常用的攻击生成方法是投影梯度下降(Projected Gradient Descent, PGD),它被认为是生成强大、转移性低的对抗样本的黄金标准。
核心步骤
传统的模型训练循环:
1. 输入 $x$ -> 模型预测 $f(x)$ -> 计算损失 $L(f(x), y)$。
对抗训练循环:
1. 输入 $x$。
2. 在当前模型参数下,通过迭代优化(如PGD)生成对抗样本 $x_{adv} = x + ext{Perturbation}$,确保扰动在 $ ext{L}{ ext{p}}$ 范数限制 $ ext{epsilon}(\epsilon)$ 内。
3. 使用 $x{adv}$ 进行前向传播 -> 模型预测 $f(x_{adv})$ -> 计算损失 $L(f(x_{adv}), y)$。
4. 反向传播并更新模型参数。
实用操作:使用PGD进行鲁棒性微调
我们将使用PyTorch演示如何将PGD攻击整合到标准的微调流程中。假设我们已经有一个预训练好的分类模型 RobustModel。
环境准备
您需要安装PyTorch和用于快速实现对抗攻击的库,例如 torchattacks。
pip install torch torchattacks torchvision
代码示例:PGD对抗训练循环
以下代码展示了一个完整的鲁棒性微调循环,其中使用了 torchattacks 库中的PGD实现,这比手动编写迭代攻击过程更加高效。
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import models, datasets, transforms
import torchattacks
# 1. 初始化模型、数据加载器和优化器
# 假设使用ResNet18作为示例模型
model = models.resnet18(pretrained=True)
num_ftrs = model.fc.in_features
model.fc = nn.Linear(num_ftrs, 10) # 假设是10分类任务
model = model.cuda() if torch.cuda.is_available() else model
# 数据加载器(使用CIFAR-10作为示例)
transform = transforms.Compose([
transforms.ToTensor(),
# 注意:对抗训练通常需要去除标准化步骤,或在攻击时进行反标准化和再标准化处理。
# 此处为简化示例,暂不使用标准预处理的Normalization
])
train_dataset = datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True, num_workers=4)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=1e-4)
# 2. 定义对抗攻击
# PGD参数设置:
# eps (epsilon): L_inf 范数限制,决定了扰动的最大幅度 (例如 8/255)
# alpha (step size): 每一步迭代的步长 (例如 2/255)
# steps: 迭代次数 (例如 7)
# 初始化PGD攻击器
# 使用 L_inf 约束,扰动最大幅度设置为 8/255
eps_val = 8 / 255.0
attacker = torchattacks.PGD(model, eps=eps_val, alpha=2/255.0, steps=7, random_start=True)
print(f"开始鲁棒性微调,使用PGD L_inf (eps={eps_val:.4f})")
# 3. 执行对抗训练循环
def adversarial_train(model, train_loader, optimizer, criterion, attacker, epochs):
model.train()
device = next(model.parameters()).device
for epoch in range(epochs):
running_loss = 0.0
for i, (inputs, labels) in enumerate(train_loader):
inputs, labels = inputs.to(device), labels.to(device)
# --- 关键步骤 1: 生成对抗样本 ---
# 确保模型处于评估模式以生成最坏情况的攻击
model.eval()
inputs_adv = attacker(inputs, labels)
# --- 关键步骤 2: 使用对抗样本训练模型 ---
model.train()
optimizer.zero_grad()
outputs = model(inputs_adv)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
print(f"Epoch {epoch+1}, Loss: {running_loss / len(train_loader):.4f}")
# 开始微调(例如运行 10 个 Epoch)
if torch.cuda.is_available():
adversarial_train(model, train_loader, optimizer, criterion, attacker, epochs=10)
else:
print("请在支持CUDA的环境下运行,对抗训练对计算资源要求较高。 ")
部署前的效果评估
鲁棒性微调完成后,必须评估模型的性能。
重要提示: 传统的准确率(在干净数据上的准确率)可能会略有下降,这是对抗训练的常见权衡。我们必须关注模型在对抗样本上的准确率(鲁棒性准确率)。
评估代码片段
# 假设 test_loader 已定义
def evaluate_robustness(model, test_loader, attacker):
model.eval()
device = next(model.parameters()).device
robust_correct = 0
total = 0
with torch.no_grad():
for inputs, labels in test_loader:
inputs, labels = inputs.to(device), labels.to(device)
# 生成用于测试的对抗样本
# 注意:在评估时,我们通常使用更强的攻击 (例如更大的 steps)
inputs_adv = attacker(inputs, labels)
outputs = model(inputs_adv)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
robust_correct += (predicted == labels).sum().item()
robust_accuracy = 100 * robust_correct / total
print(f'模型在对抗样本上的准确率 (Robust Accuracy): {robust_accuracy:.2f}%')
return robust_accuracy
# 评估调整后的模型
# 重新初始化一个更强大的PGD攻击器进行评估
attacker_test = torchattacks.PGD(model, eps=8/255.0, alpha=2/255.0, steps=20, random_start=True)
# 假设 test_loader 是测试数据集加载器
# evaluate_robustness(model, test_loader, attacker_test)
部署考量
鲁棒性微调虽然增强了模型抵抗攻击的能力,但也带来了一些部署上的考量:
- 计算开销: 对抗训练所需的计算量远大于标准训练,因为它在每次迭代中都涉及多次梯度计算(PGD的迭代次数)。部署前的微调周期会显著延长。
- 推理延迟: 鲁棒模型通常比原始模型略微复杂或表现出更高的参数敏感性。然而,由于鲁棒性微调不改变模型结构,对部署后的推理延迟影响很小(如果使用相同的硬件)。
- 鲁棒性泛化: 一个经过PGD训练的模型主要对抗PGD攻击表现出色,但对其他类型的攻击(如C&W, AutoAttack)的抵抗力可能略差。为了更全面的鲁棒性,建议在部署前使用多重攻击方法进行验证,甚至可以考虑使用更先进的、更通用的防御方法如TRADES或RST。
汤不热吧