在前面已经讲了Tensorflow常用的五种优化方法,其中在结构设计上使用激活函数和多层隐藏层。在优化过程中使用指数衰减来设置学习率,加入正则化的损失函数以及滑动平均模型,有效的提高了神经网络模型的正确率。下面学习变量管理:
在上一篇博文中,将计算神经网络前向传播结果的过程抽象成了一个函数。通过这种方式在训练和测试过程中可以统一调用这个函数来获得模型的前向传播结果,函数帝国一如下:
definference(input_tensor,avg_class,weights1,biases1,weights2,biases2):
从定义来看,这个函数包含了神经网络的所有参数。但是当神经网络更复杂、参数更多时,就需要一个更好的方式来传递和管理神经网络的参数。Tensorflow提供了通过变量名称来创建或者获取一个变量的机制,由tf.get_variable和tf.variable_scope函数实现。
前面通过tf.Variable函数创建变量,除此之外,还可以通过tf.get_variable函数创建或者获取变量。下面给出两个的使用样例,效果相同。
v=tf.get_variable("v",shape=[1],initializer=tf.constant_initializer(1.0))
v=tf.Variable(tf.constant(1.0,shape=[1]),name="v")
下面是Tensorflow的7种不同的初始化函数
初始化函数 | 功能 | 主要参数 |
tf.constant_initializer | 将变量初始化为给定常量 | 常量的取值 |
tf.constant_normal_initializer | 将变量初始化为满足正态分布的随机值 | 正太分布的均值和标准差 |
tf.truncated_normal_initializer | 将变量初始化为满足正态分布的随机值,如果随机值出来的偏离平均值超过2个标准差,那么这个数将被重新随机 | 正态分布的均值和标准差 |
tf.random_uniform_initializer | 将变量初始化为满足平均分布的随机值 | 最大最小值 |
tf.uniform_unit_scaling_initializer | 将变量初始化为满足平均分布但不影响输出数量级的随机值 | factor(产生随机值时乘的系数) |
tf.zeros_initializer | 将变量设置为全0 | 变量维度 |
tf.ones_initializer | 将变量设置为全1 | 变量维度 |
如果需要通过tf.get_variable获取一个已经创建的变量,需要通过tf.variable_scope函数来生成一个上下文管理器,并明确指定在这个上下文管理器中,tf.get_variable将直接获取已经生成的变量,如下代码所示:
#在名字为foo的命名空间内创建名字为v的变量
with tf.variable_scope("foo"):
v=tf.get_variable("v",[1],initializer=tf.constant_initializer(1.0))
#因为命名空间foo中已经存在名字为v的变量,所以下面代码会报错
with tf.variable_scope("foo"):
v=tf.get_variable("v",[1])
#在生成上下文管理器时,将参数reuse设置为True。这样tf.get_variable函数将直接获取已经声明的变量
with tf.variable_scope("foo",reuse=True):
v1=tf.get_variable("v",[1])
print v==v1 #输出为True,代表v,v1代表相同的Tensorflow中的变量
#将参数reuse设置为True时,tf.variable_scope将只能获取已经创建过的变量。因为在命名空间bar中还没创建变量v,所以以下代码会报错
with tf.variable_scope("bar",reuse=True):
v=tf.get_variable("v",[1])
关于tf.variable_scope函数嵌套时,reuse参数的取值是如何确定的
with tf.variable_scope("root")
#可以通过tf.get_variable_scope().reuse函数来获取上下文管理器中reuse参数的取值
print tf.get_variable_scope().reuse #输出False,即最外层reuse是False
with tf.variable_scope("foo",reuse=True): #新建一个嵌套上下文的管理器,并指定reuse为True
print tf.get_variable_scope().reuse #输出为True
with tf.variable_scope("bar"): #新建一个嵌套的上下文管理器,但不指定reuse,这是 # #reuse的取值回合外面一层保持一致。
print tf.get_variable_scope().reuse #输出为True
print tf.get_variable_scope().reuse #输出为False,退出reuse设置为True的上下文之后,又
#回到了False.
reuse为True时,tf.get_variable函数会直接获取已经创建的变量。如果变量不存在,将报错
reuse为False时,tf.get_variable函数会创建新的变量,若变量已经存在,则报错。
同时tf.variable_scope函数生成的上下文管理器也会创建一个Tensorflow中的命名空间,在命名空间内创建的变量名称都会带上这个命名空间作为前缀。下面代码是通过tf.variable_scope来管理变量的名称
v1=tf.get_variable("v",[1])
print v1.name #输出v:0.“v”为变量的名称,“:0”表示这个变量时生成变量这个运算的第一个结果。
with tf.variable_scope("foo"):
v2=tf.get_variable("v",[1])
print v2.name #输出foo/v:0.在tf.variable_scope中创建的变量,名称前面会加入名称空间的名称,
#并通过/来分隔命名空间的名称和变量的名称
with tf.variable_scope("foo"):
with tf.variable_scope("bar"):
v3=tf.get_variable("v",[1])
print v3.name #输出foo/bar/v:0.命名空间可以嵌套,同时变量的名称也会加入所有命名空间
#的名称做前缀
v4=tf.get_variable("v1",[1])
print v4.name #输出foo/v1:0.当命名空间退出之后,变量名称也就不会在被加入前缀了
#创建一个名称为空的命名空间,并设置reuse=True
with tf.variable_scope("",reuse=True):
v5=tf.get_variable("foo/bar/v",[1]) #可以直接通过带命名空间名称的变量名来获取
#其他命名空间下的变量,比如这里通过指定名称foo/bar/v
#来获取在命名空间foo/bar/中创建的变量
print v5==v3 #输出True
v6=tf.get_variable("foo/v1",[1])
print v6==v4 #输出为True
通过tf.variable_scope和tf.get_variable函数,对前向传播结果的函数做了一些改进,代码如下:
def inference(input_tensor,reuse=False)
#定义第一层神经网络的变量和前向传播过程
with tf.variable_scope('layer1',reuse=reuse):
#根据传进来的reuse来判断是创建新变量还是使用已经创建好的。在第一次构造网络时
#需要创建新的变量,以后每次调用这个函数都直接使用reuse=True就不需要每次将变量传进来
weights=tf.get_variable("weights",[INPUT_NODE,LAYER1_NODE],
initializer=tf.truncated_normal_initializer(stddev=0.1))
biases=tf.get_variable("biases",
[LAYER1_NODE],initializer=tf.constant_initializer(0.0))
layer1=tf.nn.relu(tf.matmul(input_tensor,weights)+biases)
#类似地定义第二层神经网络的变量和前向传播过程
with tf.variable_scope('layer2',reuse=reuse):
weights=tf.get_variable("weights",[LAYER1_NODE,OUTPUT_NODE],
initializer=tf.truncated_normal_initializer(stddev=0.1))
biases=tf.get_variable("biases",[OUTPUT_NODE],
tf.constant_initializer(0.0))
layer2=tf.matmul(layer1,weights)+biases
#返回最后前向传播结果
return layer2
x=tf.placeholder(tf.float32,[None,INPUT_NODE],name='x-input')
y=inference(x)