LLM Engineer's Handbook
Chapitre 6 / 11 · 14 min de lecture

L'alignement par préférences (DPO)

Aller au-delà du SFT : aligner le modèle sur des préférences humaines avec des données choisi/rejeté et l'optimisation directe (DPO).

Le réglage supervisé (Supervised Fine-Tuning, SFT) du chapitre précédent a fait l'essentiel : il a appris au modèle la forme d'une bonne réponse — suivre une instruction, adopter un format, mobiliser un domaine. Mais le SFT atteint vite ses limites. Il capture mal les nuances des préférences humaines et la longue traîne des interactions qu'un modèle rencontrera en production. Il sait reproduire une réponse correcte, pas vraiment distinguer une bonne réponse d'une réponse simplement acceptable. C'est là qu'intervient l'alignement par préférences (preference alignment) : un ensemble de techniques qui injectent un retour humain ou IA dans l'entraînement pour affiner non plus la forme, mais le jugement du modèle.

Ce chapitre suit Iusztin et Labonne dans leur choix pédagogique : parmi toutes les méthodes d'alignement, ils privilégient l'optimisation directe des préférences (Direct Preference Optimization, DPO) pour sa simplicité et son efficacité. On y verra pourquoi aligner après le SFT, ce qu'est un jeu de données de préférences, en quoi le DPO se distingue du RLHF historique, et comment l'implémenter concrètement pour modifier le « style d'écriture » du LLM Twin du livre — un exemple à généraliser bien au-delà de ce projet.

Pourquoi aligner après le SFT

Le SFT optimise une seule chose : maximiser la probabilité des réponses présentes dans le jeu d'entraînement. Le modèle apprend à imiter des réponses cibles, sans aucune notion de ce qui est préférable. Or pour quantité de tâches, la qualité dépend de facteurs subjectifs — naturel, engagement, pertinence contextuelle, concision — qu'une simple cible supervisée ne sait pas exprimer.

L'idée centrale de l'alignement par préférences est de fournir au modèle deux réponses au même prompt : une réponse choisie (chosen) et une réponse rejetée (rejected). On lui apprend non pas « voici la réponse », mais « celle-ci est meilleure que celle-là ». Cette comparaison ouvre un éventail de cas où l'alignement bat le SFT seul :

Cas d'usagePourquoi le SFT seul échoueApport des préférences
Agents conversationnelsLe naturel d'une réponse est subjectifComparer meilleure/pire réponse capture la finesse
Modération de contenuLes cas limites exigent un jugement nuancéLe modèle comprend le raisonnement derrière la décision
RésuméUn résumé correct n'est pas forcément utileApprend concision, pertinence, cohérence
Génération de codePlusieurs solutions correctes, qualité inégaleCapture lisibilité, efficacité, bonnes pratiques
Écriture créativeQualité hautement subjectiveCapture style, créativité, impact émotionnel
TraductionBLEU mesure l'exactitude, pas la fluiditéApprend ce qu'un locuteur natif préfère

Dans tous ces scénarios, la réponse rejetée est aussi importante que la réponse choisie : elle représente le comportement que l'on veut éliminer. Sans elle, on retomberait sur un simple jeu d'instructions. C'est ce contraste qui donne à l'alignement sa flexibilité.

Note

L'alignement ne remplace pas le SFT, il le complète. On part toujours d'un modèle déjà passé par le SFT (un bon point de départ), puis on l'affine sur des préférences. Le livre note d'ailleurs que le DPO est moins destructeur que le SFT et a un impact plus doux sur le modèle final — il sert même à « réparer » un réseau après fusion (merging) ou élagage (pruning).

Construire un jeu de données de préférences

Les principes de qualité sont les mêmes que pour les jeux d'instructions : maximiser exactitude, diversité et complexité, en passant par la curation, la déduplication, la décontamination, l'évaluation qualité, l'exploration, la génération et l'augmentation. La différence tient à la structure de l'échantillon.

Là où un jeu d'instructions contient des paires (instruction, réponse), un jeu de préférences contient des triplets :

{
  "prompt": "Raconte-moi une blague sur les pieuvres.",
  "chosen": "Pourquoi les pieuvres ne jouent-elles pas aux cartes
             au casino ? Parce qu'elles ne savent pas compter
             au-delà de huit.",
  "rejected": "Combien de chatouilles faut-il pour faire rire
               une pieuvre ? Dix-touilles."
}

L'objectif d'entraînement est limpide : pousser le modèle à générer la réponse chosen plutôt que la rejected. Contrairement aux jeux d'instructions, il n'existe aucun format standardisé (pas d'Alpaca ni de ShareGPT) ; la plupart des jeux suivent simplement ces trois colonnes. Les conversations multi-tours sont rares en alignement : au moment de l'écriture du livre, les grandes bibliothèques de fine-tuning ne les gèrent pas et n'extraient que le premier ou le dernier message.

Combien de données ?

Bonne nouvelle : le DPO demande beaucoup moins d'échantillons que le SFT pour modifier sensiblement le comportement. La quantité dépend de la taille du modèle (les grands modèles sont plus efficaces en données) et de la complexité de la tâche.

Type d'alignementObjectifOrdre de grandeur
Généraliste (fournisseurs de LLM)Améliorer la performance globaleDes millions de paires
Open source (communauté)Améliorer benchmarks, réparer un réseau10 000 à 100 000
Spécifique à une tâcheModifier un style, refuser certaines requêtes100 à 10 000

Un exemple frappant cité par les auteurs : pour apprendre à un modèle à déclarer qu'il n'a pas été entraîné par OpenAI ou Meta, 200 à 500 paires suffisent — les rejected revendiquant une autre origine, les chosen affirmant la bonne. La qualité prime toujours sur la quantité.

Générer et évaluer les préférences

Génération et évaluation sont liées : on produit des réponses, puis on les classe. Avant de générer, mieux vaut inspecter les jeux open source existants (le dataset HH-RLHF d'Anthropic pour l'utile/inoffensif, ou le Summarize from Human Feedback d'OpenAI). Quand il faut générer, quatre stratégies se distinguent selon qui crée et qui évalue les réponses :

Génération / ÉvaluationQualitéPassage à l'échelleVerdict pratique
Humaine / HumaineTrès haute (nuances)Très coûteuxRéservé aux grands labos
Humaine / LLMMoyenneInefficaceRarement utilisé
LLM / HumaineBonneBon compromisSouvent préféré (juger < rédiger)
LLM / LLMVariableExcellentDe plus en plus courant (synthétique)

L'évaluation par paires (pairwise ranking) — présenter deux réponses et demander la meilleure — est plus fiable que le scoring absolu, car elle imite la façon dont les humains comparent. On peut encore l'améliorer en fournissant une réponse de référence et en demandant un raisonnement étape par étape (chain-of-thought).

Attention

L'évaluation par un LLM-juge (LLM-as-a-judge) souffre de biais systématiques : biais de position (la première réponse est favorisée), biais de longueur (les réponses longues sont préférées), biais de famille (un LLM préfère les sorties de modèles de sa propre famille). Parades : randomiser l'ordre A/B, donner des exemples few-shot calibrés, et faire voter plusieurs modèles en jury plutôt qu'un seul.

Point clé : l'évaluation n'est pas toujours nécessaire. On peut faire émerger les préférences de la génération elle-même — par exemple, un modèle de haute qualité produit les réponses préférées, un modèle plus faible (ou volontairement bridé) les alternatives rejetées. C'est exactement l'approche du LLM Twin : pour donner au modèle un ton plus authentique, les auteurs prennent comme chosen des extraits réels des articles d'origine, et comme rejected les réponses générées par le modèle. La vérité-terrain étant dans le texte source, aucun juge LLM complexe n'est requis — seulement deux filtres qualité (longueur minimale, format de ponctuation). Le pipeline final a généré 2 970 échantillons, filtrés à 1 467.

Du RLHF au DPO

Pour comprendre la valeur du DPO, il faut connaître ce qu'il remplace.

RLHF : puissant mais complexe

L'apprentissage par renforcement à partir de retours humains (Reinforcement Learning from Human Feedback, RLHF) combine l'apprentissage par renforcement et le jugement humain. Il est né d'un constat : pour des tâches complexes, définir manuellement une fonction de récompense est difficile et exposé au reward hacking. Le RLHF procède en boucle sur deux composants :

┌─────────────────┐   compare des reponses    ┌──────────────────┐
│  Retour humain  │ ────────────────────────► │  Modele de       │
│ (preferences A/B)│                           │  recompense      │
└─────────────────┘                           │  (reward model)  │
                                              └────────┬─────────┘
                                                       │ score

                          ┌──────────────────────────────────────┐
                          │  Optimisation de la politique (PPO)    │
                          │  + regularisation KL vs modele gele    │
                          └──────────────────────────────────────┘

Un modèle de récompense (reward model) est d'abord appris à partir des préférences humaines (souvent via un modèle de Bradley-Terry). Puis un algorithme de RL — le plus populaire étant PPO (Proximal Policy Optimization) — optimise la politique du LLM pour maximiser cette récompense. Une divergence de Kullback-Leibler (KL divergence) ancre le modèle entraîné à sa version d'origine gelée, l'empêchant de trop dériver.

C'est efficace, mais lourd. Le RLHF est coûteux en calcul, potentiellement instable, et exige une expertise RL. Pire : malgré sa supériorité théorique, il a parfois sous-performé face à des approches plus simples en pratique.

DPO : se passer du reward model

Introduit par Rafailov et al. en 2023 (« Your Language Model is Secretly a Reward Model »), le DPO reformule le problème. Son intuition mathématique : sous l'objectif RLHF standard (maximiser la récompense sous contrainte KL avec une politique de référence), il existe une expression analytique de la politique optimale. On peut donc exprimer l'apprentissage des préférences directement en termes de la politique du modèle — sans modèle de récompense séparé, ni algorithme de RL.

En pratique, le DPO se ramène à une simple perte d'entropie croisée binaire appliquée directement aux probabilités de sortie du modèle. L'intuition de cette perte :

Pour chaque triplet (prompt, chosen, rejected) :

  augmenter   log P(chosen | prompt)
  diminuer    log P(rejected | prompt)

  ... tout en restant proche d'un modele de REFERENCE (gele)
      pour ne pas trop deriver.

L'ecart de log-probabilite (chosen vs rejected)
doit croitre, puis se stabiliser (plateau).

Autrement dit, on augmente l'écart de log-probabilité entre la réponse choisie et la rejetée. L'ancrage au modèle de référence est contrôlé par un paramètre bêta (beta) compris entre 0 et 1 : à 0, la référence est ignorée et le modèle entraîné peut beaucoup s'écarter ; une valeur de 0,1 est la plus courante. Tout se fait par descente de gradient standard, sans échantillonnage du modèle pendant l'entraînement ni boucle RL.

Comparatif RLHF/PPO vs DPO

CritèreRLHF / PPODPO
Modèle de récompenseRequis (entraîné à part)Aucun
AlgorithmeRL (échantillonnage, boucle)Descente de gradient (entropie croisée)
Complexité d'ingénierieÉlevée, expertise RLFaible, proche du SFT
StabilitéSensible, parfois instablePlus stable, peu sensible aux hyperparamètres
Mémoire (VRAM)Deux modèles à chargerUn seul avec adaptateurs LoRA/QLoRA
Plafond de performancePlus haut à très grande échelleAtteint l'essentiel à coût moindre
Données requisesPaires de préférencesPaires de préférences (idem)

Astuce

Avec des adaptateurs (LoRA, QLoRA), le DPO devient encore plus économe : comme seuls les adaptateurs sont entraînés, le modèle de base non modifié sert directement de modèle de référence. On ne charge donc qu'un seul modèle au lieu de deux, ce qui économise une quantité notable de VRAM.

Le DPO n'est pas exempt de défauts : il exige toujours des paires de préférences (coûteuses à collecter) et perd certaines garanties théoriques du RL. Pour des entraînements à très grande échelle (millions d'échantillons), les méthodes inspirées de PPO gardent un plafond de performance supérieur. Mais pour la majorité des applications, le DPO offre l'essentiel des bénéfices à un coût bien moindre. C'est pourquoi le livre le retient.

Implémenter le DPO en pratique

Le code suivant aligne le modèle TwinLlama-3.1-8B issu du SFT, via la bibliothèque Unsloth (mais le DPOTrainer provient de TRL et fonctionne aussi seul). On charge le modèle SFT, on l'équipe d'adaptateurs LoRA, puis on lance l'entraînement.

from unsloth import PatchDPOTrainer
PatchDPOTrainer()  # corrige les logs DPO en notebook

import torch
from datasets import load_dataset
from unsloth import FastLanguageModel, is_bfloat16_supported
from trl import DPOConfig, DPOTrainer  # specifiques au DPO

max_seq_length = 2048
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name="mlabonne/TwinLlama-3.1-8B",  # le modele SFT
    max_seq_length=max_seq_length,
    load_in_4bit=False,  # True = QLoRA (moins de VRAM)
)

# Adaptateurs LoRA : le modele de base sert de reference.
model = FastLanguageModel.get_peft_model(
    model,
    r=32,
    lora_alpha=32,
    lora_dropout=0,
    target_modules=["q_proj", "k_proj", "v_proj", "up_proj",
                    "down_proj", "o_proj", "gate_proj"],
)

Le jeu de données fournit directement les colonnes prompt, chosen, rejected. On applique le gabarit de chat uniquement à l'instruction ; les réponses choisie et rejetée n'ont besoin que d'être suffixées par le jeton de fin de séquence (EOS).

dataset = load_dataset("mlabonne/llmtwin-dpo", split="train")

alpaca_template = """Below is an instruction that describes a task.
Write a response that appropriately completes the request.

### Instruction:
{}

### Response:
"""
EOS_TOKEN = tokenizer.eos_token

def format_samples(example):
    example["prompt"] = alpaca_template.format(example["prompt"])
    example["chosen"] = example["chosen"] + EOS_TOKEN
    example["rejected"] = example["rejected"] + EOS_TOKEN
    return example

dataset = dataset.map(format_samples)
dataset = dataset.train_test_split(test_size=0.05)

Vient l'entraînement. Par rapport au SFT, deux paramètres nouveaux : ref_model (mis à None car les adaptateurs LoRA font office de référence) et beta.

trainer = DPOTrainer(
    model=model,
    ref_model=None,        # LoRA : la base = la reference
    tokenizer=tokenizer,
    beta=0.5,              # ancrage fort a la reference (voir encart)
    train_dataset=dataset["train"],
    eval_dataset=dataset["test"],
    max_length=max_seq_length // 2,
    max_prompt_length=max_seq_length // 2,
    args=DPOConfig(
        learning_rate=2e-6,    # bien plus bas que le SFT (3e-4)
        lr_scheduler_type="linear",
        per_device_train_batch_size=2,
        gradient_accumulation_steps=8,
        num_train_epochs=1,    # 1 seule epoque (vs 3 au SFT)
        fp16=not is_bfloat16_supported(),
        bf16=is_bfloat16_supported(),
        optim="adamw_8bit",
        weight_decay=0.01,
        warmup_steps=10,
        eval_strategy="steps",
        eval_steps=0.2,
        report_to="comet_ml",  # suivi d'experiences
        seed=0,
    ),
)
trainer.train()

Notez les choix : un taux d'apprentissage très faible (2e-6 contre 3e-4 au SFT) et une seule époque. C'est délibéré — j'y reviens dans les pièges.

À retenir

Le beta est ici monté à 0,5 au lieu du 0,1 habituel. Pourquoi ? L'objectif (imiter un style décontracté) entre en conflit avec la tendance naturelle du DPO à rendre le modèle plus verbeux et formel — entre autres parce que les réponses chosen extraites du texte sont souvent plus formelles que celles générées. Un beta élevé garde le modèle proche de la référence, ce qui corrige cette dérive. Les auteurs ont entraîné plus de 20 modèles pour trouver ce réglage.

Lire les métriques du DPO

Le DPO ajoute des métriques absentes du SFT, qu'il faut surveiller :

MétriqueComportement attenduSignal d'alarme
Perte (train/val)Décroît en moyenneChute brutale à zéro = à surveiller (n'apprend plus, mais pas toujours mauvais)
Norme du gradientFaible, peu de picsPics répétés
Rewards (chosen/rejected)Écart croissantÉcart stagnant ou inversé
Margins (chosen − rejected)Croît vite puis plateauReste plat
AccuracyAugmente progressivement100 % atteint trop vite

Le reward est la différence moyenne entre les log-probabilités du modèle entraîné et du modèle de référence. La métrique margins (écart entre récompense choisie et rejetée) doit croître puis se stabiliser. Une accuracy atteignant 100 % trop vite indique un jeu de données trop facile : il faudrait ajouter des exemples plus difficiles. Le DPO est globalement plus délicat à déboguer que le SFT (présence d'un modèle de référence), mais infiniment plus simple que PPO.

Le résultat

La comparaison entre les deux modèles est parlante. Le modèle SFT décrit le SFT comme alignant les réponses sur « les attentes humaines » dans un style très formel. Le modèle DPO, lui, est à la fois plus exact (il identifie correctement les modèles pré-entraînés comme source) et moins formel — un texte qu'on emploierait réellement dans un article de blog. L'alignement a déplacé non pas le savoir du modèle, mais sa voix.

Pièges et variantes

Le DPO a beau être robuste, plusieurs écueils méritent l'attention :

  • Sur-optimisation et dérive de style. Comme vu, le DPO pousse vers la verbosité et la formalité. D'où la nécessité d'un fine-tuning chirurgical : faible taux d'apprentissage, peu d'époques, beta ajusté.
  • Dégradation des capacités. Trop optimiser sur un signal de préférence étroit peut éroder des compétences générales. Le suivi des métriques (perte qui tombe à zéro, accuracy trop haute) sert de garde-fou.
  • Biais des annotateurs. Que les préférences viennent d'humains ou de LLM-juges, elles transportent des biais (position, longueur, famille) qui se gravent dans le modèle aligné.
  • Coût des données appariées. Le DPO partage avec le RLHF le besoin de paires de préférences, qui restent coûteuses à collecter.

Le DPO n'est qu'une porte d'entrée. D'autres algorithmes d'alignement, disponibles dans TRL et Axolotl, font des compromis différents : IPO (Identity Preference Optimization) ajoute une régularisation pour limiter le sur-apprentissage des préférences ; KTO (Kahneman-Tversky Optimization) se passe de paires et accepte un signal binaire (réponse simplement « bonne » ou « mauvaise »), facilitant la collecte ; ORPO (Odds Ratio Preference Optimization) fusionne SFT et alignement en une seule étape, sans modèle de référence. Le choix dépend de vos données, de votre budget et de votre tolérance à la complexité.

À retenir

  • Le SFT apprend la forme, l'alignement par préférences affine le jugement : on enseigne au modèle à préférer une réponse chosen à une réponse rejected pour le même prompt. La réponse rejetée est aussi importante que la choisie.
  • Un jeu de préférences est fait de triplets (prompt, chosen, rejected), sans format standard, et demande bien moins d'échantillons que le SFT — de 200 paires pour une tâche ciblée à des millions pour l'alignement généraliste.
  • Le RLHF (reward model + PPO) est puissant mais coûteux et instable ; le DPO s'en passe en optimisant directement sur les paires via une simple entropie croisée, en restant ancré à un modèle de référence (paramètre beta).
  • L'intuition du DPO : augmenter l'écart de log-probabilité entre choisi et rejeté ; avec des adaptateurs LoRA, la base sert de référence, d'où un seul modèle en mémoire.
  • En pratique, on aligne chirurgicalement (taux d'apprentissage faible, une époque) et l'on surveille des métriques propres au DPO : rewards, margins, accuracy — une accuracy à 100 % trop vite trahit un jeu trop facile.
  • Attention à la sur-optimisation, à la dégradation des capacités et aux biais d'annotation ; au-delà du DPO, explorez IPO, KTO (signal binaire) et ORPO (SFT et alignement fusionnés).