LSTM Autoencoder

Estoy tratando de construir un autocodificador LSTM con el objective de obtener un vector de tamaño fijo a partir de una secuencia, que representa la secuencia lo mejor posible. Este autoencoder consta de dos partes:

  • Codificador LSTM : toma una secuencia y devuelve un vector de salida ( return_sequences = False )
  • Decodificador LSTM : toma un vector de salida y devuelve una secuencia ( return_sequences = True )

Entonces, al final, el codificador es un LSTM de muchos a uno y el decodificador es un LSTM de uno a muchos .

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

En un nivel alto, la encoding se ve así (similar a lo descrito aquí ):

 encoder = Model(...) decoder = Model(...) autoencoder = Model(encoder.inputs, decoder(encoder(encoder.inputs))) autoencoder.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) autoencoder.fit(data, data, batch_size=100, epochs=1500) 

La forma (número de ejemplos de entrenamiento, longitud de secuencia, dimensión de entrada) de la matriz de data es (1200, 10, 5) y se ve así:

 array([[[1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0], ..., [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]], ... ] 

Problema: no estoy seguro de cómo proceder, especialmente cómo integrar LSTM al Model y cómo hacer que el decodificador genere una secuencia a partir de un vector.

Estoy usando keras con backend tensorflow .

EDITAR: Si alguien quiere probar, aquí está mi procedimiento para generar secuencias aleatorias con secuencias en movimiento (incluido el relleno):

 import random import math def getNotSoRandomList(x): rlen = 8 rlist = [0 for x in range(rlen)] if x <= 7: rlist[x] = 1 return rlist sequence = [[getNotSoRandomList(x) for x in range(round(random.uniform(0, 10)))] for y in range(5000)] ### Padding afterwards from keras.preprocessing import sequence as seq data = seq.pad_sequences( sequences = sequence, padding='post', maxlen=None, truncating='post', value=0. ) 

Los modelos pueden ser de la manera que quieras. Si lo entendí bien, ¿solo quieres saber cómo crear modelos con LSTM?

Usando LSTMs

Bueno, primero, tienes que definir cómo se ve tu vector codificado. Supongamos que desea que sea una matriz de 20 elementos, un vector de 1 dimensión. Por lo tanto, la forma (Ninguno, 20). El tamaño depende de usted, y no hay una regla clara para saber cuál es la ideal.

Y su entrada debe ser tridimensional, como su (1200,10,5). En los resúmenes de keras y los mensajes de error, se mostrará como (Ninguno, 10,5), ya que “Ninguno” representa el tamaño del lote, que puede variar cada vez que entrene / prediga.

Hay muchas formas de hacer esto, pero, supongamos que solo desea una capa LSTM:

 from keras.layers import * from keras.models import Model inpE = Input((10,5)) #here, you don't define the batch size outE = LSTM(units = 20, return_sequences=False, ...optional parameters...)(inpE) 

Esto es suficiente para un codificador muy simple que da como resultado una matriz con 20 elementos (pero puede astackr más capas si lo desea). Vamos a crear el modelo:

 encoder = Model(inpE,outE) 

Ahora, para el decodificador, se vuelve oscuro. Ya no tiene una secuencia real, sino un vector significativo estático. Es posible que desee utilizar LTSM, supondrán que el vector es una secuencia.

Pero aquí, como la entrada tiene forma (Ninguna, 20), primero debe volver a darle forma a una matriz tridimensional para adjuntar una capa LSTM a continuación.

La forma en que lo reformes es totalmente tuya. 20 pasos de 1 elemento? 1 paso de 20 elementos? 10 pasos de 2 elementos? ¿Quién sabe?

 inpD = Input((20,)) outD = Reshape((10,2))(inpD) #supposing 10 steps of 2 elements 

Es importante tener en cuenta que si ya no tiene 10 pasos, no podrá habilitar simplemente “return_sequences” y obtener la salida que desea. Tendrás que trabajar un poco. En realidad, no es necesario usar “return_sequences” o incluso usar LSTM, pero puede hacerlo.

Como en mi remodelación tengo 10 pasos de tiempo (intencionalmente), estará bien usar “return_sequences”, porque el resultado tendrá 10 pasos de tiempo (como entrada inicial)

 outD1 = LSTM(5,return_sequences=True,...optional parameters...)(outD) #5 cells because we want a (None,10,5) vector. 

Podría trabajar de muchas otras formas, como simplemente crear un LSTM de 50 celdas sin devolver secuencias y luego remodelar el resultado:

 alternativeOut = LSTM(50,return_sequences=False,...)(outD) alternativeOut = Reshape((10,5))(alternativeOut) 

Y nuestro modelo va:

 decoder = Model(inpD,outD1) alternativeDecoder = Model(inpD,alternativeOut) 

Después de eso, unes los modelos con tu código y entrenas el codificador automático. Los tres modelos tendrán los mismos pesos, por lo que puede hacer que el codificador traiga resultados simplemente usando su método de predict .

 encoderPredictions = encoder.predict(data) 

Lo que a menudo veo sobre los LSTM para generar secuencias es algo así como predecir el siguiente elemento.

Toma solo algunos elementos de la secuencia y trata de encontrar el siguiente elemento. Y tomas otro segmento un paso adelante y así sucesivamente. Esto puede ser útil para generar secuencias.

Puede encontrar un codificador automático de secuencia a secuencia simple aquí: https://blog.keras.io/building-autoencoders-in-keras.html