1. 程式人生 > >卷積神經網絡(CNN)

卷積神經網絡(CNN)

分類 tro 最大的 color b- nal 情況 屬於 時間

一、引言

  神經網絡不是具體的算法,而是一種模型構造的思路或者方式,BP神經網絡是通過線性分類器後面直接跟隨激勵神經元,然後前後收尾相連接形成網絡的方式。每一個神經元節點的輸入都來自於上一層的每個神經元的輸出,這種方式叫做“全連接”。當然BP神經網絡也可以不是全連接的,後面會講到。

  全連接的好處在於從他的連接方式上看是每個輸入維度的信息都會傳播到其後的任意一個結點中去,會最大程度地讓整個網絡中的節點都不會“漏掉”這個維度所貢獻的因素。不過他的缺點更加明顯,那就是整個網絡由於都是“全連接”方式,所以w和b參數格外的多,這就使得訓練過程中說要更新的參數權重非常多,整個網絡訓練的收斂會非常慢。於是發明了卷積神經網絡

(convolutional neural network,CNN)。

  卷積神經網絡同樣是一種前饋神經網絡,他的神經元可以響應一部分覆蓋範圍內的周圍單元,在大規模的模式識別有很好的性能表現,該網絡可以避免對圖片的復雜前期預處理,直接輸入原始圖像。

  卷積網絡的兩大特點:

  (1)、卷積網絡由至少一個卷積層,用來提取特征

  (2)、卷積網絡的卷積層通過權值共享的方式進行工作,大大減少權值w的數量,使得在訓練中達到同樣識別率的情況下收斂速度明顯快與全連接BP網絡。

二、卷積

  卷積是通過兩個函數f和g生成第三個函數的一種數學算子,表征函數f和g經過翻轉和平移的重疊部分的面積。

  卷積的數學定義是這樣的:$$h(x)=f(x)*g(x)=\int_{-\infty }^{+\infty }f(t)g(x-t)dt$$

  $f(t)g(x-t)$是,$f(t)$先不動,$g(-t)$相當於$g(t)$函數的圖像沿著y軸(t=0)做一次翻轉。$g(x-t)$相當於g(-t)的整個圖像沿著t軸平移,向右平移x個單位。卷積的值等於$f(t)$和$g(x-t)$相乘後與y=0軸圍城的面積。在隨著x變化移動的過程中,由於g(x-t)移動產生的h(x)的對應變化就是整個卷積公式的意義了————一個移動中用x進行取樣的過程,或者說特征提取。

三、卷積核

  理解了卷積之後再理解卷積核,就容易多了,我們只需要理解它是在滑動中去特征提取就足夠了。

卷積核的表達式:$$f(x)=wx+b$$

  我們先假設有這樣一幅5*5一共25個像素點的圖片,每個像素點只有1和0兩種取值。我們設計一個卷積核:

$$w= [1,0,1,0,1,0,1,0,1],b=[0]$$

  指定圖片中從左到右從上到下的9個像素作為x,挨個與w相乘完成內積。

技術分享圖片 技術分享圖片

 $$f(x)=1*1+0*1+1*1+0*0+1*1+1*0+0*1+0*0+1*1+0=4$$

  結果右邊的正方形第一個存儲空間就會輸出6,這些存儲空間就叫做卷積層的feature map,也就是圖中convolved Feature部分。9個信息被壓縮成一個,這當然屬於無損壓縮,還原肯定是還原不回去的了。這個抽樣的過程就叫做特征的提取。同時也是一種信息壓縮。

  卷積層的工作就是這樣,至於w和b值初始化之後,也是通過一輪一輪的訓練,在降低損失函數的目的下不斷的學習和更新。

  在卷積核的$f(x)=wx+b$輸出後一般會跟一個激勵函數緊隨其後,現在的CNN網絡中的激勵函數非常喜歡用ReLU函數,

四、卷積層的其他參數

  還有兩個重要的參數需要註意一個是Padding(填充),一個是Striding(步幅)。

4.1 Padding(填充)

  填充是指用多少像素單位來填充輸入圖像(向量)的邊界。如下圖所示,圖片的四周區域都進行Padding,通常都是用來填充0,一般在800*600的圖過卷積層的時候,能夠在四周各Padding上5-10個單位就不少了。

技術分享圖片

技術分享圖片

Padding大概有兩種目的,

目的1:保持邊界信息。如果不加Padding的話,最邊緣的信息其實僅僅被卷積核掃描了一遍,而圖片中間的像素點信息被掃描了多遍,在一定程度上就愛你工地了邊界上信息的參考程度。

目的2:如果輸入的圖片尺寸有差異,可以通過Padding來進行補齊,使得輸入的尺寸一致,以免頻繁調整卷積核和其它層的工作模式。

