# PaCA : adaptation de la connexion partielle

[PaCA](https://huggingface.co/papers/2503.01905) (ICLR 2025) est une méthode PEFT qui vise la vitesse d’entraînement et la mémoire d’activation. Elle ajuste finement `r` colonnes d’entrée sélectionnées aléatoirement (« connexions partielles ») de chaque poids pré-entraîné ciblé. Les seuls paramètres entraînables sont les mises à jour de ces colonnes ; contrairement à LoRA, PaCA n’ajoute aucune matrice de faible rang supplémentaire.

Des méthodes telles que LoRA exécutent une petite branche de faible rang à côté de chaque couche pré-entraînée. Cette branche nécessite peu de FLOPs, mais elle est exécutée séquentiellement avec la couche pré-entraînée et conserve sa propre copie de l’activation d’entrée pour le passage arrière. PaCA évite les deux :

- **Un seul GEMM par couche.** Les colonnes adaptées sont écrites dans le poids préentraîné juste avant sa multiplication matricielle et restaurées juste après, de sorte que les passes avant et arrière exécutent chacune une seule multiplication matricielle, exactement comme la couche de base gelée.
- **Activations partielles.** Le gradient des colonnes adaptées ne dépend que des `r` canaux d’entrée correspondants, seuls ceux-ci sont donc conservés pour le passage arrière au lieu de l’entrée complète.

En termes de poids résultants, un adaptateur PaCA est équivalent à un adaptateur LoRA de rang `r` dont la matrice `A` est un sélecteur de colonnes fixe : `W' = W + delta @ S`, où `S` sélectionne les `r` colonnes. Il peut donc être converti en un adaptateur LoRA de rang `r` sans perte via [convert_to_lora()](/docs/peft/main/fr/package_reference/lora_conversion#peft.convert_to_lora), par exemple pour le servir avec une pile d'inférence LoRA.

Quand utiliser PaCA :

- Vous souhaitez une précision au niveau de LoRA, mais avec des étapes de fine-tuning plus rapides et une mémoire d'activation plus faible, par exemple pour traiter des séquences plus longues ou des lots plus volumineux sur le même GPU.
- Vous souhaitez un adaptateur qui fusionne exactement dans les poids de base (la mise à jour est une simple mise à jour de colonne).

Contraintes actuelles :

- Seules les couches `nn.Linear` (y compris les couches linéaires quantifiées) sont prises en charge.
- PaCA exécute lui-même la multiplication matricielle au lieu d'appeler la méthode `forward` de la couche de base, de sorte que les hooks de forward enregistrés sur la couche de base ne sont pas appelés (un avertissement est émis). Enregistrez les hooks sur la couche PaCA à la place.
- Les lots d'adaptateurs mixtes (argument `adapter_names`) ne sont pas pris en charge.
- L'entraînement avec des poids fragmentés (FSDP, DeepSpeed ZeRO-3) n'a pas encore été testé.
- `torch.compile` est pris en charge : lors de la compilation, l’échange de colonnes, le matmul et la restauration s’exécutent en tant qu’opérations personnalisées opaques (`torch.ops.peft.paca_linear_forward`/`_backward`), de sorte que le compilateur ne copie pas les poids de base. Cela nécessite `torch.library.custom_op` (PyTorch >= 2.4) ; sinon, l’implémentation eager est tracée.
- `paca_alpha / r` met à l'échelle la mise à jour de la colonne et agit donc comme un multiplicateur du taux d'apprentissage effectif.
- Pour l’inférence, fusionnez l’adaptateur (`merge_and_unload()`) ; le forward non fusionné continue d’échanger les colonnes à chaque appel.

## Utilisation

```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()
```

Par défaut, chaque couche ciblée ajuste `r` colonnes sélectionnées aléatoirement ; dans l’article, cela a donné des résultats comparables à la sélection des colonnes par norme de poids ou par gradients accumulés. Pour choisir vous-même les colonnes, par exemple pour essayer une autre stratégie de sélection ou pour utiliser un nombre différent de colonnes par couche, passez `paca_indices_pattern`. Ses clés sont des noms de couches ou des expressions régulières, comme dans `rank_pattern` de 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))},
)
```

Les couches qui correspondent à une clé affinent les colonnes données, tandis que toutes les autres couches ciblées sélectionnent `r` colonnes aléatoires. L'échelle est `paca_alpha / r` avec le `r` de la configuration dans chaque couche, de sorte que `paca_alpha` a la même signification pour toutes les couches.

L'abstract de l'article est :

> Les algorithmes de fine-tuning efficace en paramètres (PEFT) réduisent la consommation mémoire et les coûts de calcul du fine-tuning de grands modèles de réseaux de neurones en n'entraînant que quelques paramètres d'adaptateurs supplémentaires, plutôt que l'ensemble du modèle. Cependant, la réduction des coûts de calcul due au PEFT ne se traduit pas nécessairement par une réduction du temps d'entraînement ; bien que les coûts de calcul des couches d'adaptateurs soient beaucoup plus faibles que ceux des couches pré-entraînées, il est bien connu que ces deux types de couches sont traités séquentiellement sur les GPU, ce qui entraîne un surcoût de latence important. LoRA et ses variantes évitent ce surcoût de latence en fusionnant les matrices d'adaptateurs de faible rang avec les poids pré-entraînés lors de l'inférence. Toutefois, ces couches ne peuvent pas être fusionnées pendant l'entraînement, car les poids pré-entraînés doivent rester figés tandis que les matrices d'adaptateurs de faible rang sont mises à jour en continu au cours de l'entraînement. De plus, LoRA et ses variantes ne réduisent pas la mémoire d'activation, car la première matrice d'adaptateur de faible rang nécessite toujours les activations d'entrée des poids pré-entraînés pour calculer les gradients des poids. Pour atténuer ce problème, nous proposons l'adaptation de connexions partielles (PaCA), qui effectue le fine-tuning de connexions partielles sélectionnées aléatoirement au sein des poids pré-entraînés, au lieu d'introduire des couches d'adaptateurs dans le modèle. PaCA améliore non seulement la vitesse d'entraînement en éliminant le surcoût temporel dû au traitement séquentiel des couches d'adaptateurs et des couches pré-entraînées, mais réduit également la mémoire d'activation, car seules des activations partielles, plutôt que des activations complètes, doivent être stockées pour le calcul des gradients. Par rapport à LoRA, PaCA réduit le temps d'entraînement de 22 % et la consommation mémoire totale de 16 %, tout en maintenant une précision comparable dans divers scénarios de fine-tuning, tels que le fine-tuning sur le jeu de données MMLU et l'instruction tuning sur le jeu de données Oasst1. PaCA peut également être combiné avec la quantification, permettant le fine-tuning de grands modèles tels que LLaMA3.1-70B. En outre, PaCA permet un entraînement avec des séquences 23 % plus longues et améliore le débit de 16 % sur les GPU NVIDIA A100 et les HPU INTEL Gaudi2 par rapport à LoRA.

## Aperçu des benchmarks

<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)
```

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

