連載一:PyCon2018|用slim呼叫PNASNet模型(附原始碼)

程式碼醫生發表於2019-03-04
第八屆中國Python開發者大會PyConChina2018,由PyChina.org發起,由來自CPyUG/TopGeek等社群的30位組織者,近150位志願者在北京、上海、深圳、杭州、成都等城市舉辦。致力於推動各類Python相關的技術在網際網路、企業應用等領域的研發和應用。

程式碼醫生工作室有幸接受邀請,參加了這次會議的北京站專場。在會上主要分享了《人工智慧實戰案例分享-影象處理與數值分析》。

會上分享的一些案例主要是來源於《python帶我起飛——入門、進階、商業實戰》一書與《深度學習之TensorFlow:入門、原理與進階實戰》一書。另外,還擴充了若干其它案例。在本文作為補充,將會上分享的其它案例以詳細的圖文方式補充進來,並提供原始碼。共分為4期連載。

  1. 用slim呼叫PNASNet模型

  2. 用slim微調PNASNet模型

  3. 用對抗樣本攻擊PNASNet模型

  4. 惡意域名檢測例項

連載一:PyCon2018|用slim呼叫PNASNet模型(附原始碼)

使用AI模型來識別影象是桌子、貓、狗,還是其他

本章將演示一個應用AI模型進行影象識別的例子。通過該例項能夠讓讀者真真切切的感受到AI的強大,及使用模型的操作過程。

案例描述

通過程式碼載入現有模型,對任意圖片進行分類識別,觀察識別結果。

本案使用的是在ImgNet資料集上訓練好的PNASNet模型。PNASNet模型是目前最優秀的圖片識別模型之一。該模型在ImgNet資料集上訓練後,可以識別1000種類別的圖片。要完成該案例,需要先下載TensorFlow中的models模組及對應的與訓練模型。下面就來詳細介紹。

程式碼環境及模型準備

為了使讀者能夠快速完成該例項,直觀上感受到模型的識別能力,可以直接使用本書配套的資源。並將其放到程式碼的同級目錄下即可。

如果想體驗下從零開始手動搭建,也可以按照下面的方法準備程式碼環境及預編譯模型。

1. 下載TensorFlow models模組

TensorFlow models模組中包含了使用TensorFlow框架完成的各種不同模型,可以直接拿來使用。在TensorFlow models模組中進行二次開發,可以使AI專案開發變得簡單快捷。來到以下網址:

github.com/tensorflow/…

可以通過git 將程式碼clone下來,也可以手動下載(具體操作見《深度學習之TensorFlow:入門、原理與進階實戰》一書的8.5.2節)。

2. 部署TensorFlow slim模組

解壓之後,將其中\models-master\research路徑下的slim資料夾(如圖1),複製到原生程式碼的同級路徑下。


連載一:PyCon2018|用slim呼叫PNASNet模型(附原始碼)

圖1 slim程式碼庫路徑

slim庫又叫做TF-slim,是TensorFlow 1.0之後推出的一個新的輕量級高階API介面。將很多常見TensorFlow函式做了二次封裝,使程式碼變得更加簡潔。

在TF-slim模組裡面同時提供了大量用TF-slim寫好的網路模型結構程式碼,以及用該程式碼訓練出的模型檔案。本例中就是使用TF-slim模組中訓練好的PNASNet模型檔案。

3. 下載PNASNet模型

訪問如下網站,可以下載訓練好的PNASNet模型:

github.com/tensorflow/…

該連結開啟後,可以找到“pnasnet-5_large_2017_12_13.tar.gz”的下載地址,如圖2。


連載一:PyCon2018|用slim呼叫PNASNet模型(附原始碼)

圖2 PNASNet模型下載頁面

下載完後,將其解壓,會得到如下圖3中的檔案結構。

連載一:PyCon2018|用slim呼叫PNASNet模型(附原始碼)

圖3 PNASNet模型檔案

將整個pnasnet-5_large_2017_12_13資料夾放到原生程式碼的同級目錄下。在使用時,只需要指定好模型的路徑:“pnasnet-5_large_2017_12_13”,系統便會自動載入模型裡面的檔案及內容。

注意:

在圖2中,可以看到,出來本例項所用的PNASNet模型外,還有好多其他的模型。其中倒數第二行的mobilenet_v2_1.0_224.tgz模型也是比較常用的,該模型體積小、運算快,常用於在移動裝置。

4. 準備ImgNet資料集標籤

由於本例中使用的PNASNet預訓練模型是在ImgNet資料集上訓練好的模型,在使用該模型分類是,還需要有與其對應的標籤檔案。slim中已經將獲得標籤檔案的操作直接封裝到了程式碼裡,直接呼叫即可。由於標籤檔案是英文分類,讀起來不太直觀。這裡提供了一個翻譯好的中文標籤分類檔案“中文標籤.csv”。也在書籍同步的配套資源中。

前面4項都準備好後,整體的目錄結構如圖4所示。

連載一:PyCon2018|用slim呼叫PNASNet模型(附原始碼)

圖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 \n', '丁鯛 \n', '金魚 \n', '大白鯊 \n', '虎鯊 \n']

一共輸出了兩行,第一行為英文標籤,第二行為中文標籤。

程式碼實現:定義網路結構

通過程式碼,定義了佔位符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_13\model.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行)。這個過程叫做圖片預處理。經過預處理後的圖片放到模型中,才能夠得到準確的結果。

程式碼執行後,輸出結果如下:

連載一:PyCon2018|用slim呼叫PNASNet模型(附原始碼)

結果一共顯示了3幅圖,3段文字。每幅圖片下一行的文字,為模型識別出來的結果。在每幅圖中,左側為原始圖片,右側為預處理後的圖片。

結尾

文內程式碼可以直接執行使用。如果不想手動搭建,還可以下載本文的配套程式碼。

【程式碼獲取】:關注公眾號:xiangyuejiqiren    公眾號回覆“pycon1

如果覺得本文有用

可以分享給更多小夥伴

連載一:PyCon2018|用slim呼叫PNASNet模型(附原始碼)


相關文章