【问题标题】:Understanding Tensorflow control dependencies了解 TensorFlow 控制依赖项
【发布时间】:2019-03-11 03:42:04
【问题描述】:

我正在努力加强对 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 个权重/参数,空间复杂度不会爆炸吗?

【问题讨论】:

  • tf.control_dependencies 在那个 sn-p 中没有做任何事情。当您创建控制依赖关系上下文时,它会影响在其中创建的新操作,但该块内没有新操作,只是对现有操作的评估。
  • 可以举个例子吗?

标签: python tensorflow machine-learning controls


【解决方案1】:

在您发布的 sn-p 中,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()

v1v2 都是初始化为0 然后更新的变量。但是,每个都在更新中使用另一个变量的值。在一个常规的 Python 程序中,事情会按顺序运行,所以 upd1 会先运行(所以v1 会是1)然后upd2 会运行(所以v2 会是2,因为v1 是@ 987654335@)。但是 TensorFlow 不记录操作的创建顺序,只记录它们的依赖关系。所以也可能发生upd2upd1之前运行(所以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]))

我并不总是得到相同的结果(我个人得到1 12 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 对赋值有一个隐式依赖,所以事情会按预期工作。

但是,如果您想始终使用未更新的变量值计算 v1v2 的新值(也就是说,始终以 v1v21) ?在这种情况下,您可以使用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()

在这里,只有在计算出 v1v2 的新值之后,才能进行赋值操作,因此在这两种情况下,它们的最终值将始终为 1

【讨论】:

  • 谢谢,我理解我的误解。但是,如果我们使用多个 sess.run 命令而不是单个 sess.run([list]) 来执行语句会怎样?每次更新都会创建一个像分配一样的张量吗?那么运行大量迭代不会造成内存浪费吗?
  • @pranav 控制依赖项(以及一般的依赖项)仅在对run 的同一调用中相关。对run 的不同调用不共享除了有状态对象(变量)之外的任何信息,也就是说,中间值从头开始重新计算,即使它们相同。运行更新节点(例如sess.run(upd1))不会在图中创建新的操作或张量,它只是运行计算并更改变量值。
  • 知道了。谢谢。
  • 对我来说,with tf.control_dependencies([new_v1, new_v2]): 似乎是为了确保首先计算 new_v1 和 new_v2,然后计算上下文中的内容:upd1 = tf.assign(v1, new_v1)upd2 = tf.assign(v2, new_v2)。我说的对吗?
猜你喜欢
  • 2018-05-12
  • 2018-01-23
  • 1970-01-01
  • 1970-01-01
  • 2021-03-06
  • 2013-06-05
  • 2012-08-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多