1.指数衰减学习率
目的:
- 一开始较快速度收敛
- 之后快收敛时,更加稳定得收敛至最优解
def exponential_decay(learning_rate,
global_step,
decay_steps,
decay_rate,
staircase=False,
name=None)
衰减后的学习率计算公式:
decayed_learning_rate = learning_rate * decay_rate ^ (global_step / decay_steps)
global_step==0
时,decayed_learning_rate == learning_rate
global_step
较大时,decayed_learning_rate == learning_rate * 系数
staircase==False
,decayed_learning_rate
的变化是连续的;
staircase==True
,decayed_learning_rate
得变化是阶梯状的,每次迭代次数达到decay_steps
时,在原始学习率上乘上系数
Question:你并不知道什么时候该减少学习率,让网络稳定收敛,单纯靠global_step
实在草率。所以exponential_decay
方法的参数都是超参数,仅能凭经验设置。
2. tf.control_dependecies
此函数表示了tf
中op
的依赖性关系。
x = tf.Variable(1.0, name='x')
x_plus_1 = tf.assign_add(x, 1, name='x_plus')
with tf.control_dependencies([x_plus_1]):
y = x
z=tf.identity(x,name='z_added')
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
for i in range(5):
print(sess.run(z))
# 输出 2,3,4,5,6
# 如果改为输出 print(sess.run(y)) ,则结果为 1,1,1,1,1
# 原因在我之前博客讲的tf的图流动机制
即对with tf.control_dependencies([pre_op]):
内部的op
操作,必须先进行pre_op
操作.
而简单的y = x
并不是图的op
,图中的赋值op
用tf.identity
(其原理是创建新的结点,再把原节点信息copy过去)
tf.control_dependencies
常和tf.assign_add
配合使用,达到先做更新op
再处理后续.
3. tf.train.ExponentialMovingAverage()
ExponentialMovingAverage类的初始化函数:
def __init__(self, decay, num_updates=None, zero_debias=False,
name="ExponentialMovingAverage"):
...
更新公式:
shadow_variable = decay * shadow_variable + (1 - decay) * variable
其中shadow_variable
表示上一次迭代的值;variable
表示此次BP更新的后值(w - α*δloss/δw)
decay
变量一般取0.99
/0.999
等接近1的数字。当num_updates
不是NONE
,
系数decay
的取值为min(decay, (1 + num_updates) / (10 + num_updates))
可见,decay
:
刚开始训练时,不需要滑动平均,取
(1 + num_updates) / (10 + num_updates)
,较小,BP更新后的值variable
占主导
训练快结束时,模型参数不需要太多调整,保持稳定即可,同时迭代次数很大(1 + num_updates) / (10 + num_updates)
会接近于1,大于0.99
/0.999
,则让之前的shadow_variable
起主导作用
滑动平均机制:作用在BP更新完权重后,让训练在后期变得更加平缓,稳定。
具体代码:
import tensorflow as tf
v1 = tf.Variable(0, dtype=tf.float32)
step = tf.Variable(tf.constant(0))
ema = tf.train.ExponentialMovingAverage(0.99, step)
maintain_average = ema.apply([v1]) # ema.apply([v1])对v1做ExponentialMovingAverage
with tf.Session() as sess:
init = tf.initialize_all_variables()
sess.run(init)
# v1是未进行ExponentialMovingAverage的shadow_variable
# ema.average(v1)取出本轮被ema.apply([v1])计算的ExponentialMovingAverage后的variable
print(sess.run([v1, ema.average(v1)])) # 初始的值都为0 variable和shadow_variable一样
sess.run(tf.assign(v1, 5)) # 模拟BP后v1变成了5
print(sess.run(maintain_average))
print(sess.run([v1, ema.average(v1)])) # decay=min(0.99, 1/10)=0.1, v1=0.1*0+0.9*5=4.5
sess.run(tf.assign(step, 10000)) # steps=10000
sess.run(tf.assign(v1, 10)) # v1=10
sess.run(maintain_average)
print(sess.run([v1, ema.average(v1)])) # decay=min(0.99,(1+10000)/(10+10000))=0.99, v1=0.99*4.5+0.01*10=4.555
sess.run(maintain_average)
print(sess.run([v1, ema.average(v1)])) # decay=min(0.99,(1+10000)/(10+10000))=0.99, v1=0.99*4.555+0.01*10=4.6
- 只有被
ema.apply(var)
的variable
才会在ema.average(var)
时,有具体值;否则输出NONE
并且EMA被广泛的应用在深度学习的BN层中,RMSprop,adadelta,adam等梯度下降方法.