本篇文章8751字,读完约22分钟
雷锋。(公开号码:雷锋。新闻:在之前发表的文章《谈论cnn:如何通过优化解决输入图像》中,我们提到了对抗样本的问题。作为本文的继续,我们将讨论如何通过快速梯度符号法在caffe中生成对抗样本。《智湖》栏目发表的原作者《达文西》是经雷锋授权的。
快速梯度符号法首先回顾了克里斯蒂安·塞格迪的论文《谈论cnn:如何通过优化解决输入图像》中通过添加噪声来生成对策样本的方法:
其中n是所需的噪声和相应的系数,l是属于某一类别的x+n的损失,c是错误类别的标签。L-bfgs是本文中用来去除图像噪声的方法。虽然这种方法是稳定和有效的,但它是对计算能力的考验。无论如何,christian在谷歌有很多强大的机器。使用这种方法生成计数器样本自然没有问题,但是如果它不是一个土皇帝,它就不合适。为了解决这个问题,本文的第六作者、生成对抗网络的发明者ian goodfellow提出了一种更快、更方便的方法来生成解释和调和示例中的对抗样本:
这种方法的思想非常简单,即使输入图像向降低类别置信度的方向移动一步,在所有维度上具有相同的大小。由于输入通常是高维的(如224×224),而当前主流的神经网络结构是relu系统的激活函数,其线性度实际上很高,所以即使它很小,每个维数加一个块的效果通常也足以对结果产生很大的影响,如以下:
在计算上,这种方法有很大的优势,因为它只需要一次前向梯度计算和一次后向梯度计算。伊恩·古德费勒称之为快速梯度设计法。
用caffe生成对抗样本的fgs方法非常简单,可以用任何框架轻松实现。ian goodfellow有一个正式的完整工具包,基于tensorflow,详细链接:
t/rkaxouz
这是caffe的python接口实现的一个例子。
首先,我们需要准备好要攻击的模型。这里我们使用在imagenet数据集上预先训练的squeezenet v1.0作为例子:
t/rkaxwrl
下载两个文件就足够了:
t/rkaxrq7
t/rkax3rz
由于需要逆向计算,下载deploy.prototxt后的第一件事就是添加以下句子:
force_backward: true
首先,将准备好的模型定义和参数文件加载到caffe中,并初始化用于读取三通道彩色图片的转换器:
#攻击模型
model _ definition =/path/to/deploy . prototxt
model _ weights =/path/to/squeezenet _ v 1.0 . caffe model
channel_means = numpy.array([104。,117。,123。])
#初始化网络
net = caffe.net(model_definition,model_weights,caffe.test)
n _ channels,height,width = net . blob[data]。形状[-3:]
net.blobs数据]。整形(1,n _通道,高度,宽度)
#初始化变压器
transformer = caffe . io . transformer({ data:net . blob[data]. data . shape })
transformer.set _转置(数据,(2,0,1))
transformer.set_mean(数据,通道_mean)
transformer.set_raw_scale(数据,255)
transformer.set_channel_swap(数据,(2,1,0))
因为它只演示了如何制作对抗样本,为了方便起见,一次只处理一张图片。下一步是读取图片,向前计算类别的置信度,向后计算梯度。我们使用以下白色小狗的图片作为输入:
代码如下:
#加载图像并转发
img = caffe . io . load _ image(little _ white _ dog . jpg)
transformed_img = transformer.preprocess( data , img)transformed _ img = transformer . preparation(数据,img)
net.blobs[ data ].data[0] = transformed_imgnet.blobs数据]。数据[0] = transformed_img
net.forward()
#获取预测标签索引
pred = numpy . arg max(net . blob[prob]. data . flat())
#设置梯度方向以减少当前预测
net . blob[prob]。diff[0][pred] = -1。
#用快速梯度符号法生成攻击图像
diffs = net.backward()
diff _ sign _ mat = numpy . sign(diff[data])
对抗噪声= 1.0 *差分符号
这样,用它来抵消叠加在原始图像上的样本噪声就很好了。在这段代码中,我们执行生成一个计数器样本,以减少当前模型的预测类别,其中每个像素在梯度方向上的前进幅度为1.0。如果要生成一个对抗样本,使模型预测图像成为一个指定的类别,则需要将为梯度赋值的语句更改为以下语句:
net . blob[prob _ blob]。diff[0][label_index]=1。
其中label_index是您希望模型做出错误预测的类别。应该注意的是,由caffe.io.load_image读取的图片是一个0到1之间的数组。经过变压器处理后,新数组中每个像素的值将在0到255之间。此外,所获得的噪声通常不是最终结果,因为有必要考虑像素值在被添加到原始图像之后是否会溢出,所以用于生成最终反采样图像的代码如下:
#剪辑超出值
attack_hwc = transformer.deprocess(data_blob, transformed_img + adversarial_noise[0])攻击_ hwc = transformer . de process(data _ blob,transformed_img +敌对_noise[0])
攻击_ hwc[攻击_hwc > 1] = 1。
attack_hwc[attack_hwc
attack_img = transformer.preprocess(data_blob, attack_hwc)攻击_hwc[攻击_hwc攻击_img = transformer .预处理(data_blob,攻击_ hwc)
attack_img就是和caffe的blob形状一致的对抗样本了,attack_hwc是维度按照图片高度,图片宽度,图片通道顺序的格式,可以用matplotlib直接可视化。攻击_img是与caffe的斑点形状相同的对抗样本。attack _ hwc是根据图片高度、图片宽度和图片通道的顺序而定的尺寸格式,可以用matplotlib直接可视化。
可视化和简单分析为了便于分析,我们将生成对抗样本的过程打包成一个函数:
def make _ n _ test _对抗性_示例(
img,网络,变压器,ε,
data_blob= data,prob_blob= prob,
label _ index =无,top_k=5):
#加载图像并转发
transformed_img = transformer.preprocess(data_blob, img)transformed _ img = transformer . preparation(data _ blob,img)
net.blobs[data_blob].data[0] = transformed_imgnet . blob[data _ blob]。数据[0] = transformed_img
net.forward()
probs = [x代表枚举中的x(net . blob[prob _ blob]. data . flat())]
num _ class = len(probs)
sorted_probs = sorted(probs,key=itemgetter(1),reverse=true)
top_preds = sorted_probs[:top_k]
pred = sorted_probs[0][0]
#如果设置了label_index,
#针对标签生成一个对抗性示例,
#否则
#降低预测标签的概率
net . blob[prob _ blob]。差异[...] = 0
如果类型(label_index)为int且0为net . blob[prob _ blob]。diff[0][label_index] = 1。
否则:
net . blob[prob _ blob]。diff[0][pred] = -1。
#用快速梯度符号法生成攻击图像
diffs = net.backward()
diff _ sign _ mat = numpy . sign(diff[data _ blob])
对抗噪声=ε*差分符号
#剪辑超出值
attack_hwc = transformer.deprocess(data_blob, transformed_img + adversarial_noise[0])攻击_ hwc = transformer . de process(data _ blob,transformed_img +敌对_noise[0])
攻击_ hwc[攻击_hwc > 1] = 1。
attack_hwc[attack_hwc
attack_img = transformer.preprocess(data_blob, attack_hwc)攻击_hwc[攻击_hwc攻击_img = transformer .预处理(data_blob,攻击_ hwc)
net.blobs[data_blob].data[0] = attack_imgnet . blob[data _ blob]。数据[0] =攻击_img
net.forward()
probs = [x代表枚举中的x(net . blob[prob _ blob]. data . flat())]
sorted_probs = sorted(probs,key=itemgetter(1),reverse=true)
top _ attack _ preds = sorted _ probs[:top _ k]
返回攻击_hwc,顶部攻击_preds,顶部攻击_preds
该函数使用caffe.io.load_image读取的数组作为输入图像,并且需要网络和转换器。ε是噪声的幅度,label_index默认为无。此时,生成的计数器样本降低了当前预测的可信度。如果label_index设置为指定的类别,则生成的对抗样本将尝试增加模型预测该类别的可信度。最后,该函数返回可由matplotlib直接可视化的挑战样本攻击_hwc、原始图片的模型预测的前k个类别和相应的置信度前p,以及挑战样本的模型预测的前k个类别和相应的置信度前p。
上述功能的结果可以通过以下功能可视化:
def visualize_attack(title, original_img, attack_img, original_preds, attacked_preds, labels):def visualize _ attack(标题、原始_img、攻击_img、原始_preds、攻击_preds、标签):
pred = original_preds[0][0]
攻击_pred =攻击_ pred[0][0]
k = len(original_preds)
fig_name = {}: {}至{}。格式(标题、标签[pred]、标签[attached _ pred])
pyplot.figure(fig_name)
for img, plt0, plt1, preds in [对于img,plt0,plt1,preds in [
(original_img, 231, 234, original_preds),(original _ img,231,234,original _ preds),
(attack_img, 233, 236, attacked_preds)(攻击_img,233,236,攻击_preds)
]:
pyplot.subplot(plt0)
pyplot.axis(关闭)
pyplot.imshow(img)pyplot.imshow(img)
ax = pyplot.subplot(plt1)
pyplot.axis(关闭)
ax.set_xlim([0,2])
bars = ax.barh(范围(k-1,-1,-1),[x[1]代表preds中的x])
对于I,枚举中的bar(bar):
x _ loc = bar . get _ x()+bar . get _ width()
y_loc = k - i - 1
标签=标签[preds[i][0]]
ax.text(x_loc,y_loc,{}: {:.2f}%。格式(标签,preds[i][1]*100))
pyplot.subplot(232)
pyplot.axis(关闭)
noise = attack_img - original_img噪声=攻击_img -原始_img
pyplot.imshow(255 *噪声)
该代码将显示原始图片和模型预测的类别和置信度,样本图片和模型预测的类别和置信度,以及叠加在原始图片上的噪声。此外,为了便于直观理解,您需要输入每个类别的名称。对于imagenet数据,您可以从caffe下载synset _ words.txt,然后按顺序读取列表中的类别。在下面的例子中,我们假设这个列表是标签。
一切都准备好了,要想看到效果,首先要用振幅为1:
attack_img, original_preds, attacked_preds = \攻击_img,原始_preds,攻击_preds = \
make_n_test_adversarial_example(img, net, transformer, 1.0)make _ n _ test _对抗性示例(img,net,transformer,1.0)
visualize_attack( example0 , img, attack_img, original_preds, attacked_preds, labels)可视化攻击(示例0,img,攻击img,原始preds,攻击preds,标签)
结果如下:
中国园林狗不属于imagenet的范畴,因此模型预测的结果是大比利牛斯山脉。考虑到小狗的皮毛颜色和形状,这个结果是合理的,这表明squeezenet v1.0仍然是好的。经过1个像素的噪声叠加后,模型的预测结果变得模糊不清)……...
接下来,尝试生成一个模型预测为特定类别的对抗样本。既然最初的类别是大白熊,试试直接预测为真的大白熊,也就是冰熊:
attack_img, original_preds, attacked_preds = \攻击_img,原始_preds,攻击_preds = \
make_n_test_adversarial_example(img, net, transformer, 1.0, label_index=296)make _ n _ test _对抗性示例(img,net,transformer,1.0,label_index=296)
visualize_attack( example1 , img, attack_img, original_preds, attacked_preds, labels)可视化攻击(示例1,img,攻击img,原始preds,攻击preds,标签)
从结果来看,这是非常好的,这是一个非常高的信心水平,但黄鼠狼再次排名第二。无论是大白熊狗、北极熊还是黄鼠狼,都是哺乳动物。事实上,它在外观上是相似的。接下来,再努力一点。试着预测小白狗是一只振幅为1的鸵鸟。该代码将替换先前代码的label_index,并停止粘贴:
它仍然是一个黄鼠狼,所以尝试使用更强的噪声,并将噪声幅度设置为2.0:
成功地,虽然置信度不是很高,但是噪声幅度被进一步提高到6.0:
预测鸵鸟的信心大大提高了!那么,噪声幅度越大,预测鸵鸟的置信度越高吗?根据伊恩论文中的图表(图4),看起来是这样的:
ian论文的一个主要论点是,在流行的深层网络中,对抗样本存在的主要原因是模型是高度线性的,这在上述论文的图4中得到了支持,并且对抗样本可以在不同的模型之间进行推广。但是为什么线性是主要原因呢?伊恩似乎没有给出定量的、特别有说服力的证据。事实上,最初的图4只是mnist的一个例子,稍微复杂的数据的线性度已经被削弱了,比如伊恩自己为kdkings写的文章《深度学习敌对范例-澄清误解》中的图片。文章详细信息:
t/rlvzahm
本质上,这是因为在高维空之间的搜索是不可行的,以抵制样本的存在,并且很自然地抵制样本出现在数据和模型不能到达的角落。虽然模型的线性度和相应的输入空的划分是计数器样本存在的主要原因,但是由于其他因素引起的计数器样本也是不可忽视的,例如狗变成蟾蜍的情况。毕竟,作为一种通用的逼近器,神经网络起源于非线性。
虽然没有距离的概念来更好地通过迭代生成对抗样本的分类模型,但是在输入空中明显相似的类别将会更接近。从上半部分的例子中还可以看出,狗比较容易变成熊或黄鼠狼,变成鸵鸟稍微难一点,而变成其他不太相似的动物,比如球拍,就更难了。我们还在球拍对抗样本上尝试了鸵鸟对抗样本的四个振幅(1.0,2.0,6.0,18.0),结果如下。球拍相关链接如下:
球拍-郎/
经验丰富的黑脚雪貂、黄鼠狼、天竺鼠,最后变成了蟾蜍。这表明,线性解决方案是无效的这种球拍是非常不同于小狗。事实上,在许多情况下,用纯fgs创建对抗样本是无效的,可能是因为这两个类别之间的差异太大;也许某个类别内的差异太大(例如,imagenet中的所有狗都被算作一个类别,而其他的被算作一个类别的两个类别);即使是最极端的类别也可能处于relu小于0的“死区”。仅考虑前两种情况,我们需要一种比fgs更好、更实用的方法。因为fgs直接向前迈出一大步可能是错误的,一个自然的想法是从梯度下降的想法中学习,一步一步地进行迭代。虽然这种方法是非常非线性的(从梯度方向来看),并且需要计算很多次,但它仍然比l-bfgs方法简单,并且其效果是群外的。伊恩·古德费勒在iclr 2017年的论文《物理世界中的敌对例子》中描述了这种方法,该论文进一步细分为两种类型:1)降低预测作为原始类别的可信度;2)提高最小可能类别的置信度。
基于这一思想,我们修改了第二种方法,并尝试通过迭代方法来增加球拍的置信度,每次迭代和十次迭代的置信度为0.1:
attack_img, original_preds, attacked_preds = \攻击_img,原始_preds,攻击_preds = \
make_n_test_adversarial_example(img, net, transformer, 0.1, label_index=752)make _ n _ test _对抗性示例(img,net,transformer,0.1,label_index=752)
对于范围(9)中的I:
attack_img, _, attacked_preds = \攻击_img,_,攻击_preds = \
make_n_test_adversarial_example(attack_img, net, transformer, 0.1, label_index=752)make _ n _ test _对抗性示例(攻击_img,网络,转换器,0.1,标签_索引=752)
visualize_attack( racket_try1 .format(i), img, attack_img, original_preds, attacked_preds, labels)可视化_攻击(球拍_尝试1。格式(I),img,攻击_img,原始_preds,攻击_preds,标签)
应该注意的是,通过外部调用进行迭代的写入效率不高,而且每次都包含一个冗余的正向计算。为了简单起见,这里写了这个,迭代的结果如下:
成功拿到球拍。
有关详细信息,请参见本文中的完整代码:
t/rkayode
雷锋。com相关阅读:
谈论cnn:如何通过优化解决输入图像
卷积神经网络不能处理“图”结构数据吗?这篇文章告诉你答案
开发者特别会议|英伟达深度学习学院现场授课
英伟达dli高级工程师现场指导,理论联系实际,深入学习!
课程链接:mooc.ai/course/90
雷锋文章版权所有。严禁擅自转载。详情请参考转载说明。
标题:如何用 Caffe 生成对抗样本?这篇文章告诉你一个更高效的算法
地址:http://www.hcsbodzyz.com/hcxw/9874.html