了解 Tensorflow 控制依赖

pra*_*nav 8 python controls machine-learning tensorflow

我正在尝试更深入地掌握 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)
Run Code Online (Sandbox Code Playgroud)

代码的输出是 8。所以我推断,因为 z=x+y,分配节点没有被评估(对吧?)。但这不是说tensorflow的结果可能是错误的吗?这意味着我们需要在每次操作期间创建新节点,以强制 TensorFlow 计算导致结果的所有节点。但是在说训练一个 10000 步的神经网络时,如果每一步创建一组新的 1000 个权重/参数,空间复杂度会不会爆炸?

jde*_*esa 15

在您发布的代码段中,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()
Run Code Online (Sandbox Code Playgroud)

v1v2都是初始化0然后更新的变量。但是,每个都在更新中使用另一个变量的值。在常规的 Python 程序中,事情会按顺序运行,所以upd1会先运行(所以v1会是1)和upd2之后(v2会是2,因为v11)。但是 TensorFlow 不记录操作的创建顺序,只记录它们的依赖关系。因此,也可能发生upd2在之前运行upd1(因此v1将是2v2将是1)或两个更新值(v2 + 1v1 + 1)在分配之前计算(因此两者v1v2将是)1到底)。事实上,如果我多次运行它:

for i in range(10):
    with tf.Session() as sess:
        sess.run(init)
        sess.run([upd1, upd2])
        print(*sess.run([v1, v2]))
Run Code Online (Sandbox Code Playgroud)

我并不总是得到相同的结果(我个人得到1 12 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()
Run Code Online (Sandbox Code Playgroud)

这里v2使用 计算新值upd1,保证是更新后变量的值。所以这里upd2对赋值有一个隐含的依赖,所以事情会按预期工作。

但是,如果您想始终计算v1v2使用未更新的变量值的新值(即,始终以 bothv1v2being结束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()
Run Code Online (Sandbox Code Playgroud)

在这里,在计算v1和的新值之前无法进行赋值操作v2,因此1在这两种情况下它们的最终值始终是。