Fine tuning SMLs

Fine tuning SMLs Fine tuning SMLs

Ajuste fino de SMLs com Hugging Facelink image 80

Nesta postagem, veremos como ajustar modelos de linguagem pequenos, como ajustar a classificação de texto e a geração de texto. Primeiro, veremos como fazer isso com as bibliotecas da Hugging Face, já que a Hugging Face se tornou um participante muito importante no ecossistema de IA atualmente.

Mas, embora as bibliotecas do Hugging Face sejam muito importantes e úteis, é muito importante saber como o treinamento é realmente feito e o que está acontecendo por trás dele, portanto, vamos repetir o treinamento para classificação e geração de texto, mas com o Pytorch.

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..

Ajuste fino para classificação de texto com o Hugging Facelink image 81

Loginlink image 82

Para fazer upload do resultado do treinamento no hub, primeiro precisamos fazer login e, para isso, precisamos de um token.

Para criar um token, acesse a página setings/tokens de sua conta, que terá a seguinte aparência

User-Access-Token-dark](https://pub-fb664c455eca46a2ba762a065ac900f7.r2.dev/User-Access-Token-dark.webp)

Clique em New token e será exibida uma janela para criar um novo token.

new-token-dark

Nomeamos o token e o criamos com a função write ou com a função Fine-grained, que nos permite selecionar exatamente quais permissões o token terá.

Depois de criado, copiamos e colamos o arquivo abaixo

	
from huggingface_hub import notebook_login
notebook_login()
Copy

Conjunto de dadoslink image 83

Agora, faremos o download de um conjunto de dados. Neste caso, faremos o download de um conjunto de dados de avaliações da Amazon

	
from huggingface_hub import notebook_login
notebook_login()
from datasets import load_dataset
dataset = load_dataset("mteb/amazon_reviews_multi", "en")
Copy

Vamos dar uma olhada nisso

	
from huggingface_hub import notebook_login
notebook_login()
from datasets import load_dataset
dataset = load_dataset("mteb/amazon_reviews_multi", "en")
dataset
Copy
	
DatasetDict({
train: Dataset({
features: ['id', 'text', 'label', 'label_text'],
num_rows: 200000
})
validation: Dataset({
features: ['id', 'text', 'label', 'label_text'],
num_rows: 5000
})
test: Dataset({
features: ['id', 'text', 'label', 'label_text'],
num_rows: 5000
})
})

Vemos que você tem um conjunto de treinamento com 200.000 amostras, um conjunto de validação com 5.000 amostras e um conjunto de teste com 5.000 amostras.

Vamos dar uma olhada em um exemplo do conjunto de treinamento

	
from random import randint
idx = randint(0, len(dataset['train']) - 1)
dataset['train'][idx]
Copy
	
{'id': 'en_0907914',
'text': 'Mixed with fir it’s passable Not the scent I had hoped for . Love the scent of cedar, but this one missed',
'label': 3,
'label_text': '3'}

Vemos que você tem a avaliação no campo text e a pontuação dada pelo usuário no campo label.

Como vamos criar um modelo de classificação de texto, precisamos saber quantas classes teremos.

	
num_classes = len(dataset['train'].unique('label'))
num_classes
Copy
	
5

Teremos 5 classes, agora vamos ver o valor mínimo dessas classes para saber se a pontuação começa em 0 ou 1. Para isso, usamos o método unique

	
dataset.unique('label')
Copy
	
{'train': [0, 1, 2, 3, 4],
'validation': [0, 1, 2, 3, 4],
'test': [0, 1, 2, 3, 4]}

O valor mínimo será 0

Para o treinamento, os rótulos precisam estar em um campo chamado labels, enquanto em nosso conjunto de dados eles estão em um campo chamado label, portanto, criamos o novo campo lables com o mesmo valor de label.

Criamos uma função que faz o que queremos

	
def set_labels(example):
example['labels'] = example['label']
return example
Copy

Aplicamos a função ao conjunto de dados

	
def set_labels(example):
example['labels'] = example['label']
return example
dataset = dataset.map(set_labels)
Copy

Vejamos como é o conjunto de dados

	
def set_labels(example):
example['labels'] = example['label']
return example
dataset = dataset.map(set_labels)
dataset['train'][idx]
Copy
	
{'id': 'en_0907914',
'text': 'Mixed with fir it’s passable Not the scent I had hoped for . Love the scent of cedar, but this one missed',
'label': 3,
'label_text': '3',
'labels': 3}

Tokeniserlink image 84

Como temos revisões de texto no conjunto de dados, precisamos tokenizá-las para colocar os tokens no modelo.

	
from transformers import AutoTokenizer
checkpoint = "openai-community/gpt2"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
Copy

Agora criamos uma função para tokenizar o texto. Vamos fazer com que todas as frases tenham o mesmo comprimento, de modo que o tokenizador truncará quando necessário e adicionará tokens de preenchimento quando necessário. Também pedimos que ele retorne tensores pytorch.

O comprimento de cada frase é de 768 tokens porque estamos usando o modelo GPT2 pequeno, que, como vimos na postagem GPT2, tem uma dimensão de incorporação de 768 tokens.

	
from transformers import AutoTokenizer
checkpoint = "openai-community/gpt2"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
def tokenize_function(examples):
return tokenizer(examples["text"], padding="max_length", truncation=True, max_length=768, return_tensors="pt")
Copy

Vamos tentar tokenizar um texto

	
from transformers import AutoTokenizer
checkpoint = "openai-community/gpt2"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
def tokenize_function(examples):
return tokenizer(examples["text"], padding="max_length", truncation=True, max_length=768, return_tensors="pt")
tokens = tokenize_function(dataset['train'][idx])
Copy
	
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[11], line 1
----> 1 tokens = tokenize_function(dataset['train'][idx])
Cell In[10], line 2, in tokenize_function(examples)
1 def tokenize_function(examples):
----> 2 return tokenizer(examples["text"], padding="max_length", truncation=True, max_length=768, return_tensors="pt")
File ~/miniconda3/envs/nlp_/lib/python3.11/site-packages/transformers/tokenization_utils_base.py:2883, in PreTrainedTokenizerBase.__call__(self, text, text_pair, text_target, text_pair_target, add_special_tokens, padding, truncation, max_length, stride, is_split_into_words, pad_to_multiple_of, return_tensors, return_token_type_ids, return_attention_mask, return_overflowing_tokens, return_special_tokens_mask, return_offsets_mapping, return_length, verbose, **kwargs)
2881 if not self._in_target_context_manager:
2882 self._switch_to_input_mode()
-> 2883 encodings = self._call_one(text=text, text_pair=text_pair, **all_kwargs)
2884 if text_target is not None:
2885 self._switch_to_target_mode()
File ~/miniconda3/envs/nlp_/lib/python3.11/site-packages/transformers/tokenization_utils_base.py:2989, in PreTrainedTokenizerBase._call_one(self, text, text_pair, add_special_tokens, padding, truncation, max_length, stride, is_split_into_words, pad_to_multiple_of, return_tensors, return_token_type_ids, return_attention_mask, return_overflowing_tokens, return_special_tokens_mask, return_offsets_mapping, return_length, verbose, **kwargs)
2969 return self.batch_encode_plus(
2970 batch_text_or_text_pairs=batch_text_or_text_pairs,
2971 add_special_tokens=add_special_tokens,
(...)
2986 **kwargs,
2987 )
2988 else:
-> 2989 return self.encode_plus(
2990 text=text,
2991 text_pair=text_pair,
2992 add_special_tokens=add_special_tokens,
2993 padding=padding,
2994 truncation=truncation,
2995 max_length=max_length,
2996 stride=stride,
2997 is_split_into_words=is_split_into_words,
2998 pad_to_multiple_of=pad_to_multiple_of,
2999 return_tensors=return_tensors,
3000 return_token_type_ids=return_token_type_ids,
3001 return_attention_mask=return_attention_mask,
3002 return_overflowing_tokens=return_overflowing_tokens,
3003 return_special_tokens_mask=return_special_tokens_mask,
3004 return_offsets_mapping=return_offsets_mapping,
3005 return_length=return_length,
3006 verbose=verbose,
3007 **kwargs,
3008 )
File ~/miniconda3/envs/nlp_/lib/python3.11/site-packages/transformers/tokenization_utils_base.py:3053, in PreTrainedTokenizerBase.encode_plus(self, text, text_pair, add_special_tokens, padding, truncation, max_length, stride, is_split_into_words, pad_to_multiple_of, return_tensors, return_token_type_ids, return_attention_mask, return_overflowing_tokens, return_special_tokens_mask, return_offsets_mapping, return_length, verbose, **kwargs)
3032 """
3033 Tokenize and prepare for the model a sequence or a pair of sequences.
3034
(...)
3049 method).
3050 """
3052 # Backward compatibility for 'truncation_strategy', 'pad_to_max_length'
-> 3053 padding_strategy, truncation_strategy, max_length, kwargs = self._get_padding_truncation_strategies(
3054 padding=padding,
3055 truncation=truncation,
3056 max_length=max_length,
3057 pad_to_multiple_of=pad_to_multiple_of,
3058 verbose=verbose,
3059 **kwargs,
3060 )
3062 return self._encode_plus(
3063 text=text,
3064 text_pair=text_pair,
(...)
3080 **kwargs,
3081 )
File ~/miniconda3/envs/nlp_/lib/python3.11/site-packages/transformers/tokenization_utils_base.py:2788, in PreTrainedTokenizerBase._get_padding_truncation_strategies(self, padding, truncation, max_length, pad_to_multiple_of, verbose, **kwargs)
2786 # Test if we have a padding token
2787 if padding_strategy != PaddingStrategy.DO_NOT_PAD and (self.pad_token is None or self.pad_token_id < 0):
-> 2788 raise ValueError(
2789 "Asking to pad but the tokenizer does not have a padding token. "
2790 "Please select a token to use as `pad_token` `(tokenizer.pad_token = tokenizer.eos_token e.g.)` "
2791 "or add a new pad token via `tokenizer.add_special_tokens({'pad_token': '[PAD]'})`."
2792 )
2794 # Check that we will truncate to a multiple of pad_to_multiple_of if both are provided
2795 if (
2796 truncation_strategy != TruncationStrategy.DO_NOT_TRUNCATE
2797 and padding_strategy != PaddingStrategy.DO_NOT_PAD
(...)
2800 and (max_length % pad_to_multiple_of != 0)
2801 ):
ValueError: Asking to pad but the tokenizer does not have a padding token. Please select a token to use as `pad_token` `(tokenizer.pad_token = tokenizer.eos_token e.g.)` or add a new pad token via `tokenizer.add_special_tokens({'pad_token': '[PAD]'})`.

Recebemos um erro porque o tokenizador GPT2 não tem um token para preenchimento e nos pede para atribuir um, sugerindo que façamos tokenizer.pad_token = tokenizer.eos_token, e assim o fazemos.

	
tokenizer.pad_token = tokenizer.eos_token
Copy

Testamos novamente a função de tokenização.

	
tokenizer.pad_token = tokenizer.eos_token
tokens = tokenize_function(dataset['train'][idx])
tokens['input_ids'].shape, tokens['attention_mask'].shape
Copy
	
(torch.Size([1, 768]), torch.Size([1, 768]))

Agora que verificamos que a função tokeniza bem, aplicamos essa função ao conjunto de dados, mas também a aplicamos em lotes para que seja executada mais rapidamente.

Também tiramos proveito disso e eliminamos as colunas que não são necessárias.

	
dataset = dataset.map(tokenize_function, batched=True, remove_columns=['text', 'label', 'id', 'label_text'])
Copy

Agora vamos ver como é o conjunto de dados

	
dataset = dataset.map(tokenize_function, batched=True, remove_columns=['text', 'label', 'id', 'label_text'])
dataset
Copy
	
DatasetDict({
train: Dataset({
features: ['id', 'text', 'label', 'label_text', 'labels'],
num_rows: 200000
})
validation: Dataset({
features: ['id', 'text', 'label', 'label_text', 'labels'],
num_rows: 5000
})
test: Dataset({
features: ['id', 'text', 'label', 'label_text', 'labels'],
num_rows: 5000
})
})

Vemos que temos os campos "labels" (rótulos), "input_ids" (IDs de entrada) e "attention_mask" (máscara de atenção), que é o que nos interessa treinar.

Modelolink image 85

Instanciamos um modelo para classificação de sequências e informamos a ele o número de classes que temos.

	
from transformers import AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=num_classes)
Copy
	
