Ну, я думаю, что лучше преобразовать ваши данные в (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, чтобы сделать его 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 относится к числу желаемых меток, которые мы хотим предсказать для местоположения на каждом временном шаге.
Дополнительные примечания:
По мере увеличения количества слоев и параметров (т. Е. Модель становится глубже), вам может потребоваться решить такие проблемы, как исчезающий градиент (* 1035)* 1 , 2 ) и переоснащение ( 1 , 2 , 3 ).Одним из решений первого варианта является использование слоя BatchNormalization
сразу после каждого (обучаемого) уровня, чтобы обеспечить нормализацию данных, поступающих на следующий уровень.Для предотвращения переобучения вы можете использовать Dropout
слоев (и / или установить dropout
и recurrent_dropout
аргументов в LSTM
слоях).
Как вы можете видеть выше, я предположил, что мы передаем модели временную серию длиной 50. Это связано с этапом предварительной обработки данных, на котором вам нужно создать оконные обучающие (и тестовые) выборки из всей вашей (длинной)временных рядов и подавать их партиями в вашу модель для обучения.
Как я прокомментировал в коде, вы можете добавить несколько слоев LSTM друг на друга, чтобы увеличить репрезентативную способностьсеть.Но имейте в виду, что это может увеличить время обучения и сделать вашу модель (гораздо более) склонной к переобучению.Сделайте это, если у вас есть обоснованные причины для этого (т.е. вы экспериментировали с одним слоем LSTM и не получили хороших результатов).В качестве альтернативы вы можете использовать GRU
слоев вместо этого, но может быть компромисс между емкостью представления и вычислительными затратами (т. Е. Временем обучения) по сравнению со слоем LSTM.
Чтобы сделать выходную форму сети совместимой с формой ваших данных, вы можете использовать слой Dense
после слоя (ов) LSTM или настроить количество единиц последнего слоя LSTM.
Очевидно, что приведенный выше код только для демонстрации, и вам может понадобиться настроить его гиперпараметры (например, количество слоев, количество фильтров, размер ядра, используемый оптимизатор, функции активации и т. Д.) И эксперимент (много!) для получения окончательной рабочей модели с большой точностью.
Если вы тренируетесь на GPU, вы можете использовать CuDNNLSTM
(CuDNNGRU
) слой вместо LSTM
(GRU) для увеличения скорости обучения, поскольку он был оптимизирован для графических процессоров.
И не забудьте нормализовать тренировочные данные (этоочень важно и помогает трамного процесса).