在tensorflow中,有两个scope, 一个是name_scope一个是variable_scope,这两个scope到底有什么区别呢?
- * name_scope: * 为了更好地管理变量的命名空间而提出的。比如在 tensorboard 中,因为引入了 name_scope, 我们的 Graph 看起来才井然有序。
- * variable_scope: * 大大大部分情况下,跟 tf.get_variable() 配合使用,实现变量共享的功能。
三个例子
先看第一个程序:
with tf.name_scope("hello") as name_scope:
arr1 = tf.get_variable("arr1", shape=[2,10],dtype=tf.float32)
arr2 = tf.Variable(1, name="arr2", dtype=tf.float32)
print(name_scope) #hello/
print(arr1.name) #arr1:0
print(arr2.name) #hello/arr2:0
print("scope_name:%s " % tf.get_variable_scope().original_name_scope) #空
#输出
hello/
arr1:0
hello/arr2:0
scope_name:
可以看出:
- tf.name_scope() 返回的是 一个string,”hello/”
- 在name_scope使用
get_variable()
中定义的 variable 的 name 并没有前缀 - 在name_scope使用
variable()
定义的variable的名字是有 “hello/”前缀的 - tf.get_variable_scope().original_name_scope 是空
第二个程序:
import tensorflow as tf
with tf.variable_scope("hello") as variable_scope:
arr1 = tf.get_variable("arr1", shape=[2, 10], dtype=tf.float32)
arr2 = tf.Variable(1, name="arr2", dtype=tf.float32)
print(variable_scope)#<tensorflow.python.ops.variable_scope.VariableScope object at 0x7fbc09959210>
print(variable_scope.name) #打印出变量空间名字 #hello
print(arr1.name) #hello/arr1:0
print(arr2.name) #hello/arr2:0
print(tf.get_variable_scope().original_name_scope) #hello/
#tf.get_variable_scope() 获取的就是variable_scope
with tf.variable_scope("xixi") as v_scope2:
print(tf.get_variable_scope().original_name_scope) #hello/xixi/
#输出
<tensorflow.python.ops.variable_scope.VariableScope object at 0x0000020B2AAF9390>
hello
hello/arr1:0
hello/arr2:0
hello/
hello/xixi/
可以看出:
- tf.variable_scope() 返回的是一个
VariableScope
对象 - variable_scope使用
get_variable
定义的variable 的name加上了”hello/”前缀 - tf.get_variable_scope().original_name_scope 是 嵌套后的scope name
第三个程序:
with tf.name_scope("name1"):
with tf.variable_scope("var1"):
w = tf.get_variable("w",shape=[2])
res = tf.add(w,[3])
print(w.name)
print(res.name)
# 输出
var1/w:0
name1/var1/Add:0
可以看出:
variable_scope
和name_scope
都会给op
的name
加上前缀- 这实际上是因为创建
variable_scope
时内部会创建一个同名的name_scope
对比三个个程序可以看出:
name_scope
返回的是 string, 而variable_scope
返回的是对象. 这也可以感觉到,variable_scope
能干的事情比name_scope
要多.- name_scope对 get_variable()创建的变量 的名字不会有任何影响,而创建的
op
会被加上前缀. - tf.get_variable_scope() 返回的只是 variable_scope,不管 name_scope. 所以以后我们在使用tf.get_variable_scope().reuse_variables() 时可以无视name_scope
其他:
with tf.name_scope("scope1") as scope1:
with tf.name_scope("scope2") as scope2:
print(scope2)
#输出:
scope1/scope2/ 最后有斜杠
with tf.variable_scope("scope1") as scope1:
with tf.variable_scope("scope2") as scope2:
print(scope2)
print(scope2.name)
#输出:
<tensorflow.python.ops.variable_scope.VariableScope object at 0x00000194F95C81D0>
scope1/scope2
tf.name_scope()可以用来干什么
对
tf.get_variable
不起作用,只对tf.Variable
起作用
典型的 TensorFlow 可以有数以千计的节点,如此多而难以一下全部看到,甚至无法使用标准图表工具来展示。为简单起见,我们为op/tensor
名划定范围,并且可视化把该信息用于在图表中的节点上定义一个层级。默认情况下, 只有顶层节点会显示。下面这个例子使用tf.name_scope在hidden命名域下定义了三个操作:
import tensorflow as tf
with tf.name_scope('hidden') as scope:
a = tf.constant(5, name='alpha')
W = tf.Variable(tf.random_uniform([1, 2], -1.0, 1.0), name='weights')
b = tf.Variable(tf.zeros([1]), name='biases')
print(a.name) #hidden/alpha
print(W.name) #hidden/weights
print(b.name) #hidden/biases
#输出
hidden/alpha
hidden/weights
hidden/biases
name_scope 是给op_name加前缀, variable_scope是给get_variable()创建的变量的名字加前缀。
tf.variable_scope有时也会处理命名冲突
import tensorflow as tf
def test(name=None):
with tf.variable_scope(name, default_name="scope") as scope:
w = tf.get_variable("w", shape=[2, 10])
test()
test()
ws = tf.trainable_variables()
for w in ws:
print(w.name)
#scope/w:0
#scope_1/w:0
#可以看出,如果只是使用default_name这个属性来创建variable_scope的时候,会处理命名冲突
其它
- tf.name_scope(None) 有清除name scope的作用
import tensorflow as tf
with tf.name_scope("hehe"):
w1 = tf.Variable(1.0)
with tf.name_scope(None):
w2 = tf.Variable(2.0)
print(w1.name)
print(w2.name)
#hehe/Variable:0
#Variable:0
tf.variable_scope()可以用来干什么
对
tf.get_variable
和tf.Variable
都起作用
variable_scope 用来管理 variable 详见variable_scope
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
注意这里,在不同的name_scope中的相同variable_scope中,可以定义同一个变量
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
输出:
var_scope/var:0
var_scope/var:0
一个变量共享的真实代码示例:
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)
总结
简单来看
1. 使用tf.Variable()
的时候,tf.name_scope()
和tf.variable_scope()
都会给 Variable
和 op
的 name
属性加上前缀。
2. 使用tf.get_variable()
的时候,tf.name_scope()
就不会给 tf.get_variable()
创建出来的Variable
加前缀。但是 tf.Variable()
创建出来的就会受到 name_scope
的影响.