Some weights of GPT2ForSequenceClassification were not initialized from the model checkpoint at openai-community/gpt2 and are newly initialized: ['score.weight']
You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.

Ele nos informa que os pesos da camada score foram inicializados aleatoriamente e que precisamos treiná-los novamente.

O modelo GPT2 teria a seguinte aparência

	
from transformers import AutoModelForCausalLM
casual_model = AutoModelForCausalLM.from_pretrained(checkpoint)
Copy

Enquanto o modelo GPT2 para gerar texto é o seguinte

Vamos dar uma olhada em sua arquitetura

	
from transformers import AutoModelForCausalLM
casual_model = AutoModelForCausalLM.from_pretrained(checkpoint)
casual_model
Copy
	
GPT2LMHeadModel(
(transformer): GPT2Model(
(wte): Embedding(50257, 768)
(wpe): Embedding(1024, 768)
(drop): Dropout(p=0.1, inplace=False)
(h): ModuleList(
(0-11): 12 x GPT2Block(
(ln_1): LayerNorm((768,), eps=1e-05, elementwise_affine=True)
(attn): GPT2Attention(
(c_attn): Conv1D()
(c_proj): Conv1D()
(attn_dropout): Dropout(p=0.1, inplace=False)
(resid_dropout): Dropout(p=0.1, inplace=False)
)
(ln_2): LayerNorm((768,), eps=1e-05, elementwise_affine=True)
(mlp): GPT2MLP(
(c_fc): Conv1D()
(c_proj): Conv1D()
(act): NewGELUActivation()
(dropout): Dropout(p=0.1, inplace=False)
)
)
)
(ln_f): LayerNorm((768,), eps=1e-05, elementwise_affine=True)
)
(lm_head): Linear(in_features=768, out_features=50257, bias=False)
)

E agora a arquitetura do modelo que usaremos para classificar as avaliações.

	
model
Copy
	
GPT2ForSequenceClassification(
(transformer): GPT2Model(
(wte): Embedding(50257, 768)
(wpe): Embedding(1024, 768)
(drop): Dropout(p=0.1, inplace=False)
(h): ModuleList(
(0-11): 12 x GPT2Block(
(ln_1): LayerNorm((768,), eps=1e-05, elementwise_affine=True)
(attn): GPT2Attention(
(c_attn): Conv1D()
(c_proj): Conv1D()
(attn_dropout): Dropout(p=0.1, inplace=False)
(resid_dropout): Dropout(p=0.1, inplace=False)
)
(ln_2): LayerNorm((768,), eps=1e-05, elementwise_affine=True)
(mlp): GPT2MLP(
(c_fc): Conv1D()
(c_proj): Conv1D()
(act): NewGELUActivation()
(dropout): Dropout(p=0.1, inplace=False)
)
)
)
(ln_f): LayerNorm((768,), eps=1e-05, elementwise_affine=True)
)
(score): Linear(in_features=768, out_features=5, bias=False)
)

Há dois aspectos a serem mencionados aqui

  • A primeira é que, em ambas, a primeira camada tem dimensões de 50257x768, o que corresponde a 50257 tokens possíveis do vocabulário GPT2 e 768 dimensões da incorporação, portanto, fizemos bem em tokenizar as avaliações com um tamanho de 768 tokens.
  • A segunda é que o modelo casual (o modelo de geração de texto) tem, no final, uma camada Linear que gera 50257 valores, ou seja, é responsável por prever o próximo token e atribui um valor a cada token possível. Já o modelo de classificação tem uma camada Linear que gera apenas 5 valores, um para cada classe, o que nos dará a probabilidade de a avaliação pertencer a cada classe.

É por isso que recebemos a mensagem de que os pesos da camada score foram inicializados aleatoriamente, porque a biblioteca de transformadores removeu a camada Linear de 768x50257 e adicionou uma camada Linear de 768x5, inicializou-a com valores aleatórios e precisamos treiná-la para nosso problema específico.

Excluímos o modelo casual, porque não vamos usá-lo.

	
del casual_model
Copy

Treinadorlink image 86

Vamos agora configurar os argumentos de treinamento

	
del casual_model
from transformers import TrainingArguments
metric_name = "accuracy"
model_name = "GPT2-small-finetuned-amazon-reviews-en-classification"
LR = 2e-5
BS_TRAIN = 28
BS_EVAL = 40
EPOCHS = 3
WEIGHT_DECAY = 0.01
training_args = TrainingArguments(
model_name,
eval_strategy="epoch",
save_strategy="epoch",
learning_rate=LR,
per_device_train_batch_size=BS_TRAIN,
per_device_eval_batch_size=BS_EVAL,
num_train_epochs=EPOCHS,
weight_decay=WEIGHT_DECAY,
lr_scheduler_type="cosine",
warmup_ratio = 0.1,
fp16=True,
load_best_model_at_end=True,
metric_for_best_model=metric_name,
push_to_hub=True,
)
Copy

Definir uma métrica para o carregador de dados de validação

	
del casual_model
from transformers import TrainingArguments
metric_name = "accuracy"
model_name = "GPT2-small-finetuned-amazon-reviews-en-classification"
LR = 2e-5
BS_TRAIN = 28
BS_EVAL = 40
EPOCHS = 3
WEIGHT_DECAY = 0.01
training_args = TrainingArguments(
model_name,
eval_strategy="epoch",
save_strategy="epoch",
learning_rate=LR,
per_device_train_batch_size=BS_TRAIN,
per_device_eval_batch_size=BS_EVAL,
num_train_epochs=EPOCHS,
weight_decay=WEIGHT_DECAY,
lr_scheduler_type="cosine",
warmup_ratio = 0.1,
fp16=True,
load_best_model_at_end=True,
metric_for_best_model=metric_name,
push_to_hub=True,
)
import numpy as np
from evaluate import load
metric = load("accuracy")
def compute_metrics(eval_pred):
print(eval_pred)
predictions, labels = eval_pred
predictions = np.argmax(predictions, axis=1)
return metric.compute(predictions=predictions, references=labels)
Copy

Agora definimos o treinador

	
del casual_model
from transformers import TrainingArguments
metric_name = "accuracy"
model_name = "GPT2-small-finetuned-amazon-reviews-en-classification"
LR = 2e-5
BS_TRAIN = 28
BS_EVAL = 40
EPOCHS = 3
WEIGHT_DECAY = 0.01
training_args = TrainingArguments(
model_name,
eval_strategy="epoch",
save_strategy="epoch",
learning_rate=LR,
per_device_train_batch_size=BS_TRAIN,
per_device_eval_batch_size=BS_EVAL,
num_train_epochs=EPOCHS,
weight_decay=WEIGHT_DECAY,
lr_scheduler_type="cosine",
warmup_ratio = 0.1,
fp16=True,
load_best_model_at_end=True,
metric_for_best_model=metric_name,
push_to_hub=True,
)
import numpy as np
from evaluate import load
metric = load("accuracy")
def compute_metrics(eval_pred):
print(eval_pred)
predictions, labels = eval_pred
predictions = np.argmax(predictions, axis=1)
return metric.compute(predictions=predictions, references=labels)
from transformers import Trainer
trainer = Trainer(
model,
training_args,
train_dataset=dataset['train'],
eval_dataset=dataset['validation'],
tokenizer=tokenizer,
compute_metrics=compute_metrics,
)
Copy

Treinamos

trainer.train()
      
  0%|          | 0/600000 [00:00<?, ?it/s]
      ---------------------------------------------------------------------------
      ValueError                                Traceback (most recent call last)
      Cell In[21], line 1
      ----> 1 trainer.train()
      
      File ~/miniconda3/envs/nlp_/lib/python3.11/site-packages/transformers/trainer.py:1876, in Trainer.train(self, resume_from_checkpoint, trial, ignore_keys_for_eval, **kwargs)
         1873 try:
         1874     # Disable progress bars when uploading models during checkpoints to avoid polluting stdout
         1875     hf_hub_utils.disable_progress_bars()
      -> 1876     return inner_training_loop(
         1877         args=args,
         1878         resume_from_checkpoint=resume_from_checkpoint,
         1879         trial=trial,
         1880         ignore_keys_for_eval=ignore_keys_for_eval,
         1881     )
         1882 finally:
         1883     hf_hub_utils.enable_progress_bars()
      
      File ~/miniconda3/envs/nlp_/lib/python3.11/site-packages/transformers/trainer.py:2178, in Trainer._inner_training_loop(self, batch_size, args, resume_from_checkpoint, trial, ignore_keys_for_eval)
         2175     rng_to_sync = True
         2177 step = -1
      -> 2178 for step, inputs in enumerate(epoch_iterator):
         2179     total_batched_samples += 1
         2181     if self.args.include_num_input_tokens_seen:
      
      File ~/miniconda3/envs/nlp_/lib/python3.11/site-packages/accelerate/data_loader.py:454, in DataLoaderShard.__iter__(self)
          452 # We iterate one batch ahead to check when we are at the end
          453 try:
      --> 454     current_batch = next(dataloader_iter)
          455 except StopIteration:
          456     yield
      
      File ~/miniconda3/envs/nlp_/lib/python3.11/site-packages/torch/utils/data/dataloader.py:631, in _BaseDataLoaderIter.__next__(self)
          628 if self._sampler_iter is None:
          629     # TODO(https://github.com/pytorch/pytorch/issues/76750)
          630     self._reset()  # type: ignore[call-arg]
      --> 631 data = self._next_data()
          632 self._num_yielded += 1
          633 if self._dataset_kind == _DatasetKind.Iterable and \
          634         self._IterableDataset_len_called is not None and \
          635         self._num_yielded > self._IterableDataset_len_called:
      
      File ~/miniconda3/envs/nlp_/lib/python3.11/site-packages/torch/utils/data/dataloader.py:675, in _SingleProcessDataLoaderIter._next_data(self)
          673 def _next_data(self):
          674     index = self._next_index()  # may raise StopIteration
      --> 675     data = self._dataset_fetcher.fetch(index)  # may raise StopIteration
          676     if self._pin_memory:
          677         data = _utils.pin_memory.pin_memory(data, self._pin_memory_device)
      
      File ~/miniconda3/envs/nlp_/lib/python3.11/site-packages/torch/utils/data/_utils/fetch.py:54, in _MapDatasetFetcher.fetch(self, possibly_batched_index)
           52 else:
           53     data = self.dataset[possibly_batched_index]
      ---> 54 return self.collate_fn(data)
      
      File ~/miniconda3/envs/nlp_/lib/python3.11/site-packages/transformers/data/data_collator.py:271, in DataCollatorWithPadding.__call__(self, features)
          270 def __call__(self, features: List[Dict[str, Any]]) -> Dict[str, Any]:
      --> 271     batch = pad_without_fast_tokenizer_warning(
          272         self.tokenizer,
          273         features,
          274         padding=self.padding,
          275         max_length=self.max_length,
          276         pad_to_multiple_of=self.pad_to_multiple_of,
          277         return_tensors=self.return_tensors,
          278     )
          279     if "label" in batch:
          280         batch["labels"] = batch["label"]
      
      File ~/miniconda3/envs/nlp_/lib/python3.11/site-packages/transformers/data/data_collator.py:66, in pad_without_fast_tokenizer_warning(tokenizer, *pad_args, **pad_kwargs)
           63 tokenizer.deprecation_warnings["Asking-to-pad-a-fast-tokenizer"] = True
           65 try:
      ---> 66     padded = tokenizer.pad(*pad_args, **pad_kwargs)
           67 finally:
           68     # Restore the state of the warning.
           69     tokenizer.deprecation_warnings["Asking-to-pad-a-fast-tokenizer"] = warning_state
      
      File ~/miniconda3/envs/nlp_/lib/python3.11/site-packages/transformers/tokenization_utils_base.py:3299, in PreTrainedTokenizerBase.pad(self, encoded_inputs, padding, max_length, pad_to_multiple_of, return_attention_mask, return_tensors, verbose)
         3297 # The model's main input name, usually `input_ids`, has be passed for padding
         3298 if self.model_input_names[0] not in encoded_inputs:
      -> 3299     raise ValueError(
         3300         "You should supply an encoding or a list of encodings to this method "
         3301         f"that includes {self.model_input_names[0]}, but you provided {list(encoded_inputs.keys())}"
         3302     )
         3304 required_input = encoded_inputs[self.model_input_names[0]]
         3306 if required_input is None or (isinstance(required_input, Sized) and len(required_input) == 0):
      
      ValueError: You should supply an encoding or a list of encodings to this method that includes input_ids, but you provided ['label', 'labels']

