1 滑動平均概述
滑動平均(也稱為 影子值 ):記錄了每一個參數一段時間內過往值的平均,增加了模型的泛化性。
滑動平均通常針對所有參數進行優化:W 和 b,
簡單地理解,滑動平均像是給參數加了一個影子,參數變化,影子緩慢追隨。
滑動平均的表示公式為
影子 = 衰減率 * 影子 + ( 1 - 衰減率 ) * 參數
或
滑動平均值 = 衰減率 * 滑動平均值 + ( 1 - 衰減率 )* 參數
備注
影子初值 = 參數初值
衰減率 = min{ MOVING_AVERAGE_DECAY, (1+輪數) / (10 + 輪數 ) }
示例:
MOVING_AVERAGE_DECAY 為 0.99, 參數 w1 為 0,輪數 global_step 為 0,w1的滑動平均值為 0 。
參數w1更新為 1 時,則
w1的滑動平均值 = min( 0.99, 1/10 ) * 0 + ( 1 - min( 0.99, 1/10 ) * 1 = 0.9
?假設輪數 global_step 為 100 時,參數 w1 更新為 10 時,則
w1滑動平均值 = min(0.99, 101/110) * 0.9 + ( 1 - min( 0.99, 101/110) * 10 = 1.644
再次運行
w1滑動平均值 = min(0.99, 101/110) * 1.644 + ( 1 - min( 0.99, 101/110) * 10 = 2.328
再次運行
w1滑動平均值 = 2.956
?
2 滑動平均在Tensorflow中的表示方式
第一步 實例化滑動平均類ema
ema = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY(滑動平均衰減率),global_step(輪數計數器,表示當前輪數)
)
備注:
MOVING_AVERAGE_DECAY 滑動平均衰減率是超參數,一般設定的值比較大;
global_step - 輪數計數器,表示當前輪數,這個參數與其他計數器公用。
第二步 求算滑動平均節點ema_op
ema_op = ema.apply([])
ema.apply([ ]) 函數表示對 [ ] 中的所有數值求滑動平均。
示例:
ema_op = ema.apply(tf.trainable_variables())
每當運行此代碼時,會對所以待優化參數進行求滑動平均運算。
第三步 具體實現方式
在工程應用中,我們通常會將計算滑動平均 ema_op 和訓練過程 train_step 綁定在一起運行,使其合成一個訓練節點,實現的代碼如下
with tf.control_dependencies([ train_step, ema_op ]):train_op = tf.no_op(name = 'train')
?
另外:
查看某參數的滑動平均值
函數ema.average(參數名) --->? 返回 ’ 參數名 ’ 的滑動平均值,
3 示例代碼
# 待優化參數w1,不斷更新w1參數,求w1的滑動平均(影子)import tensorflow as tf# 1. 定義變量及滑動平均類# 定義一個32位浮點變量并賦初值為0.0, w1 = tf.Variable(0, dtype=tf.float32)# 輪數計數器,表示NN的迭代輪數,賦初始值為0,同時不可被優化(不參數訓練) global_step = tf.Variable(0, trainable=False)# 設定衰減率為0.99 MOVING_AVERAGE_DECAY = 0.99# 實例化滑動平均類 ema = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY, global_step)# ema.apply()函數中的參數為待優化更新列表 # 每運行sess.run(ema_op)時,會對函數中的參數求算滑動平均值 # tf.trainable_variables()函數會自動將所有待訓練的參數匯總為待列表 # 因該段代碼中僅有w1一個參數,ema_op = ema.apply([w1])與下段代碼等價 ema_op = ema.apply(tf.trainable_variables())# 2. 查看不同迭代中變量取值的變化。 with tf.Session() as sess:# 初始化init_op = tf.global_variables_initializer()sess.run(init_op)# 用ema.average(w1)獲取w1滑動平均值 (要運行多個節點,作為列表中的元素列出,寫在sess.run中)# 打印出當前參數w1和w1滑動平均值print("current global_step:", sess.run(global_step))print("current w1", sess.run([w1, ema.average(w1)]))# 參數w1的值賦為1sess.run(tf.assign(w1, 1))sess.run(ema_op)print("current global_step:", sess.run(global_step))print("current w1", sess.run([w1, ema.average(w1)]))# 更新global_step和w1的值,模擬出輪數為100時,參數w1變為10, 以下代碼global_step保持為100,每次執行滑動平均操作,影子值會更新 sess.run(tf.assign(global_step, 100))sess.run(tf.assign(w1, 10))sess.run(ema_op)print("current global_step:", sess.run(global_step))print("current w1:", sess.run([w1, ema.average(w1)]))# 每次sess.run會更新一次w1的滑動平均值 sess.run(ema_op)print("current global_step:", sess.run(global_step))print("current w1:", sess.run([w1, ema.average(w1)]))sess.run(ema_op)print("current global_step:", sess.run(global_step))print("current w1:", sess.run([w1, ema.average(w1)]))sess.run(ema_op)print("current global_step:" , sess.run(global_step))print("current w1:", sess.run([w1, ema.average(w1)]))sess.run(ema_op)print("current global_step:" , sess.run(global_step))print("current w1:", sess.run([w1, ema.average(w1)]))
運行
current global_step: 0 current w1 [0.0, 0.0] current global_step: 0 current w1 [1.0, 0.9] current global_step: 100 current w1: [10.0, 1.6445453] current global_step: 100 current w1: [10.0, 2.3281732] current global_step: 100 current w1: [10.0, 2.955868] current global_step: 100 current w1: [10.0, 3.532206] current global_step: 100 current w1: [10.0, 4.061389]
?
w1 的滑動平均值都向參數 w1 靠近。可見,滑動平均追隨參數的變化而變化。