tf.Variable、tf.get_variable、tf.variable_scope、tf.name_scope、random、initializer

转自:tensorflow学习笔记(二十三):variable与get_variable

   TF.VARIABLE、TF.GET_VARIABLE、TF.VARIABLE_SCOPE以及TF.NAME_SCOPE关系

tf.Variable与tf.get_variable()

tf.Variable(initial_value=None, trainable=True, collections=None, validate_shape=True, 
caching_device=None, name=None, variable_def=None, dtype=None, expected_shape=None, 
import_scope=None)
tf.get_variable(name, shape=None, dtype=None, initializer=None, regularizer=None, 
trainable=True, collections=None, caching_device=None, partitioner=None, validate_shape=True, 
custom_getter=None)

 

区别

使用tf.Variable时,如果检测到命名冲突,系统会自己处理。使用tf.get_variable()时,系统不会处理冲突,而会报错

import tensorflow as tf
w_1 = tf.Variable(3,name="w_1")
w_2 = tf.Variable(1,name="w_1")
print w_1.name
print w_2.name
#输出
#w_1:0
#w_1_1:0
import tensorflow as tf

w_1 = tf.get_variable(name="w_1",initializer=1)
w_2 = tf.get_variable(name="w_1",initializer=2)
#错误信息
#ValueError: Variable w_1 already exists, disallowed. Did
#you mean to set reuse=True in VarScope?

基于这两个函数的特性,当我们需要共享变量的时候,需要使用tf.get_variable()。在其他情况下,这两个的用法是一样的

 

get_variable()与Variable的实质区别

来看下面一段代码:

import tensorflow as tf

with tf.variable_scope("scope1"):
  w1 = tf.get_variable("w1", shape=[])
  w2 = tf.Variable(0.0, name="w2")
with tf.variable_scope("scope1", reuse=True):
  w1_p = tf.get_variable("w1", shape=[])
  w2_p = tf.Variable(1.0, name="w2")

print(w1 is w1_p, w2 is w2_p)
#输出
#True False


看到这,就可以明白官网上说的参数复用的真面目了。由于tf.Variable() 每次都在创建新对象,所有reuse=True 和它并没有什么关系。

对于get_variable(),来说,如果已经创建的变量对象,就把那个对象返回,如果没有创建变量对象的话,就创建一个新的。

 

random Tensor

可用于赋值给tf.Variable()的第一个参数

tf.random_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)

tf.truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)

tf.random_uniform(shape, minval=0, maxval=None, dtype=tf.float32, seed=None, name=None)

tf.random_shuffle(value, seed=None, name=None)

tf.random_crop(value, size, seed=None, name=None)

tf.multinomial(logits, num_samples, seed=None, name=None)

tf.random_gamma(shape, alpha, beta=None, dtype=tf.float32, seed=None, name=None)

tf.set_random_seed(seed)

 

constant value tensor

tf.zeros(shape, dtype=tf.float32, name=None)

tf.zeros_like(tensor, dtype=None, name=None)

tf.ones(shape, dtype=tf.float32, name=None)

tf.ones_like(tensor, dtype=None, name=None)

tf.fill(dims, value, name=None)

tf.constant(value, dtype=None, shape=None, name='Const')

 

initializer

tf.constant_initializer(value=0, dtype=tf.float32)
tf.random_normal_initializer(mean=0.0, stddev=1.0, seed=None, dtype=tf.float32)
tf.truncated_normal_initializer(mean=0.0, stddev=1.0, seed=None, dtype=tf.float32)
tf.random_uniform_initializer(minval=0, maxval=None, seed=None, dtype=tf.float32)
tf.uniform_unit_scaling_initializer(factor=1.0, seed=None, dtype=tf.float32)
tf.zeros_initializer(shape, dtype=tf.float32, partition_info=None)
tf.ones_initializer(dtype=tf.float32, partition_info=None)
tf.orthogonal_initializer(gain=1.0, dtype=tf.float32, seed=None)

 

tf.Variable与tf.get_variable

当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_varialbe和tf.Variable最大的区别在于:tf.Variable的变量名是一个可选项,通过name=’v’的形式给出。但是tf.get_variable必须指定变量名。

tf.get_variable与tf.variable_scope

上面已经提到过了:TensorFlow中通过变量名获取变量的机制主要是通过tf.get_variable和tf.variable_scope实现的。在这里,我主要解释下大家深恶痛绝的reuse问题。 
其实只要记住一件事情就ok了:当reuse为False或者None时(这也是默认值),同一个tf.variable_scope下面的变量名不能相同;当reuse为True时,tf.variable_scope只能获取已经创建过的变量。 
下面我们通过代码来看下:

#reuse=False时会报错的情况:
with tf.variable_scope('foo'):
    v = tf.get_variable('v',[1],initializer=tf.constant_initializer(1.0))
 
with tf.variable_scope('foo'):
    v1 = tf.get_variable('v',[1])

在这种情况下会报错:Variable foo/v already exists, disallowed.Did you mean to set reuse=True in Varscope? 
其原因就是在命名空间foo中创建了相同的变量。如果我要在foo下创建一个变量v1,其name=‘v’,只需要将reuse设置为Ture就ok了。将上面第二部分代码修改为:

with tf.variable_scope('foo', reuse=True):
    v1 = tf.get_variable('v',[1])
    print(v1.name)      #结果为foo/v

当reuse已经设置为True时,tf.variable_scope只能获取已经创建过的变量。这个时候,在命名空间bar中创建name=‘v’的变量v3,将会报错:Variable bar/v dose not exists, diallowed. Did you mean to set reuse=None in VarScope?

with tf.variable_scope('bar', reuse=True):
    v3 = tf.get_variable('v',[1])

简而言之,reuse=False时,tf.variable_scope创建变量;reuse=True时,tf.variable_scope获取变量

 

tf.variable_scope与tf.name_scope

除了tf.variable_scope,tf.name_scope函数也提供了命名空间管理的功能。这两个函数在大部分情况下是等价的,唯一的区别是在使用tf.get_variable函数时。 
tf.get_variable函数不受tf.name_scope的影响。 
我们从代码看下这句话的具体意思。 
首先是tf.variable_scope:

with tf.variable_scope('foo'):
    a = tf.get_variable('bar',[1])
    print(a.name)#结果为foo/bar:0

再看tf.name_scope:

with tf.name_scope('a'):
    a=tf.Variable([1])
    print(a.name)#结果为a/Variable:0
 
    b=tf.get_variable('b',[1])
    print(b.name)#结果为b:0

从这个结果中,我们能很清晰地看到,tf.get_variable创建的变量并不是a/b:0,而是b:0。这就表示了在tf.name_scope函数下,tf.get_variable不受其约束。

 

我的尝试

import tensorflow as tf

tf.reset_default_graph()

with tf.variable_scope('v_scope') as scope1:
    Weights1 = tf.get_variable('Weights', shape=[2,3])
#    bias1 = tf.get_variable('bias', shape=[3])


with tf.variable_scope('v_scope', reuse=True) as scope2:
    Weights2 = tf.get_variable('Weights')

print Weights1.name
print Weights2.name
v_scope/Weights:0
v_scope/Weights:0

通过测试也发现,如果把上述的Weights1和Weights2同时放入一个variable_scope(reuse=True)当中,既创建又获取会报错:

ValueError: Variable v_scope/Weights does not exist, or was not created with tf.get_variable(). Did you mean to set reuse=None in VarScope?

posted @ 2019-04-13 16:57  Johnny、  阅读(259)  评论(0编辑  收藏  举报