如何在LSTM自编码器中使用掩码层来掩蔽输入/输出?

我正在尝试使用LSTM自编码器进行序列到序列的学习,输入序列的长度是可变的,使用以下代码:

inputs = Input(shape=(None, input_dim))masked_input = Masking(mask_value=0.0, input_shape=(None,input_dim))(inputs)encoded = LSTM(latent_dim)(masked_input)decoded = RepeatVector(timesteps)(encoded)decoded = LSTM(input_dim, return_sequences=True)(decoded)sequence_autoencoder = Model(inputs, decoded)encoder = Model(inputs, encoded)

其中inputs是用0填充到相同长度的原始序列数据(timesteps)。使用上述代码,输出也是timesteps长度,但在计算损失函数时,我们只希望输出中的前Ni个元素(其中Ni是输入序列i的长度,对于不同的序列可能不同)。有谁知道有什么好的方法可以做到这一点吗?

谢谢!


回答:

选项1:如果你接受分批训练,你可以始终不进行填充训练。

请参阅这个答案,了解如何简单地分离等长度的批次:Keras误解训练数据形状

在这种情况下,你所需要做的就是以另一种方式执行“重复”操作,因为你在训练时没有确切的长度。

因此,你可以用以下代码代替RepeatVector

import keras.backend as Kdef repeatFunction(x):    #x[0]是(batch,latent_dim)    #x[1]是inputs: (batch,length,features)    latent = K.expand_dims(x[0],axis=1) #shape(batch,1,latent_dim)    inpShapeMaker = K.ones_like(x[1][:,:,:1]) #shape (batch,length,1)    return latent * inpShapeMaker#代替RepeatVector:Lambda(repeatFunction,output_shape=(None,latent_dim))([encoded,inputs])

选项2(不太好):在RepeatVector之后使用另一个掩码。

我试过这个方法,它确实有效,但我们不会在末尾得到0,而是会得到最后一个值重复到末尾。因此,你将不得不对目标数据进行奇怪的填充,将最后一步重复到末尾。

例如:目标[[[1,2],[5,7]]]将不得不变成[[[1,2],[5,7],[5,7],[5,7]…]]

这可能会使你的数据非常不平衡,我认为……

def makePadding(x):    #x[0]是已经重复的encoded      #x[1]是inputs        #padding = 1表示inputs中的实际数据,0表示0    padding =  K.cast( K.not_equal(x[1][:,:,:1],0), dtype=K.floatx())        #假设你没有为非填充数据使用0    #padding在latent_dim上重复    padding = K.repeat_elements(padding,rep=latent_dim,axis=-1)    return x[0]*paddinginputs = Input(shape=(timesteps, input_dim))masked_input = Masking(mask_value=0.0)(inputs)encoded = LSTM(latent_dim)(masked_input)decoded = RepeatVector(timesteps)(encoded)decoded = Lambda(makePadding,output_shape=(timesteps,latent_dim))([decoded,inputs])decoded = Masking(mask_value=0.0)(decoded)decoded = LSTM(input_dim, return_sequences=True)(decoded)sequence_autoencoder = Model(inputs, decoded)encoder = Model(inputs, encoded)

选项3(最佳):直接从输入中裁剪输出,这也消除了梯度

def cropOutputs(x):    #x[0]是末尾的decoded    #x[1]是inputs    #两者具有相同的形状    #padding = 1表示inputs中的实际数据,0表示0    padding =  K.cast( K.not_equal(x[1],0), dtype=K.floatx())        #如果你对非填充数据使用零,它们将失去反向传播    return x[0]*padding........decoded = LSTM(input_dim, return_sequences=True)(decoded)decoded = Lambda(cropOutputs,output_shape=(timesteps,input_dim))([decoded,inputs])

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注