Керас: Как сформировать входные данные для слоев CNN и LSTM? - PullRequest
0 голосов
/ 28 сентября 2018

Я строю модель для прогнозирования геопространственно-временных наборов данных.

Мои данные имеют исходные размеры (объекты, широта, долгота, время), то есть для каждого объекта и в каждой точке широты / долготы естьвременные ряды.

Я создал модель CNN-LSTM с использованием Keras, например, так (я полагаю, что ниже необходимо изменить, это только первая попытка):

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

Может кто-нибудь посоветовать, как мне лучше сформировать своюданные для ввода и / или как структурировать слои модели таким образом, который наиболее подходит для этого приложения?Заранее спасибо ...

1 Ответ

0 голосов
/ 29 сентября 2018

Ну, я думаю, что лучше преобразовать ваши данные в (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) для увеличения скорости обучения, поскольку он был оптимизирован для графических процессоров.

  • И не забудьте нормализовать тренировочные данные (этоочень важно и помогает трамного процесса).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...