理解 Tensorflow 控制依赖
Understanding Tensorflow control dependencies
我正在努力更好地掌握 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,assign 节点还没有被评估(对吧?)。但是这不就意味着tensorflow的结果可能是错误的吗?这意味着我们需要在每次操作期间创建新节点,以强制 TensorFlow 计算导致结果的所有节点。但是如果训练一个有 10000 个步骤的神经网络,如果每个步骤创建一组新的 1000 weights/parameters space 复杂性不会爆炸吗?
在您发布的代码段中,tf.control_dependencies
没有任何效果。该函数创建一个上下文,其中 新操作 创建时具有对给定操作的控制依赖性,但在您的代码中,上下文中没有新操作,只是对先前存在的操作进行评估。
在大多数情况下,TensorFlow 中的控制流是 "obvious",因为只有一种方法可以正确进行计算。但是,当涉及有状态对象(即变量)时,有些情况可能会产生歧义。考虑以下示例:
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
运行s 在 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
也是可能的)。例如,如果您想在 v1
更新后计算 v2
的新值,您可以执行以下操作:
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
和 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
。
我正在努力更好地掌握 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,assign 节点还没有被评估(对吧?)。但是这不就意味着tensorflow的结果可能是错误的吗?这意味着我们需要在每次操作期间创建新节点,以强制 TensorFlow 计算导致结果的所有节点。但是如果训练一个有 10000 个步骤的神经网络,如果每个步骤创建一组新的 1000 weights/parameters space 复杂性不会爆炸吗?
在您发布的代码段中,tf.control_dependencies
没有任何效果。该函数创建一个上下文,其中 新操作 创建时具有对给定操作的控制依赖性,但在您的代码中,上下文中没有新操作,只是对先前存在的操作进行评估。
在大多数情况下,TensorFlow 中的控制流是 "obvious",因为只有一种方法可以正确进行计算。但是,当涉及有状态对象(即变量)时,有些情况可能会产生歧义。考虑以下示例:
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
运行s 在 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
也是可能的)。例如,如果您想在 v1
更新后计算 v2
的新值,您可以执行以下操作:
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
和 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
。