第12章 訓練你的第一個CNN


  第12章 訓練你的第一個CNN

      既然熟悉了CNN基礎,我們將用python和keras實現我們的第一個CNN。我們通過快速的回顧當構建和訓練你的CNNs時應當注意的keras配置開始本章。之后將實現ShallowNet,它是一個僅有單個CONV層的非常淺的CNN。但是,不要被這個網絡的簡潔性蒙蔽了你,ShallowNet在CIFAR-10和Animals數據集上,與我們到目前為止本書所回顧的任何其它方法相比,它將獲得高分類精確度的能力。

1         Keras配置和將圖像轉為數組

在我們實現ShallowNet之前,我們首先需要查看keras.json配置文件,以及該文件中的設置將如何影響您如何實現自己的CNNs。我們也將實現第二個名為ImageToArrayPreprocessor的圖像預處理功能,它接收一副輸入圖像並且將它轉換為keras可以工作的NumPy數組。

1.1  理解keras.json配置文件

在我們第一次將keras庫導入python shell或執行import keras的python腳本時,keras將在home目錄下產生一個keras.json的文件,現在我們打開該文件查看,vim ~/.keras/keras.json:

 

      我們注意到這個json格式文件有4個key以及對應的4個值,epsilon值在keras庫的不同位置使用用於防止除以0操作錯誤,默認值為1e-7是固定的且不應該被改變。之后我們有一個floatx的值表示浮點精度,設置為float32是精度安全的。

      還有兩個極其重要的配置為image_data_format和backend。默認keras庫使用TensorFlow數值計算后端,我們也可以僅僅通過替換“tensorflow”成“theano”變成Theano計算后端。Keras庫允許你編寫與這些后端兼容的代碼。最后這個image_data_format可配置兩個值:channels_last和channels_first。我們知道圖像在OpenCV中是按照(rows,columns,channels)的順序表示,這也是keras默認配置的channels_last方式,即通道作為數組的最后的維度。兩種設置,是因為在Theano社區,用戶傾向於channels_first順序,但是在TensorFlow發行版中教程和示例都是channels_last順序,為了保持兼容,keras使用兩種順序。並且keras引入一個img_to_array的函數用於接收圖像輸入參數,並按照這個默認配置順序來返回一個數組。

1.2  圖像到數組預處理器

本節我們通過引入一個新的ImageToArrayPreprocessor預處理器用於將輸入圖像變為keras庫支持的數組順序的數組格式。我們首先將github上的chapter7/pyimagesearch文件夾拷貝到chapter12下,然后在preprocessing/下創建imagetoarraypreprocessor.py文件,此時的目錄架構如下所示:

     

       我們打開剛創建的imagetoarraypreprocessor.py文件,開始寫代碼,具體代碼見https://github.com/shengqishi8787/Starter_Bundle.git

      

       首先from keras.preprocessing.image import img_to_array導入圖像轉為數組的包,這里我們可以明確的指定通道在前或在后,但是最好是讓keras根據keras的json配置文件自行決定。而且我們在這里定義一個類來處理預處理而不是直接調用img_to_array方法,是因為我們這樣做可以方便的對圖像通過預處理列表進行一系列預處理,即可以通過構建一個預處理鏈條來對圖像一步步處理。基於我們在之前對圖像縮放的預處理,我們現在有了兩個預處理,那么我們可以構建一個預處理鏈條,首先應用SimplePreprocessor對圖像縮放到32×32尺寸,然后調用ImageToArrayPreprocessor對圖像按默認通道變為數組格式,如圖1所示:

              

                            圖1 預處理鏈條示例
       用這種方式將簡單的預處理器串在一起,每個預處理器負責一個小任務,這是一種簡單的構建一個可擴展的專門用於圖像分類的深度學習庫的方式。后續預處理中我們也將采用這種方式。

2         ShallowNet

       ShallowNet網絡架構僅包含很少層,可概括為:INPUT => CONV => RELU => FC。

