# PaCA: Adaptação de Conexão Parcial

[PaCA](https://huggingface.co/papers/2503.01905) (ICLR 2025) é um método PEFT que visa a velocidade de treinamento e a memória de ativação. Ele faz o ajuste fino de `r` colunas de entrada selecionadas aleatoriamente ("conexões parciais") de cada peso pré-treinado alvo. Os únicos parâmetros treináveis são as atualizações dessas colunas; diferentemente do LoRA, o PaCA não adiciona matrizes de baixo posto extras.

Métodos como LoRA executam um pequeno ramo de baixo posto ao lado de cada camada pré-treinada. O ramo requer poucos FLOPs, mas é executado sequencialmente com a camada pré-treinada e mantém sua própria cópia da ativação de entrada para a passagem reversa. O PaCA evita ambos:

- **Um GEMM por camada.** As colunas adaptadas são gravadas no peso pré-treinado imediatamente antes do seu matmul e restauradas imediatamente depois, de modo que o forward e o backward executam cada um um único matmul, exatamente como a camada base congelada.
- **Ativações parciais.** O gradiente das colunas adaptadas depende apenas dos `r` canais de entrada correspondentes, portanto, apenas esses são salvos para a passagem reversa, em vez da entrada completa.

Em termos dos pesos resultantes, um adaptador PaCA é equivalente a um adaptador LoRA de rank `r` cuja matriz `A` é um seletor de colunas fixo: `W' = W + delta @ S`, em que `S` seleciona as `r` colunas. Portanto, ele pode ser convertido em um adaptador LoRA de rank `r` sem perda por meio de [convert_to_lora()](/docs/peft/main/pt/package_reference/lora_conversion#peft.convert_to_lora), por exemplo, para servi-lo com uma pilha de inferência LoRA.

Quando usar o PaCA:

- Você deseja precisão no nível do LoRA, mas com etapas de fine-tuning mais rápidas e menor memória de ativação, por exemplo, para caber sequências mais longas ou lotes maiores na mesma GPU.
- Você deseja um adaptador que se mescla exatamente nos pesos base (a atualização é uma atualização simples de coluna).

Restrições atuais:

- Somente camadas `nn.Linear` (incluindo camadas lineares quantizadas) são suportadas.
- O PaCA executa o matmul em si, em vez de chamar o `forward` da camada base, portanto, os forward hooks registrados na camada base não são chamados (um aviso é emitido). Registre os hooks na camada PaCA.
- Lotes de adaptadores mistos (argumento `adapter_names`) não são suportados.
- O treinamento com pesos fragmentados (FSDP, DeepSpeed ZeRO-3) ainda não foi testado.
- `torch.compile` é suportado: durante a compilação, a troca de colunas, o matmul e a restauração são executados como operações personalizadas opacas (`torch.ops.peft.paca_linear_forward`/`_backward`), de modo que o compilador não copia os pesos base. Isso requer `torch.library.custom_op` (PyTorch >= 2.4); caso contrário, a implementação eager é rastreada.
- `paca_alpha / r` escala a atualização da coluna e, portanto, atua como um multiplicador da taxa de aprendizado efetiva.
- Para inferência, merge o adaptador (`merge_and_unload()`); o forward não mesclado ainda troca as colunas a cada chamada.

## Uso

```python
from transformers import AutoModelForCausalLM
from peft import PacaConfig, get_peft_model

model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.2-3B")
config = PacaConfig(r=16, paca_alpha=16, target_modules="all-linear", random_seed=0)
model = get_peft_model(model, config)
model.print_trainable_parameters()
```

Por padrão, cada camada alvo faz o fine-tuning de `r` colunas selecionadas aleatoriamente; no artigo, isso teve desempenho equivalente ao de selecionar as colunas pela norma de peso ou pelos gradientes acumulados. Para escolher as colunas você mesmo, por exemplo para tentar outra estratégia de seleção ou para usar um número diferente de colunas por camada, passe `paca_indices_pattern`. Suas chaves são nomes de camadas ou expressões regulares, como em `rank_pattern` do LoRA:

```python
config = PacaConfig(
    r=16,
    paca_alpha=16,
    target_modules=["q_proj", "v_proj"],
    paca_indices_pattern={"layers.0.self_attn.q_proj": [0, 2, 4, 6], "layers.1.self_attn.v_proj": list(range(32))},
)
```

Camadas que correspondem a uma chave fazem o fine-tuning das colunas dadas, enquanto todas as outras camadas-alvo selecionam `r` colunas aleatórias. A escala é `paca_alpha / r` com o `r` da configuração em cada camada, de modo que `paca_alpha` significa o mesmo para todas as camadas.

O resumo do artigo é:

> Algoritmos de ajuste fino eficiente em parâmetros (PEFT) anteriores reduzem o uso de memória e os custos computacionais do ajuste fino de modelos grandes de redes neurais treinando apenas alguns parâmetros adicionais de adaptador, em vez do modelo inteiro. No entanto, a redução nos custos computacionais devido ao PEFT não se traduz necessariamente em uma redução no tempo de treinamento; embora os custos computacionais das camadas de adaptador sejam muito menores do que os das camadas pré-treinadas, é bem conhecido que esses dois tipos de camadas são processados sequencialmente em GPUs, resultando em um sobrecarga significativa de latência. LoRA e suas variantes evitam essa sobrecarga de latência mesclando as matrizes de adaptador de baixo rank com os pesos pré-treinados durante a inferência. No entanto, essas camadas não podem ser mescladas durante o treinamento, pois os pesos pré-treinados devem permanecer congelados enquanto as matrizes de adaptador de baixo rank são atualizadas continuamente ao longo do treinamento. Além disso, LoRA e suas variantes não reduzem a memória de ativação, pois a primeira matriz de adaptador de baixo rank ainda requer as ativações de entrada dos pesos pré-treinados para calcular os gradientes dos pesos. Para mitigar esse problema, propomos a Adaptação de Conexão Parcial (PaCA), que ajusta conexões parciais selecionadas aleatoriamente dentro dos pesos pré-treinados, em vez de introduzir camadas de adaptador no modelo. A PaCA não apenas melhora a velocidade de treinamento ao eliminar a sobrecarga de tempo devido ao processamento sequencial das camadas de adaptador e pré-treinadas, mas também reduz a memória de ativação, pois apenas ativações parciais, em vez de ativações completas, precisam ser armazenadas para o cálculo de gradientes. Em comparação com o LoRA, a PaCA reduz o tempo de treinamento em 22% e o uso total de memória em 16%, mantendo precisão comparável em vários cenários de ajuste fino, como ajuste fino no conjunto de dados MMLU e ajuste de instruções no conjunto de dados Oasst1. A PaCA também pode ser combinada com quantização, permitindo o ajuste fino de modelos grandes, como o LLaMA3.1-70B. Além disso, a PaCA permite o treinamento com sequências 23% mais longas e melhora a taxa de transferência em 16% tanto na GPU NVIDIA A100 quanto no HPU INTEL Gaudi2, em comparação com o LoRA.

## Visão geral do benchmark

<iframe src="https://peft-internal-testing-peft-method-comparison-embed.hf.space/?highlight[type]=PACA" frameborder="0" width="850" height="1000"
>

# API

## PacaConfig[[peft.PacaConfig]]

#### peft.PacaConfig[[peft.PacaConfig]]

```python
peft.PacaConfig(task_type: Optional[Union[str, TaskType]] = None, peft_type: Optional[Union[str, PeftType]] = None, auto_mapping: Optional[dict] = None, peft_version: Optional[str] = None, base_model_name_or_path: Optional[str] = None, revision: Optional[str] = None, inference_mode: bool = False, r: int = 8, paca_alpha: int = 8, target_modules: list[str] | str | None = None, exclude_modules: list[str] | str | None = None, layers_to_transform: list[int] | int | None = None, layers_pattern: list[str] | str | None = None, random_seed: int | None = None, paca_indices_pattern: dict | None = <factory>, init_weights: bool = True, modules_to_save: list[str] | None = None)
```

[Fonte](https://github.com/huggingface/peft/blob/main/src/peft/tuners/paca/config.py#L23)

**Parâmetros:**

r (`int`, *opcional*, padrão `8`) : Número de colunas de entrada (conexões parciais) que são ajustadas em cada camada alvo. Para um peso de forma `(out_features, in_features)`, o PaCA treina `r * out_features` parâmetros, o mesmo número que a matriz `B` de um adaptador LoRA com rank `r`. Não deve exceder `in_features`.

paca_alpha (`int`, *opcional*, padrão `8`) : Fator de escala. A atualização das colunas selecionadas é `paca_alpha / r * delta`. Assim como `lora_alpha`, isso atua como um multiplicador da taxa de aprendizado efetiva do adaptador.

target_modules (`Union[list[str], str]`, *opcional*) : Lista de nomes de módulos ou expressão regular dos nomes de módulos a serem substituídos por PaCA. Por exemplo, `['q_proj', 'v_proj']` ou `'.*decoder.*(SelfAttention|EncDecAttention).*(q|v)$'`. Se especificado como `'all-linear'`, todos os módulos lineares, exceto a camada de saída, são selecionados. Apenas camadas `nn.Linear` são suportadas.

exclude_modules (`Union[list[str], str]`, *opcional*) : Os nomes dos módulos para os quais o adaptador não deve ser aplicado. Ao passar uma string, será realizada uma correspondência por regex. Ao passar uma lista de strings, será realizada uma correspondência exata ou será verificado se o nome do módulo termina com qualquer uma das strings passadas.

layers_to_transform (`Union[list[int], int]`, *opcional*) : Os índices das camadas a serem transformadas. Se este argumento for especificado, o PEFT transformará apenas os índices das camadas especificados dentro desta lista. Se um único inteiro for passado, o PEFT transformará apenas a camada neste índice.

layers_pattern (`Optional[Union[list[str], str]]`, *opcional*) : O nome do padrão da camada, usado apenas se `layers_to_transform` for diferente de `None`. Isso deve apontar para o `nn.ModuleList` do modelo, que frequentemente é chamado de `'layers'` ou `'h'`.

random_seed (`int`, *opcional*, padrão `None`) : Semente usada para selecionar as conexões parciais. Cada camada usa uma seleção diferente derivada desta semente e do nome da camada. Se `None`, o gerador global de números aleatórios do torch é utilizado. Os índices selecionados são sempre armazenados no checkpoint do adaptador, portanto a semente não é necessária para carregar um adaptador treinado.

paca_indices_pattern (`dict`, *opcional*) : Mapeamento opcional de nomes de camadas ou expressões regulares para os índices das colunas de entrada que são ajustadas finamente nas camadas correspondentes, em vez de `r` selecionadas aleatoriamente, por exemplo `{'^model.layers.0.self_attn.q_proj': [0, 2, 4]}`. Isso também permite um número diferente de colunas por camada. Os índices de uma camada devem ser únicos e menores que `in_features`. A escala é `paca_alpha / r` com o `r` desta configuração em todas as camadas, independentemente do número de índices fornecidos. Camadas-alvo que não correspondem a nenhuma chave usam `r` colunas selecionadas aleatoriamente.

init_weights (`bool`, *opcional*, padrão `True`) : Se `True`, a atualização das colunas selecionadas é inicializada com zero, ou seja, o modelo adaptado é idêntico ao modelo base na inicialização. Defina como `False` para inicializar com valores aleatórios; isso é destinado apenas para testes.

modules_to_save (`list[str]`, *opcional*) : Lista de módulos, além das camadas PaCA, que devem ser configurados como treináveis e salvos no checkpoint final. Por exemplo, em tarefas de Classificação de Sequência ou Classificação de Tokens, a camada final `classifier/score` é inicializada aleatoriamente e, portanto, precisa ser treinável e salva.

Esta é a classe de configuração para armazenar a configuração de um [PacaModel](/docs/peft/main/pt/package_reference/paca#peft.PacaModel).

PaCA (Partial Connection Adaptation, https://huggingface.co/papers/2503.01905) faz o fine-tuning de `r` colunas de entrada selecionadas aleatoriamente (conexões parciais) de cada peso pré-treinado alvo. Os únicos parâmetros treináveis são as atualizações dessas colunas; diferentemente do LoRA, o PaCA não adiciona matrizes de baixo rank extras. Imediatamente antes do matmul, as colunas adaptadas são substituídas no peso pré-treinado e restauradas imediatamente depois, de modo que o forward e o backward executam cada um um único GEMM, e apenas os `r` canais de entrada selecionados são mantidos na memória para o passo de backward.

## PacaModel[[peft.PacaModel]]

#### peft.PacaModel[[peft.PacaModel]]

```python
peft.PacaModel(model, peft_config: Union[PeftConfig, dict[str, PeftConfig]], adapter_name: str, low_cpu_mem_usage: bool = False, state_dict: Optional[dict[str, torch.Tensor]] = None)
```

[Fonte](https://github.com/huggingface/peft/blob/main/src/peft/tuners/paca/model.py#L38)

**Parâmetros:**

model ([PreTrainedModel](https://huggingface.co/docs/transformers/main/en/main_classes/model#transformers.PreTrainedModel)) : O modelo a ser adaptado.

config ([PacaConfig](/docs/peft/main/pt/package_reference/paca#peft.PacaConfig)) : A configuração do modelo PaCA.

adapter_name (`str`) : O nome do adaptador, padrão é `"default"`.

low_cpu_mem_usage (`bool`, `optional`, padrão `False`) : Cria pesos de adaptador vazios no dispositivo meta. Útil para acelerar o processo de carregamento.

**Retorna:** `torch.nn.Module`

O modelo PaCA.

Cria um modelo de Adaptação de Conexão Parcial (PaCA) a partir de um modelo pré-treinado. O método é descrito em https://huggingface.co/papers/2503.01905.

Exemplo:

```py
>>> from transformers import AutoModelForCausalLM
>>> from peft import PacaConfig, get_peft_model

>>> base_model = AutoModelForCausalLM.from_pretrained("facebook/opt-125m")
>>> config = PacaConfig(r=16, paca_alpha=16, target_modules="all-linear")
>>> model = get_peft_model(base_model, config)
```

**Atributos**:
- **model** ([PreTrainedModel](https://huggingface.co/docs/transformers/main/en/main_classes/model#transformers.PreTrainedModel)) -- O modelo a ser adaptado.
- **peft_config** ([PacaConfig](/docs/peft/main/pt/package_reference/paca#peft.PacaConfig)): A configuração do modelo PaCA.

