【问题标题】:Get last output of dynamic_rnn in tensorflow?获取张量流中dynamic_rnn的最后输出?
【发布时间】:2016-04-23 23:25:13
【问题描述】:

我正在使用 dynamic_rnn 处理 MNIST 数据:

# LSTM Cell
lstm = rnn_cell.LSTMCell(num_units=200,
                         forget_bias=1.0,
                         initializer=tf.random_normal)

# Initial state
istate = lstm.zero_state(batch_size, "float")

# Get lstm cell output
output, states = rnn.dynamic_rnn(lstm, X, initial_state=istate)

# Output at last time point T
output_at_T = output[:, 27, :]

完整代码:http://pastebin.com/bhf9MgMe

lstm 的输入是(batch_size, sequence_length, input_size)

因此output_at_T 的尺寸为(batch_size, sequence_length, num_units),其中num_units=200

我需要沿sequence_length 维度获取最后一个输出。在上面的代码中,它被硬编码为27。但是,我事先不知道sequence_length,因为它可以在我的应用程序中逐批更改。

我试过了:

output_at_T = output[:, -1, :]

但它表示尚未实现负索引,我尝试使用占位符变量和常量(理想情况下,我可以为特定批次提供sequence_length);都没有用。

有什么方法可以在 tensorflow atm 中实现类似的东西?

【问题讨论】:

标签: python tensorflow


【解决方案1】:
output[:, -1, :]

现在可以与 Tensorflow 1.x 一起使用!!

【讨论】:

  • 这仅适用于sequence_length 对于output 中的每个元素都相同的情况。
  • 这个问题是关于动态长度的,这不起作用
【解决方案2】:

您是否注意到 dynamic_rnn 有两个输出?

  1. 输出 1,我们称之为 h,在每个时间步都有所有输出(即 h_1、h_2 等),
  2. 输出 2,final_state,有两个元素:cell_state,以及批次中每个元素的最后一个输出(只要您将序列长度输入到 dynamic_rnn)。

所以来自:

h, final_state= tf.dynamic_rnn( ..., sequence_length=[batch_size_vector], ... )

批次中每个元素的最后状态是:

final_state.h

请注意,这包括批次的每个元素的序列长度不同的情况,因为我们使用的是 sequence_length 参数。

【讨论】:

  • final_state.h 是返回最后一个输出还是最后一个隐藏状态
  • @bluesummers final_state.h 是批次中每个元素的最终激活(即最终输出),而 final_state.c 是单元格的状态
  • 谢谢。为了清楚起见,final_state.h 将具有 [batch_size, lstm_units] 的尺寸?
【解决方案3】:

这就是gather_nd 的用途!

def extract_axis_1(data, ind):
    """
    Get specified elements along the first axis of tensor.
    :param data: Tensorflow tensor that will be subsetted.
    :param ind: Indices to take (one for each element along axis 0 of data).
    :return: Subsetted tensor.
    """

    batch_range = tf.range(tf.shape(data)[0])
    indices = tf.stack([batch_range, ind], axis=1)
    res = tf.gather_nd(data, indices)

    return res

在您的情况下(假设 sequence_length 是一个一维张量,每个轴 0 元素的长度):

output = extract_axis_1(output, sequence_length - 1)

现在输出是一个维度为[batch_size, num_cells]的张量。

【讨论】:

  • 不需要这样做,dynamic_rnn 将最后一个状态作为输出。检查我的答案。
  • @Escachator 仅当序列长度相同时(在批次内)才有效。 OP 说“我事先不知道sequence_length,因为它可以在我的应用程序中逐批更改”所以这可能是一个公平的假设 - 我不知道。即使批次中的序列长度不同(并且数据已填充),我的答案也有效。
  • 如果您知道(或得到)'ind',您就知道批次中每个元素的序列长度。然后你可以在 dynamic_rnn 的 'sequence_length' 参数中输入它,一旦它到达批次的每个元素,它将停止计算。然后你只需要final_state.h。我可能应该将其添加到我的答案中。
  • @Escachator 确实如此,但如果您想访问最后的元素,它并没有真正的帮助!见this post
  • 你总是可以开发一个函数,给定一个批次,给你每个元素的序列长度。我假设你正在填充它。您甚至可以将新的 tf.data.Dataset API 与 map 函数一起使用。然后你在 tf.dynamic_rnn 的 sequence_length 中输入它,你就完成了。它可能会更快,因为 dynamic_rnn 将在每个元素到达末尾时停止计算。
