tensorflow中有两个关于variable的op,tf.Variable()与tf.get_variable()下面介绍这两个的用法与区别:
tf.Variable()
W = tf.Variable(<initial-value>, name=<optional-name>)
用于生成一个初始值为initial-value的变量。必须指定初始化值
tf.get_variable()
W = tf.get_variable(name, shape=None, dtype=tf.float32, initializer=None,
regularizer=None, trainable=True, collections=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?
- 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(),来说,如果已经创建的变量对象,就把那个对象返回,如果没有创建变量对象的话,就创建一个新的。
细说 tf.variable_scope()函数的用法
如果已经存在的变量没有设置为共享变量,TensorFlow 运行到第二个拥有相同名字的变量的时候,就会报错。为了解决这个问题,TensorFlow 提出了 tf.variable_scope 函数:它的主要作用是,在一个作用域 scope 内共享一些变量,举个简单的栗子:
with tf.variable_scope("foo"):
v = tf.get_variable("v", [1]) #v.name == "foo/v:0"
简单来说就是给变量名前再加了个变量空间名。
- 接下来看看怎么用tf.get_variable()实现共享变量:
with tf.variable_scope("one"):
a = tf.get_variable("v", [1]) #a.name == "one/v:0"
with tf.variable_scope("one"):
b = tf.get_variable("v", [1]) #创建两个名字一样的变量会报错 ValueError: Variable one/v already exists
with tf.variable_scope("one", reuse = True): #注意reuse的作用。
c = tf.get_variable("v", [1]) #c.name == "one/v:0" 成功共享,因为设置了reuse
assert a==c #Assertion is true, they refer to the same object.
然后看看如果用tf.Variable() 会有什么效果:
with tf.variable_scope("two"):
d = tf.get_variable("v", [1]) #d.name == "two/v:0"
e = tf.Variable(1, name = "v", expected_shape = [1]) #e.name == "two/v_1:0"
assert d==e #AssertionError: they are different objects
可以看到,同样的命名空间(‘two’)和名字(v),但是d和e的值却不一样。
t推荐使用 tf.get_variable():
推荐使用tf.get_variable(), 因为:
- 初始化更方便
比如用xavier_initializer:
W = tf.get_variable("W", shape=[784, 256],
initializer=tf.contrib.layers.xavier_initializer())
- 方便共享变量
因为tf.get_variable() 会检查当前命名空间下是否存在同样name的变量,可以方便共享变量。而tf.Variable 每次都会新建一个变量。
需要注意的是tf.get_variable() 要配合reuse和tf.variable_scope() 使用。
既然说到了tf.variable_name
,那再来简单说一下tf.name_scope
。关于二者的区别会单独写一篇博客介绍。简而言之,name_scope
主要是给variable_name
加前缀,也可以给op_name
加前缀;name_scope
是给op_name
加前缀。
上边的例子中已经讲到了给变量加前缀,那对于op_name
呢,在tf.variable_scope
作用域下的操作,也会被加上前缀:
with tf.variable_scope("foo"):
x = 1.0 + tf.get_variable("v", [1])
assert x.op.name == "foo/add"
值得一提的是,variable_scope主要用在循环神经网络中(RNN)的操作中,其中需要大量的共享变量。
接下来,看看tf.name_scope
的示例:
在TensorFlow中常常会有数以千记的节点,在可视化的过程中很难一下子展示出来,因此需要用name_scope
划分,在可视化中,这表示在计算图中的一个层级。name_scope
会影响到op_name
,但不会影响用tf.get_variable()
创建的变量,而会影响通过tf.Variable()
创建的变量,因此: