Cómo predecir el precio de Bitcoin y Ethereum con RNN-LSTM en Keras

2017 fue un gran año para la Inteligencia Artificial y la Criptomoneda. Ha habido muchas investigaciones y avances en la industria de la IA y definitivamente la IA es una de las tecnologías más modernas en la actualidad y aún más en el futuro. Una cosa que personalmente no vi venir a la corriente principal en 2017 fueron las criptomonedas. Fue una corrida de toros masiva con algunos retornos locos de la inversión en criptomonedas como Bitcoin, Ethereum, Litecoin, Ripple, etc.

Comencé a profundizar en los detalles de las técnicas de Machine Learning a principios de 2017 y, como muchos otros expertos y entusiastas de ML, aplicar estas técnicas en el mercado de criptomonedas es muy tentador. La parte interesante es la variedad de formas y métodos que los modelos ML y Deep Learning pueden usarse en el mercado de valores o en nuestro caso, el mercado de cifrado.

Descubrí que construir un modelo de predicción de un solo punto podría ser un gran punto de partida para explorar el aprendizaje profundo con series temporales como los datos de precios. Por supuesto, no termina aquí, siempre hay margen para mejorar y agregar más datos de entrada. Mi favorito es utilizar Deep Reinforcement Learning para agentes comerciales automatizados. En lo que estoy trabajando actualmente, sin embargo, aprender a usar redes LSTM y construir un buen modelo de predicción será el primer paso.

Prerrequisitos y entorno de desarrollo

Supongo que tiene algunas habilidades de codificación en Python y conocimientos básicos de Machine Learning, en particular Deep Learning. De lo contrario, consulte esta publicación para obtener una descripción general rápida.

Mi elección para el entorno de desarrollo es Colab de Google. Elegí Colab por la simplicidad de la configuración del entorno y el acceso a la GPU gratuita, que hace una gran diferencia en el tiempo de entrenamiento. Aquí hay un tutorial sobre cómo configurar y usar colab en su Google Drive. Puede encontrar mi cuaderno Colab completo aquí y aquí en GitHub.

En caso de que desee configurar el entorno de AWS, hace un tiempo también escribí un tutorial sobre cómo configurar la instancia de AWS con Docker en la GPU. Aqui esta el link.

Usaré la biblioteca Keras con el backend TensorFlow para construir el modelo y entrenarme en datos históricos.

¿Qué es la red neuronal recurrente?

Para explicar las redes neuronales recurrentes, volvamos primero a una red perceptrónica simple con una capa oculta. Dicha red hará un buen trabajo para problemas simples de clasificación. Al agregar más capas ocultas, la red será capaz de deducir patrones más complejos en nuestros datos de entrada y aumentar la precisión de las predicciones. Sin embargo, este tipo de redes son buenas para tareas que son independientes del historial donde el orden temporal no importa. Por ejemplo, la clasificación de imágenes que la muestra anterior en el conjunto de entrenamiento no afecta a la siguiente muestra. En otras palabras, los perceptrones no tienen memoria del pasado. Esto es lo mismo para las redes neuronales convolucionales, que son una arquitectura más complicada de perceptrones diseñados para el reconocimiento de imágenes.

Una red neuronal perceptrón simple con una capa oculta y dos salidas

Los RNN son un tipo de red neuronal que resuelve el problema de la memoria pasada para los perceptrones mediante un bucle en el estado oculto del paso de tiempo anterior en la red junto con la muestra de entrada actual.

Permítanme elaborar más sobre esto, en cada paso de tiempo cuando llegue una nueva muestra, la red olvidará cuál fue la muestra en el paso anterior, una forma de resolver este problema para las series de tiempo es introducir la entrada anterior muestra con la muestra actual para que nuestra red pueda tener una idea de lo que sucedió anteriormente, sin embargo, de esta manera no podremos capturar el historial completo de la serie de tiempo antes del paso anterior. Un mejor enfoque será tomar la capa oculta resultante (la matriz de peso de la capa oculta) de la muestra de entrada anterior y alimentarla a nuestra red junto con la muestra de entrada actual.

