Comprensión de Keras LSTMs


Estoy tratando de reconciliar mi comprensión de LSTMs y señalado aquí en este post de Christopher Olah implementado en Keras. Estoy siguiendo el blog escrito por Jason Brownlee para el tutorial de Keras. Lo que más me confunde es,

  1. la remodelación de La serie de datos en [samples, time steps, features] y
  2. Los LSTMs con estado

Vamos a concentrarnos en las dos preguntas anteriores con referencia al código pegado a continuación:

# reshape into X=t and Y=t+1
look_back = 3
trainX, trainY = create_dataset(train, look_back)
testX, testY = create_dataset(test, look_back)

# reshape input to be [samples, time steps, features]
trainX = numpy.reshape(trainX, (trainX.shape[0], look_back, 1))
testX = numpy.reshape(testX, (testX.shape[0], look_back, 1))
########################
# The IMPORTANT BIT
##########################
# create and fit the LSTM network
batch_size = 1
model = Sequential()
model.add(LSTM(4, batch_input_shape=(batch_size, look_back, 1), stateful=True))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
for i in range(100):
    model.fit(trainX, trainY, nb_epoch=1, batch_size=batch_size, verbose=2, shuffle=False)
    model.reset_states()

Nota: create_dataset toma una secuencia de longitud N y devuelve una matriz N-look_back de la cual cada elemento es una secuencia de longitud look_back.

¿Qué es Time Steps y Features?

Como se puede ver, TrainX es una matriz 3-D con Time_steps y Feature siendo las dos últimas dimensiones respectivamente (3 y 1 en este código en particular). Con respecto a la imagen de abajo, ¿significa esto que estamos considerando el caso many to one, donde el número de cajas rosadas son 3? O significa literalmente que la longitud de la cadena es 3 (es decir, solo se consideran 3 recuadros verdes). introduzca la descripción de la imagen aquí

¿El argumento features se vuelve relevante cuando consideramos series multivariantes? por ejemplo, modelando dos acciones financieras simultáneamente?

LSTMs con estado

¿Significa LSTMs con estado que guardamos los valores de memoria de la celda entre tiradas de lotes? Si este es el caso, batch_size es uno, y la memoria se restablece entre las carreras de entrenamiento, así que cuál era el punto de decir que era con estado. Supongo que esto está relacionado al hecho de que los datos de entrenamiento no se barajan, pero no estoy seguro de cómo.

¿Algún pensamiento? Referencia de la imagen: http://karpathy.github.io/2015/05/21/rnn-effectiveness /

Editar 1: {[42]]}

Un poco confundido sobre el comentario de @van acerca de que las cajas rojas y verdes son iguales. Así que solo para confirmar, ¿las siguientes llamadas a la API corresponden a los diagramas desenrollados? Especialmente teniendo en cuenta el segundo diagrama (batch_size fue arbitrariamente escoger.): introduzca la descripción de la imagen aquí introduzca la descripción de la imagen aquí

Editar 2: {[42]]}

Para las personas que han hecho el curso de aprendizaje profundo de Udacity y todavía están confundidas sobre el argumento time_step, mire la siguiente discusión: https://discussions.udacity.com/t/rnn-lstm-use-implementation/163169

Actualización:

Resulta que model.add(TimeDistributed(Dense(vocab_len))) era lo que estaba buscando. He aquí un ejemplo: https://github.com/sachinruk/ShakespeareBot

Actualización 2:

Tengo resumí la mayor parte de mi comprensión de LSTMs aquí: https://www.youtube.com/watch?v=ywinX5wgdEU

Author: Sachin_ruk, 2016-08-02

3 answers

En primer lugar, usted elige grandes tutoriales(1,2) para empezar.

Qué significa Time-step: Time-steps==3 en X. shape (Que describe la forma de datos) significa que hay tres cajas rosadas. Dado que en Keras cada paso requiere una entrada, por lo tanto el número de las cajas verdes debería ser igual al número de cajas rojas. A menos que hackees la estructura.

Muchos a muchos vs. muchos a uno: En keras, hay un parámetro return_sequences cuando inicializa LSTM o GRU o SimpleRNN. Cuando return_sequences es False (por defecto), entonces es muchos a uno, como se muestra en la imagen. Su forma de retorno es (batch_size, hidden_unit_length), que representan el último estado. Cuando return_sequences es True, entonces es muchos a muchos. Su forma de retorno es (batch_size, time_step, hidden_unit_length)

El argumento features se vuelve relevante : El argumento Feature significa "Qué tamaño tiene su caja roja" o cuál es la dimensión de entrada en cada paso. Si desea predecir, por ejemplo, 8 tipos de información de mercado, entonces puede generar sus datos con feature==8.

Con estado : Puede buscar el código fuente. Al inicializar el estado, si stateful==True, entonces el estado del último entrenamiento se utilizará como el estado inicial, de lo contrario generará un nuevo estado. Todavía no he encendido stateful. Sin embargo, no estoy de acuerdo con que el batch_size solo puede ser 1 cuando stateful==True.

Actualmente, genera sus datos con los datos recopilados. Imagen su información de stock viene como corriente, en lugar de esperando un día para recopilar todos los datos secuenciales, le gustaría generar datos de entrada en línea mientras entrena/predice con la red. Si tiene 400 acciones que comparten una misma red, puede configurar batch_size==400.

 89
Author: Van,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-03 08:09:59

Como complemento a la respuesta aceptada, esta respuesta muestra los comportamientos de keras y cómo lograr cada imagen.

Comportamiento general de Keras

El procesamiento interno estándar de keras es siempre un muchos a muchos como en la siguiente imagen (donde utilicé features=2, presión y temperatura, solo como ejemplo):

ManyToMany

En esta imagen, aumenté el número de pasos a 5, para evitar confusiones con las otras dimensiones.

Para esto ejemplo:

  • Tenemos N tanques de aceite
  • Pasamos 5 horas tomando medidas cada hora (pasos de tiempo)
  • Medimos dos características:
    • Presión P
    • Temperatura T

Nuestra matriz de entrada debería entonces tener la forma de (N,5,2):

        [     Step1      Step2      Step3      Step4      Step5
Tank A:    [[Pa1,Ta1], [Pa2,Ta2], [Pa3,Ta3], [Pa4,Ta4], [Pa5,Ta5]],
Tank B:    [[Pb1,Tb1], [Pb2,Tb2], [Pb3,Tb3], [Pb4,Tb4], [Pb5,Tb5]],
  ....
Tank N:    [[Pn1,Tn1], [Pn2,Tn2], [Pn3,Tn3], [Pn4,Tn4], [Pn5,Tn5]],
        ]

Entradas para ventanas correderas

A menudo, se supone que las capas LSTM procesan las secuencias completas. Dividir ventanas puede no ser la mejor idea. La capa tiene interna afirma cómo una secuencia está evolucionando a medida que avanza. Windows elimina la posibilidad de aprender secuencias largas, limitando todas las secuencias al tamaño de la ventana.

En windows, cada ventana es parte de una larga secuencia original, pero por Keras se verán cada una como una secuencia independiente:

        [     Step1    Step2    Step3    Step4    Step5
Window  A:  [[P1,T1], [P2,T2], [P3,T3], [P4,T4], [P5,T5]],
Window  B:  [[P2,T2], [P3,T3], [P4,T4], [P5,T5], [P6,T6]],
Window  C:  [[P3,T3], [P4,T4], [P5,T5], [P6,T6], [P7,T7]],
  ....
        ]

Observe que en este caso, inicialmente solo tiene una secuencia, pero la está dividiendo en muchas secuencias para crear ventanas.

El concepto de " ¿qué es un secuencia " es abstracta. Las partes importantes son:

  • puede tener lotes con muchas secuencias individuales
  • lo que hace que las secuencias sean secuencias es que evolucionan en pasos (generalmente pasos de tiempo)

Logrando cada caso con"capas simples"

Alcanzar el estándar de muchos a muchos:{[83]]}

StandardManyToMany

Puede lograr muchos a muchos con una capa LSTM simple, usando return_sequences=True:

outputs = LSTM(units, return_sequences=True)(inputs)

#output_shape -> (batch_size, steps, units)

Lograr que muchos uno:

Usando exactamente la misma capa, keras hará exactamente el mismo preprocesamiento interno, pero cuando use return_sequences=False (o simplemente ignore este argumento), keras descartará automáticamente los pasos anteriores al último:

ManyToOne

outputs = LSTM(units)(inputs)

#output_shape -> (batch_size, units) --> steps were discarded, only the last was returned

Logrando uno a muchos

Ahora bien, esto no es soportado solo por capas LSTM de keras. Tendrás que crear tu propia estrategia para multiplicar los pasos. Hay dos buenos enfoques:

  • Crear un entrada constante de varios pasos repitiendo un tensor
  • Use un stateful=True para tomar recurrentemente la salida de un paso y servirla como la entrada del siguiente paso (necesita output_features == input_features)

Uno a muchos con vector de repetición

Para ajustarse al comportamiento estándar de keras, necesitamos entradas en pasos, por lo que simplemente repetimos las entradas para la longitud que queremos:

Una vez que vuelva a comer

