Różnica między Variable i get_variable w TensorFlow

125

O ile wiem, Variablejest to domyślna operacja tworzenia zmiennej i get_variablejest używana głównie do dzielenia wagi.

Z jednej strony są ludzie, którzy sugerują użycie get_variablezamiast prymitywnej Variableoperacji, gdy potrzebujesz zmiennej. Z drugiej strony widzę po prostu jakiekolwiek użycie get_variablew oficjalnych dokumentach i prezentacjach TensorFlow.

Dlatego chcę poznać kilka praktycznych zasad, jak prawidłowo używać tych dwóch mechanizmów. Czy są jakieś „standardowe” zasady?

Lifu Huang
źródło
6
get_variable to nowy sposób, Variable to stara droga (która może być obsługiwana na zawsze), jak mówi Łukasz (PS: napisał większość nazw zmiennych w TF)
Jarosław Bulatow

Odpowiedzi:

90

Zalecałbym zawsze używać tf.get_variable(...)- ułatwi to refaktoryzację kodu, jeśli chcesz udostępniać zmienne w dowolnym momencie, np. W ustawieniu multi-gpu (zobacz przykład CIFAR z wieloma gpu). Nie ma w tym żadnych wad.

Czysty tf.Variableto niższy poziom; w pewnym momencie tf.get_variable()nie istniał, więc część kodu nadal używa metody niskiego poziomu.

Łukasz Kaiser
źródło
5
Dziękuję bardzo za odpowiedź. Ale mam jeszcze jedno pytanie na temat wymiany tf.Variablez tf.get_variablewszędzie. To wtedy, gdy chcę zainicjować zmienną za pomocą tablicy numpy, nie mogę znaleźć czystego i wydajnego sposobu zrobienia tego, tak jak to robię tf.Variable. Jak to rozwiązujesz? Dzięki.
Lifu Huang
68

tf.Variable jest klasą i istnieje kilka sposobów tworzenia tf.Variable, w tym tf.Variable.__init__i tf.get_variable.

tf.Variable.__init__: Tworzy nową zmienną o wartości początkowej .

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

tf.get_variable: Pobiera istniejącą zmienną z tymi parametrami lub tworzy nową. Możesz także użyć inicjatora.

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

Bardzo przydatne jest używanie inicjatorów, takich jak xavier_initializer:

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

Więcej informacji tutaj .

Sung Kim
źródło
Tak, Variablewłaściwie mam na myśli używanie jego __init__. Ponieważ get_variablejest to tak wygodne, zastanawiam się, dlaczego większość kodu TensorFlow, którą widziałem, używa Variablezamiast get_variable. Czy są jakieś konwencje lub czynniki, które należy wziąć pod uwagę przy wyborze między nimi? Dziękuję Ci!
Lifu Huang
Jeśli chcesz mieć określoną wartość, użycie zmiennej jest proste: x = tf.Variable (3).
Sung Kim
@SungKim normalnie, kiedy używamy tf.Variable(), możemy zainicjować go jako losową wartość z obciętego rozkładu normalnego. Oto mój przykład w1 = tf.Variable(tf.truncated_normal([5, 50], stddev = 0.01), name = 'w1'). Jaki byłby to odpowiednik? jak mam to powiedzieć, że chcę obciętego normalnego? Powinienem po prostu zrobić w1 = tf.get_variable(name = 'w1', shape = [5,50], initializer = tf.truncated_normal, regularizer = tf.nn.l2_loss)?
Euler_Salter
@Euler_Salter: Możesz użyć, tf.truncated_normal_initializer()aby uzyskać pożądany wynik.
Beta
46

Mogę znaleźć dwie główne różnice między jednym a drugim:

  1. Po pierwsze, tf.Variablezawsze tworzy nową zmienną, podczas gdy tf.get_variablepobiera istniejącą zmienną z określonymi parametrami z wykresu, a jeśli nie istnieje, tworzy nową.

  2. tf.Variable wymaga określenia wartości początkowej.

Ważne jest, aby wyjaśnić, że funkcja tf.get_variablepoprzedza nazwę z bieżącym zakresem zmiennej w celu sprawdzenia ponownego wykorzystania. Na przykład:

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

Ostatni błąd asercji jest interesujący: dwie zmienne o tej samej nazwie w tym samym zakresie mają być tą samą zmienną. Ale jeśli przetestujesz nazwy zmiennych di ezdasz sobie sprawę, że Tensorflow zmienił nazwę zmiennej e:

d.name   #d.name == "two/v:0"
e.name   #e.name == "two/v_1:0"
Jadiel de Armas
źródło
Świetny przykład! Odnośnie d.namei e.name, właśnie natknąłem się na ten dokument TensorFlow na temat operacji nazewnictwa wykresów tensorowych, który to wyjaśnia: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

Inna różnica polega na tym, że jedna jest w ('variable_store',)kolekcji, a druga nie.

Zobacz kod źródłowy :

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

Zilustruję to:

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('')

Wyjście:

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

Lerner Zhang
źródło