好吧,我认为最好将您的数据重塑为(time, lats, lons, features),即它是多通道(即特征)空间图的时间序列:
data = np.transpose(data, [3, 1, 2, 0])
然后您可以轻松地将Conv2D 和MaxPooling2D 层包裹在TimeDistributed 层中,以在每个时间步处理(多通道)地图:
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 层的组合来恢复原始地图的形状:
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 表示我们想要在每个时间步预测位置的所需标签的数量。
补充说明:
随着层数和参数的增加(即模型变得更深),您可能需要处理梯度消失(1、2)和过拟合(1、@ 987654324@,3)。前者的一种解决方案是在每个(可训练的)层之后使用BatchNormalization 层,以确保馈送到下一层的数据是标准化的。为防止过度拟合,您可以使用Dropout 层(和/或在LSTM 层中设置dropout 和recurrent_dropout 参数)。
正如您在上面看到的,我假设我们正在为模型提供长度为 50 的时间序列。这与数据预处理步骤有关,您需要从整个 ( long) 时间序列并将它们分批提供给您的模型进行训练。
正如我在代码中所评论的,您可以在彼此之上添加多个 LSTM 层以增加网络的表示能力。但请注意,它可能会增加训练时间,并使您的模型(更多)容易过度拟合。如果你有正当的理由(即你已经尝试了一个 LSTM 层但没有得到好的结果),那就这样做吧。或者,您可以改用GRU 层,但与 LSTM 层相比,表示容量和计算成本(即训练时间)之间可能存在折衷。
要使网络的输出形状与您的数据形状兼容,您可以在 LSTM 层之后使用Dense 层或调整最后一个 LSTM 层的单元数。
显然,上面的代码只是为了演示,你可能需要调整它的超参数(例如层数、过滤器数量、内核大小、使用的优化器、激活函数等)和实验(很多!) 以实现高精度的最终工作模型。
如果您在 GPU 上进行训练,则可以使用 CuDNNLSTM (CuDNNGRU) 层而不是 LSTM (GRU) 来提高训练速度,因为它已针对 GPU 进行了优化。
别忘了对训练数据进行标准化(这非常重要,对训练过程有很大帮助)。