tensorflow - the - time series forecasting with keras
Construyendo un LSTM multivariable y multitarea con Keras (3)
Pregunta 1
Hay varios enfoques para este problema. El que propones parece ser una ventana deslizante.
Pero, de hecho, no necesita dividir la dimensión temporal, puede ingresar los 3 años a la vez. Puede dividir la dimensión de los productos, en caso de que su lote sea demasiado grande para la memoria y la velocidad.
Puede trabajar con una sola matriz con forma (products, time, features)
Pregunta 2
Sí, tiene sentido usar return_sequences=True
.
Si entendí tu pregunta correctamente, tienes predicciones para cada día, ¿verdad?
Pregunta 3
Esa es realmente una pregunta abierta. Todos los enfoques tienen sus ventajas.
Pero si está considerando poner todas las características del producto juntas, ya que estas características son de naturaleza diferente, probablemente debería expandir todas las características posibles como si hubiera un gran vector que tenga en cuenta todas las características de todos los productos.
Si cada producto tiene características independientes que se aplican solo a sí mismo, la idea de crear modelos individuales para cada producto no me parece una locura.
También puede hacer que la identificación del producto sea una entrada vectorial de un solo uso y usar un solo modelo.
Pregunta 4
Dependiendo del enfoque que elija, puede:
- Dividir algunos productos como datos de validación.
- Deje la parte final de los pasos de tiempo como datos de validación.
- Pruebe un método de validación cruzada que deje diferentes longitudes para el entrenamiento y la prueba (sin embargo, cuanto más largos sean los datos de prueba, mayor será el error, sin embargo, es posible que desee recortar estos datos de prueba para que tengan una longitud fija)
Pregunta 5
También puede haber muchos enfoques.
Hay enfoques donde se utilizan ventanas correderas. Entrenas a tu modelo para tiempos de tiempo fijos.
Y hay enfoques donde entrenas las capas LSTM con toda la longitud. En este caso, primero debe predecir toda la parte conocida y luego comenzar a predecir la parte desconocida.
Mi pregunta: ¿se conocen los datos de
X
para el período en el que tiene que predecirY
? ¿DeX
también se desconoce en este período, así que también tienes que predecirX
?
Pregunta 6
Le recomiendo que eche un vistazo a esta pregunta y su respuesta: ¿Cómo lidiar con el pronóstico de series de tiempo de múltiples pasos en LSTM multivariable en keras?
Vea también este cuaderno que logra demostrar la idea: https://github.com/danmoller/TestRepo/blob/master/TestBookLSTM.ipynb
En este cuaderno, sin embargo, utilicé un enfoque que coloca a X e Y como entradas. Y predecimos el futuro X e Y.
Puedes intentar crear un modelo (si ese es el caso) solo para predecir X. Luego, un segundo modelo para predecir Y desde X.
En otro caso (si ya tiene todos los datos de X, no es necesario predecir X), puede crear un modelo que solo predice Y a partir de X. (Seguiría parte del método en el cuaderno, donde primero predice el ya conocido Y solo para hacer que su modelo se ajuste a donde está en la secuencia, entonces predice la Y desconocida): esto se puede hacer en una sola entrada X de longitud completa (que contiene la X de entrenamiento al principio y la prueba X al final).
Respuesta extra
Saber qué enfoque y qué tipo de modelo elegir es probablemente la respuesta exacta para ganar la competencia ... por lo tanto, no hay una mejor respuesta para esta pregunta, cada competidor está tratando de encontrar esta respuesta.
Preámbulo
Actualmente estoy trabajando en un problema de Aprendizaje automático en el que tenemos la tarea de utilizar datos pasados sobre las ventas de productos para predecir los volúmenes de ventas en el futuro (para que las tiendas puedan planificar mejor sus existencias). Básicamente, tenemos datos de series de tiempo, donde, para cada producto, sabemos cuántas unidades se vendieron en qué días. También tenemos información como el clima, si hubo un día festivo, si alguno de los productos se vendió, etc.
Hemos podido modelar esto con cierto éxito utilizando un MLP con capas densas, y simplemente utilizando un enfoque de ventana deslizante para incluir los volúmenes de ventas de los días circundantes. Sin embargo, creemos que podremos obtener resultados mucho mejores con un enfoque de series de tiempo como un LSTM.
Datos
Los datos que tenemos esencialmente son los siguientes:
( EDITAR: para mayor claridad, la columna "Tiempo" en la imagen de arriba no es correcta. Tenemos entradas una vez por día, no una por mes. ¡De lo contrario, la estructura es la misma!)
Así que los datos de X son de forma:
(numProducts, numTimesteps, numFeatures) = (50 products, 1096 days, 90 features)
Y los datos de Y son de forma:
(numProducts, numTimesteps, numTargets) = (50 products, 1096 days, 3 binary targets)
Así que tenemos datos para tres años (2014, 2015, 2016) y queremos capacitarnos para hacer predicciones para 2017. (Eso, por supuesto, no es 100% cierto, ya que en realidad tenemos datos hasta octubre de 2017, pero simplemente ignorar eso por ahora)
Problema
Me gustaría construir un LSTM en Keras que me permita hacer estas predicciones. Hay algunos lugares donde me estoy atascando sin embargo. Por lo tanto, tengo seis preguntas concretas (sé que se supone que una debe intentar limitar una publicación de Stackoverflow a una pregunta, pero todas están relacionadas entre sí).
En primer lugar, ¿cómo dividiría mis datos para los lotes ? Dado que tengo tres años completos, ¿tiene sentido simplemente repasar tres lotes, cada vez de un año de tamaño? ¿O tiene más sentido hacer lotes más pequeños (por ejemplo, 30 días) y también usar ventanas corredizas? Es decir, en lugar de 36 lotes de 30 días cada uno, uso 36 * 6 lotes de 30 días cada uno, ¿cada vez que resbalo con 5 días? ¿O no es esta realmente la forma en que se deben usar los LSTM? (Tenga en cuenta que hay bastante estacionalidad en los datos, ya que también necesito detectar ese tipo de tendencia a largo plazo).
En segundo lugar, ¿tiene sentido usar return_sequences=True
aquí? En otras palabras, mantengo mis datos de Y tal como están (50, 1096, 3)
modo que (hasta donde lo he entendido) hay una predicción en cada paso del tiempo para la cual se puede calcular una pérdida con respecto a los datos de destino. O estaría mejor con return_sequences=False
, de modo que solo se use el valor final de cada lote para evaluar la pérdida (es decir, si se usan lotes anuales, en 2016 para el producto 1, evaluamos el valor de diciembre de 2016 de (1,1,1)
).
En tercer lugar, ¿cómo debo tratar con los 50 productos diferentes? Son diferentes, pero aún están fuertemente correlacionados y hemos visto con otros enfoques (por ejemplo, un MLP con ventanas de tiempo simples) que los resultados son mejores cuando todos los productos se consideran en el mismo modelo. Algunas ideas que están actualmente sobre la mesa son:
- cambie la variable de destino para que no sea solo 3 variables, sino 3 * 50 = 150; Es decir, para cada producto hay tres objetivos, todos los cuales se entrenan simultáneamente.
- divida los resultados después de la capa LSTM en 50 redes densas, que toman como entrada las salidas de la LSTM, además de algunas características que son específicas para cada producto, es decir, obtenemos una red multitarea con 50 funciones de pérdida, que luego optimizamos juntos. ¿Sería eso una locura?
- considere un producto como una sola observación e incluya características específicas del producto que ya se encuentran en la capa LSTM. Use solo esta capa seguida por una capa de salida de tamaño 3 (para los tres objetivos). Empuje a través de cada producto en un lote separado.
En cuarto lugar, ¿cómo trato con los datos de validación ? Normalmente, solo mantendría una muestra seleccionada al azar para validarla, pero aquí necesitamos mantener el orden del tiempo en su lugar. Entonces, ¿supongo que lo mejor es mantener unos meses de lado?
En quinto lugar, y esta es la parte que probablemente no sea clara para mí: ¿cómo puedo usar los resultados reales para realizar predicciones ? Digamos que usé return_sequences=False
y me return_sequences=False
en los tres años en tres lotes (cada vez hasta noviembre) con el objetivo de entrenar al modelo para predecir el siguiente valor (diciembre de 2014, diciembre de 2015, diciembre de 2016). Si quiero usar estos resultados en 2017, ¿cómo funciona esto realmente? Si lo entendí correctamente, lo único que puedo hacer en este caso es alimentar al modelo con todos los puntos de datos de enero a noviembre de 2017 y me dará una predicción para diciembre de 2017. ¿Es correcto? Sin embargo, si utilizara return_sequences=True
, luego return_sequences=True
con todos los datos hasta diciembre de 2016, ¿sería capaz de obtener una predicción para enero de 2017 con solo darle al modelo las características observadas en enero de 2017? ¿O también necesito darle los 12 meses anteriores a enero de 2017? En cuanto a febrero de 2017, ¿tengo que dar el valor para 2017, además de otros 11 meses antes de eso? (Si parece que estoy confundido, es porque lo estoy!)
Por último, dependiendo de qué estructura debo usar, ¿cómo hago esto en Keras ? Lo que tengo en mente en este momento es algo como lo siguiente: (aunque esto sería para un solo producto, por lo que no resuelve tener todos los productos en el mismo modelo):
Codigo keras
trainX = trainingDataReshaped #Data for Product 1, Jan 2014 to Dec 2016
trainY = trainingTargetReshaped
validX = validDataReshaped #Data for Product 1, for ??? Maybe for a few months?
validY = validTargetReshaped
numSequences = trainX.shape[0]
numTimeSteps = trainX.shape[1]
numFeatures = trainX.shape[2]
numTargets = trainY.shape[2]
model = Sequential()
model.add(LSTM(100, input_shape=(None, numFeatures), return_sequences=True))
model.add(Dense(numTargets, activation="softmax"))
model.compile(loss=stackEntry.params["loss"],
optimizer="adam",
metrics=[''accuracy''])
history = model.fit(trainX, trainY,
batch_size=30,
epochs=20,
verbose=1,
validation_data=(validX, validY))
predictX = predictionDataReshaped #Data for Product 1, Jan 2017 to Dec 2017
prediction=model.predict(predictX)
Asi que:
En primer lugar, ¿cómo dividiría mis datos para los lotes? Dado que tengo tres años completos, ¿tiene sentido simplemente repasar tres lotes, cada vez de un año de tamaño? ¿O tiene más sentido hacer lotes más pequeños (por ejemplo, 30 días) y también usar ventanas corredizas? Es decir, en lugar de 36 lotes de 30 días cada uno, uso 36 * 6 lotes de 30 días cada uno, ¿cada vez que resbalo con 5 días? ¿O no es esta realmente la forma en que se deben usar los LSTM? (Tenga en cuenta que hay bastante estacionalidad en los datos, ya que también necesito detectar ese tipo de tendencia a largo plazo).
Honestamente, modelar tales datos es algo realmente difícil. En primer lugar, no recomendaría que use LSTM
s, ya que están diseñados para capturar un tipo de datos un poco diferente (por ejemplo, NLP o discurso donde es realmente importante modelar las dependencias a largo plazo, no la estacionalidad) y necesitan Una gran cantidad de datos para ser aprendidos. Prefiero que utilices GRU
o SimpleRNN
que son mucho más fáciles de aprender y deberían ser mejores para tu tarea.
Cuando se trata de lotes, definitivamente te aconsejo que uses una técnica de ventana fija, ya que terminará produciendo muchos más datos que alimentando un año entero o un mes entero. Intente establecer un número de días como meta parámetro, que también se optimizará utilizando diferentes valores en el entrenamiento y eligiendo el más adecuado.
Cuando se trata de la estacionalidad, por supuesto, este es un caso pero:
- Es posible que tenga muy pocos puntos de datos y años recopilados para proporcionar una buena estimación de las tendencias de la temporada,
- Usar cualquier tipo de red neuronal recurrente para capturar tales estacionalidades es una muy mala idea.
Lo que te aconsejo que hagas en su lugar es:
- intente agregar características estacionales (por ejemplo, la variable del mes, la variable del día, una variable que se establece como verdadera si hay un determinado día festivo ese día o cuántos días faltan para el siguiente día festivo importante: esta es una habitación donde podría estar realmente). creativo)
- Utilice los datos agregados del año pasado como una característica: podría, por ejemplo, alimentar los resultados del año pasado o las agregaciones de ellos como el promedio acumulado de los resultados del año pasado, el máximo, el mínimo, etc.
En segundo lugar, ¿tiene sentido usar return_sequences = True aquí? En otras palabras, mantengo mis datos de Y tal como están (50, 1096, 3) de modo que (hasta donde lo he entendido) hay una predicción en cada paso del tiempo para la cual se puede calcular una pérdida con respecto a los datos de destino. O estaría mejor con return_sequences = False, de modo que solo se use el valor final de cada lote para evaluar la pérdida (es decir, si se usan lotes anuales, en 2016 para el producto 1, evaluamos el valor de diciembre de 2016 de (1 , 1,1)).
Usar return_sequences=True
puede ser útil pero solo en los siguientes casos:
- Cuando un
LSTM
dado (u otra capa recurrente) será seguido por otra capa recurrente. - En un escenario, cuando alimenta una serie original modificada como resultado de lo que está aprendiendo simultáneamente un modelo en diferentes ventanas de tiempo, etc.
La forma descrita en un segundo punto puede ser un enfoque interesante, pero tenga en cuenta que podría ser un poco difícil de implementar, ya que tendrá que volver a escribir su modelo para obtener un resultado de producción. Lo que también podría ser más difícil es que tendrá que probar su modelo frente a muchos tipos de inestabilidades de tiempo, y este enfoque podría hacer que esto sea totalmente inviable.
En tercer lugar, ¿cómo debo tratar con los 50 productos diferentes? Son diferentes, pero aún están fuertemente correlacionados y hemos visto con otros enfoques (por ejemplo, un MLP con ventanas de tiempo simples) que los resultados son mejores cuando todos los productos se consideran en el mismo modelo. Algunas ideas que están actualmente sobre la mesa son:
- cambie la variable de destino para que no sea solo 3 variables, sino 3 * 50 = 150; Es decir, para cada producto hay tres objetivos, todos los cuales se entrenan simultáneamente.
- divida los resultados después de la capa LSTM en 50 redes densas, que toman como entrada las salidas de la LSTM, además de algunas características que son específicas para cada producto, es decir, obtenemos una red multitarea con 50 funciones de pérdida, que luego optimizamos juntos. ¿Sería eso una locura?
- considere un producto como una sola observación e incluya características específicas del producto que ya se encuentran en la capa LSTM. Use solo esta capa seguida por una capa de salida de tamaño 3 (para los tres objetivos). Empuje a través de cada producto en un lote separado.
Definitivamente optaría por una primera opción, pero antes de proporcionar una explicación detallada, discutiré las desventajas de la segunda y la tercera:
- En el segundo enfoque: no sería una locura, pero perderá muchas correlaciones entre los objetivos de los productos,
- En el tercer enfoque: perderá muchos patrones interesantes que se producen en dependencias entre diferentes series de tiempo.
Antes de llegar a mi elección, hablemos de otro problema, las redundancias en su conjunto de datos. Supongo que tienes 3 tipos de características:
- productos específicos (digamos que hay ''m'' de ellos)
- características generales - digamos que hay ''n'' de ellos.
Ahora tiene una tabla de tamaño (timesteps, m * n, products)
. Lo transformaría en una tabla de formas (timesteps, products * m + n)
ya que las características generales son las mismas para todos los productos. Esto le ahorrará una gran cantidad de memoria y también hará que sea posible alimentar a una red recurrente (tenga en cuenta que las capas recurrentes en keras
solo tienen una dimensión de característica, mientras que usted tenía dos: las de product
y las de feature
).
Entonces, ¿por qué el primer enfoque es el mejor en mi opinión? Tenga en cuenta que se aprovecha de muchas dependencias interesantes a partir de los datos. Por supuesto, esto podría dañar el proceso de entrenamiento, pero hay un truco fácil para superar esto: la reducción de la dimensionalidad . Podría, por ejemplo, entrenar a PCA
en su vector de 150 dimensiones y reducir su tamaño a uno mucho más pequeño. Gracias a sus dependencias modeladas por PCA
y su salida tiene un tamaño mucho más factible.
En cuarto lugar, ¿cómo trato con los datos de validación? Normalmente, solo mantendría una muestra seleccionada al azar para validarla, pero aquí necesitamos mantener el orden del tiempo en su lugar. Entonces, ¿supongo que lo mejor es mantener unos meses de lado?
Esta es una pregunta muy importante. Desde mi experiencia, necesitas probar tu solución contra muchos tipos de inestabilidades para asegurarte de que funciona bien. Así que unas cuantas reglas que deberías tener en cuenta:
- No debe haber superposición entre las secuencias de entrenamiento y las secuencias de prueba. Si existiera tal cosa, tendrá valores válidos de un conjunto de prueba alimentado a un modelo durante el entrenamiento,
- Debe probar la estabilidad del tiempo del modelo frente a muchos tipos de dependencias de tiempo.
El último punto puede ser un poco vago, por lo que le proporcionamos algunos ejemplos:
- estabilidad durante el año : valide su modelo entrenándolo con cada combinación posible de dos años y pruébelo en una espera (por ejemplo, 2015, 2016 contra 2017, 2015, 2017 contra 2016, etc.) - esto le mostrará cómo afectan los cambios de año tu modelo
- estabilidad de predicción futura : capacite a su modelo en un subconjunto de semanas / meses / años y pruébelo utilizando el resultado de la siguiente semana / mes / año (p. ej., capacítelo en enero de 2015, enero de 2016 y enero de 2017 y pruébelo utilizando Feburary 2015, Feburary 2016 , Datos de febrero de 2017, etc.)
- estabilidad del mes : entrene al modelo cuando se mantiene un mes determinado en un conjunto de pruebas.
Por supuesto, podrías intentar otra suspensión.
En quinto lugar, y esta es la parte que probablemente no sea clara para mí: ¿cómo puedo usar los resultados reales para realizar predicciones? Digamos que usé return_sequences = False y me entrené en los tres años en tres lotes (cada vez hasta noviembre) con el objetivo de entrenar al modelo para predecir el siguiente valor (diciembre de 2014, diciembre de 2015, diciembre de 2016). Si quiero usar estos resultados en 2017, ¿cómo funciona esto realmente? Si lo entendí correctamente, lo único que puedo hacer en este caso es alimentar al modelo con todos los puntos de datos de enero a noviembre de 2017 y me dará una predicción para diciembre de 2017. ¿Es correcto? Sin embargo, si utilizara return_sequences = Verdadero, luego entrené con todos los datos hasta diciembre de 2016, ¿sería capaz de obtener una predicción para enero de 2017 con solo darle al modelo las características observadas en enero de 2017? ¿O también necesito darle los 12 meses anteriores a enero de 2017? En cuanto a febrero de 2017, ¿tengo que dar el valor para 2017, además de otros 11 meses antes de eso? (Si parece que estoy confundido, es porque lo estoy!)
Esto depende de cómo hayas construido tu modelo:
- si
return_sequences=True
debes reescribirlo para quereturn_sequence=False
o simplemente tomar la salida y considerar solo el último paso del resultado, - Si usó una ventana fija, entonces solo necesita alimentar una ventana antes de la predicción del modelo.
Si usó una longitud variable, podría alimentar cualquier paso de tiempo que proceda al período de predicción que desee (pero le aconsejo que alimente al menos 7 días de procedimiento).
Por último, dependiendo de qué estructura debo usar, ¿cómo hago esto en Keras? Lo que tengo en mente en este momento es algo como lo siguiente: (aunque esto sería para un solo producto, por lo que no resuelve tener todos los productos en el mismo modelo)
Aquí - más información sobre qué tipo de modelo ha elegido es necesario.
Siguiendo con las dos respuestas ya proporcionadas, creo que debería echarle un vistazo a este artículo de Amazon Research sobre el pronóstico de ventas usando LSTM para ver cómo manejan los problemas que mencionó:
https://arxiv.org/abs/1704.04110
Además, también debo señalar que la regularización adecuada es extremadamente importante cuando se usan redes recurrentes, ya que su capacidad de overfit puede ser realmente espectacular. Es posible que desee consultar el "abandono recurrente variable" como se describe en este artículo.
https://arxiv.org/abs/1512.05287
Nota: esto ya se ha implementado en Tensorflow!