Какая разница между областью имен и областью переменных в 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)

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


Ответы:


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'

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

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


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, пожалуйста, обратитесь к этому Руководству по миграции .

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.