Maintains moving averages of variables by employing an exponential decay.这是官方的文档解释。
要想理解上面这句话就要知道什么是moving average和exponential decay。下面分别解释一下这两个概念。
exponential decay
在有时学习率的设置时,我们会把学习率设计为指数衰减的,就是让学习率满足一些性质的情况下不断下降,这里指数衰减的一个性质是它的衰减值是当前值的一部分,也就是说dNdt=−λNdNdt=−λN
moving average
维基百科的解释:In statistics, a moving average (rolling average or running average) is a calculation to analyze data points by creating series of averages of different subsets of the full data set. 翻译成中文:在统计学中,移动平均通过建立整个数据集中的一系列子集的平均值来分析数据点的计算方法。这种方法通常用在时间序列分析中,例如股票涨跌这样的数据都是离散的,有波动的,为了更容易分析,因此可以把这样的数据做移动平均,这样可以使得小的波动更平滑,而又能显示出长期的整体趋势。在数学上这样的操作可以看做是“卷积”。
Exponential Moving Average
上面提到moving average类似于卷积的操作,因此我们就可以在卷积核上做文章,最普通的卷积核就是每个数据的权重都相同,但是在实际中明显越近的数据价值越大,因此要让越近的数据权重越大,越远的数据权重越小,在这里使用的权重衰减策略就是指数衰减。具体的,
其中,
- αα表示经过EMA后的时间t的值
综上我们就知道了,EMA就是把一系列的离散数据点转化为更“好”的数据点,它的后面的数据点会记住前面的数据点的一些信息,离得越远记得越少。
tensorflow中的ema
tf.train.ExponentialMovingAverage是用来让模型不被更新的太快的一种方法,在实际应用中会有两个变量:模型变量variable和影子变量shadow variable,shadow_variable = decay * shadow_variable + (1 - decay) * variable,在上面这个公式中可以看到,decay使得shadow variable具有一定的缓冲能力,不会变化太快,为了让前期训练加快,可以计入num_update参数,使得decay = min(decay, (1 + num_updates) / (10 + num_updates))。
滑动平均模型概述:
主要是控制衰减率来控制参数更新前后之间的差距,从而达到减缓参数的变化值(比如:参数更新前是5,更新后是4,通过滑动平均模型之后,参数的值会在4到5之间)
对于MovingAverage的解释:
在统计学中,移动平均通过建立整个数据集中的一系列子集的平均值来分析数据点的计算方法。这种方法通常用在时间序列分析中,例如股票涨跌这样的数据都是离散的,有波动的,为了更容易分析,因此可以把这样的数据做移动平均,这样可以使得小的波动更平滑,而又能显示出长期的整体趋势。在数学上这样的操作可以看做是“卷积”。既然moving average类似于卷积的操作,因此我们就可以在卷积核上做文章,最普通的卷积核就是每个数据的权重都相同,但是在实际中明显越近的数据价值越大,因此要让越近的数据权重越大,越远的数据权重越小.
ExponentialMovingAverage函数:
tensorflow中提供了tf.train.ExponentialMovingAverage来实现滑动平均模型:
tf.train.ExponentialMovingAverage(decay,num_updates=None,zero_debias=False,
name="ExponentialMovingAverage")
在初始化ExponentialMovingAverage时,需要提供一个衰减率(decay)用于控制模型更新的速度.ExponentialMovingAverage对每一个变量会维护一个影子变量,(shadow_variable)
这个影子变量的初始值就是相应变量的初始值,每次运行变量更新时,影子变量的值会更新为:
shadow_variable=decay×shadow_variable+(1−decay)×variable
这个算法的原理:平滑、滤波,即使数据平滑变化,通过调整参数来调整变化的稳定性
shadow_variable为影子变量,variable为更新的变量,decay为衰减率,decay决定了模型更新的速度,decay越大模型越趋于稳定.在实际应用中,decay一般会设置为非常接近1 的数.为了使得模型在训练前期可以更新地更快.
ExponentialMovingAverage提供了num_updates参数来动态设置decay的大小.如果在ExponentialMovingAverage初始化时提供了num_updates参数,那么每次使用的衰减概率为
其中:
由此得:(应该求导的,求导证明是单增的)
num_updates的值越大,整个值就越大,那么decay在原decay与该值中就更倾向于选择原decay.
反之亦反.
开头说过,decay的值选择为0.9/0.99等较高的,接近1的值,而num_updates的值会选择为step(神经网络中迭代的轮数),这样,结合上面极限的结论(或许应该求导的.....我求了一下确实是递增的),step越大,decay就越会选择原decay,选择原decay的话,原shadow_variable的比重就会加大,那么shadow_variable的变化就不会太大(step与shadow_variable建立这种关系的目的....我还不太清楚,不知道跟上文所述卷积核/权重部分有没有关联)
返回值:ExponentialMovingAverage对象,通过对象调用apply方法可以通过滑动平均模型来更新参数。
import tensorflow as tf
#定义一个变量用于计算滑动平均,这个变量初始值为0,这里手动制定了变量
v1 = tf.Variable(0,dtype=tf.float32)#---------------------------------------[1]
#step变量模拟神经网络中迭代的轮数,可以用于动态控制衰减率 step-->num_update
step = tf.Variable(0,trainable=False)
#定义一个滑动平均的类(class).初始化时给定了衰减率(0.99)和控制衰减率的变量step
Moving_average = tf.train.ExponentialMovingAverage(0.99,step)
#定义一个更新变量滑动平均的操作
#这里需要给定一个列表,每次执行这个操作时,这个列表中的变量都会被更新
#更新v1
maintain_averages_op = Moving_average.apply([v1])
with tf.Session() as sess:
#初始化所有变量
init_op = tf.global_variables_initializer()#----------------------------[2]
sess.run(init_op)
#通过Moving_average.average(v1)获取滑动平均之后的取值
#在初始化之后变量v1的值和v1的滑动平均都为0
print(sess.run([v1,Moving_average.average(v1)]))
#更新变量v1的值到5
sess.run(tf.assign(v1,5))#----------------------------------------------[3]
#更新v1的滑动平均值,衰减率为min{0.99,(1+0)/(10+0)}=0.1 decay更新为0.1
#v1的滑动平均值会更新为0.1x0+0.9x5=4.5
sess.run(maintain_averages_op)
print(sess.run([v1,Moving_average.average(v1)]))
#更新step的值为10000
sess.run(tf.assign(step,10000))
#更新v1的值为10
sess.run(tf.assign(v1,10))
#衰减率变为min{0.99,(1+10000)/(10+10000)}=0.99
#v1的滑动平均值更新为0.99x4.5+0.01x10=4.555
sess.run(maintain_averages_op)
print(sess.run([v1,Moving_average.average(v1)]))
#再次更新滑动平均值
sess.run(maintain_averages_op)
print(sess.run([v1,Moving_average.average(v1)]))
函数:
[1]tf.Variable(initial_value, trainable=True, collections=None, validateshape=True, name=None): 定义图变量initial_value:初始赋值;trainable:如果为True,会把它加入到GraphKeys.TRAINABLE_VARIABLES,才能对它使用Optimizer;collections:指定该图变量的类型、默认为[GraphKeys.GLOBAL_VARIABLES]
[2]在TensorFlow的世界里,变量的定义和初始化是分开的,所有关于图变量的赋值和计算都要通过tf.Session的run来进行。想要将所有图变量进行集体初始化时应该使用tf.global_variables_initializer。
[3]tf.assign(ref,value,validateshape=None,uselocking=None,name=None): 通过将value赋值给ref来更新ref,效果等同于ref=value
tf.train.ExponentialMovingAverage解析
指出文章中错误的地方或者对文中我的疑问有解答的欢迎联系我,私信/WX:lmf18328092079均可,大家共同进步=.=