深度学习之Batch Normalization
1、Batch Normalization的引入
在機器學習領域有個很重要的假設:IID獨立同分布假設,也就是假設訓練數據和測試數據是滿足相同分布的,這是通過訓練數據獲得的模型能夠在測試集上獲得好的效果的一個基本保障。在深度學習網絡中,后一層的輸入是受前一層的影響的,而為了方便訓練網絡,我們一般都是采用Mini-Batch SGD來訓練網絡的(Mini-Batch SGD的兩個優點是:梯度更新方向更準確和并行計算速度快)。
我們知道在神經網絡訓練開始前,都要對輸入數據做一個歸一化處理,那么具體為什么需要歸一化呢?歸一化后有什么好處呢?原因在于神經網絡學習過程本質就是為了學習數據分布,一旦訓練數據與測試數據的分布不同,那么網絡的泛化能力也大大降低;另外一方面,一旦每批訓練數據的分布各不相同(batch 梯度下降),那么網絡就要在每次迭代都去學習適應不同的分布,這樣將會大大降低網絡的訓練速度,這也正是為什么我們需要對數據都要做一個歸一化預處理的原因。
對于深度網絡的訓練是一個復雜的過程,只要網絡的前面幾層發生微小的改變,那么后面幾層就會被累積放大下去。一旦網絡某一層的輸入數據的分布發生改變,那么這一層網絡就需要去適應學習這個新的數據分布,所以如果訓練過程中,訓練數據的分布一直在發生變化,那么將會影響網絡的訓練速度。
除了輸入層的數據外(因為輸入層數據,我們已經人為的為每個樣本歸一化),后面網絡每一層的輸入數據分布是一直在發生變化的,因為在訓練的時候,前面層訓練參數的更新將導致后面層輸入數據分布的變化。以網絡第二層為例:網絡的第二層輸入,是由第一層的參數和input計算得到的,而第一層的參數在整個訓練過程中一直在變化,因此必然會引起后面每一層輸入數據分布的改變。
我們把網絡中間層在訓練過程中,數據分布的改變稱之為:“Internal ?Covariate?Shift”。nternal指的是深層網絡的隱層,是發生在網絡內部的事情,而不是covariate shift問題只發生在輸入層。Batch Normalization就是來解決該問題的。Batch Normalization的基本思想就是能不能讓每個隱層節點的激活輸入分布固定下來,從而避免Internal Covariate Shift的問題。
?
2、Batch Normalization的本質思想
就像激活函數層、卷積層、全連接層、池化層一樣,BN(Batch Normalization)也屬于網絡的一層。BN的基本思想其實相當直觀:因為深層神經網絡在做非線性變換前的激活輸入值(就是那個x=WU+B,U是輸入)隨著網絡深度加深或者在訓練過程中,其分布逐漸發生偏移或者變動,之所以訓練收斂慢,一般是整體分布逐漸往非線性函數的取值區間的上下限兩端靠近(對于Sigmoid函數來說,意味著激活輸入值WU+B是大的負值或正值),所以這導致后向傳播時低層神經網絡的梯度消失,這是訓練深層神經網絡收斂越來越慢的本質原因,而BN就是通過一定的規范化手段,把每層神經網絡任意神經元這個輸入值的分布強行拉回到均值為0方差為1的標準正態分布,其實就是把越來越偏的分布強制拉回比較標準的分布,這樣使得激活輸入值落在非線性函數對輸入比較敏感的區域,這樣輸入的小變化就會導致損失函數較大的變化,意思是這樣讓梯度變大,避免梯度消失問題產生,而且梯度變大意味著學習收斂速度快,能大大加快訓練速度。
首先我們來看下期望為0,方差為1的標準正態分布:
這意味著在一個標準差范圍內,也就是說64%的概率x其值落在[-1,1]的范圍內,在兩個標準差范圍內,也就是說95%的概率x其值落在了[-2,2]的范圍內。我們知道,激活值x=WU+B,U是真正的輸入,x是某個神經元的激活值,假設非線性函數是sigmoid,那么看下sigmoid函數及其導數如下:
我們可以從中觀察到,sigmoid函數的導數范圍是(0, 0.25]。假設沒有經過BN調整前x的原先正態分布均值是-6,方差是1,那么意味著95%的值落在了[-8, -4]之間,那么對應的Sigmoid函數值及其導數的值都明顯接近于0,這是典型的梯度飽和區,在這個區域里梯度變化很慢,導數接近于0意味著梯度變化很小甚至消失。而假設經過BN后,均值是0,方差是1,那么意味著95%的x值落在了[-2, 2]區間內,很明顯這一段是sigmoid(x)函數接近于線性變換的區域,意味著x的小變化會導致非線性函數值較大的變化,也即是梯度變化較大,對應導數函數圖中明顯大于0的區域,就是梯度非飽和區。
這種性質不只是適用于sigmoid函數,也適用于其他的激活函數。而且從圖中經過BN后,使得大部分的激活值落入非線性函數的線性區內(也就是在0附近的那一段,很多激活函數都有這樣的性質),在這里對應的導數遠離導數飽和區,這樣來加速訓練收斂過程。
但是從上面來看,把大部分激活值拉入到線性區,也就相當于在網絡的傳輸過程中對輸入值做了一系列的線性變換,那么此時網絡的表達能力急劇下降,而且深層也沒有意義(多層的線性轉換和一層的線性轉換是一樣的)。為了解決這個問題,BN對標準化后的值X又進行了scale加上shift操作(y=scale*x+shift)。對每個神經元增加了兩個參數scale和shift參數,這兩個參數是通過訓練學習到的,意思是通過scale和shift把這個值從標準正態分布左移或者由移一點并長胖一點或者變瘦一點,每個實例挪動的程度不一樣,這樣等價于非線性函數的值從正中心周圍的線性區往非線性區動了動。這樣看似之前的標準化變換毫無意義,又回到了起點。其實不然,大神博主張俊林認為:這種做法的核心思想應該是想找到一個線性和非線性的較好平衡點,既能享受非線性的較強表達能力的好處,又避免太靠非線性區兩頭使得網絡收斂速度太慢。這種想法看似是有一定的道理的,盡量保證激活值在非線性區域,而又不會進入到梯度飽和區。
?
3、Batch Normalization算法
Batch Normalization操作就像激活函數層、卷積層、全連接層、池化層一樣,也屬于網絡中的一層。我們要對每個隱層神經元的激活值做BN,那么就可以想象成每個隱層又加上了一層BN操作層,它位于X=WU+B激活值獲得之后,非線性函數變換之前,其圖示如下:
具體BN網絡層的前向傳播過程如下
在這里的期望μB是每一次Mini-Batch SGD時的Mini-Batch的均值,σB2也是Mini-Batch的方差。
在做驗證或者測試時只有一個樣本的輸入,此時沒有Mini-Batch,那么怎么計算標準化的期望和方差呢?在訓練的過程中我們會將每一次梯度下降時的Mini-Batch的期望和方差保存起來,在驗證和測試時我們就用這些保存的期望和方差的期望值來作為此時的期望和方差(這句話有點拗口,其實就是在訓練過程中會計算很多批Mini-Batch的期望和方差,在之后的驗證和測試的時候,我們將這批Mini-Batch的期望和方差分別求平均值來作為此時的期望和方差)。具體算法流程如下:
在得到了均值和方差之后的計算和訓練時計算公式有點不一樣(也只是表現形式不一樣,本質和訓練時是一樣的):
至于為什么要寫成上述形式,可能是為了減少計算量,因為在實際的驗證和測試時我們的γ、β、μ和σ值都是已經確實的,這樣在一開始就求出
然后保存起來,這樣就避免了重復計算的過程。
?
4、Batch Normalization的優點
1)你可以選擇比較大的初始學習率,讓你的訓練速度飆漲。以前還需要慢慢調整學習率,甚至在網絡訓練到一半的時候,還需要想著學習率進一步調小的比例選擇多少比較合適,現在我們可以采用初始很大的學習率,然后學習率的衰減速度也很大,因為這個算法收斂很快。當然這個算法即使你選擇了較小的學習率,也比以前的收斂速度快,因為它具有快速訓練收斂的特性。
2)你再也不用去理會過擬合中drop out、L2正則項參數的選擇問題,采用BN算法后,你可以移除這兩項了參數,或者可以選擇更小的L2正則約束參數了,因為BN具有提高網絡泛化能力的特性。
3)再也不需要使用使用局部響應歸一化層了(局部響應歸一化是Alexnet網絡用到的方法),因為BN本身就是一個歸一化網絡層。
4)可以把訓練數據徹底打亂(防止每批訓練的時候,某一個樣本都經常被挑選到,文獻說這個可以提高1%的精度,這句話我也是百思不得其解啊)。
?
5、Batch Normalization在CNN中的應用
?BN在CNN中的應用也同樣采用共享權值的操作,把一個FilterMap看成一個整體,可以想象成是一個Filter Map對應DNN隱層中的一個神經元,所以一個Filter Map的所有神經元共享一個Scale和Shift參數,Mini-Batch里m個實例的統計量均值和方差是在p*q個神經元里共享,就是說從m*p*q個激活里面算Filter Map全局的均值和方差,這體現了Filter Map的共享參數特性,當然在實際計算的時候每個神經元還是各算各的BN轉換值,只不過采用的統計量和Scale,shift參數用的都是共享的同一套值而已。
?
6、Batch Normalization在RNN中的應用
對于RNN來說,希望引入BN的一個很自然的想法是在時間序列方向展開的方向,即水平方向(圖1)在隱層神經元節點引入BN,因為很明顯RNN在時間序列上展開是個很深的深層網絡,既然BN在深層DNN和CNN都有效,很容易猜想這個方向很可能也有效。
另外一個角度看RNN,因為在垂直方向上可以疊加RNN形成很深的Stacked ?RNN,這也是一種深層結構,所以理論上在垂直方向也可以引入BN,也可能會有效。但是一般的直覺是垂直方向深度和水平方向比一般深度不會太深,所以容易覺得水平方向增加BN會比垂直方向效果好。
然而關于上面兩種用法還是有很多爭議,不一定都能有好的結果,具體的結論可能如下:
1)RNN垂直方向引入BN的話:如果層數不夠深(感覺5層是各分界線),那么BN的效果不穩定或者是有損害效果,如果深度足夠的話,是能夠加快訓練收斂速度和泛化性能的。
2)在隱層節點做BN的話:
就是對水平序和垂直序單獨做BN,然后再相加。
3)在水平方向做BN時,因為RNN在不同時間點水平展開后參數共享的,所以就產生了BN在不同時間序列的參數也是共享的,事實證明這是不行的。因此BN在RNN中在每個時間點神經元上必須維護各自的統計量和參數。
4)在水平方向做BN時,Scala參數要足夠小,一般設置為0.1是可以的。
參考文獻:
Batch Normalization導讀
CNN和RNN中如何引入BatchNorm
深度學習(二十九)Batch Normalization 學習筆記
[深度學習] Batch Normalization算法介紹
轉載于:https://www.cnblogs.com/jiangxinyang/p/9372678.html
總結
以上是生活随笔為你收集整理的深度学习之Batch Normalization的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 数据库垂直拆分和水平拆分
- 下一篇: 《细说PHP》分页源代码
