GPT1 – Improving Language Understanding by Generative Pre-Training

GPT1 – Improving Language Understanding by Generative Pre-Training GPT1 – Improving Language Understanding by Generative Pre-Training

GPT1 - Aprimorando a compreensão da linguagem por meio de pré-treinamento generativolink image 30

Papellink image 31

Este caderno foi traduzido automaticamente para torná-lo acessível a mais pessoas, por favor me avise se você vir algum erro de digitação..

[Improving Language Understanding by Generative Pre-Training] (https://s3-us-west-2.amazonaws.com/openai-assets/research-covers/language-unsupervised/language_understanding_paper.pdf) é o artigo GPT1. Antes de ler a postagem, é necessário se colocar na situação: antes do GPT, os modelos de linguagem eram baseados em redes recorrentes (RNN), que eram redes que funcionavam relativamente bem para tarefas específicas, mas com as quais não era possível reutilizar o pré-treinamento para fazer um ajuste fino para outras tarefas. Elas também não tinham muita memória, portanto, se você colocasse frases muito longas nelas, elas não se lembravam muito bem do início da frase.

Arquiteturalink image 32

Antes de falarmos sobre a arquitetura do GPT1, vamos nos lembrar de como era a arquitetura dos Transformers.

arquitetura do transformador

O GPT1 é um modelo baseado nos decodificadores de transformador, portanto, como não temos um codificador, a arquitetura de um único decodificador é a seguinte

arquitetura do decodificador

O mecanismo de atenção entre a sentença do codificador e do decodificador é eliminado.

No documento GPT1, eles propõem a seguinte arquitetura

arquitetura gpt1

O que corresponde ao decodificador de um transformador, como vimos anteriormente, executado 12 vezes.

Resumo do artigolink image 33

As ideias mais interessantes do artigo são:

  • O modelo é treinado em um grande corpus de texto não supervisionado. Isso cria um modelo de linguagem. Um modelo de linguagem de alta capacidade é criado em um grande corpus de texto.
  • O ajuste fino é então realizado em tarefas supervisionadas de NLP com conjuntos de dados rotulados. O ajuste fino é realizado em uma tarefa-alvo supervisionada. Além disso, quando o modelo é avaliado na tarefa supervisionada, ele não é avaliado apenas nessa tarefa, mas em quão bem ele prevê o próximo token, o que ajuda a aprimorar a generalização do modelo supervisionado e faz com que o modelo converse mais rapidamente.
  • Embora já tenhamos mencionado isso, o documento diz que a arquitetura do transformador é usada, já que até aquele momento os RNNs eram usados para os modelos de linguagem. Isso levou a uma melhoria no sentido de que o que foi aprendido no primeiro treinamento (treinamento no corpus de texto não supervisionado) é mais fácil de transferir para tarefas supervisionadas. Ou seja, graças ao uso de transformadores, foi possível treinar em um corpus inteiro de texto e depois fazer o ajuste fino em tarefas supervisionadas.
  • Eles testaram o modelo em quatro tipos de tarefas de compreensão de linguagem:
    • Inferência de linguagem natural
    • Resposta às perguntas
    • Similaridade semântica
    • Classificação de textos.
  • O modelo geral (aquele treinado em todo o corpus de texto não supervisionado) supera os modelos RNN treinados de forma discriminatória que empregam arquiteturas específicas de tarefas, melhorando significativamente o estado da arte em 9 das 12 tarefas estudadas. Eles também analisaram os comportamentos de "disparo zero" do modelo pré-treinado em quatro ambientes diferentes e mostraram que ele adquire conhecimento linguístico útil para tarefas subsequentes.
  • Nos últimos anos, os pesquisadores demonstraram os benefícios do uso de embeddings, que são treinados em corpora não rotulados, para melhorar o desempenho em várias tarefas. No entanto, essas abordagens transferem informações principalmente no nível da palavra, enquanto o uso de transformadores treinados em grandes corpora de texto não supervisionados captura a semântica de nível superior, no nível da frase.

Geração de textolink image 34

Vamos ver como gerar texto com um GPT1 pré-treinado.

Primeiro, você precisa instalar o ftfy e o spacy via

pip install ftfy spacy
      ```
      

Depois de instalado, você deve fazer o download do modelo de idioma spacy que deseja usar. Por exemplo, para fazer o download do modelo em inglês, você pode executar:

python -m spacy download en_core_web_sm
      ```
      

Para gerar texto, usaremos o modelo do repositório GPT1 do Hugging Face.

Importamos as bibliotecas

	
import torch
from transformers import OpenAIGPTTokenizer, OpenAIGPTLMHeadModel, AutoTokenizer
Copy

Se você notar, importamos o OpenAIGPTTokenizer e o AutoTokenizer. Isso ocorre porque no model card do GPT1 diz para usar o OpenAIGPTTokenizer, mas na postagem da biblioteca transformers explicamos que você deve usar o AutoTokenizer para carregar o tokenizador. Então, vamos tentar os dois

	
import torch
from transformers import OpenAIGPTTokenizer, OpenAIGPTLMHeadModel, AutoTokenizer
ckeckpoints = "openai-community/openai-gpt"
tokenizer = OpenAIGPTTokenizer.from_pretrained(ckeckpoints)
auto_tokenizer = AutoTokenizer.from_pretrained(ckeckpoints)
input_tokens = tokenizer("Hello, my dog is cute and", return_tensors="pt")
input_auto_tokens = auto_tokenizer("Hello, my dog is cute and", return_tensors="pt")
print(f"input tokens: {input_tokens}")
print(f"input auto tokens: {input_auto_tokens}")
Copy
	
input tokens:
{'input_ids': tensor([[3570, 240, 547, 2585, 544, 4957, 488]]), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1]])}
input auto tokens:
{'input_ids': tensor([[3570, 240, 547, 2585, 544, 4957, 488]]), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1]])}

