Name Scope vs Variable Scope in TensorFlow [TF中Name Scope和Variable Scope的区别]
在使用TensorFlow[1.x版本]搭建模型过程中,tf.variable_scope和tf.name_scope,tf.Variable和tf.get_variable是两组重要但是容易混淆的用法。其主要作用是解决部分模型中需要的变量共享。
variable_scope和name_scope都是作用域,目的就是说明变量的作用范围和区别具有相同变量名的变量。
tf.Variable和tf.get_variable都是创建变量,但是结合variable_scope和name_scope会产生不同的变量共享效果。
对于tf.get_variable来说,tf.name_scope对其无效,也就是说tf认为当你使用tf.get_variable时,你只归属于tf.variable_scope来管理共享与否。
对于使用tf.Variable来说,tf.name_scope和tf.variable_scope功能一样,都是给变量加前缀,相当于分类管理,模块化。
tf.get_variable和tf.variable_scope配合可以实现变量共享
下面的例子,
import tensorflow as tf
with tf.name_scope('name_scope_1'):
var1 = tf.get_variable(name='var1',dtype=tf.int8)
var2 = tf.Variable(name='var2', dtype=tf.float32)
var3 = tf.Variable(name='var2', dtype=tf.float32)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name, sess.run(var1))
print(var2.name, sess.run(var2))
print(var3.name, sess.run(var3))
# 输出结果:
# var1:0 [-0.30036557] 可以看到前面不含有指定的'name_scope_x',证明name_scope对get_variable不起作用
# name_scope_1/var2:0 [ 2.]
# name_scope_1/var2_1:0 [ 2.] 可以看到变量名自行变成了'var2_1',避免了和'var2'冲突,而且有了前置scope
############################################
with tf.variable_scope('variable_scope_2') as scope:
var1 = tf.get_variable(name='var1', dtype=tf.int8)
scope.reuse_variables() # 设置共享变量
var1_reuse = tf.get_variable(name='var1')
var2 = tf.Variable(initial_value=[2], name='var2', dtype=tf.int8)
var2_reuse = tf.Variable(initial_value=[2], name='var2', dtype=tf.int8)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name, sess.run(var1))
print(var1_reuse.name, sess.run(var1_reuse))
print(var2.name, sess.run(var2))
print(var2_reuse.name, sess.run(var2_reuse))
# 输出结果:
# variable_scope_2/var1:0 [1]
# variable_scope_2/var1:0 [1] 变量var1_reuse重复使用了var1
# variable_scope_2/var2:0 [ 2.]
# variable_scope_2/var2_1:0 [ 2.] 变量var2_1是虽然初始设置了var2为变量名,但是自动变成了var2_1作为区分。
下面的例子进一步说明了他们的用法。
#下面两个例子效果相同
#Example 1
with tf.name_scope('name_scope_1') as scp1:
with tf.variable_scope('var_scope_2') as scp2:
a = tf.Variable('a')
b = tf.get_variable('b')
#Example 2
with tf.name_scope('name_scope_1') as scp1:
with tf.name_scope('var_scope_2') as scp2:
a = tf.Variable('a')
with tf.variable_scope('var_scope_2') as scp2:
b = tf.get_variable('b')
同时,共享变量本质上有两个要求,第一该变量存在,第二该变量设置为可共享
比如下面两个例子都会报错
#Example 1
with tf.variable_scope('scp1', reuse=True) as scp:
a = tf.get_varialbe('a') #报错,因为虽然设置了reuse=True,但是该变量不存在。
#Example 2
with tf.variable_scope('scp2', reuse=False) as scp:
a = tf.get_varialbe('a')
a = tf.get_varialbe('a') #报错,因为设置了reuse=False,使用get_variable无法获得相同名字的变量
设置reuse=tf.AUTO_REUSE
可以同时达到两个要求,如果变量不存在就创建并设置为可共享。
总结
-
一般情况下,
tf.variable_scope
和tf.get_variable
和搭配使用,达到变量共享的效果。 -
tf.Variable
可以单独使用,也可以搭配tf.name_scope
使用,给变量分类命名,模块化。 -
tf.get_variable
和tf.name_scope
搭配使用,无任何效果。 -
tf.Variable
和tf.variable_scope
搭配使用虽然也可以达到前缀命名效果,但是不建议如此使用,应该使用tf.name_scope
。