diff --git "a/notebooks/08_transformers_v2.ipynb" "b/notebooks/08_transformers_v2.ipynb" deleted file mode 100644--- "a/notebooks/08_transformers_v2.ipynb" +++ /dev/null @@ -1,1923 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "07aa1c3f", - "metadata": {}, - "source": [ - "\n", - "# Transformers Fine-Tuning\n", - "\n", - "---\n", - "\n", - "# Estructura\n", - "\n", - "0. Imports y configuración \n", - "1. Reproducibilidad \n", - "2. Carga de datos \n", - "3. Split correcto \n", - "4. EDA rápida \n", - "5. Helper functions \n", - "6. HuggingFace datasets \n", - "7. Baseline — DistilBERT \n", - "8. Evaluación DistilBERT \n", - "9. Fine-tuning — RoBERTa Hate \n", - "10. Evaluación RoBERTa Hate \n", - "11. Comparación de modelos \n", - "12. Error Analysis \n", - "13. Guardado del mejor modelo \n" - ] - }, - { - "cell_type": "markdown", - "id": "ab6cd7a5", - "metadata": {}, - "source": [ - "## 0. Imports y configuración" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "072caf60", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "==================================================\n", - "DEVICE INFO\n", - "==================================================\n", - "Torch version: 2.12.0+cu132\n", - "Device: cuda\n", - "GPU: NVIDIA GeForce RTX 2060\n" - ] - } - ], - "source": [ - "import os\n", - "import sys\n", - "import yaml\n", - "import random\n", - "import warnings\n", - "import numpy as np\n", - "import pandas as pd\n", - "import matplotlib.pyplot as plt\n", - "import seaborn as sns\n", - "import torch\n", - "\n", - "from pathlib import Path\n", - "from datasets import Dataset\n", - "\n", - "from sklearn.model_selection import train_test_split\n", - "from sklearn.metrics import (\n", - " classification_report,\n", - " confusion_matrix,\n", - " accuracy_score,\n", - " precision_score,\n", - " recall_score,\n", - " f1_score,\n", - " roc_auc_score,\n", - ")\n", - "\n", - "from transformers import (\n", - " AutoTokenizer,\n", - " AutoModelForSequenceClassification,\n", - " DataCollatorWithPadding,\n", - " TrainingArguments,\n", - " Trainer,\n", - " EarlyStoppingCallback,\n", - ")\n", - "\n", - "warnings.filterwarnings(\"ignore\")\n", - "\n", - "PROJECT_ROOT = Path.cwd().parent\n", - "sys.path.insert(0, str(PROJECT_ROOT))\n", - "\n", - "CONFIG_PIPE = PROJECT_ROOT / \"configs\" / \"pipeline.yaml\"\n", - "\n", - "with open(CONFIG_PIPE) as f:\n", - " pipe_cfg = yaml.safe_load(f)\n", - "\n", - "TARGET = pipe_cfg[\"data\"][\"target_binary\"]\n", - "RAND = pipe_cfg[\"pipeline\"][\"random_state\"]\n", - "\n", - "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n", - "\n", - "print(\"=\" * 50)\n", - "print(\"DEVICE INFO\")\n", - "print(\"=\" * 50)\n", - "\n", - "print(\"Torch version:\", torch.__version__)\n", - "print(\"Device:\", device)\n", - "\n", - "if torch.cuda.is_available():\n", - " print(\"GPU:\", torch.cuda.get_device_name(0))\n", - "else:\n", - " print(\"⚠️ GPU no detectada\")" - ] - }, - { - "cell_type": "markdown", - "id": "178bae13", - "metadata": {}, - "source": [ - "## 1. Reproducibilidad" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0b9084dc", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Seed configurado: 42\n" - ] - } - ], - "source": [ - "def set_seed(seed=42):\n", - "\n", - " random.seed(seed)\n", - " np.random.seed(seed)\n", - "\n", - " torch.manual_seed(seed)\n", - "\n", - " if torch.cuda.is_available():\n", - " torch.cuda.manual_seed_all(seed)\n", - "\n", - " torch.backends.cudnn.deterministic = True\n", - " torch.backends.cudnn.benchmark = False\n", - "\n", - "\n", - "set_seed(RAND)\n", - "\n", - "print(\"Seed configurado:\", RAND)" - ] - }, - { - "cell_type": "markdown", - "id": "e4800e74", - "metadata": {}, - "source": [ - "## 2. Carga de datos" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0fb40c48", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(1000, 9)\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
CommentIdTextclean_textIsToxicIsAbusiveIsProvocativeIsHatespeechIsRacistIsObscene
0Ugg2KwwX0V8-aXgCoAECIf only people would just take a step back and...people would take step back make case anyone e...0FalseFalseFalseFalseFalse
1Ugg2s5AzSPioEXgCoAECLaw enforcement is not trained to shoot to app...law enforcement train shoot apprehend train sh...1TrueFalseFalseFalseFalse
2Ugg3dWTOxryFfHgCoAECDont you reckon them 'black lives matter' bann...reckon black life matter banner hold white cun...1TrueFalseFalseFalseTrue
3Ugg7Gd006w1MPngCoAECThere are a very large number of people who do...large number people police officer call crimin...0FalseFalseFalseFalseFalse
4Ugg8FfTbbNF8IngCoAECThe Arab dude is absolutely right, he should h...arab dude absolutely right shoot extra time sh...0FalseFalseFalseFalseFalse
\n", - "
" - ], - "text/plain": [ - " CommentId Text \\\n", - "0 Ugg2KwwX0V8-aXgCoAEC If only people would just take a step back and... \n", - "1 Ugg2s5AzSPioEXgCoAEC Law enforcement is not trained to shoot to app... \n", - "2 Ugg3dWTOxryFfHgCoAEC Dont you reckon them 'black lives matter' bann... \n", - "3 Ugg7Gd006w1MPngCoAEC There are a very large number of people who do... \n", - "4 Ugg8FfTbbNF8IngCoAEC The Arab dude is absolutely right, he should h... \n", - "\n", - " clean_text IsToxic IsAbusive \\\n", - "0 people would take step back make case anyone e... 0 False \n", - "1 law enforcement train shoot apprehend train sh... 1 True \n", - "2 reckon black life matter banner hold white cun... 1 True \n", - "3 large number people police officer call crimin... 0 False \n", - "4 arab dude absolutely right shoot extra time sh... 0 False \n", - "\n", - " IsProvocative IsHatespeech IsRacist IsObscene \n", - "0 False False False False \n", - "1 False False False False \n", - "2 False False False True \n", - "3 False False False False \n", - "4 False False False False " - ] - }, - "execution_count": 70, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "DATA_PATH = (PROJECT_ROOT / \"data\" / \"processed\" / \"v2\" / \"comments_preprocessed.csv\")\n", - "\n", - "df = pd.read_csv(DATA_PATH)\n", - "\n", - "TEXT_COL = \"Text\"\n", - "\n", - "df[TEXT_COL] = (df[TEXT_COL].fillna(\"\").astype(str).str.strip())\n", - "\n", - "df = df[df[TEXT_COL] != \"\"].copy()\n", - "\n", - "df[TARGET] = df[TARGET].astype(int)\n", - "\n", - "print(df.shape)\n", - "\n", - "df.head()" - ] - }, - { - "cell_type": "markdown", - "id": "e4e4e638", - "metadata": {}, - "source": [ - "## 3. Split correcto — train / validation / test" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "85c08f41", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "==================================================\n", - "SPLITS\n", - "==================================================\n", - "Train: 699\n", - "Validation: 151\n", - "Test: 150\n" - ] - } - ], - "source": [ - "X = df[TEXT_COL]\n", - "y = df[TARGET]\n", - "\n", - "# TEST FINAL\n", - "X_temp, X_test, y_temp, y_test = train_test_split(\n", - " X,\n", - " y,\n", - " test_size=0.15,\n", - " stratify=y,\n", - " random_state=RAND,\n", - ")\n", - "\n", - "# VALIDATION\n", - "X_train, X_valid, y_train, y_valid = train_test_split(\n", - " X_temp,\n", - " y_temp,\n", - " test_size=0.1765,\n", - " stratify=y_temp,\n", - " random_state=RAND,\n", - ")\n", - "\n", - "print(\"=\" * 50)\n", - "print(\"SPLITS\")\n", - "print(\"=\" * 50)\n", - "\n", - "print(\"Train:\", len(X_train))\n", - "print(\"Validation:\", len(X_valid))\n", - "print(\"Test:\", len(X_test))" - ] - }, - { - "cell_type": "markdown", - "id": "2ef83f62", - "metadata": {}, - "source": [ - "## 4. Exploratory Data Analysis" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4372ea97", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "==================================================\n", - "CLASS DISTRIBUTION\n", - "==================================================\n", - "\n", - "Train\n", - "IsToxic\n", - "0 0.537911\n", - "1 0.462089\n", - "Name: proportion, dtype: float64\n", - "\n", - "Validation\n", - "IsToxic\n", - "0 0.536424\n", - "1 0.463576\n", - "Name: proportion, dtype: float64\n", - "\n", - "Test\n", - "IsToxic\n", - "0 0.54\n", - "1 0.46\n", - "Name: proportion, dtype: float64\n" - ] - } - ], - "source": [ - "print(\"=\" * 50)\n", - "print(\"CLASS DISTRIBUTION\")\n", - "print(\"=\" * 50)\n", - "\n", - "print(\"\\nTrain\")\n", - "print(y_train.value_counts(normalize=True))\n", - "\n", - "print(\"\\nValidation\")\n", - "print(y_valid.value_counts(normalize=True))\n", - "\n", - "print(\"\\nTest\")\n", - "print(y_test.value_counts(normalize=True))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "49b2f924", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "count 699.000000\n", - "mean 33.991416\n", - "std 49.942057\n", - "min 1.000000\n", - "25% 8.000000\n", - "50% 19.000000\n", - "75% 39.000000\n", - "max 815.000000\n", - "Name: Text, dtype: float64\n" - ] - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1IAAAHXCAYAAAC2xGtFAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAUFtJREFUeJzt3Xt8j/Xj//Hne2Mns83szDbHMMeitCKKzCHlQ59SZEqUhtBHrHJO69OnT5FEfb6FioSikvOZnGU5C2GKbQ7ZHMe21++Pbnv/etuGawcbe9xvt/ft5v16va7X9bpe78vm6bqu19tmjDECAAAAANwwp6IeAAAAAADcaghSAAAAAGARQQoAAAAALCJIAQAAAIBFBCkAAAAAsIggBQAAAAAWEaQAAAAAwCKCFAAAAABYRJACgNtAWlqa3nrrLS1atKiohwIAQIlAkAJwSxkxYoRsNttN2Vfz5s3VvHlz+/uVK1fKZrNp9uzZN2X/f2ez2TRixIhc6wcOHKhp06apcePGN2U83bt3V6VKlQqsv5v5ud6Iqz/7wpR1Xq1cuTJP2xe3uSvpCvrvBoDiiyAFoMhMmTJFNpvN/nJzc1NISIiioqL0wQcf6OzZswWyn2PHjmnEiBGKj48vkP6Km5kzZ2ru3LlasGCBfHx8ino4t6Xb/RwqSfgsARSUUkU9AAAYNWqUKleurCtXrigxMVErV65U//799d577+n7779XvXr17G3feOMNDRkyxFL/x44d08iRI1WpUiU1aNDghrdbvHixpf0UposXL6pUqew/so0x+v3337VgwQKFhYUVwchuT1d/9nk9h1D8FPZn+b///U+ZmZkF3i+A4ocgBaDItWnTRo0aNbK/j42N1fLly/XII4/o0Ucf1Z49e+Tu7i5JKlWqVI6BoiBduHBBHh4ecnFxKdT9WOHm5pZjuc1m08CBA2/yaG5/xemzx63h/PnzKlOmjEqXLl3UQwFwk3BrH4Bi6aGHHtLQoUN15MgRffnll/bynJ4HWbJkiZo0aSIfHx95enqqRo0aeu211yT99fzJ3XffLUl69tln7bcRTpkyRdJfz8LUqVNHW7du1QMPPCAPDw/7trk9J5ORkaHXXntNQUFBKlOmjB599FEdPXrUoU2lSpXUvXv3bNvm1OelS5c0YsQI3XHHHXJzc1NwcLA6duyogwcP2tvk9IzUtm3b1KZNG3l5ecnT01MtWrTQhg0bHNpk3T75008/aeDAgfL391eZMmX0j3/8QydOnMg2vpzMnTtXderUkZubm+rUqaM5c+bk2C4zM1Njx45V7dq15ebmpsDAQL3wwgv6888/b2g/V0tPT9fo0aNVtWpVubq6qlKlSnrttdeUlpbm0K5SpUp65JFHtHbtWt1zzz1yc3NTlSpV9Pnnn2frc/v27WrWrJnc3d1VsWJFvfnmm5o8ebJsNpsOHz5sb/f3z+l655CVz/r3339Xhw4dVKZMGQUEBGjAgAHZjuda1q5dq7vvvltubm6qWrWqPv7441zbfvnll2rYsKHc3d3l6+urzp07ZztPc/PHH3+oR48eCgkJkaurqypXrqzevXvr8uXL9ja//fab/vnPf8rX11ceHh6699579eOPPzr0k/X818yZMzVy5EhVqFBBZcuW1eOPP66UlBSlpaWpf//+CggIkKenp5599tkc5+NGjiXr7/Lu3bv14IMPysPDQxUqVNA777zjMJ5rfZZr1qzRP//5T4WFhcnV1VWhoaEaMGCALl686LCv7t27y9PTUwcPHlTbtm1VtmxZdenSxV539TNS58+f1yuvvKLQ0FC5urqqRo0aevfdd2WMcWh3rZ9lAIofrkgBKLaeeeYZvfbaa1q8eLF69uyZY5tdu3bpkUceUb169TRq1Ci5urrqwIED+umnnyRJtWrV0qhRozRs2DD16tVLTZs2lSTdd9999j5OnTqlNm3aqHPnzuratasCAwOvOa4xY8bIZrNp8ODBSk5O1tixY9WyZUvFx8fbr5zdqIyMDD3yyCNatmyZOnfurJdffllnz57VkiVLtHPnTlWtWjXX427atKm8vLz06quvqnTp0vr444/VvHlzrVq1KtuiE3379lW5cuU0fPhwHT58WGPHjlWfPn309ddfX3N8ixcvVqdOnRQREaG4uDidOnVKzz77rCpWrJit7QsvvKApU6bo2WefVb9+/XTo0CF9+OGH2rZtm3766SfL/1P//PPPa+rUqXr88cf1yiuvaOPGjYqLi9OePXuyhbkDBw7o8ccfV48ePRQdHa3PPvtM3bt3V8OGDVW7dm1Jf4WDBx98UDabTbGxsSpTpoz+7//+T66urtccx42cQzfi4sWLatGihRISEtSvXz+FhIToiy++0PLly29o+x07dqhVq1by9/fXiBEj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bH3xxReSlO3Wpas5OTmpRYsWatGihd577z299dZbev3117VixQq1bNnyhv8xfqP279/v8N4YowMHDjh831W5cuV05syZbNseOXLE4Xa8qlWrauPGjbpy5coNL8bg7+8vDw8P7du3L1vd3r175eTklO1/+vMiPDxcUvbjlZRt31WrVtXSpUt1//33F0gwDQ8PV2Zmpvbv32//n3tJSkpK0pkzZ+xjs9rngQMHspXnVHa1a51DN/pZh4eHa+fOnTLGOPSX0+d4NX9/f7m7u9/wZ2GMUeXKlXXHHXdct++r9+Pl5aWdO3des114eHiu519WfUHIz7HkJrfPcseOHfr11181depUdevWzV6+ZMmSfO0vPDxcS5cu1dmzZx2uSuU0V9f7WQageOHWPgDF0vLlyzV69GhVrlz5ms+wnD59OltZ1jMwWcsolylTRpJy/MduXnz++ecOz23Nnj1bx48fV5s2bexlVatW1YYNGxyWi543b162W+46deqkkydP6sMPP8y2n9z+F93Z2VmtWrXSd99953A7YVJSkqZPn64mTZrIy8srr4dnFxwcrAYNGmjq1KkOtzUtWbIk2zMwTzzxhDIyMjR69Ohs/aSnp1ue+7Zt20qSxo4d61D+3nvvSZLatWtnqT/pr0C+fv16xcfH28tOnz6d61W0v7vWOXSjn3Xbtm117NgxzZ4921524cIFffLJJ9fdv7Ozs6KiojR37lwlJCTYy/fs2aNFixY5tO3YsaOcnZ01cuTIbOeQMUanTp3KdT9OTk7q0KGDfvjhB23ZsiVbfVZ/bdu21aZNm7R+/Xp73fnz5/XJJ5+oUqVK2Z6hy6v8HEtucvsss674/H0/xhiNGzfO8j7+rm3btsrIyMj2d/z999+XzWaz/9y4kZ9lAIoXrkgBKHILFizQ3r17lZ6erqSkJC1fvlxLlixReHi4vv/++1y/jFaSRo0apdWrV6tdu3YKDw9XcnKyPvroI1WsWNH+IHzVqlXl4+OjSZMmqWzZsipTpowaN26sypUr52m8vr6+atKkiZ599lklJSVp7NixqlatmsMS7c8//7xmz56t1q1b64knntDBgwf15ZdfZlvOvFu3bvr88881cOBAbdq0SU2bNtX58+e1dOlSvfTSS3rsscdyHMObb75p/86Zl156SaVKldLHH3+stLQ0h+/Nya+4uDi1a9dOTZo0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j6dNmzY6cuSI5s+fryVLlqhFixaKiYnRu+++a/3gAeA2R5ACAOjtt99WgwYN7IsSZPH391diYqKMMfZl0ePj4/O9v7vuuktff/21AgIC5OXldcPb1apVS1OmTNH58+ftQeGnn36Sk5NTtrH/fZvvv//eoWzDhg3ZxrN7925Vq1bN0nEkJCTo2LFjCgkJsff797H89NNP+uijj9S2bVtJfz2vdfLkyVz7W7duncLDw/X666/by44cOWJ5vznZu3evTp06pbfffluhoaGSpC1btmRr5+/vr+joaEVHR6tp06YaNGgQQQoAcsCtfQAA1a1bV126dNEHH3zgUN68eXOdOHFC77zzjg4ePKgJEyZowYIF+d5fly5d5Ofnp8cee0xr1qzRoUOHtHLlSvXr1++aC1906dJFbm5uio6O1s6dO7VixQr17dtXzzzzjAIDA3Pc5sUXX9T+/fs1aNAg7du3T9OnT9eUKVMc2gwePFjr1q1Tnz59FB8fr/379+u777677mITWWP55ZdftGbNGvXr109PPPGEgoKCJEnVq1fXF198oT179mjjxo3q0qWL3N3dc+2vevXqSkhI0IwZM3Tw4EF98MEHmjNnjuX95iQsLEwuLi4aP368fvvtN33//fcaPXq0Q5thw4bpu+++04EDB7Rr1y7NmzdPtWrVuuYcAEBJRZACAEiSRo0aZb/1LkutWrX00UcfacKECapfv742bdqkf/3rX/nel4eHh1avXq2wsDB17NhRtWrVUo8ePXTp0qVrXqHy8PDQokWLdPr0ad199916/PHH1aJFC3344Ye5bhMWFqZvvvlGc+fOVf369TVp0iS99dZbDm3q1aunVatW6ddff1XTpk115513atiwYfYrPrmpVq2aOnbsqLZt26pVq1aqV6+ePvroI3v9p59+qj///FN33XWXnnnmGfXr108BAQG59vfoo49qwIAB6tOnjxo0aKB169Zp6NChlvebE39/f02ZMkWzZs1SRESE3n777WxXmlxcXBQbG6t69erpgQcekLOzs2bMmHHNfgGgpLKZq29+BwAA1zVixAjNnTu3QG51BADcergiBQAAAAAWEaQAAAAAwCJu7QMAAAAAi7giBQAAAAAWEaQAAAAAwCKCFAAAAABYRJACAAAAAIsIUgAAAABgEUEKAAAAACwiSAEAAACARQQpAAAAALDo/wEHuJoPXZAC9wAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "train_lengths = X_train.str.split().apply(len)\n", - "\n", - "print(train_lengths.describe())\n", - "\n", - "plt.figure(figsize=(10, 5))\n", - "\n", - "sns.histplot(train_lengths, bins=40)\n", - "\n", - "plt.title(\"Distribución de longitud de comentarios\")\n", - "plt.xlabel(\"Número de palabras\")\n", - "\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "ad7e7704", - "metadata": {}, - "source": [ - "## 5. Helper Functions" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "836d5be7", - "metadata": {}, - "outputs": [], - "source": [ - "def build_hf_dataset(X, y):\n", - "\n", - " df_local = pd.DataFrame({\n", - " \"text\": X.values,\n", - " \"label\": y.astype(int).values,\n", - " })\n", - "\n", - " return Dataset.from_pandas(df_local)\n", - "\n", - "\n", - "def tokenize_dataset(dataset, tokenizer, max_len):\n", - "\n", - " def tokenize(batch):\n", - "\n", - " return tokenizer(\n", - " batch[\"text\"],\n", - " truncation=True,\n", - " max_length=max_len,\n", - " )\n", - "\n", - " dataset = dataset.map(tokenize, batched=True)\n", - "\n", - " dataset = dataset.remove_columns([\"text\"])\n", - "\n", - " dataset.set_format(\"torch\")\n", - "\n", - " return dataset\n", - "\n", - "\n", - "def compute_metrics(eval_pred):\n", - "\n", - " logits, labels = eval_pred\n", - "\n", - " probs = torch.softmax(\n", - " torch.tensor(logits),\n", - " dim=1\n", - " )[:, 1].numpy()\n", - "\n", - " preds = np.argmax(logits, axis=1)\n", - "\n", - " return {\n", - "\n", - " \"accuracy\": accuracy_score(labels, preds),\n", - "\n", - " \"precision_toxic\": precision_score(\n", - " labels,\n", - " preds,\n", - " pos_label=1,\n", - " ),\n", - "\n", - " \"recall_toxic\": recall_score(\n", - " labels,\n", - " preds,\n", - " pos_label=1,\n", - " ),\n", - "\n", - " \"f1_toxic\": f1_score(\n", - " labels,\n", - " preds,\n", - " pos_label=1,\n", - " ),\n", - "\n", - " \"roc_auc\": roc_auc_score(labels, probs),\n", - " }\n", - "\n", - "\n", - "def evaluate_model(trainer, hf_test, y_test, model_name):\n", - "\n", - " pred_output = trainer.predict(hf_test)\n", - "\n", - " logits = pred_output.predictions\n", - "\n", - " probs = torch.softmax(\n", - " torch.tensor(logits),\n", - " dim=1\n", - " )[:, 1].numpy()\n", - "\n", - " preds = np.argmax(logits, axis=1)\n", - "\n", - " print(\"=\" * 60)\n", - " print(model_name)\n", - " print(\"=\" * 60)\n", - "\n", - " print(classification_report(\n", - " y_test,\n", - " preds,\n", - " target_names=[\"No tóxico\", \"Tóxico\"]\n", - " ))\n", - "\n", - " cm = confusion_matrix(y_test, preds)\n", - "\n", - " plt.figure(figsize=(6, 5))\n", - "\n", - " sns.heatmap(\n", - " cm,\n", - " annot=True,\n", - " fmt=\"d\",\n", - " cmap=\"Blues\",\n", - " xticklabels=[\"No tóxico\", \"Tóxico\"],\n", - " yticklabels=[\"No tóxico\", \"Tóxico\"],\n", - " )\n", - "\n", - " plt.title(f\"{model_name} — Confusion Matrix\")\n", - "\n", - " plt.xlabel(\"Predicción\")\n", - " plt.ylabel(\"Real\")\n", - "\n", - " plt.savefig(PROJECT_ROOT / 'reports' / 'v2' / f\"{model_name}_confusion.png\",\n", - " dpi=150, bbox_inches='tight')\n", - "\n", - " plt.show()\n", - "\n", - " return {\n", - " \"accuracy\": accuracy_score(y_test, preds),\n", - " \"precision\": precision_score(y_test, preds),\n", - " \"recall\": recall_score(y_test, preds),\n", - " \"f1\": f1_score(y_test, preds),\n", - " \"roc_auc\": roc_auc_score(y_test, probs),\n", - " \"preds\": preds,\n", - " \"probs\": probs,\n", - " }" - ] - }, - { - "cell_type": "markdown", - "id": "988496e6", - "metadata": {}, - "source": [ - "## 6. HuggingFace Dataset" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f6f76741", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Dataset({\n", - " features: ['text', 'label'],\n", - " num_rows: 699\n", - "})\n" - ] - } - ], - "source": [ - "hf_train_raw = build_hf_dataset(X_train, y_train)\n", - "hf_valid_raw = build_hf_dataset(X_valid, y_valid)\n", - "hf_test_raw = build_hf_dataset(X_test, y_test)\n", - "\n", - "print(hf_train_raw)" - ] - }, - { - "cell_type": "markdown", - "id": "7986014a", - "metadata": {}, - "source": [ - "\n", - "# 7. Baseline — DistilBERT\n", - "\n", - "DistilBERT será el baseline generalista.\n", - "\n", - "Ventajas:\n", - "- más liviano\n", - "- rápido\n", - "- estable\n", - "- ideal para datasets pequeños\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1e8f8d34", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "distilbert-base-uncased\n" - ] - } - ], - "source": [ - "DISTIL_MODEL = \"distilbert-base-uncased\"\n", - "\n", - "MAX_LEN = 128\n", - "BATCH_SIZE = 8\n", - "EPOCHS = 3\n", - "LR = 2e-5\n", - "\n", - "print(DISTIL_MODEL)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b9ee6361", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Map: 100%|██████████| 699/699 [00:00<00:00, 9167.52 examples/s]\n", - "Map: 100%|██████████| 151/151 [00:00<00:00, 8833.19 examples/s]\n", - "Map: 100%|██████████| 150/150 [00:00<00:00, 10128.07 examples/s]\n" - ] - } - ], - "source": [ - "distil_tokenizer = AutoTokenizer.from_pretrained(\n", - " DISTIL_MODEL\n", - ")\n", - "\n", - "distil_train = tokenize_dataset(\n", - " hf_train_raw,\n", - " distil_tokenizer,\n", - " MAX_LEN,\n", - ")\n", - "\n", - "distil_valid = tokenize_dataset(\n", - " hf_valid_raw,\n", - " distil_tokenizer,\n", - " MAX_LEN,\n", - ")\n", - "\n", - "distil_test = tokenize_dataset(\n", - " hf_test_raw,\n", - " distil_tokenizer,\n", - " MAX_LEN,\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8e867b40", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Loading weights: 100%|██████████| 100/100 [00:00<00:00, 1192.80it/s]\n", - "[transformers] \u001b[1mDistilBertForSequenceClassification LOAD REPORT\u001b[0m from: distilbert-base-uncased\n", - "Key | Status | \n", - "------------------------+------------+-\n", - "vocab_transform.bias | UNEXPECTED | \n", - "vocab_projector.bias | UNEXPECTED | \n", - "vocab_layer_norm.weight | UNEXPECTED | \n", - "vocab_transform.weight | UNEXPECTED | \n", - "vocab_layer_norm.bias | UNEXPECTED | \n", - "classifier.weight | MISSING | \n", - "classifier.bias | MISSING | \n", - "pre_classifier.bias | MISSING | \n", - "pre_classifier.weight | MISSING | \n", - "\n", - "Notes:\n", - "- UNEXPECTED:\tcan be ignored when loading from different task/architecture; not ok if you expect identical arch.\n", - "- MISSING:\tthose params were newly initialized because missing from the checkpoint. Consider training on your downstream task.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DistilBertForSequenceClassification\n" - ] - } - ], - "source": [ - "distil_collator = DataCollatorWithPadding(tokenizer=distil_tokenizer)\n", - "\n", - "distil_model = AutoModelForSequenceClassification.from_pretrained(\n", - " DISTIL_MODEL,\n", - " num_labels=2,\n", - ")\n", - "\n", - "distil_model.to(device)\n", - "\n", - "print(distil_model.__class__.__name__)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ed09755c", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[transformers] warmup_ratio is deprecated and will be removed in v5.2. Use `warmup_steps` instead.\n" - ] - } - ], - "source": [ - "distil_args = TrainingArguments(\n", - "\n", - " output_dir= PROJECT_ROOT / \"models\" / \"distilbert_results\",\n", - "\n", - " learning_rate=LR,\n", - "\n", - " num_train_epochs=EPOCHS,\n", - "\n", - " per_device_train_batch_size=BATCH_SIZE,\n", - " per_device_eval_batch_size=BATCH_SIZE,\n", - "\n", - " weight_decay=0.01,\n", - "\n", - " eval_strategy=\"epoch\",\n", - " save_strategy=\"epoch\",\n", - "\n", - " load_best_model_at_end=True,\n", - "\n", - " metric_for_best_model=\"f1_toxic\",\n", - " greater_is_better=True,\n", - "\n", - " warmup_ratio=0.1,\n", - "\n", - " logging_steps=10,\n", - "\n", - " fp16=torch.cuda.is_available(),\n", - "\n", - " report_to=\"none\",\n", - "\n", - " seed=RAND,\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "827eed3d", - "metadata": {}, - "outputs": [], - "source": [ - "distil_early_stopping = EarlyStoppingCallback(early_stopping_patience=2)\n", - "\n", - "distil_trainer = Trainer(\n", - "\n", - " model=distil_model,\n", - "\n", - " args=distil_args,\n", - "\n", - " train_dataset=distil_train,\n", - " eval_dataset=distil_valid,\n", - "\n", - " processing_class=distil_tokenizer,\n", - "\n", - " data_collator=distil_collator,\n", - "\n", - " compute_metrics=compute_metrics,\n", - "\n", - " callbacks=[distil_early_stopping],\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "eea8b514", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "==================================================\n", - "TRAINING DISTILBERT\n", - "==================================================\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - " \n", - " \n", - " [264/264 00:38, Epoch 3/3]\n", - "
\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
EpochTraining LossValidation LossAccuracyPrecision ToxicRecall ToxicF1 ToxicRoc Auc
10.5621220.5368170.7152320.7213110.6285710.6717560.808818
20.4170880.5419870.7549670.6987950.8285710.7581700.833510
30.3167110.5690830.7682120.7536230.7428570.7482010.823986

" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Writing model shards: 100%|██████████| 1/1 [00:02<00:00, 2.02s/it]\n", - "Writing model shards: 100%|██████████| 1/1 [00:02<00:00, 2.25s/it]\n", - "Writing model shards: 100%|██████████| 1/1 [00:02<00:00, 2.22s/it]\n" - ] - }, - { - "data": { - "text/plain": [ - "TrainOutput(global_step=264, training_loss=0.44362344886317395, metrics={'train_runtime': 36.2928, 'train_samples_per_second': 57.78, 'train_steps_per_second': 7.274, 'total_flos': 54207108392208.0, 'train_loss': 0.44362344886317395, 'epoch': 3.0})" - ] - }, - "execution_count": 83, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "print(\"=\" * 50)\n", - "print(\"TRAINING DISTILBERT\")\n", - "print(\"=\" * 50)\n", - "\n", - "distil_trainer.train()" - ] - }, - { - "cell_type": "markdown", - "id": "0b64fe6f", - "metadata": {}, - "source": [ - "## 8. Evaluación — DistilBERT" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9647c651", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "============================================================\n", - "DistilBERT\n", - "============================================================\n", - " precision recall f1-score support\n", - "\n", - " No tóxico 0.82 0.72 0.76 81\n", - " Tóxico 0.71 0.81 0.76 69\n", - "\n", - " accuracy 0.76 150\n", - " macro avg 0.76 0.76 0.76 150\n", - "weighted avg 0.77 0.76 0.76 150\n", - "\n" - ] - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "

" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "distil_results = evaluate_model(\n", - " distil_trainer,\n", - " distil_test,\n", - " y_test,\n", - " \"DistilBERT\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "92d5d1bc", - "metadata": {}, - "source": [ - "\n", - "# 9. Fine-Tuning especializado — RoBERTa Hate\n", - "\n", - "Modelo especializado en:\n", - "- hate speech\n", - "- toxicidad\n", - "- abuso online\n", - "\n", - "Modelo:\n", - "cardiffnlp/twitter-roberta-base-hate\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "40cbdf8d", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "cardiffnlp/twitter-roberta-base-hate\n" - ] - } - ], - "source": [ - "HATE_MODEL = \"cardiffnlp/twitter-roberta-base-hate\"\n", - "\n", - "MAX_LEN = 128\n", - "BATCH_SIZE = 8\n", - "EPOCHS = 3\n", - "LR = 2e-5\n", - "\n", - "print(HATE_MODEL)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6d0d9245", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Map: 100%|██████████| 699/699 [00:00<00:00, 13631.74 examples/s]\n", - "Map: 100%|██████████| 151/151 [00:00<00:00, 9566.49 examples/s]\n", - "Map: 100%|██████████| 150/150 [00:00<00:00, 10121.39 examples/s]\n" - ] - } - ], - "source": [ - "hate_tokenizer = AutoTokenizer.from_pretrained(\n", - " HATE_MODEL\n", - ")\n", - "\n", - "hate_train = tokenize_dataset(\n", - " hf_train_raw,\n", - " hate_tokenizer,\n", - " MAX_LEN,\n", - ")\n", - "\n", - "hate_valid = tokenize_dataset(\n", - " hf_valid_raw,\n", - " hate_tokenizer,\n", - " MAX_LEN,\n", - ")\n", - "\n", - "hate_test = tokenize_dataset(\n", - " hf_test_raw,\n", - " hate_tokenizer,\n", - " MAX_LEN,\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5114bb65", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Loading weights: 100%|██████████| 201/201 [00:00<00:00, 5778.78it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "RobertaForSequenceClassification\n" - ] - } - ], - "source": [ - "hate_collator = DataCollatorWithPadding(tokenizer=hate_tokenizer)\n", - "\n", - "hate_model = AutoModelForSequenceClassification.from_pretrained(\n", - " HATE_MODEL,\n", - " num_labels=2,\n", - " ignore_mismatched_sizes=True,\n", - ")\n", - "\n", - "hate_model.to(device)\n", - "\n", - "print(hate_model.__class__.__name__)" - ] - }, - { - "cell_type": "markdown", - "id": "9fb50f46", - "metadata": {}, - "source": [ - "## 10. Fine-Tuning controlado" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c3729fb1", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Classification head desbloqueada\n", - "\n", - "Trainable params: 592,130\n", - "Total params: 124,647,170\n", - "Trainable %: 0.48%\n" - ] - } - ], - "source": [ - "# Congelar backbone\n", - "\n", - "for param in hate_model.base_model.parameters():\n", - " param.requires_grad = False\n", - "\n", - "# Classification head entrenable\n", - "classifier_found = False\n", - "\n", - "for name, param in hate_model.named_parameters():\n", - "\n", - " if \"classifier\" in name:\n", - "\n", - " param.requires_grad = True\n", - " classifier_found = True\n", - "\n", - "if classifier_found:\n", - " print(\"Classification head desbloqueada\")\n", - "else:\n", - " print(\"⚠️ No se encontró classifier head\")\n", - "\n", - "# Verificación\n", - "total_params = 0\n", - "trainable_params = 0\n", - "\n", - "for p in hate_model.parameters():\n", - "\n", - " total_params += p.numel()\n", - "\n", - " if p.requires_grad:\n", - " trainable_params += p.numel()\n", - "\n", - "pct = trainable_params / total_params * 100\n", - "\n", - "print()\n", - "print(f\"Trainable params: {trainable_params:,}\")\n", - "print(f\"Total params: {total_params:,}\")\n", - "print(f\"Trainable %: {pct:.2f}%\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7a0a4821", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[transformers] warmup_ratio is deprecated and will be removed in v5.2. Use `warmup_steps` instead.\n" - ] - } - ], - "source": [ - "hate_args = TrainingArguments(\n", - "\n", - " output_dir= PROJECT_ROOT / \"models\" / \"roberta_hate_results\",\n", - "\n", - " learning_rate=LR,\n", - "\n", - " num_train_epochs=EPOCHS,\n", - "\n", - " per_device_train_batch_size=BATCH_SIZE,\n", - " per_device_eval_batch_size=BATCH_SIZE,\n", - "\n", - " weight_decay=0.01,\n", - "\n", - " eval_strategy=\"epoch\",\n", - " save_strategy=\"epoch\",\n", - "\n", - " load_best_model_at_end=True,\n", - "\n", - " metric_for_best_model=\"f1_toxic\",\n", - " greater_is_better=True,\n", - "\n", - " warmup_ratio=0.1,\n", - "\n", - " logging_steps=10,\n", - "\n", - " fp16=torch.cuda.is_available(),\n", - "\n", - " report_to=\"none\",\n", - "\n", - " seed=RAND,\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6a3acd3d", - "metadata": {}, - "outputs": [], - "source": [ - "hate_early_stopping = EarlyStoppingCallback(early_stopping_patience=2)\n", - "\n", - "hate_trainer = Trainer(\n", - "\n", - " model=hate_model,\n", - "\n", - " args=hate_args,\n", - "\n", - " train_dataset=hate_train,\n", - " eval_dataset=hate_valid,\n", - "\n", - " processing_class=hate_tokenizer,\n", - "\n", - " data_collator=hate_collator,\n", - "\n", - " compute_metrics=compute_metrics,\n", - "\n", - " callbacks=[hate_early_stopping],\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a5752cbb", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "==================================================\n", - "TRAINING ROBERTA HATE\n", - "==================================================\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - " \n", - " \n", - " [264/264 00:39, Epoch 3/3]\n", - "
\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
EpochTraining LossValidation LossAccuracyPrecision ToxicRecall ToxicF1 ToxicRoc Auc
10.6139990.5140290.7218540.7692310.5714290.6557380.844621
20.6121990.4972690.7417220.7924530.6000000.6829270.853704
30.5560860.4924560.7417220.7818180.6142860.6880000.856085

" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Writing model shards: 100%|██████████| 1/1 [00:06<00:00, 6.59s/it]\n", - "Writing model shards: 100%|██████████| 1/1 [00:06<00:00, 6.55s/it]\n", - "Writing model shards: 100%|██████████| 1/1 [00:06<00:00, 6.07s/it]\n" - ] - }, - { - "data": { - "text/plain": [ - "TrainOutput(global_step=264, training_loss=0.6079502448891149, metrics={'train_runtime': 35.1712, 'train_samples_per_second': 59.623, 'train_steps_per_second': 7.506, 'total_flos': 107744491058700.0, 'train_loss': 0.6079502448891149, 'epoch': 3.0})" - ] - }, - "execution_count": 93, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "print(\"=\" * 50)\n", - "print(\"TRAINING ROBERTA HATE\")\n", - "print(\"=\" * 50)\n", - "\n", - "hate_trainer.train()" - ] - }, - { - "cell_type": "markdown", - "id": "d18a20d2", - "metadata": {}, - "source": [ - "## 11. Evaluación — RoBERTa Hate" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d58a64a5", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "============================================================\n", - "RoBERTa Hate\n", - "============================================================\n", - " precision recall f1-score support\n", - "\n", - " No tóxico 0.69 0.79 0.74 81\n", - " Tóxico 0.70 0.58 0.63 69\n", - "\n", - " accuracy 0.69 150\n", - " macro avg 0.69 0.68 0.69 150\n", - "weighted avg 0.69 0.69 0.69 150\n", - "\n" - ] - }, - { - "data": { - "image/png": "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uJ6IiEimWMkTEZHR4ux6IiIimeLseiIiIiqWWMkTEZHRknkhzyRPRERGTOZZnsP1REREMsVKnoiIjBZn1xMREckUZ9cTERFRscRKnoiIjJbMC3kmeSIiMmIyz/IcriciIpIpVvJERGS0OLueiIhIpji7noiIiIolVvJERGS0ZF7IM8kTEZERk3mW53A9ERGRTLGSJyIio8XZ9URERDLF2fVERERULLGSJyIioyXzQp5JnoiIjJjMszyH64mIiGSKlTwRERktzq4nIiKSKc6uJyIiomKJlTwRERktmRfyTPJERGS8OFxPRERExRIreSIiMmLyLuWZ5ImIyGhxuJ6IiIiKJVbyRERktGReyDPJExGR8eJwPRERERVLrOSJiMho8d71REREciXvHM/heiIiIrliJU9EREZL5oU8K3kiIjJeCoXhlrwIDw/HBx98ABsbGzg5OaFdu3aIiYnR2SY1NRX9+vVDyZIlYW1tjaCgINy7dy9P+2GSJyIiKmT79u1Dv379cOTIEezcuRPp6en48MMPkZycrN0mNDQUmzZtwqpVq7Bv3z7cvXsX7du3z9N+FEIIYejgpXbo8hOpQyAqcKsu5O0bPVFxNKNt5QLt/8GzDIP15WiT/zPgDx48gJOTE/bt24dGjRohMTERjo6OWLZsGTp06AAAuHjxIqpUqYLDhw+jfv36ueqXlTwRERkvheEWjUaDp0+f6iwajSZXYSQmJgIAHBwcAAAnTpxAeno6AgICtNtUrlwZHh4eOHz4cK4Pj0meiIjIAMLDw6FWq3WW8PDwt74uKysLgwcPhp+fH6pVqwYAiI+Ph4WFBezs7HS2dXZ2Rnx8fK5j4ux6IiIyWoacXR8WFoYhQ4botCmVyre+rl+/fjh37hwOHjxowGheYJInIiKjZch71yuVylwl9Vf1798ff//9N/bv34/SpUtr211cXJCWloaEhASdav7evXtwcXHJdf8criciIipkQgj0798f69atw549e1CuXDmd9T4+PjA3N8fu3bu1bTExMYiNjYWvr2+u98NKnoiIjJZU967v168fli1bhg0bNsDGxkZ7nl2tVkOlUkGtVqNnz54YMmQIHBwcYGtriwEDBsDX1zfXM+sBJnkiIjJiUj1qdt68eQCAJk2a6LRHREQgJCQEADB9+nSYmJggKCgIGo0GgYGBmDt3bp72w+vkiYop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", - "text/plain": [ - "

" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "hate_results = evaluate_model(\n", - " hate_trainer,\n", - " hate_test,\n", - " y_test,\n", - " \"RoBERTa Hate\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "c15c6ff1", - "metadata": {}, - "source": [ - "## 12. Comparación de modelos" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d7f2b05f", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
ModelAccuracyPrecisionRecallF1ROC-AUC
0DistilBERT0.7600000.7088610.8115940.7567570.865987
1RoBERTa Hate0.6933330.7017540.5797100.6349210.797370
\n", - "
" - ], - "text/plain": [ - " Model Accuracy Precision Recall F1 ROC-AUC\n", - "0 DistilBERT 0.760000 0.708861 0.811594 0.756757 0.865987\n", - "1 RoBERTa Hate 0.693333 0.701754 0.579710 0.634921 0.797370" - ] - }, - "execution_count": 95, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "comparison_df = pd.DataFrame({\n", - "\n", - " \"Model\": [\n", - " \"DistilBERT\",\n", - " \"RoBERTa Hate\",\n", - " ],\n", - "\n", - " \"Accuracy\": [\n", - " distil_results[\"accuracy\"],\n", - " hate_results[\"accuracy\"],\n", - " ],\n", - "\n", - " \"Precision\": [\n", - " distil_results[\"precision\"],\n", - " hate_results[\"precision\"],\n", - " ],\n", - "\n", - " \"Recall\": [\n", - " distil_results[\"recall\"],\n", - " hate_results[\"recall\"],\n", - " ],\n", - "\n", - " \"F1\": [\n", - " distil_results[\"f1\"],\n", - " hate_results[\"f1\"],\n", - " ],\n", - "\n", - " \"ROC-AUC\": [\n", - " distil_results[\"roc_auc\"],\n", - " hate_results[\"roc_auc\"],\n", - " ],\n", - "})\n", - "\n", - "comparison_df" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2c757b76", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAArMAAAHXCAYAAACvatLKAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAOZ5JREFUeJzt3XlcVXX+x/H3vQgXUcGFBHQYULHcJTEMHQdrKFxaLGuoLJAxbJG0H5NNmiPaRmNmWONklqiVjubSbphhzuRSOjhW7vsyKqijgmKCcs/vjx7e6QYYJHD52uv5eJzHg/s93+/3fM7lweHN4ZxzbZZlWQIAAAAMZPd0AQAAAMDPRZgFAACAsQizAAAAMBZhFgAAAMYizAIAAMBYhFkAAAAYizALAAAAYxFmAQAAYCzCLABcRrKysvTaa695ugwAqDWEWQAwRJ8+fdSnT58K1y9YsEAjR47UNddcU3tFAYCHEWYB1Khdu3bpgQceUOvWreXr6yt/f3/16tVLU6ZM0Xfffefp8i4bO3bs0IMPPqh33nlH3bp1q9a5V6xYIZvNVu5y1113ufqtXbtWDz/8sKKiouTt7S2bzVal7ZSUlGjKlCm6+uqr5e/vr8aNG6tjx44aNmyYtm7dWq37BODyUc/TBQC4fH388ce688475XA4lJiYqE6dOqmkpEQrV67UqFGjtGnTJk2fPt3TZRrj008/rXDd119/rZkzZ6pfv341tv0RI0aUOesbHh7u+nrJkiV644031KVLF7Vu3Vrbt2+v0vyDBg3SJ598orvvvlspKSk6d+6ctm7dqo8++kg9e/ZUu3btqmM3AFxmbJZlWZ4uAsDlZ8+ePerSpYt+9atfafny5QoJCXFbv3PnTn388ccaOXKkhyqsOU6nUyUlJfL19fV0KdVixYoVuu6667RgwQLdcccdFfbLz8+Xv7+/6tevr9TUVE2dOlWV/RWzbt06RUdH69lnn9WYMWPc1pWWlurkyZNq1qzZJe1HZZ09e1Y+Pj6y2/nnJWACflIB1IiJEyfq9OnTmjFjRpkgK0kRERFuQfb8+fN6+umn1aZNGzkcDoWHh2vMmDEqLi52GxceHq6bbrpJK1asUPfu3VW/fn117txZK1askCQtXrxYnTt3lq+vr6KiovTvf//bbfyQIUPUsGFD7d69W/Hx8WrQoIFatGihp556qkzwmjRpknr27KlmzZqpfv36ioqK0sKFC8vsi81mU2pqqubMmaOOHTvK4XAoOzu7SnNI0ttvv63o6Gj5+fmpSZMm+u1vf+t2Nra8a2aPHDmioUOHKigoSL6+vuratatmz57t1mfv3r2y2WyaNGmSpk+f7nqPr7nmGq1bt67cWn6OoKAg1a9f/2eN3bVrlySpV69eZdZ5eXmVCbIHDx7U0KFD1aJFCzkcDrVq1UoPPfSQSkpKXH12796tO++8U02bNpWfn5+uvfZaffzxx27zXLiEYt68eRo7dqxatmwpPz8/FRYWSpK++uor9e3bVwEBAfLz81NsbKxWrVr1s/YRQM3gMgMANeLDDz9U69at1bNnz0r1v//++zV79mzdcccd+uMf/6ivvvpKGRkZ2rJli9599123vjt37tQ999yjBx54QPfee68mTZqkm2++WdOmTdOYMWP08MMPS5IyMjL0+9//Xtu2bXM7y1ZaWqq+ffvq2muv1cSJE5Wdna309HSdP39eTz31lKvflClTdMstt2jw4MEqKSnRvHnzdOedd+qjjz7SgAED3Gpavny53nnnHaWmpiowMND17/fKzjFhwgSNHz9ePXv21FNPPSUfHx999dVXWr58uW688cZy37PvvvtOffr00c6dO5WamqpWrVppwYIFGjJkiE6ePFnmrPfcuXN16tQpPfDAA7LZbJo4caJuv/127d69W97e3j/5PTp16pSOHTvm1ta0adNqOYMZFhYmSZozZ4569eqlevUq/vV06NAhRUdH6+TJkxo2bJjatWungwcPauHChTpz5ox8fHyUn5+vnj176syZMxoxYoSaNWum2bNn65ZbbtHChQt12223uc359NNPy8fHR4899piKi4vl4+Oj5cuXq1+/foqKilJ6errsdrtmzpyp66+/Xl988YWio6Mveb8BVAMLAKpZQUGBJcm69dZbK9V/w4YNliTr/vvvd2t/7LHHLEnW8uXLXW1hYWGWJGv16tWutqVLl1qSrPr161v79u1ztb/22muWJOvzzz93tSUlJVmSrEceecTV5nQ6rQEDBlg+Pj7W0aNHXe1nzpxxq6ekpMTq1KmTdf3117u1S7Lsdru1adOmMvtWmTl27Nhh2e1267bbbrNKS0vd+judTtfXsbGxVmxsrOt1ZmamJcl6++233eaPiYmxGjZsaBUWFlqWZVl79uyxJFnN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sE9ERITOnTunV155Rbt379Zbb71VrZc/tW3bVm+99Za2bNmir776SoMHD1b9+vXd+pR3bB43bpzefPNNTZgwQZs2bdKWLVs0b948jR07ttpqQ91BmMVlKzs7WyEhIQoPD1ffvn31+eef6+WXX9b7778vLy+vMv0bNWqkiRMnqnv37rrmmmu0d+9eLVmyxPVX/Isvvqhly5YpNDRUV199dZXrCAkJUY8ePbRu3TotWLBAffr0ceuXnJzs6ndheeWVVy46d2pqqrZs2aIFCxZUuh4AdVO9evWUmpqqiRMnqqioSM8//7wGDRqk++67T926ddPOnTu1dOlSNWnSxG1cXFyc61g3bNgw9e/fX/Pnz3frs2nTpjLHlx9es1+epk2bKjExUePHj3f7sJkf6tq1qyZPnqy//OUv6tSpk+bMmeN6pGF1mDFjhk6cOKFu3brpvvvucz2q7IfKOzbHx8fro48+0qeffqprrrlG1157rV566aWf3GeYyWZxSgcAAACG4swsAAAAjEWYBQAAgLEIswAAADAWYRYAAADGIswCAADAWIRZAAAAGIswCwAAAGMRZgHgMrVixQrZbDadPHmy0mPCw8OVmZlZYzUBQHUjzAKAhwwZMkQ2m00PPvhgmXXDhw+XzWbTkCFDar8wADAIYRYAPCg0NFTz5s3Td99952o7e/as5s6dq1//+tcerAwAzECYBQAP6tatm0JDQ7V48WJX2+LFi/XrX//a9TnzklRcXOz6XHpfX1/95je/0bp169zmWrJkia688krVr19f1113nfbu3VtmeytXrlTv3r1Vv359hYaGasSIESoqKqqx/QOAmkaYBQAP+8Mf/qCZM2e6XmdlZSk5Odmtz+OPP65FixZp9uzZWr9+vSIiIhQfH6/jx49Lkg4cOKDbb79dN998szZs2KD7779fTzzxhNscu3btUt++fTVo0CB98803mj9/vlauXKnU1NSa30kAqCGEWQDwsHvvvVcrV67Uvn37tG/fPq1atUr33nuva31RUZFeffVVvfDCC+rXr586dOig119/XfXr19eMGTMkSa+++qratGmjF198UVdddZUGDx5c5nrbjIwMDR48WI8++qjatm2rnj176uWXX9abb76ps2fP1uYuA0C1qefpAgDgl+6KK67QgAEDNGvWLFmWpQEDBigwMNC1fteuXTp37px69erlavP29lZ0dLS2bNkiSdqyZYt69OjhNm9MTIzb66+//lrffPON5syZ42qzLEtOp1N79uxR+/bta2L3AKBGEWYBoA74wx/+4Pp3/9SpU2tkG6dPn9YDDzygESNGlFnHzWYATEWYBYA6oG/fviopKZHNZlN8fLzbujZt2sjHx0erVq1SWFiYJOncuXNat26dHn30UUlS+/bt9cEHH7iN+/LLL91ed+vWTZs3b1ZERETN7QgA1DKumQWAOsDLy0tbtmzR5s2b5eXl5bauQYMGeuihhzRq1ChlZ2dr8+bNSklJ0ZkzZzR06FBJ0oMPPqgdO3Zo1KhR2rZtm+bOnatZs2a5zfOnP/1Jq1evVmpqqjZs2KAdO3bo/fff5wYwAEYjzAJAHeHv7y9/f/9y1z3//PMaNGiQ7rvvPnXr1k07d+7U0qVL1aRJE0nfXyawaNEivffee+rataumTZum5557zm2OLl266B//+Ie2b9+u3r176+qrr9a4cePUokWLGt83AKgpNsuyLE8XAQAAAPwcnJkFAACAsQizAAAAMBZhFgAAAMYizAIAAMBYhFkAAAAYizALAAAAYxFmAQAAYCzCLAAAAIxFmAUAAICxCLMAAAAwFmEWAAAAxiLMAgAAwFj/D8UaLF174v4vAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plt.figure(figsize=(8, 5))\n", - "\n", - "sns.barplot(\n", - " data=comparison_df,\n", - " x=\"Model\",\n", - " y=\"F1\",\n", - ")\n", - "\n", - "plt.title(\"Comparación F1 Score\")\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "7603506d", - "metadata": {}, - "source": [ - "## 13. Error Analysis" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0f32e457", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Best model: DistilBERT\n" - ] - } - ], - "source": [ - "if hate_results[\"f1\"] >= distil_results[\"f1\"]:\n", - "\n", - " best_name = \"RoBERTa Hate\"\n", - " best_preds = hate_results[\"preds\"]\n", - " best_probs = hate_results[\"probs\"]\n", - "\n", - "else:\n", - "\n", - " best_name = \"DistilBERT\"\n", - " best_preds = distil_results[\"preds\"]\n", - " best_probs = distil_results[\"probs\"]\n", - "\n", - "print(\"Best model:\", best_name)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1d7148ce", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Errores: 36\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
textrealpredprob_toxicis_error
0So sad, he looked like such a nice young man000.098947False
1peggy Hubbard for president000.175114False
2Thats a real parent, a real mother. Nothing bu...010.875734True
3Lol stupid mooslims110.884139False
4Another great video and thanks for not putting...000.323487False
\n", - "
" - ], - "text/plain": [ - " text real pred prob_toxic \\\n", - "0 So sad, he looked like such a nice young man 0 0 0.098947 \n", - "1 peggy Hubbard for president 0 0 0.175114 \n", - "2 Thats a real parent, a real mother. Nothing bu... 0 1 0.875734 \n", - "3 Lol stupid mooslims 1 1 0.884139 \n", - "4 Another great video and thanks for not putting... 0 0 0.323487 \n", - "\n", - " is_error \n", - "0 False \n", - "1 False \n", - "2 True \n", - "3 False \n", - "4 False " - ] - }, - "execution_count": 98, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "error_df = pd.DataFrame({\n", - "\n", - " \"text\": X_test.values,\n", - " \"real\": y_test.values,\n", - " \"pred\": best_preds,\n", - " \"prob_toxic\": best_probs,\n", - "})\n", - "\n", - "error_df[\"is_error\"] = (\n", - " error_df[\"real\"] != error_df[\"pred\"]\n", - ")\n", - "\n", - "print(\"Errores:\", error_df[\"is_error\"].sum())\n", - "error_df.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "64457e22", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================================================================\n", - "FALSE NEGATIVES\n", - "================================================================================\n", - "\n", - "Prob toxicidad: 0.3945\n", - "------------------------------------------------------------\n", - "They are protecting and serving us, from people like Michael Brown. The guy deserved to be killed, cry more about it...\n", - "\n", - "Prob toxicidad: 0.497\n", - "------------------------------------------------------------\n", - "So the autopsy showed a number of wounds to the right arm making the scenario of him being shot with his hands raised a lot less likely. Or are we still trying to claim that? Let's see, innocent unarmed gentle giant, minding his own business, gunned down in cold blood for jaywalking by a sadistic, jack-booted, racist thug of a police officer who shot the innocent youth in the back while his hands were raised trying to surrender. I keep forgetting which BS story we are still trying to defend and which claims have been totally refuted by the facts. Regardless, it \"doesn't matter\" because we have already decided that the cop is guilty.\n", - "\n", - "Prob toxicidad: 0.2156\n", - "------------------------------------------------------------\n", - "Let's get this straight and present the facts as the mass media should have from the beginning. 18 yr old (by all legal aspects an adult) robs a convince store. The criminal later flees the seen and is aprehended by the police. Resists arrest and altercation occurs between the two. The police (as in every case similar to this uses force). Criminal is killed. The killing goes to court. A randomly selected jury views all the evidence and hears out all witnesses which pertain to the case.  Radom jury reaches unanimous verdict of not guilty. Im sorry protestors I can't here over all this DEMOCRACY!\n", - "\n", - "Prob toxicidad: 0.0761\n", - "------------------------------------------------------------\n", - "Ah, beautiful.\n", - "\n", - "Prob toxicidad: 0.337\n", - "------------------------------------------------------------\n", - "Remember that time every other race rioted because someone of their race got shot by a white cop after attacking the officer or waving a gun around?\n", - "Remember the huge riot last year when a 13 month old was shot in the head by 2 black kids?\n", - "\n", - "Oh.\n", - "\n", - "Prob toxicidad: 0.3528\n", - "------------------------------------------------------------\n", - "finally a black person with a unbiased opinion. An incredibly high percentage of black lives are lost among themselves and only an extremely small fraction from police.  Black people need to take responsibility for their violence.\n", - "\n", - "Prob toxicidad: 0.3718\n", - "------------------------------------------------------------\n", - "Bottom line: Michael Brown was a drug addict criminal, a violent criminal.\n", - "So why should anyone feel bad he got killed, unless you're a criminal yourself?\n", - "\n", - "Prob toxicidad: 0.1755\n", - "------------------------------------------------------------\n", - "Hahahahaha.  This guy is Ed Bassmaster's character ALWAYS TESTE. Ed Bassmaster has a semi-retarded character who is cross-eyed just like this guy\n", - "\n", - "Prob toxicidad: 0.4335\n", - "------------------------------------------------------------\n", - "All you have to do is drive slowly towards them. If they're smart, they'll get out of the way.\n", - "\n", - "Prob toxicidad: 0.1389\n", - "------------------------------------------------------------\n", - "Seeing the comments on here just proves how backward this country is.\n" - ] - } - ], - "source": [ - "false_negatives = error_df[(error_df[\"real\"] == 1) & (error_df[\"pred\"] == 0)]\n", - "\n", - "print(\"=\" * 80)\n", - "print(\"FALSE NEGATIVES\")\n", - "print(\"=\" * 80)\n", - "\n", - "for idx, row in false_negatives.head(10).iterrows():\n", - "\n", - " print(\"\\nProb toxicidad:\", round(row[\"prob_toxic\"], 4))\n", - " print(\"-\" * 60)\n", - " print(row[\"text\"])\n" - ] - }, - { - "cell_type": "markdown", - "id": "db158aab", - "metadata": {}, - "source": [ - "## 14. Guardado del mejor modelo" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8cc4001e", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Writing model shards: 100%|██████████| 1/1 [00:02<00:00, 2.58s/it]" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Modelo guardado en: /mnt/c/Users/under/Documents/F5/3_Projects/Project_9_Equipo3/Project_YT/models/best_distilbert\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\n" - ] - } - ], - "source": [ - "SAVE_DIR = PROJECT_ROOT / \"models\"\n", - "\n", - "if best_name == \"RoBERTa Hate\":\n", - "\n", - " final_model = hate_trainer\n", - " final_tokenizer = hate_tokenizer\n", - "\n", - " save_path = SAVE_DIR / \"best_roberta_hate\"\n", - "\n", - "else:\n", - "\n", - " final_model = distil_trainer\n", - " final_tokenizer = distil_tokenizer\n", - "\n", - " save_path = SAVE_DIR / \"best_distilbert\"\n", - "\n", - "final_model.save_model(save_path)\n", - "final_tokenizer.save_pretrained(save_path)\n", - "print(\"Modelo guardado en:\", save_path)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "py310", - "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.10.20" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -}