Deep Learning

Unidad 4: Redes Neuronales Recurrentes (RNNs)

Francisco Plaza Vega

Ingeniería en Estadística

1 Redes Neuronales Recurrentes

1.1 ¿Qué dice YouTube?

1.2 ¿Qué son los datos secuenciales?

Datos secuenciales

Conjunto de observaciones recopiladas y ordenadas en función de un criterio temporal, espacial, o de cualquier otra dimensión en la que el orden de las observaciones sea esencial para su análisis.

  • Los algoritmos típicos de aprendizaje supervisado asumen que la entrada es independiente e idénticamente distribuida (IID), lo que significa que los ejemplos de entrenamiento son mutuamente independientes y tienen la misma distribución subyacente.

  • Si se tiene una muestra que consiste en \(n\) ejemplos de entrenamiento, \(x^{(1)}, x^{(2)}, \dots, x^{(n)}\), el orden en que se usan los datos para entrenar el algoritmo de aprendizaje automático no importa.

Ejemplo, los datos de iris
En el conjunto de datos **Iris**, cada flor ha sido medida de manera independiente, y las mediciones de una flor no influyen en las mediciones de otra flor.


library(datasets)
library(tidyverse)
data(iris)
iris %>% 
  slice_sample(n=10)
   Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
1           6.4         2.8          5.6         2.2  virginica
2           5.2         4.1          1.5         0.1     setosa
3           6.5         3.0          5.5         1.8  virginica
4           6.1         2.9          4.7         1.4 versicolor
5           5.6         2.5          3.9         1.1 versicolor
6           5.0         2.0          3.5         1.0 versicolor
7           4.4         3.2          1.3         0.2     setosa
8           4.5         2.3          1.3         0.3     setosa
9           6.7         3.0          5.0         1.7 versicolor
10          7.2         3.6          6.1         2.5  virginica

Lo anterior no funciona cuando trabajamos con secuencias, donde por definición, el orden importa.

Ejemplo: Datos financieros

  • Supongamos que tenemos una muestra de \(n\) ejemplos de entrenamiento, que representa el valor de mercado de cierta acción en un día particular.

  • Si el objetivo es predecir el valor del mercado de esa acción para los próximos tres días, tendría sentido considerar los precios previos en un orden cronológico, como al emplear un modelo Autoregresivo (AR) de series de tiempo.

library(cryptoQuotes)
library(xts)
library(tidyverse)
BTC <- get_quote(
  ticker   = "BTCUSDT",
  source   = "binance",
  futures  = FALSE,
  interval = "1d",
  from     = Sys.Date() - 90
)
data.frame(date = index(BTC),
           BTC = BTC$close) %>% 
  mutate(date = as.POSIXct(date)) %>% 
  ggplot()+
  geom_line(aes(x=date, y=close), color="#00a499", linewidth=1.5) +
  ylab("Precio de BTC en (USD)") + xlab("Días") +
  theme_minimal()

1.3 Series de tiempo

Un recordatorio… o no?

  • Una serie de tiempo corresponde a una colección de observaciones \(y_t\), registradas en un tiempo específico \(t\).

  • Usualmente \(t \in \mathbb{Z}\), donde \(\mathbb{Z} = \{..., -2, -1, 0, 1, 2, ... \}\) es un conjunto de valores enteros positivos y negativos. En la práctica, sólo una parte finita de los datos está disponible, donde podemos escribir la serie de tiempo como \(\{y_1, y_2, ..., y_n \}\).

  • Formalmente, una serie de tiempo \(\{y_t \}\) corresponde a una realización de un proceso estocástico que está compuesto de variables aleatorias observadas a lo largo del tiempo.

  • Una serie de tiempo de tipo discreta, es aquella en la que la colección de tiempos \(T_0\) en la que se hacen las observaciones es un conjunto discreto.

  • Una serie de tiempo de tipo continua es obtenida cuando las observaciones son tomadas de manera continua sobre un intervalo de tiempo, por ejemplo \(T_0 = [0,1]\).

Una de las características principales de las series de tiempo es el hecho que observaciones sucesivas no son usualmente independientes, por lo que el análisis debe tomar en cuenta el orden temporal de las observaciones.

