在递归循环中分配给TensorFlow变量

时间:2018-08-20 19:35:59

标签: python tensorflow

在Tensorflow 1.9中,我想创建一个网络,然后将网络的输出(预测)递归地反馈到网络的输入中。在此循环中,我要将网络做出的预测存储在列表中。

这是我的尝试:

    # Define the number of steps over which to loop the network
    num_steps = 5

    # Define the network weights
    weights_1 = np.random.uniform(0, 1, [1, 10]).astype(np.float32)
    weights_2 = np.random.uniform(0, 1, [10, 1]).astype(np.float32)

    # Create a variable to store the predictions, one for each loop
    predictions = tf.Variable(np.zeros([num_steps, 1]), dtype=np.float32)

    # Define the initial prediction to feed into the loop
    initial_prediction = np.array([[0.1]], dtype=np.float32)
    x = initial_prediction

    # Loop through the predictions
    for step_num in range(num_steps):
        x = tf.matmul(x, weights_1)
        x = tf.matmul(x, weights_2)
        predictions[step_num-1].assign(x)

    # Define the final prediction
    final_prediction = x

    # Start a session
    sess = tf.Session()
    sess.run(tf.global_variables_initializer())

    # Make the predictions
    last_pred, all_preds = sess.run([final_prediction, predictions])
    print(last_pred)
    print(all_preds)

这会打印出来:

[[48.8769]]

[[0.]
 [0.]
 [0.]
 [0.]
 [0.]]

因此,尽管final_prediction的值看起来正确,但predictions的值却不是我期望的。尽管有predictions行,看来predictions[step_num-1].assign(x)从未真正分配过。

请有人可以向我解释为什么这不起作用,我应该怎么做?谢谢!

1 个答案:

答案 0 :(得分:2)

之所以会这样,是因为assign像其他任何操作一样仅是TF op,因此仅在需要时才执行。由于到final_prediction的路径上没有任何内容依赖于assign op,并且predictions只是一个变量,因此该赋值永远不会执行。

我认为最直接的解决方案是替换行

predictions[step_num-1].assign(x)

通过

x = predictions[step_num-1].assign(x)

之所以可行,是因为assign还返回了它所分配的值。现在,要计算final_prediction TF,实际上需要“遍历” assign操作,因此应该执行分配。

另一种选择是使用tf.control_dependencies,这是在计算其他操作时“强制” TF计算特定操作的一种方法。但是,在这种情况下,可能有点棘手,因为我们要强制执行的操作(assign)取决于循环中正在计算的值,而我不确定TF在其中执行填充的顺序案件。以下应该起作用:

for step_num in range(num_steps):
    x = tf.matmul(x, weights_1)
    x = tf.matmul(x, weights_2)
    with tf.control_dependencies([predictions[step_num-1].assign(x)]):
        x = tf.identity(x)

我们使用tf.identity作为noop只是为了用control_dependencies包装一些东西。我认为这是两者之间更灵活的选择。但是,它附带了the docs中讨论的一些警告。