[Tensorflow学习系列]Tensorflow学习二:正则化和滑动平均
本文是Tensorflow学习系列之第二篇
深度学习之TensorFlow构建训练模型
1.指数衰减的学习率设置
2.正则化避免过拟合
3.滑动平均使得最终模型更健壮
正则化
如图所示,为了解决过拟合,我们要对模型正则化。正则化的思想就是在损失函数中加入刻画模型复杂程度的指标。假设模型的损失函数为J(θ),那么我们在使用优化算法来优化损失函数的时候,不是直接优化J(θ),而是优化J(θ)+ λ *R(w)。其中R(w)是指模型的复杂程度,λ表示模型复杂损失在总损失中的比例。需要注意的是这里的θ表示的是一个神经网络中的所有参数,它包括权重和偏置。一般来说,模型复杂度只由其权重(w)来决定。而常用的来刻画模型复杂度的函数R(w)有两种,L1和L2
L1原理
L2原理
也可以共同使用
举例:
import numpy as np
import numpy.random as random
#正则化
weights=tf.constant([[1.0, -2.0],[-3.0 , 4.0]])
with tf.Session() as sess:
# L2正则化:tf.contrib.layers.L2_regularizer(lambda)(w)函数可以计算L2正则化项的值 。
# lambda参数表示了正则化项的权重,也就是公式J(θ)+λR(w)中的λ。w为需要计算正则化损失的参数。
print("L1正则化值为:",end="")
# 输出为(|1|+|-2|+|-3|+|4|)x0.5=5。其中0.5为正则化项的权重。
print(sess.run((tf.contrib.layers.l1_regularizer(0.5)(weights))))
#输出为(1^2+(-2)^2+3^2+(-4)^2)/2*0.5=7.5
print("L2正则化值为:", end="")
print(sess.run(tf.contrib.layers.l2_regularizer(0.5)(weights)))
输出为: 5
7.5
滑动平均模型
滑动平均模型可以是模型在测试数据集上具有更强的鲁棒性。在采用随机梯度下降法训练神经网络时,可以在一定程度上提高模型在测试数据上的表现。
tf.train.ExponentialMovingAverage()函数来实现滑动平均模型。
在初始化函数时需要提供一个衰减率(decay)用于控制模型变量的更新速度。ExponentialMovingAverage会为训练时的每个可训练变量提供一个影子变量(shadow_variable)。该值的初始值等于相应变量的初始值,每次变量更新时,影子变量的值会更新为:
影子变量=衰减率*影子变量+(1-衰减率)*变量
shadow_variable为 影子变量,variable为待更新的变量,decay为衰减率,衰减率越大模型越稳定,因为从上实在可以看出,衰减率越大,影子变量受变量更新的影响越小。在实际应用中,decay一般会设置成非常接近1的数(如0.999或0.9999)。
定义滑动平均模型
形式:tf.train.ExponentialMovingAverage(decay, num_updates=None, name=“ExponentialMovingAverage”)这个
其中有两个较为重要的参数:
decay :必填,为衰减率,用于控制模型更新的速度。
num_updates:选填,默认为none。用于控制衰减率decay的变化,若num_updates为none,则衰减率不变。当使用num_updates后,衰减率就为:
可以看出,num_updates越大,衰减率就越大。num_updates一般会为迭代轮数,所以当迭代轮数越大,模型参数就越稳定。
注:
apply()方法添加了训练变量的影子副本,并保持了其影子副本中训练变量的移动平均值操作。在每次训练之后调用此操作,更新移动平均值。
average()和average_name()方法可以获取影子变量及其名称。
import tensorflow as tf
# 定义变量v1用于滑动平均验证,并将其初始化为0.注意的是计算滑动平均时变量类型必须是实数型。tf.float32正好是实数型
v1 = tf.Variable(0, dtype=tf.float32) # 初始化v1变量
# step用来模拟神经网络的迭代步数,迭代步数通常在tf.train.GradientDescentOptimizer(lr).minimize(loss_train,global_step=global_step_train)函数执行时自动完成加1操作
step = tf.Variable(0, trainable=False) # 初始化step为0
# 初始化衰减率为0.99
ema = tf.train.ExponentialMovingAverage(0.99, step) # 定义平滑类,设置参数以及step
# 定义一个更新变量滑动平均的操作。这里需要给定一个列表,每次执行该操作时这个列表中的变量都会进行跟新
maintain_averages_op = ema.apply([v1]) # 定义更新变量平均操作,
with tf.Session() as sess:
# 初始化
init_op = tf.global_variables_initializer()
sess.run(init_op)
# 通过ema.average(v1)获得滑动平均后的值。
print("变量v1的初始值为: %f ,对应滑动平均初始值为:%f" % (sess.run(v1), sess.run(ema.average(v1))))
# 更新变量v1的取值
sess.run(tf.assign(v1, 5))
sess.run(maintain_averages_op)
# 衰减率为min(0.99,(1+step)/(10+step))=min(0.99,0.1)=0.1,所以v1的滑动平均会被更新为0.1*0+(1-0.1)*5=4.5
print("变量v1的第一次更新值为: %f ,对应滑动平均值为:%f" % (sess.run(v1), sess.run(ema.average(v1))))
# 更新step和v1的取值
sess.run(tf.assign(step, 10000))
sess.run(tf.assign(v1, 10))
sess.run(maintain_averages_op)
# 衰减率为min(0.99,(1+step)/(10+step))=min(0.99,10001/10010)=0.99 ,所以v1的滑动平均会被更新为0.99*4.5+(1-0.99)*10=4.555
print("变量v1的第二次更新值为: %f ,对应滑动平均值为:%f" % (sess.run(v1), sess.run(ema.average(v1))))
输出结果为