目錄
一、batch normalization和layer normalization的動機
三、Bert、Transformer中爲何使用的是LN而很少使用BN
在深度學習中經常看到batch normalization的使用,在Bert模型裏面經常看到layer normalization的使用。它們都是歸一化的方法,具體的作用和區別以及爲何能夠work,我認爲需要有一個很好的理解。因此,在參考了一些資料形成了這篇博客。
一、batch normalization和layer normalization的動機
batch normalization和layer normalization,顧名思義其實也就是對數據做歸一化處理——也就是對數據以某個角度或者層面做0均值1方差的處理。
在機器學習和深度學習中,有一個共識:獨立同分布的數據可以簡化模型的訓練以及提升模型的預測能力——這是通過訓練數據獲得的模型能夠在測試集獲得好的效果的一個基本保障。也就是說我們在使用機器學習和深度學習的時候,會把數據儘可能的做一個獨立同分布的處理,用來加快模型的訓練速度和提升模型的性能。說到這裏就不得不提一下——白化whitening。
白化whitening
什麼是白化呢?就是對數據進行如下的2個操作:
1、去除數據之間的關聯性,使之滿足獨立這個條件;2、使得特徵具有相同的均值和方差,就是同分布。
以上就是白化,具體的算法有PCA降維白化,參考博文——機器學習(七)白化whitening。
首先看看,深度學習中的一個經典問題。Internal Covariate Shift——內部變量偏移
Internal Covariate Shift——內部變量偏移
深度學習這種包含很多隱層的網絡結構,在訓練過程中,因爲各層參數不停在變化。另一方面,深度神經網絡一般都是很多層的疊加,每一層的參數更新都會導致上層的輸入數據在輸出時分佈規律發生了變化,並且這個差異會隨着網絡深度增大而增大——這就是Internal Covariate Shift。它會導致什麼樣的問題呢?
每個神經元的輸入數據不再是獨立同分布的了,那麼:
- 上層參數需要不斷適應新的輸入數據分佈,降低學習速度
- 下層輸入的變化可能趨向於變大或者變小,導致上層落入飽和區。反向傳播時低層神經網絡的梯度消失,這是訓練深層神經網絡收斂越來越慢的本質原因——梯度消失。
BN把每層神經網絡任意神經元這個輸入值的分佈強行拉回到均值爲0方差爲1的標準正態分佈,其實就是把越來越偏的分佈強制拉回比較標準的分佈。這樣讓梯度變大,避免梯度消失問題產生,而且梯度變大意味着學習收斂速度快,能大大加快訓練速度。經過BN後,目前大部分Activation的值落入非線性函數的線性區內,其對應的導數遠離導數飽和區,這樣來加速訓練收斂過程。
這就是在深度學習中使用BN的一個原因和動機,當然使用LN也是同樣的以不同的方式來達到相似的效果。
對於爲何BN能起作用這個問題,有不同的觀點。有人認爲BN能夠減少ICS問題,但是有人發佈論文說並沒有直接的證據表明BN能夠穩定數據分佈的穩定性,同時也不能減少ICS。作者認爲起作用的原因是由於:An empirical analysis of the optimization of deep network loss surfaces
1、BN層讓損失函數更平滑
2、BN更有利於梯度下降,使得梯度不會出現過大或者過小的梯度值。
二、BN和LN的框架原理
2.1BN和LN的具體操作原理
BN一般怎麼使用呢?原論文的作者是建議把BN放在激活函數之前,但是後面有人建議放在之後,效果都差不太多。
圖片來自博文——Batch Normalization詳解
以上就是在一些神經網絡中,BN的插入位置。
下面來看看具體的BN公式和流程。現在假設batch size爲m,那麼在前向傳播過程中每個節點就有m個輸出。則有如下計算方式:
變換後某個神經元的激活x形成了均值爲0,方差爲1的正態分佈,目的是把值往後續要進行的非線性變換的線性區拉動,增大導數值,增強反向傳播信息流動性,加快訓練收斂速度。但是這樣會導致網絡表達能力下降,爲了防止這一點,每個神經元增加兩個調節參數(scale和shift),這兩個參數是通過訓練來學習到的,用來對變換後的激活反變換,使得網絡表達能力增強,即對變換後的激活進行如下的scale和shift操作,這其實是變換的反操作:
BN不同,LN是針對深度網絡的某一層的所有神經元的輸入按以下公式進行normalize操作——來自博客:Layer Normalization
1)計算各層的期望μ和標註差σ
l表示第l個隱藏層,H表示該層的節點數,a表示某一個節點在激活前的值,即a=w*x。
2)標準化
g和b分別表示增益和偏置參數,可以納入訓練隨樣本一羣訓練。
3)加入激活函數輸出
2.2BN和LN的優點和不足
BN具有一些什麼樣的優點呢?
a、加快神經網絡的訓練時間。BN強行拉平了數據分佈,它可以讓收斂速度更快。使得總的訓練時間更短。
b、容忍更高的學習率(learning rate)和初始化權重更容易。對於深層網絡來說,權重的初始化要求是很高的,而BN能夠動態的調整數據分佈,因此初始化的要求就不像以前那麼嚴格了。
c、可以支持更多的損失函數。有些損失函數在一定的業務場景下表現的很差,就是因爲輸入落入了激活函數的死亡區域——飽和區域。而BN的本質作用就是可以重新拉正數據分佈,避免輸入落入飽和區域,從而減緩梯度消失的問題。
d、提供了一點正則化的作用,可能使得結果更好。BN在一定的程度上起到了dropout的作用,因此在適用BN的網絡中可以不用dropout來實現。
那麼BN的不足呢?
a、BN對於batch_size的大小還是比較敏感的,batch_size很小的時候,其梯度不夠穩定,效果反而不好。
b、BN對於序列網絡,RNN、lstm等模型的效果並不好
針對以上BN的不足,主要是BN應用到RNN、LSTM等網絡上效果不好的缺點,研究人員提出了LN。在繼承了BN的優點上,還有另外2個優點:
1、LN能夠很好的應用在RNN、lstm等類似的網絡上。
2、LN是針對一層網絡所有的神經元做數據歸一化,因此對batch_size的大小並不敏感。
2.3BN和LN的不同
從原理操作上來講,BN針對的是同一個batch內的所有數據,而LN則是針對單個樣本。另外,從特徵維度來說,BN是對同一batch內的數據的同一緯度做歸一化,因此有多少維度就有多少個均值和方差;而LN則是對單個樣本的所有維度來做歸一化,因此一個batch中就有batch_size個均值和方差。借用知乎上的一張圖——batchNormalization與layerNormalization的區別——來說明:
簡單的來說就是BN和LN進行處理的方向不同。
2.4BN和LN的實例代碼展示
直接上代碼:
import torch
from torch.nn import BatchNorm1d
from torch.nn import LayerNorm
def show_difference_BN_LN():
input = torch.tensor([[4.0, 3.0, 2.0],
[3.0, 3.0, 2.0],
[2.0, 2.0, 2.0]
])
print(input)
print(input.size())
BN = BatchNorm1d(input.size()[1]) #`C` from an expected input of size (N, C, L)` or :math:`L` from input of size :math:`(N, L)`
BN_output = BN(input)
print('BN_output:')
print(BN_output)
print('BN_output.size()',BN_output.size())
print('*'*20)
LN = LayerNorm(input.size()[1:]) #normalized_shape (int or list or torch.Size): input shape from an expected input
LN_output = LN(input)
print('LN_output:')
print( LN_output)
print('LN_output.size()', LN_output.size())
print('#' * 40)
input_text = torch.tensor([
[[1.0, 4.0, 7.0],
[0.0, 2.0, 4.0]
],
[[1.0, 3.0, 6.0],
[2.0, 3.0, 1.0]
]
])
print(input_text)
print(input_text.size())
BN = BatchNorm1d(2)#`C` from an expected input of size (N, C, L)` or :math:`L` from input of size :math:`(N, L)`
BN_output = BN(input_text)
print('BN_output:')
print( BN_output)
print('BN_output.size()', BN_output.size())
print('*' * 20)
# LN = LayerNorm(input_text.size()[1:])
LN = LayerNorm(3)
LN_output = LN(input_text)
print('LN_output:')
print( LN_output)
print('LN_output.size()', LN_output.size())
if __name__ == '__main__':
show_difference_BN_LN()
結果如下:
上圖中,第一個torch.Size([3, 3])輸入的結果用紅色框表上的出現0的地方,和我想的一樣,然後藍色框出現的0不理解。
第二個輸入torch.Size([2, 2, 3])的結果LN的輸出出現0的地方很好理解,符合LN均值歸一化;BN則是沒有太看懂!有理解很清楚的人可以講解一下!萬分感謝!這個細節我還沒有理解到位——表示好難。。。。。。。。
三、Bert、Transformer中爲何使用的是LN而很少使用BN
其實這個問題是一個比較難的問題,我個人理解也是很有限的。參閱了很多資料,比較能接受2個解釋。
3.1第一個解釋
我們先把這個問題轉化一下,因爲Bert和Transformer基本都是應用到了NLP任務上。所以可以這樣問:
爲何CV數據任務上很少用LN,用BN的比較多,而NLP上應用LN是比較多的?
我們用文本數據句話來說明BN和LN的操作區別。
我是中國人我愛中國
武漢抗疫非常成功0
大家好纔是真的好0
人工智能很火000
上面的4條文本數據組成了一個batch的數據,那麼BN的操作的時候
就會把4條文本相同位置的字來做歸一化處理,例如:我、武、大、人
我認爲這裏就破壞了一句話內在語義的聯繫。
而LN則是針對每一句話做歸一化處理。例如:我是中國人我愛中國——歸一化處理後,一句話內每個字之間的聯繫並沒有破壞。從這個角度看,LN就比較適合NLP任務,也就是bert和Transformer用的比較多。
3.2第二個解釋
1、layer normalization 有助於得到一個球體空間中符合0均值1方差高斯分佈的 embedding, batch normalization不具備這個功能。
2、layer normalization可以對transformer學習過程中由於多詞條embedding累加可能帶來的“尺度”問題施加約束,相當於對錶達每個詞一詞多義的空間施加了約束,有效降低模型方差。batch normalization也不具備這個功能。
NLP和CV的任務差別:
圖像數據是自然界客觀存在的,像素的組織形式已經包含了“信息”
NLP數據則是又embedding開始的,這個embedding並不是客觀存在的,它是由我們設計的網絡學習出來的。
通過layer normalization得到的embedding是 以座標原點爲中心,1爲標準差,越往外越稀疏的球體空間中。這個正是我們理想的數據分佈。
另外一詞多義的表示中——簡單來說,每個詞有一片相對獨立的小空間,通過在這個小空間中產生一個小的偏移來達到表示一詞多義的效果。transformer每一層都做了這件事,也就是在不斷調整每個詞在空間中的位置。這個調整就可以由layer normalization 來實現,batch normalization是做不到的。
參考文章
batchNormalization與layerNormalization的區別