Aller au contenu principal

Module 5 — LoRA : adaptateurs de rang faible

Le module 4 a placé LoRA dans la famille PEFT. Ce module l'ouvre pour de bon : d'où vient l'astuce mathématique, ce que rang et alpha règlent vraiment, quels modules cibler dans un Transformer, combien de paramètres cela entraîne au juste, et comment un seul modèle de base porte plusieurs adaptateurs échangés à la volée.

L'observation fondatrice

Un modèle pré-entraîné contient des matrices de poids massives — pour Mistral 7B, chaque matrice de projection dans l'attention fait 4 096 par 4 096, soit près de 17 millions de valeurs. L'affinage complet met à jour ces matrices entièrement. Or, en 2021, Hu et coll. ont observé quelque chose de fort : la différence entre les poids avant et après affinage, notée ΔW\Delta W, est de rang effectif très faible — souvent 8, 16 ou 32 pour un vecteur de dimension 4 096.

Traduit : sur 4 096 directions possibles dans l'espace des poids, l'affinage n'en pousse vraiment que quelques dizaines. Le reste est du bruit numérique. Si ΔW\Delta W est de rang faible, on peut le représenter par un produit de deux petites matrices au lieu d'une grande.

ΔW=BA\Delta W = B \cdot A

AA est de taille r×dr \times d et BB de taille d×rd \times r, avec rr le rang choisi, très petit devant dd. La matrice de poids modifiée devient :

W=W+αrBAW' = W + \frac{\alpha}{r} \cdot B \cdot A

Pendant l'entraînement, WW est gelé. Seules AA et BB apprennent, initialisées de sorte que BAB \cdot A vaille zéro au départ — ce qui garantit qu'on part exactement du modèle de base. À l'inférence, on peut soit calculer les deux termes séparément, soit fusionner BAB \cdot A dans WW pour effacer tout surcoût (module 9).

Le rang rr et le facteur α\alpha

Deux réglages pilotent LoRA. Ils sont souvent confondus, à tort.

Le rang rr contrôle la capacité de l'adaptateur : combien de directions il peut pousser. Les valeurs typiques vont de 4 à 64, avec 16 ou 32 pour la plupart des tâches. Plus rr est grand, plus l'adaptateur peut apprendre, mais plus il compte de paramètres et plus il risque le surapprentissage sur un petit jeu. Pour nos deux mille paires transcription vers compte rendu, r=16r = 16 est un choix raisonnable ; sur un jeu de cinquante mille exemples, r=32r = 32 ou 6464 peut aider.

Le facteur alpha α\alpha contrôle l'échelle de la contribution de l'adaptateur. Le rapport α/r\alpha / r apparaît devant le produit BAB \cdot A : c'est un gain scalaire. La convention courante est α=2r\alpha = 2r, ce qui donne un rapport α/r=2\alpha / r = 2. Ce rapport de 2 fait que l'adaptateur pèse deux fois plus que le modèle de base sur les directions qu'il apprend, ce qui est empiriquement un bon point de départ.

Rang rrFacteur α\alphaRapport α/r\alpha/rContexte typique
8162tâches simples, petits jeux
16322valeur par défaut, nos comptes rendus
32642jeux plus grands, tâches plus difficiles
32160,5adaptateur volontairement discret
8324adaptateur agressif, à surveiller

Une erreur classique consiste à multiplier rr par deux et α\alpha par deux en pensant simplement doubler la capacité — cela laisse le rapport inchangé et n'apporte souvent presque rien. Modifier α\alpha à rr fixé change le comportement plus qu'on ne le croit.

Où placer les adaptateurs

Toutes les matrices d'un Transformer ne se valent pas pour LoRA. Le mécanisme d'attention en compte plusieurs — projections q, k, v et o — et chaque couche MLP en ajoute deux ou trois (gate, up, down). Cibler tout casse le budget mémoire, ne rien cibler ne fait rien.

