【问题标题】:Keras: Masking and FlatteningKeras:掩蔽和展平
【发布时间】:2019-01-20 09:30:30
【问题描述】:

我很难构建一个处理屏蔽输入值的简单模型。我的训练数据由可变长度的 GPS 轨迹列表组成,即每个元素包含纬度和经度的列表。

有70个训练样例

由于它们的长度可变,我用零填充它们,目的是告诉 Keras 忽略这些零值。

train_data = keras.preprocessing.sequence.pad_sequences(train_data, maxlen=max_sequence_len, dtype='float32', 
                                           padding='pre', truncating='pre', value=0)

然后我像这样构建一个非常基本的模型

model = Sequential()
model.add(Dense(16, activation='relu',input_shape=(max_sequence_len, 2)))
model.add(Flatten())
model.add(Dense(2, activation='sigmoid'))

在之前的一些尝试和错误之后,我意识到我需要Flatten 层,否则拟合模型会引发错误

ValueError: Error when checking target: expected dense_87 to have 3 dimensions, but got array with shape (70, 2)

但是,通过包含 Flatten 层,我不能使用 Masking 层(忽略填充的零),否则 Keras 会抛出此错误

TypeError: Layer flatten_31 does not support masking, but was passed an input_mask: Tensor("masking_9/Any_1:0", shape=(?, 48278), dtype=bool)

我已经广泛搜索,在这里阅读 GitHub 问题和大量 Q/A,但我无法弄清楚。

【问题讨论】:

    标签: python python-3.x tensorflow keras deep-learning


    【解决方案1】:

    掩蔽似乎确实有问题。但别担心:0 不会让你的模型变得更糟;最多效率低下。

    我建议使用卷积方法而不是纯 Dense 或 RNN。我认为这对 GPS 数据非常有效。

    请尝试以下代码:

    from keras.preprocessing.sequence import pad_sequences
    from keras import Sequential
    from keras.layers import Dense, Flatten, Masking, LSTM, GRU, Conv1D, Dropout, MaxPooling1D
    import numpy as np
    import random
    
    max_sequence_len = 70
    
    n_samples = 100
    num_coordinates = 2 # lat/long
    
    data = [[[random.random() for _ in range(num_coordinates)]
             for y in range(min(x, max_sequence_len))]
            for x in range(n_samples)]
    
    train_y = np.random.random((n_samples, 2))
    
    train_data = pad_sequences(data, maxlen=max_sequence_len, dtype='float32',
                               padding='pre', truncating='pre', value=0)
    
    model = Sequential()
    model.add(Conv1D(32, (5, ), input_shape=(max_sequence_len, num_coordinates)))
    model.add(Dropout(0.5))
    model.add(MaxPooling1D())
    model.add(Flatten())
    model.add(Dense(2, activation='relu'))
    model.compile(loss='mean_squared_error', optimizer="adam")
    model.fit(train_data, train_y)
    

    【讨论】:

    • 感谢您的示例。不幸的是,它并没有提高我的准确性,但这很可能是我的数据中的一个错误。我注意到我的 max_sequence_len (198720) 和 min_sequence_len (3!!) 存在巨大差异,所以这显然是一个问题
    • @PhilipO'Brien 不用担心,可以理解!我建议只取序列的前几个部分和最后一个部分,比如 200 个部分。还包括序列长度的数字。这应该有帮助!
    【解决方案2】:

    您可以使用 全局池 层,而不是使用 Flatten 层。

    这些适用于折叠长度/时间维度,而不会失去使用可变长度的能力。

    因此,您可以尝试GlobalAveragePooling1DGlobalMaxPooling1D,而不是Flatten()

    他们都没有在代码中使用supports_masking,因此必须小心使用。

    平均值会考虑比最大值更多的输入(因此应该屏蔽的值)。

    最大值将只取长度中的一个。幸运的是,如果您所有的有用值都高于掩码位置的值,它将间接保留掩码。它可能需要比其他更多的输入神经元。

    也就是说,是的,请尝试建议的 Conv1D 或 RNN (LSTM) 方法。


    使用掩码创建自定义池化层

    您还可以创建自己的池化层(需要一个功能性 API 模型,您可以在其中传递模型的输入和要池化的张量)

    下面是一个基于输入应用掩码的平均池化示例:

    def customPooling(maskVal):
        def innerFunc(x):
            inputs = x[0]
            target = x[1]
    
            #getting the mask by observing the model's inputs
            mask = K.equal(inputs, maskVal)
            mask = K.all(mask, axis=-1, keepdims=True)
    
            #inverting the mask for getting the valid steps for each sample
            mask = 1 - K.cast(mask, K.floatx())
    
            #summing the valid steps for each sample
            stepsPerSample = K.sum(mask, axis=1, keepdims=False)
    
            #applying the mask to the target (to make sure you are summing zeros below)
            target = target * mask
    
            #calculating the mean of the steps (using our sum of valid steps as averager)
            means = K.sum(target, axis=1, keepdims=False) / stepsPerSample
    
            return means
    
        return innerFunc
    
    
    x = np.ones((2,5,3))
    x[0,3:] = 0.
    x[1,1:] = 0.
    
    
    print(x)
    
    inputs = Input((5,3))
    out = Lambda(lambda x: x*4)(inputs)
    out = Lambda(customPooling(0))([inputs,out])
    
    model = Model(inputs,out)
    model.predict(x)
    

    【讨论】:

    • 感谢真正有用的解释。真的很难决定奖励赏金的答案,但我觉得 PascalVKooten 只是在直接适用于我的问题方面掩盖了它。
    猜你喜欢
    • 2017-01-23
    • 1970-01-01
    • 1970-01-01
    • 2017-07-10
    • 1970-01-01
    • 1970-01-01
    • 2018-07-29
    • 2017-12-07
    • 2017-02-23
    相关资源
    最近更新 更多