Різниця між змінною та get_variable в TensorFlow


125

Наскільки я знаю, Variableце операція за замовчуванням для створення змінної, і get_variableв основному використовується для обміну вагою.

З одного боку, деякі люди пропонують використовувати get_variableзамість примітивної Variableоперації всякий раз, коли вам потрібна змінна. З іншого боку, я просто бачу будь-яке використання get_variableв офіційних документах і демонстраціях TensorFlow.

Таким чином, я хочу знати кілька правил, як правильно використовувати ці два механізми. Чи є якісь "стандартні" принципи?


6
get_variable - це новий спосіб, Variable - це старий спосіб (який може підтримуватися назавжди), як каже Лукаш (PS: він написав велику частину імені змінної, яка визначається в TF)
Ярослав Булатов

Відповіді:


90

Я б рекомендував завжди використовувати tf.get_variable(...)- це полегшить рефакторинг коду, якщо вам потрібно в будь-який час ділитися змінними, наприклад, в налаштуваннях для декількох gpu (див. Приклад CIFAR Multi-gpu). Немає його недоліків.

Чисто tf.Variableнижчий рівень; в якийсь момент tf.get_variable()не існувало, тому якийсь код все ще використовує шлях низького рівня.


5
Дуже дякую за вашу відповідь. Але я до сих пір одне питання про те , як замінити tf.Variableз tf.get_variableвсюди. Ось тоді, коли я хочу ініціалізувати змінну з нумерованим масивом, я не можу знайти чистий та ефективний спосіб зробити це, як я роблю tf.Variable. Як ти це вирішуєш? Дякую.
Ліфу Хуанг

68

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. Чи є якісь умовності або фактори, які слід враховувати при виборі між ними. Дякую!
Ліфу Хуанг

Якщо ви хочете мати певне значення, використовувати 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()бажаний результат.
Бета

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я щойно натрапив на цей документ TensorFlow щодо операції з іменування тензорних графіків, що пояснює це: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.
Atlas7

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>}

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.