1.應用場景
卷積神經網絡的應用不可謂不廣泛,主要有兩大類,數據預測和圖片處理。數據預測自然不需要多說,圖片處理主要包含有圖像分類,檢測,識別,以及分割方面的應用。
圖像分類:場景分類,目標分類
圖像檢測:顯著性檢測,物體檢測,語義檢測等等
圖像識別:人臉識別,字符識別,車牌識別,行為識別,步態識別等等
圖像分割:前景分割,語義分割
2.卷積神經網絡結構
卷積神經網絡主要是由輸入層、卷積層、激活函數、池化層、全連接層、損失函數組成,表面看比較復雜,其實質就是特征提取以及決策推斷。
要使特征提取盡量准確,就需要將這些網絡層結構進行組合,比如經典的卷積神經網絡模型AlexNet:5個卷積層+3個池化層+3個連接層結構。
2.1 卷積(convolution)
卷積的作用就是提取特征,因為一次卷積可能提取的特征比較粗糙,所以多次卷積,以及層層縱深卷積,層層提取特征(千萬要區別於多次卷積,因為每一層里含有多次卷積)。
這里可能就有小伙伴問:為什么要進行層層縱深卷積,而且還要每層多次?
你可以理解為物質A有自己的多個特征(高、矮、胖、瘦、、、),所以在物質A上需要多次提取,得到不同的特征,然后這些特征組合后發生化學反應生成物質B,
而物質B又有一些新的專屬於自己的特征,所以需要進一步卷積。這是我個人的理解,不對的話或者有更形象的比喻還請不吝賜教啊。
在卷積層中,每一層的卷積核是不一樣的。比如AlexNet
第一層:961111(96表示卷積核個數,11表示卷積核矩陣寬高) stride(步長) = 4 pad(邊界補零) = 0
第二層:25655 stride(步長) = 1 pad(邊界補零) = 2
第三,四層:38433 stride(步長) = 1 pad(邊界補零) = 1
第五層:2563*3 stride(步長) = 1 pad(邊界補零) = 2
卷積的篇幅說了這么多,那么到底是如何進行運算的呢,雖說網絡上關於卷積運算原理鋪天蓋地,但是個人總感覺講得不夠透徹,或者說本人智商有待提高,
希望通過如下這幅圖(某位大神的傑作)來使各位看官們能夠真正理解。
這里舉的例子是一個輸入圖片(553),卷積核(333),有兩個(Filter W0,W1),偏置b也有兩個(Bios b0,b1),卷積結果Output Volumn(332),步長stride = 2。
輸入:773 是因為 pad = 1 (在圖片邊界行和列都補零,補零的行和的數目是1),
(對於彩色圖片,一般都是RGB3種顏色,號稱3通道,77指圖片高h * 寬w)
,補零的作用是能夠提取圖片邊界的特征。
卷積核深度為什么要設置成3呢?這是因為輸入是3通道,所以卷積核深度必須與輸入的深度相同。至於卷積核寬w,高h則是可以變化的,但是寬高必須相等。
卷積核輸出o[0,0,0] = 3 (Output Volumn下淺綠色框結果),這個結果是如何得到的呢? 其實關鍵就是矩陣對應位置相乘再相加(千萬不要跟矩陣乘法搞混淆啦)
=> w0[:,:,0] * x[:,:,0]藍色區域矩陣(R通道) + w0[:,:,1] * x[:,:,1]藍色區域矩陣(G通道)+ w0[:,:,2] * x[:,:,2]藍色區域矩陣(B通道) + b0(千萬不能丟,因為 y = w * x + b)
第一項 => 0 * 1 + 0 * 1 + 0 * 1 + 0 * (-1) + 1 * (-1) + 1 * 0 + 0 * (-1) + 1 * 1 + 1 * 0 = 0
第二項 => 0 * (-1) + 0 * (-1) + 0 * 1 + 0 * (-1) + 0 * 1 + 1 * 0 + 0 * (-1) + 2 * 1 + 2 * 0 = 2
第三項 => 0 * 1 + 0 * 0 + 0 * (-1) + 0 * 0 + 2 * 0 + 2 * 0 + 0 * 1 + 0 * (-1) + 0 * (-1) = 0
卷積核輸出o[0,0,0] = > 第一項 + 第二項 + 第三項 + b0 = 0 + 2 + 0 + 1 = 3
o[0,0,1] = -5 又是如何得到的呢?
因為這里的stride = 2 ,所以 輸入的窗口就要滑動兩個步長,也就是紅色框的區域,而運算跟之前是一樣的
第一項 => 0 * 1 + 0 * 1 + 0 * 1 + 1 * (-1) + 2 * (-1) + 2 * 0 + 1 * (-1) + 1 * 1 + 2 * 0 = -3
第二項 => 0 * (-1) + 0 * (-1) + 0 * 1 + 1 * (-1) + 2 * 1 + 0 * 0 + 2 * (-1) + 1 * 1 + 1 * 0 = 0
第三項 => 0 * 1 + 0 * 0 + 0 * (-1) + 2 * 0 + 0 * 0 + 1 * 0 + 0 * 1 + 2 * (-1) + 1 * (-1) = - 3
卷積核輸出o[0,0,1] = > 第一項 + 第二項 + 第三項 + b0 = (-3) + 0 + (-3) + 1 = -5
之后以此卷積核窗口大小在輸入圖片上滑動,卷積求出結果,因為有兩個卷積核,所有就有兩個輸出結果。
這里小伙伴可能有個疑問,輸出窗口是如何得到的呢?
這里有一個公式:輸出窗口寬 w = (輸入窗口寬 w - 卷積核寬 w + 2 * pad)/stride + 1 ,輸出高 h = 輸出窗口寬 w
以上面例子, 輸出窗口寬 w = ( 5 - 3 + 2 * 1)/2 + 1 = 3 ,則輸出窗口大小為 3 * 3,因為有2個輸出,所以是 33*2。
2.2 Relu激活函數
相信看過卷積神經網絡結構(CNN)的伙伴們都知道,激活函數無處不在,特別是CNN中,在卷積層后,全連接(FC)后都有激活函數Relu的身影,
那么這就自然不得不讓我們產生疑問:
問題1、為什么要用激活函數?它的作用是什么?
問題2、在CNN中為什么要用Relu,相比於sigmoid,tanh,它的優勢在什么地方?
對於第1個問題:由 y = w * x + b 可知,如果不用激活函數,每個網絡層的輸出都是一種線性輸出,而我們所處的現實場景,其實更多的是各種非線性的分布。
這也說明了激活函數的作用是將線性分布轉化為非線性分布,能更逼近我們的真實場景。
對於第2個問題: 先看sigmoid,tanh分布
他們在 x -> 時,輸出就變成了恆定值,因為求梯度時需要對函數求一階偏導數,而不論是sigmoid,還是tanhx,他們的偏導都為0,
也就是存在所謂的梯度消失問題,最終也就會導致權重參數w , b 無法更新。相比之下,Relu就不存在這樣的問題,另外在 x > 0 時,
Relu求導 = 1,這對於反向傳播計算dw,db,是能夠大大的簡化運算的。
使用sigmoid還會存在梯度爆炸的問題,比如在進行前向傳播和反向傳播迭代次數非常多的情況下,sigmoid因為是指數函數,其結果中
某些值會在迭代中累積,並成指數級增長,最終會出現NaN而導致溢出。
2.3 池化
池化層一般在卷積層+ Relu之后,它的作用是:
1、減小輸入矩陣的大小(只是寬和高,而不是深度),提取主要特征。(不可否認的是,在池化后,特征會有一定的損失,所以,有些經典模型就去掉了池化這一層)。
它的目的是顯而易見的,就是在后續操作時能降低運算。
2、一般采用mean_pooling(均值池化)和max_pooling(最大值池化),對於輸入矩陣有translation(平移),rotation(旋轉),能夠保證特征的不變性。
mean_pooling 就是輸入矩陣池化區域求均值,這里要注意的是池化窗口在輸入矩陣滑動的步長跟stride有關,一般stride = 2.(圖片是直接盜過來,這里感謝原創)
最右邊7/4 => (1 + 1 + 2 + 3)/4
max_pooling 最大值池化,就是每個池化區域的最大值放在輸出對應位置上。
2.4 全連接(full connection)
作用:分類器角色,將特征映射到樣本標記空間,本質是矩陣變換(affine)。
至於變換的實現見后面的代碼流程圖,或者最好是跟一下代碼,這樣理解更透徹。
2.5 損失函數(softmax_loss)
作用:計算損失loss,從而求出梯度grad。
常用損失函數有:MSE均方誤差,SVM(支持向量機)合頁損失函數,Cross Entropy交叉熵損失函數。
這幾種損失函數目前還看不出誰優誰劣,估計只有在具體的應用場景中去驗證了。至於這幾種損失函數的介紹,
大家可以去參考《常用損失函數小結》https://blog.csdn.net/zhangjunp3/article/details/80467350,這個哥們寫得比較詳細。
在后面的代碼實例中,用到的是softmax_loss,它屬於Cross Entropy交叉熵損失函數。
softmax計算公式:
其中, 是要計算的類別 的網絡輸出,分母是網絡輸出所有類別之和(共有 個類別), 表示第 類的概率。
交叉熵損失:
其中, 是類別 的真實標簽, 表示第 類的概率, 是樣本總數, 是類別數。
梯度:
其中 ypred[i]表示真實標簽對應索引下預測的目標值, j類別索引。
這個有點折磨人,原理講解以及推導請大家可以參考這位大神的博客:http://www.cnblogs.com/zongfa/p/8971213.html。
2.6 前向傳播(forward propagation)
前向傳播包含之前的卷積,Relu激活函數,池化(pool),全連接(fc),可以說,在損失函數之前操作都屬於前向傳播。
主要是權重參數w , b 初始化,迭代,以及更新w, b,生成分類器模型。
2.7 反向傳播(back propagation)
反向傳播包含損失函數,通過梯度計算dw,db,Relu激活函數逆變換,反池化,反全連接。
2.8 隨機梯度下降(sgd_momentum)
作用:由梯度grad計算新的權重矩陣w
sgd公式:
其中,η為學習率,gt為x在t時刻的梯度。
一般我們是將整個數據集分成n個epoch,每個epoch再分成m個batch,每次更新都利用一個batch的數據,而非整個訓練集。
優點:batch的方法可以減少機器的壓力,並且可以更快地收斂。
缺點:其更新方向完全依賴於當前的batch,因而其更新十分不穩定。
為了解決這個問題,momentum就橫空出世了,具體原理詳解見下路派出所(這名字霸氣)的博客http://www.cnblogs.com/callyblog/p/8299074.html。
momentum即動量,它模擬的是物體運動時的慣性,即更新的時候在一定程度上保留之前更新的方向,同時利用當前batch的梯度微調最終的更新方向。
這樣一來,可以在一定程度上增加穩定性,從而學習地更快,並且還有一定擺脫局部最優的能力:
其中,ρ 即momentum,表示要在多大程度上保留原來的更新方向,這個值在0-1之間,在訓練開始時,由於梯度可能會很大,所以初始值一般選為0.5;
當梯度不那么大時,改為0.9。η 是學習率,即當前batch的梯度多大程度上影響最終更新方向,跟普通的SGD含義相同。ρ 與 η 之和不一定為1。
3.代碼實現流程圖以及介紹
代碼流程圖:費了老大勁,終於弄完了,希望對各位看官們有所幫助,建議對比流程圖和跟蹤代碼,加深對原理的理解。
特別是前向傳播和反向傳播維度的變換,需要重點關注。
4. 參考文獻
視覺一只白的博客《常用損失函數小結》https://blog.csdn.net/zhangjunp3/article/details/80467350
理想萬歲的博客《Softmax函數詳解與推導》:http://www.cnblogs.com/zongfa/p/8971213.html
下路派出所的博客《深度學習(九) 深度學習最全優化方法總結比較(SGD,Momentum,Nesterov Momentum,Adagrad,Adadelta,RMSprop,Adam)》
http://www.cnblogs.com/callyblog/p/8299074.html