《TensorFlow 实战Google深度学习框架》一书中比较简单的部分就不做过多介绍。由于本书对滑动平均模型介绍个人感觉有点过简,所以详细介绍这一节知识点。
一、激活函数
tensorflow提供了多种激活函数,常用的有:
x = tf.constant([1.,2.])
y1 = tf.sigmoid(x)
y2 = tf.tanh(x)
y3 = tf.nn.relu(x)
y4 = tf.nn.leaky_relu(x)
y5 = tf.nn.softmax(x)
with tf.Session() as sess:
print(sess.run(y4))
二、损失函数定义
损失函数常用函数
tf.log:对张量求对数
tf.matmul:矩阵乘法
tf.clip_by_value:将张量数值限制在一个范围之内(在第一篇中已做详述)
v = tf.constant([[1.1,2.2,3.3], [4.1,5.2,6.3]])
with tf.Session() as sess:
print(tf.clip_by_value(v, 2.5, 4.5).eval())
tf.reduce_mean:对矩阵做平均
v = tf.constant([[1.1,2.2,3.3], [4.1,5.2,6.3]])
with tf.Session() as sess:
print(tf.reduce_mean(v).eval())
tf.reduce_sum:对矩阵求和
tf.nn.softmax_cross_entropy_with_logits:softmax回归的交叉熵损失函数
# y是真实样本标签,y_hat是预测标签
loss = tf.nn.softmax_cross_entropy_with_logits(
labels = y, logits = y_hat)
均方误差损失函数:
mse = tf.reduce_mean(tf.square(y - y_hat))
自定义损失函数
tf.greater:比较两个输入张量中的每一个元素大小,返回比较结果
tf.where:当第一个参数即选择条件为True,tf.where选择第二个参数,反之选择第三个参数
# tf.greater
loss = tf.reduce_sum(tf.where(tf.greater(v1, v2),
(v1 - v2) * a, (v2 - v1) * b))
三、神经网络优化算法
1.优化学习率
为了能解决学习率过大和过小的问题,使用指数衰减法能有效解决问题。
tf.train.exponential_decay函数实现了指数衰减学习率
decayed_learning_rate = \
learning_rate * decay_rate ^ (global_step / decay_steps)
decayed_learning_rate:表示每一轮优化时使用的学习率
learning_rate:为事先设定的初始学习率
decay_rate:衰减系数
decay_steps:衰减速度
同时衰减方式有阶梯状衰减学习率和连续衰减学习率,通过staircase设置,当为True时是阶梯函数,反之为连续衰减
global_step = tf.Variable(0)
# 使用exponential_decay生成新的学习率
learning_rate = tf.train.exponential_decay(
0.1, global_step, 100, 0.96, staircase = True)
learning_step = tf.train.GradientDescentOptimizer(learning_rate).minize(...,global_step = global_step)
2.正则化
L1和L2正则化
weights = tf.constant([[1.0, -2.0], [-3.0, 4.0]])
with tf.Session() as sess:
# L1正则化的使用
print(sess.run(tf.contrib.layers.l1_regularizer(0.5)(weights)))
# L2正则化的使用
print(sess.run(tf.contrib.layers.l2_regularizer(0.5)(weights)))
实际应用中,常使用L2正则化
w = tf.Variable(tf.random_normal([2, 1], stddev = 1, seed = 1))
y = tf.matmul(x, w)
loss = tf.reduce_mean(tf.square(y - y_hat)) + tf.contrib.layers.l2_regularizer(lambd)(w)
当网络结构较为复杂的时候,使用上述定义正则化的方式会导致代码的可读性较差,因此常使用下述定义方法:
def get_weight(shape, lambd):
# 生成变量
var = tf.Variable(tf.random_normal(shape), dtype = tf.float32)
# 将新生成的变量L2正则化损失项加入集合中
tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(lambd)(var))
return var
x = tf.placeholder(tf.float32, shape = [None, 2])
y = tf.placeholder(tf.float32, shape = [None, 1])
batch_size = 8
lambd = 0.001
# 定义每层网络中的节点数
layer_dimension = [2, 10, 10, 10, 1]
# 神经网络的层数
n_layers = len(layer_dimension)
# 当前传播至最深层的节点
cur_layer = x
in_dimension = layer_dimension[0]
# 循环创建五层全连接神经网络
for i in range(1, n_layers):
out_dimension = layer_dimension[i]
weight = get_weight((in_dimension, out_dimension), lambd)
bias = tf.Variable(tf.zeros([out_dimension]))
cur_layer = tf.nn.relu(tf.matmul(cur_layer, weight) + bias)
in_dimension = layer_dimension[i]
# 定义损失函数
mse_loss = tf.reduce_mean(tf.square(y - y_hat))
# 将均方误差损失函数加入损失集合
tf.add_to_collection("losses", mse_loss)
# tf.get_collection以列表的形式返回losses集合中所有元素
# 由正则化损失函数的形式我们可以知道,将这些元素部分加在一起得到最终损失函数
loss = tf.add_n(tf.get_collection('losses'))
四、滑动平均模型
因为在深度学习算法理论中,由于本人才疏学浅,刚看到这个模型的时候也是一脸懵逼,不曾了解过滑动平均模型,经过多方查阅后得知,滑动平均模型机制即在更新参数的时候防止参数更新发生突变情况,因此会有一个影子变量的概念,这个影子变量与原变量之间的对应关系可以有效的防止参数发生不正常的更新现象,能有效增加模型的健壮性。
Tensorflow中提供tf.train.ExponentialMovingAverage来实现滑动平均模型。
该函数为每个变量维护一个影子变量,影子变量的初始值就是相应变量的初始值。影子变量根据下式更新:
shadow_variable:影子变量
variable:待更新变量
decay:衰减率
观察上式可以知道,衰减率decay决定模型更新速度,decay越大,shadow_variable(此时代表原来旧的影子变量)占比就越大,对新的影子变量更新幅度就更小。同时为了能使模型在训练前期更新得更快,ExponentialMovingAverage初始化提供了num_updates参数,由此定义:
上述式子就表示了当迭代次数num_updates,可以发现随着迭代次数的增加,decay也逐渐趋向于1,这样在迭代后期,此时模型可能已经收敛到最有点附近,却保证了模型不会出现非正常的参数更新情况。
# 定义变量用于计算滑动平均
v1 = tf.Variable(0, dtype = tf.float32)
# step表示之前提到的num_updates,初始没有训练,自然也就是0.
# 随着step增加,控制衰减率decay
step = tf.Variable(0, trainable = False)
# 定义滑动窗口类,衰减率被初始化成0.99,控制衰减率是之前
ema = tf.train.ExponentialMovingAverage(0.99, step)
# 定义一个更新变量滑动平均的操作。通过给定一个列表,列表内的所有变量都会被更新
maintain_averages_op = ema.apply([v1])
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
# 因为初始化都为0,所以输出为0
print(sess.run([v1, ema.average(v1)]))
# 把5赋值给v1,计算得到滑动平均更新为4.5
sess.run(tf.assign(v1, 5))
sess.run(maintain_averages_op)
print(sess.run([v1, ema.average(v1)]))
# step = 1000
sess.run(tf.assign(step, 10000))
sess.run(tf.assign(v1, 10))
sess.run(maintain_averages_op)
print(sess.run([v1, ema.average(v1)]))
sess.run(maintain_averages_op)
print(sess.run([v1, ema.average(v1)]))