Tensorflow seq2seq chatbot всегда дает одинаковые результаты - PullRequest
0 голосов
/ 03 июня 2018

Я пытаюсь создать чат-бот seq2seq с Tensorflow, но, похоже, он сходится к одним и тем же выводам, несмотря на разные входы.Модель дает разные выходы при первоначальной инициализации, но быстро сходится к тем же выходам через несколько эпох.Это все еще проблема даже после многих эпох и низких затрат.Тем не менее, модели, кажется, хорошо работают, когда тренируются с меньшими наборами данных (скажем, 20), но не с большими.

Я тренируюсь на Cornell Movie Dialogs Corpus с 100-мерной перчаткой и 50000 вокабамипредтренированное встраивание.

Кажется, что кодировщик имеет очень близкие конечные состояния (в диапазонах около 0,01) при совершенно разных входах.Я попытался использовать простой LSTM / GRU, двунаправленный LSTM / GRU, многослойный / сложенный LSTM / GRU и многослойный двунаправленный LSTM / GRU.Узлы рН были протестированы с 16 до 2048 скрытых единиц.Единственное отличие состоит в том, что модель имеет тенденцию выводить только начальный и конечный токены (GO и EOS) при наличии меньших скрытых единиц.

Для многослойного GRU, вот мой код:

cell_encode_0 = tf.contrib.rnn.GRUCell(self.n_hidden)
cell_encode_1 = tf.contrib.rnn.GRUCell(self.n_hidden)
cell_encode_2 = tf.contrib.rnn.GRUCell(self.n_hidden)
self.cell_encode = tf.contrib.rnn.MultiRNNCell([cell_encode_0, cell_encode_1, cell_encode_2])
# identical decoder

...

embedded_x = tf.nn.embedding_lookup(self.word_embedding, self.x)
embedded_y = tf.nn.embedding_lookup(self.word_embedding, self.y)

_, self.encoder_state = tf.nn.dynamic_rnn(
    self.cell_encode,
    inputs=embedded_x,
    dtype=tf.float32,
    sequence_length=self.x_length
    )

# decoder for training
helper = tf.contrib.seq2seq.TrainingHelper(
    inputs=embedded_y,
    sequence_length=self.y_length
    )

decoder = tf.contrib.seq2seq.BasicDecoder(
    self.cell_decode,
    helper,
    self.encoder_state,
    output_layer=self.projection_layer
    )

outputs, _, _ = tf.contrib.seq2seq.dynamic_decode(decoder, maximum_iterations=self.max_sequence, swap_memory=True)

return outputs.rnn_output

...

# Optimization
dynamic_max_sequence = tf.reduce_max(self.y_length)
mask = tf.sequence_mask(self.y_length, maxlen=dynamic_max_sequence, dtype=tf.float32)
crossent = tf.nn.sparse_softmax_cross_entropy_with_logits(
    labels=self.y[:, :dynamic_max_sequence], logits=self.network())
self.cost = (tf.reduce_sum(crossent * mask) / batch_size)
self.train_op = tf.train.AdamOptimizer(self.learning_rate).minimize(self.cost)

Полный код см. На github .(Если вы хотите проверить это, запустите train.py)

Что касается гиперпараметров, я пробовал скорость обучения от 0,1 до 0,0001 и размеры пакетов от 1 до 32. Другоечем обычные и ожидаемые эффекты, они не помогают с проблемой.

1 Ответ

0 голосов
/ 02 октября 2018

После нескольких месяцев копания я наконец нашел проблему.Кажется, что RNN требует токенов GO на входах декодера, но не на выходах (тот, который вы используете для стоимости).По сути, RNN ожидает, что его данные будут следующими:

Вход кодера: GO foo foo foo EOS

Вход декодера / правда заземления: GO bar bar bar EOS

Вывод декодера: bar bar bar EOS EOS / PAD

В моем коде я включил токен GO и на вход, и на выход декодера, в результате чего RNN повторял одинаковые токены (GO -> GO,бар -> бар).Это можно легко исправить, создав дополнительную переменную, в которой нет первого столбца (токенов GO) основной истины.В numpy это выглядит примерно так:

# y is ground truth with shape[0] = batch and shape[1] = token index
np.concatenate([y[:, 1:], np.full([y.shape[0], 1], EOS)], axis=1)
...