insfsilva commited on
Commit
edac844
·
verified ·
1 Parent(s): b41ac6b

Upload Portuguese_Sentiment_Analysis.ipynb

Browse files
Files changed (1) hide show
  1. Portuguese_Sentiment_Analysis.ipynb +1829 -0
Portuguese_Sentiment_Analysis.ipynb ADDED
@@ -0,0 +1,1829 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": null,
6
+ "metadata": {
7
+ "id": "5YjKoArIA-wD"
8
+ },
9
+ "outputs": [],
10
+ "source": [
11
+ "# Instruction to avoid the extense logs for pip install\n",
12
+ "%%capture\n",
13
+ "\n",
14
+ "# This block installs all the dependencies required to train a basic sentiment analyzer.\n",
15
+ "# It only needs to run once at the beginning of the code execution.\n",
16
+ "!pip install -U pt_pump_up\n",
17
+ "!pip install -U datasets\n",
18
+ "!pip install -U transformers"
19
+ ]
20
+ },
21
+ {
22
+ "cell_type": "code",
23
+ "execution_count": null,
24
+ "metadata": {
25
+ "colab": {
26
+ "base_uri": "https://localhost:8080/"
27
+ },
28
+ "id": "HkrJAyMwFC2k",
29
+ "outputId": "c3f8c7f2-d27c-40f0-da62-634abc098551"
30
+ },
31
+ "outputs": [
32
+ {
33
+ "output_type": "stream",
34
+ "name": "stdout",
35
+ "text": [
36
+ "\u001b[33mWARNING: Ignoring invalid distribution -ransformers (/usr/local/lib/python3.10/dist-packages)\u001b[0m\u001b[33m\n",
37
+ "\u001b[0mCollecting numpy==1.26.0\n",
38
+ " Using cached numpy-1.26.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (18.2 MB)\n",
39
+ "\u001b[33mWARNING: Ignoring invalid distribution -ransformers (/usr/local/lib/python3.10/dist-packages)\u001b[0m\u001b[33m\n",
40
+ "\u001b[0mInstalling collected packages: numpy\n",
41
+ " Attempting uninstall: numpy\n",
42
+ " Found existing installation: numpy 1.26.4\n",
43
+ " Uninstalling numpy-1.26.4:\n",
44
+ " Successfully uninstalled numpy-1.26.4\n",
45
+ "\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",
46
+ "cudf-cu12 24.4.1 requires pandas<2.2.2dev0,>=2.0, but you have pandas 2.2.2 which is incompatible.\n",
47
+ "cudf-cu12 24.4.1 requires pyarrow<15.0.0a0,>=14.0.1, but you have pyarrow 16.1.0 which is incompatible.\n",
48
+ "ibis-framework 8.0.0 requires pyarrow<16,>=2, but you have pyarrow 16.1.0 which is incompatible.\n",
49
+ "pt-pump-up 0.0.11 requires numpy>=1.26.4, but you have numpy 1.26.0 which is incompatible.\u001b[0m\u001b[31m\n",
50
+ "\u001b[0mSuccessfully installed numpy-1.26.0\n"
51
+ ]
52
+ }
53
+ ],
54
+ "source": [
55
+ "# Hotfix to deal with module 'numpy.linalg._umath_linalg' has no attribute '_ilp64' error that only happens in colab\n",
56
+ "!pip install numpy==1.26.0"
57
+ ]
58
+ },
59
+ {
60
+ "cell_type": "code",
61
+ "execution_count": null,
62
+ "metadata": {
63
+ "id": "vaxy_YLFB8PE"
64
+ },
65
+ "outputs": [],
66
+ "source": [
67
+ "\n",
68
+ "import torch\n",
69
+ "\n",
70
+ "# The model needs a GPU to Train. Without GPU it would take ages to train\n",
71
+ "if not torch.cuda.is_available():\n",
72
+ " raise Exception(\"GPU not available. Please enable it in the notebook settings.\")"
73
+ ]
74
+ },
75
+ {
76
+ "cell_type": "code",
77
+ "execution_count": null,
78
+ "metadata": {
79
+ "id": "TLbjjbX2uI2x",
80
+ "colab": {
81
+ "base_uri": "https://localhost:8080/"
82
+ },
83
+ "outputId": "ed180b72-bab9-4e2a-e848-6ae92425c01d"
84
+ },
85
+ "outputs": [
86
+ {
87
+ "output_type": "stream",
88
+ "name": "stdout",
89
+ "text": [
90
+ "\u001b[33mWARNING: Ignoring invalid distribution -ransformers (/usr/local/lib/python3.10/dist-packages)\u001b[0m\u001b[33m\n",
91
+ "\u001b[0mRequirement already satisfied: datasets in /usr/local/lib/python3.10/dist-packages (2.20.0)\n",
92
+ "Requirement already satisfied: filelock in /usr/local/lib/python3.10/dist-packages (from datasets) (3.15.3)\n",
93
+ "Requirement already satisfied: numpy>=1.17 in /usr/local/lib/python3.10/dist-packages (from datasets) (1.26.0)\n",
94
+ "Requirement already satisfied: pyarrow>=15.0.0 in /usr/local/lib/python3.10/dist-packages (from datasets) (16.1.0)\n",
95
+ "Requirement already satisfied: pyarrow-hotfix in /usr/local/lib/python3.10/dist-packages (from datasets) (0.6)\n",
96
+ "Requirement already satisfied: dill<0.3.9,>=0.3.0 in /usr/local/lib/python3.10/dist-packages (from datasets) (0.3.8)\n",
97
+ "Requirement already satisfied: pandas in /usr/local/lib/python3.10/dist-packages (from datasets) (2.2.2)\n",
98
+ "Requirement already satisfied: requests>=2.32.2 in /usr/local/lib/python3.10/dist-packages (from datasets) (2.32.3)\n",
99
+ "Requirement already satisfied: tqdm>=4.66.3 in /usr/local/lib/python3.10/dist-packages (from datasets) (4.66.4)\n",
100
+ "Requirement already satisfied: xxhash in /usr/local/lib/python3.10/dist-packages (from datasets) (3.4.1)\n",
101
+ "Requirement already satisfied: multiprocess in /usr/local/lib/python3.10/dist-packages (from datasets) (0.70.16)\n",
102
+ "Requirement already satisfied: fsspec[http]<=2024.5.0,>=2023.1.0 in /usr/local/lib/python3.10/dist-packages (from datasets) (2023.6.0)\n",
103
+ "Requirement already satisfied: aiohttp in /usr/local/lib/python3.10/dist-packages (from datasets) (3.9.5)\n",
104
+ "Requirement already satisfied: huggingface-hub>=0.21.2 in /usr/local/lib/python3.10/dist-packages (from datasets) (0.23.4)\n",
105
+ "Requirement already satisfied: packaging in /usr/local/lib/python3.10/dist-packages (from datasets) (24.1)\n",
106
+ "Requirement already satisfied: pyyaml>=5.1 in /usr/local/lib/python3.10/dist-packages (from datasets) (6.0.1)\n",
107
+ "Requirement already satisfied: aiosignal>=1.1.2 in /usr/local/lib/python3.10/dist-packages (from aiohttp->datasets) (1.3.1)\n",
108
+ "Requirement already satisfied: attrs>=17.3.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp->datasets) (23.2.0)\n",
109
+ "Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib/python3.10/dist-packages (from aiohttp->datasets) (1.4.1)\n",
110
+ "Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib/python3.10/dist-packages (from aiohttp->datasets) (6.0.5)\n",
111
+ "Requirement already satisfied: yarl<2.0,>=1.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp->datasets) (1.9.4)\n",
112
+ "Requirement already satisfied: async-timeout<5.0,>=4.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp->datasets) (4.0.3)\n",
113
+ "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",
114
+ "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",
115
+ "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests>=2.32.2->datasets) (3.7)\n",
116
+ "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",
117
+ "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests>=2.32.2->datasets) (2024.6.2)\n",
118
+ "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.10/dist-packages (from pandas->datasets) (2.8.2)\n",
119
+ "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.10/dist-packages (from pandas->datasets) (2023.4)\n",
120
+ "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.10/dist-packages (from pandas->datasets) (2024.1)\n",
121
+ "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",
122
+ "\u001b[33mWARNING: Ignoring invalid distribution -ransformers (/usr/local/lib/python3.10/dist-packages)\u001b[0m\u001b[33m\n",
123
+ "\u001b[0m"
124
+ ]
125
+ }
126
+ ],
127
+ "source": [
128
+ "# HuggingFace standard library to download datasets from the HuggingFace Hub\n",
129
+ "!pip install -U datasets\n",
130
+ "\n",
131
+ "from datasets import load_dataset"
132
+ ]
133
+ },
134
+ {
135
+ "cell_type": "code",
136
+ "execution_count": null,
137
+ "metadata": {
138
+ "id": "NonjqjgkAzkm"
139
+ },
140
+ "outputs": [],
141
+ "source": [
142
+ "# Usage of the PT-Pump-Up library is not mandatory, but it will make your life easier.\n",
143
+ "# It reuses code previously developed for similar NLP tasks. That is already tested and validated.\n",
144
+ "from pt_pump_up.benchmarking import TrainerFactory"
145
+ ]
146
+ },
147
+ {
148
+ "cell_type": "markdown",
149
+ "metadata": {
150
+ "id": "J5-xoiDDXS0R"
151
+ },
152
+ "source": [
153
+ "### Sentiment Analysis with BERT"
154
+ ]
155
+ },
156
+ {
157
+ "cell_type": "code",
158
+ "metadata": {
159
+ "colab": {
160
+ "base_uri": "https://localhost:8080/"
161
+ },
162
+ "id": "zax-hsAmXVMD",
163
+ "outputId": "0e7370f4-15d4-44e1-e04d-700bf3bc50a8"
164
+ },
165
+ "source": [
166
+ "import gc\n",
167
+ "import torch\n",
168
+ "\n",
169
+ "torch.cuda.empty_cache()\n",
170
+ "gc.collect()\n",
171
+ "\n",
172
+ "\n",
173
+ "!nvidia-smi\n"
174
+ ],
175
+ "execution_count": null,
176
+ "outputs": [
177
+ {
178
+ "output_type": "stream",
179
+ "name": "stdout",
180
+ "text": [
181
+ "Thu Aug 1 16:02:17 2024 \n",
182
+ "+---------------------------------------------------------------------------------------+\n",
183
+ "| NVIDIA-SMI 535.104.05 Driver Version: 535.104.05 CUDA Version: 12.2 |\n",
184
+ "|-----------------------------------------+----------------------+----------------------+\n",
185
+ "| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |\n",
186
+ "| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |\n",
187
+ "| | | MIG M. |\n",
188
+ "|=========================================+======================+======================|\n",
189
+ "| 0 Tesla T4 Off | 00000000:00:04.0 Off | 0 |\n",
190
+ "| N/A 73C P0 31W / 70W | 11471MiB / 15360MiB | 0% Default |\n",
191
+ "| | | N/A |\n",
192
+ "+-----------------------------------------+----------------------+----------------------+\n",
193
+ " \n",
194
+ "+---------------------------------------------------------------------------------------+\n",
195
+ "| Processes: |\n",
196
+ "| GPU GI CI PID Type Process name GPU Memory |\n",
197
+ "| ID ID Usage |\n",
198
+ "|=======================================================================================|\n",
199
+ "+---------------------------------------------------------------------------------------+\n"
200
+ ]
201
+ }
202
+ ]
203
+ },
204
+ {
205
+ "cell_type": "markdown",
206
+ "metadata": {
207
+ "id": "6YNYgk8EC9f_"
208
+ },
209
+ "source": [
210
+ "### Setup\n",
211
+ "\n",
212
+ "We'll need [the Transformers library](https://huggingface.co/transformers/) by Hugging Face:"
213
+ ]
214
+ },
215
+ {
216
+ "cell_type": "code",
217
+ "metadata": {
218
+ "id": "U4Xpam-YYN0D",
219
+ "colab": {
220
+ "base_uri": "https://localhost:8080/"
221
+ },
222
+ "outputId": "ff83ebe3-63db-4ff3-f4fe-7737566b1a93"
223
+ },
224
+ "source": [
225
+ "!pip install -q -U watermark"
226
+ ],
227
+ "execution_count": null,
228
+ "outputs": [
229
+ {
230
+ "output_type": "stream",
231
+ "name": "stdout",
232
+ "text": [
233
+ "\u001b[33mWARNING: Ignoring invalid distribution -ransformers (/usr/local/lib/python3.10/dist-packages)\u001b[0m\u001b[33m\n",
234
+ "\u001b[0m\u001b[33mWARNING: Ignoring invalid distribution -ransformers (/usr/local/lib/python3.10/dist-packages)\u001b[0m\u001b[33m\n",
235
+ "\u001b[0m"
236
+ ]
237
+ }
238
+ ]
239
+ },
240
+ {
241
+ "cell_type": "code",
242
+ "metadata": {
243
+ "id": "wq4WwHKPDE_x",
244
+ "colab": {
245
+ "base_uri": "https://localhost:8080/"
246
+ },
247
+ "outputId": "4b0610e4-5ae5-4f92-833c-4d6e547d89fe"
248
+ },
249
+ "source": [
250
+ "!pip install -qq transformers"
251
+ ],
252
+ "execution_count": null,
253
+ "outputs": [
254
+ {
255
+ "output_type": "stream",
256
+ "name": "stdout",
257
+ "text": [
258
+ "\u001b[33mWARNING: Ignoring invalid distribution -ransformers (/usr/local/lib/python3.10/dist-packages)\u001b[0m\u001b[33m\n",
259
+ "\u001b[0m\u001b[33mWARNING: Ignoring invalid distribution -ransformers (/usr/local/lib/python3.10/dist-packages)\u001b[0m\u001b[33m\n",
260
+ "\u001b[0m"
261
+ ]
262
+ }
263
+ ]
264
+ },
265
+ {
266
+ "cell_type": "code",
267
+ "metadata": {
268
+ "colab": {
269
+ "base_uri": "https://localhost:8080/"
270
+ },
271
+ "id": "_W04uiKzDGnF",
272
+ "outputId": "d301c90f-ec5a-40db-8781-4623f4a609c5"
273
+ },
274
+ "source": [
275
+ "%reload_ext watermark\n",
276
+ "%watermark -v -p numpy,pandas,torch,transformers"
277
+ ],
278
+ "execution_count": null,
279
+ "outputs": [
280
+ {
281
+ "output_type": "stream",
282
+ "name": "stdout",
283
+ "text": [
284
+ "Python implementation: CPython\n",
285
+ "Python version : 3.10.12\n",
286
+ "IPython version : 7.34.0\n",
287
+ "\n",
288
+ "numpy : 1.26.0\n",
289
+ "pandas : 2.2.2\n",
290
+ "torch : 2.3.0+cu121\n",
291
+ "transformers: 4.43.2\n",
292
+ "\n"
293
+ ]
294
+ }
295
+ ]
296
+ },
297
+ {
298
+ "cell_type": "code",
299
+ "source": [
300
+ "pip install huggingface_hub"
301
+ ],
302
+ "metadata": {
303
+ "id": "CzEnu5jZc4vM"
304
+ },
305
+ "execution_count": null,
306
+ "outputs": []
307
+ },
308
+ {
309
+ "cell_type": "code",
310
+ "source": [
311
+ "!huggingface-cli login"
312
+ ],
313
+ "metadata": {
314
+ "id": "qDortxA9c1dG"
315
+ },
316
+ "execution_count": null,
317
+ "outputs": []
318
+ },
319
+ {
320
+ "cell_type": "code",
321
+ "source": [
322
+ "from collections import defaultdict\n",
323
+ "import torch\n",
324
+ "from huggingface_hub import HfApi, upload_file\n",
325
+ "api = HfApi()\n",
326
+ "\n",
327
+ "# Defina o nome do repositório\n",
328
+ "repo_id = \"insfsilva/SentimentAnalysis-IMDB-Portuguese-bert-large-portuguese-cased\""
329
+ ],
330
+ "metadata": {
331
+ "id": "6fJCtx-McxeG"
332
+ },
333
+ "execution_count": null,
334
+ "outputs": []
335
+ },
336
+ {
337
+ "cell_type": "markdown",
338
+ "metadata": {
339
+ "id": "hexarFBTDo4r"
340
+ },
341
+ "source": [
342
+ "#### Setup & Config"
343
+ ]
344
+ },
345
+ {
346
+ "cell_type": "code",
347
+ "metadata": {
348
+ "id": "wVtdTVF4DazQ"
349
+ },
350
+ "source": [
351
+ "import transformers\n",
352
+ "from transformers import BertModel, BertTokenizer, AdamW, get_linear_schedule_with_warmup\n",
353
+ "import torch\n",
354
+ "\n",
355
+ "import numpy as np\n",
356
+ "import pandas as pd\n",
357
+ "import seaborn as sns\n",
358
+ "from pylab import rcParams\n",
359
+ "import matplotlib.pyplot as plt\n",
360
+ "from matplotlib import rc\n",
361
+ "from sklearn.model_selection import train_test_split\n",
362
+ "from sklearn.metrics import confusion_matrix, classification_report\n",
363
+ "from collections import defaultdict\n",
364
+ "from textwrap import wrap\n",
365
+ "\n",
366
+ "from torch import nn, optim\n",
367
+ "from torch.utils.data import Dataset, DataLoader\n",
368
+ "import torch.nn.functional as F\n",
369
+ "\n",
370
+ "%matplotlib inline\n",
371
+ "%config InlineBackend.figure_format='retina'\n",
372
+ "\n",
373
+ "sns.set(style='whitegrid', palette='muted', font_scale=1.2)\n",
374
+ "\n",
375
+ "HAPPY_COLORS_PALETTE = [\"#01BEFE\", \"#FFDD00\", \"#FF7D00\", \"#FF006D\", \"#ADFF02\", \"#8F00FF\"]\n",
376
+ "\n",
377
+ "sns.set_palette(sns.color_palette(HAPPY_COLORS_PALETTE))\n",
378
+ "\n",
379
+ "rcParams['figure.figsize'] = 12, 8\n",
380
+ "\n",
381
+ "RANDOM_SEED = 42\n",
382
+ "np.random.seed(RANDOM_SEED)\n",
383
+ "torch.manual_seed(RANDOM_SEED)\n",
384
+ "\n",
385
+ "device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n",
386
+ "device"
387
+ ],
388
+ "execution_count": null,
389
+ "outputs": []
390
+ },
391
+ {
392
+ "cell_type": "code",
393
+ "metadata": {
394
+ "id": "_PhgD2fiWmTo"
395
+ },
396
+ "source": [
397
+ "df = pd.read_csv('/content/imdb-reviews-pt-br.csv')\n",
398
+ "df.head()"
399
+ ],
400
+ "execution_count": null,
401
+ "outputs": []
402
+ },
403
+ {
404
+ "cell_type": "code",
405
+ "metadata": {
406
+ "id": "9C1BU77AEFgI"
407
+ },
408
+ "source": [
409
+ "df.shape"
410
+ ],
411
+ "execution_count": null,
412
+ "outputs": []
413
+ },
414
+ {
415
+ "cell_type": "markdown",
416
+ "metadata": {
417
+ "id": "WXZDP5WwEKO8"
418
+ },
419
+ "source": [
420
+ "We have about 11k examples. Let's check for missing values:\n",
421
+ "\n"
422
+ ]
423
+ },
424
+ {
425
+ "cell_type": "code",
426
+ "metadata": {
427
+ "id": "iXPjHlkIWZvA"
428
+ },
429
+ "source": [
430
+ "df.info()"
431
+ ],
432
+ "execution_count": null,
433
+ "outputs": []
434
+ },
435
+ {
436
+ "cell_type": "markdown",
437
+ "metadata": {
438
+ "id": "E8xR01alEwOP"
439
+ },
440
+ "source": [
441
+ "Great, no missing values in the score and review texts! Do we have class imbalance?"
442
+ ]
443
+ },
444
+ {
445
+ "cell_type": "code",
446
+ "metadata": {
447
+ "id": "WUfzETcuExZq"
448
+ },
449
+ "source": [
450
+ "sns.countplot(df.sentiment)\n",
451
+ "plt.xlabel('Labels');"
452
+ ],
453
+ "execution_count": null,
454
+ "outputs": []
455
+ },
456
+ {
457
+ "cell_type": "code",
458
+ "metadata": {
459
+ "id": "okU44oZQE7Tt"
460
+ },
461
+ "source": [
462
+ "class_names = ['negative', 'positive']"
463
+ ],
464
+ "execution_count": null,
465
+ "outputs": []
466
+ },
467
+ {
468
+ "cell_type": "code",
469
+ "metadata": {
470
+ "id": "qVxTGOeMFAhw"
471
+ },
472
+ "source": [
473
+ "ax = sns.countplot(df.sentiment)\n",
474
+ "plt.xlabel('review sentiment')\n",
475
+ "ax.set_xticklabels(class_names);"
476
+ ],
477
+ "execution_count": null,
478
+ "outputs": []
479
+ },
480
+ {
481
+ "cell_type": "code",
482
+ "source": [
483
+ "df['sentiment'] = df['sentiment'].map({'neg': 0, 'pos': 1})\n",
484
+ "\n",
485
+ "# Exibe as primeiras linhas do DataFrame após a conversão\n",
486
+ "print(\"\\nApós a conversão:\")\n",
487
+ "print(df.head())\n"
488
+ ],
489
+ "metadata": {
490
+ "id": "HGkxsgVdDlOi"
491
+ },
492
+ "execution_count": null,
493
+ "outputs": []
494
+ },
495
+ {
496
+ "cell_type": "code",
497
+ "source": [
498
+ "df"
499
+ ],
500
+ "metadata": {
501
+ "id": "SgSz7TDyEJCJ"
502
+ },
503
+ "execution_count": null,
504
+ "outputs": []
505
+ },
506
+ {
507
+ "cell_type": "markdown",
508
+ "metadata": {
509
+ "id": "2RIoVgVwFGxN"
510
+ },
511
+ "source": [
512
+ "## Data Preprocessing\n",
513
+ "\n",
514
+ "You might already know that Machine Learning models don't work with raw text. You need to convert text to numbers (of some sort). BERT requires even more attention (good one, right?). Here are the requirements:\n",
515
+ "\n",
516
+ "- Add special tokens to separate sentences and do classification\n",
517
+ "- Pass sequences of constant length (introduce padding)\n",
518
+ "- Create array of 0s (pad token) and 1s (real token) called *attention mask*\n",
519
+ "\n",
520
+ "The Transformers library provides (you've guessed it) a wide variety of Transformer models (including BERT). It works with TensorFlow and PyTorch! It also includes prebuild tokenizers that do the heavy lifting for us!\n"
521
+ ]
522
+ },
523
+ {
524
+ "cell_type": "code",
525
+ "metadata": {
526
+ "id": "sVZo_lRVFDQh"
527
+ },
528
+ "source": [
529
+ "PRE_TRAINED_MODEL_NAME = 'neuralmind/bert-base-portuguese-cased'"
530
+ ],
531
+ "execution_count": null,
532
+ "outputs": []
533
+ },
534
+ {
535
+ "cell_type": "markdown",
536
+ "metadata": {
537
+ "id": "7Qp57OGfHy4M"
538
+ },
539
+ "source": [
540
+ "https://huggingface.co/neuralmind/bert-base-portuguese-cased\n",
541
+ "\n",
542
+ "https://github.com/neuralmind-ai/portuguese-bert"
543
+ ]
544
+ },
545
+ {
546
+ "cell_type": "markdown",
547
+ "metadata": {
548
+ "id": "V-oaIAX6GQd-"
549
+ },
550
+ "source": [
551
+ "Let's load a pre-trained [BertTokenizer](https://huggingface.co/transformers/model_doc/bert.html#berttokenizer):"
552
+ ]
553
+ },
554
+ {
555
+ "cell_type": "code",
556
+ "metadata": {
557
+ "id": "_14-cLRrGGP-"
558
+ },
559
+ "source": [
560
+ "tokenizer = BertTokenizer.from_pretrained(PRE_TRAINED_MODEL_NAME)"
561
+ ],
562
+ "execution_count": null,
563
+ "outputs": []
564
+ },
565
+ {
566
+ "cell_type": "markdown",
567
+ "metadata": {
568
+ "id": "CmDWEEIFGU85"
569
+ },
570
+ "source": [
571
+ "We'll use this text to understand the tokenization process:"
572
+ ]
573
+ },
574
+ {
575
+ "cell_type": "code",
576
+ "metadata": {
577
+ "id": "GHf6ubxeGVUo"
578
+ },
579
+ "source": [
580
+ "sample_txt = 'Quem conta um conto aumenta um ponto.'"
581
+ ],
582
+ "execution_count": null,
583
+ "outputs": []
584
+ },
585
+ {
586
+ "cell_type": "markdown",
587
+ "metadata": {
588
+ "id": "ANQLQ87YGuhI"
589
+ },
590
+ "source": [
591
+ "Some basic operations can convert the text to tokens and tokens to unique integers (ids):"
592
+ ]
593
+ },
594
+ {
595
+ "cell_type": "code",
596
+ "metadata": {
597
+ "id": "Q0ZYj5BqGSRY"
598
+ },
599
+ "source": [
600
+ "tokens = tokenizer.tokenize(sample_txt)\n",
601
+ "token_ids = tokenizer.convert_tokens_to_ids(tokens)\n",
602
+ "\n",
603
+ "print(f' Sentence: {sample_txt}')\n",
604
+ "print(f' Tokens: {tokens}')\n",
605
+ "print(f'Token IDs: {token_ids}')"
606
+ ],
607
+ "execution_count": null,
608
+ "outputs": []
609
+ },
610
+ {
611
+ "cell_type": "markdown",
612
+ "metadata": {
613
+ "id": "v_D7UIRrKH9g"
614
+ },
615
+ "source": [
616
+ "### Special Tokens\n",
617
+ "\n",
618
+ "`[SEP]` - marker for ending of a sentence"
619
+ ]
620
+ },
621
+ {
622
+ "cell_type": "code",
623
+ "metadata": {
624
+ "id": "TuUvyBXFKI_0"
625
+ },
626
+ "source": [
627
+ "tokenizer.sep_token, tokenizer.sep_token_id"
628
+ ],
629
+ "execution_count": null,
630
+ "outputs": []
631
+ },
632
+ {
633
+ "cell_type": "markdown",
634
+ "metadata": {
635
+ "id": "bmidBkN1KOyu"
636
+ },
637
+ "source": [
638
+ "`[CLS]` - we must add this token to the start of each sentence, so BERT knows we're doing classification"
639
+ ]
640
+ },
641
+ {
642
+ "cell_type": "code",
643
+ "metadata": {
644
+ "id": "rJLW4_zEKKLU"
645
+ },
646
+ "source": [
647
+ "tokenizer.cls_token, tokenizer.cls_token_id"
648
+ ],
649
+ "execution_count": null,
650
+ "outputs": []
651
+ },
652
+ {
653
+ "cell_type": "markdown",
654
+ "metadata": {
655
+ "id": "rVutL1_1KS16"
656
+ },
657
+ "source": [
658
+ "There is also a special token for padding:"
659
+ ]
660
+ },
661
+ {
662
+ "cell_type": "code",
663
+ "metadata": {
664
+ "id": "E6hw82DTKTSI"
665
+ },
666
+ "source": [
667
+ "tokenizer.pad_token, tokenizer.pad_token_id"
668
+ ],
669
+ "execution_count": null,
670
+ "outputs": []
671
+ },
672
+ {
673
+ "cell_type": "markdown",
674
+ "metadata": {
675
+ "id": "B6nVbxU-KWOZ"
676
+ },
677
+ "source": [
678
+ "BERT understands tokens that were in the training set. Everything else can be encoded using the `[UNK]` (unknown) token:"
679
+ ]
680
+ },
681
+ {
682
+ "cell_type": "code",
683
+ "metadata": {
684
+ "id": "fcoGQ_i4KY5_"
685
+ },
686
+ "source": [
687
+ "tokenizer.unk_token, tokenizer.unk_token_id"
688
+ ],
689
+ "execution_count": null,
690
+ "outputs": []
691
+ },
692
+ {
693
+ "cell_type": "markdown",
694
+ "metadata": {
695
+ "id": "39XPl_0-Kdck"
696
+ },
697
+ "source": [
698
+ "All of that work can be done using the [`encode_plus()`](https://huggingface.co/transformers/main_classes/tokenizer.html#transformers.PreTrainedTokenizer.encode_plus) method:"
699
+ ]
700
+ },
701
+ {
702
+ "cell_type": "code",
703
+ "metadata": {
704
+ "id": "WuqMkd4UKQtv"
705
+ },
706
+ "source": [
707
+ "encoding = tokenizer.encode_plus(\n",
708
+ " sample_txt,\n",
709
+ " max_length=32,\n",
710
+ " add_special_tokens=True, # Add '[CLS]' and '[SEP]'\n",
711
+ " return_token_type_ids=False,\n",
712
+ " #padding='longest',\n",
713
+ " pad_to_max_length=True,\n",
714
+ " return_attention_mask=True,\n",
715
+ " return_tensors='pt', # Return PyTorch tensors\n",
716
+ ")\n",
717
+ "\n",
718
+ "encoding.keys()"
719
+ ],
720
+ "execution_count": null,
721
+ "outputs": []
722
+ },
723
+ {
724
+ "cell_type": "markdown",
725
+ "metadata": {
726
+ "id": "V64k2WIHKj_W"
727
+ },
728
+ "source": [
729
+ "The token ids are now stored in a Tensor and padded to a length of 32:"
730
+ ]
731
+ },
732
+ {
733
+ "cell_type": "code",
734
+ "metadata": {
735
+ "id": "llb6Q4JoKkVs"
736
+ },
737
+ "source": [
738
+ "print(len(encoding['input_ids'][0]))\n",
739
+ "encoding['input_ids'][0]"
740
+ ],
741
+ "execution_count": null,
742
+ "outputs": []
743
+ },
744
+ {
745
+ "cell_type": "markdown",
746
+ "metadata": {
747
+ "id": "GJ3591WBKoFh"
748
+ },
749
+ "source": [
750
+ "The attention mask has the same length:"
751
+ ]
752
+ },
753
+ {
754
+ "cell_type": "code",
755
+ "metadata": {
756
+ "id": "-YFYP7_zKoW3"
757
+ },
758
+ "source": [
759
+ "print(len(encoding['attention_mask'][0]))\n",
760
+ "encoding['attention_mask']"
761
+ ],
762
+ "execution_count": null,
763
+ "outputs": []
764
+ },
765
+ {
766
+ "cell_type": "markdown",
767
+ "metadata": {
768
+ "id": "KUJXjJVhKrmF"
769
+ },
770
+ "source": [
771
+ "We can inverse the tokenization to have a look at the special tokens:"
772
+ ]
773
+ },
774
+ {
775
+ "cell_type": "code",
776
+ "metadata": {
777
+ "id": "UPlKoS5dKsFG"
778
+ },
779
+ "source": [
780
+ "tokenizer.convert_ids_to_tokens(encoding['input_ids'][0])"
781
+ ],
782
+ "execution_count": null,
783
+ "outputs": []
784
+ },
785
+ {
786
+ "cell_type": "markdown",
787
+ "metadata": {
788
+ "id": "-w0xt3vKKwMq"
789
+ },
790
+ "source": [
791
+ "### Choosing Sequence Length\n"
792
+ ]
793
+ },
794
+ {
795
+ "cell_type": "code",
796
+ "metadata": {
797
+ "id": "36vHlDrzKxj3"
798
+ },
799
+ "source": [
800
+ "token_lens = []\n",
801
+ "\n",
802
+ "for txt in df.text_pt:\n",
803
+ " tokens = tokenizer.encode(txt, max_length=512)\n",
804
+ " token_lens.append(len(tokens))"
805
+ ],
806
+ "execution_count": null,
807
+ "outputs": []
808
+ },
809
+ {
810
+ "cell_type": "markdown",
811
+ "metadata": {
812
+ "id": "YV-5tsnXLntz"
813
+ },
814
+ "source": [
815
+ "and plot the distribution:"
816
+ ]
817
+ },
818
+ {
819
+ "cell_type": "code",
820
+ "metadata": {
821
+ "id": "K7aQTcu8Lp26"
822
+ },
823
+ "source": [
824
+ "sns.distplot(token_lens)\n",
825
+ "plt.xlim([0, 520]);\n",
826
+ "plt.xlabel('Token count');"
827
+ ],
828
+ "execution_count": null,
829
+ "outputs": []
830
+ },
831
+ {
832
+ "cell_type": "code",
833
+ "source": [
834
+ "token_lens[500]\n",
835
+ "max(token_lens)"
836
+ ],
837
+ "metadata": {
838
+ "id": "4WC0s1mLGgiU"
839
+ },
840
+ "execution_count": null,
841
+ "outputs": []
842
+ },
843
+ {
844
+ "cell_type": "markdown",
845
+ "metadata": {
846
+ "id": "djv5kONnLxb-"
847
+ },
848
+ "source": [
849
+ "Most of the reviews seem to contain less than 128 tokens, but we'll be on the safe side and choose a maximum length of 160."
850
+ ]
851
+ },
852
+ {
853
+ "cell_type": "code",
854
+ "metadata": {
855
+ "id": "UQalJqpBLrLB"
856
+ },
857
+ "source": [
858
+ "MAX_LEN = 512"
859
+ ],
860
+ "execution_count": null,
861
+ "outputs": []
862
+ },
863
+ {
864
+ "cell_type": "markdown",
865
+ "metadata": {
866
+ "id": "dKDyNuXWL5KX"
867
+ },
868
+ "source": [
869
+ "We have all building blocks required to create a PyTorch dataset. Let's do it:"
870
+ ]
871
+ },
872
+ {
873
+ "cell_type": "code",
874
+ "metadata": {
875
+ "id": "DxQSt1sZL5kp"
876
+ },
877
+ "source": [
878
+ "class IMDBDataset(Dataset):\n",
879
+ "\n",
880
+ " def __init__(self, texts, labels, tokenizer, max_len):\n",
881
+ " self.texts = texts\n",
882
+ " self.labels = labels\n",
883
+ " self.tokenizer = tokenizer\n",
884
+ " self.max_len = max_len\n",
885
+ "\n",
886
+ " def __len__(self):\n",
887
+ " return len(self.texts)\n",
888
+ "\n",
889
+ " def __getitem__(self, item):\n",
890
+ " text = str(self.texts[item])\n",
891
+ " label = self.labels[item]\n",
892
+ "\n",
893
+ " encoding = self.tokenizer.encode_plus(\n",
894
+ " text,\n",
895
+ " add_special_tokens=True,\n",
896
+ " max_length=self.max_len,\n",
897
+ " return_token_type_ids=False,\n",
898
+ " #padding='longest',\n",
899
+ " pad_to_max_length=True,\n",
900
+ " return_attention_mask=True,\n",
901
+ " return_tensors='pt',\n",
902
+ " )\n",
903
+ "\n",
904
+ " return {\n",
905
+ " 'text': text,\n",
906
+ " 'input_ids': encoding['input_ids'].flatten(),\n",
907
+ " 'attention_mask': encoding['attention_mask'].flatten(),\n",
908
+ " 'labels': torch.tensor(label, dtype=torch.long)\n",
909
+ " }"
910
+ ],
911
+ "execution_count": null,
912
+ "outputs": []
913
+ },
914
+ {
915
+ "cell_type": "markdown",
916
+ "metadata": {
917
+ "id": "2_w5mFC9L-i6"
918
+ },
919
+ "source": [
920
+ "The tokenizer is doing most of the heavy lifting for us. We also return the review texts, so it'll be easier to evaluate the predictions from our model. Let's split the data:"
921
+ ]
922
+ },
923
+ {
924
+ "cell_type": "code",
925
+ "metadata": {
926
+ "id": "aLqEExhdL-_p"
927
+ },
928
+ "source": [
929
+ "df_train, df_test = train_test_split(df, test_size=0.1, random_state=RANDOM_SEED)\n",
930
+ "df_val, df_test = train_test_split(df_test, test_size=0.5, random_state=RANDOM_SEED)"
931
+ ],
932
+ "execution_count": null,
933
+ "outputs": []
934
+ },
935
+ {
936
+ "cell_type": "code",
937
+ "metadata": {
938
+ "id": "tGSB9J8tMBIC"
939
+ },
940
+ "source": [
941
+ "df_train.shape, df_val.shape, df_test.shape"
942
+ ],
943
+ "execution_count": null,
944
+ "outputs": []
945
+ },
946
+ {
947
+ "cell_type": "markdown",
948
+ "metadata": {
949
+ "id": "Tid8js2AMEzJ"
950
+ },
951
+ "source": [
952
+ "We also need to create a couple of data loaders. Here's a helper function to do it:"
953
+ ]
954
+ },
955
+ {
956
+ "cell_type": "code",
957
+ "metadata": {
958
+ "id": "ys08dkFnMFOx"
959
+ },
960
+ "source": [
961
+ "def create_data_loader(df, tokenizer, max_len, batch_size):\n",
962
+ " ds = IMDBDataset(\n",
963
+ " texts=df.text_pt.to_numpy(),\n",
964
+ " labels=df.sentiment.to_numpy(),\n",
965
+ " tokenizer=tokenizer,\n",
966
+ " max_len=max_len\n",
967
+ " )\n",
968
+ "\n",
969
+ " return DataLoader(\n",
970
+ " ds,\n",
971
+ " batch_size=batch_size,\n",
972
+ " num_workers=4\n",
973
+ " )"
974
+ ],
975
+ "execution_count": null,
976
+ "outputs": []
977
+ },
978
+ {
979
+ "cell_type": "code",
980
+ "metadata": {
981
+ "id": "9ht8GyZnMGqi"
982
+ },
983
+ "source": [
984
+ "BATCH_SIZE = 32\n",
985
+ "\n",
986
+ "train_data_loader = create_data_loader(df_train, tokenizer, MAX_LEN, BATCH_SIZE)\n",
987
+ "val_data_loader = create_data_loader(df_val, tokenizer, MAX_LEN, BATCH_SIZE)\n",
988
+ "test_data_loader = create_data_loader(df_test, tokenizer, MAX_LEN, BATCH_SIZE)"
989
+ ],
990
+ "execution_count": null,
991
+ "outputs": []
992
+ },
993
+ {
994
+ "cell_type": "markdown",
995
+ "metadata": {
996
+ "id": "ZTB7u2Y5MOAY"
997
+ },
998
+ "source": [
999
+ "Let's have a look at an example batch from our training data loader:\n",
1000
+ "\n",
1001
+ "\n"
1002
+ ]
1003
+ },
1004
+ {
1005
+ "cell_type": "code",
1006
+ "metadata": {
1007
+ "id": "6KxMc6MleUDu"
1008
+ },
1009
+ "source": [
1010
+ "len(train_data_loader)"
1011
+ ],
1012
+ "execution_count": null,
1013
+ "outputs": []
1014
+ },
1015
+ {
1016
+ "cell_type": "code",
1017
+ "metadata": {
1018
+ "id": "fK1LVloAMJr1"
1019
+ },
1020
+ "source": [
1021
+ "data = next(iter(train_data_loader))\n",
1022
+ "data.keys()"
1023
+ ],
1024
+ "execution_count": null,
1025
+ "outputs": []
1026
+ },
1027
+ {
1028
+ "cell_type": "code",
1029
+ "metadata": {
1030
+ "id": "tkeqE-FWMPiZ"
1031
+ },
1032
+ "source": [
1033
+ "print(data['input_ids'].shape)\n",
1034
+ "print(data['attention_mask'].shape)\n",
1035
+ "print(data['labels'].shape)"
1036
+ ],
1037
+ "execution_count": null,
1038
+ "outputs": []
1039
+ },
1040
+ {
1041
+ "cell_type": "markdown",
1042
+ "metadata": {
1043
+ "id": "4OhEv9k9Mca6"
1044
+ },
1045
+ "source": [
1046
+ "## Sentiment Classification with BERT and Hugging Face"
1047
+ ]
1048
+ },
1049
+ {
1050
+ "cell_type": "markdown",
1051
+ "metadata": {
1052
+ "id": "J8yGbr4vMhYv"
1053
+ },
1054
+ "source": [
1055
+ "There are a lot of helpers that make using BERT easy with the Transformers library. Depending on the task you might want to use [BertForSequenceClassification](https://huggingface.co/transformers/model_doc/bert.html#bertforsequenceclassification), [BertForQuestionAnswering](https://huggingface.co/transformers/model_doc/bert.html#bertforquestionanswering) or something else.\n",
1056
+ "\n",
1057
+ "But who cares, right? We're *hardcore*! We'll use the basic [BertModel](https://huggingface.co/transformers/model_doc/bert.html#bertmodel) and build our sentiment classifier on top of it. Let's load the model:"
1058
+ ]
1059
+ },
1060
+ {
1061
+ "cell_type": "code",
1062
+ "metadata": {
1063
+ "id": "B_Zv3uXgMh9l"
1064
+ },
1065
+ "source": [
1066
+ "bert_model = BertModel.from_pretrained(PRE_TRAINED_MODEL_NAME)"
1067
+ ],
1068
+ "execution_count": null,
1069
+ "outputs": []
1070
+ },
1071
+ {
1072
+ "cell_type": "markdown",
1073
+ "metadata": {
1074
+ "id": "-wc2P7aiMpGC"
1075
+ },
1076
+ "source": [
1077
+ "And try to use it on the encoding of our sample text:"
1078
+ ]
1079
+ },
1080
+ {
1081
+ "cell_type": "code",
1082
+ "metadata": {
1083
+ "id": "tsPxPiG5Mptq"
1084
+ },
1085
+ "source": [
1086
+ "last_hidden_state, pooled_output = bert_model(\n",
1087
+ " input_ids=encoding['input_ids'],\n",
1088
+ " attention_mask=encoding['attention_mask']\n",
1089
+ ")"
1090
+ ],
1091
+ "execution_count": null,
1092
+ "outputs": []
1093
+ },
1094
+ {
1095
+ "cell_type": "markdown",
1096
+ "metadata": {
1097
+ "id": "Z9TpeUr8Ms7b"
1098
+ },
1099
+ "source": [
1100
+ "The `last_hidden_state` is a sequence of hidden states of the last layer of the model. Obtaining the `pooled_output` is done by applying the [BertPooler](https://github.com/huggingface/transformers/blob/edf0582c0be87b60f94f41c659ea779876efc7be/src/transformers/modeling_bert.py#L426) on `last_hidden_state`."
1101
+ ]
1102
+ },
1103
+ {
1104
+ "cell_type": "markdown",
1105
+ "metadata": {
1106
+ "id": "I2tokVklN3OS"
1107
+ },
1108
+ "source": [
1109
+ "You can think of the `pooled_output` as a summary of the content, according to BERT. Albeit, you might try and do better. Let's look at the shape of the output."
1110
+ ]
1111
+ },
1112
+ {
1113
+ "cell_type": "code",
1114
+ "metadata": {
1115
+ "id": "Su91OfW7MtaK"
1116
+ },
1117
+ "source": [
1118
+ "bert_model.config.hidden_size"
1119
+ ],
1120
+ "execution_count": null,
1121
+ "outputs": []
1122
+ },
1123
+ {
1124
+ "cell_type": "markdown",
1125
+ "metadata": {
1126
+ "id": "sadx51ayOJSx"
1127
+ },
1128
+ "source": [
1129
+ "We can use all of this knowledge to create a classifier that uses the BERT model:"
1130
+ ]
1131
+ },
1132
+ {
1133
+ "cell_type": "code",
1134
+ "metadata": {
1135
+ "id": "lM-0eiqhNUbN"
1136
+ },
1137
+ "source": [
1138
+ "class SentimentClassifier(nn.Module):\n",
1139
+ "\n",
1140
+ " def __init__(self, n_classes):\n",
1141
+ " super(SentimentClassifier, self).__init__()\n",
1142
+ " self.bert = BertModel.from_pretrained(PRE_TRAINED_MODEL_NAME, return_dict=False)\n",
1143
+ " self.drop = nn.Dropout(p=0.3)\n",
1144
+ " #The last_hidden_state is a sequence of hidden states of the last layer of the model\n",
1145
+ " self.out = nn.Linear(self.bert.config.hidden_size, n_classes)\n",
1146
+ "\n",
1147
+ " def forward(self, input_ids, attention_mask):\n",
1148
+ " _, pooled_output = self.bert(\n",
1149
+ " input_ids=input_ids,\n",
1150
+ " attention_mask=attention_mask\n",
1151
+ " )\n",
1152
+ " output = self.drop(pooled_output)\n",
1153
+ " return self.out(output)"
1154
+ ],
1155
+ "execution_count": null,
1156
+ "outputs": []
1157
+ },
1158
+ {
1159
+ "cell_type": "markdown",
1160
+ "metadata": {
1161
+ "id": "oWHPz4z6OMU9"
1162
+ },
1163
+ "source": [
1164
+ "Our classifier delegates most of the heavy lifting to the BertModel. We use a dropout layer for some regularization and a fully-connected layer for our output. Note that we're returning the raw output of the last layer since that is required for the cross-entropy loss function in PyTorch to work.\n",
1165
+ "\n",
1166
+ "This should work like any other PyTorch model. Let's create an instance and move it to the GPU:"
1167
+ ]
1168
+ },
1169
+ {
1170
+ "cell_type": "code",
1171
+ "metadata": {
1172
+ "id": "9Z4pMOzZOMuv"
1173
+ },
1174
+ "source": [
1175
+ "model = SentimentClassifier(len(class_names))\n",
1176
+ "model = model.to(device)"
1177
+ ],
1178
+ "execution_count": null,
1179
+ "outputs": []
1180
+ },
1181
+ {
1182
+ "cell_type": "code",
1183
+ "source": [
1184
+ "len(class_names)"
1185
+ ],
1186
+ "metadata": {
1187
+ "id": "lvADEz3lIjbP"
1188
+ },
1189
+ "execution_count": null,
1190
+ "outputs": []
1191
+ },
1192
+ {
1193
+ "cell_type": "markdown",
1194
+ "metadata": {
1195
+ "id": "OqsR6aKCOT5o"
1196
+ },
1197
+ "source": [
1198
+ "We'll move the example batch of our training data to the GPU:"
1199
+ ]
1200
+ },
1201
+ {
1202
+ "cell_type": "code",
1203
+ "metadata": {
1204
+ "id": "OdKyQQKhOUZ7"
1205
+ },
1206
+ "source": [
1207
+ "input_ids = data['input_ids'].to(device)\n",
1208
+ "attention_mask = data['attention_mask'].to(device)\n",
1209
+ "\n",
1210
+ "print(input_ids.shape) # batch size x seq length\n",
1211
+ "print(attention_mask.shape) # batch size x seq length"
1212
+ ],
1213
+ "execution_count": null,
1214
+ "outputs": []
1215
+ },
1216
+ {
1217
+ "cell_type": "markdown",
1218
+ "metadata": {
1219
+ "id": "Ux4i9Nr1OYWT"
1220
+ },
1221
+ "source": [
1222
+ "To get the predicted probabilities from our trained model, we'll apply the softmax function to the outputs:"
1223
+ ]
1224
+ },
1225
+ {
1226
+ "cell_type": "markdown",
1227
+ "metadata": {
1228
+ "id": "7Q8gFB-7dsYU"
1229
+ },
1230
+ "source": [
1231
+ "### Training\n",
1232
+ "\n",
1233
+ "To reproduce the training procedure from the BERT paper, we'll use the [AdamW](https://huggingface.co/transformers/main_classes/optimizer_schedules.html#adamw) optimizer provided by Hugging Face. It corrects weight decay, so it's similar to the original paper. We'll also use a linear scheduler with no warmup steps:"
1234
+ ]
1235
+ },
1236
+ {
1237
+ "cell_type": "code",
1238
+ "metadata": {
1239
+ "id": "7X1BJqEXEjB-"
1240
+ },
1241
+ "source": [
1242
+ "EPOCHS = 4\n",
1243
+ "\n",
1244
+ "optimizer = AdamW(model.parameters(), lr=2e-5, correct_bias=False)\n",
1245
+ "total_steps = len(train_data_loader) * EPOCHS\n",
1246
+ "\n",
1247
+ "scheduler = get_linear_schedule_with_warmup(\n",
1248
+ " optimizer,\n",
1249
+ " num_warmup_steps=0,\n",
1250
+ " num_training_steps=total_steps\n",
1251
+ ")\n",
1252
+ "\n",
1253
+ "loss_fn = nn.CrossEntropyLoss().to(device)"
1254
+ ],
1255
+ "execution_count": null,
1256
+ "outputs": []
1257
+ },
1258
+ {
1259
+ "cell_type": "markdown",
1260
+ "metadata": {
1261
+ "id": "GJu9X-TEd2-t"
1262
+ },
1263
+ "source": [
1264
+ "How do we come up with all hyperparameters? The BERT authors have some recommendations for fine-tuning:\n",
1265
+ "\n",
1266
+ "- Batch size: 16, 32\n",
1267
+ "- Learning rate (Adam): 5e-5, 3e-5, 2e-5\n",
1268
+ "- Number of epochs: 2, 3, 4\n",
1269
+ "\n",
1270
+ "\n",
1271
+ "Let's continue with writing a helper function for training our model for one epoch:"
1272
+ ]
1273
+ },
1274
+ {
1275
+ "cell_type": "code",
1276
+ "metadata": {
1277
+ "id": "tvGtIud7d1O0"
1278
+ },
1279
+ "source": [
1280
+ "def train_epoch(\n",
1281
+ " model,\n",
1282
+ " data_loader,\n",
1283
+ " loss_fn,\n",
1284
+ " optimizer,\n",
1285
+ " device,\n",
1286
+ " scheduler,\n",
1287
+ " n_examples\n",
1288
+ "):\n",
1289
+ " model = model.train()\n",
1290
+ "\n",
1291
+ " losses = []\n",
1292
+ " correct_predictions = 0\n",
1293
+ "\n",
1294
+ " for d in data_loader:\n",
1295
+ " input_ids = d[\"input_ids\"].to(device)\n",
1296
+ " attention_mask = d[\"attention_mask\"].to(device)\n",
1297
+ " labels = d[\"labels\"].to(device)\n",
1298
+ "\n",
1299
+ " outputs = model(\n",
1300
+ " input_ids=input_ids,\n",
1301
+ " attention_mask=attention_mask\n",
1302
+ " )\n",
1303
+ "\n",
1304
+ " _, preds = torch.max(outputs, dim=1)\n",
1305
+ " loss = loss_fn(outputs, labels)\n",
1306
+ "\n",
1307
+ " correct_predictions += torch.sum(preds == labels)\n",
1308
+ " losses.append(loss.item())\n",
1309
+ "\n",
1310
+ " loss.backward()\n",
1311
+ " nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)\n",
1312
+ " optimizer.step()\n",
1313
+ " scheduler.step()\n",
1314
+ " optimizer.zero_grad()\n",
1315
+ "\n",
1316
+ " return correct_predictions.double() / n_examples, np.mean(losses)"
1317
+ ],
1318
+ "execution_count": null,
1319
+ "outputs": []
1320
+ },
1321
+ {
1322
+ "cell_type": "markdown",
1323
+ "metadata": {
1324
+ "id": "JJQJjc1Hd6Zt"
1325
+ },
1326
+ "source": [
1327
+ "Training the model should look familiar, except for two things. The scheduler gets called every time a batch is fed to the model. We're avoiding exploding gradients by clipping the gradients of the model using [clip_grad_norm_](https://pytorch.org/docs/stable/nn.html#clip-grad-norm).\n",
1328
+ "\n",
1329
+ "Let's write another one that helps us evaluate the model on a given data loader:"
1330
+ ]
1331
+ },
1332
+ {
1333
+ "cell_type": "code",
1334
+ "metadata": {
1335
+ "id": "Xkg8XyzZd5to"
1336
+ },
1337
+ "source": [
1338
+ "def eval_model(model, data_loader, loss_fn, device, n_examples):\n",
1339
+ " model = model.eval()\n",
1340
+ "\n",
1341
+ " losses = []\n",
1342
+ " correct_predictions = 0\n",
1343
+ "\n",
1344
+ " with torch.no_grad():\n",
1345
+ " for d in data_loader:\n",
1346
+ " input_ids = d[\"input_ids\"].to(device)\n",
1347
+ " attention_mask = d[\"attention_mask\"].to(device)\n",
1348
+ " labels = d[\"labels\"].to(device)\n",
1349
+ "\n",
1350
+ " outputs = model(\n",
1351
+ " input_ids=input_ids,\n",
1352
+ " attention_mask=attention_mask\n",
1353
+ " )\n",
1354
+ " _, preds = torch.max(outputs, dim=1)\n",
1355
+ "\n",
1356
+ " loss = loss_fn(outputs, labels)\n",
1357
+ "\n",
1358
+ " correct_predictions += torch.sum(preds == labels)\n",
1359
+ " losses.append(loss.item())\n",
1360
+ "\n",
1361
+ " return correct_predictions.double() / n_examples, np.mean(losses)"
1362
+ ],
1363
+ "execution_count": null,
1364
+ "outputs": []
1365
+ },
1366
+ {
1367
+ "cell_type": "code",
1368
+ "source": [
1369
+ "from huggingface_hub import HfApi\n",
1370
+ "api = HfApi()\n",
1371
+ "api.create_repo(repo_id=repo_id, exist_ok=True)"
1372
+ ],
1373
+ "metadata": {
1374
+ "id": "AfCElgQYekkH"
1375
+ },
1376
+ "execution_count": null,
1377
+ "outputs": []
1378
+ },
1379
+ {
1380
+ "cell_type": "code",
1381
+ "source": [
1382
+ "from huggingface_hub import Repository\n",
1383
+ "repo = Repository(local_dir=\"best_model\", clone_from=repo_id)"
1384
+ ],
1385
+ "metadata": {
1386
+ "id": "iE7vC_74iy64"
1387
+ },
1388
+ "execution_count": null,
1389
+ "outputs": []
1390
+ },
1391
+ {
1392
+ "cell_type": "markdown",
1393
+ "metadata": {
1394
+ "id": "dKtLIg1Qd-gC"
1395
+ },
1396
+ "source": [
1397
+ "Using those two, we can write our training loop. We'll also store the training history:"
1398
+ ]
1399
+ },
1400
+ {
1401
+ "cell_type": "code",
1402
+ "metadata": {
1403
+ "id": "FD7hwSShd-HU"
1404
+ },
1405
+ "source": [
1406
+ "%%time\n",
1407
+ "\n",
1408
+ "history = defaultdict(list)\n",
1409
+ "best_accuracy = 0\n",
1410
+ "\n",
1411
+ "for epoch in range(EPOCHS):\n",
1412
+ "\n",
1413
+ " print(f'Epoch {epoch + 1}/{EPOCHS}')\n",
1414
+ " print('-' * 4)\n",
1415
+ "\n",
1416
+ " train_acc, train_loss = train_epoch(\n",
1417
+ " model,\n",
1418
+ " train_data_loader,\n",
1419
+ " loss_fn,\n",
1420
+ " optimizer,\n",
1421
+ " device,\n",
1422
+ " scheduler,\n",
1423
+ " len(df_train)\n",
1424
+ " )\n",
1425
+ "\n",
1426
+ " print(f'Train loss {train_loss} accuracy {train_acc}')\n",
1427
+ "\n",
1428
+ " val_acc, val_loss = eval_model(\n",
1429
+ " model,\n",
1430
+ " val_data_loader,\n",
1431
+ " loss_fn,\n",
1432
+ " device,\n",
1433
+ " len(df_val)\n",
1434
+ " )\n",
1435
+ "\n",
1436
+ " print(f'Val loss {val_loss} accuracy {val_acc}')\n",
1437
+ " print()\n",
1438
+ "\n",
1439
+ " history['train_acc'].append(train_acc)\n",
1440
+ " history['train_loss'].append(train_loss)\n",
1441
+ " history['val_acc'].append(val_acc)\n",
1442
+ " history['val_loss'].append(val_loss)\n",
1443
+ "\n",
1444
+ "\n",
1445
+ " if val_acc > best_accuracy:\n",
1446
+ " print(\"Melhor modelo encontrado, a guardar e a fazer push para o Hub...\")\n",
1447
+ "\n",
1448
+ " model.save_pretrained('best_model')\n",
1449
+ " tokenizer.save_pretrained('best_model')\n",
1450
+ "\n",
1451
+ "\n",
1452
+ " repo.push_to_hub(commit_message=f\"epoch {epoch + 1} - val_acc {val_acc:.4f}\")\n",
1453
+ "\n",
1454
+ " best_accuracy = val_acc\n",
1455
+ "\n",
1456
+ "\n",
1457
+ "repo.push_to_hub()"
1458
+ ],
1459
+ "execution_count": null,
1460
+ "outputs": []
1461
+ },
1462
+ {
1463
+ "cell_type": "markdown",
1464
+ "metadata": {
1465
+ "id": "5TPmJAz9TKlv"
1466
+ },
1467
+ "source": [
1468
+ "Note that we're storing the state of the best model, indicated by the highest validation accuracy.\n",
1469
+ "\n",
1470
+ "Whoo, this took some time! We can look at the training vs validation accuracy:"
1471
+ ]
1472
+ },
1473
+ {
1474
+ "cell_type": "code",
1475
+ "metadata": {
1476
+ "id": "anE8h-syhBiB"
1477
+ },
1478
+ "source": [
1479
+ "plt.plot(history['train_acc'], label='train accuracy')\n",
1480
+ "plt.plot(history['val_acc'], label='validation accuracy')\n",
1481
+ "\n",
1482
+ "plt.title('Training history')\n",
1483
+ "plt.ylabel('Accuracy')\n",
1484
+ "plt.xlabel('Epoch')\n",
1485
+ "plt.legend()\n",
1486
+ "plt.ylim([0, 1]);"
1487
+ ],
1488
+ "execution_count": null,
1489
+ "outputs": []
1490
+ },
1491
+ {
1492
+ "cell_type": "markdown",
1493
+ "metadata": {
1494
+ "id": "CusxQuuFTPwj"
1495
+ },
1496
+ "source": [
1497
+ "The training accuracy starts to approach 100% after 10 epochs or so. You might try to fine-tune the parameters a bit more, but this will be good enough for us.\n",
1498
+ "\n",
1499
+ "Don't want to wait? Uncomment the next cell to download my pre-trained model:"
1500
+ ]
1501
+ },
1502
+ {
1503
+ "cell_type": "code",
1504
+ "metadata": {
1505
+ "id": "NdKQjFZaTMj7"
1506
+ },
1507
+ "source": [
1508
+ "# !gdown --id 1-2Lnf3e1wN25WwhX35tMOqQM_8Ds-2Ey #==> PUT MY ID 1-2Lnf3e1wN25WwhX35tMOqQM_8Ds-2Ey/\n",
1509
+ "\n",
1510
+ "# model = SentimentClassifier(len(class_names))\n",
1511
+ "# model.load_state_dict(torch.load('best_model_state.bin'))\n",
1512
+ "# model = model.to(device)"
1513
+ ],
1514
+ "execution_count": null,
1515
+ "outputs": []
1516
+ },
1517
+ {
1518
+ "cell_type": "markdown",
1519
+ "metadata": {
1520
+ "id": "Ie-jdgYtTVMl"
1521
+ },
1522
+ "source": [
1523
+ "### Evaluation\n",
1524
+ "\n",
1525
+ "So how good is our model on predicting sentiment? Let's start by calculating the accuracy on the test data:"
1526
+ ]
1527
+ },
1528
+ {
1529
+ "cell_type": "code",
1530
+ "metadata": {
1531
+ "id": "VZko6upATa7I"
1532
+ },
1533
+ "source": [
1534
+ "test_acc, _ = eval_model(\n",
1535
+ " model,\n",
1536
+ " test_data_loader,\n",
1537
+ " loss_fn,\n",
1538
+ " device,\n",
1539
+ " len(df_test)\n",
1540
+ ")\n",
1541
+ "\n",
1542
+ "test_acc.item()"
1543
+ ],
1544
+ "execution_count": null,
1545
+ "outputs": []
1546
+ },
1547
+ {
1548
+ "cell_type": "markdown",
1549
+ "metadata": {
1550
+ "id": "viRJUSeOTneC"
1551
+ },
1552
+ "source": [
1553
+ "The accuracy is about 1% lower on the test set. Our model seems to generalize well.\n",
1554
+ "\n",
1555
+ "We'll define a helper function to get the predictions from our model:"
1556
+ ]
1557
+ },
1558
+ {
1559
+ "cell_type": "code",
1560
+ "metadata": {
1561
+ "id": "eWVt9c9yTbY2"
1562
+ },
1563
+ "source": [
1564
+ "\n",
1565
+ "def get_predictions(model, data_loader):\n",
1566
+ " model = model.eval()\n",
1567
+ "\n",
1568
+ " texts_pt = []\n",
1569
+ " predictions = []\n",
1570
+ " prediction_probs = []\n",
1571
+ " real_values = []\n",
1572
+ "\n",
1573
+ " with torch.no_grad():\n",
1574
+ " for d in data_loader:\n",
1575
+ "\n",
1576
+ " texts = d[\"text\"]\n",
1577
+ " input_ids = d[\"input_ids\"].to(device)\n",
1578
+ " attention_mask = d[\"attention_mask\"].to(device)\n",
1579
+ " labels = d[\"labels\"].to(device)\n",
1580
+ "\n",
1581
+ " outputs = model(\n",
1582
+ " input_ids=input_ids,\n",
1583
+ " attention_mask=attention_mask\n",
1584
+ " )\n",
1585
+ " _, preds = torch.max(outputs, dim=1)\n",
1586
+ "\n",
1587
+ " probs = F.softmax(outputs, dim=1)\n",
1588
+ "\n",
1589
+ " texts_pt.extend(texts)\n",
1590
+ " predictions.extend(preds)\n",
1591
+ " prediction_probs.extend(probs)\n",
1592
+ " real_values.extend(labels)\n",
1593
+ "\n",
1594
+ " predictions = torch.stack(predictions).cpu()\n",
1595
+ " prediction_probs = torch.stack(prediction_probs).cpu()\n",
1596
+ " real_values = torch.stack(real_values).cpu()\n",
1597
+ " return texts_pt, predictions, prediction_probs, real_values"
1598
+ ],
1599
+ "execution_count": null,
1600
+ "outputs": []
1601
+ },
1602
+ {
1603
+ "cell_type": "markdown",
1604
+ "metadata": {
1605
+ "id": "bE7DFsi1T4pk"
1606
+ },
1607
+ "source": [
1608
+ "This is similar to the evaluation function, except that we're storing the text of the reviews and the predicted probabilities (by applying the softmax on the model outputs):"
1609
+ ]
1610
+ },
1611
+ {
1612
+ "cell_type": "code",
1613
+ "metadata": {
1614
+ "id": "wqDtEAAET2qD"
1615
+ },
1616
+ "source": [
1617
+ "y_text_pt, y_pred, y_pred_probs, y_test = get_predictions(\n",
1618
+ " model,\n",
1619
+ " test_data_loader\n",
1620
+ ")"
1621
+ ],
1622
+ "execution_count": null,
1623
+ "outputs": []
1624
+ },
1625
+ {
1626
+ "cell_type": "markdown",
1627
+ "metadata": {
1628
+ "id": "D3fNSJqdT8oT"
1629
+ },
1630
+ "source": [
1631
+ "Let's have a look at the classification report\n",
1632
+ "\n"
1633
+ ]
1634
+ },
1635
+ {
1636
+ "cell_type": "code",
1637
+ "metadata": {
1638
+ "id": "4nx51SfMT69t"
1639
+ },
1640
+ "source": [
1641
+ "print(classification_report(y_test, y_pred, target_names=class_names))"
1642
+ ],
1643
+ "execution_count": null,
1644
+ "outputs": []
1645
+ },
1646
+ {
1647
+ "cell_type": "code",
1648
+ "metadata": {
1649
+ "id": "LISbHZAIT-it"
1650
+ },
1651
+ "source": [
1652
+ "def show_confusion_matrix(confusion_matrix):\n",
1653
+ " hmap = sns.heatmap(confusion_matrix, annot=True, fmt=\"d\", cmap=\"Blues\")\n",
1654
+ " hmap.yaxis.set_ticklabels(hmap.yaxis.get_ticklabels(), rotation=0, ha='right')\n",
1655
+ " hmap.xaxis.set_ticklabels(hmap.xaxis.get_ticklabels(), rotation=30, ha='right')\n",
1656
+ " plt.ylabel('True sentiment')\n",
1657
+ " plt.xlabel('Predicted sentiment');\n",
1658
+ "\n",
1659
+ "cm = confusion_matrix(y_test, y_pred)\n",
1660
+ "df_cm = pd.DataFrame(cm, index=class_names, columns=class_names)\n",
1661
+ "show_confusion_matrix(df_cm)"
1662
+ ],
1663
+ "execution_count": null,
1664
+ "outputs": []
1665
+ },
1666
+ {
1667
+ "cell_type": "markdown",
1668
+ "metadata": {
1669
+ "id": "SGrauBCKUNs4"
1670
+ },
1671
+ "source": [
1672
+ "\n",
1673
+ "This confirms that our model is having difficulty classifying neutral reviews. It mistakes those for negative and positive at a roughly equal frequency.\n",
1674
+ "\n",
1675
+ "That's a good overview of the performance of our model. But let's have a look at an example from our test data:"
1676
+ ]
1677
+ },
1678
+ {
1679
+ "cell_type": "code",
1680
+ "metadata": {
1681
+ "id": "ryOEAWnCUDes"
1682
+ },
1683
+ "source": [
1684
+ "idx = 10\n",
1685
+ "\n",
1686
+ "texts = y_text_pt[idx]\n",
1687
+ "true_sentiment = y_test[idx]\n",
1688
+ "pred_df = pd.DataFrame({\n",
1689
+ " 'class_names': class_names,\n",
1690
+ " 'values': y_pred_probs[idx]\n",
1691
+ "})"
1692
+ ],
1693
+ "execution_count": null,
1694
+ "outputs": []
1695
+ },
1696
+ {
1697
+ "cell_type": "code",
1698
+ "metadata": {
1699
+ "id": "NfUZerrFUQgF"
1700
+ },
1701
+ "source": [
1702
+ "print(\"\\n\".join(wrap(texts)))\n",
1703
+ "print()\n",
1704
+ "print(f'True sentiment: {class_names[true_sentiment]}')"
1705
+ ],
1706
+ "execution_count": null,
1707
+ "outputs": []
1708
+ },
1709
+ {
1710
+ "cell_type": "markdown",
1711
+ "metadata": {
1712
+ "id": "__zvq7oAUoTq"
1713
+ },
1714
+ "source": [
1715
+ "Now we can look at the confidence of each sentiment of our model:\n",
1716
+ "\n"
1717
+ ]
1718
+ },
1719
+ {
1720
+ "cell_type": "code",
1721
+ "metadata": {
1722
+ "id": "yI2foZLwUa-D"
1723
+ },
1724
+ "source": [
1725
+ "sns.barplot(x='values', y='class_names', data=pred_df, orient='h')\n",
1726
+ "plt.ylabel('sentiment')\n",
1727
+ "plt.xlabel('probability')\n",
1728
+ "plt.xlim([0, 1]);"
1729
+ ],
1730
+ "execution_count": null,
1731
+ "outputs": []
1732
+ },
1733
+ {
1734
+ "cell_type": "markdown",
1735
+ "metadata": {
1736
+ "id": "VKKFcZWGUtPT"
1737
+ },
1738
+ "source": [
1739
+ "### Predicting on Raw Text\n",
1740
+ "\n",
1741
+ "Let's use our model to predict the sentiment of some raw text:"
1742
+ ]
1743
+ },
1744
+ {
1745
+ "cell_type": "markdown",
1746
+ "metadata": {
1747
+ "id": "Y_uMQh4iU7oz"
1748
+ },
1749
+ "source": [
1750
+ "We have to use the tokenizer to encode the text:\n",
1751
+ "\n"
1752
+ ]
1753
+ },
1754
+ {
1755
+ "cell_type": "code",
1756
+ "metadata": {
1757
+ "id": "qBhmfageU0KH"
1758
+ },
1759
+ "source": [
1760
+ "sample_text = \"Eu não sei\""
1761
+ ],
1762
+ "execution_count": null,
1763
+ "outputs": []
1764
+ },
1765
+ {
1766
+ "cell_type": "code",
1767
+ "metadata": {
1768
+ "id": "IhBP47RrU7Fo"
1769
+ },
1770
+ "source": [
1771
+ "encoded_text = tokenizer.encode_plus(\n",
1772
+ " sample_text,\n",
1773
+ " max_length=MAX_LEN,\n",
1774
+ " add_special_tokens=True,\n",
1775
+ " return_token_type_ids=False,\n",
1776
+ " pad_to_max_length=True,\n",
1777
+ " return_attention_mask=True,\n",
1778
+ " return_tensors='pt',\n",
1779
+ ")"
1780
+ ],
1781
+ "execution_count": null,
1782
+ "outputs": []
1783
+ },
1784
+ {
1785
+ "cell_type": "markdown",
1786
+ "metadata": {
1787
+ "id": "78iajgyHU_np"
1788
+ },
1789
+ "source": [
1790
+ "Let's get the predictions from our model:\n",
1791
+ "\n"
1792
+ ]
1793
+ },
1794
+ {
1795
+ "cell_type": "code",
1796
+ "metadata": {
1797
+ "id": "l7yUhQJoU9yb"
1798
+ },
1799
+ "source": [
1800
+ "input_ids = encoded_text['input_ids'].to(device)\n",
1801
+ "attention_mask = encoded_text['attention_mask'].to(device)\n",
1802
+ "\n",
1803
+ "output = model(input_ids, attention_mask)\n",
1804
+ "_, prediction = torch.max(output, dim=1)\n",
1805
+ "\n",
1806
+ "print(f'Text: {sample_text}')\n",
1807
+ "print(f'Sentiment : {class_names[prediction]}')"
1808
+ ],
1809
+ "execution_count": null,
1810
+ "outputs": []
1811
+ }
1812
+ ],
1813
+ "metadata": {
1814
+ "accelerator": "GPU",
1815
+ "colab": {
1816
+ "gpuType": "T4",
1817
+ "provenance": []
1818
+ },
1819
+ "kernelspec": {
1820
+ "display_name": "Python 3",
1821
+ "name": "python3"
1822
+ },
1823
+ "language_info": {
1824
+ "name": "python"
1825
+ }
1826
+ },
1827
+ "nbformat": 4,
1828
+ "nbformat_minor": 0
1829
+ }