一 引入
当神经网络结构比较简单时,我们可以很好的管理神经网络中的参数。一旦网络结构变得复杂,参数更多,就需要一个好的方式来管理和传递神经网络中的参数了。
TensorFlow提供了通过变量名称来创建或获取一个变量的机制。在这个机制中,在不同的函数中可以通过变量的名称来使用变量,而不是每次都是将变量通过函数传参的方式来使用变量。TensorFlow中使用变量名称获取变量的机智主要通过tf.get_variable和 tf.variabel_scope函数实现的。
二 tf.Variable函数以及tf.get_variable函数
tf.get_variable和tf.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")
tf.get_variable和tf.Variable函数创建变量的过程基本是一样的。TensorFlow中提供的initializer函数一共有七种。分别如下:
1
名称:tf.constant_initializer
功能:将变量初始化为给定常量
主要参数:常量的取值
2
名称:tf.random_normal_initializer
功能:将变量初始化为满足正太分布的随机值
主要参数:正太分布的均值和标准差
3
名称:tf.truncated_normal_initializer
功能:将变量初始化为满足正太分布的随机值,但如果随机出来的值偏离平均值超过两个标准差,那么这个数将会被重新随机
主要参数:正太分布的均值和标准差
4
名称:tf.random_uniform_initializer
功能:将变量初始化为满足平均分布的随机值
主要参数:最大、最小值
5
名称:tf.uniform_unit_scaling_initializer
功能:将变量初始化为满足平均分布但不影响输出数量级的随机值
主要参数:factor(产生随机数时乘以的系数)
6
名称:tf.zeros_initializer
功能:将变量设置全为0
主要参数:变量维度
7
名称:tf.ones_initializer
功能:将变量设置全为1
主要参数:变量维度
两个函数最大区别在于指定变量的名称的参数,tf.Variable函数,变量name是一个可选的参数,通过name="v"的形式给出。但是对于tf.get_variable,变量名称是一个必选的参数。它会根据这个名字去创建或获取变量。在以上例程中,它会试图创建一个名字为v的变量,如果创建失败(比如已经存在),程序就会报错。这是变量名复用的结果。
如果需要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))
# 在命名空间已经存在变量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 (v1 == v) #输出为true
#在bar命名空间中没有创建变量v,所以下面代码将会报错
with tf.variable_scope("bar",reusue=True):
v = tf.get_variable("v",[1])
当tf.variabel_scope函数使用参数reuse=True生成上下文管理器时,这个上下文管理器内所有的tf.get_variable函数将会直接获取已经生成变量,如果不存在,将会报错。相反,如果reuse=False,将会创建新的变量,如果同名变量存在,将会报错。
三 tf.variable_scope函数
TensorFlow中的tf.variable_scope函数是可以嵌套的,当嵌套时,reuse参数的取值是如何确定的。
with tf.variable_scope("root"):
#可以通过tf.get_variable_scope().reuse函数来获取当前上下文管理器中的reuse参数
print tf.get_variable_scope().reuse #输出为False
with tf.variable_scope("foo",reuse=True): #新建一个嵌套的上下文管理器
print tf.get_variable_scope().reuse #输出true
with tf.variable_scope(“bar”): #不指定reuse
print tf.get_variable_scope().reuse #输出True
print tf.get_variable_scope().reuse #输出False 退出reuse设置为True的上下文
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
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("v",[1])
print v4.name #输出foo/v1:0
with tf.variable_scope("",reuse=True):
v5 = tf.get_variable("foo/bar/v",[1]) #可以直接通过命名空间的变量名来获取其他命名空间下的
#变量
print v5 == v3 #True
v6 = tf.get_variable("foo/v1",[1])
print v6 = v4 #True
四 参考
《TensorFlow:实战Google深度学习框架》