TensorFlow提供了通过变量名称来创建或获取一个变量的机制。通过这个机制,在不同函数中可以直接通过变量名字来使用变量,而不需要将变量通过参数的形式到处传递。
TensorFlow通过变量名来获取变量的机制主要通过tf.get_variable、tf.variable_scope函数实现的。
一、tf.get_variable
1. 通过tf.get_variable函数创建一个变量
通过tf.Variable函数创建一个变量,除了tf.Variable函数,TensorFlow还提供了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")
initializer函数和随机数及常量生成函数大部分是一一对应的。如tf.constant_initializer和常数生成函数tf.constant功能上是一致的。TensorFlow提供了7种不同的初始化函数。
tf.get_variable和tf.Variable函数的区别:
指定变量名称的参数。对于tf.Variable函数,变量名称是一个可选参数,通过name=”v”的形式给出。但是对tf.get_variable函数,变量名称是一个必填参数。tf.get_variable会根据这个名字去创建或获取变量。
在上述样例中,tf.get_variable首先会试图创建一个名字为v的参数,如果创建失败(同名),程序会报错,避免无意识的变量复用造成的错误。
2.通过tf.get_variable获取一个已经创建的变量
需要通过tf.variable_scope函数来生成一个上下文管理器,并明确指定在这个上下文管理器中,tf.get_varaible将直接获取已生成的变量。以下代码给出了如果获取一个已经生成的变量。
#在名字为foo的命名空间内创建名字为v的变量
with tf.variable_scope("foo"):
v=tf.get_varaible("v",[1],initializer=tf.constant_initializer(1.0))
#因为在命名空间foo中已经存在名字为v的变量,所以以下代码将会报错
#Variable foo/v already exists,disallowed.Did you mean to set reuse=True in VarScope?
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,代表v1和v是相同的TensorFlow中的变量
#将参数reuse设置为True时,tf.variable_scope将只能获取已创建过的变量。因为在命名空间bar中还没有创建变量v,所以
#以下代码会报错:
#Variable bar/v does not exits,disallowed.Did you mean to set reuse =None in VarScope?
with tf.variable_scope("bar",reuse=True):
v=tf.get_varaible("v",[1])
3.tf.variable_scope嵌套使用
以下代码说明了当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):
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的上下文后,reuse的值又回到
#了False
4.通过tf.variable_scope来管理变量的名称
tf.variable_scope函数生成的上下文管理器也会创建一个TensorFlow命名空间,在命名空间内创建的变量名称都会带上这个命名空间作为前缀。所以tf.variable_scope除了可以控制tf.get_variable执行的功能,还提供了管理变量命名空间的方式。以下代码显示了如何通过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])
#可以直接通过带命名空间名称的变量名来获取其他命名空间下的变量。
print(v5==v3) #True
v6=tf.get_variable("foo/v1",[1])
print(v6==v4) #True
当神经网络结构复杂、参数更多时,使用这种变量管理方式将大大提高程序可读性。