我正在尝试使用 Keras 的 LSTM 和 TensorFlow 后端来实现序列到序列的任务。输入是长度可变的英语句子。为了构建一个具有 2-D shape 的数据集[batch_number, max_sentence_length]
,我EOF
在行尾添加并用足够的占位符填充每个句子,例如#
. 然后将句子中的每个字符转换为 one-hot 向量,从而使数据集具有 3-D 形状[batch_number, max_sentence_length, character_number]
。在 LSTM 编码器和解码器层之后,计算输出和目标之间的 softmax 交叉熵。
为了消除模型训练中的填充效应,可以对输入和损失函数使用掩码。Keras 中的掩码输入可以使用layers.core.Masking
. 在 TensorFlow 中,可以按如下方式对损失函数进行掩码:TensorFlow 中的自定义掩码损失函数。
但是,我没有找到在 Keras 中实现它的方法,因为 Keras 中用户定义的损失函数只接受参数y_true
和y_pred
. 那么如何输入真实sequence_lengths
的损失函数和掩码呢?
此外,我_weighted_masked_objective(fn)
在\keras\engine\training.py
. 它的定义是
为目标函数添加对掩蔽和样本加权的支持。
但似乎该功能只能接受fn(y_true, y_pred)
. 有没有办法使用这个功能来解决我的问题?
具体来说,我修改了Yu-Yang的例子。
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 中掩盖损失函数呢?