张量流中名称范围和变量范围的区别是什么?

Xiu*_*ang 259 tensorflow

这些功能之间有什么区别?

tf.variable_op_scope(values, name, default_name, initializer=None)

返回上下文管理器,用于定义创建变量的op.此上下文管理器验证给定值来自同一图形,确保该图形是默认图形,并推送名称范围和变量范围.


tf.op_scope(values, name, default_name=None)

返回定义Python操作时使用的上下文管理器.此上下文管理器验证给定值是否来自同一图,确保该图是默认图,并推送名称范围.


tf.name_scope(name)

Graph.name_scope()使用默认图表的包装器.有关Graph.name_scope()详细信息,请参阅


tf.variable_scope(name_or_scope, reuse=None, initializer=None)

返回变量范围的上下文.变量范围允许创建新变量并共享已创建的变量,同时提供检查以避免意外创建或共享.有关详细信息,请参阅变量范围操作方法,此处我们仅提供一些基本示例.

And*_*bis 361

让我们从变量共享的简短介绍开始.它是一种TensorFlow允许共享在代码的不同部分中访问的变量而不传递对变量的引用的机制.

该方法tf.get_variable可以与变量的名称一起用作参数,以创建具有此类名称的新变量或检索之前创建的变量.这与使用tf.Variable构造函数不同,构造函数每次调用时都会创建一个新变量(如果已存在具有此类名称的变量,则可能会为变量名称添加后缀).

出于可变共享机制的目的,引入了单独类型的范围(变量范围).

因此,我们最终有两种不同类型的范围:

两个作用域对所有操作以及使用创建的变量具有相同的效果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
Run Code Online (Sandbox Code Playgroud)

放置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
Run Code Online (Sandbox Code Playgroud)

这使我们可以轻松地在程序的不同部分共享变量,即使在不同的名称范围内:

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
Run Code Online (Sandbox Code Playgroud)

UPDATE

随着版本r0.11的,op_scope并且variable_op_scope弃用,取而代之name_scopevariable_scope.

  • 谢谢你的明确解释.当然,后续问题是"_为什么Tensorflow有这两种令人困惑的类似机制呢?为什么不用一个`scope`方法替换它们,这种方法有效地做了`variable_scope`?" (40认同)
  • 原因是,对于可变范围,可以为可重用变量定义单独的范围,这些变量不受用于定义操作的当前名称范围的影响. (22认同)
  • 我不认为我在概念上理解为什么甚至需要区分`variable_scope`和`name_scope`.如果一个人创建一个变量(以任何方式使用`tf.Variable`或`tf.get_variable`),对我而言,如果我们指定范围或其全名,我们应该始终能够获得它.我不明白为什么一个人忽略了范围名称而另一个没有.你了解这种奇怪行为的理性吗? (8认同)
  • 您好,您能解释为什么variable_scope中的变量名始终以:0结尾?这是否意味着可能有变量名称以:1,:2等结束,那么这怎么可能发生呢? (6认同)
  • @JamesFan每个“声明”都是一个操作,因此当您说a = tf.Variable(.. name)时,您将返回一个张量,但实际上也创建了一个操作。如果打印a,您将得到带有0的张量。如果打印a.op,您将获得将计算该张量值的运算。 (2认同)

Sal*_*ali 71

无论variable_op_scopeop_scope现在已过时,不应该使用的.

关于其他两个,在我尝试通过创建一个简单的例子来可视化所有内容之前,我也很难理解variable_scopename_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()
Run Code Online (Sandbox Code Playgroud)

在这里,我创建了一个函数,它创建了一些变量和常量,并在范围内对它们进行分组(取决于我提供的类型).在这个函数中,我还打印了所有变量的名称.之后,我执行图表以获取结果值的值并保存事件文件以在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 
Run Code Online (Sandbox Code Playgroud)

如果打开TensorBoard,您会看到类似的模式(如您所见b,在scope_name矩形之外): 在此输入图像描述


这给你答案:

现在你看到tf.variable_scope()为所有变量的名称添加前缀(无论你如何创建它们),ops,常量.另一方面tf.name_scope()忽略使用创建的变量,tf.get_variable()因为它假设您知道要使用哪个变量以及在哪个范围内.

关于共享变量的好文档告诉你

tf.variable_scope():管理传递给的名称的名称空间tf.get_variable().

相同的文档提供了有关变量范围如何工作以及何时有用的更多详细信息.

  • 通过示例和视觉效果的精彩回答,让我们得到这个答案的人气! (2认同)

Ale*_*ban 43

命名空间是一种以分层方式组织变量和运算符名称的方法(例如"scopeA/scopeB/scopeC/op1")

上述来源的链接有助于消除此文档问题的歧义.

此示例显示所有类型的作用域都为变量和运算符定义名称空间,但有以下区别:

  1. 范围定义tf.variable_op_scopetf.variable_scope兼容tf.get_variable(忽略其他两个范围)
  2. tf.op_scope并且tf.variable_op_scope只需选择指定的变量列表的图来创建一个范围.除了他们的行为等于tf.name_scopetf.variable_scope相应
  3. tf.variable_scopevariable_op_scope添加指定的或默认的初始化程序.


P-G*_*-Gn 11

让我们简单一点:只需使用tf.variable_scope.引用TF开发人员,:

目前,除内部代码和库外,我们建议大家使用variable_scope而不是使用name_scope.

除了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
Run Code Online (Sandbox Code Playgroud)

通过坚持variable_scope只有你避免由于这种不兼容性的一些头痛.


sgu*_*sgu 9

至于API r0.11,op_scope并且variable_op_scope都被弃用了. 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'
Run Code Online (Sandbox Code Playgroud)


fab*_*ioM 7

您可以将它们视为两组: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
Run Code Online (Sandbox Code Playgroud)

请注意v两个示例中变量的名称.

同样的tf.name_scopetf.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
Run Code Online (Sandbox Code Playgroud)

您可以在教程中阅读有关变量范围的更多信息.之前在Stack Overflow上提出了类似的问题.