Como você pode ver, com os dois tokenizadores você obtém os mesmos tokens. Portanto, para tornar o código mais geral, de modo que, se você alterar os pontos de verificação, não precisará alterar o código, vamos usar o AutoTokenizer.

Em seguida, criamos o dispositivo, o tokenizador e o modelo.

	
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
tokenizer = AutoTokenizer.from_pretrained(ckeckpoints)
model = OpenAIGPTLMHeadModel.from_pretrained(ckeckpoints).to(device)
Copy

Como instanciamos o modelo, vamos ver quantos parâmetros ele tem

	
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
tokenizer = AutoTokenizer.from_pretrained(ckeckpoints)
model = OpenAIGPTLMHeadModel.from_pretrained(ckeckpoints).to(device)
params = sum(p.numel() for p in model.parameters())
print(f"Number of parameters: {round(params/1e6)}M")
Copy
	
Number of parameters: 117M

Na era de bilhões de parâmetros, podemos ver que o GPT1 tinha apenas 117 milhões de parâmetros.

Criamos os tokens de entrada para o modelo

	
input_sentence = "Hello, my dog is cute and"
input_tokens = tokenizer(input_sentence, return_tensors="pt").to(device)
input_tokens
Copy
	
{'input_ids': tensor([[3570, 240, 547, 2585, 544, 4957, 488]], device='cuda:0'), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1]], device='cuda:0')}

Nós os passamos para o modelo para gerar os tokens de saída.

output_tokens = model.generate(**input_tokens)
      
      print(f"output tokens: \n{output_tokens}")
      
output tokens: 
      tensor([[ 3570,   240,   547,  2585,   544,  4957,   488,   249,   719,   797,
                 485,   921,   575,   562,   246,  1671,   239,   244, 40477,   244]],
             device='cuda:0')
      
