【问题标题】:How to feed back RNN output to input in tensorflow如何将RNN输出反馈到张量流中的输入
【发布时间】:2017-02-24 14:00:43
【问题描述】:

如果假设我有一个训练有素的 RNN(例如语言模型),并且我想看看它自己会生成什么,我应该如何将其输出反馈到其输入?

我阅读了以下相关问题:

理论上我很清楚,在 tensorflow 中我们使用截断的反向传播,所以我们必须定义我们想要“跟踪”的最大步长。我们还为批次保留了一个维度,因此如果我想训练正弦波,我必须提供 [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 次迭代中收敛。到目前为止,我已经了解到,在这种情况下,图表包含 n_samples 数量的 LSTM 单元共享它们的参数,并且我只能将输入作为 时间序列 提供给它们。但是,当 生成 样本时,网络显式依赖于其先前的输出 - 这意味着我无法一次提供展开的模型。我试图在每一步计算状态和输出:

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

等等……

如果我想使用这个经过训练的网络在接下来的时间步中使用它自己的输出作为输入,该怎么办?

【问题讨论】:

    标签: python tensorflow lstm recurrent-neural-network


    【解决方案1】:

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

    1. 确保您的输入占位符可以接受动态序列长度,即时间维度的大小为None
    2. 确保您使用的是tf.nn.dynamic_rnn(您在发布的示例中使用)。
    3. 将初始状态传递给dynamic_rnn
    4. 然后,在测试时,您可以循环遍历您的序列并单独输入每个时间步长(即最大序列长度为 1)。此外,您只需继承 RNN 的内部状态。请参阅下面的伪代码(变量名称参考您的代码 sn-p)。

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

    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
    

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

    如果你想不仅在测试时进行这种预测,而且在训练时也可以这样做,但实现起来有点复杂。

    【讨论】:

    • 我正在尝试在火车时间执行此操作 - 是否有替代手动展开 RNN 的替代方法(即是否有某种方法不必提前指定 X?)
    • @tegan 您可以创建自己的单元格或使用tf.nn.raw_rnn,这样您就可以更好地控制调用 LSTM 单元格之前和之后发生的事情。看看this blog post,仔细阅读raw_rnn的TF文档。
    • 谢谢! tl;博士对于任何阅读的人,使用 raw_rnn 而不是 dynamic_rnn,它允许您(以及其他灵活性)为输入传递一个 lambda。
    • @tegan 关于tf.nn.raw_rnn 工作原理的更详细的帖子可以在这篇帖子中找到:stackoverflow.com/questions/39681026/…
    • @kafman 当我们的输入包含多个时间序列并且我们仅预测模型的一个输出并且希望在时间步时将此预测输出与其他输入一起使用时,我们如何使用此方法@ 987654333@?
    【解决方案2】:

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

    1. 使用零初始化变量作为每个时间步的输入状态
    2. 每次您完成截断序列并获得一些输出状态时,使用您刚刚获得的输出状态更新状态变量。

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

    1. 获取状态到 python 并在下次反馈它们,就像在 ptb example in tensorflow/models 中所做的那样
    2. 在图中构建一个更新操作并添加一个依赖项,就像在 ptb example in tensorpack 中所做的那样。

    【讨论】:

    • 是这样吗,如果我使用时间步 4,那么输入提要会像这样:[0, 0, 0, 0 ][0, 0, 0, h0][0, 0, h0, h1][0, h0, h1, h2][h0, h1, h2, h3][h1, h2, h3, h4] ...等
    • 假设您在谈论方法 1。您只需输入初始状态 (0,0,0,0)。 tensorflow 中的 rnn 函数已经计算了内部状态
    • 计算内部状态,但是,如果我输入 (0,0,0,0),那么我会得到 4 个输出 (hidden, h) 值 - 我想从中使用 只有第一个作为下一个的INPUT。顺便说一句,我不想​​提供网络的 states (c & h),而是它的最后一个 prediction,这意味着如果 state_size=N 比我必须进一步处理状态获得单个标量进行预测。我在提到的官方实现中找不到相对的答案。您能否用特定的行更新您的答案?谢谢:)
    • 我对您现在要问的内容以及符号感到困惑。什么是h0-h4?它们是隐藏状态还是模型的输出? 4个输出(隐藏,h)值是什么意思? rnn 函数为您提供一个大小为 (batch x time x cell_size) 的输出和另一个 (batch x state_size) 的输出。
    • 抱歉不清楚。 h0-h4 表示隐藏状态——在这个例子中是单个标量 ht 在时间 t。也许这个github问题会澄清,我想问什么:github.com/craffel/nntools/issues/15
    【解决方案3】:

    我知道我参加聚会有点晚了,但我认为这个要点可能很有用:

    https://gist.github.com/CharlieCodex/f494b27698157ec9a802bc231d8dcf31

    它允许您通过过滤器自动输入输入并作为输入返回到网络中。要使形状匹配 processing 可以设置为 tf.layers.Dense 层。

    如有任何问题请提出!

    编辑:

    在您的特定情况下,创建一个 lambda,它将 dynamic_rnn 输出处理到您的字符向量空间中。例如:

    # if you have:
    W = tf.Variable( ... )
    B = tf.Variable( ... )
    Yo, Ho = tf.nn.dynamic_rnn( cell , inputs , state )
    logits = tf.matmul(W, Yo) + B
     ...
    # use self_feeding_rnn as
    process_yo = lambda Yo: tf.matmul(W, Yo) + B
    Yo, Ho = self_feeding_rnn( cell, seed, initial_state, processing=process_yo)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多