Tensorflow
为了更好的管理变量,提供了variable scope
机制,其官方解释如下:
Variable scope object to carry defaults to provide to get_variable
.
Many of the arguments we need for get_variable
in a variable store are most easily handled with a context. This object is used for the defaults. Attributes:
name
:name
of the current scope, used as prefix inget_variable
.initializer
: 传给get_variable
的默认initializer
。如果get_variable
的时候指定了initializer
,那么将覆盖这个默认的initializer
。regularizer
: 传给get_variable
的默认regulizer
。reuse
:Boolean
orNone
, setting the reuse inget_variable
.caching_device
:string
,callable
, orNone
: the caching device passed toget_variable
.partitioner
:callable
orNone
: the partitioner passed toget_variable
.custom_getter
: default custom getter passed toget_variable
.name_scope
: The name passed totf.name_scope
.dtype
: default type passed toget_variable
(defaults toDT_FLOAT
).
regularizer
参数的作用是给在本variable_scope
下创建的weights
加上正则项,这样我们就可以不同variable_scope
下的参数加不同的正则项了。可以看出,用variable scope
管理get_varibale
是很方便的。
确定get_variable的prefixed name
代码示例如下:
import tensorflow as tf
with tf.variable_scope("tet1"):
var3 = tf.get_variable("var3", shape=[2], dtype=tf.float32)
print(var3.name)
with tf.variable_scope("tet2"):
var4 = tf.get_variable("var4", shape=[2], dtype=tf.float32)
print(var4.name)
执行结果:
tet1/var3:0
tet2/var4:0
variable scope
是可以嵌套的:
import tensorflow as tf
with tf.variable_scope("tet1"):
var3 = tf.get_variable("var3", shape=[2], dtype=tf.float32)
print(var3.name)
with tf.variable_scope("tet2"):
var4 = tf.get_variable("var4", shape=[2], dtype=tf.float32)
print(var4.name)
执行结果:
tet1/var3:0
tet1/tet2/var4:0
get_varibale.name
以创建变量的scope
作为名字的prefix
:
import tensorflow as tf
def te2():
with tf.variable_scope("te2"):
var2 = tf.get_variable("var2", shape=[2], dtype=tf.float32)
print(var2.name)
def te1():
with tf.variable_scope("te1"):
var1 = tf.get_variable("var1", shape=[2], dtype=tf.float32)
return var1
return te1() # 在scope的te2内调用的
res = te2()
print(res.name)
执行结果:
te2/var2:0
te2/te1/var1:0
对比下面的代码:
import tensorflow as tf
def te2():
with tf.variable_scope("te2"):
var2 = tf.get_variable("var2", shape=[2], dtype=tf.float32)
print(var2.name)
def te1():
with tf.variable_scope("te1"):
var1 = tf.get_variable("var1", shape=[2], dtype=tf.float32)
return var1
return te1() # 在scope的te2外面调用的
res = te2()
print(res.name)
执行结果:
te2/var2:0
te1/var1:0
需要注意一点的是tf.variable_scope("name")
与tf.variable_scope(scope)
的区别,代码1
如下:
import tensorflow as tf
with tf.variable_scope("scope"):
var1 = tf.get_variable("w", shape=[1])
print(var1.name) # 执行结果“scope/w”
with tf.variable_scope("scope"):
var2 = tf.get_variable("w", shape=[1])
print(var2.name) # 执行结果“scope/scope/w”
代码2
如下:
import tensorflow as tf
with tf.variable_scope("scope"):
var1 = tf.get_variable("w", shape=[1])
print(var1.name) # 执行结果“scope/w”
scope = tf.get_variable_scope()
with tf.variable_scope(scope): # 这种方式设置的scope,是用的外部的scope
var2 = tf.get_variable("w", shape=[1]) # 这个变量的name也是“scope/w”,因此会报出错误
print(var2.name)
共享变量
共享变量的前提是变量的名字是一样的,变量的名字是由变量名和其scope
前缀一起构成,tf.get_variable_scope().reuse_variables()
允许共享当前scope
下的所有变量。
import tensorflow as tf
with tf.variable_scope("level1"):
var1 = tf.get_variable("w", shape=[1])
print(var1.name)
scope = tf.get_variable_scope()
with tf.variable_scope("level2"):
var2 = tf.get_variable("w", shape=[1])
print(var2.name)
with tf.variable_scope("level1", reuse=True):
var1 = tf.get_variable("w", shape=[1])
print(var1.name)
scope = tf.get_variable_scope()
with tf.variable_scope(scope):
var2 = tf.get_variable("w", shape=[1])
print(var2.name)
执行结果:
level1/w:0
level1/level2/w:0
level1/w:0
level1/w:0
在Tensorflow
中,有两个scope
,一个是name_scope
,另一个是variable_scope
,这两个scope
到底有什么区别呢?
先看第一个程序:
import tensorflow as tf
with tf.name_scope("hello") as name_scope:
arr1 = tf.get_variable("arr1", shape=[2, 10], dtype=tf.float32)
print(name_scope)
print(arr1.name)
print("scope_name:%s " % tf.get_variable_scope().original_name_scope)
执行结果:
hello/
arr1:0
scope_name:
可以看出,tf.name_scope
返回的是一个string
,在name_scope
中定义的variable
的name
并没有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)
print(variable_scope)
print(variable_scope.name) # 打印出变量空间名字
print(arr1.name)
# tf.get_variable_scope获取的就是variable_scope
print(tf.get_variable_scope().original_name_scope)
with tf.variable_scope("xixi") as v_scope2:
# tf.get_variable_scope获取的就是v_scope2
print(tf.get_variable_scope().original_name_scope)
执行结果:
<tensorflow.python.ops.variable_scope.VariableScope object at 0x00000000086649B0>
hello
hello/arr1:0
hello/
hello/xixi/
可以看出,tf.variable_scope
返回的是一个op
对象,variable_scope
中定义的variable
的name
加上了hello/
前缀;tf.get_variable_scope
的original_name_scope
是嵌套后的scope name
。
第三个程序如下:
import tensorflow as tf
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
加上前缀。
对比三个程序可以看出:
name_scope
对get_variable
创建的变量的名字不会有任何影响,而创建的op
会被加上前缀。tf.get_variable_scope
返回的只是variable_scope
,不管name_scope
,所以以后我们在使用tf.get_variable_scope().reuse_variables()
时可以无视name_scope
。
其它情况如下:
import tensorflow as tf
with tf.name_scope("scope1") as scope1:
with tf.name_scope("scope2") as scope2:
print(scope2) # 结果为“scope1/scope2/”
另外一个:
import tensorflow as tf
with tf.variable_scope("scope1") as scope1:
with tf.variable_scope("scope2") as scope2:
print(scope2.name) # 结果为“scope1/scope2”
name_scope可以用来干什么?
典型的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)
print(W.name)
print(b.name)
执行结果:
hidden/alpha:0
hidden/weights:0
hidden/biases:0
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
的时候,tf.name_scope
和tf.variable_scope
都会给Variable
和op
的name
属性加上前缀。 - 使用
tf.get_variable
的时候,tf.name_scope
就不会给tf.get_variable
创建出来的Variable
加前缀。