Keras 深度學習之貓狗大戰

項目地址和代碼:Project_Dogs_vs_Cats
項目詳細報告:Report_dogs_vs_cats.pdf
keras 版本:2.1.5


1.問題定義和數據集獲取:
        項目屬於計算機視覺領域中的圖像分類問題。圖像分類的過程非常明確:給定已經標記的數據集,提取特徵,訓練得到分類器。項目使用Kaggle競賽提供的Dogs vs. Cats數據集,任務是對給定的貓和狗的圖片進行分類,因此是二分類問題(Binary Classification)。
        項目要解決的問題是使用12500張貓和12500張狗的圖片作爲測試集,訓練一個合適的模型,能夠在給定的12500張未見過的圖像中分辨貓和狗。在機器學習領域,用於分類的策略,包括K均值聚類、支持向量機等,均能夠用於處理該二分類問題。但在圖像分類領域,神經網絡技術具有更加明顯的優勢,特別是深度卷積神經網絡,已成功地應用於圖像識別領域。

2.選擇度量成功的標準(損失函數):
        
分類準確度(accuracy)和代價函數(Cost Function)是常用的分類評估指標。爲了對模型進行更細緻的評價,代價函數更加合理。通過代價函數計算結果的值越小,就代表模型擬合的越好。神經網絡的代價函數是用於logistic迴歸的一個泛化。Kaggle官網在此次競賽中對預測結果的評估採用的是對數損失函數log loss:
                                                  \textrm{LogLoss} = - \frac{1}{n} \sum_{i=1}^n \left[ y_i \log(\hat{y}_i) + (1 - y_i) \log(1 - \hat{y}_i)\right],                                                           
        式中, n爲測試集圖像總數量; \hat{y}_{i}指圖像類別爲狗的預測概率;如果圖像類別爲狗, \hat{y}_{i}爲1,如果爲貓, \hat{y}_{i}爲0。對數損失值越小,預測結果越優。

3.確定評估方法:
        
三種常見的評估方法(evaluation protocols):(1)維持一個驗證集不變,這通常在數據充足的情況下使用;(2)k-折交叉驗證,數據量較少情況下;(2)迭代的k-折交叉驗證,數據量較少而要求高精度模型評價時使用。這裏選擇第一種方法。
        
