En esta sección, aprenderemos a construir una Red Neuronal Recurrente (RNN) desde cero utilizando PyTorch. Las RNNs son especialmente útiles para tareas que involucran datos secuenciales, como el procesamiento de lenguaje natural (NLP) y la predicción de series temporales.

Objetivos

  • Comprender la estructura básica de una RNN.
  • Implementar una RNN simple en PyTorch.
  • Entrenar la RNN con un conjunto de datos secuenciales.
  • Evaluar el rendimiento de la RNN.

  1. Estructura Básica de una RNN

Una RNN procesa secuencias de datos paso a paso, manteniendo un estado oculto que captura información sobre los pasos anteriores. La fórmula básica de una RNN es:

\[ h_t = \tanh(W_{ih} x_t + W_{hh} h_{t-1} + b_h) \] \[ y_t = W_{ho} h_t + b_o \]

Donde:

  • \( h_t \) es el estado oculto en el tiempo \( t \).
  • \( x_t \) es la entrada en el tiempo \( t \).
  • \( W_{ih} \), \( W_{hh} \), y \( W_{ho} \) son matrices de pesos.
  • \( b_h \) y \( b_o \) son sesgos.
  • \( y_t \) es la salida en el tiempo \( t \).

  1. Implementación de una RNN Simple en PyTorch

2.1. Importar Librerías Necesarias

import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np

2.2. Definir la Clase de la RNN

class SimpleRNN(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(SimpleRNN, self).__init__()
        self.hidden_size = hidden_size
        self.i2h = nn.Linear(input_size + hidden_size, hidden_size)
        self.i2o = nn.Linear(hidden_size, output_size)
        self.softmax = nn.LogSoftmax(dim=1)

    def forward(self, input, hidden):
        combined = torch.cat((input, hidden), 1)
        hidden = self.i2h(combined)
        output = self.i2o(hidden)
        output = self.softmax(output)
        return output, hidden

    def initHidden(self):
        return torch.zeros(1, self.hidden_size)

2.3. Crear una Instancia de la RNN

n_hidden = 128
rnn = SimpleRNN(input_size=10, hidden_size=n_hidden, output_size=2)

2.4. Definir el Conjunto de Datos y el Proceso de Entrenamiento

Para este ejemplo, utilizaremos datos secuenciales generados aleatoriamente.

# Generar datos secuenciales aleatorios
def generate_data(seq_length, num_sequences):
    data = []
    for _ in range(num_sequences):
        seq = np.random.rand(seq_length, 10)
        label = np.random.randint(0, 2)
        data.append((seq, label))
    return data

# Crear el conjunto de datos
train_data = generate_data(seq_length=5, num_sequences=1000)

# Definir la función de pérdida y el optimizador
criterion = nn.NLLLoss()
optimizer = optim.SGD(rnn.parameters(), lr=0.01)

2.5. Entrenar la RNN

def train(rnn, data, epochs=10):
    for epoch in range(epochs):
        total_loss = 0
        for seq, label in data:
            rnn.zero_grad()
            hidden = rnn.initHidden()
            for i in range(len(seq)):
                input = torch.tensor([seq[i]], dtype=torch.float)
                output, hidden = rnn(input, hidden)
            loss = criterion(output, torch.tensor([label], dtype=torch.long))
            loss.backward()
            optimizer.step()
            total_loss += loss.item()
        print(f'Epoch {epoch+1}, Loss: {total_loss/len(data)}')

# Entrenar la RNN
train(rnn, train_data)

  1. Evaluación del Rendimiento de la RNN

3.1. Definir el Conjunto de Datos de Prueba

test_data = generate_data(seq_length=5, num_sequences=200)

3.2. Evaluar la RNN

def evaluate(rnn, data):
    correct = 0
    with torch.no_grad():
        for seq, label in data:
            hidden = rnn.initHidden()
            for i in range(len(seq)):
                input = torch.tensor([seq[i]], dtype=torch.float)
                output, hidden = rnn(input, hidden)
            _, predicted = torch.max(output, 1)
            if predicted.item() == label:
                correct += 1
    accuracy = correct / len(data)
    print(f'Accuracy: {accuracy * 100}%')

# Evaluar la RNN
evaluate(rnn, test_data)

Conclusión

En esta sección, hemos construido una RNN simple desde cero utilizando PyTorch. Hemos cubierto la estructura básica de una RNN, implementado la clase de la RNN, entrenado la red con datos secuenciales y evaluado su rendimiento. Este conocimiento es fundamental para avanzar hacia arquitecturas más complejas y aplicaciones prácticas de RNNs en tareas de procesamiento de lenguaje natural y predicción de series temporales.

En el próximo módulo, exploraremos las Redes de Memoria a Largo Plazo (LSTM), una variante de las RNNs que aborda algunos de los problemas comunes de las RNNs estándar, como el desvanecimiento del gradiente.

© Copyright 2024. Todos los derechos reservados