Recebemos um erro novamente porque o modelo não foi atribuído a um token de preenchimento, portanto, assim como no tokenizador, nós o atribuímos ao modelo

	
del casual_model
from transformers import TrainingArguments
metric_name = "accuracy"
model_name = "GPT2-small-finetuned-amazon-reviews-en-classification"
LR = 2e-5
BS_TRAIN = 28
BS_EVAL = 40
EPOCHS = 3
WEIGHT_DECAY = 0.01
training_args = TrainingArguments(
model_name,
eval_strategy="epoch",
save_strategy="epoch",
learning_rate=LR,
per_device_train_batch_size=BS_TRAIN,
per_device_eval_batch_size=BS_EVAL,
num_train_epochs=EPOCHS,
weight_decay=WEIGHT_DECAY,
lr_scheduler_type="cosine",
warmup_ratio = 0.1,
fp16=True,
load_best_model_at_end=True,
metric_for_best_model=metric_name,
push_to_hub=True,
)
import numpy as np
from evaluate import load
metric = load("accuracy")
def compute_metrics(eval_pred):
print(eval_pred)
predictions, labels = eval_pred
predictions = np.argmax(predictions, axis=1)
return metric.compute(predictions=predictions, references=labels)
from transformers import Trainer
trainer = Trainer(
model,
training_args,
train_dataset=dataset['train'],
eval_dataset=dataset['validation'],
tokenizer=tokenizer,
compute_metrics=compute_metrics,
)
trainer.train()
model.config.pad_token_id = model.config.eos_token_id
Copy

Recriamos os argumentos do instrutor com o novo modelo, que agora tem um token de preenchimento, o instrutor e treinamos novamente.

	
del casual_model
from transformers import TrainingArguments
metric_name = "accuracy"
model_name = "GPT2-small-finetuned-amazon-reviews-en-classification"
LR = 2e-5
BS_TRAIN = 28
BS_EVAL = 40
EPOCHS = 3
WEIGHT_DECAY = 0.01
training_args = TrainingArguments(
model_name,
eval_strategy="epoch",
save_strategy="epoch",
learning_rate=LR,
per_device_train_batch_size=BS_TRAIN,
per_device_eval_batch_size=BS_EVAL,
num_train_epochs=EPOCHS,
weight_decay=WEIGHT_DECAY,
lr_scheduler_type="cosine",
warmup_ratio = 0.1,
fp16=True,
load_best_model_at_end=True,
metric_for_best_model=metric_name,
push_to_hub=True,
)
import numpy as np
from evaluate import load
metric = load("accuracy")
def compute_metrics(eval_pred):
print(eval_pred)
predictions, labels = eval_pred
predictions = np.argmax(predictions, axis=1)
return metric.compute(predictions=predictions, references=labels)
from transformers import Trainer
trainer = Trainer(
model,
training_args,
train_dataset=dataset['train'],
eval_dataset=dataset['validation'],
tokenizer=tokenizer,
compute_metrics=compute_metrics,
)
trainer.train()
model.config.pad_token_id = model.config.eos_token_id
training_args = TrainingArguments(
model_name,
eval_strategy="epoch",
save_strategy="epoch",
learning_rate=LR,
per_device_train_batch_size=BS_TRAIN,
per_device_eval_batch_size=BS_EVAL,
num_train_epochs=EPOCHS,
weight_decay=WEIGHT_DECAY,
lr_scheduler_type="cosine",
warmup_ratio = 0.1,
fp16=True,
load_best_model_at_end=True,
metric_for_best_model=metric_name,
push_to_hub=True,
logging_dir="./runs",
)
trainer = Trainer(
model,
training_args,
train_dataset=dataset['train'],
eval_dataset=dataset['validation'],
tokenizer=tokenizer,
compute_metrics=compute_metrics,
)
Copy

Agora que vimos que tudo está bem, podemos treinar.

trainer.train()
      
[ 2250/21429 45:38 < 6:29:27, 0.82 it/s, Epoch 0.31/3]
Epoch Training Loss Validation Loss

[21429/21429 7:19:25, Epoch 3/3]
Epoch Training Loss Validation Loss Accuracy
1 0.807400 0.820341 0.652000
2 0.751900 0.802189 0.654600
3 0.718100 0.810221 0.657800

<transformers.trainer_utils.EvalPrediction object at 0x782767ea1450>
      <transformers.trainer_utils.EvalPrediction object at 0x782767eeefe0>
      <transformers.trainer_utils.EvalPrediction object at 0x782767eecfd0>
      
Out[28]:
TrainOutput(global_step=21429, training_loss=0.7846888848762739, metrics={'train_runtime': 26367.7801, 'train_samples_per_second': 22.755, 'train_steps_per_second': 0.813, 'total_flos': 2.35173445632e+17, 'train_loss': 0.7846888848762739, 'epoch': 3.0})

Avaliaçãolink image 87

Depois de treinados, avaliamos o conjunto de dados de teste

trainer.evaluate(eval_dataset=dataset['test'])
      
[125/125 01:15]
<transformers.trainer_utils.EvalPrediction object at 0x7826ddfded40>
      
Out[29]:
{'eval_loss': 0.7973636984825134,
       'eval_accuracy': 0.6626,
       'eval_runtime': 76.3016,
       'eval_samples_per_second': 65.529,
       'eval_steps_per_second': 1.638,
       'epoch': 3.0}

Publicar o modelolink image 88

Agora que temos nosso modelo treinado, podemos compartilhá-lo com o mundo, portanto, primeiro criamos um cartão de modelo.

	
del casual_model
from transformers import TrainingArguments
metric_name = "accuracy"
model_name = "GPT2-small-finetuned-amazon-reviews-en-classification"
LR = 2e-5
BS_TRAIN = 28
BS_EVAL = 40
EPOCHS = 3
WEIGHT_DECAY = 0.01
training_args = TrainingArguments(
model_name,
eval_strategy="epoch",
save_strategy="epoch",
learning_rate=LR,
per_device_train_batch_size=BS_TRAIN,
per_device_eval_batch_size=BS_EVAL,
num_train_epochs=EPOCHS,
weight_decay=WEIGHT_DECAY,
lr_scheduler_type="cosine",
warmup_ratio = 0.1,
fp16=True,
load_best_model_at_end=True,
metric_for_best_model=metric_name,
push_to_hub=True,
)
import numpy as np
from evaluate import load
metric = load("accuracy")
def compute_metrics(eval_pred):
print(eval_pred)
predictions, labels = eval_pred
predictions = np.argmax(predictions, axis=1)
return metric.compute(predictions=predictions, references=labels)
from transformers import Trainer
trainer = Trainer(
model,
training_args,
train_dataset=dataset['train'],
eval_dataset=dataset['validation'],
tokenizer=tokenizer,
compute_metrics=compute_metrics,
)
trainer.train()
model.config.pad_token_id = model.config.eos_token_id
training_args = TrainingArguments(
model_name,
eval_strategy="epoch",
save_strategy="epoch",
learning_rate=LR,
per_device_train_batch_size=BS_TRAIN,
per_device_eval_batch_size=BS_EVAL,
num_train_epochs=EPOCHS,
weight_decay=WEIGHT_DECAY,
lr_scheduler_type="cosine",
warmup_ratio = 0.1,
fp16=True,
load_best_model_at_end=True,
metric_for_best_model=metric_name,
push_to_hub=True,
logging_dir="./runs",
)
trainer = Trainer(
model,
training_args,
train_dataset=dataset['train'],
eval_dataset=dataset['validation'],
tokenizer=tokenizer,
compute_metrics=compute_metrics,
)
trainer.train()
trainer.evaluate(eval_dataset=dataset['test'])
trainer.create_model_card()
Copy

E agora podemos publicá-lo. Como a primeira coisa que fizemos foi fazer login no hub da huggingface, poderemos fazer o upload para o nosso hub sem nenhum problema.

	
del casual_model
from transformers import TrainingArguments
metric_name = "accuracy"
model_name = "GPT2-small-finetuned-amazon-reviews-en-classification"
LR = 2e-5
BS_TRAIN = 28
BS_EVAL = 40
EPOCHS = 3
WEIGHT_DECAY = 0.01
training_args = TrainingArguments(
model_name,
eval_strategy="epoch",
save_strategy="epoch",
learning_rate=LR,
per_device_train_batch_size=BS_TRAIN,
per_device_eval_batch_size=BS_EVAL,
num_train_epochs=EPOCHS,
weight_decay=WEIGHT_DECAY,
lr_scheduler_type="cosine",
warmup_ratio = 0.1,
fp16=True,
load_best_model_at_end=True,
metric_for_best_model=metric_name,
push_to_hub=True,
)
import numpy as np
from evaluate import load
metric = load("accuracy")
def compute_metrics(eval_pred):
print(eval_pred)
predictions, labels = eval_pred
predictions = np.argmax(predictions, axis=1)
return metric.compute(predictions=predictions, references=labels)
from transformers import Trainer
trainer = Trainer(
model,
training_args,
train_dataset=dataset['train'],
eval_dataset=dataset['validation'],
tokenizer=tokenizer,
compute_metrics=compute_metrics,
)
trainer.train()
model.config.pad_token_id = model.config.eos_token_id
training_args = TrainingArguments(
model_name,
eval_strategy="epoch",
save_strategy="epoch",
learning_rate=LR,
per_device_train_batch_size=BS_TRAIN,
per_device_eval_batch_size=BS_EVAL,
num_train_epochs=EPOCHS,
weight_decay=WEIGHT_DECAY,
lr_scheduler_type="cosine",
warmup_ratio = 0.1,
fp16=True,
load_best_model_at_end=True,
metric_for_best_model=metric_name,
push_to_hub=True,
logging_dir="./runs",
)
trainer = Trainer(
model,
training_args,
train_dataset=dataset['train'],
eval_dataset=dataset['validation'],
tokenizer=tokenizer,
compute_metrics=compute_metrics,
)
trainer.train()
trainer.evaluate(eval_dataset=dataset['test'])
trainer.create_model_card()
trainer.push_to_hub()
Copy

Uso do modelolink image 89

