Aller au contenu principal

Chapitre 2 : PEFT vs Affinage Complet

Comprendre les Compromis​

Choisir entre PEFT et l'affinage complet nécessite de comprendre leurs forces et limites respectives.


Comparaison Complète​

AspectAffinage CompletPEFT
Mémoire4-6x taille du modèle0.1-0.5x taille du modèle
VitessePlus lent2-3x plus rapide
Plafond de QualitéLe plus élevéLégèrement inférieur
Risque d'OubliÉlevéAucun
MatérielGPU coûteuxGPU grand public
Échange d'AdaptateursNonOui
Surcharge d'InférenceAucuneMinime (ou fusion)

Comparaison de la Mémoire​

Analyse Détaillée​

def calculate_memory(params_billions, method):
"""Calculer la mémoire d'entraînement approximative."""
params = params_billions * 1e9

if method == "full_ft":
# Poids + Gradients + Optimiseur (2 états) + Activations
weights = params * 2 # bf16
gradients = params * 2
optimizer = params * 4 * 2 # fp32, 2 états
activations = params * 0.5 # Estimation approximative
return (weights + gradients + optimizer + activations) / 1e9

elif method == "lora":
# Poids gelés + petits gradients/optimiseur LoRA
weights = params * 2
lora_params = params * 0.01 # ~1% entraînable
lora_training = lora_params * (2 + 2 + 8) # grad + optimiseur
return (weights + lora_training) / 1e9

elif method == "qlora":
# Poids 4 bits + entraînement LoRA
weights = params * 0.5 # 4 bits
lora_params = params * 0.01
lora_training = lora_params * (2 + 2 + 8)
return (weights + lora_training) / 1e9

# Résultats pour le modèle 7B
print(f"Affinage Complet : {calculate_memory(7, 'full_ft'):.1f} GB") # ~77 GB
print(f"LoRA : {calculate_memory(7, 'lora'):.1f} GB") # ~15 GB
print(f"QLoRA : {calculate_memory(7, 'qlora'):.1f} GB") # ~4 GB

Comparaison de la Qualité​

Résultats Empiriques​

La recherche montre de manière cohérente que PEFT atteint une qualité comparable :

TâcheAffinage CompletLoRADifférence
Classification de Texte94.2%93.8%-0.4%
Résumé45.3 ROUGE44.9 ROUGE-0.9%
Suivi d'Instructions8.2/108.0/10-2.4%
Génération de Code67.1%65.8%-1.9%

Quand PEFT Est Insuffisant​

PEFT peut sous-performer pour :

  • Changements de domaine significatifs : Pré-entraînement → domaine très spécialisé
  • Nouveaux formats de sortie : Très différents de toutes les données d'entraînement
  • Qualité maximale possible : Quand chaque 0.1% compte
  • Nouveaux comportements complexes : Modèles profondément intégrés
# Exemple : PEFT pourrait avoir des difficultés avec
# 1. Modèle médical à partir d'un LLM général (changement de domaine majeur)
# 2. Langue entièrement nouvelle non présente dans le pré-entraînement
# 3. Référentiels de compétition où chaque point compte

Comparaison de la Vitesse d'Entraînement​

Mesures de Débit​

MéthodeTemps par ÉpoqueVitesse Relative
Affinage Complet60 min1x
LoRA25 min2.4x
QLoRA30 min2x

Pourquoi PEFT est Plus Rapide​

  1. Moins de calculs de gradients : Calculer uniquement les gradients pour les paramètres entraînables
  2. Moins de bande passante mémoire : Moins d'octets à déplacer
  3. Mises à jour de l'optimiseur plus petites : Moins d'états à maintenir
# Le calcul des gradients évolue avec les paramètres entraînables
# Affinage Complet : 7 milliards de calculs de gradients
# LoRA : 70 millions de calculs de gradients (100x moins)

Comparaison de la Flexibilité​

PEFT : Multiples Adaptateurs​

# Charger le modèle de base une fois
base_model = AutoModelForCausalLM.from_pretrained("llama-3.1-8b")

# Créer différents adaptateurs
adapters = {
"customer_support": "adapters/support/",
"code_review": "adapters/code/",
"translation": "adapters/translate/",
}

# Changement d'adaptateur à l'exécution
for task, adapter_path in adapters.items():
model = PeftModel.from_pretrained(base_model, adapter_path)
# Utiliser le modèle pour la tâche
model.unload() # Retirer l'adaptateur

Affinage Complet : Modèles Séparés​

# Chaque tâche nécessite le chargement d'un modèle complet différent
models = {
"customer_support": "models/support-full/", # 15GB
"code_review": "models/code-full/", # 15GB
"translation": "models/translate-full/", # 15GB
}
# Total : 45GB de stockage, coût élevé de changement

