首页 文章

如何在TensorFlow中处理具有可变长度序列的批次?

提问于
浏览
15

我试图使用RNN(特别是LSTM)进行序列预测 . 在这里,我遇到了一些问题 . 例如:

sent_1 = "I am flying to Dubain"
sent_2 = "I was traveling from US to Dubai"

我在这里尝试做的是预测前一个单词之后的下一个单词,作为基于此Benchmark for building a PTB LSTM model的简单RNN .

num_steps 参数(用于展开以前的隐藏状态)应该在每个Tensorflow的纪元中保持不变?基本上,不可能批量处理句子,因为批次中的句子长度不同 .

# inputs = [tf.squeeze(input_, [1])
 #           for input_ in tf.split(1, num_steps, inputs)]
 # outputs, states = rnn.rnn(cell, inputs, initial_state=self._initial_state)

在这里,每个句子都需要改变 num_steps . 我尝试了几次黑客攻击,但似乎没有任何工作 .

5 回答

  • 4

    您可以使用以下描述的bucketing和padding的概念:

    Sequence-to-Sequence Models

    此外,创建RNN网络的rnn函数接受参数 sequence_length.

    例如,您可以创建相同大小的句子桶,用必要数量的零填充它们,或者代表零字的占位符,然后将它们与seq_length = len(zero_words)一起提供 .

    seq_length = tf.placeholder(tf.int32)
    outputs, states = rnn.rnn(cell, inputs, initial_state=initial_state, sequence_length=seq_length)
    
    sess = tf.Session()
    feed = {
        seq_length: 20,
        #other feeds
    }
    sess.run(outputs, feed_dict=feed)
    

    看看这个reddit线程:

    Tensorflow basic RNN example with 'variable length' sequences

  • 17

    您可以使用 dynamic_rnn 代替并通过将数组传递给 sequence_length 参数来指定每个序列的长度 . 示例如下:

    def length(sequence):
        used = tf.sign(tf.reduce_max(tf.abs(sequence), reduction_indices=2))
        length = tf.reduce_sum(used, reduction_indices=1)
        length = tf.cast(length, tf.int32)
        return length
    
    from tensorflow.nn.rnn_cell import GRUCell
    
    max_length = 100
    frame_size = 64
    num_hidden = 200
    
    sequence = tf.placeholder(tf.float32, [None, max_length, frame_size])
    output, state = tf.nn.dynamic_rnn(
        GRUCell(num_hidden),
        sequence,
        dtype=tf.float32,
        sequence_length=length(sequence),
    )
    

    代码取自perfect article上的主题,请同时查看 .

    更新:另一个great postdynamic_rnn vs rnn 你可以找到

  • 4

    您可以限制输入序列的最大长度,将较短的长度填充到该长度,记录每个序列的长度并使用tf.nn.dynamic_rnn . 它像往常一样处理输入序列,但是在序列的最后一个元素之后,由 seq_length 指示,它只是复制单元状态,并且对于输出它输出零 - 张量 .

  • 14

    您可以使用描述中的bucketing和padding的想法

    Sequence-to-Sequence Models

    创建RNN网络的rnn函数也接受参数sequence_length .

    例如,您可以创建相同大小的数据桶,用必要数量的零填充它们,或者代表零字的placeholdres,然后将它们与seq_length = len(zero_words)一起提供 .

    seq_length = tf.placeholder(tf.int32)
    outputs, states = rnn.rnn(cell, inputs,initial_state=initial_state,sequence_length=seq_length)
    
    sess = tf.Session()
    feed = {
    seq_lenght: 20,
    #other feeds
           }
    sess.run(outputs, feed_dict=feed)
    

    在这里,最重要的是,如果你想利用一个句子获得的状态作为下一个句子的状态,当你提供sequence_length时,(假设20和填充后的句子是50) . 你想要在第20步获得的状态 . 为此,做

    tf.pack(states)
    

    那个电话之后

    for i in range(len(sentences)):
    state_mat   = session.run([states],{
                m.input_data: x,m.targets: y,m.initial_state: state,     m.early_stop:early_stop })
    state = state_mat[early_stop-1,:,:]
    
  • 1

    很抱歉发布一个死的问题,但我刚刚提交了PR以获得更好的解决方案 . dynamic_rnn 非常灵活,但非常慢 . 它是有效的,如果它是你唯一的选择,但CuDNN要快得多 . 此PR增加了对 CuDNNLSTM 的可变长度的支持,因此您希望很快能够使用它 .

    您需要按降序排序序列 . 然后你可以 pack_sequence ,运行你的RNN,然后 unpack_sequence .

    https://github.com/tensorflow/tensorflow/pull/22308

相关问题