camilaaeromoca commited on
Commit
6b7264a
·
verified ·
1 Parent(s): 2e6b3d0

Upload Mini-Projeto3-Modelagem.ipynb

Browse files
Files changed (1) hide show
  1. Mini-Projeto3-Modelagem.ipynb +988 -0
Mini-Projeto3-Modelagem.ipynb ADDED
@@ -0,0 +1,988 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# <font color='blue'>Data Science Academy</font>\n",
8
+ "# <font color='blue'>Deep Learning Para Aplicações de IA com PyTorch e Lightning</font>\n",
9
+ "\n",
10
+ "## <font color='blue'>Mini-Projeto 3 - Modelagem</font>\n",
11
+ "## <font color='blue'>Fine-Tuning de Modelo LLM Para Tarefa Específica e Deploy de Web App com Gradio</font>"
12
+ ]
13
+ },
14
+ {
15
+ "cell_type": "markdown",
16
+ "metadata": {},
17
+ "source": [
18
+ "![DSA](imagens/MP3.png)"
19
+ ]
20
+ },
21
+ {
22
+ "cell_type": "markdown",
23
+ "metadata": {},
24
+ "source": [
25
+ "## Instalando e Carregando os Pacotes"
26
+ ]
27
+ },
28
+ {
29
+ "cell_type": "code",
30
+ "execution_count": 1,
31
+ "metadata": {},
32
+ "outputs": [
33
+ {
34
+ "name": "stdout",
35
+ "output_type": "stream",
36
+ "text": [
37
+ "Versão da Linguagem Python Usada Neste Jupyter Notebook: 3.10.9\n"
38
+ ]
39
+ }
40
+ ],
41
+ "source": [
42
+ "# Versão da Linguagem Python\n",
43
+ "from platform import python_version\n",
44
+ "print('Versão da Linguagem Python Usada Neste Jupyter Notebook:', python_version())"
45
+ ]
46
+ },
47
+ {
48
+ "cell_type": "code",
49
+ "execution_count": 2,
50
+ "metadata": {},
51
+ "outputs": [],
52
+ "source": [
53
+ "# Para atualizar um pacote, execute o comando abaixo no terminal ou prompt de comando:\n",
54
+ "# pip install -U nome_pacote\n",
55
+ "\n",
56
+ "# Para instalar a versão exata de um pacote, execute o comando abaixo no terminal ou prompt de comando:\n",
57
+ "# !pip install nome_pacote==versão_desejada\n",
58
+ "\n",
59
+ "# Depois de instalar ou atualizar o pacote, reinicie o jupyter notebook.\n",
60
+ "\n",
61
+ "# Instala o pacote watermark. \n",
62
+ "# Esse pacote é usado para gravar as versões de outros pacotes usados neste jupyter notebook.\n",
63
+ "!pip install -q -U watermark"
64
+ ]
65
+ },
66
+ {
67
+ "cell_type": "code",
68
+ "execution_count": 3,
69
+ "metadata": {},
70
+ "outputs": [
71
+ {
72
+ "name": "stdout",
73
+ "output_type": "stream",
74
+ "text": [
75
+ "env: TF_CPP_MIN_LOG_LEVEL=3\n"
76
+ ]
77
+ }
78
+ ],
79
+ "source": [
80
+ "%env TF_CPP_MIN_LOG_LEVEL=3"
81
+ ]
82
+ },
83
+ {
84
+ "cell_type": "code",
85
+ "execution_count": 4,
86
+ "metadata": {},
87
+ "outputs": [],
88
+ "source": [
89
+ "!pip install -q torch==2.0.1"
90
+ ]
91
+ },
92
+ {
93
+ "cell_type": "code",
94
+ "execution_count": 5,
95
+ "metadata": {},
96
+ "outputs": [],
97
+ "source": [
98
+ "!pip install -q transformers==4.31.0"
99
+ ]
100
+ },
101
+ {
102
+ "cell_type": "code",
103
+ "execution_count": 6,
104
+ "metadata": {},
105
+ "outputs": [],
106
+ "source": [
107
+ "!pip install -q accelerate"
108
+ ]
109
+ },
110
+ {
111
+ "cell_type": "code",
112
+ "execution_count": 7,
113
+ "metadata": {},
114
+ "outputs": [],
115
+ "source": [
116
+ "# Imports\n",
117
+ "import torch\n",
118
+ "import transformers\n",
119
+ "import numpy as np\n",
120
+ "import torch.nn.functional as F\n",
121
+ "from accelerate import Accelerator\n",
122
+ "from torch.utils.data import Dataset\n",
123
+ "from transformers import AutoConfig, AutoModelForCausalLM, GPT2Tokenizer\n",
124
+ "from transformers import GPT2Tokenizer"
125
+ ]
126
+ },
127
+ {
128
+ "cell_type": "code",
129
+ "execution_count": 8,
130
+ "metadata": {},
131
+ "outputs": [
132
+ {
133
+ "name": "stdout",
134
+ "output_type": "stream",
135
+ "text": [
136
+ "Author: Data Science Academy\n",
137
+ "\n",
138
+ "numpy : 1.23.5\n",
139
+ "torch : 2.0.1\n",
140
+ "transformers: 4.31.0\n",
141
+ "\n"
142
+ ]
143
+ }
144
+ ],
145
+ "source": [
146
+ "# Versões dos pacotes usados neste jupyter notebook\n",
147
+ "%reload_ext watermark\n",
148
+ "%watermark -a \"Data Science Academy\" --iversions"
149
+ ]
150
+ },
151
+ {
152
+ "cell_type": "markdown",
153
+ "metadata": {},
154
+ "source": [
155
+ "## Carregando o LLM\n",
156
+ "\n",
157
+ "https://huggingface.co/gpt2\n",
158
+ "\n",
159
+ "O modelo terá a mesma arquitetura do GPT-2, mas com algumas modificações para torná-lo menor. As principais mudanças são o tamanho do vocabulário que é 13 porque só vai lidar com números mais o padding token, o \"+\" e o \"=\". A janela de contexto suportará apenas 6 tokens, pois estamos interessados apenas em realizar a adição de dois dígitos únicos."
160
+ ]
161
+ },
162
+ {
163
+ "cell_type": "code",
164
+ "execution_count": 9,
165
+ "metadata": {},
166
+ "outputs": [],
167
+ "source": [
168
+ "# Tamanho do vocabulário\n",
169
+ "vocab_size = 13"
170
+ ]
171
+ },
172
+ {
173
+ "cell_type": "code",
174
+ "execution_count": 10,
175
+ "metadata": {},
176
+ "outputs": [],
177
+ "source": [
178
+ "# Comprimento da sequência\n",
179
+ "sequence_length = 4"
180
+ ]
181
+ },
182
+ {
183
+ "cell_type": "code",
184
+ "execution_count": 11,
185
+ "metadata": {},
186
+ "outputs": [],
187
+ "source": [
188
+ "# Comprimento do resultado\n",
189
+ "result_length = 2"
190
+ ]
191
+ },
192
+ {
193
+ "cell_type": "code",
194
+ "execution_count": 12,
195
+ "metadata": {},
196
+ "outputs": [],
197
+ "source": [
198
+ "# Comprimento do contexto\n",
199
+ "context_length = sequence_length + result_length"
200
+ ]
201
+ },
202
+ {
203
+ "cell_type": "code",
204
+ "execution_count": 13,
205
+ "metadata": {},
206
+ "outputs": [],
207
+ "source": [
208
+ "# Parâmetros de configuração do modelo GPT-2\n",
209
+ "config = AutoConfig.from_pretrained(\"gpt2\", \n",
210
+ " vocab_size = vocab_size, \n",
211
+ " n_ctx = context_length, \n",
212
+ " n_head = 4, \n",
213
+ " n_layer = 2) "
214
+ ]
215
+ },
216
+ {
217
+ "cell_type": "code",
218
+ "execution_count": 14,
219
+ "metadata": {},
220
+ "outputs": [],
221
+ "source": [
222
+ "# Carrega o modelo\n",
223
+ "modelo = AutoModelForCausalLM.from_config(config)"
224
+ ]
225
+ },
226
+ {
227
+ "cell_type": "code",
228
+ "execution_count": 15,
229
+ "metadata": {},
230
+ "outputs": [],
231
+ "source": [
232
+ "# Função para calcular o tamanho do modelo\n",
233
+ "def model_size(model):\n",
234
+ " return sum(t.numel() for t in modelo.parameters())"
235
+ ]
236
+ },
237
+ {
238
+ "cell_type": "code",
239
+ "execution_count": 16,
240
+ "metadata": {},
241
+ "outputs": [
242
+ {
243
+ "name": "stdout",
244
+ "output_type": "stream",
245
+ "text": [
246
+ "Tamanho do Modelo: 15.0M parâmetros\n"
247
+ ]
248
+ }
249
+ ],
250
+ "source": [
251
+ "print(f'Tamanho do Modelo: {model_size(modelo)/1000**2:.1f}M parâmetros')"
252
+ ]
253
+ },
254
+ {
255
+ "cell_type": "markdown",
256
+ "metadata": {},
257
+ "source": [
258
+ "Este modelo tem 15 milhões de parâmetros em vez dos 111 milhões de parâmetros da configuração padrão \"gpt2\"."
259
+ ]
260
+ },
261
+ {
262
+ "cell_type": "code",
263
+ "execution_count": 17,
264
+ "metadata": {},
265
+ "outputs": [
266
+ {
267
+ "data": {
268
+ "text/plain": [
269
+ "transformers.models.gpt2.modeling_gpt2.GPT2LMHeadModel"
270
+ ]
271
+ },
272
+ "execution_count": 17,
273
+ "metadata": {},
274
+ "output_type": "execute_result"
275
+ }
276
+ ],
277
+ "source": [
278
+ "type(modelo)"
279
+ ]
280
+ },
281
+ {
282
+ "cell_type": "code",
283
+ "execution_count": 18,
284
+ "metadata": {},
285
+ "outputs": [],
286
+ "source": [
287
+ "# Salva o modelo em disco\n",
288
+ "modelo.save_pretrained(\"modelos/modelo_inicial\")"
289
+ ]
290
+ },
291
+ {
292
+ "cell_type": "markdown",
293
+ "metadata": {},
294
+ "source": [
295
+ "## Tokenizador Personalizado"
296
+ ]
297
+ },
298
+ {
299
+ "cell_type": "code",
300
+ "execution_count": 19,
301
+ "metadata": {},
302
+ "outputs": [],
303
+ "source": [
304
+ "# Definindo uma classe chamada NumberTokenizer, que é usada para tokenizar os números\n",
305
+ "class DSATokenizer:\n",
306
+ " \n",
307
+ " # Método construtor da classe, que é executado quando um objeto dessa classe é criado\n",
308
+ " def __init__(self, numbers_qty = 10):\n",
309
+ " \n",
310
+ " # Lista de tokens possíveis que o tokenizador pode encontrar\n",
311
+ " vocab = ['+', '=', '-1', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']\n",
312
+ " \n",
313
+ " # Definindo a quantidade de números que o tokenizador pode lidar\n",
314
+ " self.numbers_qty = numbers_qty\n",
315
+ " \n",
316
+ " # Definindo o token de preenchimento (padding)\n",
317
+ " self.pad_token = '-1'\n",
318
+ " \n",
319
+ " # Criando um dicionário que mapeia cada token para um índice único\n",
320
+ " self.encoder = {str(v):i for i,v in enumerate(vocab)}\n",
321
+ " \n",
322
+ " # Criando um dicionário que mapeia cada índice único de volta ao token correspondente\n",
323
+ " self.decoder = {i:str(v) for i,v in enumerate(vocab)}\n",
324
+ " \n",
325
+ " # Obtendo o índice do token de preenchimento no encoder\n",
326
+ " self.pad_token_id = self.encoder[self.pad_token]\n",
327
+ "\n",
328
+ " # Método para decodificar uma lista de IDs de token de volta para uma string\n",
329
+ " def decode(self, token_ids):\n",
330
+ " return ' '.join(self.decoder[t] for t in token_ids)\n",
331
+ "\n",
332
+ " # Método que é chamado quando o objeto da classe é invocado como uma função\n",
333
+ " def __call__(self, text):\n",
334
+ " # Dividindo o texto em tokens individuais e retornando uma lista dos IDs correspondentes\n",
335
+ " return [self.encoder[t] for t in text.split()]"
336
+ ]
337
+ },
338
+ {
339
+ "cell_type": "markdown",
340
+ "metadata": {},
341
+ "source": [
342
+ "> Vamos testar o tokenizador!"
343
+ ]
344
+ },
345
+ {
346
+ "cell_type": "code",
347
+ "execution_count": 20,
348
+ "metadata": {},
349
+ "outputs": [],
350
+ "source": [
351
+ "# Cria o objeto do tokenizador\n",
352
+ "tokenizer = DSATokenizer(vocab_size)"
353
+ ]
354
+ },
355
+ {
356
+ "cell_type": "code",
357
+ "execution_count": 21,
358
+ "metadata": {},
359
+ "outputs": [
360
+ {
361
+ "data": {
362
+ "text/plain": [
363
+ "{0: '+',\n",
364
+ " 1: '=',\n",
365
+ " 2: '-1',\n",
366
+ " 3: '0',\n",
367
+ " 4: '1',\n",
368
+ " 5: '2',\n",
369
+ " 6: '3',\n",
370
+ " 7: '4',\n",
371
+ " 8: '5',\n",
372
+ " 9: '6',\n",
373
+ " 10: '7',\n",
374
+ " 11: '8',\n",
375
+ " 12: '9'}"
376
+ ]
377
+ },
378
+ "execution_count": 21,
379
+ "metadata": {},
380
+ "output_type": "execute_result"
381
+ }
382
+ ],
383
+ "source": [
384
+ "# Decoder do tokenizador\n",
385
+ "tokenizer.decoder"
386
+ ]
387
+ },
388
+ {
389
+ "cell_type": "code",
390
+ "execution_count": 22,
391
+ "metadata": {},
392
+ "outputs": [
393
+ {
394
+ "data": {
395
+ "text/plain": [
396
+ "[4, 0, 4, 1, 5]"
397
+ ]
398
+ },
399
+ "execution_count": 22,
400
+ "metadata": {},
401
+ "output_type": "execute_result"
402
+ }
403
+ ],
404
+ "source": [
405
+ "# Testando o tokenizador\n",
406
+ "tokenizer(\"1 + 1 = 2\")"
407
+ ]
408
+ },
409
+ {
410
+ "cell_type": "markdown",
411
+ "metadata": {},
412
+ "source": [
413
+ "## Criando o Dataset\n",
414
+ "\n",
415
+ "O conjunto de dados deve ser criado neste formato:\n",
416
+ "\n",
417
+ "- Entrada: \"2 + 3 = 0\" onde os 4 primeiros caracteres representam a sequência de entrada e o quinto caractere representa o primeiro caracter da saída.\n",
418
+ "\n",
419
+ "- Saída: \"+ 3 = 0 5\" onde os 2 últimos dígitos representam o resultado da adição e os 3 primeiros dígitos são ignorados durante o treinamento e preenchidos com o pad.\n",
420
+ "\n",
421
+ "O resultado é um conjunto de dados de sequências tokenizadas de números."
422
+ ]
423
+ },
424
+ {
425
+ "cell_type": "code",
426
+ "execution_count": 23,
427
+ "metadata": {},
428
+ "outputs": [],
429
+ "source": [
430
+ "# Definindo uma classe chamada CriaDataset, que herda da classe Dataset do PyTorch\n",
431
+ "class CriaDataset(Dataset):\n",
432
+ "\n",
433
+ " # Método construtor da classe, que é executado quando um objeto dessa classe é criado\n",
434
+ " def __init__(self, split, length = 6):\n",
435
+ " \n",
436
+ " # Verificando se a divisão do dataset (split) é 'treino' ou 'teste'\n",
437
+ " assert split in {'treino', 'teste'}\n",
438
+ " self.split = split\n",
439
+ " self.length = length\n",
440
+ " \n",
441
+ " # Definindo o método len que retorna o tamanho do dataset. \n",
442
+ " # Nesse caso, o tamanho é fixo e igual a 1 milhão.\n",
443
+ " def __len__(self):\n",
444
+ " return 1000000 \n",
445
+ "\n",
446
+ " # Definindo o método getitem que é usado para obter um item específico do dataset\n",
447
+ " def __getitem__(self, idx):\n",
448
+ "\n",
449
+ " # Criando uma lista com todos os números disponíveis que não são tokens de padding e são numéricos\n",
450
+ " available_numbers = [int(n) for n in tokenizer.decoder.values() if n != tokenizer.pad_token and str(n).isnumeric()]\n",
451
+ " \n",
452
+ " # Selecionando aleatoriamente números da lista de números disponíveis para criar uma entrada (input)\n",
453
+ " inp = torch.tensor(np.random.choice(available_numbers, size = result_length))\n",
454
+ " \n",
455
+ " # Calculando a soma dos números selecionados e criando um tensor\n",
456
+ " sol = torch.tensor([int(i) for i in str(inp.sum().item())])\n",
457
+ " \n",
458
+ " # Preenchendo o tensor com zeros para que tenha o tamanho desejado\n",
459
+ " sol = torch.nn.functional.pad(sol, (1 if sol.size()[0] == 1 else 0,0), 'constant', 0)\n",
460
+ "\n",
461
+ " # Concatenando a entrada e a solução em um tensor\n",
462
+ " cat = torch.cat((inp, sol), dim = 0)\n",
463
+ "\n",
464
+ " # Criando os tensores de entrada e alvo para o treinamento do modelo\n",
465
+ " x = cat[:-1].clone()\n",
466
+ " y = cat[1:].clone()\n",
467
+ "\n",
468
+ " # Definindo o primeiro elemento do tensor alvo como o token de padding\n",
469
+ " y[:1] = int(tokenizer.pad_token)\n",
470
+ "\n",
471
+ " # Transformando os tensores x e y em strings\n",
472
+ " x = str(x[0].item()) + ' + ' + str(x[1].item()) + ' = ' + str(x[2].item())\n",
473
+ " y = '-1 ' + str(y[0].item()) + ' -1 ' + str(y[1].item()) + ' ' + str(y[2].item())\n",
474
+ " \n",
475
+ " # Tokenizando as strings de entrada e alvo\n",
476
+ " tokenized_input = tokenizer(x)\n",
477
+ " tokenized_output = tokenizer(y)\n",
478
+ " \n",
479
+ " # Retornando os tensores de entrada e alvo como itens do dataset\n",
480
+ " return torch.tensor(tokenized_input), torch.tensor(tokenized_output)"
481
+ ]
482
+ },
483
+ {
484
+ "cell_type": "markdown",
485
+ "metadata": {},
486
+ "source": [
487
+ "## Datasets de Treino e Teste"
488
+ ]
489
+ },
490
+ {
491
+ "cell_type": "code",
492
+ "execution_count": 24,
493
+ "metadata": {},
494
+ "outputs": [],
495
+ "source": [
496
+ "dataset_treino = CriaDataset('treino', length = sequence_length)"
497
+ ]
498
+ },
499
+ {
500
+ "cell_type": "code",
501
+ "execution_count": 25,
502
+ "metadata": {},
503
+ "outputs": [],
504
+ "source": [
505
+ "dataset_teste = CriaDataset('teste', length = sequence_length)"
506
+ ]
507
+ },
508
+ {
509
+ "cell_type": "code",
510
+ "execution_count": 26,
511
+ "metadata": {},
512
+ "outputs": [],
513
+ "source": [
514
+ "x, y = dataset_treino[0]"
515
+ ]
516
+ },
517
+ {
518
+ "cell_type": "code",
519
+ "execution_count": 27,
520
+ "metadata": {},
521
+ "outputs": [
522
+ {
523
+ "data": {
524
+ "text/plain": [
525
+ "tensor([10, 0, 4, 1, 3])"
526
+ ]
527
+ },
528
+ "execution_count": 27,
529
+ "metadata": {},
530
+ "output_type": "execute_result"
531
+ }
532
+ ],
533
+ "source": [
534
+ "x"
535
+ ]
536
+ },
537
+ {
538
+ "cell_type": "code",
539
+ "execution_count": 28,
540
+ "metadata": {},
541
+ "outputs": [
542
+ {
543
+ "data": {
544
+ "text/plain": [
545
+ "tensor([ 2, 2, 2, 3, 11])"
546
+ ]
547
+ },
548
+ "execution_count": 28,
549
+ "metadata": {},
550
+ "output_type": "execute_result"
551
+ }
552
+ ],
553
+ "source": [
554
+ "y"
555
+ ]
556
+ },
557
+ {
558
+ "cell_type": "code",
559
+ "execution_count": 29,
560
+ "metadata": {},
561
+ "outputs": [
562
+ {
563
+ "name": "stdout",
564
+ "output_type": "stream",
565
+ "text": [
566
+ "7 + 1 = 0\n"
567
+ ]
568
+ }
569
+ ],
570
+ "source": [
571
+ "print(tokenizer.decode(x.numpy()))"
572
+ ]
573
+ },
574
+ {
575
+ "cell_type": "code",
576
+ "execution_count": 30,
577
+ "metadata": {},
578
+ "outputs": [
579
+ {
580
+ "name": "stdout",
581
+ "output_type": "stream",
582
+ "text": [
583
+ "-1 -1 -1 0 8\n"
584
+ ]
585
+ }
586
+ ],
587
+ "source": [
588
+ "print(tokenizer.decode(y.numpy()))"
589
+ ]
590
+ },
591
+ {
592
+ "cell_type": "markdown",
593
+ "metadata": {},
594
+ "source": [
595
+ "## Loop de Treinamento"
596
+ ]
597
+ },
598
+ {
599
+ "cell_type": "code",
600
+ "execution_count": 31,
601
+ "metadata": {},
602
+ "outputs": [],
603
+ "source": [
604
+ "num_epochs = 2"
605
+ ]
606
+ },
607
+ {
608
+ "cell_type": "code",
609
+ "execution_count": 32,
610
+ "metadata": {},
611
+ "outputs": [],
612
+ "source": [
613
+ "batch_size = 100"
614
+ ]
615
+ },
616
+ {
617
+ "cell_type": "code",
618
+ "execution_count": 33,
619
+ "metadata": {},
620
+ "outputs": [],
621
+ "source": [
622
+ "optimizer = torch.optim.Adam(modelo.parameters())"
623
+ ]
624
+ },
625
+ {
626
+ "cell_type": "code",
627
+ "execution_count": 34,
628
+ "metadata": {},
629
+ "outputs": [],
630
+ "source": [
631
+ "dados = torch.utils.data.DataLoader(dataset_treino, shuffle = True, batch_size = batch_size)"
632
+ ]
633
+ },
634
+ {
635
+ "cell_type": "markdown",
636
+ "metadata": {},
637
+ "source": [
638
+ "https://pypi.org/project/accelerate/"
639
+ ]
640
+ },
641
+ {
642
+ "cell_type": "code",
643
+ "execution_count": 35,
644
+ "metadata": {},
645
+ "outputs": [],
646
+ "source": [
647
+ "import accelerate\n",
648
+ "from accelerate import Accelerator"
649
+ ]
650
+ },
651
+ {
652
+ "cell_type": "code",
653
+ "execution_count": 36,
654
+ "metadata": {},
655
+ "outputs": [],
656
+ "source": [
657
+ "accelerator = Accelerator()"
658
+ ]
659
+ },
660
+ {
661
+ "cell_type": "code",
662
+ "execution_count": 37,
663
+ "metadata": {},
664
+ "outputs": [
665
+ {
666
+ "name": "stdout",
667
+ "output_type": "stream",
668
+ "text": [
669
+ "Author: Data Science Academy\n",
670
+ "\n",
671
+ "numpy : 1.23.5\n",
672
+ "accelerate : 0.21.0\n",
673
+ "torch : 2.0.1\n",
674
+ "transformers: 4.31.0\n",
675
+ "\n"
676
+ ]
677
+ }
678
+ ],
679
+ "source": [
680
+ "# Versões dos pacotes usados neste jupyter notebook\n",
681
+ "%reload_ext watermark\n",
682
+ "%watermark -a \"Data Science Academy\" --iversions"
683
+ ]
684
+ },
685
+ {
686
+ "cell_type": "code",
687
+ "execution_count": 38,
688
+ "metadata": {},
689
+ "outputs": [],
690
+ "source": [
691
+ "modelo, optimizer, dados = accelerator.prepare(modelo, optimizer, dados)"
692
+ ]
693
+ },
694
+ {
695
+ "cell_type": "code",
696
+ "execution_count": 39,
697
+ "metadata": {},
698
+ "outputs": [
699
+ {
700
+ "data": {
701
+ "text/plain": [
702
+ "GPT2LMHeadModel(\n",
703
+ " (transformer): GPT2Model(\n",
704
+ " (wte): Embedding(13, 768)\n",
705
+ " (wpe): Embedding(1024, 768)\n",
706
+ " (drop): Dropout(p=0.1, inplace=False)\n",
707
+ " (h): ModuleList(\n",
708
+ " (0-1): 2 x GPT2Block(\n",
709
+ " (ln_1): LayerNorm((768,), eps=1e-05, elementwise_affine=True)\n",
710
+ " (attn): GPT2Attention(\n",
711
+ " (c_attn): Conv1D()\n",
712
+ " (c_proj): Conv1D()\n",
713
+ " (attn_dropout): Dropout(p=0.1, inplace=False)\n",
714
+ " (resid_dropout): Dropout(p=0.1, inplace=False)\n",
715
+ " )\n",
716
+ " (ln_2): LayerNorm((768,), eps=1e-05, elementwise_affine=True)\n",
717
+ " (mlp): GPT2MLP(\n",
718
+ " (c_fc): Conv1D()\n",
719
+ " (c_proj): Conv1D()\n",
720
+ " (act): NewGELUActivation()\n",
721
+ " (dropout): Dropout(p=0.1, inplace=False)\n",
722
+ " )\n",
723
+ " )\n",
724
+ " )\n",
725
+ " (ln_f): LayerNorm((768,), eps=1e-05, elementwise_affine=True)\n",
726
+ " )\n",
727
+ " (lm_head): Linear(in_features=768, out_features=13, bias=False)\n",
728
+ ")"
729
+ ]
730
+ },
731
+ "execution_count": 39,
732
+ "metadata": {},
733
+ "output_type": "execute_result"
734
+ }
735
+ ],
736
+ "source": [
737
+ "modelo.train()"
738
+ ]
739
+ },
740
+ {
741
+ "cell_type": "code",
742
+ "execution_count": 40,
743
+ "metadata": {},
744
+ "outputs": [
745
+ {
746
+ "name": "stdout",
747
+ "output_type": "stream",
748
+ "text": [
749
+ "Epoch: 1/2 --- Erro: 0.10058706998825073\n",
750
+ "Epoch: 2/2 --- Erro: 0.05222655460238457\n",
751
+ "CPU times: user 6min 51s, sys: 899 ms, total: 6min 52s\n",
752
+ "Wall time: 6min 55s\n"
753
+ ]
754
+ }
755
+ ],
756
+ "source": [
757
+ "%%time\n",
758
+ "\n",
759
+ "# Iniciando o loop para as épocas de treinamento\n",
760
+ "for epoch in range(num_epochs):\n",
761
+ "\n",
762
+ " # Iterando por cada batch (conjunto) de dados de entrada e alvos no dataset de treinamento\n",
763
+ " for source, targets in dados:\n",
764
+ "\n",
765
+ " # Resetando os gradientes acumulados no otimizador\n",
766
+ " optimizer.zero_grad()\n",
767
+ "\n",
768
+ " # Calculando a perda (loss) através da entropia cruzada entre as previsões do modelo e os alvos verdadeiros. \n",
769
+ " # Os tensores são \"achatados\" para que possam ser passados para a função de entropia cruzada. \n",
770
+ " # O índice do token de preenchimento (pad_token) é ignorado no cálculo da perda.\n",
771
+ " loss = F.cross_entropy(modelo(source).logits.flatten(end_dim = 1), \n",
772
+ " targets.flatten(end_dim = 1), \n",
773
+ " ignore_index = tokenizer.pad_token_id)\n",
774
+ "\n",
775
+ " # Calculando os gradientes da perda em relação aos parâmetros do modelo\n",
776
+ " accelerator.backward(loss)\n",
777
+ "\n",
778
+ " # Atualizando os parâmetros do modelo utilizando os gradientes calculados\n",
779
+ " optimizer.step()\n",
780
+ "\n",
781
+ " # Recalculando a perda após a etapa de otimização. \n",
782
+ " loss = F.cross_entropy(modelo(source).logits.flatten(end_dim = 1), \n",
783
+ " targets.flatten(end_dim = 1), \n",
784
+ " ignore_index = tokenizer.pad_token_id)\n",
785
+ "\n",
786
+ " # Imprimindo a época atual e a perda após cada época de treinamento\n",
787
+ " print(f'Epoch: {epoch+1}/{num_epochs} --- Erro: {loss.item()}')"
788
+ ]
789
+ },
790
+ {
791
+ "cell_type": "markdown",
792
+ "metadata": {},
793
+ "source": [
794
+ "## Avaliação do Modelo"
795
+ ]
796
+ },
797
+ {
798
+ "cell_type": "code",
799
+ "execution_count": 41,
800
+ "metadata": {},
801
+ "outputs": [],
802
+ "source": [
803
+ "# Definindo a função gera_solution com três parâmetros: input, solution_length e model\n",
804
+ "def faz_previsao(entrada, solution_length = 6, model = modelo):\n",
805
+ "\n",
806
+ " # Colocando o modelo em modo de avaliação. \n",
807
+ " model.eval()\n",
808
+ "\n",
809
+ " # Convertendo a entrada (string) em tensor utilizando o tokenizer. \n",
810
+ " # O tensor é uma estrutura de dados que o modelo de aprendizado de máquina pode processar.\n",
811
+ " entrada = torch.tensor(tokenizer(entrada))\n",
812
+ "\n",
813
+ " # Enviando o tensor de entrada para o dispositivo de cálculo disponível (CPU ou GPU)\n",
814
+ " entrada = entrada.to(accelerator.device)\n",
815
+ "\n",
816
+ " # Iniciando uma lista vazia para armazenar a solução\n",
817
+ " solution = []\n",
818
+ "\n",
819
+ " # Loop que gera a solução de comprimento solution_length\n",
820
+ " for i in range(solution_length):\n",
821
+ "\n",
822
+ " # Alimentando a entrada atual ao modelo e obtendo a saída\n",
823
+ " saida = model(entrada)\n",
824
+ "\n",
825
+ " # Pegando o índice do maior valor no último conjunto de logits (log-odds) da saída, \n",
826
+ " # que é a previsão do modelo para o próximo token\n",
827
+ " predicted = saida.logits[-1].argmax()\n",
828
+ "\n",
829
+ " # Concatenando a previsão atual com a entrada atual. \n",
830
+ " # Isso servirá como a nova entrada para a próxima iteração.\n",
831
+ " entrada = torch.cat((entrada, predicted.unsqueeze(0)), dim = 0)\n",
832
+ "\n",
833
+ " # Adicionando a previsão atual à lista de soluções e convertendo o tensor em um número Python padrão\n",
834
+ " solution.append(predicted.cpu().item())\n",
835
+ "\n",
836
+ " # Decodificando a lista de soluções para obter a string de saída e retornando-a\n",
837
+ " return tokenizer.decode(solution)"
838
+ ]
839
+ },
840
+ {
841
+ "cell_type": "code",
842
+ "execution_count": 42,
843
+ "metadata": {},
844
+ "outputs": [],
845
+ "source": [
846
+ "# Definindo a função avalia_modelo com dois parâmetros: num_samples e log\n",
847
+ "def avalia_modelo(num_samples = 1000, log = False):\n",
848
+ "\n",
849
+ " # Iniciando um contador para as previsões corretas\n",
850
+ " correct = 0\n",
851
+ "\n",
852
+ " # Loop que itera num_samples vezes\n",
853
+ " for i in range(num_samples):\n",
854
+ "\n",
855
+ " # Obtendo a entrada e o alvo (resposta correta) do i-ésimo exemplo do conjunto de teste\n",
856
+ " entrada, target = dataset_teste[i]\n",
857
+ "\n",
858
+ " # Convertendo os tensores de entrada e alvo em arrays numpy para processamento posterior\n",
859
+ " entrada = entrada.cpu().numpy()\n",
860
+ " target = target.cpu().numpy()\n",
861
+ "\n",
862
+ " # Decodificando a entrada e o alvo utilizando o tokenizer\n",
863
+ " entrada = tokenizer.decode(entrada[:sequence_length])\n",
864
+ " target = tokenizer.decode(target[sequence_length-1:])\n",
865
+ "\n",
866
+ " # Gerando a previsão utilizando a função faz_previsao\n",
867
+ " predicted = faz_previsao(entrada, solution_length = result_length, model = modelo)\n",
868
+ " \n",
869
+ " # Se a previsão for igual ao alvo, incrementa o contador de previsões corretas\n",
870
+ " if target == predicted:\n",
871
+ " correct += 1\n",
872
+ " # Se log for True, imprime detalhes do exemplo e a previsão correta\n",
873
+ " if log:\n",
874
+ " print(f'Acerto do Modelo: Input: {entrada} Target: {target} Previsão: {predicted}')\n",
875
+ " else:\n",
876
+ " # Se log for True, imprime detalhes do exemplo e a previsão errada\n",
877
+ " if log:\n",
878
+ " print(f'Erro do Modelo: Input: {entrada} Target: {target} Previsão: {predicted}')\n",
879
+ "\n",
880
+ " # Ao final do loop, calcula a acurácia (número de previsões corretas dividido pelo número total de exemplos) \n",
881
+ " print(f'Acurácia: {correct/num_samples}')"
882
+ ]
883
+ },
884
+ {
885
+ "cell_type": "code",
886
+ "execution_count": 43,
887
+ "metadata": {},
888
+ "outputs": [
889
+ {
890
+ "name": "stdout",
891
+ "output_type": "stream",
892
+ "text": [
893
+ "Acerto do Modelo: Input: 0 + 1 = Target: 0 1 Previsão: 0 1\n",
894
+ "Acerto do Modelo: Input: 0 + 3 = Target: 0 3 Previsão: 0 3\n",
895
+ "Acerto do Modelo: Input: 1 + 8 = Target: 0 9 Previsão: 0 9\n",
896
+ "Acerto do Modelo: Input: 2 + 4 = Target: 0 6 Previsão: 0 6\n",
897
+ "Acerto do Modelo: Input: 2 + 4 = Target: 0 6 Previsão: 0 6\n",
898
+ "Acerto do Modelo: Input: 5 + 8 = Target: 1 3 Previsão: 1 3\n",
899
+ "Acerto do Modelo: Input: 1 + 4 = Target: 0 5 Previsão: 0 5\n",
900
+ "Acerto do Modelo: Input: 8 + 9 = Target: 1 7 Previsão: 1 7\n",
901
+ "Acerto do Modelo: Input: 5 + 9 = Target: 1 4 Previsão: 1 4\n",
902
+ "Acerto do Modelo: Input: 2 + 4 = Target: 0 6 Previsão: 0 6\n",
903
+ "Acurácia: 1.0\n"
904
+ ]
905
+ }
906
+ ],
907
+ "source": [
908
+ "# Executa a função\n",
909
+ "avalia_modelo(num_samples = 10, log = True)"
910
+ ]
911
+ },
912
+ {
913
+ "cell_type": "code",
914
+ "execution_count": 44,
915
+ "metadata": {},
916
+ "outputs": [
917
+ {
918
+ "name": "stdout",
919
+ "output_type": "stream",
920
+ "text": [
921
+ "Acurácia: 1.0\n"
922
+ ]
923
+ }
924
+ ],
925
+ "source": [
926
+ "# Executa a função\n",
927
+ "avalia_modelo(num_samples = 1000, log = False)"
928
+ ]
929
+ },
930
+ {
931
+ "cell_type": "code",
932
+ "execution_count": 45,
933
+ "metadata": {},
934
+ "outputs": [
935
+ {
936
+ "data": {
937
+ "text/plain": [
938
+ "transformers.models.gpt2.modeling_gpt2.GPT2LMHeadModel"
939
+ ]
940
+ },
941
+ "execution_count": 45,
942
+ "metadata": {},
943
+ "output_type": "execute_result"
944
+ }
945
+ ],
946
+ "source": [
947
+ "type(modelo)"
948
+ ]
949
+ },
950
+ {
951
+ "cell_type": "code",
952
+ "execution_count": 46,
953
+ "metadata": {},
954
+ "outputs": [],
955
+ "source": [
956
+ "modelo.save_pretrained(\"modelos/modelo_final\")"
957
+ ]
958
+ },
959
+ {
960
+ "cell_type": "markdown",
961
+ "metadata": {},
962
+ "source": [
963
+ "# Fim"
964
+ ]
965
+ }
966
+ ],
967
+ "metadata": {
968
+ "kernelspec": {
969
+ "display_name": "Python 3 (ipykernel)",
970
+ "language": "python",
971
+ "name": "python3"
972
+ },
973
+ "language_info": {
974
+ "codemirror_mode": {
975
+ "name": "ipython",
976
+ "version": 3
977
+ },
978
+ "file_extension": ".py",
979
+ "mimetype": "text/x-python",
980
+ "name": "python",
981
+ "nbconvert_exporter": "python",
982
+ "pygments_lexer": "ipython3",
983
+ "version": "3.10.9"
984
+ }
985
+ },
986
+ "nbformat": 4,
987
+ "nbformat_minor": 2
988
+ }