Limpamos o máximo possível

	
del casual_model
from transformers import TrainingArguments
metric_name = "accuracy"
model_name = "GPT2-small-finetuned-amazon-reviews-en-classification"
LR = 2e-5
BS_TRAIN = 28
BS_EVAL = 40
EPOCHS = 3
WEIGHT_DECAY = 0.01
training_args = TrainingArguments(
model_name,
eval_strategy="epoch",
save_strategy="epoch",
learning_rate=LR,
per_device_train_batch_size=BS_TRAIN,
per_device_eval_batch_size=BS_EVAL,
num_train_epochs=EPOCHS,
weight_decay=WEIGHT_DECAY,
lr_scheduler_type="cosine",
warmup_ratio = 0.1,
fp16=True,
load_best_model_at_end=True,
metric_for_best_model=metric_name,
push_to_hub=True,
)
import numpy as np
from evaluate import load
metric = load("accuracy")
def compute_metrics(eval_pred):
print(eval_pred)
predictions, labels = eval_pred
predictions = np.argmax(predictions, axis=1)
return metric.compute(predictions=predictions, references=labels)
from transformers import Trainer
trainer = Trainer(
model,
training_args,
train_dataset=dataset['train'],
eval_dataset=dataset['validation'],
tokenizer=tokenizer,
compute_metrics=compute_metrics,
)
trainer.train()
model.config.pad_token_id = model.config.eos_token_id
training_args = TrainingArguments(
model_name,
eval_strategy="epoch",
save_strategy="epoch",
learning_rate=LR,
per_device_train_batch_size=BS_TRAIN,
per_device_eval_batch_size=BS_EVAL,
num_train_epochs=EPOCHS,
weight_decay=WEIGHT_DECAY,
lr_scheduler_type="cosine",
warmup_ratio = 0.1,
fp16=True,
load_best_model_at_end=True,
metric_for_best_model=metric_name,
push_to_hub=True,
logging_dir="./runs",
)
trainer = Trainer(
model,
training_args,
train_dataset=dataset['train'],
eval_dataset=dataset['validation'],
tokenizer=tokenizer,
compute_metrics=compute_metrics,
)
trainer.train()
trainer.evaluate(eval_dataset=dataset['test'])
trainer.create_model_card()
trainer.push_to_hub()
import torch
import gc
def clear_hardwares():
torch.clear_autocast_cache()
torch.cuda.ipc_collect()
torch.cuda.empty_cache()
gc.collect()
clear_hardwares()
clear_hardwares()
Copy

Como fizemos o upload do modelo em nosso hub, podemos baixá-lo e usá-lo.

	
del casual_model
from transformers import TrainingArguments
metric_name = "accuracy"
model_name = "GPT2-small-finetuned-amazon-reviews-en-classification"
LR = 2e-5
BS_TRAIN = 28
BS_EVAL = 40
EPOCHS = 3
WEIGHT_DECAY = 0.01
training_args = TrainingArguments(
model_name,
eval_strategy="epoch",
save_strategy="epoch",
learning_rate=LR,
per_device_train_batch_size=BS_TRAIN,
per_device_eval_batch_size=BS_EVAL,
num_train_epochs=EPOCHS,
weight_decay=WEIGHT_DECAY,
lr_scheduler_type="cosine",
warmup_ratio = 0.1,
fp16=True,
load_best_model_at_end=True,
metric_for_best_model=metric_name,
push_to_hub=True,
)
import numpy as np
from evaluate import load
metric = load("accuracy")
def compute_metrics(eval_pred):
print(eval_pred)
predictions, labels = eval_pred
predictions = np.argmax(predictions, axis=1)
return metric.compute(predictions=predictions, references=labels)
from transformers import Trainer
trainer = Trainer(
model,
training_args,
train_dataset=dataset['train'],
eval_dataset=dataset['validation'],
tokenizer=tokenizer,
compute_metrics=compute_metrics,
)
trainer.train()
model.config.pad_token_id = model.config.eos_token_id
training_args = TrainingArguments(
model_name,
eval_strategy="epoch",
save_strategy="epoch",
learning_rate=LR,
per_device_train_batch_size=BS_TRAIN,
per_device_eval_batch_size=BS_EVAL,
num_train_epochs=EPOCHS,
weight_decay=WEIGHT_DECAY,
lr_scheduler_type="cosine",
warmup_ratio = 0.1,
fp16=True,
load_best_model_at_end=True,
metric_for_best_model=metric_name,
push_to_hub=True,
logging_dir="./runs",
)
trainer = Trainer(
model,
training_args,
train_dataset=dataset['train'],
eval_dataset=dataset['validation'],
tokenizer=tokenizer,
compute_metrics=compute_metrics,
)
trainer.train()
trainer.evaluate(eval_dataset=dataset['test'])
trainer.create_model_card()
trainer.push_to_hub()
import torch
import gc
def clear_hardwares():
torch.clear_autocast_cache()
torch.cuda.ipc_collect()
torch.cuda.empty_cache()
gc.collect()
clear_hardwares()
clear_hardwares()
from transformers import pipeline
user = "maximofn"
checkpoints = f"{user}/{model_name}"
task = "text-classification"
classifier = pipeline(task, model=checkpoints, tokenizer=checkpoints)
Copy

Agora, se quisermos retornar a probabilidade de todas as classes, basta usar o classificador que acabamos de instanciar, com o parâmetro top_k=None.

	
del casual_model
from transformers import TrainingArguments
metric_name = "accuracy"
model_name = "GPT2-small-finetuned-amazon-reviews-en-classification"
LR = 2e-5
BS_TRAIN = 28
BS_EVAL = 40
EPOCHS = 3
WEIGHT_DECAY = 0.01
training_args = TrainingArguments(
model_name,
eval_strategy="epoch",
save_strategy="epoch",
learning_rate=LR,
per_device_train_batch_size=BS_TRAIN,
per_device_eval_batch_size=BS_EVAL,
num_train_epochs=EPOCHS,
weight_decay=WEIGHT_DECAY,
lr_scheduler_type="cosine",
warmup_ratio = 0.1,
fp16=True,
load_best_model_at_end=True,
metric_for_best_model=metric_name,
push_to_hub=True,
)
import numpy as np
from evaluate import load
metric = load("accuracy")
def compute_metrics(eval_pred):
print(eval_pred)
predictions, labels = eval_pred
predictions = np.argmax(predictions, axis=1)
return metric.compute(predictions=predictions, references=labels)
from transformers import Trainer
trainer = Trainer(
model,
training_args,
train_dataset=dataset['train'],
eval_dataset=dataset['validation'],
tokenizer=tokenizer,
compute_metrics=compute_metrics,
)
trainer.train()
model.config.pad_token_id = model.config.eos_token_id
training_args = TrainingArguments(
model_name,
eval_strategy="epoch",
save_strategy="epoch",
learning_rate=LR,
per_device_train_batch_size=BS_TRAIN,
per_device_eval_batch_size=BS_EVAL,
num_train_epochs=EPOCHS,
weight_decay=WEIGHT_DECAY,
lr_scheduler_type="cosine",
warmup_ratio = 0.1,
fp16=True,
load_best_model_at_end=True,
metric_for_best_model=metric_name,
push_to_hub=True,
logging_dir="./runs",
)
trainer = Trainer(
model,
training_args,
train_dataset=dataset['train'],
eval_dataset=dataset['validation'],
tokenizer=tokenizer,
compute_metrics=compute_metrics,
)
trainer.train()
trainer.evaluate(eval_dataset=dataset['test'])
trainer.create_model_card()
trainer.push_to_hub()
import torch
import gc
def clear_hardwares():
torch.clear_autocast_cache()
torch.cuda.ipc_collect()
torch.cuda.empty_cache()
gc.collect()
clear_hardwares()
clear_hardwares()
from transformers import pipeline
user = "maximofn"
checkpoints = f"{user}/{model_name}"
task = "text-classification"
classifier = pipeline(task, model=checkpoints, tokenizer=checkpoints)
labels = classifier("I love this product", top_k=None)
labels
Copy
	
0%| | 0/600000 [00:00<?, ?it/s]
[{'label': 'LABEL_4', 'score': 0.8253807425498962},
{'label': 'LABEL_3', 'score': 0.15411493182182312},
{'label': 'LABEL_2', 'score': 0.013907806016504765},
{'label': 'LABEL_0', 'score': 0.003939222544431686},
{'label': 'LABEL_1', 'score': 0.0026572425849735737}]

Se quisermos apenas a classe com a maior probabilidade, faremos o mesmo, mas com o parâmetro top_k=1.

	
label = classifier("I love this product", top_k=1)
label
Copy
	
[{'label': 'LABEL_4', 'score': 0.8253807425498962}]

E se quisermos n classes, faremos o mesmo, mas com o parâmetro top_k=n.

	
two_labels = classifier("I love this product", top_k=2)
two_labels
Copy
	
[{'label': 'LABEL_4', 'score': 0.8253807425498962},
{'label': 'LABEL_3', 'score': 0.15411493182182312}]

Também podemos testar o modelo com o Automodel e o AutoTokenizer.

	
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch
model_name = "GPT2-small-finetuned-amazon-reviews-en-classification"
user = "maximofn"
checkpoint = f"{user}/{model_name}"
num_classes = 5
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=num_classes).half().eval().to("cuda")
Copy
	
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch
model_name = "GPT2-small-finetuned-amazon-reviews-en-classification"
user = "maximofn"
checkpoint = f"{user}/{model_name}"
num_classes = 5
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=num_classes).half().eval().to("cuda")
tokens = tokenizer.encode("I love this product", return_tensors="pt").to(model.device)
with torch.no_grad():
output = model(tokens)
logits = output.logits
lables = torch.softmax(logits, dim=1).cpu().numpy().tolist()
lables[0]
Copy
	
[0.003963470458984375,
0.0026721954345703125,
0.01397705078125,
0.154541015625,
0.82470703125]

Se você quiser testar o modelo com mais detalhes, poderá vê-lo em Maximofn/GPT2-small-finetuned-amazon-reviews-en-classification

Ajuste fino para geração de texto com o Hugging Facelink image 90

Para ter certeza de que não tenho problemas de memória VRAM, reiniciei o notebook.

Loginlink image 91

Para fazer upload do resultado do treinamento no hub, primeiro precisamos fazer login e, para isso, precisamos de um token.

Para criar um token, acesse a página setings/tokens de sua conta, que terá a seguinte aparência

