10分钟详解EMA(滑动平均)并解决EMA下ckpt权重与pb权重表现不一问题

2020-06-02 11:29:13 浏览数 (1)

今天用YunYang的evaluate.py评估模型的时候,意外发现用同样的ckpt权重文件转换而成的pb文件效果不一样,使用ckpt的效果非常差,仔细研究后才发现是滑动平均(EMA)搞的鬼,于是便重新重温了一下EMA。

目录

  • EMA定义
  • EMA原理理解
  • ckpt和pb保存不同的原因
  • 参考

EMA定义与原理

  • EMA(ExponentialMovingAverage),也就是我们常说的滑动平均模型,一般在采用SGD(随机梯度下降)训练的时候,都会用他来提高我们在测试数据的表现,我们从[1]结合tensorflow提供的api来说一下他的定义:
  • Tensorflow提供了tf.train.ExponentialMovingAverage来实现滑动平均模型。在初始化ExponentialMovingAverage时,需要提供一个衰减率(decay)。这个衰减率将用于控制模型更新的速度,这个第二部分会告诉大家是怎么控制的。ExponentialMovingAverage对每一个变量会维护一个影子变量(shadow variable),顾名思义,这个影子变量的初始值就是相应变量的初始值,而每次运行变量更新时,影子变量的值就会被更新为:
shadow_variable = decay × shadow_variable (1-decay)× variable
  • 其中,shadow_variable就是我们的影子变量,variable就是我们本次准备更新的变量(也就是我们的权重),decay是衰减率。

EMA原理理解

  • 上面的那个公式看似复杂,其实很容易理解,其实EMA就是把每一次梯度下降更新后的权重值和前一次的权重值进行了一种“联系”,这种联系让我们的模型更新还需要看上一次更新的脸色,没那么“随意”。具体举个例子来说:比如上一次的权重值shadow_variable为4,衰减率decay为0.999,这次经过SGD准备更新的权重值variable为5,那么我们新更新的权重值就是0.999×4 0.001×5=4.001,我们可以看到采用EMA之后的更新明显受限于上一次更新的权重。
  • 经过上面那个例子,我们也可以明白decay决定了模型更新的速度,decay越大模型越趋于稳定(稳定的意思就是和上一次更新的权重值相差不大),在实际应用中,decay一般会设成非常接近1的数(比如0.999或者0.9999)。当然为了使得模型训练前期可以更新得更快,ExponentialMovingAverage也提供了一个num_updates参数来动态设置decay的大小,这里就不多说了。

ckpt和pb保存不同的原因

  • 众所周知,pb权重是由ckpt转换而来,他们的表现理论上是一致的,那我们的EMA终究是怎么干扰了我们ckpt的表现呢?这个要从tensorflow读取使用变量的滑动平均值的方式说起:tensorflow通过tf.train.ExponentialMovingAverage的variables_to_restore()函数获取变量重命名字典,这说明如果我们通过saver = tf.train.Saver(ema_obj.variables_to_restore())后saver.resore来恢复读取权重文件的话(ema_obj是我们定义好的一个滑动平均的类),我们读取的将会是我们本来最后一次准备更新的权重,而不是我们的影子变量,也正是因为这个重命名机制从而导致了我们的ckpt和pb表现不同的关键。
  • 解决方法很简单,只需要删掉saver里面的ema_obj.variables_to_restore()就可以解决。

参考

[1] :《Tensorflow实战Google深度学习框架》

0 人点赞