Muchos a uno y muchos a muchos ejemplos de LSTM en Keras

108

Intento entender los LSTM y cómo construirlos con Keras. Descubrí que existen principalmente los 4 modos para ejecutar un RNN (los 4 correctos en la imagen)

ingrese la descripción de la imagen aquí Fuente de la imagen: Andrej Karpathy

Ahora me pregunto cómo se vería un fragmento de código minimalista para cada uno de ellos en Keras. Entonces algo como

model = Sequential()
model.add(LSTM(128, input_shape=(timesteps, data_dim)))
model.add(Dense(1))

para cada una de las 4 tareas, quizás con un poco de explicación.

Luca Thiede
fuente

Respuestas:

121

Entonces:

  1. Uno a uno : podría usar una Densecapa ya que no está procesando secuencias:

    model.add(Dense(output_size, input_shape=input_shape))
  2. Uno a muchos : esta opción no se admite bien ya que encadenar modelos no es muy fácil Keras, por lo que la siguiente versión es la más sencilla:

    model.add(RepeatVector(number_of_times, input_shape=input_shape))
    model.add(LSTM(output_size, return_sequences=True))
  3. Muchos a uno : en realidad, su fragmento de código es (casi) un ejemplo de este enfoque:

    model = Sequential()
    model.add(LSTM(1, input_shape=(timesteps, data_dim)))
  4. Muchos a muchos : este es el fragmento más sencillo cuando la longitud de la entrada y la salida coincide con el número de pasos recurrentes:

    model = Sequential()
    model.add(LSTM(1, input_shape=(timesteps, data_dim), return_sequences=True))
  5. Muchos a muchos cuando el número de pasos difiere de la longitud de entrada / salida : esto es increíblemente difícil en Keras. No hay fragmentos de código fáciles para codificar eso.

EDITAR: Anuncio 5

En una de mis aplicaciones recientes, implementamos algo que podría ser similar a muchos a muchos de la cuarta imagen. En caso de que desee tener una red con la siguiente arquitectura (cuando una entrada es más larga que la salida):

                                        O O O
                                        | | |
                                  O O O O O O
                                  | | | | | | 
                                  O O O O O O

Puede lograr esto de la siguiente manera:

    model = Sequential()
    model.add(LSTM(1, input_shape=(timesteps, data_dim), return_sequences=True))
    model.add(Lambda(lambda x: x[:, -N:, :]

¿Dónde Nestá el número de últimos pasos que desea cubrir (en la imagen N = 3)?

Desde este punto llegar a:

                                        O O O
                                        | | |
                                  O O O O O O
                                  | | | 
                                  O O O 

es tan simple como una secuencia de relleno artificial de longitud Nusando, por ejemplo, con 0vectores, para ajustarlo a un tamaño apropiado.

Marcin Możejko
fuente
10
Una aclaración: por ejemplo, para muchos a uno, usa LSTM (1, input_shape = (timesteps, data_dim))) Pensé que el 1 representa el número de celdas LSTM / nodos ocultos, pero aparentemente no ¿Cómo codificaría un Many- a uno con, digamos, 512 nodos sin embargo, ¿qué? (Debido a que leí algo similar, pensé que se haría con model.add (LSTM (512, input_shape = ...)) model.add (Dense (1)) ¿para qué se usa eso?)
Luca Thiede
1
En este caso, su código, después de corregir un error tipográfico debería estar bien.
Marcin Możejko
¿Por qué usamos RepeatVector y no un vector con la primera entrada 1 = 0 y todas las demás entradas = 0 (según la imagen de arriba, no hay ninguna entrada en los estados posteriores, y no siempre es la misma entrada, lo que Repeat Vector haría en mi entendimiento)
Luca Thiede
1
Si piensa detenidamente en esta imagen, es solo una presentación conceptual de una idea de uno a muchos . Todas estas unidades ocultas deben aceptar algo como entrada. Por lo tanto, podrían aceptar la misma entrada como entrada con la primera entrada igual a xy otra igual a 0. Pero, por otro lado, también podrían aceptar que lo mismo se xrepita muchas veces. Un enfoque diferente es encadenar modelos que son difíciles Keras. La opción que proporcioné es el caso más fácil de arquitectura de uno a muchos en Keras.
Marcin Możejko
Agradable ! Estoy pensando en usar LSTM N to N en una arquitectura GAN. Tendré un generador basado en LSTM. Le daré a este generador (como se usa en "Variable latente" en gans) la primera mitad de la serie de tiempo y este generador producirá la segunda mitad de la serie de tiempo. Luego combinaré las dos mitades (real y generada) para producir la entrada "falsa" para el gan. ¿Crees que usar el punto 4 de tu solución funcionará? o, en otras palabras, ¿es esta (solución 4) la forma correcta de hacer esto?
rjpg
6

Gran respuesta de @Marcin Możejko

Me gustaría añadir lo siguiente a NR.5 (muchos a muchos con diferentes in / out longitud):

A) como Vanilla LSTM

model = Sequential()
model.add(LSTM(N_BLOCKS, input_shape=(N_INPUTS, N_FEATURES)))
model.add(Dense(N_OUTPUTS))

B) como Encoder-Decoder LSTM

model.add(LSTM(N_BLOCKS, input_shape=(N_INPUTS, N_FEATURES))  
model.add(RepeatVector(N_OUTPUTS))
model.add(LSTM(N_BLOCKS, return_sequences=True))  
model.add(TimeDistributed(Dense(1)))
model.add(Activation('linear')) 
gustavz
fuente
1
¿Podría explicar los detalles de la B) Encoder-Decoder LSTMarquitectura? Tengo problemas para comprender las funciones de los pasos "RepeatVector" / "TimeDistributed".
Marsellus Wallace