library(tidyverse)
library(ggplot2)
library(readr)

# Vino ----
# URL de los datos
url <- "https://raw.githubusercontent.com/rajansharm/Time-Series-Analysis/refs/heads/master/AusWineSales.csv"

# Leer los datos desde el enlace
wine_data <- read_csv(url)

# Convertir el campo 'YearMonth' a formato de fecha
wine_data$YearMonth <- as.Date(paste0(wine_data$YearMonth, "-01"))

# Crear el gráfico
wine =
ggplot(wine_data, aes(x = YearMonth, y = Red)) +
  geom_line(color = "#00a499", linewidth = 0.7) +            
  geom_point(color = "#00a499", size = 2) +
  labs(
    x = "Años",
    y = "Ventas de vino tinto\n en Australia"
  ) +
  theme_bw()
library(tidyverse)
library(ggplot2)
library(readr)
library(zoo)

# SST ----
url <- "https://psl.noaa.gov/data/correlation/nina34.anom.data"
data_raw <- read_lines(url)
data_lines <- data_raw %>%
  .[-1] %>%                                # Eliminar automáticamente la primera línea
  .[str_detect(., "^[ ]*[0-9]{4}")]        # Mantener líneas que comienzan con un año de 4 dígitos

# Convertir las líneas en un data frame procesable
data <- data_lines %>%
  str_trim() %>%
  str_split("\\s+", simplify = TRUE) %>%
  as.data.frame(stringsAsFactors = FALSE) %>%
  set_names(c("Year", paste0("Month_", 1:12))) %>%
  mutate(across(everything(), as.numeric)) %>%
  pivot_longer(cols = starts_with("Month_"), names_to = "Month", values_to = "Temperature") %>%
  mutate(Month = as.numeric(str_remove(Month, "Month_")),
         Time = Year + (Month - 1) / 12) %>%
  filter(Temperature > -99)

# Calcular la media móvil de 5 años
data <- data %>%
  arrange(Time) %>%
  mutate(Moving_Avg = rollmean(Temperature, k = 60, fill = NA, align = "center")) # 5 años * 12 meses = 60

# Crear la gráfica
sst =  ggplot(data, aes(x = Time)) +
  geom_line(aes(y = Temperature), color = "#00a499", alpha = 1, size = 0.8) +
  geom_line(aes(y = Moving_Avg), color = "#ea7600", size = 1) + # Línea de tendencia
  labs(
    x = "Años",
    y = "TSM en la región\n Niño34 (°C)"
  ) +
  theme_bw()
library(tidyverse)
library(ggplot2)
library(latex2exp)

# Continua 1 ----
cont1 = data.frame(t = seq(0,200)) %>% 
  mutate(N = rnorm(length(t)),
         x = cos(t/10) + N) %>% 
  ggplot(aes(x = t, y=x)) +
  geom_line(color = "#00a499", linewidth = 0.7) +            
  geom_point(color = "#00a499", size = 2) +
  xlab(TeX("t")) + 
  ylab(TeX("$X_t = cos(\\frac{t}{10})+N_t")) +
  theme_bw()

# Continua 2 ----
cont2 = data.frame(t = seq(0,100)) %>% 
  mutate(x = cos(0.2*t + pi/3)) %>% 
  ggplot(aes(x = t, y=x)) +
  geom_line(color = "#00a499", linewidth = 0.7) +            
  geom_point(color = "#00a499", size = 2) +
  xlab(TeX("t")) + 
  ylab(TeX("$X_t = cos(0.2t + \\frac{\\pi}{3})")) +
  theme_bw()

1.4 Objetivos del análisis de series de tiempo

Existen distintos objetivos posibles del análisis de series de tiempo. Estos objetivos pueden ser clasificados en 4 categorías:

  • Describir
  • Explicar
  • Predecir
  • Controlar

1.5 Representando secuencias

A partir de las definiciones de Raschka y Mirjalili (2019)

Traducido de @Raschka2019

1.6 Categorías en la modelación de secuencias

Traducido de @Raschka2019

1.6.1 Muchos a uno

Traducido de @Raschka2019

Many-to-one (Muchos a uno): Los datos de entrada son una secuencia, pero la salida es un vector o escalar de tamaño fijo, no una secuencia. Por ejemplo, en el análisis de sentimiento, la entrada es un texto (como una reseña de película) y la salida es una etiqueta de clase (por ejemplo, una etiqueta que indica si al crítico le gustó la película).

1.6.2 Uno a Muchos

Traducido de @Raschka2019

One-to-many (Uno a muchos): Los datos de entrada están en formato estándar y no son una secuencia, pero la salida es una secuencia. Un ejemplo de esta categoría es la generación de subtítulos para imágenes: la entrada es una imagen y la salida es una frase en inglés que resume el contenido de esa imagen.

1.6.3 Muchos a Muchos

Traducido de @Raschka2019

Traducido de @Raschka2019

Many-to-many (Muchos a muchos): Tanto las entradas como las salidas son secuencias. Esta categoría puede dividirse aún más dependiendo de si las entradas y salidas están sincronizadas o no.

  • Un ejemplo de una tarea many-to-many sincronizada es la clasificación de video, donde cada cuadro en un video está etiquetado.

  • Un ejemplo de una tarea many-to-many con retraso sería la traducción de un idioma a otro. Por ejemplo, una frase completa en inglés debe ser procesada por una máquina antes de que se produzca su traducción al español.

2 RNN para secuencias

2.1 Entendiendo el mecanismo cíclico de las RNNs

Traducido de @Raschka2019

Ambas redes tienen solo una capa oculta. En esta representación, las unidades no se muestran, pero asumimos que la capa de entrada \((x)\), la capa oculta \((h)\) y la capa de salida \((o)\) son vectores que contienen muchas unidades.

  • En una red feedforward estándar, la información fluye desde la capa de entrada hasta la capa oculta, y luego desde la capa oculta hasta la capa de salida. Por otro lado, en una RNN (Red Neuronal Recurrente), la capa oculta recibe su entrada tanto de la capa de entrada del instante de tiempo actual como de la capa oculta del instante de tiempo anterior.

  • El flujo de información entre pasos de tiempo adyacentes en la capa oculta permite que la red tenga una memoria de eventos pasados. Este flujo de información se representa usualmente como un bucle, también conocido como un borde recurrente (recurrent edge) en notación de grafos, lo cual explica el origen del nombre de esta arquitectura general de RNN.

Similar a los MLP, las RNN pueden consistir en múltiples capas ocultas.

  • Cada unidad oculta en una red neuronal estándar (MLP) recibe sólo una entrada: la preactivación neta asociada a la capa de entrada. Sin embargo, cada unidad oculta en una RNN recibe dos conjuntos distintos de entradas: la preactivación desde la capa de entrada y la activación de la misma capa oculta desde el paso de tiempo anterior, \(t - 1\).

  • En el primer paso de tiempo, \(t = 0\), el estado oculto inicial usualmente se inicializa en cero o se considera un parámetro aprendible. Luego, en un paso de tiempo donde \(t > 0\), las unidades ocultas reciben su entrada desde el punto de datos en el tiempo actual, \(x^{(t)}\), y desde los valores anteriores de las unidades ocultas en \(t - 1\), indicados como \(h^{(t-1)}\).

En el caso de una RNN multicapa:

  • capa_1: La primera capa oculta se representa como \(\mathbf{h}_1^{(t)}\) y recibe su entrada desde el punto de datos \(\mathbf{x}^{(t)}\) y desde los valores ocultos de la misma capa, pero en el paso de tiempo anterior, \(\mathbf{h}_1^{(t-1)}\).

  • capa_2: La segunda capa oculta, \(\mathbf{h}_2^{(t)}\), recibe el estado oculto de la capa inferior en el mismo instante, \(\mathbf{h}_1^{(t)}\), junto con su propio estado oculto anterior, \(\mathbf{h}_2^{(t-1)}\).

2.2 Cálculo de activaciones en una RNN

