tf.name_scope()和tf.variable_scope()是两个作用域,一般与两个创建/调用变量的函数tf.variable() 和tf.get_variable()搭配使用。它们搭配在一起的两个常见用途:1)变量共享
为什么要共享变量?举个简单的例子:例如,当我们研究生成对抗网络GAN的时候,判别器的任务是如果接收到的是生成器生成的图像,判别器就尝试优化自己的网络结构来使自己输出0,如果接收到的是来自真实数据的图像,那么就尝试优化自己的网络结构来使自己输出1。也就是说,生成图像和真实图像经过判别器的时候,要共享同一套变量,所以TensorFlow引入了变量共享机制。
“共享变量” 的应用场景:RNN应用例子
在tf.variable_scope的作用域下,通过get_variable()使用已经创建的变量,实现了变量的共享。在 train RNN 和 test RNN 的时候, RNN 的 time_steps 会有不同的取值, 这将会影响到整个 RNN 的结构, 所以导致在 test 的时候, 不能单纯地使用 train 时建立的那个 RNN. 但是 train RNN 和 test RNN 又必须是有同样的 weights biases 的参数. 所以, 这时, 就是使用 reuse variable 的好时机.
首先介绍两个创建variable的方法
tf.Variable(initial_value, name, dtype, trainable, collection)
tf.get_variable(name, shape, dtype, initializer, trainable, collection)
其中,tf.Variable每次调用都会创建一个新的变量,如果变量名字相同,就在后面加N:
first_a = tf.Variable(name='a', initial_value=1, dtype=tf.int32)
second_a = tf.Variable(name='a', initial_value=1, dtype=tf.int32)
sess = tf.Session()
sess.run(tf.global_variables_initializer())
print(first_a.name) # a_1:0
print(second_a.name) # a_2:0
而,tf.get_variable
的做法是,如果这个变量名字已经存在了,就拿这个变量,不再创建新的变量。
但是需要注意的是,一定要在scope中,使用reuse这个选项,如下是错误的
first_a = tf.get_variable(name='a', shape=(1), initializer=tf.zeros_initializer, dtype=tf.int32)
不使用reuse是不能get_variable相同名字的变量的;而使用resue又只能在variable_scope中:
with tf.variable_scope('var_scope') as scope:
v = tf.get_variable(name='v', shape=[1], initializer=tf.zeros_initializer)
with tf.variable_scope(scope, reuse=True):
v1 = tf.get_variable(name='v', shape=[1], initializer=tf.zeros_initializer)
sess = tf.Session()
sess.run(tf.global_variables_initializer())
assert v == v1
print(v.name) #var_scope/v:0
print(v1.name) #var_scope/v:0
tf.name_scope中
对tf.get_variable
不起作用,只对tf.Variable
起作用
with tf.name_scope("my_scope"):
v1 = tf.get_variable("var1", [1], dtype=tf.float32)
v2 = tf.Variable(1, name="var2", dtype=tf.float32)
a = tf.add(v1, v2)
print(v1.name) # var1:0
print(v2.name) # my_scope/var2:0
print(a.name) # my_scope/Add:0
tf.variable_scope中
对tf.get_variable
和tf.Variable
都起作用
with tf.variable_scope("my_scope"):
v1 = tf.get_variable("var1", [1], dtype=tf.float32)
v2 = tf.Variable(1, name="var2", dtype=tf.float32)
a = tf.add(v1, v2)
print(v1.name) # my_scope/var1:0
print(v2.name) # my_scope/var2:0
print(a.name) # my_scope/Add:0
这种机制允许在不用的name_scope中使用tf.get_variable
来share变量,但是需要注意的是,一定要声明reuse:
with tf.name_scope("foo"):
with tf.variable_scope("var_scope"):
v = tf.get_variable("var", [1])
with tf.name_scope("bar"):
with tf.variable_scope("var_scope", reuse=True):
v1 = tf.get_variable("var", [1])
assert v1 == v
print(v.name) # var_scope/var:0
print(v1.name) # var_scope/var:0****
II. TF中有两种作用域类型
命名域 (name scope),通过tf.name_scope 或 tf.op_scope创建;
变量域 (variable scope),通过tf.variable_scope 或 tf.variable_op_scope创建;
这两种作用域,对于使用tf.Variable()方式创建的变量,具有相同的效果,都会在变量名称前面,加上域名称。
对于通过tf.get_variable()方式创建的变量,只有variable scope名称会加到变量名称前面,而name scope不会作为前缀。例如 print(v1.name) # var1:0
例子:
with tf.name_scope("my_name_scope"):
v1 = tf.get_variable("var1", [1], dtype=tf.float32)
v2 = tf.Variable(1, name="var2", dtype=tf.float32)
a = tf.add(v1, v2)
print(v1.name) # var1:0
print(v2.name) # my_name_scope/var2:0
print(a.name) # my_name_scope/Add:0
小结:name_scope不会作为tf.get_variable变量的前缀,但是会作为tf.Variable的前缀。
例子:
with tf.variable_scope("my_variable_scope"):
v1 = tf.get_variable("var1", [1], dtype=tf.float32)
v2 = tf.Variable(1, name="var2", dtype=tf.float32)
a = tf.add(v1, v2)
print(v1.name) # my_variable_scope/var1:0
print(v2.name) # my_variable_scope/var2:0
print(a.name) # my_variable_scope/Add:0
小结:在variable_scope的作用域下,tf.get_variable()和tf.Variable()都加了scope_name前缀。因此,在tf.variable_scope的作用域下,通过get_variable()可以使用已经创建的变量,实现了变量的共享。
作者:刘小米92
链接:https://www.imooc.com/article/22966
来源:慕课网
本文原创发布于慕课网 ,转载请注明出处,谢谢合作
作者:kelseyh
链接:https://www.jianshu.com/p/ce44b403c468
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。