Как работать с партиями с последовательностями переменной длины в 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