Para simplificar, consideraremos solo una capa oculta; sin embargo, el mismo concepto aplica a RNNs multicapa.

Cada borde dirigido (las conexiones entre cajas) en la representación de una RNN que acabamos de ver está asociado a una matriz de pesos. Estos pesos no dependen del tiempo \(t\), por lo tanto, se comparten a lo largo del eje temporal. Las distintas matrices de pesos en una RNN de una sola capa son las siguientes:

  • \(\mathbf{W}_{xh}\): La matriz de pesos entre la entrada, \(\mathbf{x}^{(t)}\), y la capa oculta, \(\mathbf{h}\)

  • \(\mathbf{W}_{hh}\): La matriz de pesos asociada al borde recurrente

  • \(\mathbf{W}_{ho}\): La matriz de pesos entre la capa oculta y la capa de salida

En ciertas implementaciones, puede observarse que las matrices de pesos, \(\mathbf{W}_{xh}\) y \(\mathbf{W}_{hh}\), se concatenan horizontalmente en una matriz combinada, \(\mathbf{W}_h = [\mathbf{W}_{xh} \, \mathbf{W}_{hh}]\). Más adelante en esta sección, también utilizaremos esta notación.

El cálculo de las activaciones es muy similar al de los perceptrones multicapa estándar y otros tipos de redes neuronales feedforward. Para la capa oculta, la entrada neta, \(\mathbf{z}_h\) (preactivación), se calcula mediante una combinación lineal, es decir, computamos la suma de las multiplicaciones de las matrices de pesos con los vectores correspondientes y añadimos el término de sesgo:

\[ \mathbf{z}_h^{(t)} = \mathbf{W}_{xh} \mathbf{x}^{(t)} + \mathbf{W}_{hh} \mathbf{h}^{(t-1)} + \mathbf{b}_h \]

Luego, las activaciones de las unidades ocultas en el instante de tiempo \(t\) se calculan de la siguiente manera:

\[ \mathbf{h}^{(t)} = \phi_h \left( \mathbf{z}_h^{(t)} \right) = \phi_h \left( \mathbf{W}_{xh} \mathbf{x}^{(t)} + \mathbf{W}_{hh} \mathbf{h}^{(t-1)} + \mathbf{b}_h \right) \]

Aquí, \(\mathbf{b}_h\) es el vector de sesgo para las unidades ocultas y \(\phi_h(\cdot)\) es la función de activación de la capa oculta.

En caso de que se desee utilizar la matriz de pesos concatenada, \(\mathbf{W}_h = [\mathbf{W}_{xh} \, \mathbf{W}_{hh}]\), la fórmula para calcular las unidades ocultas cambia de la siguiente manera:

\[ \mathbf{h}^{(t)} = \phi_h \left( \left[ \mathbf{W}_{xh} \, \mathbf{W}_{hh} \right] \begin{bmatrix} \mathbf{x}^{(t)} \\ \mathbf{h}^{(t-1)} \end{bmatrix} + \mathbf{b}_h \right) \]

Una vez que se han calculado las activaciones de las unidades ocultas en el paso de tiempo actual, se computan las activaciones de la capa de salida de la siguiente forma:

\[ \mathbf{o}^{(t)} = \phi_o \left( \mathbf{W}_{ho} \mathbf{h}^{(t)} + \mathbf{b}_o \right) \]

Para clarificar aún más este proceso, se muestra cómo se computan estas activaciones con ambas formulaciones.

2.3 Entrenamiento de RNNs

El algoritmo de aprendizaje para RNNs fue introducido en 1990: Backpropagation Through Time: What It Does and How to Do It (Werbos 1990).

La derivación de los gradientes puede ser algo compleja, pero la idea básica es que la pérdida total, \(L\), es la suma de todas las funciones de pérdida en los tiempos \(t = 1\) hasta \(t = T\):

\[ L = \sum_{t=1}^{T} L^{(t)} \]

Esta forma aparece naturalmente en problemas muchos-a-muchos. En problemas muchos-a-uno, la pérdida puede calcularse solo al final, por ejemplo \(L = L^{(T)}\).

