我正在构建一个模型来预测地理时空数据集。
我的数据具有原始维度(特征、纬度、经度、时间),即对于每个特征和每个纬度/经度点都有一个时间序列。
我已经像这样使用 Keras 创建了一个 CNN-LSTM 模型(我假设下面需要修改,这只是第一次尝试):
def define_model_cnn_lstm(features, lats, lons, times):
"""
Create and return a model with CN and LSTM layers. Input and output data is
expected to have shape (lats, lons, times).
:param lats: latitude dimension of input 3-D array
:param lons: longitude dimension of input 3-D array
:param times: time dimension of input 3-D array
:return: CNN-LSTM model appropriate to the expected input array
"""
# define the CNN model layers, wrapping each CNN layer in a TimeDistributed layer
model = Sequential()
model.add(TimeDistributed(Conv2D(features, (3, 3),
activation='relu',
padding='same',
input_shape=(lats, lons, times))))
model.add(TimeDistributed(MaxPooling2D(pool_size=(2, 2))))
model.add(TimeDistributed(Flatten()))
# add the LSTM layer, and a final Dense layer
model.add(LSTM(units=times, activation='relu', stateful=True))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
return model
我的假设是该模型将采用具有形状(特征、纬度、经度、时间)的数据,例如,如果我的地理空间网格为 180 x 360 并且每个点有 100 个时间步长,并且每个观察点有 4 个特征/样本,那么形状将是 (4, 180, 360, 100)。
我假设我希望模型将具有形状(特征、纬度、经度、时间)的数组作为输入,并能够预测具有形状(标签、纬度、经度、时间)的标签数组作为输出。我首先使用单个变量作为我的标签,但稍后也能有多变量输出(即标签 > 1)可能会很有趣。
我应该如何最好地塑造我的输入数据,和/或如何以最适合此应用程序的方式构建模型层?
最佳答案
好吧,我认为最好将您的数据 reshape 为(time, lats, lons, features)
,即它是多 channel (即特征)空间图的时间序列:
data = np.transpose(data, [3, 1, 2, 0])
然后你就可以轻松地包装
Conv2D
和 MaxPooling2D
TimeDistributed
内的层在每个时间步处理(多 channel )映射的层:num_steps = 50
lats = 128
lons = 128
features = 4
out_feats = 3
model = Sequential()
model.add(TimeDistributed(Conv2D(16, (3, 3), activation='relu', padding='same'),
input_shape=(num_steps, lats, lons, features)))
model.add(TimeDistributed(MaxPooling2D(pool_size=(2, 2))))
model.add(TimeDistributed(Conv2D(32, (3, 3), activation='relu', padding='same')))
model.add(TimeDistributed(MaxPooling2D(pool_size=(2, 2))))
model.add(TimeDistributed(Conv2D(32, (3, 3), activation='relu', padding='same')))
model.add(TimeDistributed(MaxPooling2D(pool_size=(2, 2))))
到目前为止,我们将有一个形状为
(50, 16, 16, 32)
的张量.然后我们可以使用 Flatten
层(当然,包裹在 TimeDistributed
层中以免丢失时间轴)并将结果提供给一个或多个 LSTM 层(使用 return_sequence=True
以获取每个时间步的输出):model.add(TimeDistributed(Flatten()))
# you may stack multiple LSTM layers on top of each other here
model.add(LSTM(units=64, return_sequences=True))
然后我们需要回去。所以我们需要先将LSTM层的结果reshape成2D然后使用
UpSampling2D
的组合和 Conv2D
图层以恢复原始 map 的形状:model.add(TimeDistributed(Reshape((8, 8, 1))))
model.add(TimeDistributed(UpSampling2D((2,2))))
model.add(TimeDistributed(Conv2D(32, (3,3), activation='relu', padding='same')))
model.add(TimeDistributed(UpSampling2D((2,2))))
model.add(TimeDistributed(Conv2D(32, (3,3), activation='relu', padding='same')))
model.add(TimeDistributed(UpSampling2D((2,2))))
model.add(TimeDistributed(Conv2D(16, (3,3), activation='relu', padding='same')))
model.add(TimeDistributed(UpSampling2D((2,2))))
model.add(TimeDistributed(Conv2D(out_feats, (3,3), padding='same')))
这是模型摘要:
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
time_distributed_132 (TimeDi (None, 50, 128, 128, 16) 592
_________________________________________________________________
time_distributed_133 (TimeDi (None, 50, 64, 64, 16) 0
_________________________________________________________________
time_distributed_134 (TimeDi (None, 50, 64, 64, 32) 4640
_________________________________________________________________
time_distributed_135 (TimeDi (None, 50, 32, 32, 32) 0
_________________________________________________________________
time_distributed_136 (TimeDi (None, 50, 32, 32, 32) 9248
_________________________________________________________________
time_distributed_137 (TimeDi (None, 50, 16, 16, 32) 0
_________________________________________________________________
time_distributed_138 (TimeDi (None, 50, 8192) 0
_________________________________________________________________
lstm_13 (LSTM) (None, 50, 64) 2113792
_________________________________________________________________
time_distributed_139 (TimeDi (None, 50, 8, 8, 1) 0
_________________________________________________________________
time_distributed_140 (TimeDi (None, 50, 16, 16, 1) 0
_________________________________________________________________
time_distributed_141 (TimeDi (None, 50, 16, 16, 32) 320
_________________________________________________________________
time_distributed_142 (TimeDi (None, 50, 32, 32, 32) 0
_________________________________________________________________
time_distributed_143 (TimeDi (None, 50, 32, 32, 32) 9248
_________________________________________________________________
time_distributed_144 (TimeDi (None, 50, 64, 64, 32) 0
_________________________________________________________________
time_distributed_145 (TimeDi (None, 50, 64, 64, 16) 4624
_________________________________________________________________
time_distributed_146 (TimeDi (None, 50, 128, 128, 16) 0
_________________________________________________________________
time_distributed_147 (TimeDi (None, 50, 128, 128, 3) 435
=================================================================
Total params: 2,142,899
Trainable params: 2,142,899
Non-trainable params: 0
_________________________________________________________________
如您所见,我们有一个形状为
(50, 128, 128, 3)
的输出张量其中 3 是指我们想要在每个时间步预测位置的所需标签数量。补充说明:
BatchNormalization
紧接在每个(可训练的)层之后的层,以确保馈送到下一层的数据是规范化的。为了防止过度拟合,您可以使用 Dropout
层(和/或在 dropout
层中设置 recurrent_dropout
和 LSTM
参数)。 GRU
层,但与 LSTM 层相比,表示能力和计算成本(即训练时间)之间可能存在权衡。 Dense
LSTM 层之后的层或调整最后一个 LSTM 层的单元数。 CuDNNLSTM
( CuDNNGRU
) 层而不是 LSTM
(GRU) 以提高训练速度,因为它已针对 GPU 进行了优化。 关于python - Keras:如何为 CNN 和 LSTM 层塑造输入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52562133/