Tensorflow 实战Google深度学习框架——学习笔记(三)TensorFlow中提供的网络优化函数

4.4.1 学习率的设置

学习率过大会导致参数在靠近最优值的时候来回摆动,过小会导致参数迭代速度太慢,TensorFlow针对这种问题提供了一种更加灵活的学习率设置方法——指数衰减法。
指数衰减法先用较大的学习率来获得较优解,随着迭代逐步减小学习率,使得模型在后期更加稳定地接近最优解。这个方法即是tf.tarin.exponential_decay(),它实现了以下代码的功能
decayed_learning_rate = learning_rate * decay_rate ^ (global_step / decay_steps)
其中decayed_learning_rate为每一轮使用的学习率,learning_rate为设置的初始学习率,decay_rate为衰减系数,decay_steps为衰减速度。 global_step为总迭代次数
tf.tarin.exponential_decay()可以通过设置参数staircase选择不同的衰减方式,默认为False。当staircase为True的时候global_step / decay_steps会被转化为整数,这使得学习率成为一个阶梯函数。这个时候decay_steps代表了完整训练一遍所有数据所需要的迭代次数。整个公式意味着每完整地迭代一遍数据,学习率才会减小一次,这使得训练集中的所有数据对于模型的训练有相同的作用。当使用连续的指数衰减学习率的时候,意味着越往后的数据对于模型的训练作用越小。
这里写图片描述
下面是tf.tarin.exponential_decay()的使用

import tensorflow as tf


global_step = tf.Variable(0)  # 定义总迭代次数

# 其中0.1的基础学习率learning_rate,100是衰减速度decay_steps, 每训练一百次就乘以0.96(衰减)一次
# 0.96是衰减系数decay_rate,staircase=True表示这个一个阶梯函数, global_step
learning_rate = tf.train.exponential_decay(0.1, global_step, 100, 0.96, staircase=True)
learning_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(...my loss..., global_step=global_step)

4.4.2 过拟合问题

过拟合问题简单来说就是模型过度匹配训练集数据,但是对于之外的数据没有太好的匹配度。举个例子来说就是一个猫狗分类器在训练集上的准确率有95%,但是在测试集上的准确率只有70%,这就叫过拟合。
针对过拟合的一种解决方法是正则化,本质上是通过限制权重的大小,使得模型不能随意拟合训练数据中的随机噪音。
回归主题,TensorFlow中的正则化过程是:

w = tf.Variable(tf.random_normal([2, 1], stddev=1, seed=1))
y = tf.matmul(x, w)

loss = tf.reduce_mean(tf.square(yhat - y)) + tf.contrib.layersers.l2_regularizer(lambd)(w)
# lamdb是指λ

在上面的程序中,loss是定义的损失函数,由两个部分组成,第一个部分是均方差损失函数;第二个部分是L2正则化,防止模型过度拟合数据中的噪音lambd是正则化的权重。()中的w就是需要正则化的参数,由此可见使用方法是tf.contrib.layersers.l2_regularizer(正则化的权重)(正则化的参数)
最后,在放到sess中run()j就好了: sess.run(tf.reduce_mean(tf.square(yhat - y)) + tf.contrib.layersers.l2_regularizer(lambd)(w))

但是这种方式还可以更加简便,现在的长度不适合用在复杂的网络之中。为了解决这个问题,使用TensorFlow中提供的集合
以下代码给出了通过集合计算一个5层神经网络带L2正则化的损失函数计算过程

import tensorflow as tf

def get_weight(shape, lambd):
    # 根据维度生成一个随机参数
    var = tf.Variable(tf.random_normal(shape, dtype=tf.float32))
    # 将参数L2正则化之后加入到losses集合中
    tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(lambd)(var))
    return var

x = tf.placeholder(tf.float32, shape=(None, 2))
yhat = tf.placeholder(tf.float32, shape=(None, 1))
batch_size = 8

