FGSM
传送门
FGSM 利用了梯度上升的思想,通过损失函数相对于输入图像的梯度来找到 最容易 迷惑网络的方向,并沿着这个方向对图像进行微小的扰动。
FGSM 的基本想法是,沿着这个梯度的符号方向对图像进行微调,以最大化损失函数。具体公式为:
FGSM攻击算法代码:
# 定义 FGSM 攻击函数
def fgsm_attack(image, epsilon, data_grad):
# 生成扰动方向
sign_data_grad = data_grad.sign()
# 生成对抗样本
perturbed_image = image + epsilon * sign_data_grad
# 对抗样本像素值范围约束在 [0,1]
perturbed_image = torch.clamp(perturbed_image, 0, 1)
return perturbed_image
PGD:
传送门
PGD算法在论文 《Towards Deep Learning Models Resistant to Adversarial Attacks 》中提出,它既是产生对抗样本的攻击算法,也是对抗训练的防御算法。
除此之外,PGD算法也是一阶中的最强攻击(一阶是指利用一阶导数)
设想目标模型如果是一个线性模型,损失函数对输入的导数一定是一个固定值,一次迭代和多次迭代时扰动的方向都不会发生改变,但是,如果目标模型为非线性,每次迭代之间的方向都有可能会发生变化,这时FGSM的单次迭代效果肯定不如PGD的效果好。FGSM算法通过一步计算,可能达不到最优效果,而PGD算法则是每次走一小步,但是多走几次,如果超过了扰动半径为ε的空间,就重新映射回来。
下面来看一下PGD算法的公式:
这里主要看一下公式最前面的投影到x+S的意思:就是通过一系列操作得到对抗样本后,将对抗样本减去原始图像得到了扰动值,然后将扰动值限制在-ε到+ε之间,得到了新的扰动值,原始图像加上新的扰动值就是最终生成的对抗样本。
关于对式子中sgn(L(θ,x,y)’)的理解可从FGSM中获取:
在FGSM中引入符号函数可以确定对抗扰动的方向。Goodfellow指出,如果我们的变化量与梯度的变化方向完全一致,那么将对分类结果产生较大的变化。因此,在FGSM中不需要关心具体的梯度大小,只需要知道方向即可。
符号函数sign:
PGD的核心代码:
# PGD攻击方式,属于FGSM攻击的变体
def PGD_attack(model, image, label, epsilon=0.8, alpha=0.1, iters=40):
image = image.to(device)
label = label.to(device)
loss = nn.CrossEntropyLoss()
ori_image = image.data
for i in range(iters): # 每次走一小步,但是多走几次
image.requires_grad = True
output = model(image)
model.zero_grad()
cost = loss(output, label).to(device)
cost.backward()
# 对抗样本 = 原始图像 + 扰动
adv_image = image + alpha * image.grad.sign()
# 限制扰动范围
eta = torch.clamp(adv_image - ori_image, min=-epsilon, max=epsilon)
# 进行下一轮的对抗样本生成
image = torch.clamp(ori_image + eta, min=0, max=1).detach()
return image