超乾貨|使用Keras和CNN構建分類器(內含代碼和講解)

clipboard.png

爲了讓文章不那麼枯燥,我構建了一個精靈圖鑑數據集(Pokedex)這都是一些受歡迎的精靈圖。咱們在已經準備好的圖像數據集上,使用Keras庫訓練一個卷積神經網絡(CNN)。數組

深度學習數據集

clipboard.png

上圖是來自咱們的精靈圖鑑深度學習數據集中的合成圖樣本。個人目標是使用Keras庫和深度學習訓練一個CNN,對Pokedex數據集中的圖像進行識別和分類。Pokedex數據集包括:Bulbasaur (234 images);Charmander (238 images);Squirtle (223 images);Pikachu (234 images);Mewtwo (239 images)服務器

訓練圖像包括如下組合:電視或電影的靜態幀;交易卡;行動人物;玩具和小玩意兒;圖紙和粉絲的藝術效果圖。網絡

在這種多樣化的訓練圖像的狀況下,實驗結果證實,CNN模型的分類準確度高達97%!架構

CNN和Keras庫的項目結構

該項目分爲幾個部分,目錄結構以下:機器學習

clipboard.png

如上圖所示,共分爲3個目錄:函數

1.數據集:包含五個類,每一個類都是一個子目錄。工具

2.示例:包含用於測試卷積神經網絡的圖像。學習

3.pyimagesearch模塊:包含咱們的SmallerVGGNet模型類。測試

另外,根目錄下有5個文件:優化

1.plot.png:訓練腳本運行後,生成的訓練/測試準確性和損耗圖。

2.lb.pickle:LabelBinarizer序列化文件,在類名稱查找機制中包含類索引。

3.pokedex.model:序列化Keras CNN模型文件(即「權重文件」)。

4.train.py:訓練Keras CNN,繪製準確性/損耗函數,而後將卷積神經網絡和類標籤二進制文件序列化到磁盤。

5.classify.py:測試腳本。

Keras和CNN架構

clipboard.png

咱們今天使用的CNN架構,是由Simonyan和Zisserman在2014年的論文「用於大規模圖像識別的強深度卷積網絡」中介紹的VGGNet網絡的簡單版本,結構圖如上圖所示。該網絡架構的特色是:

1.只使用3*3的卷積層堆疊在一塊兒來增長深度。

2.使用最大池化來減少數組大小。

3.網絡末端全鏈接層在softmax分類器以前。

假設你已經在系統上安裝並配置了Keras。若是沒有,請參照如下鏈接瞭解開發環境的配置教程:

1.配置Ubuntu,使用Python進行深度學習。

2.設置Ubuntu 16.04 + CUDA + GPU,使用Python進行深度學習。

3.配置macOS,使用Python進行深度學習。

繼續使用SmallerVGGNet——VGGNet的更小版本。在pyimagesearch模塊中建立一個名爲smallervggnet.py的新文件,並插入如下代碼:

clipboard.png

注意:在pyimagesearch中建立一個_init_.py文件,以便Python知道該目錄是一個模塊。若是你對_init_.py文件不熟悉或者不知道如何使用它來建立模塊,你只需在原文的「下載」部分下載目錄結構、源代碼、數據集和示例圖像。

如今定義SmallerVGGNet類:

clipboard.png

該構建方法須要四個參數:

1.width:圖像寬度。

2.height :圖像高度。

3.depth :圖像深度。

4.classes :數據集中類的數量(這將影響模型的最後一層),咱們使用了5個Pokemon 類。

注意:咱們使用的是深度爲三、大小爲96 * 96的輸入圖像。後邊解釋輸入數組經過網絡的空間維度時,請記住這一點。

因爲咱們使用的是TensorFlow後臺,所以用「channels last」對輸入數據進行排序;若是想用「channels last」,則能夠用代碼中的23-25行進行處理。

爲模型添加層,下圖爲第一個CONV => RELU => POOL代碼塊:

clipboard.png

卷積層有32個內核大小爲3*3的濾波器,使用RELU激活函數,而後進行批量標準化。

池化層使用3 3的池化,將空間維度從96 96快速下降到32 32(輸入圖像的大小爲96 96 * 3的來訓練網絡)。

如代碼所示,在網絡架構中使用Dropout。Dropout隨機將節點從當前層斷開,並鏈接到下一層。這個隨機斷開的過程有助於下降模型中的冗餘——網絡層中沒有任何單個節點負責預測某個類、對象、邊或角。

在使用另一個池化層前,添加(CONV => RELU)* 2層:

clipboard.png

在下降輸入數組的空間維度前,將多個卷積層RELU層堆疊在一塊兒能夠學習更豐富的特徵集。

請注意:將濾波器大小從32增長到64。隨着網絡的深刻,輸入數組的空間維度越小,濾波器學習到的內容更多;將最大池化層從33下降到22,以確保不會過快地下降空間維度。在這個過程當中再次執行Dropout。

