camilaaeromoca commited on
Commit
b594c4c
·
verified ·
1 Parent(s): 189c083

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -262
app.py CHANGED
@@ -7,268 +7,6 @@ from torch.utils.data import Dataset
7
  from transformers import AutoConfig, AutoModelForCausalLM, GPT2Tokenizer
8
  from transformers import GPT2Tokenizer
9
 
10
- # Tamanho do vocabulário
11
- vocab_size = 13
12
- # Comprimento da sequência
13
- sequence_length = 4
14
- # Comprimento do resultado
15
- result_length = 2
16
- # Comprimento do contexto
17
- context_length = sequence_length + result_length
18
- # Parâmetros de configuração do modelo GPT-2
19
- config = AutoConfig.from_pretrained("gpt2",
20
- vocab_size = vocab_size,
21
- n_ctx = context_length,
22
- n_head = 4,
23
- n_layer = 2)
24
-
25
- # Carrega o modelo
26
- modelo = AutoModelForCausalLM.from_config(config)
27
- # Função para calcular o tamanho do modelo
28
- def model_size(model):
29
- return sum(t.numel() for t in modelo.parameters())
30
- print(f'Tamanho do Modelo: {model_size(modelo)/1000**2:.1f}M parâmetros')
31
- #Tamanho do Modelo: 15.0M parâmetros
32
- #Este modelo tem 15 milhões de parâmetros em vez dos 111 milhões de parâmetros da configuração padrão "gpt2".
33
-
34
- type(modelo)
35
- transformers.models.gpt2.modeling_gpt2.GPT2LMHeadModel
36
- # Salva o modelo em disco
37
- modelo.save_pretrained("modelos/modelo_inicial")
38
-
39
- # Definindo uma classe chamada NumberTokenizer, que é usada para tokenizar os números
40
- class DSATokenizer:
41
-
42
- # Método construtor da classe, que é executado quando um objeto dessa classe é criado
43
- def __init__(self, numbers_qty = 10):
44
-
45
- # Lista de tokens possíveis que o tokenizador pode encontrar
46
- vocab = ['+', '=', '-1', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
47
-
48
- # Definindo a quantidade de números que o tokenizador pode lidar
49
- self.numbers_qty = numbers_qty
50
-
51
- # Definindo o token de preenchimento (padding)
52
- self.pad_token = '-1'
53
-
54
- # Criando um dicionário que mapeia cada token para um índice único
55
- self.encoder = {str(v):i for i,v in enumerate(vocab)}
56
-
57
- # Criando um dicionário que mapeia cada índice único de volta ao token correspondente
58
- self.decoder = {i:str(v) for i,v in enumerate(vocab)}
59
-
60
- # Obtendo o índice do token de preenchimento no encoder
61
- self.pad_token_id = self.encoder[self.pad_token]
62
-
63
- # Método para decodificar uma lista de IDs de token de volta para uma string
64
- def decode(self, token_ids):
65
- return ' '.join(self.decoder[t] for t in token_ids)
66
-
67
- # Método que é chamado quando o objeto da classe é invocado como uma função
68
- def __call__(self, text):
69
- # Dividindo o texto em tokens individuais e retornando uma lista dos IDs correspondentes
70
- return [self.encoder[t] for t in text.split()]
71
-
72
-
73
- # Cria o objeto do tokenizador
74
- tokenizer = DSATokenizer(vocab_size)
75
- # Decoder do tokenizador
76
- tokenizer.decoder
77
-
78
- # Testando o tokenizador
79
- tokenizer("1 + 1 = 2")
80
-
81
- # Definindo uma classe chamada CriaDataset, que herda da classe Dataset do PyTorch
82
- class CriaDataset(Dataset):
83
-
84
- # Método construtor da classe, que é executado quando um objeto dessa classe é criado
85
- def __init__(self, split, length = 6):
86
-
87
- # Verificando se a divisão do dataset (split) é 'treino' ou 'teste'
88
- assert split in {'treino', 'teste'}
89
- self.split = split
90
- self.length = length
91
-
92
- # Definindo o método len que retorna o tamanho do dataset.
93
- # Nesse caso, o tamanho é fixo e igual a 1 milhão.
94
- def __len__(self):
95
- return 1000000
96
-
97
- # Definindo o método getitem que é usado para obter um item específico do dataset
98
- def __getitem__(self, idx):
99
-
100
- # Criando uma lista com todos os números disponíveis que não são tokens de padding e são numéricos
101
- available_numbers = [int(n) for n in tokenizer.decoder.values() if n != tokenizer.pad_token and str(n).isnumeric()]
102
-
103
- # Selecionando aleatoriamente números da lista de números disponíveis para criar uma entrada (input)
104
- inp = torch.tensor(np.random.choice(available_numbers, size = result_length))
105
-
106
- # Calculando a soma dos números selecionados e criando um tensor
107
- sol = torch.tensor([int(i) for i in str(inp.sum().item())])
108
-
109
- # Preenchendo o tensor com zeros para que tenha o tamanho desejado
110
- sol = torch.nn.functional.pad(sol, (1 if sol.size()[0] == 1 else 0,0), 'constant', 0)
111
-
112
- # Concatenando a entrada e a solução em um tensor
113
- cat = torch.cat((inp, sol), dim = 0)
114
-
115
- # Criando os tensores de entrada e alvo para o treinamento do modelo
116
- x = cat[:-1].clone()
117
- y = cat[1:].clone()
118
-
119
- # Definindo o primeiro elemento do tensor alvo como o token de padding
120
- y[:1] = int(tokenizer.pad_token)
121
-
122
- # Transformando os tensores x e y em strings
123
- x = str(x[0].item()) + ' + ' + str(x[1].item()) + ' = ' + str(x[2].item())
124
- y = '-1 ' + str(y[0].item()) + ' -1 ' + str(y[1].item()) + ' ' + str(y[2].item())
125
-
126
- # Tokenizando as strings de entrada e alvo
127
- tokenized_input = tokenizer(x)
128
- tokenized_output = tokenizer(y)
129
-
130
- # Retornando os tensores de entrada e alvo como itens do dataset
131
- return torch.tensor(tokenized_input), torch.tensor(tokenized_output)
132
-
133
- dataset_treino = CriaDataset('treino', length = sequence_length)
134
- dataset_teste = CriaDataset('teste', length = sequence_length)
135
- x, y = dataset_treino[0]
136
- x
137
-
138
- y
139
-
140
- print(tokenizer.decode(x.numpy()))
141
- print(tokenizer.decode(y.numpy()))
142
-
143
- num_epochs = 2
144
- batch_size = 100
145
- optimizer = torch.optim.Adam(modelo.parameters())
146
- dados = torch.utils.data.DataLoader(dataset_treino, shuffle = True, batch_size = batch_size)
147
-
148
- import accelerate
149
- from accelerate import Accelerator
150
- accelerator = Accelerator()
151
-
152
- modelo, optimizer, dados = accelerator.prepare(modelo, optimizer, dados)
153
-
154
- modelo.train()
155
-
156
-
157
- # Iniciando o loop para as épocas de treinamento
158
- for epoch in range(num_epochs):
159
-
160
- # Iterando por cada batch (conjunto) de dados de entrada e alvos no dataset de treinamento
161
- for source, targets in dados:
162
-
163
- # Resetando os gradientes acumulados no otimizador
164
- optimizer.zero_grad()
165
-
166
- # Calculando a perda (loss) através da entropia cruzada entre as previsões do modelo e os alvos verdadeiros.
167
- # Os tensores são "achatados" para que possam ser passados para a função de entropia cruzada.
168
- # O índice do token de preenchimento (pad_token) é ignorado no cálculo da perda.
169
- loss = F.cross_entropy(modelo(source).logits.flatten(end_dim = 1),
170
- targets.flatten(end_dim = 1),
171
- ignore_index = tokenizer.pad_token_id)
172
-
173
- # Calculando os gradientes da perda em relação aos parâmetros do modelo
174
- accelerator.backward(loss)
175
-
176
- # Atualizando os parâmetros do modelo utilizando os gradientes calculados
177
- optimizer.step()
178
-
179
- # Recalculando a perda após a etapa de otimização.
180
- loss = F.cross_entropy(modelo(source).logits.flatten(end_dim = 1),
181
- targets.flatten(end_dim = 1),
182
- ignore_index = tokenizer.pad_token_id)
183
-
184
- # Imprimindo a época atual e a perda após cada época de treinamento
185
- print(f'Epoch: {epoch+1}/{num_epochs} --- Erro: {loss.item()}')
186
-
187
- # Definindo a função gera_solution com três parâmetros: input, solution_length e model
188
- def faz_previsao(entrada, solution_length = 6, model = modelo):
189
-
190
- # Colocando o modelo em modo de avaliação.
191
- model.eval()
192
-
193
- # Convertendo a entrada (string) em tensor utilizando o tokenizer.
194
- # O tensor é uma estrutura de dados que o modelo de aprendizado de máquina pode processar.
195
- entrada = torch.tensor(tokenizer(entrada))
196
-
197
- # Enviando o tensor de entrada para o dispositivo de cálculo disponível (CPU ou GPU)
198
- entrada = entrada.to(accelerator.device)
199
-
200
- # Iniciando uma lista vazia para armazenar a solução
201
- solution = []
202
-
203
- # Loop que gera a solução de comprimento solution_length
204
- for i in range(solution_length):
205
-
206
- # Alimentando a entrada atual ao modelo e obtendo a saída
207
- saida = model(entrada)
208
-
209
- # Pegando o índice do maior valor no último conjunto de logits (log-odds) da saída,
210
- # que é a previsão do modelo para o próximo token
211
- predicted = saida.logits[-1].argmax()
212
-
213
- # Concatenando a previsão atual com a entrada atual.
214
- # Isso servirá como a nova entrada para a próxima iteração.
215
- entrada = torch.cat((entrada, predicted.unsqueeze(0)), dim = 0)
216
-
217
- # Adicionando a previsão atual à lista de soluções e convertendo o tensor em um número Python padrão
218
- solution.append(predicted.cpu().item())
219
-
220
- # Decodificando a lista de soluções para obter a string de saída e retornando-a
221
- return tokenizer.decode(solution)
222
-
223
- # Definindo a função avalia_modelo com dois parâmetros: num_samples e log
224
- def avalia_modelo(num_samples = 1000, log = False):
225
-
226
- # Iniciando um contador para as previsões corretas
227
- correct = 0
228
-
229
- # Loop que itera num_samples vezes
230
- for i in range(num_samples):
231
-
232
- # Obtendo a entrada e o alvo (resposta correta) do i-ésimo exemplo do conjunto de teste
233
- entrada, target = dataset_teste[i]
234
-
235
- # Convertendo os tensores de entrada e alvo em arrays numpy para processamento posterior
236
- entrada = entrada.cpu().numpy()
237
- target = target.cpu().numpy()
238
-
239
- # Decodificando a entrada e o alvo utilizando o tokenizer
240
- entrada = tokenizer.decode(entrada[:sequence_length])
241
- target = tokenizer.decode(target[sequence_length-1:])
242
-
243
- # Gerando a previsão utilizando a função faz_previsao
244
- predicted = faz_previsao(entrada, solution_length = result_length, model = modelo)
245
-
246
- # Se a previsão for igual ao alvo, incrementa o contador de previsões corretas
247
- if target == predicted:
248
- correct += 1
249
- # Se log for True, imprime detalhes do exemplo e a previsão correta
250
- if log:
251
- print(f'Acerto do Modelo: Input: {entrada} Target: {target} Previsão: {predicted}')
252
- else:
253
- # Se log for True, imprime detalhes do exemplo e a previsão errada
254
- if log:
255
- print(f'Erro do Modelo: Input: {entrada} Target: {target} Previsão: {predicted}')
256
-
257
- # Ao final do loop, calcula a acurácia (número de previsões corretas dividido pelo número total de exemplos)
258
- print(f'Acurácia: {correct/num_samples}')
259
-
260
- # Executa a função
261
- avalia_modelo(num_samples = 10, log = True)
262
-
263
- # Executa a função
264
- avalia_modelo(num_samples = 1000, log = False)
265
-
266
- type(modelo)
267
-
268
- modelo.save_pretrained("modelos/modelo_final")
269
-
270
-
271
-
272
  modelo_llm = AutoModelForCausalLM.from_pretrained("modelos/modelo_final")
273
 
274
  # Definindo uma classe chamada NumberTokenizer, que é usada para tokenizar os números
 
7
  from transformers import AutoConfig, AutoModelForCausalLM, GPT2Tokenizer
8
  from transformers import GPT2Tokenizer
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  modelo_llm = AutoModelForCausalLM.from_pretrained("modelos/modelo_final")
11
 
12
  # Definindo uma classe chamada NumberTokenizer, que é usada para tokenizar os números