Недавно я отправился в небольшое интересное путешествие, пытаясь улучшить Учебник по переводу с вниманием Tensorflow, и подумал, что о результатах стоит поделиться со всем миром. Моя цель состояла в том, чтобы реализовать ту же логику, что и в вышеупомянутом руководстве, но сделать это более похожим на Keras способом, удалив активный код. Вторичной целью было ускорить выполнение учебника, чтобы обучение на полном наборе данных было несколько более управляемым. Я считаю, что мне удалось добиться успеха с обеих сторон, и в этой статье я расскажу, как это сделать.

Прежде всего: эта статья на Medium - лишь путь к гораздо большему описанию. Большинство текстовых объяснений того, что я сделал и почему я это сделал, можно найти в записной книжке, которую я написал при составлении этой программы:



В приведенную выше ссылку включен автономный файл Python, включающий мой собственный слой Keras «LSTMWithAttention». Этот слой функционально идентичен обычному слою Keras LSTM, за исключением того, что он принимает тензор «констант» вместе со стандартным вводом состояния. Этот тензор «констант» должен иметь форму [длина входной последовательности, глубина кодирования]. Он используется для предоставления «контекста», на который уровень LSTM может «обращать внимание». Другими словами, уровень LSTMWithAttention научится смотреть на части закодированной входной последовательности, чтобы улучшить свой контекст и (будем надеяться) свою производительность.

Также включено включение уровня LSTMWithAttention в то, что я называю «режимом внимания». В этом режиме выходом уровня является функция softmax для закодированной входной последовательности, которая демонстрирует, какую часть последовательности модель просматривает на любом заданном временном шаге. На графике в pyplot это выглядит примерно так:

Я считаю, что такое поведение возникает из-за случайного шума. Я настоятельно рекомендую вам обучить одну из этих моделей, чтобы увидеть ее собственными глазами, если у вас есть немного вычислительных ресурсов и свободное время.

Если вы не хотите нажимать на Jupyter Notebook, вот фрагмент кода, демонстрирующий, насколько легко использовать этот слой LSTMWithAttention для создания (без энтузиазма!) Модели нейронного преобразования Seq2Seq с использованием чистого Keras:

# Encoder Layers
attenc_inputs = Input(shape=(len_input,), name="attenc_inputs")
attenc_emb = Embedding(input_dim=vocab_in_size, output_dim=embedding_dim)
attenc_lstm = CuDNNLSTM(units=units, return_sequences=True, return_state=True)
attenc_outputs, attstate_h, attstate_c = attenc_lstm(attenc_emb(attenc_inputs))
attenc_states = [attstate_h, attstate_c]
attdec_inputs = Input(shape=(None,))
attdec_emb = Embedding(input_dim=vocab_out_size, output_dim=embedding_dim)
attdec_lstm = LSTMWithAttention(units=units, return_sequences=True, return_state=True)
# Note that the only real difference here is that we are feeding attenc_outputs to the decoder now.
attdec_lstm_out, _, _ = attdec_lstm(inputs=attdec_emb(attdec_inputs), 
                                    constants=attenc_outputs, 
                                    initial_state=attenc_states)
attdec_d1 = Dense(units, activation="relu")
attdec_d2 = Dense(vocab_out_size, activation="softmax")
attdec_out = attdec_d2(Dropout(rate=.4)(attdec_d1(Dropout(rate=.4)(attdec_lstm_out))))
attmodel = Model([attenc_inputs, attdec_inputs], attdec_out)
attmodel.compile(optimizer=tf.train.AdamOptimizer(), loss="sparse_categorical_crossentropy", metrics=['sparse_categorical_accuracy'])