layer_dim = [2, 10, 10, 10, 1]  # 定义每一层网络中的节点数

n_layers = len(layer_dim)  # 定义网络的层数

cur_layer = x

in_dim = layer_dim[0]  # 输入层的节点个数

# 通过循环来生成5层全连接的神经网络结构
for i in range(1, n_layers):
    out_dim = layer_dim[i]  # 获取下一层的节点个数
    # 根据当前层和下一层的节点数随机生成对应维度的权重w,lambd设置为0.001
    # 在生成的同时,在get_weight()中还把L2正则化的损失值加到了losses集合中
    weight = get_weight([in_dim, out_dim], 0.001) 
    bias = tf.Variable(tf.constant(0.1, shape=[out_dim]))  # 根据下一层节点数生成对应维度的bias
    cur_layer = tf.nn.relu(tf.matmul(cur_layer, weight) + bias)
    in_dim = layer_dim[i]  # 计算过后更新下一层节点数为当前节点数

# 损失函数
mse_loss = tf.reduce_mean(tf.square(yhat - cur_layer))

# 将均方误差损失函数加入到losses集和
tf.add_to_collection('losses', mse_loss)

# get_collection()方法返回集合中所有元素组成的列表
# 此时losses列表中包含了各个weight的L2正则化损失值和损失函数的值,
# 将这些全部加起来就可以获得整个神经网络的L2正则化后的新损失函数
# tf.add_n()用于将列表中元素全部加起来
loss = tf.add_n(tf.get_collection('losses')) 

上面的方法在创建权重w的时候还把w的所有正则化损失值加到了losses集合中,最后在用get_collection()的方法获取losses集合的所有值,全部加起来获得具有L2正则化效果的损失函数值。大大提高的代码的可读性和重复可用性

4.4.3 滑动平均模型

滑动平均模型在很多应用上都可以一定程度地提高模型在测试数据上的鲁棒性
这里写图片描述
代码实现方式如下:

import tensorflow as tf


# 定义一个变量用于计算滑动平均,初始值为0.这里注意手动定义了变量的类型
# 为tf.float32,因为所有需要计算滑动平均的变量必须是实数型
v1 = tf.Variable(0, dtype=tf.float32)

# 用step模拟神经网络中的迭代次数,可以用于动态控制衰减率
step = tf.Variable(0, trainable=False)  

# 定义一个滑动平均的类,给定衰减率0.99和控制衰减率的变量step
ema = tf.train.ExponentialMovingAverage(0.99, step)

# 定义一个更新滑动平均的操作。需要给定一个列表,每次执行这个操作列表中的数据都会被更新
maintain_average_op = ema.apply([v1])

with tf.Session() as sess:
    init = tf.global_variables_initializer()
    sess.run(init)

    # 通过ema.average(v1)获取滑动平均之后的取值。在初始化之后变量v1的值和v2的滑动平均都是0
    print(sess.run([v1, ema.average(v1)]))  # 输出[0.0, 0.0]

    # 更新变量v1值为5
    sess.run(tf.assign(v1, 5))

    # 更新v1的滑动平均值。衰减率为min(0.99, (1+step)/(10+step)=0.1) = 0.1
    # 所以v1被更新成0.1 * 0 + 0.9 * 5 = 4.5
    sess.run(maintain_average_op)
    print(sess.run([v1, ema.average(v1)]))

    # 更新step的值为10000
    sess.run(tf.assign(step, 10000))
    # 更新v1的值为10
    sess.run(tf.assign(v1, 10))

    # 更新v1的滑动平均值,衰减率为0.99,v1的滑动平均被更新为0.99*4.5 + 0.01*10=4.555
    sess.run(maintain_average_op)
    print(sess.run([v1, ema.average(v1)]))

    sess.run(maintain_average_op)
    print(sess.run([v1, ema.average(v1)]))

猜你喜欢

转载自blog.csdn.net/m0_38106113/article/details/81514000
今日推荐