1. 程式人生 > >CNN(卷積神經網路)詳解

CNN(卷積神經網路)詳解

Why CNN

首先回答這樣一個問題,為什麼我們要學CNN,或者說CNN為什麼在很多領域收穫成功?還是先拿MNIST來當例子說。MNIST資料結構不清楚的話自行百度。。

我自己實驗用兩個hidden layer的DNN(全連線深度神經網路)在MNIST上也能取得不錯的成績(98.29%)。下面是一個三個hidden layer的網路結構圖
盜圖1
盜圖1

全連線深度神經網路,顧名思義,每個神經元都與相鄰層的神經元連線。在這個實驗中,每個數字的image是28*28,也就是784(=28*28)個數值,每個數值對應一個畫素值,值的大小反應畫素點的強度。這就意味著我們網路的輸入層有784個神經元。輸出層呢?由於我們是預測0-9這幾個數字,輸出層當然就是10個神經元了。至於隱藏層節點的個數我們可以自行選定,本實驗中選的是500.

我們想想為什麼DNN在訓練後能夠正確地分類?那肯定是它學到了東西,學到什麼東西呢?它學到了圖片中的某些空間結構,不同數字它們的空間結構肯定是不一樣的,而這樣的空間結構就是由畫素點與畫素點之間的關係形成。我們再仔細看DNN輸入層和第一個隱藏層,發現它對我們輸入的784個畫素點是同等對待的,也就是說它此時並沒有考慮畫素點與畫素點之間的關係。有沒有一個好點的模型能夠考慮到這點呢?那就是CNN

CNN有三個幾本思想,區域性感受野(local receptive fields) 權值共享(shared weights) 池化(pooling)

區域性感受野(local receptive fields)

剛剛我們在DNN中是把輸入層784個神經元排成了一條長線,這裡我們還原圖片原來的樣子(28*28),如下圖

強迫症的同學就不要數每行每列幾個了,我已經數過了是28了。。偷笑
盜圖2
盜圖2

DNN中,我們會把輸入層的每個神經元都與第一個隱藏層的每個神經元連線(看看盜圖1)。而在CNN中我們這樣做的,第一個隱藏層的神經元只與區域性區域輸入層的神經元相連。下圖就是第一個隱藏層的某個神經元與區域性區域輸入層的神經元相連的情況。
盜圖3
盜圖3

這裡的區域性區域就是區域性感受野,它像一個架在輸入層上的視窗。你可以認為某一個隱藏層的神經元學習分析了它”視野範圍“(區域性感受野)裡的特徵。圖中一個隱藏層的神經元有5*5個權值引數與之對應。

我們移動這樣一個視窗使它能夠掃描整張圖,每次移動它都會有一個不同的節點與之對應。我們從輸入層左上角開始,如下
盜圖4
盜圖4

然後,我們一個畫素往右滑動一個畫素,如下
盜圖5
盜圖5

以此類推可以形成第一個隱藏層,注意我們的圖片是28*28的,視窗是5*5的,可以得到一個24*24(24=28-5+1)個神經元的隱藏層

這裡我們的視窗指滑動了一個畫素,通常說成一步(stride),也可以滑動多步,這裡的stride也是一個超參,訓練是可以根據效果調整,同樣,視窗大小也是一個超參。

權值共享(Shared weights and biases)
上一節中提到一個隱藏層的神經元有5*5個權值引數與之對應。這裡要補充下,這24*24個隱藏層的神經元它們的權值和偏移值是共享的 用公式描述下

σ(b+l=04m=04wl,maj+l,k+m)

σ代表的是啟用函式,如sigmoid函式等,b就是偏移值,w就是5*5個共享權值矩陣,我們用矩陣a表示輸入層的神經元,ax,y表示第x+1行第y+1列那個神經元(注意,這裡的下標預設都是從0開始計的,a0,0表示第一行第一列那個神經元)所以通過矩陣w線性mapping後再加上偏移值就得到公式中括號裡的式子,表示的是隱藏層中第j+1行k+1列那個神經元的輸入。有點暈的話就參照上面的圖,圖4就是j=k=0的情況,圖5是j=0,k=1. 最後加上啟用函式就表示該隱藏神經元的輸出了。這部分原理和DNN是一樣的,如果把w改成28*28的矩陣就變成了全連線,就是DNN了。

我們能不能簡化一下這個公式呢

a1=σ(b+wa0)

a1表示隱藏層的輸出,a0表示隱藏層的輸入,而∗就表示卷積操作(convolution operation) 這也正是卷積神經網路名字的由來。

由於權值共享,視窗移來移去還是同一個視窗,也就意味著第一個隱藏層所有的神經元從輸入層探測(detect)到的是同一種特徵(feature),只是從輸入層的不同位置探測到(圖片的中間,左上角,右下角等等),必須強調下,一個視窗只能學到一種特徵!另外,視窗還有其他叫法:卷積核(kernal),過濾器(filter)。我們在做影象識別時光學習一個特徵肯定是不夠的,我們想要學習更多的特徵,就需要更多的視窗。如果用三個視窗的話如下圖
盜圖6
盜圖6

視窗與視窗間的w和b是不共享的,三個視窗就表示有三個w矩陣和三個偏移值b,結果是從整張圖片的各個位置學到三種不同的特徵。到這裡肯定有人會問,你說學到特徵了,怎麼證明學到了呀?現在我們用20個視窗來學習MNIST裡的圖片特徵,我們只看20個窗口裡的權值矩陣w,如果把這20個w畫成20張黑白圖,每張圖片都是5*5(一個權值代表一個畫素點),如下圖所示
盜圖7
盜圖7

