14 卷積神經網路(進階)

藍子娃娃發表於2020-11-01

卷積神經網路

  這篇部落格主要介紹更復雜的網路結構怎樣去實現?在上一篇部落格我們實現了一個非常簡單的序列的神經網路結構,裡面用了兩個卷積層,兩個池化層,然後是一個全連線層,最後得到相應的輸出。
  
在這裡插入圖片描述
  
  下面我們看一種更為複雜的,不是序列結構的網路。第一種網路結構是 GoogleNet(如下圖),其中藍色塊表示卷積,紅色塊表示池化,黃色塊表示 Softmax,綠色的塊表示其它比如拼接層等等。

在這裡插入圖片描述
  
  那麼我們看到這樣一種網路結構,很多小夥伴可能就傻眼了,如果按照之前的方法一個一個去定義,什麼時候才能把這個網路寫完,寫完之後程式碼量可想而知。我們在定義網路的時候,在程式語言中,想要減少程式碼量首先就得減少程式碼冗餘,減少程式碼冗餘有兩種常用的方法:第一種在程式導向的程式設計中使用函式減少程式碼冗餘,第二種就是在物件導向的程式設計中使用類減少程式碼冗餘。
  
  那麼我們首先得觀察一下這個網路中是否存在相似的結構以致於把這些相似的結構封裝成函式或類。

在這裡插入圖片描述
  
  上面用紅框圈出的部分都是相同的,那麼我們就可以將該部分封裝起來。這個部分在 GoogleNet 中叫做 Inception。下面我們就來看看 Inception 模組是怎樣實現的?下面是該模組的圖示,該模組主要由四個分支構成,每個分支中使用了不同的 kernel-size。

在這裡插入圖片描述
  
  為什麼 Inception 要設計成這樣呢?因為我們在構造神經網路的時候有一些超引數是很難選擇的,比如卷積核的大小。所以這個 GoogleNet 的出發點就是不知道哪個 kernel-size 最好,那麼就在一個模組裡面把幾種卷積核都使用一遍,然後將它們的結果疊加在一起,假設 3x3 的卷積核比較好,相應的 3x3 的權重就會大一些,其它的權重就會變小。所以它是提供了幾種候選的卷積神經網路的配置,將來通過訓練自動的找出當前最優的卷積的組合。
  

  我們再來看看模組中的 Concatenate ,它的意思是將張量進行拼接。如下圖所示,在進行 Concatenate 之前輸出的是四個張量,我們需要把這些張量拼接成一個張量。而且做 Concatenate 時,必須要保證每個影像的寬度和高度是相同的。比如說,我們最後輸出的張量都是 ( b , c , w , h ) (b, c, w, h) (b,c,w,h),那麼從下圖中四條路徑求出的張量唯一不同的可以是 c c c,但是 w w w h h h 必須保持一致。

在這裡插入圖片描述
  
  我們可以觀察到,上圖中 1x1 的卷積核比較多。下面我舉一個簡單的例子,展示 1x1 的卷積核的計算過程。下面有一個單層的通道和一個 1x1 的卷積核做卷積,那麼計算如下:

在這裡插入圖片描述
  
  如果輸入有多個通道,那麼就需要給每個通道配一個 1x1 的卷積核。

在這裡插入圖片描述
  
  注意做完卷積之後,還需要進行求和。

在這裡插入圖片描述
  
  從上面的結果我們可以得出,我們從一個 3 通道的輸入變成了一個 1 通道的輸出,所以 1x1 的卷積核主要的工作就是改變通道的數量,它可以從 C 1 C_1 C1 變為 C 2 C_2 C2,你可能就會有這樣的疑問,為什麼要使用 1x1 的卷積核,直接做卷積不就可以了?
  
  下面我們來看看為什麼要使用 1x1 的卷積核?首先我們看這麼一個運算,我們的輸入有 192 個通道,影像大小為 28x28,然後我們用一個 5x5 的卷積核做卷積。

