Files
Procesamiento-de-Lenguaje-N…/Labs/Laboratorio_lstm_Alejandro_Lembke.ipynb
2026-08-27 10:43:58 -06:00

9.4 KiB
Executable File

Laboratorio LSTM para Predicción de Palabras en PyTorch

En este laboratorio construiremos un modelo LSTM para predecir la siguiente palabra dada una secuencia de palabras. Usaremos un corpus pequeño para facilitar la comprensión.

Objetivos

  • Preparar datos para modelar secuencias
  • Implementar un modelo LSTM en PyTorch
  • Entrenar el modelo para predecir la siguiente palabra
  • Evaluar el modelo

Instrucciones Generales

  1. Completar las partes marcadas con # COMPLETAR
  2. Este laboratorio sera realizado de manera individual
  3. Formato de Entrega: Su solución debe subirla en un archivo ZIP enviado por GES y debe contener el archivo .ipynb con sus respuestas a cada uno de los incisos que se necesitan # COMPLETAR.

Paso 1: Corpus y tokenización

In [1]:
# Corpus simple
corpus = [
    "el gato come pescado",
    "el perro come hueso",
    "el gato juega con el perro",
    "el pez nada en el agua",
    "el perro corre rápido"
]

def tokenize_corpus(corpus):
    tokens = []
    for sentence in corpus:
        tokens.extend(sentence.lower().split())
    return tokens

tokens = tokenize_corpus(corpus)
print("Tokens:", tokens)
Tokens: ['el', 'gato', 'come', 'pescado', 'el', 'perro', 'come', 'hueso', 'el', 'gato', 'juega', 'con', 'el', 'perro', 'el', 'pez', 'nada', 'en', 'el', 'agua', 'el', 'perro', 'corre', 'rápido']

Paso 2: Crear vocabulario e índices

In [2]:
vocab = sorted(set(tokens))
word_to_idx = {word: i for i, word in enumerate(vocab)}
idx_to_word = {i: word for word, i in word_to_idx.items()}

print("Vocabulario:", vocab)
Vocabulario: ['agua', 'come', 'con', 'corre', 'el', 'en', 'gato', 'hueso', 'juega', 'nada', 'perro', 'pescado', 'pez', 'rápido']

Paso 3: Crear dataset de secuencias para predecir la siguiente palabra

Con un tamaño de secuencia fijo (por ejemplo 3), crearemos pares (entrada, objetivo) donde la entrada es una secuencia de palabras y el objetivo es la palabra siguiente.

In [3]:
def create_sequences(tokens, seq_length):
    inputs = []
    targets = []
    for i in range(len(tokens) - seq_length):
        seq_in = tokens[i:i+seq_length]
        seq_out = tokens[i+seq_length]
        inputs.append([word_to_idx[w] for w in seq_in])
        targets.append(word_to_idx[seq_out])
    return inputs, targets

seq_length = 3
inputs, targets = create_sequences(tokens, seq_length)

print("Ejemplo de entrada (índices):", inputs[0])
print("Ejemplo de objetivo (índice):", targets[0])
Ejemplo de entrada (índices): [4, 6, 1]
Ejemplo de objetivo (índice): 11

Paso 4: Definir el modelo LSTM

In [4]:
import torch
import torch.nn as nn

class LSTMWordPredictor(nn.Module):
    def __init__(self, vocab_size, embedding_dim, hidden_dim):
        super(LSTMWordPredictor, self).__init__()
        self.embedding = nn.Embedding(vocab_size, embedding_dim)
        self.lstm = nn.LSTM(embedding_dim, hidden_dim, batch_first=True)
        self.linear = nn.Linear(hidden_dim, vocab_size)

    def forward(self, x):
        embeds = self.embedding(x)  # x shape: (batch, seq_length)
        lstm_out, _ = self.lstm(embeds)  # lstm_out shape: (batch, seq_length, hidden_dim)
        # COMPLETAR: Tomar la salida del último timestep
        last_out = lstm_out[:, -1, :]  # COMPLETAR
        out = self.linear(last_out)  # out shape: (batch, vocab_size)
        return out

embedding_dim = 10
hidden_dim = 20
vocab_size = len(vocab)
model = LSTMWordPredictor(vocab_size, embedding_dim, hidden_dim)
print(model)
LSTMWordPredictor(
  (embedding): Embedding(14, 10)
  (lstm): LSTM(10, 20, batch_first=True)
  (linear): Linear(in_features=20, out_features=14, bias=True)
)

Paso 5: Entrenamiento del modelo

In [5]:
import torch.optim as optim

def train(model, inputs, targets, epochs=100, lr=0.01):
    loss_function = nn.CrossEntropyLoss()
    optimizer = optim.Adam(model.parameters(), lr=lr)

    for epoch in range(epochs):
        total_loss = 0
        for i in range(len(inputs)):
            input_seq = torch.tensor([inputs[i]], dtype=torch.long)  # batch_size=1
            target = torch.tensor([targets[i]], dtype=torch.long)

            model.zero_grad()
            output = model(input_seq)
            loss = loss_function(output, target)
            loss.backward()
            optimizer.step()
            total_loss += loss.item()
        if (epoch+1) % 20 == 0:
            print(f"Epoch {epoch+1}, Loss: {total_loss/len(inputs):.4f}")

train(model, inputs, targets)
Epoch 20, Loss: 0.0294
Epoch 40, Loss: 0.0075
Epoch 60, Loss: 0.0035
Epoch 80, Loss: 0.0020
Epoch 100, Loss: 0.0013

Paso 6: Función para predecir la siguiente palabra dada una secuencia

In [6]:
def predict_next_word(model, input_words, word_to_idx, idx_to_word):
    model.eval()
    with torch.no_grad():
        input_idx = torch.tensor([[word_to_idx[w] for w in input_words]], dtype=torch.long)
        output = model(input_idx)
        predicted_idx = output.argmax(dim=1).item()
        return idx_to_word[predicted_idx]

# Prueba
input_seq = ["el", "gato", "come"]
print(f"Dada la secuencia {input_seq}, la siguiente palabra predicha es: {predict_next_word(model, input_seq, word_to_idx, idx_to_word)}")
Dada la secuencia ['el', 'gato', 'come'], la siguiente palabra predicha es: pescado

¡Felicidades!

Has implementado un modelo LSTM para predecir la siguiente palabra dada una secuencia de palabras