Понимание зависимостей управления Tensorflow - PullRequest
1 голос
/ 11 марта 2019

Я пытаюсь лучше понять TensorFlow. Я наткнулся на концепцию управления зависимостями. Я понимаю, что указанный нами порядок действий не имеет отношения к Tensorflow во время выполнения. Чтобы оптимизировать скорость выполнения, TensorFlow самостоятельно определяет порядок вычисления узлов. Но мы можем настроить порядок выполнения, используя tf.control_dependencies. Я не могу понять варианты использования функции. Кто-нибудь может направить меня на какой-то ресурс (кроме документации) или объяснить работу этой функции? Пример:

tf.reset_default_graph()
x = tf.Variable(5)
y=tf.Variable(3)
assign = tf.assign(x,x+y)
z = x+assign
with tf.Session() as sess:
   sess.run(tf.global_variables_initializer())
   with tf.control_dependencies([assign]):
        z_out = sess.run(z)

print(z_out)

Вывод кода равен 8. Итак, я заключаю, что, поскольку z = x + y, узел назначения не был оценен (верно?). Но не значит ли это, что результат тензорного потока может быть ошибочным? Это означает, что нам нужно создавать новые узлы во время каждой операции, чтобы заставить TensorFlow вычислять все узлы, приводящие к результату. Но, скажем, обучение нейронной сети с 10000 шагами, если каждый шаг создает новый набор из 1000 весов / параметров, не будет ли взрываться сложность пространства?

1 Ответ

2 голосов
/ 11 марта 2019

В опубликованном вами фрагменте 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 в обоих случаях.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...