當前位置:
首頁 > 最新 > 我用Python實現了12500張貓狗圖像的精準分類

我用Python實現了12500張貓狗圖像的精準分類

在這篇文章中,我們將展示如何建立一個深度神經網路,能做到以 90% 的精度來對圖像進行分類,而在深度神經網路,特別是卷積神經網路興起之前,這還是一個非常困難的問題。

深度學習是目前人工智慧領域裡最讓人興奮的話題之一了,它基於生物學領域的概念發展而來,現如今是一系列演算法的集合。

事實已經證明深度學習在計算機視覺、自然語言處理、語音識別等很多的領域裡都可以起到非常好的效果。

在過去的 6 年裡,深度學習已經應用到非常廣泛的領域,很多最近的技術突破,都和深度學習相關。

這裡僅舉幾個例子:特斯拉的自動駕駛汽車、Facebook 的照片標註系統、像 Siri 或 Cortana 這樣的虛擬助手、聊天機器人、能進行物體識別的相機,這些技術突破都要歸功於深度學習。

在這麼多的領域裡,深度學習在語言理解、圖像分析這種認知任務上的表現已經達到了我們人類的水平。

如何構建一個在圖像分類任務上能達到 90% 精度的深度神經網路?

這個問題看似非常簡單,但在深度神經網路特別是卷積神經網路(CNN)興起之前,這是一個被計算機科學家們研究了很多年的棘手問題。

本文分為以下三個部分進行講解:

一個有趣的實例:給貓和狗的圖像分類

有很多的圖像數據集是專門用來給深度學習模型進行基準測試的,我在這篇文章中用到的數據集來自 Cat vs Dogs Kaggle competition,這份數據集包含了大量狗和貓的帶有標籤的圖片。

和每一個 Kaggle 比賽一樣,這份數據集也包含兩個文件夾:

我們觀察一下這些圖片的特點,這些圖片各種各樣,解析度也各不相同。圖片中的貓和狗形狀、所處位置、體表顏色各不一樣。

它們的姿態不同,有的在坐著而有的則不是,它們的情緒可能是開心的也可能是傷心的,貓可能在睡覺,而狗可能在汪汪地叫著。照片可能以任一焦距從任意角度拍下。

這些圖片有著無限種可能,對於我們人類來說在一系列不同種類的照片中識別出一個場景中的寵物自然是毫不費力的事情,然而這對於一台機器來說可不是一件小事。

實際上,如果要機器實現自動分類,那麼我們需要知道如何強有力地描繪出貓和狗的特徵,也就是說為什麼我們認為這張圖片中的是貓,而那張圖片中的卻是狗。這個需要描繪每個動物的內在特徵。

深度神經網路在圖像分類任務上效果很好的原因是,它們有著能夠自動學習多重抽象層的能力,這些抽象層在給定一個分類任務後又可以對每個類別給出更簡單的特徵表示。

深度神經網路可以識別極端變化的模式,在扭曲的圖像和經過簡單的幾何變換的圖像上也有著很好的魯棒性。讓我們來看看深度神經網路如何來處理這個問題的。

配置深度學習環境

深度學習的計算量非常大,當你在自己的電腦上跑一個深度學習模型時,你就能深刻地體會到這一點。

但是如果你使用 GPUs,訓練速度將會大幅加快,因為 GPUs 在處理像矩陣乘法這樣的並行計算任務時非常高效,而神經網路又幾乎充斥著矩陣乘法運算,所以計算性能會得到令人難以置信的提升。

我自己的電腦上並沒有一個強勁的 GPU,因此我選擇使用一個亞馬遜雲服務 (AWS) 上的虛擬機,這個虛擬機名為 p2.xlarge,它是亞馬遜 EC2 的一部分。

這個虛擬機的配置包含一個 12GB 顯存的英偉達GPU、一個 61GB 的 RAM、4 個 vCPU 和 2496 個 CUDA 核。

可以看到這是一台性能巨獸,讓人高興的是,我們每小時僅需花費 0.9 美元就可以使用它。當然,你還可以選擇其他配置更好的虛擬機,但對於我們現在將要處理的任務來說,一台 p2.xlarge 虛擬機已經綽綽有餘了。