/home/wallabot/miniconda3/envs/nlp/lib/python3.11/site-packages/transformers/generation/utils.py:1178: UserWarning: Using the model-agnostic default `max_length` (=20) to control the generation length. We recommend setting `max_new_tokens` to control the maximum length of the generation.
        warnings.warn(
      

Decodificamos os tokens para obter a declaração de saída

	
output_tokens = model.generate(**input_tokens)
print(f"output tokens: {output_tokens}")
decoded_output = tokenizer.decode(output_tokens[0], skip_special_tokens=True)
print(f"decoded output: {decoded_output}")
Copy
	
output tokens:
tensor([[ 3570, 240, 547, 2585, 544, 4957, 488, 249, 719, 797,
485, 921, 575, 562, 246, 1671, 239, 244, 40477, 244]],
device='cuda:0')
decoded output:
hello, my dog is cute and i'm going to take him for a walk. "
"

Já conseguimos gerar texto com o GPT1

Gerar token para o texto do tokenlink image 35

Usamos o model.generate para gerar os tokens de saída de uma só vez, mas vamos ver como gerá-los um a um. Para fazer isso, em vez de usar model.generate, usaremos model, que, na verdade, chama o método model.forward.

	
outputs = model(**input_tokens)
outputs
Copy
	
CausalLMOutput(loss=None, logits=tensor([[[ -5.9486, -5.8697, -18.4258, ..., -9.7371, -10.4495, 0.8814],
[ -6.1212, -4.8031, -14.3970, ..., -6.5411, -9.5051, -1.2015],
[ -7.4231, -6.3615, -14.7297, ..., -10.4575, -8.4600, -1.5183],
...,
[ -5.4751, -5.8803, -13.7767, ..., -10.5048, -12.4167, -6.1584],
[ -7.2052, -6.0198, -21.5040, ..., -16.2941, -14.0494, -1.2416],
[ -7.7240, -7.3631, -17.3174, ..., -12.1546, -12.3327, -1.7169]]],
device='cuda:0', grad_fn=<UnsafeViewBackward0>), hidden_states=None, attentions=None)

Vemos que isso gera muitos dados, mas primeiro vamos dar uma olhada nas chaves de saída.

	
outputs.keys()
Copy
	
odict_keys(['logits'])

Nesse caso, temos apenas os logits do modelo, vamos ver seu tamanho.

	
logits = outputs.logits
logits.shape
Copy
	
torch.Size([1, 7, 40478])

Vamos ver quantos tokens tínhamos na entrada.

	
input_tokens.input_ids.shape
Copy
	
torch.Size([1, 7])

Bem, temos o mesmo número de logits na saída e na entrada. Isso é normal

Obtemos os logits da última posição da saída

	
nex_token_logits = logits[0,-1]
nex_token_logits.shape
Copy
	
torch.Size([40478])

Há um total de 40478 logits, ou seja, há um vocabulário de 40478 tokens e temos que ver qual token tem a maior probabilidade.

	
softmax_logits = torch.softmax(nex_token_logits, dim=0)
softmax_logits.shape
Copy
	
torch.Size([40478])
	
next_token_prob, next_token_id = torch.max(softmax_logits, dim=0)
next_token_prob, next_token_id
Copy
	
(tensor(0.1898, device='cuda:0', grad_fn=<MaxBackward0>),
tensor(249, device='cuda:0'))

Obtivemos o seguinte token, agora vamos decodificá-lo

	
tokenizer.decode(next_token_id.item())
Copy
	
'i'

Obtivemos o seguinte token usando o método guloso, ou seja, o token com a maior probabilidade. Mas já vimos na postagem sobre a biblioteca de transformadores, as [formas de gerar textos] (https://maximofn.com/hugging-face-transformers/#Formas-de-generaci%C3%B3n-de-texto) que podem ser feitas por amostragem, top-k, top-p, etc.

Vamos colocar tudo em uma função e ver o que acontece se gerarmos alguns tokens.

	
def generate_next_greedy_token(input_sentence, tokenizer, model, device):
input_tokens = tokenizer(input_sentence, return_tensors="pt").to(device)
outputs = model(**input_tokens)
logits = outputs.logits
nex_token_logits = logits[0,-1]
softmax_logits = torch.softmax(nex_token_logits, dim=0)
next_token_prob, next_token_id = torch.max(softmax_logits, dim=0)
return next_token_prob, next_token_id
Copy
	
def generate_next_greedy_token(input_sentence, tokenizer, model, device):
input_tokens = tokenizer(input_sentence, return_tensors="pt").to(device)
outputs = model(**input_tokens)
logits = outputs.logits
nex_token_logits = logits[0,-1]
softmax_logits = torch.softmax(nex_token_logits, dim=0)
next_token_prob, next_token_id = torch.max(softmax_logits, dim=0)
return next_token_prob, next_token_id
def generate_greedy_text(input_sentence, tokenizer, model, device, max_length=20):
generated_text = input_sentence
for _ in range(max_length):
next_token_prob, next_token_id = generate_next_greedy_token(generated_text, tokenizer, model, device)
generated_text += tokenizer.decode(next_token_id.item())
return generated_text
Copy

Agora vamos gerar o texto

	
def generate_next_greedy_token(input_sentence, tokenizer, model, device):
input_tokens = tokenizer(input_sentence, return_tensors="pt").to(device)
outputs = model(**input_tokens)
logits = outputs.logits
nex_token_logits = logits[0,-1]
softmax_logits = torch.softmax(nex_token_logits, dim=0)
next_token_prob, next_token_id = torch.max(softmax_logits, dim=0)
return next_token_prob, next_token_id
def generate_greedy_text(input_sentence, tokenizer, model, device, max_length=20):
generated_text = input_sentence
for _ in range(max_length):
next_token_prob, next_token_id = generate_next_greedy_token(generated_text, tokenizer, model, device)
generated_text += tokenizer.decode(next_token_id.item())
return generated_text
generate_greedy_text("Hello, my dog is cute and", tokenizer, model, device)
Copy
	
'Hello, my dog is cute andi." '

O resultado é bastante repetitivo, como já foi visto em [ways to generate text] (https://maximofn.com/hugging-face-transformers/#Formas-de-generaci%C3%B3n-de-texto).

Ajuste fino do GPTlink image 37

Cálculo da perdalink image 38

Antes de começarmos a fazer o ajuste fino do GPT1, vamos dar uma olhada em um aspecto. Antes, quando costumávamos obter a saída do modelo, fazíamos o seguinte

	
outputs = model(**input_tokens)
outputs
Copy
	
CausalLMOutput(loss=None, logits=tensor([[[ -5.9486, -5.8697, -18.4258, ..., -9.7371, -10.4495, 0.8814],
[ -6.1212, -4.8031, -14.3970, ..., -6.5411, -9.5051, -1.2015],
[ -7.4231, -6.3615, -14.7297, ..., -10.4575, -8.4600, -1.5183],
...,
[ -5.4751, -5.8803, -13.7767, ..., -10.5048, -12.4167, -6.1584],
[ -7.2052, -6.0198, -21.5040, ..., -16.2941, -14.0494, -1.2416],
[ -7.7240, -7.3631, -17.3174, ..., -12.1546, -12.3327, -1.7169]]],
device='cuda:0', grad_fn=<UnsafeViewBackward0>), hidden_states=None, attentions=None)

Você pode ver que obtemos loss=None.

	
print(outputs.loss)
Copy
	
None

Como precisaremos da perda para fazer o ajuste fino, vamos ver como obtê-la.

Se consultarmos a documentação do método forward de OpenAIGPTLMHeadModel, veremos que ele diz que a saída retorna um objeto do tipo transformers.modeling_outputs.CausalLMOutput, portanto, se consultarmos a documentação de transformers.modeling_outputs.CausalLMOutput, veremos que ele diz que retorna loss se labels for passado para o método forward.

Se acessarmos o código-fonte do método forward, veremos este bloco de código

perda = Nenhuma
              se labels não for None:
                  # Deslocamento de modo que os tokens < n prevejam n
                  shift_logits = lm_logits[..., :-1, :].contiguous()
                  shift_labels = labels[..., 1:].contiguous()
                  # Achatar os tokens
                  loss_fct = CrossEntropyLoss()
                  loss = loss_fct(shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1))
      ```
      
      Em outras palavras, a "perda" é calculada da seguinte forma
      
       * Deslocamento de logits e rótulos: a primeira parte é deslocar logits (`lm_logits`) e rótulos (`labels`) para que `tokens < n` prevejam `n`, ou seja, a partir de uma posição `n`, o próximo token é previsto a partir dos anteriores.
       * CrossEntropyLoss: é criada uma instância da função de perda `CrossEntropyLoss()`.
       * Achatar tokens: os logits e os rótulos são achatados usando `view(-1, shift_logits.size(-1))` e `view(-1)`, respectivamente. Isso é feito para que os logits e os rótulos tenham a mesma forma para a função de perda.
       * Cálculo da perda: finalmente, a perda é calculada usando a função de perda `CrossEntropyLoss()` com os logits achatados e os rótulos achatados como entradas.
      
      Em resumo, a "perda" é calculada como a perda de entropia cruzada entre os logits deslocados e achatados e os rótulos deslocados e achatados.
      
      Portanto, se passarmos os rótulos para o método `forward`, ele retornará a `perda`.
      
	
outputs = model(**input_tokens, labels=input_tokens.input_ids)
outputs.loss
Copy
	
tensor(4.2607, device='cuda:0', grad_fn=<NllLossBackward0>)

Conjunto de dadoslink image 39

Para o treinamento, usaremos um conjunto de dados de piadas em inglês [short-jokes-dataset] (https://huggingface.co/datasets/Maximofn/short-jokes-dataset), que é um conjunto de dados com 231 mil piadas em inglês.

Baixamos o conjunto de dados

	
from datasets import load_dataset
jokes = load_dataset("Maximofn/short-jokes-dataset")
jokes
Copy
	
DatasetDict({
train: Dataset({
features: ['ID', 'Joke'],
num_rows: 231657
})
})

Vamos dar uma olhada nisso

	
jokes["train"][0]
Copy
	
{'ID': 1,
'Joke': '[me narrating a documentary about narrators] "I can't hear what they're saying cuz I'm talking"'}

Treinamento Pytorchlink image 40

Primeiro, vamos dar uma olhada em como o treinamento puro do Pytorch seria feito.

Reinicie o notebook para que não haja problemas de memória da GPU

	
import torch
from transformers import OpenAIGPTLMHeadModel, AutoTokenizer
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
ckeckpoints = "openai-community/openai-gpt"
tokenizer = AutoTokenizer.from_pretrained(ckeckpoints)
model = OpenAIGPTLMHeadModel.from_pretrained(ckeckpoints)
model = model.to(device)
Copy

Conjunto de dados Pytorchlink image 41

Criar uma classe de conjunto de dados do Pytorch

	
import torch
from transformers import OpenAIGPTLMHeadModel, AutoTokenizer
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
ckeckpoints = "openai-community/openai-gpt"
tokenizer = AutoTokenizer.from_pretrained(ckeckpoints)
model = OpenAIGPTLMHeadModel.from_pretrained(ckeckpoints)
model = model.to(device)
from torch.utils.data import Dataset
class JokesDataset(Dataset):
def __init__(self, dataset, tokenizer):
self.dataset = dataset
self.joke = "JOKE: "
self.end_of_text_token = "<|endoftext|>"
self.tokenizer = tokenizer
def __len__(self):
return len(self.dataset["train"])
def __getitem__(self, item):
sentence = self.joke + self.dataset["train"][item]["Joke"] + self.end_of_text_token
tokens = self.tokenizer(sentence, return_tensors="pt")
return sentence, tokens
Copy

Nós o instanciamos

	
import torch
from transformers import OpenAIGPTLMHeadModel, AutoTokenizer
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
ckeckpoints = "openai-community/openai-gpt"
tokenizer = AutoTokenizer.from_pretrained(ckeckpoints)
model = OpenAIGPTLMHeadModel.from_pretrained(ckeckpoints)
model = model.to(device)
from torch.utils.data import Dataset
class JokesDataset(Dataset):
def __init__(self, dataset, tokenizer):
self.dataset = dataset
self.joke = "JOKE: "
self.end_of_text_token = "<|endoftext|>"
self.tokenizer = tokenizer
def __len__(self):
return len(self.dataset["train"])
def __getitem__(self, item):
sentence = self.joke + self.dataset["train"][item]["Joke"] + self.end_of_text_token
tokens = self.tokenizer(sentence, return_tensors="pt")
return sentence, tokens
dataset = JokesDataset(jokes, tokenizer=tokenizer)
Copy

Aqui está um exemplo

sentence, tokens = dataset[5]
      print(sentence)
      tokens.input_ids.shape, tokens.attention_mask.shape
      
JOKE: Why can't Barbie get pregnant? Because Ken comes in a different box. Heyooooooo<|endoftext|>
      
Out[27]:
(torch.Size([1, 30]), torch.Size([1, 30]))

Dataloaderlink image 42

Agora, criamos um carregador de dados do Pytorch

	
import torch
from transformers import OpenAIGPTLMHeadModel, AutoTokenizer
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
ckeckpoints = "openai-community/openai-gpt"
tokenizer = AutoTokenizer.from_pretrained(ckeckpoints)
model = OpenAIGPTLMHeadModel.from_pretrained(ckeckpoints)
model = model.to(device)
from torch.utils.data import Dataset
class JokesDataset(Dataset):
def __init__(self, dataset, tokenizer):
self.dataset = dataset
self.joke = "JOKE: "
self.end_of_text_token = "<|endoftext|>"
self.tokenizer = tokenizer
def __len__(self):
return len(self.dataset["train"])
def __getitem__(self, item):
sentence = self.joke + self.dataset["train"][item]["Joke"] + self.end_of_text_token
tokens = self.tokenizer(sentence, return_tensors="pt")
return sentence, tokens
dataset = JokesDataset(jokes, tokenizer=tokenizer)
sentence, tokens = dataset[5]
print(sentence)
tokens.input_ids.shape, tokens.attention_mask.shape
from torch.utils.data import DataLoader
BS = 1
joke_dataloader = DataLoader(dataset, batch_size=BS, shuffle=True)
Copy

Vemos um lote

	
import torch
from transformers import OpenAIGPTLMHeadModel, AutoTokenizer
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
ckeckpoints = "openai-community/openai-gpt"
tokenizer = AutoTokenizer.from_pretrained(ckeckpoints)
model = OpenAIGPTLMHeadModel.from_pretrained(ckeckpoints)
model = model.to(device)
from torch.utils.data import Dataset
class JokesDataset(Dataset):
def __init__(self, dataset, tokenizer):
self.dataset = dataset
self.joke = "JOKE: "
self.end_of_text_token = "<|endoftext|>"
self.tokenizer = tokenizer
def __len__(self):
return len(self.dataset["train"])
def __getitem__(self, item):
sentence = self.joke + self.dataset["train"][item]["Joke"] + self.end_of_text_token
tokens = self.tokenizer(sentence, return_tensors="pt")
return sentence, tokens
dataset = JokesDataset(jokes, tokenizer=tokenizer)
sentence, tokens = dataset[5]
print(sentence)
tokens.input_ids.shape, tokens.attention_mask.shape
from torch.utils.data import DataLoader
BS = 1
joke_dataloader = DataLoader(dataset, batch_size=BS, shuffle=True)
sentences, tokens = next(iter(joke_dataloader))
len(sentences), tokens.input_ids.shape, tokens.attention_mask.shape
Copy
	
JOKE: Why can't Barbie get pregnant? Because Ken comes in a different box. Heyooooooo<|endoftext|>
(1, torch.Size([1, 1, 29]), torch.Size([1, 1, 29]))

Treinamentolink image 43

from transformers import AdamW, get_linear_schedule_with_warmup
      import tqdm
      
      BATCH_SIZE = 32
      EPOCHS = 5
      LEARNING_RATE = 3e-5
      WARMUP_STEPS = 5000
      MAX_SEQ_LEN = 500
      
      model.train()
      optimizer = AdamW(model.parameters(), lr=LEARNING_RATE)
      scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps=WARMUP_STEPS, num_training_steps=-1)
      proc_seq_count = 0
      batch_count = 0
      
      tmp_jokes_tens = None
      
      for epoch in range(EPOCHS):
          
          print(f"EPOCH {epoch} started" + '=' * 30)
          progress_bar = tqdm.tqdm(joke_dataloader, desc="Training")
          
          for sample in progress_bar:
      
              sentence, tokens = sample
              
              #################### "Fit as many joke sequences into MAX_SEQ_LEN sequence as possible" logic start ####
              joke_tens = tokens.input_ids[0].to(device)
      
              # Skip sample from dataset if it is longer than MAX_SEQ_LEN
              if joke_tens.size()[1] > MAX_SEQ_LEN:
                  continue
              
              # The first joke sequence in the sequence
              if not torch.is_tensor(tmp_jokes_tens):
                  tmp_jokes_tens = joke_tens
                  continue
              else:
                  # The next joke does not fit in so we process the sequence and leave the last joke 
                  # as the start for next sequence 
                  if tmp_jokes_tens.size()[1] + joke_tens.size()[1] > MAX_SEQ_LEN:
                      work_jokes_tens = tmp_jokes_tens
                      tmp_jokes_tens = joke_tens
                  else:
                      #Add the joke to sequence, continue and try to add more
                      tmp_jokes_tens = torch.cat([tmp_jokes_tens, joke_tens[:,1:]], dim=1)
                      continue
              ################## Sequence ready, process it trough the model ##################
                  
              outputs = model(work_jokes_tens, labels=work_jokes_tens)
              loss = outputs.loss
              loss.backward()
                             
              proc_seq_count = proc_seq_count + 1
              if proc_seq_count == BATCH_SIZE:
                  proc_seq_count = 0    
                  batch_count += 1
                  optimizer.step()
                  scheduler.step() 
                  optimizer.zero_grad()
                  model.zero_grad()
      
              progress_bar.set_postfix({'loss': loss.item(), 'lr': scheduler.get_last_lr()[0]})
              if batch_count == 10:
                  batch_count = 0
      
/home/wallabot/miniconda3/envs/nlp/lib/python3.11/site-packages/transformers/optimization.py:429: FutureWarning: This implementation of AdamW is deprecated and will be removed in a future version. Use the PyTorch implementation torch.optim.AdamW instead, or set `no_deprecation_warning=True` to disable this warning
        warnings.warn(
      
EPOCH 0 started==============================
      
Training: 100%|██████████| 231657/231657 [11:31<00:00, 334.88it/s, loss=2.88, lr=2.93e-6]
      
EPOCH 1 started==============================
      
Training: 100%|██████████| 231657/231657 [11:30<00:00, 335.27it/s, loss=2.49, lr=5.87e-6]
      
EPOCH 2 started==============================
      
Training: 100%|██████████| 231657/231657 [11:17<00:00, 341.75it/s, loss=2.57, lr=8.81e-6]
      
EPOCH 3 started==============================
      
Training: 100%|██████████| 231657/231657 [11:18<00:00, 341.27it/s, loss=2.41, lr=1.18e-5]
      
EPOCH 4 started==============================
      
Training: 100%|██████████| 231657/231657 [11:19<00:00, 341.04it/s, loss=2.49, lr=1.47e-5]
      

Inferêncialink image 44

Vamos ver como o modelo faz piadas.

	
from transformers import AdamW, get_linear_schedule_with_warmup
import tqdm
BATCH_SIZE = 32
EPOCHS = 5
LEARNING_RATE = 3e-5
WARMUP_STEPS = 5000
MAX_SEQ_LEN = 500
model.train()
optimizer = AdamW(model.parameters(), lr=LEARNING_RATE)
scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps=WARMUP_STEPS, num_training_steps=-1)
proc_seq_count = 0
batch_count = 0
tmp_jokes_tens = None
for epoch in range(EPOCHS):
print(f"EPOCH {epoch} started" + '=' * 30)
progress_bar = tqdm.tqdm(joke_dataloader, desc="Training")
for sample in progress_bar:
sentence, tokens = sample
#################### "Fit as many joke sequences into MAX_SEQ_LEN sequence as possible" logic start ####
joke_tens = tokens.input_ids[0].to(device)
# Skip sample from dataset if it is longer than MAX_SEQ_LEN
if joke_tens.size()[1] > MAX_SEQ_LEN:
continue
# The first joke sequence in the sequence
if not torch.is_tensor(tmp_jokes_tens):
tmp_jokes_tens = joke_tens
continue
else:
# The next joke does not fit in so we process the sequence and leave the last joke
# as the start for next sequence
if tmp_jokes_tens.size()[1] + joke_tens.size()[1] > MAX_SEQ_LEN:
work_jokes_tens = tmp_jokes_tens
tmp_jokes_tens = joke_tens
else:
#Add the joke to sequence, continue and try to add more
tmp_jokes_tens = torch.cat([tmp_jokes_tens, joke_tens[:,1:]], dim=1)
continue
################## Sequence ready, process it trough the model ##################
outputs = model(work_jokes_tens, labels=work_jokes_tens)
loss = outputs.loss
loss.backward()
proc_seq_count = proc_seq_count + 1
if proc_seq_count == BATCH_SIZE:
proc_seq_count = 0
batch_count += 1
optimizer.step()
scheduler.step()
optimizer.zero_grad()
model.zero_grad()
progress_bar.set_postfix({'loss': loss.item(), 'lr': scheduler.get_last_lr()[0]})
if batch_count == 10:
batch_count = 0
sentence_joke = "JOKE:"
input_tokens_joke = tokenizer(sentence_joke, return_tensors="pt").to(device)
output_tokens_joke = model.generate(**input_tokens_joke)
decoded_output_joke = tokenizer.decode(output_tokens_joke[0], skip_special_tokens=True)
print(f"decoded joke: {decoded_output_joke}")
Copy
	
/home/wallabot/miniconda3/envs/nlp/lib/python3.11/site-packages/transformers/optimization.py:429: FutureWarning: This implementation of AdamW is deprecated and will be removed in a future version. Use the PyTorch implementation torch.optim.AdamW instead, or set `no_deprecation_warning=True` to disable this warning
warnings.warn(
decoded joke:
joke : what do you call a group of people who are not afraid of the dark? a group

Você pode ver que você passa uma sequência com a palavra joke e ele retorna uma piada. Mas se você retornar outra string, ela não retornará

	
sentence_joke = "My dog is cute and"
input_tokens_joke = tokenizer(sentence_joke, return_tensors="pt").to(device)
output_tokens_joke = model.generate(**input_tokens_joke)
decoded_output_joke = tokenizer.decode(output_tokens_joke[0], skip_special_tokens=True)
print(f"decoded joke: {decoded_output_joke}")
Copy
	
decoded joke:
my dog is cute and i'm not sure if i should be offended or not. "

Continuar lendo

DoLa – Decoding by Contrasting Layers Improves Factuality in Large Language Models

DoLa – Decoding by Contrasting Layers Improves Factuality in Large Language Models

Você já conversou com um LLM e ele lhe respondeu algo que parece ter bebido café de máquina a noite toda? 😂 Isso é o que chamamos de alucinação no mundo dos LLMs! Mas não se preocupe, pois não é que seu modelo de linguagem esteja louco (embora às vezes possa parecer isso 🤪). A verdade é que os LLMs podem ser um pouco... criativos quando se trata de gerar texto. Mas graças ao DoLa, um método que usa camadas de contraste para melhorar a viabilidade dos LLMs, podemos evitar que nossos modelos de linguagem se transformem em escritores de ficção científica 😂. Nesta publicação, explicarei como o DoLa funciona e mostrarei um exemplo de código para que você possa entender melhor como tornar seus LLMs mais confiáveis e menos propensos a inventar histórias. Vamos salvar nossos LLMs da loucura e torná-los mais úteis! 🚀

Últimos posts -->

Você viu esses projetos?

Subtify

Subtify Subtify

Gerador de legendas para vídeos no idioma que você desejar. Além disso, coloca uma legenda de cor diferente para cada pessoa

Ver todos os projetos -->

Quer aplicar IA no seu projeto? Entre em contato!

Quer melhorar com essas dicas?

Últimos tips -->

Use isso localmente

Os espaços do Hugging Face nos permitem executar modelos com demos muito simples, mas e se a demo quebrar? Ou se o usuário a deletar? Por isso, criei contêineres docker com alguns espaços interessantes, para poder usá-los localmente, aconteça o que acontecer. Na verdade, se você clicar em qualquer botão de visualização de projeto, ele pode levá-lo a um espaço que não funciona.

Ver todos os contêineres -->

Quer aplicar IA no seu projeto? Entre em contato!

Você quer treinar seu modelo com esses datasets?

short-jokes-dataset

Dataset com piadas em inglês

opus100

Dataset com traduções de inglês para espanhol

netflix_titles

Dataset com filmes e séries da Netflix

Ver mais datasets -->