https://blog.csdn.net/qq_25737169/article/details/79048516
https://www.cnblogs.com/bonelee/p/8528722.html
Notes on Batch Normalization
Notes on Batch Normalization
在訓練深層神經網絡的過程中, 由於輸入層的參數在不停的變化, 因此, 導致了當前層的分布在不停的變化, 這就導致了在訓練的過程中, 要求 learning rate 要設置的非常小, 另外, 對參數的初始化的要求也很高. 作者把這種現象稱為 internal convariate shift. Batch Normalization 的提出就是為了解決這個問題的. BN 在每一個 training mini-batch 中對每一個 feature 進行 normalize. 通過這種方法, 使得網絡可以使用較大的 learning rate, 而且, BN 具有一定的 regularization 作用.
為什么需要 Batch Normalization
在神經網絡的優化中最常用最進本的方法是 SGD, 其目標是尋找最小化 loss function 的參數:
[Math Processing Error]θ=argminθ1N∑i=1NL(xi,θ)
在求解的過程中, 一般是使用 minibatch 的方法, 簡單來說, 就是計算下面的梯度:
[Math Processing Error]1m∑∂L(xi,θ)∂θ
使用 minibatch 的方法有兩個好處:
- minibatch 計算出來的 loss 可以看做是整個 trainset 的 loss 的近似值.
- minibatch 中, 可以並行地計算 m 各樣本, 因此, 使用 minibatch 的方法比原始的 SGD 方法速度更快.
然而, SGD 算法有其固有缺點:
- 對初始值要求很高, 如果參數的初始化不好, 經常不能收斂
- 學習率比較難設置, 由於每一層 input 數據的 scale 不同, 導致 backward 的梯度的 scale 也不同, 為了保證不會 gradient vanish, 只能設置較小的 learning rate, 而, 較小的 learning rate 使得整個學習過程很慢
- 第 N 層的輸入受前面 N-1 層的影響, 在深度學習中, 網絡層數很多, 因此, 及時前面 layer 的很小的影響, 當到達第 N 層的時候, 會被放大很多倍.
在深度神經網絡中, 每一層輸入數據的分布都不同, 因此, 每一層的參數都要去學習不同的分布. 而主要由於上述 #3 的原因, 使得這個過程比較困難. 為了說明這個問題, 使用一個簡單的例子. 考慮如下的一個兩層的神經網絡:
[Math Processing Error]F2(F1(θ1,x),θ2)
[Math Processing Error]F1 的輸出作為 [Math Processing Error]F2 的輸入, 因此, 在學習的過程中, 當 [Math Processing Error]F1 的輸入 [Math Processing Error]x 的分布變化的時候 (在選擇 minibatch 的使用根本無法保證每次選擇的 minibatch 的分布是相同的), [Math Processing Error]F2 的參數在向最優解收斂的過程中就會產生偏差, 因此, 導致了收斂速度變慢. 而 BN 就是要解決這個問題.
想象一下, 如果 [Math Processing Error]F2 的學習不受 [Math Processing Error]F1 的輸入 [Math Processing Error]x 的影響, 即不管 [Math Processing Error]x 輸入的是什么, [Math Processing Error]F2 的輸入都是相同的分布, 這樣, [Math Processing Error]F2 就不用調整去適應由於 [Math Processing Error]x 輸入變化帶來的影響, 那么, 是否就可以解決這個問題了呢? 因此, 這就是 BN 的提出.
Batch Normalization 是什么
Input: Values of [Math Processing Error]x over a mini-batch, [Math Processing Error]B=x1…m
Output: [Math Processing Error]γ,β
[Math Processing Error](1)μβ=1m∑i=1mxi(2)σβ2=1m∑i=1m(xi−μβ)2(3)x^i=xi−μβσβ2+ϵ(4)yi=γx^i+β
為什么 Batch Normalization 可以加速訓練
- 允許網絡使用較高的 learning rate. 在傳統的深度網絡訓練中, 如果使用較大的 learning rate 很容易導致 gradient vanish 或者 gradient explode. 通過在整個網絡中 normalize activations, 可以防止參數的較小的改變被應用到較大的或者次優的 activation 中. 另一方面, BN 使得網絡對於 parameter 的 scale 更加魯棒. 通常情況下, large learning rate 會 increase the scale of layer parameters, 進而會放大 BP 的梯度, 導致了 model explosion. BN 的使用使得網絡在 BP 的時候不會受到 parameter scale 的影響. 這是因為: [Math Processing Error](5)BN(Wu)=BN((aW)u)(6)(7)∂BN((aW)u)∂u=∂Wu∂u(8)(9)∂BN((aW)u)∂aW=1a⋅∂Wu∂W
- 具有一定的 regularization 作用, 可以減少 Dropout 的使用. dropout 的作用是方法 overfitting, 實驗發現, BN 可以 reduce overfitting.
- 降低 [Math Processing Error]L2 權重衰減系數.
- 取消 LRN(Local Response Normalization).
- Reduce the photomatric distortions. 因為 BN 使得訓練過程更快, 能 observe 到的 sample 次數變少, 所以, 減少 distorting 使得網絡 focus 在真實的圖片上面.
- BN 不僅僅限定在 ReLU 上, 而且, 對其它的 activation 也同樣適用.
基礎 | batchnorm原理及代碼詳解
前言:Batchnorm是深度網絡中經常用到的加速神經網絡訓練,加速收斂速度及穩定性的算法,可以說是目前深度網絡必不可少的一部分。
本文旨在用通俗易懂的語言,對深度學習的常用算法–batchnorm的原理及其代碼實現做一個詳細的解讀。本文主要包括以下幾個部分。
- Batchnorm主要解決的問題
- Batchnorm原理解讀
- Batchnorm的優點
- Batchnorm的源碼解讀
第一節:Batchnorm主要解決的問題
首先,此部分也即是講為什么深度網絡會需要batchnormbatchnorm,我們都知道,深度學習的話尤其是在CV上都需要對數據做歸一化,因為深度神經網絡主要就是為了學習訓練數據的分布,並在測試集上達到很好的泛化效果,但是,如果我們每一個batch輸入的數據都具有不同的分布,顯然會給網絡的訓練帶來困難。另一方面,數據經過一層層網絡計算后,其數據分布也在發生着變化,此現象稱為InternalInternal CovariateCovariate ShiftShift,接下來會詳細解釋,會給下一層的網絡學習帶來困難。batchnormbatchnorm直譯過來就是批規范化,就是為了解決這個分布變化問題。
1.1 Internal Covariate Shift
InternalInternal CovariateCovariate ShiftShift :此術語是google小組在論文BatchBatch NormalizatoinNormalizatoin 中提出來的,其主要描述的是:訓練深度網絡的時候經常發生訓練困難的問題,因為,每一次參數迭代更新后,上一層網絡的輸出數據經過這一層網絡計算后,數據的分布會發生變化,為下一層網絡的學習帶來困難(神經網絡本來就是要學習數據的分布,要是分布一直在變,學習就很難了),此現象稱之為InternalInternal CovariateCovariate ShiftShift。
BatchBatch NormalizatoinNormalizatoin 之前的解決方案就是使用較小的學習率,和小心的初始化參數,對數據做白化處理,但是顯然治標不治本。
1.2 covariate shift
InternalInternal CovariateCovariate ShiftShift 和CovariateCovariate ShiftShift具有相似性,但並不是一個東西,前者發生在神經網絡的內部,所以是InternalInternal,后者發生在輸入數據上。CovariateCovariate ShiftShift主要描述的是由於訓練數據和測試數據存在分布的差異性,給網絡的泛化性和訓練速度帶來了影響,我們經常使用的方法是做歸一化或者白化。想要直觀感受的話,看下圖:
舉個簡單線性分類栗子,假設我們的數據分布如a所示,參數初始化一般是0均值,和較小的方差,此時擬合的y=wx+by=wx+b如b圖中的橘色線,經過多次迭代后,達到紫色線,此時具有很好的分類效果,但是如果我們將其歸一化到0點附近,顯然會加快訓練速度,如此我們更進一步的通過變換拉大數據之間的相對差異性,那么就更容易區分了。
CovariateCovariate ShiftShift 就是描述的輸入數據分布不一致的現象,對數據做歸一化當然可以加快訓練速度,能對數據做去相關性,突出它們之間的分布相對差異就更好了。BatchnormBatchnorm做到了,前文已說過,BatchnormBatchnorm是歸一化的一種手段,極限來說,這種方式會減小圖像之間的絕對差異,突出相對差異,加快訓練速度。所以說,並不是在深度學習的所有領域都可以使用BatchNormBatchNorm,下文會寫到其不適用的情況。
第二節:Batchnorm 原理解讀
本部分主要結合原論文部分,排除一些復雜的數學公式,對BatchNormBatchNorm的原理做盡可能詳細的解釋。
之前就說過,為了減小InternalInternal CovariateCovariate ShiftShift,對神經網絡的每一層做歸一化不就可以了,假設將每一層輸出后的數據都歸一化到0均值,1方差,滿足正太分布,但是,此時有一個問題,每一層的數據分布都是標准正太分布,導致其完全學習不到輸入數據的特征,因為,費勁心思學習到的特征分布被歸一化了,因此,直接對每一層做歸一化顯然是不合理的。
但是如果稍作修改,加入可訓練的參數做歸一化,那就是BatchNormBatchNorm實現的了,接下來結合下圖的偽代碼做詳細的分析:
之所以稱之為batchnorm是因為所norm的數據是一個batch的,假設輸入數據是β=x1...mβ=x1...m共m個數據,輸出是yi=BN(x)yi=BN(x),batchnormbatchnorm的步驟如下:
1.先求出此次批量數據xx的均值,μβ=1m∑mi=1xiμβ=1m∑i=1mxi
2.求出此次batch的方差,σ2β=1m∑i=1m(xi−μβ)2σβ2=1m∑i=1m(xi−μβ)2
3.接下來就是對xx做歸一化,得到x−ixi−
4.最重要的一步,引入縮放和平移變量γγ和ββ ,計算歸一化后的值,yi=γx−iyi=γxi− +β+β
接下來詳細介紹一下這額外的兩個參數,之前也說過如果直接做歸一化不做其他處理,神經網絡是學不到任何東西的,但是加入這兩個參數后,事情就不一樣了,先考慮特殊情況下,如果γγ和ββ分別等於此batch的方差和均值,那么yiyi不就還原到歸一化前的xx了嗎,也即是縮放平移到了歸一化前的分布,相當於batchnormbatchnorm沒有起作用,ββ 和γγ分別稱之為 平移參數和縮放參數 。這樣就保證了每一次數據經過歸一化后還保留的有學習來的特征,同時又能完成歸一化這個操作,加速訓練。
先用一個簡單的代碼舉個小栗子:
def Batchnorm_simple_for_train(x, gamma, beta, bn_param): """ param:x : 輸入數據,設shape(B,L) param:gama : 縮放因子 γ param:beta : 平移因子 β param:bn_param : batchnorm所需要的一些參數 eps : 接近0的數,防止分母出現0 momentum : 動量參數,一般為0.9, 0.99, 0.999 running_mean :滑動平均的方式計算新的均值,訓練時計算,為測試數據做准備 running_var : 滑動平均的方式計算新的方差,訓練時計算,為測試數據做准備 """ running_mean = bn_param['running_mean'] #shape = [B] running_var = bn_param['running_var'] #shape = [B] results = 0. # 建立一個新的變量 x_mean=x.mean(axis=0) # 計算x的均值 x_var=x.var(axis=0) # 計算方差 x_normalized=(x-x_mean)/np.sqrt(x_var+eps) # 歸一化 results = gamma * x_normalized + beta # 縮放平移 running_mean = momentum * running_mean + (1 - momentum) * x_mean running_var = momentum * running_var + (1 - momentum) * x_var #記錄新的值 bn_param['running_mean'] = running_mean bn_param['running_var'] = running_var return results , bn_param
看完這個代碼是不是對batchnorm有了一個清晰的理解,首先計算均值和方差,然后歸一化,然后縮放和平移,完事!但是這是在訓練中完成的任務,每次訓練給一個批量,然后計算批量的均值方差,但是在測試的時候可不是這樣,測試的時候每次只輸入一張圖片,這怎么計算批量的均值和方差,於是,就有了代碼中下面兩行,在訓練的時候實現計算好meanmean varvar測試的時候直接拿來用就可以了,不用計算均值和方差。
running_mean = momentum * running_mean + (1 - momentum) * x_mean running_var = momentum * running_var + (1 - momentum) * x_var
所以,測試的時候是這樣的:
def Batchnorm_simple_for_test(x, gamma, beta, bn_param): """ param:x : 輸入數據,設shape(B,L) param:gama : 縮放因子 γ param:beta : 平移因子 β param:bn_param : batchnorm所需要的一些參數 eps : 接近0的數,防止分母出現0 momentum : 動量參數,一般為0.9, 0.99, 0.999 running_mean :滑動平均的方式計算新的均值,訓練時計算,為測試數據做准備 running_var : 滑動平均的方式計算新的方差,訓練時計算,為測試數據做准備 """ running_mean = bn_param['running_mean'] #shape = [B] running_var = bn_param['running_var'] #shape = [B] results = 0. # 建立一個新的變量 x_normalized=(x-running_mean )/np.sqrt(running_var +eps) # 歸一化 results = gamma * x_normalized + beta # 縮放平移 return results , bn_param
你是否理解了呢?如果還沒有理解的話,歡迎再多看幾遍。
第三節:Batchnorm源碼解讀
本節主要講解一段tensorflow中BatchnormBatchnorm的可以使用的代碼33,如下:
代碼來自知乎,這里加入注釋幫助閱讀。
def batch_norm_layer(x, train_phase, scope_bn): with tf.variable_scope(scope_bn): # 新建兩個變量,平移、縮放因子 beta = tf.Variable(tf.constant(0.0, shape=[x.shape[-1]]), name='beta', trainable=True) gamma = tf.Variable(tf.constant(1.0, shape=[x.shape[-1]]), name='gamma', trainable=True) # 計算此次批量的均值和方差 axises = np.arange(len(x.shape) - 1) batch_mean, batch_var = tf.nn.moments(x, axises, name='moments') # 滑動平均做衰減 ema = tf.train.ExponentialMovingAverage(decay=0.5) def mean_var_with_update(): ema_apply_op = ema.apply([batch_mean, batch_var]) with tf.control_dependencies([ema_apply_op]): return tf.identity(batch_mean), tf.identity(batch_var) # train_phase 訓練還是測試的flag # 訓練階段計算runing_mean和runing_var,使用mean_var_with_update()函數 # 測試的時候直接把之前計算的拿去用 ema.average(batch_mean) mean, var = tf.cond(train_phase, mean_var_with_update, lambda: (ema.average(batch_mean), ema.average(batch_var))) normed = tf.nn.batch_normalization(x, mean, var, beta, gamma, 1e-3) return normed
至於此行代碼tf.nn.batch_normalization()就是簡單的計算batchnorm過程啦,代碼如下:
這個函數所實現的功能就如此公式:γ(x−μ)σ+βγ(x−μ)σ+β
def batch_normalization(x, mean, variance, offset, scale, variance_epsilon, name=None): with ops.name_scope(name, "batchnorm", [x, mean, variance, scale, offset]): inv = math_ops.rsqrt(variance + variance_epsilon) if scale is not None: inv *= scale return x * inv + (offset - mean * inv if offset is not None else -mean * inv)
第四節:Batchnorm的優點
主要部分說完了,接下來對BatchNorm做一個總結:
- 沒有它之前,需要小心的調整學習率和權重初始化,但是有了BN可以放心的使用大學習率,但是使用了BN,就不用小心的調參了,較大的學習率極大的提高了學習速度,
- Batchnorm本身上也是一種正則的方式,可以代替其他正則方式如dropout等
- 另外,個人認為,batchnorm降低了數據之間的絕對差異,有一個去相關的性質,更多的考慮相對差異性,因此在分類任務上具有更好的效果。
注:或許大家都知道了,韓國團隊在2017NTIRE圖像超分辨率中取得了top1的成績,主要原因竟是去掉了網絡中的batchnorm層,由此可見,BN並不是適用於所有任務的,在image-to-image這樣的任務中,尤其是超分辨率上,圖像的絕對差異顯得尤為重要,所以batchnorm的scale並不適合。
參考文獻:
【1】http://blog.csdn.net/zhikangfu/article/details/53391840
【2】http://geek.csdn.net/news/detail/160906
【3】 https://www.zhihu.com/question/53133249
http://shuokay.com/2016/05/28/batch-norm/
Notes on Batch Normalization
在訓練深層神經網絡的過程中, 由於輸入層的參數在不停的變化, 因此, 導致了當前層的分布在不停的變化, 這就導致了在訓練的過程中, 要求 learning rate 要設置的非常小, 另外, 對參數的初始化的要求也很高. 作者把這種現象稱為 internal convariate shift. Batch Normalization 的提出就是為了解決這個問題的. BN 在每一個 training mini-batch 中對每一個 feature 進行 normalize. 通過這種方法, 使得網絡可以使用較大的 learning rate, 而且, BN 具有一定的 regularization 作用.
為什么需要 Batch Normalization
在神經網絡的優化中最常用最進本的方法是 SGD, 其目標是尋找最小化 loss function 的參數:
在求解的過程中, 一般是使用 minibatch 的方法, 簡單來說, 就是計算下面的梯度:
使用 minibatch 的方法有兩個好處:
- minibatch 計算出來的 loss 可以看做是整個 trainset 的 loss 的近似值.
- minibatch 中, 可以並行地計算 m 各樣本, 因此, 使用 minibatch 的方法比原始的 SGD 方法速度更快.
然而, SGD 算法有其固有缺點:
- 對初始值要求很高, 如果參數的初始化不好, 經常不能收斂
- 學習率比較難設置, 由於每一層 input 數據的 scale 不同, 導致 backward 的梯度的 scale 也不同, 為了保證不會 gradient vanish, 只能設置較小的 learning rate, 而, 較小的 learning rate 使得整個學習過程很慢
- 第 N 層的輸入受前面 N-1 層的影響, 在深度學習中, 網絡層數很多, 因此, 及時前面 layer 的很小的影響, 當到達第 N 層的時候, 會被放大很多倍.
在深度神經網絡中, 每一層輸入數據的分布都不同, 因此, 每一層的參數都要去學習不同的分布. 而主要由於上述 #3 的原因, 使得這個過程比較困難. 為了說明這個問題, 使用一個簡單的例子. 考慮如下的一個兩層的神經網絡:
F1F1 的輸出作為 F2F2 的輸入, 因此, 在學習的過程中, 當 F1F1 的輸入 xx 的分布變化的時候 (在選擇 minibatch 的使用根本無法保證每次選擇的 minibatch 的分布是相同的), F2F2 的參數在向最優解收斂的過程中就會產生偏差, 因此, 導致了收斂速度變慢. 而 BN 就是要解決這個問題.
想象一下, 如果 F2F2 的學習不受 F1F1 的輸入 xx 的影響, 即不管 xx 輸入的是什么, F2F2 的輸入都是相同的分布, 這樣, F2F2 就不用調整去適應由於 xx 輸入變化帶來的影響, 那么, 是否就可以解決這個問題了呢? 因此, 這就是 BN 的提出.
Batch Normalization 是什么
Input: Values of xx over a mini-batch, B=x1…mB=x1…m
Output: γ,βγ,β
為什么 Batch Normalization 可以加速訓練
- 允許網絡使用較高的 learning rate. 在傳統的深度網絡訓練中, 如果使用較大的 learning rate 很容易導致 gradient vanish 或者 gradient explode. 通過在整個網絡中 normalize activations, 可以防止參數的較小的改變被應用到較大的或者次優的 activation 中. 另一方面, BN 使得網絡對於 parameter 的 scale 更加魯棒. 通常情況下, large learning rate 會 increase the scale of layer parameters, 進而會放大 BP 的梯度, 導致了 model explosion. BN 的使用使得網絡在 BP 的時候不會受到 parameter scale 的影響. 這是因為:
BN(Wu)=BN((aW)u)∂BN((aW)u)∂u=∂Wu∂u∂BN((aW)u)∂aW=1a⋅∂Wu∂W(5)(6)(7)(8)(9)(5)BN(Wu)=BN((aW)u)(6)(7)∂BN((aW)u)∂u=∂Wu∂u(8)(9)∂BN((aW)u)∂aW=1a⋅∂Wu∂W
- 具有一定的 regularization 作用, 可以減少 Dropout 的使用. dropout 的作用是方法 overfitting, 實驗發現, BN 可以 reduce overfitting.
- 降低 L2L2 權重衰減系數.
- 取消 LRN(Local Response Normalization).
- Reduce the photomatric distortions. 因為 BN 使得訓練過程更快, 能 observe 到的 sample 次數變少, 所以, 減少 distorting 使得網絡 focus 在真實的圖片上面.
- BN 不僅僅限定在 ReLU 上, 而且, 對其它的 activation 也同樣適用.