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]) #可以直接通过带命名空间的变量名来获取其它命名空间下的变量。
#比如这里通过指定名称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函数,以下代码对5.2.1小节中定义的前向传播结果的函数做了一些改进。
def inference(input_sensor,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_sensor,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],initializer=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)
#在程序中需要使用训练好的神经网络进行推导时,可以直接调用inference(new_x,True).
#如果需要使用滑动平均模型可以参考5.2.1小节中使用的代码,把计算滑动平均的类传到inference函数中即可。
#获取或者创建变量的部分不需要改变。
#new_x=···
#new_y=inference(new_x,True)
使用上面这段代码所示的方式,就不再需要将所有变量都作为参数传递到不同的函数中了。当神经网络结构更加复杂、参数更多时,使用这种变量管理的方式将大大提高程序的可读性。