下面我們将對2014年奪得ImageNet的定位第一和分類第二的VGG網絡進行分析,在此過程中更多的是對這篇經典文章的感性分析,希望和大家共同交流産生共鳴,如果有了解不到位的也真誠期待指出錯誤。

Simonyan, Karen, and Andrew Zisserman. “Very deep convolutional networks for large-scale image recognition.” arXiv preprint arXiv:1409.1556 (2014).
論文下載下傳位址:https://arxiv.org/pdf/1409.1556.pdf
這篇文章是以比賽為目的——解決ImageNet中的1000類圖像分類和定位問題。在此過程中,作者做了六組實驗,對應6個不同的網絡模型,這六個網絡深度逐漸遞增的同時,也有各自的特點。實驗表明最後兩組,即深度最深的兩組16和19層的VGGNet網絡模型在分類和定位任務上的效果最好。作者是以斬獲2014年分類第二(第一是GoogLeNet),定位任務第一。
其中,模型的名稱——“VGG”代表了牛津大學的Oxford Visual Geometry Group,該小組隸屬于1985年成立的Robotics Research Group,該Group研究範圍包括了機器學習到移動機器人。下面是一段來自知乎對同年GoogLeNet和VGG的描述:
GoogLeNet和VGG的Classification模型從原理上并沒有與傳統的CNN模型有太大不同。大家所用的Pipeline也都是:訓練時候:各種資料Augmentation(剪裁,不同大小,調亮度,飽和度,對比度,偏色),剪裁送入CNN模型,Softmax,Backprop。測試時候:盡量把測試資料又各種Augmenting(剪裁,不同大小),把測試資料各種Augmenting後在訓練的不同模型上的結果再繼續Averaging出最後的結果。
需要注意的是,在VGGNet的6組實驗中,後面的4個網絡均使用了pre-trained model A的某些層來做參數初始化。雖然作者沒有提該方法帶來的性能增益,但我認為是很大的。不過既然是開篇,先來看看VGG的特點:
- 小卷積核。作者将卷積核全部替換為3x3(極少用了1x1);
- 小池化核。相比AlexNet的3x3的池化核,VGG全部為2x2的池化核;
- 層數更深特征圖更寬。基于前兩點外,由于卷積核專注于擴大通道數、池化專注于縮小寬和高,使得模型架構上更深更寬的同時,計算量的增加放緩;
- 全連接配接轉卷積。網絡測試階段将訓練階段的三個全連接配接替換為三個卷積,測試重用訓練時的參數,使得測試得到的全卷積網絡因為沒有全連接配接的限制,因而可以接收任意寬或高為的輸入。
最後我會再次引用CS231n對于VGG的中肯評價進行總結,不過還是先從當時的任務和曆史背景開始說明。
任務背景
自從2012年AlexNet将深度學習的方法應用到ImageNet的圖像分類比賽中并取得state of the art的驚人結果後,大家都競相效仿并在此基礎上做了大量嘗試和改進,先從兩個性能提升的例子說起:
- 小卷積核。在第一個卷積層用了更小的卷積核和卷積stride(Zeiler & Fergus, 2013; Sermanet et al., 2014);
- 多尺度。訓練和測試使用整張圖的不同尺度(Sermanet et al., 2014; Howard, 2014)。
作者也是看到這兩個沒有談到深度的工作,因而受到啟發,不僅将上面的兩種方法應用到自己的網絡設計和訓練測試階段,同時想再試試深度對結果的影響。
小卷積核
說到網絡深度,這裡就不得不提到卷積,雖然AlexNet有使用了11x11和5x5的大卷積,但大多數還是3x3卷積,對于stride=4的11x11的大卷積核,我認為在于一開始原圖的尺寸很大因而備援,最為原始的紋理細節的特征變化用大卷積核盡早捕捉到,後面的更深的層數害怕會丢失掉較大局部範圍内的特征相關性,後面轉而使用更多3x3的小卷積核(和一個5x5卷積)去捕捉細節變化。
而VGGNet則清一色使用3x3卷積。因為卷積不僅涉及到計算量,還影響到感受野。前者關系到是否友善部署到移動端、是否能滿足實時處理、是否易于訓練等,後者關系到參數更新、特征圖的大小、特征是否提取的足夠多、模型的複雜度和參數量等等。
計算量
在計算量這裡,為了突出小卷積核的優勢,我拿同樣conv3x3、conv5x5、conv7x7、conv9x9和conv11x11,在224x224x3的RGB圖上(設定pad=1,stride=4,output_channel=96)做卷積,卷積層的參數規模和得到的feature map的大小如下:
從上表可以看出,大卷積核帶來的特征圖和卷積核得參數量并不大,無論是單獨去看卷積核參數或者特征圖參數,不同kernel大小下這二者加和的結構都是30萬的參數量,也就是說,無論大的卷積核還是小的,對參數量來說影響不大甚至持平。
增大的反而是卷積的計算量,在表格中列出了計算量的公式,最後要乘以2,代表乘加操作。為了盡可能證一緻,這裡所有卷積核使用的stride均為4,可以看到,conv3x3、conv5x5、conv7x7、conv9x9、conv11x11的計算規模依次為:1600萬,4500萬,1.4億、2億,這種規模下的卷積,雖然參數量增長不大,但是計算量是驚人的。
總結一下,我們可以得出兩個結論:
- 同樣stride下,不同卷積核大小的特征圖和卷積參數差别不大;
- 越大的卷積核計算量越大。
其實對比參數量,卷積核參數的量級在十萬,一般都不會超過百萬。相比全連接配接的參數規模是上一層的feature map和全連接配接的神經元個數相乘,這個計算量也就更大了。其實一個關鍵的點——多個小卷積核的堆疊比單一大卷積核帶來了精度提升,這也是最重要的一點。
感受野
說完了計算量我們再來說感受野。這裡給出一張VGG作者的PPT,作者在VGGNet的實驗中隻用了兩種卷積核大小:1x1和3x3。作者認為兩個3x3的卷積堆疊獲得的感受野大小,相當一個5x5的卷積;而3個3x3卷積的堆疊擷取到的感受野相當于一個7x7的卷積。
見下圖,輸入的8個元素可以視為feature map的寬或者高,當輸入為8個神經元經過三層conv3x3的卷積得到2個神經元。三個網絡分别對應stride=1,pad=0的conv3x3、conv5x5和conv7x7的卷積核在3層、1層、1層時的結果。因為這三個網絡的輸入都是8,也可看出2個3x3的卷積堆疊獲得的感受野大小,相當1層5x5的卷積;而3層的3x3卷積堆疊擷取到的感受野相當于一個7x7的卷積。
- input=8,3層conv3x3後,output=2,等同于1層conv7x7的結果;
- input=8,2層conv3x3後,output=2,等同于2層conv5x5的結果。
或者我們也可以說,三層的conv3x3的網絡,最後兩個輸出中的一個神經元,可以看到的感受野相當于上一層是3,上上一層是5,上上上一層(也就是輸入)是7。
此外,倒着看網絡,也就是backprop的過程,每個神經元相對于前一層甚至輸入層的感受野大小也就意味着參數更新會影響到的神經元數目。在分割問題中卷積核的大小對結果有一定的影響,在上圖三層的conv3x3中,最後一個神經元的計算是基于第一層輸入的7個神經元,換句話說,反向傳播時,該層會影響到第一層conv3x3的前7個參數。從輸出層往回forward同樣的層數下,大卷積影響(做參數更新時)到的前面的輸入神經元越多。
優點
既然說到了VGG清一色用小卷積核,結合作者和自己的觀點,這裡整理出小卷積核比用大卷積核的三點優勢:
- 更多的激活函數、更豐富的特征,更強的辨識能力。卷積後都伴有激活函數,更多的卷積核的使用可使決策函數更加具有辨識能力,此外就卷積本身的作用而言,3x3比7x7就足以捕獲特征的變化:3x3的9個格子,最中間的格子是一個感受野中心,可以捕獲上下左右以及斜對角的特征變化。主要在于3個堆疊起來後,三個3x3近似一個7x7,網絡深了兩層且多出了兩個非線性ReLU函數,(特征多樣性和參數參數量的增大)使得網絡容量更大(關于model capacity,AlexNet的作者認為可以用模型的深度和寬度來控制capacity),對于不同類别的區分能力更強(此外,從模型壓縮角度也是要摒棄7x7,用更少的參數獲得更深更寬的網絡,也一定程度代表着模型容量,後人也認為更深更寬比矮胖的網絡好);
- 卷積層的參數減少。相比5x5、7x7和11x11的大卷積核,3x3明顯地減少了參數量,這點可以回過頭去看上面的表格。比方input channel數和output channel數均為C,那麼3層conv3x3卷積所需要的卷積層參數是:3x(Cx3x3xC)=27C^2,而一層conv7x7卷積所需要的卷積層參數是:Cx7x7xC=49C^2。conv7x7的卷積核參數比conv3x3多了(49-27)/27x100% ≈ 81%;
- 小卷積核代替大卷積核的正則作用帶來性能提升。作者用三個conv3x3代替一個conv7x7,認為可以進一步分解(decomposition)原本用7x7大卷積核提到的特征,這裡的分解是相對于同樣大小的感受野來說的。關于正則的了解我覺得還需要進一步分析。
其實最重要的還是多個小卷積堆疊在分類精度上比單個大卷積要好。
小池化核
這裡的“小”是相對于AlexNet的3x3的池化核來說的。不過在說池化前,先說一下CS231n的部落格裡的描述網絡結構的layer pattern,一般常見的網絡都可以表示為:INPUT -> [[CONV -> RELU]*N -> POOL?]*M -> [FC -> RELU]*K -> FC的形式,其中,?表示pool是一個可選項。這樣的pattern因為可以對小卷積核堆疊,很自然也更适合描述深層網絡的建構,例如INPUT -> FC表示一個線性分類器。
不過從layer pattern中的[[CONV -> RELU]*N -> POOL?]*M部分,可以看出卷積層一般後面接完激活函數就緊跟池化層。對于這點我的了解是,池化做的事情是根據對應的max或者average方式進行特征篩選,還是在做特征工程上的事情。
2012年的AlexNet,其pooling的kernel size全是奇數,裡面所有池化采用kernel size為3x3,stride為2的max-pooling。而VGGNet所使用的max-pooling的kernel size均為2x2,stride為2的max-pooling。pooling kernel size從奇數變為偶數。小kernel帶來的是更細節的資訊捕獲,且是max-pooling更見微的同時進一步知躇。
在當時也有average pooling,但是在圖像任務上max-pooling的效果更勝一籌,是以圖像大多使用max-pooling。在這裡我認為max-pooling更容易捕捉圖像上的變化,梯度的變化,帶來更大的局部資訊差異性,更好地描述邊緣、紋理等構成語義的細節資訊,這點尤其展現在網絡可視化上。
概述全連接配接和特征圖
全連接配接
VGG最後三個全連接配接層在形式上完全平移AlexNet的最後三層,VGGNet後面三層(三個全連接配接層)為:
- FC4096-ReLU6-Drop0.5,FC為高斯分布初始化(std=0.005),bias常數初始化(0.1)
- FC4096-ReLU7-Drop0.5,FC為高斯分布初始化(std=0.005),bias常數初始化(0.1)
- FC1000(最後接SoftMax1000分類),FC為高斯分布初始化(std=0.005),bias常數初始化(0.1)
超參數上隻有最後一層fc有變化:bias的初始值,由AlexNet的0變為0.1,該層初始化高斯分布的标準差,由AlexNet的0.01變為0.005。超參數的變化,我的了解是,作者自己的感性了解指導認為,我以貢獻bias來降低标準差,相當于标準差和bias間trade-off,或許作者實驗validate發現這個值比之前AlexNet設定的(std=0.01,bias=0)要更好。
特征圖
網絡在随層數遞增的過程中,通過池化也逐漸忽略局部資訊,特征圖的寬度高度随着每個池化操作縮小50%,5個池化l操作使得寬或者高度變化過程為:224->112->56->28->14->7,但是深度depth(或說是channel數),随着5組卷積在每次增大一倍:3->64->128->256->512->512。特征資訊從一開始輸入的224x224x3被變換到7x7x512,從原本較為local的資訊逐漸分攤到不同channel上,随着每次的conv和pool操作打散到channel層級上。
特征圖的寬高從512後開始進入全連接配接層,因為全連接配接層相比卷積層更考慮全局資訊,将原本有局部資訊的特征圖(既有width,height還有channel)全部映射到4096次元。也就是說全連接配接層前是7x7x512次元的特征圖,估算大概是25000,這個全連接配接過程要将25000映射到4096,大概是5000,換句話說全連接配接要将資訊壓縮到原來的五分之一。VGGNet有三個全連接配接,我的了解是作者認為這個映射過程的學習要慢點來,太快不易于捕捉特征映射來去之間的細微變化,讓backprop學的更慢更細一些(更逐漸)。
換句話說,次元在最後一個卷積後達到7x7x512,即大概25000,緊接着壓縮到4096維,可能是作者認為這個過程太急,又接一個fc4096作為緩沖,同時兩個fc4096後的relu又接dropout0.5去過渡這個過程,因為最後即将給1k-way softmax,是以又接了一個fc1000去降低softmax的學習壓力。
feature map次元的整體變化過程是:先将local資訊壓縮,并分攤到channel層級,然後無視channel和local,通過fc這個變換再進一步壓縮為稠密的feature map,這樣對于分類器而言有好處也有壞處,好處是将local資訊隐藏于/壓縮到feature map中,壞處是資訊壓縮都是有損失的,相當于local資訊被破壞了(分類器沒有考慮到,其實對于圖像任務而言,單張feature map上的local資訊還是有用的)。
但其實不難發現,卷積隻增加feature map的通道數,而池化隻減少feature map的寬高。如今也有不少做法用大stride卷積去替代池化,未來可能沒有池化。
卷積組
說到特征圖的變化,我們可以進一步切分網絡觀察整體結構,再次拿出CS231n的部落格裡的描述網絡結構的layer pattern:INPUT -> [[CONV -> RELU]*N -> POOL?]*M -> [FC -> RELU]*K -> FC,以pooling操作為切分點對整個網絡分組的話,我們會得到五組卷積,五組卷積中有2種卷積組的形式,切分後的VGG網絡可以描述成下面這樣:
- 前兩組卷積形式一樣,每組都是:conv-relu-conv-relu-pool;
- 中間三組卷積形式一樣,每組都是:conv-relu-conv-relu-conv-relu-pool;
- 最後三個組全連接配接fc層,前兩組fc,每組都是:fc-relu-dropout;最後一個fc僅有fc。
雖然CS231n裡将這種形式稱為layer pattern,但我更喜歡把以卷積起始池化為止的最短結構稱之為“卷積組”。
不難發現VGG有兩種卷積組,第二種([conv-relu]-[conv-relu]-[conv-relu]-pool)比第一種([conv-relu]-[conv-relu]-pool) 多了一個[conv-relu]。我的了解是:
- 多出的relu對網絡中層進一步壓榨提煉特征。結合一開始單張feature map的local資訊更多一些,還沒來得及把資訊分攤到channel級别上,那麼往後就慢慢以增大conv filter的形式遞增地擴大channel數,等到了網絡的中層,channel數升得差不多了(資訊分攤到channel上得差不多了),那麼還想抽local的資訊,就通過再加一個[conv-relu]的形式去壓榨提煉特征。有點類似傳統特征工程中,已有的特征在固定的模型下沒有性能提升了,那就用更多的非線性變換對已有的特征去做變換,産生更多的特征的意味;
- 多出的conv對網絡中層進一步進行學習指導和控制不要将特征資訊漂移到channel級别上。
- 上一點更多的是relu的帶來的了解,那麼多出的[conv-relu]中conv的意味就是模型更強的對資料分布學習過程的限制力/控制力,做到資訊backprop可以回傳回來的學習指導。本身多了relu特征變換就加劇(權力釋放),那麼再用一個conv去控制(權力回收),也在指導網絡中層的收斂;
- 其實conv本身關注單張feature map上的局部資訊,也是在嘗試去盡量平衡已經失衡的channel級别(depth)和local級别(width、height)之間的天平。這個conv控制着特征的資訊量不要過于向着channel級别偏移。
關于Layer pattern,CS231n的部落格給出如下觀點:
- 串聯和串聯中帶有并聯的網絡架構。近年來,GoogLeNet在其網絡結構中引入了Inception子產品,ResNet中引入了Residual Block,這些子產品都有自己複雜的操作。換句話說,傳統一味地去串聯網絡可能并不如這樣串聯為主線,帶有一些并聯同類操作但不同參數的子產品可能在特征提取上更好。 是以我認為這裡本質上依舊是在做特征工程,隻不過把這個過程放在block或者module的小的網絡結構裡,畢竟kernel、stride、output的大小等等超參數都要自己設定,目的還是産生更多豐富多樣的特征。
- 用在ImageNet上pre-trained過的模型。設計自己模型架構很浪費時間,尤其是不同的模型架構需要跑資料來驗證性能,是以不妨使用别人在ImageNet上訓練好的模型,然後在自己的資料和問題上在進行參數微調,收斂快精度更好。 我認為隻要性能好精度高,選擇什麼樣的模型架構都可以,但是有時候要結合應用場景,對實時性能速度有要求的,可能需要多小網絡,或者分級小網絡,或者級聯的模型,或者做大網絡的知識蒸餾得到小網絡,甚至對速度高精度不要求很高的,可以用傳統方法。
層次元
要說到layer pattern,不得不提到sizing pattern,其實這裡相當于前面feature map次元變化的補充,這也是CS231n裡所講到的。對于每種層,有不同的預設設定:
輸入層
大都是2的N次方,這和網絡中卷積或者池化層出現的stride為2的次數有關,比方VGGNet中每個pattern的卷積不會對feature map的寬度和高度有改變,而每個pattern結束前總會做一個stride為2的下采樣,因為有5組,那麼做5次就是32,是以VGGNet網絡input大小一般都是32的倍數,即,n是下采樣的次數,a是最終卷積和池化得到的feature map大小,如224或者384。
卷積層
現在常用的是小卷積核如3x3或者1x1。卷積為了保留feature map不變,通常會采取pad為1的操作,其實具體來說應該是:為了保證卷積後的feature map的寬度和高度不變,那麼有pad=(F-1)/2,但我覺得這個有點問題,可以改成更一般的形式,不過首先可以看看計算下一層feature map寬高的公式:
因為要保證和一樣,有,那麼可以導出:
當Stride=1時,那麼pad=(F-1)/2。因為現在stride=1的3x3卷積用的多,是以大家會預設說是pad=1(關于這點上,也是由于實驗發現這樣保留feature map的寬高情況下,性能好的緣故,我認為填補主要是針對stride大于1的情況帶來的邊界問題,如果input尺寸不是事先設定的,那麼就會有邊界無法卷積到的問題帶來資訊丢失。不過這種填補我認為也有一定問題,就是說原本conv3x3去計算對應位置的3x3,而填補後為0,這樣相當于少算了一些值,這肯定還是有影響的)。但若stride不是1,那麼要保證前後feature map的寬高一樣,就要根據上面的公式計算得出。
另一個點是通常與Input比較接近的conv會采用大卷積核。關于接近input層使用較大的卷積核這點,我認為先是考慮到後面的操作,先盡可能用大的卷積核cover更多的原始資訊(雖然經過了卷積有一些變換),第二點在于大卷積核帶來的大感受野,後面的卷積層能的一個神經元能看到更大的input,第三點是GPU的顯存受限,經典的例子就是AlexNet使用stride=4的conv11x11,目的就是從一開始就減少顯存占用,其實這裡的大stride,我覺得起到了一些正則的作用。但缺點也很明顯,因為卷積核變大,矩陣乘法實作卷積時,若沒有大stride,那麼第一個矩陣的列數,也就是第二個矩陣的行數,會變大,帶來大的計算量。是以在AlexNet中,大卷積核也對應使用了大的stride值。
池化層
常見2x2的max-pooling,少見3x3或者更大的kernel。更大的kernel帶來的問題是資訊丢失帶來的資訊損失,此外,stride通常為2;
其實按照以上的設定看來,也是有好處的。卷積專注于保留白間資訊前提下的channel變換,而池化則專注于空間資訊的變換(下采樣)。
全連接配接轉卷積
VGG比較神奇的一個特點就是“全連接配接轉卷積”,下面是作者原文test小節中的一句:
Namely, the fully-connected layers are first converted to convolutional layers (the first FC layer to a 7 × 7 conv. layer, the last two FC layers to 1 × 1 conv. layers).
也就是說,作者在測試階段把網絡中原本的三個全連接配接層依次變為1個conv7x7,2個conv1x1,也就是三個卷積層。改變之後,整個網絡由于沒有了全連接配接層,網絡中間的feature map不會固定,是以網絡對任意大小的輸入都可以處理,因而作者在緊接着的後一句說到: The resulting fully-convolutional net is then applied to the whole (uncropped) image。
上圖是VGG網絡最後三層的替換過程,上半部分是訓練階段,此時最後三層都是全連接配接層(輸出分别是4096、4096、1000),下半部分是測試階段(輸出分别是1x1x4096、1x1x4096、1x1x1000),最後三層都是卷積層。下面我們來看一下詳細的轉換過程(以下過程都沒有考慮bias,略了):
先看訓練階段,有4096個輸出的全連接配接層FC6的輸入是一個7x7x512的feature map,因為全連接配接層的緣故,不需要考慮局部性, 可以把7x7x512看成一個整體,25508(=7x7x512)個輸入的每個元素都會與輸出的每個元素(或者說是神經元)産生連接配接,是以每個輸入都會有4096個系數對應4096個輸出,是以網絡的參數(也就是兩層之間連線的個數,也就是每個輸入元素的系數個數)規模就是7x7x512x4096。對于FC7,輸入是4096個,輸出是4096個,因為每個輸入都會和輸出相連,即每個輸出都有4096條連線(系數),那麼4096個輸入總共有4096x4096條連線(系數),最後一個FC8計算方式一樣,略。
再看測試階段,由于換成了卷積,第一個卷積後要得到4096(或者說是1x1x4096)的輸出,那麼就要對輸入的7x7x512的feature map的寬高(即width、height次元)進行降維,同時對深度(即Channel/depth次元)進行升維。要把7x7降維到1x1,那麼幹脆直接一點,就用7x7的卷積核就行,另外深度層級的升維,因為7x7的卷積把寬高降到1x1,那麼剛好就升高到4096就好了,最後得到了1x1x4096的feature map。這其中卷積的參數量上,把7x7x512看做一組卷積參數,因為該層的輸出是4096,那麼相當于要有4096組這樣7x7x512的卷積參數,那麼總共的卷積參數量就是:
[7x7x512]x4096,這裡将7x7x512用中括号括起來,目的是把這看成是一組,就不會懵。
第二個卷積依舊得到1x1x4096的輸出,因為輸入也是1x1x4096,三個次元(寬、高、深)都沒變化,可以很快計算出這層的卷積的卷積核大小也是1x1,而且,通道數也是4096,因為對于輸入來說,1x1x4096是一組卷積參數,即一個完整的filter,那麼考慮所有4096個輸出的情況下,卷積參數的規模就是[1x1x4096]x4096。第三個卷積的計算一樣,略。
其實VGG的作者把訓練階段的全連接配接替換為卷積是參考了OverFeat的工作,如下圖是OverFeat将全連接配接換成卷積後,帶來可以處理任意分辨率(在整張圖)上計算卷積,而無需對原圖resize的優勢。
不過可以看到,訓練階段用的是crop或者resize到14x14的輸入圖像,而測試階段可以接收任意次元,如果使用未經crop的原圖作為輸入(假設原圖比crop或者resize到訓練尺度的圖像要大),這會帶來一個問題:feature map變大了。比方VGG訓練階段用224x224x3的圖作為模型輸入,經過5組卷積和池化,最後到7x7x512次元,最後經過無論是三個卷積或者三個全連接配接,次元都會到1x1x4096->1x1x4096->1x1x1000,而使用384x384x3的圖做模型輸入,到五組卷積和池化做完(即),那麼feature map變為12x12x512,經過三個由全連接配接變的三個卷積,即feature map經曆了6x6x4096->6x6x4096->6x6x1000的變化過程後,再把這個6x6x1000的feature map進行average,最終交給SoftMax的是1x1x1000的feature map進行分類。
以上便是将全連接配接轉換成卷積以及将轉換後的全卷積網絡應用到測試階段的方式。其實進一步來看卷積與全連接配接,二者最明顯的差異不外乎一個前者是局部連接配接,但其實二者都有用到全局資訊,隻是卷積是通過層層堆疊來利用的,而全連接配接就不用說了,全連接配接的方式直接将上一層的特征圖全部用上,稀疏性比較大,而卷積從網絡深度這一角度,基于輸入到目前層這一過程逐級逐層榨取的方式利用全局資訊。
1x1卷積
VGG在最後的三個階段都用到了1x1卷積核,選用1x1卷積核的最直接原因是在次元上繼承全連接配接,然而作者首先認為1x1卷積可以增加決策函數(decision function,這裡的決策函數我認為就是softmax)的非線性能力,非線性是由激活函數ReLU決定的,本身1x1卷積則是線性映射,即将輸入的feature map映射到同樣次元的feature map。作者還提到“Network in Network” architecture of Lin et al. (2014).這篇文章就大量使用了1x1卷積核。
此外,查了知乎簡單總結下1x1卷積的特點(就不說加入非線性這個conv自帶的特點了):
1.專注于跨通道的特征組合:conv1x1根本不考慮單通道上像素的局部資訊(不考慮局部資訊),專注于那一個卷積核内部通道的資訊整合。conv3x3既考慮跨通道,也考慮局部資訊整合;
2.對feature map的channel級别降維或升維:例如224x224x100的圖像(或feature map)經過20個conv1x1的卷積核,得到224x224x20的feature map。尤其當卷積核(即filter)數量達到上百個時,3x3或5x5卷積的計算會非常耗時,是以1x1卷積在3x3或5x5卷積計算前先降低feature map的次元。
關于小卷積核前人就有使用,如Ciresan et al. (2011)還有Goodfellow et al. (2014),後者使用11層的網絡解決街道數量的識别問題(street number classification,我也沒看懂是回歸還是分類),結果顯示更深的網絡可以帶來更好地網絡性能。而作者在小卷積核的基礎上使用了更多層數,2014年ImageNet分類比賽的第一名使用GoogLeNet,Szegedy et al., (2014)也使用了更小的卷積核、更深達到22層的網絡,使用了5x5、3x3和1x1卷積(實際還用到了7x7的卷積,第一層卷積)。但GoogLeNet的拓撲結構比較複雜,上圖是Inception module的結構圖,可以看到module内直接使用了常見的三種卷積核進行并聯,并将最後的結果feature map直接concate到一起,而VGGNet則是使用傳統卷積核串聯的方式。
然而,分類性能上同樣的單模型,VGGNet比GoogLeNet在top5的錯分率要低,雖然不确定是否是因為GoogLeNet沒做multi-crop和dense eval.,但假設他們都做了,這樣看來似乎VGG從實驗結果上表現出其結構設計上比GoogLeNet更适合解決分類問題。
但總之,這種将全連接配接轉成卷積的方式還是很有意思的。但轉換後是直接拿來用先前的參數好還是否需要做參數微調轉換後的卷積層,還需要實驗說明。
實驗結論和評價
12年到14年的挑戰賽都使用的是1000個類别的ILSVRC-2012資料集(Large Scale Visual Recognition Challenge),其中:
- 訓練集:130萬張圖檔;
- 驗證集:5萬張圖檔;
- 測試集:10萬張圖檔,這組資料的label沒有給出(with held-out class labels)。
兩個性能評估準則:top-1和top-5 error。前一個是多類分類錯誤率,錯分的圖像的比率。後一個是ILSVRC中主要的評估名額,計算的是預測出來的top5的類别裡沒有ground truth的比率,即top-5 error。
實驗結論
因為作者自己在下面實驗的緣故,當然沒有測試集的ground truth類别,是以作者就用驗證集當做測試集來觀察模型性能。這裡作者使用兩種方式來評估模型在測試集(實際的驗證集)的性能表現:single scale evaluation和multi-scale evaluation。實驗結論:
- LRN層無性能增益(A和A-LRN)。作者通過網絡A和A-LRN發現AlexNet曾經用到的LRN層(local response normalization,LRN是一種跨通道去normalize像素值的方法)沒有性能提升,是以在後面的4組網絡中均沒再出現LRN層。 當然我也感覺沒啥用,想到max-pooling比average-pooling效果好,我就感覺這個LRN沒啥用,不過如果把LRN改成跨通道的max-normal,我感覺說不定會有性能提升。特征得到retain更明顯。
- 深度增加,分類性能提高(A、B、C、D、E)。從11層的A到19層的E,網絡深度增加對top1和top5的error下降很明顯,是以作者得出這個結論,但其實除了深度外,其他幾個網絡寬度等因素也在變化,depth matters的結論不夠convincing。
- conv1x1的非線性變化有作用(C和D)。C和D網絡層數相同,但D将C的3個conv3x3換成了conv1x1,性能提升。這點我了解是,跨通道的資訊交換/融合,可以産生豐富的特征易于分類器學習。conv1x1相比conv3x3不會去學習local的局部像素資訊,專注于跨通道的資訊交換/融合,同時為後面全連接配接層(全連接配接層相當于global卷積)做準備,使之學習過程更自然。
- 多小卷積核比單大卷積核性能好(B)。作者做了實驗用B和自己一個不在實驗組裡的較淺網絡比較,較淺網絡用conv5x5來代替B的兩個conv3x3。多個小卷積核比單大卷積核效果好,換句話說當考慮卷積核大小時:depths matters。
評價
最後貼出CS231n的評價:
The runner-up in ILSVRC 2014 was the network from Karen Simonyan and Andrew Zisserman that became known as the VGGNet. Its main contribution was in showing that the depth of the network is a critical component for good performance. Their final best network contains 16 CONV/FC layers and, appealingly, features an extremely homogeneous architecture that only performs 3x3 convolutions and 2x2 pooling from the beginning to the end. Their pretrained model is available for plug and play use in Caffe. A downside of the VGGNet is that it is more expensive to evaluate and uses a lot more memory and parameters (140M). Most of these parameters are in the first fully connected layer, and it was since found that these FC layers can be removed with no performance downgrade, significantly reducing the number of necessary parameters.
不難提煉出如下結論:
- 深度提升性能;
- 最佳模型:VGG16,從頭到尾隻有3x3卷積與2x2池化。簡潔優美;
- 開源pretrained model。與開源深度學習架構Caffe結合使用,助力更多人來學習;
- 卷積可代替全連接配接。整體參數達1億4千萬,主要在于第一個全連接配接層,用卷積來代替後,參數量下降(這裡的說法我認為是錯的,替代前後用同樣的輸入尺寸,網絡參數量、feature map、計算量三者沒有變化)且無精度損失。
參考
以下是一些參考文獻,雖然不少地方引用了,但是偷懶沒有在文中具體标明。老實說,有時間能看原汁原味的東西就不要看别人吃過的,即使是我寫的這篇,看原版的東西我覺得收獲更大一些。
- ILSVRC-2014 presentation http://www.robots.ox.ac.uk/~karen/pdf/ILSVRC_2014.pdf
- http://cs231n.stanford.edu/slides/2017/cs231n_2017_lecture9.pdf
- Convolutional neural networks on the iPhone with VGGNet http://machinethink.net/blog/convolutional-neural-networks-on-the-iphone-with-vggnet/
- A Matlab Toolkit for Distance Metric Learning http://www.cs.cmu.edu/~liuy/distlearn.htm
- 圖像進行中的L1-normalize 和L2-normalize - CSDN部落格 注:公式寫錯了http://blog.csdn.net/a200800170331/article/details/21737741
- Feature Visualization https://distill.pub/2017/feature-visualization/#enemy-of-feature-vis
- TensorFlow 教程 #14 - DeepDream(多圖預警) https://zhuanlan.zhihu.com/p/27546601
- caffe/pooling_layer.cpp at 80f44100e19fd371ff55beb3ec2ad5919fb6ac43 · BVLC/caffehttps://github.com/BVLC/caffe/blob/80f44100e19fd371ff55beb3ec2ad5919fb6ac43/src/caffe/layers/pooling_layer.cpp
- VGG網絡中測試時為什麼全連結改成卷積? - 知乎 https://www.zhihu.com/question/53420266
- pooling mean max 前向和反向傳播 - CSDN部落格 http://blog.csdn.net/junmuzi/article/details/53206600
- caffe/pooling_layer.cpp at 80f44100e19fd371ff55beb3ec2ad5919fb6ac43 · BVLC/caffehttps://github.com/BVLC/caffe/blob/80f44100e19fd371ff55beb3ec2ad5919fb6ac43/src/caffe/layers/pooling_layer.cpp
- Deep learning:四十七(Stochastic Pooling簡單了解) - tornadomeet - 部落格園https://www.cnblogs.com/tornadomeet/p/3432093.html
- Convolutional Neural Networks - Basics · Machine Learning Notebookhttps://mlnotebook.github.io/post/CNN1/
- 在 Caffe 中如何計算卷積? - 知乎 https://www.zhihu.com/question/28385679
- High Performance Convolutional Neural Networks for Document Processing Kumar Chellapilla, Sidd Puri, Patrice Simard https://hal.archives-ouvertes.fr/file/index/docid/112631/filename/p1038112283956.pdf