Trois configurations reviennent en pratique :

  • Minimaleq_proj et v_proj seulement. C'est la configuration originale du papier LoRA. Économe, souvent suffisante pour des tâches proches du pré-entraînement.
  • Étendue — les quatre projections d'attention (q, k, v, o). Bon compromis pour la plupart des cas, dont notre fil rouge. C'est celle qu'on utilise dans le module 4.
  • Complète — attention plus les projections MLP (gate, up, down). Coûteuse, réservée aux jeux plus difficiles où l'attention seule ne suffit pas à apprendre le format visé.
config_etendue = LoraConfig(
r=16, lora_alpha=32,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
lora_dropout=0.05, bias="none", task_type="CAUSAL_LM",
)

config_complete = LoraConfig(
r=16, lora_alpha=32,
target_modules=[
"q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj",
],
lora_dropout=0.05, bias="none", task_type="CAUSAL_LM",
)

Une bonne pratique consiste à commencer par la configuration étendue, mesurer la qualité, et ne passer à la configuration complète que si un plafond visible apparaît sur les courbes de validation.

Combien de paramètres au juste

Un calcul rapide clarifie l'intérêt. Pour Mistral 7B, avec r=16r = 16 et la configuration étendue sur 32 couches d'attention :

  • chaque projection est 4096×40964096 \times 4096 ;
  • son adaptateur LoRA fait r4096+4096r=2409616=131072r \cdot 4096 + 4096 \cdot r = 2 \cdot 4096 \cdot 16 = 131\,072 valeurs ;
  • quatre projections par couche, 32 couches : 43213107216,84 \cdot 32 \cdot 131\,072 \approx 16{,}8 millions de valeurs.

Seize millions de paramètres à entraîner, contre 7,25 milliards pour l'affinage complet — le rapport est de 430. Les états d'optimiseur suivent la même échelle : au lieu de 56 gigaoctets pour Adam, on est à environ 130 mégaoctets. C'est cette bascule d'ordre de grandeur qui rend l'affinage praticable sur un GPU modeste, avant même de parler de QLoRA au module suivant.

Un modèle, plusieurs adaptateurs

Un adaptateur LoRA se sauvegarde dans un fichier de quelques dizaines à quelques centaines de mégaoctets. Cette légèreté permet un mode de déploiement radicalement différent du modèle affiné classique : on garde un seul modèle de base en mémoire et l'on attache l'adaptateur voulu à chaque requête.

from peft import PeftModel

# Modele de base charge une seule fois.
base = AutoModelForCausalLM.from_pretrained(
"mistralai/Mistral-7B-Instruct-v0.3", torch_dtype="bfloat16", device_map="auto",
)

# Adaptateur specifique a la tache.
modele = PeftModel.from_pretrained(base, "notre-org/mistral-comptes-rendus")

# Passage a un autre adaptateur sans recharger le modele de base.
modele.load_adapter("notre-org/mistral-mails-clients", adapter_name="mails")
modele.set_adapter("mails")

Trois adaptateurs de cent mégaoctets chacun tiennent dans l'espace d'un modèle de 14 gigaoctets. Pour une entreprise qui décline le même modèle sur plusieurs tâches, l'économie de mémoire GPU est massive.

La règle mnémotechnique

Rang rr : combien de directions le modèle peut apprendre. Facteur α\alpha : combien fort ces directions parlent. Un rang trop faible bride, un rang trop élevé bruite ; un α\alpha trop faible passe inaperçu, un α\alpha trop élevé écrase le modèle de base. Le rapport α/r=2\alpha / r = 2 est le bon défaut.

En résumé

  • La mise à jour induite par l'affinage est de rang effectif faible ; LoRA la représente par un produit BAB \cdot A de deux petites matrices.
  • Le rang rr règle la capacité (typiquement 8 à 32), le facteur α\alpha règle l'échelle (convention α=2r\alpha = 2r).
  • Cibler les projections d'attention couvre la plupart des cas ; étendre aux projections MLP ne se fait qu'en cas de plafond mesuré.
  • Le nombre de paramètres entraînés est de l'ordre de quelques millions ; un même modèle de base peut porter plusieurs adaptateurs.

Module suivant : QLoRA, la variante quantifiée qui fait tenir tout cela sur un seul GPU de 24 Go.