卷積神經網路入門詳解

卷積神經網路入門詳解

來自專欄機器學習與圖像處理6 人贊了文章

本文章為李宏毅老師機器學習課程的筆記,關注微信公眾號【輪子工廠】,後台回復關鍵字:機器學習,可獲取李宏毅教授整套機器學習視頻與課件。

1. 卷積神經網路結構概述

如果用全連接神經網路處理大尺寸圖像具有三個明顯的缺點:

(1)首先將圖像展開為向量會丟失空間信息;

(2)其次參數過多效率低下,訓練困難;

(3)同時大量的參數也很快會導致網路過擬合。

而使用卷積神經網路可以很好地解決上面的三個問題。

與常規神經網路不同,卷積神經網路的各層中的神經元是3維排列的:寬度、高度和深度。其中的寬度和高度是很好理解的,因為本身卷積就是一個二維模板,但是在卷積神經網路中的深度指的是激活數據體的第三個維度,而不是整個網路的深度,整個網路的深度指的是網路的層數。舉個例子來理解什麼是寬度,高度和深度,假如使用CIFAR-10中的圖像是作為卷積神經網路的輸入,該輸入數據體的維度是32x32x3(寬度,高度和深度)。我們將看到,層中的神經元將只與前一層中的一小塊區域連接,而不是採取全連接方式。對於用來分類CIFAR-10中的圖像的卷積網路,其最後的輸出層的維度是1x1x10,因為在卷積神經網路結構的最後部分將會把全尺寸的圖像壓縮為包含分類評分的一個向量,向量是在深度方向排列的。下面是例子:

圖 1. 全連接神經網路與卷積神經網路的對比

圖1中左側是一個3層的神經網路;右側是一個卷積神經網路,將它的神經元在成3個維度(寬、高和深度)進行排列。卷積神經網路的每一層都將3D的輸入數據變化為神經元3D的激活數據並輸出。在圖1的右側,紅色的輸入層代表輸入圖像,所以它的寬度和高度就是圖像的寬度和高度,它的深度是3(代表了紅、綠、藍3種顏色通道),與紅色相鄰的藍色部分是經過卷積和池化之後的激活值(也可以看做是神經元) ,後面是接著的卷積池化層。

2. 構建卷積神經網路的各種層

卷積神經網路主要由這幾類層構成:輸入層、卷積層,ReLU層、池化(Pooling)層和全連接層(全連接層和常規神經網路中的一樣)。通過將這些層疊加起來,就可以構建一個完整的卷積神經網路。在實際應用中往往將卷積層與ReLU層共同稱之為卷積層,所以卷積層經過卷積操作也是要經過激活函數的。具體說來,卷積層和全連接層(CONV/FC)對輸入執行變換操作的時候,不僅會用到激活函數,還會用到很多參數,即神經元的權值w和偏差b;而ReLU層和池化層則是進行一個固定不變的函數操作。卷積層和全連接層中的參數會隨著梯度下降被訓練,這樣卷積神經網路計算出的分類評分就能和訓練集中的每個圖像的標籤吻合了。

2.1 卷積層

卷積層是構建卷積神經網路的核心層,它產生了網路中大部分的計算量。注意是計算量而不是參數量。

2.1.1 卷積層作用

1. 濾波器的作用或者說是卷積的作用。卷積層的參數是有一些可學習的濾波器集合構成的。每個濾波器在空間上(寬度和高度)都比較小,但是深度和輸入數據一致(這一點很重要,後面會具體介紹)。直觀地來說,網路會讓濾波器學習到當它看到某些類型的視覺特徵時就激活,具體的視覺特徵可能是某些方位上的邊界,或者在第一層上某些顏色的斑點,甚至可以是網路更高層上的蜂巢狀或者車輪狀圖案。

2. 可以被看做是神經元的一個輸出。神經元只觀察輸入數據中的一小部分,並且和空間上左右兩邊的所有神經元共享參數(因為這些數字都是使用同一個濾波器得到的結果)。

3. 降低參數的數量。這個由於卷積具有「權值共享」這樣的特性,可以降低參數數量,達到降低計算開銷,防止由於參數過多而造成過擬合。

2.1.2 感受野(重點理解)

在處理圖像這樣的高維度輸入時,讓每個神經元都與前一層中的所有神經元進行全連接是不現實的。相反,我們讓每個神經元只與輸入數據的一個局部區域連接。該連接的空間大小叫做神經元的感受野(receptive field),它的尺寸是一個超參數(其實就是濾波器的空間尺寸)。在深度方向上,這個連接的大小總是和輸入量的深度相等。需要再次強調的是,我們對待空間維度(寬和高)與深度維度是不同的:連接在空間(寬高)上是局部的,但是在深度上總是和輸入數據的深度一致,這一點會在下面舉例具體說明。

圖 2. 舉例說明感受野的連接及尺寸說明

在圖 2 中展現的卷積神經網路的一部分,其中的紅色為輸入數據,假設輸入數據體尺寸為[32x32x3](比如CIFAR-10的RGB圖像),如果感受野(或濾波器尺寸)是5x5,那麼卷積層中的每個神經元會有輸入數據體中[5x5x3]區域的權重,共5x5x3=75個權重(還要加一個偏差參數)。注意這個連接在深度維度上的大小必須為3,和輸入數據體的深度一致。其中還有一點需要注意,對應一個感受野有75個權重,這75個權重是通過學習進行更新的,所以很大程度上這些權值之間是不相等(也就對於同一個卷積核,它對於與它連接的輸入的每一層的權重都是獨特的,不是同樣的權重重複輸入層層數那麼多次就可以的)。在這裡相當於前面的每一個層對應一個傳統意義上的卷積模板,每一層與自己卷積模板做完卷積之後,再將各個層的結果加起來,再加上偏置,注意是一個偏置,無論輸入輸入數據是多少層,一個卷積核就對應一個偏置。