Dado que la pérdida en el tiempo \(t\) depende de las unidades ocultas en todos los pasos de tiempo anteriores \(1 : t\), el gradiente se calcula de la siguiente forma:

\[ \frac{\partial L^{(t)}}{\partial \mathbf{W}_{hh}} = \frac{\partial L^{(t)}}{\partial \mathbf{o}^{(t)}} \times \frac{\partial \mathbf{o}^{(t)}}{\partial \mathbf{h}^{(t)}} \times \left( \sum_{k=1}^{t} \frac{\partial \mathbf{h}^{(t)}}{\partial \mathbf{h}^{(k)}} \times \frac{\partial \mathbf{h}^{(k)}}{\partial \mathbf{W}_{hh}} \right) \]

Aquí, \(\frac{\partial \mathbf{h}^{(t)}}{\partial \mathbf{h}^{(k)}}\) se calcula como el producto de derivadas a través de los pasos de tiempo adyacentes:

\[ \frac{\partial \mathbf{h}^{(t)}}{\partial \mathbf{h}^{(k)}} = \prod_{i = k+1}^{t} \frac{\partial \mathbf{h}^{(i)}}{\partial \mathbf{h}^{(i-1)}} \]

Recurrencia en la capa oculta versus recurrencia en la capa de salida

Hasta ahora, hemos visto redes recurrentes en las que la capa oculta posee la propiedad recurrente. Sin embargo, es importante notar que existe un modelo alternativo en el cual la conexión recurrente proviene desde la capa de salida. En este caso, las activaciones netas de la capa de salida en el paso de tiempo anterior, \(\mathbf{o}^{t-1}\), pueden agregarse de una de las siguientes dos maneras:

  • A la capa oculta en el paso de tiempo actual, \(\mathbf{h}^{t}\) (mostrado en la figura siguiente como output-to-hidden recurrence)

  • A la capa de salida en el paso de tiempo actual, \(\mathbf{o}^{t}\) (mostrado en la figura siguiente como output-to-output recurrence)

3 Los desafíos de aprender interacciones de largo alcance: Redes LSTM

Back propagation through time (BPTT) introduce nuevos desafíos. Debido al factor multiplicativo, \(\frac{\partial \mathbf{h}^{(t)}}{\partial \mathbf{h}^{(k)}}\), en el cálculo de los gradientes de una función de pérdida, surgen los llamados problemas de gradientes que se desvanecen (vanishing) y gradientes que explotan (exploding).

  • Para intuir el problema, imaginemos una recurrencia escalar muy simple. En ese caso, \(\frac{\partial \mathbf{h}^{(t)}}{\partial \mathbf{h}^{(k)}}\) implica \(t - k\) multiplicaciones; por lo tanto, multiplicar el peso \(w\) por sí mismo \(t - k\) veces da como resultado un factor de \(w^{t-k}\):

    • Si \(|w| < 1\), este factor se vuelve muy pequeño cuando \(t - k\) es grande.

    • Por otro lado, si el peso del borde recurrente es \(|w| > 1\), entonces \(w^{t-k}\) se vuelve muy grande cuando \(t - k\) es grande.

  • Esta expresión escalar es una simplificación pedagógica. En una RNN real, el comportamiento depende del producto de matrices jacobianas, pesos recurrentes y derivadas de las funciones de activación.

  • Cabe notar que un gran valor de \(t - k\) se refiere a dependencias de largo alcance (long-range dependencies). Si estás interesado y deseas investigar esto en más detalle, puedes leer On the difficulty of training recurrent neural networks (Pascanu et al. 2012).

3.1 ¿Qué podemos hacer en la práctica?

  • Gradient clipping: limita la magnitud de los gradientes y se utiliza principalmente para controlar gradientes explosivos.

  • Truncated Backpropagation Through Time (TBPTT): reduce el costo computacional y limita cuántos pasos hacia atrás fluye el gradiente, pero también limita la capacidad de aprender dependencias de largo alcance.

  • LSTM y GRU: introducen mecanismos de compuertas y caminos de actualización más estables que ayudan a preservar información y mitigar el desvanecimiento del gradiente.

Idea clave