User-Access-Token-dark](https://pub-fb664c455eca46a2ba762a065ac900f7.r2.dev/User-Access-Token-dark.webp)

Clique em New token e será exibida uma janela para criar um novo token.

new-token-dark

Nomeamos o token e o criamos com a função write ou com a função Fine-grained, que nos permite selecionar exatamente quais permissões o token terá.

Depois de criado, copiamos e colamos o arquivo abaixo

	
from huggingface_hub import notebook_login
notebook_login()
Copy

Conjunto de dadoslink image 92

Vamos usar um conjunto de dados de [piadas em inglês] (https://huggingface.co/datasets/Maximofn/short-jokes-dataset)

	
from huggingface_hub import notebook_login
notebook_login()
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
Copy
	
DatasetDict({
train: Dataset({
features: ['ID', 'Joke'],
num_rows: 231657
})
})

Vemos que se trata de um único conjunto de treinamento com mais de 200.000 piadas. Portanto, mais adiante, teremos de dividi-lo em treinamento e avaliação.

Vamos dar uma olhada em um exemplo

	
from random import randint
idx = randint(0, len(jokes['train']) - 1)
jokes['train'][idx]
Copy
	
{'ID': 198387,
'Joke': 'My hot dislexic co-worker said she had an important massage to give me in her office... When I got there, she told me it can wait until I put on some clothes.'}

Vemos que ela tem uma identificação da piada que não nos interessa em absoluto e a piada em si

Caso você tenha pouca memória de GPU, farei um subconjunto do conjunto de dados, escolha a porcentagem de piadas que deseja usar.

	
percent_of_train_dataset = 1 # If you want 50% of the dataset, set this to 0.5
subset_dataset = jokes["train"].select(range(int(len(jokes["train"]) * percent_of_train_dataset)))
subset_dataset
Copy
	
Dataset({
features: ['ID', 'Joke'],
num_rows: 231657
})

Agora, dividimos o subconjunto em um conjunto de treinamento e um conjunto de validação.

	
percent_of_train_dataset = 0.90
split_dataset = subset_dataset.train_test_split(train_size=int(subset_dataset.num_rows * percent_of_train_dataset), seed=19, shuffle=False)
train_dataset = split_dataset["train"]
validation_test_dataset = split_dataset["test"]
split_dataset = validation_test_dataset.train_test_split(train_size=int(validation_test_dataset.num_rows * 0.5), seed=19, shuffle=False)
validation_dataset = split_dataset["train"]
test_dataset = split_dataset["test"]
print(f"Size of the train set: {len(train_dataset)}. Size of the validation set: {len(validation_dataset)}. Size of the test set: {len(test_dataset)}")
Copy
	
Size of the train set: 208491. Size of the validation set: 11583. Size of the test set: 11583

Tokeniserlink image 93

Instanciar o tokenizador. Instanciar o token de preenchimento do tokenizador para não recebermos um erro como antes.

	
from transformers import AutoTokenizer
checkpoints = "openai-community/gpt2"
tokenizer = AutoTokenizer.from_pretrained(checkpoints)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
Copy

Para maior controle, adicionaremos dois novos tokens para o início e o fim de uma piada.

	
from transformers import AutoTokenizer
checkpoints = "openai-community/gpt2"
tokenizer = AutoTokenizer.from_pretrained(checkpoints)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
new_tokens = ['<SJ>', '<EJ>'] # Start and end of joke tokens
num_added_tokens = tokenizer.add_tokens(new_tokens)
print(f"Added {num_added_tokens} tokens")
Copy
	
Added 2 tokens

Criamos uma função para adicionar os novos tokens às sentenças

	
joke_column = "Joke"
def format_joke(example):
example[joke_column] = '<SJ> ' + example['Joke'] + ' <EJ>'
return example
Copy

Selecionamos as colunas de que não precisamos

	
joke_column = "Joke"
def format_joke(example):
example[joke_column] = '<SJ> ' + example['Joke'] + ' <EJ>'
return example
remove_columns = [column for column in train_dataset.column_names if column != joke_column]
remove_columns
Copy
	
['ID']

Formatamos o conjunto de dados e excluímos as colunas de que não precisamos.

	
train_dataset = train_dataset.map(format_joke, remove_columns=remove_columns)
validation_dataset = validation_dataset.map(format_joke, remove_columns=remove_columns)
test_dataset = test_dataset.map(format_joke, remove_columns=remove_columns)
train_dataset, validation_dataset, test_dataset
Copy
	
(Dataset({
features: ['Joke'],
num_rows: 208491
}),
Dataset({
features: ['Joke'],
num_rows: 11583
}),
Dataset({
features: ['Joke'],
num_rows: 11583
}))

Agora, criamos uma função para tokenizar as piadas.

	
def tokenize_function(examples):
return tokenizer(examples[joke_column], padding="max_length", truncation=True, max_length=768, return_tensors="pt")
Copy

Tokenize o conjunto de dados e exclua a coluna com o texto

	
def tokenize_function(examples):
return tokenizer(examples[joke_column], padding="max_length", truncation=True, max_length=768, return_tensors="pt")
train_dataset = train_dataset.map(tokenize_function, batched=True, remove_columns=[joke_column])
validation_dataset = validation_dataset.map(tokenize_function, batched=True, remove_columns=[joke_column])
test_dataset = test_dataset.map(tokenize_function, batched=True, remove_columns=[joke_column])
train_dataset, validation_dataset, test_dataset
Copy
	
(Dataset({
features: ['input_ids', 'attention_mask'],
num_rows: 208491
}),
Dataset({
features: ['input_ids', 'attention_mask'],
num_rows: 11583
}),
Dataset({
features: ['input_ids', 'attention_mask'],
num_rows: 11583
}))

Modelolink image 94

Agora, instanciamos o modelo para geração de texto e atribuímos o token de fim de cadeia ao token de carregamento.

	
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(checkpoints)
model.config.pad_token_id = model.config.eos_token_id
Copy

Vemos o tamanho do vocabulário do modelo

	
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(checkpoints)
model.config.pad_token_id = model.config.eos_token_id
vocab_size = model.config.vocab_size
vocab_size
Copy
	
50257

Ele tem 50257 tokens, que é o tamanho do vocabulário do GPT2. Mas como dissemos que criaríamos dois novos tokens com o início da piada e o fim da piada, nós os adicionamos ao modelo

	
model.resize_token_embeddings(len(tokenizer))
new_vocab_size = model.config.vocab_size
print(f"Old vocab size: {vocab_size}. New vocab size: {new_vocab_size}. Added {new_vocab_size - vocab_size} tokens")
Copy
	
Old vocab size: 50257. New vocab size: 50259. Added 2 tokens

Os dois novos tokens foram adicionados

Treinamentolink image 95

Definimos os parâmetros de treinamento

	
from transformers import TrainingArguments
metric_name = "accuracy"
model_name = "GPT2-small-finetuned-Maximofn-short-jokes-dataset-casualLM"
output_dir = f"./training_results"
LR = 2e-5
BS_TRAIN = 28
BS_EVAL = 32
EPOCHS = 3
WEIGHT_DECAY = 0.01
WARMUP_STEPS = 100
training_args = TrainingArguments(
model_name,
eval_strategy="epoch",
save_strategy="epoch",
learning_rate=LR,
per_device_train_batch_size=BS_TRAIN,
per_device_eval_batch_size=BS_EVAL,
warmup_steps=WARMUP_STEPS,
num_train_epochs=EPOCHS,
weight_decay=WEIGHT_DECAY,
lr_scheduler_type="cosine",
warmup_ratio = 0.1,
fp16=True,
load_best_model_at_end=True,
# metric_for_best_model=metric_name,
push_to_hub=True,
)
Copy

Agora não usamos metric_for_best_model, depois de definir o treinador, explicamos o motivo

Definimos o treinador

	
from transformers import TrainingArguments
metric_name = "accuracy"
model_name = "GPT2-small-finetuned-Maximofn-short-jokes-dataset-casualLM"
output_dir = f"./training_results"
LR = 2e-5
BS_TRAIN = 28
BS_EVAL = 32
EPOCHS = 3
WEIGHT_DECAY = 0.01
WARMUP_STEPS = 100
training_args = TrainingArguments(
model_name,
eval_strategy="epoch",
save_strategy="epoch",
learning_rate=LR,
per_device_train_batch_size=BS_TRAIN,
per_device_eval_batch_size=BS_EVAL,
warmup_steps=WARMUP_STEPS,
num_train_epochs=EPOCHS,
weight_decay=WEIGHT_DECAY,
lr_scheduler_type="cosine",
warmup_ratio = 0.1,
fp16=True,
load_best_model_at_end=True,
# metric_for_best_model=metric_name,
push_to_hub=True,
)
from transformers import Trainer
trainer = Trainer(
model,
training_args,
train_dataset=train_dataset,
eval_dataset=validation_dataset,
tokenizer=tokenizer,
# compute_metrics=compute_metrics,
)
Copy

Nesse caso, não passamos uma função compute_metrics; se ela não for passada, a loss será usada durante a avaliação para avaliar o modelo. É por isso que, ao definir os argumentos, não definimos metric_for_best_model, pois não usaremos uma métrica para avaliar o modelo, mas a loss.

Treinamos

trainer.train()
      
  0%|          | 0/625473 [00:00<?, ?it/s]
      ---------------------------------------------------------------------------
      ValueError                                Traceback (most recent call last)
      Cell In[19], line 1
      ----> 1 trainer.train()
      
      File ~/miniconda3/envs/nlp_/lib/python3.11/site-packages/transformers/trainer.py:1885, in Trainer.train(self, resume_from_checkpoint, trial, ignore_keys_for_eval, **kwargs)
         1883         hf_hub_utils.enable_progress_bars()
         1884 else:
      -> 1885     return inner_training_loop(
         1886         args=args,
         1887         resume_from_checkpoint=resume_from_checkpoint,
         1888         trial=trial,
         1889         ignore_keys_for_eval=ignore_keys_for_eval,
         1890     )
      
      File ~/miniconda3/envs/nlp_/lib/python3.11/site-packages/transformers/trainer.py:2216, in Trainer._inner_training_loop(self, batch_size, args, resume_from_checkpoint, trial, ignore_keys_for_eval)
         2213     self.control = self.callback_handler.on_step_begin(args, self.state, self.control)
         2215 with self.accelerator.accumulate(model):
      -> 2216     tr_loss_step = self.training_step(model, inputs)
         2218 if (
         2219     args.logging_nan_inf_filter
         2220     and not is_torch_xla_available()
         2221     and (torch.isnan(tr_loss_step) or torch.isinf(tr_loss_step))
         2222 ):
         2223     # if loss is nan or inf simply add the average of previous logged losses
         2224     tr_loss += tr_loss / (1 + self.state.global_step - self._globalstep_last_logged)
      
      File ~/miniconda3/envs/nlp_/lib/python3.11/site-packages/transformers/trainer.py:3238, in Trainer.training_step(self, model, inputs)
         3235     return loss_mb.reduce_mean().detach().to(self.args.device)
         3237 with self.compute_loss_context_manager():
      -> 3238     loss = self.compute_loss(model, inputs)
         3240 del inputs
         3241 torch.cuda.empty_cache()
      
      File ~/miniconda3/envs/nlp_/lib/python3.11/site-packages/transformers/trainer.py:3282, in Trainer.compute_loss(self, model, inputs, return_outputs)
         3280 else:
         3281     if isinstance(outputs, dict) and "loss" not in outputs:
      -> 3282         raise ValueError(
         3283             "The model did not return a loss from the inputs, only the following keys: "
         3284             f"{','.join(outputs.keys())}. For reference, the inputs it received are {','.join(inputs.keys())}."
         3285         )
         3286     # We don't use .loss here since the model may return tuples instead of ModelOutput.
         3287     loss = outputs["loss"] if isinstance(outputs, dict) else outputs[0]
      
      ValueError: The model did not return a loss from the inputs, only the following keys: logits,past_key_values. For reference, the inputs it received are input_ids,attention_mask.

Como podemos ver, ele nos dá um erro, diz que o modelo não retorna o valor da perda, o que é fundamental para podermos treinar.

Primeiro, vamos ver como é um exemplo do conjunto de dados.

	
from transformers import TrainingArguments
metric_name = "accuracy"
model_name = "GPT2-small-finetuned-Maximofn-short-jokes-dataset-casualLM"
output_dir = f"./training_results"
LR = 2e-5
BS_TRAIN = 28
BS_EVAL = 32
EPOCHS = 3
WEIGHT_DECAY = 0.01
WARMUP_STEPS = 100
training_args = TrainingArguments(
model_name,
eval_strategy="epoch",
save_strategy="epoch",
learning_rate=LR,
per_device_train_batch_size=BS_TRAIN,
per_device_eval_batch_size=BS_EVAL,
warmup_steps=WARMUP_STEPS,
num_train_epochs=EPOCHS,
weight_decay=WEIGHT_DECAY,
lr_scheduler_type="cosine",
warmup_ratio = 0.1,
fp16=True,
load_best_model_at_end=True,
# metric_for_best_model=metric_name,
push_to_hub=True,
)
from transformers import Trainer
trainer = Trainer(
model,
training_args,
train_dataset=train_dataset,
eval_dataset=validation_dataset,
tokenizer=tokenizer,
# compute_metrics=compute_metrics,
)
trainer.train()
idx = randint(0, len(train_dataset) - 1)
sample = train_dataset[idx]
sample
Copy
	
0%| | 0/625473 [00:00<?, ?it/s]
{'input_ids': [50257,
4162,
750,
262,
18757,
6451,
2245,
2491,
30,
4362,
340,
373,
734,
10032,
13,
220,
50258,
50256,
50256,
...,
50256,
50256,
50256],
'attention_mask': [1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
0,
0,
0,
...,
0,
0,
0]}

Como podemos ver, temos um dicionário com input_ids e attention_mask e, se o passarmos para o modelo, obteremos o seguinte

	
import torch
output = model(
input_ids=torch.Tensor(sample["input_ids"]).long().unsqueeze(0).to(model.device),
attention_mask=torch.Tensor(sample["attention_mask"]).long().unsqueeze(0).to(model.device),
)
print(output.loss)
Copy
	
None

Como podemos ver, ele não retorna o valor da perda porque está aguardando um valor para labels, que não foi passado a ele. No exemplo anterior, em que fizemos o ajuste fino para a classificação de texto, dissemos que os rótulos tinham de ser passados para um campo no conjunto de dados chamado labels, mas, nesse caso, não temos esse campo no conjunto de dados.

Se agora atribuirmos os lables aos input_ids e observarmos novamente a perda

	
import torch
output = model(
input_ids=torch.Tensor(sample["input_ids"]).long().unsqueeze(0).to(model.device),
attention_mask=torch.Tensor(sample["attention_mask"]).long().unsqueeze(0).to(model.device),
labels=torch.Tensor(sample["input_ids"]).long().unsqueeze(0).to(model.device)
)
print(output.loss)
Copy
	
tensor(102.1873, device='cuda:0', grad_fn=<NllLossBackward0>)

Agora temos uma "perda".

Portanto, temos duas opções: adicionar um campo labels ao conjunto de dados, com os valores de input_ids ou usar uma função da biblioteca transformers chamada data_collator; nesse caso, usaremos DataCollatorForLanguageModeling. Vamos dar uma olhada nisso

	
from transformers import DataCollatorForLanguageModeling
my_data_collator=DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)
Copy

Passamos a amostra sample por meio desse data_collator.

	
from transformers import DataCollatorForLanguageModeling
my_data_collator=DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)
collated_sample = my_data_collator([sample]).to(model.device)
Copy

