Introducción
Las Unidades Recurrentes con Puerta (GRUs, por sus siglas en inglés) son una variante de las Redes Neuronales Recurrentes (RNNs) diseñadas para abordar el problema del desvanecimiento del gradiente y mejorar la capacidad de las RNNs para capturar dependencias a largo plazo en secuencias de datos. Las GRUs son similares a las Redes de Memoria a Largo Plazo (LSTM), pero con una estructura más simple y menos parámetros.
Conceptos Clave
- Puerta de Actualización: Controla cuánto de la información pasada debe ser llevada al futuro.
- Puerta de Reinicio: Decide cuánto de la información pasada debe ser olvidada.
- Estado Oculto: Representa la memoria de la red en un momento dado.
Estructura de una GRU
Una GRU tiene dos puertas principales: la puerta de actualización y la puerta de reinicio. A continuación se muestra la estructura matemática de una GRU:
-
Puerta de Actualización: \[ z_t = \sigma(W_z \cdot [h_{t-1}, x_t]) \] Donde:
- \( z_t \) es el vector de la puerta de actualización.
- \( W_z \) son los pesos de la puerta de actualización.
- \( h_{t-1} \) es el estado oculto anterior.
- \( x_t \) es la entrada en el tiempo \( t \).
- \( \sigma \) es la función sigmoide.
-
Puerta de Reinicio: \[ r_t = \sigma(W_r \cdot [h_{t-1}, x_t]) \] Donde:
- \( r_t \) es el vector de la puerta de reinicio.
- \( W_r \) son los pesos de la puerta de reinicio.
-
Estado Candidato: \[ \tilde{h}t = \tanh(W \cdot [r_t * h{t-1}, x_t]) \] Donde:
- \( \tilde{h}_t \) es el estado candidato.
- \( W \) son los pesos de la red.
- \( * \) denota la multiplicación elemento a elemento.
-
Estado Oculto: \[ h_t = (1 - z_t) * h_{t-1} + z_t * \tilde{h}_t \]
Implementación en PyTorch
Ejemplo Práctico
Vamos a implementar una GRU simple en PyTorch para predecir una secuencia de números.
Paso 1: Importar Librerías
Paso 2: Definir la Clase de la GRU
class GRUNet(nn.Module): def __init__(self, input_size, hidden_size, output_size, num_layers): super(GRUNet, self).__init__() self.hidden_size = hidden_size self.num_layers = num_layers self.gru = nn.GRU(input_size, hidden_size, num_layers, batch_first=True) self.fc = nn.Linear(hidden_size, output_size) def forward(self, x): h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device) out, _ = self.gru(x, h0) out = self.fc(out[:, -1, :]) return out
Paso 3: Preparar los Datos
# Generar datos de ejemplo def create_inout_sequences(input_data, tw): inout_seq = [] L = len(input_data) for i in range(L-tw): train_seq = input_data[i:i+tw] train_label = input_data[i+tw:i+tw+1] inout_seq.append((train_seq, train_label)) return inout_seq data = np.sin(np.linspace(0, 100, 1000)) train_window = 10 train_inout_seq = create_inout_sequences(data, train_window) # Convertir a tensores train_inout_seq = [(torch.tensor(seq, dtype=torch.float32).unsqueeze(0), torch.tensor(label, dtype=torch.float32)) for seq, label in train_inout_seq]
Paso 4: Entrenar el Modelo
# Hiperparámetros input_size = 1 hidden_size = 50 output_size = 1 num_layers = 1 num_epochs = 100 learning_rate = 0.01 # Inicializar el modelo, la función de pérdida y el optimizador model = GRUNet(input_size, hidden_size, output_size, num_layers) criterion = nn.MSELoss() optimizer = optim.Adam(model.parameters(), lr=learning_rate) # Entrenamiento for epoch in range(num_epochs): for seq, labels in train_inout_seq: optimizer.zero_grad() y_pred = model(seq.unsqueeze(-1)) loss = criterion(y_pred, labels) loss.backward() optimizer.step() if epoch % 10 == 0: print(f'Epoch {epoch}, Loss: {loss.item()}')
Paso 5: Evaluar el Modelo
# Evaluar el modelo model.eval() test_inputs = data[:train_window].tolist() for i in range(100): seq = torch.tensor(test_inputs[-train_window:], dtype=torch.float32).unsqueeze(0).unsqueeze(-1) with torch.no_grad(): test_inputs.append(model(seq).item()) # Visualizar los resultados import matplotlib.pyplot as plt plt.plot(data, label='Original Data') plt.plot(range(train_window, train_window+100), test_inputs[train_window:], label='Predicted Data') plt.legend() plt.show()
Ejercicio Práctico
Ejercicio
Implementa una GRU para predecir la serie temporal de la función coseno en lugar de la función seno. Sigue los mismos pasos que en el ejemplo anterior, pero cambia la generación de datos para usar la función coseno.
Solución
# Generar datos de ejemplo con la función coseno data = np.cos(np.linspace(0, 100, 1000)) train_window = 10 train_inout_seq = create_inout_sequences(data, train_window) # Convertir a tensores train_inout_seq = [(torch.tensor(seq, dtype=torch.float32).unsqueeze(0), torch.tensor(label, dtype=torch.float32)) for seq, label in train_inout_seq] # Inicializar el modelo, la función de pérdida y el optimizador model = GRUNet(input_size, hidden_size, output_size, num_layers) criterion = nn.MSELoss() optimizer = optim.Adam(model.parameters(), lr=learning_rate) # Entrenamiento for epoch in range(num_epochs): for seq, labels in train_inout_seq: optimizer.zero_grad() y_pred = model(seq.unsqueeze(-1)) loss = criterion(y_pred, labels) loss.backward() optimizer.step() if epoch % 10 == 0: print(f'Epoch {epoch}, Loss: {loss.item()}') # Evaluar el modelo model.eval() test_inputs = data[:train_window].tolist() for i in range(100): seq = torch.tensor(test_inputs[-train_window:], dtype=torch.float32).unsqueeze(0).unsqueeze(-1) with torch.no_grad(): test_inputs.append(model(seq).item()) # Visualizar los resultados plt.plot(data, label='Original Data') plt.plot(range(train_window, train_window+100), test_inputs[train_window:], label='Predicted Data') plt.legend() plt.show()
Conclusión
En esta sección, hemos aprendido sobre las Unidades Recurrentes con Puerta (GRUs), su estructura y cómo implementarlas en PyTorch. Las GRUs son una herramienta poderosa para trabajar con secuencias de datos y pueden ser utilizadas en una variedad de aplicaciones, desde la predicción de series temporales hasta el procesamiento de lenguaje natural. En el próximo módulo, exploraremos temas avanzados como las Redes Generativas Antagónicas (GANs) y el Aprendizaje por Refuerzo con PyTorch.
PyTorch: De Principiante a Avanzado
Módulo 1: Introducción a PyTorch
- ¿Qué es PyTorch?
- Configuración del Entorno
- Operaciones Básicas con Tensores
- Autograd: Diferenciación Automática
Módulo 2: Construcción de Redes Neuronales
- Introducción a las Redes Neuronales
- Creación de una Red Neuronal Simple
- Funciones de Activación
- Funciones de Pérdida y Optimización
Módulo 3: Entrenamiento de Redes Neuronales
- Carga y Preprocesamiento de Datos
- Bucle de Entrenamiento
- Validación y Pruebas
- Guardar y Cargar Modelos
Módulo 4: Redes Neuronales Convolucionales (CNNs)
- Introducción a las CNNs
- Construcción de una CNN desde Cero
- Aprendizaje por Transferencia con Modelos Preentrenados
- Ajuste Fino de CNNs
Módulo 5: Redes Neuronales Recurrentes (RNNs)
- Introducción a las RNNs
- Construcción de una RNN desde Cero
- Redes de Memoria a Largo Plazo (LSTM)
- Unidades Recurrentes con Puerta (GRUs)
Módulo 6: Temas Avanzados
- Redes Generativas Antagónicas (GANs)
- Aprendizaje por Refuerzo con PyTorch
- Despliegue de Modelos PyTorch
- Optimización del Rendimiento