再添加一個(CONV => RELU)* 2 => POOL代碼塊:

clipboard.png

咱們已經將濾波器的大小增長到128。對25%的節點執行Droupout以減小過擬合。

最後,還有一組FC => RELU層和一個softmax分類器:

clipboard.png

Dense(1024)使用具備校訂的線性單位激活和批量歸一化指定全鏈接層。

最後再執行一次Droupout——在訓練期間咱們Droupout了50%的節點。一般狀況下,你會在全鏈接層在較低速率下使用40-50%的Droupout,其餘網絡層爲10-25%的Droupout。

用softmax分類器對模型進行四捨五入,該分類器將返回每一個類別標籤的預測機率值。

CNN + Keras訓練腳本的實現

既然VGGNet小版本已經實現,如今咱們使用Keras來訓練卷積神經網絡。

建立一個名爲train.py的新文件,並插入如下代碼,導入須要的軟件包和庫:

clipboard.png

使用」Agg」 matplotlib後臺,以即可以將數字保存在背景中(第3行)。

ImageDataGenerator類用於數據加強,這是一種對數據集中的圖像進行隨機變換(旋轉、剪切等)以生成其餘訓練數據的技術。數據加強有助於防止過擬合。

第7行導入了Adam優化器,用於訓練網絡。

第9行的LabelBinarizer是一個重要的類,其做用以下:

1.輸入一組類標籤的集合(即表示數據集中人類可讀的類標籤字符串)。

2.將類標籤轉換爲獨熱編碼矢量。

3.容許從Keras CNN中進行整型類別標籤預測,並轉換爲人類可讀標籤。

常常會有讀者問:如何將類標籤字符串轉換爲整型?或者如何將整型轉換爲類標籤字符串。答案就是使用LabelBinarizer類。

第10行的train_test_split函數用來建立訓練和測試分叉。

讀者對我本身的imutils包較爲了解。若是你沒有安裝或更新,能夠經過如下方式進行安裝:

clipboard.png

若是你使用的是Python虛擬環境,確保在安裝或升級imutils以前,用workon命令訪問特定的虛擬環境。

咱們來解析一下命令行參數:

clipboard.png

對於咱們的訓練腳本,有三個必須的參數:

1.--dataset:輸入數據集的路徑。數據集放在一個目錄中,其子目錄表明每一個類,每一個子目錄約有250個精靈圖片。

2.--model:輸出模型的路徑,將訓練模型輸出到磁盤。

3.--labelbin:輸出標籤二進制器的路徑。

還有一個可選參數--plot。若是不指定路徑或文件名,那麼plot.png文件則在當前工做目錄中。

不須要修改第22-31行來提供新的文件路徑,代碼在運行時會自行處理。

如今,初始化一些重要的變量:

clipboard.png

第35-38行對訓練Keras CNN時使用的重要變量進行初始化:

1.-EPOCHS:訓練網絡的次數。

2.-INIT-LR:初始學習速率值,1e-3是Adam優化器的默認值,用來優化網絡。

3.-BS:將成批的圖像傳送到網絡中進行訓練,同一時期會有多個批次,BS值控制批次的大小。

4.-IMAGE-DIMS:提供輸入圖像的空間維度數。輸入的圖像爲96963(即RGB)。

而後初始化兩個列表——data和labels,分別保存預處理後的圖像和標籤。第46-48行抓取全部的圖像路徑並隨機擾亂。

如今,對全部的圖像路徑ImagePaths進行循環:

clipboard.png

首先對imagePaths進行循環(第51行),再對圖像進行加載(第53行),而後調整其大小以適應模型(第54行)。

如今,更新data和labels列表。

調用Keras庫的img_to_arry函數,將圖像轉換爲與Keras庫兼容的數組(第55行),而後將圖像添加到名爲data的列表中(第56行)。

對於labels列表,咱們在第60行文件路徑中提取出label,並將其添加在第61行。

那麼,爲何須要類標籤分解過程呢?

考慮到這樣一個事實,咱們有目的地建立dataset目錄結構,格式以下:

clipboard.png

第60行的路徑分隔符能夠將路徑分割成一個數組,而後獲取列表中的倒數第二項——類標籤。

而後進行額外的預處理、二值化標籤和數據分區,代碼以下:

clipboard.png

首先將data數組轉換爲NumPy數組,而後將像素強度縮放到[0,1]範圍內(第64行),也要將列表中的labels轉換爲NumPy數組(第65行)。打印data矩陣的大小(以MB爲單位)。

而後使用scikit-learn庫的LabelBinarzer對標籤進行二進制化(第70和71行)。

對於深度學習(或者任何機器學習),一般的作法是將訓練和測試分開。第75和76行將訓練集和測試集按照80/20的比例進行分割。

接下來建立圖像數據加強對象:

clipboard.png

由於訓練數據有限(每一個類別的圖像數量小於250),所以能夠利用數據加強爲模型提供更多的圖像(基於現有圖像),數據加強是一種很重要的工具。