**Paramètres :**

r (`int`, *facultatif*, valeur par défaut `8`) : Nombre de colonnes d'entrée (connexions partielles) qui sont affinées dans chaque couche ciblée. Pour un poids de forme `(out_features, in_features)`, PaCA entraîne `r * out_features` paramètres, le même nombre que la matrice `B` d'un adaptateur LoRA de rang `r`. Ne doit pas dépasser `in_features`.

paca_alpha (`int`, *facultatif*, valeur par défaut `8`) : Facteur d'échelle. La mise à jour des colonnes sélectionnées est `paca_alpha / r * delta`. Comme `lora_alpha`, cela agit comme un multiplicateur du taux d'apprentissage effectif de l'adaptateur.

target_modules (`Union[list[str], str]`, *facultatif*) : Liste de noms de modules ou expression régulière des noms de modules à remplacer par PaCA. Par exemple, `['q_proj', 'v_proj']` ou `'.*decoder.*(SelfAttention|EncDecAttention).*(q|v)$'`. Si cette valeur est spécifiée comme `'all-linear'`, tous les modules linéaires, à l'exception de la couche de sortie, sont sélectionnés. Seules les couches `nn.Linear` sont prises en charge.

exclude_modules (`Union[list[str], str]`, *facultatif*) : Les noms des modules auxquels l'adaptateur ne doit pas être appliqué. Lors du passage d'une chaîne de caractères, une correspondance par expression régulière est effectuée. Lors du passage d'une liste de chaînes de caractères, soit une correspondance exacte est effectuée, soit il est vérifié si le nom du module se termine par l'une des chaînes passées.

layers_to_transform (`Union[list[int], int]`, *facultatif*) : Les index des couches à transformer. Si cet argument est spécifié, PEFT ne transformera que les index de couches spécifiés dans cette liste. Si un entier unique est transmis, PEFT ne transformera que la couche à cet index.

