2014年,牛津大學計算機視覺組(Visual Geometry Group)和Google DeepMind公司的研究員一起研發出了新的深度卷積神經網絡:VGGNet,並取得了ILSVRC2014比賽分類項目的第二名(第一名是GoogLeNet,也是同年提出的).論文下載 Very Deep Convolutional Networks for Large-Scale Image Recognition。論文主要針對卷積神經網絡的深度對大規模圖像集識別精度的影響,主要貢獻是使用很小的卷積核(\(3\times3\))構建各種深度的卷積神經網絡結構,並對這些網絡結構進行了評估,最終證明16-19層的網絡深度,能夠取得較好的識別精度。 這也就是常用來提取圖像特征的VGG-16和VGG-19。
VGG可以看成是加深版的AlexNet,整個網絡由卷積層和全連接層疊加而成,和AlexNet不同的是,VGG中使用的都是小尺寸的卷積核(\(3\times3\))。
VGG的特點
- 結構簡潔,如下圖VGG-19的網絡結構
對比,前文介紹的AlexNet的網絡結構圖,是不是有種賞心悅目的感覺。整個結構只有\(3\times3\)的卷積層,連續的卷積層后使用池化層隔開。雖然層數很多,但是很簡潔。
- 小卷積核和連續的卷積層
VGG中使用的都是\(3\times3\)卷積核,並且使用了連續多個卷積層。這樣做的好處:- 使用連續的的多個小卷積核(\(3\times3\)),來代替一個大的卷積核(例如(\(5\times5\))。
使用小的卷積核的問題是,其感受野必然變小。所以,VGG中就使用連續的\(3\times3\)卷積核,來增大感受野。VGG認為2個連續的\(3\times3\)卷積核能夠替代一個\(5\times5\)卷積核,三個連續的\(3\times3\)能夠代替一個\(7\times7\)。
- 小卷積核的參數較少。3個\(3\times3\)的卷積核參數為\(3 \times 3 \times = 27\),而一個\(7\times7\)的卷積核參數為\(7\times7 = 49\)
- 由於每個卷積層都有一個非線性的激活函數,多個卷積層增加了非線性映射。
- 使用連續的的多個小卷積核(\(3\times3\)),來代替一個大的卷積核(例如(\(5\times5\))。
- 小池化核,使用的是\(2\times 2\)
- 通道數更多,特征度更寬
每個通道代表着一個FeatureMap,更多的通道數表示更豐富的圖像特征。VGG網絡第一層的通道數為64,后面每層都進行了翻倍,最多到512個通道,通道數的增加,使得更多的信息可以被提取出來。 - 層數更深
使用連續的小卷積核代替大的卷積核,網絡的深度更深,並且對邊緣進行填充,卷積的過程並不會降低圖像尺寸。僅使用小的池化單元,降低圖像的尺寸。 - 全連接轉卷積(測試階段)
這也是VGG的一個特點,在網絡測試階段將訓練階段的三個全連接替換為三個卷積,使得測試得到的全卷積網絡因為沒有全連接的限制,因而可以接收任意寬或高為的輸入,這在測試階段很重要。
如本節第一個圖所示,輸入圖像是224x224x3,如果后面三個層都是全連接,那么在測試階段就只能將測試的圖像全部都要縮放大小到224x224x3,才能符合后面全連接層的輸入數量要求,這樣就不便於測試工作的開展。
全連接轉卷積的替換過程如下:
例如\(7 \times 7 \times 512\)的層要跟4096個神經元的層做全連接,則替換為對\(7 \times 7 \times 512\)的層作通道數為4096、卷積核為\(1 \times 1\)卷積。
這個“全連接轉卷積”的思路是VGG作者參考了OverFeat的工作思路,例如下圖是OverFeat將全連接換成卷積后,則可以來處理任意分辨率(在整張圖)上計算卷積,這就是無需對原圖做重新縮放處理的優勢。
VGG網絡結構
VGG網絡相比AlexNet層數多了不少,但是其結構卻簡單不少。
- VGG的輸入為\(224 \times 224 \times 3\)的圖像
- 對圖像做均值預處理,每個像素中減去在訓練集上計算的RGB均值。
- 網絡使用連續的小卷積核(\(3 \times 3\))做連續卷積,卷積的固定步長為1,並在圖像的邊緣填充1個像素,這樣卷積后保持圖像的分辨率不變。
- 連續的卷積層會接着一個池化層,降低圖像的分辨率。空間池化由五個最大池化層進行,這些層在一些卷積層之后(不是所有的卷積層之后都是最大池化)。在2×2像素窗口上進行最大池化,步長為2。
- 卷積層后,接着的是3個全連接層,前兩個每個都有4096個通道,第三是輸出層輸出1000個分類。
- 所有的隱藏層的激活函數都使用的是ReLU
- 使用\(1\times1\)的卷積核,為了添加非線性激活函數的個數,而且不影響卷積層的感受野。
- 沒有使用局部歸一化,作者發現局部歸一化並不能提高網絡的性能。
VGG論文主要是研究網絡的深度對其分類精度的影響,所以按照上面的描述設計規則,作者實驗的了不同深度的網絡結構
所有網絡結構都遵從上面提到的設計規則,並且僅是深度不同,也就是卷積層的個數不同:從網絡A中的11個加權層(8個卷積層和3個FC層)到網絡E中的19個加權層(16個卷積層和3個FC層)。卷積層的寬度(通道數)相當小,從第一層中的64開始,然后在每個最大池化層之后增加2倍,直到達到512。
上圖給出了各個深度的卷積層使用的卷積核大小以及通道的個數。最后的D,E網絡就是大名鼎鼎的VGG-16和VGG-19了。
AlexNet僅僅只有8層,其可訓練的參數就達到了60M,VGG系列的參數就更恐怖了,如下圖(單位是百萬)
由於參數大多數集中在后面三個全連接層,所以雖然網絡的深度不同,全連接層確實相同的,其參數區別倒不是特別的大。
VGG訓練與測試
論文首先將訓練圖像縮放到最小邊長度的方形,設縮放后的訓練圖像的尺寸為\(S \times S\)。網絡訓練時對訓練圖像進行隨機裁剪,裁剪尺寸為網絡的輸入尺寸\(224 \times 224\)。如果\(S =224\),則輸入網絡的圖像就是整個訓練圖像;如果\(S > 224\),則隨機裁剪訓練圖像包含目標的部分。
對於訓練集圖像的尺寸設置,論文中使用了兩種方法:
- 固定尺寸訓練,設置\(S = 256\)和\(S = 384\)
- 多尺度訓練,每個訓練圖像從一定范圍內\([S_{min},S_{max}],(S_{min}=256,S_{max}=512)\)進行隨機采樣。由於圖像中的目標可能具有不同的大小,因此在訓練期間考慮到這一點是有益的。這也可以看作是通過尺度抖動進行訓練集增強,其中單個模型被訓練在一定尺度范圍內識別對象。
網絡性能評估
-
單尺度評估,測試圖像固定尺度。結果如下表
通過評估結果,可以看出:- 局部歸一化(A-LRN)網絡,對網絡A的結果並沒有很大的提升。
- 網絡的性能隨着網絡的加深而提高。應該注意到B,C,D這個網絡的性能。C網絡好於B網絡,說明額外添加的非線性激活函數,確實是有好處的;但是,D網絡好於C網絡,這說明也可以使用非平凡的感受野( non-trivial receptive fields)來捕獲更多的信息更有用。
- 當網絡層數達到19層時,使用VGG架構的錯誤率就不再隨着層數加深而提高了。更深的網絡應該需要更多的數據集。
- 論文還將網絡B與具有5×5卷積層的淺層網絡進行了比較,淺層網絡可以通過用單個5×5卷積層替換B中每對3×3卷積層得到。測量的淺層網絡top-1錯誤率比網絡B的top-1錯誤率(在中心裁剪圖像上)高7%,這證實了具有小濾波器的深層網絡優於具有較大濾波器的淺層網絡。
- 訓練時的尺寸抖動(訓練圖像大小\(S \in [256,512]\))得到的結果好於固定尺寸,這證實了通過尺度抖動進行的訓練集增強確實有助於捕獲多尺度圖像統計。
-
多尺度評估,測試圖像的尺度抖動對性能的影響
對同一張測試圖像,將其縮放到不同的尺寸進行測試,然后取這幾個測試結果的平均值,作為最終的結果(有點像集成學習,所不同的是,這里是測試圖像的尺寸不同)。使用了三種尺寸的測試圖像:\(Q\)表示測試圖像,\(S\)表示訓練是圖像尺寸:\(Q = S - 32\),\(Q = S + 32\),前面兩種是針對訓練圖像是固定大小的,對於訓練時圖像尺寸在一定范圍內抖動的,則可以使用更大的測試圖像尺寸。\(Q = \{S_{min},0.5(S_{min} + S_{max}),S_{max}\}\).
評估結果如下:
評估結果表明,訓練圖像尺度抖動優於使用固定最小邊S。 -
稠密和多裁剪圖像評估
Dense(密集評估),即指全連接層替換為卷積層(第一FC層轉換到7×7卷積層,最后兩個FC層轉換到1×1卷積層),最后得出一個預測的score map,再對結果求平均。
multi-crop,即對圖像進行多樣本的隨機裁剪,將得到多張裁剪得到的圖像輸入到網絡中,最終對所有結果平均
從上圖可以看出,多裁剪的結果是好於密集估計的。而且這兩種方法確實是互補的,因為它們的組合優於其中的每一種。
由於不同的卷積邊界條件,多裁剪圖像評估是密集評估的補充:當將ConvNet應用於裁剪圖像時,卷積特征圖用零填充,而在密集評估的情況下,相同裁剪圖像的填充自然會來自於圖像的相鄰部分(由於卷積和空間池化),這大大增加了整個網絡的感受野,因此捕獲了更多的圖像內容信息。
評估結論
- 在訓練時,可以使用多尺度抖動的訓練圖像,其精度好於固定尺寸的訓練集。
- 測試時,使用多裁剪和密集評估(卷積層替換全連接層)像結合的方法
Keras實現
依照VGG的設計原則,只使用小尺寸的\(3\times3\)卷積核以及\(2 \times 2\)的池化單元,實現一個小型的網絡模型。
class MiniVGGNet:
@staticmethod
def build(width,height,depth,classes):
model = Sequential()
inputShape = (height,width,depth)
chanDim = -1
if K.image_data_format() == "channels_first":
inputShape = (depth,height,width)
chanDim = 1
model.add(Conv2D(32,(3,3),padding="same",input_shape=inputShape))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(Conv2D(32,(3,3),padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.25))
model.add(Conv2D(64,(3,3),padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(Conv2D(64,(3,3),padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(512))
model.add(Activation("relu"))
model.add(BatchNormalization())
model.add(Dropout(0.25))
model.add(Dense(classes))
model.add(Activation("softmax"))
return model
最終輸出10分類,應用於CIFAR10,表現如下: