Keras: remodelar para conectar lstm e conv
Esta questão existe como umquestão do github , também. Gostaria de construir uma rede neural em Keras que contenha convoluções 2D e uma camada LSTM.
A rede deve classificar MNIST. Os dados de treinamento no MNIST são 60000 imagens em escala de cinza de dígitos manuscritos de 0 a 9. Cada imagem tem 28x28 pixels.
Dividei as imagens em quatro partes (esquerda / direita, cima / baixo) e as reorganizei em quatro ordens para obter seqüências para o LSTM.
| | |1 | 2|
|image| -> ------- -> 4 sequences: |1|2|3|4|, |4|3|2|1|, |1|3|2|4|, |4|2|3|1|
| | |3 | 4|
Uma das sub-imagens pequenas tem a dimensão 14 x 14. As quatro seqüências são empilhadas juntas ao longo da largura (não importa se a largura ou a altura).
Isso cria um vetor com a forma [60000, 4, 1, 56, 14] em que:
60000 é o número de amostras4 é o número de elementos em uma sequência (# de timesteps)1 é a profundidade das cores (escala de cinza)56 e 14 são largura e alturaAgora isso deve ser dado ao modelo Keras. O problema é alterar as dimensões de entrada entre a CNN e o LSTM. Pesquisei online e encontrei esta pergunta:Python keras como alterar o tamanho da entrada após a camada de convolução na camada lstm
A solução parece ser uma camada de Remodelagem, que nivela a imagem, mas mantém os timestados (em oposição a uma camada de Achatamento, que retraía tudo, exceto o tamanho do lote).
Aqui está o meu código até agora:
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"))
Este código cria uma mensagem de erro:
ValueError: o tamanho total da nova matriz deve ser inalterado
Aparentemente, a entrada para a camada Remodelar está incorreta. Como alternativa, tentei passar os timesteps para a camada Remodelar também:
model.add(Reshape((4,56*14)))
Isso não parece certo e, em qualquer caso, o erro permanece o mesmo.
Estou fazendo isso da maneira certa? Uma camada Remodelar é a ferramenta adequada para conectar CNN e LSTM?
Existem abordagens bastante complexas para esse problema. Tal como este:https://github.com/fchollet/keras/pull/1456 Uma camada TimeDistributed que parece ocultar a dimensão timestep das seguintes camadas.
Ou isto:https://github.com/anayebi/keras-extra Um conjunto de camadas especiais para combinar CNNs e LSTMs.
Por que existem soluções tão complicadas (pelo menos elas me parecem complicadas), se uma simples Remodelagem faz o truque?
ATUALIZAR:
De maneira vergonhosa, esqueci que as dimensões serão alteradas pelo pool e (por falta de preenchimento) as convoluções também.kgrm me aconselhou a usarmodel.summary()
para verificar as dimensões.
A saída da camada antes da camada Remodelar é(None, 32, 26, 5)
, Alterei a remodelagem para:model.add(Reshape((32*26*5,)))
.
Agora o ValueError se foi, em vez disso, o LSTM reclama:
Exceção: A entrada 0 é incompatível com a camada lstm_5: esperado ndim = 3, encontrado ndim = 2
Parece que preciso passar a dimensão timestep por toda a rede. Como eu posso fazer isso ? Se eu adicioná-lo ao input_shape da Convolução, ele também reclama:Convolution2D(nb_filters, kernel_size[0], kernel_size[1], border_mode="valid", input_shape=[4, 1, 56,14])
Exceção: A entrada 0 é incompatível com a camada convolution2d_44: esperado ndim = 4, encontrado ndim = 5