Estoy tratando de conciliar mi comprensión de los LSTM y lo señalé aquí en esta publicación 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,
- La remodelación de la serie de datos en
[samples, time steps, features]
y, - Los LSTM 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 N-look_back
matriz de la cual cada elemento es una look_back
secuencia de longitud.
¿Qué son los pasos de tiempo y las características?
Como se puede ver, TrainX es una matriz tridimensional 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 a continuación, ¿significa esto que estamos considerando el many to one
caso, donde el número de cajas rosadas es 3? ¿O significa literalmente que la longitud de la cadena es 3 (es decir, solo se consideran 3 casillas verdes)?
¿El argumento de las características se vuelve relevante cuando consideramos series multivariadas? por ejemplo, modelar dos acciones financieras simultáneamente?
LSTM con estado
¿Los LSTM con estado significan que guardamos los valores de memoria de la celda entre ejecuciones de lotes? Si este es el caso, batch_size
es uno, y la memoria se restablece entre las sesiones de entrenamiento, entonces, ¿cuál era el punto de decir que tenía estado? Supongo que esto está relacionado con el hecho de que los datos de entrenamiento no se mezclan, pero no estoy seguro de cómo hacerlo.
¿Alguna idea? Referencia de la imagen: http://karpathy.github.io/2015/05/21/rnn-effectiveness/
Editar 1:
Un poco confundido sobre el comentario de @ van sobre las cajas rojas y verdes que son iguales. Entonces, para confirmar, ¿las siguientes llamadas a la API corresponden a los diagramas desenrollados? Especialmente observando el segundo diagrama ( batch_size
fue elegido arbitrariamente):
Edición 2:
Para las personas que han realizado el curso de aprendizaje profundo de Udacity y aún están confundidos sobre el argumento time_step, miren la siguiente discusión: https://discussions.udacity.com/t/rnn-lstm-use-implementation/163169
Actualizar:
Resulta que model.add(TimeDistributed(Dense(vocab_len)))
era lo que estaba buscando. Aquí hay un ejemplo: https://github.com/sachinruk/ShakespeareBot
Actualización2:
He resumido la mayor parte de mi comprensión de los LSTM aquí: https://www.youtube.com/watch?v=ywinX5wgdEU
fuente
Respuestas:
En primer lugar, elige excelentes tutoriales ( 1 , 2 ) para comenzar.
Qué significa Time-step :
Time-steps==3
en X.shape (Describir la forma de los datos) significa que hay tres cuadros rosados. Dado que en Keras cada paso requiere una entrada, por lo tanto, el número de cuadros verdes generalmente debería ser igual al número de cuadros rojos. A menos que hackees la estructura.muchos a muchos versus muchos a uno : en keras, hay un
return_sequences
parámetro cuando se inicializaLSTM
oGRU
oSimpleRNN
. Cuandoreturn_sequences
esFalse
(por defecto), entonces es muchos a uno como se muestra en la imagen. Su forma de retorno es(batch_size, hidden_unit_length)
, que representa el último estado. Cuandoreturn_sequences
esTrue
, entonces es de muchos a muchos . Su forma de retorno es(batch_size, time_step, hidden_unit_length)
¿El argumento de las características se vuelve relevante ? El argumento de las características significa "Qué tan grande es su cuadro rojo" o cuál es la dimensión de entrada en cada paso. Si desea predecir, por ejemplo, 8 tipos de información de mercado, 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 de la última capacitación se usará como el estado inicial, de lo contrario generará un nuevo estado. No he encendidostateful
todavía. Sin embargo, no estoy de acuerdo con quebatch_size
solo puede ser 1 cuandostateful==True
.Actualmente, genera sus datos con los datos recopilados. La imagen de su información de stock se presentará como flujo, en lugar de esperar 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 compartiendo una misma red, puede configurar
batch_size==400
.fuente
stateful: Boolean (default False). If True, the last state for each sample at index i in a batch will be used as initial state for the sample of index i in the following batch.
lookback = 1
?stateful=True
: El tamaño del lote puede ser lo que desee, pero debe atenerse a él. Si usted construye su modelo con un tamaño de lote de 5, entonces todofit()
,predict()
y métodos relacionados a requerir un lote de 5. Nota sin embargo que este estado no se guardará conmodel.save()
, lo que podría parecer indeseable. Sin embargo, puede agregar manualmente el estado al archivo hdf5, si lo necesita. Pero efectivamente, esto le permite cambiar el tamaño del lote simplemente guardando y recargando un modelo.Como complemento de la respuesta aceptada, esta respuesta muestra comportamientos keras y cómo lograr cada imagen.
Comportamiento general de Keras
El procesamiento interno estándar de Keras es siempre de muchos a muchos como en la siguiente imagen (donde usé
features=2
, presión y temperatura, solo como ejemplo):En esta imagen, aumenté el número de pasos a 5, para evitar confusión con las otras dimensiones.
Para este ejemplo:
Nuestra matriz de entrada debería ser algo así como
(N,5,2)
: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 estados internos sobre cómo evoluciona una secuencia 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 secuencia original larga, pero Keras las verá como una secuencia independiente:
Tenga en cuenta que en este caso, inicialmente tiene solo una secuencia, pero la está dividiendo en muchas secuencias para crear ventanas.
El concepto de "qué es una secuencia" es abstracto. Las partes importantes son:
Logrando cada caso con "capas individuales"
Alcanzar el estándar de muchos a muchos:
Puede lograr muchos a muchos con una simple capa LSTM, utilizando
return_sequences=True
:Logrando muchos a uno:
Usando exactamente la misma capa, los keras harán exactamente el mismo preprocesamiento interno, pero cuando use
return_sequences=False
(o simplemente ignore este argumento), los keras descartarán automáticamente los pasos anteriores al último:Logrando uno a muchos
Ahora, esto no es compatible solo con las capas de Keras LSTM. Tendrás que crear tu propia estrategia para multiplicar los pasos. Hay dos buenos enfoques:
stateful=True
para tomar el resultado de un paso y servirlo como entrada del siguiente paso (necesidadesoutput_features == input_features
)Uno a muchos con vector de repetición
Para adaptarnos al comportamiento estándar de Keras, necesitamos entradas en pasos, por lo tanto, simplemente repetimos las entradas para la longitud que queremos:
Comprensión 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 ingresar "partes" de las secuencias en etapas. La diferencia es:
stateful=False
, el segundo lote contiene secuencias completamente nuevas, independientes del primer lotestateful=True
, el segundo lote continúa el primer lote, extendiendo las mismas secuencias.Es como dividir las secuencias en ventanas también, con estas dos diferencias principales:
stateful=True
verá estas ventanas conectadas como una sola secuencia largaEn
stateful=True
, cada lote nuevo se interpretará como la continuación del lote anterior (hasta que llamemodel.reset_states()
).Ejemplo de entradas, el lote 1 contiene los pasos 1 y 2, el lote 2 contiene los pasos 3 a 5:
¡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 cantidad 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.Honestamente, el enfoque repetido es probablemente una mejor opción para este caso. Pero ya que estamos investigando
stateful=True
, este es un buen ejemplo. La mejor manera de usar esto es el próximo caso "muchos a muchos".Capa:
Ahora, vamos a necesitar un bucle manual para las predicciones:
Muchos a muchos con stateful = True
Ahora, aquí, tenemos una aplicación muy agradable: dada una secuencia de entrada, intente predecir sus futuros pasos desconocidos.
Estamos utilizando el mismo método que en el "uno a muchos" anterior, con la diferencia de que:
Capa (igual que la anterior):
Formación:
Vamos a entrenar nuestro modelo para predecir el siguiente paso de las secuencias:
Prediciendo:
La primera etapa de nuestra predicción implica "ajustar los estados". Es por eso que vamos a predecir la secuencia completa nuevamente, incluso si ya conocemos esta parte de ella:
Ahora vamos al bucle como en el caso uno a muchos. ¡Pero no restablezca los estados aquí! . Queremos que el modelo sepa en qué paso de la secuencia se encuentra (y sabe que está en el primer paso nuevo debido a la predicción que acabamos de hacer)
Este enfoque se utilizó en estas respuestas y archivo:
Logrando 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.
Un ejemplo interesante que ha estado apareciendo es el "autoencoder" que tiene un "codificador muchos a uno" seguido de un decodificador "uno a muchos":
Codificador:
Descifrador:
Usando el método de "repetición";
Autoencoder:
Entrenar con
fit(X,X)
Explicaciones adicionales
Si desea detalles sobre cómo se calculan los pasos en los LSTM, o detalles sobre los
stateful=True
casos anteriores, puede leer más en esta respuesta: Dudas con respecto a `Comprender los LSTM de Keras`fuente
my_cell = LSTM(num_output_features_per_timestep, return_state=True)
, seguido de un bucle dea, _, c = my_cell(output_of_previous_time_step, initial_states=[a, c])
Cuando tiene return_sequences en su última capa de RNN, no puede usar una simple capa densa en lugar de usar TimeDistributed.
Aquí hay un ejemplo de código que podría ayudar a otros.
palabras = keras.layers.Input (batch_shape = (None, self.maxSequenceLength), name = "input")
fuente