В опубликованном вами фрагменте tf.control_dependencies
не оказывает никакого влияния. Функция создает контекст, в котором новые операции создаются с управляющей зависимостью от заданных операций, но в вашем коде нет новых операций в контексте, только оценка ранее существующих операций.
В большинстве случаев поток управления в TensorFlow является «очевидным» в том смысле, что существует только один способ правильно выполнить вычисления. Однако когда задействованы объекты с состоянием (то есть переменные), существуют ситуации, которые могут быть неоднозначными. Рассмотрим следующий пример:
import tensorflow as tf
v1 = tf.Variable(0)
v2 = tf.Variable(0)
upd1 = tf.assign(v1, v2 + 1)
upd2 = tf.assign(v2, v1 + 1)
init = tf.global_variables_initializer()
v1
и v2
- обе переменные, инициализированные до 0
, а затем обновленные. Однако каждый из них использует значение другой переменной в обновлении. В обычной программе на Python все должно выполняться последовательно, поэтому сначала запускается upd1
(поэтому v1
будет 1
) и upd2
после (поэтому v2
будет 2
, потому что v1
было 1
). Но TensorFlow не записывает порядок, в котором создаются операции, только их зависимости. Также может случиться так, что upd2
будет запущен до upd1
(так что v1
будет 2
и v2
будет 1
) или что оба значения обновления (v2 + 1
и v1 + 1
) будут вычислены до назначения (так что v1
и v2
будут 1
в конце). Действительно, если я запускаю его несколько раз:
for i in range(10):
with tf.Session() as sess:
sess.run(init)
sess.run([upd1, upd2])
print(*sess.run([v1, v2]))
Я не всегда получаю один и тот же результат (лично я получаю 1 1
и 2 1
, хотя технически 1 2
также возможно). Например, если вы хотите вычислить новое значение для v2
после обновления v1
, вы можете просто сделать следующее:
import tensorflow as tf
v1 = tf.Variable(0)
v2 = tf.Variable(0)
upd1 = tf.assign(v1, v2 + 1)
upd2 = tf.assign(v2, upd1 + 1)
init = tf.global_variables_initializer()
Здесь новое значение v2
вычисляется с использованием upd1
, которое гарантированно будет значением переменной после обновления. Так что здесь upd2
будет иметь неявную зависимость от назначения, и поэтому все будет работать так, как ожидалось.
Но что, если вы хотите всегда вычислять новые значения для v1
и v2
, используя неотменяемые значения переменных (то есть, в результате оба значения v1
и v2
будут 1
) ? В этом случае вы можете использовать tf.control_dependencies
:
import tensorflow as tf
v1 = tf.Variable(0)
v2 = tf.Variable(0)
new_v1 = v2 + 1
new_v2 = v1 + 1
with tf.control_dependencies([new_v1, new_v2]):
upd1 = tf.assign(v1, new_v1)
upd2 = tf.assign(v2, new_v2)
init = tf.global_variables_initializer()
Здесь операции присваивания не могут выполняться до тех пор, пока не будут вычислены новые значения для v1
и v2
, поэтому их окончательные значения всегда будут 1
в обоих случаях.