机器学习对抗攻击

一、前言

如今机器学习和深度学习已经成为众多领域甚至是非计算机领域研究热点,各种商业化的应用也是层出不穷,可以说为新兴产业的发展带来了强劲的动力。但是从安全角度考虑,其受攻击的可能性,以及其是否具备强抗打击能力一直是安全界关注的焦点。最近两年已经有安全人员开始对其安全性展开了研究,攻击的手法主有两个方面,一是对抗样本的生成,二是机器学习代码本身的漏洞挖掘,这里我们主要讨论第一点。

对抗样本也分为多种类型,最常见的是图像和语音,本文主要从图像对抗样本生成的角度研究其安全性。对抗性图像攻击是攻击者构造一张对抗性图像,使人眼和图像识别机器识别的类型不同。如下图所示,一个攻击样本在人类看来是正常的,能够被人眼正常识别,但是机器学习会将其识别成“恶意的”结果,这个“恶意的”结果可能只是个与正确的结果与不同,并不在意究竟被识别成什么,但也可能是某个特定的精心指定的错误结果,从而达到期待的攻击效果(让机器学习模型产生幻觉)。

比如攻击者可以针对使用图像识别的无人车,构造出一个图片,在人眼看来是一个停车标志,但是在汽车看来是一个限速120的标志,从而制造一场交通事故。

二、概念

对抗样本(Adversarial Examples)在数据集中通过故意添加细微的干扰所形成输入样本,受干扰之后的输入导致模型以高置信度给出了一个错误的输出。

三、原理

这里我们先提一个机器学习的一个基本问题:学习数据的分布。具体的就是从训练数据中进行学习,如果学习成功,则可以泛化到所有数据,包含没见过的测试数据。Anh Nguyen的论文《Deep Neural Networks are Easily Fooled: High Confidence Predictions for Unrecognizable Images》中有个比较形象的示意:

图上方的三种颜色的点表示数据的分布状况,黑色的线表示分布边界。在这里数据的边界很容易被确定,因为数据相对较多,算法很容易找到规律。下方区域因为样本存在的概率极低,远离上方数据的主要分布区域,其分类边界很难控制。所以对抗样本的构造可以有两个思路,一种是从一个确定类别的样本出发,对其做一些修改,让模型判定为另一种类别,即图中左上角蓝色圆点向白色方框的转变;另一种思路是利用分类边界的不可确定性,在远离小圆点的区域,很容易得到算法高概率认为是一个类别的样本,而实际上却难以辨认的对抗性样本,在图中即是G0和I0的例子。

对于第一个思路,以深度神经网络为例,深度神经网络是数学上可微的模型,在训练过程中通常使用反向传播算法得到每层的梯度来调整网络参数。假设神经网络的输入是X,类别标签是Y,网络参数是W,输出是F(X)=W*X。训练神经网络时,对于每个确定的输入样本X,我们反复调整网络参数W使得输出值F(X)趋向于该样本的类别标签Y。生成对抗样本使用同样的方法,区别只是我们固定网络参数W,反复修改输入样本X使得输出值F(X)趋向于攻击目标Y’。这意味着我们只需要修改目标函数以及约束条件,就可以使用与训练神经网络同样的方法计算得到对抗性样本

那么什么是约束条件呢?从X起始求解X’使得F(X’)=Y’的过程中,我们必须保证X’的标签不是Y’。例如,对于一个手写体输入“1”,如果我们把它改成“2”使得模型判别是“2”,那就不算是攻击。在计算机视觉领域,我们不太可能使用人力判定攻击方法生成的每一个样本X’,因此引入了距离函数Δ(X, X’)。我们假设在一定的距离内,X’的 含义和标签与X是一致的。距离函数可以选择不同的Norm来表示,比如L2, L∞, 和L0 ,这里的距离便是约束。

怎么修改输入样本X呢?目前图片对抗样本的生成主要是添加噪声的方式,在Christian Szegedy的论文《Intriguing properties of neural networks》提到了计算噪声的方法:

其中n是要求的噪音,α是相应的系数,L是x+n属于某个类别的loss,c是某个错误类别的标签。论文中用来得到图像噪声的办法是L-BFGS,这个方法虽然稳定有效,但是很考验算力。针对这个问题,这篇文章的第六作者,生成式对抗网络的发明人Ian Goodfellow在《Explaining and Harnessing Adversarial Examples》中提出了一种更快速方便的方法来产生对抗样本:

这种方法的思想非常简单,就是让输入图像朝着让类别置信度降低的方向上移动一个在各个维度上都是ε这么大小的一步。因为输入通常是高维的(比如224×224),再加上现在的主流神经网络结构都是ReLU系的激活函数,线性程度其实很高,所以即使是很小的ε,每个维度的效果加一块,通常也足以对结果产生很大的影响,比如下面这样:

在计算上,这种方法优势巨大,因为只需要一次前向和一次后向梯度计算就可以了。Ian Goodfellow称之为FSG(Fast Gradient Sign method)。

对于第二个思路,可以利用Fuzzing测试的方式生成对抗样本。以手写数字图像识别为例,我们的目标是产生对抗图片,使其看起来是“1”,而机器学习模型却识别为“2”。我们的主要思路是将这样一个对抗样本生成的问题,转换为一个漏洞挖掘的问题,如下图所示:

实际的做法就是将“1”的图片进行大量的变异然后放到模型里尝试,如果模型将其识别成“2”或者其他数字,那么这个变异的样本就是我们要找的对抗样本,且极有可能就是处在分类边界不确定的区域。

四、实践

本文选用SqueezeNet轻量级神经网络模型作为攻击对象,在Caffeine框架的基础上实现FSG对抗样本生成的方法。首先在Caffe中装载准备好的模型定义和参数文件,并初始化读取三通道彩色图片的transformer:

# model to attack
model_definition = 'deploy.prototxt'
model_weights = 'squeezenet_v1.0.caffemodel'
channel_means = numpy.array([104., 117., 123.])

# initialize net
net = caffe.Net(model_definition, model_weights, caffe.TEST)
n_channels, height, width = net.blobs['data'].shape[-3:]
net.blobs['data'].reshape(1, n_channels, height, width)

# initialize transformer
transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape})
transformer.set_transpose('data', (2, 0, 1))
transformer.set_mean('data', channel_means)
transformer.set_raw_scale('data', 255)
transformer.set_channel_swap('data', (2, 1, 0))

在实际处理时以下面这张图片为例,读取图片并进行前向计算类别置信度,和后向计算梯度

代码如下:

 # Load image & forward
transformed_img = transformer.preprocess(data_blob, img)
net.blobs[data_blob].data[0] = transformed_img
net.forward()
probs = [x for x in enumerate(net.blobs[prob_blob].data.flatten())]
num_classes = len(probs)
sorted_probs = sorted(probs, key=itemgetter(1), reverse=True)
top_preds = sorted_probs[:top_k]
pred = sorted_probs[0][0]
print sorted_probs[0],

# if label_index is set,
# generate a adversarial example toward the label,
# else
# reduce the probability of predicted label
net.blobs[prob_blob].diff[...] = 0
if type(label_index) is int and 0 <= label_index < num_classes:
    net.blobs[prob_blob].diff[0][label_index] = 1.
else:
    net.blobs[prob_blob].diff[0][pred] = -1.

# generate attack image with fast gradient sign method
diffs = net.backward()
diff_sign_mat = numpy.sign(diffs[data_blob])
adversarial_noise = epsilon * diff_sign_mat

adversarial_noise即是要叠加在原始样本上的噪声,第31行和第30行分别表示两种改变原始样本的方式。第一种,当没有定义label_index的时候,会将样本向减弱当前类别方向改变,前进幅度为1.0。这样得到的噪声并不是最终的结果,需要将其叠加在原始图像上;第二种,当定义label_index的时候,会将样本向指定的label_index类别方向改变,前进幅度为1.0。要注意的是,用caffe.io.load_image读取的图片是一个值为0到1之间的矩阵,经过transformer的处理之后,得到的新的矩阵中每个像素的值会在0到255之间。所以加入到原图片后还得考虑像素值是否会溢出,所以产生最后对抗样本图片的代码如下:

# clip exceeded values
attack_hwc = transformer.deprocess(data_blob, transformed_img + adversarial_noise[0])
attack_hwc[attack_hwc > 1] = 1.
attack_hwc[attack_hwc < 0] = 0.
attack_img = transformer.preprocess(data_blob, attack_hwc)

所有代码整合以后,先尝试第一种改变图像的方式,将样本向减弱当前类别方向改变,运行结果如下所示

