2016-12-22 65 views
7

Myślałem, że przypisania zmiennych są wykonywane po wszystkich operacjach na liście podanej do sesji sess.run, ale poniższy kod zwraca różne wyniki przy różnym wykonaniu. Wydaje się, że losowo uruchamia operacje na liście i przypisuje zmienną po uruchomieniu operacji na liście.Tensorflow: Kiedy są wykonywane przypisania zmiennych w sess.run z listą?

a = tf.Variable(0) 
b = tf.Variable(1) 
c = tf.Variable(1) 
update_a = tf.assign(a, b + c) 
update_b = tf.assign(b, c + a) 
update_c = tf.assign(c, a + b) 

with tf.Session() as sess: 
    sess.run(initialize_all_variables) 
    for i in range(5): 
    a_, b_, c_ = sess.run([update_a, update_b, update_c]) 

Chciałbym poznać terminy przypisań zmiennych. Które są poprawne: "update_x -> assign x -> ... -> udpate_z -> assign z" lub "update_x -> udpate_y -> udpate_z -> assign a, b, c"? (gdzie (x, y, z) jest permutacją (a, b, c)) Dodatkowo, jeśli istnieje sposób, który realizuje to ostatnie przydział (przydział jest wykonywany po wykonaniu wszystkich operacji na liście), proszę daj mi znać, jak to zrealizować.

Odpowiedz

9

Trzy operacje update_a, update_b i update_c nie mają współzależności w przepływu danych wykresu, tak TensorFlow może zdecydować się wykonać je w dowolnej kolejności. (W obecnej implementacji możliwe jest, że wszystkie trzy z nich będą wykonywane równolegle na różnych wątkach.) Drugą nitką jest to, że odczyty zmiennych są domyślnie buforowane, więc w twoim programie wartość jest przypisana w update_b (tj. c + a) może użyć oryginalnej lub zaktualizowanej wartości a, w zależności od tego, kiedy zmienna zostanie po raz pierwszy odczytana.

Jeśli chcesz się upewnić, że operacje przebiegają w określonej kolejności, możesz użyć bloków with tf.control_dependencies([...]):, aby wymusić wykonanie operacji w bloku po operacjach wymienionych na liście. Możesz użyć bloku tf.Variable.read_value() wewnątrz bloku with tf.control_dependencies([...]):, aby wyznaczyć punkt, w którym zmienna jest odczytana jawnie.

Dlatego, jeśli chcesz, aby upewnić się, że update_a dzieje przed update_b i update_b dzieje przed update_c, można zrobić:

update_a = tf.assign(a, b + c) 

with tf.control_dependencies([update_a]): 
    update_b = tf.assign(b, c + a.read_value()) 

with tf.control_dependencies([update_b]): 
    update_c = tf.assign(c, a.read_value() + b.read_value()) 
+0

Dziękujemy za odpowiedź @mrry. Doceniłem to i zrozumiałem, jak określić kolejność operacji w moim kodzie. Następnie mam jeszcze jedno pytanie dotyczące twojej odpowiedzi. Jeśli operacje na liście mają pewne współzależności, czy ich wartości są przypisane po wykonaniu wszystkich operacji? A w takim przypadku, jaka jest kolejność wykonywania operacji domyślnie (bez użycia 'tf.control_dependencies'). – Sarah

+0

Co rozumiesz przez "operacje na liście"? Ogólnie rzecz biorąc, opcje ops mogą być uruchamiane, gdy tylko ich nowa wartość jest dostępna. Operacje o zmiennej treści mogą być uruchamiane natychmiast po rozpoczęciu kroku. Jednak bez wyraźnych zależności kontrolnych (lub danych), przypisanie do zmiennej może nastąpić przed lub po odczytaniu tej samej zmiennej, w zależności od tego, w jaki sposób są planowane operacje. Domyślna kolejność jest w tym przypadku niezdefiniowana. – mrry

+0

Przepraszamy za niejednoznaczny przypadek. Mam na myśli listę operacji, takich jak '[op1, op2, op3]'. Mogę mieć nieporozumienia. Pseudo kod: 'v = tf.Variable (0), c = tf.constant (3), add = tf.add (v, c), update = tf.assign (v, add), mul = tf.mul (add, update), sess.run ([mul, mul]) 'daje' [9, 9] 'not' [9, 36] '. Więc myślałem, że zadanie jest wykonywane po wszystkich operacjach na liście '[mul, mul]', tak jak mul -> mul -> assign, not mul -> assign -> mul -> assign. – Sarah

1

Na podstawie tego przykładu twoje,

v = tf.Variable(0) 
c = tf.constant(3) 
add = tf.add(v, c) 
update = tf.assign(v, add) 
mul = tf.mul(add, update) 

with tf.Session() as sess: 
    sess.run(tf.initialize_all_variables()) 
    res = sess.run([mul, mul]) 
    print(res) 

Wyjście: [9, 9]

Otrzymujesz [9, 9] i jest to w rzeczywistości to, o co go poprosiliśmy. Pomyśl o tym tak:

Podczas biegu, po pobraniu mul z listy, szuka definicji tego i znajduje tf.mul(add, update). Teraz potrzebuje wartości add, która prowadzi do tf.add(v, c). Tak, to korki w wartości v i c, pobiera wartość add jako 3.

Ok, teraz musimy wartość update który jest zdefiniowany jako tf.assign(v, add). Mamy wartości zarówno add (które zostały obliczone teraz jako 3) & v. Tak więc aktualizuje wartość v na wartość 3, która jest również wartością dla update.

Teraz ma wartości dla add i update które są 3. W ten sposób mnożenie daje 9 w mul.

Na podstawie wyniku, który otrzymamy, myślę, że dla następnego elementu (operacji) na liście, po prostu zwraca właśnie obliczoną wartość mul. Nie jestem pewien, czy robi to ponownie, czy po prostu zwraca tę samą (buforowaną?) Wartość, którą właśnie obliczył dla mul, zdając sobie sprawę, że mamy wynik lub te operacje zdarzają się równolegle (dla każdego elementu na liście). Może @mrry lub @YaroslavBulatov mogą komentować tę część, proszę?


Cytowanie @ komentarzu mrry za:

Po wywołaniu sess.run([x, y, z]) raz TensorFlow wykonuje każdego PO, że te tensory zależą jeden raz tylko (o ile istnieje tf.while_loop() na wykresie). Jeśli tensor pojawi się dwa razy na liście (np. mul w twoim przykładzie), TensorFlow wykona go raz i zwróci dwie kopie wyniku. Aby wykonać zadanie więcej niż raz, musisz wielokrotnie wywołać sess.run() lub użyć tf.while_loop(), aby umieścić pętlę na wykresie.