在tensorflow中使用batch normalization


問題

訓練神經網絡是一個很復雜的過程,在前面提到了深度學習中常用的激活函數,例如ELU或者Relu的變體能夠在開始訓練的時候很大程度上減少梯度消失或者爆炸問題,但是卻不能保證在訓練過程中不出現該問題,例如在訓練過程中每一層輸入數據分布發生了改變了,那么我們就需要使用更小的learning rate去訓練,這一現象被稱為internal covariate shiftBatch Normalization能夠很好的解決這一問題。目前該算法已經被廣泛應用在深度學習模型中,該算法的強大至於在於:

  • 可以選擇一個較大的學習率,能夠達到快速收斂的效果。
  • 能夠起到Regularizer的效果,在一些情況下可以不使用Dropout,因為BN提高了模型的泛化能力

介紹

我們在將數據輸入到神經網絡中往往需要對數據進行歸一化,原因在於模型的目的就是為了學習模型的數據的分布,如果訓練集的數據分布和測試集的不一樣那么模型的泛化能力就會很差,另一方面如果模型的每一 batch的數據分布都不一樣,那么模型就需要去學習不同的分布,這樣模型的訓練速度會大大降低。
BN是一個獨立的步驟,被應用在激活函數之前,它簡單地對輸入進行零中心(zero-center)和歸一化(normalize),然后使用兩個新參數來縮放和移動結果(一個用於縮放,另一個用於縮放轉移)。 換句話說,BN讓模型學習最佳的尺度和 每層的輸入的平均值。
為了零中心和歸一化數據的分布,BN需要去估算輸入的mean和standard deviation。

 

應用

tensorflow中有不同級別的封裝層,我一般使用的tf.layers。這次用的是tf.layers.batch_normalization.

def myConv(x_in, nf, strides=1, is_training=True, name = 'conv3d'):
    with tf.variable_scope(name):
        # x_out = Conv3D(nf, kernel_size=3, padding='same',
        #        kernel_initializer='he_normal', strides=strides)(x_in)
        x_out = tf.layers.conv3d(inputs=x_in,
                                 filters=nf,
                                 kernel_size=(3, 3, 3),
                                 strides=strides,
                                 padding='same',
                                 kernel_initializer=tf.keras.initializers.he_normal(),
                                 )
        x_out = batch_norm(x_out,is_training)
        x_out = LeakyRelU(x_out, 0.2)
        return x_out
def batch_norm(x, is_train=True):
    with tf.variable_scope("batch_norm"):
        return tf.layers.batch_normalization(x,
                                             epsilon=1e-5,
                                             momentum=0.99,
                                             training=is_train,
                                            )

這是因為在計算BN中需要計算moving_meanmoving_variance並且更新,所以在執行run的時候需要將其添加到執行列表中。需要下面這段代碼這樣才能計算μ和σ的滑動平均(測試時會用到),測試時traing設為False。

extra_update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
        with tf.control_dependencies(extra_update_ops):
            self.g_A_trainer = optimizer.minimize(g_loss_A, var_list=g_A_vars)

在網上看到了很多這個問題的討論,也有人自己寫了一個BN層,最終還是去閱讀了源碼和官方教程這樣寫的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM