Wiki IA
LLM et IA Générative

Fine-tuning et RLHF

Adapter et aligner les modèles de langage

Le fine-tuning permet d'adapter un modèle pré-entraîné à une tâche ou un domaine spécifique. Le RLHF (Reinforcement Learning from Human Feedback) aligne le modèle avec les préférences humaines.

Quand fine-tuner ?

Fine-tuning vs alternatives

BesoinSolution
Nouvelles connaissancesRAG
Style/format spécifiqueFine-tuning
Tâche très spécialiséeFine-tuning
Comportement personnaliséFine-tuning + RLHF
Données confidentiellesFine-tuning local

Indicateurs pour le fine-tuning

✓ Fine-tuner si :
- Le prompt engineering ne suffit pas
- Besoin de réponses dans un format très spécifique
- Domaine technique avec jargon particulier
- Volume important de requêtes similaires
- Latence critique (modèle plus petit)

✗ Éviter si :
- Peu de données d'entraînement (<100 exemples)
- Les connaissances changent souvent (→ RAG)
- Budget limité
- Besoin de flexibilité

Types de fine-tuning

Full Fine-tuning

Entraîner tous les paramètres du modèle.

Modèle original (7B params)

Entraînement sur nouvelles données

Nouveau modèle (7B params modifiés)

Avantages : Performance optimale Inconvénients : Coûteux, risque de catastrophic forgetting

Parameter-Efficient Fine-Tuning (PEFT)

Entraîner seulement une petite partie des paramètres.

LoRA (Low-Rank Adaptation)

Ajoute des matrices de faible rang aux couches existantes.

            ┌─────────┐
     x ────→│ Weights │────→ y (original)
            │    W    │
            └─────────┘
                 +
            ┌───┐ ┌───┐
     x ────→│ A │→│ B │────→ Δy (adaptation)
            └───┘ └───┘
           r×d   d×r

W' = W + BA  où rank(BA) = r << d
from peft import LoraConfig, get_peft_model

config = LoraConfig(
    r=16,                    # Rang (8-64 typique)
    lora_alpha=32,           # Scaling
    target_modules=["q_proj", "v_proj"],  # Couches ciblées
    lora_dropout=0.1,
    bias="none"
)

model = get_peft_model(base_model, config)
# Paramètres entraînables : ~0.1% du total

QLoRA

LoRA avec quantification 4-bit du modèle de base.

from transformers import BitsAndBytesConfig

bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.float16,
)

model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-2-7b-hf",
    quantization_config=bnb_config,
    device_map="auto"
)

Avantage : Fine-tuner un modèle 7B sur un GPU 24GB.

Comparaison des méthodes

MéthodeParams entraînésMémoirePerformance
Full FT100%Très hauteMeilleure
LoRA0.1-1%MoyenneExcellente
QLoRA0.1-1%BasseTrès bonne
Prefix Tuning~0.1%BasseBonne
Adapters1-5%MoyenneTrès bonne

Préparation des données

Format des données

{"messages": [
  {"role": "system", "content": "Tu es un assistant médical."},
  {"role": "user", "content": "Quels sont les symptômes de la grippe ?"},
  {"role": "assistant", "content": "Les symptômes de la grippe incluent..."}
]}

Qualité des données

✓ Données de qualité :
- Réponses bien écrites
- Factuellement correctes
- Représentatives de l'usage cible
- Diversifiées

✗ À éviter :
- Réponses trop courtes/longues
- Erreurs factuelles
- Biais indésirables
- Données sensibles/PII

Volume recommandé

TâcheMinimumIdéal
Classification1001000+
Génération simple5005000+
Chat/Assistant100010000+
Domaine technique5002000+

Entraînement avec Hugging Face

Configuration complète

from transformers import (
    AutoModelForCausalLM,
    AutoTokenizer,
    TrainingArguments,
    Trainer
)
from datasets import load_dataset
from peft import LoraConfig, get_peft_model

# Charger le modèle
model_name = "mistralai/Mistral-7B-v0.1"
model = AutoModelForCausalLM.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)

# Configuration LoRA
lora_config = 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"
)

model = get_peft_model(model, lora_config)

# Charger les données
dataset = load_dataset("json", data_files="training_data.jsonl")

# Configuration d'entraînement
training_args = TrainingArguments(
    output_dir="./results",
    num_train_epochs=3,
    per_device_train_batch_size=4,
    gradient_accumulation_steps=4,
    learning_rate=2e-4,
    warmup_steps=100,
    logging_steps=10,
    save_steps=500,
    fp16=True,
)

# Entraînement
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=dataset["train"],
    tokenizer=tokenizer,
)

trainer.train()

Fine-tuning via API (OpenAI)

from openai import OpenAI

client = OpenAI()

# Upload du fichier
file = client.files.create(
    file=open("training_data.jsonl", "rb"),
    purpose="fine-tune"
)

# Lancer le fine-tuning
job = client.fine_tuning.jobs.create(
    training_file=file.id,
    model="gpt-3.5-turbo",
    hyperparameters={
        "n_epochs": 3
    }
)

# Suivre le statut
status = client.fine_tuning.jobs.retrieve(job.id)
print(status.status)

# Utiliser le modèle fine-tuné
response = client.chat.completions.create(
    model=job.fine_tuned_model,
    messages=[{"role": "user", "content": "..."}]
)

RLHF : Reinforcement Learning from Human Feedback

Le RLHF aligne les modèles avec les préférences humaines.

Pipeline RLHF

┌─────────────────────────────────────────────────────────────┐
│                     PIPELINE RLHF                            │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  1. SUPERVISED FINE-TUNING (SFT)                            │
│     Modèle base → Entraînement sur réponses de qualité      │
│                          ↓                                   │
│  2. REWARD MODEL TRAINING                                   │
│     Collecte préférences humaines (A > B)                   │
│     Entraîner un modèle de récompense                       │
│                          ↓                                   │
│  3. PPO OPTIMIZATION                                        │
│     Optimiser la politique avec le reward model             │
│     Équilibrer récompense et divergence KL                  │
│                          ↓                                   │
│  Modèle aligné                                              │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Étape 1 : Supervised Fine-Tuning

Entraîner sur des exemples de haute qualité.

# Données : prompts + réponses idéales écrites par des humains
sft_dataset = [
    {"prompt": "Explique la gravité", "response": "La gravité est..."},
    ...
]

Étape 2 : Reward Model

Entraîner un modèle à prédire les préférences humaines.

# Données : paires de réponses avec préférence
preference_data = [
    {
        "prompt": "Question...",
        "chosen": "Bonne réponse...",
        "rejected": "Mauvaise réponse..."
    },
    ...
]

# Le reward model apprend à donner un score plus élevé à "chosen"

Étape 3 : PPO

Optimiser le modèle avec le reward model.

from trl import PPOTrainer, PPOConfig

ppo_config = PPOConfig(
    learning_rate=1e-5,
    batch_size=256,
    mini_batch_size=64,
    ppo_epochs=4,
)

ppo_trainer = PPOTrainer(
    config=ppo_config,
    model=model,
    ref_model=ref_model,  # Modèle de référence pour KL penalty
    tokenizer=tokenizer,
    reward_model=reward_model,
)

# Boucle d'entraînement
for batch in dataloader:
    query_tensors = tokenizer(batch["prompts"])
    response_tensors = model.generate(query_tensors)
    rewards = reward_model(query_tensors, response_tensors)
    ppo_trainer.step(query_tensors, response_tensors, rewards)

DPO : Direct Preference Optimization

Alternative simplifiée au RLHF, sans reward model explicite.

RLHF : SFT → Reward Model → PPO
DPO  : SFT → Optimization directe sur préférences

Implémentation DPO

from trl import DPOTrainer, DPOConfig

dpo_config = DPOConfig(
    beta=0.1,  # Température
    learning_rate=5e-7,
)

trainer = DPOTrainer(
    model=model,
    ref_model=ref_model,
    args=dpo_config,
    train_dataset=preference_dataset,
    tokenizer=tokenizer,
)

trainer.train()

DPO vs RLHF

AspectRLHFDPO
ComplexitéHauteMoyenne
Reward modelNécessaireNon
StabilitéMoins stablePlus stable
PerformanceRéférenceComparable
ImplémentationDifficileSimple

Constitutional AI (CAI)

Approche d'Anthropic pour l'alignement sans feedback humain massif.

1. Red teaming : Générer des prompts problématiques
2. Self-critique : Le modèle critique ses propres réponses
3. Révision : Le modèle améliore selon des principes (constitution)
4. RL : Optimiser avec les réponses révisées comme cible

Bonnes pratiques

Éviter le catastrophic forgetting

# Mélanger données nouvelles et données générales
combined_dataset = concatenate([
    new_task_data,
    sample(general_data, n=len(new_task_data))
])

Hyperparamètres recommandés

# LoRA
r = 8-64           # Plus grand = plus expressif
lora_alpha = 16-64 # Généralement 2× r
dropout = 0.05-0.1

# Entraînement
learning_rate = 1e-4 à 2e-4  # LoRA
learning_rate = 1e-5 à 5e-5  # Full fine-tuning
batch_size = 4-32
epochs = 1-5
warmup_ratio = 0.03-0.1

Validation

# Toujours garder un jeu de validation
train_data, val_data = dataset.train_test_split(test_size=0.1)

# Surveiller la loss de validation
# Arrêter si elle augmente (overfitting)

Déploiement

Fusionner les poids LoRA

# Fusionner les adapters avec le modèle de base
merged_model = model.merge_and_unload()
merged_model.save_pretrained("./merged_model")

Quantification pour le déploiement

from transformers import AutoModelForCausalLM
import torch

model = AutoModelForCausalLM.from_pretrained(
    "./merged_model",
    torch_dtype=torch.float16,
    device_map="auto"
)

# Ou quantification 4-bit pour inference
model = AutoModelForCausalLM.from_pretrained(
    "./merged_model",
    load_in_4bit=True,
)

Résumé

FINE-TUNING = Adapter un modèle pré-entraîné

Types :
├── Full Fine-tuning : Tous les paramètres
├── LoRA : Matrices low-rank (~0.1% params)
├── QLoRA : LoRA + Quantification 4-bit
└── Prefix Tuning : Tokens apprenables

RLHF = Aligner avec les préférences humaines
├── SFT : Supervised Fine-Tuning initial
├── Reward Model : Prédire les préférences
└── PPO : Optimiser avec récompenses

Alternatives :
├── DPO : Optimisation directe (plus simple)
└── CAI : Auto-critique selon constitution

Quand fine-tuner :
✓ Style/format très spécifique
✓ Domaine technique pointu
✓ Volume de requêtes similaires
✗ Connaissances changeantes (→ RAG)

On this page