第八屆中國Python開發者大會PyConChina2018,由PyChina.org發起,由來自CPyUG/TopGeek等社群的30位組織者,近150位志願者在北京、上海、深圳、杭州、成都等城市舉辦。致力於推動各類Python相關的技術在網際網路、企業應用等領域的研發和應用。
程式碼醫生工作室有幸接受邀請,參加了這次會議的北京站專場。在會上主要分享了《人工智慧實戰案例分享-影像處理與數值分析》。
會上分享的一些案例主要是來源於《python帶我起飛——入門、進階、商業實戰》一書與《深度學習之TensorFlow:入門、原理與進階實戰》一書。另外,還擴充了若干其它案例。在本文作為補充,將會上分享的其它案例以詳細的圖文方式補充進來,並提供原始碼。共分為4期連載。
-
用slim呼叫PNASNet模型
-
用slim微調PNASNet模型
-
用對抗樣本攻擊PNASNet模型
-
惡意域名檢測例項
使用AI模型來識別影像是桌子、貓、狗,還是其他
本章將演示一個應用AI模型進行影像識別的例子。通過該例項能夠讓讀者真真切切的感受到AI的強大,及使用模型的操作過程。
案例描述
通過程式碼載入現有模型,對任意圖片進行分類識別,觀察識別結果。
本案使用的是在ImgNet資料集上訓練好的PNASNet模型。PNASNet模型是目前最優秀的圖片識別模型之一。該模型在ImgNet資料集上訓練後,可以識別1000種類別的圖片。要完成該案例,需要先下載TensorFlow中的models模組及對應的與訓練模型。下面就來詳細介紹。
程式碼環境及模型準備
為了使讀者能夠快速完成該例項,直觀上感受到模型的識別能力,可以直接使用本書配套的資源。並將其放到程式碼的同級目錄下即可。
如果想體驗下從零開始手動搭建,也可以按照下面的方法準備程式碼環境及預編譯模型。
1. 下載TensorFlow models模組
TensorFlow models模組中包含了使用TensorFlow框架完成的各種不同模型,可以直接拿來使用。在TensorFlow models模組中進行二次開發,可以使AI專案開發變得簡單快捷。來到以下網址:
可以通過git 將程式碼clone下來,也可以手動下載(具體操作見《深度學習之TensorFlow:入門、原理與進階實戰》一書的8.5.2節)。
2. 部署TensorFlow slim模組
解壓之後,將其中models-master
esearch路徑下的slim資料夾(如圖1),複製到原生程式碼的同級路徑下。
圖1 slim程式碼庫路徑
slim庫又叫做TF-slim,是TensorFlow 1.0之後推出的一個新的輕量級高階API介面。將很多常見TensorFlow函式做了二次封裝,使程式碼變得更加簡潔。
在TF-slim模組裡面同時提供了大量用TF-slim寫好的網路模型結構程式碼,以及用該程式碼訓練出的模型檔案。本例中就是使用TF-slim模組中訓練好的PNASNet模型檔案。
3. 下載PNASNet模型
訪問如下網站,可以下載訓練好的PNASNet模型:
該連結開啟後,可以找到“pnasnet-5_large_2017_12_13.tar.gz”的下載地址,如圖2。
圖2 PNASNet模型下載頁面
下載完後,將其解壓,會得到如下圖3中的檔案結構。
圖3 PNASNet模型檔案
將整個pnasnet-5_large_2017_12_13資料夾放到原生程式碼的同級目錄下。在使用時,只需要指定好模型的路徑:“pnasnet-5_large_2017_12_13”,系統便會自動載入模型裡面的檔案及內容。
注意:
4. 準備ImgNet資料集標籤
由於本例中使用的PNASNet預訓練模型是在ImgNet資料集上訓練好的模型,在使用該模型分類是,還需要有與其對應的標籤檔案。slim中已經將獲得標籤檔案的操作直接封裝到了程式碼裡,直接呼叫即可。由於標籤檔案是英文分類,讀起來不太直觀。這裡提供了一個翻譯好的中文標籤分類檔案“中文標籤.csv”。也在書籍同步的配套資源中。
前面4項都準備好後,整體的目錄結構如圖4所示。
圖4 例項1檔案結構
在圖4中,會看到還有三個圖片檔案“72.jpg”、“hy.jpg”、“ps.jpg”,這三個檔案是用於測試使用的圖片,讀者可以替換為自己所要識別的檔案。
程式碼實現:初始化環境變數,並載入ImgNet標籤
首先將本地的slim作為引用庫載入到系統的環境變數裡。接著將ImgNet標籤載入並顯示出來。
import sys #初始化環境變數
nets_path = r`slim`
if nets_path not in sys.path:
sys.path.insert(0,nets_path)
else:
print(`already add slim`)
import tensorflow as tf #引入標頭檔案
from PIL import Image
from matplotlib import pyplot as plt
from nets.nasnet import pnasnet
import numpy as np
from datasets import imagenet
slim = tf.contrib.slim
tf.reset_default_graph()
image_size = pnasnet.build_pnasnet_large.default_image_size #獲得圖片輸入尺寸
labels = imagenet.create_readable_names_for_imagenet_labels() #獲得資料集標籤
print(len(labels),labels) #顯示輸出標籤
def getone(onestr):
return onestr.replace(`,`,` `)
with open(`中文標籤.csv`,`r+`) as f: #開啟檔案
labels =list( map(getone,list(f)) )
print(len(labels),type(labels),labels[:5])
複製程式碼
使用AI模型來識別影像
程式碼中提供了英文與中文的兩種標籤。在實際應用中使用了中文的標籤。程式執行後輸出結果如下:
1001 {0: `background`, 1: `tench, Tinca tinca`, 2: `goldfish, Carassius auratus`, 3: `great white shark, white shark, man-eater, man-eating shark, Carcharodon carcharias`, 4: `tiger shark, Galeocerdo cuvieri`, 5: `hammerhead, hammerhead shark`,……,994: `gyromitra`, 995: `stinkhorn, carrion fungus`, 996: `earthstar`, 997: `hen-of-the-woods, hen of the woods, Polyporus frondosus, Grifola frondosa`, 998: `bolete`, 999: `ear, spike, capitulum`, 1000: `toilet tissue, toilet paper, bathroom tissue`}
1001 <class `list`> [`背景known
`, `丁鯛
`, `金魚
`, `大白鯊
`, `虎鯊
`]
一共輸出了兩行,第一行為英文標籤,第二行為中文標籤。
程式碼實現:定義網路結構
通過程式碼,定義了佔位符input_imgs,用於輸入待識別的圖片。接著定義網路節點end_points,對接預訓練模型的輸出節點。end_points是一個字典,裡面Predictions對應的值就是最終的輸出結果。該值中放置著1000個元素的陣列,代表預測圖片在這1000個分類中的概率。通過tf.argmax函式對最終結果進行轉化,得到陣列中最大的那個數的索引,便是該圖片的分類。
sample_images = [`hy.jpg`, `ps.jpg`,`72.jpg`] #定義待測試圖片路徑
input_imgs = tf.placeholder(tf.float32, [None, image_size,image_size,3]) #定義佔位符
x1 = 2 *( input_imgs / 255.0)-1.0 #歸一化圖片
arg_scope = pnasnet.pnasnet_large_arg_scope() #獲得模型名稱空間
with slim.arg_scope(arg_scope):
logits, end_points = pnasnet.build_pnasnet_large(x1,num_classes = 1001, is_training=False)
prob = end_points[`Predictions`]
y = tf.argmax(prob,axis = 1) #獲得結果的輸出節點
複製程式碼
使用AI模型來識別影像(續)
在34行程式碼中的arg_scope是名稱空間的意思。在TensorFlow中相同名稱的不同張量是通過名稱空間來劃分的。關於名稱空間的更多知識可以參考《深度學習之TensorFlow:入門、原理與進階實戰》一書的4.3節。
程式碼中第28行指定了待識別圖片的名稱。如果想識別自己的圖片,直接修改該行程式碼中的圖片名稱即可。
程式碼實現:載入模型進行識別
指定好要載入的預訓練模型,建立會話進行圖片識別。
checkpoint_file = r`pnasnet-5_large_2017_12_13model.ckpt` #定義模型路徑
saver = tf.train.Saver() #定義saver,用於載入模型
with tf.Session() as sess: #建立會話
saver.restore(sess, checkpoint_file) #載入模型
def preimg(img): #定義圖片預處理函式
ch = 3
if img.mode==`RGBA`: #相容RGBA圖片
ch = 4
imgnp = np.asarray(img.resize((image_size,image_size)),
dtype=np.float32).reshape(image_size,image_size,ch)
return imgnp[:,:,:3]
#獲得原始圖片與預處理圖片
batchImg = [ preimg( Image.open(imgfilename) ) for imgfilename in sample_images ]
orgImg = [ Image.open(imgfilename) for imgfilename in sample_images ]
yv,img_norm = sess.run([y,x1], feed_dict={input_imgs: batchImg}) #輸入到模型
print(yv,np.shape(yv)) #顯示輸出結果
def showresult(yy,img_norm,img_org): #定義顯示圖片函式
plt.figure()
p1 = plt.subplot(121)
p2 = plt.subplot(122)
p1.imshow(img_org) #顯示圖片
p1.axis(`off`)
p1.set_title("organization image")
p2.imshow(img_norm) #顯示圖片
p2.axis(`off`)
p2.set_title("input image")
plt.show()
print(yy,labels[yy])
for yy,img1,img2 in zip(yv,batchImg,orgImg): #顯示每條結果及圖片
showresult(yy,img1,img2)
複製程式碼
使用AI模型來識別影像(續)
在TensorFlow中,模型執行時會有個圖的概念。在本例中,原始的網路結構會在靜態圖中定義好,接著通過建立一個會話(程式碼41行)讓當前程式碼與靜態圖連線起來。呼叫sess中的run函式將資料輸入到靜態圖中,並返回結果,從而實現圖片的識別。
在模型識別之前,所有的圖片都要統一成固定大小的尺寸(程式碼49行),並進行歸一化(程式碼32行)。這個過程叫做圖片預處理。經過預處理後的圖片放到模型中,才能夠得到準確的結果。
程式碼執行後,輸出結果如下:
結果一共顯示了3幅圖,3段文字。每幅圖片下一行的文字,為模型識別出來的結果。在每幅圖中,左側為原始圖片,右側為預處理後的圖片。
結尾
文內程式碼可以直接執行使用。如果不想手動搭建,還可以下載本文的配套程式碼。
【程式碼獲取】:關注公眾號:xiangyuejiqiren 公眾號回覆“pycon1”
如果覺得本文有用
可以分享給更多小夥伴