[tf]中的variable scope以及三种创建变量方式

变量的命名空间是为了更好的管理和重用变量,因为神经网络的节点和参数非常多,我们需要scope来清楚的知道变量是那一层的。

  • name_scope: 为了更好地管理变量的命名空间而提出的。比如在 tensorboard 中,因为引入了 name_scope, 我们的 Graph 看起来才井然有序
  • variable_scope:绝大部分情况下,根tf.get_variable()配合使用,实现变量共享的功能。

三种方式创建变量

tf.placeholdertf.Variabletf.get_variable
上面三种方式定义的变量具有相同的类型,而且只有 tf.get_variable() 创建的变量之间会发生命名冲突。在实际使用中,三种创建变量方式的用途也是分工非常明确的。

tf.placeholder

  • tf.placeholder(dtype, shape=None, name=None) 占位符。trainable==False,类似于函数的传递参数,在图运行前必须先传入值。
import tensorflow as tf
input1 = tf.placeholder(tf.float32)
input2 = tf.placeholder(tf.float32)
output = input1 * input2
with tf.Session() as sess:
    print sess.run(output, feed_dict = {input1:[3.], input2: [4.]})

tf.Variable

  • tf.Variable([1,2,3], initializer = init , name = 'va') ,先创建形状,在创建初始化,再创建name的方式。
  • tf.Variable(tf.truncated_normal([1,2,3], stddev =0.1)):直接创建初始化:应该是最为方便的方式。
  • tf.Variable(tf.constant(0.1 , shape =[1,2,3])):也是直接创建初始化的一种形式,只不过是直接使用常数进行初始化。
  • global_step = tf.Variable(0 , trainable = False):创建一个用于记录的不可训练的变量。
  • 下面这两个定义是等价的,常数初始化函数tf.constant_initializer和常数生成函数tf.constant在功能上是一致的。
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.get_variable中变量名称是一个必填的参数,这个函数会根据这个名字常见或获取变量,如果创建失败(有同名的参数),那么程序就会报错,这是为了避免无意识的变量复用造成的错误。

  • tf.get_variable('conv_1',initializer = tf.random_normal(shape=[1,2,3],minval=0.4,maxval=1.4))一般都是和 tf.variable_scope() 配合使用,从而实现变量共享的功能。
  • tf.name_scope() 并不会对tf.get_variable() 创建的变量有任何影响。 即在name_scope('hello')内部使用 get_variable() 中定义的 variable ,这个variable的 name 并没有 “hello/”前缀。
  • tf.name_scope() 主要是用来管理命名空间的,这样子让我们的整个模型更加有条理。而 tf.variable_scope() 的作用是为了实现变量共享,它和tf.get_variable()来完成变量共享的功能,tf.name_scope()可以和with tf.variable_scope():联合使用,用于给get_variable创建的变量加上联合命名空间
with tf.name_scope("name1"):
    with tf.variable_scope("var1"):
        w = tf.get_variable("w",shape=[2])
        res = tf.add(w,[3])
>>var1/w:0
name1/var1/Add:0
  • tf.trainable_variables()获取所有的可训练的变量,默认的是tf.variabletf.get_variable()创建的。
vs = tf.trainable_variables()
print 'There are %d train_able_variables in the Graph: ' % len(vs)
for v in vs:
with tf.name_scope('nsc1'):
    v1 = tf.Variable([1], name='v1')
    with tf.variable_scope('vsc1'):
        v2 = tf.Variable([1], name='v2')
        v3 = tf.get_variable(name='v3', shape=[])
print ('v1.name: ', v1.name)
print ('v2.name: ', v2.name)
print ('v3.name: ', v3.name)
>>v1.name:  nsc1/v1:0
v2.name:  nsc1/vsc1/v2:0
v3.name:  vsc1/v3:0

一个例子比较variable()和get_ variable()

  • variable可以看到 重复命名的,后面使用标号_1进行区分。
import tensorflow as tf
# 设置GPU按需增长
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
sess = tf.Session(config=config)
 
# 拿官方的例子改动一下
def my_image_filter():
    conv1_weights = tf.Variable(tf.random_normal([5, 5, 32, 32]),
        name="conv1_weights")
    conv1_biases = tf.Variable(tf.zeros([32]), name="conv1_biases")
    conv2_weights = tf.Variable(tf.random_normal([5, 5, 32, 32]),
        name="conv2_weights")
    conv2_biases = tf.Variable(tf.zeros([32]), name="conv2_biases")
    return None
 
