Какая разница между областью имен и областью переменных в tenorflow?

276

В чем различия между этими функциями?

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

Возвращает менеджер контекста для определения операции, которая создает переменные. Этот диспетчер контекста проверяет, что заданные значения принадлежат одному и тому же графу, гарантирует, что этот граф является графом по умолчанию, и выдвигает область имен и область переменных.


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

Возвращает менеджер контекста для использования при определении Python op. Этот диспетчер контекста проверяет, что заданные значения принадлежат одному и тому же графу, гарантирует, что этот граф является графом по умолчанию, и расширяет область имен.


tf.name_scope(name)

Оболочка для Graph.name_scope()использования графика по умолчанию. Смотрите Graph.name_scope()для более подробной информации.


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

Возвращает контекст для области видимости переменной. Область действия переменных позволяет создавать новые переменные и обмениваться уже созданными, предоставляя проверки, чтобы не создавать или делиться случайно. Для получения дополнительной информации см. Область действия переменной. Здесь мы представляем только несколько основных примеров.

Сюй Ян
источник
Возможный дубликат В чем разница между variable_scope и name_scope?
nbro

Ответы:

377

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

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

Именно с целью механизма совместного использования переменных был введен отдельный тип области действия (область действия переменной).

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

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

Анджей Пронобис
источник
41
Спасибо за четкое объяснение. Естественно, последующим вопросом будет: « Почему в Tensorflow есть оба этих схожих до смешения механизма? Почему бы не заменить их только одним scopeметодом, который эффективно работает variable_scope
Джон
8
Я не думаю, что концептуально понимаю, почему различие между variable_scopeи name_scopeдаже необходимо. Если кто-то создает переменную (каким-либо образом с помощью tf.Variableили tf.get_variable), мне кажется более естественным, что мы всегда сможем получить ее, если укажем область действия или ее полное имя. Я не понимаю, почему один игнорирует предметное имя, а другой нет. Ты понимаешь рациональное для этого странного поведения?
Чарли Паркер
23
Причина в том, что с переменной областью можно определить отдельные области для переменных многократного использования, на которые не влияет текущая область имени, используемая для определения операций.
Анджей Пронобис
6
Здравствуйте, вы можете объяснить, почему имя переменной в variable_scope всегда заканчивается на: 0? Означает ли это, что имена переменных могут оканчиваться на: 1,: 2 и т. Д., Как это может произойти?
Джеймс Фан
2
@JamesFan Каждое «объявление» - это операция, поэтому, когда вы говорите a = tf.Variable (.. name), вы возвращаете тензор, но на самом деле он тоже создает операцию. если вы напечатаете, вы получите тензор с: 0. Если вы напечатаете a.op, вы получите операцию, которая вычислит это тензорное значение.
Роберт Лугг
84

И 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за пределами scope_nameпрямоугольника):


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

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

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

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

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

Сальвадор Дали
источник
2
Невероятный ответ с примером и наглядными материалами, давайте ответим на этот вопрос людям!
Дэвид Паркс
43

Пространства имен - это способ организации имен для переменных и операторов в иерархическом порядке (например, "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добавьте указанный или инициализатор по умолчанию.
Александр Горбан
источник
Для графа, в котором были созданы указанные переменные? Означает ли это, что, как в примере выше, fabrizioM с tf.variable_op_scope ([a, b], name, "mysum2") в качестве области действия, здесь параметры a и b не затрагиваются этой функцией, а переменные, определенные в этой области действия, затрагиваются?
Сюй Ян
Ответ на оба вопроса - да: график, на котором были созданы указанные переменные, но они не изменены.
Александр Горбан
Означает ли это, что tf.name_scope и tf.variable_scope будут использоваться только в графе по умолчанию, но когда вы явно определяете и создаете граф с помощью tf.Graph (), две другие функции tf.op_scope и tf.variable_op_scope не могут использоваться в этот график!
Сюй Ян
12

Давайте сделаем это просто: просто используйте 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только вы избегаете некоторых головных болей из-за такого рода несовместимости.

Р-Оп
источник
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'
SGU
источник
8

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

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

fabrizioM
источник
2

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

[...] когда мы это делаем with tf.variable_scope("name"), это неявно открывает 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"

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

Гильермо Гонсалес де Гарибай
источник
2

Tensorflow 2.0 Compatible Ответ : объяснения Andrzej Pronobisи Salvador Daliочень подробные сведения о функциях, связанных с Scope.

Из рассмотренных выше функций Scope, которые активны на данный момент (17 февраля 2020 г.), являются 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, пожалуйста, обратитесь к этому Руководству по миграции .

Поддержка Tensorflow
источник