第79到81行使用ImageDataGenerator對變量aug進行初始化,即ImageDataGenerator。
如今,咱們開始編譯模型和訓練:

clipboard.png

第85行和第86行使用96*96*3的輸入圖像初始化Keras CNN模型。注意,我將SmallerVGGNet設計爲接受96*96*3輸入圖像。

第87行使用具備學習速率衰減的Adam優化器,而後在88行和89行使用分類交叉熵編譯模型。

若只有2個類別,則使用二元交叉熵做爲損失函數。

93-97行調用Keras的fit_generator方法訓練網絡。這一過程須要花費點時間,這取決於你是用CPU仍是GPU進行訓練。

一旦Keras CNN訓練完成,咱們須要保存模型(1)和標籤二進制化器(2),由於在訓練或測試集之外的圖像上進行測試時,須要從磁盤中加載出來:

clipboard.png

對模型(101行)和標籤二進制器(105-107行)進行序列化,以便稍後在classify.py腳本中使用。

clipboard.png

最後,繪製訓練和損失的準確性圖,並保存到磁盤(第121行),而不是顯示出來,緣由有二:(1)個人服務器在雲端;(2)確保不會忘記保存圖。

使用Keras訓練CNN

執行如下代碼訓練模型:

clipboard.png

訓練腳本的輸出結果如上圖所示,Keras CNN模型在訓練集上的分類準確率爲96.84%;在測試集上的準確率爲97.07%

訓練損失函數和準確性圖以下:

clipboard.png

如上圖所示,對模型訓練100次,並在有限的過擬合下實現了低損耗。在新的數據上也能得到更高的準確性。

建立CNN和Keras的腳本

如今,CNN已經訓練過了,咱們須要編寫一個腳本,對新圖像進行分類。新建一個文件,並命名爲classify.py,插入如下代碼:

clipboard.png

上圖中第2-9行導入必要的庫。

clipboard.png

咱們來解析下代碼中的參數(12-19行),須要的三個參數以下:

1.--model:已訓練模型的路徑。

2.--labelbin:標籤二進制器的路徑。

3.--image:輸入圖像的路徑。

接下來,加載圖像並對其進行預處理:

clipboard.png

第22行加載輸入圖像image,並複製一個副本,賦值給out(第23行)。

和訓練過程使用的預處理方式同樣,咱們對圖像進行預處理(26-29行)。加載模型和標籤二值化器(34和35行),對圖像進行分類:

clipboard.png

隨後,對圖像進行分類並建立標籤(39-41行)。

剩餘的代碼用於顯示:

clipboard.png

第46-47行從filename中提取精靈圖鑑的名字,並與label進行比較。Correct變量是「正確(correct)」或「不正確(incorrect)」。而後執行如下操做:

1.50行將機率值和「正確/不正確」文本添加到類別標籤label上。

2.51行調整輸出圖像大小,使其適合屏幕輸出。

3.52和53行在輸出圖像上繪製標籤。

4.57和58行顯示輸出圖像並等待按鍵退出。

用KNN和Keras對圖像分類

運行classify.py腳本(確保已經從原文「下載」部分獲取代碼和圖片)!下載並解壓縮文件到這個項目的根目錄下,而後從Charmander圖像開始。代碼及試驗結果以下:

clipboard.png

Bulbasaur圖像分類的代碼及結果以下所示:

clipboard.png

圖片描述

其餘圖像的分類代碼和以上兩個圖像的代碼同樣,可自行驗證其結果。

模型的侷限性

該模型的主要侷限是訓練數據少。我在各類不一樣的圖像進行測試,發現有時分類不正確。我仔細地檢查了輸入圖像和神經網絡,發現圖像中的主要顏色會影響分類結果。

例如,若是圖像中有許多紅色和橙色,則可能會返回「Charmander」標籤;圖像中的黃色一般會返回「Pikachu」標籤。這歸因於輸入數據,精靈圖鑑是虛構的,它沒有「真實世界」中的真實圖像。而且,咱們只爲每一個類別提供了比較有限的數據(約225-250張圖片)。

理想狀況下,訓練卷積神經網絡時,每一個類別至少應有500-1,000幅圖像。

能夠將Keras深度學習模型做爲REST API嗎?

若是想將此模型(或任何其餘深度學習模型)用做REST API運行,能夠參照下面的博文內容:

1.構建一個簡單的Keras + 深度學習REST API

2.可擴展的Keras + 深度學習REST API

3.使用Keras,Redis,Flask和Apache進行深度學習

總結

這篇文章主要介紹瞭如何使用Keras庫來訓練卷積神經網絡(CNN)。使用的是本身建立的數據集(精靈圖鑑)做爲訓練集和測試集,其分類的準確度達到97.07%。

本文由阿里云云棲社區組織翻譯。

文章原標題《Keras and Convolutional Neural Networks (CNNs)》,譯者:Mags,審校:袁虎。

詳情請閱讀原文

相關文章
相關標籤/搜索