diff-PGD:基于DM改进的PGD攻击
论文:Diffusion-Based Adversarial Sample Generation for Improved Stealthiness and Controllability
1.前面攻击的缺点及本文贡献
许多威胁模型被设计来为数字空间攻击和物理世界攻击生成对抗样本,并根据攻击区域和风格参考等提示生成更多定制的对抗样本 然而,这些模型大多数都没有被设计来保持输出样本的真实性,导致对抗样本明显偏离自然图像的分布。 事实上,在数字世界攻击的环境中,例如涉及 RGB 图像的攻击,更高的成功率和可迁移性与生成的样本的更大变化相关,从而导致隐蔽性与有效性的权衡。 此外,物理世界攻击的扰动是巨大的、不现实的,并且很容易被人类注意到
最近,针对数字和物理世界都提出了产生更真实的对抗样本的方法,比如优化添加到干净图像语义空间的扰动,并有人提出使用一种基于GAN的或其他先验知识来提供样本的真实性[1][2].
基于 GAN 的方法可以生成逼真的图像,但对抗样本是从噪声中采样的,因此缺乏可控性。 随后[3]对现实对抗样本的研究引入了语义对抗样本的概念。这些是欺骗模型的无界扰动,同时确保修改后的图像具有与原始图像相同的语义信息。 虽然语义空间中的变换可以减少像素空间中的高频模式,但这种方法仍然会受到颜色抖动或图像失真的影响,从而导致隐蔽性降低。 此外,这种方法需要仔细调整超参数,从而导致训练过程不稳定。
本文贡献:
(1)提出了一种称为基于扩散的投影梯度下降(Diff-PGD)的新颖框架,用于生成真实的对抗样本。 将扩散模型的强先验知识结合到对抗样本生成中,有助于生成具有高隐身性和可控性的对抗样本,通过利用扩散模型引导的梯度,Diff-PGD 确保对抗样本保持接近原始数据分布,同时保持其有效性
(2)Diff-PGD可以有效地应用于许多任务,包括数字攻击、定制攻击和物理世界攻击,优于PGD、AdvPatch和AdvCam等基线方法
(3)我们探索了Diff-PGD样品的可转移性和抗纯化特性,并通过实验评估表明,由Diff-PGD生成的对抗性样品优于原始的PGD方法
2. DDIM的respacing加速采样过程
DDIM的确定性采样过程

其中αt实则是DDPM论文的~αt,如果针对所有的t,本论文提出的扩散过程是一个更一般化的扩散过程,采样过程也是一个更一般化的采样过程 σt=,则前向过程变成了马尔可夫的形式,生成过程变成了DDPM σt=0时,采样过程不再进入随机性噪声,则整个采样过程就是一个确定的生成过程,这个就是DDIM模型 DDIM:就是从一个更一般化的,非马尔可夫扩散过程和采样过程中设置σt=0变成一个确定性的构成, 单单纯的DDIM只是一个模型并不能起到加速采样,还是需要从xT一直采样到x1...x0最后输出
respacing加速采样
对DDIM引入respacing加速采样是伤害非常小,起到加速效果,其实DDPM也能用但伤害比较大
(1)过去采样过程一直被认为是反向扩散过程的近似,前向过程有T步则生成过程也被迫进行T步的采样
(2)但是,只要qσ(xt|x0)固定,去噪目标L1不依赖于特定的扩散过程,我们可以考虑长度小于T的前向过程,采样过程也不用逐步逐步的逼近马尔可夫的前向扩散过程
3 区域PGD攻击
在某些情况下,我们需要保持图像的某些部分不变,并且仅在定义的区域中生成对抗扰动。 这用于定制攻击,例如,以给定的自然风格攻击遮蔽区域。 在这里,我们考虑使用 PGD 攻击给定图像的掩模区域(由掩模 M 确定)的子问题,称为区域 PGD(rPGD)。 具体来说,输出的对抗样本应满足
显然,当M取全1时,rPGD降为原始PGD
对于之前基于梯度的方法,很容易将
修改为
,其中
是没有梯度流的原始图像的副本。受扰动的区域将显示出与其他区域相比较大的分布变化,从而变得不自然。
4 diff-PGD伪代码实现

