2018年7月6日 星期五

CNN筆記 - 卷積類神經網路(Convolutional Neural Network, CNN)

        Convolutional Neural Network 介紹

     
        本文將會介紹近年來在影像辨識領域相當熱門的卷積類神經網路(convolutional neural network, CNN),或是稱呼較大眾化的名稱──深度學習(Deep Learning,雖然它只是深度學習其中的一環),希望這篇文章能作為各位開啟認識CNN大門。

  本文各節可依照是否為CNN特有之功能做分類,如下:
  1. 類神經網路既存
    • Feedforward (前向傳導)
    • Loss Function (損失函數)
    • Backpropagation (反向傳播學習)
  2. CNN新增特性
    • Convolution (卷積) 
    • Max Pooling (池化)

--------------------------------------------------------------------------------------------------------------------------

        在人工視覺領域中,對於如何利用最少的限制條件來描述訓練模型,得到最強健的特徵,藉此解決物件、場景高變化性問題一直是重要的研究方向,其中包括角度、光源、遮蔽等等。

        近年影像辨識研究領域中,因為科技發達而有大量且多元的影像需要進行訓練與辨識,在傳統的訓練與辨識當中,要使模型學習數以十萬、百萬計的影像十分不容易,因為過去總是需要根據人的主觀建立描述影像的特徵擷取法,常見的人工特徵例如LBP (Local Binary Pattern)、HoG (Histogram of Gradient)、Haar-like等等。然而要找到一個強健的特徵來描述龐大資料是相當困難的任務,若以無法描述廣大資料的特徵建立模型,理所當然的在使用上受到限制,CNN的主要功能就是以電腦自己找出有用的特徵取代人工定義特徵。近年隨著科技的發達,硬體獲得極大的進步,過去因硬體限制而不被重視的卷積類神經網路逐漸受到重視,並且獲得極大的成功,逐漸發展為一個獨立且成熟的方法。

        卷積類神經網路(convolutional neural network, CNN)為前饋神經網路(feedforward)之一,利用convolution的方式將影像中顏色、紋理、光源、大小等等做為類神經網路(neural network)的輸入特徵。與原始的類神經網路往相比,最大特色在於局部感知權重共享,藉由卷積核抽取影像的局部特徵,並且讓影像各區域共享這個卷積核,如此一來能改善原先類神經網路將影像拉成$1×N$向量時,輸入資料失去局部關聯性的問題,因此常運用於局部關係強烈的圖像辨識領域。

        CNN的基本思想非常的簡單直觀,利用多樣化的影像資料庫做為訓練影像,將影像利用數以百萬計的神經網路參數(一群具有特定功能的參數我們稱為model)向網路輸出端傳遞,在輸出端計算目標與預測的誤差,藉由反向傳播學習不斷更新神經網路的權重值,造就卷積類神經網路可解決大量資料的問題,因此對於高變化性、大量且高維的影像辨識而言,具有很大的應用與研究價值,網路架構常包含單個或多個卷積層(convolution layer)、池化層(pooling layer,subsampling),並在再輸出端連結全連接層(fully-connected layer,原始的類神經網路)。典型的CNN如下圖所示:

典型的卷積類神經網路架構


  • Feedforward (前向傳導)

        當我們於眾多函式組中找出針對特定模式辨別之模型,我們即可利用此模型所學習到參數進行預測(由損失函數決定預測的目標,可能是分類、回歸,或是兩者的結合)。(測試階段即是在模型建立後利用前向傳導達成)

        在全連接層(傳統的神經網路),抑或是CNN中的卷積層,數值經過前饋網路傳遞參數時,若我們用$l$來代表當前層,當前層由上一層輸出經過激活函數可以下式表達:

