Как работать с партиями с последовательностями переменной длины в TensorFlow?

Я пытался использовать RNN (в частности, LSTM) для прогнозирования последовательности. Тем не менее, я столкнулся с проблемой с переменной длиной последовательности. Например,

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

Я пытаюсь предсказать следующее слово после текущего с помощью простого RNN на основе этого теста для построения модели PTB LSTM.

Однако параметр 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 необходимо изменить в моем случае для каждого предложения. Я пробовал несколько взломов, но ничего не работает.

Ответ 1

Вы можете использовать идеи группирования и заполнения, которые описаны в:

Модели от последовательности к последовательности

Также функция 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:

Базовый пример RNN Tensorflow с последовательностями переменной длины

Ответ 2

Вместо этого вы можете использовать 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),
)

Код берется из идеальной статьи по этой теме, пожалуйста, также проверьте его.

Обновление: еще один отличный пост на dynamic_rnn vs rnn вы можете найти

Ответ 3

Вы можете использовать идеи bucketing и padding, которые описаны в

  Модели последовательности к последовательности

Также функция 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_lenght: 20,
#other feeds
       }
sess.run(outputs, feed_dict=feed)

Здесь самое главное, если вы хотите использовать состояния, полученные одним предложением, как состояние для следующего предложения, когда вы предоставляете sequence_length (допустим, 20 и предложение после заполнения равно 50), Вы хотите, чтобы состояние было получено на 20-м шаге. Для этого do

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,:,:]

Ответ 4

Вы можете ограничить максимальную длину ваших входных последовательностей, наложить более короткие на эту длину, записать длину каждой последовательности и использовать tf.nn.dynamic_rnn. Он обрабатывает входные последовательности как обычно, но после последнего элемента последовательности, обозначенного символом seq_length, он просто копирует состояние ячейки через, а для вывода выводит нулевой тензор.

Ответ 5

Извините, что опубликовал сообщение о нерешенной проблеме, но я просто представил PR для лучшего решения. dynamic_rnn чрезвычайно гибок, но ужасно медленен. Это работает, если это ваш единственный вариант, но CuDNN намного быстрее. Этот PR добавляет поддержку переменной длины в CuDNNLSTM, так что вы, надеюсь, сможете использовать это в ближайшее время.

Вам нужно отсортировать последовательности по убыванию длины. Затем вы можете pack_sequence, запустить ваши RNN, а затем unpack_sequence.

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