在Keras LSTM自动编码器中重构消耗的序列掩码

时间:2020-05-17 02:13:05

标签: keras lstm tensorflow2.0

我正在设法解决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。

先谢谢您。

1 个答案:

答案 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。