神经网络优化(3)滑动平均

中国大学mooc课程笔记:《人工智能实践:Tensorflow笔记》曹健 第四讲:神经网络优化 课程地址 课程地址


滑动平均:记录了一段时间内模型中所有参数 w 和 b 各自的平均值。利用滑动平均值可以增强模型的泛化能力。

prt32.png

用 Tesnsorflow 函数表示为:

1
ema = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAYglobal_step) 

其中,MOVING_AVERAGE_DECAY 表示滑动平均衰减率,一般会赋接近 1 的值,global_step 表示当前训练了多少轮。

1
ema_op = ema.apply(tf.trainable_variables())

其中,ema.apply()函数实现对括号内参数求滑动平均,tf.trainable_variables()函数实现把所有待训练参数汇总为列表。

1
2
with tf.control_dependencies([train_step, ema_op]): 
      train_op = tf.no_op(name='train') 

其中,该函数实现将滑动平均和训练过程同步运行。

查看模型中参数的平均值,可以用 ema.average()函数。

例如:

ptr34.png

代码:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import tensorflow as tf

# 1.定义变量及滑动平均类
# 定义一个32位浮点型变量,初始值位0.0,这个代码就是不断更新参数W1,优化W1参数,滑动平均个W1的影子

w1 = tf.Variable(0, dtype=tf.float32)

# 定义num_updates(NN的迭代轮数),初始值为0,不可被优化训练,这个参数不训练
global_step = tf.Variable(0, trainable=False)

# 实例化滑动平均类,给删减率为0.99,当前轮数global_step
MOVING_AVERAGE_DECAY = 0.99
ema = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY, global_step)

# ema.apply后的括号里是更新列表,每次运行sess.run(ema_op)时,对更新列表中的元素求滑动平均值。
# 在实际应用中会使用tf.trainable_varibles()自动将所有待训练的参数汇总为列表
# ema_op = ema.apply(tf.trainable_variables())
ema_op = ema.apply(tf.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)]))

输出结果:

1
2
3
4
5
6
7
8
9
[0.0, 0.0]
[1.0, 0.89999998]
[10.0, 1.6445453]
[10.0, 2.3281732]
[10.0, 2.955868]
[10.0, 3.5322061]
[10.0, 4.061389]
[10.0, 4.5472751]
[10.0, 4.9934072]

小结

关于模型的泛化能力:

“机器学习的目标很少是去复制训练数据,而是预测新情况。也就是说,我们希望对于训练集之外的输入(其正确的输出并没有在训练集中给出)能够产生正确的输出。训练集上训练的模型在多大程度上能够对新的实例预测出正确输出称为泛化。”

参考资料: http://book.51cto.com/art/200906/130579.htm

PS: 前几天,感觉进度慢,着急看代码,才发现面对自己毫无头绪的知识结构并且学习时间不那么充裕时,着急直接看或者耐心一点一点积累都行不通。要兵分两路,一面学习基础知识,一面探索高层次的思想,这样也许会更好些。前些日子的功夫也不白费,起码配置好了游戏环境,接下来需要一个实例来体验训练游戏的流程,然后阅读例子程序代码,这就需要这些基础的代码积累,毕竟这些是机器学习的原子知识点。再提醒自己一句,不要着急,也不要放松,在有限的时间内做好力所能及的事,别留遗憾。