4.2 Stride(步幅)

  Stride可以理解為每次滑動的單位。一般取Stride=1,當Stride比較大的時候,會跳過很多信息,但好處是處理時間大大的縮短。

  在設計網絡的時候,先設置Stride=1,如果工作狀況已經很理想,而希望通過加大Stride來獲得一些性能的提升或者存儲量的減少。那麽可以通過適當的調整Stride=2,來獲得速度的提升。

五、池化層

  池化層實際上是對Feature Map所做的數據處理之後又進行了一次所謂的池化處理。常見的兩種池化操作有兩種:

一種叫做Max Pooling,就是在前面輸出過來的數據做一個取最大值的處理,

技術分享圖片

另一種叫做Mean Pooling,就是在前面輸出過來的數據做一個取平均值的處理。

池化層有這麽幾種功能:

第一:它進行了一次特征提取,減小了下一層數據的處理量

第二:這個特征提取,能夠有更大的可能性進一步獲取更為抽象的信息,防止過擬合,也可以說提高了一定的漢化能力。

第三:能夠對輸入的微小變化產生更大的容忍。

激活函數

Sigmoid 激活函數

sigmoid函數定義如下

$$\sigma (x)=\frac{1}{1+e^{-z}} ;z=wx+b$$

如下圖所示:實現sigmoid函數的代碼

技術分享圖片
import matplotlib.pyplot as plt
import numpy as np

def sigmoid(x):
    # 直接返回sigmoid函數
    return 1. / (1. + np.exp(-x))

def plot_sigmoid():
    # param:起點,終點,間距
    x = np.arange(-6, 6, 0.001)
    y = sigmoid(x)
    print("x等於0的點", sigmoid(0))
    plt.plot(x, [0.5] * len(x), b:)        # 畫水平虛線
    plt.plot([0] * len(y), y, b:)
    plt.plot(x, y, "r")
    plt.show()

if __name__ == __main__:
    plot_sigmoid()
Sigmoid

技術分享圖片

當輸入在$(-\infty ,+\infty)$的區間上變化,位於$(0,1)$區間上的輸出值變化很小,sigmoid函數是連續的,

以sigmoid為激活函數的神經單元具有感知器類似的行為。

ReLU 激活函數

ReLU被稱為修正線性單元,ReLU的函數定義為:

$$f(x)=max(0,x)$$

對於負值函數值為零,對於正值函數值呈線性增長。

技術分享圖片

SOFTMAX 激活函數

  神經元中有兩個部分,一個是線性單元,一個是激勵函數(非線性)。SOFTMAX的函數表達式是:

$$SOFTMAX:a_i=\sigma_i(z)=\frac{e^{z_i}}{\sum_{j=1}^{m}e^{z_j}},z_i=w_ix+b$$

作用:把神經元中線性部分輸出的得分值(score),轉換為概率值。softmax輸出的是(歸一化)概率,

  含有softmax激活函數的網絡層有這樣一個性質:$\sum_{i=1}^{j}\sigma _i(z)=1$,可以解釋為每個節點的輸出值小於等於1。softmax激勵函數通常在神經網絡的最後一層作為分類器的輸出,輸出值(概率)最大的即為分類結果。

$$貓:\begin{pmatrix}0.05\\ 0.05\\ 0.7\\ 0.2\end{pmatrix}
狗:\begin{pmatrix}0.8\\ 0.06\\ 0.01\\ 0.04\end{pmatrix}$$

交叉熵 損失函數

  SOFTMAX的損失函數叫做“交叉熵”。假如從盒中黑球的個數為16,白球的個數為14,那麽從盒中抽到黑球的先驗概率為$\frac{16}{30}$,熵越大,事件的不確定性越大。

  交叉熵的表達式為:$$L=-\sum_{i}y_i\log a_i$$

  式中$a_i$是softmax激勵函數的輸出,$y_i$是線性單元的輸出值。

  交叉熵所描述的是經過訓練分類結果的信息熵和測試集分類結果的信息熵之間的差距。在擬合過程中產生的熵是有差距的,這個差距由交叉熵來定義。那麽只要熵差越小,就越接近真實值。

$$標簽分類結果:\begin{pmatrix}1\\ 0\\ 0\\ 0\end{pmatrix}
訓練分類結果:\begin{pmatrix}0.8\\ 0.05\\ 0.1\\ 0.05\end{pmatrix}$$

使用交叉熵作為損失函數可以避免梯度消散。

One-hot編碼 OHE

  獨熱編碼(one-hot encoding):使用一個向量的每一個維度來標識一種性質的有無。

$$貓:\begin{pmatrix}1\\ 0\\ 0\\ 0\end{pmatrix}
狗:\begin{pmatrix}0\\ 1\\ 0\\ 0\end{pmatrix}
蛇:\begin{pmatrix}0\\ 0\\ 1\\ 0\end{pmatrix}
豬:\begin{pmatrix}0\\ 0\\ 0\\ 1\end{pmatrix}$$

梯度消失問題

  梯度消失就是訓練的損失函數$Loss$不再收斂,$Loss$過早的不再下降,精確度也過早的不再提高。有兩種方法:

方法一:初始化一個合適的w

  假設我們把w初始化成10,在sigmoid函數為0的地方,導數的絕對值是$\frac{1}{4}$,這樣看來確實是大了,但是原來是導數太小導致網絡前端的w更新太慢,後者是變化率太高,一次變化量太大。

方法二:選一個合適的激活函數——ReLU

$$y=\left\{\begin{matrix}0&&x \leq 0\\ x&&x>0\end{matrix}\right.$$

技術分享圖片

  這個激活函數的優點在於:在第一象限不會有明顯的梯度下降問題,因為導數恒為1,並且求導計算時間比sigmoid小很多。

歸一化

  歸一化的目的就是讓各維度的數據分布經過“拉伸”投影到一個近似的尺度範圍去。

  常見的歸一化方法有:線性函數歸一化、0均值歸一化,通過softmax函數也是一種歸一化操作。

線性函數歸一化:$X_{norm}=\frac{X-X_{min}}{X_{max}-X_{min}}$

零均值歸一化:各維度的值減去各自的平均值,這樣就有一堆有正有負的值且0在中心位置。

參數初始化問題

  在搭建神經網絡的時候,我們有件事情不得不做,那就是參數w、b等的初始化,業界來說,把整個網路中所有的w初始化成以0為均值、以一個很小的$\mu$為標準差的正態分布的方式會比較好。

  最常見的是以0為均值、1為方差的正態分布來隨機初始化。

  還有一種常見的初始化方法是以0為均值、1為方差的正態分布生成後除以當前層的神經元個數的算術平方來獲得初始化。

  如果你非要問為什麽,思路大致是這樣的:對於一個模型中輸入權重的設置相當於一種重視程度,而一個模型中需要我們非常重視或者不怎麽重視的輸入一定是少數,而其他大部分輸入的信息可能就比較中庸,對判斷結果影響比較小的因素的信息比較多。

  說來也有意思,自然界中大部分數據的統計分布都服從高斯分布的特點。

正則化

L1正則化懲罰項:  $Lose = {Lose}_0 + \frac{\lambda }{n}\sum_{w}|w|$

L2正則化懲罰項:  $Lose = {Lose}_0 + \frac{\lambda }{2n}\sum_{w}|w^2|$

  我們對損失方式添加了正則化懲罰項來進行改造。加上正則化懲罰項能在一定程度上避免過擬合。

  前一部分的損失函數叫做“經驗風險”,經驗風險就是由於擬合結果和樣本標簽之間的殘差總和所產生的這種經驗差距所帶來的風險。

  後一部分的損失函數叫做“結構風險”,結構風險是因為我們希望這種描述能夠簡潔來保證其泛化性的良好。

  註意$\lambda$不是指學習率,而是一個權重,也可以稱為正則化系數,表示對後面這部分的“重視程度”。

舉個例子,比如我們兩個模型的輸入權重系數為下所示,我們使用L2正則化懲罰系數,為了方便我們只計算“結構風險”

$$W_1=\begin{pmatrix}1\\ 0\\ 0\\ 0\end{pmatrix}
W_2=\begin{pmatrix}\frac{1}{4}\\ \frac{1}{4}\\ \frac{1}{4}\\ \frac{1}{4}\end{pmatrix}$$

$$\sum W_1^2=[1,0,0,0]^2=1^2+0^2+0^2+0^2=1$$

$$\sum W_2^2=[\frac{1}{4},\frac{1}{4},\frac{1}{4},\frac{1}{4}]^2={\frac{1}{4}}^2+{\frac{1}{4}}^2+{\frac{1}{4}}^2+{\frac{1}{4}}^2={\frac{1}{4}}$$

  由上可見,模型2的結構風險比模型1的小,所以模型2的損失函數小,模型2的泛化能力更強。這就是正則化的好處。

其他的超參數

  超參數是指那些在機器學習算法中訓練前設定的一些初始化參數,這些參數沒法通過算法本身來學習。比如:$W_0,b_0$,還有學習率$\eta$

不唯一模型

  我們如果訓練多次,比較結果深度學習的模型可能會每次都不一樣,因為訓練過程中的隨機因素比較多,幾乎遍布整個訓練過程,比如:隨機梯度下降算法選取的求梯度數據,還有去正態分布的權值。

卷積網路做圖片分類

  用CNN應用於CIFAR-10的一個實驗。聲明一點,普通的全連接BP網絡跑一下CIFAR-10也是一個比較好的結果,只不過用CNN跑能夠收斂的更快,更高的精確度。項目中包含60000張32*32像素的彩色圖片,擁有10個不同類別的標簽。其中訓練集50000張,測試集10000張。tensorflow官方在github提供了CNN做CIFAR10實驗的代碼,位置在models/tutorials/images/cifar10。

單個GPU版本:cifar10_trian.py,以及cifar10.py、cifar10_input.py。

多個GPU版本:cifar10_multi_gpu_train.py

卷積神經網絡(CNN)