\begin{equation} x^l = \sigma(z^l),\end{equation}
\begin{equation}  z^l=w^l x^{l-1}+b^{l-1}\end{equation}

  其中$σ(∙)$代表激活函數,可能是較經典的sigmoid function $σ(z^l )=1/((1+e^{z^l }))$,但先前的研究發現使用ReLU (rectified linear unit)於梯度下降時,收斂速度會比sigmoid快許多,且使一部分神經元的輸出為0,可以創造網路的稀疏性,達到緩解過擬合(over-fitting)現象的效果。此外,sigmoid函數於較大或較小值的梯度趨近於零,因此容易產生梯度消失(gradient vanishing)的問題,由其是深層網路經由反向傳播計算梯度時,根據連鎖律(chain rule)以小梯度相乘,更容易造成梯度趨近於零,而ReLU於正區間緩解這個問題。由於上述的優點,目前ReLU是應用最為廣泛的激活函數,可利用下式表達:
\begin{equation} f(x) = max(0, x)\end{equation}

(激活函數:ReLU函數圖)
  • Loss Function (損失函數)
    • 輸入資料經過前向傳導播後,可以得到一組代表預測結果的輸出向量,為了評估目前參數的好壞,我們需要設置一個損失函數來評斷與標準答案的距離,以這個距離當作指標來修正參數。常見的損失函數有:(其中$\hat{y}為標準答案、y為模型預測答案$)
      • Linear Regression (線性回歸)
      • Logistic Regression (邏輯回歸)
        • 交叉熵誤差(cross-entropy error):$L = - \sum_{i}^N\hat{y_i}log(y_i)$

  • Backpropagation (反向傳播學習)

        就如同上面損失函數的敘述,當我們要解決一個分類或回歸問題時,需要設定一個損失函數(loss function),獲得評估目前參數的好壞的指標,這個指標就是用來指引反向傳播學習時的方向,有了學習的方向,才能在不斷學習後,從函數組中找到我們所需的模型。

        整體流程是藉由損失函數計算出誤差後,再更新參數($w$與$b$),不斷重複這兩個步驟,直到找出能使損失函數最小化的$w^*$與$b^*$,可用下式表達演算法的最終目標:
\begin{equation}L(w,b)=\sum_{n=1}^N \frac{1}{2}(\hat{y}-(wx+b))^2\end{equation}
\begin{equation}w^{*},b^{*}=\underset{w,b}{argmin} (L(w,b))\end{equation}

        神經網路再求解上述問題時,會先隨機初始化初始權重$w^0$與初始偏差$b^0$,隨後每次更新參數時,藉由梯度下降法(gradient descent,GD)從函數組中找出最佳解。我們可以藉由動畫快速了解梯度下降法的使用過程,如下:(梯度下降可視化請看Python筆記 - Matplotlib - 製作圖表動畫 (以梯度下降法為例)Python筆記 - Matplotlib - 繪製3D動畫 (以雙變數梯度下降法為例))

(綠色點是每次更新後的位置,目標是找到曲面z的最小值)


        梯度下降法即是計算原參數($w^{l-1}$ 、$b^{l-1}$)與損失函數的偏導數乘上學習率(learning rate, $η$)的差值,藉此找出能使損失函數誤差更低的新參數組($w^l$、$b^l$),如下式所示:
\begin{equation} w^{l}=w^{l-1} - \eta\frac{\partial L}{\partial w}\left. \right|_{w=w^{l-1},b=b^{l-1}}\end{equation}
\begin{equation} b^{l}=b^{l-1} - \eta\frac{\partial L}{\partial w}\left. \right|_{w=w^{l-1},b=b^{l-1}}\end{equation}
        如何求解各參數的梯度也是很大的學問,最直觀的方法就是利用數值解法,藉由代入參數微小的變化,即可推算出參數的梯度。然而這直觀的方法雖然簡單,但會造成求解梯度時耗費大量的時間,因此為了快速求解梯度下降法中損失函數的偏導數,需要引入反向傳播學習法(Backpropagation),反向傳播學習主要可分為前向傳播(forward pass)與反向傳播(backward pass)兩大部分。接下來我們將推導其運算過程,首先,我們由連鎖律可得知損失函數對$w$與$b$的偏導數,第$l$層時第$i$個節點可如下式所示:
\begin{equation}\frac{\partial L(w,b)}{\partial w_i^l}=\frac{\partial L(w,b)}{\partial z_i^l}\frac{\partial z_i^l}{\partial w_i^l}\end{equation}
\begin{equation}\frac{\partial L(w,b)}{\partial b_i^l}=\frac{\partial L(w,b)}{\partial z_i^l}\frac{\partial z_i^l}{\partial b_i^l}\end{equation}
其中$z_i^l$與其偏導數可表達如下式:
\begin{equation}
z_i^l=\sum_{i=1}^{N}w_i^l x_i^{l-1}+b_i^l
\end{equation}
\begin{equation}
\frac{\partial z_i^l}{\partial w_i^l}=x_i^{l-1},\frac{\partial z_i^l}{\partial b_i^l}=1
\end{equation}

        由上述結果可得知:藉由前向傳播計算出所有激活值後,即可得知$\frac{\partial z_i^l}{\partial w_i^l}
$與$\frac{\partial z_i^l}{\partial b_i^l}
$,此時未知數只剩$\frac{\partial L(w,b))}{\partial z_i^l}$
,因此再經由反向傳播求出損失函數對激活函數的輸入$z_i^l$的偏導數,即可進行神經網路的參數更新。若接下來經過一個激活函數$σ(∙)$後就是我們的最終輸出$y$,也就是輸出的關係式如下:
\begin{equation}
y_i=\sigma(z_i^l)
\end{equation}
  因此未知的$\frac{\partial L(w,b))}{\partial z_i^l}$可寫成:
\begin{equation}
\frac{\partial L(w,b)}{\partial z_i^l}=\frac{\partial L(w,b)}{\partial y_i}\frac{\partial y_i}{\partial z_i^l}
\end{equation}
  到這裡我們可以發現這兩個微分我們都是已知的,因此我們可以輕易地算出他們的乘積:
\begin{equation}
=>\frac{\partial L(w,b)}{\partial z_i^l}=\frac{\partial L(w,b)}{\partial y_i}\sigma'(z)
\end{equation}
  接著再將$\frac{\partial L(w,b))}{\partial z_i^l}$帶入$\frac{\partial L(w,b)}{\partial w_i^l}$與$\frac{\partial L(w,b)}{\partial b_i^l}$的式子中,即可得到各參數的梯度,我們便可以快速地利用梯度下降法更新參數。

  • Convolution (卷積) (主要功能為特徵擷取)

        在圖像辨識領域,廣泛採用convolution layer作為特徵擷取層,學習過影像處理的人,應該聽說過知名的影像邊緣偵測器(梯度擷取器)──Sobel Filter,CNN藉由梯度下降學習的權重就是卷積核的權重,藉由學習卷積核權重就可以擷取出有用的影像特徵。下圖是一個CNN卷積核學習的實際例子,我們隨機挑選CNN中的一個$3×3$的卷積核,左側是經過1 epoch (完成一次完整訓練集學習的單位),右側則是經過80 epoch,每個圖像的下方搭配的數值矩陣是對應上圖filter中的pixel value:

(卷積核權重學習變化示意圖)

  與原始的類神經網路往相比,採用卷積的概念也降低了深層神經網路的權重數量這是因為CNN最大特色是局部感知權重共享。原始神經網路的全連接層(fully connected layer,或稱隱藏層──hidden layer)是將所有神經元彼此連接,若考慮一$200×200$影像,共有$200×200$個神經元(一個影像像素即對應一組權重與偏差),若下層具有相同數量之神經元,即共有$(200×200)^2$個權重需要訓練,如下圖所示:


        然而影像關係是屬於局部性的,故每個神經元不需與影像中所有像素連接,且與過複雜的連接導致維度過大,也會致使訓練與測試時間過長。因此我們可改採用局部連接(每個神經元只對濾波器遮罩到的區塊連接)。$200×200$影像 一樣有$200×200$個神經元,若設置$10×10$的濾波器做局部連接,然而下層每個神經元只需要與$10×10$個神經元相連接,參數數量會降為$200×200×(10×10)$,如下圖:


        影像之局部特性與其局部區域於統計上相同特性,故即使我們藉由學習影像的局部訊息學習模型參數,仍可以將其運用至其他區塊,即可從局部區塊學習共同的參數,藉此抽取影像特徵。因此可導入convolution概念解決此問題,若考慮以$10×10$卷積核設置為共享的學習參數並設置使用濾波器為$10$個,則權重總量縮減至$(10×10)×10$,使神經網路於影像辨識領域可達到實用性質,此外,因為抽取局部特徵的概念,也強化了鄰近pixel間的關聯性,如下圖:




   
        在一個$m×n$的影像$I$中,若具有一之$a×b$濾波器$G$於$I$內之子區塊$I_x$進行卷積,可將其輸出表示為下式,其中$σ(∙)$為激活函數(activation function),

