cite from: http://blog.csdn.net/myarrow/article/details/51848285
1. 機器學習流程簡介
1)一次性設置(One time setup)
-激活函數(Activation functions)
- 數據預處理(Data Preprocessing)
- 權重初始化(Weight Initialization)
-正則化(Regularization:避免過擬合的一種技術)
- 梯度檢查(Gradient checking)
2)動態訓練(Training dynamics)
- 跟蹤學習過程 (Babysitting the learning process)
- 參數更新 (Parameter updates)
- 超級參數優化(Hyperparameter optimization)
- 批量歸一化(BN:Batch Normalization:解決在訓練過程中,中間層數據分布發生改變的問題,以防止梯度消失或爆炸、加快訓練速度)
3)評估(Evaluation)
- 模型組合(Model ensembles)
(訓練多個獨立的模型,測試時,取這些模型結果的平均值)
神經網絡學習過程本質就是為了:學習數據分布,一旦訓練數據與測試數據的分布不同,那么網絡的泛化能力也大大降低,所以需要使用輸入數據歸一化方法,使訓練數據與測試數據的分布相同。
詳細內容參見:激活函數
總結:
1)使用ReLU時,使Learning Rates盡量小
2)嘗試使用Leaky ReLU/Maxout/ELU
3)可以使用tanh,但期望不要太高
4)不要使用sigmoid
1)為什么輸入數據需要歸一化(Normalized Data)?
歸一化后有什么好處呢?原因在于神經網絡學習過程本質就是為了學習數據分布,一旦訓練數據與測試數據的分布不同,那么網絡的泛化能力也大大降低;另外一
方面,一旦每批訓練數據的分布各不相同(batch
梯度下降),那么網絡就要在每次迭代都去學習適應不同的分布,這樣將會大大降低網絡的訓練速度,這也正是為什么我們需要對數據都要做一個歸一化預處理的原
因。
對于深度網絡的訓練是一個復雜的過程,只要網絡的前面幾層發生微小的改變,那么后面幾層就會被累積放大下去。一旦網絡某一層的輸入數據的分布發生改
變,那么這一層網絡就需要去適應學習這個新的數據分布,所以如果訓練過程中,訓練數據的分布一直在發生變化,那么將會影響網絡的訓練速度。
4. 權重初始化(Weight Initialization)
1)小的隨機數
w= 0.01 * np.random.randn(fan_in,fan_out)
2)神經元將飽和,梯度為0
w = 1.0 * np.random.randn(fan_in,fan_out)
3)合理的初始化(Xavier init)
w = np.random.randn((fan_in,fan_out)/np.sqrt(fan_in)
權重初始化是一個重要的研究領域。
5. 批量歸一化(BN: Batch Normalization)
1)隨機梯度下降法(SGD)對于訓練深度網絡簡單高效,但是它有個毛病,就是需要我們人為的去選擇參數,比如學習率、參數初始化、權重衰減系數、Drop out比例等。這些參數的選擇對訓練結果至關重要,以至于我們很多時間都浪費在這些的調參上。那么使用BN(詳見論文《Batch Normalization_ Accelerating Deep Network Training by Reducing Internal Covariate Shift》)之后,你可以不需要那么刻意的慢慢調整參數。
2)神經網絡一旦訓練起來,那么參數就要發生更新,除了輸入層的數據外(因為輸入層數據,我們已經人為的為每個樣本歸一化),后面網絡每一層的輸入數據分布是一直在發生變化的,因為在訓練的時候,前面層訓練參數的更新將導致后面層輸入數據分布的變化。以網絡第二層為例:網絡的第二層輸入,是由第一層的參數和input計算得到的,而第一層的參數在整個訓練過程中一直在變化,因此必然會引起后面每一層輸入數據分布的改變。我們把網絡中間層在訓練過程中,數據分布的改變稱之為:“Internal ?Covariate Shift”。Paper所提出的算法,就是要解決在訓練過程中,中間層數據分布發生改變的情況,于是就有了Batch ?Normalization,這個牛逼算法的誕生。
3)BN的地位:與激活函數層、卷積層、全連接層、池化層一樣,BN(Batch Normalization)也屬于網絡的一層。
4)BN的本質原理:在網絡的每一層輸入的時候,又插入了一個歸一化層,也就是先做一個歸一化處理(歸一化至:均值0、方差為1),然后再進入網絡的下一層。不過文獻歸一化層,可不像我們想象的那么簡單,它是一個可學習、有參數(γ、β)的網絡層。
5)歸一化公式:
6)如果是僅僅使用上面的歸一化公式,對網絡某一層A的輸出數據做歸一化,然后送入網絡下一層B,這樣是會影響到本層網絡A所學習到的特征的。比如我網
絡中間某一層學習到特征數據本身就分布在S型激活函數的兩側,你強制把它給我歸一化處理、標準差也限制在了1,把數據變換成分布于s函數的中間部分,這樣
就相當于我這一層網絡所學習到的特征分布被你搞壞了,這可怎么辦?于是文獻使出了一招驚天地泣鬼神的招式:變換重構,引入了可學習參數γ、β,這就是算法
關鍵之處:
上面的公式表明,通過學習到的重構參數γ、β,是可以恢復出原始的某一層所學到的特征的。
7)引入了這個可學習重構參數γ、β,讓我們的網絡可以學習恢復出原始網絡所要學習的特征分布。最后Batch Normalization網絡層的前向傳導過程公式就是:
8)BN層是對于每個神經元做歸一化處理,甚至只需要對某一個神經元進行歸一化,而不是對一整層網絡的神經元進行歸一化。既然BN是對單個神經元的運算,那么在CNN中卷積層上要怎么搞?假如某一層卷積層有6個特征圖,每個特征圖的大小是100*100,這樣就相當于這一層網絡有6*100*100個神經元,如果采用BN,就會有6*100*100個參數γ、β,這樣豈不是太恐怖了。因此卷積層上的BN使用,其實也是使用了類似權值共享的策略,把一整張特征圖當做一個神經元進行處理。
9)卷積神經網絡經過卷積后得到的是一系列的特征圖,如果min-batch
sizes為m,那么網絡某一層輸入數據可以表示為四維矩陣(m,f,w,h),m為min-batch
sizes,f為特征圖個數,w、h分別為特征圖的寬高。在CNN中我們可以把每個特征圖看成是一個特征處理(一個神經元),因此在使用Batch
Normalization,mini-batch size
的大小就是:m*w*h,于是對于每個特征圖都只有一對可學習參數:γ、β。說白了吧,這就是相當于求取所有樣本所對應的一個特征圖的所有神經元的平均
值、方差,然后對這個特征圖神經元做歸一化。
10) ? ?在使用BN前,減小學習率、小心的權重初始化的目的是:使其輸出的數據分布不要發生太大的變化。
11)BN的作用:
1)改善流經網絡的梯度
2)允許更大的學習率,大幅提高訓練速度:
你
可以選擇比較大的初始學習率,讓你的訓練速度飆漲。以前還需要慢慢調整學習率,甚至在網絡訓練到一半的時候,還需要想著學習率進一步調小的比例選擇多少比
較合適,現在我們可以采用初始很大的學習率,然后學習率的衰減速度也很大,因為這個算法收斂很快。當然這個算法即使你選擇了較小的學習率,也比以前的收斂
速度快,因為它具有快速訓練收斂的特性;
3)減少對初始化的強烈依賴
4)改善正則化策略:作為正則化的一種形式,輕微減少了對dropout的需求
你再也不用去理會過擬合中drop out、L2正則項參數的選擇問題,采用BN算法后,你可以移除這兩項了參數,或者可以選擇更小的L2正則約束參數了,因為BN具有提高網絡泛化能力的特性;
5)再也不需要使用使用局部響應歸一化層了(局部響應歸一化是Alexnet網絡用到的方法,搞視覺的估計比較熟悉),因為BN本身就是一個歸一化網絡層;
6)可以把訓練數據徹底打亂(防止每批訓練的時候,某一個樣本都經常被挑選到,文獻說這個可以提高1%的精度)。
注:以上為學習過程,在測試時,均值和方差(mean/std)不基于小批量進行計算, 可取訓練過程中的激活值的均值。
1)實際測試時,我們依然使用下面的公式:
這里的均值和方差已經不是針對某一個Batch了,而是針對整個數據集而言。因此,在訓練過程中除了正常的前向傳播和反向求導之外,我們還要記錄每一個Batch的均值和方差,以便訓練完成之后按照下式計算整體的均值和方差:
上面簡單理解就是:對于均值來說直接計算所有batch u值的平均值;然后對于標準偏差采用每個batch σB的無偏估計。最后測試階段,BN的使用公式就是:
2)BN可以應用于一個神經網絡的任何神經元上。文獻主要是把BN變換,置于網絡激活函數層的前面。在沒有采用BN的時候,激活函數層是這樣的:
z=g(Wu+b)
也就是我們希望一個激活函數,比如s型函數s(x)的自變量x是經過BN處理后的結果。因此前向傳導的計算公式就應該是:
z=g(BN(Wu+b))
其實因為偏置參數b經過BN層后其實是沒有用的,最后也會被均值歸一化,當然BN層后面還有個β參數作為偏置項,所以b這個參數就可以不用了。因此最后把BN層+激活函數層就變成了:
z=g(BN(Wu))
1)Learning Rate
- Learning Rate太小(如1e-6),cost下降很慢
- Learning Rate太大(如1e-6),cost增長爆炸 (cur cost > 3* original cost)
- 在[1e-3,1e-5]范圍內比較合適
2)Mini-batch SGD
Loop:
1.Samplea batch of data
2.Forwardprop it through the graph, get loss
3.Backpropto calculate the gradients
4.Updatethe parameters using gradient
參數優化的目的是:減少損失(loss), 直至損失收斂(convergence)
每次基于整個數據集計算梯度。
[python]view plaincopy
foriinrange(nb_epochs):
params_grad?=?evaluate_gradient(loss_function,?data,?params)
params?=?params?-?learning_rate?*?params_grad
7.1.2 SGD(Stochastic Gradient Descent: 隨機梯度下降)
每次基于一個數據樣本計算梯度。
[python]view plaincopy
foriinrange(nb_epochs):
np.random.shuffle(data)
forexampleindata:
params_grad?=?evaluate_gradient(loss_function,?example,?params)
params?=?params?-?learning_rate?*?params_grad
7.1.3?Mini-batch Gradient Descent
每次基于n個數據樣本計算梯度。
[python]view plaincopy
foriinrange(nb_epochs):
np.random.shuffle(data)
forbatchinget_batches(data,?batch_size=50):
params_grad?=?evaluate_gradient(loss_function,?batch,?params)
params?=?params?-?learning_rate?*?params_grad
優點:
1)減少參數更新的變化, 從而得到更加穩定的收斂
2)使用先進的Deep Learning庫,可以高效地計算mini-batch的梯度
注:n一般取[50,256]范圍內的數,視具體應用而定。
1)選擇合適的Learning Rate是困難的,太小導致收斂慢,太大阻礙收斂或且導致損失函數在最小值附近波動或發散;
2)預先定義的Learning Rate變動規則不能適應數據集的特性;
3)同樣的Learning Rate運用到所有的參數更新(后面的AdaGrad, AdaDelta, RMSProp, Adam為解決此問題而生);
4)最小化高度非凸損失函數的羝問題是:避免陷入眾多的局部最優值。
關鍵優點: 利用物體運動時的慣性,加快到達全局最優點的速度,且減少振蕩。
關鍵缺點:球盲目地沿著斜坡向山下滾。
當Loss function的表面曲線的一維比其它維有更多的溝壑時,SGD要跨越此溝壑是困難的,如上圖左邊所示,SGD沿著溝壑的斜坡振蕩,然后猶猶豫豫地向局部最優點前進。
Momentum即動量,它模擬的是物體運動時的慣性,即更新的時候在一定程度上保留之前更新的方向,同時利用當前batch的梯度微調最終的更新方向。這樣一來,可以在一定程度上增加穩定性,從而學習地更快,并且還有一定擺脫局部最優的能力:
[python]view plaincopy
#?Momentum?update
V?=?gama?*?V?+?learning_rate?*?dw#?integrate?velocity
w?-=?V#?integrate?position
就是Momentum,經常取0.5,0.9,或0.99,有時隨著時間而變化,從0.5到0.99;表示要在多大程度上保留原來的更新方向,這個值在0-1之間,在訓練開始時,由于梯度可能會很大,所以初始值一般選為0.5;當梯度不那么大時,改為0.9。
是學習率,即當前batch的梯度多大程度上影響最終更新方向,跟普通的SGD含義相同。
與
之和不一定為1。
Momentum的物理解釋是:當我們把球推下山時,球不斷地累積其動量,速度越來越快(直到其最大速度,如果有空氣阻力,如
<1),同樣的事情發生在參數更新中:梯度保持相同方向的維度的動量不停地增加,梯度方向不停變化的維度的動量不停地減少,因此可以得到更快的收斂速度并減少振蕩。
7.3?Nesterov Accelerated Gradient (NAG)
關鍵優點:一個聰明的球,知道它將到哪兒去,且知道在斜坡向上之前減速。
沿著當前方向,先走一步,然后再看向哪個方向走最快,這樣對前方的情況就有了更多地了解,可以做出明智的決策。
[python]view plaincopy
w_ahead?=?w?-?gama?*?v
#?evaluate?dw_ahead?(the?gradient?at?w_ahead?instead?of?at?w)
v?=?gama?*?v?+?learning_rate?*?dw_ahead
w?-=?v
Momentum:
1)計算當前的梯度(上圖中:比較小的藍色向量)
2)沿著更新的累積的梯度方向進行一大跳(上圖中:比較大的藍色向量)
NAG:
1)沿著以前累積的梯度方向進行一大跳 (上圖中:棕色向量)
2)在新的位置測量梯度,然后進行校正(上圖中:綠色向量)
3)這個有預料的更新可以防止走的太快并導致增加的響應
關鍵區別:
1)計算梯度的位置不一樣
7.4 每個參數有自適應的學習率(Per-parameter Adaptive Learning Rate)
本章描述的方法(AdaGrad、AdaDelta、RMSprop、Adam)專為解決Learning Rate自適應的問題。
前面討論的基于梯度的優化方法(SGD、Momentum、NAG)的Learning Rate是全局的,且對所有參數是相同的。
參數的有些維度變化快,有些維度變化慢;有些維度是負的斜坡,有些維度是正的斜坡(如鞍點);采用相同的Learning Rate是不科學的,比如有的參數可能已經到了僅需要微調的階段,但又有些參數由于對應樣本少等原因,還需要較大幅度的調動。理想的方案是根據參數每個維度的變化率,采用對應的Learning Rate。
下面討論如何自適應Learing Rate的方案:AdaGrad、AdaDelta、RMSProp、Adam。
7.4.1 AdaGrad(Adaptive Gradient?)
關鍵優點:不需要手動調整Learning Rate,默認值為0.01即可。
關鍵缺點:在分母中累積了梯度的平方,且此累積值單調遞增,從而導致Learning Rate單調遞減,直至無限小,從而不能再學到相關知識(AdaDelta、RMSprop、Adam專為解決此問題而生)。
AdaGrad方法給參數的每個維度給出適應的Learning Rate。給不經常更新的參數以較大的Learning Rate, 給經常更新的參數以較小的Learning Rate。Google使用此優化方法“識別Youtube視頻中的貓” 。
在AdaGrad中,每個參數
在每一次更新時都使用不同的Learming Rate。
其公式如下:
θi
其示意代碼如下:
[python]view plaincopy
#?Assume?the?gradient?dx?and?parameter?vector?x
cache?+=?dx**2
x?-=?learning_rate?*?dx?/?(np.sqrt(cache?+1e-8))
learning_rate?是初始學習率,由于之后會自動調整學習率,所以初始值就不像之前的算法那樣重要了。而1e-8指一個比較小的數,用來保證分母非0。
其含義是,對于每個參數,隨著其更新的總距離增多,其學習速率也隨之變慢。
7.4.2 AdaDelta (Adaptive Delta)
關鍵優點:1) 解決了AdaGrad Learning Rate單調遞減的問題。(是AdaGrad的擴展)
2) 不需要設置默認的Learning Rate
RMS(Root Mean Squared) : 均方根
Adagrad算法存在三個問題:
1)其學習率是單調遞減的,訓練后期學習率非常小
2)其需要手工設置一個全局的初始學習率
3)更新W時,左右兩邊的單位不同
Adadelta針對上述三個問題提出了比較漂亮的解決方案。
RMSprop是由Geoff Hinton設計的。RMSprop與AdaDelta的目的一樣:解決AdaGrad的Learning Rate逐步消失的問題。
7.4.4 Adam (Adaptive Moment Estimation)
Adam的目的是:為每個參數計算自適應的Learning Rate。
其實際效果與AdaDelta、RMSProp相比,毫不遜色!
SGD optimization on Beale's function
SGD optimization on Long Valley
SGD optimization on?Saddle Point
1)總結:
- RMSprop是AdaGrad的擴展,以解決learning rate逐步消失的問題
- RMSprop與AdaDelta相比,AdaDelta在分子更新規則中使用了參數RMS更新,其它相同
- Adam與RMSprop相比,增加了偏差校正和動量
- RMSprop、AdaDelta和Adam是非常類似的算法,在類似的環境下,效果相當
-從整體上看,Adam目前是最好的選擇
2)如果輸入數據是稀疏的(sparse),使用adaptive learning-rate(AdaGrad、AdaDelta、RMSprop、Adam)可以獲得最好的結果,且不需要調整learning rate;
3)如果你關心快速收斂,你應當選擇adaptive learning-rate方法
7.7.1 Shuffling and Curriculum Learning
1)Shuffling:每次迭代前,隨機打亂訓練樣本的順序
2)Curriculum Learning:把訓練樣本按某種有意義的方式進行排序,對逐步解決困難問題有效。
7.7.2 批量歸一化Batch Normalization (BN)
為了便于訓練,我們經常歸一化參數的初始值,通過mean=0, variance=1的高斯分布來初始化參數。在訓練過程中,我們不同程度地更新參數,使用參數失去了歸一化,這將降低訓練速度且放大變化,網絡越深問題越嚴重。
BN為每一個mini-batch重建歸一化參數。使模型結構的部分進行歸一化,我們可以使用更高的learning rate,且參數初始化要求沒哪么高。
此外,BN還作為一個正則化(Regularizer),可以減少或避免使用Dropout。
正則化(Regularizer):是一個用于解決過擬合(Overfitting)問題的一種技術。具體實現方法是在損失函數中增加懲罰因子(參數向量的范數,1范數(L1)或2范數(L2))lambda*N(w)。
在訓練時,總是監視驗證集的錯誤率,如果驗證集的錯誤率不能得到改善,應當停止訓練。
在前向計算時,隨機設置一些神經元的值為0,如下圖所示:
示意代碼如下:
[python]view plaincopy
p?=0.5#?probability?of?keeping?a?unit?active,?higher?=?less?dropout
deftrain_step(X)
"""?X?contains?the?data?"""
#?forward?pass?for?example?3-layer?neural?network
H1?=?np.maximum(0,?np.dot(W1,?X)?+?b1)
M1?=?np.random.rand(*H1.shape)?<?p#?first?dropout?mask
H1?*=?M1#?drop
H2?=?np.maximum(0,?np.dot(W2,?H1)?+?b2)
M2?=?np.random.rand(*H2.shape)?<?p#?send?dropout?mask
H2?*=?M2#?drop
out?=?np.dot(W3,H2)?+?b3
相當于訓練多個模型,一個dropout mask對應一個模型,且這些模型共享參數。
在測試時,不需要dropout, 直接計算每層的激活值,然后進行scale作為本層最終輸出的激活值,其代碼如下:
[python]view plaincopy
defpredict(X):
#?ensembled?forward?pass
H1?=?np.maxmium(0,?np.dot(W1,X)+b1)?*?p#?Note:?scale?the?activations
H2?=?np.maxmium(0,?np.dot(W2,H1)+b2)?*?p#?Note:?scale?the?activations
out?=?np.dot(W3,H2)?+?b3