4.準備數據(數據預處理):
        訓練集包括25000張被標記的貓和狗的圖片(各佔一半)。測試集爲12500張未被標記的圖片,同樣是貓狗圖片各佔一半。測試集將作爲輸入來訓練分類器。在數據用於訓練前須進行預處理,使數據格式與模型相匹配。另外,數據預處理還可以應用數據增強技術,包括圖片裁剪或填充、歸一化。如果計算資源有限,還可以將圖像轉化爲灰度圖像存儲。數據集的部分圖片如圖所示:
 


        訓練集圖像的尺寸分佈如下圖所示。通過該散點圖,我們可以非常直觀地瞭解數據的構成:絕大部分圖像的尺寸都分佈在500×500內。貓和狗的圖片各自都只有一張圖像的尺寸偏離正常範圍內,屬於異常值。於是下一步,我們首先找出這兩幅圖像。
 


      這兩幅圖像如下方左圖所示。但是,我們的圖像在輸入模型訓練前,是需要進行數據預處理的,例如我們可能對圖像進行尺寸縮放或裁剪以使輸入數據格式統一。圖像裁剪可能會影響模型的訓練,因爲它可能將圖像的有用信息丟棄。而在這個項目中,我們將只使用尺寸縮放。縮放後的貓狗圖像如下方右圖所示,我們還是可以很確定地辨別出貓和狗,這說明了圖像縮放這種預處理方式並不會對模型分類帶來壞影響,並不影響其學習,所以這對異常值是沒有必要處理的!
                                                                    

       既然圖像的尺寸對模型的訓練不會帶來影響或者影響甚微,那麼便接着探索數據集是否存在其他異常值。由於讀取圖像時三個通道的值都限制在[0,255]內,分佈範圍較小,因此圖像通道值的最大值和最小值和均值都不會成爲異常值。因而,將目光投向通道值的標準差,原因是通過標準差更可能發現異常值。設想一下,假如一幅圖像中通道值的標準差很小,這意味着圖像越接近於純色,則其包含的信息量越少,越不容易用於提取可用於分類的特徵。爲了簡化問題,將圖像讀取爲灰度圖,這樣就只需要分析單通道了。
       下面兩幅圖像分別是所有貓狗圖像中,灰度圖模型下,通道值標準差最小的情況。可以看到,雖然圖像顏色比較單一,但是我們還是能夠通過人眼清晰地識別出貓和狗,因此這部分不存在異常值!
 

       訓練數據的異常值還有另一種情況,那就是類別標籤標註上的異常值。尋找這些異常值最直接但同時也是最繁瑣的方法,就是耐心地將訓練集裏面的圖片都手動檢查一遍!但事實上我們可以用其他方式解決,那就是使用預處理模型來進行排查,這將大大減少我們的工作量。基本思路是,使用表現最佳的預處理模型(這裏選擇在Imagenet上表現很好的Xception)對訓練集的圖片進行預測,給出預測正確分類概率最高的n個分類。檢驗貓、狗標籤是否在這n個類別之內,若不在則將該圖片視爲可能的異常值。
       利用Xception預測後,使用 decode_predictions ,設置top參數爲n(一開始均設置爲30),將預測結果轉化,獲得預測正確分類概率最高的n個分類。檢驗貓、狗標籤是否在這n個類別之內,若不在則將圖像視爲可能的異常值。此時,貓狗圖片中的可能異常值數量分別爲80和23,如下圖所示爲部分查找得到的可能異常值。
 

                                                                     圖a. 貓圖片可能異常值(Top參數均爲30
 

                                                                  圖b. 狗圖片可能異常值(Top參數均爲30
       可以看到,當top參數均設置爲30時,貓圖片的異常值統計數量較狗圖片多,同時錯誤統計也多。對於狗圖片的異常值統計情況,則幾乎沒有失誤。這可能是由於imagenet在構建數據集時對狗的歸類做的比較詳細(imagenet上狗的類別有118種,而貓的類別只有7種)。因此,我認爲設置top參數時,應該將貓和狗分開討論,不能一概而論。經過一番嘗試,我將貓的top參數設置爲35,狗的top參數設置爲10,最後獲得的部分可能的異常值如下圖所示,其中貓有62幅,狗有36幅。相較於完全手動檢查一遍,這已經大大降低了工作量。
 


                                                                 圖a. 貓圖片可能異常值(Top參數均爲35
 

                                                                 圖b. 狗圖片可能異常值(Top參數均爲10

       從上面的分析可以看到,貓狗大戰數據集的異常值主要是標註上的異常值。在將訓練數據輸入模型訓練之前,需要將這些異常數據進行預處理。我將考慮一下處理方式:(1)將與主題完全無關的圖片刪除;(2)對於分類錯誤的圖片,修改類別標註(例如本來是狗的圖片卻標註爲貓,這時候就需要將標註修改);(3)將背景複雜的圖片進行裁剪。
        這些異常值很難通過數據科學的方法(均值、平均值等)進行描述和發現,在處理的時候選擇也只能手動處理。


5.設計一個優於隨機預測的簡單模型:
       對於圖片分類問題,存在一些分類效果很好的深度卷積網絡,例如AlexNet、Inception,但在一開始,我們會先使用簡單的分類模型進行訓練並觀察其表現。在該項目中,我首先建立了如下結構的簡單模型,它的分類準確性確實要明顯優於隨機分類:


       可以看到,該簡單CNN模型由若干個層“堆疊”而成,且可以分成這三部分:(1)輸入層;(2)卷積層和池化層的組合;(3)全連接的多層感知機分類器。在需要處理過擬合問題時通常還會引入dropout層。

6.設計過擬合模型:
       
自己從頭設計CNN有時並不是一個好的決定,它既費時而且又不一定能獲得優秀的表現。所以,在該項目將採用遷移學習的方法,其中使用的用於fine tune的預訓練模型包括 VGG16,ResNet50,Inception v3和Xception。
       本項目中,在使用各個預訓練模型時,都採取了同一個流程。首先,嘗試使用特徵提取方法。第一步,加載去掉頂層分類器的模型(留下卷積層)之結構和權重,並將訓練數據輸入模型,提取特徵向量;第二步,爲卷積層添加全連接層和drop out層,輸入上一步提取的特徵向量進行分類,觀察分類結果並評價。第三步,爲卷積層添加一個包含卷積核的頂層分類器,將加載的卷積基礎層凍結(不凍結頂層分類器的卷積核),重新編譯模型。輸入圖片數據進行訓練,得到一個訓練過的頂層分類器。之後,嘗試使用參數微調方法。在使用特徵提取手段時,我們已經得到了一個包含卷積層的頂層分類器。現在,可以將凍結的卷積層解開部分層,與頂層分類器一起訓練。參數微調就是微調加載的模型的部分卷積層以及新加入的頂層分類器的權重。
       這裏需要注意的是:爲了順利地進行參數微調,模型的各個層都需要以預先訓練過的權重爲初始值。所以,不能將隨機初始化權重的全連接層放在預訓練過的卷積層之上,否則會破壞卷積層預訓練獲得的權重。體現在前面談到的流程中,就是先使用特徵提取方法訓練頂層分類器,再基於這個頂層分類器進行參數微調。
       另外,參數微調時不會選擇訓練整個網絡的權重,而只微調位於模型中較深的部分卷積層,這在一定程度上可以防止過擬合。在前面已經提到,因爲由底層卷積模塊學習到的特徵更具一般性,而不是抽象性。
       對於VGG16模型,我首先嚐試選擇將其卷積模塊的末尾3個卷積層凍結然後再進行參數微調,但效果並不理想。於是我又將凍結層擴大至末尾4個卷積層,進行參數微調;對於InceptionV3,選擇將249層之前的層凍結;對於Resnet50,選擇將168層之前的層凍結;對於Xception,選擇將126層之前的層凍結。下圖所示表示了VGG16參數微調的設置方法,其他模型的設置原理與此類似。
 


7.調整模型、調整超參數:
       應用參數微調技術時應該在比較低的學習率下訓練,這裏使用的學習率爲0.00001,優化器爲RMSprop。較低的學習率可以使訓練過程中保持較低的更新幅度,以防止破壞模型卷積層預訓練的特徵。
       在一開始,我將Batch size 設置爲50,但是在訓練時發現模型不容易收斂,而且在測試集和驗證集上的損失函數值波動較大,引入Keras的回調函數EarlyStopping(EarlyStopping能夠讓模型在訓練時根據設定的條件停止)時,需將patience參數設置爲較大的值。故後面將Batch size調整爲較大值。但Batch size太大對GPU顯存資源也是一個很大的負荷,最終將訓練時的Batch size調整爲100。
       爲了應對模型過擬合問題,我使用了數據增強技術來訓練一個新的網絡,所以所有epoch中是不會有兩次相同的輸入的。但是,這些輸入仍然是相互關聯的,因爲它們來自有限的原始圖像,數據增強並不能產生新的信息,而只能重新混合現有的信息。因此,這可能不足以完全擺脫過度擬合。爲了進一步克服過度擬合,我還將在模型中全連接層分類器的前面添加一個dropout層這是一種正則化手段,不過跟Regularization不同的是,它是通過將訓練的層中的部分神經元的輸出置零來實現的。在這裏,使用的Dropout參數爲0.5。
       但在參數微調過程中,我發現Xception很快就停止訓練了,因爲使用了EarlyStopping回調函數,而且val_acc和val_loss都呈現出模型的性能在下降的趨勢,最後參數微調效果也不理想。於是我增大了數據增強的幅度,重新跑了一遍程序,這時Xception模型依然很快就停止訓練,但是val_acc和val_loss卻是往好的趨勢變化。在這之後,我果斷將EarlyStopping中的stop參數調整爲較大的整數,從而增加Xception訓練的epoch數量。
       所有模型的訓練都在Jupyter Notebook中完成。程序批量讀取圖片,並根據具體模型進行相應的數據預處理,包括數據增加技術。各模型訓練過程如圖中所示,由於參數微調時的模型的頂層分類器之權重是由特徵提取過程中訓練過的,因此在訓練的一開始,模型就已經表現得比較好了。後三個模型在整個參數微調過程中,模型的改進幅度並不明顯。最終訓練得到的結果準確率已經很高了。
 

       可以看到模型表現相對較優的是Xception、Inception V3,它們在驗證集上的分類準確率均高於99%,損失值均低於0.03。而Inception V3在驗證集上的分類準確率已經達到了0.993%,logloss值爲0.025左右,參數微調效果非常理想,和Xception十分接近!ResNet50雖然也達到了不錯的分類準確性,但結果卻和Inception V3想比卻處於劣勢。初步猜測是模型訓練時參數設置不夠合理導致的,例如數據增強的設置,在往後的學習中會進行驗證。VGG16的表現相對於前面三種模型則處於明顯的劣勢,畢竟VGG16相對較老,網絡結構也較淺。

8.特徵融合:
       
使用預訓練的模型進行參數微調確實比使用自己搭建的模型能夠獲得更小的損失函數值,但是訓練過程還是十分緩慢的。在對每一個模型進行參數微調前,我都有都嘗試直接使用特徵向量來進行分類,而且個別模型的分類結果十分理想,包括ResNet50、InceptionV3和Xception。因此,嘗試將提取的多個較優模型的特徵進行組合,是一個非常可行的方案!
       整個構建過程很簡單。首先,我們選擇在前面的訓練中表現最好的三個模型ResNet50、InceptionV3和Xception作爲特徵融合的對象模型。接着,先將數據輸入各個模型中,提取特徵向量並保存下來。然後,將對應同一個訓練樣本的來自這三個模型的三個特徵向量在長度上進行堆疊,最終得到共12500個維度爲3×2048=6144的特徵向量。
       最後,構建一個簡單的神經網絡,輸入上一步特徵融合得到的特徵向量集合,進行訓練。應用特徵融合技術構建的模型如圖所示(這部分代碼和思路借鑑自楊培文老師,由衷感謝!)。
 

       運用特徵融合方法的訓練曲線如下圖所示,最終在驗證集上的準確率很輕鬆地就達到了99.6%,val_loss也只有0.012。
 




 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章