Machine learning 如何在LSTM自动编码器中使用屏蔽层屏蔽输入/输出?

Machine learning 如何在LSTM自动编码器中使用屏蔽层屏蔽输入/输出?,machine-learning,deep-learning,keras,lstm,autoencoder,Machine Learning,Deep Learning,Keras,Lstm,Autoencoder,我正在尝试使用LSTM autoencoder以可变长度的序列作为输入进行序列到序列学习,使用以下代码: 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)(enco

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

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)
其中,
输入
是用0填充到相同长度的原始序列数据(
时间步
)。使用上述代码,输出也是长度
timesteps
,但当我们计算损失函数时,我们只需要输出的第一个
Ni
元素(其中
Ni
是输入序列i的长度,对于不同的序列可能不同)。有人知道有什么好办法吗

谢谢

选项1:如果您接受单独批次的培训,则始终可以不使用填充进行培训。 请参阅此答案,了解分离等长批次的简单方法:

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

因此,您可以使用以下内容,而不是
RepeatVector

import keras.backend as K

def repeatFunction(x):

    #x[0] is (batch,latent_dim)
    #x[1] is 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

#instead of RepeatVector:
Lambda(repeatFunction,output_shape=(None,latent_dim))([encoded,inputs])
选项2(闻起来不好闻):重复之后使用另一个掩蔽。 我尝试了这个方法,它是有效的,但是我们在最后没有得到0,我们得到的最后一个值重复到最后。因此,您必须在目标数据中进行奇怪的填充,重复最后一步直到结束

示例:目标[[1,2],[5,7]]]必须是[[1,2],[5,7],[5,7],[5,7]…]

我认为,这可能会使您的数据严重失衡

def makePadding(x):

    #x[0] is encoded already repeated  
    #x[1] is inputs    

    #padding = 1 for actual data in inputs, 0 for 0
    padding =  K.cast( K.not_equal(x[1][:,:,:1],0), dtype=K.floatx())
        #assuming you don't have 0 for non-padded data

    #padding repeated for latent_dim
    padding = K.repeat_elements(padding,rep=latent_dim,axis=-1)

    return x[0]*padding

inputs = 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(最佳):直接从输入裁剪输出,这也消除了梯度
你试过用零填充输出吗?@DanielMöller输出的长度已经是
时间步
,如果我用零填充它会更长吗?对不起,用零填充“目标”。@DanielMöller是的,我就是这么做的,问题与填充有关。例如,如果一个特定的输入有5个元素,当它被送入自动编码器时,它会被5个长度为10的零填充。理想情况下,在计算损耗时,我们只需要关心输出的前5个元素,但由于最后5个元素的存在(除非它们都是零,这几乎是不可能的),损耗会更大。所以我想知道,在计算损耗时,我是否可以“掩盖”输出的最后5个元素?现在我知道了。。。在“RepeatVector”之后再做一次掩蔽怎么样?我会写一个选项…但也许真正最好的选项是组合选项2和3(当你有中间掩码时,你可以节省处理时间,并且在最后消除会影响损失函数的无意义重复值)。我现在不想尝试的一个测试是:创建一个带有屏蔽的模型,看看重复的输出是否参与反向传播。后端函数通常会将1映射为1,并使用Ano或tensorflow函数。他们在这里:---我不知道反向传播是如何工作的,但我假设Keras把这一切留给tensorflow/theano去做。我总是假设
equal
/
not_equal
的结果是常量。它们不会反向传播,但不会改变它们修改的张量的反向传播,当然,除非它们为0。到目前为止,我的尝试都很成功。我是说,我的意思是。
def cropOutputs(x):

    #x[0] is decoded at the end
    #x[1] is inputs
    #both have the same shape

    #padding = 1 for actual data in inputs, 0 for 0
    padding =  K.cast( K.not_equal(x[1],0), dtype=K.floatx())
        #if you have zeros for non-padded data, they will lose their backpropagation

    return x[0]*padding

....
....

decoded = LSTM(input_dim, return_sequences=True)(decoded)
decoded = Lambda(cropOutputs,output_shape=(timesteps,input_dim))([decoded,inputs])