tf.assign to variable slice 在 tf.while_loop 中不起作用



下面的代码有什么问题? 如果tf.assign操作发生在循环之外,则应用于tf.Variable的一部分时工作正常。 但是,在这种情况下,它给出了以下错误。

import tensorflow as tf
v = [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
n = len(v)
a = tf.Variable(v, name = 'a')
def cond(i, a):
return i < n 
def body(i, a):
tf.assign(a[i], a[i-1] + a[i-2])
return i + 1, a
i, b = tf.while_loop(cond, body, [2, a]) 

结果在:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/hrbigelow/anaconda3/lib/python3.6/site-packages/tensorflow/python/ops/control_flow_ops.py", line 3210, in while_loop
result = loop_context.BuildLoop(cond, body, loop_vars, shape_invariants)
File "/home/hrbigelow/anaconda3/lib/python3.6/site-packages/tensorflow/python/ops/control_flow_ops.py", line 2942, in BuildLoop
pred, body, original_loop_vars, loop_vars, shape_invariants)
File "/home/hrbigelow/anaconda3/lib/python3.6/site-packages/tensorflow/python/ops/control_flow_ops.py", line 2879, in _BuildLoop
body_result = body(*packed_vars_for_body)
File "/home/hrbigelow/ai/lb-wavenet/while_var_test.py", line 11, in body
tf.assign(a[i], a[i-1] + a[i-2])
File "/home/hrbigelow/anaconda3/lib/python3.6/site-packages/tensorflow/python/ops/state_ops.py", line 220, in assign
return ref.assign(value, name=name)
File "/home/hrbigelow/anaconda3/lib/python3.6/site-packages/tensorflow/python/ops/array_ops.py", line 697, in assign
raise ValueError("Sliced assignment is only supported for variables")
ValueError: Sliced assignment is only supported for variables

变量不是循环内运行的操作的输出,而是存在于循环外部的外部实体。因此,您不必将其作为参数提供。

此外,您需要强制进行更新,例如在body中使用tf.control_dependencies

import tensorflow as tf
v = [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
n = len(v)
a = tf.Variable(v, name = 'a')
def cond(i):
return i < n 
def body(i):
op = tf.assign(a[i], a[i-1] + a[i-2])
with tf.control_dependencies([op]):
return i + 1
i = tf.while_loop(cond, body, [2])
sess = tf.InteractiveSession()
tf.global_variables_initializer().run()
i.eval()
print(a.eval())
# [ 1  1  2  3  5  8 13 21 34 55 89]

您可能希望谨慎行事,并设置parallel_iterations=1以强制循环按顺序运行。

从 CUDA 的角度来看,不允许分配单个索引是有意义的,因为它否定了异构并行计算的所有性能优势。

我知道这会增加一些计算开销,但它有效。

import tensorflow as tf
v = [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
n = len(v)
a = tf.Variable(v, name = 'a',dtype=tf.float32)
def cond(i, a):
return i < n 
def body(i, a1):
e = tf.eye(n,n)[i]
a1 = a1 + e *(a1[i-1] + a1[i-2])
return i + 1, a1
i, b = tf.while_loop(cond, body, [2, a]) 
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print('i: ',sess.run(i))
print('b: ',sess.run(b))

最新更新