5.2.5 使用tensorflow生成对抗样本
下面介绍在tensorflow平台生成对抗样本的基本过程,示例代码为:
https://github.com/duoergun0729/adversarial_examples/blob/master/code/
5-case2-tensorflow-pb.ipynb
在示例中,通过损失函数在反向传递过程中直接调整原始图像的值,直到满足最大迭代次数或者对抗样本预测值达到预期为止,这里需要指出的是inception和alexnet模型中相同物体对应的标签是不一样的,比如熊猫在inception中为169,在alexnet中为388,如图5-8所示。
图5-8 使用tensorflow生成对抗样本的流程
首先加载使用的库文件,被攻击的模型是pb格式,tensorflow把计算图以及模型参数都保存在一个pb文件中,因此不用额外引入模型计算图定义的库。
import numpy as np
from pil import image
import tensorflow as tf
import re
创建会话并定义可以训练的变量adv,adv保存攻击样本,target为定向攻击的标签值。
session=tf.session()
#adv为对抗样本可以被训练和修改的量
adv = tf.get_variable(name="adv", shape=[1,100,100,3], dtype=tf.float32,
initializer=tf.zeros_initializer)
target = tf.placeholder(tf.int32)
从pb文件中还原出计算图,并与当前会话关联。在还原计算图的过程中,把输入的tensor与adv关联起来,从而达到把变量adv变成计算图输入的目的。
def create_graph(dirname):
with tf.gfile.fastgfile(dirname, 'rb') as f:
graph_def = session.graph_def
graph_def.parsefromstring(f.read())
_ = tf.import_graph_def(graph_def, name='adv',
input_map={"expanddims:0":adv} )
#从'http://download.tensorflow.org/models/image/imagenet/inception-2015-12-05.tgz'下载并解压到指定路径
create_graph("models/classify_image_graph_def.pb")
完成计算图和tensor的定义后,也只是完成了定义全部变量,并没有完成初始化操作,需要通过tf.global_variables_initializer手工进行初始化。
# 初始化参数非常重要
session.run(tf.global_variables_initializer())
tensorlist=[n.name for n in session.graph_def.node]
#这里注意,一定要查看当前tensor的名称,因为导入pb时指定了名称前缀adv
softmax_tensor = session.graph.get_tensor_by_name('adv_1/softmax:0')
logits_tensor=session.graph.get_tensor_by_name('adv_1/softmax/logits:0')
对原始图像进行预测,并显示top3的预测值。
imagename="../picture/cropped_panda.jpg"
image=np.array(image.open(imagename).convert('rgb')).astype(np.float32)
#[100,100,3]->[1,100,100,3]
image=np.expand_dims(image, axis=0)
predictions = session.run(softmax_tensor,
{adv: image})
predictions = np.squeeze(predictions)
# creates node id --> english string lookup.
node_lookup = nodelookup()
#获得top 3预测结果
top_k = predictions.argsort()[-3:][::-1]
for node_id in top_k:
human_string = node_lookup.id_to_string(node_id)
score = predictions[node_id]
print('%s (score = %.5f)(id = %d)' % (human_string, score,node_id))
在图像分类领域,经常使用top3或者top5的预测值,衡量准确率和错误率时也使用top3或者top5的预测值来计算,比如top3预测值中有一个正确,也可以理解为预测正确,反之亦然。本例中的预测结果top1就是熊猫,满足预期。
giant panda, panda, panda bear, coon bear, ailuropoda melanoleuca (score =
0.89233)(id = 169)
indri, indris, indri indri, indri brevicaudatus (score = 0.00859)(id = 75)
lesser panda, red panda, panda, bear cat, cat bear, ailurus fulgens (score =
0.00264)(id = 7)
下面开始迭代求解,定义学习率lr和迭代的最大次数epochs。定义损失函数为交叉熵函数,具体以预测结果的logits值与攻击目标标签计算交叉熵。优化器使用adam,由于adam自身也包含需要根据训练过程调整的参数,所以还需要调用tf.global_variables_initializer进行一次参数初始化。
epochs=500
lr=0.1
target_label=288
cross_entropy =
tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits_tensor,
labels=[target])
optimizer = tf.train.adamoptimizer(lr)
train_step=optimizer.minimize(loss=cross_entropy,var_list=[adv])
# 初始化参数非常重要,adam的参数也需要这样初始化,gradientdescent可以省略这一步
session.run(tf.global_variables_initializer())
迭代开始前,把adv的值初始化为原始图像值。
#初始化
session.run(tf.assign(adv, image))
for epoch in range(epochs):
#获得损失值、对抗样本和预测值
loss,_,adv_img,predictions=session.run([cross_entropy,
train_step,adv,softmax_tensor],
{target:target_label})
predictions = np.squeeze(predictions)
label=np.argmax(predictions)
print("epoch={} loss={} label={}".format(epoch,loss,label))
#如果定向攻击成功
if label == target_label:
#打印top3预测结果
top_k = predictions.argsort()[-3:][::-1]
for node_id in top_k:
human_string = node_lookup.id_to_string(node_id)
score = predictions[node_id]
print('%s (score = %.5f)(id = %d)' % (human_string, score,node_id))
break
经过34轮迭代计算,攻击成功,预测标签为288。
epoch=32 loss=[2.6293871] label=169
epoch=33 loss=[2.3296964] label=169
epoch=34 loss=[2.0458288] label=288
snowmobile (score = 0.12927)(id = 288)
giant panda, panda, panda bear, coon bear, ailuropoda melanoleuca (score =
0.12047)(id = 169)
indri, indris, indri indri, indri brevicaudatus (score = 0.04191)(id = 75)