outputs = RepeatVector(steps)(inputs) #where inputs is (batch,features)
outputs = LSTM(units,return_sequences=True)(outputs)

#output_shape -> (batch_size, steps, units)

Entendiendo stateful = True

Ahora viene uno de los posibles usos de stateful=True (además de evitar cargar datos que no pueden caber en la memoria de su computadora a la vez)

Stateful nos permite introducir "partes" de las secuencias en etapas. La diferencia es:

  • En stateful=False, el segundo lote contiene secuencias completamente nuevas, independientes del primer lote
  • En stateful=True, el segundo lote continúa el primer lote, extendiendo las mismas secuencias.

Es como dividir las secuencias en windows también, con estos dos diferencias:

  • estas ventanas no se superponen!!
  • stateful=True verá estas ventanas conectadas como una sola secuencia larga

En stateful=True, cada nuevo lote se interpretará como si continuara el lote anterior (hasta que llame a model.reset_states()).

  • La secuencia 1 en el lote 2 continuará la secuencia 1 en el lote 1.
  • La secuencia 2 en el lote 2 continuará la secuencia 2 en el lote 1.
  • La secuencia n en el lote 2 continuará la secuencia n en lote 1.

Ejemplo de entradas, lote 1 contiene los pasos 1 y 2, lote 2 contiene los pasos 3 a 5:

                   BATCH 1                           BATCH 2
        [     Step1      Step2        |    [    Step3      Step4      Step5
Tank A:    [[Pa1,Ta1], [Pa2,Ta2],     |       [Pa3,Ta3], [Pa4,Ta4], [Pa5,Ta5]],
Tank B:    [[Pb1,Tb1], [Pb2,Tb2],     |       [Pb3,Tb3], [Pb4,Tb4], [Pb5,Tb5]],
  ....                                |
Tank N:    [[Pn1,Tn1], [Pn2,Tn2],     |       [Pn3,Tn3], [Pn4,Tn4], [Pn5,Tn5]],
        ]                                  ]

Observe la alineación de los tanques en el lote 1 y el lote 2! Es por eso que necesitamos shuffle=False (a menos que estemos usando solo una secuencia, por supuesto).

Puede tener cualquier número de lotes, indefinidamente. (Para tener longitudes variables en cada lote, use input_shape=(None,features).

Uno a muchos con stateful = True

Para nuestro caso aquí, vamos a usar solo 1 paso por lote, porque queremos obtener un paso de salida y hacer que sea una entrada.

Tenga en cuenta que el comportamiento en la imagen no es "causado por" stateful=True. Forzaremos ese comportamiento en un bucle manual a continuación. En este ejemplo, stateful=True es lo que nos "permite" detener la secuencia, manipular lo que queremos y continuar desde donde nos detuvimos.

UneToManyStateful

Honestamente, el enfoque de repetición es probablemente una mejor opción para este caso. Pero ya que estamos buscando stateful=True, este es un buen ejemplo. La mejor manera de usar esto es el siguiente caso de "muchos a muchos".

Capa:

outputs = LSTM(units=features, 
               stateful=True, 
               return_sequences=True, #just to keep a nice output shape even with length 1
               input_shape=(None,features))(inputs) 
    #units = features because we want to use the outputs as inputs
    #None because we want variable length

#output_shape -> (batch_size, steps, units) 

Ahora, vamos a necesitar un bucle manual para las predicciones:

input_data = someDataWithShape((batch, 1, features))

#important, we're starting new sequences, not continuing old ones:
model.reset_states()

output_sequence = []
last_step = input_data
for i in steps_to_predict:

    new_step = model.predict(last_step)
    output_sequence.append(new_step)
    last_step = new_step

 #end of the sequences
 model.reset_states()

Muchos a muchos con stateful = True{[83]]}

Ahora, aquí, tenemos una aplicación muy agradable: dada una secuencia de entrada, tratar de predecir sus futuros pasos desconocidos.

Estamos usando el mismo método que en el "uno a muchos" anterior, con la diferencia de que:

  • usaremos la secuencia en sí mismo para ser los datos objetivo, un paso por delante
  • conocemos parte de la secuencia (así que descartamos esta parte de los resultados).

Muchos histéricos

Capa (igual que la anterior):

outputs = LSTM(units=features, 
               stateful=True, 
               return_sequences=True, 
               input_shape=(None,features))(inputs) 
    #units = features because we want to use the outputs as inputs
    #None because we want variable length

#output_shape -> (batch_size, steps, units) 

Capacitación:

Vamos a entrenar a nuestro modelo para predecir el siguiente paso de las secuencias:{[34]]}