Vemos como é a saída

	
from transformers import DataCollatorForLanguageModeling
my_data_collator=DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)
collated_sample = my_data_collator([sample]).to(model.device)
for key, value in collated_sample.items():
print(f"{key} ({value.shape}): {value}")
Copy
	
input_ids (torch.Size([1, 768])): tensor([[50257, 4162, 750, 262, 18757, 6451, 2245, 2491, 30, 4362,
340, 373, 734, 10032, 13, 220, 50258, 50256, ..., 50256, 50256]],
device='cuda:0')
attention_mask (torch.Size([1, 768])): tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, ..., 0, 0]],
device='cuda:0')
labels (torch.Size([1, 768])): tensor([[50257, 4162, 750, 262, 18757, 6451, 2245, 2491, 30, 4362,
340, 373, 734, 10032, 13, 220, 50258, -100, ..., -100, -100]],
device='cuda:0')

Como você pode ver, o data_collator criou um campo labels e atribuiu a ele os valores de input_ids. Os tokens que são mascarados receberam um valor de -100. Isso se deve ao fato de que, quando definimos o data_collator, passamos a ele o parâmetro mlm=False, o que significa que não estamos fazendo Masked Language Modeling, mas Language Modeling, portanto, ele não mascara nenhum token original.

Vamos ver se agora temos uma perda com esse data_collator.

	
output = model(**collated_sample)
output.loss
Copy
	
tensor(102.7181, device='cuda:0', grad_fn=<NllLossBackward0>)

Portanto, redefinimos o trainer com o data_collator e treinamos novamente.

	
from transformers import DataCollatorForLanguageModeling
trainer = Trainer(
model,
training_args,
train_dataset=train_dataset,
eval_dataset=validation_dataset,
tokenizer=tokenizer,
data_collator=DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False),
)
Copy
trainer.train()
      
[22341/22341 2:33:28, Epoch 3/3]
Epoch Training Loss Validation Loss
1 3.386600 3.258979
2 3.259900 3.199673
3 3.212600 3.192009

There were missing keys in the checkpoint model loaded: ['lm_head.weight'].
      
TrainOutput(global_step=22341, training_loss=3.505178199598342, metrics={'train_runtime': 9209.5353, 'train_samples_per_second': 67.916, 'train_steps_per_second': 2.426, 'total_flos': 2.45146666696704e+17, 'train_loss': 3.505178199598342, 'epoch': 3.0})

Avaliaçãolink image 96

Depois de treinado, avaliamos o modelo no conjunto de dados de teste.

trainer.evaluate(eval_dataset=test_dataset)
      
[362/362 01:04]
{'eval_loss': 3.201305866241455,
       'eval_runtime': 65.0033,
       'eval_samples_per_second': 178.191,
       'eval_steps_per_second': 5.569,
       'epoch': 3.0}

Publicar o modelolink image 97

Criamos o cartão modelo

	
from transformers import DataCollatorForLanguageModeling
trainer = Trainer(
model,
training_args,
train_dataset=train_dataset,
eval_dataset=validation_dataset,
tokenizer=tokenizer,
data_collator=DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False),
)
trainer.train()
trainer.evaluate(eval_dataset=test_dataset)
trainer.create_model_card()
Copy

Nós o publicamos

trainer.push_to_hub()
      
events.out.tfevents.1720875425.8de3af1b431d.6946.1:   0%|          | 0.00/364 [00:00<?, ?B/s]
CommitInfo(commit_url='https://huggingface.co/Maximofn/GPT2-small-finetuned-Maximofn-short-jokes-dataset-casualLM/commit/d107b3bb0e02076483238f9975697761015ec390', commit_message='End of training', commit_description='', oid='d107b3bb0e02076483238f9975697761015ec390', pr_url=None, pr_revision=None, pr_num=None)

Uso do modelolink image 98

Limpamos o máximo possível

	
from transformers import DataCollatorForLanguageModeling
trainer = Trainer(
model,
training_args,
train_dataset=train_dataset,
eval_dataset=validation_dataset,
tokenizer=tokenizer,
data_collator=DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False),
)
trainer.train()
trainer.evaluate(eval_dataset=test_dataset)
trainer.create_model_card()
trainer.push_to_hub()
import torch
import gc
def clear_hardwares():
torch.clear_autocast_cache()
torch.cuda.ipc_collect()
torch.cuda.empty_cache()
gc.collect()
clear_hardwares()
clear_hardwares()
Copy

Baixamos o modelo e o tokenizador

	
from transformers import DataCollatorForLanguageModeling
trainer = Trainer(
model,
training_args,
train_dataset=train_dataset,
eval_dataset=validation_dataset,
tokenizer=tokenizer,
data_collator=DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False),
)
trainer.train()
trainer.evaluate(eval_dataset=test_dataset)
trainer.create_model_card()
trainer.push_to_hub()
import torch
import gc
def clear_hardwares():
torch.clear_autocast_cache()
torch.cuda.ipc_collect()
torch.cuda.empty_cache()
gc.collect()
clear_hardwares()
clear_hardwares()
from transformers import AutoTokenizer, AutoModelForCausalLM
user = "maximofn"
checkpoints = f"{user}/{model_name}"
tokenizer = AutoTokenizer.from_pretrained(checkpoints)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
model = AutoModelForCausalLM.from_pretrained(checkpoints)
model.config.pad_token_id = model.config.eos_token_id
Copy
	
events.out.tfevents.1720875425.8de3af1b431d.6946.1: 0%| | 0.00/364 [00:00<?, ?B/s]
Special tokens have been added in the vocabulary, make sure the associated word embeddings are fine-tuned or trained.

Verificamos se o tokenizador e o modelo têm os dois tokens extras que adicionamos.

	
tokenizer_vocab = tokenizer.get_vocab()
model_vocab = model.config.vocab_size
print(f"tokenizer_vocab: {len(tokenizer_vocab)}. model_vocab: {model_vocab}")
Copy
	
tokenizer_vocab: 50259. model_vocab: 50259

Vemos que eles têm 50259 tokens, ou seja, os 50257 tokens do GPT2 mais os 2 que adicionamos.

Criamos uma função para gerar piadas

	
def generate_joke(prompt_text):
text = f"<SJ> {prompt_text}"
tokens = tokenizer(text, return_tensors="pt").to(model.device)
with torch.no_grad():
output = model.generate(**tokens, max_new_tokens=256, eos_token_id=tokenizer.encode("<EJ>")[-1])
return tokenizer.decode(output[0], skip_special_tokens=False)
Copy

Geramos uma piada

generate_joke("Why didn't the frog cross the road?")
      
Setting `pad_token_id` to `eos_token_id`:50258 for open-end generation.
      
Out[15]:
"<SJ> Why didn't the frog cross the road? Because he was frog-in-the-face. <EJ>"

Se você quiser testar o modelo com mais detalhes, poderá vê-lo em Maximofn/GPT2-small-finetuned-Maximofn-short-jokes-dataset-casualLM

Ajuste fino para classificação de texto com o Pytorchlink image 99

Repetimos o treinamento com o Pytorch

Reinicie o notebook para ter certeza de que

Conjunto de dadoslink image 100

Fizemos o download do mesmo conjunto de dados que usamos no treinamento com as bibliotecas Hugging Face.

	
def generate_joke(prompt_text):
text = f"<SJ> {prompt_text}"
tokens = tokenizer(text, return_tensors="pt").to(model.device)
with torch.no_grad():
output = model.generate(**tokens, max_new_tokens=256, eos_token_id=tokenizer.encode("<EJ>")[-1])
return tokenizer.decode(output[0], skip_special_tokens=False)
generate_joke("Why didn't the frog cross the road?")
from datasets import load_dataset
dataset = load_dataset("mteb/amazon_reviews_multi", "en")
Copy

Criamos uma variável com o número de classes

	
def generate_joke(prompt_text):
text = f"<SJ> {prompt_text}"
tokens = tokenizer(text, return_tensors="pt").to(model.device)
with torch.no_grad():
output = model.generate(**tokens, max_new_tokens=256, eos_token_id=tokenizer.encode("<EJ>")[-1])
return tokenizer.decode(output[0], skip_special_tokens=False)
generate_joke("Why didn't the frog cross the road?")
from datasets import load_dataset
dataset = load_dataset("mteb/amazon_reviews_multi", "en")
num_classes = len(dataset['train'].unique('label'))
num_classes
Copy
	
Setting `pad_token_id` to `eos_token_id`:50258 for open-end generation.
5

Antes, processávamos todo o conjunto de dados para criar um campo chamado labels, mas agora isso não é necessário porque vamos programar tudo nós mesmos, portanto, nos adaptamos à aparência do conjunto de dados.

Tokeniserlink image 101

Criamos o tokenizador. Atribuímos o token de preenchimento para não recebermos um erro como antes.

	
from transformers import AutoTokenizer
checkpoint = "openai-community/gpt2"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
tokenizer.pad_token = tokenizer.eos_token
Copy

Criamos uma função para tokenizar o conjunto de dados

	
from transformers import AutoTokenizer
checkpoint = "openai-community/gpt2"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
tokenizer.pad_token = tokenizer.eos_token
def tokenize_function(examples):
return tokenizer(examples["text"], padding="max_length", truncation=True, max_length=768, return_tensors="pt")
Copy

