1. 程式人生 > >深度學習:卷積神經網路CNN入門

深度學習:卷積神經網路CNN入門

該文是,並假設你理解前饋神經網路。

目錄

  • 視覺感知
    • 畫面識別是什麼
    • 識別結果取決於什麼
  • 影象表達
    • 畫面識別的輸入
    • 畫面不變形
  • 前饋神經網路做畫面識別的不足
  • 卷積神經網路做畫面識別
    • 區域性連線
    • 空間共享
    • 輸出空間表達
    • Depth維的處理
    • Zero padding
    • 形狀、概念抓取
    • 多filters
    • 非線性
    • 輸出尺寸控制
    • 矩陣乘法執行卷積
    • Max pooling
    • 全連線層
    • 結構發展
  • 畫面不變性的滿足
    • 平移不變性
    • 旋轉和視角不變性
    • 尺寸不變性
    • Inception的理解
    • 1x1卷積核理解
    • 跳層連線ResNet

視覺感知

一、畫面識別是什麼任務?

學習知識的第一步就是明確任務,清楚該知識的輸入輸出。卷積神經網路最初是服務於畫面識別的,所以我們先來看看畫面識別的實質是什麼。

先觀看幾組動物與人類視覺的差異對比圖。

1. 蒼蠅的視覺和人的視覺的差異

<img src="https://pic2.zhimg.com/50/v2-55069445ed54ce163b76c611ba26b639_hd.jpg" data-caption="" data-rawwidth="384" data-rawheight="216" class="content_image" width="384">
<img src="https://pic2.zhimg.com/50/v2-4a0ea7ba42166b62bc4f42e8b150815d_hd.png" data-caption="" data-rawwidth="1280" data-rawheight="479" class="origin_image zh-lightbox-thumb" width="1280" data-original="https://pic2.zhimg.com/v2-4a0ea7ba42166b62bc4f42e8b150815d_r.png">

2. 蛇的視覺和人的視覺的差異

<img src="https://pic2.zhimg.com/50/v2-a4d35c245931f264ed9a0716fdf20685_hd.jpg" data-caption="" data-rawwidth="384" data-rawheight="216" class="content_image" width="384"><img src="https://pic4.zhimg.com/50/v2-3da84b5b80ba7a0d779284566f80be93_hd.png" data-caption="" data-rawwidth="1280" data-rawheight="479" class="origin_image zh-lightbox-thumb" width="1280" data-original="https://pic4.zhimg.com/v2-3da84b5b80ba7a0d779284566f80be93_r.png">