2.1.3 神經元的空間排列

感受野講解了卷積層中每個神經元與輸入數據體之間的連接方式,但是尚未討論輸出數據體中神經元的數量,以及它們的排列方式。3個超參數控制著輸出數據體的尺寸:深度(depth),步長(stride)和零填充(zero-padding)。

(1) 輸出數據體的深度:它是一個超參數,和使用的濾波器的數量一致,而每個濾波器在輸入數據中尋找一些不同的東西,即圖像的某些特徵。如圖2 所示,將沿著深度方向排列、感受野相同的神經元集合稱為深度列(depth column),也有人使用纖維(fibre)來稱呼它們。

(2) 在滑動濾波器的時候,必須指定步長。當步長為1,濾波器每次移動1個像素;當步長為2,濾波器滑動時每次移動2個像素,當然步長也可以是不常用的3,或者更大的數字,但這些在實際中很少使用)。這個操作會讓輸出數據體在空間上變小。

(3) 有時候將輸入數據體用0在邊緣處進行填充是很方便的。這個零填充(zero-padding)的尺寸是一個超參數。零填充有一個良好性質,即可以控制輸出數據體的空間尺寸(最常用的是用來保持輸入數據體在空間上的尺寸,使得輸入和輸出的寬高都相等)。

輸出數據體在空間上的尺寸 W_2×H_2×D_2 可以通過輸入數據體尺寸 W_1×H_1×D_1 ,卷積層中神經元的感受野尺寸(F),步長(S),濾波器數量(K)和零填充的數量(P)計算輸出出來。

一般說來,當步長S=1時,零填充的值是P=(F-1)/2,這樣就能保證輸入和輸出數據體有相同的空間尺寸。

步長的限制:注意這些空間排列的超參數之間是相互限制的。舉例說來,當輸入尺寸W=10,不使用零填充 P=0,濾波器尺寸 F=3,此時步長 S=2 是行不通,因為 (W-F+2P)/S+1=(10-3+0)/2+1=4.5,結果不是整數,這就是說神經元不能整齊對稱地滑過輸入數據體。因此,這些超參數的設定就被認為是無效的,一個卷積神經網路庫可能會報出一個錯誤,通過修改零填充值、修改輸入數據體尺寸,或者其他什麼措施來讓設置合理。在後面的卷積神經網路結構小節中,讀者可以看到合理地設置網路的尺寸讓所有的維度都能正常工作,是相當讓人頭痛的事;而使用零填充和遵守其他一些設計策略將會有效解決這個問題。

2.1.4 權值共享

在卷積層中權值共享是用來控制參數的數量。假如在一個卷積核中,每一個感受野採用的都是不同的權重值(卷積核的值不同),那麼這樣的網路中參數數量將是十分巨大的。

權值共享是基於這樣的一個合理的假設:如果一個特徵在計算某個空間位置 (x1,y1)(x1,y1) 的時候有用,那麼它在計算另一個不同位置 (x2,y2)(x2,y2) 的時候也有用。基於這個假設,可以顯著地減少參數數量。換言之,就是將深度維度上一個單獨的2維切片看做深度切片(depth slice),比如一個數據體尺寸為[55x55x96]的就有96個深度切片,每個尺寸為[55x55],其中在每個深度切片上的結果都使用同樣的權重和偏差獲得的。在這樣的參數共享下,假如一個例子中的第一個卷積層有96個卷積核,那麼就有96個不同的權重集了,一個權重集對應一個深度切片,如果卷積核的大小是 11x11的,圖像是RGB 3 通道的,那麼就共有96x11x11x3=34,848個不同的權重,總共有34,944個參數(因為要+96個偏差),並且在每個深度切片中的55x55 的結果使用的都是同樣的參數。

在反向傳播的時候,都要計算每個神經元對它的權重的梯度,但是需要把同一個深度切片上的所有神經元對權重的梯度累加,這樣就得到了對共享權重的梯度。這樣,每個切片只更新一個權重集。這樣做的原因可以通過下面這張圖進行解釋

圖 3. 將卷積層用全連接層的形式表示

如上圖所示,左側的神經元是將每一個感受野展開為一列之後串聯起來(就是展開排成一列,同一層神經元之間不連接)。右側的 Deep1i 是深度為1的神經元的第 i 個, Deep2i 是深度為2的神經元的第 i 個,同一個深度的神經元的權值都是相同的,黃色的都是相同的(上面4個與下面4個的參數相同),藍色都是相同的。所以現在回過頭來看上面說的卷積神經網路的反向傳播公式對梯度進行累加求和也是基於這點考慮(同一深度的不同神經元共用一組參數,所以累加);而每個切片只更新一個權重集的原因也是這樣的,因為從圖3 中可以看到,不同深度的神經元不會公用相同的權重,所以只能更新一個權重集。

注意,如果在一個深度切片中的所有權重都使用同一個權重向量,那麼卷積層的前向傳播在每個深度切片中可以看做是在計算神經元權重和輸入數據體的卷積(這就是「卷積層」名字由來)。這也是為什麼總是將這些權重集合稱為濾波器(filter)(或卷積核(kernel)),因為它們和輸入進行了卷積。

