第五章 卷積神經網路(CNN)
第五章 卷積神經網路(CNN)
標籤(空格分隔): 深度學習
5.1 卷積神經網路的組成層
在卷積神經網路中,有3種最主要的層:
- 卷積運算層
- 池化層
- 全連線層
一個完整的神經網路就是由這三種層疊加組成的。
結構示例
拿CIFAR-10資料集舉例,一個典型的該資料集上的卷積神經網路分類器應該有[INPUT - CONV - RELU - POOL - FC]的結構,
- INPUT[32*32*3]包含原始圖片資料中的全部畫素,長寬都是32,有RGB 3個顏色通道。
- CONV卷積層中,沒個神經元會和上一層的若干小區域連線,計算權重和小區域畫素的內積,舉個例子可能產出的結果資料是[32*32*12]的。
- RELU層,就是神經元激勵層,主要的計算就是max(0,x),結果資料依舊是[32*32*12]。
- POOLing層做的事情,可以理解成一個下采樣,可能得到的結果維度就變為[16*16*12]了。
- 全連線層一般用於最後計算類別得分,得到的結果為[1*1*10]的,其中的10對應10個不同的類別。和名字一樣,這一層的所有神經元會和上一層的所有神經元有連線。
這樣,卷積神經網路作為一箇中間的通道,就一步步把原始的影象資料轉成最後的類別得分了。有一個點我們要提一下,剛才說到了有幾種不同的神經網路層,其中有一些層是有待訓練引數的,另外一些沒有。詳細一點說,卷積層和全連線層包含權重和偏移的;而RELU和POOLing層只是一個固定的函式運算,是不包含權重和偏移引數的。不過POOLing層包含了我們手動指定的超引數,這個我們之後會提到。
總結一下:
- (1)一個卷積神經網路由多種不同型別的層(卷積層/RELU層/POOLing層/全連線層等)疊加而成。
- (2)每一層的輸入結構是3維的資料,計算完輸出依舊是3維的資料。
- (3)卷積層和全連線層包含訓練引數,RELU 和 POOLing 層不包含。
- (4)卷積層,全連線層和 POOLing 層包含超引數,RELU 層沒有。
下圖為 CIFAR-10 資料集構建的一個卷積神經網路結構示意圖:
5.2 卷積如何檢測邊緣資訊?
卷積運算是卷積神經網路最基本的組成部分,神經網路的前幾層首先檢測邊緣,然後,後面的層有可能檢測到物體的部分割槽域,更靠後的一些層可能檢測到完整的物體。
先介紹一個概念,過濾器:
這是一個3*3的過濾器,是一個矩陣,數值如上所示。
假設我們有一個6*6的灰度影象:
把這個影象與過濾器進行卷積運算,卷積運算在此處用“*”表示。
我們看一下發生了什麼事,把過濾器最準影象左上方3*3的範圍,逐一相乘並相加,得到-5。
同理,將過濾器右移進行相同操作,再下移,直到過濾器對準影象右下角最後一格。依次運算得到一個4*4的矩陣。
OK,瞭解了過濾器以及卷積運算後,讓我們看看為何過濾器能檢測物體邊緣:
舉一個最簡單的例子:
這張圖片如上所示,左半邊全是白的,右半邊全是灰的,過濾器還是用之前那個,把他們進行卷積:
可以看到,最終得到的結果中間是一段白色,兩邊為灰色,於是垂直邊緣被找到了。為什麼呢?因為在6*6影象中紅框標出來的部分,也就是影象中的分界線所在部分,與過濾器進行卷積,結果是30。而在不是分界線的所有部分進行卷積,結果都為0.
在這個圖中,白色的分界線很粗,那是因為66的影象實在太小了,若是換成10001000的影象,我們會發現在最終結果中,分界線不粗且很明顯。
這就是檢測物體垂直邊緣的例子,水平邊緣的話只需將過濾器旋轉90度。
5.3 卷積的幾個基本定義?
首先,我們需要就定義一個卷積層的幾個引數達成一致。
5.3.1 卷積核大小
(Kernel Size): 卷積核的大小定義了卷積的檢視範圍。二維的常見選擇大小是3,即3×3畫素。
5.3.2 卷積核的步長
(Stride): Stride定義了核心的步長。雖然它的預設值通常為1,但我們可以將步長設定為2,然後對類似於MaxPooling的影象進行向下取樣。
5.3.3 邊緣填充
(Padding): Padding用於填充輸入影象的邊界。一個(半)填充的卷積將使空間輸出維度與輸入相等,而如果卷積核大於1,則未被填充的卷積將會使一些邊界消失。
5.3.4 輸入和輸出通道
一個卷積層接受一定數量的輸入通道(I),並計算一個特定數量的輸出通道(O),這一層所需的引數可以由IOK計算,K等於卷積核中值的數量。
5.4 卷積的網路型別分類?
5.4.1 普通卷積
5.4.2 擴張卷積
又名帶洞的(atrous)卷積,擴張的卷積引入了另一個被稱為擴張率(dilation rate)的卷積層。這定義了卷積核中值之間的間隔。一個3×3卷積核的擴張率為2,它的檢視與5×5卷積核相同,而只使用9個引數。想象一下,取一個5×5卷積核,每兩行或兩列刪除一行或一列。
這將以同樣的計算代價提供更廣闊的視角。擴張的卷積在實時分割領域特別受歡迎。如果需要廣泛的檢視,並且不能負擔多個卷積或更大的卷積核,那麼就使用它們。
舉例:
5.4.3 轉置卷積
轉置卷積也就是反捲積(deconvolution)。雖然有些人經常直接叫它反捲積,但嚴格意義上講是不合適的,因為它不符合一個反捲積的概念。反捲積確實存在,但它們在深度學習領域並不常見。一個實際的反捲積會恢復卷積的過程。想象一下,將一個影象放入一個卷積層中。現在把輸出傳遞到一個黑盒子裡,然後你的原始影象會再次出來。這個黑盒子就完成了一個反捲積。這是一個卷積層的數學逆過程。
一個轉置的卷積在某種程度上是相似的,因為它產生的相同的空間解析度是一個假設的反捲積層。然而,在值上執行的實際數學操作是不同的。一個轉置的卷積層執行一個常規的卷積,但是它會恢復它的空間變換(spatial transformation)。
在這一點上,你應該非常困惑,讓我們來看一個具體的例子:
5×5的影象被饋送到一個卷積層。步長設定為2,無邊界填充,而卷積核是3×3。結果得到了2×2的影象。
如果我們想要逆轉這個過程,我們需要反向的數學運算,以便從我們輸入的每個畫素中生成9個值。然後,我們將步長設定為2來遍歷輸出影象。這就是一個反捲積過程。
一個轉置的卷積並不會這樣做。唯一的共同點是,它保證輸出將是一個5×5的影象,同時仍然執行正常的卷積運算。為了實現這一點,我們需要在輸入上執行一些奇特的填充。
正如你現在所能想象的,這一步不會逆轉上面的過程。至少不考慮數值。
它僅僅是重新構造了之前的空間解析度並進行了卷積運算。這可能不是數學上的逆過程,但是對於編碼-解碼器(Encoder-Decoder)架構來說,這仍然是非常有用的。這樣我們就可以把影象的尺度上推(upscaling)和卷積結合起來,而不是做兩個分離的過程。
如果我們想反轉這個過程,我們需要反數學運算,以便從我們輸入的每個畫素中生成9個值。之後,我們以2步幅的設定來遍歷輸出影象。這將是一個反捲積。
5.4.4 可分離卷積
在一個可分離卷積中,我們可以將核心操作拆分成多個步驟。我們用y = conv(x,k)表示卷積,其中y是輸出影象,x是輸入影象,k是核心。這一步很簡單。接下來,我們假設k可以由下面這個等式計算得出:k = k1.dot(k2)。這將使它成為一個可分離的卷積,因為我們可以通過對k1和k2做2個一維卷積來取得相同的結果,而不是用k做二維卷積。
我們以通常用於影象處理的Sobel核心為例。你可以通過乘以向量[1,0,-1]和[1,2,1] .T獲得相同的核心。在執行相同的操作時,你只需要6個而不是9個引數。
上面的示例顯示了所謂的空間可分離卷積,據我所知,這並不是在深度學習中使用的。我只是想確保在他人費勁地操作時,你不會受到如此困惑。在神經網路中,我們通常使用的是一種叫做深度可分離卷積的神經網路。
5.5 圖解12種不同型別的2D卷積?
http://www.sohu.com/a/159591827_390227
5.6 2D卷積與3D卷積有什麼區別?
5.6.1 2D卷積
2D卷積操作如圖所示,為了解釋的更清楚,分別展示了單通道和多通道的操作。且為了畫圖方便,假定只有1個filter,即輸出影象只有一個chanel。
其中,針對單通道,輸入影象的channel為1,卷積核尺寸為 (k_h, k_w, 1),卷積核在輸入影象上的的空間維度(即(height,width)兩維)上進行進行滑窗操作,每次滑窗和 (k_h, k_w) 視窗內的values進行卷積操作(現在都用相關操作取代),得到輸出影象中的一個value。針對多通道,假定輸入影象的channel為3,卷積核尺寸為 (k_h, k_w, 3), 卷積核在輸入影象上的的空間維度(即(h, w)兩維)上進行進行滑窗操作,每次滑窗與3個channels上的 (k_h, k_w) 視窗內的所有的values進行相關操作,得到輸出影象中的一個value。
5.6.2 3D卷積
3D卷積操作如圖2所示,同樣分為單通道和多通道,且只使用一個filter,輸出一個channel。其中,針對單通道,與2D卷積不同之處在於,輸入影象多了一個 length 維度,卷積核也多了一個k_l維度,因此卷積核在輸入3D影象的空間維度(height和widthw維)和length維度上均進行滑窗操作,每次滑窗與 (k_h, k_w, k_l) 視窗內的values進行相關操作,得到輸出3D影象中的一個value.
針對多通道,則與2D卷積的操作一樣,每次滑窗與3個channels上的 (k_h, k_w, k_l) 視窗內的所有values進行相關操作,得到輸出3D影象中的一個value。
5.7 有哪些池化方法?
在卷積神經網路中,我們經常會碰到池化操作,而池化層往往在卷積層後面,通過池化來降低卷積層輸出的特徵向量,同時改善結果(不易出現過擬合)。
為什麼可以通過降低維度呢?
因為影象具有一種“靜態性”的屬性,這也就意味著在一個影象區域有用的特徵極有可能在另一個區域同樣適用。因此,為了描述大的影象,一個很自然的想法就是對不同位置的特徵進行聚合統計,例如,人們可以計算影象一個區域上的某個特定特徵的平均值 (或最大值)來代表這個區域的特徵。[1]
5.7.1 一般池化(General Pooling)
池化作用於影象中不重合的區域(這與卷積操作不同),過程如下圖。
我們定義池化視窗的大小為sizeX,即下圖中紅色正方形的邊長,定義兩個相鄰池化視窗的水平位移/豎直位移為stride。一般池化由於每一池化視窗都是不重複的,所以sizeX=stride。
最常見的池化操作為平均池化mean pooling和最大池化max pooling:
- 平均池化:計算影象區域的平均值作為該區域池化後的值。
- 最大池化:選影象區域的最大值作為該區域池化後的值。
5.7.2 重疊池化(General Pooling)
重疊池化正如其名字所說的,相鄰池化視窗之間會有重疊區域,此時sizeX>stride。論文中[2]中,作者使用了重疊池化,其他的設定都不變的情況下, top-1和top-5 的錯誤率分別減少了0.4% 和0.3%。
5.7.3 空金字塔池化(Spatial Pyramid Pooling)
空間金字塔池化可以把任何尺度的影象的卷積特徵轉化成相同維度,這不僅可以讓CNN處理任意尺度的影象,還能避免cropping和warping操作,導致一些資訊的丟失,具有非常重要的意義。
一般的CNN都需要輸入影象的大小是固定的,這是因為全連線層的輸入需要固定輸入維度,但在卷積操作是沒有對影象尺度有限制,所有作者提出了空間金字塔池化,先讓影象進行卷積操作,然後轉化成維度相同的特徵輸入到全連線層,這個可以把CNN擴充套件到任意大小的影象。
空間金字塔池化的思想來自於Spatial Pyramid Model,它一個pooling變成了多個scale的pooling。用不同大小池化視窗作用於卷積特徵,我們可以得到1X1,2X2,4X4的池化結果,由於conv5中共有256個過濾器,所以得到1個256維的特徵,4個256個特徵,以及16個256維的特徵,然後把這21個256維特徵連結起來輸入全連線層,通過這種方式把不同大小的影象轉化成相同維度的特徵。
對於不同的影象要得到相同大小的pooling結果,就需要根據影象的大小動態的計算池化視窗的大小和步長。假設conv5輸出的大小為aa,需要得到nn大小的池化結果,可以讓視窗大小sizeX為[a/n],步長為[a/n]。下圖以conv5輸出的大小為13*13為例。
疑問:如果conv5輸出的大小為1414,[pool11]的sizeX=stride=14,[pool22]的sizeX=stride=7,這些都沒有問題,但是,[pool44]的sizeX=5,stride=4,最後一列和最後一行特徵沒有被池化操作計算在內。
SPP其實就是一種多個scale的pooling,可以獲取影象中的多尺度資訊;在CNN中加入SPP後,可以讓CNN處理任意大小的輸入,這讓模型變得更加的flexible。
5.8 1x1卷積作用?
1×1的卷積大概有兩個方面的作用:
- 實現跨通道的互動和資訊整合。
- 進行卷積核通道數的降維和升維。
下面詳細解釋一下:
-
1×1的卷積層(可能)引起人們的重視是在NIN的結構中,論文中林敏師兄的想法是利用MLP代替傳統的線性卷積核,從而提高網路的表達能力。文中同時利用了跨通道pooling的角度解釋,認為文中提出的MLP其實等價於在傳統卷積核後面接cccp層,從而實現多個feature map的線性組合,實現跨通道的資訊整合。而cccp層是等價於1×1卷積的,因此細看NIN的caffe實現,就是在每個傳統卷積層後面接了兩個cccp層(其實就是接了兩個1×1的卷積層)。
-
進行降維和升維引起人們重視的(可能)是在GoogLeNet裡。對於每一個Inception模組(如下圖),原始模組是左圖,右圖中是加入了1×1卷積進行降維的。雖然左圖的卷積核都比較小,但是當輸入和輸出的通道數很大時,乘起來也會使得卷積核引數變的很大,而右圖加入1×1卷積後可以降低輸入的通道數,卷積核引數、運算複雜度也就跟著降下來了。以GoogLeNet的3a模組為例,輸入的feature map是28×28×192,3a模組中1×1卷積通道為64,3×3卷積通道為128,5×5卷積通道為32,如果是左圖結構,那麼卷積核引數為1×1×192×64+3×3×192×128+5×5×192×32,而右圖對3×3和5×5卷積層前分別加入了通道數為96和16的1×1卷積層,這樣卷積核引數就變成了1×1×192×64+(1×1×192×96+3×3×96×128)+(1×1×192×16+5×5×16×32),引數大約減少到原來的三分之一。同時在並行pooling層後面加入1×1卷積層後也可以降低輸出的feature map數量,左圖pooling後feature map是不變的,再加捲積層得到的feature map,會使輸出的feature map擴大到416,如果每個模組都這樣,網路的輸出會越來越大。而右圖在pooling後面加了通道為32的1×1卷積,使得輸出的feature map數降到了256。GoogLeNet利用1×1的卷積降維後,得到了更為緊湊的網路結構,雖然總共有22層,但是引數數量卻只是8層的AlexNet的十二分之一(當然也有很大一部分原因是去掉了全連線層)。
最近大熱的MSRA的ResNet同樣也利用了1×1卷積,並且是在3×3卷積層的前後都使用了,不僅進行了降維,還進行了升維,使得卷積層的輸入和輸出的通道數都減小,引數數量進一步減少,如下圖的結構。(不然真不敢想象152層的網路要怎麼跑起來TAT)
5.9 卷積層和池化層有什麼區別?
首先可以從結構上可以看出,卷積之後輸出層的維度減小,深度變深。但池化層深度不變。同時池化可以把很多資料用最大值或者平均值代替。目的是降低資料量。降低訓練的引數。對於輸入層,當其中畫素在鄰域發生微小位移時,池化層的輸出是不變的,從而能提升魯棒性。而卷積則是把資料通過一個卷積核變化成特徵,便於後面的分離。
1:卷積
當從一個大尺寸影象中隨機選取一小塊,比如說 8x8 作為樣本,並且從這個小塊樣本中學習到了一些特徵,這時我們可以把從這個 8x8 樣本中學習到的特徵作為探測器,應用到這個影象的任意地方中去。特別是,我們可以用從 8x8 樣本中所學習到的特徵跟原本的大尺寸影象作卷積,從而對這個大尺寸影象上的任一位置獲得一個不同特徵的啟用值。
下面給出一個具體的例子:假設你已經從一個 96x96 的影象中學習到了它的一個 8x8 的樣本所具有的特徵,假設這是由有 100 個隱含單元的自編碼完成的。為了得到卷積特徵,需要對 96x96 的影象的每個 8x8 的小塊影象區域都進行卷積運算。也就是說,抽取 8x8 的小塊區域,並且從起始座標開始依次標記為(1,1),(1,2),…,一直到(89,89),然後對抽取的區域逐個執行訓練過的稀疏自編碼來得到特徵的啟用值。在這個例子裡,顯然可以得到 100 個集合,每個集合含有 89x89 個卷積特徵。
2:說下池化,其實池化很容易理解,先看圖:
轉自: http://blog.csdn.net/silence1214/article/details/11809947
比如上方左側矩陣A是2020的矩陣要進行大小為1010的池化,那麼左側圖中的紅色就是10*10的大小,對應到右側的矩陣,右側每個元素的值,是左側紅色矩陣每個元素的值得和再處於紅色矩陣的元素個數,也就是平均值形式的池化。
3:上面說了下卷積和池化,再說下計算中需要注意到的。在程式碼中使用的是彩色圖,彩色圖有3個通道,那麼對於每一個通道來說要單獨進行卷積和池化,有一個地方尤其是進行卷積的時候要注意到,隱藏層的每一個值是對應到一幅圖的3個通道穿起來的,所以分3個通道進行卷積之後要加起來,正好才能對應到一個隱藏層的神經元上,也就是一個feature上去。
5.10 卷積核一定越大越好?
AlexNet中用到了一些非常大的卷積核,比如11×11、5×5卷積核,之前人們的觀念是,卷積核越大,receptive field(感受野)越大,看到的圖片資訊越多,因此獲得的特徵越好。雖說如此,但是大的卷積核會導致計算量的暴增,不利於模型深度的增加,計算效能也會降低。於是在VGG(最早使用)、Inception網路中,利用2個3×3卷積核的組合比1個5×5卷積核的效果更佳,同時引數量(3×3×2+1 VS 5×5×1+1) 被降低,因此後來3×3卷積核被廣泛應用在各種模型中。多個小的卷積核疊加使用要遠比一個大的卷積核單獨使用效果要好的多,在連通性不變的情況下,大大降低了引數個數和計算複雜度。當然,卷積核也不是越小越好,對於特別稀疏的資料比如下圖所示,當使用比較小的卷積核的時候可能無法表示其特徵,如果採用較大的卷積核則會導致複雜度極大的增加。總而言之,我們應該選擇多個相對小的卷積核來進行卷積。
5.11 每層卷積只能用一種尺寸的卷積核?
傳統的層疊式網路,基本上都是一個個卷積層的堆疊,每層只用一個尺寸的卷積核,例如VGG結構中使用了大量的3×3卷積層。事實上,同一層feature map可以分別使用多個不同尺寸的卷積核,以獲得不同尺度的特徵,再把這些特徵結合起來,得到的特徵往往比使用單一卷積核的要好,谷歌的GoogLeNet,或者說Inception系列的網路,就使用了多個卷積核的結構:
如上圖所示,一個輸入的feature map 分別同時經過1×1、3×3、5×5的卷積核的處理,得出的特徵再組合起來,獲得更佳的特徵。
5.12 怎樣才能減少卷積層引數量?
發明GoogleNet的團隊發現,如果僅僅引入多個尺寸的卷積核,會帶來大量的額外的引數,受到Network In Network中1×1卷積核的啟發,為了解決這個問題,他們往Inception結構中加入了一些1×1的卷積核,如圖所示:
加入1×1卷積核的Inception結構
根據上圖,我們來做個對比計算,假設輸入feature map的維度為256維,要求輸出維度也是256維。有以下兩種操作:
- (1)256維的輸入直接經過一個3×3×256的卷積層,輸出一個256維的feature map,那麼引數量為:256×3×3×256 = 589,824
- (2)256維的輸入先經過一個1×1×64的卷積層,再經過一個3×3×64的卷積層,最後經過一個1×1×256的卷積層,輸出256維,引數量為:256×1×1×64 + 64×3×3×64 + 64×1×1×256 = 69,632。足足把第一種操作的引數量降低到九分之一!
1×1卷積核也被認為是影響深遠的操作,往後大型的網路為了降低引數量都會應用上1×1卷積核。
5.13 卷積操作時必須同時考慮通道和區域嗎?
標準的卷積過程可以看上圖,一個2×2的卷積核在卷積時,對應影象區域中的所有通道均被同時考慮,問題在於,為什麼一定要同時考慮影象區域和通道?我們為什麼不能把通道和空間區域分開考慮?
Xception網路就是基於以上的問題發明而來。我們首先對每一個通道進行各自的卷積操作,有多少個通道就有多少個過濾器。得到新的通道feature maps之後,這時再對這批新的通道feature maps進行標準的1×1跨通道卷積操作。這種操作被稱為 “DepthWise convolution” ,縮寫“DW”。
這種操作是相當有效的,在imagenet 1000類分類任務中已經超過了InceptionV3的表現,而且也同時減少了大量的引數,我們來算一算,假設輸入通道數為3,要求輸出通道數為256,兩種做法:
- 直接接一個3×3×256的卷積核,引數量為:3×3×3×256 = 6,912
- DW操作,分兩步完成,引數量為:3×3×3 + 3×1×1×256 = 795,又把引數量降低到九分之一!
因此,一個depthwise操作比標準的卷積操作降低不少的引數量,同時論文中指出這個模型得到了更好的分類效果。
5.14 採用寬卷積的好處有什麼?
5.14.1 窄卷積和寬卷積
對於窄卷積來說,是從第一個點開始做卷積,每次視窗滑動固定步幅。比如下圖左部分為窄卷積。那麼注意到越在邊緣的位置被卷積的次數越少。於是有了寬卷積的方法,可以看作在卷積之前在邊緣用0補充,常見有兩種情況,一個是全補充,入下圖右部分,這樣輸出大於輸入的維度。另一種常用的方法是補充一部0值,使得輸出和輸入的維度一致。這裡文中給了一個公式 。這裡npadding在全補充裡是filter-1,在輸入輸出相等時,就要主要奇偶性了,注意到卷積核常為奇數。
5.14.2 為什麼採用寬卷積?
通過將輸入邊角的值納入到滑窗中心進行計算,以便損失更少的資訊。
5.15 卷積層輸出的深度與哪個部件的個數相同?
輸出深度(通道)與卷積核(過濾器)的個數相等。
5.16 如何得到卷積層輸出的深度?
引數共享:在卷積層中使用引數共享是用來控制引數的數量。假設在第一個卷積層就有55x55x96=290,400個神經元,每個有11x11x3=364個引數和1個偏差。將這些合起來就是290400x364=105,705,600個引數。單單第一層就有這麼多引數,顯然這個數目是非常大的。
作一個合理的假設:如果一個特徵在計算某個空間位置(x,y)的時候有用,那麼它在計算另一個不同位置(x2,y2)的時候也有用。基於這個假設,可以顯著地減少引數數量。換言之,就是將深度維度上一個單獨的2維切片看做深度切片(depth slice),比如一個數據體尺寸為[55x55x96]的就有96個深度切片,每個尺寸為[55x55]。在每個深度切片上的神經元都使用同樣的權重和偏差。在這樣的引數共享下,例子中的第一個卷積層就只有96個不同的權重集了,一個權重集對應一個深度切片,共有96x11x11x3=34,848個不同的權重,或34,944個引數(+96個偏差)。
w_conv1=weight_variable([5,5,1,32])
可以看出,上面的32表示的是卷積層輸出的深度,因為大家都明白width和height都可以通過公式計算得到,但是很多文獻都沒有告訴深度是如何得到的,下面是我的認識:
- 因為這個深度是沒有公式可以計算出來的,因為深度是一個經驗值,如上面程式碼的32 ,其實是一個經驗值,是通過調整引數發現32是一個最合適的值,可以得到最好的準確率,但是不同的影象的深度是不一樣的。
- 這個深度表示用了多少個卷積核,下面這個圖可以說明一下:
上圖就可以很有效的說明 :卷積層輸出的深度==卷積核的個數。
5.17 啟用函式通常放在卷積神經網路的那個操作之後?
通常放在卷積層之後。
5.18 如何理解最大池化層有幾分縮小?
池化層:對輸入的特徵圖進行壓縮,一方面使特徵圖變小,簡化網路計算複雜度;一方面進行特徵壓縮,提取主要特徵。
池化操作一般有兩種,一種是Avy Pooling,一種是max Pooling。
同樣地採用一個2*2的filter,max pooling是在每一個區域中尋找最大值,這裡的stride=2,最終在原特徵圖中提取主要特徵得到右圖。
注1:(Avy pooling現在不怎麼用了,方法是對每一個22的區域元素求和,再除以4,得到主要特徵),而一般的filter取22,最大取3*3,stride取2,壓縮為原來的1/4.
注2:這裡的pooling操作是特徵圖縮小,有可能影響網路的準確度,因此可以通過增加特徵圖的深度來彌補。
5.19 理解影象卷積與反捲積
5.19.1 影象卷積
首先給出一個輸入輸出結果
那他是怎樣計算的呢?
卷積的時候需要對卷積核進行180的旋轉,同時卷積核中心與需計算的影象畫素對齊,輸出結構為中心對齊畫素的一個新的畫素值,計算例子如下:
這樣計算出左上角(即第一行第一列)畫素的卷積後像素值。
給出一個更直觀的例子,從左到右看,原畫素經過卷積由1變成-8。
通過滑動卷積核,就可以得到整張圖片的卷積結果
5.19.2 影象反捲積
這裡提到的反捲積跟1維訊號處理的反捲積計算是很不一樣的,FCN作者稱為backwards convolution,有人稱Deconvolution layer is a very unfortunate name and should rather be called a transposed convolutional layer. 我們可以知道,在CNN中有con layer與pool layer,con layer進行對影象卷積提取特徵,pool layer 對影象縮小一半篩選重要特徵,對於經典的影象識別CNN網路,如IMAGENET,最後輸出結果是1X1X1000,1000是類別種類,1x1得到的是。FCN作者,或者後來對end to end研究的人員,就是對最終1x1的結果使用反捲積(事實上FCN作者最後的輸出不是1X1,是圖片大小的32分之一,但不影響反捲積的使用)。
這裡影象的反捲積與full卷積原理是一樣的,使用了這一種反捲積手段使得影象可以變大,FCN作者使用的方法是這裡所說反捲積的一種變體,這樣就可以獲得相應的畫素值,影象可以實現end to end。
這裡說另外一種反捲積做法,假設原圖是33,首先使用上取樣讓影象變成77,可以看到影象多了很多空白的畫素點。使用一個33的卷積核對影象進行滑動步長為1的valid卷積,得到一個55的影象,我們知道的是使用上取樣擴大圖片,使用反捲積填充影象內容,使得影象內容變得豐富,這也是CNN輸出end to end結果的一種方法。韓國作者Hyeonwoo Noh使用VGG16層CNN網路後面加上對稱的16層反捲積與上取樣網路實現end to end 輸出,其不同層上取樣與反捲積變化效果如下:
經過上面的解釋與推導,對卷積有基本的瞭解,但是在影象上的deconvolution究竟是怎麼一回事,可能還是不能夠很好的理解,因此這裡再對這個過程解釋一下。 目前使用得最多的deconvolution有2種,上文都已經介紹。
- 方法1:full卷積, 完整的卷積可以使得原來的定義域變大。
- 方法2:記錄pooling index,然後擴大空間,再用卷積填充。
影象的deconvolution過程如下:
輸入:2x2, 卷積核:4x4, 滑動步長:3, 輸出:7x7
即輸入為2x2的圖片經過4x4的卷積核進行步長為3的反捲積的過程
- 輸入圖片每個畫素進行一次full卷積,根據full卷積大小計算可以知道每個畫素的卷積後大小為 1+4-1=4, 即4x4大小的特徵圖,輸入有4個畫素所以4個4x4的特徵圖
- 將4個特徵圖進行步長為3的fusion(即相加); 例如紅色的特徵圖仍然是在原來輸入位置(左上角),綠色還是在原來的位置(右上角),步長為3是指每隔3個畫素進行fusion,重疊部分進行相加,即輸出的第1行第4列是由紅色特陣圖的第一行第四列與綠色特徵圖的第一行第一列相加得到,其他如此類推。
可以看出翻卷積的大小是由卷積核大小與滑動步長決定, in是輸入大小, k是卷積核大小, s是滑動步長, out是輸出大小 得到 out = (in - 1) * s + k 上圖過程就是, (2 - 1) * 3 + 4 = 7
5.20 不同卷積後圖像大小計算?
5.20.1 型別劃分
2維卷積的計算分為了3類:1.full 2.same 3. valid
1、full
藍色為原影象,白色為對應卷積所增加的padding,通常全部為0,綠色是卷積後圖片。圖6的卷積的滑動是從卷積核右下角與圖片左上角重疊開始進行卷積,滑動步長為1,卷積核的中心元素對應卷積後圖像的畫素點。可以看到卷積後的影象是4X4,比原圖2X2大了,我們還記1維卷積大小是n1+n2-1,這裡原圖是2X2,卷積核3X3,卷積後結果是4X4,與一維完全對應起來了。其實這才是完整的卷積計算,其他比它小的卷積結果都是省去了部分畫素的卷積
2、same
3、valid
5.20.2 計算公式
這裡,我們可以總結出full,same,valid三種卷積後圖像大小的計算公式:
- full: 滑動步長為1,圖片大小為N1xN1,卷積核大小為N2xN2,卷積後圖像大小:N1+N2-1 x N1+N2-1。
- same: 滑動步長為1,圖片大小為N1xN1,卷積核大小為N2xN2,卷積後圖像大小:N1xN1。
- valid:滑動步長為S,圖片大小為N1xN1,卷積核大小為N2xN2,卷積後圖像大小:(N1-N2)/S+1 x (N1-N2)/S+1。
5.21 步長、填充大小與輸入輸出關係總結?
在設計深度學習網路的時候,需要計算輸入尺寸和輸出尺寸,那麼就要設計卷積層的的各種引數。這裡有一些設計時候的計算公式,方便得到各層的引數。
這裡簡化下,約定:
5.21.1 沒有0填充,單位步長
5.21.2 零填充,單位步長
<1>半填充
<2>全填充
參考圖如下圖所示
5.21.3 不填充,非單位步長
5.21.4 零填充,非單位步長
http://blog.csdn.net/u011692048/article/details/77572024
https://arxiv.org/pdf/1603.07285.pdf
5.22 理解反捲積和棋盤效應
5.22.1 為什麼出現棋盤現象?
影象生成網路的上取樣部分通常用反捲積網路,不合理的卷積核大小和步長會使反捲積操作產生棋盤效應 (checkerboard artifacts)。
重疊圖案也在二維中形成。兩個軸上的不均勻重疊相乘,產生不同亮度的棋盤狀圖案。
事實上,不均勻重疊往往在二維上更極端!因為兩個模式相乘,所以它的不均勻性是原來的平方。例如,在一個維度中,一個步長為2,大小為3的反捲積的輸出是其輸入的兩倍,但在二維中,輸出是輸入的4倍。
現在,生成影象時,神經網路通常使用多層反捲積,從一系列較低解析度的描述中迭代建立更大的影象。雖然這些堆疊的反捲積可以消除棋盤效應,但它們經常混合,在更多尺度上產生棋盤效應。
直觀地看,假設生成的影象中包含1只黑貓。黑貓身體部分的畫素顏色應平滑過渡,或極端地說,該部分應全為黑色。實際生成的影象中該部分卻有深深淺淺的近黑方塊組成,很像棋盤的網格,即棋盤效應。
https://distill.pub/2016/deconv-checkerboard/
http://blog.csdn.net/shadow_guo/article/details/52862161
5.22.2 有哪些方法可以避免棋盤效應?
(1)第一種方法是用到的反捲積核的大小可被步長整除,從而避免重疊效應。與最近成功用於影象超解析度的技術“子畫素卷積”(sub-pixel convolution)等價。
(2)另一種方法是從卷積操作中分離出對卷積後更高解析度的特徵圖上取樣來計算特徵。例如,可以先縮放影象(最近鄰插值或雙線性插值),再卷積。
反捲積與不同縮放卷積方法都是線性操作,並可用矩陣去解釋。對於每個輸出視窗,反捲積操作的輸入唯一,縮放卷積會以阻礙高頻棋盤效應的方式來隱式地集中權重(weight-tying)。
縮放卷積
縮放卷積為線性操作:假設原影象為A,經過插值後的影象為A+B;用卷積核C對插值縮放後的影象卷積,得到最終的影象 ,其中*為卷積操作。則可將縮放卷積分解為原影象卷積和插值增量影象卷積,或卷積的原影象和卷積的插值增量影象。
C為卷積操作的卷積核。此時為上取樣,理解為反捲積操作中的卷積核。
(1)最近鄰縮放卷積
發現,插值增量影象表示的矩陣為原影象表示的矩陣下移1行。可將原影象矩陣看成環形佇列(佇列最後1行的輸出送入佇列的第1行)。
(2)雙線性縮放卷積
發現,插值增量影象可細分為原影象表示的矩陣下移1行後乘以1/2與原影象表示的矩陣上移1行後乘以1/2。
5.23 CNN主要的計算瓶頸
CNN的訓練主要是在卷積層和子取樣層的互動上,其主要的計算瓶頸是:
- 1)前向傳播過程:下采樣每個卷積層的maps;
- 2)反向傳播過程:上取樣高層子取樣層的靈敏度map,以匹配底層的卷積層輸出maps的大小;
- 3)sigmoid的運用和求導。
舉例:
對於第一和第二個問題,我們考慮的是如何用Matlab內建的影象處理函式去實現上取樣和下采樣的操作。對於上取樣,imresize函式可以搞定,但需要很大的開銷。一個比較快速的版本是使用Kronecker乘積函式kron。通過一個全一矩陣ones來和我們需要上取樣的矩陣進行Kronecker乘積,就可以實現上取樣的效果。對於前向傳播過程中的下采樣,imresize並沒有提供在縮小影象的過程中還計算nxn塊內畫素的和的功能,所以沒法用。一個比較好和快速的方法是用一個全一的卷積核來卷積影象,然後簡單的通過標準的索引方法來取樣最後卷積結果。例如,如果下采樣的域是2x2的,那麼我們可以用2x2的元素全是1的卷積核來卷積影象。然後再卷積後的影象中,我們每個2個點採集一次資料,y=x(1:2:end,1:2:end),這樣就可以得到了兩倍下采樣,同時執行求和的效果。
對於第三個問題,實際上有些人以為Matlab中對sigmoid函式進行inline的定義會更快,其實不然,Matlab與C/C++等等語言不一樣,Matlab的inline反而比普通的函式定義更非時間。所以,我們可以直接在程式碼中使用計算sigmoid函式及其導數的真實程式碼。
5.24 CNN的引數經驗設定
對於卷積神經網路的引數設定,沒有很明確的方法,這只是眾多學者的一些經驗。
1、learning-rate 學習速率:學習速率越小,模型收斂花費的時間就越長,但是可以提高模型精確度。一般初始設定為0.1,然後每次除以0.2或者0.5來改進,得到最終值;
2、batch-size 樣本批次容量:影響模型的優化程度和收斂速度,需要參考你的資料集大小來設定,具體問題具體分析;
3、weight-decay 權重衰減:用來在反向傳播中更新權重和偏置,一般設定為0.005;
4、epoch-number 訓練次數:包括所有訓練樣本的一個正向傳遞和一個反向傳遞,訓練至模型收斂即可;(注:和迭代週期iteration不一樣)
而且,也不是說訓練的次數越多,測試精度就會越高,可能會因為預訓練的模型太複雜,而我的資料集樣本數量太少,種類太單一,而出現過擬合。
5.25 提高泛化能力的方法總結
http://blog.csdn.net/u010900574/article/details/51992156
5.25.1 主要方法
一般來說,提高泛化能力的方法主要有以下幾個:
- 正則化
- 增加神經網路層數
- 使用正確的代價函式
- 使用好的權重初始化技術
- 人為拓展訓練集
- 棄權技術
5.25.2 主要方法
下面我們通過實驗結果給這些引數優化理論一個直觀的結果
(1)普通的全連線神經網路的效果
我們使用一個隱藏層,包含100個隱藏神經元,輸入層是784,輸出層是one-hot編碼的形式,最後一層是Softmax層。訓練過程採用對數似然代價函式,60次迭代,學習速率η=0.1,隨機梯度下降的小批量資料大小為10,沒有正則化。在測試集上得到的結果是97.8%,程式碼如下:
>>> import network3
>>> from network3 import Network
>>> from network3 import ConvPoolLayer, FullyConnectedLayer, SoftmaxLayer
>>> training_data, validation_data, test_data = network3.load_data_shared()
>>> mini_batch_size = 10
>>> net = Network([FullyConnectedLayer(n_in=784, n_out=100),
SoftmaxLayer(n_in=100, n_out=10)], mini_batch_size)
>>> net.SGD(training_data, 60, mini_batch_size, 0.1, validation_data, test_data)
(2)使用卷積神經網路 — 僅一個卷積層
輸入層是卷積層,55的區域性感受野,也就是一個55的卷積核,一共20個特徵對映。最大池化層選用2*2的大小。後面是100個隱藏神經元的全連線層。結構如圖所示
在這個架構中,我們把卷積層和chihua層看做是學習輸入訓練影象中的區域性感受野,而後的全連線層則是一個更抽象層次的學習,從整個影象整合全域性資訊。也是60次迭代,批量資料大小是10,學習率是0.1.程式碼如下。
>>> net = Network([
ConvPoolLayer(image_shape=(mini_batch_size, 1, 28, 28),
filter_shape=(20, 1, 5, 5),
poolsize=(2, 2)),
FullyConnectedLayer(n_in=20*12*12, n_out=100),
SoftmaxLayer(n_in=100, n_out=10)], mini_batch_size)
>>> net.SGD(training_data, 60, mini_batch_size, 0.1,
validation_data, test_data)
經過三次執行取平均後,準確率是98.78%,這是相當大的改善。錯誤率降低了1/3,。卷積神經網路開始顯現威力。
(3)使用卷積神經網路 — 兩個卷積層
我們接著插入第二個卷積-混合層,把它插入在之前的卷積-混合層和全連線層之間,同樣的55的區域性感受野,22的池化層。
>>> net = Network([
ConvPoolLayer(image_shape=(mini_batch_size, 1, 28, 28),
filter_shape=(20, 1, 5, 5),
poolsize=(2, 2)),
ConvPoolLayer(image_shape=(mini_batch_size, 20, 12, 12),
filter_shape=(40, 20, 5, 5),
poolsize=(2, 2)),
FullyConnectedLayer(n_in=40*4*4, n_out=100),
SoftmaxLayer(n_in=100, n_out=10)], mini_batch_size)
>>> net.SGD(training_data, 60, mini_batch_size, 0.1, validation_data, test_data)
這一次,我們擁有了99.06%的準確率。
(4)使用卷積神經網路 — 兩個卷積層+線性修正單元(ReLU)+正則化
上面我們使用的Sigmod啟用函式,現在我們換成線性修正啟用函式ReLU ,f(z)=max(0,z)f(z)=max(0,z),我們選擇60個迭代期,學習速率η=0.03,η=0.03, ,使用L2正則化,正則化引數λ=0.1λ=0.1,程式碼如下:
>>> from network3 import ReLU
>>> net = Network([
ConvPoolLayer(image_shape=(mini_batch_size, 1, 28, 28),
filter_shape=(20, 1, 5, 5),
poolsize=(2, 2),
activation_fn=ReLU),
ConvPoolLayer(image_shape=(mini_batch_size, 20, 12, 12),
filter_shape=(40, 20, 5, 5),
poolsize=(2, 2),
activation_fn=ReLU),
FullyConnectedLayer(n_in=40*4*4, n_out=100, activation_fn=ReLU),
SoftmaxLayer(n_in=100, n_out=10)], mini_batch_size)
>>> net.SGD(training_data, 60, mini_batch_size, 0.03,
validation_data, test_data, lmbda=0.1)
這一次,我們獲得了99.23%的準確率,超過了S型啟用函式的99.06%. ReLU的優勢是max(0,z)max(0,z)中z取最大極限時不會飽和,不像是S函式,這有助於持續學習。
(5)使用卷積神經網路,即兩個卷基層+線性修正單元(ReLU)+正則化+拓展資料集
拓展訓練集資料的一個簡單方法是將每個訓練影象由一個畫素來代替,無論是上一個畫素,下一個畫素,或者左右的畫素。其他的方法也有改變亮度,改變解析度,圖片旋轉,扭曲,位移等。我們把50,000幅影象人為拓展到250,000幅影象。使用第4節一樣的網路,因為我們是在訓練5倍的資料,所以減少了過擬合的風險。
>>> expanded_training_data, _, _ = network3.load_data_shared(
"../data/mnis