Las Redes de Memoria a Largo Plazo (LSTM, por sus siglas en inglés) son un tipo especial de red neuronal recurrente (RNN) que se utilizan para modelar secuencias de datos y resolver problemas donde las dependencias a largo plazo son cruciales. Las LSTM están diseñadas para mitigar el problema del desvanecimiento del gradiente, que es común en las RNN tradicionales.

Conceptos Clave de las LSTM

  1. Celdas de LSTM: La unidad básica de una LSTM es la celda, que tiene la capacidad de mantener información a lo largo del tiempo.
  2. Puertas de LSTM: Las celdas de LSTM tienen tres tipos de puertas que controlan el flujo de información:
    • Puerta de Entrada: Decide qué información de la entrada actual debe ser almacenada en la celda.
    • Puerta de Olvido: Decide qué información debe ser eliminada de la celda.
    • Puerta de Salida: Decide qué parte de la información de la celda debe ser utilizada para la salida actual.

Arquitectura de una Celda LSTM

La arquitectura de una celda LSTM se puede visualizar de la siguiente manera:

          ┌───────────────┐
          │    Entrada    │
          └───────────────┘
                 │
                 ▼
          ┌───────────────┐
          │  Puerta de    │
          │    Entrada    │
          └───────────────┘
                 │
                 ▼
          ┌───────────────┐
          │  Estado de    │
          │    la Celda   │
          └───────────────┘
                 │
                 ▼
          ┌───────────────┐
          │  Puerta de    │
          │    Olvido     │
          └───────────────┘
                 │
                 ▼
          ┌───────────────┐
          │  Puerta de    │
          │    Salida     │
          └───────────────┘
                 │
                 ▼
          ┌───────────────┐
          │    Salida     │
          └───────────────┘

Implementación de una LSTM en PyTorch

Paso 1: Importar las Bibliotecas Necesarias

import torch
import torch.nn as nn
import torch.optim as optim

Paso 2: Definir la Arquitectura de la LSTM

class LSTMNetwork(nn.Module):
    def __init__(self, input_size, hidden_size, output_size, num_layers):
        super(LSTMNetwork, self).__init__()
        self.hidden_size = hidden_size
        self.num_layers = num_layers
        self.lstm = nn.LSTM(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)
        c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)
        
        out, _ = self.lstm(x, (h0, c0))
        out = self.fc(out[:, -1, :])
        return out

Paso 3: Preparar los Datos

Para este ejemplo, utilizaremos datos sintéticos. En un caso real, los datos deben ser preprocesados y divididos en secuencias.

import numpy as np

# Datos sintéticos
data = np.sin(np.linspace(0, 100, 1000))
sequence_length = 10

def create_sequences(data, seq_length):
    xs = []
    ys = []
    for i in range(len(data)-seq_length):
        x = data[i:i+seq_length]
        y = data[i+seq_length]
        xs.append(x)
        ys.append(y)
    return np.array(xs), np.array(ys)

X, y = create_sequences(data, sequence_length)
X = torch.tensor(X, dtype=torch.float32).unsqueeze(-1)
y = torch.tensor(y, dtype=torch.float32)

Paso 4: Entrenar la Red LSTM

# Hiperparámetros
input_size = 1
hidden_size = 50
output_size = 1
num_layers = 2
num_epochs = 100
learning_rate = 0.001

# Modelo, criterio y optimizador
model = LSTMNetwork(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):
    model.train()
    outputs = model(X)
    optimizer.zero_grad()
    loss = criterion(outputs, y)
    loss.backward()
    optimizer.step()
    
    if (epoch+1) % 10 == 0:
        print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')

Paso 5: Evaluar el Modelo

model.eval()
with torch.no_grad():
    predicted = model(X).detach().numpy()

import matplotlib.pyplot as plt

plt.plot(data, label='Original Data')
plt.plot(np.arange(sequence_length, sequence_length + len(predicted)), predicted, label='Predicted Data')
plt.legend()
plt.show()

Ejercicio Práctico

Ejercicio: Modifica el código anterior para predecir una secuencia de valores de una serie temporal diferente, como el precio de una acción o la temperatura diaria.

Solución:

  1. Obtener y Preprocesar los Datos: Descarga los datos de una serie temporal diferente y preprocésalos de manera similar a como se hizo con los datos sintéticos.
  2. Modificar la Arquitectura: Ajusta los hiperparámetros de la red LSTM según sea necesario.
  3. Entrenar y Evaluar el Modelo: Entrena el modelo con los nuevos datos y evalúa su rendimiento.

Conclusión

En esta sección, hemos aprendido sobre las Redes de Memoria a Largo Plazo (LSTM) y cómo implementarlas en PyTorch. Las LSTM son poderosas para modelar secuencias de datos y resolver problemas con dependencias a largo plazo. Hemos cubierto la arquitectura básica de una celda LSTM, cómo definir una red LSTM en PyTorch, y cómo entrenar y evaluar el modelo.

En el próximo módulo, exploraremos las Unidades Recurrentes con Puerta (GRUs), que son una variante de las LSTM con una arquitectura más simple.

© Copyright 2024. Todos los derechos reservados