Miro la matriz de peso de la capa oculta como el estado mental de la red, si lo vemos de esta manera, la capa oculta ya ha capturado el pasado en forma de distribución de peso en todas sus neuronas, lo que es una representación mucho más rica del pasado para nuestra red. La imagen debajo del blog de colah proporcionará una buena visualización de lo que sucede en un RNN.

cuando entra Xt, el estado oculto de Xt-1 se concatenará con Xt y se convertirá en la entrada de la red en el momento t. Este proceso se repetirá para cada muestra en una serie de tiempo.

Traté de mantenerlo lo más simple posible. Si desea profundizar en los RNN, existen excelentes recursos que le recomiendo encarecidamente. Aquí hay algunos buenos recursos sobre RNN:

  • Introducción a las RNN
  • Redes neuronales recurrentes para principiantes
  • La efectividad irracional de las redes neuronales recurrentes

¿Qué es la memoria a corto y largo plazo?

Antes de contarte qué es LSTM, déjame contarte sobre el mayor problema con los RNN. Hasta ahora, todo se ve bien sobre los RNN hasta que lo entrenemos a través de la propagación inversa. A medida que el gradiente de nuestras muestras de entrenamiento se propaga hacia atrás a través de nuestra red, se vuelve cada vez más débil, para cuando llega a esas neuronas que representan puntos de datos más antiguos en nuestra serie de tiempo, no tiene el jugo para ajustarlas adecuadamente. Este problema se llama gradiente de fuga. Una celda LSTM es un tipo de RNN que almacena información importante sobre el pasado y olvida las piezas sin importancia. De esta manera, cuando el gradiente se propaga hacia atrás, no será consumido por información innecesaria.

Piensa en ti mismo cuando lees un libro, a menudo después de terminar un capítulo, aunque puedes recordar de qué trataba el capítulo anterior, es posible que no puedas recordar todos los puntos importantes al respecto. Una forma de resolver este problema, destacamos y tomamos nota de aquellos puntos que son importantes para recordar y no tenemos en cuenta las explicaciones y los rellenos que no son críticos para el tema. Comprender las redes LSTM de Christopher Olah es un gran recurso para una comprensión profunda de las LSTM.

Vamos a codificar

Lo primero es lo primero, importamos las bibliotecas que necesitamos para nuestro proyecto.

importar gc
fecha y hora de importación
importar pandas como pd
importar numpy como np
importar matplotlib.pyplot como plt

importar keras
de keras.models import Sequential
from keras.layers import Activation, Dense
de keras.layers import LSTM
desde keras.layers import Dropout

Información histórica

He usado datos históricos de www.coinmarketcap.com, puede usar cualquier otra fuente, pero me pareció muy simple y directo para esta publicación. Obtendremos los datos de precios diarios de Bitcoin. Sin embargo, en el cuaderno Colab también verá el código de Ethereum. Escribí el código de manera que sea reutilizable para otras criptomonedas.

Ahora vamos a escribir una función para obtener los datos del mercado.

Ahora obtengamos los datos de Bitcoin y cárguelos en la variable ‘‘ ‘btc_data’ ’’ y muestremos las primeras cinco filas de nuestros datos.

btc_data = get_market_data ("bitcoin", etiqueta = 'BTC')
btc_data.head ()
datos de mercado para BTC

Echemos un vistazo al precio de "cierre" de Bitcoin y su volumen diario a lo largo del tiempo

show_plot (btc_data, tag = 'BTC')

Preparación de datos