【解决方案4】:

大多数答案都涵盖了它,但此代码片段可能有助于了解 dynamic_rnn 层真正返回的内容

=> (outputs, final_output_state) 的元组。

因此对于具有 最大序列长度 T 个时间步长的输入 输出 的形状为 [Batch_size, T, num_inputs](给定 time_major=False;默认值)并且它包含每个时间步的输出状态h1, h2.....hT

final_output_state 的形状为 [Batch_size,num_inputs],并具有每个批次序列的最终单元状态 cT 和输出状态 hT

但由于使用了dynamic_rnn,我猜你的序列长度因每个批次而异。

    import tensorflow as tf
    import numpy as np
    from tensorflow.contrib import rnn
    tf.reset_default_graph()

    # Create input data
    X = np.random.randn(2, 10, 8)

    # The second example is of length 6 
    X[1,6:] = 0
    X_lengths = [10, 6]

    cell = tf.nn.rnn_cell.LSTMCell(num_units=64, state_is_tuple=True)

    outputs, states  = tf.nn.dynamic_rnn(cell=cell,
                                         dtype=tf.float64,
                                         sequence_length=X_lengths,
                                         inputs=X)

    result = tf.contrib.learn.run_n({"outputs": outputs, "states":states},
                                    n=1,
                                    feed_dict=None)
    assert result[0]["outputs"].shape == (2, 10, 64)
    print result[0]["outputs"].shape
    print result[0]["states"].h.shape
    # the final outputs state and states returned must be equal for each      
    # sequence
    assert(result[0]["outputs"][0][-1]==result[0]["states"].h[0]).all()
    assert(result[0]["outputs"][-1][5]==result[0]["states"].h[-1]).all()
    assert(result[0]["outputs"][-1][-1]==result[0]["states"].h[-1]).all()

最终断言将失败,因为第二个序列的最终状态是在第 6 个时间步,即。索引 5 和 [6:9] 的其余输出在第二个时间步中都是 0

【讨论】:

    【解决方案5】:

    我是 Stackoverflow 的新手,还不能发表评论,所以我正在写这个新答案。 @VM_AI,最后一个索引是tf.shape(output)[1] - 1。 所以,重复使用你的答案:

    # Let's first fetch the last index of seq length
    # last_index would have a scalar value
    last_index = tf.shape(output)[1] - 1
    # Then let's reshape the output to [sequence_length,batch_size,num_units]
    # for convenience
    output_rs = tf.transpose(output,[1,0,2])
    # Last state of all batches
    last_state = tf.nn.embedding_lookup(output_rs,last_index)
    

    这对我有用。

    【讨论】:

    • 问题要求的是最后一个动态状态,而不是数组中的最后一个状态
    【解决方案6】:

    您应该能够使用 tf.shape(output) 访问您的 output 张量的形状。 tf.shape() 函数将返回一个包含 output 张量大小的一维张量。在您的示例中,这将是 (batch_size, sequence_length, num_units)

    然后您应该能够将output_at_T 的值提取为output[:, tf.shape(output)[1], :]

    【讨论】:

      【解决方案7】:

      TensorFlow 中有一个函数tf.shape 可以让您获得形状的符号解释,而不是由output._shape[1] 返回的None。在获取最后一个索引后,您可以使用tf.nn.embedding_lookup 进行查找,尤其是在要获取的数据很高的情况下,因为这会并行查找32 by default

      # Let's first fetch the last index of seq length
      # last_index would have a scalar value
      last_index = tf.shape(output)[1] 
      # Then let's reshape the output to [sequence_length,batch_size,num_units]
      # for convenience
      output_rs = tf.transpose(output,[1,0,2])
      # Last state of all batches
      last_state = tf.nn.embedding_lookup(output_rs,last_index)
      

      这应该可行。

      只是为了澄清@Benoit Steiner 所说的话。他的解决方案不起作用,因为 tf.shape 将返回形状值的符号解释,并且不能用于切片张量,即直接索引

      【讨论】:

        猜你喜欢
        • 2017-05-07
        • 2020-10-13
        • 1970-01-01
        • 1970-01-01
        • 2019-04-08
        • 1970-01-01
        • 2018-12-22
        • 1970-01-01
        • 2016-06-29
        相关资源
        最近更新 更多