Estas estrategias ayudan, pero no eliminan mágicamente todos los problemas de gradientes. En la práctica, conviene combinarlas con una buena escala de datos, regularización, selección cuidadosa de la longitud de secuencia y evaluación empírica.

3.2 Esquema general de una celda LSTM

  • Las LSTM fueron introducidas por primera vez para superar el problema de los gradientes que se desvanecen (vanishing gradient problem) en el artículo de Hochreiter y Schmidhuber (1997).

  • El bloque fundamental de una LSTM es una celda de memoria (memory cell), que esencialmente representa o reemplaza la capa oculta de las RNN estándar.

La estructura interna de una celda LSTM muestra tres componentes fundamentales, conocidos como puertas (gates), que controlan el flujo de información dentro de la celda:

  • Forget Gate (Puerta de olvido): decide qué parte de la información del estado de celda anterior \(\mathbf{c}^{(t-1)}\) debe ser descartada. Esta puerta evalúa qué tan relevante sigue siendo la información del pasado y produce una salida \(\mathbf{f}_t\) que modula dicha memoria.

  • Input Gate (Puerta de entrada): regula qué nueva información, proveniente de la entrada actual \(\mathbf{x}^{(t)}\) y del estado oculto anterior \(\mathbf{h}^{(t-1)}\), será incorporada al estado de celda actual. La señal de esta puerta se denota como \(\mathbf{i}_t\).

  • Output Gate (Puerta de salida): determina qué parte del estado de celda actualizado \(\mathbf{c}^{(t)}\) se convierte en la salida de la celda, es decir, en el nuevo estado oculto \(\mathbf{h}^{(t)}\) que se propaga al siguiente paso de tiempo o a la capa superior.

3.2.1 Un doble clic a las celdas LSTM

3.3 El camino del estado de la celda

La actualización del estado de la celda tiene una estructura principalmente aditiva:

\[ \mathbf{c}^{(t)} = \mathbf{f}_t \odot \mathbf{c}^{(t-1)} + \mathbf{i}_t \odot \widetilde{\mathbf{c}}_t. \]

Esto permite que la información pueda propagarse por más pasos de tiempo cuando los valores de la puerta de olvido son cercanos a uno.

Compuertas continuas

Las compuertas no son interruptores binarios. La función sigmoide entrega valores entre 0 y 1, por lo que cada puerta regula de manera continua cuánto recordar, cuánto actualizar y cuánto exponer como salida.

3.4 Puerta de olvido

Compuertas o gates

La compuerta de olvido (\(\mathbf{f}_t\)) decide qué parte del estado de celda anterior, \(\mathbf{c}^{(t-1)}\), se conserva y qué parte se atenúa.

\[ \mathbf{f}_t = \sigma\left( \mathbf{W}_{xf}\mathbf{x}^{(t)} + \mathbf{W}_{hf}\mathbf{h}^{(t-1)} + \mathbf{b}_f \right). \]

Nota

La compuerta de olvido no formaba parte de la celda LSTM original. Fue añadida años más tarde para mejorar el modelo original. El artículo lleva por título Learning to Forget: Continual Prediction with LSTM (Gers et al. 2000).

3.5 Puerta de entrada y contenido candidato

La compuerta de entrada regula cuánta información nueva se incorpora, mientras que el contenido candidato propone qué podría agregarse al estado de la celda.

\[ \mathbf{i}_t = \sigma\left( \mathbf{W}_{xi}\mathbf{x}^{(t)} + \mathbf{W}_{hi}\mathbf{h}^{(t-1)} + \mathbf{b}_i \right), \]

\[ \widetilde{\mathbf{c}}_t = \tanh\left( \mathbf{W}_{xc}\mathbf{x}^{(t)} + \mathbf{W}_{hc}\mathbf{h}^{(t-1)} + \mathbf{b}_c \right). \]

3.6 Actualización del estado y salida

La celda mezcla memoria anterior y contenido nuevo, y luego decide qué parte de ese estado se expone como estado oculto.

\[ \mathbf{c}^{(t)} = \mathbf{f}_t \odot \mathbf{c}^{(t-1)} + \mathbf{i}_t \odot \widetilde{\mathbf{c}}_t, \]

