83、Tensorflow中的变量管理

'''
Created on Apr 21, 2017

@author: P0079482
'''
#如何通过tf.variable_scope函数来控制tf.ger_variable函数获取已经创建过的变量
#在名字为foo的命名空间内创建名字为v的变量
import tensorflow as tf
with tf.variable_scope("foo"):
    v = tf.get_variable("v",shape=[1],initializer=tf.constant_initializer(1.0))
#因为在命名空间foo中已经存在名为v的变量,所有下面的代码将会报错:
#Variable foo/v already exists,
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,代表v,v1代表的是相同的Tensorflow中的变量
#将参数reuse设置为True是,tf.variable_scope将只能获取已经创建过的变量。
#因为在命名空间bar中还没有创建变量v,所以下面的代码将会报错
with tf.variable_scope("bar",reuse=True):
    v = tf.get_variable("v",[1])
#如果tf.variable_scope函数使用reuse=None或者reuse=False创建上下文管理器
#tf.get_variable操作将创建新的变量。
#如果同名的变量已经存在,则tf.get_variable函数将报错
#Tensorflow中tf.variable_scope函数是可以嵌套的
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): #新建一个嵌套的上下文管理器并指定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
#tf.variable_scope函数生成的上下文管理器也会创建一个Tensorflow中的命名空间
#在命名空间内创建的变量名称都会带上这个命名空间作为前缀
#所以tf.variable_scope函数除了可以控制tf.get_variable执行的功能之外
#这个函数也提供了一个管理命名空间的方式
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)
    v6=tf.get_variable("foo/v1",[1])
    print(v6==v4)
#通过tf.variable_scope和tf.get_variable函数,以下代码对inference函数的前向传播结果做了一些改进
def inference(input_tensor,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_tensor,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)