PEFT documentation

Lily : Adaptation interconnectée de faible rang à travers les couches

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v0.21.0).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Lily : Adaptation interconnectée de faible rang à travers les couches

Lily est une technique de fine-tuning efficace en termes de paramètres qui introduit le partage de poids inter-couches pour les matrices d'adaptateurs. Plutôt que d'apprendre une paire AB indépendante par couche comme dans LoRA, Lily utilise des adaptateurs A partagés localement (chaque A est partagé sur un bloc de stride_A couches consécutives) et des experts B partagés globalement (un petit pool de num_B adaptateurs B est partagé entre toutes les couches). À chaque passe avant, un routeur léger dépendant des données calcule une combinaison pondérée par softmax des experts B pour produire le B effectif pour cette couche et cette entrée.

Ce partage peut réduire le nombre total de matrices d’adaptateurs de 2N (LoRA standard) à N / stride_A + num_B, libérant ainsi le budget de paramètres pour utiliser un rang r beaucoup plus élevé — typiquement 2×–4× celui utilisé en LoRA. Un rang plus élevé et une meilleure interconnectivité augmentent le rang effectif de la mise à jour des poids ΔW = A × combined_B, ce qui améliore les performances d’adaptation.

La combinaison B est dépendante des données (les poids du routeur dépendent des activations d’entrée à l’exécution), merge et unmerge ne sont donc pas pris en charge. Si la fusion des poids est requise pour votre déploiement, envisagez d’autres méthodes telles que LoRA.

Lily a actuellement les contraintes supplémentaires suivantes :

  • Seules les couches nn.Linear sont prises en charge.
  • Les couches quantifiées ne sont pas prises en charge.

Si ces contraintes ne conviennent pas à votre cas d’usage, envisagez plutôt d’autres méthodes.

L'abstract de l'article est :

L’adaptation de faible rang (LoRA) est une méthode de fine-tuning efficace en paramètres (PEFT) largement utilisée, qui apprend des mises à jour de poids ΔW = AB pour les poids pré-entraînés W à l’aide d’adaptateurs de faible rang A et B. Bien que LoRA garantisse une efficacité matérielle, ses mises à jour de poids de faible rang limitent les performances d’adaptation. Dans cet article, nous proposons l’adaptation interconnectée de faible rang entre les couches (Lily), une nouvelle méthode PEFT qui introduit un cadre interconnecté avec des experts A partagés localement et des experts B partagés globalement. Cette structure élimine les paires AB redondantes par couche, permettant un ΔW de rang supérieur avec un nombre égal ou inférieur de paramètres. Pour améliorer l’expressivité, nous utilisons des routeurs dépendants des données pour déterminer les interconnexions A-B, empêchant les experts B de converger vers le même comportement et améliorant la puissance de représentation à travers les domaines. Des expériences à travers différentes modalités, architectures et tailles de modèles démontrent les performances supérieures et l’efficacité de Lily.

Aperçu des benchmarks

API

LilyConfig

classe peft.LilyConfig

< >

( 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 = 32stride_A: int = 1num_B: int = 2scaling: float = 1.0target_modules: Optional[Union[list[str], str]] = Noneexclude_modules: Optional[Union[list[str], str]] = Nonemodules_to_save: Optional[list[str]] = Nonelayers_to_transform: Optional[Union[list[int], int]] = Nonelayers_pattern: Optional[Union[list[str], str]] = Noneinit_weights: bool = True )

