Неожиданный (случайный) порядок выполнения с использованием tf.control_dependencies (tensorflow v1)

Когда я запускаю следующий код (tf v1.12.0), я получаю либо 6.0 (x-›mul-›ident), 7.0 (x-›mul-›add-›ident, либо 9.0 (x-›add-›mul -›идент.).

Может кто-нибудь объяснить, почему порядок выполнения операций не контролируется tf.control_dependencies? Я бы подумал, что по крайней мере add_op будет выполнен до того, как что-либо в контексте управления будет рассмотрено.

tf.reset_default_graph()

x=tf.Variable(2.0)
add_op = tf.assign_add(x, 1)
mul_op = tf.assign(x, 3*x)

with tf.control_dependencies([add_op]):
    out_op = tf.identity(mul_op)

init_op = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init_op)
    print(sess.run([out_op]))

Спасибо!


person user5915898    schedule 29.06.2020    source источник


Ответы (1)


Это потому, что mul_op не зависит от add_op. Скорее out_op зависит как от mul_op (как явный ввод), так и от add_op как управляющей зависимости. В TensorFlow 1.x (и в TensorFlow 2.x внутри контекста tf.Graph) порядок операций в Python не влияет на порядок операций в среде выполнения TensorFlow .

Чтобы вызвать детерминированное поведение для приведенного выше примера, есть несколько вариантов.

  1. Создайте mul_op внутри контекста tf.control_dependencies, используя add_op:
add_op = tf.assign_add(x, 1)
with tf.control_dependencies([add_op]):
  mul_op = tf.assign(x, 3 * x)
  1. Пусть mul_op принимает результат сложения (add_op) в качестве входных данных.
add_op = tf.assign_add(x, 1)
mul_op = tf.assign(x, 3 * add_op)
  1. Удалите зависимость управления от операции идентификации и вызовите sess.run() для out_op и add_op явно.
x=tf.Variable(2.0)
add_op = tf.assign_add(x, 1)
mul_op = tf.assign(x, 3*x)
out_op = tf.identity(mul_op)
init_op = tf.global_variables_initializer()
with tf.Session() as sess:
    sess.run(init_op)
    sess.run(add_op)
    print(sess.run(out_op))

Они всегда возвращают 9.0.

Чтобы копнуть действительно глубже и посмотреть, каковы зависимости на графике, вы можете попробовать:

tf.get_default_graph().as_graph_def()

и посмотрите, каковы значения input для каждого узла на графике.

person Zachary Garrett    schedule 30.06.2020
comment
Спасибо за ответ! Чтобы уточнить, означает ли это, что между mul_op и add_op нет установленного порядка выполнения (помимо того, что они оба должны выполняться до out_op)? Я понимаю, как это объясняет выходы 7 и 9, но как насчет 6? В этом случае кажется, что out_op выполняется раньше, чем add_op. - person user5915898; 30.06.2020
comment
Обновлен ответ, чтобы указать еще несколько параметров, но да: порядок операций в исходном коде Python не влияет на порядок операций, выполняемых TensorFlow. Когда переменная x является входом для операции, она неявно вызывает x.read_value(). Возможно, переменная, прочитанная для mul_op (которая выполняется, потому что out_op зависит от нее _непосредственно), происходит до выполнения add_op (от которой out_op зависит через управление), что приводит к назначению 2.0 * 3. Это можно рассматривать как состояние гонки чтения-записи из-за отсутствия зависимостей. - person Zachary Garrett; 01.07.2020