Какая разница в области имен и области переменных в тензорном потоке?

Каковы различия между этими функциями?

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)

Возвращает контекст для области переменных. Область переменной позволяет создавать новые переменные и делиться уже созданными, обеспечивая при этом проверки, чтобы не создавать или делиться случайно. Подробнее см. В разделе "Область видимости переменных", здесь мы приводим лишь несколько базовых примеров.

Ответ 1

Пусть начнется краткое введение в обмен переменных. Это механизм в TensorFlow который позволяет использовать переменные, доступные в разных частях кода, без передачи ссылок на переменную вокруг.

Метод tf.get_variable может использоваться с именем переменной в качестве аргумента либо для создания новой переменной с таким именем, либо для получения той, которая была создана ранее. Это отличается от использования конструктора tf.Variable который будет создавать новую переменную каждый раз, когда она вызывается (и потенциально добавляет суффикс к имени переменной, если переменная с таким именем уже существует).

Для механизма обмена переменными используется отдельный тип области (область переменных).

В результате мы получаем два разных типа областей:

  • область имени, созданная с помощью tf.name_scope
  • переменная область, созданная с помощью tf.variable_scope

Обе области действия имеют одинаковый эффект для всех операций, а также для переменных, созданных с использованием 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

Единственный способ размещения переменной, доступной с помощью 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 обе устарели и заменены на name_scope и variable_scope.

Ответ 2

И variable_op_scope, и op_scope теперь устарели и не должны использоваться вообще.

Что касается двух других, у меня также были проблемы с пониманием разницы между variable_scope и 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 находится вне прямоangularьника scope_name):


Это дает вам ответ:

Теперь вы видите, что tf.variable_scope() добавляет префикс к именам всех переменных (независимо от того, как вы их создаете), ops, констант. С другой стороны, tf.name_scope() игнорирует переменные, созданные с помощью tf.get_variable(), поскольку предполагает, что вы знаете, какую переменную и в какой области вы хотите использовать.

Хорошая документация по совместному использованию переменных говорит вам, что

tf.variable_scope(): управляет пространствами имен для имен, переданных в tf.get_variable().

Эта же документация содержит более подробную информацию о том, как работает Variable Scope и когда это полезно.

Ответ 3

Пространства имен - это способ организации имен переменных и операторов иерархическим образом (например, "scopeA/scopeB/scopeC/op1")

  • tf.name_scope создает пространство имен для операторов в графе по умолчанию.
  • tf.variable_scope создает пространство имен для переменных и операторов в графе по умолчанию.

  • tf.op_scope же, как tf.name_scope, но для графика, в котором были созданы указанные переменные.

  • tf.variable_op_scope же, как tf.variable_scope, но для графика, в котором были созданы указанные переменные.

Ссылки на источники, приведенные выше, помогают устранить эту проблему.

В этом примере показано, что все типы областей определяют пространства имен как для переменных, так и для операторов со следующими отличиями:

  1. области, определенные tf.variable_op_scope или tf.variable_scope, совместимы с tf.get_variable (он игнорирует две другие области)
  2. tf.op_scope и tf.variable_op_scope просто выберите граф из списка указанных переменных, чтобы создать область действия. Помимо их поведения, равного tf.name_scope и tf.variable_scope соответственно
  3. tf.variable_scope и variable_op_scope добавьте указанный или инициализатор по умолчанию.

Ответ 4

Что касается 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'

Ответ 5

Давайте сделаем это просто: просто используйте 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

Придерживаясь только variable_scope, вы избегаете некоторых головных болей из-за такого рода несовместимости.

Ответ 6

Вы можете рассматривать их как две группы: 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

Подробнее о области переменных вы можете узнать в учебнике. Аналогичный вопрос был перед перед переполнением стека.

Ответ 7

Из последнего раздела этой страницы документации tensorflow: Имена ops в tf.variable_scope()

[...], когда мы делаем with tf.variable_scope("name"), это неявно открывает a tf.name_scope("name"). Например:

with tf.variable_scope("foo"):
  x = 1.0 + tf.get_variable("v", [1])
assert x.op.name == "foo/add"

Области имен можно открыть в дополнение к области переменных, а затем они будут влиять только на имена операционных систем, но не на переменные.

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"

При открытии области переменной с использованием захваченного объекта вместо строки мы не изменяем текущую область имен для ops.