我的虛擬機工作在 Deep Learning AMI CUDA 8 Ubuntu Version 系統上,現在讓我們對這個系統有一個更清楚的了解吧。

這個系統基於一個 Ubuntu 16.04 伺服器,已經包裝好了所有的我們需要的深度學習框架(TensorFlow,Theano,Caffe,Keras),並且安裝好了 GPU 驅動(聽說自己安裝驅動是噩夢般的體驗)。

如果你對 AWS 不熟悉的話,你可以參考下面的兩篇文章:

這兩篇文章可以讓你知道兩點:

用 TensorFlow 和 Keras 建立一個貓/狗圖片分類器

環境配置好後,我們開始著手建立一個可以將貓狗圖片分類的卷積神經網路,並使用到深度學習框架 TensorFlow 和 Keras。

先介紹下 Keras:Keras 是一個高層神經網路 API,它由純 Python 編寫而成並基於Tensorflow、Theano 以及 CNTK 後端,Keras 為支持快速實驗而生,能夠把你的 idea 迅速轉換為結果。

從頭開始搭建一個卷積神經網路

首先,我們設置一個端到端的 pipeline 訓練 CNN,將經歷如下幾步:數據準備和增強、架構設計、訓練和評估。

我們將繪製訓練集和測試集上的損失和準確度指標圖表,這將使我們能夠更直觀地評估模型在訓練中的改進變化。

數據準備

在開始之前要做的第一件事是從 Kaggle 上下載並解壓訓練數據集。

我們必須重新組織數據以便讓 Keras 更容易地處理它們。我們創建一個 data 文件夾,並在其中創建兩個子文件夾:

在上面的兩個文件夾之下,每個文件夾依然包含兩個子文件夾:

最後我們得到下面的文件結構:

data/

train/

dogs/

dog001.jpg

dog002.jpg

...

cats/

cat001.jpg

cat002.jpg

...

validation/

dogs/

dog001.jpg

dog002.jpg

...

cats/

cat001.jpg

cat002.jpg

這個文件結構讓我們的模型知道從哪個文件夾中獲取到圖像和訓練或測試用的標籤。這裡提供了一個函數允許你來重新構建這個文件樹,它有 2 個參數:圖像的總數目、測試集 r 的比重。

我使用了:

現在讓我們裝載 Keras 和它的依賴包吧:

圖像生成器和數據增強

在訓練模型時,我們不會將整個數據集裝載進內存,因為這種做法並不高效,特別是你使用的還是你自己本地的機器。

我們將用到 ImageDataGenerator 類,這個類可以無限制地從訓練集和測試集中批量地引入圖像流。在ImageDataGenerator 類中,我們將在每個批次引入隨機修改。

這個過程我們稱之為數據增強(dataaugmentation)。它可以生成更多的圖片使得我們的模型不會看見兩張完全相同的圖片。這種方法可以防止過擬合,也有助於模型保持更好的泛化性。

我們要創建兩個 ImageDataGenerator 對象。train_datagen 對應訓練集,val_datagen 對應測試集,兩者都會對圖像進行縮放,train_datagen 還將做一些其他的修改。

基於前面的兩個對象,我們接著創建兩個文件生成器:

每個生成器在實時數據增強的作用下,在目錄處可以生成批量的圖像數據。這樣,數據將會無限制地循環生成。

模型結構

我將使用擁有 3 個卷積/池化層和 2 個全連接層的 CNN。3 個卷積層將分別使用 32,32,64 的 3 * 3的濾波器(fiter)。在兩個全連接層,我使用了 dropout 來避免過擬合。

我使用隨機梯度下降法進行優化,參數 learning rate 為 0.01,momentum 為 0.9。

Keras 提供了一個非常方便的方法來展示模型的全貌。對每一層,我們可以看到輸出的形狀和可訓練參數的個數。在開始擬合模型前,檢查一下是個明智的選擇。

model.summary()

下面讓我們看一下網路的結構。

結構可視化

在訓練模型前,我定義了兩個將在訓練時調用的回調函數 (callback function):