\[ \mathbf{o}_t = \sigma\left( \mathbf{W}_{xo}\mathbf{x}^{(t)} + \mathbf{W}_{ho}\mathbf{h}^{(t-1)} + \mathbf{b}_o \right), \]

\[ \mathbf{h}^{(t)} = \mathbf{o}_t \odot \tanh\left(\mathbf{c}^{(t)}\right). \]

Otros modelos avanzados de RNN

Las LSTM proporcionan un enfoque básico para modelar dependencias de largo alcance en secuencias. Sin embargo, es importante destacar que existen muchas variaciones de las LSTM descritas en la literatura.

También vale la pena mencionar la Unidad Recurrente con Compuertas (Gated Recurrent Unit, GRU), propuesta en 2014. La GRU mantiene la idea de compuertas, pero con una arquitectura más compacta (Cho et al. 2014; Chung et al. 2014).

4 Gated Recurrent Unit (GRU)

4.1 Una arquitectura recurrente más compacta

La Gated Recurrent Unit, GRU, utiliza compuertas para controlar el flujo de información, pero presenta una estructura más simple que una LSTM (Cho et al. 2014; Zhang et al. 2023).

  • No mantiene un estado de celda separado \(\mathbf{c}^{(t)}\).

  • Toda la memoria se representa mediante el estado oculto \(\mathbf{h}^{(t)}\).

  • Utiliza dos compuertas principales: compuerta de actualización, \(\mathbf{z}_t\), y compuerta de reinicio, \(\mathbf{r}_t\).

4.2 Compuertas de una GRU

\[ \mathbf{z}_t = \sigma\left( \mathbf{W}_{xz}\mathbf{x}^{(t)} + \mathbf{W}_{hz}\mathbf{h}^{(t-1)} + \mathbf{b}_z \right), \]

\[ \mathbf{r}_t = \sigma\left( \mathbf{W}_{xr}\mathbf{x}^{(t)} + \mathbf{W}_{hr}\mathbf{h}^{(t-1)} + \mathbf{b}_r \right). \]

  • \(\mathbf{z}_t\) controla cuánto se conserva del estado anterior.

  • \(\mathbf{r}_t\) controla cuánto del pasado se utiliza para construir el candidato.

4.3 Candidato y actualización

\[ \widetilde{\mathbf{h}}^{(t)} = \tanh\left( \mathbf{W}_{xh}\mathbf{x}^{(t)} + \mathbf{W}_{hh} \left( \mathbf{r}_t\odot\mathbf{h}^{(t-1)} \right) + \mathbf{b}_h \right), \]

\[ \mathbf{h}^{(t)} = \mathbf{z}_t\odot\mathbf{h}^{(t-1)} + \left(1-\mathbf{z}_t\right) \odot\widetilde{\mathbf{h}}^{(t)}. \]

Lectura rápida

Con esta convención, si \(\mathbf{z}_t\) es cercano a uno, la GRU conserva principalmente el estado anterior. Si \(\mathbf{z}_t\) es cercano a cero, usa más el candidato.

4.4 LSTM versus GRU

4.4.1 LSTM

  • Estado oculto \(\mathbf{h}^{(t)}\).
  • Estado de celda \(\mathbf{c}^{(t)}\).
  • Puertas de olvido, entrada y salida.
  • Mayor control explícito de la memoria.

4.4.2 GRU

  • Un único estado \(\mathbf{h}^{(t)}\).
  • Puertas de actualización y reinicio.
  • Menor cantidad de parámetros para una dimensión oculta equivalente.
  • Arquitectura más compacta.

Nota

No existe una arquitectura universalmente superior. La elección entre LSTM y GRU debe evaluarse empíricamente según los datos, el tamaño de la muestra y la tarea (Chung et al. 2014).

5 Aplicaciones de RNN, LSTM y GRU

5.1 Mapa rápido de aplicaciones

5.2 ¿Dónde pueden utilizarse?

