卷積神經網絡
卷積神經網絡(CNN)是深度學習技術中極具代表的網絡結構之一,在圖像處理領域取得了很大的成功。在國際標準ImageNet數據集上,許多成功的模型都是基於CNN的。CNN相較於傳統的圖像處理算法的優點之一在於:可以直接輸入原始圖像,避免了對圖像複雜的前期預處理過程(如:提取特徵等)。傳統的神經網絡採用全連接的方式,即:輸入層到隱藏層的神經元都是全部連接的,這樣做將導致參數量巨大,使得網絡訓練耗時甚至難以訓練,而CNN則通過局部連接、權值共享等方法避免這一困難。
在圖像處理中,往往把圖像表示爲像素的向量,比如一個1000×1000的圖像,可以表示爲一個1000000的向量。在神經網絡中,如果隱含層數目與輸入層一樣,也是1000000時,那麼輸入層到隱含層的參數數據爲1000000×1000000=10^12,這樣參數就太多了,基本沒法訓練。所以圖像處理要想練成神經網絡大法,必先減少參數、加快速度。卷積神經網絡有兩種神器可以降低參數數目:局部連接(Sparse Connectivity)和權值共享(Shared Weights)方法。
-------------------------------------------------------------------------------------------------------------------------------------
局部連接
局部連接的示意圖,如下圖所示:
在上圖中,左邊是全連接,右邊是局部連接。對於一個1000 × 1000的輸入圖像而言,如果下一個隱藏層的神經元數目爲10^6個,採用全連接則有1000 × 1000 × 10^6 = 10^12個權值參數,如此數目巨大的參數幾乎難以訓練;而採用局部連接,隱藏層的每個神經元僅與圖像中10 × 10的局部圖像相連接,那麼此時的權值參數數量爲10 × 10 × 10^6 = 10^8,將直接減少4個數量級。
-------------------------------------------------------------------------------------------------------------------------------------
權值共享
採用上述方法,雖然減少了參數,但是參數量依然很多。爲了進一步減少參數,可以再採用權值共享。具體做法是,在局部連接中隱藏層的每一個神經元連接的是一個10 × 10的局部圖像,因此有10 × 10個權值參數。將這10 × 10個權值參數共享給剩下的神經元,也就是說隱藏層中10^6個神經元的權值參數相同,那麼此時不管隱藏層神經元的數目是多少,需要訓練的參數就是這
10 × 10個權值參數(也就是卷積核的大小)。
-------------------------------------------------------------------------------------------------------------------------------------
多卷積核
上面所述只有100個參數時,表明只有1個10*10的卷積核,顯然,特徵提取是不充分的。我們可以添加多個卷積核,比如:32個卷積核,這樣就可以學習32種特徵。採用多卷積核時,如下圖所示:
在上圖中,不同顏色表明不同的卷積核,每個卷積核都會將圖像生成爲另一幅圖像。比如,兩個卷積核就可以將生成兩幅圖像,這兩幅圖像可以看做是一張圖像的不同的通道
-------------------------------------------------------------------------------------------------------------------------------------池化
通過卷積獲得了特徵之後,我們希望利用這些特徵進行分類。理論上講,人們可以利用所有提取到的特徵去訓練分類器,但這樣面臨着計算量的挑戰。例如:對於一個 96X96 像素的圖像,假設已經學習得到了400個特徵,卷積核大小爲8X8,卷積核步長爲1,每一個特徵和圖像卷積後都會得到一個 (96 − 8 + 1) × (96 − 8 + 1) = 7921 維的卷積特徵,由於有 400 個特徵,所以每個圖像都會得到一個 7921 × 400 = 3,168,400 維的卷積特徵向量。學習一個擁有超過 3 百萬特徵輸入的分類器十分不便,並且容易出現過擬合問題。
爲了解決這個問題,首先回憶一下,我們之所以決定使用卷積後的特徵是因爲圖像具有一種“靜態性”的屬性,這也就意味着在一個圖像區域有用的特徵極有可能在另一個區域同樣適用。因此,爲了描述大的圖像,一個很自然的想法就是對不同位置的特徵進行聚合統計,例如,人們可以計算圖像一個區域上的某個特定特徵的平均值 (或最大值)。這些概要統計特徵不僅具有低得多的維度 (相比使用所有提取得到的特徵),同時還會改善結果(不容易過擬合)。這種聚合的操作就叫做池化 (pooling),有時也稱爲平均池化或者最大池化 (取決於計算池化的方法)。
-------------------------------------------------------------------------------------------------------------------------------------
卷積層的進一步分析
假設輸入圖像爲w1 * h1 * c1,w1表示寬度,h1表示高度,c1表示通道數(圖像的深度),輸出圖像爲w2 * h2 * c2
在卷積層中,n表示卷積核的個數,k*k表示卷積核大小,p表示擴充邊緣,s表示卷積核步長,那麼有:
w2 = (w1 + 2 * p - k) / s + 1
h2 = (h1 + 2 * p - k) / s + 1
c2 = n
每個濾波器的權值個數爲k * k * c1,偏置的個數爲1,所以每個濾波器有 k * k * c1 + 1個參數;
該卷積層總共需要訓練的參數爲( k * k * c1 + 1 ) * n,網絡中的連接數爲 ( k * k * c1 + 1 ) * n * w2 * h2
------------------------------------------------------------------------------------------------------------------------------------
感受野的計算
由上面的分析知道:output_size = (input_size + 2*padding - kernel_size) / stride + 1,進而可以推出:
input_size = (output_size -1)*stride +kernel_size - 2*padding
在計算感受野時,需要說明以下情況:
1)在第一層卷積層的輸出特徵圖,感受野的大小等於濾波器的大小
2)深層卷積層的感受野的大小和它之前所有層的濾波器的大小、步長有關係
3)計算感受野大小時,忽略了圖像邊緣的影響,即不考慮padding的大小
綜上所述,我們在計算感受野時,採用 top to down 的方式, 即先計算最深層在前一層上的感受野,然後逐漸傳遞到第一層,採用如下公式:
RF = 1 #待計算的feature map上的感受野大小
for layer in (top layer To down layer):
RF = ((RF -1)* stride) + kernel_size
Caffe的卷積層、池化層
layer {
name: "conv1"
type: "Convolution"
bottom: "data"
top: "conv1"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
convolution_param {
num_output: 20
kernel_size: 5
stride: 1
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
num_output: 卷積核的個數
kernel_size: 卷積核的大小,如果卷積核的長和寬不等,需要用kernel_h和kernel_w分別設定
stride: 卷積核的步長,默認爲1。也可以用stride_h和stride_w來設置。
pad: 擴充邊緣,默認爲0,不擴充。 擴充的時候是左右、上下對稱的,比如卷積核的大小爲5*5,那麼pad設置爲2,則四個邊緣都擴充2個像素,即寬度和高度都擴充了4個像素,這樣卷積運算之後的特徵圖就不會變小。也可以通過pad_h和pad_w來分別設定。
weight_filler: 權值初始化
bias_filler: 偏置項的初始化
輸入:n * c0 * w0 *
h0
輸出:n * c1 * w1 * h1,
c1是參數中的num_output,也就是生成的特徵圖的個數
w1=(w0 +
2*pad - kernel_size) / stride +1;
h1 =(h0 + 2*pad - kernel_size) / stride +1;
-------------------------------------------------------------------------------------------------------------------------------------
池化層的定義:
layer {
name: "pool1"
type: "Pooling"
bottom: "conv1"
top: "pool1"
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
kernel_size: 池化的核大小,也可以用kernel_h和kernel_w分別設定。
pool: 池化方法,默認爲MAX。目前可用的方法有MAX, AVE, 或STOCHASTIC
pad: 和卷積層的pad的一樣,進行邊緣擴充,默認爲0
stride: 池化的步長,默認爲1。一般我們設置爲2,即不重疊。也可以用stride_h和stride_w來設置。
pooling層的運算方法基本是和卷積層是一樣的。
輸入:n*c*w0*h0
輸出:n*c*w1*h1
和卷積層的區別就是其中的c保持不變
w1=(w0 + 2*pad - kernel_size) / stride +1;
h1 =(h0 + 2*pad - kernel_size) / stride +1;
如果設置stride爲2,前後兩次卷積部分不重疊。100*100的特徵圖池化後,變成50*50
LeNet_5模型參數的分析
對於該模型的分析,主要參考其他博客,沒有看過相關論文,可能存在一些錯誤,歡迎大家指出。
輸入層:
輸入圖像爲32*32大小,這比Mnist(一個公認的手寫數據庫)中最大的字母還大。這樣做的原因是希望潛在的明顯特徵如筆畫斷電或角點能夠出現在最高層特徵監測子感受野的中心。
--------------------------------------------------------------------------------------------------------------------------------------------------------
C1層:
該層爲卷積層,有6個28*28特徵圖。
輸入圖片大小: (32*32)*1
卷積窗大小: 5*5
卷積窗種類: 6
輸出特徵圖數量: 6
輸出特徵圖大小: 28*28 (32-5+1)
神經元數量: 4707 (28*28)*6
連接數: 122304 (5*5+1)*28*28*6
可訓練參數: 156 (5*5+1)*6,每個濾波器有25個unit參數和一個bias參數
--------------------------------------------------------------------------------------------------------------------------------------------------------
該層爲下采樣層,有6個14*14的特徵圖,且特徵圖中的每個單元與C1中相對應特徵圖的2*2鄰域相連接。S2層每個單元的4個輸入相加,乘以一個可訓練參數,再加上一個可訓練偏置,並通過sigmoid函數計算最終結果。對於該層的參數分析, 沒有理解好???
輸入圖片大小: (28*28)*6
卷積窗大小: 2*2
卷積窗種類: 6 ???
輸出下采樣圖數量: 6
輸出下采樣圖大小: 14*14 (28/2)
神經元數量: 1176 (14*14)*6
連接數: 2352 (1+1)*14*14*6 (5880 (2*2+1)*14*14*6 )
可訓練參數: 12 (1+1)*6
--------------------------------------------------------------------------------------------------------------------------------------------------------
C3層:
該層爲卷積層,它通過5x5的卷積核去卷積S2層,得到的特徵圖只有10x10個神經元,但是它有16種不同的卷積核,所以存在16個特徵圖。需要注意的是:C3中的每個特徵圖是連接到S2中的所有6個或者幾個特徵圖的,表示本層的特徵圖是上一層提取到的特徵圖的不同組合(這個做法也並不是唯一的)。
C3中每個特徵圖由S2中所有6個或者幾個特徵圖組合而成。爲什麼不把S2中的每個特徵圖連接到每個C3的特徵圖呢?原因有2點。第一,不完全的連接機制將連接的數量保持在合理的範圍內。第二,也是最重要的,其破壞了網絡的對稱性。由於不同的特徵圖有不同的輸入,所以迫使他們抽取不同的特徵。
例如,存在的一個方式是:C3的前6個特徵圖以S2中3個相鄰的特徵圖子集爲輸入,接下來的6個特徵圖以S2中4個相鄰特徵圖子集爲輸入。然後的3個特徵圖以S2中不相鄰的4個特徵圖子集爲輸入。最後一個特徵圖將S2中所有特徵圖爲輸入。這樣C3層有1516個可訓練參數和151600個連接,,如下圖所示:
輸入圖片大小: (14*14)*6
卷積窗大小: 5*5
卷積窗種類: 16
輸出特徵圖數量: 16
輸出特徵圖大小: 10*10 (14-5+1)
神經元數量: 1600 (10*10)*16
連接數: 151600 1516*10*10
可訓練參數: 1516 6*(3*25+1)+6*(4*25+1)+3*(4*25+1)+1*(6*25+1)
--------------------------------------------------------------------------------------------------------------------------------------------------------
S4層:
該層爲下采樣層,有16個5*5大小的特徵圖。特徵圖中的每個單元與C3中相應特徵圖的2*2鄰域相連接,跟C1和S2之間的連接一樣。
輸入圖片大小: (10*10)*16
卷積窗大小: 2*2
卷積窗種類: 16
輸出下采樣圖數量: 16
輸出下采樣圖大小: 5*5 10/2
神經元數量: 400 (5*5)*16
連接數: 800 (1+1)*5*5*16 (2000 (2*2+1)*5*5*16)
可訓練參數: 32 (1+1)*16
--------------------------------------------------------------------------------------------------------------------------------------------------------
C5層:
該層爲卷積層,有120個特徵圖。特徵圖中的每個單元與S4層的全部16個特徵圖的5*5鄰域相連。由於S4層特徵圖的大小也爲5*5(同濾波器大小一樣),故C5特徵圖的大小爲1*1,這構成了S4和C5之間的全連接。之所以仍將C5標示爲卷積層,而非全相聯層,是因爲如果LeNet-5的輸入變大,而其他的保持不變,那麼此時特徵圖的維數就會比1*1大。
輸入圖片大小: (5*5)*16
卷積窗大小: 5*5
卷積窗種類: 120
輸出特徵圖數量: 120
輸出特徵圖大小: 1*1 (5-5+1)
神經元數量: 120 (1*1)*120
連接數: 48120 (5*5*16+1)*1*1*120
可訓練參數: 48120 (5*5*16+1)*120
--------------------------------------------------------------------------------------------------------------------------------------------------------
F6層:
F6層有84個單元(之所以選這個數字的原因來自於輸出層的設計),與C5層全相連。如同經典神經網絡,F6層計算輸入向量和權重向量之間的點積,再加上一個偏置,然後將其傳遞給sigmoid函數產生單元的一個狀態。
輸入圖片大小: (1*1)*120
卷積窗大小: 1*1
卷積窗種類: 84
輸出特徵圖數量: 1
輸出特徵圖大小: 84
神經元數量: 84
連接數: 10164 120*84+84
可訓練參數: 10164 120*84+84
--------------------------------------------------------------------------------------------------------------------------------------------------------
OUTPUT層:
輸入圖片大小: 1*84
輸出特徵圖數量: 1*10
輸出層由歐式徑向基函數單元組成,每類一個單元,有84個輸入。換句話說,每個輸出RBF單元計算輸入向量和參數向量之間的歐式距離。輸入離參數向量越遠,RBF輸出的越大。一個RBF輸出可以被理解爲衡量輸入模式和與RBF相關聯類的一個模型的匹配程度的懲罰項。用概率術語來說,RBF輸出可以被理解爲F6層配置空間的高斯分佈的負log-likelihood。給定一個輸入模式,損失函數應能使得F6的配置與RBF參數向量(即模式的期望分類)足夠接近。這些單元的參數是人工選取並保持固定的(至少初始時候如此)。這些參數向量的成分被設爲-1或1。雖然這些參數可以以-1和1等概率的方式任選,或者構成一個糾錯碼,但是被設計成一個相應字符類的7*12大小(即84)的格式化圖片。這種表示對識別單獨的數字不是很有用,但是對識別可打印ASCII集中的字符串很有用。
使用這種分佈編碼而非更常用的“1 of N”編碼用於產生輸出的另一個原因是,當類別比較大的時候,非分佈編碼的效果比較差。原因是大多數時間非分佈編碼的輸出必須爲0。這使得用sigmoid單元很難實現。另一個原因是分類器不僅用於識別字母,也用於拒絕非字母。使用分佈編碼的RBF更適合該目標。因爲與sigmoid不同,他們在輸入空間的較好限制的區域內興奮,而非典型模式更容易落到外邊。
RBF參數向量起着F6層目標向量的角色。需要指出這些向量的成分是+1或-1,這正好在F6 sigmoid的範圍內,因此可以防止sigmoid函數飽和。實際上,+1和-1是sigmoid函數的最大彎曲的點處。這使得F6單元運行在最大非線性範圍內。必須避免sigmoid函數的飽和,因爲這將會導致損失函數較慢的收斂和病態問題。