# Estratégias de geração

Uma estratégia de decodificação define como um modelo deve selecionar o próximo token gerado. Existem muitos tipos de estratégias de decodificação, e a escolha da estratégia adequada tem um impacto significativo na qualidade do texto gerado.

Este guia ajudará você a entender as diferentes estratégias de decodificação disponíveis no Transformers e como e quando usá-las.

## Métodos básicos de decodificação

Estes são métodos de decodificação bem estabelecidos e devem ser seu ponto de partida para tarefas de geração de texto.

### Busca gulosa

A busca gulosa é a estratégia de decodificação padrão. Ela seleciona o token mais provável a cada etapa. A menos que especificado em [GenerationConfig](/docs/transformers/main/pt/main_classes/text_generation#transformers.GenerationConfig), essa estratégia gera no máximo 20 novos tokens.

A busca gulosa funciona bem para tarefas com saídas relativamente curtas, em que a criatividade não é uma prioridade. No entanto, ela falha ao gerar sequências mais longas, pois começa a se repetir.

```py
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from accelerate import Accelerator

device = Accelerator().device

tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt").to(device)

model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf", dtype=torch.float16).to(device)
# explicitly set to default length because Llama2 generation length is 4096
outputs = model.generate(**inputs, max_new_tokens=20)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
'Hugging Face is an open-source company that provides a suite of tools and services for building, deploying, and maintaining natural language processing'
```

### Amostragem

A amostragem, ou amostragem multinomial, seleciona aleatoriamente um token com base na distribuição de probabilidade sobre todo o vocabulário do modelo (em oposição ao token mais provável, como na busca gulosa). Isso significa que todo token com probabilidade não nula tem a chance de ser selecionado. As estratégias de amostragem reduzem a repetição e podem gerar saídas mais criativas e diversificadas.

Ative a amostragem multinomial com `do_sample=True` e `num_beams=1`.

```py
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from accelerate import Accelerator

device = Accelerator().device

tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt").to(device)

model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf", dtype=torch.float16).to(device)
# explicitly set to 100 because Llama2 generation length is 4096
outputs = model.generate(**inputs, max_new_tokens=50, do_sample=True, num_beams=1)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
'Hugging Face is an open-source company 🤗\nWe are open-source and believe that open-source is the best way to build technology. Our mission is to make AI accessible to everyone, and we believe that open-source is the best way to achieve that.'
```

### Busca por feixe

A busca por feixe (beam search) acompanha várias sequências geradas (feixes) em cada passo de tempo. Após um certo número de passos, ela seleciona a sequência com a maior probabilidade *global*. Diferentemente da busca gulosa, essa estratégia pode "olhar para frente" e escolher uma sequência com maior probabilidade global, mesmo que os tokens iniciais tenham uma probabilidade menor. Ela é mais adequada para tarefas baseadas na entrada, como descrever uma imagem ou reconhecimento de fala. Você também pode usar `do_sample=True` com a busca por feixe para amostrar em cada passo, mas a busca por feixe ainda removerá de forma gulosa as sequências de baixa probabilidade entre os passos.

> [!TIP]
> Confira o [visualizador de beam search](https://huggingface.co/spaces/m-ric/beam_search_visualizer) para ver como o beam search funciona.

Ative a busca por feixe com o parâmetro `num_beams` (deve ser maior que 1, caso contrário, é equivalente à busca gulosa).

```py
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from accelerate import Accelerator

device = Accelerator().device

tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt").to(device)

model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf", dtype=torch.float16).to(device)
# explicitly set to 100 because Llama2 generation length is 4096
outputs = model.generate(**inputs, max_new_tokens=50, num_beams=2)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
"['Hugging Face is an open-source company that develops and maintains the Hugging Face platform, which is a collection of tools and libraries for building and deploying natural language processing (NLP) models. Hugging Face was founded in 2018 by Thomas Wolf']"
```

## Métodos de geração personalizados

Métodos de geração personalizados permitem comportamentos especializados, como:

- fazer o modelo continuar pensando se ele estiver incerto;
- reverter a geração se o modelo travar;
- tratar tokens especiais com lógica personalizada;
- use caches de KV especializados;

Habilitamos métodos de geração personalizados por meio de repositórios de modelos, assumindo uma tag de modelo e uma estrutura de arquivos específicas (veja a subseção abaixo). Este recurso é uma extensão do [código de modelagem personalizado](./models#custom-models) e, como tal, requer a configuração de `trust_remote_code=True`.

Se um repositório de modelos contém um método de geração personalizado, a maneira mais fácil de testá-lo é carregar o modelo e gerar com ele:

```py
from transformers import AutoModelForCausalLM, AutoTokenizer

# `transformers-community/custom_generate_example` holds a copy of `Qwen/Qwen2.5-0.5B-Instruct`, but
# with custom generation code -> calling `generate` uses the custom generation method!
tokenizer = AutoTokenizer.from_pretrained("transformers-community/custom_generate_example")
model = AutoModelForCausalLM.from_pretrained(
    "transformers-community/custom_generate_example", device_map="auto", trust_remote_code=True
)

inputs = tokenizer(["The quick brown"], return_tensors="pt").to(model.device)
# The custom generation method is a minimal greedy decoding implementation. It also prints a custom message at run time.
gen_out = model.generate(**inputs)
# you should now see its custom message, "✨ using a custom generation method ✨"
print(tokenizer.batch_decode(gen_out, skip_special_tokens=True))
'The quick brown fox jumps over a lazy dog, and the dog is a type of animal. Is'
```

Repositórios de modelos com métodos de geração personalizados possuem uma propriedade especial: seu método de geração pode ser carregado a partir de **qualquer** modelo por meio do argumento `custom_generate` de [generate()](/docs/transformers/main/pt/main_classes/text_generation#transformers.GenerationMixin.generate). Isso significa que qualquer pessoa pode criar e compartilhar seu método de geração personalizado para potencialmente funcionar com qualquer modelo do Transformers, sem exigir que os usuários instalem pacotes Python adicionais.

```py
from transformers import AutoModelForCausalLM, AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct")
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct", device_map="auto")

inputs = tokenizer(["The quick brown"], return_tensors="pt").to(model.device)
# `custom_generate` replaces the original `generate` by the custom generation method defined in
# `transformers-community/custom_generate_example`
gen_out = model.generate(**inputs, custom_generate="transformers-community/custom_generate_example", trust_remote_code=True)
print(tokenizer.batch_decode(gen_out, skip_special_tokens=True)[0])
'The quick brown fox jumps over a lazy dog, and the dog is a type of animal. Is'
```

Você deve ler o arquivo `README.md` do repositório que contém a estratégia de geração personalizada para ver quais são as diferenças nos novos argumentos e no tipo de saída, caso existam. Caso contrário, você pode assumir que funciona como o método base [generate()](/docs/transformers/main/pt/main_classes/text_generation#transformers.GenerationMixin.generate).

> [!TIP]
> Você pode encontrar todos os métodos de geração personalizados [buscando pela tag personalizada](https://huggingface.co/models?other=custom_generate), `custom_generate`.

Considere o repositório do Hub [transformers-community/custom_generate_example](https://huggingface.co/transformers-community/custom_generate_example) como exemplo. O `README.md` indica que ele possui um argumento de entrada adicional, `left_padding`, que adiciona um número de tokens de padding antes do prompt.

```py
gen_out = model.generate(
    **inputs, custom_generate="transformers-community/custom_generate_example", trust_remote_code=True, left_padding=5
)
print(tokenizer.batch_decode(gen_out)[0])
'<|endoftext|><|endoftext|><|endoftext|><|endoftext|><|endoftext|>The quick brown fox jumps over the lazy dog.\n\nThe sentence "The quick'
```

Se o método personalizado tiver requisitos de Python fixados que o seu ambiente não atende, você receberá uma exceção sobre requisitos ausentes. Por exemplo, [transformers-community/custom_generate_bad_requirements](https://huggingface.co/transformers-community/custom_generate_bad_requirements) tem um conjunto impossível de requisitos definido em seu arquivo `custom_generate/requirements.txt`, e você verá a mensagem de erro abaixo se tentar executá-lo.

```text
ImportError: Missing requirements in your local environment for `transformers-community/custom_generate_bad_requirements`:
foo (installed: None)
bar==0.0.0 (installed: None)
torch>=99.0 (installed: 2.6.0)
```

Atualizar os requisitos do Python de acordo com isso removerá essa mensagem de erro.

### Criando um método de geração personalizado

Para criar um novo método de geração, você precisa criar um novo repositório [**Model**](https://huggingface.co/new) e enviar alguns arquivos para ele.

1. O modelo com o qual você projetou seu método de geração.
2. `custom_generate/generate.py`, que contém toda a lógica para o seu método de geração personalizado.
3. `custom_generate/requirements.txt`, usado para adicionar opcionalmente novos requisitos do Python e/ou fixar versões específicas para usar corretamente o seu método.
4. `README.md`, onde você deve adicionar a tag `custom_generate` e documentar aqui quaisquer novos argumentos ou diferenças no tipo de saída do seu método personalizado.

Depois de adicionar todos os arquivos necessários, seu repositório deve ficar assim

```text
your_repo/
├── README.md          # include the 'custom_generate' tag
├── config.json
├── ...
└── custom_generate/
    ├── generate.py
    └── requirements.txt
```

#### Adicionando o modelo base

O ponto de partida para o seu método de geração personalizado é um repositório de modelo, assim como qualquer outro. O modelo a ser adicionado a esse repositório deve ser o modelo com o qual você projetou seu método, e ele deve fazer parte de um par funcional e autossuficiente de modelo-geração. Quando o modelo neste repositório é carregado, o seu método de geração personalizado substituirá `generate`. Não se preocupe — seu método de geração ainda pode ser carregado com qualquer outro modelo do Transformers, conforme explicado na seção acima.

Se você simplesmente quiser copiar um modelo existente, pode

```py
from transformers import AutoModelForCausalLM, AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("source/model_repo")
model = AutoModelForCausalLM.from_pretrained("source/model_repo")
tokenizer.save_pretrained("your/generation_method", push_to_hub=True)
model.save_pretrained("your/generation_method", push_to_hub=True)
```

#### generate.py

Este é o núcleo do seu método de geração. Ele *deve* conter um método chamado `generate`, e esse método *deve* conter um argumento `model` como seu primeiro argumento. `model` é a instância do modelo, o que significa que você tem acesso a todos os atributos e métodos do modelo, incluindo os definidos em [GenerationMixin](/docs/transformers/main/pt/main_classes/text_generation#transformers.GenerationMixin) (como o método base `generate`).

> [!WARNING]
> `generate.py` deve ser colocado em uma pasta chamada `custom_generate` e não no nível raiz do repositório. Os caminhos de arquivo para esse recurso são fixos.

Por baixo dos panos, quando o método base [generate()](/docs/transformers/main/pt/main_classes/text_generation#transformers.GenerationMixin.generate) é chamado com um argumento `custom_generate`, ele primeiro verifica seus requisitos em Python (se houver), em seguida localiza o método `generate` personalizado em `generate.py` e, por fim, chama o `generate` personalizado. Todos os argumentos recebidos e o `model` são encaminhados para o seu método `generate` personalizado, com a exceção dos argumentos usados para acionar a geração personalizada (`trust_remote_code` e `custom_generate`).

Isso significa que o seu `generate` pode ter uma mistura de argumentos originais e personalizados (além de um tipo de saída diferente), conforme mostrado abaixo.

```py
import torch

def generate(model, input_ids, generation_config=None, left_padding=None, **kwargs):
    generation_config = generation_config or model.generation_config  # default to the model generation config
    cur_length = input_ids.shape[1]
    max_length = generation_config.max_length or cur_length + generation_config.max_new_tokens

    # Example of custom argument: add `left_padding` (integer) pad tokens before the prompt
    if left_padding is not None:
        if not isinstance(left_padding, int) or left_padding < 0:
            raise ValueError(f"left_padding must be an integer larger than 0, but is {left_padding}")

        pad_token = kwargs.pop("pad_token", None) or generation_config.pad_token_id or model.config.pad_token_id
        if pad_token is None:
            raise ValueError("pad_token is not defined")
        batch_size = input_ids.shape[0]
        pad_tensor = torch.full(size=(batch_size, left_padding), fill_value=pad_token).to(input_ids.device)
        input_ids = torch.cat((pad_tensor, input_ids), dim=1)
        cur_length = input_ids.shape[1]

    # Simple greedy decoding loop
    while cur_length < max_length:
        logits = model(input_ids).logits
        next_token_logits = logits[:, -1, :]
        next_tokens = torch.argmax(next_token_logits, dim=-1)
        input_ids = torch.cat((input_ids, next_tokens[:, None]), dim=-1)
        cur_length += 1

    return input_ids
```

Siga as práticas recomendadas abaixo para garantir que seu método de geração personalizado funcione como esperado.

- Sinta-se à vontade para reutilizar a lógica de validação e preparação de entrada do [generate()](/docs/transformers/main/pt/main_classes/text_generation#transformers.GenerationMixin.generate) original.
- Fixe a versão do `transformers` nos requisitos se você usar qualquer método/atributo privado em `model`.
- Considere adicionar validação de modelo, validação de entrada ou até mesmo um arquivo de teste separado para ajudar os usuários a verificar a sanidade do seu código em seu ambiente.

Seu método `generate` personalizado pode importar código de forma relativa a partir da pasta `custom_generate`. Por exemplo, se você tiver um arquivo `utils.py`, pode importá-lo da seguinte forma:

```py
from .utils import some_function
```

Apenas imports relativos da mesma pasta `custom_generate` são suportados. Imports de pastas pai/irmã não são válidos. O argumento `custom_generate` também funciona localmente com qualquer diretório que contenha uma estrutura `custom_generate`, o que é o fluxo de trabalho recomendado para desenvolver seu método de geração personalizado.

```py
gen_out = model.generate(**inputs, custom_generate="path/to/local/dir", trust_remote_code=True)
```

> [!WARNING]
> Carregar um diretório local ainda executa o seu `custom_generate/generate.py`, portanto, requer `trust_remote_code=True` da mesma forma que um repositório do Hub. Passe `trust_remote_code=True` apenas para código que você escreveu ou revisou.

#### requirements.txt

Você pode, opcionalmente, especificar requisitos adicionais de Python em um arquivo `requirements.txt` dentro da pasta `custom_generate`. Eles são verificados em tempo de execução e uma exceção será lançada caso estejam ausentes, orientando os usuários a atualizar seu ambiente de forma correspondente.

#### README.md

O arquivo `README.md` no nível raiz do repositório do modelo geralmente descreve o modelo em si. No entanto, como o foco do repositório é o método de geração personalizado, recomendamos fortemente que o foco seja direcionado para a descrição desse método. Além da descrição do método, recomendamos documentar quaisquer diferenças de entrada e/ou saída em relação ao [generate()](/docs/transformers/main/pt/main_classes/text_generation#transformers.GenerationMixin.generate) original. Dessa forma, os usuários podem focar no que é novo e recorrer à documentação do Transformers para os detalhes de implementação genéricos.

Para facilitar a descoberta, recomendamos fortemente que você adicione a tag `custom_generate` ao seu repositório. Para isso, o topo do seu arquivo `README.md` deve se parecer com o exemplo abaixo. Depois de enviar o arquivo, você deve ver a tag no seu repositório!

```text
---
library_name: transformers
tags:
  - custom_generate
---

(your markdown content here)
```

Práticas recomendadas:

- Documente as diferenças de entrada e saída em [generate()](/docs/transformers/main/pt/main_classes/text_generation#transformers.GenerationMixin.generate).
- Adicione exemplos autossuficientes para permitir experimentação rápida.
- Descreva requisitos flexíveis, como o fato de o método funcionar bem apenas com uma determinada família de modelos.

### Reutilizando a preparação de entrada do `generate`

Se você estiver adicionando um novo loop de decodificação, pode ser que queira preservar a preparação de entrada presente em `generate` (expansão de lote, máscaras de atenção, processadores de logits, critérios de parada, etc.). Você também pode passar um **callable** para `custom_generate` para reutilizar o pipeline completo de preparação de [generate()](/docs/transformers/main/pt/main_classes/text_generation#transformers.GenerationMixin.generate), sobrescrevendo apenas o loop de decodificação.

```py
def custom_loop(model, input_ids, attention_mask, logits_processor, stopping_criteria, generation_config, **model_kwargs):
    next_tokens = input_ids
    while input_ids.shape[1] < stopping_criteria[0].max_length:
        logits = model(next_tokens, attention_mask=attention_mask, **model_kwargs).logits
        next_token_logits = logits_processor(input_ids, logits[:, -1, :])
        next_tokens = torch.argmax(next_token_logits, dim=-1)[:, None]
        input_ids = torch.cat((input_ids, next_tokens), dim=-1)
        attention_mask = torch.cat((attention_mask, torch.ones_like(next_tokens)), dim=-1)
    return input_ids

output = model.generate(
    **inputs,
    custom_generate=custom_loop,
    max_new_tokens=10,
)
```

> [!TIP]
> Se você publicar um repositório `custom_generate`, sua implementação de `generate` pode, por sua vez, definir um objeto chamável e passá-lo para `model.generate()`. Isso permite personalizar o loop de decodificação, ao mesmo tempo em que você se beneficia da lógica de preparação de entrada integrada ao Transformers.

### Encontrando métodos de geração personalizados

Você pode encontrar todos os métodos de geração personalizados [buscando pela tag personalizada](https://huggingface.co/models?other=custom_generate), `custom_generate`. Além da tag, curatamos duas coleções de métodos `custom_generate`:

- [Métodos de geração personalizados - Comunidade](https://huggingface.co/collections/transformers-community/custom-generation-methods-community-6888fb1da0efbc592d3a8ab6) -- uma coleção de métodos poderosos contribuídos pela comunidade;
- [Métodos de geração personalizados - Tutoriais](https://huggingface.co/collections/transformers-community/custom-generation-methods-tutorials-6823589657a94940ea02cfec) -- uma coleção de implementações de referência para métodos que anteriormente faziam parte do `transformers`, além de tutoriais para `custom_generate`.

## Recursos

Leia o post no blog [Como gerar texto: usando diferentes métodos de decodificação para geração de linguagem com Transformers](https://huggingface.co/blog/how-to-generate) para uma explicação de como funcionam as estratégias de decodificação mais comuns.

