Esenciales del aprendizaje profundo : Introducción a la memoria a largo plazo

Introducción

Los problemas de predicción de secuencias han existido durante mucho tiempo. Son considerados como uno de los problemas más difíciles de resolver en la industria de la ciencia de datos. Incluyen una amplia gama de problemas; desde la predicción de las ventas hasta la búsqueda de patrones en los datos de los mercados de valores, desde la comprensión de los argumentos de las películas hasta el reconocimiento de su forma de hablar, desde las traducciones de idiomas hasta la predicción de la próxima palabra en el teclado de su iPhone.

Con los recientes avances que se han producido en la ciencia de los datos, se ha descubierto que para casi todos estos problemas de predicción de secuencias, las redes de memoria a largo plazo, también conocidas como LSTM, se han observado como la solución más eficaz.

Las LSTM tienen una ventaja sobre las redes neuronales convencionales de avance y las RNN en muchos aspectos. Esto se debe a su propiedad de recordar selectivamente patrones durante largos periodos de tiempo. El propósito de este artículo es explicar las LSTM y permitirle utilizarlas en problemas de la vida real. Nota: Para leer el artículo, debes tener conocimientos básicos de redes neuronales y de cómo funciona Keras (una biblioteca de aprendizaje profundo). Puedes consultar los artículos mencionados para entender estos conceptos:

  • Entendiendo las redes neuronales desde cero
  • Fundamentos del aprendizaje profundo – Introducción a las redes neuronales recurrentes
  • Tutorial: Optimización de redes neuronales usando Keras (con caso de estudio de reconocimiento de imágenes)

Tabla de contenidos

  1. Flashback: Una mirada a las Redes Neuronales Recurrentes (RNN)
  2. Limitaciones de las RNN
  3. Mejoras sobre las RNN : Memoria a Largo Plazo (LSTM)
  4. Arquitectura de las LSTM
    1. Puerta de olvido
    2. Puerta de entrada
    3. Puerta de salida
  5. Generación de texto mediante LSTMs.

Flashback: Una mirada a las Redes Neuronales Recurrentes (RNN)

Toma un ejemplo de datos secuenciales, que pueden ser los datos del mercado de valores para una acción en particular. Un modelo de aprendizaje automático simple o una red neuronal artificial puede aprender a predecir los precios de las acciones basándose en una serie de características: el volumen de la acción, el valor de apertura, etc. Aunque el precio de las acciones depende de estas características, también depende en gran medida de los valores de las acciones en los días anteriores. De hecho, para un comerciante, estos valores en los días anteriores (o la tendencia) es un factor decisivo para las predicciones.

En las redes neuronales convencionales de avance, todos los casos de prueba se consideran independientes. Es decir, cuando se ajusta el modelo para un día concreto, no se tienen en cuenta los precios de las acciones de los días anteriores.

Esta dependencia del tiempo se consigue mediante las redes neuronales recurrentes. Una RNN típica tiene el siguiente aspecto:

Esto puede ser intimidante a primera vista, pero una vez desplegado, parece mucho más sencillo:

Ahora es más fácil para nosotros visualizar cómo estas redes están considerando la tendencia de los precios de las acciones, antes de predecir los precios de las acciones para hoy. Aquí cada predicción en el tiempo t (h_t) depende de todas las predicciones anteriores y de la información aprendida de ellas.

Las RNN pueden resolver nuestro propósito de manejo de secuencias en gran medida pero no del todo. Queremos que nuestros ordenadores sean lo suficientemente buenos como para escribir sonetos de Shakespeare. Ahora bien, las RNN son geniales cuando se trata de contextos cortos, pero para poder construir una historia y recordarla, necesitamos que nuestros modelos sean capaces de entender y recordar el contexto que hay detrás de las secuencias, igual que un cerebro humano. Esto no es posible con una simple RNN.

¿Por qué? Echemos un vistazo.

Limitaciones de las RNN

Las Redes Neuronales Recurrentes funcionan bien cuando se trata de dependencias a corto plazo. Es decir, cuando se aplican a problemas como:

