对抗样本的线性解释
数字图像通常采用每个像素8bit来编码,因此会抛弃小于1/255的信息。设原始图像为
,扰动噪声为
,扰动之后的图像为:
如果
小于特征的精度,那么分类器如果做出不同的相应是不合理的。格式上的,对于well-separated类,我们期望的是分类器对于
和
分配相同的类别只要最大范数
。
,其中
是一个足够小的,无法被感知到的数。考虑在权重
和对抗样本
之间的点乘:
扰动
被增长激活通过
。我们最大化增长激活通过
。因为加减1以内的数都是无法被感知的,所以采用
函数是最大化的扰动值。这里假设
具有
维,权重向量的平均数量级为
,那么通过点乘之后激活被增加到
.虽然
作为一个常数是不变的,但是维度
会随着线性增长伴随着高维空间,此时对于输入的无穷小改变则会引起输出较大的改变。
对于非线性模型的线性扰动
上图展示了Fast adversarial examples应用在GoogleNet上。通过加上一个人类感知不到的小向量,向量的值为
乘输入像素点关于误差的梯度值的符号值。这里
,符合经过GoogleNet转换为实数后8bit图像编码的最小数量级。图中加上噪声后,熊猫被识别为长臂猿,并且置信度为99.3%,所以此方法叫做fast gradient sign method,简称FGSM。
使用foolbox实现对pre-trained模型攻击
需要提供一张imagenet数据集中的一张图片并命名为val.jpeg和对应的标签值。这里采用pytorch预训练的ResNet-18模型进行攻击。
import foolbox
import torch
import torchvision.models as models
import numpy as np
import cv2
# instantiate the model
resnet18 = models.resnet18(pretrained=True).eval()
if torch.cuda.is_available():
resnet18 = resnet18.cuda()
mean = np.array([0.485, 0.456, 0.406]).reshape((3, 1, 1))
std = np.array([0.229, 0.224, 0.225]).reshape((3, 1, 1))
fmodel = foolbox.models.PyTorchModel(
resnet18, bounds=(0, 1), num_classes=1000, preprocessing=(mean, std))
# get source image and label
image_path = 'val.JPEG'
image = cv2.imread(image_path)
image = cv2.resize(image, (224,) * 2)[..., ::-1].transpose((2, 0, 1)).astype(np.float32)
image = image / 255. # because our model expects values in [0, 1]
label = 0
print('True label', label)
print('predicted class', np.argmax(fmodel.forward_one(image)))
# apply attack on source image
attack = foolbox.attacks.FGSM(fmodel)
# 如果攻击失败,返回空值
adversarial = attack(image, label)
np.save('adversarial.npy', adversarial) # 保存攻击之后的图像
print('adversarial class', np.argmax(fmodel.forward_one(adversarial)))
输出:
True label 0
predicted class 0
adversarial class 997
这里解释一下attack对象的参数:
call(self, input_or_adv, label=None, unpack=True, epsilons=1000, max_epsilon=1)
Parameters:
- input_or_adv: numpy.ndarray or Adversarial The original, unperturbed input as a numpy.ndarray or an Adversarial instance.
- label:int The reference label of the original input. Must be passed if a is a numpy.ndarray, must not be passed if a is an Adversarial instance.
- unpack:bool If true, returns the adversarial input, otherwise returns the Adversarial object.
- epsilons:int or Iterable[float] Either Iterable of step sizes in the direction of the sign of the gradient or number of step sizes between 0 and max_epsilon that should be tried.
- max_epsilon:float Largest step size if epsilons is not an iterable.
如果epsilons是int型的数,那么
epsilons= np.linspace(0, max_epsilon, num=epsilons + 1)[1:]
或者epsilons是一个可迭代的浮点数,比如:
epsilons=[0.1, 0.2, 0.3]
FGSM会从小的epsilon开始进行攻击,直至找到可以攻击成功的epsilon值。若攻击失败,则会返回空值。若仅想要使用一个epsilon值来攻击,则可以设置epsilons=[0.1]
和max_epsilon=0
,即:
adversarial = attack(image, label, epsilons=[0.001], max_epsilon=0)
可视化加噪声后的样本以及sign图
import matplotlib.pyplot as plt
import cv2
import numpy as np
plt.subplot(1, 3, 1)
plt.title('Original')
image_path = 'val.JPEG'
image = cv2.imread(image_path)
image = cv2.resize(image, (224,) * 2)[..., ::-1] / 255
plt.imshow(image) # division by 255 to convert [0, 255] to [0, 1]
plt.axis('off')
plt.subplot(1, 3, 2)
plt.title('Adversarial')
adversarial = np.load('adversarial.npy').transpose((1, 2, 0))
plt.imshow(adversarial)
plt.axis('off')
plt.subplot(1, 3, 3)
plt.title('Difference')
sign = np.sign(adversarial - image)
plt.imshow((sign- sign.min())/ (sign.max()-sign.min()))
plt.axis('off')
plt.show()
对抗性训练
标准的监督训练不会指定选择的函数可以对对抗样本具有对抗性。作者认为基于FGSM的对抗目标函数是一个有效的正则项:
作者的默认参数为
,此方法可以持续更新所提供的对抗样本,来对抗现有版本的模型。
转载:https://blog.csdn.net/winycg/article/details/102557047