Aller au contenu principal

Chapitre 1 : Comprendre LoRA

L'intuition derrière l'adaptation de faible rang​

LoRA (Low-Rank Adaptation) est une technique élégante qui repose sur une observation simple mais puissante : nous n'avons pas besoin de mettre à jour tous les paramètres pour adapter un modèle à de nouvelles tâches.


L'idée principale​

Observation clé​

Lors de l'ajustement de modèles pré-entraînés, les mises à jour de poids ont souvent un faible "rang intrinsèque"—ce qui signifie que les changements peuvent être capturés par un ensemble de paramètres beaucoup plus petit.

Analogie​

Pensez-y comme à la modification d'un document :

  • Ajustement Complet : Réécrire tout le document
  • LoRA : Ajouter des notes autocollantes avec des corrections

Le document original (modèle de base) reste intact, et les notes autocollantes (adaptateurs LoRA) capturent les changements.


Comment fonctionne LoRA​

Ajustement Traditionnel​

Dans une couche de réseau neuronal :

h = Wx

Où W est une matrice de poids de taille (d × d).

L'ajustement complet met à jour W directement :

W' = W + ΔW

Où ΔW est le changement appris pour tous les paramètres (d × d).

Approche de LoRA​

LoRA représente ΔW comme un produit de deux matrices plus petites :

ΔW = BA

Où :

  • B a une taille (d × r)
  • A a une taille (r × d)
  • r est beaucoup plus petit que d (r ≪ d)

Le passage avant devient :

h = Wx + BAx = (W + BA)x

Représentation Visuelle​


Économies de Paramètres​

Exemple : Une Matrice de Poids 4096 × 4096​

# Matrice de poids originale
d = 4096
original_params = d * d # 16,777,216 paramètres

# LoRA avec rang 16
r = 16
lora_params = d * r + r * d # 131,072 paramètres

# Économies
reduction = 1 - (lora_params / original_params)
print(f"Réduction des paramètres : {reduction:.2%}") # 99.22%

Pour un Modèle Complet​

ModèleOriginalLoRA (r=16)Réduction
7B7,000,000,000~4,000,00099.94%
13B13,000,000,000~8,000,00099.94%
70B70,000,000,000~40,000,00099.94%

Pourquoi le Faible Rang Fonctionne​

Dimensionnalité Intrinsèque​

La recherche montre que les mises à jour d'ajustement ont tendance à se situer dans un sous-espace de faible dimensionnalité :

  1. Les modèles pré-entraînés ont déjà des représentations riches
  2. L'adaptation des tâches nécessite un "pilotage" plutôt qu'une "reconstruction"
  3. De nombreuses dimensions de l'espace des poids sont redondantes pour des tâches spécifiques

Preuves Empiriques​

D'après l'article original de LoRA :

  • r=4 souvent suffisant pour de nombreuses tâches
  • r=8-16 recommandé pour des adaptations complexes
  • r=64+ rarement nécessaire, rendements décroissants

Initialisation​

Matrice A : Gaussienne Aléatoire​

# A est initialisé avec de petites valeurs aléatoires
A = torch.randn(r, d) * 0.01

Matrice B : Zéro​

# B est initialisé à zéro
B = torch.zeros(d, r)

Pourquoi Cette Initialisation ?​

Au début de l'entraînement : BA = 0 × A = 0
→ Sortie inchangée par rapport au modèle de base
→ Début d'entraînement stable
→ Adaptation progressive

Quelles Couches Cibler​

Architecture Transformer​

Bloc d'Attention :
├── Projection de requête (q_proj) ← Cible commune
├── Projection de clé (k_proj) ← Parfois cible
├── Projection de valeur (v_proj) ← Cible commune
└── Projection de sortie (o_proj) ← Parfois cible

Bloc Feed-Forward :
├── Projection de porte (gate_proj) ← Parfois cible
├── Projection ascendante (up_proj) ← Parfois cible
└── Projection descendante (down_proj)← Parfois cible

Configurations Communes​

ConfigurationModules CiblésCas d'Utilisation
Minimalq_proj, v_projExpériences rapides
Standardq_proj, k_proj, v_proj, o_projÉquilibré
CompletToute l'attention + FFCapacité maximale

Fusionner LoRA​

Pendant l'Inférence (Avec Adaptateur)​

# Deux chemins : base + LoRA
output = W @ x + B @ A @ x

Léger surcoût dû au calcul supplémentaire.

Fusionné (Sans Adaptateur)​

# Fusionner une fois
W_merged = W + B @ A

# Chemin unique à l'inférence
output = W_merged @ x

Pas de surcoût—identique au modèle ajusté.

Exemple de Fusion​

from peft import PeftModel

# Charger le modèle avec adaptateur
model = PeftModel.from_pretrained(base_model, "path/to/adapter")

# Fusionner l'adaptateur dans le modèle de base
model = model.merge_and_unload()

# Maintenant, le modèle est un modèle régulier sans surcoût d'adaptateur
model.save_pretrained("merged-model")

Variantes de LoRA​

LoRA Standard​

La formulation originale décrite ci-dessus.

LoRA+​

Applique des taux d'apprentissage différents aux matrices A et B.

DoRA (Adaptation de Faible Rang Décomposée en Poids)​

Sépare l'amplitude et la direction des poids.

GaLore (Projection de Gradient de Faible Rang)​

Projette les gradients dans un espace de faible rang.


Points Clés à Retenir​

✅ LoRA représente les mises à jour de poids comme des produits de matrices de faible rang

✅ Entraîne seulement ~0.01-0.1% des paramètres originaux

✅ B initialisé à zéro assure un début d'entraînement stable

✅ Cible courante : projections d'attention (q_proj, v_proj)

✅ Peut être fusionné pour un surcoût d'inférence nul

✅ Le faible rang fonctionne car l'ajustement a une faible dimensionnalité intrinsèque


Prochaines Étapes​

Continuez vers Chapitre 2 : Mathématiques de LoRA pour les fondations mathématiques.


Vérification Rapide​

Avant de continuer, assurez-vous de pouvoir répondre :

  1. Comment LoRA représente-t-il les mises à jour de poids ?
  2. Pourquoi B est-il initialisé à zéro ?
  3. Que signifie "faible rang" dans le contexte de LoRA ?