首页 文章

如何在张量流中反馈RNN输出到输入

提问于
浏览
7

假设我有一个训练有素的RNN(例如语言模型),并且我想看看它自己会产生什么, how should I feed its output back to its input?

我阅读了以下相关问题:

从理论上讲,我很清楚,在张量流中,我们使用截断的反向传播,因此我们必须定义我们想要的最大步长"trace" . 我们也为批量保留了一个维度,因此如果我想训练一个正弦波,我必须输入 [None, num_step, 1] 输入 .

以下代码有效:

tf.reset_default_graph()
n_samples=100

state_size=5

lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(state_size, forget_bias=1.)
def_x = np.sin(np.linspace(0, 10, n_samples))[None, :, None]
zero_x = np.zeros(n_samples)[None, :, None]
X = tf.placeholder_with_default(zero_x, [None, n_samples, 1])
output, last_states = tf.nn.dynamic_rnn(inputs=X, cell=lstm_cell, dtype=tf.float64)

pred = tf.contrib.layers.fully_connected(output, 1, activation_fn=tf.tanh)

Y = np.roll(def_x, 1)
loss = tf.reduce_sum(tf.pow(pred-Y, 2))/(2*n_samples)


opt = tf.train.AdamOptimizer().minimize(loss)
sess = tf.InteractiveSession()
tf.global_variables_initializer().run()

# Initial state run
plt.show(plt.plot(output.eval()[0]))
plt.plot(def_x.squeeze())
plt.show(plt.plot(pred.eval().squeeze()))

steps = 1001
for i in range(steps):
    p, l, _= sess.run([pred, loss, opt])

LSTM的状态大小可以变化,我也尝试将正弦波馈入网络和零,并且在两种情况下它都在~500次迭代中收敛 . 到目前为止,我已经理解,在这种情况下,图表包含共享其参数的LSTM单元格数量,我只能将输入作为时间序列输入到我这里 . 但是,当 generating 样本时,网络显然取决于其先前的输出 - 这意味着我无法立即提供展开的模型 . 我尝试在每一步计算状态和输出:

with tf.variable_scope('sine', reuse=True):
    X_test = tf.placeholder(tf.float64)
    X_reshaped = tf.reshape(X_test, [1, -1, 1])
    output, last_states = tf.nn.dynamic_rnn(lstm_cell, X_reshaped, dtype=tf.float64)
    pred = tf.contrib.layers.fully_connected(output, 1, activation_fn=tf.tanh)


    test_vals = [0.]
    for i in range(1000):
        val = pred.eval({X_test:np.array(test_vals)[None, :, None]})
        test_vals.append(val)

然而,在该模型中,似乎LSTM细胞之间没有连续性 . 这里发生了什么?

我是否必须使用100个时间步骤初始化零数组,并将每个运行的结果分配给数组?就像喂网络一样:

运行0: input_feed = [0, 0, 0 ... 0]; res1 = result

运行1: input_feed = [res1, 0, 0 ... 0]; res2 = result

运行1: input_feed = [res1, res2, 0 ... 0]; res3 = result

等等...

What to do if I want to use this trained network to use its own output as its input in the following time step?

2 回答

  • 5

    如果我理解正确,你想找到一种方法来输出时间步 t 的输出作为时间步 t+1 的输入,对吗?为此,您可以在测试时使用相对简单的工作:

    • 确保输入占位符可以接受动态序列长度,即时间维度的大小为 None .

    • 确保您使用的是 tf.nn.dynamic_rnn (您在发布的示例中执行此操作) .

    • 将初始状态传递给 dynamic_rnn .

    • 然后,在测试时,您可以遍历序列并单独提供每个时间步(即最大序列长度为1) . 此外,您只需要继承RNN的内部状态 . 请参阅下面的伪代码(变量名称引用您的代码段) .

    即,将模型的定义更改为以下内容:

    lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(state_size, forget_bias=1.)
    X = tf.placeholder_with_default(zero_x, [None, None, 1])  # [batch_size, seq_length, dimension of input]
    batch_size = tf.shape(self.input_)[0]
    initial_state = lstm_cell.zero_state(batch_size, dtype=tf.float32)
    def_x = np.sin(np.linspace(0, 10, n_samples))[None, :, None]
    zero_x = np.zeros(n_samples)[None, :, None]
    output, last_states = tf.nn.dynamic_rnn(inputs=X, cell=lstm_cell, dtype=tf.float64,
        initial_state=initial_state)
    pred = tf.contrib.layers.fully_connected(output, 1, activation_fn=tf.tanh)
    

    然后你可以这样执行推理:

    fetches = {'final_state': last_state,
               'prediction': pred}
    
    toy_initial_input = np.array([[[1]]])  # put suitable data here
    seq_length = 20  # put whatever is reasonable here for you
    
    # get the output for the first time step
    feed_dict = {X: toy_initial_input}
    eval_out = sess.run(fetches, feed_dict)
    outputs = [eval_out['prediction']]
    next_state = eval_out['final_state']
    
    for i in range(1, seq_length):
        feed_dict = {X: outputs[-1],
                     initial_state: next_state}
        eval_out = sess.run(fetches, feed_dict)
        outputs.append(eval_out['prediction'])
        next_state = eval_out['final_state']
    
    # outputs now contains the sequence you want
    

    请注意,这也适用于批次,但如果您在同一批次中使用不同长度的序列,则可能会更复杂一些 .

    如果您不仅要在测试时执行此类预测,还要在训练时执行此类预测,那么也可以执行此类预测,但实现起来要复杂一些 .

  • 0

    您可以使用自己的输出(最后一个状态)作为下一步输入(初始状态) . 一种方法是:

    • 在每个时间步使用零初始化变量作为输入状态

    • 每次完成截断序列并得到一些输出状态时,用你刚刚得到的输出状态更新状态变量 .

    第二个可以通过以下任一方式完成:

相关问题