2014年,牛津大學計算機視覺組(Visual Geometry Group)和Google DeepMind公司一起研發了新的卷積神經網路,並命名為VGGNet。VGGNet是比AlexNet更深的深度卷積神經網路,該模型獲得了2014年ILSVRC競賽的第二名,第一名是GoogLeNet(我們之後會介紹)。
論文《Very Deep Convolutional Networks for Large-Scale Image Recognition》
論文傳送門:https://arxiv.org/abs/1409.1556
1. 網路結構
VGG 的結構與 AlexNet 類似,區別是深度更深,但形式上更加簡單。VGG由5層卷積層、3層全連線層、1層softmax輸出層構成,層與層之間使用maxpool(最大化池)分開,所有隱藏層的啟用單元都採用ReLU函式。作者在原論文中,根據卷積層不同的子層數量,設計了A、A-LRN、B、C、D、E這6種網路結構。
這6種網路結構相似,都是由5層卷積層、3層全連線層組成,區別在於每個卷積層的子層數量不同,從A至E依次增加,總的網路深度從11層到19層。表格中的卷積層參數列示為“conv(感受野大小)-通道數”,例如con3-64,表示使用3×3的卷積核,通道數為64;最大池化表示為maxpool,層與層之間使用maxpool分開;全連線層表示為“FC-神經元個數”,例如FC-4096表示包含4096個神經元的全連線層;最後是softmax層。
其中,D表示著名的VGG16,E表示著名的VGG19。下面以VGG16為例,來詳細剖析一下VGG的網路結構。VGG16的結構如下圖所示:
VGG16總共包含16個子層,第1層卷積層由2個conv3-64組成,第2層卷積層由2個conv3-128組成,第3層卷積層由3個conv3-256組成,第4層卷積層由3個conv3-512組成,第5層卷積層由3個conv3-512組成,然後是2個FC4096,1個FC1000。總共16層,這也就是VGG16名字的由來。
1.1 輸入層
VGG輸入圖片的尺寸是224x224x3。
1.2 第1層卷積層
第1層卷積層由2個conv3-64組成。
該層的處理流程是:卷積–>ReLU–> 卷積–>ReLU–>池化。
卷積:輸入是224x224x3,使用64個3x3x3的卷積核進行卷積,padding=1,stride=1,根據公式:
(input_size + 2 * padding – kernel_size) / stride + 1=(224+2*1-3)/1+1=224
得到輸出是224x224x64。
ReLU:將卷積層輸出的FeatureMap輸入到ReLU函式中。
卷積:輸入是224x224x64,使用64個3x3x64的卷積核進行卷積,padding=1,stride=1,根據公式:
(input_size + 2 * padding – kernel_size) / stride + 1=(224+2*1-3)/1+1=224
得到輸出是224x224x64。
ReLU:將卷積層輸出的FeatureMap輸入到ReLU函式中。
池化:使用2×2,stride=2的池化單元進行最大池化操作(max pooling)。根據公式:
(224+2*0-2)/2+1=112
每組得到的輸出為112x112x64。
1.3 第2層卷積層
第2層卷積層由2個conv3-128組成。
該層的處理流程是:卷積–>ReLU–> 卷積–>ReLU–>池化。
卷積:輸入是112x112x64,使用128個3x3x64的卷積核進行卷積,padding=1,stride=1,根據公式:
(input_size + 2 * padding – kernel_size) / stride + 1=(112+2*1-3)/1+1=112
得到輸出是112x112x128。
ReLU:將卷積層輸出的FeatureMap輸入到ReLU函式中。
卷積:輸入是112x112x128,使用128個3x3x128的卷積核進行卷積,padding=1,stride=1,根據公式:
(input_size + 2 * padding – kernel_size) / stride + 1=(112+2*1-3)/1+1=112
得到輸出是112x112x128。
ReLU:將卷積層輸出的FeatureMap輸入到ReLU函式中。
池化:使用2×2,stride=2的池化單元進行最大池化操作(max pooling)。根據公式:
(112+2*0-2)/2+1=56
每組得到的輸出為56x56x128。
1.4 第3層卷積層
第3層卷積層由3個conv3-256組成。
該層的處理流程是:卷積–>ReLU–> 卷積–>ReLU–>池化。
卷積:輸入是56x56x128,使用256個3x3x128的卷積核進行卷積,padding=1,stride=1,根據公式:
(input_size + 2 * padding – kernel_size) / stride + 1=(56+2*1-3)/1+1=56
得到輸出是56x56x256。
ReLU:將卷積層輸出的FeatureMap輸入到ReLU函式中。
卷積:輸入是56x56x256,使用256個3x3x256的卷積核進行卷積,padding=1,stride=1,根據公式:
(input_size + 2 * padding – kernel_size) / stride + 1=(56+2*1-3)/1+1=56
得到輸出是56x56x256。
ReLU:將卷積層輸出的FeatureMap輸入到ReLU函式中。
池化:使用2×2,stride=2的池化單元進行最大池化操作(max pooling)。根據公式:
(56+2*0-2)/2+1=28
每組得到的輸出為28x28x256。
1.5 第4層卷積層
第4層卷積層由3個conv3-512組成。
該層的處理流程是:卷積–>ReLU–> 卷積–>ReLU–>池化。
卷積:輸入是28x28x256,使用512個3x3x256的卷積核進行卷積,padding=1,stride=1,根據公式:
(input_size + 2 * padding – kernel_size) / stride + 1=(28+2*1-3)/1+1=28
得到輸出是28x28x512。
ReLU:將卷積層輸出的FeatureMap輸入到ReLU函式中。
卷積:輸入是28x28x512,使用512個3x3x512的卷積核進行卷積,padding=1,stride=1,根據公式:
(input_size + 2 * padding – kernel_size) / stride + 1=(28+2*1-3)/1+1=28
得到輸出是28x28x512。
ReLU:將卷積層輸出的FeatureMap輸入到ReLU函式中。
池化:使用2×2,stride=2的池化單元進行最大池化操作(max pooling)。根據公式:
(28+2*0-2)/2+1=14
每組得到的輸出為14x14x512。
1.6 第5層卷積層
第5層卷積層由3個conv3-512組成。
該層的處理流程是:卷積–>ReLU–> 卷積–>ReLU–>池化。
卷積:輸入是14x14x512,使用512個3x3x512的卷積核進行卷積,padding=1,stride=1,根據公式:
(input_size + 2 * padding – kernel_size) / stride + 1=(14+2*1-3)/1+1=14
得到輸出是14x14x512。
ReLU:將卷積層輸出的FeatureMap輸入到ReLU函式中。
卷積:輸入是14x14x512,使用512個3x3x512的卷積核進行卷積,padding=1,stride=1,根據公式:
(input_size + 2 * padding – kernel_size) / stride + 1=(14+2*1-3)/1+1=14
得到輸出是14x14x512。
ReLU:將卷積層輸出的FeatureMap輸入到ReLU函式中。
池化:使用2×2,stride=2的池化單元進行最大池化操作(max pooling)。根據公式:
(14+2*0-2)/2+1=7
每組得到的輸出為7x7x512。
1.7 第1層全連線層
第1層全連線層FC4096由4096個神經元組成。
該層的處理流程是:FC–>ReLU–>Dropout。
FC:輸入是7x7x512的FeatureMap,展開為77512的一維向量,即77512個神經元,輸出為4096個神經元。
ReLU:這4096個神經元的運算結果通過ReLU啟用函式中。
Dropout:隨機的斷開全連線層某些神經元的連線,通過不啟用某些神經元的方式防止過擬合。
1.8 第2層全連線層
第2層全連線層FC4096由4096個神經元組成。
該層的處理流程是:FC–>ReLU–>Dropout。
FC:輸入是4096個神經元,輸出為4096個神經元。
ReLU:這4096個神經元的運算結果通過ReLU啟用函式中。
Dropout:隨機的斷開全連線層某些神經元的連線,通過不啟用某些神經元的方式防止過擬合。
1.9 第3層全連線層
第3層全連線層FC1000由1000個神經元組成,對應ImageNet資料集的1000個類別。
該層的處理流程是:FC。
FC:輸入是4096個神經元,輸出為1000個神經元。
1.10 softmax層
該層的流程為:Softmax
Softmax:這1000個神經元的運算結果通過Softmax函式中,輸出1000個類別對應的預測概率值。
2. 全卷積網路
接著對1.7、1.8、1.9節的內容進行介紹。這三節講的是全連線網路,VGG16在訓練的時候使用的是全連線網路。然而在測試驗證階段,網路結構稍有不同,作者將全連線全部替換為卷積網路。
先介紹做法!
2.1 第1層全連線層
輸入為7x7x512的FeatureMap,使用4096個7x7x512的卷積核進行卷積,由於卷積核尺寸與輸入的尺寸完全相同,即卷積核中的每個係數只與輸入尺寸的一個畫素值相乘一一對應,根據公式:
(input_size + 2 * padding – kernel_size) / stride + 1=(7+2*0-7)/1+1=1
得到輸出是1x1x4096。相當於4096個神經元,但屬於卷積層。
2.2 第2層全連線層
輸入為1x1x4096的FeatureMap,使用4096個1x1x4096的卷積核進行卷積,由於卷積核尺寸與輸入的尺寸完全相同,即卷積核中的每個係數只與輸入尺寸的一個畫素值相乘一一對應,根據公式:
(input_size + 2 * padding – kernel_size) / stride + 1=(1+2*0-1)/1+1=1
得到輸出是1x1x4096。相當於4096個神經元,屬於卷積層。
2.3 第2層全連線層
輸入為1x1x4096的FeatureMap,使用1000個1x1x4096的卷積核進行卷積,由於卷積核尺寸與輸入的尺寸完全相同,即卷積核中的每個係數只與輸入尺寸的一個畫素值相乘一一對應,根據公式:
(input_size + 2 * padding – kernel_size) / stride + 1=(1+2*0-1)/1+1=1
得到輸出是1x1x1000。相當於1000個神經元,屬於卷積層。
得到1x1x1000的輸出之後,最後經過softmax層進行預測類別。
2.4 為什麼要將全連線層轉變為全卷積層?
作者將三個全連線層轉成了1個7×7,和 2 個 1×1 的卷積層。從下圖可以看到,以第一個全連線層為例,要轉卷積層,FC6的輸入是 7×7×512,輸出是4096(也可以看做 1×1×4096),那麼就要對輸入在尺寸上(寬高)降維(從7×7 降到 1×1)和深度(channel 或者 depth)升維(從512 升到4096)。把7×7降到1×1,使用大小為 7×7的卷積核就好了,卷積核個數設定為4096,即卷積核為7×7×4096(下圖中的[7×7×512]×4096 表示有 4096 個 [7×7×512] 這樣的卷積核,7×7×4096 是簡寫形式忽略了輸入的深度),經過對輸入卷積就得到了最終的 1×1×4096 大小的 feature map。
為什麼要在模型測試的時候將全連線層轉變為全卷積層呢?最直接的原因是讓網路模型可以接受任意大小的尺寸。
我們在前面介紹的時候限定了網路輸入圖片的尺寸是224x224x3。如果後面三個層都是全連線,遇到寬高大於224的圖片就需要進行圖片的剪裁、縮放或其它處理,使圖片尺寸統一到224x224x3,才能符合後面全連線層的輸入要求。但是,我們並不能保證每次裁剪都能將圖片中的關鍵目標保留下來,可能裁剪去的部分恰好包含了目標,造成裁減丟失關鍵目標資訊,影響模型的測試精度。
(輸出是一個分類得分圖,通道的數量和類別的數量相同,空間解析度依賴於輸入影像尺寸。最終為了得到固定尺寸的分類得分向量,將分類得分圖進行空間平均化(求和——池化)。我們同樣使用水平翻轉來對測試集進行資料增強;在原始影像和翻轉影像上的soft-max分類概率的平均值作為這幅影像的最終得分。)
使用全卷積層,即使圖片尺寸大於224x224x3,最終經過softmax層得到的得分圖就不是1x1x1000,例如是2x2x1000,這裡的通道1000與類別的數量相同,空間解析度2×2依賴於輸入影像尺寸。然後將得分圖進行空間平均化(求和池化),得到的還是1x1x1000。最後對1000個通道的得分進行比較,取較大值作為預測類別。
這樣做的好處就是大大減少特徵位置對分類帶來的影響。
舉個簡單的例子:
從上圖我們可以看出,貓在原圖片中不同的位置,如果使用全連線層很容易使得剪裁之後的圖片丟失關鍵目標。然而使用全卷積層,對原圖片直接進行卷積,最終得分圖經過求和池化後得到的得分都是1,即不管貓在圖片的什麼位置,都能判定這張圖片中有貓,保證分類正確。保留原圖,使用全卷積層,相當於貓在哪我不管,我只要貓,於是我讓模型去把這個貓找到,實際就是把feature map整合成一個值,這個值大,就有貓,這個值小,那就可能沒貓!和這個貓在圖片哪裡關係不大了,魯棒性大大增強。
3. VGG網路特點
3.1 結構簡潔
雖然VGG層數較多,總的網路深度從11層到19層,但是它的整體結構還是相對簡單。概括來說,VGG由5層卷積層(每個卷積層的子層數量不同)、3層全連線層、softmax輸出層構成,層與層之間使用maxpooling(最大化池)分開,所有隱層的啟用單元都採用ReLU函式。
3.2 小卷積核
小卷積核是VGG的一個重要特點,VGG沒有采用AlexNet中比較大的卷積核尺寸(如7×7),而是通過降低卷積核的大小(3×3),增加摺積子層數來達到同樣的效能(VGG:從1到4卷積子層,AlexNet:1子層)。
VGG使用多個較小卷積核(3×3)的卷積層代替一個卷積核較大的卷積層,VGG作者認為兩個3×3的卷積堆疊獲得的感受野大小,相當一個5×5的卷積;而3個3×3卷積的堆疊獲取到的感受野相當於一個7×7的卷積。示意圖如下所示:
使用3×3小卷積核的好處有兩個方面:
一是大幅度減少模型引數數量。例如使用2個3×3的卷積核代替1個5×5的卷積核,通道數為C,1個5×5的卷積核引數量為55C,2個3×3的卷積核引數量為233*C,引數兩減小了28%。另外,小卷積核選取小的 stride可以防止較大的stride導致細節資訊的丟失。
二是多層卷積層(每個卷積層後都有非線性啟用函式),增加非線性,提升模型效能。
此外,我們注意到在VGG網路結構D中,還使用了1×1卷積核,1×1卷積核可以在不改變感受野的情況下,增加模型的非線性(後面的非線性啟用函式)。同時,還可以用它來整合各通道的資訊,並輸出指定通道數。通道數減小即降維,通道數增加即升維。
3.3 小池化核
相比AlexNet的3×3的池化核,VGG全部採用2×2的池化核。
3.4 通道數更多,特徵度更寬
每個通道代表著一個FeatureMap,更多的通道數表示更豐富的影像特徵。VGG網路第一層的通道數為64,後面每層都進行了翻倍,最多到512個通道,通道數的增加,使得更多的資訊可以被提取出來。
3.5 層數更深
使用連續的3×3小卷積核代替大的卷積核,網路的深度更深,並且對邊緣進行填充,卷積的過程並不會減小影像尺寸。僅使用小的2×2池化單元,減小影像的尺寸。
3.6 全連線轉卷積
這部分內容在全卷積網路已經介紹過了。
3.7 模型引數
A、A-LRN、B、C、D、E這6種網路結構的深度雖然從11層增加至19層,但引數量變化不大,這是由於基本上都是採用了小卷積核,引數主要集中在全連線層。
3.8 其他
A-LRN網路結構使用了LRN層(local response normalization,區域性響應歸一化),這在AlexNet網路中也使用過。但是作者實驗發現使用LRN並沒有帶來效能的提升,因此在其它組的網路中均沒再出現LRN層。
從11層的A到19層的E,網路深度增加對top1和top5的錯誤率下降很明顯。
VGG作者用B網路和一個較淺網路比較,較淺網路用1個5×5卷積核來代替B的2個3×3卷積核,結果顯示多個小卷積核比單個大卷積核效果要好。
關於VGG的更多細節和實驗對比結果,建議大家直接看原論文!
手撕 CNN 經典網路系列:
手撕 CNN 經典網路之 LeNet-5(MNIST 實戰篇)
手撕 CNN 經典網路之 LeNet-5(CIFAR10 實戰篇)
手撕 CNN 經典網路之 AlexNet(PyTorch 實戰篇)