Я пытаюсь реализовать задачу от последовательности к последовательности, используя LSTM от Keras с бэкэндом TensorFlow. Входные данные - английские предложения переменной длины. Чтобы создать набор данных с двумерной формой [batch_number, max_sentence_length]
, я добавляю EOF
в конце строки и дополняю каждое предложение достаточным количеством заполнителей, например #
. А затем каждый символ в предложении преобразуется в горячий вектор, так что набор данных имеет трехмерную форму [batch_number, max_sentence_length, character_number]
. После уровней кодера и декодера LSTM вычисляется кросс-энтропия softmax между выходом и целью.
Чтобы устранить эффект заполнения при обучении модели, можно использовать маскирование для функций ввода и потерь. Ввод маски в Keras можно выполнить с помощью layers.core.Masking
. В TensorFlow маскирование функции потерь можно выполнить следующим образом: настраиваемая функция маскированных потерь в TensorFlow .
Однако я не нашел способа реализовать это в Keras, поскольку определяемая пользователем функция потерь в Keras принимает только параметры y_true
и y_pred
. Итак, как ввести true sequence_lengths
в функцию потерь и маску?
Кроме того, я нахожу функцию _weighted_masked_objective(fn)
в \keras\engine\training.py
. Его определение
Добавляет поддержку маскирования и взвешивания выборки к целевой функции.
Но похоже, что функция может принимать только fn(y_true, y_pred)
. Есть ли способ использовать эту функцию для решения моей проблемы?
Чтобы быть конкретным, я модифицирую пример Ю-Янга.
from keras.models import Model
from keras.layers import Input, Masking, LSTM, Dense, RepeatVector, TimeDistributed, Activation
import numpy as np
from numpy.random import seed as random_seed
random_seed(123)
max_sentence_length = 5
character_number = 3 # valid character 'a, b' and placeholder '#'
input_tensor = Input(shape=(max_sentence_length, character_number))
masked_input = Masking(mask_value=0)(input_tensor)
encoder_output = LSTM(10, return_sequences=False)(masked_input)
repeat_output = RepeatVector(max_sentence_length)(encoder_output)
decoder_output = LSTM(10, return_sequences=True)(repeat_output)
output = Dense(3, activation='softmax')(decoder_output)
model = Model(input_tensor, output)
model.compile(loss='categorical_crossentropy', optimizer='adam')
model.summary()
X = np.array([[[0, 0, 0], [0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 1, 0]],
[[0, 0, 0], [0, 1, 0], [1, 0, 0], [0, 1, 0], [0, 1, 0]]])
y_true = np.array([[[0, 0, 1], [0, 0, 1], [1, 0, 0], [0, 1, 0], [0, 1, 0]], # the batch is ['##abb','#babb'], padding '#'
[[0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 1, 0], [0, 1, 0]]])
y_pred = model.predict(X)
print('y_pred:', y_pred)
print('y_true:', y_true)
print('model.evaluate:', model.evaluate(X, y_true))
# See if the loss computed by model.evaluate() is equal to the masked loss
import tensorflow as tf
logits=tf.constant(y_pred, dtype=tf.float32)
target=tf.constant(y_true, dtype=tf.float32)
cross_entropy = tf.reduce_mean(-tf.reduce_sum(target * tf.log(logits),axis=2))
losses = -tf.reduce_sum(target * tf.log(logits),axis=2)
sequence_lengths=tf.constant([3,4])
mask = tf.reverse(tf.sequence_mask(sequence_lengths,maxlen=max_sentence_length),[0,1])
losses = tf.boolean_mask(losses, mask)
masked_loss = tf.reduce_mean(losses)
with tf.Session() as sess:
c_e = sess.run(cross_entropy)
m_c_e=sess.run(masked_loss)
print("tf unmasked_loss:", c_e)
print("tf masked_loss:", m_c_e)
Вывод в Keras и TensorFlow сравнивается следующим образом:
Как показано выше, после некоторых типов слоев маскирование отключено. Итак, как замаскировать функцию потерь в Keras при добавлении этих слоев?