# Ajuste fino de parâmetros eficientes

Métodos de [ajuste fino eficiente em parâmetros (PEFT)](https://huggingface.co/docs/peft/index) ajustam apenas um pequeno número de parâmetros extras do modelo (adapters) sobre um modelo pré-treinado. Como apenas os parâmetros dos adapters são atualizados, o otimizador rastreia muito menos gradientes e estados, reduzindo significativamente o uso de memória. Os adapters são leves, o que os torna convenientes de compartilhar, armazenar e carregar.

O Transformers se integra diretamente à biblioteca PEFT por meio de [PeftAdapterMixin](/docs/transformers/main/pt/main_classes/peft#transformers.integrations.PeftAdapterMixin), adicionado a todas as classes [PreTrainedModel](/docs/transformers/main/pt/main_classes/model#transformers.PreTrainedModel). Você pode carregar, adicionar, treinar, alternar e excluir adaptadores sem precisar envolver seu modelo em um [PeftModel](https://huggingface.co/docs/peft/main/en/package_reference/peft_model#peft.PeftModel) separado. Todos os métodos PEFT que não são baseados em prompt são suportados (LoRA, IA3, AdaLoRA). Métodos baseados em prompt, como prompt tuning e prefix tuning, exigem o uso direto da [biblioteca PEFT](https://huggingface.co/docs/peft/index).

Instale o PEFT para começar. A integração requer `peft >= 0.20.0`.

```shell
pip install -U peft
```

## Adicionar um adaptador

Crie uma configuração PEFT, como [LoraConfig](https://huggingface.co/docs/peft/main/en/package_reference/lora#peft.LoraConfig), por exemplo, e anexe-a a um modelo com [add_adapter()](/docs/transformers/main/pt/main_classes/peft#transformers.integrations.PeftAdapterMixin.add_adapter).

```py
from peft import LoraConfig, TaskType
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("google/gemma-2-2b")

lora_config = LoraConfig(
    task_type=TaskType.CAUSAL_LM,
    inference_mode=False,
    r=8,
    lora_alpha=32,
    lora_dropout=0.1,
)

model.add_adapter(lora_config, adapter_name="my_adapter")
```

### Ajuste fino completo de camadas específicas

Para treinar módulos adicionais junto com um adaptador (por exemplo, a cabeça do modelo de linguagem), especifique-os em `modules_to_save`. `modules_to_save` especifica as camadas que são totalmente ajustadas junto com o adaptador, de modo que *todos* os seus parâmetros são atualizados. Isso é útil quando certas camadas precisam de atualizações, por exemplo, a cabeça do modelo de linguagem (`lm_head`), ao adaptar um LM causal para classificação de sequência.

```py
lora_config = LoraConfig(
    modules_to_save=["lm_head"],
    ...
)
model.add_adapter(lora_config)
```

### Escolhendo quais camadas adaptar

Para arquiteturas comuns (Llama, Gemma, Qwen, etc.), o PEFT possui alvos padrão predefinidos (como `q_proj` e `v_proj`), então você não precisa especificar `target_modules`. Se você quiser direcionar diferentes camadas, ou se o modelo não tiver alvos predefinidos, passe `target_modules` explicitamente como uma lista de nomes de módulos ou um padrão de expressão regular.

```py
lora_config = LoraConfig(
    target_modules=["q_proj", "k_proj"],
    ...
)
model.add_adapter(lora_config)
```

## Treinamento

Passe o modelo com um adaptador anexado para o [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) e chame [train()](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer.train). O [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) atualiza apenas os parâmetros do adaptador (aqueles com `requires_grad=True`), pois o modelo base está congelado.

```py
from transformers import Trainer, TrainingArguments

training_args = TrainingArguments(
    output_dir="./output",
    num_train_epochs=3,
    per_device_train_batch_size=4,
)

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=dataset,
)

trainer.train()
```

Durante o treinamento, os checkpoints do [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) contêm apenas os pesos do adaptador (`adapter_model.safetensors`) e a configuração (`adapter_config.json`), mantendo os checkpoints pequenos. O modelo base não está incluído.

Após o treinamento, salve o adaptador final com [save_pretrained()](/docs/transformers/main/pt/main_classes/model#transformers.PreTrainedModel.save_pretrained).

```py
model.save_pretrained("./my_adapter")
```

### Retomando a partir de um checkpoint

O [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) detecta automaticamente checkpoints de adaptadores ao retomar. O [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) varre o diretório do checkpoint em busca de subdiretórios que contenham pesos de adaptadores e recarrega cada adaptador com o estado treinável correto.

```py
trainer.train(resume_from_checkpoint="./output/checkpoint-1000")
```

### Treinamento distribuído

Os adaptadores PEFT funcionam com treinamento distribuído nativamente.

No ZeRO-3, o [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) passa `exclude_frozen_parameters=True` ao salvar checkpoints com um modelo PEFT. Os pesos do modelo base congelados são ignorados. Apenas os parâmetros do adaptador treinável são salvos, reduzindo o tamanho do checkpoint e o tempo de salvamento.

Para o FSDP, o [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) atualiza a política de auto-wrap do FSDP para tratar corretamente as camadas LoRA. Para QLoRA (modelo base quantizado + LoRA), o [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) também ajusta a política de precisão mista para corresponder ao dtype de armazenamento da quantização.

Você pode carregar adaptadores PEFT em um modelo base com paralelismo de tensores e deixar que o PEFT gerencie a divisão dos pesos do adaptador. Carregar um adaptador requer `peft >= 0.21.1`. Consulte [Paralelismo de tensores](./tensor_parallelism) para treinamento com TP.

## Carregando um adaptador

Para carregar um adaptador, o repositório do Hub ou o diretório local deve conter um arquivo `adapter_config.json` e os pesos do adaptador.

[from_pretrained()](/docs/transformers/main/pt/main_classes/model#transformers.PreTrainedModel.from_pretrained) detecta adaptadores automaticamente. Quando encontra um `adapter_config.json`, ele lê o campo `base_model_name_or_path` para carregar o modelo base correto e, em seguida, carrega o adaptador sobre ele.

```py
from transformers import AutoModelForCausalLM

# Automatically loads the base model and attaches the adapter
model = AutoModelForCausalLM.from_pretrained("klcsp/gemma7b-lora-alpaca-11-v1")
```

Para carregar um adaptador em um modelo existente, use [load_adapter()](/docs/transformers/main/pt/main_classes/peft#transformers.integrations.PeftAdapterMixin.load_adapter).

```py
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("google/gemma-7b")
model.load_adapter("klcsp/gemma7b-lora-alpaca-11-v1")
```

Para modelos grandes, carregue uma versão quantizada em precisão de 8 bits ou 4 bits com [bitsandbytes](./quantization/bitsandbytes) para economizar memória. Adicione `device_map="auto"` para distribuir o modelo entre o hardware disponível.

```py
from transformers import AutoModelForCausalLM, BitsAndBytesConfig

model = AutoModelForCausalLM.from_pretrained(
    "klcsp/gemma7b-lora-alpaca-11-v1",
    quantization_config=BitsAndBytesConfig(load_in_8bit=True),
    device_map="auto",
)
```

## Gerenciando vários adaptadores

Um modelo pode manter vários adaptadores ao mesmo tempo. Adicione adaptadores com nomes únicos e alterne entre eles conforme necessário.

```py
from peft import LoraConfig

model.add_adapter(LoraConfig(r=8, lora_alpha=32), adapter_name="adapter_1")
model.add_adapter(LoraConfig(r=16, lora_alpha=64), adapter_name="adapter_2")
```

Use [set_adapter()](/docs/transformers/main/pt/main_classes/peft#transformers.integrations.PeftAdapterMixin.set_adapter) para ativar um adaptador específico. Os outros adaptadores são desativados, mas permanecem na memória.

```py
model.set_adapter("adapter_2")
```

[enable_adapters()](/docs/transformers/main/pt/main_classes/peft#transformers.integrations.PeftAdapterMixin.enable_adapters) habilita todos os adaptadores anexados, e [disable_adapters()](/docs/transformers/main/pt/main_classes/peft#transformers.integrations.PeftAdapterMixin.disable_adapters) os desabilita.

```py
# Disable all adapters for base model inference
model.disable_adapters()

# Re-enable all adapters
model.enable_adapters()
```

Use [active_adapters()](/docs/transformers/main/pt/main_classes/peft#transformers.integrations.PeftAdapterMixin.active_adapters) para ver quais adaptadores estão atualmente ativos.

```py
model.active_adapters()
# ["adapter_1"]
```

Remova adaptadores que você não precisa mais com [delete_adapter()](/docs/transformers/main/pt/main_classes/peft#transformers.integrations.PeftAdapterMixin.delete_adapter) para liberar memória.

```py
model.delete_adapter("adapter_1")
```

## Troca de adaptadores

Carregar um novo adaptador a cada solicitação de serviço aloca nova memória. Se o modelo for compilado com `torch.compile`, cada novo adaptador dispara uma recompilação. O hotswap substitui os pesos do adaptador no local, evitando ambos os problemas. Apenas adaptadores LoRA são suportados.

Pass `hotswap=True` ao carregar um adaptador LoRA para substituir seus pesos em um slot de adaptador existente. Defina `adapter_name` com o nome do adaptador a ser substituído (`"default"` é o nome padrão do adaptador).

```py
model = AutoModel.from_pretrained(...)
# Load the first adapter normally
model.load_adapter(adapter_path_1)
# Generate outputs with adapter 1
...
# Hotswap the second adapter in-place
model.load_adapter(adapter_path_2, hotswap=True, adapter_name="default")
# Generate outputs with adapter 2
```

### torch.compile

Para modelos compilados, chame [enable_peft_hotswap()](/docs/transformers/main/pt/main_classes/peft#transformers.integrations.PeftAdapterMixin.enable_peft_hotswap) *antes* de carregar o primeiro adaptador e antes de compilar.

```py
model = AutoModel.from_pretrained(...)
max_rank = ...  # highest rank among all LoRAs you'll load
model.enable_peft_hotswap(target_rank=max_rank)
model.load_adapter(adapter_path_1, adapter_name="default")
model = torch.compile(model, ...)
output_1 = model(...)

# Hotswap without recompilation
model.load_adapter(adapter_path_2, adapter_name="default")
output_2 = model(...)
```

O argumento `target_rank` define o rank máximo entre todos os adaptadores LoRA que você vai carregar. Se você tiver adaptadores com rank 8 e rank 16, passe `target_rank=16`. O padrão é 128.

Após chamar `enable_peft_hotswap`, todas as chamadas subsequentes de `load_adapter` usam hotswap por padrão. Passe `hotswap=False` explicitamente para desativar o hotswap.

A recompilação ainda pode ocorrer se o adapter trocado em tempo de execução (hotswapped) visar mais camadas do que o adapter inicial. Carregue primeiro o adapter que visa o maior número de camadas para evitar a recompilação.

> [!TIP]
> Envolva seu código em `with torch._dynamo.config.patch(error_on_recompile=True)` para detectar recompilações inesperadas. Se você detectar recompilação mesmo seguindo as etapas acima, abra uma issue com [PEFT](https://github.com/huggingface/peft/issues) com um exemplo reproduzível.

## Próximas etapas

- A [documentação](https://huggingface.co/docs/peft/index) do PEFT abrange toda a gama de métodos e opções do PEFT.
- A [referência de hotswapping](https://huggingface.co/docs/peft/main/en/package_reference/hotswap#peft.utils.hotswap.hotswap_adapter) do PEFT detalha as limitações e os casos extremos.
- Um [post de blog](https://huggingface.co/blog/lora-fast) faz o benchmark de como o `torch.compile` com hotswapping melhora o tempo de execução.