注意,有時候參數共享假設可能沒有意義,特別是當卷積神經網路的輸入圖像是一些明確的中心結構時候。這時候我們就應該期望在圖片的不同位置學習到完全不同的特徵(而一個卷積核滑動地與圖像做卷積都是在學習相同的特徵)。一個具體的例子就是輸入圖像是人臉,人臉一般都處於圖片中心,而我們期望在不同的位置學習到不同的特徵,比如眼睛特徵或者頭髮特徵可能(也應該)會在圖片的不同位置被學習。在這個例子中,通常就放鬆參數共享的限制,將層稱為局部連接層(Locally-Connected Layer)。

2.1.5 卷積層的超參數及選擇

由於參數共享,每個濾波器包含 F?F?D_1 個權重(字元的具體含義在2.1.3中有介紹),卷積層一共有 F?F?D_1?K 個權重和 K 個偏置。在輸出數據體中,第d個深度切片(空間尺寸是 W_2×H_2 ),用第d個濾波器和輸入數據進行有效卷積運算的結果(使用步長S),最後在加上第d個偏差。

對這些超參數,常見的設置是 F=3,S=1,P=1,F=3,S=1,P=1。同時設置這些超參數也有一些約定俗成的慣例和經驗,可以在下面的「卷積神經網路結構」中查看。

2.1.6 卷積層演示

因為3D數據難以可視化,所以所有的數據(輸入數據體是藍色,權重數據體是紅色,輸出數據體是綠色)都採取將深度切片按照列的方式排列展現。輸入數據體的尺寸是W1=5,H1=5,D1=3W1=5,H1=5,D1=3,卷積層參數K=2,F=3,S=2,P=1K=2,F=3,S=2,P=1。就是說,有2個濾波器,濾波器的尺寸是3?33?3,它們的步長是2。因此,輸出數據體的空間尺寸是(5?3+2)/2+1=3(5?3+2)/2+1=3。注意輸入數據體使用了零填充P=1P=1,所以輸入數據體外邊緣一圈都是0。下面的例子在綠色的輸出激活數據上循環演示,展示了其中每個元素都是先通過藍色的輸入數據和紅色的濾波器逐元素相乘,然後求其總和,最後加上偏差得來。

圖 4. 卷積層演示過程

2.1.7 用矩陣乘法實現卷積

卷積運算本質上就是在濾波器和輸入數據的局部區域間做點積。卷積層的常用實現方式就是利用這一點,將卷積層的前向傳播變成一個巨大的矩陣乘法。

(1) 輸入圖像的局部區域被 im2coim2co l操作拉伸為列。比如輸入是[227x227x3],要與尺寸為11x11x3的濾波器以步長為4進行卷積,就依次取輸入中的[11x11x3]數據塊,然後將其拉伸為長度為11x11x3=363的列向量。重複進行這一過程,因為步長為4,所以經過卷積後的寬和高均為(227-11)/4+1=55,共有55x55=3,025個個神經元。因為每一個神經元實際上都是對應有 363 的列向量構成的感受野,即一共要從輸入上取出 3025 個 363 維的列向量。所以經過im2col操作得到的輸出矩陣 XcolXcol 的尺寸是[363x3025],其中每列是拉伸的感受野。注意因為感受野之間有重疊,所以輸入數據體中的數字在不同的列中可能有重複。

(2) 卷積層的權重也同樣被拉伸成行。舉例,如果有96個尺寸為[11x11x3]的濾波器,就生成一個矩陣WrowWrow,尺寸為[96x363]。

(3) 現在卷積的結果和進行一個大矩陣乘法 np.dot(Wrow,Xcol)np.dot(Wrow,Xcol) 是等價的了,能得到每個濾波器和每個感受野間的點積。在我們的例子中,這個操作的輸出是[96x3025],給出了每個濾波器在每個位置的點積輸出。注意其中的 np.dotnp.dot計算的是矩陣乘法而不是點積。

(4) 結果最後必須被重新變為合理的輸出尺寸[55x55x96]。

這個方法的缺點就是佔用內存太多,因為在輸入數據體中的某些值在XcolXcol中被複制了多次;優點在於矩陣乘法有非常多的高效底層實現方式(比如常用的BLAS API)。還有,同樣的im2col思路可以用在池化操作中。反向傳播:卷積操作的反向傳播(同時對於數據和權重)還是一個卷積(但是和空間上翻轉的濾波器)。使用一個1維的例子比較容易演示。這兩部分中,不是很懂如何用矩陣的形式進行匯聚操作和反向傳播。

2.1.8 其他形式的卷積操作

1x1卷積:一些論文中使用了1x1的卷積,這個方法最早是在論文Network in Network中出現。人們剛開始看見這個1x1卷積的時候比較困惑,尤其是那些具有信號處理專業背景的人。因為信號是2維的,所以1x1卷積就沒有意義。但是,在卷積神經網路中不是這樣,因為這裡是對3個維度進行操作,濾波器和輸入數據體的深度是一樣的。比如,如果輸入是[32x32x3],那麼1x1卷積就是在高效地進行3維點積(因為輸入深度是3個通道);另外的一種想法是將這種卷積的結果看作是全連接層的一種實現方式,詳見本文2.4.2 部分。

擴張卷積:最近一個研究(Fisher Yu和Vladlen Koltun的論文)給卷積層引入了一個新的叫擴張(dilation)的超參數。到目前為止,我們只討論了卷積層濾波器是連續的情況。但是,讓濾波器中元素之間有間隙也是可以的,這就叫做擴張。如圖5 為進行1擴張。

圖 5. 擴張卷積的例子及擴張前後的疊加效果