5 核心实现代码
主函数
#respace=ddim50 classifier=resNet50 全局的diff-PGD攻击,classifier=resNet50,respace=ddim50,t=3
def Attack_Global(classifier, device, respace, t, eps=16, iter=10, name='attack_global', alpha=2, version='v1', skip=200):
#PGD参数:最大扰动eps=0.06 单次最大扰动alpha=0.007 迭代次数=10
pgd_conf = gen_pgd_confs(eps=eps, alpha=alpha, iter=iter, input_range=(0, 1))
# vis/attack_global_gradpass_v2/resnet50_eps16_iter10_ddim50_t3/
save_path = f'vis/{name}_{version}/{classifier}_eps{eps}_iter{iter}_{respace}_t{t}/'
mp(save_path)
#获取resNet50模型,设置到GPU,评估模式不更新梯度参数
classifier = get_archs(classifier, 'imagenet')
classifier = classifier.to(device)
classifier.eval()
# dataset = get_dataset(
# 'imagenet', split='test'
# )
image_path = "../data/干净样本.jpg"
image = Image.open(image_path)
# 定义图像预处理的变换
preprocess = transforms.Compose([
transforms.Resize((224, 224)), # 调整图像大小为 224x224
transforms.ToTensor(), # 将图像转换为 PyTorch Tensor
])
# 对图像进行预处理
x = preprocess(image)
# 在第0维添加一个维度,使其成为形状为 [1, 3, 224, 224] 的 Tensor
x = x.unsqueeze(0)
x = x.to(device)
y=classifier(x).argmax(1)
"""
diffusion:类型是SpacedDiffusion,继承于gaussian_diffusion
里面调用space_timesteps 通过减少采样步数实现加速采样
"""
""" model:一个U-Net模型,预测每时间步添加的噪声 """
model, diffusion = get_imagenet_dm_conf(device=device, respace=respace)
# model=0
# diffusion=0
c = 0
for i in range(1):
# for i in tqdm(range(dataset.__len__())):
if i % skip != 0:
continue
time_st = time.time()
# print(f'{c}/{dataset.__len__()//skip}')
#
#
# x, y = dataset[i]
# x = x[None, ].to(device)
# y = torch.tensor(y)[None, ].to(device)
x=x.to(device)
y=y.to(device)
y_pred = classifier(x).argmax(1) # original prediction
if version == 'v1':
#x_adv的噪声都是PGD攻击添加的,DDIM仅利用对抗损失指导噪声添加的方向
x_adv = generate_x_adv_denoised(x, y_pred, diffusion, model, classifier, pgd_conf, device, t)
elif version == 'v2':
# x_adv的噪声都是PGD攻击添加的,DDIM仅利用对抗损失指导噪声添加的方向
x_adv = generate_x_adv_denoised_v2(x, y_pred, diffusion, model, classifier, pgd_conf, device, t)
cprint('time: {:.3}'.format(time.time() - time_st), 'g')
with torch.no_grad():
net = Denoised_Classifier(diffusion, model, classifier, t)
#生成的x_adv就是论文中的xn,xn的迁移性更加好,但由于噪声从头到尾都是PGD添加的,噪声还是比较明显
#pred_x0就是论文的x0n,再使用DDIM进行加噪去噪处理,此时diffusion就真正作用于噪声的,纯化了图像
#使得图像更加自然
pred_x0 = net.sdedit(x_adv, t)
pkg = {
'x': x,
'y': y,
'x_adv': x_adv,
'x_adv_diff': pred_x0,
}
PGD攻击
#x:干净样本,y干净样本对应的真实标签,t=3 pgd_conf:eps:0.06 alapa=0.007 iter=10
@torch.no_grad()
def generate_x_adv_denoised_v2(x, y, diffusion, model, classifier, pgd_conf, device, t):
#
net = Denoised_Classifier(diffusion, model, classifier, t)
delta = torch.zeros(x.shape).to(x.device)
# delta.requires_grad_()
#交叉熵损失
loss_fn=torch.nn.CrossEntropyLoss(reduction="sum")
eps = pgd_conf['eps']
alpha = pgd_conf['alpha']
iter = pgd_conf['iter']
for pgd_iter_id in range(iter):
#x_diff是对抗样本x经过diffusion加噪去噪处理后的图像
x_diff = net.sdedit(x+delta, t).detach()
x_diff.requires_grad_()
with torch.enable_grad():
#计算对抗损失
loss = loss_fn(classifier(x_diff), y)
loss.backward()
#获取梯度符号
grad_sign = x_diff.grad.data.sign()
#根据梯度符号影响PGD添加到图像的扰动
delta += grad_sign * alpha
#限制单次扰动大小
delta = torch.clamp(delta, -eps, eps)
print("Done")
#限制整体扰动大小
x_adv = torch.clamp(x+delta, 0, 1)
# 注意从头到尾diffusion没有直接进行对x_adv的噪声添加或删除,而是
#仅仅将其用于输出图像分类用于计算对抗损失从而间接影响PGD添加到x的扰动
return x_adv.detach()
DDIM扩散与采样优化
#Denoised_Classifier 是PGD攻击里面的predict模型(ResNet50图像分类预测模型)
# model是U-Net预测噪声模型 diffusion是SpacedDiffusion可以进行加速采样
class Denoised_Classifier(torch.nn.Module):
def __init__(self, diffusion, model, classifier, t):
super().__init__()
self.diffusion = diffusion
self.model = model
self.classifier = classifier
self.t = t
#本案例t=3,x是PGD中加了随机噪声的图片,最后的输出是对抗样本x经过diffusion加噪去噪处理后的图像
def sdedit(self, x, t, to_01=True):
# assume the input is 0-1
t_int = t
#将x的像素范围转-1到+1
x = x * 2 - 1
#t转为一个tensor,其值仍然是3
t = torch.full((x.shape[0], ), t).long().to(x.device)
#把加了PGD噪声的x当作是初始的x0,noise的初始化在函数里面实现,这里获取第t步x0添加完噪声的图片x_t
x_t = self.diffusion.q_sample(x, t)
sample = x_t
# print(x_t.min(), x_t.max())
# si(x_t, 'vis/noised_x.png', to_01=True)
indices = list(range(t+1))[::-1]
# visualize
l_sample=[]
l_predxstart=[]
# indices=[3,2,1,0],进行四次循环
for i in indices:
#针对x_t进行去采样处理(去噪),其中t=3,使用ddim加速采样(去噪)
#因为调用一次ddim_sample仅进行一步去噪,所以需要循环执行
# out = self.diffusion.ddim_sample(self.model, sample, t)
out = self.diffusion.ddim_sample(self.model, sample, torch.full((x.shape[0], ), i).long().to(x.device))
sample = out["sample"]
l_sample.append(out['sample'])
l_predxstart.append(out['pred_xstart'])
# visualize
si(torch.cat(l_sample), 'l_sample.png', to_01=1)
si(torch.cat(l_predxstart), 'l_pxstart.png', to_01=1)
# 将图像的像素值从-1到1还原回0到1
if to_01:
sample = (sample + 1) / 2
return sample
def forward(self, x):
#加噪且去噪后的图像out
out = self.sdedit(x, self.t)
# 得到这个图像out经过ResNet50后的预测类别
out = self.classifier(out)
#注意并没有把对抗样本x经过diffusion加噪去噪处理后的图像返回
#而仅仅将其用于输出图像分类用于计算对抗损失从而间接影响PGD添加到x的扰动
return out
[1]R. Lapid and M. Sipper. Patch of invisibility: Naturalistic black-box adversarial attacks on object detectors. arXiv preprint arXiv:2303.04238, 2023Z.
[2]Hu, S. Huang, X. Zhu, F. Sun, B. Zhang, and X. Hu. Adversarial texture for fooling person detectors
in the physical world. In Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern
Recognition, pages 13307–13316, 2022
[3]H. Hosseini and R. Poovendran. Semantic adversarial examples. In Proceedings of the IEEE Conference
on Computer Vision and Pattern Recognition Workshops, pages 1614–1619, 2018
更多推荐



所有评论(0)