PEFT documentation
PSOFT
PSOFT
PSOFT est une méthode de fine-tuning efficace en paramètres basée sur le fine-tuning orthogonal (OFT) qui préserve les relations géométriques des vecteurs de colonnes des poids pré-entraînés tout en atteignant un équilibre entre les performances et l'efficacité multi-dimensionnelle, incluant le nombre de paramètres, l'utilisation de la mémoire et le coût de calcul. En restreignant les transformations orthogonales à un sous-espace principal de faible rang dérivé des poids pré-entraînés, PSOFT comble l'écart entre LoRA et OFT, offrant à la fois des garanties théoriques et une adaptabilité pratique. Son efficacité est validée par des évaluations étendues sur divers benchmarks, notamment GLUE, VTAB-1K, GSM8K, MATH et des benchmarks de raisonnement de bon sens.
- Seules les couches
nn.Linearsont prises en charge. - Les couches quantifiées ne sont pas prises en charge.
L'abstract de l'article est :
Porté par la croissance rapide du nombre de paramètres des modèles, le fine-tuning efficace en termes de paramètres (PEFT) est devenu essentiel pour adapter les grands modèles à diverses tâches en aval dans des conditions de ressources computationnelles limitées. Dans ce paradigme, le fine-tuning orthogonal et ses variantes préservent les représentations sémantiques des modèles pré-entraînés, mais peinent à concilier expressivité et efficacité en termes de nombre de paramètres, de mémoire et de calcul. Pour surmonter cette limitation, nous proposons le fine-tuning orthogonal efficace avec adaptation du sous-espace principal (PSOFT), qui restreint les transformations orthogonales au sous-espace principal des poids pré-entraînés. Plus précisément, PSOFT construit ce sous-espace via une décomposition matricielle pour permettre des transformations compatibles, établit une condition théorique qui maintient strictement la géométrie de ce sous-espace pour une préservation sémantique essentielle, et introduit des vecteurs ajustables efficaces qui relâchent progressivement l'orthogonalité pendant l'entraînement pour améliorer l'adaptabilité. Des expériences étendues sur 35 tâches de NLP et de CV à travers quatre modèles représentatifs démontrent que PSOFT offre une solution pratique et évolutive pour atteindre simultanément la préservation sémantique, l'expressivité et l'efficacité multidimensionnelle dans le PEFT.
Fonctionnement de PSOFT
PSOFT décompose chaque matrice de poids en et en utilisant la SVD :
Le sous-espace principal est construit à partir des $r$ premières composantes singulières :
(PSOFT-SO : PSOFT avec orthogonalité stricte)
(PSOFT-RO : PSOFT avec orthogonalité relâchée
Lors de l'entraînement, $A$, $B$ et sont figés, et seul (ou avec et $\beta$) est entraînable.
Pour assurer la compatibilité avec le framework PEFT (qui s'attend à des mises à jour additives des poids), PSOFT est implémenté sous la forme additive suivante :
Paramètres entraînables
Après l'application de PSOFT :
- Les poids du modèle d'origine ($A$, $B$ et $W_{\text{res}}$) sont figés.
- Seule la matrice orthogonale (et éventuellement $\alpha$, $\beta$) est entraînable.
- Aucun paramètre de biais supplémentaire n'est introduit.
Utilisation de base
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PsoftConfig, get_peft_model
# Load base model
model_id = "facebook/opt-125m"
model = AutoModelForCausalLM.from_pretrained(model_id)
# Configure PSOFT
config = PsoftConfig(
r=32, # the dimension of trainable matrix R,
psoft_alpha=32, # scaling factor (typically set to r in PSOFT),
target_modules=["q_proj", "v_proj"], # target attention projection layers
ab_svd_init="psoft_init", # principal subspace initialization
psoft_svd="full", # SVD method
psoft_orth=True, # enable orthogonal R (Cayley parameterization)
psoft_mag_a=True, # enable tunable vector alpha
psoft_mag_b=True, # enable tunable vector beta
use_cayley_neumann=False, # disable Cayley–Neumann approximation
num_cayley_neumann_terms=5, # number of Neumann series terms
cayley_neumann_eps=None, # improve numerical stability
)
# Apply PSOFT
model = get_peft_model(model, config)
model.train()
tokenizer = AutoTokenizer.from_pretrained(model_id)
tokenizer.pad_token = tokenizer.eos_token
# Train
inputs = tokenizer("Hello world", return_tensors="pt", padding=True)
loss = model(**inputs, labels=inputs["input_ids"]).loss
loss.backward()
trainable = [p for p in model.parameters() if p.requires_grad]
optimizer = torch.optim.AdamW(trainable, lr=5e-4)
optimizer.step()
optimizer.zero_grad(set_to_none=True)Options de configuration
Mode différent
(PSOFT-SO : PSOFT avec orthogonalité stricte)
config = PsoftConfig(psoft_orth=True,psoft_mag_a=False,psoft_mag_b=False)(PSOFT-RO : PSOFT avec orthogonalité relâchée)
config = PsoftConfig(psoft_orth=True,psoft_mag_a=True,psoft_mag_b=True)Bonnes pratiques
- Choix du rang : les rangs plus petits (par exemple
32–128) conviennent aux tâches plus simples, tandis que les rangs plus grands (par exemple64–256) offrent une expressivité accrue pour les tâches plus complexes, au prix d'un nombre de paramètres et de calculs plus élevés. - Scaling Factor: Le facteur d'échelle est généralement défini sur dans PSOFT.
- Taux d'apprentissage : utilisez des taux d'apprentissage standard (par exemple,
1e-4à5e-3) pour un entraînement stable. - Initialisation SVD : l'option
lowrankest plus efficace en mémoire et en calcul quefull, ce qui la rend plus adaptée aux grands modèles. - Approximation de Cayley–Neumann : lorsque le rang est élevé, l’activation de l’approximation de Cayley–Neumann peut améliorer considérablement l’efficacité computationnelle, tandis que le bénéfice est moins marqué pour les petits rangs. En pratique, un petit nombre de termes de la série de Neumann (généralement
5) offre généralement un bon équilibre entre précision et efficacité.
Aperçu des benchmarks
API
PsoftConfig
classe peft.PsoftConfig
< source >( task_type: Optional[Union[str, TaskType]] = Nonepeft_type: Optional[Union[str, PeftType]] = Noneauto_mapping: Optional[dict] = Nonepeft_version: Optional[str] = Nonebase_model_name_or_path: Optional[str] = Nonerevision: Optional[str] = Noneinference_mode: bool = Falser: int = 32target_modules: Optional[Union[list[str], str]] = Noneexclude_modules: Optional[Union[list[str], str]] = Nonepsoft_alpha: int = 32psoft_dropout: float = 0.0fan_in_fan_out: bool = Falseab_svd_init: Literal['psoft_init', 'pissa_init'] = 'psoft_init'psoft_svd: Literal['full', 'lowrank'] = 'full'psoft_svd_lowrank_niter: int = 10random_seed: int = 0psoft_orth: bool = Truepsoft_mag_b: bool = Truepsoft_mag_a: bool = Trueuse_cayley_neumann: bool = Falsenum_cayley_neumann_terms: int = 5cayley_neumann_eps: Optional[float] = Nonemodules_to_save: Optional[list[str]] = Noneinit_weights: bool = Truelayers_to_transform: Optional[Union[list[int], int]] = Nonelayers_pattern: Optional[Union[list[str], str]] = None )
Paramètres
- r (
int) — Valeur par défaut : 32. Le rang PSOFT (r) contrôle la capacité de l’adaptateur via une transformation R de taille r*r. Des rangs plus faibles, de 32 à 128, sont généralement suffisants pour des tâches simples. Les tâches plus complexes peuvent bénéficier de rangs de 64 à 256, ce qui augmente l’expressivité au prix de paramètres et de calculs supplémentaires. Consultez l’article pour des configurations validées empiriquement : https://openreview.net/forum?id=FSHrinMArK. - target_modules (
Optional[Union[List[str], str]]) — Les noms des modules auxquels appliquer l’adaptateur. Si ce paramètre est spécifié, seuls les modules portant les noms indiqués seront remplacés. En cas de chaîne de caractères, une correspondance par expression régulière est effectuée. En cas de liste de chaînes de caractères, une correspondance exacte est réalisée ou il est vérifié si le nom du module se termine par l’une des chaînes fournies. Si la valeur est « all-linear », tous les modules linéaires/Conv1D sont sélectionnés (si le modèle est un PreTrainedModel, la couche de sortie est exclue). Si ce paramètre n’est pas spécifié, les modules sont choisis en fonction de l’architecture du modèle. Si l’architecture est inconnue, une erreur est levée — dans ce cas, vous devez spécifier manuellement les modules cibles. - exclude_modules (
Optional[Union[List[str], str]]) — Les noms des modules auxquels l’adaptateur ne doit pas être appliqué. Si une chaîne de caractères est transmise, une correspondance par expression régulière est effectuée. Si une liste de chaînes de caractères est transmise, une correspondance exacte est effectuée ou il est vérifié si le nom du module se termine par l’une des chaînes transmises. - psoft_alpha (
int) — Valeur par défaut : 32. Il contrôle le facteur d'échelle de PSOFT. Sémantique identique à alpha de LoRA. - psoft_dropout (
float) — Valeur par défaut : 0.0. Dropout pour le chemin PSOFT. Même sémantique que le dropout LoRA. - fan_in_fan_out (
bool) — Définissez cette valeur sur True si la couche à remplacer stocke les poids sous la forme (fan_in, fan_out). Par exemple, gpt-2 utiliseConv1Dqui stocke les poids sous la forme (fan_in, fan_out) et il convient donc de définir cette valeur surTrue. - ab_svd_init (
Literal["psoft_init", "pissa_init"]) — Valeur par défaut : ‘psoft_init’. Stratégie d’initialisation pour A et B utilisée pour construire le sous-espace principal dans PSOFT. ‘psoft_init’ : initialisation basée sur la SVD avec A orthogonale par ligne, garantissant une orthogonalité stricte (PSOFT). ‘pissa_init’ : initialisation basée sur la SVD avec A et B symétriques (PiSSA standard). - psoft_svd (
Literal["full", "lowrank"]) — Valeur par défaut : ‘full’. Backend SVD pour l’initialisation : ‘full’ utilise torch.linalg.svd ; ‘lowrank’ utilise torch.svd_lowrank. - psoft_svd_lowrank_niter (
int) — Utilisé uniquement lorsque psoft_svd=‘lowrank’. Valeur par défaut : 10. Nombre d’itérations de puissance utilisées par torch.svd_lowrank lorsque psoft_svd=‘lowrank’. - psoft_orth (
bool) — Valeur par défaut : ‘True’. Si True, contraint R à être orthogonale via la paramétrisation de Cayley, préservant les relations géométriques entre les colonnes des vecteurs de poids pré-entraînés. Si False, R est une matrice libre sans contraintes d’orthogonalité. - psoft_mag_b (
bool) — Valeur par défaut : ‘True’. Si True, apprend un vecteur de mise à l’échelle diagonale sur le côté ‘output’ de R. Souvent associé à psoft_mag_a pour augmenter l’adaptabilité à la tâche, au prix d’une légère distorsion de la géométrie pré-entraînée. - psoft_mag_a (
bool) — Valeur par défaut : ‘True’. Si True, apprend un vecteur d’échelle diagonale sur le côté ‘input’ de R. Souvent associé à psoft_mag_b pour augmenter l’adaptabilité à la tâche, au prix d’une légère distorsion de la géométrie pré-entraînée. - use_cayley_neumann (
bool) — Valeur par défaut : ‘False’. Indique s’il faut utiliser la formulation de Cayley-Neumann de PSOFT ou non. Définissez-la sur True pour améliorer l’efficacité computationnelle, au prix d’une erreur d’approximation plus importante pour l’orthogonalité. - num_cayley_neumann_terms (
int) — Valeur par défaut : 5. Utilisé uniquement lorsque use_cayley_neumann=True. Nombre de termes de Cayley-Neumann à utiliser. Un nombre plus élevé réduit l'erreur d'approximation liée à l'orthogonalité. - cayley_neumann_eps (
optional[float]) — Valeur par défaut : ‘None’. Utilisé uniquement lorsque use_cayley_neumann=True. Limite optionnelle de la norme de Frobenius pour la matrice génératrice Q dans l’approximation de Cayley-Neumann. Si None (par défaut), aucun rééchelonnement n’est appliqué. Si défini à une valeur dans (0, 1) (par ex. 0,9), Q est rééchelonné chaque fois que ||Q||_F dépasse le seuil afin d’améliorer la stabilité numérique. Voir https://spherelab.ai/oftv2/ pour plus de détails. - init_weights (
bool) — Valeur par défaut : ‘True’. Indique s’il faut initialiser les poids des couches PSOFT avec leur initialisation par défaut. Ne modifiez pas ce paramètre, sauf si vous savez exactement ce que vous faites. - modules_to_save (
List[str]) — Liste des modules, en dehors des couches d’adaptateur, à définir comme entraînables et à enregistrer dans le point de contrôle final. - layers_to_transform (
Union[List[int], int]) — Les indices de couches à transformer. Si une liste d'entiers est transmise, l'adaptateur sera appliqué aux indices de couches spécifiés dans cette liste. Si un seul entier est transmis, les transformations seront appliquées à la couche située à cet index. - layers_pattern (
Optional[Union[List[str], str]]) — Le nom du motif de couche, utilisé uniquement silayers_to_transformest différent deNone. Il doit cibler lenn.ModuleListdu modèle, souvent appelé'layers'ou'h'.
Configuration pour PSOFT (Efficient Orthogonal Fine-Tuning with Principal Subspace Adaptation).
PSOFT insère une transformation orthogonale R de rang r*r entre les matrices de faible rang A et B, de sorte que la mise à jour de faible rang est ΔW = B @ (R-I) @ A. Seule R (et les vecteurs ajustables optionnels) est entraînée ; A et B sont initialisées avec psoft_init (basé sur la SVD, A orthogonale par ligne) et figées.
PsoftModel
classe peft.PsoftModel
< source >( modelpeft_config: Union[PeftConfig, dict[str, PeftConfig]]adapter_name: strlow_cpu_mem_usage: bool = Falsestate_dict: Optional[dict[str, torch.Tensor]] = None )
Modèle PSOFT (Efficient Orthogonal Fine-Tuning with Principal Subspace Adaptation).
Insère une transformation orthogonale (ou mise à l’échelle) R de rang r*r entre A et B de faible rang : ΔW = B @ (R-I) @ A. Utilisez ab_svd_init="psoft_init" pour initialiser A/B à partir de la SVD et les geler, en n’entraînant que R (et les vecteurs d’amplitude optionnels).