🎯 Intro 🏗️ Arquitectura 📐 Matemáticas ⚠️ Problemas 💻 Código 🚀 Evolución 🧠 Quiz

🧠 Clase Magistral: Redes Neuronales Recurrentes (RNN)

👨‍🏫 Profesor: Sergio Gevatschnaider

⏱️ Duración: 90 m

🎯 Nivel: Intermedio

🎯 1. ¿Por qué necesitamos memoria?

📚 Definición Formal

Las Redes Neuronales Recurrentes (RNN) son una clase de redes neuronales artificiales donde las conexiones entre nodos forman un grafo dirigido a lo largo de una secuencia temporal. Esto les permite exhibir un comportamiento dinámico temporal y usar un estado interno (memoria) para procesar secuencias de entradas de longitud variable.

🩺 El Médico Amnésico vs. El Médico con Bloc de Notas

Red Neuronal Tradicional (Feedforward) - El Médico Amnésico: Imagina ir a un médico que tiene amnesia. Cada vez que lo visitas, no recuerda nada de tu historial. Si le dices "tengo tos", te recetará un jarabe. Si al día siguiente vuelves y dices "ahora tengo fiebre", te dará un antipirético, ignorando por completo que ayer tenías tos. No puede diagnosticar una neumonía porque no puede conectar los síntomas a lo largo del tiempo.

Red Neuronal Recurrente (RNN) - El Médico con Bloc de Notas: Ahora imagina un médico que anota todo en un bloc. Cuando llegas con tos, lo anota. Al día siguiente, cuando llegas con fiebre, lee su nota sobre la tos y dice: "Interesante, tos ayer y fiebre hoy... esto podría ser algo más serio". ¡Ha usado el contexto previo (su memoria) para hacer un diagnóstico más inteligente! Ese "bloc de notas" es el estado oculto de una RNN.

🏗️ 2. El Corazón de la RNN: El Bucle

La magia de una RNN reside en un concepto simple pero poderoso: un bucle. La red procesa un elemento de la secuencia y pasa una "memoria" de lo que vio al siguiente paso. Esta "memoria" se llama estado oculto (hidden state).

Visualización: Plegada vs. Desplegada en el Tiempo

A la izquierda, la RNN en su forma compacta (plegada). A la derecha, la misma red desplegada a través del tiempo, mostrando cómo la información fluye.

A x_t h_t Forma Plegada A A A x_0 x_1 x_2 h_0 h_1 h_2 Forma Desplegada
  • x_t: Es la entrada en el paso de tiempo t (ej. una palabra en una oración).
  • A: Es la celda de la RNN, que realiza el cálculo. Es la misma en cada paso.
  • h_t: Es el estado oculto (la salida) en el paso t. Contiene información sobre las entradas vistas hasta ese momento. Es la "memoria" que se pasa al siguiente paso.

📐 3. Las Matemáticas de la Memoria

¿Cómo se calcula exactamente el nuevo estado oculto h_t? Es una combinación de la memoria anterior h_{t-1} y la nueva información x_t.

Ecuación de Transición de Estado

ht = tanh(Whh * ht-1 + Wxh * xt + bh)

🧠 Actualización de Memoria
📤 Ecuación de Salida
⚖️ Pesos Compartidos
  • h_{t-1}: El estado oculto (memoria) del paso anterior.
  • x_t: La entrada actual.
  • W_{hh}: La matriz de pesos para la memoria anterior.
  • W_{xh}: La matriz de pesos para la entrada actual.
  • b_h: El sesgo (bias) del estado oculto.
  • tanh: Una función de activación que mantiene los valores entre -1 y 1, evitando que la memoria "explote".

A menudo, queremos una salida en cada paso de tiempo (ej. traducir una palabra en cada paso). Esta se calcula a partir del estado oculto actual:

yt = softmax(Why * ht + by)
  • y_t: La salida predicha en el paso t.
  • W_{hy}: La matriz de pesos que transforma la memoria en una salida.
  • b_y: El sesgo de la salida.

¡El Secreto es Compartir!

Es CRUCIAL entender que las matrices de pesos (W_{hh}, W_{xh}, W_{hy}) y los sesgos son los mismos en cada paso de tiempo. Esto es lo que permite a la RNN generalizar su conocimiento a través de la secuencia. No aprende una regla para la primera palabra y otra para la tercera; aprende una única regla sobre cómo actualizar su memoria basándose en la nueva información, sin importar en qué punto de la secuencia se encuentre.

⚠️ 4. El Talón de Aquiles: Gradientes a Largo Plazo

Las RNN simples son maravillosas, pero tienen un problema fundamental cuando las secuencias son muy largas: el problema de la desaparición y explosión del gradiente.

🗣️ El Juego del Teléfono (Desaparición) vs. El Eco del Micrófono (Explosión)

