web-dev-qa-db-de.com

Keras: Maskieren und Abflachen

Ich habe Schwierigkeiten beim Erstellen eines einfachen Modells, das sich mit maskierten Eingabewerten befasst. Meine Trainingsdaten bestehen aus Listen variabler Länge von GPS-Spuren, d. H. Listen, bei denen jedes Element Breitengrad und Längengrad enthält.

Es gibt 70 Trainingsbeispiele 

 enter image description here

Da sie unterschiedliche Längen haben, fülle ich sie mit Nullen auf, mit dem Ziel, Keras darauf hinzuweisen, diese Nullwerte zu ignorieren.

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

 enter image description here

Ich baue dann so ein sehr grundlegendes Modell

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

Nach einigem Ausprobieren stellte ich fest, dass ich die Flatten-Schicht brauche, oder das Modell würde den Fehler auslösen

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

Durch das Einbeziehen dieser Flatten-Ebene kann ich jedoch keine Masking-Ebene verwenden (um die aufgefüllten Nullen zu ignorieren) oder Keras löst diesen Fehler aus

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

Ich habe ausführlich gesucht, GitHub-Probleme gelesen und viel Q/A hier gelesen, aber ich kann es nicht verstehen. 

6
Philip O'Brien

Maskierung scheint abgehört zu sein. Aber keine Sorge: Die Nullen werden Ihr Modell nicht verschlimmern. höchstens weniger effizient.

Ich würde empfehlen, einen Convolutional-Ansatz anstelle von Pure Dense oder RNN zu verwenden. Ich denke, das wird für GPS-Daten sehr gut funktionieren.

Bitte versuchen Sie den folgenden Code:

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)
2
PascalVKooten

Anstelle einer Flatten-Ebene können Sie auch eine Global Pooling -Ebene verwenden. 

Diese sind geeignet, um die Längen-/Zeitdimension zu reduzieren, ohne die Fähigkeit zur Verwendung variabler Längen zu verlieren. 

Anstelle von Flatten() können Sie also einen GlobalAveragePooling1D oder GlobalMaxPooling1D ausprobieren.

Keiner von ihnen verwendet supports_masking in ihrem Code, daher müssen sie mit Vorsicht verwendet werden.

Der Durchschnitt berücksichtigt mehr Eingänge als den Maximalwert (daher die Werte, die maskiert werden sollen). 

Das Maximum nimmt nur einen von der Länge an. Wenn alle Ihre nützlichen Werte höher sind als die Werte in der maskierten Position, wird die Maske indirekt beibehalten. Es wird wahrscheinlich noch mehr Eingangsneuronen als die anderen benötigen.

Ja, probieren Sie die vorgeschlagenen Ansätze Conv1D oder RNN (LSTM). 


Erstellen einer benutzerdefinierten Pooling-Ebene mit Maske

Sie können auch Ihre eigene Pooling-Schicht erstellen (benötigt ein funktionales API-Modell, bei dem Sie sowohl die Eingaben des Modells als auch den Tensor übergeben, den Sie bündeln möchten.)

Nachfolgend ein Arbeitsbeispiel mit durchschnittlichem Pooling, bei dem eine Maske basierend auf den Eingaben angewendet wird: 

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)
1
Daniel Möller