En el tema anterior vimos por qué las redes neuronales resultaron tan importantes para el NLP. Sin embargo, también señalamos un problema central: el texto es secuencial, y no todas las arquitecturas manejan bien el orden y la dependencia entre palabras.
Las redes recurrentes, conocidas como RNN por su nombre en inglés Recurrent Neural Networks, surgieron precisamente para enfrentar ese desafío.
Su idea principal es procesar la secuencia paso a paso, manteniendo una forma de memoria interna que resume lo visto hasta el momento.
Si procesamos una oración como un simple vector fijo, podemos perder información importante sobre el orden de las palabras. En lenguaje natural, el orden importa mucho.
Una secuencia no es solo un conjunto de tokens. Cada palabra aparece en una posición y su interpretación suele depender de lo que vino antes. Las RNN intentan incorporar esa dimensión temporal o secuencial al procesamiento.
La palabra recurrente indica que la red reutiliza una misma transformación en cada paso de la secuencia. En lugar de tener una operación completamente distinta para cada palabra, la RNN aplica repetidamente la misma lógica mientras avanza token por token.
En cada paso recibe dos elementos:
Con esos dos elementos calcula un nuevo estado y, si corresponde, una salida.
El concepto más importante en una RNN es el estado oculto. Puede pensarse como una memoria compacta de lo que la red ha leído hasta el momento.
Cuando entra una nueva palabra, la red combina esa palabra con el estado previo y produce un nuevo estado. Así, la información se va arrastrando de un paso al siguiente.
Si la secuencia es "el gato duerme", al llegar a "duerme" la red ya ha procesado "el" y "gato", y su estado interno debería contener una representación útil de ese contexto.
Una RNN no ve toda la oración como una única pieza estática. La recorre en orden, generalmente de izquierda a derecha, actualizando su estado a cada paso.
Esto permite modelar secuencias de longitud variable y capturar, al menos en principio, la dependencia entre elementos consecutivos.
La idea tiene un atractivo claro para NLP: el texto se parece naturalmente a una secuencia temporal de símbolos.
Podemos imaginar una RNN como un lector que avanza palabra por palabra y va tomando notas mentales sobre lo leído. Esas notas no son una copia exacta del texto, sino un resumen comprimido del contexto acumulado.
Cada nueva palabra puede modificar ese resumen, reforzando algunas pistas y desplazando otras.
Una RNN puede utilizarse de distintas maneras según la tarea:
Esto la vuelve bastante flexible para distintos problemas de NLP.
Supongamos que queremos clasificar una reseña como positiva o negativa. Una RNN puede leer la secuencia de palabras y producir una representación final del texto en su último estado oculto. A partir de ese estado, una capa de salida puede decidir la clase.
La esperanza es que ese estado final haya capturado información suficiente sobre el contenido y el tono de la reseña.
En tareas como etiquetado gramatical o reconocimiento de entidades, puede interesar producir una salida en cada posición. En ese caso, la RNN procesa la secuencia y genera una predicción por token.
Por ejemplo, al leer una oración, puede intentar decidir en cada palabra si se trata de un sustantivo, un verbo, una entidad geográfica u otra categoría.
El gran aporte de las RNN fue introducir una forma explícita de manejar secuencias y contexto acumulado. Frente a modelos que solo reciben un vector fijo sin orden, las RNN incorporan una noción de historia.
Esto las hizo especialmente relevantes antes de la aparición de mecanismos de atención y Transformers.
Otra característica importante es que la misma transformación se reutiliza en todos los pasos de la secuencia. Eso significa que la red comparte parámetros a lo largo del tiempo.
Gracias a esta compartición, el modelo puede aplicarse a secuencias de distintas longitudes sin necesitar un conjunto distinto de pesos para cada posición.
El entrenamiento de una RNN sigue la lógica general de las redes neuronales: el modelo produce salidas, calcula una pérdida y ajusta sus parámetros para reducir el error.
La diferencia es que ahora el cálculo debe considerar una cadena de pasos temporales. Esto hace que el entrenamiento sea más delicado que en arquitecturas completamente feedforward.
En teoría, una RNN puede transportar información a lo largo de muchos pasos. En la práctica, mantener dependencias largas resulta difícil.
Si una palabra importante apareció muy al comienzo de la secuencia, la red puede tener problemas para conservar esa señal hasta mucho después. Esto afecta tareas en las que una decisión depende de contexto lejano.
Una de las limitaciones más conocidas de las RNN simples es el desvanecimiento del gradiente. Durante el entrenamiento, las señales de ajuste pueden debilitarse a medida que retroceden muchos pasos en la secuencia.
Como consecuencia, la red tiene dificultades para aprender relaciones que conectan elementos lejanos entre sí.
Existe también el problema opuesto, conocido como explosión del gradiente, donde las actualizaciones pueden volverse inestables.
Las RNN suelen funcionar razonablemente bien cuando las dependencias relevantes no son excesivamente largas y cuando la estructura secuencial local es importante.
Por eso fueron muy utilizadas en tareas como:
Una RNN básica suele recorrer la secuencia en un solo sentido, por ejemplo de izquierda a derecha. Pero en algunas tareas conviene mirar tanto el pasado como el futuro relativo de cada palabra.
Para eso surgieron las RNN bidireccionales, que procesan la secuencia en ambos sentidos y combinan la información. Así, la representación de una palabra puede incorporar contexto previo y posterior.
Normalmente, una RNN no recibe palabras en bruto, sino embeddings. Cada token se convierte primero en un vector denso y luego ese vector se entrega a la red recurrente.
Esto permite que la red trabaje con representaciones numéricas más informativas y que pueda generalizar mejor entre palabras similares.
Las RNN fueron un paso muy importante en la historia del NLP neuronal por varias razones:
Con el tiempo también quedaron claras sus debilidades:
Estas limitaciones motivaron el desarrollo de variantes más sofisticadas.
Si el gran problema de las RNN simples era retener información útil a lo largo del tiempo, era natural buscar arquitecturas con mecanismos de memoria más robustos.
De ahí surgieron LSTM y GRU, que agregaron compuertas y estrategias de control del flujo de información para conservar mejor el contexto relevante y olvidar lo que no importa.
| Aspecto | RNN simple | Modelos no secuenciales |
|---|---|---|
| Orden de palabras | Lo incorpora explícitamente. | Puede perderse o simplificarse. |
| Longitud variable | Se adapta bien. | Suele requerir más diseño manual. |
| Dependencias largas | Limitadas en la práctica. | Generalmente pobres si no hay mecanismo especial. |
| Paralelización | Más difícil por el procesamiento paso a paso. | Más simple en algunos modelos feedforward. |
Con PyTorch podemos ver una RNN muy pequeña procesando una secuencia de tokens. El objetivo aquí no es entrenarla, sino observar cómo la arquitectura produce un estado final después de recorrer el texto paso a paso.
import torch
import torch.nn as nn
batch_size = 2
longitud = 4
dim_entrada = 6
dim_oculta = 8
x = torch.randn(batch_size, longitud, dim_entrada)
rnn = nn.RNN(input_size=dim_entrada, hidden_size=dim_oculta, batch_first=True)
salidas, estado_final = rnn(x)
print("Salidas por paso:", salidas.shape) # (2, 4, 8)
print("Estado final:", estado_final.shape) # (1, 2, 8)
La parte interesante es que la red devuelve una salida por cada paso de la secuencia y también un estado final que resume lo leído. Esa es la mecánica básica que hizo tan influyentes a las RNN en NLP.
Las redes recurrentes representaron un avance decisivo porque introdujeron una forma explícita de trabajar con secuencias en NLP. Gracias a ellas, el contexto dejó de tratarse como una mera vecindad estática y pasó a modelarse como una historia que se va acumulando.
Sin embargo, su memoria interna resultó insuficiente en muchos casos reales. Por eso, la siguiente etapa fue crear arquitecturas recurrentes más efectivas para conservar información importante durante más tiempo.
En el próximo tema estudiaremos precisamente LSTM y GRU para secuencias de texto.