变量管理即是当神经网络参数在网络结构更加复杂的时候,参数更加多的时候,来用一个更好的方式来管理网络神经的参数,tensorflow提供他送过名称来创建或者获取一个变量名的机制,通过这个机制,在不同函数中可以直接通过变量的名字来使用变量,而不需要将变量通过参数的形式来传递。
在创建变量的时候采用的“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 函数最大的区别在于指定变量名称的参数。对于tf.Variable 函数, 变量名称是一个可选的参数,通过name= ~”的形式给出。但是对于tf.get_ variable 函数,变量名称是一个必填的参数。tf.get_variable 会根据这个名字去创建或者获取变量。在以上样例程序中, tf.get_variable 首先会试图去创建一个名字为v 的参数,如果创建失败(比如已经有同名的参数),那么这个程序就会报错。这是为了避免无意识的变量复用造成的错误。比如在定义神经网络参数时,第一层网络的权重已经叫weights 了,那么在创建第二层神经网络时,如果参数名仍然叫weights ,就会触发变量重用的错误。否则两层神经网络共用一个权重会出现一些比较难以发现的错误。如果需要通过tf.get_ variable 获取一个已经创建的变量,需要通过tf. variable_ scope 函数来生成一个上下文管理器,并明确指定在这个上下文管理器中, 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",reuse=True):
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
#命名空间为bar中没有创建变量v,则下列代码会报错:
with tf.variable_scope("bar",reuse=True):
v=tf.get_variable(
"v",[1]
)
tf.variable_scope函数嵌套时:
为指定reuse时,reuse为false,当有指定时,为指定值,镶嵌管理器的reuse值与外层保持一致。
with tf.get_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,
#此时该管理器的值与外层保持一致
print(tf.get_variable_scope().reuse)
#当退出reuse=true的层后,最外层的reuse仍然为false
print(tf.get_variable_scope().reuse)
用在mnist的数据集中:
def inference(input_tensor,reuse=False):
#定义第一层神经网络的前向传播过程
with tf.Variable_scope('layer1',reuse=reuse):
#根据传进来的reuse来判断是否创建变量还是使用已经
# 创建好的,
weights=tf.get_variable("weights",[INPUT_NODE,LAYER1NODE],
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):
#根据传进来的reuse来判断是否创建变量还是使用已经
# 创建好的,
weights=tf.get_variable("weights",[INPUT_NODE,LAYER1NODE],
initializer=tf.truncated_normal_initializer(stddev=0.1))
biases=tf.get_variable("biases",[LAYER1_NODE],
initializer=tf.constant_initializer(0.0))
layer2=tf.matmul(input_tensor,weights)+biases
#返回最后的传播结果
return layer2
x=tf.placeholder(tf.float32,[None,INPUT_NODE],name='x-input')
y=inference(x)
使用上述的代码可以不再需要将所有的变量都作为参数都传递到函数中去了,当神经网络更加复杂的时候,参数更多的时候,使用这种变量可以大大提高程序的可读性。