Comparaison de l'Inférence​

PEFT avec Adaptateurs​

# Légère surcharge due au calcul de l'adaptateur
# Latence : ~5-10% plus lente par token

# Option 1 : Garder l'adaptateur séparé
model = PeftModel.from_pretrained(base, adapter)
output = model.generate(input_ids)

# Option 2 : Fusionner pour zéro surcharge
model = model.merge_and_unload() # Pas de surcharge d'adaptateur
output = model.generate(input_ids)

PEFT Fusionné = Vitesse de l'Affinage Complet​

Après fusion :

W_merged = W_base + B × A # Calcul unique
# L'inférence est identique au modèle entièrement affiné

Analyse des Coûts​

Coûts d'Entraînement​

MéthodeGPU NécessaireTempsCoût (À la Demande)
Affinage Complet (7B)A100-80GB4 hr$24
LoRA (7B)A100-40GB1.5 hr$6
QLoRA (7B)RTX 40902 hr$2

Considérations à Long Terme​

Scénario : Affiner pour 10 tâches différentes

Affinage Complet :
- 10 sessions d'entraînement sur des GPU coûteux
- 10 modèles complets à stocker (150GB)
- Chargement de modèles différents par tâche

PEFT :
- 10 sessions d'entraînement sur des GPU moins chers
- 1 modèle de base + 10 adaptateurs (15GB + 200MB)
- Changement rapide d'adaptateur

Cadre de Décision​

Choisir PEFT Quand :​

✅ La mémoire GPU est limitée (< 40GB)
✅ Besoin d'expérimenter rapidement
✅ Variations multiples de tâches nécessaires
✅ Vouloir préserver les capacités du modèle de base
✅ Le coût est un facteur significatif
✅ La production nécessite un changement d'adaptateur

Choisir l'Affinage Complet Quand :​

✅ La qualité maximale est critique
✅ Un changement de domaine significatif est requis
✅ Les ressources ne sont pas une contrainte
✅ Modèle à usage unique nécessaire
✅ Déploiement en tant que modèle fusionné de toute façon
✅ La recherche nécessite un contrôle total


Stratégies Hybrides​

Commencer avec PEFT, Améliorer si Nécessaire​

# Phase 1 : Expérimentation rapide avec LoRA
lora_model = train_with_lora(dataset_small)
evaluate(lora_model) # Vérifier si la qualité est suffisante

# Phase 2 : Si PEFT n'est pas suffisant, essayer l'affinage complet
if quality_gap > threshold:
full_ft_model = train_full(dataset_full)

PEFT pour l'Itération, Affinage Complet pour le Final​

# Itérer sur les données/hyperparamètres avec PEFT (rapide, bon marché)
for experiment in experiments:
model = train_lora(config=experiment)
score = evaluate(model)
if score > best_score:
best_config = experiment

# Entraînement final avec l'affinage complet en utilisant les meilleurs paramètres
final_model = train_full(config=best_config)

Recommandations Pratiques​

Pour la Plupart des Cas d'Utilisation : Commencer avec PEFT​

# Recommandation par défaut pour la plupart des praticiens
from peft import LoraConfig, get_peft_model

config = LoraConfig(
r=16,
lora_alpha=32,
target_modules=["q_proj", "v_proj", "k_proj", "o_proj"],
lora_dropout=0.05,
)

model = get_peft_model(base_model, config)
# Entraîner et évaluer

Pour la Production : Envisager la Fusion​

# Après l'entraînement, fusionner pour le déploiement
model = model.merge_and_unload()
model.save_pretrained("./production-model")
# Se comporte maintenant exactement comme un modèle entièrement affiné

Points Clés​

✅ PEFT atteint 90-99% de la qualité de l'affinage complet avec 80-95% de mémoire en moins

✅ L'affinage complet a un plafond de qualité plus élevé mais à un coût significatif

✅ PEFT permet le changement d'adaptateur ; l'affinage complet crée des modèles fixes

✅ PEFT fusionné a des performances d'inférence identiques à l'affinage complet

✅ Commencer avec PEFT, passer à l'affinage complet uniquement si nécessaire

✅ Considérer le coût total incluant le stockage, le changement et l'itération


Prochaines Étapes​

Continuez vers Chapitre 3 : Aperçu des Méthodes PEFT pour explorer toutes les techniques PEFT disponibles.


Vérification Rapide​

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

  1. Combien de mémoire PEFT économise-t-il par rapport à l'affinage complet ?
  2. Quand l'affinage complet pourrait-il surpasser PEFT ?
  3. Quel est l'avantage des adaptateurs PEFT fusionnés ?