Las arquitecturas recurrentes pueden emplearse en tareas donde el orden y el contexto acumulado son relevantes:

  • Clasificación de secuencias: análisis de sentimiento o clasificación de señales.

  • Etiquetado de secuencias: asignar una categoría a cada palabra o instante.

  • Generación de secuencias: texto, música o señales.

  • Pronóstico de series temporales: predecir uno o varios valores futuros.

5.3 Procesamiento de lenguaje natural

En lenguaje natural, cada palabra o token se interpreta considerando el contexto proporcionado por los elementos anteriores de la secuencia.

  • Muchos a uno: una reseña completa se transforma en una etiqueta de sentimiento.

  • Muchos a muchos sincronizado: cada palabra recibe una etiqueta gramatical o una categoría.

  • Secuencia a secuencia: una oración de entrada se transforma en una oración de salida, como ocurre en traducción automática.

5.4 Generación de texto

\[ p(x^{(1)},\ldots,x^{(T)}) = \prod_{t=1}^{T} p\left( x^{(t)} \mid x^{(1)},\ldots,x^{(t-1)} \right). \]

Durante entrenamiento y generación

Durante el entrenamiento puede utilizarse el elemento verdadero anterior como entrada, estrategia conocida como teacher forcing. Durante la generación, el elemento predicho se incorpora nuevamente al modelo para producir el siguiente.

5.5 RNN y LSTM para series temporales

Para construir un problema supervisado, una ventana de observaciones pasadas puede utilizarse para predecir uno o varios valores futuros:

\[ \left[ \mathbf{x}^{(t-p+1)}, \ldots, \mathbf{x}^{(t)} \right] \longrightarrow \left[ y^{(t+1)}, \ldots, y^{(t+H)} \right]. \]

donde \(p\) representa la longitud de la ventana de entrada y \(H\) el horizonte de pronóstico.

5.6 RNN y LSTM para series temporales

Las entradas pueden incluir una única serie o múltiples covariables, por ejemplo capturas, esfuerzo pesquero, temperatura superficial del mar e índices climáticos.

  • La ventana de entrada resume el pasado disponible.

  • El horizonte de pronóstico define cuántos pasos hacia adelante queremos predecir.

  • La validación debe respetar la dirección del tiempo.

5.7 Una precaución importante en series temporales

Advertencia

  • Las muestras de entrenamiento, validación y prueba deben respetar el orden temporal.

  • La normalización debe estimarse utilizando únicamente los datos de entrenamiento.

  • Las observaciones futuras no pueden utilizarse para construir variables de entrada del pasado.

  • El desempeño debe compararse con modelos de referencia simples, como persistencia, promedio histórico o modelos autorregresivos básicos.

6 Referencias

Cho, Kyunghyun, Bart van Merriënboer, Dzmitry Bahdanau, y Yoshua Bengio. 2014. «On the Properties of Neural Machine Translation: Encoder–Decoder Approaches». arXiv preprint arXiv:1409.1259.
Chung, Junyoung, Caglar Gulcehre, KyungHyun Cho, y Yoshua Bengio. 2014. «Empirical evaluation of gated recurrent neural networks on sequence modeling». arXiv preprint arXiv:1412.3555.
Gers, Felix A, Jürgen Schmidhuber, y Fred Cummins. 2000. «Learning to forget: Continual prediction with LSTM». Neural computation 12 (10): 2451-71.
Hochreiter, Sepp, y Jürgen Schmidhuber. 1997. «Long short-term memory». Neural computation 9 (8): 1735-80.
Pascanu, Razvan, Tomas Mikolov, y Yoshua Bengio. 2012. «On the difficulty of training Recurrent Neural Networks». arXiv e-prints, arXiv-1211.
Raschka, Sebastian, y Vahid Mirjalili. 2019. Python machine learning: Machine learning and deep learning with Python, scikit-learn, and TensorFlow 2. Packt Publishing Ltd.
Werbos, Paul J. 1990. «Backpropagation through time: what it does and how to do it». Proceedings of the IEEE 78 (10): 1550-60.
Zhang, Aston, Zachary C Lipton, Mu Li, y Alexander J Smola. 2023. Dive into deep learning. Cambridge University Press.