天天看點

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

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

深度學習資料集

上圖是來自我們的精靈圖鑒深度學習資料集中的合成圖樣本。我的目标是使用Keras庫和深度學習訓練一個CNN,對Pokedex資料集中的圖像進行識别和分類。Pokedex資料集包括:

Bulbasaur 

(234 images);

Charmander

 (238 images);

Squirtle 

(223 images);

Pikachu  Mewtwo 

(239 images)

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

在這種多樣化的訓練圖像的情況下,

實驗結果證明, CNN 模型的分類準确度高達 97

Keras 庫的項目結構

該項目分為幾個部分,目錄結構如下:

如上圖所示,共分為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:測試腳本。

架構

我們今天使用的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的新檔案,并插入以下代碼:

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

注意:在pyimagesearch中建立一個_init_.py檔案,以便Python知道該目錄是一個子產品。如果你對_init_.py檔案不熟悉或者不知道如何使用它來建立子產品,你隻需在原文的“

下載下傳

”部分下載下傳目錄結構、源代碼、資料集和示例圖像。

現在定義SmallerVGGNet類:

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

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

1.width:圖像寬度。

2.height :圖像高度。

3.depth :圖像深度。

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

注意:我們使用的是深度為3、大小為96 * 96的輸入圖像。後邊解釋輸入數組通過網絡的空間次元時,請記住這一點。

由于我們使用的是TensorFlow背景,是以用“channels last”對輸入資料進行排序;如果想用“channels last”,則可以用代碼中的23-25行進行處理。

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

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

卷積層有32個核心大小為3*3的濾波器,使用RELU激活函數,然後進行批量标準化。

池化層使用3 *3的池化,将空間次元從96 *96快速降低到32 * 32(輸入圖像的大小為96 * 96 * 3的來訓練網絡)。

如代碼所示,在網絡架構中使用Dropout。Dropout随機将節點從目前層斷開,并連接配接到下一層。這個随機斷開的過程有助于降低模型中的備援——網絡層中沒有任何單個節點負責預測某個類、對象、邊或角。

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

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

在降低輸入數組的空間次元前,将多個卷積層RELU層堆疊在一起可以學習更豐富的特征集。

請注意:将濾波器大小從32增加到64。随着網絡的深入,輸入數組的空間次元越小,濾波器學習到的内容更多;将最大池化層從3*3降低到2*2,以確定不會過快地降低空間次元。在這個過程中再次執行Dropout。

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

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

我們已經将濾波器的大小增加到128。對25%的節點執行Droupout以減少過拟合。

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

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

Dense(1024)使用具有校正的線性機關激活和批量歸一化指定全連接配接層。

最後再執行一次Droupout——在訓練期間我們Droupout了50%的節點。通常情況下,你會在全連接配接層在較低速率下使用40-50%的Droupout,其他網絡層為10-25%的Droupout。

用softmax分類器對模型進行四舍五入,該分類器将傳回每個類别标簽的預測機率值。

CNN + Keras 訓練腳本的實作

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

建立一個名為train.py的新檔案,并插入以下代碼,導入需要的軟體包和庫:

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

使用”Agg” matplotlib背景,以便可以将數字儲存在背景中(第3行)。

ImageDataGenerator類用于資料增強,這是一種對資料集中的圖像進行随機變換(旋轉、剪切等)以生成其他訓練資料的技術。資料增強有助于防止過拟合。

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

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

1.輸入一組類标簽的集合(即表示資料集中人類可讀的類标簽字元串)。

2.将類标簽轉換為獨熱編碼矢量。

3.允許從Keras CNN中進行整型類别标簽預測,并轉換為人類可讀标簽。

經常會有讀者問:如何将類标簽字元串轉換為整型?或者如何将整型轉換為類标簽字元串。答案就是使用LabelBinarizer類。

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

讀者對

我自己的imutils包

較為了解。如果你沒有安裝或更新,可以通過以下方式進行安裝:

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

如果你使用的是Python虛拟環境,確定在安裝或更新imutils之前,用workon指令通路特定的虛拟環境。

我們來解析一下指令行參數:

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

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

1.--dataset:輸入資料集的路徑。資料集放在一個目錄中,其子目錄代表每個類,每個子目錄約有250個精靈圖檔。

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

3.--labelbin:輸出标簽二進制器的路徑。

還有一個可選參數--plot。如果不指定路徑或檔案名,那麼plot.png檔案則在目前工作目錄中。

不需要修改第22-31行來提供新的檔案路徑,代碼在運作時會自行處理。

現在,初始化一些重要的變量:

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

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

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

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

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

4.-IMAGE-DIMS:提供輸入圖像的空間次元數。輸入的圖像為96*96*3(即RGB)。

然後初始化兩個清單——data和labels,分别儲存預處理後的圖像和标簽。第46-48行抓取所有的圖像路徑并随機擾亂。