左图是原始图像,下方是图像识别的可能性最高的五种结果,可能性最高的结果是边境牧羊犬(border collie),由于图片中是一只无名犬,从直观上来说算法的准确率还算可以;中图是生成的噪声;右图是叠加噪声之后的图像,下方是图像识别的可能性最高的五种结果,而此时的结果与左图已经完全不同了,可能性最高的是波士顿公牛(boston bull)。噪声叠加前后在人眼看来没有任何差别,但是机器学习模型却会得出完全不同的结果,这就是我们在图3-1提到的效果。

然后是第二种改变图像的方式,将样本向指定的label_index类别方向改变,这里我们指定将其改变为北极熊(ice bear),运行结果如下:

由上图可见,北极熊(ice bear)已经出现在了预测的结果中,只是置信度只有13.20%,接下来我们尝试将噪声的强度增加为2.0,结果如下:

极熊(ice bear)的置信度已经提高到46.14%且排在了第一位,那么是不是强度越高,更改的效果就越好呢?在Ian Goodfellow的论文《Explaining and Harnessing Adversarial Examples》中有如下的一个实验曲线图

这是一个攻击手写数字识别模型的一个实验(手写数字识别是神经网络当中的经典实验),图中以数字“4”为例,当ε为0时指不加入任何噪声;当ε为负数时指将样本向减弱当前类别方向改变;当 ε为正数时指将样本向指定的类别方向改变。这里看到这种变化基本上是线性的,也就是说噪声强度越高,改变程度越大。接下来将噪声强度分别改为3.0、4.0、5.0、6.0,分别得到如下结果:

当噪声强度为6.0的时候置信度最高的已经是泰迪熊(teddy)了,为什么跟预期的不一致呢?暂时没有找到太好的解释,只能说对抗样本的产生噪声强度并不是完全线性的。这里可能还要探究对抗样本存在的根本的原因–高维空间搜索的不可行。学习的过程可以看做是搜索的过程,它在预定义的假设空间中搜索假设,使其与训练样例有最佳的拟合度。但是在高维空间中必然有模型和数据无法触及的盲区,这也就导致了对抗样本的存在。

基于上面的问题,接下来我们考虑一下如何更好的生成对抗样本。前面的实验都是以1.0为步长调整噪声强度,效果不一定会好,一个较好的方法就是借鉴梯度法的思路,以一个较小的步长多次迭代。这种方法效果较好的但是由于迭代会导致较慢的速度,将代码做如下调整,迭代运行20次,每次增加强度为0.05的噪声。

attack_img, original_preds, attacked_preds = \
    make_n_test_adversarial_example(img, net, transformer, 0.05, label_index=296)
for i in range(19):
    attack_img, _, attacked_preds = \
        make_n_test_adversarial_example(attack_img, net, transformer, 0.05, label_index=296)

可以看到经过20的迭代加入噪声,北极熊(ice bear)的置信度已经高达100%。将整个迭代过程用曲线表示出来则如下图所示,其中红线是图像被识别成边境牧羊犬(border collie)的置信度变化过程,随着噪声逐次叠加其知悉度越来越小;黄线是被识别成猫鼬(meerkat)的置信度变化过程,由于在20次的迭代过程中只出现一次这样的结果,单点无法成线,所以出现了图中的断点;蓝线是被识别成北极熊(ice bear)的置信度变化过程,随着迭代次数增加其置信度逐渐增加,第20次时已经基本达到100%。

Ian Goodfellow在ICLR 2017的论文《Adversarial Examples in The Physical World》中也描述了这种方法,并进一步细分为两步:1)减小预测为原始类别的置信度;2)增大原来被预测为最小可能类别的置信度。这一描述与上图的置信度变化十分吻合。

五、结论

本文主要从对抗样本生成的角度研究了机器学习对抗攻击的原理和具体攻击过程,并对对抗样本生成的算法进行了评估。实验表明对抗样本可以有效的对机器学习模型产生干扰,使其做出错误的预测结果。不过在实验过程中也发现并不是每一个样本都可以很轻松的转换为其他任意类型的样本,在转换的过程中也存在着某种制约,比如“狗”向“杯子”的转变难度要远大于“狗”向“熊”的转变难度,样本的内在关联起到了很重要的作用。

六、参考文献

http://blog.csdn.net/u010193446/article/details/53259294

http://blog.csdn.net/xiangzhihong8/article/details/70207976

http://www.freebuf.com/articles/neopoints/124614.html

https://www.csdn.net/article/2015-12-28/2826566

https://arxiv.org/pdf/1412.6572.pdf

https://arxiv.org/pdf/1412.1897.pdf

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*