第八屆中國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」
若是以爲本文有用
能夠分享給更多小夥伴