在這裡插入圖片描述
  
  那麼最後要進行浮點數的運算如下:

在這裡插入圖片描述
  
  那麼進行一個卷積運算需要 1億2千萬次運算。我們在神經網路中,實際上我們最大的問題就是運算量太大,我們經常需要想辦法降低運算量,所以就提出了用 1x1 的卷積核來降低運算量。還是之前的輸入和輸出,只不過在中間加了一層 1x1 的卷積。

在這裡插入圖片描述
  
  看上去好像比之前的網路結構更加的複雜,但是我們實際上看一下運算量。
  
在這裡插入圖片描述

  最後計算量為 1千200萬,是之前運算量的 1/10。
  

  下面我們來看看 Inception 到底是怎樣實現的?用具體的程式碼來分析。為了方便觀察,我們將圖旋轉了一下,來看每一個分支怎樣來實現。

在這裡插入圖片描述
  

  這裡面需要注意一點,由於每個分支最後輸出的張量的 w w w h h h 一定要是相同的,所以在做卷積的時候,一定要保證卷積前後影像大小不變,所以在用 3x3 的卷積核做卷積時,需要加上 padding=1;用 5x5 的卷積核做卷積時,需要加上 padding=2。
  
  最後,我們需要將四個途徑的輸出沿著通道的維度拼接成一個張量,這個拼接的過程就是 Concatenate。

在這裡插入圖片描述
  
  Concatenate 的程式碼如下:
在這裡插入圖片描述
  
  程式碼中的 dim=1 表示沿著通道數進行拼接,因為最後輸出的四個張量都是 ( b , c , w , h ) (b, c, w, h) (b,c,w,h) b b b 為 0, c c c 為 1, w w w 為 2, h h h 為 3。

  
  我們將整個 Inception 的程式碼整合到一起就得到了 Inception 類:
  在這裡插入圖片描述
  
  構造網路的程式碼如下:

在這裡插入圖片描述
  

  下面我們介紹另外一種使用非常多的主幹網路叫做 Residual net,它的思想就是我們把 3x3 的卷積一直不停的堆下去,它的效能會不會變好?他們做實驗發現,對於 CIFAR-10 資料集來說,在測試資料集中 20 層的卷積的效能要比 56 層的卷積要好,在測試資料集中也是如此。

在這裡插入圖片描述
  
  當然這有可能是因為堆積了 50 層,模型變得越複雜,可能是發生了過擬合或其它一些情況,其中有一種可能叫做梯度消失
  
  那怎麼解決梯度消失的問題呢?
  
  平時的神經網路就是一層疊一層,首先是權重層,然後經過啟用就會得到輸出。

在這裡插入圖片描述
  
  在 Residual net 中,加了一個跳連線。

在這裡插入圖片描述
  
  為什麼說加了一層跳連線就可以解決梯度消失的問題呢?因為 H ( x ) = F ( x ) + x H(x) = F(x) + x H(x)=F(x)+x,當在求 H ( x ) H(x) H(x) x x x 的導數時,當 F ( x ) F(x) F(x) x x x 的導數很小時,趨近於 0,但是後面加了一個 x x x x x x 的導數 1,所以 H ( x ) H(x) H(x) x x x 的導數整體就趨近於 1,很好的解決了梯度消失的問題。
  
  下面我就在 MNIST 資料集上新增相應的 Residual Network,在做 Residual 時,必須保證輸入和輸出的維度是一樣的。

在這裡插入圖片描述
  
  下面我們看上面流程圖中 Residual Block 怎麼來實現?

在這裡插入圖片描述
  

  構造好 Residual Block 之後,我們就可以在網路中新增 Residual Block。
  
在這裡插入圖片描述
  
  在下面這篇論文中有很多關於 Residual Block 的設計。

在這裡插入圖片描述
  比如說:

在這裡插入圖片描述


   具體程式碼見 14 卷積神經網路(進階).ipynb

相關文章