我正在设法解决Keras中不同时间步长的输入的序列到序列自动编码(LSTM)问题。我对使用这样的网络将可变长度序列编码为固定向量特别感兴趣(对于LSTM编码器,不使用return_sequences = True)。
作为一个示例,仅带有遮罩层...
import numpy as np
import tensorflow as tf
test_data = np.array([[[1,2,1],[3,2,1],[0,0,0],[0,0,0]],
[[2,1,1],[3,1,2],[1,2,1],[3,3,3]],
[[3,2,3],[1,3,2],[1,1,1],[0,0,0]],
[[1,1,2],[0,0,0],[0,0,0,],[0,0,0]],
[[2,1,3],[4,2,0],[1,1,2],[1,3,2]]],dtype=np.float32)
input_layer = tf.keras.layers.Input((4,3))
masking_layer = tf.keras.layers.Masking(mask_value=0)(input_layer)
# masks correctly to this point
model = tf.keras.models.Model(inputs=input_layer, outputs=masking_layer)
print(model(test_data)._keras_mask)
给予
tf.Tensor(
[[ True True False False]
[ True True True True]
[ True True True False]
[ True False False False]
[ True True True True]], shape=(5, 4), dtype=bool)
符合预期。添加LSTM编码层会占用此掩码:
encode_layer = tf.keras.layers.LSTM(64)(masking_layer)
model = tf.keras.models.Model(inputs=input_layer, outputs= encode_layer)
print(model(test_data)._keras_mask)
不产生任何结果(再次,这是预期的)。我想做的是(以某种方式)重新构造由masking_layer生成的掩码,并将其应用于我用来馈送LSTM解码器的RepeatVector:
repeated = tf.keras.layers.RepeatVector(5)(encode_layer)
# it's here I'd like to reincarnate the mask, as it should propagate to the decoder
decode_layer = tf.keras.layers.LSTM(5,return_sequences=True)(repeated)
model = tf.keras.models.Model(inputs=input_layer, outputs=decode_layer)
我尝试实现Lambda层以尝试从Mask层读取Mask,但是我认为我严重误解了这一步骤
get_mask = lambda x: masking_layer._keras_mask
Lambda_layer = tf.keras.layers.Lambda(lambda x: x, mask=get_mask)(repeated)
这只会生成TypeError:()接受1个位置参数,但给出了2个。
对于您有任何关于这样复活口罩的见解,我将不胜感激。我知道我可以完全重新考虑网络,但是我想保留单矢量编码表示,并避免在编码LSTM上使用return_sequences = True。
先谢谢您。
答案 0 :(得分:0)
尽管我很想听听其他解决方案,但这似乎对我有用。可能比这更优雅...
我根据Keras的默认遮罩层创建了一个自定义层Reapply_Masking。它需要两个输入层:Input [0]是要向其应用蒙版的层(在我的示例中是RepeatVector层); Input [1]是原始蒙版之前的图层(在我的示例中为input_layer)。
它会像Masking层一样重新计算mask,并且将Input [0]的masked时间步长清零以达到良好的测量效果(Keras的masking层也是如此)。
class Reapply_Masking(Layer):
def __init__(self, mask_value, **kwargs):
super(Reapply_Masking, self).__init__(**kwargs)
self.supports_masking = True
self.mask_value = mask_value
def compute_output_shape(self, input_shape_list):
return input_shape_list[0].shape
def compute_mask(self, input_list, mask=None):
return K.any(math_ops.not_equal(input_list[1], self.mask_value), axis=-1)
def call(self, input_list):
to_output = input_list[0]
boolean_mask = array_ops.squeeze(K.any(
math_ops.not_equal(input_list[1], self.mask_value), axis=-1, keepdims=True),axis=-1)
dim =(input_list[0].shape[-1])
killer = math_ops.cast(tf.keras.backend.repeat_elements(tf.expand_dims(boolean_mask,axis=2), dim, axis=2),
to_output.dtype)
outputs = to_output * killer
outputs._keras_mask = boolean_mask
return outputs
def get_config(self):
config = {'mask_value': self.mask_value}
base_config = super(Reapply_Masking, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
我似乎能够保存/恢复模型,但只能使用.h5格式和custom_objects。