我還使用了 keras-tqdm,這是一個和 keras 完美整合的非常棒的進度條。它可以讓我們非常容易地監視模型的訓練過程。

要想使用它,你僅需要從 keras_tqdm 中載入 TQDMNotebookCallback 類,然後將它作為第三個回調函數傳遞進去。

下面的圖在一個簡單的樣例上展示了 keras-tqdm 的效果。

關於訓練過程,還有幾點要說的:

這個模型運行時的計算量非常大:

分類結果

我們在模型運行 34 個 epoch 後達到了 89.4% 的準確率(下文展示訓練/測試錯誤和準確率),考慮到我沒有花費很多時間來設計網路結構,這已經是一個很好的結果了。現在我們可以將模型保存,以備以後使用。

model.save(`./models/model4.h5)

下面我們在同一張圖上繪製訓練和測試中的損失指標值:

當在兩個連續的 epoch 中,測試損失值沒有改善時,我們就中止訓練過程。

下面繪製訓練集和測試集上的準確度。

這兩個指標一直是增長的,直到模型即將開始過擬合的平穩期。

裝載預訓練的模型

我們在自己設計的 CNN 上取得了不錯的結果,但還有一種方法能讓我們取得更高的分數:直接載入一個在大型數據集上預訓練過的卷積神經網路的權重,這個大型數據集包含 1000 個種類的貓和狗的圖片。

這樣的網路會學習到與我們分類任務相關的特徵。

我將載入 VGG16 網路的權重,具體來說,我要將網路權重載入到所有的卷積層。這個網路部分將作為一個特徵檢測器來檢測我們將要添加到全連接層的特徵。

與 LeNet5 相比,VGG16 是一個非常大的網路,它有 16 個可以訓練權重的層和 1.4 億個參數。要了解有關 VGG16 的信息,請參閱此篇 pdf 鏈接:https://arxiv.org/pdf/1409.1556.pdf

現在我們將圖像傳進網路來得到特徵表示,這些特徵表示將會作為神經網路分類器的輸入。

圖像在傳遞到網路中時是有序傳遞的,所以我們可以很容易地為每張圖片關聯上標籤。

現在我們設計了一個小型的全連接神經網路,附加上從 VGG16 中抽取到的特徵,我們將它作為 CNN 的分類部分。

在 15 個 epoch 後,模型就達到了 90.7% 的準確度。這個結果已經很好了,注意現在每個 epoch 在我自己的電腦上跑也僅需 1 分鐘。

許多深度學習領域的大牛人物都鼓勵大家在做分類任務時使用預訓練網路,實際上,預訓練網路通常使用的是在一個非常大的數據集上生成的非常大的網路。

而 Keras 可以讓我們很輕易地下載像 VGG16、GoogleNet、ResNet 這樣的預訓練網路。想要了解更多關於這方面的信息,請參考這裡:https://keras.io/applications/

有一句很棒的格言是:不要成為英雄!不要重複發明輪子!使用預訓練網路吧!

接下來還可以做什麼?

如果你對改進一個傳統 CNN 感興趣的話,你可以:

如果你對使用預訓練網路獲得更好的分類結果感興趣的話,你可以嘗試:

如果你想知道 CNN 這個深度學習模型到底學習到了什麼東西,你可以:

如果你想使用訓練過的模型:

總結

這是一篇手把手教你在 AWS 上搭建深度學習環境的教程,並且教你怎樣從頭開始建立一個端到端的模型,另外本文也教了你怎樣基於一個預訓練的網路來搭建一個 CNN 模型。

用 Python 來做深度學習是讓人愉悅的事情,而 Keras 讓數據的預處理和網路層的搭建變得更加簡單。

如果有一天你需要按自己的想法來搭建一個神經網路,你可能需要用到其他的深度學習框架。

現在在自然語言處理領域,也有很多人開始使用卷積神經網路了,下面是一些基於此的工作:

作者:AhmedBesbes,張盛強翻譯

編輯:陶家龍、孫淑娟


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Python 的精彩文章:

Python作SCI圖起步

TAG:Python |