現在,對所有的圖像路徑ImagePaths進行循環:

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

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

現在,更新data和labels清單。

調用Keras庫的img_to_arry函數,将圖像轉換為與Keras庫相容的數組(第55行),然後将圖像添加到名為data的清單中(第56行)。

對于labels清單,我們在第60行檔案路徑中提取出label,并将其添加在第61行。

那麼,為什麼需要類标簽分解過程呢?

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

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

第60行的路徑分隔符可以将路徑分割成一個數組,然後擷取清單中的倒數第二項——類标簽。

然後進行額外的預處理、二值化标簽和資料分區,代碼如下:         

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

首先将data數組轉換為NumPy數組,然後将像素強度縮放到[0,1]範圍内(第64行),也要将清單中的labels轉換為NumPy數組(第65行)。列印data矩陣的大小(以MB為機關)。

然後使用scikit-learn庫的LabelBinarzer對标簽進行二進制化(第70和71行)。

對于深度學習(或者任何機器學習),通常的做法是将訓練和測試分開。第75和76行将訓練集和測試集按照80/20的比例進行分割。

接下來建立圖像資料增強對象:

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

因為訓練資料有限(每個類别的圖像數量小于250),是以可以利用資料增強為模型提供更多的圖像(基于現有圖像),資料增強是一種很重要的工具。

第79到81行使用ImageDataGenerator對變量aug進行初始化,即ImageDataGenerator。      

            現在,我們開始編譯模型和訓練:

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

第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),因為在訓練或測試集以外的圖像上進行測試時,需要從磁盤中加載出來:

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

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

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

最後,繪制訓練和損失的準确性圖,并儲存到磁盤(第121行),而不是顯示出來,原因有二:(1)我的伺服器在雲端;(2)確定不會忘記儲存圖。

使用 訓練

執行以下代碼訓練模型:

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

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

訓練損失函數和準确性圖如下:

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

如上圖所示,對模型訓練100次,并在有限的過拟合下實作了低損耗。在新的資料上也能獲得更高的準确性。

建立 的腳本

現在,CNN已經訓練過了,我們需要編寫一個腳本,對新圖像進行分類。建立一個檔案,并命名為classify.py,插入以下代碼:

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

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

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

我們來解析下代碼中的參數(12-19行),需要的三個參數如下:

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

2.--labelbin:标簽二進制器的路徑。

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

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

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

第22行加載輸入圖像image,并複制一個副本,指派給out(第23行)。

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

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

随後,對圖像進行分類并建立标簽(39-41行)。

剩餘的代碼用于顯示:

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

第46-47行從filename中提取精靈圖鑒的名字,并與label進行比較。Correct變量是“正确(correct)”或“不正确(incorrect)”。然後執行以下操作:

1.50行将機率值和“正确/不正确”文本添加到類别标簽label上。

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

3.52和53行在輸出圖像上繪制标簽。

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

KNN 對圖像分類

運作classify.py腳本(確定已經從原文“下載下傳”部分擷取代碼和圖檔)!下載下傳并解壓縮檔案到這個項目的根目錄下,然後從Charmander圖像開始。代碼及試驗結果如下:

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

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

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

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

模型的局限性

該模型的主要局限是訓練資料少。我在各種不同的圖像進行測試,發現有時分類不正确。我仔細地檢查了輸入圖像和神經網絡,發現圖像中的主要顔色會影響分類結果。

例如,如果圖像中有許多紅色和橙色,則可能會傳回“Charmander”标簽;圖像中的黃色通常會傳回“Pikachu”标簽。這歸因于輸入資料,精靈圖鑒是虛構的,它沒有“真實世界”中的真實圖像。并且,我們隻為每個類别提供了比較有限的資料(約225-250張圖檔)。

理想情況下,訓練卷積神經網絡時,每個類别至少應有 500-1,000 幅圖像。 可以将 深度學習模型作為 REST API 嗎?

如果想将此模型(或任何其他深度學習模型)用作REST API運作,可以參照下面的博文内容:

建構一個簡單的Keras + 深度學習REST API 可擴充的Keras + 深度學習REST API 使用Keras,Redis,Flask和Apache進行深度學習 總結

這篇文章主要介紹了如何使用Keras庫來訓練卷積神經網絡(CNN)。使用的是自己建立的資料集(精靈圖鑒)作為訓練集和測試集,其分類的準确度達到97.07%。

數十款阿裡雲産品限時折扣中,趕緊點選領劵開始雲上實踐吧!

以上為譯文。

本文由北郵

@愛可可-愛生活

 老師推薦,

阿裡雲雲栖社群

組織翻譯。

文章原标題《

Keras and Convolutional Neural Networks (CNNs)

》,譯者:Mags,審校:袁虎。 文章為簡譯,更為詳細的内容,請檢視 原文