totalSequences = someSequencesShaped((batch, steps, features))
    #batch size is usually 1 in these cases (often you have only one Tank in the example)

X = totalSequences[:,:-1] #the entire known sequence, except the last step
Y = totalSequences[:,1:] #one step ahead of X

#loop for resetting states at the start/end of the sequences:
for epoch in range(epochs):
    model.reset_states()
    model.train_on_batch(X,Y)

Predicción:

La primera etapa de nuestra predicción implica "ajustar los estados". Por eso vamos a predecir la secuencia completa de nuevo, incluso si ya conocemos esta parte de ella:

model.reset_states() #starting a new sequence
predicted = model.predict(totalSequences)
firstNewStep = predicted[:,-1:] #the last step of the predictions is the first future step

Ahora vamos al bucle como en el caso de uno a muchos. Pero ¡no restablezcas los estados aquí!. Queremos que el modelo sepa en qué paso de la secuencia está (y sabe que está en el primer paso nuevo debido a la predicción que acabamos de hacer anteriormente)

output_sequence = [firstNewStep]
last_step = firstNewStep
for i in steps_to_predict:

    new_step = model.predict(last_step)
    output_sequence.append(new_step)
    last_step = new_step

 #end of the sequences
 model.reset_states()

Este enfoque se utilizó en estas respuestas y archivo:

Lograr configuraciones complejas

En todos los ejemplos anteriores, mostré el comportamiento de "una capa".

Por supuesto, puede apilar muchas capas una encima de la otra, no necesariamente todas siguiendo el mismo patrón, y crear sus propios modelos.

Uno un ejemplo interesante que ha estado apareciendo es el " autoencoder "que tiene un" codificador de muchos a uno "seguido de un decodificador de" uno a muchos":

Codificador:

inputs = Input((steps,features))

#a few many to many layers:
outputs = LSTM(hidden1,return_sequences=True)(inputs)
outputs = LSTM(hidden2,return_sequences=True)(outputs)    

#many to one layer:
outputs = LSTM(hidden3)(outputs)

encoder = Model(inputs,outputs)

Decodificador:

Usando el método" repetir";

inputs = Input((hidden3,))

#repeat to make one to many:
outputs = RepeatVector(steps)(inputs)

#a few many to many layers:
outputs = LSTM(hidden4,return_sequences=True)(outputs)

#last layer
outputs = LSTM(features,return_sequences=True)(outputs)

decoder = Model(inputs,outputs)

Autoencoder:

inputs = Input((steps,features))
outputs = encoder(inputs)
outputs = decoder(outputs)

autoencoder = Model(inputs,outputs)

Tren con fit(X,X)

 42
Author: Daniel Möller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-24 13:32:41

Cuando tiene return_sequences en su última capa de RNN, no puede usar una capa densa simple en lugar de usar TimeDistributed.

Aquí hay un ejemplo de código que podría ayudar a otros.

Palabras = keras.capas.Input (batch_shape=(None, self.maxSequenceLength), name = "input")

    # Build a matrix of size vocabularySize x EmbeddingDimension 
    # where each row corresponds to a "word embedding" vector.
    # This layer will convert replace each word-id with a word-vector of size Embedding Dimension.
    embeddings = keras.layers.embeddings.Embedding(self.vocabularySize, self.EmbeddingDimension,
        name = "embeddings")(words)
    # Pass the word-vectors to the LSTM layer.
    # We are setting the hidden-state size to 512.
    # The output will be batchSize x maxSequenceLength x hiddenStateSize
    hiddenStates = keras.layers.GRU(512, return_sequences = True, 
                                        input_shape=(self.maxSequenceLength,
                                        self.EmbeddingDimension),
                                        name = "rnn")(embeddings)
    hiddenStates2 = keras.layers.GRU(128, return_sequences = True, 
                                        input_shape=(self.maxSequenceLength, self.EmbeddingDimension),
                                        name = "rnn2")(hiddenStates)

    denseOutput = TimeDistributed(keras.layers.Dense(self.vocabularySize), 
        name = "linear")(hiddenStates2)
    predictions = TimeDistributed(keras.layers.Activation("softmax"), 
        name = "softmax")(denseOutput)  

    # Build the computational graph by specifying the input, and output of the network.
    model = keras.models.Model(input = words, output = predictions)
    # model.compile(loss='kullback_leibler_divergence', \
    model.compile(loss='sparse_categorical_crossentropy', \
        optimizer = keras.optimizers.Adam(lr=0.009, \
            beta_1=0.9,\
            beta_2=0.999, \
            epsilon=None, \
            decay=0.01, \
            amsgrad=False))
 0
Author: Sanjay Krishna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-25 09:05:36