Una gran parte de la construcción de cualquier modelo de Deep Learning es preparar nuestros datos para ser consumidos por la red neuronal para entrenamiento o predicción. Este paso se llama Preprocesamiento, que podría incluir varios pasos según el tipo de datos que estamos utilizando. En nuestro caso, realizaremos las siguientes tareas como parte de nuestro preprocesamiento:

  • Limpieza de datos, llenando puntos de datos faltantes
  • Fusionar múltiples canales de datos. Bitcoin y Ethereum en un marco de datos
  • Eliminar columnas innecesarias
  • Ordene nuestros datos en orden ascendente según la fecha
  • Dividir los datos para entrenamiento y prueba
  • Cree muestras de entrada y normalícelas entre 0 y 1
  • Cree salidas objetivo para los conjuntos de entrenamiento y prueba y normalícelas entre 0 y 1
  • Convierta nuestros datos en una matriz numpy para que nuestro modelo los consuma

La parte de limpieza de datos ya se realizó en nuestra primera función donde cargamos los datos. A continuación puede encontrar las funciones necesarias para realizar las tareas anteriores:

Aquí está el código para trazar funciones y crear etiquetas de fecha

Aquí llamaremos a las funciones anteriores para crear los conjuntos de datos finales para nuestro modelo.

train_set = train_set.drop ('Fecha', 1)
test_set = test_set.drop ('Fecha', 1)
X_train = create_inputs (train_set)
Y_train_btc = create_outputs (train_set, coin = 'BTC')
X_test = create_inputs (test_set)
Y_test_btc = create_outputs (test_set, coin = 'BTC')
Y_train_eth = create_outputs (train_set, coin = 'ETH')
Y_test_eth = create_outputs (test_set, coin = 'ETH')
X_train, X_test = to_array (X_train), to_array (X_test)

Ahora construyamos nuestro modelo LSTM-RNN. En este modelo, he usado 3 capas de LSTM con 512 neuronas por capa, seguido de 0.25 Dropout después de cada capa de LSTM para evitar un ajuste excesivo y, finalmente, una capa densa para producir nuestras salidas.

Gráfico de cálculo de TensorFlow exportado desde TensorBoard

He usado "tanh" para mi función de activación y Error cuadrático medio para mi pérdida y "adam" como mi optimizador. Sugiero jugar con diferentes opciones de estas funciones y ver cómo afectan el rendimiento de su modelo.

Aquí está nuestro resumen del modelo:

He descartado mis hiperparámetros para el código completo al principio del código para facilitar los cambios para diferentes variaciones desde un solo lugar. Aquí están mis hiperparámetros:

neuronas = 512
activación_función = 'tanh'
pérdida = 'mse'
optimizador = "adam"
abandono = 0.25
batch_size = 12
épocas = 53
window_len = 7
tamaño_entrenamiento = 0.8
merge_date = '2016-01-01'

Ahora es el momento de capacitar a nuestro modelo sobre los datos que hemos recopilado.

# limpia la memoria
gc.collect ()
# semilla aleatoria para reproducibilidad
np.random.seed (202)
# inicializar la arquitectura del modelo
btc_model = build_model (X_train, output_size = 1, neuronas = neuronas)
# modelo de tren en datos
btc_history = btc_model.fit (X_train, Y_train_btc, epochs = epochs, batch_size = batch_size, verbose = 1, validation_data = (X_test, Y_test_btc), shuffle = False)

El código anterior puede tardar un tiempo en terminar, dependiendo de su potencia informática y, cuando esté listo, su modelo entrenado también estará listo :)

Veamos los resultados de BTC y ETH

No está mal para empezar :)

Hay una gran publicación de blog escrita por David Sheehan donde aprendí por primera vez sobre cómo usar LSTM para la predicción de precios de criptomonedas. Aquí está el enlace a su blog.

Actualización 1:

  • Se eliminó add_volatility ya que no afectaba el rendimiento
  • Creó plot_results () y agregó etiquetas de fecha a la figura
  • reemplazó MAE con MSE como función de pérdida
  • Se incrementó el tamaño del lote de 64 a 128
  • Diagrama de gráfico computacional TF agregado

Actualización 2:

  • Podría mejorar ligeramente el rendimiento (reduciendo la pérdida) reduciendo la longitud de la ventana de 7 días a 3 días y la cantidad de neuronas a 1024.

¡Espero que hayas disfrutado esta publicación!