Graph 修正tensorflow运行中的竞争条件

Graph 修正tensorflow运行中的竞争条件,graph,tensorflow,race-condition,ambiguous,Graph,Tensorflow,Race Condition,Ambiguous,我想在GPU上维护一个变量,并对该变量执行一些操作。下面的代码片段是一个简单的例子 import numpy as np import tensorflow as tf with tf.Graph().as_default(): i = tf.placeholder(tf.int32, [4], name='i') y = tf.placeholder(tf.float32, [4], name='y') _x = tf.get_variable('x', [4]

我想在GPU上维护一个变量,并对该变量执行一些操作。下面的代码片段是一个简单的例子

import numpy as np
import tensorflow as tf

with tf.Graph().as_default():

    i = tf.placeholder(tf.int32, [4], name='i') 
    y = tf.placeholder(tf.float32, [4], name='y') 
    _x = tf.get_variable('x', [4], initializer=tf.random_normal_initializer())
    x = _x + tf.reduce_sum(tf.mul(_x,y))
    assign_op = tf.assign(_x, x).op
    permute_op = tf.assign(_x, tf.gather(_x, i))

    ii = np.array([1,2,3,0])
    yy = np.random.randn(4)

    s = tf.Session()
    s.run(tf.initialize_all_variables())
    xxx0 = s.run(_x)
    s.run([permute_op, assign_op], feed_dict={i: ii, y: yy})
    xxx1 = s.run(_x)
    print('assigned then permuted', np.allclose((xxx0+np.dot(xxx0,yy))[ii], xxx1))
    print('permuted then assigned', np.allclose((xxx0[ii]+np.dot(xxx0[ii], yy)), xxx1))
问题是这个程序在赋值运算和置换运算的顺序方面是不明确的。因此,最后两个print语句中的一个或另一个将为真,但哪个语句在程序的多次运行中随机变化。我可以将其分为两个步骤,第一个运行permute_op,第二个运行assign_op,但这似乎效率较低


有没有一种有效的方法来打破竞争条件并使结果可预测?

对两个赋值进行排序的最简单方法是使用第一个赋值的结果作为第二个赋值的变量输入。这会在分配之间创建数据依赖关系,从而使它们具有确定性顺序。例如:

assigned = tf.assign(_x, x)
permuted = tf.assign(assigned, tf.gather(assigned, i))

sess.run(permuted.op)  # Runs both assignments.
请注意,我将排列和赋值操作的顺序与您在问题中所说的相反,因为先进行排列,然后进行更新仍然存在竞争。即使这不是您想要的语义,原则也应该很清楚

另一种方法是将
与tf.control_dependencies(ops)一起使用:
块,其中
ops
是必须在
块中的操作之前运行的操作列表(例如分配)。使用起来有点麻烦,因为在读取变量的更新值时必须小心。(就像C中的非易失性变量一样,读取可以被缓存。)强制读取的典型习惯用法是使用
tf.identity(var.ref())
,因此示例如下所示:

assign_op = tf.assign(_x, x).op

with tf.control_dependencies([assign_op]):
    # Read updated value of `_x` after `assign_op`.
    new_perm = tf.gather(tf.identity(_x.ref()), i) 
    permute_op = tf.assign(_x, new_perm).op

sess.run(permute_op)  # Runs both assignments.