2.1  實現ShallowNet

       為了保持簡潔,我們在上述目錄結構中創建一個nn,然后在nn下創建一個conv的文件夾,里面包含我們的CNN架構:

        

       在conv下的shallownet.py包含我們的ShallowNet架構實現,現在讓我們實現它:

        

 
        
       2-9行我們導入必要的類,其中Conv2D為keras的卷積層實現,之后的Activation將以激活函數作為輸入實現激活功能。Flatten類將以多維卷作為輸入,然后在將這個輸入送入Dense層之前flatten成1D數組。
       我們定義了一個ShallowNet的類以及一個build方法,該方法在本書中都是用來構建CNN網絡並返回給調用函數。該方法接收4個參數,即輸入圖像的寬、高、深度、以及類別數目(如Animals數據集為3,CIFAR-10為10)。
       我們在第15-19行對輸入圖像根據配置的深度優先順序進行數組格式轉換,在所有構建中都建議使用這些操作。
       在形狀shape定義好后,下面就可以根據CNN模型架構來順序構建模型了,首先在Conv2D中構建卷積層如第22行,其中參數分別為核數目、感受野大小F×F,然后設定padding=”name”保持輸出尺寸與輸入尺寸一致。最后通過26-29行完成softmax分類器的設置完成該模型的配置。
       現在我們完成了ShallowNet的定義,就可以編寫真正的驅動腳本,進行加載數據集、預處理、訓練網絡。我們將在Animals和CIFAR-10數據集上演示。

2.2  在Animals上演示ShallowNet

       我們首先創建一個shallownet_animals.py文件,確保該文件與我們的pyimagesearch模塊在同一個目錄下。注意如果我們想按照下面的導入進行模塊導入,我們需要將nn/conv/以及preprocessing/下的__init__.py文件配置,即將對應文件夾下的類包含到里面即可,如:

          

       代碼見GitHub,在導入必要的庫之后。我們首先通過解析參數,來加載需要的數據集。加載后,在26-33行通過鏈表預處理依次對圖像縮放、轉換並且進行歸一化到[0, 1]。
       然后在第37-42行對數據集進行划分,分成75%的訓練集和25%的測試集。並對標簽進行向量化。
       准備好數據集,我們就可以在第46-54行對模型進行初始化並且進行訓練網絡。訓練完成后,在57-61進行評估網絡。最后進行畫圖顯示評估曲線。
       運行代碼python shallownet_animals.py –dataset ../datasets/animals后可顯示訓練結果:

          

       以及訓練與測試曲線圖:

                    

       我們看到在測試數據集上我們ShallowNet獲得了71%的分類正確率,比我們之前的前饋神經網絡59%提高了很多。使用更高級的訓練網絡以及更強大的網絡架構,我們還可以獲得更高的分類正確率。
       由上述圖曲線可以看出,在epoch為20或60時學習有一點大的波動——這很可能由於學習率太高了,可在第16章闡述克服。我們還看到在epoch為30之后,訓練和測試損失出現分歧,暗示我們的網絡對訓練數據的建模太過接近和過擬合了。我們可以通過獲得更多的數據或采用像數據增加(data augmentation)這樣的技術(在Practitioner Bundle中)來糾正這個問題。
       在大約epoch為60時,我們的測試正確率飽和了——不能再超過70%的正確率了,但是我們的訓練正確率卻能夠達到超過85%。那么,在將來通過收集更多的數據、應用數據增加、更仔細的調整學習率將能夠提高這個結果。
       我們這里的使用極其簡單的CNN網絡就獲得了71%的正確率。
 

2.3  在CIFAR-10上演示ShallowNet

       該數據集的驗證見github的chapter12/下的shallownet_cifar10.py。基本處理過程與在digital數據集上過程類似。計算完成后,損失與精確度結果如下:
   

            

       可看到該圖示的結果與上一例子基本一致,都出現了過擬合,由於我們使用了有限的樣本數據。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM