Adding Lab2
This commit is contained in:
Executable
+343
@@ -0,0 +1,343 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "FA46Pv6apDow",
|
||||
"metadata": {
|
||||
"id": "FA46Pv6apDow"
|
||||
},
|
||||
"source": [
|
||||
"# Laboratorio LSTM para Predicción de Palabras en PyTorch\n",
|
||||
"\n",
|
||||
"En este laboratorio construiremos un modelo LSTM para predecir la siguiente palabra dada una secuencia de palabras.\n",
|
||||
"Usaremos un corpus pequeño para facilitar la comprensión.\n",
|
||||
"\n",
|
||||
"## Objetivos\n",
|
||||
"- Preparar datos para modelar secuencias\n",
|
||||
"- Implementar un modelo LSTM en PyTorch\n",
|
||||
"- Entrenar el modelo para predecir la siguiente palabra\n",
|
||||
"- Evaluar el modelo\n",
|
||||
"\n",
|
||||
"## Instrucciones Generales\n",
|
||||
"\n",
|
||||
"1. Completar las partes marcadas con `# COMPLETAR`\n",
|
||||
"2. Este laboratorio sera realizado de manera individual\n",
|
||||
"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`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "bdXnzzlXpDo0",
|
||||
"metadata": {
|
||||
"id": "bdXnzzlXpDo0"
|
||||
},
|
||||
"source": [
|
||||
"## Paso 1: Corpus y tokenización"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "7lG9qusMpDo1",
|
||||
"metadata": {
|
||||
"id": "7lG9qusMpDo1"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"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']\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Corpus simple\n",
|
||||
"corpus = [\n",
|
||||
" \"el gato come pescado\",\n",
|
||||
" \"el perro come hueso\",\n",
|
||||
" \"el gato juega con el perro\",\n",
|
||||
" \"el pez nada en el agua\",\n",
|
||||
" \"el perro corre rápido\"\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"def tokenize_corpus(corpus):\n",
|
||||
" tokens = []\n",
|
||||
" for sentence in corpus:\n",
|
||||
" tokens.extend(sentence.lower().split())\n",
|
||||
" return tokens\n",
|
||||
"\n",
|
||||
"tokens = tokenize_corpus(corpus)\n",
|
||||
"print(\"Tokens:\", tokens)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "QdIyZmm7pDo3",
|
||||
"metadata": {
|
||||
"id": "QdIyZmm7pDo3"
|
||||
},
|
||||
"source": [
|
||||
"## Paso 2: Crear vocabulario e índices"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "Wxl8oFqEpDo3",
|
||||
"metadata": {
|
||||
"id": "Wxl8oFqEpDo3"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Vocabulario: ['agua', 'come', 'con', 'corre', 'el', 'en', 'gato', 'hueso', 'juega', 'nada', 'perro', 'pescado', 'pez', 'rápido']\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"vocab = sorted(set(tokens))\n",
|
||||
"word_to_idx = {word: i for i, word in enumerate(vocab)}\n",
|
||||
"idx_to_word = {i: word for word, i in word_to_idx.items()}\n",
|
||||
"\n",
|
||||
"print(\"Vocabulario:\", vocab)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "PNZK2ruxpDo4",
|
||||
"metadata": {
|
||||
"id": "PNZK2ruxpDo4"
|
||||
},
|
||||
"source": [
|
||||
"## Paso 3: Crear dataset de secuencias para predecir la siguiente palabra\n",
|
||||
"\n",
|
||||
"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."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "YU7iNATepDo4",
|
||||
"metadata": {
|
||||
"id": "YU7iNATepDo4"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Ejemplo de entrada (índices): [4, 6, 1]\n",
|
||||
"Ejemplo de objetivo (índice): 11\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def create_sequences(tokens, seq_length):\n",
|
||||
" inputs = []\n",
|
||||
" targets = []\n",
|
||||
" for i in range(len(tokens) - seq_length):\n",
|
||||
" seq_in = tokens[i:i+seq_length]\n",
|
||||
" seq_out = tokens[i+seq_length]\n",
|
||||
" inputs.append([word_to_idx[w] for w in seq_in])\n",
|
||||
" targets.append(word_to_idx[seq_out])\n",
|
||||
" return inputs, targets\n",
|
||||
"\n",
|
||||
"seq_length = 3\n",
|
||||
"inputs, targets = create_sequences(tokens, seq_length)\n",
|
||||
"\n",
|
||||
"print(\"Ejemplo de entrada (índices):\", inputs[0])\n",
|
||||
"print(\"Ejemplo de objetivo (índice):\", targets[0])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "HeeOssQNpDo4",
|
||||
"metadata": {
|
||||
"id": "HeeOssQNpDo4"
|
||||
},
|
||||
"source": [
|
||||
"## Paso 4: Definir el modelo LSTM"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "bZqzjashpDo5",
|
||||
"metadata": {
|
||||
"id": "bZqzjashpDo5"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"LSTMWordPredictor(\n",
|
||||
" (embedding): Embedding(14, 10)\n",
|
||||
" (lstm): LSTM(10, 20, batch_first=True)\n",
|
||||
" (linear): Linear(in_features=20, out_features=14, bias=True)\n",
|
||||
")\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import torch\n",
|
||||
"import torch.nn as nn\n",
|
||||
"\n",
|
||||
"class LSTMWordPredictor(nn.Module):\n",
|
||||
" def __init__(self, vocab_size, embedding_dim, hidden_dim):\n",
|
||||
" super(LSTMWordPredictor, self).__init__()\n",
|
||||
" self.embedding = nn.Embedding(vocab_size, embedding_dim)\n",
|
||||
" self.lstm = nn.LSTM(embedding_dim, hidden_dim, batch_first=True)\n",
|
||||
" self.linear = nn.Linear(hidden_dim, vocab_size)\n",
|
||||
"\n",
|
||||
" def forward(self, x):\n",
|
||||
" embeds = self.embedding(x) # x shape: (batch, seq_length)\n",
|
||||
" lstm_out, _ = self.lstm(embeds) # lstm_out shape: (batch, seq_length, hidden_dim)\n",
|
||||
" # COMPLETAR: Tomar la salida del último timestep\n",
|
||||
" last_out = lstm_out[:, -1, :] # COMPLETAR\n",
|
||||
" out = self.linear(last_out) # out shape: (batch, vocab_size)\n",
|
||||
" return out\n",
|
||||
"\n",
|
||||
"embedding_dim = 10\n",
|
||||
"hidden_dim = 20\n",
|
||||
"vocab_size = len(vocab)\n",
|
||||
"model = LSTMWordPredictor(vocab_size, embedding_dim, hidden_dim)\n",
|
||||
"print(model)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "_ykl-dihpDo5",
|
||||
"metadata": {
|
||||
"id": "_ykl-dihpDo5"
|
||||
},
|
||||
"source": [
|
||||
"## Paso 5: Entrenamiento del modelo"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "AZDWmoBXpDo6",
|
||||
"metadata": {
|
||||
"id": "AZDWmoBXpDo6"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Epoch 20, Loss: 0.0294\n",
|
||||
"Epoch 40, Loss: 0.0075\n",
|
||||
"Epoch 60, Loss: 0.0035\n",
|
||||
"Epoch 80, Loss: 0.0020\n",
|
||||
"Epoch 100, Loss: 0.0013\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import torch.optim as optim\n",
|
||||
"\n",
|
||||
"def train(model, inputs, targets, epochs=100, lr=0.01):\n",
|
||||
" loss_function = nn.CrossEntropyLoss()\n",
|
||||
" optimizer = optim.Adam(model.parameters(), lr=lr)\n",
|
||||
"\n",
|
||||
" for epoch in range(epochs):\n",
|
||||
" total_loss = 0\n",
|
||||
" for i in range(len(inputs)):\n",
|
||||
" input_seq = torch.tensor([inputs[i]], dtype=torch.long) # batch_size=1\n",
|
||||
" target = torch.tensor([targets[i]], dtype=torch.long)\n",
|
||||
"\n",
|
||||
" model.zero_grad()\n",
|
||||
" output = model(input_seq)\n",
|
||||
" loss = loss_function(output, target)\n",
|
||||
" loss.backward()\n",
|
||||
" optimizer.step()\n",
|
||||
" total_loss += loss.item()\n",
|
||||
" if (epoch+1) % 20 == 0:\n",
|
||||
" print(f\"Epoch {epoch+1}, Loss: {total_loss/len(inputs):.4f}\")\n",
|
||||
"\n",
|
||||
"train(model, inputs, targets)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "mMC-G_8bpDo6",
|
||||
"metadata": {
|
||||
"id": "mMC-G_8bpDo6"
|
||||
},
|
||||
"source": [
|
||||
"## Paso 6: Función para predecir la siguiente palabra dada una secuencia"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "r8HT4xnLpDo6",
|
||||
"metadata": {
|
||||
"id": "r8HT4xnLpDo6"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Dada la secuencia ['el', 'gato', 'come'], la siguiente palabra predicha es: pescado\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def predict_next_word(model, input_words, word_to_idx, idx_to_word):\n",
|
||||
" model.eval()\n",
|
||||
" with torch.no_grad():\n",
|
||||
" input_idx = torch.tensor([[word_to_idx[w] for w in input_words]], dtype=torch.long)\n",
|
||||
" output = model(input_idx)\n",
|
||||
" predicted_idx = output.argmax(dim=1).item()\n",
|
||||
" return idx_to_word[predicted_idx]\n",
|
||||
"\n",
|
||||
"# Prueba\n",
|
||||
"input_seq = [\"el\", \"gato\", \"come\"]\n",
|
||||
"print(f\"Dada la secuencia {input_seq}, la siguiente palabra predicha es: {predict_next_word(model, input_seq, word_to_idx, idx_to_word)}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "SxtYrqIErt3w",
|
||||
"metadata": {
|
||||
"id": "SxtYrqIErt3w"
|
||||
},
|
||||
"source": [
|
||||
"## ¡Felicidades!\n",
|
||||
"\n",
|
||||
"Has implementado un modelo LSTM para predecir la siguiente palabra dada una secuencia de palabras"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.12.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -7,3 +7,4 @@ Repositorio con los laboratorios de la asignatura.
|
||||
| # | Laboratorio | Notebook |
|
||||
|---|---|---|
|
||||
| 1 | Word2Vec desde cero (Skip-gram, CBOW, gensim, PyTorch) | [Lab 1 - Word2Vec](Labs/word2vec_Alejandro_Lembke.ipynb) |
|
||||
| 2 | LSTM para predicción de la siguiente palabra (PyTorch) | [Lab 2 - LSTM](Labs/Laboratorio_lstm_Alejandro_Lembke.ipynb) |
|
||||
|
||||
Reference in New Issue
Block a user