Paramètres

  • r (int) — Rang de Lily. Détermine la dimension cachée interne de chaque adaptateur et le rang de la mise à jour des poids A @ B. Dans Lily, le nombre d’adaptateurs étant généralement plus faible que dans LoRA, chaque adaptateur doit porter plus de capacité ; il est donc recommandé d’utiliser un r plus élevé que dans LoRA — typiquement 2x, 3x ou 4x le rang LoRA que vous utiliseriez normalement. Le nombre total de paramètres entraîlables évolue avec r * (total_layers / stride_A + num_B), il est donc recommandé d’augmenter r tout en maintenant stride_A élevé et num_B faible.
  • stride_A (int) — Le nombre de couches consécutives qui partagent un adaptateur A. Par exemple, si stride_A=4, toutes les 4 couches adjacentes partagent le même adaptateur A, ce qui donne total_layers / stride_A adaptateurs A distincts au total. L'adaptateur A compresse l'entrée en une représentation de rang faible de taille r. stride_A ne doit pas être inférieur à
    1. Valeurs suggérées : 2, 3 ou 4 (c’est-à-dire partager toutes les 2, 3 ou 4 couches). Garder stride_A élevé (moins d’adaptateurs A distincts) et augmenter r à la place conduit à de meilleures performances que le compromis inverse (petit stride_A, petit r). Définir stride_A=1 signifie que chaque couche possède son propre adaptateur A. NOTE : le partage des A se fait au sein de chaque cible (couches ayant le même suffixe de cible). Par exemple, si vos target_modules sont ['q_proj', 'v_proj'] et que vous définissez stride_A=2, alors toutes les 2 couches q_proj adjacentes partageront un adaptateur A, et toutes les 2 couches v_proj adjacentes partageront un autre adaptateur A, mais les couches q_proj et v_proj ne partageront pas d’adaptateurs A entre elles car elles ont des suffixes différents.
  • num_B (int) — Le nombre d'adaptateurs B partagés. Contrairement aux adaptateurs A (qui sont groupés par couche), tous les adaptateurs B sont partagés globalement sur toutes les couches. Pour chaque passe avant, un routeur calcule une combinaison pondérée de tous les num_B adaptateurs B (en utilisant des poids normalisés par softmax) pour produire un unique adaptateur B combiné, qui projette ensuite la représentation de faible rang vers la dimension d'origine. Il est recommandé de définir num_B à un ordre de grandeur similaire à total_layers / stride_A. Valeurs suggérées : total_layers / 2, total_layers / 3 ou total_layers / 4. De manière similaire à stride_A, préférez un num_B plus petit avec un r plus grand plutôt qu'un num_B plus grand avec un r plus petit. REMARQUE : pour entraîner le routeur, vous avez besoin d'au moins 2 adaptateurs B (c'est-à-dire num_B >= 2), car le routeur apprend à calculer une combinaison pondérée des adaptateurs B. REMARQUE : le partage des B se fait au sein de chaque cible (couches ayant le même suffixe de cible). Par exemple, si vos target_modules sont ['q_proj', 'v_proj'] et que vous définissez num_B=4, il y aura 4 adaptateurs B partagés entre toutes les couches q_proj, et 4 autres adaptateurs B partagés entre toutes les couches v_proj, mais les couches q_proj et v_proj ne partageront pas d'adaptateurs B entre elles car elles ont des suffixes différents.
  • target_modules (Union[List[str], str], facultatif) — Les noms des modules auxquels appliquer Lily. Peut être une liste de chaînes de caractères de noms de modules (par ex. ['q_proj', 'v_proj']) ou un motif regex (par ex. '.*decoder.*(SelfAttention|EncDecAttention).*(q|v)$'). Si non spécifié, Lily sera appliqué à toutes les couches linéaires prises en charge.
  • scaling (float) — Un multiplicateur scalaire appliqué à la sortie combinée de l’adaptateur (scaling * A @ combined_B) avant de l’ajouter au passage avant du poids figé. Contrairement à LoRA, Lily n’utilise pas de formulation alpha / r ; à la place, scaling est un multiplicateur direct. Cette conception permet de balayer facilement des valeurs sur une échelle logarithmique (par ex. 0.01, 0.1, 1.0, 10.0). La valeur optimale dépend de la tâche et doit être traitée comme un hyperparamètre. Nous recommandons de commencer avec 1.0.
  • modules_to_save (List[str], facultatif) — Liste des modules, à l'exception des couches Lily, à 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.
  • exclude_modules (Union[List[str], str], facultatif) — 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.
  • 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 indiqués dans cette liste. Si un entier unique est transmis, PEFT ne transformera que la couche située à 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 et si le motif de couche ne figure pas dans les motifs de couches courants. Il doit cibler le nn.ModuleList du modèle, souvent appelé 'layers' ou 'h'.
  • init_weights (bool) — Indique s'il faut initialiser les poids de l'adaptateur Lily en utilisant le schéma d'initialisation par défaut : les matrices A sont initialisées avec Kaiming uniform, et les matrices B sont initialisées à zéro, ce qui garantit que la sortie de l'adaptateur est nulle au début de l'entraînement et ne perturbe pas le modèle pré-entraîné. Il est fortement recommandé de conserver cette valeur à True sauf si vous avez une raison spécifique de la modifier.

Ceci est la classe de configuration destinée à stocker la configuration d'un LilyModel.

LilyModel

classe peft.LilyModel

< >

( modelpeft_config: Union[PeftConfig, dict[str, PeftConfig]]adapter_name: strlow_cpu_mem_usage: bool = Falsestate_dict: Optional[dict[str, torch.Tensor]] = None ) → torch.nn.Module

Paramètres

  • model (torch.nn.Module) — Le modèle à adapter.
  • config (LilyConfig) — La configuration du modèle Lily.
  • adapter_name (str) — Le nom de l'adaptateur, par défaut "default".

Retourne

torch.nn.Module

Le modèle PEFT de Lily.

Crée un modèle Low-Rank Interconnected Adaptation Across Layers (Lily) à partir d'un modèle transformers pré-entraîné.

La méthode est décrite en détail dans https://arxiv.org/abs/2407.09946.

Attributs :

Update on GitHub