(更多對比圖請參考連結

通過上面的兩組對比圖可以知道,即便是相同的圖片經過不同的視覺系統,也會得到不同的感知。

這裡引出一條知識:生物所看到的景象並非世界的原貌,而是長期進化出來的適合自己生存環境的一種感知方式。 蛇的獵物一般是夜間行動,所以它就進化出了一種可以在夜間也能很好觀察的感知系統,感熱。

任何視覺系統都是將影象反光與腦中所看到的概念進行關聯。

<img src="https://pic4.zhimg.com/50/v2-2c82abd20c4e7c40f7f13f035b924b0b_hd.png" data-caption="" data-rawwidth="223" data-rawheight="97" class="content_image" width="223">

所以畫面識別實際上並非識別這個東西客觀上是什麼,而是尋找人類的視覺關聯方式,並再次應用。 如果我們不是人類,而是蛇類,那麼畫面識別所尋找的 就和現在的不一樣。

畫面識別實際上是尋找(學習)人類的視覺關聯方式 ,並再次應用

二、圖片被識別成什麼取決於哪些因素?

下面用兩張圖片來體會識別結果取決於哪些因素。

1. 老婦與少女

<img src="https://pic4.zhimg.com/50/v2-c902a9e33b0322051a5f9165e9439247_hd.jpg" data-caption="" data-rawwidth="198" data-rawheight="255" class="content_image" width="198">

請觀察上面這張圖片,你看到的是老婦還是少女? 以不同的方式去觀察這張圖片會得出不同的答案。 圖片可以觀察成有大鼻子、大眼睛的老婦。也可以被觀察成少女,但這時老婦的嘴會被識別成少女脖子上的項鍊,而老婦的眼睛則被識別為少女的耳朵。

2. 海豚與男女

<img src="https://pic3.zhimg.com/50/v2-7e5bc60a9e9bd0b597e4b650fecc439e_hd.jpg" data-caption="" data-rawwidth="394" data-rawheight="509" class="content_image" width="394">

上面這張圖片如果是成人觀察,多半看到的會是一對親熱的男女。倘若兒童看到這張圖片,看到的則會是一群海豚(男女的輪廓是由海豚構造出的)。所以,識別結果受年齡,文化等因素的影響,換句話說:

圖片被識別成什麼不僅僅取決於圖片本身,還取決於圖片是如何被觀察的。

影象表達

我們知道了“畫面識別是從大量的(x,y)資料中尋找人類的視覺關聯方式 ,並再次應用。 其x-是輸入,表示所看到的東西y-輸出,表示該東西是什麼。

在自然界中,x是物體的反光,那麼在計算機中,影象又是如何被表達和儲存的呢?

<img src="https://pic2.zhimg.com/50/v2-d2859e5c486ed704492ab80079e99535_hd.gif" data-caption="" data-rawwidth="291" data-rawheight="290" data-thumbnail="https://pic2.zhimg.com/50/v2-d2859e5c486ed704492ab80079e99535_hd.jpg" class="content_image" width="291">

[from]

影象在計算機中是一堆按順序排列的數字,數值為0到255。0表示最暗,255表示最亮。 你可以把這堆數字用一個長長的向量來表示,也就是tensorflow的mnist教程中784維向量的表示方式。 然而這樣會失去平面結構的資訊,為保留該結構資訊,通常選擇矩陣的表示方式:28x28的矩陣。

上圖是隻有黑白顏色的灰度圖,而更普遍的圖片表達方式是RGB顏色模型,即紅(Red)、綠(Green)、藍(Blue)三原色的色光以不同的比例相加,以產生多種多樣的色光。

這樣,RGB顏色模型中,單個矩陣就擴充套件成了有序排列的三個矩陣,也可以用三維張量去理解,其中的每一個矩陣又叫這個圖片的一個channel。

在電腦中,一張圖片是數字構成的“長方體”。可用 寬width, 高height, 深depth 來描述,如圖。

<img src="https://pic1.zhimg.com/50/v2-0d24890b2e0d73f4ce4ad17ebfb2d0c4_hd.png" data-caption="" data-rawwidth="305" data-rawheight="252" class="content_image" width="305">
畫面識別的輸入x是shape為(width, height, depth)的三維張量。

接下來要考慮的就是該如何處理這樣的“數字長方體”。

畫面不變性

在決定如何處理“數字長方體”之前,需要清楚所建立的網路擁有什麼樣的特點。 我們知道一個物體不管在畫面左側還是右側,都會被識別為同一物體,這一特點就是不變性(invariance),如下圖所示。

<img src="https://pic3.zhimg.com/50/v2-b9aed3dd68b9818561faa7d8ed24ea5a_hd.png" data-caption="" data-rawwidth="567" data-rawheight="769" class="origin_image zh-lightbox-thumb" width="567" data-original="https://pic3.zhimg.com/v2-b9aed3dd68b9818561faa7d8ed24ea5a_r.png">

我們希望所建立的網路可以儘可能的滿足這些不變性特點。

為了理解卷積神經網路對這些不變性特點的貢獻,我們將用不具備這些不變性特點的前饋神經網路來進行比較。

圖片識別--前饋神經網路

方便起見,我們用depth只有1的灰度圖來舉例。 想要完成的任務是:在寬長為4x4的圖片中識別是否有下圖所示的“橫折”。 圖中,黃色圓點表示值為0的畫素,深色圓點表示值為1的畫素。 我們知道不管這個橫折在圖片中的什麼位置,都會被認為是相同的橫折。

<img src="https://pic2.zhimg.com/50/v2-18c11c6f485e9f1bbc9a50eb3d248439_hd.png" data-caption="" data-rawwidth="411" data-rawheight="374" class="content_image" width="411">

若訓練前饋神經網路來完成該任務,那麼表達影象的三維張量將會被攤平成一個向量,作為網路的輸入,即(width, height, depth)為(4, 4, 1)的圖片會被展成維度為16的向量作為網路的輸入層。再經過幾層不同節點個數的隱藏層,最終輸出兩個節點,分別表示“有橫折的概率”和“沒有橫折的概率”,如下圖所示。

<img src="https://pic2.zhimg.com/50/v2-2b411af47b1cad7b727bb676c847ce59_hd.png" data-caption="" data-rawwidth="499" data-rawheight="505" class="origin_image zh-lightbox-thumb" width="499" data-original="https://pic2.zhimg.com/v2-2b411af47b1cad7b727bb676c847ce59_r.png">

下面我們用數字(16進位制)對圖片中的每一個畫素點(pixel)進行編號。 當使用右側那種物體位於中間的訓練資料來訓練網路時,網路就只會對編號為5,6,9,a的節點的權重進行調節。 若讓該網路識別位於右下角的“橫折”時,則無法識別。

<img src="https://pic2.zhimg.com/50/v2-ce9919e4930c1f29241afec0538b2605_hd.png" data-caption="" data-rawwidth="816" data-rawheight="505" class="origin_image zh-lightbox-thumb" width="816" data-original="https://pic2.zhimg.com/v2-ce9919e4930c1f29241afec0538b2605_r.png">

解決辦法是用大量物體位於不同位置的資料訓練,同時增加網路的隱藏層個數從而擴大網路學習這些變體的能力。

然而這樣做十分不效率,因為我們知道在左側的“橫折”也好,還是在右側的“橫折”也罷,大家都是“橫折”。 為什麼相同的東西在位置變了之後要重新學習?有沒有什麼方法可以將中間所學到的規律也運用在其他的位置? 換句話說,也就是讓不同位置用相同的權重

圖片識別--卷積神經網路

卷積神經網路就是讓權重在不同位置共享的神經網路。

區域性連線

在卷積神經網路中,我們先選擇一個區域性區域,用這個區域性區域去掃描整張圖片。 區域性區域所圈起來的所有節點會被連線到下一層的一個節點上。

為了更好的和前饋神經網路做比較,我將這些以矩陣排列的節點展成了向量。 下圖展示了被紅色方框所圈中編號為0,1,4,5的節點是如何通過w_1,w_2,w_3,w_4連線到下一層的節點0上的。

<img src="https://pic1.zhimg.com/50/v2-e877b9099b1139c1a34b0bf66bf92aa4_hd.png" data-caption="" data-rawwidth="513" data-rawheight="514" class="origin_image zh-lightbox-thumb" width="513" data-original="https://pic1.zhimg.com/v2-e877b9099b1139c1a34b0bf66bf92aa4_r.png">

這個帶有連線強弱的紅色方框就叫做 filterkernelfeature detector。 而filter的範圍叫做filter size,這裡所展示的是2x2的filter size。

\left[ \begin{matrix} w_1&w_2\\ w_3&w_4\\ \end{matrix} \right] (1)

第二層的節點0的數值就是區域性區域的線性組合,即被圈中節點的數值乘以對應的權重後相加。 用x表示輸入值,y表示輸出值,用圖中標註數字表示角標,則下面列出了兩種計算編號為0的輸出值y_0的表示式。

注:在區域性區域的線性組合後,也會和前饋神經網路一樣,加上一個偏移量b_0

\begin{split} y_0 &= x_0*w_1 + x_1*w_2+ x_4*w_3+ x_5*w_4+b_0\\y_0 &= \left[ \begin{matrix} w_1&w_2& w_3&w_4 \end{matrix} \right] \cdot \left[ \begin{matrix} x_0\\ x_1\\ x_4\\ x_5\\ \end{matrix} \right]+b_0 \end{split} (2)

空間共享

當filter掃到其他位置計算輸出節點y_i 時,w_1,w_2,w_3,w_4包括b_0是共用的。

下面這張動態圖展示了當filter掃過不同區域時,節點的連結方式。 動態圖的最後一幀則顯示了所有連線。 可以注意到,每個輸出節點並非像前饋神經網路中那樣與全部的輸入節點連線,而是部分連線。 這也就是為什麼大家也叫前饋神經網路(feedforward neural network)為fully-connected neural network。 圖中顯示的是一步一步的移動filter來掃描全圖,一次移動多少叫做stride。

<img src="https://pic1.zhimg.com/50/v2-4fd0400ccebc8adb2dffe24aac163e70_hd.gif" data-caption="" data-rawwidth="513" data-rawheight="514" data-thumbnail="https://pic1.zhimg.com/50/v2-4fd0400ccebc8adb2dffe24aac163e70_hd.jpg" class="origin_image zh-lightbox-thumb" width="513" data-original="https://pic1.zhimg.com/v2-4fd0400ccebc8adb2dffe24aac163e70_r.gif">
空間共享也就是卷積神經網路所引入的先驗知識。

輸出表達

如先前在影象表達中提到的,圖片不用向量去表示是為了保留圖片平面結構的資訊。 同樣的,卷積後的輸出若用上圖的排列方式則丟失了平面結構資訊。 所以我們依然用矩陣的方式排列它們,就得到了下圖所展示的連線。

<img src="https://pic2.zhimg.com/50/v2-e1691956fd1beb5d7a637924a1a73d91_hd.png" data-caption="" data-rawwidth="513" data-rawheight="514" class="origin_image zh-lightbox-thumb" width="513" data-original="https://pic2.zhimg.com/v2-e1691956fd1beb5d7a637924a1a73d91_r.png">

這也就是你們在網上所看到的下面這張圖。在看這張圖的時候請結合上圖的連線一起理解,即輸入(綠色)的每九個節點連線到輸出(粉紅色)的一個節點上的。

<img src="https://pic3.zhimg.com/50/v2-7fce29335f9b43bce1b373daa40cccba_hd.gif" data-caption="" data-rawwidth="526" data-rawheight="384" data-thumbnail="https://pic3.zhimg.com/50/v2-7fce29335f9b43bce1b373daa40cccba_hd.jpg" class="origin_image zh-lightbox-thumb" width="526" data-original="https://pic3.zhimg.com/v2-7fce29335f9b43bce1b373daa40cccba_r.gif">

經過一個feature detector計算後得到的粉紅色區域也叫做一個“Convolved Feature” 或 “Activation Map” 或 “Feature Map”。

Depth維的處理

現在我們已經知道了depth維度只有1的灰度圖是如何處理的。 但前文提過,圖片的普遍表達方式是下圖這樣有3個channels的RGB顏色模型。 當depth為複數的時候,每個feature detector是如何卷積的?

<img src="https://pic1.zhimg.com/50/v2-0d24890b2e0d73f4ce4ad17ebfb2d0c4_hd.png" data-caption="" data-rawwidth="305" data-rawheight="252" class="content_image" width="305">

現象:2x2所表達的filter size中,一個2表示width維上的區域性連線數,另一個2表示height維上的區域性連線數,並卻沒有depth維上的區域性連線數,是因為depth維上並非區域性,而是全部連線的。

在2D卷積中,filter在張量的width維, height維上是區域性連線,在depth維上是貫串全部channels的。

類比:想象在切蛋糕的時候,不管這個蛋糕有多少層,通常大家都會一刀切到底,但是在長和寬這兩個維上是區域性切割。

下面這張圖展示了,在depth為複數時,filter是如何連線輸入節點到輸出節點的。 圖中紅、綠、藍顏色的節點表示3個channels。 黃色節點表示一個feature detector卷積後得到的Feature Map。 其中被透明黑框圈中的12個節點會被連線到黃黑色的節點上。

  • 在輸入depth為1時:被filter size為2x2所圈中的4個輸入節點連線到1個輸出節點上。
  • 在輸入depth為3時:被filter size為2x2,但是貫串3個channels後,所圈中的12個輸入節點連線到1個輸出節點上。
  • 在輸入depth為n時:2x2xn個輸入節點連線到1個輸出節點上。
<img src="https://pic3.zhimg.com/50/v2-23db15ec3f783bbb5cf811711e46dbba_hd.png" data-caption="" data-rawwidth="302" data-rawheight="382" class="content_image" width="302">

(可從vectary在3D編輯下檢視)

注意:三個channels的權重並不共享。 即當深度變為3後,權重也跟著擴增到了三組,如式子(3)所示,不同channels用的是自己的權重。 式子中增加的角標r,g,b分別表示red channel, green channel, blue channel的權重。

\left[ \begin{matrix} w_{r1}&w_{r2}\\ w_{r3}&w_{r4}\\ \end{matrix} \right], \left[ \begin{matrix} w_{g1}&w_{g2}\\ w_{g3}&w_{g4}\\ \end{matrix} \right], \left[ \begin{matrix} w_{b1}&w_{b2}\\ w_{b3}&w_{b4}\\ \end{matrix} \right] (3)

計算例子:用x_{r0}表示red channel的編號為0的輸入節點,x_{g5}表示green channel編號為5個輸入節點。x_{b1}表示blue channel。如式子(4)所表達,這時的一個輸出節點實際上是12個輸入節點的線性組合。

\begin{split} y_0 &= x_{r0}*w_{r1} + x_{r1}*w_{r2}+ x_{r4}*w_{r3}+ x_{r5}*w_{r4}+ x_{g0}*w_{g1} + x_{g1}*w_{g2}+ x_{g4}*w_{g3}+ x_{g5}*w_{g4}+ x_{b0}*w_{b1} + x_{b1}*w_{b2}+ x_{b4}*w_{b3}+ x_{b5}*w_{b4}+b_0\\y_0 &= \left[ \begin{matrix} w_{r1}&w_{r2}& w_{r3}&w_{r4} \end{matrix} \right] \cdot \left[ \begin{matrix} x_{r0}\\ x_{r1}\\ x_{r4}\\ x_{r5}\\ \end{matrix} \right] +\left[ \begin{matrix} w_{g1}&w_{g2}& w_{g3}&w_{g4} \end{matrix} \right] \cdot \left[ \begin{matrix} x_{g0}\\ x_{g1}\\ x_{g4}\\ x_{g5}\\ \end{matrix} \right]+\left[ \begin{matrix} w_{b1}&w_{b2}& w_{b3}&w_{b4} \end{matrix} \right] \cdot \left[ \begin{matrix} x_{b0}\\ x_{b1}\\ x_{b4}\\ x_{b5}\\ \end{matrix} \right]+b_0\end{split}(4)

當filter掃到其他位置計算輸出節點y_i時,那12個權重在不同位置是共用的,如下面的動態圖所展示。 透明黑框圈中的12個節點會連線到被白色邊框選中的黃色節點上。

<img src="https://pic3.zhimg.com/50/v2-0bc83b72ef50099b70a10cc3ab528f62_hd.gif" data-caption="" data-rawwidth="326" data-rawheight="455" data-thumbnail="https://pic3.zhimg.com/50/v2-0bc83b72ef50099b70a10cc3ab528f62_hd.jpg" class="content_image" width="326">
每個filter會在width維, height維上,以區域性連線和空間共享,並貫串整個depth維的方式得到一個Feature Map。

Zero padding

細心的讀者應該早就注意到了,4x4的圖片被2x2的filter卷積後變成了3x3的圖片,每次卷積後都會小一圈的話,經過若干層後豈不是變的越來越小? Zero padding就可以在這時幫助控制Feature Map的輸出尺寸,同時避免了邊緣資訊被一步步捨棄的問題。

例如:下面4x4的圖片在邊緣Zero padding一圈後,再用3x3的filter卷積後,得到的Feature Map尺寸依然是4x4不變。

<img src="https://pic2.zhimg.com/50/v2-c1010eb5dcf032ea95eab495a45f9b31_hd.png" data-caption="" data-rawwidth="173" data-rawheight="173" class="content_image" width="173">

通常大家都想要在卷積時保持圖片的原始尺寸。 選擇3x3的filter和1的zero padding,或5x5的filter和2的zero padding可以保持圖片的原始尺寸。 這也是為什麼大家多選擇3x3和5x5的filter的原因。 另一個原因是3x3的filter考慮到了畫素與其距離為1以內的所有其他畫素的關係,而5x5則是考慮畫素與其距離為2以內的所有其他畫素的關係。

尺寸:Feature Map的尺寸等於(input_size + 2 * padding_size − filter_size)/stride+1。

注意:上面的式子是計算width或height一維的。padding_size也表示的是單邊補零的個數。例如(4+2-3)/1+1 = 4,保持原尺寸。

不用去背這個式子。其中(input_size + 2 * padding_size)是經過Zero padding擴充後真正要卷積的尺寸。 減去 filter_size後表示可以滑動的範圍。 再除以可以一次滑動(stride)多少後得到滑動了多少次,也就意味著得到了多少個輸出節點。 再加上第一個不需要滑動也存在的輸出節點後就是最後的尺寸。

形狀、概念抓取

知道了每個filter在做什麼之後,我們再來思考這樣的一個filter會抓取到什麼樣的資訊。

我們知道不同的形狀都可由細小的“零件”組合而成的。比如下圖中,用2x2的範圍所形成的16種形狀可以組合成格式各樣的“更大”形狀。

卷積的每個filter可以探測特定的形狀。又由於Feature Map保持了抓取後的空間結構。若將探測到細小圖形的Feature Map作為新的輸入再次卷積後,則可以由此探測到“更大”的形狀概念。 比如下圖的第一個“大”形狀可由2,3,4,5基礎形狀拼成。第二個可由2,4,5,6組成。第三個可由6,1組成。

<img src="https://pic1.zhimg.com/50/v2-f53f6ac43abd2555cfbbba6ea7fdc0e4_hd.png" data-caption="" data-rawwidth="484" data-rawheight="291" class="origin_image zh-lightbox-thumb" width="484" data-original="https://pic1.zhimg.com/v2-f53f6ac43abd2555cfbbba6ea7fdc0e4_r.png">

除了基礎形狀之外,顏色、對比度等概念對畫面的識別結果也有影響。卷積層也會根據需要去探測特定的概念。

可以從下面這張圖中感受到不同數值的filters所卷積過後的Feature Map可以探測邊緣,稜角,模糊,突出等概念。

<img src="https://pic1.zhimg.com/50/v2-644d108587a6ce7fa471ede5d2e11e98_hd.png" data-caption="" data-rawwidth="342" data-rawheight="562" class="content_image" width="342">

[from]

如我們先前所提,圖片被識別成什麼不僅僅取決於圖片本身,還取決於圖片是如何被觀察的。

而filter內的權重矩陣W是網路根據資料學習得到的,也就是說,我們讓神經網路自己學習以什麼樣的方式去觀察圖片。

拿老婦與少女的那幅圖片舉例,當標籤是少女時,卷積網路就會學習抓取可以成少女的形狀、概念。 當標籤是老婦時,卷積網路就會學習抓取可以成老婦的形狀、概念。

下圖展現了在人臉識別中經過層層的卷積後,所能夠探測的形狀、概念也變得越來越抽象和複雜。

<img src="https://pic2.zhimg.com/50/v2-c78b8d059715bb5f42c93716a98d5a69_hd.jpg" data-caption="" data-rawwidth="366" data-rawheight="546" class="content_image" width="366">
卷積神經網路會盡可能尋找最能解釋訓練資料的抓取方式。

多filters

每個filter可以抓取探測特定的形狀的存在。 假如我們要探測下圖的長方框形狀時,可以用4個filters去探測4個基礎“零件”。

<img src="https://pic1.zhimg.com/50/v2-6df64fccc9a8e2f696626f85233acb3c_hd.png" data-caption="" data-rawwidth="123" data-rawheight="127" class="content_image" width="123"> <img src="https://pic4.zhimg.com/50/v2-65461a21a909eca2e190c54db59a2c8f_hd.png" data-caption="" data-rawwidth="315" data-rawheight="82" class="content_image" width="315">

因此我們自然而然的會選擇用多個不同的filters對同一個圖片進行多次抓取。 如下圖(動態圖過大,如果顯示不出,請看到該連結觀看),同一個圖片,經過兩個(紅色、綠色)不同的filters掃描過後可得到不同特點的Feature Maps。 每增加一個filter,就意味著你想讓網路多抓取一個特徵。

<img src="https://pic2.zhimg.com/50/v2-c7f1ea1d42820b4de30bd548c3986ecd_hd.gif" data-caption="" data-rawwidth="212" data-rawheight="120" data-thumbnail="https://pic2.zhimg.com/50/v2-c7f1ea1d42820b4de30bd548c3986ecd_hd.jpg" class="content_image" width="212">

[from]

這樣卷積層的輸出也不再是depth為1的一個平面,而是和輸入一樣是depth為複數的長方體。

如下圖所示,當我們增加一個filter(紫色表示)後,就又可以得到一個Feature Map。 將不同filters所卷積得到的Feature Maps按順序堆疊後,就得到了一個卷積層的最終輸出。

<img src="https://pic1.zhimg.com/50/v2-d11e1d2f2c41b6df713573f8155bc324_hd.png" data-caption="" data-rawwidth="1271" data-rawheight="629" class="origin_image zh-lightbox-thumb" width="1271" data-original="https://pic1.zhimg.com/v2-d11e1d2f2c41b6df713573f8155bc324_r.png">
卷積層的輸入是長方體,輸出也是長方體。

這樣卷積後輸出的長方體可以作為新的輸入送入另一個卷積層中處理。

加入非線性

和前饋神經網路一樣,經過線性組合和偏移後,會加入非線性增強模型的擬合能力。

將卷積所得的Feature Map經過ReLU變換(elementwise)後所得到的output就如下圖所展示。

<img src="https://pic3.zhimg.com/50/v2-54a469b2873542e75abf2bc5d8fcaa1a_hd.png" data-caption="" data-rawwidth="748" data-rawheight="280" class="origin_image zh-lightbox-thumb" width="748" data-original="https://pic3.zhimg.com/v2-54a469b2873542e75abf2bc5d8fcaa1a_r.png">

[from]

輸出長方體

現在我們知道了一個卷積層的輸出也是一個長方體。 那麼這個輸出長方體的(width, height, depth)由哪些因素決定和控制。

這裡直接用CS231n的Summary:

<img src="https://pic1.zhimg.com/50/v2-a9983c3cee935b68c73965bc1abe268c_hd.png" data-caption="" data-rawwidth="383" data-rawheight="376" class="content_image" width="383">

計算例子:請體會CS231n的Convolution Demo部分的演示。

矩陣乘法執行卷積

如果按常規以掃描的方式一步步計算區域性節點和filter的權重的點乘,則不能高效的利用GPU的並行能力。 所以更普遍的方法是用兩個大矩陣的乘法來一次性囊括所有計算。

因為卷積層的每個輸出節點都是由若干個輸入節點的線性組合所計算。 因為輸出的節點個數是W_2 \times H_2\times D_2,所以就有W_2 \times H_2\times D_2個線性組合。

讀過我寫的線性代數教程的讀者請回憶,矩陣乘矩陣的意義可以理解為批量的線性組合按順序排列。 其中一個矩陣所表示的資訊是多組權重,另一個矩陣所表示的資訊是需要進行組合的向量。 大家習慣性的把組成成分放在矩陣乘法的右邊,而把權重放在矩陣乘法的左邊。 所以這個大型矩陣乘法可以用W_{row}\cdot X_{col}表示,其中W_{row}X_{col}都是矩陣。

<img src="https://pic1.zhimg.com/50/v2-11a4d56793af815eb2b4585d64aec178_hd.png" data-caption="" data-rawwidth="551" data-rawheight="136" class="origin_image zh-lightbox-thumb" width="551" data-original="https://pic1.zhimg.com/v2-11a4d56793af815eb2b4585d64aec178_r.png">

卷積的每個輸出是由區域性的輸入節點和對應的filter權重展成向量後所計算的,如式子(2)。 那麼W_{row}中的每一行則是每個filter的權重,有F\cdot F \cdot D_1個; 而X_{col}的每一列是所有需要進行組合的節點(上面的動態圖中被黑色透明框圈中的節點),也有F\cdot F \cdot D_1個。X_{col}的列的個數則表示每個filter要滑動多少次才可以把整個圖片掃描完,有W_2\cdot H_2次。 因為我們有多個filters,W_{row}的行的個數則是filter的個數K

最後我們得到:

W_{row} \in R^{K \times F\cdot F \cdot D_1}

X_{col} \in R^{F\cdot F \cdot D_1 \times W_2\cdot H_2}

W_{row}\cdot X_{col} \in R^{K \times W_2\cdot H_2}

當然矩陣乘法後需要將W_{row}\cdot X_{col}整理成形狀為W_2 \times H_2\times D_2的三維張量以供後續處理(如再送入另一個卷積層)。X_{col}則也需要逐步的區域性滑動圖片,最後堆疊構成用於計算矩陣乘法的形式。

Max pooling

在卷積後還會有一個pooling的操作,儘管有其他的比如average pooling等,這裡只提max pooling。

max pooling的操作如下圖所示:整個圖片被不重疊的分割成若干個同樣大小的小塊(pooling size)。每個小塊內只取最大的數字,再捨棄其他節點後,保持原有的平面結構得出output。

<img src="https://pic1.zhimg.com/50/v2-1a4b2a3795d8f073e921d766e70ce6ec_hd.jpg" data-caption="" data-rawwidth="787" data-rawheight="368" class="origin_image zh-lightbox-thumb" width="787" data-original="https://pic1.zhimg.com/v2-1a4b2a3795d8f073e921d766e70ce6ec_r.jpg">

[from]

max pooling在不同的depth上是分開執行的,且不需要引數控制。 那麼問題就max pooling有什麼作用?部分資訊被捨棄後難道沒有影響嗎?

<img src="https://pic4.zhimg.com/50/v2-cd717414dcf32dac4df73c00f1e7c6c3_hd.jpg" data-caption="" data-rawwidth="514" data-rawheight="406" class="origin_image zh-lightbox-thumb" width="514" data-original="https://pic4.zhimg.com/v2-cd717414dcf32dac4df73c00f1e7c6c3_r.jpg">

[from]

Max pooling的主要功能是downsampling,卻不會損壞識別結果。 這意味著卷積後的Feature Map中有對於識別物體不必要的冗餘資訊。 那麼我們就反過來思考,這些“冗餘”資訊是如何產生的。

直覺上,我們為了探測到某個特定形狀的存在,用一個filter對整個圖片進行逐步掃描。但只有出現了該特定形狀的區域所卷積獲得的輸出才是真正有用的,用該filter卷積其他區域得出的數值就可能對該形狀是否存在的判定影響較小。 比如下圖中,我們還是考慮探測“橫折”這個形狀。 卷積後得到3x3的Feature Map中,真正有用的就是數字為3的那個節點,其餘數值對於這個任務而言都是無關的。 所以用3x3的Max pooling後,並沒有對“橫折”的探測產生影響。 試想在這裡例子中如果不使用Max pooling,而讓網路自己去學習。 網路也會去學習與Max pooling近似效果的權重。因為是近似效果,增加了更多的parameters的代價,卻還不如直接進行Max pooling。

<img src="https://pic1.zhimg.com/50/v2-8e9d7ec0662e903e475bd93a64067554_hd.png" data-caption="" data-rawwidth="545" data-rawheight="345" class="origin_image zh-lightbox-thumb" width="545" data-original="https://pic1.zhimg.com/v2-8e9d7ec0662e903e475bd93a64067554_r.png">

Max pooling還有類似“選擇句”的功能。假如有兩個節點,其中第一個節點會在某些輸入情況下最大,那麼網路就只在這個節點上流通訊息;而另一些輸入又會讓第二個節點的值最大,那麼網路就轉而走這個節點的分支。

但是Max pooling也有不好的地方。因為並非所有的抓取都像上圖的極端例子。有些周邊資訊對某個概念是否存在的判定也有影響。 並且Max pooling是對所有的Feature Maps進行等價的操作。就好比用相同網孔的漁網打魚,一定會有漏網之魚。

全連線層

當抓取到足以用來識別圖片的特徵後,接下來的就是如何進行分類。 全連線層(也叫前饋層)就可以用來將最後的輸出對映到線性可分的空間。 通常卷積網路的最後會將末端得到的長方體平攤(flatten)成一個長長的向量,並送入全連線層配合輸出層進行分類。

卷積神經網路大致就是covolutional layer, pooling layer, ReLu layer, fully-connected layer的組合,例如下圖所示的結構。

<img src="https://pic4.zhimg.com/50/v2-cf87890eb8f2358f23a1ac78eb764257_hd.png" data-caption="" data-rawwidth="748" data-rawheight="263" class="origin_image zh-lightbox-thumb" width="748" data-original="https://pic4.zhimg.com/v2-cf87890eb8f2358f23a1ac78eb764257_r.png">

[from]

這裡也體現了深層神經網路或deep learning之所以稱deep的一個原因:模型將特徵抓取層和分類層合在了一起。 負責特徵抓取的卷積層主要是用來學習“如何觀察”。

下圖簡述了機器學習的發展,從最初的人工定義特徵再放入分類器的方法,到讓機器自己學習特徵,再到如今儘量減少人為干涉的deep learning。

<img src="https://pic1.zhimg.com/50/v2-60e7c1e89c5aed5b828cbb24fc1e5a80_hd.png" data-caption="" data-rawwidth="566" data-rawheight="789" class="origin_image zh-lightbox-thumb" width="566" data-original="https://pic1.zhimg.com/v2-60e7c1e89c5aed5b828cbb24fc1e5a80_r.png">

[from]

結構發展

以上介紹了卷積神經網路的基本概念。 以下是幾個比較有名的卷積神經網路結構,詳細的請看CS231n

  • LeNet:第一個成功的卷積神經網路應用
  • AlexNet:類似LeNet,但更深更大。使用了層疊的卷積層來抓取特徵(通常是一個卷積層馬上一個max pooling層)
  • ZF Net:增加了中間卷積層的尺寸,讓第一層的stride和filter size更小。
  • GoogLeNet:減少parameters數量,最後一層用max pooling層代替了全連線層,更重要的是Inception-v4模組的使用。
  • VGGNet:只使用3x3 卷積層和2x2 pooling層從頭到尾堆疊。
  • ResNet:引入了跨層連線和batch normalization。
  • DenseNet:將跨層連線從頭進行到尾。

總結一下:這些結構的發展趨勢有:

  • 使用small filter size的卷積層和pooling
  • 去掉parameters過多的全連線層
  • Inception(稍後會對其中的細節進行說明)
  • 跳層連線

不變性的滿足

接下來會談談我個人的,對於畫面不變性是如何被卷積神經網路滿足的想法。 同時結合不變性,對上面提到的結構發展的重要變動進行直覺上的解讀。

需要明白的是為什麼加入不變性可以提高網路表現。 並不是因為我們用了更炫酷的處理方式,而是加入了先驗知識,無需從零開始用資料學習,節省了訓練所需資料量。 思考表現提高的原因一定要從訓練所需要的資料量切入。 提出滿足新的不變性特點的神經網路是計算機視覺的一個主要研究方向。

平移不變性

可以說卷積神經網路最初引入區域性連線和空間共享,就是為了滿足平移不變性。

<img src="https://pic4.zhimg.com/50/v2-1aac56212d5d143a006d569318e3ee8b_hd.png" data-caption="" data-rawwidth="550" data-rawheight="136" class="origin_image zh-lightbox-thumb" width="550" data-original="https://pic4.zhimg.com/v2-1aac56212d5d143a006d569318e3ee8b_r.png">

因為空間共享,在不同位置的同一形狀就可以被等價識別,所以不需要對每個位置都進行學習。

<img src="https://pic2.zhimg.com/50/v2-18c11c6f485e9f1bbc9a50eb3d248439_hd.png" data-caption="" data-rawwidth="411" data-rawheight="374" class="content_image" width="411">

旋轉和視角不變性

個人覺得卷積神經網路克服這一不變性的主要手段還是靠大量的資料。 並沒有明確加入“旋轉和視角不變性”的先驗特性。

<img src="https://pic2.zhimg.com/50/v2-0ce892f8b247f2b48a76cc57cbcba41d_hd.png" data-caption="" data-rawwidth="552" data-rawheight="250" class="origin_image zh-lightbox-thumb" width="552" data-original="https://pic2.zhimg.com/v2-0ce892f8b247f2b48a76cc57cbcba41d_r.png">

尺寸不變性

與平移不變性不同,最初的卷積網路並沒有明確照顧尺寸不變性這一特點。

我們知道filter的size是事先選擇的,而不同的尺寸所尋找的形狀(概念)範圍不同。

從直觀上思考,如果選擇小範圍,再一步步通過組合,仍然是可以得到大範圍的形狀。 如3x3尺寸的形狀都是可以由2x2形狀的圖形組合而成。所以形狀的尺寸不變性對卷積神經網路而言並不算問題。 這恐怕ZF Net讓第一層的stride和filter size更小,VGGNet將所有filter size都設定成3x3仍可以得到優秀結果的一個原因。

但是,除了形狀之外,很多概念的抓取通常需要考慮一個畫素與周邊更多畫素之間的關係後得出。 也就是說5x5的filter也是有它的優點。 同時,小尺寸的堆疊需要很多個filters來共同完成,如果需要抓取的形狀恰巧在5x5的範圍,那麼5x5會比3x3來的更有效率。 所以一次性使用多個不同filter size來抓取多個範圍不同的概念是一種順理成章的想法,而這個也就是Inception。 可以說Inception是為了尺寸不變性而引入的一個先驗知識。

Inception

下圖是Inception的結構,儘管也有不同的版本,但是其動機都是一樣的:消除尺寸對於識別結果的影響,一次性使用多個不同filter size來抓取多個範圍不同的概念,並讓網路自己選擇需要的特徵。

你也一定注意到了藍色的1x1卷積,撇開它,先看左邊的這個結構。

輸入(可以是被卷積完的長方體輸出作為該層的輸入)進來後,通常我們可以選擇直接使用畫素資訊(1x1卷積)傳遞到下一層,可以選擇3x3卷積,可以選擇5x5卷積,還可以選擇max pooling的方式downsample剛被卷積後的feature maps。 但在實際的網路設計中,究竟該如何選擇需要大量的實驗和經驗的。 Inception就不用我們來選擇,而是將4個選項給神經網路,讓網路自己去選擇最合適的解決方案。

接下來我們再看右邊的這個結構,多了很多藍色的1x1卷積。 這些1x1卷積的作用是為了讓網路根據需要能夠更靈活的控制資料的depth的。

<img src="https://pic2.zhimg.com/50/v2-9692631d087622f1b34c80055f13fac5_hd.png" data-caption="" data-rawwidth="983" data-rawheight="311" class="origin_image zh-lightbox-thumb" width="983" data-original="https://pic2.zhimg.com/v2-9692631d087622f1b34c80055f13fac5_r.png">

1x1卷積核

如果卷積的輸出輸入都只是一個平面,那麼1x1卷積核並沒有什麼意義,它是完全不考慮畫素與周邊其他畫素關係。 但卷積的輸出輸入是長方體,所以1x1卷積實際上是對每個畫素點,在不同的channels上進行線性組合(資訊整合),且保留了圖片的原有平面結構,調控depth,從而完成升維或降維的功能。

如下圖所示,如果選擇2個filters的1x1卷積層,那麼資料就從原本的depth 3 降到了2。若用4個filters,則起到了升維的作用。

這就是為什麼上面Inception的4個選擇中都混合一個1x1卷積,如右側所展示的那樣。 其中,綠色的1x1卷積本身就1x1卷積,所以不需要再用另一個1x1卷積。 而max pooling用來去掉卷積得到的Feature Map中的冗餘資訊,所以出現在1x1卷積之前,緊隨剛被卷積後的feature maps。(由於沒做過實驗,不清楚調換順序會有什麼影響。)

<img src="https://pic1.zhimg.com/50/v2-59429b22ac90930c502736b33db0d8e0_hd.png" data-caption="" data-rawwidth="643" data-rawheight="517" class="origin_image zh-lightbox-thumb" width="643" data-original="https://pic1.zhimg.com/v2-59429b22ac90930c502736b33db0d8e0_r.png">

跳層連線

前饋神經網路也好,卷積神經網路也好,都是一層一層逐步變換的,不允許跳層組合。 但現實中是否有跳層組合的現象?

比如說我們在判斷一個人的時候,很多時候我們並不是觀察它的全部,或者給你的圖片本身就是殘缺的。 這時我們會靠單個五官,外加這個人的著裝,再加他的身形來綜合判斷這個人,如下圖所示。 這樣,即便圖片本身是殘缺的也可以很好的判斷它是什麼。 這和前饋神經網路的先驗知識不同,它允許不同層級之間的因素進行資訊互動、綜合判斷。

殘差網路就是擁有這種特點的神經網路。大家喜歡用identity mappings去解釋為什麼殘差網路更優秀。 這裡我只是提供了一個以先驗知識的角度去理解的方式。 需要注意的是每一層並不會像我這裡所展示的那樣,會形成明確的五官層。 只是有這樣的組合趨勢,實際無法保證神經網路到底學到了什麼內容。

<img src="https://pic4.zhimg.com/50/v2-40fb6ab7bf89ce43af1c52e673da65eb_hd.png" data-caption="" data-rawwidth="509" data-rawheight="507" class="origin_image zh-lightbox-thumb" width="509" data-original="https://pic4.zhimg.com/v2-40fb6ab7bf89ce43af1c52e673da65eb_r.png">

用下圖舉一個更易思考的例子。 圖形1,2,3,4,5,6是第一層卷積層抓取到的概念。 圖形7,8,9是第二層卷積層抓取到的概念。 圖形7,8,9是由1,2,3,4,5,6的基礎上組合而成的。

但當我們想要探測的圖形10並不是單純的靠圖形7,8,9組成,而是第一個卷積層的圖形6和第二個卷積層的8,9組成的話,不允許跨層連線的卷積網路不得不用更多的filter來保持第一層已經抓取到的圖形資訊。並且每次傳遞到下一層都需要學習那個用於保留前一層圖形概念的filter的權重。 當層數變深後,會越來越難以保持,還需要max pooling將冗餘資訊去掉。

一個合理的做法就是直接將上一層所抓取的概念也跳層傳遞給下下一層,不用讓其每次都重新學習。 就好比在程式設計時構建了不同規模的functions。 每個function我們都是保留,而不是重新再寫一遍。提高了重用性。

同時,因為ResNet使用了跳層連線的方式。也不需要max pooling對保留低層資訊時所產生的冗餘資訊進行去除。

<img src="https://pic3.zhimg.com/50/v2-87fc4b7449d751c59977c3a368ae6f7e_hd.png" data-caption="" data-rawwidth="484" data-rawheight="436" class="origin_image zh-lightbox-thumb" width="484" data-original="https://pic3.zhimg.com/v2-87fc4b7449d751c59977c3a368ae6f7e_r.png">

Inception中的第一個1x1的卷積通道也有類似的作用,但是1x1的卷積仍有權重需要學習。 並且Inception所使用的結合方式是concatenate的合併成一個更大的向量的方式,而ResNet的結合方式是sum。 兩個結合方式各有優點。 concatenate當需要用不同的維度去組合成新觀念的時候更有益。 而sum則更適用於並存的判斷。比如既有油頭髮,又有胖身軀,同時穿著常年不洗的牛仔褲,三個不同層面的概念並存時,該人會被判定為程式設計師的情況。 又比如雙向LSTM中正向和逆向序列抓取的結合常用相加的方式結合。在語音