layers_pattern (`Optional[Union[list[str], str]]`, *facultatif*) : Le nom du motif de couche, utilisé uniquement si `layers_to_transform` est différent de `None`. Il doit cibler le `nn.ModuleList` du modèle, souvent appelé `'layers'` ou `'h'`.

random_seed (`int`, *facultatif*, valeur par défaut `None`) : Graine utilisée pour sélectionner les connexions partielles. Chaque couche utilise une sélection différente dérivée de cette graine et du nom de la couche. Si `None`, le générateur aléatoire global de torch est utilisé. Les indices sélectionnés sont toujours stockés dans le point de contrôle de l'adaptateur, de sorte que la graine n'est pas nécessaire pour charger un adaptateur entraîné.

paca_indices_pattern (`dict`, *facultatif*) : Correspondance facultative entre les noms de couches ou des expressions régulières et les indices de colonnes d'entrée qui sont affinés dans les couches correspondantes, au lieu de `r` colonnes sélectionnées aléatoirement, par exemple `{'^model.layers.0.self_attn.q_proj': [0, 2, 4]}`. Cela permet également d'utiliser un nombre différent de colonnes par couche. Les indices d'une couche doivent être uniques et inférieurs à `in_features`. L'échelle est `paca_alpha / r` avec le `r` de cette configuration dans toutes les couches, indépendamment du nombre d'indices fournis. Les couches ciblées qui ne correspondent à aucune clé utilisent `r` colonnes sélectionnées aléatoirement.

init_weights (`bool`, *facultatif*, valeur par défaut `True`) : Si `True`, la mise à jour des colonnes sélectionnées est initialisée à zéro, c'est-à-dire que le modèle adapté est identique au modèle de base à l'initialisation. Définir sur `False` pour initialiser avec des valeurs aléatoires ; cela est uniquement destiné aux tests.

modules_to_save (`list[str]`, *facultatif*) : Liste des modules, à l'exception des couches PaCA, à définir comme entraînables et à enregistrer dans le point de contrôle final. Par exemple, dans les tâches de classification de séquences ou de classification de jetons, la couche finale `classifier/score` est initialisée aléatoirement et doit donc être entraînable et enregistrée.

Ceci est la classe de configuration destinée à stocker la configuration d'un [PacaModel](/docs/peft/main/fr/package_reference/paca#peft.PacaModel).

PaCA (Partial Connection Adaptation, https://huggingface.co/papers/2503.01905) ajuste finement `r` colonnes d’entrée aléatoirement sélectionnées (connexions partielles) de chaque poids pré-entraîné ciblé. Les seuls paramètres entraînables sont les mises à jour de ces colonnes ; contrairement à LoRA, PaCA n’ajoute aucune matrice de rang faible supplémentaire. Juste avant la multiplication matricielle, les colonnes adaptées sont insérées dans le poids pré-entraîné et restaurées juste après, de sorte que les passes avant et arrière exécutent chacune un seul GEMM, et que seuls les `r` canaux d’entrée sélectionnés sont conservés en mémoire pour la passe arrière.

## 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)
```

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

**Paramètres :**

model ([PreTrainedModel](https://huggingface.co/docs/transformers/main/en/main_classes/model#transformers.PreTrainedModel)) : Le modèle à adapter.

config ([PacaConfig](/docs/peft/main/fr/package_reference/paca#peft.PacaConfig)) : La configuration du modèle PaCA.

adapter_name (`str`) : Le nom de l'adaptateur, par défaut `"default"`.

low_cpu_mem_usage (`bool`, `optional`, par défaut `False`) : Crée des poids d'adaptateur vides sur l'appareil méta. Utile pour accélérer le processus de chargement.

**Retourne :** `torch.nn.Module`

Le modèle PaCA.

Crée un modèle d'adaptation de connexion partielle (PaCA) à partir d'un modèle pré-entraîné. La méthode est décrite dans https://huggingface.co/papers/2503.01905.

Exemple :

```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)
```

**Attributs** :
- **model** ([PreTrainedModel](https://huggingface.co/docs/transformers/main/en/main_classes/model#transformers.PreTrainedModel)) -- Le modèle à adapter.
- **peft_config** ([PacaConfig](/docs/peft/main/fr/package_reference/paca#peft.PacaConfig)) : La configuration du modèle PaCA.

