Keras: Masking and Flattening Keras: Masking and Flattening python-3.x python-3.x

Keras: Masking and Flattening


Masking does seem bugged. But do not worry: the 0s are not going to make your model worse; at most less efficient.

I would recommend using a Convolutional approach instead of pure Dense or perhaps RNN. I think this will work really well for GPS data.

Please try the following code:

from keras.preprocessing.sequence import pad_sequencesfrom keras import Sequentialfrom keras.layers import Dense, Flatten, Masking, LSTM, GRU, Conv1D, Dropout, MaxPooling1Dimport numpy as npimport randommax_sequence_len = 70n_samples = 100num_coordinates = 2 # lat/longdata = [[[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)


Instead of using a Flatten layer, you could use a Global Pooling layer.

These are suited to collapse the length/time dimension without losing the capability of using variable lengths.

So, instead of Flatten(), you can try a GlobalAveragePooling1D or GlobalMaxPooling1D.

None of them use supports_masking in their code, so they must be used with care.

The average one will consider more inputs than the max (thus the values that should be masked).

The max will take only one from the length. With luck, if all your useful values are higher than the ones in the masked position, it will indirectly preserve the mask. It will probably need even more input neurons than the other.

That said, yes, try the Conv1D or RNN (LSTM) appoaches suggested.


Creating a custom pooling layer with mask

You can also create your own pooling layer (needs a functional API model where you pass both the model's inputs and the tensor which you want to pool)

Below, a working example with average pooling applying a mask based on the inputs:

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 innerFuncx = 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)