在某些設置中,擴張卷積與正常卷積結合起來非常有用,因為在很少的層數內更快地彙集輸入圖片的大尺度特徵。比如,如果上下重疊2個3x3的卷積層,那麼第二個卷積層的神經元的感受野是輸入數據體中5x5的區域(可以成這些神經元的有效感受野是5x5,如圖5 所示)。如果我們對卷積進行擴張,那麼這個有效感受野就會迅速增長。

2.2 池化層

通常在連續的卷積層之間會周期性地插入一個池化層。它的作用是逐漸降低數據體的空間尺寸,這樣的話就能減少網路中參數的數量,使得計算資源耗費變少,也能有效控制過擬合。匯聚層使用 MAX 操作,對輸入數據體的每一個深度切片獨立進行操作,改變它的空間尺寸。最常見的形式是匯聚層使用尺寸2x2的濾波器,以步長為2來對每個深度切片進行降採樣,將其中75%的激活信息都丟掉。每個MAX操作是從4個數字中取最大值(也就是在深度切片中某個2x2的區域),深度保持不變。

匯聚層的一些公式:輸入數據體尺寸 W_1?H_1?D_1 ,有兩個超參數:空間大小FF和步長SS;輸出數據體的尺寸 W_2?H_2?D_2 ,其中

這裡面與之前的卷積的尺寸計算的區別主要在於兩點,首先在池化的過程中基本不會進行另補充;其次池化前後深度不變。

在實踐中,最大池化層通常只有兩種形式:一種是F=3,S=2F=3,S=2,也叫重疊匯聚(overlapping pooling),另一個更常用的是F=2,S=2F=2,S=2。對更大感受野進行池化需要的池化尺寸也更大,而且往往對網路有破壞性。

普通池化(General Pooling):除了最大池化,池化單元還可以使用其他的函數,比如平均池化(average pooling)或L-2範式池化(L2-norm pooling)。平均池化歷史上比較常用,但是現在已經很少使用了。因為實踐證明,最大池化的效果比平均池化要好。

反向傳播:回顧一下反向傳播的內容,其中max(x,y)函數的反向傳播可以簡單理解為將梯度只沿最大的數回傳。因此,在向前傳播經過匯聚層的時候,通常會把池中最大元素的索引記錄下來(有時這個也叫作道岔(switches)),這樣在反向傳播的時候梯度的路由就很高效。(具體如何實現我也不是很懂)。

不使用匯聚層:很多人不喜歡匯聚操作,認為可以不使用它。比如在Striving for Simplicity: The All Convolutional Net一文中,提出使用一種只有重複的卷積層組成的結構,拋棄匯聚層。通過在卷積層中使用更大的步長來降低數據體的尺寸。有發現認為,在訓練一個良好的生成模型時,棄用匯聚層也是很重要的。比如變化自編碼器(VAEs:variational autoencoders)和生成性對抗網路(GANs:generative adversarial networks)。現在看起來,未來的卷積網路結構中,可能會很少使用甚至不使用匯聚層

2.3 歸一化層

在卷積神經網路的結構中,提出了很多不同類型的歸一化層,有時候是為了實現在生物大腦中觀測到的抑制機制。但是這些層漸漸都不再流行,因為實踐證明它們的效果即使存在,也是極其有限的

2.4 全連接層

這個常規神經網路中一樣,它們的激活可以先用矩陣乘法,再加上偏差。

2.4.1 將卷積層轉化成全連接層

對於任一個卷積層,都存在一個能實現和它一樣的前向傳播函數的全連接層。該全連接層的權重是一個巨大的矩陣,除了某些特定塊(感受野),其餘部分都是零;而在非 0 部分中,大部分元素都是相等的(權值共享),具體可以參考圖3。如果把全連接層轉化成卷積層,以輸出層的 Deep11 為例,與它有關的輸入神經元只有上面四個,所以在權重矩陣中與它相乘的元素,除了它所對應的4個,剩下的均為0,這也就解釋了為什麼權重矩陣中有為零的部分;另外要把「將全連接層轉化成卷積層」和「用矩陣乘法實現卷積」區別開,這兩者是不同的,後者本身還是在計算卷積,只不過將其展開為矩陣相乘的形式,並不是」將全連接層轉化成卷積層」,所以除非權重中本身有零,否則用矩陣乘法實現卷積的過程中不會出現值為0的權重。

2.4.2 將全連接層轉化成卷積層

任何全連接層都可以被轉化為卷積層。比如,一個K=4096的全連接層,輸入數據體的尺寸是 7×7×5127×7×512,這個全連接層可以被等效地看做一個F=7,P=0,S=1,K=4096,F=7,P=0,S=1,K=4096的卷積層。換句話說,就是將濾波器的尺寸設置為和輸入數據體的尺寸設為一致的。因為只有一個單獨的深度列覆蓋並滑過輸入數據體,所以輸出將變成1×1×40961×1×4096,這個結果就和使用初始的那個全連接層一樣了。這個實際上也很好理解,因為,對於其中的一個卷積濾波器,這個濾波器的的深度為512,也就是說,雖然這個卷積濾波器的輸出只有1個,但是它的權重有7×7×5127×7×512,相當於卷積濾波器的輸出為一個神經元,這個神經元與上一層的所有神經元相連接,而這樣與前一層所有神經元相連接的神經元一共有4096個,這不就是一個全連接網路嘛~

在上述的兩種變換中,將全連接層轉化為卷積層在實際運用中更加有用。假設一個卷積神經網路的輸入是224x224x3的圖像,一系列的卷積層和匯聚層將圖像數據變為尺寸為7x7x512的激活數據體(在AlexNet中就是這樣,通過使用5個匯聚層來對輸入數據進行空間上的降採樣,每次尺寸下降一半,所以最終空間尺寸為224/2/2/2/2/2=7)。從這裡可以看到,AlexNet使用了兩個尺寸為4096的全連接層,最後一個有1000個神經元的全連接層用於計算分類評分。我們可以將這3個全連接轉化為3個卷積層:

(1) 針對第一個連接區域是[7x7x512]的全連接層,令其濾波器尺寸為F=7,這樣輸出數據體就為[1x1x4096]了。

(2) 針對第二個全連接層,令其濾波器尺寸為F=1,這樣輸出數據體為[1x1x4096]。

(3) 對最後一個全連接層也做類似的,令其F=1,最終輸出為[1x1x1000]。

這樣做的目的是讓卷積網路在一張更大的輸入圖片上滑動,得到多個輸出,這樣的轉化可以讓我們在單個向前傳播的過程中完成上述的操作。

舉個例子,如果我們想讓224x224尺寸的浮窗,以步長為32在384x384的圖片上滑動,把每個經停的位置都帶入卷積網路,最後得到6x6個位置的類別得分。上述的把全連接層轉換成卷積層的做法會更簡便。如果224x224的輸入圖片經過卷積層和匯聚層之後得到了[7x7x512]的數組,那麼,384x384的大圖片直接經過同樣的卷積層和匯聚層之後會得到[12x12x512]的數組(因為途徑5個匯聚層,尺寸變為384/2/2/2/2/2 = 12)。然後再經過上面由3個全連接層轉化得到的3個卷積層,最終得到[6x6x1000]的輸出(因為(12 - 7)/1 + 1 = 6)。這個結果正是浮窗在原圖經停的6x6個位置的得分!

面對384x384的圖像,讓(含全連接層)的初始卷積神經網路以32像素的步長獨立對圖像中的224x224塊進行多次評價,其效果和使用把全連接層變換為卷積層後的卷積神經網路進行一次前向傳播是一樣的。自然,相較於使用被轉化前的原始卷積神經網路對所有36個位置進行迭代計算,使用轉化後的卷積神經網路進行一次前向傳播計算要高效得多,因為36次計算都在共享計算資源。

這裡有幾個問題,首先為什麼是以32為步長,如果我以64為步長呢?再或者如果我們想用步長小於32(如16)的浮窗怎麼辦

首先回答其中的第一個問題。這個是因為其中一個有五個匯聚層,因為25=3225=32,也就是在原始圖像上的寬或者高增加 3232 個像素,經過這些卷積和匯聚後,將變為一個像素。現在進行舉例說明,雖然例子並沒有32那麼大的尺寸,但是意義都是一樣的。假設原始圖像的大小為 4×4,卷積核 F=3,S=1,P=1F=3,S=1,P=1,而較大的圖像的尺寸為 8×8,假設對圖像進行兩層的卷積池化,在較大的圖像上以步長為4進行滑動(22=422=4),如圖5所示

圖 5. 以步長為4在原始圖像上滑動取出4×4窗口再計算卷積的結果

對原始圖像(圖5左圖紅框)進行卷積得到的結果是圖5右圖紅色框內的結果,使用步長為4在較大的圖像獲得的結果為圖5中右側四種顏色加在一起的樣子。所以以步長為4在8x8的圖片上滑動,把每個經停的位置都帶入卷積網路,最後得到2x2個位置的卷積結果,但是如果直接使用卷積核 F=3,S=1,P=1F=3,S=1,P=1進行兩次卷積池化的話,得到的結果的大小顯然也是4×4的。

所以從獲得結果來看,這兩者是相同的,但是不同點在哪呢?如圖6所示,是在整個圖像上進行卷積運算和以步長為4在8x8的圖片上滑動所經停的第一個位置,這兩種方法使用相同的卷積核進行計算的對比圖。

圖6. 使用整張圖像和一部分圖像計算某一點處的卷積

如圖6所示,左圖代表使用整張圖像時計算a點處的卷積,右圖代表使用滑動的方法第一次經停圖像上a點的卷積,兩張圖中的a點是同一個a點。雖然同一個卷積模板進行計算,但是在計算卷積的過程是不同的!因為在右圖中a的右側及右下側是0,而在左圖中是原始的像素值,所以計算的卷積一定是不同的。但是要怎麼理解這樣的差別呢?這要從補零的意義講起,補零是因為如果不補零的話,圖像經過卷積之後的尺寸會小於原始的尺寸,補零可以保證圖像的尺寸不變,所以歸根結底補零實際上是一種圖像填充的方法。左圖中a的右邊及右下角的像素是原始圖像的像素,相當於在計算a點的時候,不是用0進行的補充,而是原始像素值進行補充,這樣的不僅可以保持卷積前後圖像的大小不變,而且可以這種圖像填充方法得到的結果顯然要比填0更接近與原始圖像,保留的信息更多。

小節

(1) 用一整圖像進行卷積和在較大的圖像上通過滑動窗提取出一個個子圖象進行卷積得到的效果是相同的。

(2) 可以這樣做的主要原因在於將最後的全連接層改寫成了卷積層。

(3) 在一整章圖像做卷積的效率要遠遠高於在圖像上滑動的效率,因為前者只需要依次前向傳播,而後者需要多次

(4) 用整張圖像計算與滑動窗口的方法對比,所補充的零更少(如上所講,不用零而是用在其旁邊的像素代替),提取的信息損失的更少。

即,用整張圖像直接計算卷積不僅僅在效率上高於使用滑動窗口的方法,而且更多的保留了圖像的細節,完勝!

另外還可以得到另一個結論當在較大的圖像上以步長為 2L2L進行滑動時,其效果與在有直接在大圖像上進行卷積得到的結果上以步長為1移動是一樣的。如圖5中的大紅色框對應小紅色框,大黃色框對應小黃色框。所以當步長為64時,將相當於以步長為2在大圖的卷積結果上移動。