# First call creates one set of 4 variables.
result1 = my_image_filter()
# Another set of 4 variables is created in the second call.
result2 = my_image_filter()
# 获取所有的可训练变量
vs = tf.trainable_variables()
print 'There are %d train_able_variables in the Graph: ' % len(vs)
for v in vs:
    print v
>>There are 8 train_able_variables in the Graph: 
Tensor("conv1_weights/read:0", shape=(5, 5, 32, 32), dtype=float32)
Tensor("conv1_biases/read:0", shape=(32,), dtype=float32)
Tensor("conv2_weights/read:0", shape=(5, 5, 32, 32), dtype=float32)
Tensor("conv2_biases/read:0", shape=(32,), dtype=float32)
Tensor("conv1_weights_1/read:0", shape=(5, 5, 32, 32), dtype=float32)
Tensor("conv1_biases_1/read:0", shape=(32,), dtype=float32)
Tensor("conv2_weights_1/read:0", shape=(5, 5, 32, 32), dtype=float32)
Tensor("conv2_biases_1/read:0", shape=(32,), dtype=float32)
  • tf.get_variable() 可以使用scope.reuse_variables()来重用变量,除了使用这个函数还可以在with tf.variable_scope("image_filters",reuse=True) as scope:中直接变量重用。
import tensorflow as tf
# 设置GPU按需增长
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
sess = tf.Session(config=config)
 
# 下面是定义一个卷积层的通用方式
def conv_relu(kernel_shape, bias_shape):
    # Create variable named "weights".
    weights = tf.get_variable("weights", kernel_shape, initializer=tf.random_normal_initializer())
    # Create variable named "biases".
    biases = tf.get_variable("biases", bias_shape, initializer=tf.constant_initializer(0.0))
    return None
def my_image_filter():
    # 按照下面的方式定义卷积层,非常直观,而且富有层次感
    with tf.variable_scope("conv1"):
        # Variables created here will be named "conv1/weights", "conv1/biases".
        relu1 = conv_relu([5, 5, 32, 32], [32])
    with tf.variable_scope("conv2"):
        # Variables created here will be named "conv2/weights", "conv2/biases".
        return conv_relu( [5, 5, 32, 32], [32])
with tf.variable_scope("image_filters") as scope:
    # 下面我们两次调用 my_image_filter 函数,但是由于引入了 变量共享机制
    # 可以看到我们只是创建了一遍网络结构。
    result1 = my_image_filter()
    scope.reuse_variables()
    result2 = my_image_filter()
# 看看下面,完美地实现了变量共享!!!
vs = tf.trainable_variables()
print 'There are %d train_able_variables in the Graph: ' % len(vs)
for v in vs:
    print v
>>There are 4 train_able_variables in the Graph: 
Tensor("image_filters/conv1/weights/read:0", shape=(5, 5, 32, 32), dtype=float32)
Tensor("image_filters/conv1/biases/read:0", shape=(32,), dtype=float32)
Tensor("image_filters/conv2/weights/read:0", shape=(5, 5, 32, 32), dtype=float32)
Tensor("image_filters/conv2/biases/read:0", shape=(32,), dtype=float32)

一个变量重用的例子

import tensorflow as tf
#在名字为foo的命名空间内创建名字为v的变量
with tf.variable_scope("foo"):
    #创建一个常量为1的v
    v= tf.get_variable('v',[1],initializer = tf.constant_initializer(1.0))
#因为在foo空间已经创建v的变量,所以下面的代码会报错
#with tf.variable_scope("foo"):
#   v= tf.get_variable('v',[1])
#在生成上下文管理器时,将参数reuse设置为True。这样tf.get_variable的函数将直接获取已声明的变量
#且调用with tf.variable_scope("foo")必须是定义的foo空间,而不能是with tf.variable_scope("")未命名或者其他空间。
with tf.variable_scope("foo",reuse =True):
    v1= tf.get_variable('v',[1])#  不写[1]也可以
    print(v1==v) #输出为True,代表v1与v是相同的变量

你可能感兴趣的:([tf]中的variable scope以及三种创建变量方式)