diff --git "a/base LSTM model.ipynb" "b/base LSTM model.ipynb" new file mode 100644--- /dev/null +++ "b/base LSTM model.ipynb" @@ -0,0 +1,1950 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "tYNpi1MX7FmW" + }, + "source": [ + "
\n", + " \n", + "

Sharif University of Technology

\n", + "

Natural Language Processing

\n", + "

Final Project

\n", + "

Spoiler classification and summary generation

\n", + "

Authors: Ali Nikkhah, Ramtin Khoshnevis, Sarina Zahedi

\n", + "

(Equal Contribution)

\n", + "
\n", + "
\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "shi9eHWZaUNq", + "outputId": "f70d8fff-e62f-4bc2-b0fe-5ec2d9592c89" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Collecting datasets\n", + " Downloading datasets-2.21.0-py3-none-any.whl.metadata (21 kB)\n", + "Requirement already satisfied: filelock in /usr/local/lib/python3.10/dist-packages (from datasets) (3.15.4)\n", + "Requirement already satisfied: numpy>=1.17 in /usr/local/lib/python3.10/dist-packages (from datasets) (1.26.4)\n", + "Collecting pyarrow>=15.0.0 (from datasets)\n", + " Downloading pyarrow-17.0.0-cp310-cp310-manylinux_2_28_x86_64.whl.metadata (3.3 kB)\n", + "Collecting dill<0.3.9,>=0.3.0 (from datasets)\n", + " Downloading dill-0.3.8-py3-none-any.whl.metadata (10 kB)\n", + "Requirement already satisfied: pandas in /usr/local/lib/python3.10/dist-packages (from datasets) (2.1.4)\n", + "Requirement already satisfied: requests>=2.32.2 in /usr/local/lib/python3.10/dist-packages (from datasets) (2.32.3)\n", + "Requirement already satisfied: tqdm>=4.66.3 in /usr/local/lib/python3.10/dist-packages (from datasets) (4.66.5)\n", + "Collecting xxhash (from datasets)\n", + " Downloading xxhash-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (12 kB)\n", + "Collecting multiprocess (from datasets)\n", + " Downloading multiprocess-0.70.16-py310-none-any.whl.metadata (7.2 kB)\n", + "Requirement already satisfied: fsspec<=2024.6.1,>=2023.1.0 in /usr/local/lib/python3.10/dist-packages (from fsspec[http]<=2024.6.1,>=2023.1.0->datasets) (2024.6.1)\n", + "Requirement already satisfied: aiohttp in /usr/local/lib/python3.10/dist-packages (from datasets) (3.10.2)\n", + "Requirement already satisfied: huggingface-hub>=0.21.2 in /usr/local/lib/python3.10/dist-packages (from datasets) (0.23.5)\n", + "Requirement already satisfied: packaging in /usr/local/lib/python3.10/dist-packages (from datasets) (24.1)\n", + "Requirement already satisfied: pyyaml>=5.1 in /usr/local/lib/python3.10/dist-packages (from datasets) (6.0.2)\n", + "Requirement already satisfied: aiohappyeyeballs>=2.3.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp->datasets) (2.3.5)\n", + "Requirement already satisfied: aiosignal>=1.1.2 in /usr/local/lib/python3.10/dist-packages (from aiohttp->datasets) (1.3.1)\n", + "Requirement already satisfied: attrs>=17.3.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp->datasets) (24.2.0)\n", + "Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib/python3.10/dist-packages (from aiohttp->datasets) (1.4.1)\n", + "Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib/python3.10/dist-packages (from aiohttp->datasets) (6.0.5)\n", + "Requirement already satisfied: yarl<2.0,>=1.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp->datasets) (1.9.4)\n", + "Requirement already satisfied: async-timeout<5.0,>=4.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp->datasets) (4.0.3)\n", + "Requirement already satisfied: typing-extensions>=3.7.4.3 in /usr/local/lib/python3.10/dist-packages (from huggingface-hub>=0.21.2->datasets) (4.12.2)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests>=2.32.2->datasets) (3.3.2)\n", + "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests>=2.32.2->datasets) (3.7)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests>=2.32.2->datasets) (2.0.7)\n", + "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests>=2.32.2->datasets) (2024.7.4)\n", + "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.10/dist-packages (from pandas->datasets) (2.8.2)\n", + "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.10/dist-packages (from pandas->datasets) (2024.1)\n", + "Requirement already satisfied: tzdata>=2022.1 in /usr/local/lib/python3.10/dist-packages (from pandas->datasets) (2024.1)\n", + "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.10/dist-packages (from python-dateutil>=2.8.2->pandas->datasets) (1.16.0)\n", + "Downloading datasets-2.21.0-py3-none-any.whl (527 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m527.3/527.3 kB\u001b[0m \u001b[31m9.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading dill-0.3.8-py3-none-any.whl (116 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m116.3/116.3 kB\u001b[0m \u001b[31m11.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading pyarrow-17.0.0-cp310-cp310-manylinux_2_28_x86_64.whl (39.9 MB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m39.9/39.9 MB\u001b[0m \u001b[31m18.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading multiprocess-0.70.16-py310-none-any.whl (134 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m134.8/134.8 kB\u001b[0m \u001b[31m10.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading xxhash-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (194 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m194.1/194.1 kB\u001b[0m \u001b[31m16.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hInstalling collected packages: xxhash, pyarrow, dill, multiprocess, datasets\n", + " Attempting uninstall: pyarrow\n", + " Found existing installation: pyarrow 14.0.2\n", + " Uninstalling pyarrow-14.0.2:\n", + " Successfully uninstalled pyarrow-14.0.2\n", + "\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n", + "cudf-cu12 24.4.1 requires pyarrow<15.0.0a0,>=14.0.1, but you have pyarrow 17.0.0 which is incompatible.\n", + "ibis-framework 8.0.0 requires pyarrow<16,>=2, but you have pyarrow 17.0.0 which is incompatible.\u001b[0m\u001b[31m\n", + "\u001b[0mSuccessfully installed datasets-2.21.0 dill-0.3.8 multiprocess-0.70.16 pyarrow-17.0.0 xxhash-3.4.1\n" + ] + } + ], + "source": [ + "!pip install datasets" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "3GvN0W_o5lCV", + "outputId": "acf96d10-3d87-4369-9920-5ce825f16710" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: kaggle in /usr/local/lib/python3.10/dist-packages (1.6.17)\n", + "Requirement already satisfied: six>=1.10 in /usr/local/lib/python3.10/dist-packages (from kaggle) (1.16.0)\n", + "Requirement already satisfied: certifi>=2023.7.22 in /usr/local/lib/python3.10/dist-packages (from kaggle) (2024.7.4)\n", + "Requirement already satisfied: python-dateutil in /usr/local/lib/python3.10/dist-packages (from kaggle) (2.8.2)\n", + "Requirement already satisfied: requests in /usr/local/lib/python3.10/dist-packages (from kaggle) (2.32.3)\n", + "Requirement already satisfied: tqdm in /usr/local/lib/python3.10/dist-packages (from kaggle) (4.66.5)\n", + "Requirement already satisfied: python-slugify in /usr/local/lib/python3.10/dist-packages (from kaggle) (8.0.4)\n", + "Requirement already satisfied: urllib3 in /usr/local/lib/python3.10/dist-packages (from kaggle) (2.0.7)\n", + "Requirement already satisfied: bleach in /usr/local/lib/python3.10/dist-packages (from kaggle) (6.1.0)\n", + "Requirement already satisfied: webencodings in /usr/local/lib/python3.10/dist-packages (from bleach->kaggle) (0.5.1)\n", + "Requirement already satisfied: text-unidecode>=1.3 in /usr/local/lib/python3.10/dist-packages (from python-slugify->kaggle) (1.3)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests->kaggle) (3.3.2)\n", + "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests->kaggle) (3.7)\n" + ] + } + ], + "source": [ + "!pip install kaggle" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "YbqRqUMT7cuE", + "outputId": "320e8152-397a-41fe-ee9f-4b3cfdb98037" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cp: cannot stat 'kaggle.json': No such file or directory\n", + "chmod: cannot access '/root/.kaggle/kaggle.json': No such file or directory\n", + "Dataset URL: https://www.kaggle.com/datasets/rmisra/imdb-spoiler-dataset\n", + "License(s): Attribution 4.0 International (CC BY 4.0)\n", + "Downloading imdb-spoiler-dataset.zip to /content\n", + "100% 330M/331M [00:18<00:00, 23.0MB/s]\n", + "100% 331M/331M [00:18<00:00, 19.1MB/s]\n" + ] + } + ], + "source": [ + "!mkdir -p ~/.kaggle\n", + "!cp kaggle.json ~/.kaggle/\n", + "!chmod 600 ~/.kaggle/kaggle.json\n", + "\n", + "# Download the dataset\n", + "!kaggle datasets download -d rmisra/imdb-spoiler-dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "fAIBnB8I7jIv", + "outputId": "ba9dc80c-26c0-4ade-f22e-a4f4405e1dea" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Archive: imdb-spoiler-dataset.zip\n", + " inflating: IMDB_movie_details.json \n", + " inflating: IMDB_reviews.json \n", + "IMDB_movie_details.json IMDB_reviews.json imdb-spoiler-dataset.zip sample_data\n" + ] + } + ], + "source": [ + "!unzip imdb-spoiler-dataset.zip\n", + "!ls" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 538 + }, + "id": "7dTJhfAd76Qu", + "outputId": "bb68ad6b-8364-44ad-8ba7-1dca651499f9" + }, + "outputs": [ + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "reviews_df" + }, + "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", + "
review_datemovie_iduser_idis_spoilerreview_textratingreview_summary
010 February 2006tt0111161ur1898687TrueIn its Oscar year, Shawshank Redemption (writt...10A classic piece of unforgettable film-making.
16 September 2000tt0111161ur0842118TrueThe Shawshank Redemption is without a doubt on...10Simply amazing. The best film of the 90's.
23 August 2001tt0111161ur1285640TrueI believe that this film is the best story eve...8The best story ever told on film
31 September 2002tt0111161ur1003471True**Yes, there are SPOILERS here**This film has ...10Busy dying or busy living?
420 May 2004tt0111161ur0226855TrueAt the heart of this extraordinary movie is a ...8Great story, wondrously told and acted
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "text/plain": [ + " review_date movie_id user_id is_spoiler \\\n", + "0 10 February 2006 tt0111161 ur1898687 True \n", + "1 6 September 2000 tt0111161 ur0842118 True \n", + "2 3 August 2001 tt0111161 ur1285640 True \n", + "3 1 September 2002 tt0111161 ur1003471 True \n", + "4 20 May 2004 tt0111161 ur0226855 True \n", + "\n", + " review_text rating \\\n", + "0 In its Oscar year, Shawshank Redemption (writt... 10 \n", + "1 The Shawshank Redemption is without a doubt on... 10 \n", + "2 I believe that this film is the best story eve... 8 \n", + "3 **Yes, there are SPOILERS here**This film has ... 10 \n", + "4 At the heart of this extraordinary movie is a ... 8 \n", + "\n", + " review_summary \n", + "0 A classic piece of unforgettable film-making. \n", + "1 Simply amazing. The best film of the 90's. \n", + "2 The best story ever told on film \n", + "3 Busy dying or busy living? \n", + "4 Great story, wondrously told and acted " + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import pandas as pd\n", + "reviews_df = pd.read_json('IMDB_reviews.json' , lines=True)\n", + "reviews_df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "tGnVLhg-N0Me", + "outputId": "08cdf747-c2fe-4438-d09e-0bc46f34ddcf" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Total number of rows in the dataset: 573913\n" + ] + } + ], + "source": [ + "print(f\"Total number of rows in the dataset: {reviews_df.shape[0]}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ma4EVw06eMbK", + "outputId": "6c4fcd54-d166-4bb0-b6c6-c6dfc863b8d3" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Total reviews: 573913\n", + "Number of spoiler reviews: 150924\n", + "Number of non-spoiler reviews: 422989\n", + "Average review length: 1460.5535246631457\n", + "Median review length: 1052.0\n", + "is_spoiler\n", + "False 0.737026\n", + "True 0.262974\n", + "Name: proportion, dtype: float64\n" + ] + } + ], + "source": [ + "import pandas as pd\n", + "\n", + "print(\"Total reviews:\", len(reviews_df))\n", + "print(\"Number of spoiler reviews:\", reviews_df['is_spoiler'].sum())\n", + "print(\"Number of non-spoiler reviews:\", len(reviews_df) - reviews_df['is_spoiler'].sum())\n", + "\n", + "reviews_df['review_length'] = reviews_df['review_text'].apply(len)\n", + "print(\"Average review length:\", reviews_df['review_length'].mean())\n", + "print(\"Median review length:\", reviews_df['review_length'].median())\n", + "\n", + "print(reviews_df['is_spoiler'].value_counts(normalize=True))\n" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "id": "2AtkJ_uGr5o-" + }, + "outputs": [], + "source": [ + "reviews_df = reviews_df[:175000]" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "XLF5DCd9jdYo", + "outputId": "326f551c-d069-4d4a-ab66-f82c9a302eb4" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "428" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(set(reviews_df['movie_id']))" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "10Kz-73LrNZM", + "outputId": "764c23d4-905d-47aa-92ce-c0c7fdd18cb2" + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + ":1: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " reviews_df['review_length'] = reviews_df['review_text'].apply(len)\n" + ] + } + ], + "source": [ + "reviews_df['review_length'] = reviews_df['review_text'].apply(len)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 472 + }, + "id": "GgxuKkb8e24K", + "outputId": "31db9f6d-44f4-4ab3-ec3a-55dfb73f8c08" + }, + "outputs": [ + { + "data": { + "image/png": "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sWDBAhQUFCAhIaHMumVE1YkTxomIyCr16tULP//8M3Q6HdRqNcLDwzF9+nQGJ7I49jwRERERVQDnPBERERFVAMMTERERUQVwzpOZGAwGXL16FS4uLmZ/rAYRERFVDSEEsrKy4OfnV+bB4nfD8GQmV69eLfPwSyIiIqoZLl26BH9//wdqy/BkJsZHP1y6dAkajcbC1RAREdGDyMzMREBAQIUe4cTwZCbGoTqNRsPwREREVMNUZMoNJ4wTERERVQDDExEREVEFMDwRERERVQDDExEREVEFMDwRERERVQDDExEREVEFMDwRERERVQDDExEREVEFMDwRERERVQDDExEREVEFMDwRERERVQDDExEREVEFMDwRERERVQDDE5k4nZKFlMx8S5dBRERktRieSJKamY+oL3di4Hd7LV0KERGR1WJ4IsmRKxko0gv8cy0HuYXFli6HiIjIKjE8keRsarb050tpeRashIiIyHoxPJHENDzlWrASIiIi68XwRJIzpcPTTYYnIiKi8jA8EQBACIFzpcJTEnueiIiIysXwRACA1KwCZBXcniTOOU9ERETlY3giAMCZlGyT95c5bEdERFQuhicCAJxNzQIANPRyAlAybCeEsGRJREREVonhiQAAZ6+V9Dx1b+INAMgt1CMtp9CSJREREVklhicCcHvYroWfBlqNPQDg0k3OeyIiIroTwxMBAM7d6nkK9nZGgIcDAN5xR0REVB6GJ8LNnEJczy4Zomvo5YwAd0cAXCiTiIioPAxPJM13quvmACe1EgEeJeGJd9wRERGVxfBE+OdWeGpw6047Y3jisB0REVFZDE+E9NwiAICXixoAEOBeMueJC2USERGVxfBEyCnUAwAcVQoAQL06JT1PV9PzUKw3WKwuIiIia8TwRMgrLHksi5NKCQDwcbGHSiFHsUEgOSPfkqURERFZHYYnKtXzVBKe5HIZfFxLhvBSsxieiIiISrNoeFqwYAFatWoFjUYDjUaD8PBw/PXXX9L+7t27QyaTmbyGDx9ucoykpCRERUXB0dER3t7eGDt2LIqLi03abNu2DW3btoVarUZwcDCWLFlSppb58+ejfv36sLe3R4cOHbB///4q+c7WKPfWA4Gd1Appm5uDCgCQkVdkkZqIiIislUXDk7+/Pz799FPEx8fj4MGDePzxx/HMM8/g2LFjUps33ngDycnJ0mvm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8GTDHmjYzq7kn0gBHwxMREQEgOHJplVk2C6/SA8hRLXURUREZM0YnmzYgw3blewTuH13HhERkS1jeLJhxvCkukd4UirkUMhLhvU4aZyIiIjhyaYVFd8atlPefc4TANjbcbkCIiIiI4YnG2YchlPeo+cJKHXHHSeNExERMTzZsuIHGLYDSt1xx54nIiIihidbVmQoGbZTyu8zbCet9cSeJyIiIoYnG1YsDdvdb86TcdiOPU9EREQWDU8LFixAq1atoNFooNFoEB4ejr/++kvan5+fj5EjR6JOnTpwdnZGv379kJKSYnKMpKQkREVFwdHREd7e3hg7diyKi4tN2mzbtg1t27aFWq1GcHAwlixZUqaW+fPno379+rC3t0eHDh2wf//+KvnO1qRY6nl60GE79jwRERFZNDz5+/vj008/RXx8PA4ePIjHH38czzzzDI4dOwYAGD16NP73v/9h9erV2L59O65evYrnnntO+rxer0dUVBQKCwuxZ88eLF26FEuWLMHkyZOlNufPn0dUVBQee+wxJCYmYtSoUXj99dexceNGqc3KlSsxZswYTJkyBX///Tdat26NyMhIpKamVt/FsAD9rfCkeNBhO/Y8ERERWTY8PfXUU+jTpw8aNWqExo0b45NPPoGzszP27t2LjIwM/PDDD5g9ezYef/xxhIWFYfHixdizZw/27t0LANi0aROOHz+OZcuWITQ0FL1798a0adMwf/58FBYWAgAWLlyIoKAgzJo1C82aNUN0dDSef/55zJkzR6pj9uzZeOONNzB06FA0b94cCxcuhKOjIxYtWmSR61Jdih90zhOXKiAiIpJYzZwnvV6PX375BTk5OQgPD0d8fDyKiooQEREhtWnatCnq1auHuLg4AEBcXBxCQkLg4+MjtYmMjERmZqbUexUXF2dyDGMb4zEKCwsRHx9v0kYulyMiIkJqU56CggJkZmaavGqaCs954rAdERGR5cPTkSNH4OzsDLVajeHDh+P3339H8+bNodPpoFKp4ObmZtLex8cHOp0OAKDT6UyCk3G/cd+92mRmZiIvLw/Xr1+HXq8vt43xGOWZMWMGXF1dpVdAQEClvr8l6R90zpPS+HBg9jwRERFZPDw1adIEiYmJ2LdvH0aMGIHBgwfj+PHjli7rviZMmICMjAzpdenSJUuXVGEPPmzHniciIiIjpaULUKlUCA4O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3DkAQLdu3aRhsu3bt2P69Ok4ffo0tm3bhrS0NBQVFaFTp06V+r6HDh3C4cOHsXz5cmmbEAIGgwHnz59Hs2bNAACtWrWS9stkMmi1WqSmpgIo6U1q1aoV7O3tpTbt27d/4BpKHxsAfH19pWMT0cNheCKiKufk5ITg4GAAwKJFi9C6dWv88MMPGDZsGLKzswEA69atQ926dU0+p1arpT8PGjRICk8rVqxAr169UKdOnXLPl52djbCwMJPwYuTl5QXg9t1yZ86cwfHjx9G5c2ecPHkS27Ztw82bN9GuXTs4OjpW6vtmZ2fjrbfewjvvvFNmX7169aQ/29nZmeyTyWQwGAyVOuedqvLYRLaO4YmIqpVcLsfEiRMxZswYvPTSS2jevDnUajWSkpLQrVu3u37upZdewqRJkxAfH49ff/0VCxcuvGvbtm3bYuXKlfD29oZGoym3TUhICNzd3fGf//wHoaGhcHZ2Rvfu3fHZZ5/h5s2blZ7vZDz/8ePHpcBYGU2aNMGyZctQUFAghcgDBw6YtDHOG9Pr9ZU+DxFVHCeME1G169+/PxQKBebPnw8XFxe8//77GD16NJYuXYpz587h77//xldffYWlS5dKn6lfvz46duyIYcOGQa/X4+mnn77r8QcNGgRPT08888wz2LlzJ86fP49t27bhnXfeweXLlwGU9MR07doVy5cvl4JSq1atUFBQgNjY2HsGOaNr164hMTHR5JWSkoLx48djz549iI6ORmJiIs6cOYM//vijzITxe3nppZdgMBjw5ptv4sSJE9i4cSO++OILqXYACAwMhEwmw9q1a3Ht2jWpF4+IqhbDExFVO6VSiejoaMycORM5OTmYNm0a/v3vf2PGjBlo1qwZevXqhXXr1iEoKMjkc4MGDcKhQ4fw7LPPwsHB4a7Hd3R0xI4dO1CvXj0899xzaNasGYYNG4b8/HyTnqhu3bpBr9dL4Ukul6Nr166QyWQPNN9pxYoVaNOmjcnru+++Q6tWrbB9+3acPn0aXbp0QZs2bTB58mT4+fk98DXSaDT43//+h8TERISGhuLDDz/E5MmTAUCaB1W3bl18/PHH+OCDD+Dj41OhcEZElScTQghLF0FERPe3fPlyDB06FBkZGfcMj0RUtTjniYjISv34449o0KAB6tati0OHDmH8+PF44YUXGJyILIzhiYjISul0OkyePBk6nQ6+vr7o378/PvnkE0uXRWTzOGxHREREVAGcME5ERERUAQxPRERERBXA8ERERERUAQxPRERERBXA8ERERERUAQxPRERERBXA8ERERERUAQxPRERERBXA8ERERERUAf8Prq5E606ExAUAAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "from wordcloud import WordCloud\n", + "\n", + "# Review length distribution\n", + "sns.histplot(reviews_df['review_length'], bins=50, kde=True)\n", + "plt.title('Distribution of Review Lengths')\n", + "plt.xlabel('Review Length')\n", + "plt.ylabel('Frequency')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 472 + }, + "id": "q--A_BllfLkp", + "outputId": "7f481aac-5743-4f7e-e17b-73c660570361" + }, + "outputs": [ + { + "data": { + "image/png": "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eeRBREREZNFMLprq1q2LDh06YPny5bh792555ERERERkcUwumn755Re0adMGM2fOhJubG8LCwrBp0ybk5+eXR35EREREFsHkJQdatGiBFi1a4NNPP0VSUhLWrl2LESNGQK/X47XXXsM333xTHnkSEZEVyMvLQ1ZWlrnTKDcXL140dwom8/T0hJ2dnbnTqBBkgiAI//Ugp06dQmRkJNLT0yvt7DmtVgulUgmNRgMnJydzp0NlrGPHjpJjk5KSyi0PIkt38eJFjBgxwtxpUDHLli1DgwYNzJ2GxTLl8/tfLW4J/H2D3rVr12Lt2rU4e/Ys1Go1YmNj/+3hiIioAvD09MSyZcvMnYZJTCnyrO3cgL//n1DZMLlo+uqrr7B27VocPnwYjRo1QkREBLZu3QovL6/yyI+IiKyInZ2d1fVqjB07FosXL5YUZ23nRmXL5IHgs2fPRtu2bXHy5EmcPXsWkydPZsFERERW67XXXivTOKq4TO5pysrKgkwmK49ciIiIzCIpKempYxc5VpGAf9HTJJPJcPDgQbzxxhtQq9X4888/AQBr1qzBoUOHyjxBIiKiZyEpKQljx4412jd27FgWTCQyuWj64YcfEBISAnt7e6SmporrM2k0Gnz00UdlniAREdGz8tprr4mDvZctW8ZLcmTkX41piouLw/Lly1G1alVxf0BAAE6dOlWmyRERERFZCpOLpgsXLiAoKKjEfqVSidzc3LLIiYiIiMjimFw0qVQqXL58ucT+Q4cOoV69emWSFBEREZGlMbloGj58ON555x0cO3YMMpkM169fR3x8PCZOnIhRo0aVR45EREREZmfykgOTJk2CXq9Hly5d8PDhQwQFBUGhUGDixIl4++23yyNHIiIiIrMzuWiSyWSYMmUK3nvvPVy+fBn3799HkyZNUL16dTx69Aj29vblkScRERGRWZl8ec7A1tYWTZo0QZs2bVC1alXMnz8f3t7eZZkbERERkcWQXDTl5+dj8uTJaN26NV566SVs2bIFALBy5Up4e3tjwYIFGD9+fHnlSURERGRWki/PTZ8+HV999RWCg4Nx5MgRhIeH480338TRo0cxf/58hIeHw8bGpjxzJSIiIjIbyUXTxo0b8e2336JXr144e/Ys/P39UVRUhNOnT/NedERERFThSb48d+3aNbRq1QoA0LRpUygUCowfP54FExEREVUK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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Box plot for review lengths by spoiler\n", + "sns.boxplot(x='is_spoiler', y='review_length', data=reviews_df)\n", + "plt.title('Review Length by Spoiler Status')\n", + "plt.xlabel('Is Spoiler')\n", + "plt.ylabel('Review Length')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "id": "DSI6GMmYTwGm", + "outputId": "ac155fef-bf01-43db-e57d-fcd909941535" + }, + "outputs": [ + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "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", + "
review_textis_spoiler
0In its Oscar year, Shawshank Redemption (writt...True
1The Shawshank Redemption is without a doubt on...True
2I believe that this film is the best story eve...True
3**Yes, there are SPOILERS here**This film has ...True
4At the heart of this extraordinary movie is a ...True
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "text/plain": [ + " review_text is_spoiler\n", + "0 In its Oscar year, Shawshank Redemption (writt... True\n", + "1 The Shawshank Redemption is without a doubt on... True\n", + "2 I believe that this film is the best story eve... True\n", + "3 **Yes, there are SPOILERS here**This film has ... True\n", + "4 At the heart of this extraordinary movie is a ... True" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data = reviews_df[['review_text', 'is_spoiler']]\n", + "data.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "U8ss94fKF0ng", + "outputId": "447aae8d-6038-4295-d0e7-07873814db51" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "175000" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data.shape[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "etofnLuVbIsH", + "outputId": "4fd63613-3ded-46b2-83a3-c2ef2627945b" + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + ":10: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " data['review_text'] = data['review_text'].apply(clean_text)\n" + ] + } + ], + "source": [ + "def clean_text(text):\n", + " text = text.lower() # Convert to lowercase\n", + " text = text.replace('\\n', ' ') # Replace newlines with spaces\n", + " text = text.replace('\\r', ' ') # Replace carriage returns with spaces\n", + " text = ''.join([c if c.isalnum() or c.isspace() else ' ' for c in text]) # Remove special characters\n", + " text = ' '.join(text.split()) # Remove extra spaces\n", + " return text\n", + "\n", + "# Apply text cleaning to the dataset\n", + "data['review_text'] = data['review_text'].apply(clean_text)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "uLA4MoGFWcic", + "outputId": "2488249f-6b26-4002-d54a-056b87116a2c" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Training set size: 131250\n", + "Validation set size: 21875\n", + "Test set size: 21875\n" + ] + } + ], + "source": [ + "from sklearn.model_selection import train_test_split\n", + "train_data, temp_data = train_test_split(data, test_size=0.25, random_state=42)\n", + "\n", + "# Split the remainder into test and validation sets\n", + "test_data, val_data = train_test_split(temp_data, test_size=0.5, random_state=42)\n", + "\n", + "# Display the sizes of each dataset\n", + "print(\"Training set size:\", len(train_data))\n", + "print(\"Validation set size:\", len(val_data))\n", + "print(\"Test set size:\", len(test_data))" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "id": "vFswYX1OYD7W" + }, + "outputs": [], + "source": [ + "from datasets import Dataset\n", + "import torch\n", + "\n", + "train_dataset = Dataset.from_pandas(train_data)\n", + "val_dataset = Dataset.from_pandas(val_data)\n", + "test_dataset = Dataset.from_pandas(test_data)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "PAe4Amsln2MB", + "outputId": "17d6ce1d-5e4c-4c55-f5dc-96a62fd176a0" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Using device: cuda\n" + ] + } + ], + "source": [ + "import torch\n", + "\n", + "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n", + "print(f\"Using device: {device}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Jnh68UU4fVNv" + }, + "source": [ + "# Model" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "AMxuCcylYi8E", + "outputId": "44c6fa5d-2a02-40ba-ba82-1aaf606ea377" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: tensorflow in /usr/local/lib/python3.10/dist-packages (2.17.0)\n", + "Requirement already satisfied: absl-py>=1.0.0 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (1.4.0)\n", + "Requirement already satisfied: astunparse>=1.6.0 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (1.6.3)\n", + "Requirement already satisfied: flatbuffers>=24.3.25 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (24.3.25)\n", + "Requirement already satisfied: gast!=0.5.0,!=0.5.1,!=0.5.2,>=0.2.1 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (0.6.0)\n", + "Requirement already satisfied: google-pasta>=0.1.1 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (0.2.0)\n", + "Requirement already satisfied: h5py>=3.10.0 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (3.11.0)\n", + "Requirement already satisfied: libclang>=13.0.0 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (18.1.1)\n", + "Requirement already satisfied: ml-dtypes<0.5.0,>=0.3.1 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (0.4.0)\n", + "Requirement already satisfied: opt-einsum>=2.3.2 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (3.3.0)\n", + "Requirement already satisfied: packaging in /usr/local/lib/python3.10/dist-packages (from tensorflow) (24.1)\n", + "Requirement already satisfied: protobuf!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<5.0.0dev,>=3.20.3 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (3.20.3)\n", + "Requirement already satisfied: requests<3,>=2.21.0 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (2.32.3)\n", + "Requirement already satisfied: setuptools in /usr/local/lib/python3.10/dist-packages (from tensorflow) (71.0.4)\n", + "Requirement already satisfied: six>=1.12.0 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (1.16.0)\n", + "Requirement already satisfied: termcolor>=1.1.0 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (2.4.0)\n", + "Requirement already satisfied: typing-extensions>=3.6.6 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (4.12.2)\n", + "Requirement already satisfied: wrapt>=1.11.0 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (1.16.0)\n", + "Requirement already satisfied: grpcio<2.0,>=1.24.3 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (1.64.1)\n", + "Requirement already satisfied: tensorboard<2.18,>=2.17 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (2.17.0)\n", + "Requirement already satisfied: keras>=3.2.0 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (3.4.1)\n", + "Requirement already satisfied: tensorflow-io-gcs-filesystem>=0.23.1 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (0.37.1)\n", + "Requirement already satisfied: numpy<2.0.0,>=1.23.5 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (1.26.4)\n", + "Requirement already satisfied: wheel<1.0,>=0.23.0 in /usr/local/lib/python3.10/dist-packages (from astunparse>=1.6.0->tensorflow) (0.44.0)\n", + "Requirement already satisfied: rich in /usr/local/lib/python3.10/dist-packages (from keras>=3.2.0->tensorflow) (13.7.1)\n", + "Requirement already satisfied: namex in /usr/local/lib/python3.10/dist-packages (from keras>=3.2.0->tensorflow) (0.0.8)\n", + "Requirement already satisfied: optree in /usr/local/lib/python3.10/dist-packages (from keras>=3.2.0->tensorflow) (0.12.1)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2.21.0->tensorflow) (3.3.2)\n", + "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2.21.0->tensorflow) (3.7)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2.21.0->tensorflow) (2.0.7)\n", + "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2.21.0->tensorflow) (2024.7.4)\n", + "Requirement already satisfied: markdown>=2.6.8 in /usr/local/lib/python3.10/dist-packages (from tensorboard<2.18,>=2.17->tensorflow) (3.6)\n", + "Requirement already satisfied: tensorboard-data-server<0.8.0,>=0.7.0 in /usr/local/lib/python3.10/dist-packages (from tensorboard<2.18,>=2.17->tensorflow) (0.7.2)\n", + "Requirement already satisfied: werkzeug>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from tensorboard<2.18,>=2.17->tensorflow) (3.0.3)\n", + "Requirement already satisfied: MarkupSafe>=2.1.1 in /usr/local/lib/python3.10/dist-packages (from werkzeug>=1.0.1->tensorboard<2.18,>=2.17->tensorflow) (2.1.5)\n", + "Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.10/dist-packages (from rich->keras>=3.2.0->tensorflow) (3.0.0)\n", + "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.10/dist-packages (from rich->keras>=3.2.0->tensorflow) (2.16.1)\n", + "Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.10/dist-packages (from markdown-it-py>=2.2.0->rich->keras>=3.2.0->tensorflow) (0.1.2)\n", + "Requirement already satisfied: keras in /usr/local/lib/python3.10/dist-packages (3.4.1)\n", + "Requirement already satisfied: absl-py in /usr/local/lib/python3.10/dist-packages (from keras) (1.4.0)\n", + "Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (from keras) (1.26.4)\n", + "Requirement already satisfied: rich in /usr/local/lib/python3.10/dist-packages (from keras) (13.7.1)\n", + "Requirement already satisfied: namex in /usr/local/lib/python3.10/dist-packages (from keras) (0.0.8)\n", + "Requirement already satisfied: h5py in /usr/local/lib/python3.10/dist-packages (from keras) (3.11.0)\n", + "Requirement already satisfied: optree in /usr/local/lib/python3.10/dist-packages (from keras) (0.12.1)\n", + "Requirement already satisfied: ml-dtypes in /usr/local/lib/python3.10/dist-packages (from keras) (0.4.0)\n", + "Requirement already satisfied: packaging in /usr/local/lib/python3.10/dist-packages (from keras) (24.1)\n", + "Requirement already satisfied: typing-extensions>=4.5.0 in /usr/local/lib/python3.10/dist-packages (from optree->keras) (4.12.2)\n", + "Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.10/dist-packages (from rich->keras) (3.0.0)\n", + "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.10/dist-packages (from rich->keras) (2.16.1)\n", + "Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.10/dist-packages (from markdown-it-py>=2.2.0->rich->keras) (0.1.2)\n" + ] + } + ], + "source": [ + "!pip install tensorflow\n", + "!pip install keras" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "id": "MjJX0nS0YnPu" + }, + "outputs": [], + "source": [ + "import pandas as pd\n", + "from tensorflow.keras.preprocessing.text import Tokenizer\n", + "from tensorflow.keras.preprocessing.sequence import pad_sequences\n", + "from tensorflow.keras.models import Sequential\n", + "from tensorflow.keras.layers import Embedding, LSTM, Dense, Dropout\n", + "\n", + "vocab_size = 8000\n", + "max_length = 2000 # Maximum review length\n", + "oov_tok = \"\"\n", + "\n", + "tokenizer = Tokenizer(num_words=vocab_size, oov_token=oov_tok)\n", + "tokenizer.fit_on_texts(train_data['review_text'])" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "id": "-zSdWsUdZXbz" + }, + "outputs": [], + "source": [ + "def tokenize_and_pad(texts):\n", + " sequences = tokenizer.texts_to_sequences(texts)\n", + " padded_sequences = pad_sequences(sequences, maxlen=max_length, padding='post')\n", + " return padded_sequences" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "id": "idHc4gFMZWK2" + }, + "outputs": [], + "source": [ + "X_train = tokenize_and_pad(train_data['review_text'])\n", + "X_val = tokenize_and_pad(val_data['review_text'])\n", + "X_test = tokenize_and_pad(test_data['review_text'])\n", + "\n", + "y_train = train_data['is_spoiler']\n", + "y_val = val_data['is_spoiler']\n", + "y_test = test_data['is_spoiler']" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Z_e8WL6IZgHq", + "outputId": "231e57cc-5f26-4dd7-cd15-522328e43b18" + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/usr/local/lib/python3.10/dist-packages/keras/src/layers/core/embedding.py:90: UserWarning: Argument `input_length` is deprecated. Just remove it.\n", + " warnings.warn(\n" + ] + } + ], + "source": [ + "from tensorflow.keras.models import Sequential\n", + "from tensorflow.keras.layers import Embedding, LSTM, Dense, Dropout\n", + "\n", + "from tensorflow.keras.layers import Bidirectional\n", + "\n", + "model = Sequential([\n", + " Embedding(vocab_size, 32, input_length=max_length),\n", + " Bidirectional(LSTM(64, return_sequences=True)), # Using a bidirectional LSTM\n", + " Dropout(0.5),\n", + " Bidirectional(LSTM(64)),\n", + " Dropout(0.5),\n", + " Dense(1, activation='sigmoid')\n", + "])" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "id": "VoQMMtlcb1kS" + }, + "outputs": [], + "source": [ + "model.build(input_shape=(None, max_length))" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 323 + }, + "id": "dd-3mlCWZj9I", + "outputId": "938cd928-8d2b-4e6e-8aa2-e61efd302386" + }, + "outputs": [ + { + "data": { + "text/html": [ + "
Model: \"sequential\"\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1mModel: \"sequential\"\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓\n",
+       "┃ Layer (type)                          Output Shape                         Param # ┃\n",
+       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩\n",
+       "│ embedding (Embedding)                │ (None, 2000, 32)            │         256,000 │\n",
+       "├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤\n",
+       "│ bidirectional (Bidirectional)        │ (None, 2000, 128)           │          49,664 │\n",
+       "├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤\n",
+       "│ dropout (Dropout)                    │ (None, 2000, 128)           │               0 │\n",
+       "├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤\n",
+       "│ bidirectional_1 (Bidirectional)      │ (None, 128)                 │          98,816 │\n",
+       "├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤\n",
+       "│ dropout_1 (Dropout)                  │ (None, 128)                 │               0 │\n",
+       "├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤\n",
+       "│ dense (Dense)                        │ (None, 1)                   │             129 │\n",
+       "└──────────────────────────────────────┴─────────────────────────────┴─────────────────┘\n",
+       "
\n" + ], + "text/plain": [ + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓\n", + "┃\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0m┃\n", + "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩\n", + "│ embedding (\u001b[38;5;33mEmbedding\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m2000\u001b[0m, \u001b[38;5;34m32\u001b[0m) │ \u001b[38;5;34m256,000\u001b[0m │\n", + "├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤\n", + "│ bidirectional (\u001b[38;5;33mBidirectional\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m2000\u001b[0m, \u001b[38;5;34m128\u001b[0m) │ \u001b[38;5;34m49,664\u001b[0m │\n", + "├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤\n", + "│ dropout (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m2000\u001b[0m, \u001b[38;5;34m128\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n", + "├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤\n", + "│ bidirectional_1 (\u001b[38;5;33mBidirectional\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m128\u001b[0m) │ \u001b[38;5;34m98,816\u001b[0m │\n", + "├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤\n", + "│ dropout_1 (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m128\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n", + "├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤\n", + "│ dense (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1\u001b[0m) │ \u001b[38;5;34m129\u001b[0m │\n", + "└──────────────────────────────────────┴─────────────────────────────┴─────────────────┘\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Total params: 404,609 (1.54 MB)\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m404,609\u001b[0m (1.54 MB)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Trainable params: 404,609 (1.54 MB)\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m404,609\u001b[0m (1.54 MB)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Non-trainable params: 0 (0.00 B)\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])\n", + "model.summary()" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "sKMQE1YGZlyW", + "outputId": "5048b049-a722-4d30-99f4-68f82684db51" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 1/8\n", + "\u001b[1m4102/4102\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1000s\u001b[0m 242ms/step - accuracy: 0.7216 - loss: 0.5929 - val_accuracy: 0.7301 - val_loss: 0.5770\n", + "Epoch 2/8\n", + "\u001b[1m4102/4102\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1042s\u001b[0m 243ms/step - accuracy: 0.7339 - loss: 0.5535 - val_accuracy: 0.7552 - val_loss: 0.5142\n", + "Epoch 3/8\n", + "\u001b[1m4102/4102\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1053s\u001b[0m 245ms/step - accuracy: 0.7586 - loss: 0.5097 - val_accuracy: 0.7632 - val_loss: 0.5039\n", + "Epoch 4/8\n", + "\u001b[1m4102/4102\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1036s\u001b[0m 244ms/step - accuracy: 0.7700 - loss: 0.4951 - val_accuracy: 0.7632 - val_loss: 0.5038\n", + "Epoch 5/8\n", + "\u001b[1m4102/4102\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1051s\u001b[0m 246ms/step - accuracy: 0.7813 - loss: 0.4803 - val_accuracy: 0.7639 - val_loss: 0.5083\n", + "Epoch 6/8\n", + "\u001b[1m4102/4102\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1042s\u001b[0m 246ms/step - accuracy: 0.7862 - loss: 0.4705 - val_accuracy: 0.7631 - val_loss: 0.5041\n", + "Epoch 7/8\n", + "\u001b[1m4102/4102\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1043s\u001b[0m 246ms/step - accuracy: 0.7963 - loss: 0.4563 - val_accuracy: 0.7644 - val_loss: 0.5167\n", + "Epoch 8/8\n", + "\u001b[1m4102/4102\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1043s\u001b[0m 247ms/step - accuracy: 0.8045 - loss: 0.4437 - val_accuracy: 0.7601 - val_loss: 0.5149\n" + ] + } + ], + "source": [ + "history = model.fit(X_train, y_train, epochs=8, batch_size=32, validation_data=(X_val, y_val))\n" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "UnGyGSeo4K4H", + "outputId": "b7e5ee3f-938a-41ad-ce94-5cb6ebec26b7" + }, + "outputs": [ + { + "metadata": { + "tags": null + }, + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n" + ] + } + ], + "source": [ + "# Save the model in HDF5 forma\n", + "model.save('my_fine_tuned_model.h5')\n" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "WeZv_N194s8z", + "outputId": "722c0f6a-edc8-462e-ce05-c20618833fc3" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Mounted at /content/drive\n" + ] + } + ], + "source": [ + "from google.colab import drive\n", + "drive.mount('/content/drive')\n" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "id": "TmLn0V0D452u" + }, + "outputs": [], + "source": [ + "import os\n", + "\n", + "model_path = '/content/drive/MyDrive/LSTMModel'\n", + "os.makedirs(model_path, exist_ok=True)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "-J6G6pG35DmR", + "outputId": "cd1e3364-1e0b-45c6-a1f6-65cdc71711e2" + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n" + ] + } + ], + "source": [ + "# Save the model in HDF5 format\n", + "model.save(os.path.join(model_path, 'my_fine_tuned_model.h5'))\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "etkORlK83kd-" + }, + "outputs": [], + "source": [ + "!nvidia-smi\n" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "id": "MOlCZi49dw9l" + }, + "outputs": [], + "source": [ + "import gc\n", + "gc.collect()\n", + "torch.cuda.empty_cache()" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "VPW3AaGFnAk4", + "outputId": "eddb477d-8a13-44fe-df8a-5bd0c5d70398" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m684/684\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m71s\u001b[0m 104ms/step - accuracy: 0.7551 - loss: 0.5165\n", + "Test Loss: 0.5159615874290466\n", + "Test Accuracy: 0.7574856877326965\n" + ] + } + ], + "source": [ + "# Evaluate the model on the test set\n", + "loss, accuracy = model.evaluate(X_test, y_test)\n", + "print(f\"Test Loss: {loss}\")\n", + "print(f\"Test Accuracy: {accuracy}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "hRSvT5cB5QMp", + "outputId": "64462d92-b4e0-4b03-be6b-42379bf65ca9" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (1.26.4)\n", + "Requirement already satisfied: scikit-learn in /usr/local/lib/python3.10/dist-packages (1.3.2)\n", + "Requirement already satisfied: tensorflow in /usr/local/lib/python3.10/dist-packages (2.17.0)\n", + "Requirement already satisfied: scipy>=1.5.0 in /usr/local/lib/python3.10/dist-packages (from scikit-learn) (1.13.1)\n", + "Requirement already satisfied: joblib>=1.1.1 in /usr/local/lib/python3.10/dist-packages (from scikit-learn) (1.4.2)\n", + "Requirement already satisfied: threadpoolctl>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from scikit-learn) (3.5.0)\n", + "Requirement already satisfied: absl-py>=1.0.0 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (1.4.0)\n", + "Requirement already satisfied: astunparse>=1.6.0 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (1.6.3)\n", + "Requirement already satisfied: flatbuffers>=24.3.25 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (24.3.25)\n", + "Requirement already satisfied: gast!=0.5.0,!=0.5.1,!=0.5.2,>=0.2.1 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (0.6.0)\n", + "Requirement already satisfied: google-pasta>=0.1.1 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (0.2.0)\n", + "Requirement already satisfied: h5py>=3.10.0 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (3.11.0)\n", + "Requirement already satisfied: libclang>=13.0.0 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (18.1.1)\n", + "Requirement already satisfied: ml-dtypes<0.5.0,>=0.3.1 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (0.4.0)\n", + "Requirement already satisfied: opt-einsum>=2.3.2 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (3.3.0)\n", + "Requirement already satisfied: packaging in /usr/local/lib/python3.10/dist-packages (from tensorflow) (24.1)\n", + "Requirement already satisfied: protobuf!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<5.0.0dev,>=3.20.3 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (3.20.3)\n", + "Requirement already satisfied: requests<3,>=2.21.0 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (2.32.3)\n", + "Requirement already satisfied: setuptools in /usr/local/lib/python3.10/dist-packages (from tensorflow) (71.0.4)\n", + "Requirement already satisfied: six>=1.12.0 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (1.16.0)\n", + "Requirement already satisfied: termcolor>=1.1.0 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (2.4.0)\n", + "Requirement already satisfied: typing-extensions>=3.6.6 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (4.12.2)\n", + "Requirement already satisfied: wrapt>=1.11.0 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (1.16.0)\n", + "Requirement already satisfied: grpcio<2.0,>=1.24.3 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (1.64.1)\n", + "Requirement already satisfied: tensorboard<2.18,>=2.17 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (2.17.0)\n", + "Requirement already satisfied: keras>=3.2.0 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (3.4.1)\n", + "Requirement already satisfied: tensorflow-io-gcs-filesystem>=0.23.1 in /usr/local/lib/python3.10/dist-packages (from tensorflow) (0.37.1)\n", + "Requirement already satisfied: wheel<1.0,>=0.23.0 in /usr/local/lib/python3.10/dist-packages (from astunparse>=1.6.0->tensorflow) (0.44.0)\n", + "Requirement already satisfied: rich in /usr/local/lib/python3.10/dist-packages (from keras>=3.2.0->tensorflow) (13.7.1)\n", + "Requirement already satisfied: namex in /usr/local/lib/python3.10/dist-packages (from keras>=3.2.0->tensorflow) (0.0.8)\n", + "Requirement already satisfied: optree in /usr/local/lib/python3.10/dist-packages (from keras>=3.2.0->tensorflow) (0.12.1)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2.21.0->tensorflow) (3.3.2)\n", + "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2.21.0->tensorflow) (3.7)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2.21.0->tensorflow) (2.0.7)\n", + "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2.21.0->tensorflow) (2024.7.4)\n", + "Requirement already satisfied: markdown>=2.6.8 in /usr/local/lib/python3.10/dist-packages (from tensorboard<2.18,>=2.17->tensorflow) (3.6)\n", + "Requirement already satisfied: tensorboard-data-server<0.8.0,>=0.7.0 in /usr/local/lib/python3.10/dist-packages (from tensorboard<2.18,>=2.17->tensorflow) (0.7.2)\n", + "Requirement already satisfied: werkzeug>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from tensorboard<2.18,>=2.17->tensorflow) (3.0.3)\n", + "Requirement already satisfied: MarkupSafe>=2.1.1 in /usr/local/lib/python3.10/dist-packages (from werkzeug>=1.0.1->tensorboard<2.18,>=2.17->tensorflow) (2.1.5)\n", + "Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.10/dist-packages (from rich->keras>=3.2.0->tensorflow) (3.0.0)\n", + "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.10/dist-packages (from rich->keras>=3.2.0->tensorflow) (2.16.1)\n", + "Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.10/dist-packages (from markdown-it-py>=2.2.0->rich->keras>=3.2.0->tensorflow) (0.1.2)\n" + ] + } + ], + "source": [ + "!pip install numpy scikit-learn tensorflow\n" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "T6uO6ZVX50JF", + "outputId": "dd48288d-9706-4e15-acd6-542171bafae4" + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING:absl:Compiled the loaded model, but the compiled metrics have yet to be built. `model.compile_metrics` will be empty until you train or evaluate the model.\n" + ] + } + ], + "source": [ + "from tensorflow.keras.models import load_model\n", + "model = load_model('my_fine_tuned_model.h5')\n" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "id": "E-YKdjrE6I34" + }, + "outputs": [], + "source": [ + "from sklearn.metrics import classification_report\n", + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "XVxaRfFB6XVo", + "outputId": "a3f35aa5-225d-47a7-97f2-3ef3ed3b97ad" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m684/684\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m80s\u001b[0m 117ms/step\n" + ] + } + ], + "source": [ + "predictions = model.predict(X_test)\n", + "predictions = (predictions > 0.5).astype(int) # Threshold predictions for binary classification\n" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Vy-eg8JG6e1j", + "outputId": "69cb6c8e-4837-417a-81f2-6a8aec773ef1" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " precision recall f1-score support\n", + "\n", + " Non-Spoiler 0.79 0.91 0.84 15695\n", + " Spoiler 0.62 0.38 0.47 6180\n", + "\n", + " accuracy 0.76 21875\n", + " macro avg 0.70 0.64 0.66 21875\n", + "weighted avg 0.74 0.76 0.74 21875\n", + "\n" + ] + } + ], + "source": [ + "report = classification_report(y_test, predictions, target_names=['Non-Spoiler', 'Spoiler'])\n", + "print(report)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "4sHnLnuQ7BNS", + "outputId": "f053ae15-8842-42f0-b7df-ef63914f85f9" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: scikit-learn in /usr/local/lib/python3.10/dist-packages (1.3.2)\n", + "Requirement already satisfied: numpy<2.0,>=1.17.3 in /usr/local/lib/python3.10/dist-packages (from scikit-learn) (1.26.4)\n", + "Requirement already satisfied: scipy>=1.5.0 in /usr/local/lib/python3.10/dist-packages (from scikit-learn) (1.13.1)\n", + "Requirement already satisfied: joblib>=1.1.1 in /usr/local/lib/python3.10/dist-packages (from scikit-learn) (1.4.2)\n", + "Requirement already satisfied: threadpoolctl>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from scikit-learn) (3.5.0)\n" + ] + } + ], + "source": [ + "!pip install scikit-learn" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": { + "id": "5-c0qcYn8GqF" + }, + "outputs": [], + "source": [ + "def prepare_input(text, tokenizer, max_length):\n", + " sequences = tokenizer.texts_to_sequences([text])\n", + " padded = pad_sequences(sequences, maxlen=max_length, padding='post')\n", + " return padded\n", + "\n", + "def predict_spoiler(text, tokenizer, model, max_length=1500):\n", + " prepared_text = prepare_input(text, tokenizer, max_length)\n", + " prediction = model.predict(prepared_text)\n", + " is_spoiler = (prediction > 0.5).astype(int) # Threshold the prediction\n", + " return bool(is_spoiler)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Unh_FyLx8Ith", + "outputId": "4d7b676f-bcb3-4ffb-f9f9-97d6e54f9a44" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 966ms/step\n", + "The text is a non-spoiler.\n" + ] + } + ], + "source": [ + "# Test the function\n", + "input_text = \"Jack Ryan is on a working vacation in London with his family. He has retired from the CIA and is a Professor at the US Naval Academy. He is seen delivering a lecture at the Royal Naval Academy in London.Meanwhile, Ryan's wife Cathy and daughter Sally are sightseeing near Buckingham Palace. Sally and Cathy come upon a British Royal Guard, and Sally tries to get the guard to react by doing an improvised tap dance in front of him. She's impressed when the guard, trained to ignore distraction, doesn't react at all, and they leave.\"\n", + "is_spoiler = predict_spoiler(input_text, tokenizer, model)\n", + "print(f\"The text is a {'spoiler' if is_spoiler else 'non-spoiler'}.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "2bjajseSZpce", + "outputId": "fd4681b2-a612-4453-bbc3-2e3552e67942" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 406ms/step\n", + "The text is a non-spoiler.\n" + ] + } + ], + "source": [ + "# Test the function\n", + "input_text = \"Three years have passed since John Brennan (Russel Crowe) and his wife Lara (Elizabeth Banks) lost their son Luke (Tyler Simpkins) in a car accident. Three years later, John is a community college teacher who is teaching English. He tries to manage his job and raising Luke.\"\n", + "is_spoiler = predict_spoiler(input_text, tokenizer, model)\n", + "print(f\"The text is a {'spoiler' if is_spoiler else 'non-spoiler'}.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "26-LoGDzZ6P1" + }, + "outputs": [], + "source": [ + "# Test the function\n", + "input_text = \"Three years have passed since John Brennan (Russel Crowe) and his wife Lara (Elizabeth Banks) lost their son Luke (Tyler Simpkins) in a car accident. Three years later, John is a community college teacher who is teaching English. He tries to manage his job and raising Luke.\"\n", + "is_spoiler = predict_spoiler(input_text, tokenizer, model)\n", + "print(f\"The text is a {'spoiler' if is_spoiler else 'non-spoiler'}.\")" + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "gpuType": "T4", + "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.11.4" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}