Desaparición del Gradiente: Imagina el juego del teléfono. Una persona susurra un mensaje a la siguiente, y así sucesivamente. Para cuando el mensaje llega al final de una larga fila, es probable que se haya debilitado, distorsionado o perdido por completo. En una RNN, la "señal" del gradiente de error de los primeros pasos se debilita a medida que se propaga hacia atrás en el tiempo, haciendo imposible que la red aprenda dependencias a largo plazo.

Explosión del Gradiente: Ahora imagina un micrófono demasiado cerca de un altavoz. El sonido entra en el micrófono, se amplifica, sale por el altavoz, vuelve a entrar en el micrófono, se amplifica aún más... y en segundos tienes un eco ensordecedor. En una RNN, si los gradientes son demasiado grandes, pueden crecer exponencialmente a medida que se propagan hacia atrás, desestabilizando el entrenamiento por completo.

La Causa Técnica

Durante el entrenamiento (llamado Backpropagation Through Time), los gradientes se multiplican repetidamente por la matriz de pesos recurrentes W_{hh}. Si los valores en esta matriz son consistentemente pequeños (< 1), el gradiente se encoge hasta desaparecer. Si son grandes (> 1), el gradiente crece hasta explotar.

💻 5. RNN en Acción: Predicción de Texto con Python

Vamos a construir una RNN simple que aprende a predecir el siguiente carácter en la frase "hola mundo".


🐍 RNN para generar texto con TensorFlow/Keras
import tensorflow as tf from tensorflow.keras import layers, models import numpy as np # --- 1. PREPARACIÓN DE DATOS --- text = "hola mundo" chars = sorted(list(set(text))) char_to_idx = {c: i for i, c in enumerate(chars)} idx_to_char = {i: c for i, c in enumerate(chars)} vocab_size = len(chars) # Crear secuencias de entrada (X) y salida (y) seq_length = 3 X_data, y_data = [], [] for i in range(len(text) - seq_length): X_data.append([char_to_idx[c] for c in text[i:i+seq_length]]) y_data.append(char_to_idx[text[i+seq_length]]) # Convertir a formato numpy y one-hot encoding X = tf.keras.utils.to_categorical(X_data, num_classes=vocab_size) y = tf.keras.utils.to_categorical(y_data, num_classes=vocab_size) print(f"Número de secuencias de entrenamiento: {len(X)}") # --- 2. CONSTRUCCIÓN DEL MODELO RNN --- model = models.Sequential([ # La capa RNN. `input_shape` es (longitud_secuencia, tamaño_vocabulario) layers.SimpleRNN(units=25, input_shape=(seq_length, vocab_size)), # Capa de salida para predecir el próximo carácter layers.Dense(units=vocab_size, activation='softmax') ]) model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) model.summary() # --- 3. ENTRENAMIENTO --- print("\n--- Entrenando el modelo... ---") model.fit(X, y, epochs=100, verbose=0) print("✅ Entrenamiento completado.") # --- 4. GENERACIÓN DE TEXTO --- def predict_next_char(seed_text): x_pred = np.zeros((1, seq_length, vocab_size)) for t, char in enumerate(seed_text): x_pred[0, t, char_to_idx[char]] = 1. prediction = model.predict(x_pred, verbose=0)[0] next_idx = np.argmax(prediction) return idx_to_char[next_idx] seed = "ola" prediction = predict_next_char(seed) print(f"\nPredicción: Si la entrada es '{seed}', el siguiente carácter es '{prediction}'") # Debería predecir ' '

🚀 6. La Evolución: LSTM y GRU

Para resolver el problema de los gradientes, se crearon arquitecturas más sofisticadas. No reemplazan el concepto de RNN, sino que proponen celdas recurrentes mucho más inteligentes.

LSTM (Long Short-Term Memory)

Innovación: Introduce un "carril expreso" llamado estado de la celda y un sistema de compuertas (gates) que regulan el flujo de información.

  • Compuerta de Olvido: Decide qué información del pasado tirar.
  • Compuerta de Entrada: Decide qué nueva información almacenar.
  • Compuerta de Salida: Decide qué parte de la memoria usar para la salida.
Beneficio: ¡Puede aprender dependencias a muy largo plazo! Es el estándar de oro para muchas tareas secuenciales.

GRU (Gated Recurrent Unit)

Innovación: Una versión simplificada de la LSTM que combina las compuertas de olvido y entrada en una única compuerta de actualización. También tiene una compuerta de reseteo. Beneficio: Es computacionalmente más eficiente que la LSTM y ofrece un rendimiento similar en muchas tareas. Una gran alternativa.

🧠 7. Prueba tus Conocimientos

Pregunta 1: ¿Cuál es la característica DEFINITORIA de una Red Neuronal Recurrente?


Pregunta 2: ¿Cuál es el principal problema que las arquitecturas LSTM y GRU vinieron a solucionar?