我很难建立一个处理被掩盖的输入值的简单模型。我的训练数据包含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问题和大量的问答,但我不知道。
答案 0 :(得分:3)
遮罩似乎没有问题。但请放心: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)
答案 1 :(得分:1)
您可以使用全局池层,而不是使用Flatten
层。
这些适合折叠长度/时间维度,而不会失去使用可变长度的能力。
因此,您可以尝试使用Flatten()
或GlobalAveragePooling1D
来代替GlobalMaxPooling1D
。
他们中的任何人都没有在代码中使用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)