前言:現今最主流的處理圖像數據的技術當屬深度神經網絡了,尤其是卷積神經網絡CNN尤為出名。本文將通過講解CNN的介紹以及使用keras搭建CNN常用模型LeNet-5實現對MNist數據集分類,從而使得讀者更好的理解CNN。
1.CNN的介紹
CNN是一種自動化提取特徵的機器學習模型。首先我們介紹CNN所用到一些基本結構單元:
1.1卷積層:在卷積層中,有一個重要的概念:權值共享。我們通過卷積核與輸入進行卷積運算。通過下圖可以理解如何進行卷積運算。卷積核從左到右對輸入進行掃描,每次滑動1格(步長為1),下圖為滑動一次後,卷積核每個元素和輸入中綠色框相應位置的元素相乘後累加,得到輸出中綠色框中的0。一般會使用多個卷積核對輸入數據進行卷積,得到多個特徵圖。
圖1:卷積運算
1.2激活層:對卷積層的輸出進行一個非線性映射,因為卷積計算是一種線性計算。常見的激活函數有relu、tanh、sigmoid等,一般使用relu。
引入非線性激活函數的原因:
如果不引入非線性映射的話,無論有多少層神經網絡,輸出都是輸入的線性組合,這與一層隱藏層的效果相當。
b.一般使用relu的原因:
在反向傳播計算梯度中,使用relu求導明顯會比tanh和sigmoid簡單,可以減少計算量。
同時,使用tanh和sigmoid,當層數較多時容易導致梯度消失,因為tanh和sigmoid的導數均小於1(可參考激活函數的導數公式),當我們神經網絡有多層的時候,每層都要乘以這個小於1的導數,就有可能接近於0,這就是所謂的梯度消失。而使用relu求導,若輸出不為0時,導數均為1,可以有效避免梯度消失問題。
另外,relu還會將小於0的映射為0,使得網絡較為稀疏,減少神經元之間的依賴,避免過擬合。
圖2:從左到右依次為sigmoid、tanh、relu激活函數
1.3池化層:池化的目的就是減少特徵圖的維度,減少數據的運算量。池化層是在卷積層之後,對卷積的輸出,進行池化運算。池化運算,一般有兩種MaxPooling和MeanPooling。選取一個池化窗口(一般為2*2),然後從左往右進行掃描,步長一般為2。如下圖MaxPooling操作,選取池化窗口中最大值作為該位置的輸出。如:左邊綠色方框中四個特徵值中,選取最大的6作為輸出相應位置的特徵值。而MeanPooling則是對於池化窗口中的特徵值求平均。
1.4全連接層:主要是對特徵進行重新的擬合,減少特徵信息的丟失。通過卷積池化操作後得到的是多個特徵矩陣,而全連接層的輸入為向量,所以在進行全連接層之前,要將多個特徵矩陣「壓平」為一個向量。
對於CNN的卷積、池化操作,其實很多文章都會詳細的介紹,但卷積和池化的意義是什麼,很多文章都沒有明確給出解釋。可能會有人認為卷積和池化可以很大程度的減少權重參數,但只是因為這個原因嗎?顯然不是的,接下來將講解CNN是如何實現有效的分類從而理解卷積和池化的意義。
用深度學習解決圖像識別問題,從直觀上講是一個從細節到抽象的過程。所謂細節,就是指輸入圖像的每個像素點,甚至像素點構成的邊也可以理解為是細節。假設我們大腦接收到一張動物圖,大腦最先反應的是該圖的點和邊。然後由點和邊抽象成各種形狀,比如三角形或者圓形等,然後再抽象成耳朵和臉等特徵。最後由這些特徵決定該圖屬於哪種動物。深度學習識別圖像也是同樣的道理。這裡關鍵的就是抽象。何為抽象呢?抽象就是把圖像中的各種零散的特徵通過某種方式匯總起來,形成新的特徵。而利用這些新的特徵可更好區分圖像類別。如剛才這個例子,點和邊就是零散的特徵,通過將邊進行匯總我們就得到了三角形或圓形等新的特徵,同理,將三角形這個特徵和一些其他零散的特徵匯總成耳朵這個新特徵。顯而易見,耳朵這個新特徵會比三角形特徵更利於識別圖像。
深度學習正是通過卷積操作實現從細節到抽象的過程。因為卷積的目的就是為了從輸入圖像中提取特徵,並保留像素間的空間關係。何以理解這句話?我們輸入的圖像其實就是一些紋理,此時,可以將卷積核的參數也理解為紋理,我們目的是使得卷積核的紋理和圖像相應位置的紋理儘可能一致。當把圖像數據和卷積核的數值放在高維空間中,紋理等價於向量,卷積操作等價於向量的相乘,相乘的結果越大,說明兩個向量方向越近,也即卷積核的紋理就更貼近於圖像的紋理。因此,卷積後的新圖像在具有卷積核紋理的區域信號會更強,其他區域則會較弱。這樣,就可以實現從細節(像素點)抽象成更好區分的新特徵(紋理)。每一層的卷積都會得到比上一次卷積更易區分的新特徵。
而池化目的主要就是為了減少權重參數,但為什麼可以以Maxpooling或者MeanPooling代表這個區域的特徵呢?這樣不會有可能損失了一些重要特徵嗎?這是因為圖像數據在連續區域具有相關性,一般局部區域的像素值差別不大。比如眼睛的局部區域的像素點的值差別並不大,故我們使用Maxpooling或者MeanPooling並不會損失很多特徵。
2項目實例
2.1模型介紹
有了上文對CNN的講解後,讀者對CNN應該有了一定的理解,接下來我們將基於此搭建CNN常見模型LeNet-5模型,並對Mnist數據集進行預測。
圖3:LeNet-5模型
從上圖LeNet-5模型中,可以了解到該模型由以下結構組成:
第一層:卷積層,這一層的輸入的原始的圖像像素,該模型接受的圖像為32*32*1,6個5*5卷積核,步長為1,不使用全0填充。所以這層輸出的尺寸為32-5+1=28,深度為6。
第二層:池化層,該層的輸入為第一層的輸出,是一個28*28*6的節點矩陣。本層採用的過濾器大小為2*2,長和寬的步長均為2,所以本層的輸出矩陣大小為14*14*6。
第三層:卷積層,本層的輸入矩陣大小為14*14*6,16個5*5卷積核,同樣不使用全0填充,步長為1,則本層的輸出為10*10*16。
第四層:池化層,該層使用2*2的過濾器,步長為2,故本層的輸出矩陣為5*5*16。
第五層:全連接層,如上文所說,在全連接層之前,需要將5*5*16的矩陣「壓扁」為一個向量。本層的輸出節點個數為120。
第六層:全連接層,該層輸出節點個數為84。
第七層:全連接層,最後一層,輸出節點個數為10,樣本的標籤個數。
2.2代碼實現
2.2.1數據導入及處理
Mnist數據集為手寫字體,訓練集有60000張圖片,測試集中有10000張圖片,標籤為0-9。由於Mnist數據集為IDX文件格式,是一種用來存儲向量與多維度矩陣的文件格式,不能直接讀取。有兩種方式可以進行讀取。第一種是Keras.datasets庫中有mnist數據集,直接調用即可,但是由於需要Keras指定地址下載數據集,速度較慢,最好先下載;第二種是使用struct庫函數解析數據集,比較麻煩,但是也可以試試(原始碼文末給出)。
圖4:導入Mnist數據集
對於mnist數據集只是做了一些簡單的預處理,將輸入數據的數據類型轉換為float32,並進行歸一化。對標籤進行獨熱編碼,因為最後輸出節點個數為10,而標籤只有1維。
圖5:數據預處理
2.2.2LeNet-5模型的搭建
圖6: Keras搭建LeNet-5模型
2.2.3訓練模型
圖7:訓練模型
2.2.4 評估模型
圖8:評估模型
最終在測試集的準確率可以達到99.7%。
通過一個簡單項目的實現,既可以幫助我們進一步了解CNN,又可以熟悉Keras應用。最終模型還可以保存到本地,便於下次使用。
圖9:保存和讀取模型
3.遷移學習
遷移學習就是把已訓練好的模型參數遷移到新模型來幫助新模型訓練。考慮到大部分數據或任務存在相關性的,所以通過遷移學習我們可以將已經學到的模型參數通過某種方式來分享給模型從而加快訓練模型。
keras.applications庫中有許多已經訓練好的模型,我們可以對已有的模型進行一些修改得到我們想要的模型,從而提高模型搭建和訓練的效率。另外,當我們的數據不足的時候,使用遷移學習思想也是一個很好的想法。在下圖,將簡單的通過遷移學習實現VGG16。但是由於VGG16模型要求輸入為RGB圖像,所以需要使用opencv模塊對圖像進行處理。
圖10:通過遷移學習高效搭建vgg16模型
通過上圖,可以看出通過遷移學習我們可以省去搭建多個卷積和池化層,並且可以省去訓練參數的時間,vgg16有3364萬個網絡權重,如果全部重新訓練將需要一段較長的時間。是否重新訓練網絡權重參數,要取決於我們要所用的數據集的分布與原模型所使用的數據集的分布是否具有相關性。因為模型訓練是讓模型學習數據的分布,如果不具有相關性,已有的網絡權重並不適合於我們的數據集。
限時免費試聽
▼
Udacity 在中國區的數據分析課程限時免費開放中!長按下方二維碼,關注公眾號「優達學習助手」,回復 「試聽」 進入教室免費學習!