神经网络优化2

上一篇博客中我们讨论了使用不同的损失函数训练参数、使用softmax()函数获得输出分类的概率分布。

这一篇中,我们将讨论学习率、滑动平均对模型参数变化及预测结果的影响。

一、学习率

1、学习率learning_rate表示了每次参数更新的幅度大小。学习率过大,会导致待优化的参数在最小值附近波动,不收敛;学习率过小,会导致待优化的参数收敛缓慢。在训练过程中,参数的更新向着损失函数梯度下降的方向(w=w-学习率乘以梯度)。

更新的公式为:

假设损失函数 loss=(w+1)^2,梯度是损失函数loss的导数为 ∇ = 2w + 2。如参数初值为5,学习率为0.2,则参数和损失函数更新如下:

损失函数 loss=(w+1)^2的图像为:

由图可知,损失函数loss的最小值会在(-1,0)处得到,此时损失函数的导数为0,得到最终参数w=-1,

实现代码:

#coding:utf-8
#设损失函数loss=(w+1)^2,令w初值为5,反向传播就是求最优w,即求最小loss对应的w值
import tensorflow as tf
#定义待优化参数w初值为5
w = tf.Variable(tf.constant(5,dtype = tf.float32))
#定义损失函数loss
loss  =  tf.square(w+1)
#定义反向传播
train_step = tf.train.GradientDescentOptimizer(0.2).minimize(loss)
#生成会话,训练40轮
with tf.Session() as sess:
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    for i in range(40):
        sess.run(train_step)
        w_val = sess.run(w)
        loss_val = sess.run(loss)
        print("After %d steps:w is %f,loss is %f."%(i,w_val,loss_val))
        

运行结果:

有运行结果可知,随着损失函数的减小,当损失函数减为零时,取得最优参数w=-1。

2、学习率的设置——指数衰减学习率

学习率过大,会导致待优化的参数在最小值附近波动,不收敛;学习率过小,会导致待优化的参数收敛速度缓慢。读者可以将上面代码中的学习率分别修改为1和0.00001查看运行结果,这里不再赘述。

其实,我们也可以让学习率随着训练轮数变化而动态更新。由此引出指数衰减学习率。

指数衰减学习率:

LEARNING_RATE_BASE——学习率初始值

LEARNING_RATE_DECAY——学习率衰减值

global-step——当前训练轮数,为不可训练型参数

LEARNING_RATE_STEP——学习率更新频率,一般取输入数据集总体样本/每次喂入样本数

若 staircase 设置为 True 时,表示 global_step/learning rate step 取整数,学习 率阶梯型衰减;若 staircase 设置为 false 时,学习率会是一条平滑下降的曲线。
若在上面例子中,模型设置过程不设置固定的学习率,使用指数衰减学习率进行训练,其中,学习率初始值设置为0.1,学习率衰减率设置为0.99,BATCH_SIZE设置为1,则代码如下:
#coding:utf-8
#设损失函数 loss=(w+1)^2,令w初值是长数10,反向传播就是求最优w,即求loss对应的w值
#使用指数衰减的学习率,在迭代初期得到较高的下降速度,可以在较小的训练轮数下去有收敛度
import tensorflow as tf

LEARNING_RATE_BASE = 0.1#学习率初始值
LEARNING_RATE_DECAY = 0.99#学习率衰减率
LEARNING_RATE_STEP = 1#喂入多少轮BATCH_SIZE后,更新一次学习率,一般设置为:总样本数/BATCH_SIZE

#运行了几轮BATCH_SIZE的计数器,初值为0,设为不被训练
global_step = tf.Variable(0,trainable=False)
#定义指数下降学习率
learning_rate = tf.train.exponential_decay(LEARNING_RATE_BASE,global_step,LEARNING_RATE_STEP,LEARNING_RATE_DECAY,staircase=True)
#定义待优化参数,
w = tf.Variable(tf.constant(5,dtype=tf.float32))
#定义损失函数loss
loss = tf.square(w+1)
#定义反向传播方法
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss,global_step=global_step)

#生成会话
with tf.Session() as sess:
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    for i in range(40):
        sess.run(train_step)
        learning_rate_val = sess.run(learning_rate)
        global_step_val=sess.run(global_step)
        w_val=sess.run(w)
        loss_val=sess.run(loss)
        print("after %s steps:global_step is %f,w is %f,learning_rate is %f,loss is %f"%(i,global_step_val,w_val,learning_rate_val,loss_val))

运行结果如下:

由此可见,随着训练轮数的增加,学习率不算减小。

二、滑动平均

滑动平均:记录了一段时间模型中所有参数w和b各自的平均值,利用滑动平均值可以增强模型的泛化能力。
滑动平均(影子)计算公式:影子=衰减率*影子+(1-衰减率)*参数
代码如下:
#coding:utf-8
import tensorflow as tf

#1.定义变量及滑动平均

#定义一个32位浮点变量,初始值为0.0,这个代码就是不断更新w1参数,优化w1参数,滑动平均做了w1的影子
w1=tf.Variable(0,dtype = tf.float32)

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

#实例化滑动平均类,给衰减率为0.99,当前轮数globa_step
MOVING_AVERAGE_DECAY = 0.99
ema = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY,global_step)
#ema.apply后的括号里是更新列表,每次运行sess.run(ema_op)时,对更新列表中的元素求滑动平均值
#在实际应用中会使用tf.trainable_variables())自动将所有待训练的参数汇总为列表
#ema_op=ema.apply([w1])
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)]))

运行结果:

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值