张量流中的名称范围和变量范围有什么区别?
What's the difference of name scope and a variable scope in tensorflow?
这些函数有什么区别?
tf.variable_op_scope(values, name, default_name, initializer=None)
Returns a context manager for defining an op that creates variables.
This context manager validates that the given values are from the same graph, ensures that that graph is the default graph, and pushes a name scope and a variable scope.
tf.op_scope(values, name, default_name=None)
Returns a context manager for use when defining a Python op.
This context manager validates that the given values are from the same graph, ensures that that graph is the default graph, and pushes a name scope.
tf.name_scope(name)
Wrapper for Graph.name_scope()
using the default graph.
See Graph.name_scope()
for more details.
tf.variable_scope(name_or_scope, reuse=None, initializer=None)
Returns a context for variable scope.
Variable scope allows to create new variables and to share already created ones while providing checks to not create or share by accident. For details, see the Variable Scope How To, here we present only a few basic examples.
您可以将它们视为两组:variable_op_scope
和 op_scope
将一组变量作为输入,旨在创建操作。区别在于它们如何影响变量的创建 tf.get_variable
:
def mysum(a,b,name=None):
with tf.op_scope([a,b],name,"mysum") as scope:
v = tf.get_variable("v", 1)
v2 = tf.Variable([0], name="v2")
assert v.name == "v:0", v.name
assert v2.name == "mysum/v2:0", v2.name
return tf.add(a,b)
def mysum2(a,b,name=None):
with tf.variable_op_scope([a,b],name,"mysum2") as scope:
v = tf.get_variable("v", 1)
v2 = tf.Variable([0], name="v2")
assert v.name == "mysum2/v:0", v.name
assert v2.name == "mysum2/v2:0", v2.name
return tf.add(a,b)
with tf.Graph().as_default():
op = mysum(tf.Variable(1), tf.Variable(2))
op2 = mysum2(tf.Variable(1), tf.Variable(2))
assert op.name == 'mysum/Add:0', op.name
assert op2.name == 'mysum2/Add:0', op2.name
注意两个例子中的变量名v
。
tf.name_scope
和 tf.variable_scope
相同:
with tf.Graph().as_default():
with tf.name_scope("name_scope") as scope:
v = tf.get_variable("v", [1])
op = tf.add(v, v)
v2 = tf.Variable([0], name="v2")
assert v.name == "v:0", v.name
assert op.name == "name_scope/Add:0", op.name
assert v2.name == "name_scope/v2:0", v2.name
with tf.Graph().as_default():
with tf.variable_scope("name_scope") as scope:
v = tf.get_variable("v", [1])
op = tf.add(v, v)
v2 = tf.Variable([0], name="v2")
assert v.name == "name_scope/v:0", v.name
assert op.name == "name_scope/Add:0", op.name
assert v2.name == "name_scope/v2:0", v2.name
您可以在 tutorial 中阅读有关变量范围的更多信息。
Stack Overflow 上有一个类似的问题 asked before。
命名空间是一种以分层方式组织变量和运算符名称的方法(例如"scopeA/scopeB/scopeC/op1")
tf.name_scope
在默认图中为运算符创建命名空间。
tf.variable_scope
在默认图中为变量和运算符创建命名空间。
tf.op_scope
与 tf.name_scope
相同,但用于创建指定变量的图表。
tf.variable_op_scope
与 tf.variable_scope
相同,但用于创建指定变量的图表。
指向上述来源的链接有助于消除此文档问题的歧义。
This example 显示所有类型的范围都为变量和运算符定义名称空间,但有以下区别:
- 由
tf.variable_op_scope
或 tf.variable_scope
定义的范围与 tf.get_variable
兼容(忽略其他两个范围)
tf.op_scope
和 tf.variable_op_scope
只是 select 指定变量列表中的一个图表,用于创建范围。除了他们的行为等于 tf.name_scope
和 tf.variable_scope
相应
tf.variable_scope
和 variable_op_scope
添加指定的或默认的初始值设定项。
让我们首先简要介绍一下变量共享。它是 TensorFlow
中的一种机制,允许共享在代码的不同部分访问的变量,而无需传递对变量的引用。
方法 tf.get_variable
can be used with the name of the variable as the argument to either create a new variable with such name or retrieve the one that was created before. This is different from using the tf.Variable
每次调用都会创建一个新变量的构造函数(如果已经存在具有此类名称的变量,则可能会向变量名称添加后缀)。
为了变量共享机制,引入了一种独立类型的作用域(variable scope)
因此,我们最终得到两种不同类型的作用域:
- 名称范围,使用
tf.name_scope
创建
- 可变范围,使用
tf.variable_scope
创建
这两个范围对所有操作以及使用 tf.Variable
创建的变量具有相同的效果,即范围将作为前缀添加到操作或变量名称中。
但是,名称范围被 tf.get_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.get_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
这使我们能够轻松地在程序的不同部分共享变量,即使在不同的名称范围内也是如此:
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
更新
从r0.11版本开始,op_scope
和variable_op_scope
都是deprecated并被name_scope
和variable_scope
取代。
至于APIr0.11,op_scope
和variable_op_scope
都是deprecated。
name_scope
和 variable_scope
可以嵌套:
with tf.name_scope('ns'):
with tf.variable_scope('vs'): #scope creation
v1 = tf.get_variable("v1",[1.0]) #v1.name = 'vs/v1:0'
v2 = tf.Variable([2.0],name = 'v2') #v2.name= 'ns/vs/v2:0'
v3 = v1 + v2 #v3.name = 'ns/vs/add:0'
来自tensorflow文档本页的最后一部分:Names of ops in tf.variable_scope()
[...] when we do with tf.variable_scope("name")
, this implicitly opens a tf.name_scope("name")
. For example:
with tf.variable_scope("foo"):
x = 1.0 + tf.get_variable("v", [1])
assert x.op.name == "foo/add"
Name scopes can be opened in addition to a variable scope, and then they will only affect the names of the ops, but not of variables.
with tf.variable_scope("foo"):
with tf.name_scope("bar"):
v = tf.get_variable("v", [1])
x = 1.0 + v
assert v.name == "foo/v:0"
assert x.op.name == "foo/bar/add"
When opening a variable scope using a captured object instead of a string, we do not alter the current name scope for ops.
两个 variable_op_scope and op_scope 现已弃用,根本不应使用。
关于其他两个,在我尝试通过创建一个简单的示例来可视化所有内容之前,我也无法理解 variable_scope and name_scope 之间的区别(它们看起来几乎相同):
import tensorflow as tf
def scoping(fn, scope1, scope2, vals):
with fn(scope1):
a = tf.Variable(vals[0], name='a')
b = tf.get_variable('b', initializer=vals[1])
c = tf.constant(vals[2], name='c')
with fn(scope2):
d = tf.add(a * b, c, name='res')
print '\n '.join([scope1, a.name, b.name, c.name, d.name]), '\n'
return d
d1 = scoping(tf.variable_scope, 'scope_vars', 'res', [1, 2, 3])
d2 = scoping(tf.name_scope, 'scope_name', 'res', [1, 2, 3])
with tf.Session() as sess:
writer = tf.summary.FileWriter('logs', sess.graph)
sess.run(tf.global_variables_initializer())
print sess.run([d1, d2])
writer.close()
我在这里创建了一个函数,它创建了一些变量和常量并将它们分组在范围内(取决于我提供的类型)。在这个函数中,我还打印了所有变量的名称。之后,我执行图形以获取结果值的值并保存事件文件以在 TensorBoard 中调查它们。如果你 运行 这个,你将得到以下内容:
scope_vars
scope_vars/a:0
scope_vars/b:0
scope_vars/c:0
scope_vars/res/res:0
scope_name
scope_name/a:0
b:0
scope_name/c:0
scope_name/res/res:0
如果您打开 TensorBoard,您会看到类似的图案(如您所见,b
在 scope_name
矩形之外):
这里给你答案:
现在你看到tf.variable_scope()
给所有变量(无论你如何创建它们)、ops、常量的名称添加前缀。另一方面,tf.name_scope()
会忽略使用 tf.get_variable()
创建的变量,因为它假定您知道要使用哪个变量以及在哪个范围内使用。
关于 Sharing variables 的一个很好的文档告诉你
tf.variable_scope()
: Manages namespaces for names passed to tf.get_variable()
.
同一文档提供了有关变量作用域如何工作以及何时有用的更多详细信息。
让我们简单点:只需使用 tf.variable_scope
。 Quoting a TF developer,:
Currently, we recommend everyone to use variable_scope
and not use name_scope
except for internal code and libraries.
除了 variable_scope
的功能基本上扩展了 name_scope
的功能之外,它们的共同表现可能会让您感到惊讶:
with tf.name_scope('foo'):
with tf.variable_scope('bar'):
x = tf.get_variable('x', shape=())
x2 = tf.square(x**2, name='x2')
print(x.name)
# bar/x:0
print(x2.name)
# foo/bar/x2:0
此行为有它的用处并证明了两个作用域的共存——但除非您知道自己在做什么,否则坚持使用 variable_scope
只会避免您因此而感到头疼。
Tensorflow 2.0 Compatible Answer: Andrzej Pronobis
和Salvador Dali
的解释很详细[=12相关的Functions =].
上面讨论的作用域函数中,截至目前(2020 年 2 月 17 日)处于活动状态的是 variable_scope
和 name_scope
.
为了社区的利益,为我们上面讨论的那些函数指定 2.0 兼容调用。
函数在1.x:
tf.variable_scope
tf.name_scope
2.x中的各自函数:
tf.compat.v1.variable_scope
tf.name_scope
(tf.compat.v2.name_scope
如果从 1.x to 2.x
迁移)
有关从 1.x 迁移到 2.x 的更多信息,请参阅此 Migration Guide。
这些函数有什么区别?
tf.variable_op_scope(values, name, default_name, initializer=None)
Returns a context manager for defining an op that creates variables. This context manager validates that the given values are from the same graph, ensures that that graph is the default graph, and pushes a name scope and a variable scope.
tf.op_scope(values, name, default_name=None)
Returns a context manager for use when defining a Python op. This context manager validates that the given values are from the same graph, ensures that that graph is the default graph, and pushes a name scope.
tf.name_scope(name)
Wrapper for
Graph.name_scope()
using the default graph. SeeGraph.name_scope()
for more details.
tf.variable_scope(name_or_scope, reuse=None, initializer=None)
Returns a context for variable scope. Variable scope allows to create new variables and to share already created ones while providing checks to not create or share by accident. For details, see the Variable Scope How To, here we present only a few basic examples.
您可以将它们视为两组:variable_op_scope
和 op_scope
将一组变量作为输入,旨在创建操作。区别在于它们如何影响变量的创建 tf.get_variable
:
def mysum(a,b,name=None):
with tf.op_scope([a,b],name,"mysum") as scope:
v = tf.get_variable("v", 1)
v2 = tf.Variable([0], name="v2")
assert v.name == "v:0", v.name
assert v2.name == "mysum/v2:0", v2.name
return tf.add(a,b)
def mysum2(a,b,name=None):
with tf.variable_op_scope([a,b],name,"mysum2") as scope:
v = tf.get_variable("v", 1)
v2 = tf.Variable([0], name="v2")
assert v.name == "mysum2/v:0", v.name
assert v2.name == "mysum2/v2:0", v2.name
return tf.add(a,b)
with tf.Graph().as_default():
op = mysum(tf.Variable(1), tf.Variable(2))
op2 = mysum2(tf.Variable(1), tf.Variable(2))
assert op.name == 'mysum/Add:0', op.name
assert op2.name == 'mysum2/Add:0', op2.name
注意两个例子中的变量名v
。
tf.name_scope
和 tf.variable_scope
相同:
with tf.Graph().as_default():
with tf.name_scope("name_scope") as scope:
v = tf.get_variable("v", [1])
op = tf.add(v, v)
v2 = tf.Variable([0], name="v2")
assert v.name == "v:0", v.name
assert op.name == "name_scope/Add:0", op.name
assert v2.name == "name_scope/v2:0", v2.name
with tf.Graph().as_default():
with tf.variable_scope("name_scope") as scope:
v = tf.get_variable("v", [1])
op = tf.add(v, v)
v2 = tf.Variable([0], name="v2")
assert v.name == "name_scope/v:0", v.name
assert op.name == "name_scope/Add:0", op.name
assert v2.name == "name_scope/v2:0", v2.name
您可以在 tutorial 中阅读有关变量范围的更多信息。 Stack Overflow 上有一个类似的问题 asked before。
命名空间是一种以分层方式组织变量和运算符名称的方法(例如"scopeA/scopeB/scopeC/op1")
tf.name_scope
在默认图中为运算符创建命名空间。tf.variable_scope
在默认图中为变量和运算符创建命名空间。tf.op_scope
与tf.name_scope
相同,但用于创建指定变量的图表。tf.variable_op_scope
与tf.variable_scope
相同,但用于创建指定变量的图表。
指向上述来源的链接有助于消除此文档问题的歧义。
This example 显示所有类型的范围都为变量和运算符定义名称空间,但有以下区别:
- 由
tf.variable_op_scope
或tf.variable_scope
定义的范围与tf.get_variable
兼容(忽略其他两个范围) tf.op_scope
和tf.variable_op_scope
只是 select 指定变量列表中的一个图表,用于创建范围。除了他们的行为等于tf.name_scope
和tf.variable_scope
相应tf.variable_scope
和variable_op_scope
添加指定的或默认的初始值设定项。
让我们首先简要介绍一下变量共享。它是 TensorFlow
中的一种机制,允许共享在代码的不同部分访问的变量,而无需传递对变量的引用。
方法 tf.get_variable
can be used with the name of the variable as the argument to either create a new variable with such name or retrieve the one that was created before. This is different from using the tf.Variable
每次调用都会创建一个新变量的构造函数(如果已经存在具有此类名称的变量,则可能会向变量名称添加后缀)。
为了变量共享机制,引入了一种独立类型的作用域(variable scope)
因此,我们最终得到两种不同类型的作用域:
- 名称范围,使用
tf.name_scope
创建
- 可变范围,使用
tf.variable_scope
创建
这两个范围对所有操作以及使用 tf.Variable
创建的变量具有相同的效果,即范围将作为前缀添加到操作或变量名称中。
但是,名称范围被 tf.get_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.get_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
这使我们能够轻松地在程序的不同部分共享变量,即使在不同的名称范围内也是如此:
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
更新
从r0.11版本开始,op_scope
和variable_op_scope
都是deprecated并被name_scope
和variable_scope
取代。
至于APIr0.11,op_scope
和variable_op_scope
都是deprecated。
name_scope
和 variable_scope
可以嵌套:
with tf.name_scope('ns'):
with tf.variable_scope('vs'): #scope creation
v1 = tf.get_variable("v1",[1.0]) #v1.name = 'vs/v1:0'
v2 = tf.Variable([2.0],name = 'v2') #v2.name= 'ns/vs/v2:0'
v3 = v1 + v2 #v3.name = 'ns/vs/add:0'
来自tensorflow文档本页的最后一部分:Names of ops in tf.variable_scope()
[...] when we do
with tf.variable_scope("name")
, this implicitly opens atf.name_scope("name")
. For example:
with tf.variable_scope("foo"):
x = 1.0 + tf.get_variable("v", [1])
assert x.op.name == "foo/add"
Name scopes can be opened in addition to a variable scope, and then they will only affect the names of the ops, but not of variables.
with tf.variable_scope("foo"):
with tf.name_scope("bar"):
v = tf.get_variable("v", [1])
x = 1.0 + v
assert v.name == "foo/v:0"
assert x.op.name == "foo/bar/add"
When opening a variable scope using a captured object instead of a string, we do not alter the current name scope for ops.
两个 variable_op_scope and op_scope 现已弃用,根本不应使用。
关于其他两个,在我尝试通过创建一个简单的示例来可视化所有内容之前,我也无法理解 variable_scope and name_scope 之间的区别(它们看起来几乎相同):
import tensorflow as tf
def scoping(fn, scope1, scope2, vals):
with fn(scope1):
a = tf.Variable(vals[0], name='a')
b = tf.get_variable('b', initializer=vals[1])
c = tf.constant(vals[2], name='c')
with fn(scope2):
d = tf.add(a * b, c, name='res')
print '\n '.join([scope1, a.name, b.name, c.name, d.name]), '\n'
return d
d1 = scoping(tf.variable_scope, 'scope_vars', 'res', [1, 2, 3])
d2 = scoping(tf.name_scope, 'scope_name', 'res', [1, 2, 3])
with tf.Session() as sess:
writer = tf.summary.FileWriter('logs', sess.graph)
sess.run(tf.global_variables_initializer())
print sess.run([d1, d2])
writer.close()
我在这里创建了一个函数,它创建了一些变量和常量并将它们分组在范围内(取决于我提供的类型)。在这个函数中,我还打印了所有变量的名称。之后,我执行图形以获取结果值的值并保存事件文件以在 TensorBoard 中调查它们。如果你 运行 这个,你将得到以下内容:
scope_vars
scope_vars/a:0
scope_vars/b:0
scope_vars/c:0
scope_vars/res/res:0
scope_name
scope_name/a:0
b:0
scope_name/c:0
scope_name/res/res:0
如果您打开 TensorBoard,您会看到类似的图案(如您所见,b
在 scope_name
矩形之外):
这里给你答案:
现在你看到tf.variable_scope()
给所有变量(无论你如何创建它们)、ops、常量的名称添加前缀。另一方面,tf.name_scope()
会忽略使用 tf.get_variable()
创建的变量,因为它假定您知道要使用哪个变量以及在哪个范围内使用。
关于 Sharing variables 的一个很好的文档告诉你
tf.variable_scope()
: Manages namespaces for names passed totf.get_variable()
.
同一文档提供了有关变量作用域如何工作以及何时有用的更多详细信息。
让我们简单点:只需使用 tf.variable_scope
。 Quoting a TF developer,:
Currently, we recommend everyone to use
variable_scope
and not usename_scope
except for internal code and libraries.
除了 variable_scope
的功能基本上扩展了 name_scope
的功能之外,它们的共同表现可能会让您感到惊讶:
with tf.name_scope('foo'):
with tf.variable_scope('bar'):
x = tf.get_variable('x', shape=())
x2 = tf.square(x**2, name='x2')
print(x.name)
# bar/x:0
print(x2.name)
# foo/bar/x2:0
此行为有它的用处并证明了两个作用域的共存——但除非您知道自己在做什么,否则坚持使用 variable_scope
只会避免您因此而感到头疼。
Tensorflow 2.0 Compatible Answer: Andrzej Pronobis
和Salvador Dali
的解释很详细[=12相关的Functions =].
上面讨论的作用域函数中,截至目前(2020 年 2 月 17 日)处于活动状态的是 variable_scope
和 name_scope
.
为了社区的利益,为我们上面讨论的那些函数指定 2.0 兼容调用。
函数在1.x:
tf.variable_scope
tf.name_scope
2.x中的各自函数:
tf.compat.v1.variable_scope
tf.name_scope
(tf.compat.v2.name_scope
如果从 1.x to 2.x
迁移)
有关从 1.x 迁移到 2.x 的更多信息,请参阅此 Migration Guide。