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
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)
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.
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)
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
).
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)