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的值赋为1 sess.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]
原文地址:https://www.cnblogs.com/gengyi/p/9901502.html