在这里我先写一下自己的初步认识,如果以后有更深的认识我还会来进行补充。
这里的代码只是一个简单的而且不全面的测试,就是初步看看函数,以及运行看看结果,并不具有实际功能。为什么这么说,待会就知道了。
首先所谓滑动平均,就是我们想让模型的参数具有一定的泛华性。何为泛化?我的解释是,该参数不但能反应当前参数的变化,还能把参数的过去值也能考虑进来。即我们训练得到的新的参数是本次训练后得到的参数与前面训练的参数的一个综合考量。
公式如下:
影子 = (1-衰减率)*参数+衰减率*影子
也就是说,这里的衰减率表示过去的参数在训练后最终参数的比重越来越大,而当前训练的参数占的比重越来越小。
首先我们在计算图中弄一个变量,靠改变这个变量来查看不同的影子值计算效果。
#1 定义变量及滑动平均类
#定义一个32位浮点变量,初始值位0.0,这个代码就是不断更新w1参数,优化w1参数,滑动平均做了个w1的影子
w1 = tf.Variable(0,dtype=tf.float32)
之后是迭代轮数:
#定义num updates,即NN的迭代轮数,初始值位0,不可被优化(训练) 运行了几轮BATCH_SIZE的计数器,初值给0,设为不被训练
global_step = tf.Variable(0,trainable=False)
实例化滑动平均类。
#实例化滑动平均类,给删减率为0.99,当前轮数为global_step
MOVINT_AVERAGE_DECAY = 0.99
ema = tf.train.ExponentialMovingAverage(MOVINT_AVERAGE_DECAY,global_step)
#ema.apply后的括号里是更新列表,每次运行sess.fun(ema_op)时,对更新列表中的元素求滑动平均值
#在实际应用中会使用tf.trainable_variable()自动将所有待训练的参数汇总为列表
#这里因为只有一个参数,所以直接用apply([w1])也是可以的
#ema_op = ema.apply([w1])
ema_op = ema.apply(tf.trainable_variables())
上面的代码,需要注意的是,训练的时候,所有可训练的数据会被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(sess.run([w1,ema.average(w1)]))
#参数w1的值赋为1
sess.run(tf.assign(w1,1))
sess.run(ema_op)
print(sess.run([w1,ema.average(w1)]))
#更新step和w1的值,模拟出100轮迭代后,参数w1变为10
sess.run(tf.assign(global_step,100))
sess.run(tf.assign(w1,10))
sess.run(ema_op)
print(sess.run([w1,ema.average(w1)]))
#每次sess.run会更新一次w1的滑动平均值
sess.run(ema_op)
print(sess.run([w1,ema.average(w1)]))
sess.run(ema_op)
print(sess.run([w1,ema.average(w1)]))
sess.run(ema_op)
print(sess.run([w1,ema.average(w1)]))
sess.run(ema_op)
print(sess.run([w1,ema.average(w1)]))
sess.run(ema_op)
print(sess.run([w1,ema.average(w1)]))
sess.run(ema_op)
print(sess.run([w1,ema.average(w1)]))
上面的程序就是设置w1,然后计算滑动平均后的参数,然后这时ema上存储的参数表就更新了,然后再次根据w1计算新的参数。
需要注意的是为了简单查看效果,这里没有更改w1的值。
打印结果:
[0.0, 0.0]
[1.0, 0.9]
[10.0, 1.6445453]
[10.0, 2.3281732]
[10.0, 2.955868]
[10.0, 3.532206]
[10.0, 4.061389]
[10.0, 4.547275]
[10.0, 4.9934072]
可以看到,数值在向w1的值(10.0)逼近。
在我们实际训练的时候,w1肯定是变化的,而我们的滑动平均后的参数就也会像影子一样跟着w1进行变化。