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