Tensorflow记录(2)

Tensorflow记录(2)

移动平均模型 (EMA)

移动平均模型(Exponential Moving Average)可以用来估计变量的局部均值,这样的做法可以使得变量的更新和取值不仅和当前的因素有关,同时还会受到历史取值的影响.

设变量\(v\)\(t\)时刻的为\(v_t\),取值为\(\theta_t\),在使用EMA后,\(v_t\)的更新将变为:

\[v_t = \beta ⋅ v_{t-1} + (1-\beta) ⋅ \theta_t\]

其中\(\beta \in [0,1)\),如下图所示,经过EMA平滑处理后的变量\(v\)在一段时间的更新后趋于稳定,而且在迭代过程中的抖动也明显减弱:

ema

\(t\)时刻变量\(v\)的移动平均值大致等于过去\(1 \over (1-\beta)\)个时刻\(\theta\)的平均值,这个结论在移动平均起始时相差比较大,所以通过\(v_t\)除以\((1-\beta^t)\)修正对均值的估计:

\[v\_biased_t = {1 \over 1-\beta^t}\]

通过上式可以发现,当\(t\)越来越大时,\(1-beta^t\)的值越接近1,因此\(v_t\)\(v\_biased_t\)的值将会越来越接近. 当\(\beta\)的取值越来越大时,移动平均得到的值会越发的和\(\theta\)的历史值相关. 使用移动平均的好处在于程序所占的内存小,因为我们不需要去保存变量的历史值,就能够估计出其均值.

Tensorflow中的EMA

相比对变量直接赋值而言,移动平均得到的值在图像上更加平缓光滑,抖动性更小,不会因为某次的异常取值而使得滑动平均值波动很大. TensorFlow 提供了 tf.train.ExponentialMovingAverage 来实现滑动平均. 在初始化 ExponentialMovingAverage 时,需要提供一个衰减率(decay),即公式中的\(\beta\). 这个衰减率将用于控制模型的更新速度. ExponentialMovingAverage 对每一个变量(variable)会维护一个影子变量(shadow_variable),这个影子变量的初始值就是相应变量的初始值,而每次运行变量更新时,影子变量的值会更新为:

\[shadow\_variable = decay ⋅ shadow\_variable + (1-decay) ⋅ variable\]

其中的shadow variable就是公式中的\(v_t\), variable就是\(\theta_t\),decay就是\(\beta\). 公式中的decay 决定了影子变量的更新速度,decay 越大影子变量越趋于稳定. 在实际运用中,decay一般会设成非常接近1的数,为了使得影子变量在训练前期可以更新更快,ExponentialMovingAverage 还提供了 num_updates 参数动态设置 decay 的大小. 如果在初始化 ExponentialMovingAverage 时提供了 num_updates 参数,那么每次使用的衰减率将是:

\[min\{decay, {1+num\_updates \over 10+num\_updates}\}\]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
v1 = tf.Variable(0, dtype=tf.float32)
step = tf.Variable(0, trainable=False)
ema = tf.train.ExponentialMovingAverage(0.99, step)
maintain_averages_op = ema.apply([v1])

with tf.Session() as sess:
# initialize
init_op = tf.global_variables_initilizer()
sess.run(init_op)
print(sess.run([v1, ema.average(v1)]))

# update v1
sess.run(tf.assign(v1, 5))
sess.run(maintain_averages_op)
print(sess.run([v1, ema.average(v1)]))

# update step and v1
sess.run(tf.assign(step, 10000))
sess.run(tf.assign(v1, 10))
sess.run(maintain_averages_op)
print(sess.run([v1, ema.average(v1)]))

# update v1 by using EMA
sess.run(maintain_averages_op)
print(sess.run([v1, ema.average(v1)]))

上面代码的执行结果时:

1
2
3
4
[0.0, 0.0]
[5.0, 4.5]
[10.0, 4.5549998]
[10.0, 4.6094499]

EMA的使用场景

移动平均模型可以使模型在测试集上更加robust,用随机梯度下降算法训练神经网络时,使用滑动平均在很多应用中都可以在一定程度上提高最终模型在测试数据上的表现. 对神经网络边的权重 weights 使用滑动平均,得到对应的影子变量 shadow_weights,之后在测试过程中使用 shadow_weights 来代替 weights 作为神经网络边的权重,这样在测试数据上效果更好. 因为 shadow_weights 的更新更加平滑,对于随机梯度下降而言,更平滑的更新说明不会偏离最优点很远. 对于 mini-batch gradient decent,可以尝试滑动平均,毕竟 mini-batch gradient decent 对参数的更新也存在抖动.

Tensoerflow持久化

tf.train.Saver 类提供了保存模型的API,通过以下代码可以实现对当前模型的保存:

1
2
saver = tf.train.Saver()
saver.save(sess, '/path/models/model.ckpt')

References

  • https://www.cnblogs.com/wuliytTaotao/p/9479958.html
  • 《TensorFlow实战Google深度学习框架》
0%