在tensorflow中的函数总包含了神经网络中的所有参数。而当神经网络的结构更加复杂、参数更多时,就需要一个更好的方式传递和管理神经中的参数了。Tensorflow提供了通过变量名称来创建或获取一个变量的机制。通过这个机制,在不同的函数中可以直接变量的名字来使用变量,而不需要将变量通过参数的形式到处传递。
Tensorflow中通过变量名称获取变量的机制主要通过tf.get_varible和tf.variable_scope函数实现的。
tf.get_varible和tf.variable_scope函数
除了tf.varible函数可以创建一个变量,tf.get_varible函数也可以来创建或者获取变量。当tf.get_varible用于创建变量时,它和tf.varible的功能基本一致。
tf.get_varible和tf.varible函数的最大区别在于指定变量名称的参数:
对于tf.varible函数,变量名称是一个可选的参数,通过name=’v’的形式给出。但是对于tf.get_varible函数,变量名称是一个必填的参数。tf.get_varible会根据这个名字去创建或者获取变量。
eg:tf.get_varible首先会试图去创建一个带有名字参数的变量,但是如果已经有同名的参数,这时就会创建失败,程序报错。这是为了避免变量复用造成的错误机制。当需要tf.get_varible获取一个已经创建的变量时,需要通过tf.varible_scope函数来生成一个上下文管理器,并明确指定在这个上下文管理中,tf.get_varible函数将直接获取已经生成的变量。
注意:在上下文管理器中当使用参数reuse=True时,这个上下文管理器内所有的tf.get_varible函数会直接获取已经创建的变量(也只能获取已经创建的变量),如果变量不存在,则tf.get_varible函数将报错;相反,如果tf.variable_scope函数使用参数reuse=None或者reuse=False创建上下文管理器,tf.get_varible操作将创建新的变量。如果同名的变量已经存在,tf.get_varible函数将报错。而且tf.variable_scope还支持嵌套,下面是示例:
import tensorflow as tf
# 在名字为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])
with tf.variable_scope("foo", reuse=True):
# 因为在上下文管理器中使用了reuse=true,所以tf.get_variable将直接获取已经声明的变量
v1 = tf.get_variable("v", [1]) # 此时v和v1代表的是相同的变量
print ('result:',v == v1)
# 将result设为true时,tf.get_variable只能获取已经定义过的变量,这里的命名空间bar中还没有创建变量v,所以下面的报错
#with tf.variable_scope("bar", reuse=True):
# v = tf.get_variable("v", [1])
print('..............................')
with tf.variable_scope("root"):
# 输出上下文管理器中reuse的参数值:输出是false时,即最外层reuse是false
print ('-',tf.get_variable_scope().reuse)
# 新建一个嵌套的上下文管理器,并指定reuse为true
with tf.variable_scope("foo", reuse=True):
print ('--',tf.get_variable_scope().reuse)
# 新建一个嵌套的上下文管理器,不指定reuse,这时的reuse和外面的一层保持一致
with tf.variable_scope("bar"):
print ('---',tf.get_variable_scope().reuse)
# 和对齐的上下文管理器的reuse保持一致
print ('-',tf.get_variable_scope().reuse)
运行结果:
result: True
..............................
- False
-- True
--- True
- False
.................................
v:0
tf.variable_scope函数生成的上下文管理器会创建一个Tensorflow中的命名空间,在命名空间内创建的变量名称都会带上这个命名空间作为前缀。所以tf.variable_scope函数除了可以控制tf.get_varible执行的功能之外,这个函数也提供一个管理变量命名空间的方式(tf.get_varible函数中创建的变量,名称前面会加入命名空间的名称,并通过/来分隔命名空间的名称和变量的名称,也可以通过带命名空间的变量名来获取其他命名空间下的变量)。
示例:
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) # 输出带命名空间的名称
# 下面是命名空间,名称的嵌套
with tf.variable_scope("foo"):
with tf.variable_scope("bar"):
v3 = tf.get_variable("v", [1])
print (v3.name)
v4 = tf.get_variable("v1", [1])
print( v4.name)
# 通过带命名空间的变量名来来获取其他命名空间下的变量
with tf.variable_scope("",reuse=True):
v5 = tf.get_variable("foo/bar/v", [1])
print (v5 == v3)
v6 = tf.get_variable("v1", [1])
print (v6 == v4)
运行结果:
v:0
foo/v:0
foo/bar/v:0
v1:0
True
True
在复杂的神经网络中这种变量管理的方法将大大提高程序的可读性。