4.深层网络

  • 深度学习的两个重要特性:多层和非线性。
  • 线性模型的局限性:
  • 任意线性模型的组合仍然还是线性模型。
  • 激活函数实现去线性化。
  • 多层网络解决异或问题。
  • 交叉熵刻画的是两个概率分布之间的距离,交叉熵值越小,两个概率分布越接近。交叉熵函数是不对称的(H(p|q)=H(q|p)),它刻画的是通过概率分布q来表达概率分布p的困难程度。p代表正确答案,q代表预测值。
# 对张量中所有元素依次求对数
tf.log()
# 矩阵乘法
tf.matmul()
# 元素之间直接相乘
*
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(
	labels=y_, logits=y)
# tf.where函数判断和选择都是在元素级别进行
loss= tf.reduce_sum(tf.where(tf.greater(v1, v2), (v1 - v2), (v2 - v1)))

梯度下降算法并不能保证被优化的函数达到全局最优解。只有当损失函数为凸函数时,梯度下降算法才能保证达到全局最优解。除了不能达到全局最优解,梯度下降算法的另一个问题就是计算时间太长。因为要在全部训练数据上最小化损失。所以损失函数是在所有训练数据上的损失和。这样在每一轮迭代中都需要计算在全部训练数据上的损失函数。
随机梯度下降算法在每一轮迭代中,随机优化某一条训练数据上的损失函数,这样每一轮参数更新的速度就大大加快了。因为每次优化的只是某一条数据上的损失函数,所以它的问题也非常明显:在某一条数据上损失函数更小并不代表在全部数据上损失函数更小,甚至无法达到局部最优。
综合二者每次计算一小部分训练数据的损失函数。通过矩阵运算,每次在一个batch上优化神经网络的参数并不会比单个数据慢太多,另外每次使用一个batch可以大大减小收敛所需要的迭代次数,同时可以使收敛到的结果更加接近梯度下降的效果。
学习率的设置

# 指数衰减法
tf.train.exponential_decay(0.1, global_step, 100, 0.96, staircase=True)

过拟合问题

tf.contrib.layers.l2_regularizer(lambda)(weights)
# add_to_collection函数将正则化损失加入集合
tf.add_to_collection(
	'losses', tf.contrib.layers.l2_regularizer(lambda)(weights))
...
mse_loss = ...
# 将均方误差损失函数加入损失集合
tf.add_to_collection('losses', mse_loss)
# get_collection返回一个列表,这个列表是所有这个集合中的元素。
# 在这个样例中,这些元素就是损失函数的不同部分,将它们加起来就是损失函数
loss = tf.add_n(tf.get_collection('losses'))
import tensorflow as tf 


# 获取一层神经网络边上的权重,并将这个权重的L2正则化损失加入名称为'loss'的集合中
def get_weight(shape, lam):
    # 生成一个变量
    var = tf.Variable(tf.random_normal(shape), dtype=tf.float32)
    # add_to_collection函数将这个新生成变量的L2正则化损失项加入集合
    # 这个函数的第一个参数'losses'是集合的名字,第二个参数是要加入这个集合的内容
    tf.add_to_collection('losses',tf.contrib.layers.l2_regularizer(lam)(var))
    # 返回生成的变量
    return var


x = tf.placeholder(tf.float32, shape=(None, 2))
y_ = tf.placeholder(tf.float32, shape=(None, 1))
batch_size = 8
# 定义了每一层网络中节点的个数
layer_dimension = [2, 10, 10, 10, 1]
# 神经网络的层数
n_layers = len(layer_dimension)

# 这个变量维护前向传播时最深层的节点,开始的时候就是输入层
cur_layer = x
# 当前层节点的个数
in_dimension = layer_dimension[0]

# 通过一个循环来生成5层全连接的神经网络结构
for i in range(1, n_layers):
    # layer_dimension[i]为下一层的节点个数
    out_dimension = layer_dimension[i]
    # 生成当前层中权重的变量,并将这个变量的L2正则化损失加入计算图上的集合
    weight = get_weight([in_dimension, out_dimension], 0.001)
    bias = tf.Variable(tf.constant(0.1, shape=[out_dimension]))
    # 使用relu激活函数
    cur_layer = tf.nn.relu(tf.matmul(cur_layer, weight) + bias)
    # 进入下一层之前将下一层的节点个数更新为当前层节点个数
    in_dimension = layer_dimension[i]

# 在定义神经网络前向传播的同时已经将所有的L2正则化损失加入了图上的集合,
# 这里只需要计算刻画模型在训练数据上表现得损失函数
mse_loss = tf.reduce_mean(tf.square(y_ - cur_layer))

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

# get_collection返回一个列表,这个列表是所有这个集合中的元素。在这个样例中,
# 这些元素就是损失函数的不同部分,将它们加起来就可以得到最终的损失函数
loss = tf.add_n(tf.get_collection('losses'))

滑动平均模型

  • 用途:用于控制变量的更新幅度,使得模型在训练初期参数更新较快,在接近最优值处参数更新较慢,幅度较小
  • 方式:主要通过不断更新衰减率来控制变量的更新幅度
  • 对每一个变量都会维护一个影子变量,影子变量的初始值为变量的初始值,每次运行变量更新时,影子变量的值会更新:
    影子变量=decay*影子变量+(1-decay)*变量
    decay越大,模型越稳定,实际应用中,一般设为非常接近1的数(比如0.9999)
v1 = tf.Variable(0, dtype=tf.float32)
step = tf.Variable(0, trainable=False)
tf.train.ExponentialMovingAverage(0.99, step)
# 定义一个更新变量滑动平均操作。这里需要给定一个列表,每次执行这个操作时,
# 这个列表中的变量都会被更新
maintain_averages_op = ema.apply([v1])
with tf.Session() as sess:
	init_op = ...
	sess.run(init_op)
	# 通过ema.average(v1)获取滑动平均之后变量的值值
	sess.run([v1, ema.average(v1)])
	sess.run(tf.assign(v1, 5))
	sess.run(maintain_averages_op)
	sess.run([v1, ema.average(v1)])
	# 更新step的值
	sess.run(tf.assgin(step, 10000))
	# 更新v1的值为10
	sess.run(tf.assgin(v1, 10))
	sess.run(maintain_averages_op)
	sess.run([v1, ema.average(v1)])
import tensorflow as tf 

# 定义一个变量用于计算滑动平均,这个变量的初始值为0.注意这里手动指定了变量的类型
# 为tf.float32,因为所有需要计算滑动平均的变量必须是实数型
v1 = tf.Variable(0, dtype=tf.float32)
# 这里step变量模拟神经网络中迭代的轮数,可以用于动态控制衰减率
step = tf.Variable(0, trainable=False)

# 定义一个滑动平均的类(class)。初始化时给定了衰减率(0.99)和控制衰减率的变量step
ema = tf.train.ExponentialMovingAverage(0.99, step)
# 定义一个更新变量滑动平均的操作。这里需要给定一个列表,每次执行这个操作时
# 这个列表中的变量都会被更新
maintain_averages_op = ema.apply([v1])
with tf.Session() as sess:
    # 初始化所有变量
    init_op = tf.initialize_all_variables()
    sess.run(init_op)

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

    # 更新变量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_averages_op)
    print(sess.run([v1, ema.average(v1)]))

    # 更新step的值为1000
    sess.run(tf.assign(step, 1000))
    # 更新v1的值为10
    sess.run(tf.assign(v1, 10))
    # 更新v1的滑动平均值。衰减率为min{0.99,(1+step)/(10+step)=0.999}=0.99,
    # 所以v1的滑动平均会被更新为0.99*4.5+0.01*10=4.555
    sess.run(maintain_averages_op)
    print(sess.run([v1, ema.average(v1)]))

    # 再次更新滑动平均值,得到的新滑动平均值为0.99*4.555+0.01*10=4.60945
    sess.run(maintain_averages_op)
    print(sess.run([v1, ema.average(v1)]))
发布了59 篇原创文章 · 获赞 17 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Miracle_520/article/details/93420940
今日推荐