{ "cells": [ { "cell_type": "markdown", "id": "bccc028d", "metadata": {}, "source": [ "# Sentiment Classification for Movie Review Dataset (Korean)\n", "\n", "본 핸즈온에서는 네이버 영화 리뷰에 대한 감정(0: 부정, 1: 긍정)을 요약한 네이버 영화 리뷰 데이터셋으로 AutoGluon 훈련을 수행합니다." ] }, { "cell_type": "code", "execution_count": 1, "id": "6b4f26a5", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n" ] } ], "source": [ "import os\n", "import torch\n", "import mxnet as mx\n", "num_gpus = torch.cuda.device_count()\n", "\n", "if num_gpus == 0:\n", " os.environ['AUTOGLUON_TEXT_TRAIN_WITHOUT_GPU'] = '1'\n", "\n", "print(num_gpus)" ] }, { "cell_type": "code", "execution_count": 2, "id": "74648979", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import warnings\n", "import matplotlib.pyplot as plt\n", "warnings.filterwarnings('ignore')\n", "np.random.seed(123)" ] }, { "cell_type": "markdown", "id": "e9b082b0", "metadata": {}, "source": [ "
\n", "\n", "## 1. Data preparation and Training\n", "\n", "https://github.com/e9t/nsmc/ 에 공개된 네이버 영화 리뷰 데이터셋을 다운로드합니다.\n", "훈련 데이터는 총 15만건이며, 테스트 데이터는 총 5만건입니다." ] }, { "cell_type": "code", "execution_count": 3, "id": "fe401129", "metadata": {}, "outputs": [], "source": [ "save_path = 'ag-02-sentiment-classifcation-kor'\n", "!rm -rf $save_path input" ] }, { "cell_type": "code", "execution_count": 4, "id": "17622d81", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "--2022-08-29 10:23:42-- https://raw.githubusercontent.com/e9t/nsmc/master/ratings_train.txt\n", "Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.111.133, 185.199.110.133, 185.199.109.133, ...\n", "Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.111.133|:443... connected.\n", "HTTP request sent, awaiting response... 200 OK\n", "Length: 14628807 (14M) [text/plain]\n", "Saving to: ‘./input/ratings_train.txt’\n", "\n", "100%[======================================>] 14,628,807 --.-K/s in 0.04s \n", "\n", "2022-08-29 10:23:42 (328 MB/s) - ‘./input/ratings_train.txt’ saved [14628807/14628807]\n", "\n", "--2022-08-29 10:23:42-- https://raw.githubusercontent.com/e9t/nsmc/master/ratings_test.txt\n", "Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.109.133, 185.199.110.133, ...\n", "Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected.\n", "HTTP request sent, awaiting response... 200 OK\n", "Length: 4893335 (4.7M) [text/plain]\n", "Saving to: ‘./input/ratings_test.txt’\n", "\n", "100%[======================================>] 4,893,335 --.-K/s in 0.02s \n", "\n", "2022-08-29 10:23:42 (237 MB/s) - ‘./input/ratings_test.txt’ saved [4893335/4893335]\n", "\n" ] } ], "source": [ "!wget -nc https://raw.githubusercontent.com/e9t/nsmc/master/ratings_train.txt -P ./input/\n", "!wget -nc https://raw.githubusercontent.com/e9t/nsmc/master/ratings_test.txt -P ./input/" ] }, { "cell_type": "code", "execution_count": 5, "id": "a0ebb893", "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "import numpy as np\n", "\n", "train_df = pd.read_csv('./input/ratings_train.txt', header=0, delimiter='\\t')\n", "test_df = pd.read_csv('./input/ratings_test.txt', header=0, delimiter='\\t')\n", "train_df = train_df[['document', 'label']]\n", "test_df = test_df[['document', 'label']]" ] }, { "cell_type": "code", "execution_count": 6, "id": "9aaeb0b0", "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", " \n", " \n", " \n", "
documentlabel
16269가벼우면서도 보여줄건 다 보여주는 성실함.1
140471겁나재밌어...ㅋㅋ아는내용그대로나와도보게되긴함..시청률이떨어지고있지만 트로트의연인 ...1
78683젊은시절 이소룡의 광팬이 되어 개봉작마다 개봉 첫날에 영화보기 위해 줄서서 기다렸던...1
2605최악...감동도없고 ....대놓고범죄..ㅡㅡ말도안돼는영화0
81156어머니에게 감사드려요ㅜㅜ1
\n", "
" ], "text/plain": [ " document label\n", "16269 가벼우면서도 보여줄건 다 보여주는 성실함. 1\n", "140471 겁나재밌어...ㅋㅋ아는내용그대로나와도보게되긴함..시청률이떨어지고있지만 트로트의연인 ... 1\n", "78683 젊은시절 이소룡의 광팬이 되어 개봉작마다 개봉 첫날에 영화보기 위해 줄서서 기다렸던... 1\n", "2605 최악...감동도없고 ....대놓고범죄..ㅡㅡ말도안돼는영화 0\n", "81156 어머니에게 감사드려요ㅜㅜ 1" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from autogluon.tabular import TabularDataset, TabularPredictor\n", "train_data = TabularDataset(train_df)\n", "test_data = TabularDataset(test_df)\n", "\n", "subsample_size = 1000 # subsample data for faster demo, try setting this to larger values\n", "train_data = train_data.sample(n=subsample_size, random_state=0)\n", "test_data = test_data.sample(n=subsample_size, random_state=0)\n", "train_data.head(5)" ] }, { "cell_type": "markdown", "id": "24380778", "metadata": {}, "source": [ "간단한 전처리를 수행합니다. 특수 문자와 한글 외 문자들을 제거하고 중복값 및 결측값을 제외합니다." ] }, { "cell_type": "code", "execution_count": 7, "id": "17a534ce", "metadata": {}, "outputs": [], "source": [ "def basic_preprocess(data):\n", " data.drop_duplicates(subset = ['document'], inplace=True)\n", " data['document'] = data['document'].str.replace(\"[^ㄱ-ㅎㅏ-ㅣ가-힣 ]\",\"\")\n", " #data['document'] = data['document'].str.replace(\"[\\,\\(\\)\\{\\}\\[\\]\\`\\'\\!\\?\\:\\;\\-\\=]\", \" \") # 특수문자 제거만 사용\n", " data = data.dropna(how='any')\n", " return data" ] }, { "cell_type": "code", "execution_count": 8, "id": "acced424", "metadata": {}, "outputs": [], "source": [ "train_data = basic_preprocess(train_data)\n", "test_data = basic_preprocess(test_data)" ] }, { "cell_type": "markdown", "id": "d6e92cf8", "metadata": {}, "source": [ "훈련 지정 시 좀 더 세부적인 하이퍼파라메터 설정이 필요하다면, 사전 정의된 preset을 사용하시면 편리합니다. TextPredictor는 사전 훈련된 BERT, RoBERT, ELECTRA가 내장되어 있으며, 한국어를 비롯한 다국어에 대한 훈련이 필요하면 `multi_cased_bert_base_fuse_late` preset을 사용하시면 됩니다." ] }, { "cell_type": "code", "execution_count": 9, "id": "ae780f5f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['default',\n", " 'medium_quality_faster_train',\n", " 'high_quality',\n", " 'best_quality',\n", " 'multilingual']" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from autogluon.text import TextPredictor, list_text_presets\n", "list_text_presets()" ] }, { "cell_type": "code", "execution_count": 10, "id": "434f02b9", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'default': {'model.hf_text.checkpoint_name': 'google/electra-base-discriminator'},\n", " 'medium_quality_faster_train': {'model.hf_text.checkpoint_name': 'google/electra-small-discriminator',\n", " 'optimization.learning_rate': 0.0004},\n", " 'high_quality': {'model.hf_text.checkpoint_name': 'google/electra-base-discriminator'},\n", " 'best_quality': {'model.hf_text.checkpoint_name': 'microsoft/deberta-v3-base',\n", " 'env.per_gpu_batch_size': 2},\n", " 'multilingual': {'model.hf_text.checkpoint_name': 'microsoft/mdeberta-v3-base',\n", " 'optimization.top_k': 1,\n", " 'env.precision': 'bf16',\n", " 'env.per_gpu_batch_size': 4}}" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list_text_presets(verbose=True)" ] }, { "cell_type": "markdown", "id": "b6ce65b1", "metadata": {}, "source": [ "### Integrated with HuggingFace's Transformers\n", "\n", "AutoGluon Text는 2022년부터 Hugging Face의 Transformers와 통합되었습니다. 이는 Hugging Face의 model hub의 모델을 가져와서 파인튜닝할 수 있다는 의미로, Hugging Face의 API 용법을 숙지할 필요가 없기 때문에 Low-code ML 구현에 이상적합니다." ] }, { "cell_type": "code", "execution_count": 11, "id": "2cd256f7", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Global seed set to 123\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "48222363596a41a28c0aa4aaadc0c704", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Downloading: 0%| | 0.00/414 [00:00" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from autogluon.text import TextPredictor\n", "\n", "predictor = TextPredictor(label='label', eval_metric='acc', path=save_path)\n", "predictor.set_verbosity(2)\n", "\n", "predictor.fit(\n", " train_data,\n", " hyperparameters={\n", " 'model.hf_text.checkpoint_name': 'daekeun-ml/koelectra-small-v3-nsmc',\n", " 'optimization.max_epochs': 2\n", " }\n", ")" ] }, { "cell_type": "markdown", "id": "0397e438", "metadata": {}, "source": [ "
\n", "\n", "## 2. Evaluation and Prediction" ] }, { "cell_type": "markdown", "id": "30454790", "metadata": {}, "source": [ "### Evaluation\n", "\n", "`predictor.evaluation()`를 사용하여 평가를 쉽게 수행할 수 있으며, F1 score 등의 추가 metric도 지정 가능합니다." ] }, { "cell_type": "code", "execution_count": 12, "id": "28ad009c", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "71ea2f5eee9f476f99dddd356ec932fd", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Predicting: 0it [00:00, ?it/s]" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "{'acc': 0.8868868868868869, 'f1': 0.884102564102564}\n" ] } ], "source": [ "if num_gpus > 0:\n", " test_score = predictor.evaluate(test_data, metrics=['acc', 'f1'])\n", " print(test_score) " ] }, { "cell_type": "markdown", "id": "ca3b444a", "metadata": {}, "source": [ "### Prediction\n", "`predictor.predict()`으로 예측을 수행할 수 있습니다." ] }, { "cell_type": "code", "execution_count": 13, "id": "ce7a657f", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "619bf1bf4e634615909e32baa7a41c56", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Predicting: 0it [00:00, ?it/s]" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\"Sentence\": 이 영화 너무너무 재미있어요. 인생 최고의 영화입니다. 최고! \"Predicted Sentiment\": 1\n", "\"Sentence\": 평점 1점도 아깝습니다..비추 \"Predicted Sentiment\": 0\n" ] } ], "source": [ "sentence1 = \"이 영화 너무너무 재미있어요. 인생 최고의 영화입니다. 최고!\"\n", "sentence2 = \"평점 1점도 아깝습니다..비추\"\n", "predictions = predictor.predict({'document': [sentence1, sentence2]})\n", "print('\"Sentence\":', sentence1, '\"Predicted Sentiment\":', predictions[0])\n", "print('\"Sentence\":', sentence2, '\"Predicted Sentiment\":', predictions[1])" ] }, { "cell_type": "markdown", "id": "d7e31a17", "metadata": {}, "source": [ "### Extract Embeddings\n", "훈련된 predictor를 사용하여 임베딩 벡터에 매핑하는 임베딩을 추출할 수도 있습니다." ] }, { "cell_type": "code", "execution_count": 14, "id": "536d070b", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "45070293f33e4125bdad87c5a2175124", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Predicting: 0it [00:00, ?it/s]" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "[[ 0.84613824 -0.0617782 0.49753773 ... -0.10038111 0.6010558\n", " -0.83211917]\n", " [-0.2658142 -0.06882589 -0.09763969 ... -0.10286628 0.33666134\n", " 0.16731662]\n", " [ 0.0561719 -0.26758084 0.03778086 ... 0.02988471 -0.33176646\n", " 0.42773318]\n", " ...\n", " [-0.19822933 0.21227556 0.06556442 ... -0.11700189 0.9228656\n", " -0.17247312]\n", " [-0.34605423 0.2459117 0.10616192 ... -0.11148816 1.0476282\n", " -0.26367357]\n", " [ 0.06941266 0.1493763 -0.43007994 ... -0.02132886 -0.39746076\n", " 0.34852082]]\n" ] } ], "source": [ "embeddings = predictor.extract_embedding(test_data)\n", "print(embeddings)" ] }, { "cell_type": "markdown", "id": "84e9945f", "metadata": {}, "source": [ "TSNE를 사용하여 추출된 임베딩을 시각화합니다. 성능 향상을 위해서는 다국어 모델보다는 한국어 전용 모델로 훈련하는 것이 더 유리합니다." ] }, { "cell_type": "code", "execution_count": 15, "id": "f714605d", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "03a0ab2258554683a873d5d03ec19dea", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Predicting: 0it [00:00, ?it/s]" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "[[ 0.84613824 -0.0617782 0.49753773 ... -0.10038111 0.6010558\n", " -0.83211917]\n", " [-0.2658142 -0.06882589 -0.09763969 ... -0.10286628 0.33666134\n", " 0.16731662]\n", " [ 0.0561719 -0.26758084 0.03778086 ... 0.02988471 -0.33176646\n", " 0.42773318]\n", " ...\n", " [-0.19822933 0.21227556 0.06556442 ... -0.11700189 0.9228656\n", " -0.17247312]\n", " [-0.34605423 0.2459117 0.10616192 ... -0.11148816 1.0476282\n", " -0.26367357]\n", " [ 0.06941266 0.1493763 -0.43007994 ... -0.02132886 -0.39746076\n", " 0.34852082]]\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "if num_gpus > 0:\n", " from sklearn.manifold import TSNE\n", " embeddings = predictor.extract_embedding(test_data)\n", " print(embeddings)\n", "\n", " X_embedded = TSNE(n_components=2, random_state=123).fit_transform(embeddings)\n", " for val, color in [(0, 'red'), (1, 'blue')]:\n", " idx = (test_data['label'].to_numpy() == val).nonzero()\n", " plt.scatter(X_embedded[idx, 0], X_embedded[idx, 1], c=color, label=f'label={val}')\n", " plt.legend(loc='best') " ] } ], "metadata": { "kernelspec": { "display_name": "conda_pytorch_p38", "language": "python", "name": "conda_pytorch_p38" }, "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.8.12" } }, "nbformat": 4, "nbformat_minor": 5 }