對於第二個問題,如果我非要以12為步長呢?是可以的,只是這個時候所獲得結果不再是如圖5的那種滑動的計算方式了。還是舉例說明,不過為了方便說明改變了一下尺寸。將步長32改為4,將步長16改為2進行分析。假如說原始的輸入圖像為一個 4×4 的圖像,現在將使用一個比原來大的圖像,是一個8×8的圖像,使用卷積核為 4×4 大小,步長為4,則在圖像進行卷積運算的如圖6左側的4個部分(紅黃綠藍),而圖6 右側的是步長為2時與原始相比增加的部分。將圖 6中兩個部分相加就可以得到步長為2它時所有進行卷積運算的部分了。

圖6 .步長為4時原始圖像進行卷積的部分及將步長改為2時比原來多出的部分

獲得步長為2的時進行卷積的區域。首先像之前一樣對原始圖像做以4為步長的卷積,這時進行卷積的部分就是圖6中左側的部分;其次將原始圖片沿寬度方向平移2個像素之後,依舊進行步長為4的卷積,這個時候進行卷積的部分為圖6中的紅色部分和綠色部分;然後沿高度方向平移2個像素之後,按步長為4進行卷積,這個時候進行卷積的部分為圖6中的藍色部分和黃色部分;最後沿高度方向和寬度方向同時移動2個像素,按步長為4進行卷積,這個時候進行卷積的部分為圖6中的紫色部分。將這些部分加在一起就是進行卷積運算你得所有區域了。

這個結果明顯是無法通過像圖5中的那樣滑動得到了,這樣的方法所需要進行卷積的區域要遠遠大於以4為步長時所需要就進行卷積運算的區域;後續的卷積都是在這一卷積的結果上進行的,所以後面的都會發生改變。

綜上,步長為32的正整數倍只是保證獲得結果可以像圖5那樣滑動的獲得的下限值。

3. 卷積神經網路的結構

卷積神經網路通常是由三種層構成:卷積層,匯聚層(除非特別說明,一般就是最大值匯聚)和全連接層(簡稱FC)。ReLU激活函數也應該算是是一層,它逐元素地進行激活函數操作,常常將它與卷積層看作是同一層。

3.1 層的排列規律

卷積神經網路最常見的形式就是將一些卷積層和ReLU層放在一起,其後緊跟匯聚層,然後重複如此直到圖像在空間上被縮小到一個足夠小的尺寸,在某個地方過渡成成全連接層也較為常見。最後的全連接層得到輸出,比如分類評分等。換句話說,最常見的卷積神經網路結構如下:

其中*指的是重複次數,POOL?指的是一個可選的匯聚層。其中N >=0,通常N<=3,M>=0,K>=0,通常K<3。例如,下面是一些常見的網路結構規律:

  • INPUT -> FC ,實現一個線性分類器,此處N = M = K = 0。
  • INPUT -> CONV -> RELU -> FC,單層的卷積神經網路
  • INPUT -> [CONV -> RELU -> POOL]*2 -> FC -> RELU -> FC,此處在每個匯聚層之間有一個卷積層,這種網路就是簡單的多層的卷積神經網路。
  • INPUT -> [CONV -> RELU -> CONV -> RELU -> POOL]*3 -> [FC -> RELU]*2 -> FC ,此處每個匯聚層前有兩個卷積層,這個思路適用於更大更深的網路(比如說這個思路就和VGG比較像),因為在執行具有破壞性的匯聚操作前,多重的卷積層可以從輸入數據中學習到更多的複雜特徵。

最新進展:傳統的將層按照線性進行排列的方法已經受到了挑戰,挑戰來自谷歌的Inception結構和微軟亞洲研究院的殘差網路(Residual Net)結構。這兩個網路的特徵更加複雜,連接結構也不同。

3.2 卷積層的大小選擇

幾個小濾波器卷積層的組合比一個大濾波器卷積層好。假設你一層一層地重疊了3個3x3的卷積層(層與層之間有非線性激活函數)。在這個排列下,第一個卷積層中的每個神經元都對輸入數據體有一個3x3的視野。第二個卷積層上的神經元對第一個卷積層有一個3x3的視野,也就是對輸入數據體有5x5的視野。同樣,在第三個卷積層上的神經元對第二個卷積層有3x3的視野,也就是對輸入數據體有7x7的視野。假設不採用這3個3x3的卷積層,二是使用一個單獨的有7x7的感受野的卷積層,那麼所有神經元的感受野也是7x7,但是就有一些缺點。首先,多個卷積層與非線性的激活層交替的結構,比單一卷積層的結構更能提取出深層的更好的特徵。其次,假設所有的數據有C個通道,那麼單獨的7x7卷積層將會包含 C×(7×7×C)=49C^2 個參數,而3個3x3的卷積層的組合僅有 3×(C×(3×3×C))=27C^2 個參數。直觀說來,最好選擇帶有小濾波器的卷積層組合,而不是用一個帶有大的濾波器的卷積層。前者可以表達出輸入數據中更多個強力特徵,使用的參數也更少。唯一的不足是,在進行反向傳播時,中間的卷積層可能會導致佔用更多的內存。

3.3 層的尺寸設置規律

  • 輸入層 ,應該能被2整除很多次。常用數字包括32(比如CIFAR-10),64,96(比如STL-10)或224(比如ImageNet卷積神經網路),384和512。
  • 卷積層 ,應該使用小尺寸濾波器(比如3x3或最多5x5),使用步長S=1。還有一點非常重要,就是對輸入數據進行零填充,這樣卷積層就不會改變輸入數據在空間維度上的尺寸。比如,當F=3,那就使用P=1來保持輸入尺寸。當F=5,P=2,一般對於任意F,當P=(F-1)/2的時候能保持輸入尺寸。如果必須使用更大的濾波器尺寸(比如7x7之類),通常只用在第一個面對原始圖像的卷積層上。
  • 匯聚層 ,負責對輸入數據的空間維度進行降採樣。最常用的設置是用用2x2感受野(即F=2)的最大值匯聚,步長為2(S=2)。注意這一操作將會把輸入數據中75%的激活數據丟棄(因為對寬度和高度都進行了2的降採樣)。另一個不那麼常用的設置是使用3x3的感受野,步長為2。最大值匯聚的感受野尺寸很少有超過3的,因為匯聚操作過於激烈,易造成數據信息丟失,這通常會導致演算法性能變差。

上文中展示的兩種設置(卷積層F=3,P=1,匯聚層F=2,P=2)是很好的,因為所有的卷積層都能保持其輸入數據的空間尺寸,匯聚層只負責對數據體從空間維度進行降採樣。如果使用的步長大於1並且不對卷積層的輸入數據使用零填充,那麼就必須非常仔細地監督輸入數據體通過整個卷積神經網路結構的過程,確認所有的步長和濾波器都尺寸互相吻合,卷積神經網路的結構美妙對稱地聯繫在一起。

為何使用零填充?使用零填充除了前面提到的可以讓卷積層的輸出數據保持和輸入數據在空間維度的不變,還可以提高演算法性能。如果卷積層值進行卷積而不進行零填充,那麼數據體的尺寸就會略微減小,那麼圖像邊緣的信息就會過快地損失掉。

因為內存限制所做的妥協:在某些案例(尤其是早期的卷積神經網路結構)中,基於前面的各種規則,內存的使用量迅速飆升。例如,使用64個尺寸為3x3的濾波器對224x224x3的圖像進行卷積,零填充為1,得到的激活數據體尺寸是[224x224x64]。這個數量就是一千萬的激活數據,或者就是72MB的內存(每張圖就是這麼多,激活函數和梯度都是)。因為GPU通常因為內存導致性能瓶頸,所以做出一些妥協是必須的。在實踐中,人們傾向於在網路的第一個卷積層做出妥協。例如,可以妥協可能是在第一個卷積層使用步長為2,尺寸為7x7的濾波器(比如在ZFnet中)。在AlexNet中,濾波器的尺寸的11x11,步長為4。

4. 案例學習

下面是卷積神經網路領域中比較有名的幾種結構:

  • LeNet ,第一個成功的卷積神經網路應用,是Yann LeCun在上世紀90年代實現的。當然,最著名還是被應用在識別數字和郵政編碼等的LeNet結構。
  • AlexNet ,AlexNet卷積神經網路在計算機視覺領域中受到歡迎,它由Alex Krizhevsky,Ilya Sutskever和Geoff Hinton實現。AlexNet在2012年的ImageNet ILSVRC 競賽中奪冠,性能遠遠超出第二名(16%的top5錯誤率,第二名是26%的top5錯誤率)。這個網路的結構和LeNet非常類似,但是更深更大,並且使用了層疊的卷積層來獲取特徵(之前通常是只用一個卷積層並且在其後馬上跟著一個匯聚層)。
  • ZF Net ,Matthew Zeiler和Rob Fergus發明的網路在ILSVRC 2013比賽中奪冠,它被稱為 ZFNet(Zeiler & Fergus Net的簡稱)。它通過修改結構中的超參數來實現對AlexNet的改良,具體說來就是增加了中間卷積層的尺寸讓第一層的步長和濾波器尺寸更小
  • GoogLeNet ,ILSVRC 2014的勝利者是谷歌的Szeged等實現的卷積神經網路。它主要的貢獻就是實現了一個奠基模塊,它能夠顯著地減少網路中參數的數量(AlexNet中有60M,該網路中只有4M)。還有,這個論文中沒有使用卷積神經網路頂部使用全連接層,而是使用了一個平均匯聚,把大量不是很重要的參數都去除掉了。GooLeNet還有幾種改進的版本,最新的一個是Inception-v4
  • VGGNet ,ILSVRC 2014的第二名是Karen Simonyan和 Andrew Zisserman實現的卷積神經網路,現在稱其為VGGNet。它主要的貢獻是展示出網路的深度是演算法優良性能的關鍵部分。他們最好的網路包含了16個卷積/全連接層。網路的結構非常一致,從頭到尾全部使用的是3x3的卷積和2x2的匯聚。他們的預訓練模型是可以在網路上獲得並在Caffe中使用的。VGGNet**不好的一點是它耗費更多計算資源,並且使用了更多的參數,導致更多的內存佔用(140M)。其中絕大多數的參數都是來自於第一個全連接層。後來發現這些全連接層即使被去除,對於性能也沒有什麼影響**,這樣就顯著降低了參數數量。
  • ResNet ,殘差網路(Residual Network)是ILSVRC2015的勝利者,由何愷明等實現。它使用了特殊的跳躍鏈接,大量使用了批量歸一化(batch normalization)。這個結構同樣在最後沒有使用全連接層。讀者可以查看何愷明的的演講(視頻,PPT),以及一些使用Torch重現網路的實驗。ResNet當前最好的卷積神經網路模型(2016年五月)。何開明等最近的工作是對原始結構做一些優化,可以看論文Identity Mappings in Deep Residual Networks,2016年3月發表。

