PEFT documentation
Prefix tuning
Prefix tuning

Prefix tuning préfixe la séquence d’entrée d’une série de vecteurs spécifiques à la tâche, qui peuvent être appris tout en gardant le modèle pré-entraîné figé. Les paramètres du préfixe sont insérés dans toutes les couches du modèle.
L'abstract de l'article est :
Le fine-tuning est la méthode de fait pour exploiter de grands modèles de langage pré-entraînés afin d’exécuter des tâches en aval. Toutefois, il modifie tous les paramètres du modèle de langage et nécessite donc de stocker une copie complète pour chaque tâche. Dans cet article, nous proposons le prefix-tuning, une alternative légère au fine-tuning pour les tâches de génération de langage naturel, qui maintient les paramètres du modèle de langage figés, mais optimise un petit vecteur continu spécifique à la tâche (appelé le préfixe). Le prefix-tuning s’inspire du prompting, permettant aux jetons suivants de prêter attention à ce préfixe comme s’il s’agissait de « jetons virtuels ». Nous appliquons le prefix-tuning à GPT-2 pour la génération de texte à partir de tableaux et à BART pour la résumation. Nous constatons qu’en n’apprenant que 0,1\% des paramètres, le prefix-tuning obtient des performances comparables dans le cas de données complètes, surpasse le fine-tuning dans les cas de données limitées et s’extrapole mieux aux exemples portant sur des sujets non vus lors de l’entraînement.
Note Pour les modèles encodeur-décodeur (seq2seq), le préfixe n'est appliqué qu'au décodeur, ce qui ne correspond pas à la spécification de l'article (voir par exemple la Figure 2). Le prefix tuning peut tout de même être affiné sur ces architectures de modèles, mais les performances pourraient être inférieures ; envisagez d'utiliser d'autres méthodes PEFT pour les modèles encodeur-décodeur.
Le prefix tuning est très similaire au prompt tuning. La principale différence est que les paramètres de préfixe sont insérés dans toutes les couches du modèle, tandis que le prompt tuning n'ajoute les paramètres de prompt qu'aux embeddings d'entrée du modèle. Les paramètres de préfixe sont également optimisés par un réseau feed-forward (FFN) séparé plutôt que par un entraînement direct sur les prompts logiciels, car cela provoque une instabilité et nuit aux performances. Le FFN est supprimé après la mise à jour des prompts logiciels.
En conséquence, les auteurs ont constaté que le prefix tuning offre des performances comparables à celles d'un fine-tuning complet du modèle, malgré un nombre de paramètres inférieur d'un facteur 1000, et qu'il se comporte encore mieux dans les scénarios à faible volume de données.
Utilisation de base
Créez un PrefixTuningConfig avec le type de tâche et le nombre de jetons virtuels à ajouter et à apprendre.
from peft import PrefixTuningConfig, get_peft_model
peft_config = PrefixTuningConfig(task_type="CAUSAL_LM", num_virtual_tokens=20)
model = get_peft_model(model, peft_config)
model.print_healthcheck()Initialisations possibles
Par défaut, le prefix tuning utilise des jetons virtuels initialisés aléatoirement. Il est également possible d’initialiser les vecteurs de manière à ce qu’ils soient proches d’une opération nulle (initialisés à zéro, ils décaleront néanmoins légèrement la masse de probabilité). Cela signifie que les préfixes injectés dans le cache KV ont un impact moindre dès le départ et réduisent la variance des performances d’entraînement.
PEFT fournit également des utilitaires pour initialiser un adaptateur de prefix-tuning à partir d'un préfixe de cache KV existant (par exemple, à partir des p premiers jetons d'un prompt/corpus). Cela n'est pris en charge que lorsque prefix_projection=False (par défaut), car dans ce cas, les paramètres appris sont le préfixe KV lui-même.
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PrefixTuningConfig, get_peft_model, initialize_kv_prefix_from_text
base = AutoModelForCausalLM.from_pretrained("gpt2")
tok = AutoTokenizer.from_pretrained("gpt2")
peft_cfg = PrefixTuningConfig(task_type="CAUSAL_LM", num_virtual_tokens=20, prefix_projection=False)
model = get_peft_model(base, peft_cfg)
initialize_kv_prefix_from_text(
model,
tok,
text="...a long context with at least num_virtual_tokens tokens...",
use_chat_template=False,
)m peft import PrefixTuningConfig, get_peft_model, initialize_kv_prefix_from_text
base = AutoModelForCausalLM.from_pretrained("gpt2")
tok = AutoTokenizer.from_pretrained("gpt2")
peft_cfg = PrefixTuningConfig(task_type="CAUSAL_LM", num_virtual_tokens=20, prefix_projection=False)
model = get_peft_model(base, peft_cfg)
initialize_kv_prefix_from_text(
model,
tok,
text="...a long context with at least num_virtual_tokens tokens...",
use_chat_template=False,
)
Assurez-vous que le texte est suffisamment long pour générer au moins num_virtual_tokens jetons, sinon l'initialisation échouera.
En guise de repère :
- commencez par une séquence de départ neutre à l'aide de
initialize_kv_prefix_from_text, il peut s'agir d'une chaîne très courte comme « Question : » - si cela ne suffit pas, utilisez une séquence plus longue pertinente pour la tâche (c’est-à-dire un prompt ingénieré), ce qui vous donne plus de jetons virtuels à faire tenir, mais aussi plus de contrôle sur le modèle
- si l’utilisation d’un texte d’initialisation n’est pas possible ou si vous souhaitez vérifier rapidement si le prefix tuning est viable, utilisez une initialisation nulle sans projection
Aperçu des benchmarks
API
PrefixTuningConfig
classe peft.PrefixTuningConfig
< 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 = Falsenum_virtual_tokens: int = Nonetoken_dim: int = Nonenum_transformer_submodules: Optional[int] = Nonenum_attention_heads: Optional[int] = Nonenum_layers: Optional[int] = Nonemodules_to_save: Optional[list[str]] = Noneinit_weights: typing.Literal['zero'] | None = Noneencoder_hidden_size: int = Noneprefix_projection: bool = False )
Paramètres
- init_weights (
Optional[str]) — Si non défini, les poids sont initialisés aléatoirement ; si défini sur « zero », les poids sont initialisés de sorte que les activations soient une opération nulle (zéro). - encoder_hidden_size (
int) — La taille cachée de l'encodeur de prompt. - prefix_projection (
bool) — Indique s'il faut projeter les embeddings de préfixe.
Ceci est la classe de configuration destinée à stocker la configuration d'un PrefixEncoder.
PrefixEncoder
classe peft.PrefixEncoder
< source >( config )
Paramètres
- config (PrefixTuningConfig) — La configuration de l'encodeur de préfixe.
Le modèle torch.nn pour encoder le préfixe.
Exemple :
>>> from peft import PrefixEncoder, PrefixTuningConfig
>>> config = PrefixTuningConfig(
... peft_type="PREFIX_TUNING",
... task_type="SEQ_2_SEQ_LM",
... num_virtual_tokens=20,
... token_dim=768,
... num_transformer_submodules=1,
... num_attention_heads=12,
... num_layers=12,
... encoder_hidden_size=768,
... )
>>> prefix_encoder = PrefixEncoder(config)Attributs :
- embedding (
torch.nn.Embedding) — La couche d'embedding de l'encodeur de préfixe. - transform (
torch.nn.Sequential) — Le MLP à deux couches pour transformer les embeddings du préfixe siprefix_projectionestTrue. - prefix_projection (
bool) — Indique s'il faut projeter les embeddings de préfixe.
Forme de l'entrée : (batch_size, num_virtual_tokens)
Forme de la sortie : (batch_size, num_virtual_tokens, 2*layers*hidden)
Chargez les embeddings de prompt aplatis enregistrés par PEFT (prompt_embeddings).
Pour le prefix tuning, cela n'est pris en charge que lorsque prefix_projection=False, car dans ce cas, les paramètres appris sont le préfixe KV lui-même (embedding.weight a la forme [num_virtual_tokens, num_layers*2*token_dim]).
Si prefix_projection=True, les paramètres sont (les embeddings de jetons virtuels + un MLP) et il n'existe pas de méthode générale pour inverser la projection afin de récupérer ces paramètres à partir d'un préfixe KV aplati.