Transformadores de rostos abraçados
A biblioteca transformers
da Hugging Face é uma das bibliotecas mais populares para trabalhar com modelos de linguagem. Sua facilidade de uso democratizou o uso da arquitetura Transformer
e tornou possível trabalhar com modelos de linguagem de última geração sem a necessidade de ter muito conhecimento na área.
Entre a biblioteca transformers
, o hub de modelos e sua facilidade de uso, os espaços e a facilidade de implementação de demonstrações, além de novas bibliotecas como datasets
, accelerate
, PEFT
e outras, eles tornaram a Hugging Face um dos participantes mais importantes no cenário de IA no momento. Eles se autodenominam "o GitHub da IA" e certamente o são.
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..
Instalação
Para instalar transformadores, você pode fazer isso com o pip
.
pip install transformers
```
ou com `conda`.
````bash
conda install conda-forge::transformers
```
Além da biblioteca, você precisa ter um backend do PyTorch ou do TensorFlow instalado. Ou seja, você precisa ter o torch
ou o tensorflow
instalados para poder usar o transformers
.
Inferência com pipeline
.
Com os pipelines transformers
, a inferência com modelos de linguagem pode ser feita de maneira muito simples. A vantagem disso é que o desenvolvimento é muito mais rápido e a criação de protótipos pode ser feita com muita facilidade. Isso também permite que pessoas que não têm muito conhecimento usem os modelos.
Com o pipeline
, você pode fazer inferência em várias tarefas diferentes. Cada tarefa tem sua própria pipeline
(NLP pipeline
, visão pipeline
etc.), mas você pode fazer uma abstração geral usando a classe pipeline
, que se encarrega de selecionar a pipeline
correta para a tarefa que você passar a ela.
Tarefas
No momento da redação desta postagem, as tarefas que podem ser realizadas com o pipeline
são:
Áudio:
- Classificação de áudio
- Classificação de cenas acústicas: marque o áudio com um rótulo de cena ("escritório", "praia", "estádio")
- Detecção de eventos acústicos: marcar o áudio com uma etiqueta de evento sonoro ("buzina de carro", "canto de baleia", "quebra de vidro")
- Marcação: marcação de áudio contendo vários sons (canto de pássaros, identificação de oradores em uma reunião)
- Classificação musical: rotular a música com um rótulo de gênero ("metal", "hip-hop", "country")
- Classificação de áudio
Reconhecimento automático de fala (ASR, reconhecimento de fala em áudio):
Visão computacional
- Classificação de imagens
- Detecção de objetos
- Segmentação de imagens
- Estimativa de profundidade
Processamento de linguagem natural (NLP) * Processamento de linguagem natural (NLP)
Classificação do texto
- Análise de sentimento
- Classificação do conteúdo
Classificação dos tokens
- Reconhecimento de entidades nomeadas (NER): marca um token de acordo com uma categoria de entidade, como organização, pessoa, local ou data.
- Marcação de parte do discurso (POS): marcação de um token de acordo com sua parte do discurso, como substantivo, verbo ou adjetivo. O POS é útil para ajudar os sistemas de tradução a entender como duas palavras idênticas são gramaticalmente diferentes (por exemplo, "cut" como substantivo versus "cut" como verbo).
Respostas às perguntas
- Extrativo: dada uma pergunta e algum contexto, a resposta é um trecho de texto do contexto que o modelo deve extrair.
- Resumo: dada uma pergunta e algum contexto, a resposta é gerada a partir do contexto; essa abordagem é tratada pelo Text2TextGenerationPipeline em vez do QuestionAnsweringPipeline mostrado abaixo.
Resumir
- Extrativo: identifica e extrai as frases mais importantes do texto original
- abstrativo: gera o resumo de destino (que pode incluir novas palavras não presentes no documento de entrada) a partir do texto original
Tradução
Modelagem de linguagem
- causal: o objetivo do modelo é prever o próximo token em uma sequência, e os tokens futuros são mascarados
- Mascarado: o objetivo do modelo é prever um token mascarado em um fluxo com acesso total aos tokens no fluxo.
Multimodal
- Respostas a perguntas sobre documentos
Uso de pipeline
A maneira mais fácil de criar uma pipeline
é simplesmente informar a tarefa que queremos que ela resolva usando o parâmetro task
. E a biblioteca selecionará o melhor modelo para essa tarefa, fará o download e o armazenará em cache para uso futuro.
from transformers import pipelinegenerator = pipeline(task="text-generation")
No model was supplied, defaulted to openai-community/gpt2 and revision 6c0e608 (https://huggingface.co/openai-community/gpt2).Using a pipeline without specifying a model name and revision in production is not recommended.
generator("Me encanta aprender de")
Como você pode ver, o texto gerado está em francês, embora eu o tenha apresentado em espanhol, por isso é importante escolher o modelo correto. Se você observar a biblioteca, ela utilizou o modelo openai-community/gpt2
, que é um modelo treinado principalmente em inglês, e quando coloquei o texto em espanhol, ele ficou confuso e gerou uma resposta em francês.
Usaremos um modelo treinado novamente em inglês usando o parâmetro model
.
generator("Me encanta aprender de")from transformers import pipelinegenerator = pipeline(task="text-generation", model="flax-community/gpt-2-spanish")
generator("Me encanta aprender de")
O texto gerado agora tem uma aparência muito melhor
A classe pipeline
tem muitos parâmetros possíveis, portanto, para ver todos eles e saber mais sobre a classe, recomendo a leitura de sua [documentação] (https://huggingface.co/docs/transformers/v4.38.1/en/main_classes/pipelines), mas vamos falar sobre um deles, pois, para o aprendizado profundo, ele é muito importante e é o device
. Ele define o dispositivo (por exemplo, cpu
, cuda:1
, mps
ou um intervalo ordinal de GPUs como 1
) no qual a pipeline
será mapeada.
No meu caso, como tenho uma GPU, defini 0
.
from transformers import pipeline
generator = pipeline(task="text-generation", model="flax-community/gpt-2-spanish", device=0)
generation = generator("Me encanta aprender de")
print(generation[0]['generated_text'])
Como funciona o `pipeline
Quando usamos pipeline
por baixo, o que está acontecendo é o seguinte
transformers-pipeline](https://pub-fb664c455eca46a2ba762a065ac900f7.r2.dev/transformers-pipeline.svg)
O texto é automaticamente tokenizado, passado pelo modelo e depois pós-processado.
Inferência com AutoClass
e pipeline
.
Vimos que o pipeline
abstrai muito do que acontece, mas podemos selecionar qual tokenizador, qual modelo e qual pós-processamento queremos usar.
Tokenização com AutoTokenizer
.
Antes de usarmos o modelo flax-community/gpt-2-spanish
para gerar texto, podemos usar seu tokenizador
generator("Me encanta aprender de")from transformers import pipelinegenerator = pipeline(task="text-generation", model="flax-community/gpt-2-spanish")generator("Me encanta aprender de")from transformers import pipelinegenerator = pipeline(task="text-generation", model="flax-community/gpt-2-spanish", device=0)generation = generator("Me encanta aprender de")print(generation[0]['generated_text'])from transformers import AutoTokenizercheckpoint = "flax-community/gpt-2-spanish"tokenizer = AutoTokenizer.from_pretrained(checkpoint)text = "Me encanta lo que estoy aprendiendo"tokens = tokenizer(text, return_tensors="pt")print(tokens)
Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.{'input_ids': tensor([[ 2879, 4835, 382, 288, 2383, 15257]]), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1]])}
Modelo AutoModel
.
Agora podemos criar o modelo e passar os tokens para ele.
from transformers import AutoModelmodel = AutoModel.from_pretrained("flax-community/gpt-2-spanish")output = model(**tokens)type(output), output.keys()
(transformers.modeling_outputs.BaseModelOutputWithPastAndCrossAttentions,odict_keys(['last_hidden_state', 'past_key_values']))
Se agora tentarmos usá-lo em uma pipeline
, receberemos um erro.
from transformers import pipeline
pipeline("text-generation", model=model, tokenizer=tokenizer)("Me encanta aprender de")
Isso se deve ao fato de que, quando funcionava, usávamos
pipeline(task="text-generation", model="flax-community/gpt-2-spanish")
```
Mas agora nós fizemos
tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")
model = AutoModel.from_pretrained("flax-community/gpt-2-spanish")
pipeline("text-generation", model=model, tokenizer=tokenizer)
```
No primeiro caso, usamos apenas pipeline
e o nome do modelo e, abaixo dele, estávamos procurando a melhor maneira de implementar o modelo e o tokenizador. Mas, no segundo caso, criamos o tokenizador e o modelo e o passamos para pipeline
, mas não o criamos de acordo com as necessidades de pipeline
.
Para corrigir isso, usamos o AutoModelFor
.
Modelo AutoModelFor
.
A biblioteca de transformadores nos dá a oportunidade de criar um modelo para uma determinada tarefa, como
AutoModelForCausalLM
, que é usado para continuar os textos- AutoModelForMaskedLM` usado para preencher lacunas
AutoModelForMaskGeneration
, que é usado para gerar máscaras- AutoModelForSeq2SeqLM, que é usado para converter de sequências em sequências, por exemplo, na tradução.
AutoModelForSequenceClassification
para classificação de texto- AutoModelForMultipleChoice` para múltipla escolha
AutoModelForNextSentencePrediction
para prever se duas frases são consecutivasAutoModelForTokenClassification
para classificação de tokens- AutoModelForQuestionAnswering` para perguntas e respostas
AutoModelForTextEncoding
para codificação de texto
Vamos usar o modelo acima para gerar texto
from transformers import AutoTokenizer, AutoModelForCausalLM
from transformers import pipeline
tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")
model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish")
pipeline("text-generation", model=model, tokenizer=tokenizer)("Me encanta aprender de")[0]['generated_text']
Agora funciona, porque criamos o modelo de uma forma que o pipeline
pode entender.
Inferência somente com AutoClass
.
Anteriormente, criamos o modelo e o tokenizador e o fornecemos ao pipeline
para fazer o necessário, mas podemos usar os métodos de inferência por conta própria.
Geração de texto casual
Criamos o modelo e o tokenizador
from transformers import pipelinepipeline("text-generation", model=model, tokenizer=tokenizer)("Me encanta aprender de")from transformers import AutoTokenizer, AutoModelForCausalLMfrom transformers import pipelinetokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish")pipeline("text-generation", model=model, tokenizer=tokenizer)("Me encanta aprender de")[0]['generated_text']from transformers import AutoTokenizer, AutoModelForCausalLMtokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)
Com device_map
, carregamos o modelo na GPU 0.
Agora temos que fazer o que o pipeline
costumava fazer.
Primeiro, geramos os tokens
from transformers import pipelinepipeline("text-generation", model=model, tokenizer=tokenizer)("Me encanta aprender de")from transformers import AutoTokenizer, AutoModelForCausalLMfrom transformers import pipelinetokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish")pipeline("text-generation", model=model, tokenizer=tokenizer)("Me encanta aprender de")[0]['generated_text']from transformers import AutoTokenizer, AutoModelForCausalLMtokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")
The model 'GPT2Model' is not supported for text-generation. Supported models are ['BartForCausalLM', 'BertLMHeadModel', 'BertGenerationDecoder', 'BigBirdForCausalLM', 'BigBirdPegasusForCausalLM', 'BioGptForCausalLM', 'BlenderbotForCausalLM', 'BlenderbotSmallForCausalLM', 'BloomForCausalLM', 'CamembertForCausalLM', 'LlamaForCausalLM', 'CodeGenForCausalLM', 'CpmAntForCausalLM', 'CTRLLMHeadModel', 'Data2VecTextForCausalLM', 'ElectraForCausalLM', 'ErnieForCausalLM', 'FalconForCausalLM', 'FuyuForCausalLM', 'GemmaForCausalLM', 'GitForCausalLM', 'GPT2LMHeadModel', 'GPT2LMHeadModel', 'GPTBigCodeForCausalLM', 'GPTNeoForCausalLM', 'GPTNeoXForCausalLM', 'GPTNeoXJapaneseForCausalLM', 'GPTJForCausalLM', 'LlamaForCausalLM', 'MarianForCausalLM', 'MBartForCausalLM', 'MegaForCausalLM', 'MegatronBertForCausalLM', 'MistralForCausalLM', 'MixtralForCausalLM', 'MptForCausalLM', 'MusicgenForCausalLM', 'MvpForCausalLM', 'OpenLlamaForCausalLM', 'OpenAIGPTLMHeadModel', 'OPTForCausalLM', 'PegasusForCausalLM', 'PersimmonForCausalLM', 'PhiForCausalLM', 'PLBartForCausalLM', 'ProphetNetForCausalLM', 'QDQBertLMHeadModel', 'Qwen2ForCausalLM', 'ReformerModelWithLMHead', 'RemBertForCausalLM', 'RobertaForCausalLM', 'RobertaPreLayerNormForCausalLM', 'RoCBertForCausalLM', 'RoFormerForCausalLM', 'RwkvForCausalLM', 'Speech2Text2ForCausalLM', 'StableLmForCausalLM', 'TransfoXLLMHeadModel', 'TrOCRForCausalLM', 'WhisperForCausalLM', 'XGLMForCausalLM', 'XLMWithLMHeadModel', 'XLMProphetNetForCausalLM', 'XLMRobertaForCausalLM', 'XLMRobertaXLForCausalLM', 'XLNetLMHeadModel', 'XmodForCausalLM'].Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.---------------------------------------------------------------------------ValueError Traceback (most recent call last)Cell In[2], line 1----> 1 tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")File ~/miniconda3/envs/nlp/lib/python3.11/site-packages/transformers/tokenization_utils_base.py:2829, 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)2827 if not self._in_target_context_manager:2828 self._switch_to_input_mode()-> 2829 encodings = self._call_one(text=text, text_pair=text_pair, **all_kwargs)2830 if text_target is not None:2831 self._switch_to_target_mode()File ~/miniconda3/envs/nlp/lib/python3.11/site-packages/transformers/tokenization_utils_base.py:2915, 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)2910 raise ValueError(2911 f"batch length of `text`: {len(text)} does not match batch length of `text_pair`:"2912 f" {len(text_pair)}."2913 )2914 batch_text_or_text_pairs = list(zip(text, text_pair)) if text_pair is not None else text-> 2915 return self.batch_encode_plus(2916 batch_text_or_text_pairs=batch_text_or_text_pairs,2917 add_special_tokens=add_special_tokens,2918 padding=padding,2919 truncation=truncation,2920 max_length=max_length,2921 stride=stride,2922 is_split_into_words=is_split_into_words,2923 pad_to_multiple_of=pad_to_multiple_of,2924 return_tensors=return_tensors,2925 return_token_type_ids=return_token_type_ids,2926 return_attention_mask=return_attention_mask,2927 return_overflowing_tokens=return_overflowing_tokens,2928 return_special_tokens_mask=return_special_tokens_mask,2929 return_offsets_mapping=return_offsets_mapping,2930 return_length=return_length,2931 verbose=verbose,2932 **kwargs,2933 )2934 else:2935 return self.encode_plus(2936 text=text,2937 text_pair=text_pair,(...)2953 **kwargs,2954 )File ~/miniconda3/envs/nlp/lib/python3.11/site-packages/transformers/tokenization_utils_base.py:3097, in PreTrainedTokenizerBase.batch_encode_plus(self, batch_text_or_text_pairs, 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)3080 """3081 Tokenize and prepare for the model a list of sequences or a list of pairs of sequences.3082(...)3093 details in `encode_plus`).3094 """3096 # Backward compatibility for 'truncation_strategy', 'pad_to_max_length'-> 3097 padding_strategy, truncation_strategy, max_length, kwargs = self._get_padding_truncation_strategies(3098 padding=padding,3099 truncation=truncation,3100 max_length=max_length,3101 pad_to_multiple_of=pad_to_multiple_of,3102 verbose=verbose,3103 **kwargs,3104 )3106 return self._batch_encode_plus(3107 batch_text_or_text_pairs=batch_text_or_text_pairs,3108 add_special_tokens=add_special_tokens,(...)3123 **kwargs,3124 )File ~/miniconda3/envs/nlp/lib/python3.11/site-packages/transformers/tokenization_utils_base.py:2734, in PreTrainedTokenizerBase._get_padding_truncation_strategies(self, padding, truncation, max_length, pad_to_multiple_of, verbose, **kwargs)2732 # Test if we have a padding token2733 if padding_strategy != PaddingStrategy.DO_NOT_PAD and (self.pad_token is None or self.pad_token_id < 0):-> 2734 raise ValueError(2735 "Asking to pad but the tokenizer does not have a padding token. "2736 "Please select a token to use as `pad_token` `(tokenizer.pad_token = tokenizer.eos_token e.g.)` "2737 "or add a new pad token via `tokenizer.add_special_tokens({'pad_token': '[PAD]'})`."2738 )2740 # Check that we will truncate to a multiple of pad_to_multiple_of if both are provided2741 if (2742 truncation_strategy != TruncationStrategy.DO_NOT_TRUNCATE2743 and padding_strategy != PaddingStrategy.DO_NOT_PAD(...)2746 and (max_length % pad_to_multiple_of != 0)2747 ):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]'})`.
Vemos que ele nos deu um erro, informando que o tokenizador não tem um token de preenchimento. A maioria dos LLMs não tem um token de preenchimento, mas para usar a biblioteca transformers
você precisa de um token de preenchimento, então o que você normalmente faz é atribuir o token de fim de frase ao token de preenchimento.
tokenizer.pad_token = tokenizer.eos_token
Agora podemos gerar os tokens
tokenizer.pad_token = tokenizer.eos_tokentokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")tokens_input.input_ids
tensor([[2879, 4835, 3760, 225, 72, 73]], device='cuda:0')
Agora, nós os passamos para o modelo que gerará novos tokens e, para isso, usamos o método generate
.
tokens_output = model.generate(**tokens_input, max_length=50)
print(f"input tokens: {tokens_input.input_ids}")
print(f"output tokens: {tokens_output}")
Podemos ver que os primeiros tokens token_inputs
são iguais aos tokens token_outputs
; os tokens a seguir são os gerados pelo modelo
Agora temos que converter esses tokens em uma frase usando o decodificador do tokenizador.
tokens_output = model.generate(**tokens_input, max_length=50)print(f"input tokens: {tokens_input.input_ids}")print(f"output tokens: {tokens_output}")sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)sentence_output
Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.'Me encanta aprender de los demás, y en este caso de los que me rodean, y es que en el fondo, es una forma de aprender de los demás. '
Já temos o texto gerado
Classificação do texto
Criamos o modelo e o tokenizador
import torchfrom transformers import AutoTokenizer, AutoModelForSequenceClassificationtokenizer = AutoTokenizer.from_pretrained("stevhliu/my_awesome_model")model = AutoModelForSequenceClassification.from_pretrained("stevhliu/my_awesome_model", device_map=0)
Geramos os tokens
import torchfrom transformers import AutoTokenizer, AutoModelForSequenceClassificationtokenizer = AutoTokenizer.from_pretrained("stevhliu/my_awesome_model")model = AutoModelForSequenceClassification.from_pretrained("stevhliu/my_awesome_model", device_map=0)text = "This was a masterpiece. Not completely faithful to the books, but enthralling from beginning to end. Might be my favorite of the three."inputs = tokenizer(text, return_tensors="pt").to("cuda")
Quando tivermos os tokens, classificaremos
import torchfrom transformers import AutoTokenizer, AutoModelForSequenceClassificationtokenizer = AutoTokenizer.from_pretrained("stevhliu/my_awesome_model")model = AutoModelForSequenceClassification.from_pretrained("stevhliu/my_awesome_model", device_map=0)text = "This was a masterpiece. Not completely faithful to the books, but enthralling from beginning to end. Might be my favorite of the three."inputs = tokenizer(text, return_tensors="pt").to("cuda")with torch.no_grad():logits = model(**inputs).logitspredicted_class_id = logits.argmax().item()prediction = model.config.id2label[predicted_class_id]prediction
'LABEL_1'
Vamos dar uma olhada nas classes
clases = model.config.id2labelclases
{0: 'LABEL_0', 1: 'LABEL_1'}
Dessa forma, ninguém pode descobrir, então nós o modificamos.
model.config.id2label = {0: "NEGATIVE", 1: "POSITIVE"}
E agora estamos de volta à classificação
model.config.id2label = {0: "NEGATIVE", 1: "POSITIVE"}with torch.no_grad():logits = model(**inputs).logitspredicted_class_id = logits.argmax().item()prediction = model.config.id2label[predicted_class_id]prediction
'POSITIVE'
Classificação de tokens
Criamos o modelo e o tokenizador
import torchfrom transformers import AutoTokenizer, AutoModelForTokenClassificationtokenizer = AutoTokenizer.from_pretrained("stevhliu/my_awesome_wnut_model")model = AutoModelForTokenClassification.from_pretrained("stevhliu/my_awesome_wnut_model", device_map=0)
Geramos os tokens
import torchfrom transformers import AutoTokenizer, AutoModelForTokenClassificationtokenizer = AutoTokenizer.from_pretrained("stevhliu/my_awesome_wnut_model")model = AutoModelForTokenClassification.from_pretrained("stevhliu/my_awesome_wnut_model", device_map=0)text = "The Golden State Warriors are an American professional basketball team based in San Francisco."inputs = tokenizer(text, return_tensors="pt").to("cuda")
Quando tivermos os tokens, classificaremos
import torchfrom transformers import AutoTokenizer, AutoModelForTokenClassificationtokenizer = AutoTokenizer.from_pretrained("stevhliu/my_awesome_wnut_model")model = AutoModelForTokenClassification.from_pretrained("stevhliu/my_awesome_wnut_model", device_map=0)text = "The Golden State Warriors are an American professional basketball team based in San Francisco."inputs = tokenizer(text, return_tensors="pt").to("cuda")with torch.no_grad():logits = model(**inputs).logitspredictions = torch.argmax(logits, dim=2)predicted_token_class = [model.config.id2label[t.item()] for t in predictions[0]]for i in range(len(inputs.input_ids[0])):print(f"{inputs.input_ids[0][i]} ({tokenizer.decode([inputs.input_ids[0][i]])}) -> {predicted_token_class[i]}")
101 ([CLS]) -> O1996 (the) -> O3585 (golden) -> B-location2110 (state) -> I-location6424 (warriors) -> B-group2024 (are) -> O2019 (an) -> O2137 (american) -> O2658 (professional) -> O3455 (basketball) -> O2136 (team) -> O2241 (based) -> O1999 (in) -> O2624 (san) -> B-location3799 (francisco) -> B-location1012 (.) -> O102 ([SEP]) -> O
Como você pode ver, os tokens correspondentes a golden
, state
, warriors
, san
e francisco
foram classificados como tokens de localização.
Resposta à pergunta
Criamos o modelo e o tokenizador
import torchfrom transformers import AutoTokenizer, AutoModelForQuestionAnsweringtokenizer = AutoTokenizer.from_pretrained("mrm8488/roberta-base-1B-1-finetuned-squadv1")model = AutoModelForQuestionAnswering.from_pretrained("mrm8488/roberta-base-1B-1-finetuned-squadv1", device_map=0)
Some weights of the model checkpoint at mrm8488/roberta-base-1B-1-finetuned-squadv1 were not used when initializing RobertaForQuestionAnswering: ['roberta.pooler.dense.bias', 'roberta.pooler.dense.weight']- This IS expected if you are initializing RobertaForQuestionAnswering from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).- This IS NOT expected if you are initializing RobertaForQuestionAnswering from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).
Geramos os tokens
question = "How many programming languages does BLOOM support?"context = "BLOOM has 176 billion parameters and can generate text in 46 languages natural languages and 13 programming languages."inputs = tokenizer(question, context, return_tensors="pt").to("cuda")
Quando tivermos os tokens, classificaremos
question = "How many programming languages does BLOOM support?"context = "BLOOM has 176 billion parameters and can generate text in 46 languages natural languages and 13 programming languages."inputs = tokenizer(question, context, return_tensors="pt").to("cuda")with torch.no_grad():outputs = model(**inputs)answer_start_index = outputs.start_logits.argmax()answer_end_index = outputs.end_logits.argmax()predict_answer_tokens = inputs.input_ids[0, answer_start_index : answer_end_index + 1]tokenizer.decode(predict_answer_tokens)
' 13'
Modelagem de linguagem com máscara (Modelagem de linguagem com máscara)
Criamos o modelo e o tokenizador
import torchfrom transformers import AutoTokenizer, AutoModelForMaskedLMtokenizer = AutoTokenizer.from_pretrained("nyu-mll/roberta-base-1B-1")model = AutoModelForMaskedLM.from_pretrained("nyu-mll/roberta-base-1B-1", device_map=0)
Some weights of the model checkpoint at nyu-mll/roberta-base-1B-1 were not used when initializing RobertaForMaskedLM: ['roberta.pooler.dense.bias', 'roberta.pooler.dense.weight']- This IS expected if you are initializing RobertaForMaskedLM from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).- This IS NOT expected if you are initializing RobertaForMaskedLM from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).
Geramos os tokens
text = "The Milky Way is a <mask> galaxy."inputs = tokenizer(text, return_tensors="pt").to("cuda")mask_token_index = torch.where(inputs["input_ids"] == tokenizer.mask_token_id)[1]
Quando tivermos os tokens, classificaremos
text = "The Milky Way is a <mask> galaxy."inputs = tokenizer(text, return_tensors="pt").to("cuda")mask_token_index = torch.where(inputs["input_ids"] == tokenizer.mask_token_id)[1]with torch.no_grad():logits = model(**inputs).logitsmask_token_logits = logits[0, mask_token_index, :]top_3_tokens = torch.topk(mask_token_logits, 3, dim=1).indices[0].tolist()for token in top_3_tokens:print(text.replace(tokenizer.mask_token, tokenizer.decode([token])))
The Milky Way is a spiral galaxy.The Milky Way is a closed galaxy.The Milky Way is a distant galaxy.
Personalização do modelo
Anteriormente, fizemos a inferência com o AutoClass
, mas fizemos isso com as configurações padrão do modelo. Mas podemos configurar o modelo como quisermos.
Vamos instanciar um modelo e dar uma olhada em sua configuração
from transformers import AutoTokenizer, AutoModelForCausalLM, AutoConfigtokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)config = AutoConfig.from_pretrained("flax-community/gpt-2-spanish")config
GPT2Config {"_name_or_path": "flax-community/gpt-2-spanish","activation_function": "gelu_new","architectures": ["GPT2LMHeadModel"],"attn_pdrop": 0.0,"bos_token_id": 50256,"embd_pdrop": 0.0,"eos_token_id": 50256,"gradient_checkpointing": false,"initializer_range": 0.02,"layer_norm_epsilon": 1e-05,"model_type": "gpt2","n_ctx": 1024,"n_embd": 768,"n_head": 12,"n_inner": null,"n_layer": 12,"n_positions": 1024,"reorder_and_upcast_attn": false,"resid_pdrop": 0.0,"scale_attn_by_inverse_layer_idx": false,"scale_attn_weights": true,"summary_activation": null,"summary_first_dropout": 0.1,"summary_proj_to_labels": true,"summary_type": "cls_index","summary_use_proj": true,"task_specific_params": {"text-generation": {"do_sample": true,"max_length": 50}},"transformers_version": "4.38.1","use_cache": true,"vocab_size": 50257}
Podemos ver a configuração do modelo, por exemplo, a função de ativação é gelu_new
, ele tem 12 head
s`, o tamanho do vocabulário é 50257 palavras etc.
Mas podemos modificar essa configuração
config = AutoConfig.from_pretrained("flax-community/gpt-2-spanish", activation_function="relu")config.activation_function
'relu'
Agora, criamos o modelo com esta configuração
model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", config=config, device_map=0)
E geramos o texto
tokenizer.pad_token = tokenizer.eos_token
tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")
tokens_output = model.generate(**tokens_input, max_length=50)
sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)
sentence_output
Vemos que essa modificação não gera um texto tão bom.
Tokenização
Até agora, vimos as diferentes maneiras de fazer inferência com a biblioteca transformers
. Agora, vamos nos aprofundar nas entranhas da biblioteca. Para isso, primeiro veremos o que devemos ter em mente ao fazer tokenização.
Não vamos explicar detalhadamente o que é tokenização, pois já explicamos isso na postagem sobre a biblioteca [tokenizers] (https://maximofn.com/hugging-face-tokenizers/).
Preenchimento
Quando você tem um lote de sequências, às vezes é necessário que, após a tokenização, todas as sequências tenham o mesmo comprimento, portanto, usamos o parâmetro padding=True
para isso.
model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", config=config, device_map=0)tokenizer.pad_token = tokenizer.eos_tokentokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")tokens_output = model.generate(**tokens_input, max_length=50)sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)sentence_outputfrom transformers import AutoTokenizerbatch_sentences = ["Pero, ¿qué pasa con el segundo desayuno?","No creo que sepa lo del segundo desayuno, Pedro","¿Qué hay de los elevensies?",]tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish", pad_token="PAD")encoded_input = tokenizer(batch_sentences, padding=True)for encoded in encoded_input["input_ids"]:print(encoded)print(f"Padding token id: {tokenizer.pad_token_id}")
Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.[2959, 16, 875, 3736, 3028, 303, 291, 2200, 8080, 35, 50257, 50257][1489, 2275, 288, 12052, 382, 325, 2200, 8080, 16, 4319, 50257, 50257][1699, 2899, 707, 225, 72, 73, 314, 34630, 474, 515, 1259, 35]Padding token id: 50257
Como podemos ver, ele adicionou paddings às duas primeiras sequências no final.
Truncado
Além de adicionar preenchimento, às vezes é necessário truncar as sequências para que elas não ocupem mais do que um determinado número de tokens. Para fazer isso, definimos truncation=True
e max_length
como o número de tokens que queremos que a sequência tenha.
from transformers import AutoTokenizerbatch_sentences = ["Pero, ¿qué pasa con el segundo desayuno?","No creo que sepa lo del segundo desayuno, Pedro","¿Qué hay de los elevensies?",]tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")encoded_input = tokenizer(batch_sentences, truncation=True, max_length=5)for encoded in encoded_input["input_ids"]:print(encoded)
[2959, 16, 875, 3736, 3028][1489, 2275, 288, 12052, 382][1699, 2899, 707, 225, 72]
As mesmas frases de antes agora geram menos tokens.
Tensionadores
Até agora, temos recebido listas de tokens, mas provavelmente estamos interessados em receber tensores do PyTorch ou do TensorFlow. Para fazer isso, usamos o parâmetro return_tensors
e especificamos de qual estrutura queremos receber o tensor; em nosso caso, escolheremos o PyTorch com pt
.
Primeiro, vemos que, sem especificar que retornamos tensores
from transformers import AutoTokenizerbatch_sentences = ["Pero, ¿qué pasa con el segundo desayuno?","No creo que sepa lo del segundo desayuno, Pedro","¿Qué hay de los elevensies?",]tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish", pad_token="PAD")encoded_input = tokenizer(batch_sentences, padding=True)for encoded in encoded_input["input_ids"]:print(type(encoded))
<class 'list'><class 'list'><class 'list'>
Recebemos listas; se quisermos receber tensores do PyTorch, usaremos return_tensors="pt"
.
from transformers import AutoTokenizerbatch_sentences = ["Pero, ¿qué pasa con el segundo desayuno?","No creo que sepa lo del segundo desayuno, Pedro","¿Qué hay de los elevensies?",]tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish", pad_token="PAD")encoded_input = tokenizer(batch_sentences, padding=True, return_tensors="pt")for encoded in encoded_input["input_ids"]:print(type(encoded), encoded.shape)print(type(encoded_input["input_ids"]), encoded_input["input_ids"].shape)
<class 'torch.Tensor'> torch.Size([12])<class 'torch.Tensor'> torch.Size([12])<class 'torch.Tensor'> torch.Size([12])<class 'torch.Tensor'> torch.Size([3, 12])
Máscaras
Quando tokenizamos uma declaração, obtemos não apenas os input_ids
, mas também a máscara de atenção. A máscara de atenção é um tensor que tem o mesmo tamanho de input_ids
e tem um 1
nas posições que são tokens e um 0
nas posições que são padding.
from transformers import AutoTokenizerbatch_sentences = ["Pero, ¿qué pasa con el segundo desayuno?","No creo que sepa lo del segundo desayuno, Pedro","¿Qué hay de los elevensies?",]tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish", pad_token="PAD")encoded_input = tokenizer(batch_sentences, padding=True)print(f"padding token id: {tokenizer.pad_token_id}")print(f" encoded_input[0] inputs_ids: {encoded_input['input_ids'][0]}")print(f"encoded_input[0] attention_mask: {encoded_input['attention_mask'][0]}")print(f" encoded_input[1] inputs_ids: {encoded_input['input_ids'][1]}")print(f"encoded_input[1] attention_mask: {encoded_input['attention_mask'][1]}")print(f" encoded_input[2] inputs_ids: {encoded_input['input_ids'][2]}")print(f"encoded_input[2] attention_mask: {encoded_input['attention_mask'][2]}")
padding token id: 50257encoded_input[0] inputs_ids: [2959, 16, 875, 3736, 3028, 303, 291, 2200, 8080, 35, 50257, 50257]encoded_input[0] attention_mask: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0]encoded_input[1] inputs_ids: [1489, 2275, 288, 12052, 382, 325, 2200, 8080, 16, 4319, 50257, 50257]encoded_input[1] attention_mask: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0]encoded_input[2] inputs_ids: [1699, 2899, 707, 225, 72, 73, 314, 34630, 474, 515, 1259, 35]encoded_input[2] attention_mask: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
Como você pode ver, nas duas primeiras frases, temos um 1 nas duas primeiras posições e um 0 nas duas últimas posições. Nessas mesmas posições, temos o token 50257
, que corresponde ao token de preenchimento.
Com essas máscaras de atenção, estamos informando ao modelo em quais tokens devemos prestar atenção e em quais não devemos prestar atenção.
A geração de texto ainda poderia ser feita se não passássemos essas máscaras de atenção, o método generate
faria o possível para inferir essa máscara, mas se a passarmos, ajudaremos a gerar um texto melhor.
Tokenizadores rápidos
Alguns tokenizadores pré-treinados têm uma versão "rápida", com os mesmos métodos que os tokenizadores normais, mas são desenvolvidos em Rust. Para utilizá-los, devemos usar a classe PreTrainedTokenizerFast
da biblioteca transformers
.
Vamos primeiro analisar o tempo de tokenização com um tokenizador normal.
%%timefrom transformers import BertTokenizertokenizer = BertTokenizer.from_pretrained("google-bert/bert-base-uncased")sentence = ("The Permaculture Design Principles are a set of universal design principles ""that can be applied to any location, climate and culture, and they allow us to design ""the most efficient and sustainable human habitation and food production systems. ""Permaculture is a design system that encompasses a wide variety of disciplines, such ""as ecology, landscape design, environmental science and energy conservation, and the ""Permaculture design principles are drawn from these various disciplines. Each individual ""design principle itself embodies a complete conceptual framework based on sound ""scientific principles. When we bring all these separate principles together, we can ""create a design system that both looks at whole systems, the parts that these systems ""consist of, and how those parts interact with each other to create a complex, dynamic, ""living system. Each design principle serves as a tool that allows us to integrate all ""the separate parts of a design, referred to as elements, into a functional, synergistic, ""whole system, where the elements harmoniously interact and work together in the most ""efficient way possible.")tokens = tokenizer([sentence], padding=True, return_tensors="pt")
CPU times: user 55.3 ms, sys: 8.58 ms, total: 63.9 msWall time: 226 ms
E agora uma rápida
%%timefrom transformers import BertTokenizerFasttokenizer = BertTokenizerFast.from_pretrained("google-bert/bert-base-uncased")sentence = ("The Permaculture Design Principles are a set of universal design principles ""that can be applied to any location, climate and culture, and they allow us to design ""the most efficient and sustainable human habitation and food production systems. ""Permaculture is a design system that encompasses a wide variety of disciplines, such ""as ecology, landscape design, environmental science and energy conservation, and the ""Permaculture design principles are drawn from these various disciplines. Each individual ""design principle itself embodies a complete conceptual framework based on sound ""scientific principles. When we bring all these separate principles together, we can ""create a design system that both looks at whole systems, the parts that these systems ""consist of, and how those parts interact with each other to create a complex, dynamic, ""living system. Each design principle serves as a tool that allows us to integrate all ""the separate parts of a design, referred to as elements, into a functional, synergistic, ""whole system, where the elements harmoniously interact and work together in the most ""efficient way possible.")tokens = tokenizer([sentence], padding=True, return_tensors="pt")
CPU times: user 42.6 ms, sys: 3.26 ms, total: 45.8 msWall time: 179 ms
Você pode ver como o BertTokenizerFast
é cerca de 40 ms mais rápido.
Formas de geração de texto
Continuando com as entranhas da biblioteca transformers
, vamos agora examinar as maneiras de gerar texto.
A arquitetura do transformador gera o próximo token mais provável. Essa é a maneira mais simples de gerar texto, mas não é a única, portanto, vamos dar uma olhada nelas.
Quando se trata de gerar um texto, não há uma maneira melhor e isso dependerá do nosso modelo e da finalidade do uso.
Busca ambiciosa
Essa é a maneira mais simples de gerar texto. Encontre o token mais provável em cada iteração.
Para gerar texto dessa forma com transformers
, você não precisa fazer nada de especial, pois essa é a forma padrão.
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)
tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")
tokens_output = model.generate(**tokens_input, max_new_tokens=500)
sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)
print(sentence_output)
Você pode ver que o texto gerado está bom, mas ele começa a se repetir. Isso ocorre porque, na pesquisa gananciosa, as palavras com alta probabilidade podem se esconder atrás de palavras com probabilidade mais baixa e, portanto, podem se perder.
Aqui, a palavra has
tem uma alta probabilidade, mas está escondida atrás de dog
, que tem uma probabilidade menor do que nice
.
Pesquisa Contrastiva
O método Contrastive Search otimiza a geração de texto selecionando opções de palavras ou frases que maximizam um critério de qualidade em detrimento de outras menos desejáveis. Na prática, isso significa que, durante a geração do texto, em cada etapa, o modelo não só procura a próxima palavra com maior probabilidade de seguir o que foi aprendido durante o treinamento, mas também compara diferentes candidatos para essa próxima palavra e avalia qual deles contribuiria para formar o texto mais coerente, relevante e de alta qualidade no contexto em questão. Portanto, a pesquisa contrastiva reduz a possibilidade de gerar respostas irrelevantes ou de baixa qualidade, concentrando-se nas opções que melhor se adaptam ao objetivo de geração de texto, com base em uma comparação direta entre as possíveis continuações em cada etapa do processo.
Para gerar texto com pesquisa contrastiva em transformers
, é necessário usar os parâmetros penalty_alpha
e top_k
ao gerar o texto.
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)
tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")
tokens_output = model.generate(**tokens_input, max_new_tokens=500, penalty_alpha=0.6, top_k=4)
sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)
print(sentence_output)
Aqui o padrão leva mais tempo para começar a se repetir.
Amostragem multinomial
Diferentemente da pesquisa gulosa, que sempre escolhe um token com a maior probabilidade como o próximo token, a amostragem multinomial (também chamada de amostragem ancestral) seleciona aleatoriamente o próximo token com base na distribuição de probabilidade de todo o vocabulário fornecido pelo modelo. Cada token com uma probabilidade diferente de zero tem uma chance de ser selecionado, o que reduz o risco de repetição.
Para ativar a Amostragem multinomial
, defina do_sample=True
e num_beams=1
.
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)
tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")
tokens_output = model.generate(**tokens_input, max_new_tokens=500, do_sample=True, num_beams=1)
sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)
print(sentence_output)
A verdade é que o modelo não se repete, mas me sinto como se estivesse conversando com uma criança pequena, que fala sobre um assunto e depois começa a falar de outros que não têm nada a ver com ele.
Pesquisa de feixe
A pesquisa de feixes reduz o risco de perder sequências de palavras ocultas de alta probabilidade, mantendo o num_beams
mais provável em cada etapa de tempo e, finalmente, escolhendo a hipótese com a maior probabilidade geral.
Para gerar com beam search
, é necessário adicionar o parâmetro num_beams
.
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)
tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")
tokens_output = model.generate(**tokens_input, max_new_tokens=500, num_beams=5)
sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)
print(sentence_output)
Ele se repete muito
Amostragem multinomial de busca de feixe
Essa técnica combina pesquisa de feixe e amostragem multinomial, em que o próximo token é selecionado aleatoriamente com base na distribuição de probabilidade de todo o vocabulário fornecido pelo modelo.
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)
tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")
tokens_output = model.generate(**tokens_input, max_new_tokens=500, num_beams=5, do_sample=True)
sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)
print(sentence_output)
Ele se repete muito
Penalidade de n-gramas de pesquisa de feixe
Para evitar a repetição, podemos penalizar a repetição de n-gramas. Para fazer isso, usamos o parâmetro no_repeat_ngram_size
.
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)
tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")
tokens_output = model.generate(**tokens_input, max_new_tokens=500, num_beams=5, no_repeat_ngram_size=2)
sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)
print(sentence_output)
Esse texto não se repete mais e também tem um pouco mais de coerência.
Entretanto, as penalidades de n-gramas devem ser usadas com cuidado. Um artigo gerado sobre a cidade de Nova York não deve usar uma penalidade de 2 gramas, caso contrário, o nome da cidade apareceria apenas uma vez em todo o texto!
Sequências de retorno de penalidade de pesquisa de feixe de n-gramas
Podemos gerar várias sequências para compará-las e manter a melhor. Para isso, usamos o parâmetro num_return_sequences
com a condição de que num_return_sequences <= num_beams
.
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)
tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")
tokens_outputs = model.generate(**tokens_input, max_new_tokens=500, num_beams=5, no_repeat_ngram_size=2, num_return_sequences=3)
for i, tokens_output in enumerate(tokens_outputs):
if i != 0:
print("\n\n")
sentence_output = tokenizer.decode(tokens_output, skip_special_tokens=True)
print(f"{i}: {sentence_output}")
Agora podemos manter a melhor sequência
Decodificação de busca de feixe diverso
A decodificação de busca de feixe diversificado é uma extensão da estratégia de busca de feixe que permite a geração de um conjunto mais diversificado de sequências de feixe para escolha.
Para gerar o texto dessa forma, precisamos usar os parâmetros num_beams
, num_beam_groups
e diversity_penalty
.
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)
tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")
tokens_output = model.generate(**tokens_input, max_new_tokens=500, num_beams=5, num_beam_groups=5, diversity_penalty=1.0)
sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)
print(sentence_output)
Esse método parece se repetir com bastante frequência
Decodificação especulativa
A decodificação especulativa (também conhecida como decodificação assistida) é uma modificação das estratégias de decodificação acima, que usa um modelo assistente (idealmente muito menor) com o mesmo tokenizador, para gerar alguns tokens candidatos. Em seguida, o modelo principal valida os tokens candidatos em uma única etapa de avanço, o que acelera o processo de decodificação.
Para gerar texto dessa forma, é necessário usar o parâmetro do_sample=True
.
No momento, a decodificação assistida só oferece suporte à pesquisa otimizada, e a decodificação assistida não oferece suporte à entrada em lote.
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)
assistant_model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)
tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")
tokens_output = model.generate(**tokens_input, max_new_tokens=500, assistant_model=assistant_model, do_sample=True)
sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)
print(sentence_output)
Esse método tem resultados muito bons
Controle de aleatoriedade da decodificação especulativa
Ao usar a decodificação assistida com métodos de amostragem, o parâmetro temperature
pode ser usado para controlar a aleatoriedade. Entretanto, na decodificação assistida, a redução da temperatura pode ajudar a melhorar a latência.
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)
assistant_model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)
tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")
tokens_output = model.generate(**tokens_input, max_new_tokens=500, assistant_model=assistant_model, do_sample=True, temperature=0.5)
sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)
print(sentence_output)
Aqui, ele não se saiu tão bem
Amostragem
É aqui que começam as técnicas usadas pelos LLMs atuais.
Em vez de selecionar sempre a palavra mais provável (o que poderia levar a textos previsíveis ou repetitivos), a amostragem introduz a aleatoriedade no processo de seleção, permitindo que o modelo explore uma variedade de palavras possíveis com base em suas probabilidades. É como lançar um dado ponderado para cada palavra. Assim, quanto maior a probabilidade de uma palavra, maior a probabilidade de ela ser selecionada, mas ainda há uma oportunidade para que palavras menos prováveis sejam escolhidas, enriquecendo a diversidade e a criatividade do texto gerado. Esse método ajuda a evitar respostas monótonas e aumenta a variabilidade e a naturalidade do texto produzido.
Como você pode ver na imagem, o primeiro token, que tem a maior probabilidade, foi repetido até 11 vezes, o segundo até 8 vezes, o terceiro até 4 vezes e o último foi adicionado apenas 1 vez. Dessa forma, ele é escolhido aleatoriamente entre todos eles, mas o resultado mais provável é o primeiro token, pois é o que aparece mais vezes
Para usar esse método, escolhemos do_sample=True
e top_k=0
.
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)
tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")
tokens_output = model.generate(**tokens_input, max_new_tokens=500, do_sample=True, top_k=0)
sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)
print(sentence_output)
Ele não gera um texto repetitivo, mas gera um texto que não parece muito coerente. Esse é o problema de poder escolher qualquer palavra
Temperatura de amostragem
Para superar o problema do método de amostragem, um parâmetro de "temperatura" é adicionado para ajustar o nível de aleatoriedade na seleção de palavras.
A temperatura é um parâmetro que modifica a forma como as probabilidades das próximas palavras possíveis são distribuídas.
Com uma temperatura de 1, a distribuição de probabilidade permanece conforme aprendida pelo modelo, mantendo um equilíbrio entre previsibilidade e criatividade.
Diminuir a temperatura (menos de 1) aumenta o peso das palavras mais prováveis, tornando o texto gerado mais previsível e coerente, mas menos diversificado e criativo.
Ao aumentar a temperatura (mais de 1), a diferença de probabilidade entre as palavras é reduzida, dando às palavras menos prováveis uma chance maior de serem selecionadas, o que aumenta a diversidade e a criatividade do texto, mas pode comprometer sua coerência e relevância.
A temperatura permite o ajuste fino do equilíbrio entre originalidade e coerência do texto gerado, adequando-o às necessidades específicas da tarefa.
Para adicionar esse parâmetro, usamos o parâmetro temperature
da biblioteca
Primeiro, tentamos um valor baixo
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)
tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")
tokens_output = model.generate(**tokens_input, max_new_tokens=500, do_sample=True, top_k=0, temperature=0.7)
sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)
print(sentence_output)
Vemos que o texto gerado tem mais coerência, mas é novamente repetitivo.
Agora tentamos um valor mais alto
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)
tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")
tokens_output = model.generate(**tokens_input, max_new_tokens=500, do_sample=True, top_k=0, temperature=1.3)
sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)
print(sentence_output)
Vemos que o texto gerado agora não é repetido, mas não faz sentido.
Amostragem top-k
Outra maneira de resolver os problemas de amostragem é selecionar as k
palavras mais prováveis, de modo que o texto gerado não seja repetitivo, mas tenha mais coerência. Essa é a solução que foi escolhida no GPT-2.
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)
tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")
tokens_output = model.generate(**tokens_input, max_new_tokens=500, do_sample=True, top_k=50)
sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)
print(sentence_output)
Agora o texto não é repetitivo e tem coerência.
Top-p de amostragem (amostragem de núcleo)
Com o top-p, o que se faz é selecionar o conjunto de palavras que torna a soma de suas probabilidades maior que p (por exemplo, 0,9). Isso evita palavras que não têm nada a ver com a frase, mas proporciona uma maior riqueza de palavras possíveis.
Como você pode ver na imagem, se você somar a probabilidade dos primeiros tokens, terá uma probabilidade maior que 0,8, portanto, só nos restam esses tokens para gerar o próximo token.
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)
tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")
tokens_output = model.generate(**tokens_input, max_new_tokens=500, do_sample=True, top_k=0, top_p=0.92)
sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)
print(sentence_output)
Você obtém um texto muito bom
Amostragem top-k e top-p
Quando o top-k
e o top-p
são combinados, são obtidos resultados muito bons.
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)
tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")
tokens_output = model.generate(**tokens_input, max_new_tokens=500, do_sample=True, top_k=50, top_p=0.95)
sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)
print(sentence_output)
Efeito da temperatura, top-k
y top-p
Neste space do HuggingFace, podemos ver o efeito da temperatura, top-k
y top-p
na geração de texto
Streaming
Podemos fazer com que as palavras saiam uma a uma usando a classe TextStreamer
.
from transformers import AutoModelForCausalLM, AutoTokenizer, TextStreamer
tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish")
tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt")
streamer = TextStreamer(tokenizer)
_ = model.generate(**tokens_input, streamer=streamer, max_new_tokens=500, do_sample=True, top_k=50, top_p=0.95)
Dessa forma, a saída foi gerada palavra por palavra.
Modelos de bate-papo
Tokenização de contexto
Um uso muito importante dos LLMs são os chatbots. Ao usar um chatbot, é importante dar a ele um contexto. No entanto, a tokenização desse contexto é diferente para cada modelo. Portanto, uma maneira de tokenizar esse contexto é usar o método apply_chat_template
dos tokenizadores.
Por exemplo, vemos como o contexto do modelo facebook/blenderbot-400M-distill
é tokenizado.
from transformers import AutoTokenizer, AutoModelForCausalLMtokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")tokenizer.pad_token = tokenizer.eos_tokenmodel = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")tokens_output = model.generate(**tokens_input, max_new_tokens=500)sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)print(sentence_output)from transformers import AutoTokenizer, AutoModelForCausalLMtokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")tokenizer.pad_token = tokenizer.eos_tokenmodel = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")tokens_output = model.generate(**tokens_input, max_new_tokens=500, penalty_alpha=0.6, top_k=4)sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)print(sentence_output)from transformers import AutoTokenizer, AutoModelForCausalLMtokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")tokenizer.pad_token = tokenizer.eos_tokenmodel = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")tokens_output = model.generate(**tokens_input, max_new_tokens=500, do_sample=True, num_beams=1)sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)print(sentence_output)from transformers import AutoTokenizer, AutoModelForCausalLMtokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")tokenizer.pad_token = tokenizer.eos_tokenmodel = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")tokens_output = model.generate(**tokens_input, max_new_tokens=500, num_beams=5)sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)print(sentence_output)from transformers import AutoTokenizer, AutoModelForCausalLMtokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")tokenizer.pad_token = tokenizer.eos_tokenmodel = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")tokens_output = model.generate(**tokens_input, max_new_tokens=500, num_beams=5, do_sample=True)sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)print(sentence_output)from transformers import AutoTokenizer, AutoModelForCausalLMtokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")tokenizer.pad_token = tokenizer.eos_tokenmodel = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")tokens_output = model.generate(**tokens_input, max_new_tokens=500, num_beams=5, no_repeat_ngram_size=2)sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)print(sentence_output)from transformers import AutoTokenizer, AutoModelForCausalLMtokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")tokenizer.pad_token = tokenizer.eos_tokenmodel = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")tokens_outputs = model.generate(**tokens_input, max_new_tokens=500, num_beams=5, no_repeat_ngram_size=2, num_return_sequences=3)for i, tokens_output in enumerate(tokens_outputs):if i != 0:print(" ")sentence_output = tokenizer.decode(tokens_output, skip_special_tokens=True)print(f"{i}: {sentence_output}")from transformers import AutoTokenizer, AutoModelForCausalLMtokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")tokenizer.pad_token = tokenizer.eos_tokenmodel = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")tokens_output = model.generate(**tokens_input, max_new_tokens=500, num_beams=5, num_beam_groups=5, diversity_penalty=1.0)sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)print(sentence_output)from transformers import AutoTokenizer, AutoModelForCausalLMtokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")tokenizer.pad_token = tokenizer.eos_tokenmodel = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)assistant_model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")tokens_output = model.generate(**tokens_input, max_new_tokens=500, assistant_model=assistant_model, do_sample=True)sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)print(sentence_output)from transformers import AutoTokenizer, AutoModelForCausalLMtokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")tokenizer.pad_token = tokenizer.eos_tokenmodel = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)assistant_model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")tokens_output = model.generate(**tokens_input, max_new_tokens=500, assistant_model=assistant_model, do_sample=True, temperature=0.5)sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)print(sentence_output)from transformers import AutoTokenizer, AutoModelForCausalLMtokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")tokenizer.pad_token = tokenizer.eos_tokenmodel = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")tokens_output = model.generate(**tokens_input, max_new_tokens=500, do_sample=True, top_k=0)sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)print(sentence_output)from transformers import AutoTokenizer, AutoModelForCausalLMtokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")tokenizer.pad_token = tokenizer.eos_tokenmodel = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")tokens_output = model.generate(**tokens_input, max_new_tokens=500, do_sample=True, top_k=0, temperature=0.7)sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)print(sentence_output)from transformers import AutoTokenizer, AutoModelForCausalLMtokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")tokenizer.pad_token = tokenizer.eos_tokenmodel = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")tokens_output = model.generate(**tokens_input, max_new_tokens=500, do_sample=True, top_k=0, temperature=1.3)sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)print(sentence_output)from transformers import AutoTokenizer, AutoModelForCausalLMtokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")tokenizer.pad_token = tokenizer.eos_tokenmodel = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")tokens_output = model.generate(**tokens_input, max_new_tokens=500, do_sample=True, top_k=50)sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)print(sentence_output)from transformers import AutoTokenizer, AutoModelForCausalLMtokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")tokenizer.pad_token = tokenizer.eos_tokenmodel = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")tokens_output = model.generate(**tokens_input, max_new_tokens=500, do_sample=True, top_k=0, top_p=0.92)sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)print(sentence_output)from transformers import AutoTokenizer, AutoModelForCausalLMtokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")tokenizer.pad_token = tokenizer.eos_tokenmodel = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish", device_map=0)tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt", padding=True).to("cuda")tokens_output = model.generate(**tokens_input, max_new_tokens=500, do_sample=True, top_k=50, top_p=0.95)sentence_output = tokenizer.decode(tokens_output[0], skip_special_tokens=True)print(sentence_output)from transformers import AutoModelForCausalLM, AutoTokenizer, TextStreamertokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish")tokenizer.pad_token = tokenizer.eos_tokenmodel = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish")tokens_input = tokenizer(["Me encanta aprender de"], return_tensors="pt")streamer = TextStreamer(tokenizer)_ = model.generate(**tokens_input, streamer=streamer, max_new_tokens=500, do_sample=True, top_k=50, top_p=0.95)from transformers import AutoTokenizercheckpoint = "facebook/blenderbot-400M-distill"tokenizer = AutoTokenizer.from_pretrained("facebook/blenderbot-400M-distill")chat = [{"role": "user", "content": "Hola, ¿Cómo estás?"},{"role": "assistant", "content": "Estoy bien. ¿Cómo te puedo ayudar?"},{"role": "user", "content": "Me gustaría saber cómo funcionan los chat templates"},]input_token_chat_template = tokenizer.apply_chat_template(chat, tokenize=True, return_tensors="pt")print(f"input tokens chat_template: {input_token_chat_template}")input_chat_template = tokenizer.apply_chat_template(chat, tokenize=False, return_tensors="pt")print(f"input chat_template: {input_chat_template}")
Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.input tokens chat_template: tensor([[ 391, 7521, 19, 5146, 131, 42, 135, 119, 773, 2736, 135, 102,90, 38, 228, 477, 300, 874, 275, 1838, 21, 5146, 131, 42,135, 119, 773, 574, 286, 3478, 86, 265, 96, 659, 305, 38,228, 228, 2365, 294, 367, 305, 135, 263, 72, 268, 439, 276,280, 135, 119, 773, 941, 74, 337, 295, 530, 90, 3879, 4122,1114, 1073, 2]])input chat_template: Hola, ¿Cómo estás? Estoy bien. ¿Cómo te puedo ayudar? Me gustaría saber cómo funcionan los chat templates</s>
Como pode ser visto, o contexto é tokenizado simplesmente deixando espaços em branco entre as declarações
Vejamos agora como fazer a tokenização do modelo mistralai/Mistral-7B-Instruct-v0.1
.
from transformers import AutoTokenizercheckpoint = "mistralai/Mistral-7B-Instruct-v0.1"tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-Instruct-v0.1")chat = [{"role": "user", "content": "Hola, ¿Cómo estás?"},{"role": "assistant", "content": "Estoy bien. ¿Cómo te puedo ayudar?"},{"role": "user", "content": "Me gustaría saber cómo funcionan los chat templates"},]input_token_chat_template = tokenizer.apply_chat_template(chat, tokenize=True, return_tensors="pt")print(f"input tokens chat_template: {input_token_chat_template}")input_chat_template = tokenizer.apply_chat_template(chat, tokenize=False, return_tensors="pt")print(f"input chat_template: {input_chat_template}")
input tokens chat_template: tensor([[ 1, 733, 16289, 28793, 4170, 28708, 28725, 18297, 28743, 28825,5326, 934, 2507, 28804, 733, 28748, 16289, 28793, 14644, 904,9628, 28723, 18297, 28743, 28825, 5326, 711, 11127, 28709, 15250,554, 283, 28804, 2, 28705, 733, 16289, 28793, 2597, 319,469, 26174, 14691, 263, 21977, 5326, 2745, 296, 276, 1515,10706, 24906, 733, 28748, 16289, 28793]])input chat_template: <s>[INST] Hola, ¿Cómo estás? [/INST]Estoy bien. ¿Cómo te puedo ayudar?</s> [INST] Me gustaría saber cómo funcionan los chat templates [/INST]
Podemos ver que esse modelo coloca as tags [INST]
e [/INST]
no início e no final de cada frase
Adicionar geração de prompts
Podemos dizer ao tokenizador para tokenizar o contexto adicionando o turno do assistente com add_generation_prompt=True
. Vejamos, primeiro tokenizamos com add_generation_prompt=False
.
from transformers import AutoTokenizercheckpoint = "HuggingFaceH4/zephyr-7b-beta"tokenizer = AutoTokenizer.from_pretrained(checkpoint)chat = [{"role": "user", "content": "Hola, ¿Cómo estás?"},{"role": "assistant", "content": "Estoy bien. ¿Cómo te puedo ayudar?"},{"role": "user", "content": "Me gustaría saber cómo funcionan los chat templates"},]input_chat_template = tokenizer.apply_chat_template(chat, tokenize=False, return_tensors="pt", add_generation_prompt=False)print(f"input chat_template: {input_chat_template}")
input chat_template: <|user|>Hola, ¿Cómo estás?</s><|assistant|>Estoy bien. ¿Cómo te puedo ayudar?</s><|user|>Me gustaría saber cómo funcionan los chat templates</s>
Agora faremos o mesmo, mas com add_generation_prompt=True
.
from transformers import AutoTokenizercheckpoint = "HuggingFaceH4/zephyr-7b-beta"tokenizer = AutoTokenizer.from_pretrained(checkpoint)chat = [{"role": "user", "content": "Hola, ¿Cómo estás?"},{"role": "assistant", "content": "Estoy bien. ¿Cómo te puedo ayudar?"},{"role": "user", "content": "Me gustaría saber cómo funcionan los chat templates"},]input_chat_template = tokenizer.apply_chat_template(chat, tokenize=False, return_tensors="pt", add_generation_prompt=True)print(f"input chat_template: {input_chat_template}")
input chat_template: <|user|>Hola, ¿Cómo estás?</s><|assistant|>Estoy bien. ¿Cómo te puedo ayudar?</s><|user|>Me gustaría saber cómo funcionan los chat templates</s><|assistant|>
Como você pode ver, ele adiciona <|assistant|>
no final para ajudar o LLM a saber que é a sua vez de responder. Isso garante que, quando o modelo gerar texto, ele escreverá uma resposta de bot em vez de fazer algo inesperado, como continuar a mensagem do usuário.
Nem todos os modelos exigem prompts de geração. Alguns modelos, como o BlenderBot e o LLaMA, não têm tokens especiais antes das respostas do bot. Nesses casos, add_generation_prompt
não terá efeito. O efeito exato que add_generation_prompt
terá depende do modelo que está sendo usado.
Geração de texto
Como podemos ver, é fácil tokenizar o contexto sem precisar saber como fazer isso para cada modelo. Então, agora vamos ver como gerar texto, que também é muito simples
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
checkpoint = "flax-community/gpt-2-spanish"
tokenizer = AutoTokenizer.from_pretrained(checkpoint, torch_dtype=torch.float16)
model = AutoModelForCausalLM.from_pretrained(checkpoint, device_map=0, torch_dtype=torch.float16)
tokenizer.pad_token = tokenizer.eos_token
messages = [
{
"role": "system",
"content": "Eres un chatbot amigable que siempre de una forma graciosa",
},
{"role": "user", "content": "¿Cuántos helicópteros puede comer un ser humano de una sentada?"},
]
input_token_chat_template = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt").to("cuda")
output = model.generate(input_token_chat_template, max_new_tokens=128, do_sample=True)
sentence_output = tokenizer.decode(output[0])
print("")
print(sentence_output)
Como você pode ver, o prompt foi tokenizado com apply_chat_template
e esses tokens foram colocados no modelo.
Geração de texto com pipeline
.
A biblioteca transformers
também permite que você use pipeline
para gerar texto com um chatbot, fazendo basicamente o mesmo que fizemos antes
from transformers import pipeline
import torch
checkpoint = "flax-community/gpt-2-spanish"
generator = pipeline("text-generation", checkpoint, device=0, torch_dtype=torch.float16)
messages = [
{
"role": "system",
"content": "Eres un chatbot amigable que siempre de una forma graciosa",
},
{"role": "user", "content": "¿Cuántos helicópteros puede comer un ser humano de una sentada?"},
]
print("")
print(generator(messages, max_new_tokens=128)[0]['generated_text'][-1])
Trem
Até agora, usamos modelos pré-treinados, mas, caso você queira fazer um ajuste fino, a biblioteca transformers
facilita muito essa tarefa.
Como os modelos de linguagem são enormes hoje em dia, retreiná-los é quase impossível em uma GPU que qualquer pessoa pode ter em casa, portanto, vamos retreinar um modelo menor. Nesse caso, vamos treinar novamente o bert-base-cased
, que é um modelo de 109 milhões de parâmetros.
Conjunto de dados
Precisamos fazer download de um conjunto de dados e, para isso, usamos a biblioteca datasets
da Hugging Face. Vamos usar o conjunto de dados de avaliações do Yelp.
from transformers import AutoModelForCausalLM, AutoTokenizerimport torchcheckpoint = "flax-community/gpt-2-spanish"tokenizer = AutoTokenizer.from_pretrained(checkpoint, torch_dtype=torch.float16)model = AutoModelForCausalLM.from_pretrained(checkpoint, device_map=0, torch_dtype=torch.float16)tokenizer.pad_token = tokenizer.eos_tokenmessages = [{"role": "system","content": "Eres un chatbot amigable que siempre de una forma graciosa",},{"role": "user", "content": "¿Cuántos helicópteros puede comer un ser humano de una sentada?"},]input_token_chat_template = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt").to("cuda")output = model.generate(input_token_chat_template, max_new_tokens=128, do_sample=True)sentence_output = tokenizer.decode(output[0])print("")print(sentence_output)from transformers import pipelineimport torchcheckpoint = "flax-community/gpt-2-spanish"generator = pipeline("text-generation", checkpoint, device=0, torch_dtype=torch.float16)messages = [{"role": "system","content": "Eres un chatbot amigable que siempre de una forma graciosa",},{"role": "user", "content": "¿Cuántos helicópteros puede comer un ser humano de una sentada?"},]print("")print(generator(messages, max_new_tokens=128)[0]['generated_text'][-1])from datasets import load_datasetdataset = load_dataset("yelp_review_full")
Vamos ver como é o conjunto de dados.
from transformers import AutoModelForCausalLM, AutoTokenizerimport torchcheckpoint = "flax-community/gpt-2-spanish"tokenizer = AutoTokenizer.from_pretrained(checkpoint, torch_dtype=torch.float16)model = AutoModelForCausalLM.from_pretrained(checkpoint, device_map=0, torch_dtype=torch.float16)tokenizer.pad_token = tokenizer.eos_tokenmessages = [{"role": "system","content": "Eres un chatbot amigable que siempre de una forma graciosa",},{"role": "user", "content": "¿Cuántos helicópteros puede comer un ser humano de una sentada?"},]input_token_chat_template = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt").to("cuda")output = model.generate(input_token_chat_template, max_new_tokens=128, do_sample=True)sentence_output = tokenizer.decode(output[0])print("")print(sentence_output)from transformers import pipelineimport torchcheckpoint = "flax-community/gpt-2-spanish"generator = pipeline("text-generation", checkpoint, device=0, torch_dtype=torch.float16)messages = [{"role": "system","content": "Eres un chatbot amigable que siempre de una forma graciosa",},{"role": "user", "content": "¿Cuántos helicópteros puede comer un ser humano de una sentada?"},]print("")print(generator(messages, max_new_tokens=128)[0]['generated_text'][-1])from datasets import load_datasetdataset = load_dataset("yelp_review_full")type(dataset)
The attention mask and the pad token id were not set. As a consequence, you may observe unexpected behavior. Please pass your input's `attention_mask` to obtain reliable results.Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.A decoder-only architecture is being used, but right-padding was detected! For correct generation results, please set `padding_side='left'` when initializing the tokenizer.Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.A decoder-only architecture is being used, but right-padding was detected! For correct generation results, please set `padding_side='left'` when initializing the tokenizer.datasets.dataset_dict.DatasetDict
Parece ser um tipo de dicionário, vamos ver quais chaves ele tem.
dataset.keys()
dict_keys(['train', 'test'])
Vamos ver quantas avaliações ele tem em cada subconjunto.
len(dataset["train"]), len(dataset["test"])
(650000, 50000)
Vamos dar uma olhada em um exemplo
dataset["train"][100]
{'label': 0,'text': 'My expectations for McDonalds are t rarely high. But for one to still fail so spectacularly...that takes something special! The cashier took my friends's order, then promptly ignored me. I had to force myself in front of a cashier who opened his register to wait on the person BEHIND me. I waited over five minutes for a gigantic order that included precisely one kid's meal. After watching two people who ordered after me be handed their food, I asked where mine was. The manager started yelling at the cashiers for "serving off their orders" when they didn't have their food. But neither cashier was anywhere near those controls, and the manager was the one serving food to customers and clearing the boards. The manager was rude when giving me my order. She didn't make sure that I had everything ON MY RECEIPT, and never even had the decency to apologize that I felt I was getting poor service. I've eaten at various McDonalds restaurants for over 30 years. I've worked at more than one location. I expect bad days, bad moods, and the occasional mistake. But I have yet to have a decent experience at this store. It will remain a place I avoid unless someone in my party needs to avoid illness from low blood sugar. Perhaps I should go back to the racially biased service of Steak n Shake instead!'}
Como podemos ver, cada amostra tem o texto e a pontuação, vamos ver quantos tipos existem
clases = dataset["train"].featuresclases
{'label': ClassLabel(names=['1 star', '2 star', '3 stars', '4 stars', '5 stars'], id=None),'text': Value(dtype='string', id=None)}
Vemos que ele tem 5 classes diferentes
num_classes = len(clases["label"].names)num_classes
5
Vamos dar uma olhada em um exemplo de teste
dataset["test"][100]
{'label': 0,'text': 'This was just bad pizza. For the money I expect that the toppings will be cooked on the pizza. The cheese and pepparoni were added after the crust came out. Also the mushrooms were out of a can. Do not waste money here.'}
Como o objetivo desta postagem não é treinar o melhor modelo, mas explicar a biblioteca transformers
do Hugging Face, vamos criar um pequeno subconjunto para treinar mais rapidamente.
small_train_dataset = dataset["train"].shuffle(seed=42).select(range(1000))small_eval_dataset = dataset["test"].shuffle(seed=42).select(range(500))
Tokenização
Já temos o conjunto de dados, como vimos no pipeline, primeiro é feita a tokenização e depois o modelo é aplicado. Portanto, temos que tokenizar o conjunto de dados.
Definimos o tokenizador
small_train_dataset = dataset["train"].shuffle(seed=42).select(range(1000))small_eval_dataset = dataset["test"].shuffle(seed=42).select(range(500))from transformers import AutoTokenizertokenizer = AutoTokenizer.from_pretrained("bert-base-cased")
A classe AutoTokenizer
tem um método chamado map
que nos permite aplicar uma função ao conjunto de dados, portanto, vamos criar uma função que tokenize o texto.
small_train_dataset = dataset["train"].shuffle(seed=42).select(range(1000))small_eval_dataset = dataset["test"].shuffle(seed=42).select(range(500))from transformers import AutoTokenizertokenizer = AutoTokenizer.from_pretrained("bert-base-cased")def tokenize_function(examples):return tokenizer(examples["text"], padding=True, truncation=True, max_length=3)
Como podemos ver, no momento, fizemos a tokenização truncando apenas 3 tokens, para que possamos ver melhor o que está acontecendo embaixo.
Usamos o método map
para usar a função que acabamos de definir no conjunto de dados.
small_train_dataset = dataset["train"].shuffle(seed=42).select(range(1000))small_eval_dataset = dataset["test"].shuffle(seed=42).select(range(500))from transformers import AutoTokenizertokenizer = AutoTokenizer.from_pretrained("bert-base-cased")def tokenize_function(examples):return tokenizer(examples["text"], padding=True, truncation=True, max_length=3)tokenized_small_train_dataset = small_train_dataset.map(tokenize_function, batched=True)tokenized_small_eval_dataset = small_eval_dataset.map(tokenize_function, batched=True)
Vemos exemplos do conjunto de dados tokenizado
small_train_dataset = dataset["train"].shuffle(seed=42).select(range(1000))small_eval_dataset = dataset["test"].shuffle(seed=42).select(range(500))from transformers import AutoTokenizertokenizer = AutoTokenizer.from_pretrained("bert-base-cased")def tokenize_function(examples):return tokenizer(examples["text"], padding=True, truncation=True, max_length=3)tokenized_small_train_dataset = small_train_dataset.map(tokenize_function, batched=True)tokenized_small_eval_dataset = small_eval_dataset.map(tokenize_function, batched=True)tokenized_small_train_dataset[100]
{'label': 3,'text': "I recently brough my car up to Edinburgh from home, where it had sat on the drive pretty much since I had left home to go to university. As I'm sure you can imagine, it was pretty filthy, so I pulled up here expecting to shell out £5 or so for a crappy was that wouldnt really be that great. Needless to say, when I realised that the cheapest was was £2, i was suprised and I was even more suprised when the car came out looking like a million dollars. Very impressive for £2, but thier prices can go up to around £6 - which I'm sure must involve so many polishes and waxes and cleans that dirt must be simply repelled from the body of your car, never getting dirty again.",'input_ids': [101, 146, 102],'token_type_ids': [0, 0, 0],'attention_mask': [1, 1, 1]}
tokenized_small_eval_dataset[100]
{'label': 4,'text': 'Had a great dinner at Elephant Bar last night! Got a coupon in the mail for 2 meals and an appetizer for $20! While they did limit the selections you could get with the coupon, we were happy with the choices so it worked out fine. Food was delicious and the service was fantastic! Waitress was very attentive and polite. Location was a plus too! Had a lovely walk around The District shops afterward. All and all, a hands down 5 stars!','input_ids': [101, 6467, 102],'token_type_ids': [0, 0, 0],'attention_mask': [1, 1, 1]}
Como podemos ver, uma chave foi adicionada com os input_ids
dos tokens, os token_type_ids
e outra com a máscara de atenção
.
Agora, fazemos a tokenização truncando para 20 tokens a fim de usar uma GPU pequena.
def tokenize_function(examples):return tokenizer(examples["text"], padding=True, truncation=True, max_length=20)tokenized_small_train_dataset = small_train_dataset.map(tokenize_function, batched=True)tokenized_small_eval_dataset = small_eval_dataset.map(tokenize_function, batched=True)
Modelo
Temos que criar o modelo que vamos treinar novamente. Como se trata de um problema de classificação, usaremos o AutoModelForSequenceClassification
.
def tokenize_function(examples):return tokenizer(examples["text"], padding=True, truncation=True, max_length=20)tokenized_small_train_dataset = small_train_dataset.map(tokenize_function, batched=True)tokenized_small_eval_dataset = small_eval_dataset.map(tokenize_function, batched=True)from transformers import AutoModelForSequenceClassificationmodel = AutoModelForSequenceClassification.from_pretrained("bert-base-cased", num_labels=5)
Some weights of BertForSequenceClassification were not initialized from the model checkpoint at bert-base-cased and are newly initialized: ['classifier.bias', 'classifier.weight']You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.
Como pode ser visto, foi criado um modelo que classifica entre 5 classes
Métricas de avaliação
Criamos uma métrica de avaliação com a biblioteca Hugging Face evaluate
. Para instalá-la, usamos
pip install evaluate
```
import numpy as npimport evaluatemetric = evaluate.load("accuracy")def compute_metrics(eval_pred):logits, labels = eval_predpredictions = np.argmax(logits, axis=-1)return metric.compute(predictions=predictions, references=labels)
Treinador
Agora, para o treinamento, usamos o objeto Trainer
. Para usar o Trainer
, precisamos de accelerate>=0.21.0
.
pip install accelerate>=0.21.0
```
Antes de criar o treinador, precisamos criar um TrainingArguments
, que é um objeto que contém todos os argumentos que o Trainer
precisa para o treinamento, ou seja, os hiperparâmetros
Um argumento obrigatório deve ser passado, output_dir
, que é o diretório de saída onde as previsões do modelo e os pontos de verificação, como a Hugging Face chama os pesos do modelo, serão gravados.
Também transmitimos uma série de outros argumentos
per_device_train_batch_size
: tamanho do lote por dispositivo para o treinamentoper_device_eval_batch_size
: tamanho do lote por dispositivo para a avaliaçãolearning_rate
: taxa de aprendizadonum_train_epochs
: número de épocas
import numpy as npimport evaluatemetric = evaluate.load("accuracy")def compute_metrics(eval_pred):logits, labels = eval_predpredictions = np.argmax(logits, axis=-1)return metric.compute(predictions=predictions, references=labels)from transformers import TrainingArgumentstraining_args = TrainingArguments(output_dir="test_trainer",per_device_train_batch_size=16,per_device_eval_batch_size=32,learning_rate=1e-4,num_train_epochs=5,)
Vamos dar uma olhada em todos os hiperparâmetros que ele configura
import numpy as npimport evaluatemetric = evaluate.load("accuracy")def compute_metrics(eval_pred):logits, labels = eval_predpredictions = np.argmax(logits, axis=-1)return metric.compute(predictions=predictions, references=labels)from transformers import TrainingArgumentstraining_args = TrainingArguments(output_dir="test_trainer",per_device_train_batch_size=16,per_device_eval_batch_size=32,learning_rate=1e-4,num_train_epochs=5,)training_args.__dict__
{'output_dir': 'test_trainer','overwrite_output_dir': False,'do_train': False,'do_eval': False,'do_predict': False,'evaluation_strategy': <IntervalStrategy.NO: 'no'>,'prediction_loss_only': False,'per_device_train_batch_size': 16,'per_device_eval_batch_size': 32,'per_gpu_train_batch_size': None,'per_gpu_eval_batch_size': None,'gradient_accumulation_steps': 1,'eval_accumulation_steps': None,'eval_delay': 0,'learning_rate': 0.0001,'weight_decay': 0.0,'adam_beta1': 0.9,'adam_beta2': 0.999,'adam_epsilon': 1e-08,'max_grad_norm': 1.0,'num_train_epochs': 5,'max_steps': -1,'lr_scheduler_type': <SchedulerType.LINEAR: 'linear'>,'lr_scheduler_kwargs': {},'warmup_ratio': 0.0,'warmup_steps': 0,'log_level': 'passive','log_level_replica': 'warning','log_on_each_node': True,'logging_dir': 'test_trainer/runs/Mar08_16-41-27_SAEL00531','logging_strategy': <IntervalStrategy.STEPS: 'steps'>,'logging_first_step': False,'logging_steps': 500,'logging_nan_inf_filter': True,'save_strategy': <IntervalStrategy.STEPS: 'steps'>,'save_steps': 500,'save_total_limit': None,'save_safetensors': True,'save_on_each_node': False,'save_only_model': False,'no_cuda': False,'use_cpu': False,'use_mps_device': False,'seed': 42,'data_seed': None,'jit_mode_eval': False,'use_ipex': False,'bf16': False,'fp16': False,'fp16_opt_level': 'O1','half_precision_backend': 'auto','bf16_full_eval': False,'fp16_full_eval': False,'tf32': None,'local_rank': 0,'ddp_backend': None,'tpu_num_cores': None,'tpu_metrics_debug': False,'debug': [],'dataloader_drop_last': False,'eval_steps': None,'dataloader_num_workers': 0,'dataloader_prefetch_factor': None,'past_index': -1,'run_name': 'test_trainer','disable_tqdm': False,'remove_unused_columns': True,'label_names': None,'load_best_model_at_end': False,'metric_for_best_model': None,'greater_is_better': None,'ignore_data_skip': False,'fsdp': [],'fsdp_min_num_params': 0,'fsdp_config': {'min_num_params': 0,'xla': False,'xla_fsdp_v2': False,'xla_fsdp_grad_ckpt': False},'fsdp_transformer_layer_cls_to_wrap': None,'accelerator_config': AcceleratorConfig(split_batches=False, dispatch_batches=None, even_batches=True, use_seedable_sampler=True),'deepspeed': None,'label_smoothing_factor': 0.0,'optim': <OptimizerNames.ADAMW_TORCH: 'adamw_torch'>,'optim_args': None,'adafactor': False,'group_by_length': False,'length_column_name': 'length','report_to': [],'ddp_find_unused_parameters': None,'ddp_bucket_cap_mb': None,'ddp_broadcast_buffers': None,'dataloader_pin_memory': True,'dataloader_persistent_workers': False,'skip_memory_metrics': True,'use_legacy_prediction_loop': False,'push_to_hub': False,'resume_from_checkpoint': None,'hub_model_id': None,'hub_strategy': <HubStrategy.EVERY_SAVE: 'every_save'>,'hub_token': None,'hub_private_repo': False,'hub_always_push': False,'gradient_checkpointing': False,'gradient_checkpointing_kwargs': None,'include_inputs_for_metrics': False,'fp16_backend': 'auto','push_to_hub_model_id': None,'push_to_hub_organization': None,'push_to_hub_token': None,'mp_parameters': '','auto_find_batch_size': False,'full_determinism': False,'torchdynamo': None,'ray_scope': 'last','ddp_timeout': 1800,'torch_compile': False,'torch_compile_backend': None,'torch_compile_mode': None,'dispatch_batches': None,'split_batches': None,'include_tokens_per_second': False,'include_num_input_tokens_seen': False,'neftune_noise_alpha': None,'distributed_state': Distributed environment: DistributedType.NONum processes: 1Process index: 0Local process index: 0Device: cuda,'_n_gpu': 1,'__cached__setup_devices': device(type='cuda', index=0),'deepspeed_plugin': None}
Agora, criamos um objeto Trainer
que será responsável pelo treinamento do modelo.
from transformers import Trainertrainer = Trainer(model=model,train_dataset=tokenized_small_train_dataset,eval_dataset=tokenized_small_eval_dataset,compute_metrics=compute_metrics,args=training_args,)
Quando tivermos um Trainer
, no qual indicamos o conjunto de dados de treinamento, o conjunto de dados de teste, o modelo, a métrica de avaliação e os argumentos do hiperparâmetro, poderemos treinar o modelo com o método train
do Trainer
.
trainer.train()
Já temos o modelo treinado, como você pode ver, com muito pouco código, podemos treinar um modelo muito rapidamente.
Recomendo enfaticamente que você aprenda o Pytorch e treine muitos modelos antes de usar uma biblioteca de alto nível como a transformers
, porque você aprende muitos fundamentos de aprendizagem profunda e pode entender melhor o que está acontecendo, especialmente porque aprenderá muito com seus erros. Mas, depois de passar por esse período, o uso de bibliotecas de alto nível, como a transformers
, acelera muito o desenvolvimento.
Testando o modelo
Agora que temos o modelo treinado, vamos testá-lo com um texto. Como o conjunto de dados que baixamos é de avaliações em inglês, vamos testá-lo com uma avaliação em inglês.
from transformers import Trainertrainer = Trainer(model=model,train_dataset=tokenized_small_train_dataset,eval_dataset=tokenized_small_eval_dataset,compute_metrics=compute_metrics,args=training_args,)trainer.train()from transformers import pipelineclasificator = pipeline("text-classification", model=model, tokenizer=tokenizer)
from transformers import Trainertrainer = Trainer(model=model,train_dataset=tokenized_small_train_dataset,eval_dataset=tokenized_small_eval_dataset,compute_metrics=compute_metrics,args=training_args,)trainer.train()from transformers import pipelineclasificator = pipeline("text-classification", model=model, tokenizer=tokenizer)clasification = clasificator("I'm liking this post a lot")clasification
0%| | 0/315 [00:00<?, ?it/s][{'label': 'LABEL_2', 'score': 0.5032550692558289}]
Vamos ver a que corresponde a classe que surgiu
clases
{'label': ClassLabel(names=['1 star', '2 star', '3 stars', '4 stars', '5 stars'], id=None),'text': Value(dtype='string', id=None)}
A relação seria
- LABEL_0: 1 estrela
- LABEL_1: 2 estrelas
- LABEL_2: 3 estrelas
- LABEL_3: 4 estrelas
- LABEL_4: 5 estrelas
Portanto, você classificou o comentário com 3 estrelas. Lembre-se de que treinamos em um subconjunto de dados e com apenas 5 épocas, portanto, não esperamos que seja muito bom.
Compartilhe o modelo no Hub do Rosto de Abraço
Quando tivermos o modelo retreinado, poderemos carregá-lo em nosso espaço no Hugging Face Hub para que outros possam usá-lo. Para fazer isso, você precisa ter uma conta no Hugging Face.
Registro em log
Para fazer upload do modelo, primeiro precisamos fazer login.
Isso pode ser feito por meio do terminal com
huggingface-cli login
```
Ou por meio do notebook, tendo instalado primeiro a biblioteca `huggingface_hub` com
````bash
pip install huggingface_hub
```
Agora, podemos fazer login com a função `notebook_login`, que criará uma pequena interface gráfica na qual devemos inserir um token Hugging Face.
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.
Nomeamos o token e o criamos com a função write
.
Uma vez criado, nós o copiamos
from huggingface_hub import notebook_loginnotebook_login()
VBox(children=(HTML(value='<center> <img src=https://huggingface.co/front/assets/huggingface_logo-noborder.sv…
Para cima depois de treinado
Depois de treinar o modelo, podemos carregá-lo no Hub usando a função push_to_hub
. Essa função tem um parâmetro obrigatório que é o nome do modelo, que deve ser exclusivo; se já houver um modelo em seu Hub com esse nome, ele não será carregado. Ou seja, o nome completo do modelo será
Ele também tem outros parâmetros opcionais, mas interessantes:
use_temp_dir
(bool, opcional): se deve ou não ser usado um diretório temporário para armazenar arquivos salvos antes de serem enviados ao Hub. O padrão é True se não houver um diretório com o mesmo nome derepo_id
e False caso contrário.commit_message
(str, opcional): mensagem de confirmação. O padrão éUpload {object}
.private
(bool, opcional): se o repositório criado deve ser privado ou não.token
(bool ou str, opcional): O token a ser usado como autorização HTTP para arquivos remotos. Se for True, será usado o token gerado pela execução do loginhuggingface-cli
(armazenado em ~/.huggingface). O padrão é True serepo_url
não for especificado.max_shard_size
(int ou str, opcional, o padrão é "5GB"): Aplicável somente a modelos. O tamanho máximo de um ponto de verificação antes de ser fragmentado. Os pontos de verificação fragmentados serão cada um menor que esse tamanho. Se for expresso como uma cadeia de caracteres, deverá ter dígitos seguidos de uma unidade (como "5MB"). O padrão é "5 GB" para que os usuários possam carregar facilmente modelos em instâncias de nível gratuito do Google Colab sem problemas de OOM (falta de memória) da CPU.create_pr
(bool, opcional, o padrão é False): se deve ou não criar um PR com os arquivos carregados ou fazer o commit diretamente.safe_serialization
(bool, opcional, o padrão é True): Se os pesos do modelo devem ou não ser convertidos para o formato safetensors para uma serialização mais segura.revision
(str, opcional): filial para a qual enviar os arquivos carregados.commit_description
(str, opcional): Descrição do commit a ser criadotags
(List[str], opcional): Lista de tags a serem inseridas no Hub.
model.push_to_hub(
"bert-base-cased_notebook_transformers_5-epochs_yelp_review_subset",
commit_message="bert base cased fine tune on yelp review subset",
commit_description="Fine-tuned on a subset of the yelp review dataset. Model retrained for post of transformers library. 5 epochs.",
)
Se formos agora ao nosso Hub, veremos que o modelo foi carregado.
Se agora entrarmos no cartão de modelo para ver
transformers_commit_inico_model_card](https://pub-fb664c455eca46a2ba762a065ac900f7.r2.dev/transformers_commit_inico_model_card.webp)
Vemos que tudo não está preenchido, faremos isso mais tarde.
Levantar durante o treinamento
Outra opção é fazer o upload enquanto estivermos treinando o modelo. Isso é muito útil quando treinamos modelos por muitos períodos e isso leva muito tempo, pois se o treinamento for interrompido (porque o computador está desligado, a sessão de colaboração terminou, os créditos da nuvem acabaram), o trabalho não será perdido. Para fazer isso, você deve adicionar push_to_hub=True
em TrainingArguments
.
model.push_to_hub("bert-base-cased_notebook_transformers_5-epochs_yelp_review_subset",commit_message="bert base cased fine tune on yelp review subset",commit_description="Fine-tuned on a subset of the yelp review dataset. Model retrained for post of transformers library. 5 epochs.",)training_args = TrainingArguments(output_dir="bert-base-cased_notebook_transformers_30-epochs_yelp_review_subset",per_device_train_batch_size=16,per_device_eval_batch_size=32,learning_rate=1e-4,num_train_epochs=30,push_to_hub=True,)trainer = Trainer(model=model,train_dataset=tokenized_small_train_dataset,eval_dataset=tokenized_small_eval_dataset,compute_metrics=compute_metrics,args=training_args,)
Podemos ver que alteramos as épocas para 30, de modo que o treinamento será mais demorado, portanto, adicionar push_to_hub=True
fará o upload do modelo para o nosso Hub durante o treinamento.
Também alteramos o output_dir
porque esse é o nome que o modelo terá no Hub.
trainer.train()
Se olharmos novamente para o nosso hub, o novo modelo aparecerá.
transformers_commit_training](https://pub-fb664c455eca46a2ba762a065ac900f7.r2.dev/transformers_commit_training.webp)
Hub como repositório git
No Hugging Face, os modelos, os espaços e os conjuntos de dados são repositórios git, portanto, você pode trabalhar com eles dessa forma. Ou seja, você pode clonar, bifurcar, fazer solicitações pull, etc.
Mas outra grande vantagem disso é que você pode usar um modelo em uma versão específica.
from transformers import AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained("bert-base-cased", num_labels=5, revision="393e083")