第八届中国Python开发者大会PyConChina2018,由PyChina.org发起,由来自CPyUG/TopGeek等社区的30位组织者,近150位志愿者在北京、上海、深圳、杭州、成都等城市举办。致力于推进各种Python相关的技术在互联网、企业应用等领域的研发和应用。
代码医生工做室有幸接受邀请,参加了此次会议的北京站专场。在会上主要分享了《人工智能实战案例分享-图像处理与数值分析》。
会上分享的一些案例主要是来源于《python带我起飞——入门、进阶、商业实战》一书与《深度学习之TensorFlow:入门、原理与进阶实战》一书。另外,还扩充了若干其它案例。在本文做为补充,将会上分享的其它案例以详细的图文方式补充进来,并提供源码。共分为4期连载。
用slim调用PNASNet模型python
用slim微调PNASNet模型git
用对抗样本攻击PNASNet模型算法
恶意域名检测实例bash
本例经过使用FGSM的方式,来生成攻击样本。对PNASNet发起攻击,使其输出的识别结果,产生错误。网络
案例描述函数
先用一张哈士奇狗的照片,输入带有预编译模型PNASNet网络。观察其返回结果。学习
经过梯度降低算法训练一个模拟样本。待模拟样本生成完成以后,输入PNASNet令其输出识别结果为盘子。优化
该案例所实现的FGSM原理很简单:将输入的图片看成训练参数。经过优化器不断的迭代,来将图片逐渐改形成输入模型认为使盘子的样子。下面就来演示其实现过程。ui
在代码“3-1 使用AI模型来识别图像.py”中,介绍了一个使用PNASNet网络的预编译模型,进行图片识别的例子。本案例就在该代码基础上实现。首先“3-1 使用AI模型来识别图像.py”代码文件的整个工做环境复制一份。并编写pnasnetfun函数,实现模型的建立。完整的代码以下:人工智能
在线性回归模型中添加指定节点到检查点文件
1 import sys #初始化环境变量
2 nets_path = r'slim'
3 if nets_path not in sys.path:
4 sys.path.insert(0,nets_path)
5 else:
6 print('already add slim')
7
8 import tensorflow as tf #引入头文件
9 from nets.nasnet import pnasnet
10 import numpy as np
11 from tensorflow.python.keras.preprocessing import image
12
13 import matplotlib as mpl
14 import matplotlib.pyplot as plt
15 mpl.rcParams['font.sans-serif']=['SimHei']#用来正常显示中文标签
16 mpl.rcParams['font.family'] = 'STSong'
17 mpl.rcParams['font.size'] = 15
18
19 slim = tf.contrib.slim
20 arg_scope = tf.contrib.framework.arg_scope
21
22 tf.reset_default_graph()
23 image_size = pnasnet.build_pnasnet_large.default_image_size #得到图片输入尺寸
24 LANG = 'ch' #使用中文标签
25
26 if LANG=='ch':
27 def getone(onestr):
28 return onestr.replace(',',' ').replace('\n','')
29
30 with open('中文标签.csv','r+') as f: #打开文件
31 labelnames =list( map(getone,list(f)) )
32 print(len(labelnames),type(labelnames),labelnames[:5]) #显示输出中文标签
33 else:
34 from datasets import imagenet
35 labelnames = imagenet.create_readable_names_for_imagenet_labels() #得到数据集标签
36 print(len(labelnames),labelnames[:5]) #显示输出标签
37
38 def pnasnetfun(input_imgs,reuse ):
39 preprocessed = tf.subtract(tf.multiply(tf.expand_dims(input_imgs, 0), 2.0), 1.0)
40 arg_scope = pnasnet.pnasnet_large_arg_scope() #得到模型命名空间
41
42 with slim.arg_scope(arg_scope): #建立PNASNet模型
43 with slim.arg_scope([slim.conv2d,
44 slim.batch_norm, slim.fully_connected,
45 slim.separable_conv2d],reuse=reuse):
46
47 logits, end_points = pnasnet.build_pnasnet_large(preprocessed,num_classes = 1001, is_training=False)
48 prob = end_points['Predictions']
49 return logits, prob复制代码
代码13~17行在《深度学习之TensorFlow:入门、原理与进阶实战》9.7.4节也用过,是支持中文显示的做用。代码43行的做用,是支持PNASNet模型的变量复用功能。
注意:
在建立模型时,须要将其设为不可训练(代码47行)。这样才能保证,在后面12.2.3节经过训练生成攻击样本时,PNASNet模型不会有变化。
在本案例中,没有使用占位符来创建输入层,而是使用了张量。使用tf.Variable定义的张量与占位符的效果同样,一样能够支持注入机制。这么作的目的是为了在后面制造攻击样本时使用。接着是载入图片、载入预编译模型、将图片注入到预编译模型中的操做。并最终可视化输出预测结果。完整的代码以下:
代码12-1 在线性回归模型中添加指定节点到检查点文件(续)
50 input_imgs = tf.Variable(tf.zeros((image_size, image_size, 3)))
51 logits, probs = pnasnetfun(input_imgs,reuse=False)
52 checkpoint_file = r'pnasnet-5_large_2017_12_13\model.ckpt' #定义模型路径
53 variables_to_restore = slim.get_variables_to_restore()
54 init_fn = slim.assign_from_checkpoint_fn(checkpoint_file, variables_to_restore,ignore_missing_vars=True)
55
56 sess = tf.InteractiveSession() #创建会话
57 init_fn(sess) #载入模型
58
59 img_path = './dog.jpg' #载入图片
60 img = image.load_img(img_path, target_size=(image_size, image_size))
61 img = (np.asarray(img) / 255.0).astype(np.float32)
62
63 def showresult(img,p): #可视化模型输出结果
64 fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 8))
65 fig.sca(ax1)
66
67 ax1.axis('off')
68 ax1.imshow(img)
69 fig.sca(ax1)
70
71 top10 = list((-p).argsort()[:10])
72 lab= [labelnames[i][:15] for i in top10]
73 topprobs = p[top10]
74 print(list(zip(top10,lab,topprobs)))
75
76 barlist = ax2.bar(range(10), topprobs)
77
78 barlist[0].set_color('g')
79 plt.sca(ax2)
80 plt.ylim([0, 1.1])
81 plt.xticks(range(10), lab, rotation='vertical')
82 fig.subplots_adjust(bottom=0.2)
83 plt.show()
84
85 p = sess.run(probs, feed_dict={input_imgs: img})[0]
86 showresult(img,p)
复制代码
代码运行后,以下结果:
[(249, '爱斯基摩犬 哈士奇 ', 0.35189062), (251, '哈士奇 ', 0.34352344), (250, '雪橇犬 阿拉斯加爱斯基摩狗 ', 0.007250515), (271, '白狼 北极狼 ', 0.0034629034), (175, '挪威猎犬 ', 0.0028237076), (538, '狗拉雪橇 ', 0.0025286602), (270, '灰狼 ', 0.0022800271), (274, '澳洲野狗 澳大利亚野犬 ', 0.0018357899), (254, '巴辛吉狗 ', 0.0015468642), (280, '北极狐狸 白狐狸 ', 0.0009330675)]
并获得可视化图片,如图12-1:
图12-1 PNASNet模型输出
图12-1中,左侧为输入的图片,右侧为其预测的结果。能够看到模型可以成功的预测出该图片内容是一只哈士奇狗。
在制做样本时,不能让图片的变化太大。还要让图片在人眼看上去可以接收才行。这里须要手动设置阈值,限制图片的变化范围。而后将生成的图片显示出来,由人眼判断图片是否正常可用。确保没有失真。完整的代码以下:
代码12-1 在线性回归模型中添加指定节点到检查点文件(续)
1 def floatarr_to_img(floatarr): #将浮点型转化为图片
2 floatarr=np.asarray(floatarr*255)
3 floatarr[floatarr>255]=255
4 floatarr[floatarr<0]=0
5 return floatarr.astype(np.uint8)
6
7 x = tf.placeholder(tf.float32, (image_size, image_size, 3)) #定义占位符
8 assign_op = tf.assign(input_imgs, x) #为input_imgs赋值
9 sess.run( assign_op, feed_dict={x: img})
10
11 below = input_imgs - 2.0/255.0 #定义图片的变化范围
12 above = input_imgs + 2.0/255.0
13
14 belowv,abovev = sess.run( [below,above]) #生成阈值图片
15
16 plt.imshow(floatarr_to_img(belowv)) #显示图片,用于人眼验证
17 plt.show()
18 plt.imshow(floatarr_to_img(abovev))
19 plt.show()复制代码
在代码第8行,为input_imgs赋值以后,才可使用。由于到目前为止input_imgs尚未初始化,必须调用input_imgs.initializer或tf.assign为其赋值。这部分知识与《深度学习之TensorFlow:入门、原理与进阶实战》一书的3.3.8节相关。
这里设置的阈值是:每一个像素上下变化最大不超过2(见代码十一、12行)。通过代码运行后,输出的图片如图12-二、图12-3。
如图12-二、12-3所示,该图片彻底在人类接收范围。一眼看去,就是一只哈士奇狗。
与正常的网络模型训练目标不一样,这里的训练目标不是模型中的权重,而是输入模型的张量。在12.2.1节中,生成模型的同时,已经将模型固定好(设为不可训练)。这样在模型训练的过程当中,反向梯度传播的最终做用值就是输入的张量input_imgs了。
训练步骤与正常的网络模型一致,设定一个其它类别的标签。建立loss节点,令每次优化时,模型的输出都接近于设置的标签类别。完整的代码以下:
代码12-1 在线性回归模型中添加指定节点到检查点文件(续)
20 label_target = 880 #设定一个其它类别的目标标签
21 label =tf.constant(label_target)
22 #定义loss节点
23 loss = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=[label])
24 learning_rate = 1e-1 #定义学习率
25 optim_step = tf.train.GradientDescentOptimizer( #定义优化器
26 learning_rate).minimize(loss, var_list=[input_imgs])
27
28 #将调整后的图片,按照指定阈值截断
29 projected = tf.clip_by_value(tf.clip_by_value(input_imgs, below, above), 0, 1)
30 with tf.control_dependencies([projected]):
31 project_step = tf.assign(input_imgs, projected)
32
33 demo_steps = 400 #定义迭代次数
34 for i in range(demo_steps): #开始训练
35 _, loss_value = sess.run([optim_step, loss])
36 sess.run(project_step)
37
38 if (i+1) % 10 == 0: #输出训练状态
39 print('step %d, loss=%g' % (i+1, loss_value))
40 if loss_value<0.02: #达到标准后,提早结束
41 break
复制代码
代码运行后,输出以下结果:
step 10, loss=5.29815
step 20, loss=0.00202808
代码显示,仅迭代20次。模型便可达到了标准。在实际运行中,因为选用的图片,和指定的其它类别不一样。迭代次数有可能不一样。
接下来就是最有意思的环节了。用训练好的攻击样原本攻击模型。实现起来很是简单,直接将input_imgs最为输入,运行模型。具体代码以下:
代码12-1 在线性回归模型中添加指定节点到检查点文件(续)
42 adv = input_imgs.eval() #获取图片
43 p = sess.run(probs)[0] #获得模型结果
44 showresult(floatarr_to_img(adv),p) #可视化模型结果
45 plt.imsave('dog880.jpg',floatarr_to_img(adv)) #保存模型复制代码
代码运行后,以下结果:
[(880, '伞 ', 0.9981244), (930, '雪糕 冰棍 冰棒 ', 0.00011489283), (630, '唇膏 口红 ', 8.979097e-05), (553, '女用长围巾 ', 4.4915465e-05), (615, '和服 ', 3.441378e-05), (729, '塑料袋 ', 3.353129e-05), (569, '裘皮大衣 ', 3.0552055e-05), (904, '假发 ', 2.2152075e-05), (898, '洗衣机 自动洗衣机 ', 2.1341652e-05), (950, '草莓 ', 2.0412743e-05)]
并获得可视化图片,如图12-4:
图12-4 模型识别攻击样本的结果
从输出结果和图12-4的显示能够看出。模型已经把哈士奇看成了伞。
【代码获取】:关注公众号:xiangyuejiqiren 公众号回复“pycon3”
若是以为本文有用
能够分享给更多小伙伴