Разница между Variable и get_variable в TensorFlow

125

Насколько мне известно, Variableэто операция по умолчанию для создания переменной и get_variableв основном используется для распределения веса.

С одной стороны, некоторые люди предлагают использовать get_variableвместо примитивной Variableоперации всякий раз, когда вам нужна переменная. С другой стороны, я просто вижу любое использование get_variableTensorFlow в официальных документах и ​​демонстрациях.

Таким образом, я хочу знать несколько практических правил о том, как правильно использовать эти два механизма. Есть какие-то «стандартные» принципы?

Лифу Хуанг
источник
6
get_variable - это новый способ, Variable - старый способ (который может поддерживаться вечно), как говорит Лукаш (PS: он написал большую часть области видимости имени переменной в TF)
Ярослав Булатов

Ответы:

90

Я бы рекомендовал всегда использовать tf.get_variable(...)- это упростит рефакторинг вашего кода, если вам нужно поделиться переменными в любое время, например, в настройке с несколькими графическими процессорами (см. Пример CIFAR с несколькими графическими процессорами). В этом нет недостатков.

Чистый tf.Variable- низший уровень; в какой-то момент tf.get_variable()не существовало, поэтому некоторый код все еще использует низкоуровневый способ.

Лукаш Кайзер
источник
5
Большое спасибо за ваш ответ. Но у меня еще один вопрос, как заменить tf.Variableна tf.get_variableвезде. То есть, когда я хочу инициализировать переменную массивом numpy, я не могу найти чистый и эффективный способ сделать это, как я делаю с tf.Variable. Как решить эту проблему? Спасибо.
Лифу Хуанг
69

tf.Variable - это класс, и есть несколько способов создать tf.Variable, включая tf.Variable.__init__и tf.get_variable.

tf.Variable.__init__: Создает новую переменную с начальным_значением .

W = tf.Variable(<initial-value>, name=<optional-name>)

tf.get_variable: Получает существующую переменную с этими параметрами или создает новую. Вы также можете использовать инициализатор.

W = tf.get_variable(name, shape=None, dtype=tf.float32, initializer=None,
       regularizer=None, trainable=True, collections=None)

Очень полезно использовать такие инициализаторы, как xavier_initializer:

W = tf.get_variable("W", shape=[784, 256],
       initializer=tf.contrib.layers.xavier_initializer())

Больше информации здесь .

Сунг Ким
источник
Да, на Variableсамом деле я имею в виду его использование __init__. Поскольку get_variableэто так удобно, мне интересно, почему большая часть кода TensorFlow, которую я видел, использовала Variableвместо get_variable. Есть ли какие-либо условности или факторы, которые следует учитывать при выборе между ними. Спасибо!
Лифу Хуанг,
Если вы хотите иметь определенное значение, использовать переменную просто: x = tf.Variable (3).
Сунг Ким
@SungKim обычно, когда мы используем, tf.Variable()мы можем инициализировать его как случайное значение из усеченного нормального распределения. Вот мой пример w1 = tf.Variable(tf.truncated_normal([5, 50], stddev = 0.01), name = 'w1'). Что бы это было эквивалентно? как мне сказать, что я хочу усеченный нормальный? Я должен просто сделать w1 = tf.get_variable(name = 'w1', shape = [5,50], initializer = tf.truncated_normal, regularizer = tf.nn.l2_loss)?
Euler_Salter
@Euler_Salter: можно использовать tf.truncated_normal_initializer()для получения желаемого результата.
Beta
46

Я могу найти два основных различия между одним и другим:

  1. Во-первых, tf.Variableэто всегда будет создавать новую переменную, тогда как tf.get_variableполучает существующую переменную с указанными параметрами из графика, а если она не существует, создает новую.

  2. tf.Variable требует указания начального значения.

Важно уточнить, что функция tf.get_variableставит перед именем префикс текущей области видимости переменной для выполнения проверок повторного использования. Например:

with tf.variable_scope("one"):
    a = tf.get_variable("v", [1]) #a.name == "one/v:0"
with tf.variable_scope("one"):
    b = tf.get_variable("v", [1]) #ValueError: Variable one/v already exists
with tf.variable_scope("one", reuse = True):
    c = tf.get_variable("v", [1]) #c.name == "one/v:0"

with tf.variable_scope("two"):
    d = tf.get_variable("v", [1]) #d.name == "two/v:0"
    e = tf.Variable(1, name = "v", expected_shape = [1]) #e.name == "two/v_1:0"

assert(a is c)  #Assertion is true, they refer to the same object.
assert(a is d)  #AssertionError: they are different objects
assert(d is e)  #AssertionError: they are different objects

Интересна последняя ошибка утверждения: две переменные с одинаковыми именами в одной области видимости должны быть одной и той же переменной. Но если вы проверите имена переменных dи eпоймете, что Tensorflow изменил имя переменной e:

d.name   #d.name == "two/v:0"
e.name   #e.name == "two/v_1:0"
Джадиэль де Армас
источник
Отличный пример! Что касается d.nameи e.name, я только что наткнулся на этот документIf the default graph already contained an operation named "answer", the TensorFlow would append "_1", "_2", and so on to the name, in order to make it unique.
TensorFlow
2

Другое отличие состоит в том, что один находится в ('variable_store',)коллекции, а другой нет.

Пожалуйста, посмотрите исходный код :

def _get_default_variable_store():
  store = ops.get_collection(_VARSTORE_KEY)
  if store:
    return store[0]
  store = _VariableStore()
  ops.add_to_collection(_VARSTORE_KEY, store)
  return store

Позвольте мне проиллюстрировать это:

import tensorflow as tf
from tensorflow.python.framework import ops

embedding_1 = tf.Variable(tf.constant(1.0, shape=[30522, 1024]), name="word_embeddings_1", dtype=tf.float32) 
embedding_2 = tf.get_variable("word_embeddings_2", shape=[30522, 1024])

graph = tf.get_default_graph()
collections = graph.collections

for c in collections:
    stores = ops.get_collection(c)
    print('collection %s: ' % str(c))
    for k, store in enumerate(stores):
        try:
            print('\t%d: %s' % (k, str(store._vars)))
        except:
            print('\t%d: %s' % (k, str(store)))
    print('')

Выход:

collection ('__variable_store',): 0: {'word_embeddings_2': <tf.Variable 'word_embeddings_2:0' shape=(30522, 1024) dtype=float32_ref>}

Лернер Чжан
источник