4.1 VGGNet的細節

我們進一步對VGGNet的細節進行分析學習。整個VGGNet中的卷積層都是以步長為1進行3x3的卷積,使用了1的零填充,匯聚層都是以步長為2進行了2x2的最大值匯聚。可以寫出處理過程中每一步數據體尺寸的變化,然後對數據尺寸和整體權重的數量進行查看:

INPUT: [224x224x3] memory: 224*224*3=150K weights: 0CONV3-64: [224x224x64] memory: 224*224*64=3.2M weights: (3*3*3)*64 = 1,728CONV3-64: [224x224x64] memory: 224*224*64=3.2M weights: (3*3*64)*64 = 36,864POOL2: [112x112x64] memory: 112*112*64=800K weights: 0CONV3-128: [112x112x128] memory: 112*112*128=1.6M weights: (3*3*64)*128 = 73,728CONV3-128: [112x112x128] memory: 112*112*128=1.6M weights: (3*3*128)*128 = 147,456POOL2: [56x56x128] memory: 56*56*128=400K weights: 0CONV3-256: [56x56x256] memory: 56*56*256=800K weights: (3*3*128)*256 = 294,912CONV3-256: [56x56x256] memory: 56*56*256=800K weights: (3*3*256)*256 = 589,824CONV3-256: [56x56x256] memory: 56*56*256=800K weights: (3*3*256)*256 = 589,824POOL2: [28x28x256] memory: 28*28*256=200K weights: 0CONV3-512: [28x28x512] memory: 28*28*512=400K weights: (3*3*256)*512 = 1,179,648CONV3-512: [28x28x512] memory: 28*28*512=400K weights: (3*3*512)*512 = 2,359,296CONV3-512: [28x28x512] memory: 28*28*512=400K weights: (3*3*512)*512 = 2,359,296POOL2: [14x14x512] memory: 14*14*512=100K weights: 0CONV3-512: [14x14x512] memory: 14*14*512=100K weights: (3*3*512)*512 = 2,359,296CONV3-512: [14x14x512] memory: 14*14*512=100K weights: (3*3*512)*512 = 2,359,296CONV3-512: [14x14x512] memory: 14*14*512=100K weights: (3*3*512)*512 = 2,359,296POOL2: [7x7x512] memory: 7*7*512=25K weights: 0FC: [1x1x4096] memory: 4096 weights: 7*7*512*4096 = 102,760,448FC: [1x1x4096] memory: 4096 weights: 4096*4096 = 16,777,216FC: [1x1x1000] memory: 1000 weights: 4096*1000 = 4,096,000TOTAL memory: 24M * 4 bytes ~= 93MB / image (only forward! ~*2 for bwd)TOTAL params: 138M parameters

注意,大部分的內存和計算時間都被前面的卷積層佔用,大部分的參數都用在後面的全連接層,這在卷積神經網路中是比較常見的。在這個例子中,全部參數有140M,但第一個全連接層就包含了100M的參數

5. 計算上的考量

在構建卷積神經網路結構時,最大的瓶頸是內存瓶頸,所以如何降低內存消耗量是一個值得思考的問題。三種內存佔用來源:

  • 1 來自中間數據體尺寸:卷積神經網路中的每一層中都有激活數據體的原始數值,以及損失函數對它們的梯度(和激活數據體尺寸一致)。通常,大部分激活數據都是在網路中靠前的層中(比如第一個卷積層)。在訓練時,這些數據需要放在內存中,因為反向傳播的時候還會用到。但是在測試時可以聰明點:讓網路在測試運行時候每層都只存儲當前的激活數據,然後丟棄前面層的激活數據,這樣就能減少巨大的激活數據量。這實際上是底層問題,在編寫框架的過程中,設計者會進行這方面的考慮。
  • 2 來自參數尺寸:即整個網路的參數的數量,在反向傳播時它們的梯度值,以及使用momentum、Adagrad或RMSProp等方法進行最優化時的每一步計算緩存。因此,存儲參數向量的內存通常需要在參數向量的容量基礎上乘以3或者更多。
  • 3 卷積神經網路實現還有各種零散的內存佔用,比如成批的訓練數據,擴充的數據等等。

一旦對於所有這些數值的數量有了一個大略估計(包含激活數據,梯度和各種雜項),數量應該轉化為以GB為計量單位。把這個值乘以4,得到原始的位元組數(因為每個浮點數佔用4個位元組,如果是雙精度浮點數那就是佔用8個位元組),然後多次除以1024分別得到佔用內存的KB,MB,最後是GB計量。如果你的網路工作得不好,一個常用的方法是降低批尺寸(batch size),因為絕大多數的內存都是被激活數據消耗掉了。


我的其它幾個高贊回答也很值得看,全是滿滿的乾貨:

譚慶波:有哪些劇情反轉的有趣故事?

大神有哪些願意分享的計算機類資源?

計算機專業必讀哪些經典書籍?

譚慶波:零基礎怎麼學Java?

——————————————————

微信搜索公眾號【輪子工廠】,後台回復關鍵字:

1.回復【圖書】:獲取15本新手自學編程,零基礎入門經典學習教材;

2.回復【我要造輪子】:獲取100多本我根據知乎上面關於計算機問題的高贊回答裡面的介紹整理出來的書籍;

3.回復【內推】:可幫你內推到大廠工作。


推薦閱讀:

模型評估和選擇
機務?演算法工程師!轉職筆記(八)
我的人工智慧學習筆記(一)
複習:NN和BP
基於TensorFlow框架的Seq2Seq英法機器翻譯模型

TAG:深度學習DeepLearning | 機器學習 | 神經網路 |