盯著其中的一張看,白色區域表示權值比較小,說明視窗的這部分對輸入層的神經元不敏感(responds less),相反黑色部分表示權值比較大,說明視窗的這部分對輸入層的神經元敏感(responds more).每張圖片都有明顯的黑白區域,這也能夠說明CNN確實學到一些和空間結構相關的特徵。究竟學的是什麼特徵呢?這個很難回答清楚,此處暫不深究,更好理解的話可以參考 Visualizing and Understanding Convolutional Networks

權值共享還有一個很大的好處,就是可以大大減少模型引數的個數。我們的例子中,一個視窗引數個數是26(5*5+1),20個視窗就是520個引數,如果換成全連線的話就是785(28*28+1)個引數,比CNN多了265個引數。可能你覺得265嘛,對計算機來說完全不算什麼。如果我們是30個隱藏層的DNN的話(深度學習裡很常見的),需要23550(785*30)個引數,是CNN的45倍多。。當然我們也不能光光去比較它們引數的個數,畢竟兩個模型本質原理上就相差甚遠,但是直覺上我們可以感受到,CNN可以依靠更少的引數來獲得和DNN相同的效果,更少的引數就意味著更快的訓練速度,這可是誰都想要的。

池化(Pooling)

CNN還有一個重要思想就是池化,池化層通常接在卷積層後面。池化這個詞聽著就很有學問,其實引入它的目的就是為了簡化卷積層的輸出。通俗地理解,池化層也在卷積層上架了一個視窗,但這個視窗比卷積層的視窗簡單許多,不需要w,b這些引數,它只是對視窗範圍內的神經元做簡單的操作,如求和,求最大值,把求得的值作為池化層神經元的輸入值,如下圖,這是一個2*2的視窗
盜圖8
盜圖8

值得注意的是,我們此時的視窗每次移動兩步,採用的是求最大值的方法,所有稱之為max-pooling,剛剛卷積層含有24*24個神經元,經過池化後到池化層就是12*12個神經元。通常卷積層的視窗是多個的,池化層的視窗也是多個的。簡單來說,卷積層用一個視窗去對輸入層做卷積操作,池化層也用一個視窗去對卷積層做池化操作。但是注意這兩個操作的本質區別。下面來看一個用三個卷積視窗和跟隨其後的池化視窗長啥樣。
盜圖9
盜圖9

怎麼理解max-pooling呢?由於經過了卷積操作,模型從輸入層學到的特徵反映在卷積層上,max-pooling做的事就是去檢測這個特徵是否在視窗覆蓋範圍的區域內。這也導致了,它會丟失這種特徵所在的精準位置資訊,所幸的是池化層可以保留相對位置資訊。而後者相比而言比前者更重要。不理解上面的話也沒關係,但是需要記住池化層一個最大的好處:經過池化後,大大減少了我們學到的特徵值,也就大大減少了後面網路層的引數(上圖可以看出池化層的神經元數明顯少於卷積層神經元數)。

max-pooling技術只是池化技術的一種,還有一種比較常用的是L2-pooling,與max-pooling唯一的區別就是在池化視窗掃過的區域裡做的操作不是求最大值,而是所有神經元平方後求和再開根號,這和我們L2正則對權值引數的操作是一樣的。實際操作中,這兩種方式都是比較常用的。池化操作方式的選擇也是我們調參工作的一部分,我們可以根據validation data集來調節,選擇更好的池化操作。

總的來看

介紹完CNN的三個幾本思想概念後我們把它串起來看下。
盜圖10
盜圖10
從左往右依次是輸入層,卷積層,池化層,輸出層。輸入層到卷積層,卷積層到池化層已經詳細介紹過了。池化層到輸出層是全連線,這和DNN是一樣的。
整體上把我CNN的網路架構,其實和DNN很相似,都是一層一層組合起來的,層與層之間的行為也是有對應的權值w和偏移值b決定的,並且它們的目的也是一致的:通過training data來學習網路結構中的w和b,從而能把輸入的圖片正確分類。很簡單吧。

到此為之,CNN的基本原理大致介紹完畢了,如果只需對CNN做大致瞭解的話上面的內容我想應該足夠了。下面主要介紹下其數學原理了。

CNN的BP演算法

DNN的BP演算法

介紹CNN的BP演算法之前還是先看下DNN的吧,兩者有很多相似的地方。
這裡我假設大家都理解了DNN的網路結構了,首先引入一些數學符號。

al:第l層神經元的輸出
zl:第l層神經元的輸入
Wl:從l-1層mapping到l層權值矩陣
bl:與上面引數對應的偏移值
x:train data的輸入
y:train data正確的label
這裡設我們的輸出層為第L層,對應aL,採用均方差來度量損失,那麼對應的損失函式就是

J(W,b,x,y)=12||aLy||22(1)
好了,有了損失函式就開始用梯度下降法了。記住我們的目的是為了求出每層的Wb
先來看下輸出層的輸出aL=σ(zL)=σ(WLaL1+bL)(2)
我們把(2)代入(1)中得到J(W,b,x,y)=12||aLy||22=12||σ(WLaL1+bL)y||22(3)
我們利用鏈式求導法,求得W,b的梯度