項目地址:https://github.com/Daya-Jin/DL_for_learner
原博客:https://daya-jin.github.io/2018/12/13/NeuralNetworks/
Convolutional Neural Networks
概述
在普通的深度神經網絡(DNN)中,每個單元都可看做是一個神經元,每一層的神經元都會接受來自上一層所有神經元的信號;句話說,前一層即使只有一個神經元是興奮的,它也會激活後面所有層的所有神經元。這種人工神經網絡設計並不符合生物神經學,生物學家發現動物在接收不同的刺激時,大腦中活躍的區域是不一樣的,這就說明神經元之間並不是全連接(Fully Connected)關係,而是一種選擇性連接的關係。這就是卷積神經網絡(Convolutional Neural Networks)誕生的起源。
CNN最初也是最廣泛應用的領域就是圖像處理,假設有一張32×32的RGB圖片,再假設眼球的神經元能看到的範圍爲5×5,並且能接受RGB信號,那麼會有類似如下的結構:
32×32×3表示的是輸入卷積網絡的圖片,5×5×3的filter也被稱爲卷積網絡的卷積核,用於提取圖片的區域特徵。CNN使用卷積核去掃描圖片,每掃描一個區域會得到一個輸出信號,那麼該圖片經過卷積核的掃描之後會得到一個信號矩陣:
具體過程見下圖(圖源百度):
信號矩陣在經過激活函數激活之後會得到一個激活矩陣,這一處理過程被稱爲激活映射(Active Mapping)。使用一個卷積核會得到一個激活矩陣,那麼使用多個卷積核會得到多個激活矩陣,即該層網絡的輸出,也是下層網絡的輸入:
在CNN中,執行激活映射的層被稱爲卷積層(Convolution Layer)。設輸入尺寸爲nn,卷積核的尺寸爲k,那麼卷積層的輸出爲n−k+1。卷積核還有一個可設定的參數,步長(stride),該參數指明卷積核每次掃描移動的行列數,在該參數設定的條件下,卷積核的輸出尺寸爲(n−k)/s+1。經過若干卷積層之後,網絡中數據的尺寸是越來越小的:
爲了防止數據尺寸縮小的太快,CNN會使用一種padding的技術,對數據的邊緣填充0值來增大輸入數據的尺寸,那麼在使用padding技術時的輸出尺寸爲:
o=(n+2p−k)/s+1
除了卷積層,CNN中還有池化層(Pooling Layer)。池化層的目的很簡單,就是對數據做降採樣(downsampling)。上面提到不使用padding的卷積層會使數據尺寸變小,對應的,在池化層中,不使用padding,並且設置較大的stride來達到數據縮減的目的。最常見的池化方法有平均池化與最大化池化。下圖爲最大化池化的示例(圖源百度):
一個完整的CNN包含若干個卷積層與池化層,最後是全連接層。注意只有卷積層纔有激活函數。
訓練
CNN中的卷積核相當於DNN中的權重矩陣,那麼CNN中的參數即是卷積核張量。一個尺寸爲k×k×d的卷積核,其中的參數數量爲:
k×k×d+1
其中+1表示的是bias。
一個簡單的CNN實現指導見此。
CNN Architectures
最初始的CNN架構應該是LeNet-5,關於該網絡的實現見此。
AlexNet
AlexNet算是首個成功的CNN結構,其在2012年的ImageNet圖像分類比賽中獲得冠軍。其網絡結構如下所示:
|
Input |
kernel num |
kernel size |
stride |
pad |
Output |
Conv1 |
227×227×3 |
96 |
11×11 |
4 |
0 |
(227−11)/4+1 |
MaxPool1 |
55×55×96 |
- |
3×3 |
2 |
- |
(55−3)/2+1 |
Norm1 |
27×27×96 |
- |
- |
- |
- |
27 |
Conv2 |
27×27×96 |
256 |
5×5 |
1 |
2 |
(27+2×2−5)/1+1 |
MaxPool2 |
27×27×256 |
- |
3×3 |
2 |
- |
(27−3)/2+1 |
Norm2 |
13×13×256 |
- |
- |
- |
- |
27 |
Conv3 |
13×13×256 |
384 |
3×3 |
1 |
1 |
(13+2×1−3)/1+1 |
Conv4 |
13×13×384 |
384 |
3×3 |
1 |
1 |
(13+2×1−3)/1+1 |
Conv5 |
13×13×384 |
256 |
3×3 |
1 |
1 |
(13+2×1−3)/1+1 |
MaxPool3 |
13×13×256 |
- |
3×3 |
2 |
- |
(13−3)/2+1 |
FC6 |
6×6×256 |
4096 |
- |
- |
- |
1×4096 |
FC7 |
1×4096 |
4096 |
- |
- |
- |
1×4096 |
FC8 |
1×4096 |
1000 |
- |
- |
- |
1×1000 |
AlexNet有幾個關鍵點:
- 首次在實踐中使用ReLU作爲激活函數
- 使用了歸一化層來做局部歸一化(LRN)
- 使用dropout技術避免過擬合
- 做了大量的數據增強(圖像翻轉、旋轉)
- 全部使用最大池化,並且池化核的步長小於核大小,使池化核之間有重疊
- 使用兩個GPU並行訓練
- 使用帶動量的SGD,當損失不再下降時手動將學習率除以10
VGG
VGG是2014年ImageNet圖像分類挑戰的亞軍,其擴展了AlexNet的結構,使用了更深層的神經網絡模型來達到更好的效果。下圖是VGG16的網絡結構圖:
VGG中只使用了兩種核:
|
kernel size |
stride |
padding |
Conv Kernel |
3×3 |
1 |
1 |
MaxPooling Kernel |
2×2 |
2 |
- |
易得VGG中的卷積層不改變數據的尺寸,但是會增加數據的深度;而最大池化層每次都會將數據的尺寸減半,但深度不變。這樣一來,數據在VGG中傳遞時尺寸不斷減小,深度不斷增加,自然地過渡到一個一維向量(預測輸出)。
並且級聯的小核卷積層相當於一個單個的大核卷積層,但是參數數量卻大大降低。假設輸入圖片維度爲(7,7,3),在經過兩個使用3×3×3卷積核的級聯卷積層後,數據流維度變爲(3,3,3),而兩層六個卷積核的參數數量爲:6×3×3×3=162;假設把兩層小核卷積層換成一個使用5×5×3卷積核的卷積層,輸出數據流維度同樣爲(3,3,3),那麼三個大卷積核的參數數量爲:3×5×5×3=225。除了減小參數數量之外,增加的卷積層爲神經網絡增加了更多的非線性因素。
接下來分析VGG16各層需要的內存量(數據流佔用內存)與參數數量:
layer |
mem |
param |
Input |
224×224×3=150K |
0 |
Conv1-1 |
224×224×64=3.2M |
64×3×3×3 |
Conv1-2 |
224×224×64=3.2M |
64×3×3×64 |
MaxPool1 |
112×112×64=800K |
0 |
Conv2-1 |
112×112×128=1.6M |
128×3×3×64 |
Conv2-2 |
112×112×128=1.6M |
128×3×3×128 |
MaxPool2 |
56×56×128=400K |
0 |
Conv3-1 |
56×56×256=800K |
256×3×3×128 |
Conv3-2 |
56×56×256=800K |
256×3×3×256 |
Conv3-3 |
56×56×256=800K |
256×3×3×256 |
MaxPool3 |
28×28×256=200K |
0 |
Conv4-1 |
28×28×512=400K |
512×3×3×256 |
Conv4-2 |
28×28×512=400K |
512×3×3×512 |
Conv4-3 |
28×28×512=400K |
512×3×3×512 |
MaxPool4 |
14×14×512=100K |
0 |
Conv5-1 |
14×14×512=100K |
512×3×3×512 |
Conv5-2 |
14×14×512=100K |
512×3×3×512 |
Conv5-3 |
14×14×512=100K |
512×3×3×512 |
MaxPool5 |
7×7×512=25K |
0 |
FC6 |
1×4096=4K |
7×7×512×4096=98M |
FC7 |
1×4096=4K |
4096×4096=16M |
FC8 |
1×1000=1K |
4096×1000=4M |
根據以上表格,發現計算時的最大內存開銷在於前面兩層卷積層,而參數的數量絕大部分都在全連接層。以每一個數字佔32bit來算,僅計算一張圖片在VGG中的前向傳播過程就至少需要60MB的內存,保存VGG模型的所有參數至少需要526MB的存儲空間。
一個不完整的VGG實現示例見這裏。
GoogLeNet
GoogLeNet是2014年ImageNet圖像分類挑戰的冠軍,它同樣擴展了AlexNet的網絡深度,但不同於VGG,GoogLeNet使用了一種全新的網絡子結構來減少參數與運算量。
Interception Module
Interception Module是GoogLeNet中出現的全新網絡子結構,如下圖所示:
一個Interception Module對上一層的輸出並行地做了三次基於不同卷積核的卷積運算與一次池化運算,並且引入了1×1的卷積核來減少數據流的深度,這樣就降低了參數數量與運算量。
Interception Module最終會將四個運算結果沿深度軸拼接起來,那麼四個運算結果的數據流深度可以不同,但是尺寸必須相同。一個Interception Module中可能的數據流尺寸如下圖所示:
注意到1×1卷積核所在層的數據流深度,比其上一層與其下一層的數據流都要小,所以1×1卷積核所在的層也叫做“瓶頸層”(bottleneck layer)。
完整的GoogLeNet結構如下圖所示:
關於GoogLeNet,值得一提的有幾點:
- 在最後一個Module之後有一個AveragePool層,其目的是爲了替代傳統的FC層,大大減少參數量,其後添加的FC層只是爲了便於調優
- 在網絡中間層添加了兩個額外的中間輸出,目的是爲了避免梯度消失;同時中間輸出會以一定的權重加到最終輸出上去
- Interception Module背後的思想在於,不同的操作,如不同大小的卷積或池化,它們所看到的視野域是不同的,將不同大小的卷積核或池化核並行應用於特徵圖,可以同時看到多種信息
一個不完整的GoogLeNet實現示例見這裏。
ResNet
有人經過實際測試發現,單純的將網絡加深並不能提升網絡的表現,深層網絡的表現反而還不如淺層網絡,甚至深層網絡在訓練集上的誤差都要高於淺層網絡。這個結論是反直覺的,因爲如果深層網絡是容易過擬合的話,那麼至少在訓練集上的表現不會弱於淺層網絡,可能的解釋就是深層網絡的模型空間太大導致太難訓練。假設在深層網絡的後面幾層直接將輸入輸出,即該層什麼都不做,那麼就可以得到一個與淺層網絡等價的深層網絡。受此啓發,ResNet誕生,ResNet中的殘差塊(residual block)如下圖所示:
每一個殘差塊包含一個或兩個3×3卷積核的卷積層,除此之外,殘差塊在激活輸出之前,會將輸入加到輸出上,相加時會對輸入再做一次卷積保證輸入輸出的深度相等。之前的GoogLeNet使用了1×1的卷積核來減少參數數量與運算量,對於過深的ResNet,同樣使用瓶頸層來提高模型的訓練效率。完整的ResNet結構就是若干個殘差塊的級聯,並且ResNet的性能在深度過深時不會受到影響。原論文中給出的ResNet結構如下圖所示:
表格中方括號括起來的表示一個殘差塊,論文中統一將resnet中所有的殘差塊分爲4部分:conv2、conv3、conv4和conv5,不同配置的resnet只有每個部分包含的殘差塊結構不同。同時還注意到類似於VGGNet,resnet中的數據流服從一個規律:數據尺寸逐漸減倍,數據流深度逐漸加倍。ResNet在最後同樣沒有直接連接FC層,大大減少了參數數量,並且使用了與GoogLeNet相同的平均池化。除此之外,還可以看到ResNet並沒有使用傳統的conv+pool的塊結構,其分別在起始和結束處放置了一個最大池化與平均池化,中間層是不含池化層,也就是說ResNet僅使用卷積核去同時完成卷積與降採樣的過程。
一個非完整的ResNet示例見此。
CNN相關計算
到目前爲止,以上CNN架構都是在網絡結構上做優化,那麼現在停下來分析一下CNN中卷積操作在計算上的複雜度。首先定義幾個變量,假設CNN的輸入數據尺寸與中間的特徵圖都是正方形,那麼定義輸入特徵圖的尺寸爲(DI,DI,CI),輸入特徵圖的尺寸爲(DO,DO,CO),卷積核的尺寸爲(DK,DK,CI),卷積核的數量爲CO。
在標準卷積操作下,每一次卷積操作的計算量爲:DK2×CI,一個卷積核的總計算量爲:DK2×CI×DO2,所有卷積核的總計算量爲:
comp=DK2×CI×DO2×CO
有論文嘗試更改卷積運算,主要有以下兩種方式。
Depthwise Separable Convolution
深度可分離卷積(DSC)不再對特徵圖的整個深度上做卷積,而是使用CI個尺寸爲(DK,DK,1)的卷積核分別對特徵圖做depthwise的卷積。不難看出DSC無法改變特徵圖的深度,所以這種卷積操作下有C=CI=CO。DSC的每一次卷積計算量爲:DK2,一個核的總計算量爲:DK2×DO2,所有核的總計算量爲DK2×DO2×C。
Pointwise Convolution
點卷積(PC)已經在之前的Googlenet與resnet中出現過了,即1×1的卷積核,在之前的網絡中用於縮小深度減少參數量。與DSC恰好相反,DSC可以改變數據流的尺寸但無法改變深度,而PC只能改變深度無法改變尺寸,所以這裏有D=DF=DK。那麼這裏來分析一下,PC的每次卷積計算量爲CI,單個核的計算量爲CI×D2,總計算量爲CI×D2×CO。
MobileNet
基於對卷積操作的改進,Google提出了輕量級的CNN架構——MobileNet,其可用於移動設備。其主要思想就是結合使用DSC與PC兩種卷積方式,大大降低了參數量與計算量。
在standard convolution操作下,計算量爲:
compstd=DK2×CI×DO2×CO
級聯DSC+PC時的計算量爲:
compcas=DK2×DO2×CI+CI×DO2×CO=DO2CI(DK2+CO)
計算量爲之前的:
compstdcompcas=DK2×CI×DO2×CODO2CI(DK2+CO)=DK2CODK2+CO=DK21+CO1
MobileNet中級聯結構(DSC+PC)的具體構成如下圖所示:
完整的網絡結構如下表所示,其中Conv dw
即級聯結構。