手把手教你使用TensorFlow生成对抗样本 | 附源码
2017-12-28 15:08
405 查看
原文链接:点击打开链接
摘要: 本文使用TensorFlow一步一步生成对抗样本,步骤明确清晰。首先生成的对抗样本不具有旋转鲁棒性,后面使用同样的方法生成具有鲁棒性的对抗样本,适合初学者对生成对抗样本的入门及动手实验。
更多深度文章,请关注:https://yq.aliyun.com/cloud
如果说卷积神经网络是昔日影帝的话,那么生成对抗已然成为深度学习研究领域中一颗新晋的耀眼新星,它将彻底地改变我们认知世界的方式。对抗学习训练为指导人工智能完成复杂任务提供了一个全新的思路,生成对抗图片能够非常轻松的愚弄之前训练好的分类器,因此如何利用生成对抗图片提高系统的鲁棒性是一个很有研究的热点问题。
神经网络合成的对抗样本很容易让人大吃一惊,这是因为对输入进行小巧精心制作的扰动就可能导致神经网络以任意选择的方式对输入进行错误地分类。鉴于对抗样本转移到物质世界,可以使其变得非常强大,因此这是一个值得关注的安全问题。比如说人脸识别,若一张对抗图像也被识别为真人的话,就会出现一些安全隐患及之后带来的巨大损失。对生成对抗图像感兴趣的读者可以关注一下最近的Kaggle挑战赛NIPS,相关的信息可以参看博主的另外一篇:
在这篇文章中,将手把手带领读者利用TensorFlow实现一个简单的算法来合成对抗样本,之后使用这种技术建立一个鲁棒的对抗性例子。
本文是一个可执行的Jupyter
notebook:可以下载并自己实验操作一下示例!
我们选择攻击在ImageNet数据集上训练的Inception
v3网络。首先我们从TF-slim图像分类库中加载预先训练的网络。这部分不是很有趣,所以请随意跳过本部分。
首先,设置输入图像。使用tf.Variable而不是使用tf.placeholder,这是因为要确保它是可训练的。当我们需要时,仍然可以输入它。
接下来,加载Inception v3模型。
接下来,加载预训练的权重。这个Inception
v3的top-5的准确率为93.9%。
接下来,编写一些代码来显示图像,并对它进行分类及显示分类结果。
加载示例图像,并确保它已被正确分类。
对抗样本
给定一个图像X,神经网络输出标签上的概率分布为P(y|X)。当手工制作对抗输入时,我们想要找到一个X',使得logP(y'|X')被最大化为目标标签y',即输入将被错误分类为目标类。通过约束一些ℓ∞半径为ε的箱,要求‖X- X'‖∞≤ε,我们可以确保X'与原始X看起来不太一样。
在这个框架中,对抗样本是解决一个约束优化的问题,可以使用反向传播和投影梯度下降来解决,基本上也是用与训练网络本身相同的技术。算法很简单:
首先将对抗样本初始化为X'←X。然后,重复以下过程直到收敛:
1. X'←X^+α⋅∇logP(y'|X')
2. X'←clip(X',X - ε,X+ε)
首先从最简单的部分开始:编写一个TensorFlow op进行相应的初始化。
接下来,编写梯度下降步骤以最大化目标类的对数概率(或最小化交叉熵)。
最后,编写投影步骤,使得对抗样本在视觉上与原始图像相似。另外,将其限定为[0,1]范围内保持有效的图像。
最后,准备合成一个对抗样本。我们任意选择“鳄梨酱”(imagenet
class 924)作为我们的目标类。
结果如下
这种对抗图像与原始图像在视觉上无法区分,没有可见的人为加工。但是它会以很高的概率分类为“鳄梨酱”。
现在来看一个更高级的例子。遵循我们的方法来合成稳健的对抗样本,以找到对猫图像的单一扰动,这在某些选择的变换分布下同时对抗,可以选择任何可微分变换的分布;在这篇文章中,我们将合成一个单一的对抗输入,设置θ∈[- π/4,π/4],这对旋转是鲁棒的。
在继续下面的工作之前,检查一下之前的例子是否能对抗旋转,比如说设置角度为θ=π/8。
看起来我们之前生成的对抗样本不是旋转不变的!
那么,如何使得一个对抗样本对变换的分布是鲁棒的呢?给定一些变换分布T,我们可以最大化Et~TlogP(y'|t(X')),约束条件为‖X- X'‖∞≤ε。可以通过投影梯度下降法来解决这个优化问题,注意到∇Et~TlogP(y'|t(X'))与Et~T∇logP(y'|t(X'))相等,并在每个梯度下降步骤中来逼近样本。
可以使用一个技巧让TensorFlow为我们做到这一点,而不是通过手动实现梯度采样得到:我们可以模拟基于采样的梯度下降,作为随机分类器的集合中的梯度下降,随机分类器从分布中随机抽取并在分类之前变换输入。
我们可以重复使用assign_op和project_step,但为了这个新目标,必须写一个新的optim_step。
最后,我们准备运行PGD来产生对抗输入。和前面的例子一样,选择“鳄梨酱”作为我们的目标类。
结果如下
这种对抗图像被高度信任地归类为“鳄梨酱”,即使是旋转的情况下!
下面来看一下在整个角度范围内产生的鲁棒对抗样本的旋转不变性,看P(y'|x')在θ∈[- π/4,π/4]。
从图中蓝色曲线可以看到,生成的对抗样本是超级有效的。
摘要: 本文使用TensorFlow一步一步生成对抗样本,步骤明确清晰。首先生成的对抗样本不具有旋转鲁棒性,后面使用同样的方法生成具有鲁棒性的对抗样本,适合初学者对生成对抗样本的入门及动手实验。
更多深度文章,请关注:https://yq.aliyun.com/cloud
如果说卷积神经网络是昔日影帝的话,那么生成对抗已然成为深度学习研究领域中一颗新晋的耀眼新星,它将彻底地改变我们认知世界的方式。对抗学习训练为指导人工智能完成复杂任务提供了一个全新的思路,生成对抗图片能够非常轻松的愚弄之前训练好的分类器,因此如何利用生成对抗图片提高系统的鲁棒性是一个很有研究的热点问题。
神经网络合成的对抗样本很容易让人大吃一惊,这是因为对输入进行小巧精心制作的扰动就可能导致神经网络以任意选择的方式对输入进行错误地分类。鉴于对抗样本转移到物质世界,可以使其变得非常强大,因此这是一个值得关注的安全问题。比如说人脸识别,若一张对抗图像也被识别为真人的话,就会出现一些安全隐患及之后带来的巨大损失。对生成对抗图像感兴趣的读者可以关注一下最近的Kaggle挑战赛NIPS,相关的信息可以参看博主的另外一篇:
《Kaggle首席技术官发布——(Kaggle)NIPS
2017对抗学习挑战赛起步指南》
在这篇文章中,将手把手带领读者利用TensorFlow实现一个简单的算法来合成对抗样本,之后使用这种技术建立一个鲁棒的对抗性例子。本文是一个可执行的Jupyter
notebook:可以下载并自己实验操作一下示例!
建立
我们选择攻击在ImageNet数据集上训练的Inceptionv3网络。首先我们从TF-slim图像分类库中加载预先训练的网络。这部分不是很有趣,所以请随意跳过本部分。
import tensorflow as tf import tensorflow.contrib.slim as slim import tensorflow.contrib.slim.nets as nets tf.logging.set_verbosity(tf.logging.ERROR) sess = tf.InteractiveSession()
首先,设置输入图像。使用tf.Variable而不是使用tf.placeholder,这是因为要确保它是可训练的。当我们需要时,仍然可以输入它。
image = tf.Variable(tf.zeros((299, 299, 3)))
接下来,加载Inception v3模型。
def inception(image, reuse): preprocessed = tf.multiply(tf.subtract(tf.expand_dims(image, 0), 0.5), 2.0) arg_scope = nets.inception.inception_v3_arg_scope(weight_decay=0.0) with slim.arg_scope(arg_scope): logits, _ = nets.inception.inception_v3( preprocessed, 1001, is_training=False, reuse=reuse) logits = logits[:,1:] # ignore background class probs = tf.nn.softmax(logits) # probabilities return logits, probs logits, probs = inception(image, reuse=False)
接下来,加载预训练的权重。这个Inception
v3的top-5的准确率为93.9%。
import tempfile from urllib.request import urlretrieve import tarfile import os data_dir = tempfile.mkdtemp() inception_tarball, _ = urlretrieve( 'http://download.tensorflow.org/models/inception_v3_2016_08_28.tar.gz') tarfile.open(inception_tarball, 'r:gz').extractall(data_dir) restore_vars = [ var for var in tf.global_variables() if var.name.startswith('InceptionV3/') ] saver = tf.train.Saver(restore_vars) saver.restore(sess, os.path.join(data_dir, 'inception_v3.ckpt'))
接下来,编写一些代码来显示图像,并对它进行分类及显示分类结果。
import json import matplotlib.pyplot as plt imagenet_json, _ = urlretrieve( 'http://www.anishathalye.com/media/2017/07/25/imagenet.json') with open(imagenet_json) as f: imagenet_labels = json.load(f) def classify(img, correct_class=None, target_class=None): fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 8)) fig.sca(ax1) p = sess.run(probs, feed_dict={image: img})[0] ax1.imshow(img) fig.sca(ax1) topk = list(p.argsort()[-10:][::-1]) topprobs = p[topk] barlist = ax2.bar(range(10), topprobs) if target_class in topk: barlist[topk.index(target_class)].set_color('r') if correct_class in topk: barlist[topk.index(correct_class)].set_color('g') plt.sca(ax2) plt.ylim([0, 1.1]) plt.xticks(range(10), [imagenet_labels[i][:15] for i in topk], rotation='vertical') fig.subplots_adjust(bottom=0.2) plt.show()
示例图像
加载示例图像,并确保它已被正确分类。import PIL import numpy as np img_path, _ = urlretrieve('http://www.anishathalye.com/media/2017/07/25/cat.jpg') img_class = 281 img = PIL.Image.open(img_path) big_dim = max(img.width, img.height) wide = img.width > img.height new_w = 299 if not wide else int(img.width * 299 / img.height) new_h = 299 if wide else int(img.height * 299 / img.width) img = img.resize((new_w, new_h)).crop((0, 0, 299, 299)) img = (np.asarray(img) / 255.0).astype(np.float32) classify(img, correct_class=img_class)
对抗样本
给定一个图像X,神经网络输出标签上的概率分布为P(y|X)。当手工制作对抗输入时,我们想要找到一个X',使得logP(y'|X')被最大化为目标标签y',即输入将被错误分类为目标类。通过约束一些ℓ∞半径为ε的箱,要求‖X- X'‖∞≤ε,我们可以确保X'与原始X看起来不太一样。
在这个框架中,对抗样本是解决一个约束优化的问题,可以使用反向传播和投影梯度下降来解决,基本上也是用与训练网络本身相同的技术。算法很简单:
首先将对抗样本初始化为X'←X。然后,重复以下过程直到收敛:
1. X'←X^+α⋅∇logP(y'|X')
2. X'←clip(X',X - ε,X+ε)
初始化
首先从最简单的部分开始:编写一个TensorFlow op进行相应的初始化。x = tf.placeholder(tf.float32, (299, 299, 3)) x_hat = image # our trainable adversarial input assign_op = tf.assign(x_hat, x)
梯度下降步骤
接下来,编写梯度下降步骤以最大化目标类的对数概率(或最小化交叉熵)。learning_rate = tf.placeholder(tf.float32, ()) y_hat = tf.placeholder(tf.int32, ()) labels = tf.one_hot(y_hat, 1000) loss = tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=[labels]) optim_step = tf.train.GradientDescentOptimizer( learning_rate).minimize(loss, var_list=[x_hat])
投影步骤
最后,编写投影步骤,使得对抗样本在视觉上与原始图像相似。另外,将其限定为[0,1]范围内保持有效的图像。epsilon = tf.placeholder(tf.float32, ()) below = x - epsilon above = x + epsilon projected = tf.clip_by_value(tf.clip_by_value(x_hat, below, above), 0, 1) with tf.control_dependencies([projected]): project_step = tf.assign(x_hat, projected)
执行
最后,准备合成一个对抗样本。我们任意选择“鳄梨酱”(imagenetclass 924)作为我们的目标类。
demo_epsilon = 2.0/255.0 # a really small perturbation demo_lr = 1e-1 demo_steps = 100 demo_target = 924 # "guacamole" # initialization step sess.run(assign_op, feed_dict={x: img}) # projected gradient descent for i in range(demo_steps): # gradient descent step _, loss_value = sess.run( [optim_step, loss], feed_dict={learning_rate: demo_lr, y_hat: demo_target}) # project step sess.run(project_step, feed_dict={x: img, epsilon: demo_epsilon}) if (i+1) % 10 == 0: print('step %d, loss=%g' % (i+1, loss_value)) adv = x_hat.eval() # retrieve the adversarial example
结果如下
step 10, loss=4.18923 step 20, loss=0.580237 step 30, loss=0.0322334 step 40, loss=0.0209522 step 50, loss=0.0159688 step 60, loss=0.0134457 step 70, loss=0.0117799 step 80, loss=0.0105757 step 90, loss=0.00962179 step 100, loss=0.00886694
这种对抗图像与原始图像在视觉上无法区分,没有可见的人为加工。但是它会以很高的概率分类为“鳄梨酱”。
classify(adv, correct_class=img_class, target_class=demo_target)
鲁棒的对抗样本
现在来看一个更高级的例子。遵循我们的方法来合成稳健的对抗样本,以找到对猫图像的单一扰动,这在某些选择的变换分布下同时对抗,可以选择任何可微分变换的分布;在这篇文章中,我们将合成一个单一的对抗输入,设置θ∈[- π/4,π/4],这对旋转是鲁棒的。在继续下面的工作之前,检查一下之前的例子是否能对抗旋转,比如说设置角度为θ=π/8。
ex_angle = np.pi/8 angle = tf.placeholder(tf.float32, ()) rotated_image = tf.contrib.image.rotate(image, angle) rotated_example = rotated_image.eval(feed_dict={image: adv, angle: ex_angle}) classify(rotated_example, correct_class=img_class, target_class=demo_target)
看起来我们之前生成的对抗样本不是旋转不变的!
那么,如何使得一个对抗样本对变换的分布是鲁棒的呢?给定一些变换分布T,我们可以最大化Et~TlogP(y'|t(X')),约束条件为‖X- X'‖∞≤ε。可以通过投影梯度下降法来解决这个优化问题,注意到∇Et~TlogP(y'|t(X'))与Et~T∇logP(y'|t(X'))相等,并在每个梯度下降步骤中来逼近样本。
可以使用一个技巧让TensorFlow为我们做到这一点,而不是通过手动实现梯度采样得到:我们可以模拟基于采样的梯度下降,作为随机分类器的集合中的梯度下降,随机分类器从分布中随机抽取并在分类之前变换输入。
num_samples = 10 average_loss = 0 for i in range(num_samples): rotated = tf.contrib.image.rotate( image, tf.random_uniform((), minval=-np.pi/4, maxval=np.pi/4)) rotated_logits, _ = inception(rotated, reuse=True) average_loss += tf.nn.softmax_cross_entropy_with_logits( logits=rotated_logits, labels=labels) / num_samples
我们可以重复使用assign_op和project_step,但为了这个新目标,必须写一个新的optim_step。
最后,我们准备运行PGD来产生对抗输入。和前面的例子一样,选择“鳄梨酱”作为我们的目标类。
demo_epsilon = 8.0/255.0 # still a pretty small perturbation demo_lr = 2e-1 demo_steps = 300 demo_target = 924 # "guacamole" # initialization step sess.run(assign_op, feed_dict={x: img}) # projected gradient descent for i in range(demo_steps): # gradient descent step _, loss_value = sess.run( [optim_step, average_loss], feed_dict={learning_rate: demo_lr, y_hat: demo_target}) # project step sess.run(project_step, feed_dict={x: img, epsilon: demo_epsilon}) if (i+1) % 50 == 0: print('step %d, loss=%g' % (i+1, loss_value)) adv_robust = x_hat.eval() # retrieve the adversarial example
结果如下
step 50, loss=0.0804289 step 100, loss=0.0270499 step 150, loss=0.00771527 step 200, loss=0.00350717 step 250, loss=0.00656128 step 300, loss=0.00226182
这种对抗图像被高度信任地归类为“鳄梨酱”,即使是旋转的情况下!
rotated_example = rotated_image.eval(feed_dict={image: adv_robust, angle: ex_angle}) classify(rotated_example, correct_class=img_class, target_class=demo_target)
评估
下面来看一下在整个角度范围内产生的鲁棒对抗样本的旋转不变性,看P(y'|x')在θ∈[- π/4,π/4]。thetas = np.linspace(-np.pi/4, np.pi/4, 301) p_naive = [] p_robust = [] for theta in thetas: rotated = rotated_image.eval(feed_dict={image: adv_robust, angle: theta}) p_robust.append(probs.eval(feed_dict={image: rotated})[0][demo_target]) rotated = rotated_image.eval(feed_dict={image: adv, angle: theta}) p_naive.append(probs.eval(feed_dict={image: rotated})[0][demo_target]) robust_line, = plt.plot(thetas, p_robust, color='b', linewidth=2, label='robust') naive_line, = plt.plot(thetas, p_naive, color='r', linewidth=2, label='naive') plt.ylim([0, 1.05]) plt.xlabel('rotation angle') plt.ylabel('target class probability') plt.legend(handles=[robust_line, naive_line], loc='lower right') plt.show()
从图中蓝色曲线可以看到,生成的对抗样本是超级有效的。
相关文章推荐
- 源码干货 | 手把手教你使用TensorFlow生成对抗样本
- 使用TensorFlow生成对抗样本
- 生成对抗网络入门详解及TensorFlow源码实现--深度学习笔记
- java wsdl反向生成源码,并使用CXF实现客户端调用代码
- 如何使用VC6编译sqlite3源码生成动态链接库(版本:sqlite-source-3_6_23_1)
- 手把手教你使用FineUI开发一个b/s结构的取送货管理信息系统(附源码+视频教程(1,2节))
- 使用Java生成word文档(附源码) 推荐
- C#分析数据库结构,使用XSL模板自动生成代码 - 清清月儿 .NET万花筒 Asp.net技术 Asp.net教程 Asp.net源码 Asp.net基础 Asp.net控件 Asp.net入门 - CSDNBlog
- 手把手教你使用FineUI开发一个b/s结构的取送货管理信息系统(附源码+视频教程(第9节))
- 使用java源码生成Kettle 4.4
- 使用vs2010编译lua5.1源码生成lua.lib
- 使用Jedis源码生成Jedis.jar
- 使用jquery.qrcode生成二维码,在线演示,下载源码
- [shiro学习笔记]第四节 使用源码生成Shiro的CHM格式的API文档
- 手把手教你使用FineUI开发一个b/s结构的取送货管理信息系统(附源码+视频教程(第3节))
- 使用FreeMarker生成静态页面,解决中文乱码问题源码
- android源码编译生成ramdisk.img和system.img解压和使用(基于海天雄A9+android2.3.3)
- Silverlight实用窍门系列:9.动态生成实体类,根据XML模板使用Emit生成动态类绑定到DataGrid【附代实例源码】
- eclipse插件开发:使用AST生成类(源码)
- 如何使用VC6编译sqlite3源码生成动态链接库(版本:sqlite-source-3_6_23_1)