Transformers documentation
Modelagem de linguagem causal
Modelagem de linguagem causal
Existem dois tipos de modelagem de linguagem: causal e mascarada. Este guia ilustra a modelagem de linguagem causal. Os modelos de linguagem causal são frequentemente usados para geração de texto. Você pode usar esses modelos para aplicações criativas, como aventuras de texto em que você escolhe o próprio caminho, ou assistentes inteligentes de codificação, como Copilot ou CodeParrot.
O modelamento de linguagem causal prevê o próximo token em uma sequência de tokens, e o modelo só pode prestar atenção aos tokens à esquerda. Isso significa que o modelo não consegue ver tokens futuros. O GPT-2 é um exemplo de modelo de linguagem causal.
Este guia mostrará como:
- Ajuste fino de DistilGPT2 no subconjunto r/askscience do conjunto de dados ELI5.
- Use seu modelo ajustado para inferência.
Para ver todas as arquiteturas e checkpoints compatíveis com esta tarefa, recomendamos consultar a página da tarefa
Antes de começar, verifique se você tem todas as bibliotecas necessárias instaladas:
pip install transformers datasets evaluate
Recomendamos que você faça login na sua conta do Hugging Face para que possa enviar e compartilhar seu modelo com a comunidade. Quando solicitado, insira seu token para fazer login:
>>> from huggingface_hub import notebook_login
>>> notebook_login()Carregar o conjunto de dados ELI5
Comece carregando os primeiros 5000 exemplos do conjunto de dados ELI5-Category com a biblioteca 🤗 Datasets. Isso lhe dará a oportunidade de experimentar e garantir que tudo funcione antes de gastar mais tempo treinando no conjunto de dados completo.
>>> from datasets import load_dataset
>>> eli5 = load_dataset("dany0407/eli5_category", split="train[:5000]")Divida o split train do conjunto de dados em um conjunto de treinamento e um conjunto de teste com o método train_test_split:
>>> eli5 = eli5.train_test_split(test_size=0.2)Em seguida, veja um exemplo:
>>> eli5["train"][0]
{'q_id': '7h191n',
'title': 'What does the tax bill that was passed today mean? How will it affect Americans in each tax bracket?',
'selftext': '',
'category': 'Economics',
'subreddit': 'explainlikeimfive',
'answers': {'a_id': ['dqnds8l', 'dqnd1jl', 'dqng3i1', 'dqnku5x'],
'text': ["The tax bill is 500 pages long and there were a lot of changes still going on right to the end. It's not just an adjustment to the income tax brackets, it's a whole bunch of changes. As such there is no good answer to your question. The big take aways are: - Big reduction in corporate income tax rate will make large companies very happy. - Pass through rate change will make certain styles of business (law firms, hedge funds) extremely happy - Income tax changes are moderate, and are set to expire (though it's the kind of thing that might just always get re-applied without being made permanent) - People in high tax states (California, New York) lose out, and many of them will end up with their taxes raised.",
'None yet. It has to be reconciled with a vastly different house bill and then passed again.',
'Also: does this apply to 2017 taxes? Or does it start with 2018 taxes?',
'This article explains both the House and senate bills, including the proposed changes to your income taxes based on your income level. URL_0'],
'score': [21, 19, 5, 3],
'text_urls': [[],
[],
[],
['https://www.investopedia.com/news/trumps-tax-reform-what-can-be-done/']]},
'title_urls': ['url'],
'selftext_urls': ['url']}Embora isso possa parecer muito, o que realmente importa é o campo text. O que é interessante nas tarefas de modelagem de linguagem é que você não precisa de rótulos (também conhecidas como tarefas não supervisionadas), pois a próxima palavra é o rótulo.
Pré-processar
O próximo passo é carregar um tokenizer DistilGPT2 para processar o subcampo text:
>>> from transformers import AutoTokenizer
>>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilgpt2")Você notará, pelo exemplo acima, que o campo text está, na verdade, aninhado dentro de answers. Isso significa que você precisará extrair o subcampo text de sua estrutura aninhada com o método flatten:
>>> eli5 = eli5.flatten()
>>> eli5["train"][0]
{'q_id': '7h191n',
'title': 'What does the tax bill that was passed today mean? How will it affect Americans in each tax bracket?',
'selftext': '',
'category': 'Economics',
'subreddit': 'explainlikeimfive',
'answers.a_id': ['dqnds8l', 'dqnd1jl', 'dqng3i1', 'dqnku5x'],
'answers.text': ["The tax bill is 500 pages long and there were a lot of changes still going on right to the end. It's not just an adjustment to the income tax brackets, it's a whole bunch of changes. As such there is no good answer to your question. The big take aways are: - Big reduction in corporate income tax rate will make large companies very happy. - Pass through rate change will make certain styles of business (law firms, hedge funds) extremely happy - Income tax changes are moderate, and are set to expire (though it's the kind of thing that might just always get re-applied without being made permanent) - People in high tax states (California, New York) lose out, and many of them will end up with their taxes raised.",
'None yet. It has to be reconciled with a vastly different house bill and then passed again.',
'Also: does this apply to 2017 taxes? Or does it start with 2018 taxes?',
'This article explains both the House and senate bills, including the proposed changes to your income taxes based on your income level. URL_0'],
'answers.score': [21, 19, 5, 3],
'answers.text_urls': [[],
[],
[],
['https://www.investopedia.com/news/trumps-tax-reform-what-can-be-done/']],
'title_urls': ['url'],
'selftext_urls': ['url']}Cada subcampo agora é uma coluna separada, conforme indicado pelo prefixo answers, e o campo text agora é uma lista. Em vez de tokenizar cada frase separadamente, converta a lista em uma string para que você possa tokenizá-las em conjunto.
Aqui está uma primeira função de pré-processamento para juntar a lista de strings de cada exemplo e tokenizar o resultado:
>>> def preprocess_function(examples):
... return tokenizer([" ".join(x) for x in examples["answers.text"]])Para aplicar essa função de pré-processamento em todo o conjunto de dados, use o método map do 🤗 Datasets. Você pode acelerar a função map definindo batched=True para processar vários elementos do conjunto de dados de uma vez e aumentando o número de processos com num_proc. Remova quaisquer colunas que você não precise:
>>> tokenized_eli5 = eli5.map(
... preprocess_function,
... batched=True,
... num_proc=4,
... remove_columns=eli5["train"].column_names,
... )Este conjunto de dados contém as sequências de tokens, mas algumas delas são mais longas do que o comprimento máximo de entrada para o modelo.
Agora você pode usar uma segunda função de pré-processamento para
- concatenar todas as sequências
- divida as sequências concatenadas em blocos menores definidos por
block_size, que devem ser mais curtos que o comprimento máximo de entrada e curtos o suficiente para a RAM da sua GPU.
>>> block_size = 128
>>> def group_texts(examples):
... # Concatenate all texts.
... concatenated_examples = {k: sum(examples[k], []) for k in examples.keys()}
... total_length = len(concatenated_examples[list(examples.keys())[0]])
... # We drop the small remainder, we could add padding if the model supported it instead of this drop, you can
... # customize this part to your needs.
... if total_length >= block_size:
... total_length = (total_length // block_size) * block_size
... # Split by chunks of block_size.
... result = {
... k: [t[i : i + block_size] for i in range(0, total_length, block_size)]
... for k, t in concatenated_examples.items()
... }
... result["labels"] = result["input_ids"].copy()
... return resultAplique a função group_texts em todo o conjunto de dados:
>>> lm_dataset = tokenized_eli5.map(group_texts, batched=True, num_proc=4)Agora, crie um lote de exemplos usando DataCollatorForLanguageModeling. É mais eficiente preencher dinamicamente as frases até o comprimento mais longo dentro de um lote durante a colação, em vez de preencher todo o conjunto de dados até o comprimento máximo.
Use o token de fim de sequência como token de preenchimento e defina mlm=False. Isso usará as entradas como rótulos deslocados para a direita em um elemento:
>>> from transformers import DataCollatorForLanguageModeling
>>> tokenizer.pad_token = tokenizer.eos_token
>>> data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)Treinar
Se você não está familiarizado com o ajuste fino de um modelo usando o Trainer, dê uma olhada no tutorial básico!
Agora você está pronto para começar a treinar seu modelo! Carregue o DistilGPT2 com AutoModelForCausalLM:
>>> from transformers import AutoModelForCausalLM, TrainingArguments, Trainer
>>> model = AutoModelForCausalLM.from_pretrained("distilbert/distilgpt2")Neste ponto, restam apenas três etapas:
- Defina os hiperparâmetros de treinamento em TrainingArguments. O único parâmetro obrigatório é
output_dir, que especifica onde salvar seu modelo. Você enviará este modelo para o Hub definindopush_to_hub=True(é necessário estar conectado ao Hugging Face para enviar seu modelo). - Passe os argumentos de treinamento para o Trainer junto com o modelo, os conjuntos de dados e o data collator.
- Chame train() para fazer o ajuste fino do seu modelo.
>>> training_args = TrainingArguments(
... output_dir="my_awesome_eli5_clm-model",
... eval_strategy="epoch",
... learning_rate=2e-5,
... weight_decay=0.01,
... push_to_hub=True,
... )
>>> trainer = Trainer(
... model=model,
... args=training_args,
... train_dataset=lm_dataset["train"],
... eval_dataset=lm_dataset["test"],
... data_collator=data_collator,
... processing_class=tokenizer,
... )
>>> trainer.train()Após a conclusão do treinamento, use o método evaluate() para avaliar seu modelo e obter sua perplexidade:
>>> import math
>>> eval_results = trainer.evaluate()
>>> print(f"Perplexity: {math.exp(eval_results['eval_loss']):.2f}")
Perplexity: 49.61Em seguida, compartilhe seu modelo no Hub com o método push_to_hub() para que todos possam usar seu modelo:
>>> trainer.push_to_hub()Para um exemplo mais detalhado de como fazer o ajuste fino de um modelo para modelagem de linguagem causal, consulte o notebook do PyTorch correspondente.
Inferência
Ótimo, agora que você ajustou um modelo, pode usá-lo para inferência!
Crie um prompt do qual você gostaria de gerar texto:
>>> prompt = "Somatic hypermutation allows the immune system to"A maneira mais simples de testar seu modelo ajustado para inferência é usá-lo em um pipeline(). Instancie um pipeline para geração de texto com seu modelo e passe seu texto para ele:
>>> from transformers import pipeline
>>> generator = pipeline("text-generation", model="username/my_awesome_eli5_clm-model")
>>> generator(prompt)
[{'generated_text': "Somatic hypermutation allows the immune system to be able to effectively reverse the damage caused by an infection.\n\n\nThe damage caused by an infection is caused by the immune system's ability to perform its own self-correcting tasks."}]Tokenize o texto e retorne os input_ids como tensores do PyTorch:
>>> from transformers import AutoTokenizer
>>> tokenizer = AutoTokenizer.from_pretrained("username/my_awesome_eli5_clm-model")
>>> inputs = tokenizer(prompt, return_tensors="pt").input_idsUse o método generate() para gerar texto. Para mais detalhes sobre as diferentes estratégias de geração de texto e os parâmetros para controlar a geração, consulte a página Estratégias de geração de texto.
>>> from transformers import AutoModelForCausalLM
>>> model = AutoModelForCausalLM.from_pretrained("username/my_awesome_eli5_clm-model")
>>> outputs = model.generate(inputs, max_new_tokens=100, do_sample=True, top_k=50, top_p=0.95)Decodifique os ids de tokens gerados de volta para texto:
>>> tokenizer.batch_decode(outputs, skip_special_tokens=True)
["Somatic hypermutation allows the immune system to react to drugs with the ability to adapt to a different environmental situation. In other words, a system of 'hypermutation' can help the immune system to adapt to a different environmental situation or in some cases even a single life. In contrast, researchers at the University of Massachusetts-Boston have found that 'hypermutation' is much stronger in mice than in humans but can be found in humans, and that it's not completely unknown to the immune system. A study on how the immune system"]