背景
深度神经网络的进展: 尽管深度神经网络在各个领域取得了突破性的进展,但其对对抗样本的脆弱性仍然存在。
现有研究的不足: 尽管最近的研究将查询次数从数百万减少到数千次,但仍然不足以满足大多数实际应用的需求。
现有决策型攻击方法的局限性: 大多数现有的决策型攻击方法在每个迭代步骤都将对抗样本限制在决策边界上,并通常采用不同的梯度估计方法进行攻击。
要解决的问题
降低决策型对抗攻击对目标模型的查询次数。
使决策型对抗攻击能够在实际场景中更有效地应用。
创新点
- 利用几何信息优化扰动:Triangle Attack (TA) 利用了三角形几何特性来优化扰动,这一方法避免了传统的梯度估计,从而减少了对目标模型的查询次数。
- 在低频空间中优化扰动:TA 通过离散余弦变换(DCT)将输入图像转换到低频空间,并在该空间中优化扰动。这种方法有效地实现了降维,提高了攻击效率。
- 不限制对抗样本在决策边界上:与现有的大多数决策型攻击方法不同,TA 不需要将对抗样本限制在决策边界上,这进一步降低了查询次数。
- 角度调整策略:TA 根据生成的对抗样本自适应地调整角度,以平衡扰动大小和找到对抗样本的难度。
方案
-
TA 的核心思想: TA 将良性样本、当前对抗样本和下一个对抗样本视为一个三角形,并利用正弦定理来优化扰动,使扰动逐渐减小。
-
TA 的算法框架: TA 遵循现有的决策型攻击框架,首先随机生成一个大的对抗扰动,然后最小化这个扰动。为了与之前的工作保持一致,TA 通过二进制搜索生成一个接近决策边界的随机扰动,并主要关注扰动的优化过程。
正弦定理(The law of sines)及其在 TA 中的应用
三角形的构造: 在任意对抗攻击的两个连续迭代步骤中,即第 t-th 和第 (t+1)-th 迭代,输入样本 x、当前对抗样本 xadv_t 和下一个对抗样本 xadv_t+1 可以自然地在输入空间 X 的一个子空间中构成一个三角形。因此,减少扰动以生成 xadv_t+1 相当于搜索一个合适的三角形,其中三个顶点分别是 x、xadv_t 和 xadv_t+1。如图1
图 1 展示了 TA 在任意迭代中构建候选三角形的示例。在第 t-th 迭代中,TA 在采样子空间中构建一个三角形,其中包含学习到的角度 αt,这个角度满足 βt + 2αt > π 的条件。通过这种方式,TA 找到一个新的对抗样本 xadv_t+1 并相应地更新 αt。
三角形的边长与角度关系: 根据正弦定理,我们可以得到图 1 中三角形的边长与其对角之间的关系:δt/sin αt = δt+1/sin (π −(αt +βt))。
减少扰动的方法: 为了贪婪地减少扰动 δt,第 t-th 三角形应该满足 δt+1/δt = sin(π−(αt+βt))/sin αt < 1,即 π −(αt +βt) < αt。因此,在第 t-th 迭代中减少扰动的方法是找到一个由输入样本 x、当前对抗样本 xadv_t 和角度 βt 和 αt 构成的三角形,满足 βt+2αt > π,并且第三个顶点应该是对抗性的。
TA在频率空间中采样 2-D 子空间来优化扰动
-
高维空间的挑战:输入图像通常位于高维空间中,例如ImageNet数据集的224×224×3尺寸,这种高维性使得攻击难以有效探索邻近区域以最小化对抗性扰动。
-
子空间利用:先前的研究(如QEBA和Surfree)表明,利用不同子空间中的信息可以提高基于决策的攻击的效率。例如,QEBA在空间变换或低频空间中对梯度估计进行随机噪声采样,但使用估计的梯度在输入空间中最小化扰动。Surfree通过在低频空间中随机采样的单位向量确定的输入空间的子空间来优化扰动。
-
低频空间的重要性:通常,低频空间包含了图像最关键信息。由于TA在输入空间中的表现不佳(如第4.4节所示),并且考虑到几何属性的普适性(如图2所示),研究者选择在每次迭代中直接在频率空间优化扰动,以有效降低维度。
-
随机采样d维线:研究者在低频空间(通常是顶部10%)中随机采样一个d维线,这条线穿过良性样本,用于确定频率空间中的唯一2-D子空间S。
-
构建候选三角形:在2-D子空间S中,可以构建候选三角形以最小化扰动。这个三角形由良性样本x、当前对抗样本xadv_t和通过几何属性学习到的角度αt以及搜索到的角度βt确定。
-
逆DCT转换:最终的对抗样本可以通过逆离散余弦变换(IDCT)转换回输入空间。
图 2 展示了 Triangle Attack(TA)在第 t-th 迭代中整个攻击过程的示例。TA 在频率空间中构建三角形,以高效地生成对抗样本。这里我们采用 DCT(离散余弦变换)进行说明,但实际上在每个迭代中我们不需要对 x 进行 DCT。我们仍然在频率空间中使用 x 和 xadv_t,而不存在歧义,因为 DCT 是一对一的映射。
TA 搜索候选三角形
图 3 展示了 TA 中如何构建一个对称的候选三角形(x, xadv_t 和 xadv_t+1,2)。当角度 β 不能导致生成对抗样本(例如 xadv_t+1,1)时,我们会在基于线 ⟨x, xadv_t⟩ 的基础上进一步构建对称三角形,以检查数据点 xadv_t+1,2。
图 4 展示了候选三角形中角度 α 大小对 TA 效果的影响。对于相同的采样角度 β,较大的角度 α 会导致更小的扰动,但也更有可能越过决策边界。
自适应地调整角度 α
-
角度 α 的平衡作用:角度 α 平衡了扰动的大小和对生成对抗样本的难度。较小的角度 α 使找到对抗样本更容易,但扰动更大,更容易越过决策边界。较大的角度 α 导致更小的扰动,但找到对抗样本的难度更大。
-
调整角度 α 的方法:TA 通过生成对抗样本并观察其效果来自适应地调整角度 α。如果生成的对抗样本 xadv_t,i+1 能够欺骗目标模型,即 f(xadv_t,i+1; θ) = y,则 TA 会增加角度 αt,i+1,否则会减少角度 αt,i+1。增加和减少的角度量由 γ 和 λ 控制,其中 γ 是变化率,λ 是一个常数。
-
角度 α 的上下界限制:为了防止角度 α 调整过快,TA 添加了角度 α 的上下界限制。较小的角度 α 会导致 β 的下界降低,使 T(x,xadv_t,αt,βt,St) 远离当前的对抗样本 xadv_t,从而降低了找到对抗样本的概率。因此,TA 通过限制角度 α 的范围来保持其在一个适当的区间内。
-
TA 的算法流程:TA 迭代地在从低频空间采样的子空间 St 中搜索候选三角形,以找到对抗样本并相应地调整角度 α。TA 的整个算法流程在 Algorithm 1 中总结。
- 输入参数:目标分类器 f 和其参数 θ,良性样本 x 和其真实标签 y,最大查询次数 Q,最大迭代次数 N,采样子空间的维度,方向线的维度,以及角度 β 的下界。
- 初始化:初始化一个大的对抗扰动 δ0,并设置初始的对抗样本 xadv_0 = x + δ0,查询次数 q = 0,迭代次数 t = 0,角度 α0 = π/2。
- 迭代过程:
实验
数据集
Dataset. To validate the effectiveness of the proposed TA, following the setting
of Surfree [39], we randomly sample 200 correctly classified images from the
ILSVRC 2012 validation set for evaluation on the corresponding models.
数据集为:readme中给出的链接内的200张图片(使用的是pytorch预训练模型)
超参数
TA 的超参数设置:对于 Triangle Attack (TA),采用以下超参数设置:
- 每个子空间的最大迭代次数 N = 2。
- 方向线维度 d = 3。
- 更新角度 α 时使用的超参数:γ = 0.01,λ = 0.05,τ = 0.1,并将最大查询次数设置为 1,000。
其他
Models.Weconsider five widely adopted models, i.e., VGG-16 [44], Inception
v3 [45], ResNet-18 [24], ResNet-101 [24] and DenseNet-121 [25]. To validate the
applicability in the real world, we evaluate TA on Tencent Cloud API3.
模型为这5个
指标:
局限性
- TA 的目标:TA 的目标是提高查询效率,通过利用三角形几何。因此,当允许更多查询次数时,全局最优解可能不如基于梯度估计的攻击方法。
- 无梯度估计的几何启发方法:其他不使用梯度估计的几何启发方法在相同情况下也表现不佳,不如 QEBA 。
- TA 的局限性:这不是 TA 的目标,可以通过使用梯度估计来轻松解决。TA 可以作为精确梯度估计攻击(如 QEBA )的预热阶段,如果在攻击中可以接受高查询次数。
复现
TA攻击结果可视化。要求:数据集为官方提供的200张图片,目标模型为ViT-Base,最大总查询次数为800,可视化最终生成的5组对抗样本与对抗噪声。
添加内容
pip install timm
安装这个库,使用
v
i
t
_
b
a
s
e
vit\_base
vit_base 模型
可视化代码:
import matplotlib.pyplot as plt
import numpy as np
import torchvision
import torch
def visualize_adversarial_samples(original_images, adversarial_images, noise, num_samples=1):
"""
可视化原始图像、对抗样本和噪声,并将对抗样本和噪声保存为图像文件。
参数:
original_images (torch.Tensor): 原始图像张量(CUDA张量)。
adversarial_images (torch.Tensor): 对抗样本张量(CUDA张量)。
noise (torch.Tensor): 噪声张量(CUDA张量)。
num_samples (int): 要可视化和保存的样本数量。默认值为5。
"""
# 创建一个3xnum_samples的子图对象
fig, axs = plt.subplots(3, num_samples, figsize=(15, 7))
titles = ['原始图像', '对抗样本', '噪声']
for i in range(num_samples):
# 将张量从GPU移到CPU并转换为numpy数组
original_image = original_images[i].squeeze()
adversarial_image = adversarial_images[i].squeeze()
original_image = original_image.cpu().detach().numpy()
adversarial_image = adversarial_image.cpu().detach().numpy()
noise = noise[i].cpu().detach().numpy()
original_image = original_image.transpose((1, 2, 0)) # 将CHW转换为HWC
adversarial_image = adversarial_image.transpose((1, 2, 0)) # 将CHW转换为HWC
# 剪切到 0 到 1 范围
adversarial_image = (adversarial_image - adversarial_image.min()) / (
adversarial_image.max() - adversarial_image.min())
adversarial_image = np.clip(adversarial_image, 0, 1)
# 显示原始图像
plt.imsave(f'原始样本图像_{i}.png', original_image)
# 保存对抗样本图像到当前目录
plt.imsave(f'对抗样本图像_{i}.png', adversarial_image)
# 保存噪声图像到当前目录,使用'viridis'颜色映射
noise_image = adversarial_image - original_image
noise_image = (noise_image - noise_image.min()) / (
noise_image.max() - noise_image.min())
noise_image = np.clip(noise_image, 0, 1)
plt.imsave(f'对抗噪声_{i}.png', noise_image, cmap='viridis')
# 显示生成的子图
plt.show()
运行
运行参数设置:–max_queries 800 --model_name vit_base
结果
TA攻击结果量化。要求:数据集为官方提供的200张图片,目标模型Swin-Tiny,最大总查询次数为800,给出这200张图片所生成对抗噪声的平均L2范数(像素值归一化到0-1时的结果)。
my_advs_l2 = l2(images, my_advs)
# Compute the average l2 norm of the perturbations
average_l2_norm = np.mean(my_advs_l2)
利用任意一种迁移攻击算法生成对抗样本,以迁移攻击算法生成的对抗样本作为决策攻击的初始点进行迭代生成最终对抗样本。要求:数据集为官方提供的200张图片,目标模型为VGG16,最大总查询次数为800,从这200张图片对抗噪声的平均L2范数(像素值归一化到0-1时的结果)与三种噪声阈值(RMSE=0.1,0.05,0.01)下的攻击成功率两个角度展示融合迁移攻击生成对抗样本前后的对比实验结果
迁移攻击的使用
# 基于迁移的攻击(FGSM在resnet上生成对抗样本)
def apply_fgsm_attack(model, images, labels, epsilon=0.03):
atk = torchattacks.FGSM(model, eps=epsilon)
adv_images = atk(images, labels)
return adv_images
if init_x is None: # 如果初始化对抗性示例x_adv为None,则使用get_x_adv函数生成
#x_adv = get_x_adv(x_o, original_label, net)
# 使用迁移攻击生成对抗样本
fmodel = models.resnet18(pretrained=True).eval().to(device)
x_adv = apply_fgsm_attack(fmodel, x_o, original_label)
# Compute the average l2 norm of the perturbations
average_l2_norm = np.mean(my_advs_l2)
print(f"Average L2 Norm of Adversarial Noise: {average_l2_norm}")
# 计算攻击成功率
success_rate = sum(my_advs_l2 <= 0.1) / len(images)
print(f"Success Rate: {success_rate}")
结果
原始:
RMSE_threshold | success_rate |
---|---|
RMSE=0.1 | 90% |
RMSE=0.05 | 67.5% |
RMSE=0.01 | 27.5% |
Average L2 Norm (Normalized):0.061015725
应用了迁移攻击:
RMSE_threshold | success_rate |
---|---|
RMSE=0.1 | 100% |
RMSE=0.05 | 100% |
RMSE=0.01 | 30% |
Average L2 Norm (Normalized):0.027907128
设计一个模块来辅助TA在迭代过程中逃离局部最优。要求:数据集为官方提供的200张图片,目标模型为VGG16,最大总查询次数为800,展示所设计方法的思路,从这200张图片对抗噪声的平均L2范数(像素值归一化到0-1时的结果)与三种噪声阈值(RMSE=0.1,0.05,0.01)下的攻击成功率两个角度展示加入新模块前后的对比实验结果。
import torch
import numpy as np
class RandomPerturbationRestart:
def __init__(self, perturbation_magnitude=0.01, restart_threshold=50, probability=0.1):
"""
初始化 RandomPerturbationRestart 类。
Args:
- perturbation_magnitude (float): 随机扰动的幅度。
- restart_threshold (int): 连续迭代次数达到重启的阈值。
- probability (float): 应用随机扰动的概率。
"""
self.perturbation_magnitude = perturbation_magnitude
self.restart_threshold = restart_threshold
self.probability = probability
self.consecutive_iterations = 0 # 记录连续迭代次数
def apply(self, x_adv):
"""
应用随机扰动并检查是否需要重启。
Args:
- x_adv (torch.Tensor): 当前的对抗样本张量。
Returns:
- torch.Tensor: 经过扰动和可能的重启后修改后的对抗样本张量。
"""
# 根据概率应用随机扰动
if np.random.rand() < self.probability:
noise = torch.randn_like(x_adv) * self.perturbation_magnitude # 生成随机扰动
x_adv += noise
x_adv = torch.clamp(x_adv, 0, 1) # 将像素值限制在 [0, 1] 范围内
# 检查是否需要根据连续迭代次数进行重启
if self.consecutive_iterations >= self.restart_threshold:
# 重启的示例逻辑:将 x_adv 重置为新的随机状态
x_adv = torch.randn_like(x_adv)
x_adv = torch.clamp(x_adv, 0, 1) # 将像素值限制在 [0, 1] 范围内
self.consecutive_iterations = 0 # 重置迭代计数器
else:
self.consecutive_iterations += 1
return x_adv
def simulated_annealing(x_o, x_adv, temp, cooling_rate):
# x_o: 原始图像
# x_adv: 当前的对抗样本
# temp: 当前的温度
# cooling_rate: 温度下降率
# 进入模拟退火循环,直到温度降至0.1
while temp > 0.1:
# 生成新的对抗样本,通过在当前对抗样本上添加一个随机噪声
new_x_adv = x_adv + torch.randn_like(x_adv) * temp
# 计算新对抗样本与原始图像的L2距离与当前对抗样本与原始图像的L2距离之差
delta_energy = torch.norm(new_x_adv - x_o, p=2) - torch.norm(x_adv - x_o, p=2)
# 如果能量降低(即新对抗样本与原始图像的距离更小),或者能量不变但概率足够大
if delta_energy < 0 or torch.exp(-delta_energy / temp) > torch.rand(1).item():
# 接受新对抗样本
x_adv = new_x_adv
# 降低温度
temp *= cooling_rate
# 返回最终的对抗样本
return x_adv
# perturbation_magnitude = 0.01
# restart_threshold = 50
# probability = 0.1
# restart_module = RandomPerturbationRestart(perturbation_magnitude, restart_threshold, probability)
# enhanced_ta_attack(ta_model, images, labels, restart_module)
# 使用重启模块对对抗性示例进行扰动
# x_adv = restart_module.apply(x_adv)
# 使用模拟退火算法对对抗性示例进行扰动
# x_adv = simulated_annealing(x_o, x_adv, 1000, 0.9)
随机扰动重启方法效果较差,平均l2距离比原来的还要高
结果
应用了模拟退火算法:
RMSE_threshold | success_rate |
---|---|
RMSE=0.1 | 92.5% |
RMSE=0.05 | 65% |
RMSE=0.01 | 32.5% |
Average L2 Norm (Normalized):0.05803299