Las RNN resultan ser bastante eficaces. Esto se debe a que este problema no tiene nada que ver con el contexto del enunciado. La RNN no necesita recordar qué se dijo antes de esto, o cuál era su significado, todo lo que necesita saber es que en la mayoría de los casos el cielo es azul. Por lo tanto, la predicción sería:

Sin embargo, las RNN de vainilla no entienden el contexto detrás de una entrada. Algo que se dijo mucho antes, no se puede recordar al hacer predicciones en el presente. Entendamos esto como un ejemplo:

Aquí, podemos entender que como el autor ha trabajado en España durante 20 años, es muy probable que posea un buen dominio del español. Pero, para hacer una predicción adecuada, la RNN necesita recordar este contexto. La información relevante puede estar separada del punto donde se necesita, por una enorme carga de datos irrelevantes. Aquí es donde una Red Neuronal Recurrente falla!

La razón detrás de esto es el problema del Gradiente de Desaparición. Para entender esto, necesitarás tener algún conocimiento sobre cómo aprende una red neuronal feed-forward. Sabemos que para una red neuronal feed-forward convencional, la actualización del peso que se aplica en una capa particular es un múltiplo de la tasa de aprendizaje, el término de error de la capa anterior y la entrada a esa capa. Por lo tanto, el término de error de una capa concreta es en algún lugar un producto de todos los errores de las capas anteriores. Cuando se trata de funciones de activación como la función sigmoidea, los valores pequeños de sus derivadas (que se producen en la función de error) se multiplican varias veces a medida que nos movemos hacia las capas iniciales. Como resultado de esto, el gradiente casi se desvanece a medida que nos movemos hacia las capas iniciales, y se hace difícil entrenar estas capas.

Un caso similar se observa en las Redes Neuronales Recurrentes. Las RNN recuerdan cosas sólo durante pequeños períodos de tiempo, es decir, si necesitamos la información después de un pequeño tiempo puede ser reproducible, pero una vez que se introducen muchas palabras, esta información se pierde en alguna parte. Este problema puede resolverse aplicando una versión ligeramente modificada de las RNN: las redes de memoria a largo plazo.

Mejora sobre las RNN: Redes LSTM (Long Short-Term Memory)

Cuando organizamos nuestra agenda para el día, priorizamos nuestras citas ¿verdad? Si en caso de que necesitemos hacer algún hueco para algo importante sabemos qué reunión podría ser cancelada para dar cabida a una posible reunión.

Resulta que una RNN no lo hace. Para añadir una nueva información, transforma la información existente por completo aplicando una función. Por ello, se modifica toda la información, en su conjunto, es decir, no se tiene en cuenta la información «importante» y la «no tan importante».

LSTMs por otro lado, hacen pequeñas modificaciones a la información mediante multiplicaciones y adiciones. Con las LSTM, la información fluye a través de un mecanismo conocido como estados de celda. De este modo, las LSTM pueden recordar u olvidar cosas de forma selectiva. La información en un estado de celda particular tiene tres dependencias diferentes.

Visualizaremos esto con un ejemplo. Tomemos el ejemplo de la predicción de los precios de las acciones para una acción en particular. El precio de las acciones de hoy dependerá de:

  1. La tendencia que haya seguido la acción en los días anteriores, tal vez una tendencia bajista o una tendencia alcista.
  2. El precio de la acción en el día anterior, porque muchos operadores comparan el precio del día anterior de la acción antes de comprarla.
  3. Los factores que pueden afectar el precio de la acción para hoy. Esto puede ser una nueva política de la empresa que está siendo ampliamente criticada, o una caída en los beneficios de la empresa, o tal vez un cambio inesperado en la alta dirección de la empresa.

Estas dependencias se pueden generalizar a cualquier problema como:

  1. El estado anterior de la célula (es decir, la información que estaba presente en la memoria después del paso de tiempo anterior)
  2. El estado oculto anterior (es decir. esto es lo mismo que la salida de la célula anterior)
  3. La entrada en el paso de tiempo actual (es decir, la nueva información que se está alimentando en ese momento)

¡Otra característica importante de LSTM es su analogía con las cintas transportadoras!

¡Así es!

Las industrias las utilizan para mover productos para diferentes procesos. Los LSTM utilizan este mecanismo para mover la información.

Podemos tener alguna adición, modificación o eliminación de información a medida que fluye a través de las diferentes capas, al igual que un producto puede ser moldeado, pintado o embalado mientras está en una cinta transportadora.

El siguiente diagrama explica la estrecha relación entre las LSTM y las cintas transportadoras.

Fuente

Aunque este diagrama ni siquiera se acerca a la arquitectura real de una LSTM, por ahora resuelve nuestro propósito.

Sólo por esta propiedad de las LSTM, en la que no manipulan toda la información sino que la modifican ligeramente, son capaces de olvidar y recordar cosas selectivamente. ¿Cómo lo hacen?, es lo que vamos a aprender en la siguiente sección…

Arquitectura de las LSTM

El funcionamiento de las LSTM se puede visualizar entendiendo el funcionamiento del equipo de un canal de noticias que cubre una noticia de asesinato. Ahora bien, una noticia se construye a partir de hechos, pruebas y declaraciones de muchas personas. Cada vez que se produce un nuevo acontecimiento se da cualquiera de los tres pasos.

Digamos que estábamos asumiendo que el asesinato se había producido por «envenenamiento» de la víctima, pero el informe de la autopsia que acaba de llegar dice que la causa de la muerte fue «un impacto en la cabeza». Siendo parte de este equipo de noticias, ¿qué haces? Inmediatamente te olvidas de la anterior causa de la muerte y de todas las historias que se tejieron en torno a este hecho.

¿Qué pasa si se introduce un sospechoso totalmente nuevo en el panorama. ¿Una persona que tenía rencores con la víctima y podría ser el asesino? Usted introduce esta información en su feed de noticias, ¿verdad?

Ahora todas estas piezas rotas de información no pueden ser servidas en los medios de comunicación principales. Por lo tanto, después de un cierto intervalo de tiempo, usted necesita para resumir esta información y la salida de las cosas relevantes a su audiencia. Tal vez en la forma de «XYZ resulta ser el principal sospechoso».

Ahora vamos a entrar en los detalles de la arquitectura de la red LSTM:

Fuente

Ahora, esto no se acerca a la versión simplificada que vimos antes, pero déjame guiarte a través de ella. Una red LSTM típica se compone de diferentes bloques de memoria llamados celdas
(los rectángulos que vemos en la imagen). Hay dos estados que se transfieren a la siguiente celda: el estado de la celda y el estado oculto. Los bloques de memoria se encargan de recordar cosas y las manipulaciones a esta memoria se hacen a través de tres mecanismos principales, llamados puertas. Cada uno de ellos se discute a continuación.

4.1 Puerta de olvido

Tomando el ejemplo de un problema de predicción de texto. Supongamos que un LSTM se alimenta, la siguiente frase:

Tan pronto como se encuentra el primer punto completo después de «persona», la puerta de olvido se da cuenta de que puede haber un cambio de contexto en la siguiente frase. Como resultado de esto, el sujeto de la frase se olvida y el lugar para el sujeto queda vacante. Y cuando empezamos a hablar de «Dan» esta posición del sujeto se asigna a «Dan». Este proceso de olvido del sujeto es provocado por la puerta del olvido.

Una puerta del olvido se encarga de eliminar la información del estado celular. La información que ya no es necesaria para que la LSTM entienda las cosas o la información que es de menor importancia se elimina mediante la multiplicación de un filtro. Esto es necesario para optimizar el rendimiento de la red LSTM.

Esta puerta toma dos entradas; h_t-1 y x_t.

h_t-1 es el estado oculto de la célula anterior o la salida de la célula anterior y x_t es la entrada en ese paso de tiempo particular. Las entradas dadas se multiplican por las matrices de pesos y se añade un sesgo. A continuación, se aplica la función sigmoide a este valor. La función sigmoide da como resultado un vector, con valores que van de 0 a 1, correspondiente a cada número del estado de la célula. Básicamente, la función sigmoidea se encarga de decidir qué valores se mantienen y cuáles se descartan. Si se obtiene un «0» para un valor concreto del estado de la célula, significa que la puerta del olvido quiere que el estado de la célula olvide por completo esa información. Del mismo modo, un «1» significa que la puerta del olvido quiere recordar toda esa información. Este vector de salida de la función sigmoidea se multiplica al estado de la célula.

4.2 Puerta de entrada

Bien, tomemos otro ejemplo en el que la LSTM está analizando una frase:

Ahora la información importante aquí es que «Bob» sabe nadar y que ha servido a la Marina durante cuatro años. Esto puede ser añadido al estado de la célula, sin embargo, el hecho de que él dijo todo esto por teléfono es un hecho menos importante y puede ser ignorado. Este proceso de adición de nueva información se puede hacer a través de la puerta de entrada.

Aquí está su estructura:

La puerta de entrada es responsable de la adición de información al estado de la célula. Esta adición de información es básicamente un proceso de tres pasos como se ve en el diagrama anterior.

  1. Regula qué valores deben ser añadidos al estado de la célula mediante la participación de una función sigmoide. Esto es básicamente muy similar a la puerta de olvido y actúa como un filtro para toda la información de h_t-1 y x_t.
  2. Crear un vector que contenga todos los posibles valores que se pueden añadir (como se percibe de h_t-1 y x_t) al estado de la célula. Esto se hace utilizando la función tanh, que da como resultado valores de -1 a +1.
  3. Multiplicar el valor del filtro regulador (la puerta sigmoidea) al vector creado (la función tanh) y luego añadir esta información útil al estado de la célula mediante la operación de adición.

Una vez realizado este proceso de tres pasos, nos aseguramos de que sólo se añade al estado de la célula aquella información que es importante y no es redundante.

4.3 Puerta de salida

No toda la información que recorre el estado de la célula, es apta para ser salida en un momento determinado. Vamos a visualizar esto con un ejemplo:

En esta frase, podría haber un número de opciones para el espacio vacío. Pero sabemos que la entrada actual de «valiente», es un adjetivo que se utiliza para describir un sustantivo. Por lo tanto, cualquier palabra que siga, tiene una fuerte tendencia a ser un sustantivo. Y por lo tanto, Bob podría ser una salida apta.

Este trabajo de seleccionar la información útil del estado actual de la célula y mostrarla como una salida se realiza a través de la puerta de salida. Esta es su estructura:

El funcionamiento de una puerta de salida puede desglosarse de nuevo en tres pasos:

  1. Creación de un vector tras aplicar la función tanh al estado de la celda, escalando así los valores al rango -1 a +1.
  2. Crear un filtro utilizando los valores de h_t-1 y x_t, de forma que pueda regular los valores que deben salir del vector creado anteriormente. Este filtro vuelve a emplear una función sigmoidea.
  3. Multiplicando el valor de este filtro regulador al vector creado en el paso 1, y enviándolo como salida y también al estado oculto de la siguiente celda.

El filtro del ejemplo anterior se asegurará de disminuir todos los demás valores menos ‘Bob’. Por lo tanto, el filtro necesita ser construido en los valores de entrada y estado oculto y ser aplicado en el vector de estado de la celda.

Generación de texto utilizando LSTMs

Hemos tenido suficiente de los conceptos teóricos y el funcionamiento de LSTMs. Ahora estaríamos tratando de construir un modelo que pueda predecir algún número n de caracteres después del texto original de Macbeth. La mayoría de los textos clásicos ya no están protegidos por derechos de autor y se pueden encontrar aquí. Una versión actualizada del archivo .txt se puede encontrar aquí.

Utilizaremos la librería Keras, que es una API de alto nivel para redes neuronales y funciona sobre TensorFlow o Theano. Así que asegúrate de que antes de sumergirte en este código tienes Keras instalado y funcional.

¡Muy bien, vamos a generar algo de texto!

  • Importando dependencias

# Importing dependencies numpy and kerasimport numpyfrom keras.models import Sequentialfrom keras.layers import Densefrom keras.layers import Dropoutfrom keras.layers import LSTMfrom keras.utils import np_utils

Importamos todas las dependencias necesarias y esto se explica por sí mismo.

  • Carga del fichero de texto y creación de mapeos de caracteres a enteros

# load textfilename = "/macbeth.txt"text = (open(filename).read()).lower()# mapping characters with integersunique_chars = sorted(list(set(text)))char_to_int = {}int_to_char = {}for i, c in enumerate (unique_chars): char_to_int.update({c: i}) int_to_char.update({i: c})

Se abre el fichero de texto y se convierten todos los caracteres a minúsculas. Para facilitar los siguientes pasos, se mapea cada carácter a un número respectivo. Esto se hace para facilitar la parte de cálculo del LSTM.

  • Preparación del conjunto de datos

# preparing input and output datasetX = Y = for i in range(0, len(text) - 50, 1): sequence = text label =text X.append( for char in sequence]) Y.append(char_to_int)

Los datos se preparan en un formato tal que si queremos que el LSTM prediga la ‘O’ de ‘HELLO’ lo introduciríamos como entrada y como salida esperada. Del mismo modo, aquí fijamos la longitud de la secuencia que queremos (establecida en 50 en el ejemplo) y luego guardamos las codificaciones de los primeros 49 caracteres en X y la salida esperada, es decir, el 50º carácter en Y.

  • Modificación de X

# reshaping, normalizing and one hot encodingX_modified = numpy.reshape(X, (len(X), 50, 1))X_modified = X_modified / float(len(unique_chars))Y_modified = np_utils.to_categorical(Y)

Una red LSTM espera que la entrada sea de la forma en que muestras es el número de puntos de datos que tenemos, pasos de tiempo es el número de pasos dependientes del tiempo que hay en un solo punto de datos, características se refiere al número de variables que tenemos para el valor verdadero correspondiente en Y. Entonces escalamos los valores en X_modificado entre 0 y 1 y uno caliente codificamos nuestros valores verdaderos en Y_modificado.

  • Definiendo el modelo LSTM

# defining the LSTM modelmodel = Sequential()model.add(LSTM(300, input_shape=(X_modified.shape, X_modified.shape), return_sequences=True))model.add(Dropout(0.2))model.add(LSTM(300))model.add(Dropout(0.2))model.add(Dense(Y_modified.shape, activation='softmax'))model.compile(loss='categorical_crossentropy', optimizer='adam')

Se utiliza un modelo secuencial que es una pila lineal de capas. La primera capa es una capa LSTM con 300 unidades de memoria y devuelve secuencias. Esto se hace para garantizar que la siguiente capa LSTM reciba secuencias y no sólo datos dispersos al azar. Después de cada capa LSTM se aplica una capa de abandono para evitar el sobreajuste del modelo. Finalmente, tenemos la última capa como una capa totalmente conectada con una activación ‘softmax’ y neuronas iguales al número de caracteres únicos, porque necesitamos dar salida a un resultado codificado en caliente.

  • Ajuste del modelo y generación de caracteres

# fitting the modelmodel.fit(X_modified, Y_modified, epochs=1, batch_size=30)# picking a random seedstart_index = numpy.random.randint(0, len(X)-1)new_string = X# generating charactersfor i in range(50): x = numpy.reshape(new_string, (1, len(new_string), 1)) x = x / float(len(unique_chars)) #predicting pred_index = numpy.argmax(model.predict(x, verbose=0)) char_out = int_to_char seq_in = for value in new_string] print(char_out) new_string.append(pred_index) new_string = new_string

El modelo se ajusta durante 100 épocas, con un tamaño de lote de 30. A continuación, fijamos una semilla aleatoria (para facilitar la reproducibilidad) y empezamos a generar caracteres. La predicción del modelo da la codificación del carácter predicho, luego se decodifica de nuevo al valor del carácter y se añade al patrón.

Así es como se vería la salida de la red

Eventualmente, después de suficientes épocas de entrenamiento, dará resultados cada vez mejores con el tiempo. Así es como se utilizaría la LSTM para resolver una tarea de predicción de secuencias.

Notas finales

Las LSTMs son una solución muy prometedora para problemas relacionados con secuencias y series temporales. Sin embargo, la única desventaja que les encuentro, es la dificultad para entrenarlos. Se necesita mucho tiempo y recursos del sistema para entrenar incluso un modelo sencillo. Pero eso es sólo una limitación de hardware. Espero haber tenido éxito en darle una comprensión básica de estas redes. Para cualquier problema o cuestión relacionada con el blog, por favor, siéntase libre de comentar a continuación.

¡Aprenda, comprométase, piratee y sea contratado!

Deja una respuesta

Tu dirección de correo electrónico no será publicada.