Nós a tokenizamos. Removemos as colunas que não são necessárias, mas agora deixamos a coluna de texto.

	
from transformers import AutoTokenizer
checkpoint = "openai-community/gpt2"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
tokenizer.pad_token = tokenizer.eos_token
def tokenize_function(examples):
return tokenizer(examples["text"], padding="max_length", truncation=True, max_length=768, return_tensors="pt")
dataset = dataset.map(tokenize_function, batched=True, remove_columns=['id', 'label_text'])
Copy
	
from transformers import AutoTokenizer
checkpoint = "openai-community/gpt2"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
tokenizer.pad_token = tokenizer.eos_token
def tokenize_function(examples):
return tokenizer(examples["text"], padding="max_length", truncation=True, max_length=768, return_tensors="pt")
dataset = dataset.map(tokenize_function, batched=True, remove_columns=['id', 'label_text'])
dataset
Copy
	
DatasetDict({
train: Dataset({
features: ['text', 'label', 'input_ids', 'attention_mask'],
num_rows: 200000
})
validation: Dataset({
features: ['text', 'label', 'input_ids', 'attention_mask'],
num_rows: 5000
})
test: Dataset({
features: ['text', 'label', 'input_ids', 'attention_mask'],
num_rows: 5000
})
})
	
percentage = 1
subset_train = dataset['train'].select(range(int(len(dataset['train']) * percentage)))
percentage = 1
subset_validation = dataset['validation'].select(range(int(len(dataset['validation']) * percentage)))
subset_test = dataset['test'].select(range(int(len(dataset['test']) * percentage)))
print(f"len subset_train: {len(subset_train)}, len subset_validation: {len(subset_validation)}, len subset_test: {len(subset_test)}")
Copy
	
len subset_train: 200000, len subset_validation: 5000, len subset_test: 5000

Modelolink image 102

Importamos os pesos e atribuímos o token de preenchimento

	
from transformers import AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=num_classes)
model.config.pad_token_id = model.config.eos_token_id
Copy
	
Some weights of GPT2ForSequenceClassification were not initialized from the model checkpoint at openai-community/gpt2 and are newly initialized: ['score.weight']
You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.

Dispositivolink image 103

Criamos o dispositivo onde tudo será executado

	
import torch
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
Copy

Passamos o modelo para o dispositivo e o passamos para o FP16 para que ele ocupe menos memória.

	
import torch
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model.half().to(device)
print()
Copy
	

Conjunto de dados Pytorchlink image 104

Criar um conjunto de dados pytorch

	
from torch.utils.data import Dataset
class ReviewsDataset(Dataset):
def __init__(self, huggingface_dataset):
self.dataset = huggingface_dataset
def __getitem__(self, idx):
label = self.dataset[idx]['label']
input_ids = torch.tensor(self.dataset[idx]['input_ids'])
attention_mask = torch.tensor(self.dataset[idx]['attention_mask'])
return input_ids, attention_mask, label
def __len__(self):
return len(self.dataset)
Copy

Instanciar os conjuntos de dados

	
from torch.utils.data import Dataset
class ReviewsDataset(Dataset):
def __init__(self, huggingface_dataset):
self.dataset = huggingface_dataset
def __getitem__(self, idx):
label = self.dataset[idx]['label']
input_ids = torch.tensor(self.dataset[idx]['input_ids'])
attention_mask = torch.tensor(self.dataset[idx]['attention_mask'])
return input_ids, attention_mask, label
def __len__(self):
return len(self.dataset)
train_dataset = ReviewsDataset(subset_train)
validatation_dataset = ReviewsDataset(subset_validation)
test_dataset = ReviewsDataset(subset_test)
Copy

Vamos dar uma olhada em um exemplo

	
from torch.utils.data import Dataset
class ReviewsDataset(Dataset):
def __init__(self, huggingface_dataset):
self.dataset = huggingface_dataset
def __getitem__(self, idx):
label = self.dataset[idx]['label']
input_ids = torch.tensor(self.dataset[idx]['input_ids'])
attention_mask = torch.tensor(self.dataset[idx]['attention_mask'])
return input_ids, attention_mask, label
def __len__(self):
return len(self.dataset)
train_dataset = ReviewsDataset(subset_train)
validatation_dataset = ReviewsDataset(subset_validation)
test_dataset = ReviewsDataset(subset_test)
input_ids, at_mask, label = train_dataset[0]
input_ids.shape, at_mask.shape, label
Copy
	
(torch.Size([768]), torch.Size([768]), 0)

Carregador de dados Pytorchlink image 105

Criamos agora um carregador de dados pytorch

	
from torch.utils.data import DataLoader
BS = 12
train_loader = DataLoader(train_dataset, batch_size=BS, shuffle=True)
validation_loader = DataLoader(validatation_dataset, batch_size=BS)
test_loader = DataLoader(test_dataset, batch_size=BS)
Copy

Vamos dar uma olhada em um exemplo

	
from torch.utils.data import DataLoader
BS = 12
train_loader = DataLoader(train_dataset, batch_size=BS, shuffle=True)
validation_loader = DataLoader(validatation_dataset, batch_size=BS)
test_loader = DataLoader(test_dataset, batch_size=BS)
input_ids, at_mask, labels = next(iter(train_loader))
input_ids.shape, at_mask.shape, labels
Copy
	
(torch.Size([12, 768]),
torch.Size([12, 768]),
tensor([2, 1, 2, 0, 3, 3, 0, 4, 3, 3, 4, 2]))

Para verificar se está tudo certo, passamos a amostra para o modelo para ver se está tudo certo. Primeiro, passamos os tokens para o dispositivo

	
input_ids = input_ids.to(device)
at_mask = at_mask.to(device)
labels = labels.to(device)
Copy

Agora, nós os passamos para o modelo

	
input_ids = input_ids.to(device)
at_mask = at_mask.to(device)
labels = labels.to(device)
output = model(input_ids=input_ids, attention_mask=at_mask, labels=labels)
output.keys()
Copy
	
odict_keys(['loss', 'logits', 'past_key_values'])

Como podemos ver, ele nos fornece a perda e os logits.

	
output['loss']
Copy
	
tensor(5.9414, device='cuda:0', dtype=torch.float16,
grad_fn=<NllLossBackward0>)
	
output['logits']
Copy
	
tensor([[ 6.1953e+00, -1.2275e+00, -2.4824e+00, 5.8867e+00, -1.4734e+01],
[ 5.4062e+00, -8.4570e-01, -2.3203e+00, 5.1055e+00, -1.1555e+01],
[ 6.1641e+00, -9.3066e-01, -2.5664e+00, 6.0039e+00, -1.4570e+01],
[ 5.2266e+00, -4.2358e-01, -2.0801e+00, 4.7461e+00, -1.1570e+01],
[ 3.8184e+00, -2.3460e-03, -1.7666e+00, 3.4160e+00, -7.7969e+00],
[ 4.1641e+00, -4.8169e-01, -1.6914e+00, 3.9941e+00, -8.7734e+00],
[ 4.6758e+00, -3.0298e-01, -2.1641e+00, 4.1055e+00, -9.3359e+00],
[ 4.1953e+00, -3.2471e-01, -2.1875e+00, 3.9375e+00, -8.3438e+00],
[-1.1650e+00, 1.3564e+00, -6.2158e-01, -6.8115e-01, 4.8672e+00],
[ 4.4961e+00, -8.7891e-02, -2.2793e+00, 4.2812e+00, -9.3359e+00],
[ 4.9336e+00, -2.6627e-03, -2.1543e+00, 4.3711e+00, -1.0742e+01],
[ 5.9727e+00, -4.3152e-02, -1.4551e+00, 4.3438e+00, -1.2117e+01]],
device='cuda:0', dtype=torch.float16, grad_fn=<IndexBackward0>)

Métricalink image 106

Vamos criar uma função para obter a métrica, que, neste caso, será a precisão

	
def predicted_labels(logits):
percent = torch.softmax(logits, dim=1)
predictions = torch.argmax(percent, dim=1)
return predictions
Copy
	
def predicted_labels(logits):
percent = torch.softmax(logits, dim=1)
predictions = torch.argmax(percent, dim=1)
return predictions
def compute_accuracy(logits, labels):
predictions = predicted_labels(logits)
correct = (predictions == labels).float()
return correct.mean()
Copy

Vamos ver como ele calcula bem

	
def predicted_labels(logits):
percent = torch.softmax(logits, dim=1)
predictions = torch.argmax(percent, dim=1)
return predictions
def compute_accuracy(logits, labels):
predictions = predicted_labels(logits)
correct = (predictions == labels).float()
return correct.mean()
compute_accuracy(output['logits'], labels).item()
Copy
	
0.1666666716337204

Otimizadorlink image 107

Como precisaremos de um otimizador, criamos um.

	
from transformers import AdamW
LR = 2e-5
optimizer = AdamW(model.parameters(), lr=LR)
Copy
	
