Keras: изменить форму, чтобы соединить lstm и conv

Этот вопрос также существует как проблема github. Я хотел бы построить нейронную сеть в Керасе, которая содержит как двумерные свертки, так и слой LSTM.

Сеть должна классифицировать MNIST. Обучающие данные в MNIST представляют собой 60000 полутоновых изображений рукописных цифр от 0 до 9. Каждое изображение имеет размер 28x28 пикселей.

Я разделил изображения на четыре части (влево / вправо, вверх / вниз) и переставил их в четыре порядка, чтобы получить последовательности для LSTM.

|     |      |1 | 2|
|image|  ->  -------   -> 4 sequences: |1|2|3|4|,  |4|3|2|1|, |1|3|2|4|, |4|2|3|1|
|     |      |3 | 4|

Одно из маленьких подизображений имеет размер 14 x 14. Четыре последовательности сгруппированы по ширине (не имеет значения, ширина или высота).

Это создает вектор с формой [60000, 4, 1, 56, 14] где:

  • 60000 это количество образцов
  • 4 - количество элементов в последовательности (количество временных шагов)
  • 1 - глубина цвета (оттенки серого)
  • 56 и 14 ширина и высота

Теперь это должно быть дано модели Кераса. Проблема состоит в том, чтобы изменить входные размеры между CNN и LSTM. Я искал в Интернете и нашел этот вопрос: Python keras, как изменить размер ввода после слоя свертки в слой lstm

Решением кажется слой Reshape, который выравнивает изображение, но сохраняет временные шаги (в отличие от слоя Flatten, который разрушит все, кроме batch_size).

Вот мой код до сих пор:

nb_filters=32
kernel_size=(3,3)
pool_size=(2,2)
nb_classes=10
batch_size=64

model=Sequential()

model.add(Convolution2D(nb_filters, kernel_size[0], kernel_size[1],
    border_mode="valid", input_shape=[1,56,14]))
model.add(Activation("relu"))
model.add(Convolution2D(nb_filters, kernel_size[0], kernel_size[1]))
model.add(Activation("relu"))
model.add(MaxPooling2D(pool_size=pool_size))


model.add(Reshape((56*14,)))
model.add(Dropout(0.25))
model.add(LSTM(5))
model.add(Dense(50))
model.add(Dense(nb_classes))
model.add(Activation("softmax"))

Этот код создает сообщение об ошибке:

ValueError: общий размер нового массива должен быть неизменным

Видимо, ввод в слой Reshape неправильный. В качестве альтернативы я также попытался передать временные шаги слою Reshape:

model.add(Reshape((4,56*14)))

Это не правильно и в любом случае ошибка остается прежней.

Я делаю это правильно? Является ли слой Reshape подходящим инструментом для соединения CNN и LSTM?

Есть довольно сложные подходы к этой проблеме. Например: https://github.com/fchollet/keras/pull/1456 Слой TimeDistributed, который, кажется, скрывает измерение временного шага от следующих слоев.

Или это: https://github.com/anayebi/keras-extra Набор специальных слоев для объединения CNN и LSTM.

Почему существуют такие сложные (по крайней мере, мне кажутся сложными) решения, если простая Reshape добивается цели?

ОБНОВЛЕНИЕ:

Смущающе, я забыл, что размеры будут меняться в результате объединения и (из-за отсутствия заполнения) сверток тоже. кгрм посоветовал мне использовать model.summary() проверить размеры.

Выход слоя перед слоем Reshape (None, 32, 26, 5)Я изменил форму: model.add(Reshape((32*26*5,))),

Теперь ошибка ValueError исчезла, вместо этого LSTM жалуется:

Исключение: вход 0 несовместим со слоем lstm_5: ожидаемый ndim=3, найденный ndim=2

Кажется, мне нужно передать измерение временного шага по всей сети. Как я могу это сделать? Если я добавлю его в input_shape в Convolution, он тоже будет жаловаться: Convolution2D(nb_filters, kernel_size[0], kernel_size[1], border_mode="valid", input_shape=[4, 1, 56,14])

Исключение: вход 0 несовместим со сверточным слоем2d_44: ожидаемый ndim=4, найденный ndim=5

1 ответ

Решение

Согласно определению Convolution2D, ваш ввод должен быть четырехмерным с размерами (samples, channels, rows, cols), Это прямая причина, почему вы получаете ошибку.

Чтобы решить эту проблему, вы должны использовать оболочку TimeDistributed. Это позволяет вам использовать статические (не повторяющиеся) слои во времени.

Другие вопросы по тегам