\begin{equation}y=\sigma(w^l I_x+b^l )\end{equation}

若設定濾波器數量為$k$,則輸出便有$k$個$(m-a+1)×(n-b+1)$的特徵圖。

  可設置的超參數 (以Caffe網路架設設定為例):

為了避免第一次接觸Caffe的人看不懂這個架構,在這裡簡易介紹一下Caffe的網路架構定義方式。神經網路每一層的類型定義在type (譬如下圖是Convolution),而傳遞方式是以bottom layer傳遞到top layer,填入的字串是layer的名稱。而下方的param就是該layer的超參數設定,如下圖:



  1. kernel_size:濾波器(卷積核,kernel)的大小
  2. stridefilter移動時間隔的pixel數量
  3. pad卷積前影像外圍補零的pixel圈數
  4. num_output:filter的數量,每個filter會輸出1張feature map,所以這超參數叫做輸出數量。
  5. weight_filler:權重初始化方式,例如gaussian, xavier等
  6. bias_filler偏權值的初始化方式。

  • Max Pooling (池化) (主要功能為影像降維)

        Pooling的操作在於影像的降維,且能提供一定程度的平移不變性。在這裡我們舉最常被使用的max pooling為例,max pooling是利用濾波器$G$在特徵影像$I$滑動,並取其局部區塊$I_x$最大值,並在$I_x$內其內部最大值擇一取代濾波器內的所有值。以一個size為2x2、stride為2的max pooling如下圖所示: (右側的四個值都是各自顏色下的最大值)


      由於max pooling的濾波器大小深度與輸入特徵影像相同,故會保持總特徵通道數不變,但特徵影像尺度降低。max pooling搭配convolution時,可用下式表示,其中$P(∙)$與$σ(∙)$分別代表max pooling與激活運算、,其中$x_i^{l-1}$代表max pooling的輸入特徵:

\begin{equation}x_i^l=\sigma(w_i^l P(x_i^{l-1})+b_i^l ) \end{equation}


  可設置的超參數 (以Caffe網路架設設定為例):



(圖源:Caffe: Pooling)

  1. kernel_size濾波器(卷積核,kernel)的大小
  2. stridefilter移動時間隔的pixel數量
  3. pad卷積前影像外圍補零的pixel圈數
  4. poolpooling的類型,max、min或avg


參考網站

Stanford University CS231n 

3 則留言:

  1. 你好,我想問一下 caffe 的卷積層範例中有 lr_mult 跟 decay_mult 這兩個參數有甚麼作用?

    回覆刪除
    回覆
    1. 這兩個參數能讓不同層有各自的learning rate與weight decay,lr_mult與decay_mult分別是這層卷積層learning rate與weight decay的乘積,譬如原本的learning rate是0.001,若lr_mult是2,就代表設置這層的learning rate為0.002

      刪除
  2. 您好 我想了解一下問中介紹梯度下降法前面為何對於layer b的計算 : b(l)=b(l−1)−η∂L/∂w 中我們還是要損失函數L對權重w求偏導數而不是對權重b? 請問這裡有沒有打錯呢?

    回覆刪除