/usr/local/lib/python3.10/dist-packages/transformers/optimization.py:588: 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(

Treinamentolink image 108

Criamos o loop de treinamento

	
from tqdm import tqdm
EPOCHS = 3
accuracy = 0
for epoch in range(EPOCHS):
model.train()
train_loss = 0
progresbar = tqdm(train_loader, total=len(train_loader), desc=f'Epoch {epoch + 1}')
for input_ids, at_mask, labels in progresbar:
input_ids = input_ids.to(device)
at_mask = at_mask.to(device)
label = labels.to(device)
output = model(input_ids=input_ids, attention_mask=at_mask, labels=label)
loss = output['loss']
train_loss += loss.item()
optimizer.zero_grad()
loss.backward()
optimizer.step()
progresbar.set_postfix({'train_loss': loss.item()})
train_loss /= len(train_loader)
progresbar.set_postfix({'train_loss': train_loss})
model.eval()
valid_loss = 0
progresbar = tqdm(validation_loader, total=len(validation_loader), desc=f'Epoch {epoch + 1}')
for input_ids, at_mask, labels in progresbar:
input_ids = input_ids.to(device)
at_mask = at_mask.to(device)
labels = labels.to(device)
output = model(input_ids=input_ids, attention_mask=at_mask, labels=labels)
loss = output['loss']
valid_loss += loss.item()
step_accuracy = compute_accuracy(output['logits'], labels)
accuracy += step_accuracy
progresbar.set_postfix({'valid_loss': loss.item(), 'accuracy': step_accuracy.item()})
valid_loss /= len(validation_loader)
accuracy /= len(validation_loader)
progresbar.set_postfix({'valid_loss': valid_loss, 'accuracy': accuracy})
Copy
	
Epoch 1: 100%|██████████| 16667/16667 [44:13<00:00, 6.28it/s, train_loss=nan]
Epoch 1: 100%|██████████| 417/417 [00:32<00:00, 12.72it/s, valid_loss=nan, accuracy=0]
Epoch 2: 100%|██████████| 16667/16667 [44:06<00:00, 6.30it/s, train_loss=nan]
Epoch 2: 100%|██████████| 417/417 [00:32<00:00, 12.77it/s, valid_loss=nan, accuracy=0]
Epoch 3: 100%|██████████| 16667/16667 [44:03<00:00, 6.30it/s, train_loss=nan]
Epoch 3: 100%|██████████| 417/417 [00:32<00:00, 12.86it/s, valid_loss=nan, accuracy=0]

Uso do modelolink image 109

Vamos testar o modelo que treinamos

Primeiro, tokenizamos um texto

	
input_tokens = tokenize_function({"text": "I love this product. It is amazing."})
input_tokens['input_ids'].shape, input_tokens['attention_mask'].shape
Copy
	
(torch.Size([1, 768]), torch.Size([1, 768]))

Agora, passamos isso para o modelo

	
output = model(input_ids=input_tokens['input_ids'].to(device), attention_mask=input_tokens['attention_mask'].to(device))
output['logits']
Copy
	
tensor([[nan, nan, nan, nan, nan]], device='cuda:0', dtype=torch.float16,
grad_fn=<IndexBackward0>)

Vemos as previsões desses logits

	
predicted = predicted_labels(output['logits'])
predicted
Copy
	
tensor([0], device='cuda:0')

Ajuste fino para geração de texto com o Pytorchlink image 110

Repetimos o treinamento com o Pytorch

Reinicie o notebook para ter certeza de que

Conjunto de dadoslink image 111

Baixamos novamente o conjunto de dados de piadas

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

Crie um subconjunto caso você esteja com pouca memória

	
percent_of_train_dataset = 1 # If you want 50% of the dataset, set this to 0.5
subset_dataset = jokes["train"].select(range(int(len(jokes["train"]) * percent_of_train_dataset)))
subset_dataset
Copy
	
Dataset({
features: ['ID', 'Joke'],
num_rows: 231657
})

Dividimos o conjunto de dados em subconjuntos de treinamento, validação e teste.

	
percent_of_train_dataset = 0.90
split_dataset = subset_dataset.train_test_split(train_size=int(subset_dataset.num_rows * percent_of_train_dataset), seed=19, shuffle=False)
train_dataset = split_dataset["train"]
validation_test_dataset = split_dataset["test"]
split_dataset = validation_test_dataset.train_test_split(train_size=int(validation_test_dataset.num_rows * 0.5), seed=19, shuffle=False)
validation_dataset = split_dataset["train"]
test_dataset = split_dataset["test"]
print(f"Size of the train set: {len(train_dataset)}. Size of the validation set: {len(validation_dataset)}. Size of the test set: {len(test_dataset)}")
Copy
	
Size of the train set: 208491. Size of the validation set: 11583. Size of the test set: 11583

Tokeniserlink image 112

Iniciamos o tokenizador e atribuímos o token do final da string ao token de preenchimento.

	
from transformers import AutoTokenizer
checkpoints = "openai-community/gpt2"
tokenizer = AutoTokenizer.from_pretrained(checkpoints)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
Copy

Adicionamos os tokens especiais para o início e o fim de uma piada.

	
from transformers import AutoTokenizer
checkpoints = "openai-community/gpt2"
tokenizer = AutoTokenizer.from_pretrained(checkpoints)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
new_tokens = ['<SJ>', '<EJ>'] # Start and end of joke tokens
num_added_tokens = tokenizer.add_tokens(new_tokens)
print(f"Added {num_added_tokens} tokens")
Copy
	
Added 2 tokens

Nós os adicionamos ao conjunto de dados

	
joke_column = "Joke"
def format_joke(example):
example[joke_column] = '<SJ> ' + example['Joke'] + ' <EJ>'
return example
remove_columns = [column for column in train_dataset.column_names if column != joke_column]
train_dataset = train_dataset.map(format_joke, remove_columns=remove_columns)
validation_dataset = validation_dataset.map(format_joke, remove_columns=remove_columns)
test_dataset = test_dataset.map(format_joke, remove_columns=remove_columns)
train_dataset, validation_dataset, test_dataset
Copy
	
(Dataset({
features: ['Joke'],
num_rows: 208491
}),
Dataset({
features: ['Joke'],
num_rows: 11583
}),
Dataset({
features: ['Joke'],
num_rows: 11583
}))

Tokenizamos o conjunto de dados

	
def tokenize_function(examples):
return tokenizer(examples[joke_column], padding="max_length", truncation=True, max_length=768, return_tensors="pt")
train_dataset = train_dataset.map(tokenize_function, batched=True, remove_columns=[joke_column])
validation_dataset = validation_dataset.map(tokenize_function, batched=True, remove_columns=[joke_column])
test_dataset = test_dataset.map(tokenize_function, batched=True, remove_columns=[joke_column])
train_dataset, validation_dataset, test_dataset
Copy
	
(Dataset({
features: ['input_ids', 'attention_mask'],
num_rows: 208491
}),
Dataset({
features: ['input_ids', 'attention_mask'],
num_rows: 11583
}),
Dataset({
features: ['input_ids', 'attention_mask'],
num_rows: 11583
}))

Modelolink image 113

Instanciar o modelo, atribuir o token de preenchimento e adicionar os novos tokens de início e fim de piada.

	
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(checkpoints)
model.config.pad_token_id = model.config.eos_token_id
model.resize_token_embeddings(len(tokenizer))
Copy
	
Embedding(50259, 768)

Dispositivolink image 114

Criamos o dispositivo e passamos o modelo para o dispositivo.

	
import torch
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model.half().to(device)
print()
Copy
	

Conjunto de dados Pytorchlink image 115

Criar um conjunto de dados pytorch

	
from torch.utils.data import Dataset
class JokesDataset(Dataset):
def __init__(self, huggingface_dataset):
self.dataset = huggingface_dataset
def __getitem__(self, idx):
input_ids = torch.tensor(self.dataset[idx]['input_ids'])
attention_mask = torch.tensor(self.dataset[idx]['attention_mask'])
return input_ids, attention_mask
def __len__(self):
return len(self.dataset)
Copy

Instanciamos os conjuntos de dados de treinamento, validação e teste.

	
from torch.utils.data import Dataset
class JokesDataset(Dataset):
def __init__(self, huggingface_dataset):
self.dataset = huggingface_dataset
def __getitem__(self, idx):
input_ids = torch.tensor(self.dataset[idx]['input_ids'])
attention_mask = torch.tensor(self.dataset[idx]['attention_mask'])
return input_ids, attention_mask
def __len__(self):
return len(self.dataset)
train_pytorch_dataset = JokesDataset(train_dataset)
validation_pytorch_dataset = JokesDataset(validation_dataset)
test_pytorch_dataset = JokesDataset(test_dataset)
Copy

Aqui está um exemplo

	
from torch.utils.data import Dataset
class JokesDataset(Dataset):
def __init__(self, huggingface_dataset):
self.dataset = huggingface_dataset
def __getitem__(self, idx):
input_ids = torch.tensor(self.dataset[idx]['input_ids'])
attention_mask = torch.tensor(self.dataset[idx]['attention_mask'])
return input_ids, attention_mask
def __len__(self):
return len(self.dataset)
train_pytorch_dataset = JokesDataset(train_dataset)
validation_pytorch_dataset = JokesDataset(validation_dataset)
test_pytorch_dataset = JokesDataset(test_dataset)
input_ids, attention_mask = train_pytorch_dataset[0]
input_ids.shape, attention_mask.shape
Copy
	
(torch.Size([768]), torch.Size([768]))

Carregador de dados Pytorchlink image 116

Criamos os carregadores de dados

	
from torch.utils.data import DataLoader
BS = 28
train_loader = DataLoader(train_pytorch_dataset, batch_size=BS, shuffle=True)
validation_loader = DataLoader(validation_pytorch_dataset, batch_size=BS)
test_loader = DataLoader(test_pytorch_dataset, batch_size=BS)
Copy

Vemos uma amostra

	
from torch.utils.data import DataLoader
BS = 28
train_loader = DataLoader(train_pytorch_dataset, batch_size=BS, shuffle=True)
validation_loader = DataLoader(validation_pytorch_dataset, batch_size=BS)
test_loader = DataLoader(test_pytorch_dataset, batch_size=BS)
input_ids, attention_mask = next(iter(train_loader))
input_ids.shape, attention_mask.shape
Copy
	
(torch.Size([28, 768]), torch.Size([28, 768]))

Passamos isso para o modelo

	
output = model(input_ids.to(device), attention_mask=attention_mask.to(device))
output.keys()
Copy
	
odict_keys(['logits', 'past_key_values'])

Como podemos ver, não temos nenhum valor de perda, pois, como vimos, temos que passar os input_ids e os labels.

	
output = model(input_ids.to(device), attention_mask=attention_mask.to(device), labels=input_ids.to(device))
output.keys()
Copy
	
odict_keys(['loss', 'logits', 'past_key_values'])

Agora temos a "perda".

	
output['loss'].item()
Copy
	
80.5625

Otimizadorlink image 117

Criamos um otimizador

	
from transformers import AdamW
LR = 2e-5
optimizer = AdamW(model.parameters(), lr=5e-5)
Copy
	
/usr/local/lib/python3.10/dist-packages/transformers/optimization.py:588: 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(

Treinamentolink image 118

Criamos o loop de treinamento

	
from tqdm import tqdm
EPOCHS = 3
for epoch in range(EPOCHS):
model.train()
train_loss = 0
progresbar = tqdm(train_loader, total=len(train_loader), desc=f'Epoch {epoch + 1}')
for input_ids, at_mask in progresbar:
input_ids = input_ids.to(device)
at_mask = at_mask.to(device)
output = model(input_ids=input_ids, attention_mask=at_mask, labels=input_ids)
loss = output['loss']
train_loss += loss.item()
optimizer.zero_grad()
loss.backward()
optimizer.step()
progresbar.set_postfix({'train_loss': loss.item()})
train_loss /= len(train_loader)
progresbar.set_postfix({'train_loss': train_loss})
Copy
	
Epoch 1: 100%|██████████| 7447/7447 [51:07<00:00, 2.43it/s, train_loss=nan]
Epoch 2: 100%|██████████| 7447/7447 [51:06<00:00, 2.43it/s, train_loss=nan]
Epoch 3: 100%|██████████| 7447/7447 [51:07<00:00, 2.43it/s, train_loss=nan]

Uso do modelolink image 119

Testamos o modelo

	
def generate_text(decoded_joke, max_new_tokens=100, stop_token='<EJ>', top_k=0, temperature=1.0):
input_tokens = tokenize_function({'Joke': decoded_joke})
output = model(input_tokens['input_ids'].to(device), attention_mask=input_tokens['attention_mask'].to(device))
nex_token = torch.argmax(output['logits'][:, -1, :], dim=-1).item()
nex_token_decoded = tokenizer.decode(nex_token)
decoded_joke = decoded_joke + nex_token_decoded
for _ in range(max_new_tokens):
nex_token = torch.argmax(output['logits'][:, -1, :], dim=-1).item()
nex_token_decoded = tokenizer.decode(nex_token)
if nex_token_decoded == stop_token:
break
decoded_joke = decoded_joke + nex_token_decoded
input_tokens = tokenize_function({'Joke': decoded_joke})
output = model(input_tokens['input_ids'].to(device), attention_mask=input_tokens['attention_mask'].to(device))
return decoded_joke
Copy
	
def generate_text(decoded_joke, max_new_tokens=100, stop_token='<EJ>', top_k=0, temperature=1.0):
input_tokens = tokenize_function({'Joke': decoded_joke})
output = model(input_tokens['input_ids'].to(device), attention_mask=input_tokens['attention_mask'].to(device))
nex_token = torch.argmax(output['logits'][:, -1, :], dim=-1).item()
nex_token_decoded = tokenizer.decode(nex_token)
decoded_joke = decoded_joke + nex_token_decoded
for _ in range(max_new_tokens):
nex_token = torch.argmax(output['logits'][:, -1, :], dim=-1).item()
nex_token_decoded = tokenizer.decode(nex_token)
if nex_token_decoded == stop_token:
break
decoded_joke = decoded_joke + nex_token_decoded
input_tokens = tokenize_function({'Joke': decoded_joke})
output = model(input_tokens['input_ids'].to(device), attention_mask=input_tokens['attention_mask'].to(device))
return decoded_joke
generated_text = generate_text("<SJ> Why didn't the frog cross the road")
generated_text
Copy
	
"<SJ> Why didn't the frog cross the road!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"

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 -->