1 卷積神經網絡簡介
在介紹卷積神經網絡(CNN)之前,我們需要了解全連接神經網絡與卷積神經網絡的區別,下面先看一下兩者的結構,如下所示:
圖1 全連接神經網絡與卷積神經網絡結構
雖然上圖中顯示的全連接神經網絡結構和卷積神經網絡的結構直觀上差異比較大,但實際上它們的整體架構是非常相似的。從上圖中可以看出,卷積神經網絡也是通過一層一層的節點組織起來的。和全連接神經網絡一樣,卷積神經網絡中的每一個節點都是一個神經元。在全連接神經網絡中,每相鄰兩層之間的節點都有邊相連,於是一般會將每一層全連接層中的節點組織成一列,這樣方便顯示連接結構。而對於卷積神經網絡,相鄰兩層之間只有部分節點相連,為了展示每一層神經元的維度,一般會將每一層卷積層的節點組織成一個三維矩陣。
在TensorFlow中訓練一個卷積神經網絡的流程和訓練一個全連接神經網絡沒有任何區別。卷積神經網絡和全連接神經網絡的唯一區別就在於神經網絡中相鄰兩層的連接方式。在進一步介紹卷積神經網絡的連接結構之前,本部分將先介紹為什么全連接神經網絡無法很好地處理圖像數據。
使用全連接神經網絡處理圖像的最大問題在於全連接層的參數太多。對於MNIST數據,每一張圖片的大小是28×28×1,其中28×28為圖片的大小,×1表示圖像是黑白的,只有一個色彩通道。假設第一層隱藏層的節點數為500個,那么一個全鏈接層的神經網絡將有28×28×500+500=392500個參數。當圖片更大時,比如在Cifar-10數據集中,圖片的大小為32×32×3,其中32×32表示圖片的大小,×3表示圖片是通過紅綠藍三個色彩通道(channel)表示的。這樣輸入層就有3072個節點,如果第一層全連接層仍然是500個節點,那么這一層全鏈接神經網絡將有3072×500+500~150萬個參數。參數增多除了導致計算速度減慢,還很容易導致過擬合問題。所以需要一個更合理的神經網絡結構來有效地減少神經網絡中參數個數。卷積神經網絡就可以達到這個目的。
下邊給出一個更加具體用於圖像分類的卷積神經網絡架構圖:
圖2:用於圖像分類的卷積神經網絡架構圖
在卷積神經網絡的前幾層中,每一層的節點都被組織成一個三維矩陣。比如處理Cifar-10數據集中的圖片時,可以將輸入層組織成一個32×32×3的三維矩陣。上圖中虛線部分展示了卷積神經網絡的一個連接示意圖,從圖中可以看出卷積神經網絡中前幾層中每一個節點只和上一層中部分的節點相連。卷積神經網絡的具體連接方式將在下一個部分介紹。
一個卷積神經網絡主要由以下5種結構組成:
1.輸入層。輸入層是整個神經網絡的輸入,在處理圖像的卷積神經網絡中,它一般代表了一張圖片的像素矩陣。比如在圖2中,最左側的三維矩陣就可以代表一張圖片。其中三維矩陣的長和寬代表了圖像的大小,而三維矩陣的深度代表了圖像的色彩通道(channel)。比如黑白圖片的深度為1,而在RGB色彩模式下;圖像的深度為3。從輸入層開始,卷積神經網絡通過不同的神經網絡結構將上一層的三維矩陣轉化為下一層的三維矩陣,直到最后的全連接層。
2.卷積層。從名字就可以看出,卷積層是一個卷積神經網絡中最為重要的部分。和傳統全連接層不同,卷積層中每一個節點的輸入只是上一層神經網絡的一小塊,這個小塊常用的大小有3×3或者5×5。卷積層試圖將神經網絡中的每一小塊進行更加深入地分析從而得到抽象程度更高的特征。一般來說,通過卷積層處理過的節點矩陣會變得更深,所以在圖2中可以看到經過卷積層之后的節點矩陣的深度會增加。
3.池化層(Pooling)。池化層神經網絡不會改變三維矩陣的深度,但是它可以縮小矩陣的大小。池化操作可以認為是將一張分辨率較高的圖片轉化為分辨率較低的圖片。通過池化層,可以進一步縮小最后全連接層中節點的個數,從而達到減少整個神經網絡中參數的目的。
4.全連接層。如圖2所示,在經過多輪卷積層和池化層的處理之后,在卷積神經網絡的最后一般會是由1到2個全連接層來給出最后的分類結果。經過幾輪卷積層和池化層的處理之后,可以認為圖像中的信息已經被抽象成了信息含量更高的特征。我們可以將卷積層和池化層看成自動圖像特征提取的過程。在特征提取完成之后,仍然需要使用全連接層來完成分類任務。
5.Softmax層。Softmax層主要用於分類問題。通過Softmax層,可以得到當前樣例屬於不同種類的概率分布情況。
2 TensorFlow實現卷積神經網絡
TensorFlow對卷積神經網絡提供了非常好的支持,下面的程序實現了一個卷積層的前向傳播過程。從以下代碼可以看出,通過TensorFlow實現卷積層是非常方便的。
#通過tf.get variable的方式創建過濾器的權重變量和偏置項變量。上面介紹了卷積層 #的參數個數只和過濾器的尺寸、深度以及當前層節點矩陣的深度有關,所以這里聲明的參數變
#量是一個四維矩陣,前面兩個維度代表了過濾器的尺寸,第三個維度表示當前層的深度,第四 #個維度表示過濾器的深度。
filter weight =tf.get variable( 'weights',[5,5,3,16],initializer=tf.truncated_normal_initializer(stddev=0.1))
#和卷積層的權重類似,當前層矩陣上不同位置的偏置項也是共享的,所以總共有下一層深度個不 #同的偏置項。本樣例代碼中16為過濾器的深度,也是神經網絡中下一層節點矩陣的深度。
biases=tf.get variable( 'biases',[16],initializer=tf.constant_initializer(0.1))
#tf.nn.conv2d提供了一個非常方便的函數來實現卷積層前向傳播的算法。這個函數的第一個輸 #入為當前層的節點矩陣。注意這個矩陣是一個四維矩陣,后面三個維度對應一個節點矩陣,第一 #維對應一個輸入batch。比如在輸入層,input[0,:,:,:]表示第一張圖片,input[1,:,:,:] #表示第二張圖片,以此類推。tf.nn.conv2d第二個參數提供了卷積層的權重,第三個參數為不 #同維度上的步長。雖然第三個參數提供的是一個長度為4的數組,但是第一維和最后一維的數字 #要求一定是1。這是因為卷積層的步長只對矩陣的長和寬有效。最后一個參數是填充(padding) #的方法,TensorFlow中提供SAME或是VALID兩種選擇。其中SAME表示添加全0填充(如 #圖6-11所示),“VALID”表示不添加。
conv=tf.nn.conv2d( input,filter weight,strides=[1,1,1,1],padding='SAME') #tf.nn.bias_add提供了一個方便的函數給每一個節點加上偏置項。注意這里不能直接使用加 #法,因為矩陣上不同位置上的節點都需要加上同樣的偏置項。
bias=tf.nn.bias_add(conv,biases) #將計算結果通過ReLU激活函數完成去線性化。
actived conv=tf.nn.relu(bias)
從圖2中可以看出,在卷積層之間往往會加上一個池化層,使用最多的是最大值池化(max pooling),tensorflow代碼如下:
#tf.nn.max pool實現了最大池化層的前向傳播過程,它的參數和tf.nn.conv2d函數類似。 #ksize提供了過濾器的尺寸,strides提供了步長信息,padding 提供了是否使用全0填充。
pool=tf.nn.max pool(actived conv,ksize=[1,3,3,1],strides=[1,2,2,1],padding='SAME')
注:
(1)卷積神經網絡中一般都是一個卷積層后接一個池化層構成一個stage;構建多個這樣的結構,然后接上全連接網絡(FC)與softmax層,就形成了前向傳播的過程。在各個stage中,卷積層units不同。
(2)當你使用TensorFlow構建好前向傳播傳播過程之后,TensorFlow內部會自動計算好反向傳播在在各個節點的微分值,然后配合梯度下降法可以找到使loss最小的點。