滑動平均模型
轉自 某大佬的公眾號
為什麽要使用滑動平均模型?
通過使用滑動平均我們可以使神經網絡模型在測試數據上更健壯,在使用隨機梯度下降算法訓練神經網絡時,通過滑動平均模型可以在一定程度上提高最終模型在測試數據上的表現:
它通過控制衰減率(decay)來控制參數更新前後之間的差距,從而達到減緩參數的變化幅度的目的(如,參數更新前是5,更新後的值是4,通過滑動平均模型之後,參數的值會在4到5之間),如果參數更新前後的值保持不變,通過滑動平均模型之後,參數的值仍然保持不變。
TensorFlow中的ExponentialMovingAverage函數實現了滑動平均模型:
tf.train.ExponentialMovingAverage(decay,num_updates=None,zero_debias=False,name="ExponentialMovingAverage")
其中decay為衰減率,num_updates為可選參數,你可以默認為None,如果設置了num_updates,那麽這個參數就代表了模型更新的次數。如果在ExponentialMovingAverage函數中初始化了num_updates參數,那麽每次使用的衰減率將會按照如下公式更新:
衰減率更新公式:
decay = min{init_decay , (1 + num_update) / (10 + num_update)}
可見隨著 num_update 更新次數的增加,(1 + num_update) / (10 + num_update 這一項的計算結果越接近1
此時原模型參數按照以下公式更新:
其中 shadow_variable 為變量更新前的數值,我們叫它影子變量,variable為變量更新後的數值,上面我們說到,隨著num_updates的增大,decay的計算結果越來越接近1,那麽1-decay就趨近於0,即,模型參數更新變得越來越慢。
這樣,我們就可以通過對num_updates的控制來使得模型在訓練初期參數更新幅度加大,在接近最優值處參數更新幅度減小,即在減少訓練時間的基礎上保證模型訓練的精度。
如何使用滑動平均模型?
這裏301給出在Tensorflow中一個簡單的滑動模型的應用,並會給出詳盡的註釋!
import tensorflow as tf #定義一個變量用於計算滑動平均,初始值為 0 ,類型為實數 v1 = tf.Variable(0, dtype = tf.float32) #step變量用來模擬神經網絡中叠代的輪數,即我們上面說的num_updates參數,用來動態控制衰減率 step = tf.Variable(0, trainable = False) #定義一個滑動平均類,初始化衰減率(0.99)和衰減率控制變量step #該函數返回一個ExponentialMovingAverage對象,該對象調用apply方法可以通過滑動平均模型來更新參數 ema = tf.train.ExponentialMovingAverage(0.99, step) #定義一個更新變量滑動平均的操作。 #這裏的給定數據需要是列表的形式,每次執行這個操作時列表中的變量都會被更新 maintain_averages_op = ema.apply([v1]) with tf.Session() as sess: init_op = tf.global_variables_initializer() sess.run(init_op) #通過ema.average(v1)獲取滑動平均之後變量的取值,此處輸出為[0.0 , 0.0] #初始化之後變量v1和v1的滑動平均都為0 print sess.run([v1, ema.average(v1)]) #更新變量v1的值為5 sess.run(tf.assign(v1, 5)) #更新v1的滑動平均值 #此時衰減率為min(0.99,(1+step)/(10+step)=0.1) = 0.1 #所以v1的滑動平均會被更新為0.1*0 + 0.9*5 = 4.5 sess.run(maintain_averages_op) print sess.run([v1, ema.average(v1)]) #輸出[5.0 , 4.5] #更新step的值為10000 sess.run(tf.assign(step, 10000)) #更新v1的值為10 sess.run(tf.assign(v1, 10)) #計算v1的滑動平均值 #此時衰減率為min(0.99,(1+step)/(10+step)=0.999999) = 0.99 #所以v1的滑動平均會被更新為0.99*4.5 + 0.01*10 = 4.555 sess.run(maintain_averages_op) print sess.run([v1, ema.average(v1)]) #輸出[10.0, 4.5549998] #再次更新滑動平均值,得到的新的滑動平均值為0.99*4.555 + 0.01*10 = 4.60945 sess.run(maintain_averages_op) print sess.run([v1, ema.average(v1)]) #輸出[10.0, 4.6094499]
滑動平均模型