{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "colab": { "provenance": [], "gpuType": "T4" }, "kernelspec": { "name": "python3", "display_name": "Python 3" }, "language_info": { "name": "python" }, "accelerator": "GPU" }, "cells": [ { "cell_type": "markdown", "source": [ "Redes Neuronales para Lenguaje Natural, 2024\n", "\n", "---\n", "# Laboratorio 1\n", "\n", "En este laboratorio construiremos analizadores de sentimiento de tres clases (positivo, negativo, neutro) en tweets, con el objetivo de comparar distintas técnicas de representación de los textos.\n", "\n", "El mínimo requerido para la aprobación de este laboratorio es completar las partes 1, 2 y 4. La parte 3 es opcional, y puede realizarse para obtener mayor puntaje en el laboratorio.\n", "\n", "**Entrega: viernes 4 de octubre**\n", "\n", "**Formato: notebook de Python (.ipynb)**\n", "\n", "**No olvidar mantener todas las salidas de cada región de código en el notebook!**\n", "\n", "---\n", "\n" ], "metadata": { "id": "t9ZNGOygrFsT" } }, { "cell_type": "markdown", "source": [ "Comenzamos con algunos imports y definiciones." ], "metadata": { "id": "jGKhZr0-Yx9O" } }, { "cell_type": "code", "source": [ "import torch\n", "import gensim\n", "import numpy as np\n", "import pandas as pd\n", "from sklearn.metrics import precision_recall_fscore_support, accuracy_score, confusion_matrix\n", "\n", "POLARITY_LABELS = ['N','P','NEU']\n", "POLARITY_ID = { p:i for (i,p) in enumerate(POLARITY_LABELS) }" ], "metadata": { "id": "sdk0m1WfYoeW" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "Descargamos los datos de la competencia TASS 2018." ], "metadata": { "id": "-wlcQnjW3PqL" } }, { "cell_type": "code", "source": [ "! wget https://www.fing.edu.uy/owncloud/index.php/s/YZm8dBsp9Sf2rog/download/tass_train.csv\n", "! wget https://www.fing.edu.uy/owncloud/index.php/s/nkBx7HHcz6gjret/download/tass_dev.csv\n", "! wget https://www.fing.edu.uy/owncloud/index.php/s/brj5axBcmXqbgK4/download/tass_test.csv" ], "metadata": { "id": "u34lygcpDC1m" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "Cargamos las tres particiones de datos de la competencia, e imprimimos algunas muestras de los datos.\n", "\n", "Este dataset está compuesto por tweets, y para cada tweet se cuenta con un identificador único, el texto del tweet y si su sentimiento es positivo, negativo o neutro (polaridad)." ], "metadata": { "id": "EY1akF6ON9UF" } }, { "cell_type": "code", "source": [ "train_df = pd.read_csv('./tass_train.csv')\n", "dev_df = pd.read_csv('./tass_dev.csv')\n", "test_df = pd.read_csv('./tass_test.csv')\n", "train_df.sample(5)" ], "metadata": { "id": "Lgs3RHq1gARr" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "En este laboratorio utilizaremos el texto como entrada (columna \"text\"), y el valor a predecir será la polaridad (columna \"polarity\").\n", "\n", "Imprimimos algunos textos de ejemplo y sus categorías, y luego imprimimos la cantidad de ejemplos de las tres clases en las tres particiones. Notar que las categorías no están balanceadas con exactitud, pero tampoco presenta un gran desbalance (máximo 5% por clase)." ], "metadata": { "id": "kFox_v-5P9UM" } }, { "cell_type": "code", "source": [ "train_text = train_df.loc[:,'text']\n", "dev_text = dev_df.loc[:,'text']\n", "test_text = test_df.loc[:,'text']\n", "\n", "train_labels = [POLARITY_ID[l] for l in train_df.loc[:,'polarity']]\n", "dev_labels = [POLARITY_ID[l] for l in dev_df.loc[:,'polarity']]\n", "test_labels = [POLARITY_ID[l] for l in test_df.loc[:,'polarity']]\n", "\n", "print(train_text[121])\n", "print(POLARITY_LABELS[train_labels[121]])\n", "\n", "print(train_text[27])\n", "print(POLARITY_LABELS[train_labels[27]])\n", "\n", "print(train_text[143])\n", "print(POLARITY_LABELS[train_labels[143]])\n", "\n", "print(*POLARITY_LABELS, sep='\\t')\n", "print(*np.bincount(train_labels), sep='\\t')\n", "print(*np.bincount(dev_labels), sep='\\t')\n", "print(*np.bincount(test_labels), sep='\\t')\n" ], "metadata": { "id": "pSGVn-fjNwNe" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "## Parte 1:\n", "Utilizando pytorch, construir un clasificador tipo Multi-Layered Perceptron (MLP) que clasifique los tweets según su sentimiento.\n", "En esta parte, se debe utilizar una representación tipo **bag-of-words (BOW)** para los tweets, la cual se utilizará como entrada de la red.\n", "\n", "Puede probar realizar diferentes alternativas dentro de la representación BOW, por ejemplo considerar o no mayúsculas y minúsculas, descartar palabras con listas de stop words, o usar N-gramas de orden mayor en vez de palabras simples.\n", "\n", "**Sugerencias:**\n", "* Utilizar la clase CountVectorizer de sklearn\n", "* Limitar el número máximo de features para no quedarse sin memoria" ], "metadata": { "id": "aUVQ4dkXQYtf" } }, { "cell_type": "code", "source": [ "# su código aquí\n" ], "metadata": { "id": "k44E9_AlM9ns" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "Evalúe el mejor clasificador encontrado en esta parte sobre el corpus de **dev**, imprimiendo la métrica accuracy, y las métricas macro-precision, macro-recall y macro-F1." ], "metadata": { "id": "krhvVHLeUqo5" } }, { "cell_type": "code", "source": [ "# su código aquí\n" ], "metadata": { "id": "TgT4CAdSU5j9" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "## Parte 2:\n", "Utilizando pytorch, construir un clasificador tipo Multi-Layered Perceptron (MLP) que clasifique los tweets según su polaridad.\n", "En esta parte, se debe utilizar una representación tipo **centroide de word embeddings** para los tweets, la cual se utilizará como entrada de la red.\n", "\n", "Puede probar realizar diferentes alternativas dentro de la representación con word embedddings, por ejemplo considerar o no mayúsculas y minúsculas, o descartar palabras con listas de stop words.\n", "\n", "**Sugerencias:**\n", "* Puede utilizar los vectores de SBWC que indicamos a continuación\n", "* O puede bajar alguna otra colección de embeddings, pero no entrene sus propios embeddings!" ], "metadata": { "id": "5klZ-zH3RuSx" } }, { "cell_type": "code", "source": [ "# Alternativas para bajar embeddings de SBWC:\n", "\n", "# Sitio oficial de la Universidad Nacional de Córdoba\n", "# ! wget https://cs.famaf.unc.edu.ar/~ccardellino/SBWCE/SBW-vectors-300-min5.bin.gz\n", "\n", "# Mirror en el Owncloud de Fing\n", "# ! wget https://www.fing.edu.uy/owncloud/index.php/s/ryHF9xWwox3NrFe/download/SBW-vectors-300-min5.bin.gz\n", "\n", "# Si los enlaces son demasiado lentos: bajarlo una sola vez y copiarlo a google drive\n", "# ! cp /content/drive/MyDrive/share/SBW-vectors-300-min5.bin.gz .\n", "\n", "# El archivo viene en un gzip, lo descomprimimos\n", "! gzip -d SBW-vectors-300-min5.bin.gz\n" ], "metadata": { "id": "gONBUsuua0ih" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "# Una vez descargado y descomprimido, lo levantamos en memoria con gensim y mostramos algunos datos básicos\n", "from gensim.models import KeyedVectors\n", "wv = KeyedVectors.load_word2vec_format(\"./SBW-vectors-300-min5.bin\", binary=True)\n", "print(\"Largo del vocabulario\", len(wv.vectors))\n", "print(\"Tamaño del vector\",wv.vectors.shape)\n", "print(\"Vector de 'perro'\", wv['perro'])" ], "metadata": { "id": "K4OCSXb6N84D" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "# su código aquí\n" ], "metadata": { "id": "6TKrfFb8T6LX" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "Evalúe el mejor clasificador encontrado en esta parte sobre el corpus de **dev**, imprimiendo la métrica accuracy, y las métricas macro-precision, macro-recall y macro-F1." ], "metadata": { "id": "cy10PcMRU8Qq" } }, { "cell_type": "code", "source": [ "# su código aquí\n" ], "metadata": { "id": "igl-xpy4U9pV" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "## Parte 3 (opcional):\n", "Elija uno de los clasificadores anteriores y realice una búsqueda automatizada de hiperparámetros del modelo. Por ejemplo, puede utilizar una búsqueda en grilla completa o una búsqueda aleatoria, eligiendo diferente cantidad de capas, número unidades por capa, funciones de activación, y valores de learning rate. Intente encontrar el mejor clasificador posible, comparándolos sobre el corpus de **dev**." ], "metadata": { "id": "pK_cPTC1T79O" } }, { "cell_type": "code", "source": [ "# su código aquí\n" ], "metadata": { "id": "kdL72afBVAbG" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "Evalúe el mejor clasificador encontrado en esta parte sobre el corpus de **dev**, imprimiendo la métrica accuracy, y las métricas macro-precision, macro-recall y macro-F1." ], "metadata": { "id": "TSWMIx_tVDzo" } }, { "cell_type": "code", "source": [ "# su código aquí\n" ], "metadata": { "id": "d-pblGJkVH3_" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "## Parte 4:\n", "Elija el mejor clasificador de todos los construidos en las partes anteriores, comparándolos utilizando la medida macro-F1, y evalúelo sobre el corpus de **test**, imprimiendo la métrica accuracy, y las métricas macro-precision, macro-recall y macro-F1." ], "metadata": { "id": "GOYqBdbKVJfh" } }, { "cell_type": "code", "source": [ "# su código aquí\n" ], "metadata": { "id": "GgJFRXTsVe8G" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "Despliege la matriz de confusión sobre el corpus de **test** para las tres clases (P, N, NEU) para el mejor clasificador construido en las partes anteriores." ], "metadata": { "id": "sESZGWIYyP3Y" } }, { "cell_type": "code", "source": [ "# su código aquí\n" ], "metadata": { "id": "YkkYI0LR39Of" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "Ahora conteste las siguientes preguntas sobre el mejor clasificador encontrado:\n", "\n", "1. ¿Cómo es la entrada de la red (BOW, embeddings, y con qué características)?\n", "2. ¿Cuál es la forma del modelo? Indique cantidad de capas, unidades, y funciones de activación. Puede usar el método print() sobre el modelo para imprimir la forma del modelo.\n", "3. Indique qué categoría o categorías fueron las más difíciles de aprender para su clasificador. ¿La categoría más difícil es la misma para el mejor clasificador de las partes 1 y 2 (y la parte 3 si la hizo)?" ], "metadata": { "id": "L1D9IB7gVgmG" } }, { "cell_type": "markdown", "source": [ "( sus respuestas aquí)\n" ], "metadata": { "id": "peHQat3XWzX2" } } ] }