Guide du fine-tuning des LLM : LoRA, QLoRA, Unsloth, Axolotl

Traduction automatique Cet article a été traduit automatiquement depuis la version originale en anglais.

La plupart des échecs de fine-tuning sont en réalité des erreurs de décision. Une équipe entraîne un modèle avant d’avoir démontré que le prompting, la retrieval ou le constrained decoding ne peuvent pas résoudre le problème. Une autre évalue sur la distribution d’entraînement, ou découvre après l’entraînement que l’artefact est difficile à servir.

Ce guide traite l’adaptation comme une expérience assortie d’une décision de sortie opérationnelle. Il commence par la frontière de décision, puis suit un parcours à travers les données, LoRA ou QLoRA, l’évaluation spécifique à la tâche, l’export et le serving.

Pour une décision rapide entre les interventions, consultez Fine-Tuning vs RAG vs Prompting.

Faut-il vraiment effectuer un fine-tuning ?

Avant de consommer des heures de GPU, déterminez si le fine-tuning est bien l’outil adapté au problème à résoudre.

Decision FlowchartDecision Flowchart

Fine-tuning vs RAG

Le fine-tuning peut modifier la manière dont un modèle utilise le langage d’un domaine, mais c’est un mauvais mécanisme de mise à jour pour des faits qui évoluent ou doivent être cités. La retrieval et le fine-tuning résolvent des parties différentes du problème et ont souvent leur place dans le même système.

FonctionnalitéFine-TuningRAG (Retrieval-Augmented Generation)
Fonction principaleModifie les poids internes pour enseigner des compétences, des styles ou des comportementsFournit un contexte externe et à jour au moment de l’inférence
Idéal pour• Styles conversationnels spécifiques
• Suivi d’instructions complexes
• Reasoning spécifique au domaine
• Données qui évoluent rapidement (actualité, cours boursiers)
• Réduction des hallucinations (grounding)
• Citation des sources
Gestion des connaissancesModifie le comportement statistique des poids ; la restitution exacte n’est pas garantieRécupère des enregistrements ou des passages qui peuvent être mis à jour et cités
Fréquence des mises à jourNécessite un nouvel entraînement pour chaque mise à jourMise à jour immédiate avec de nouveaux documents

Fine-tuning vs prompt engineering

Les LLMs modernes répondent bien aux prompts clairs accompagnés d’exemples. Testez ces options avant d’investir dans le fine-tuning.

AspectFine-TuningPrompt Engineering
Coût de mise en placeÉlevé (curation des données, calcul GPU, itérations)Faible (amélioration itérative du prompt)
FlexibilitéNécessite un nouveau cycle d’entraînement et de releaseChange avec le prompt
Format/stylePeut rendre un comportement récurrent plus probableSouvent suffisant pour le style et les formats simples
LatencePeut raccourcir les instructions répétéesDépend de la longueur du prompt et du caching du fournisseur
Idéal pourComportements complexes, distillation, réduction des coûts à grande échelleItérations rapides, exigences changeantes

[!TIP] Essayez d’abord le prompting Commencez par un prompt et des exemples représentatifs. Si seule la syntaxe de sortie est peu fiable, ajoutez du constrained decoding avant de modifier les poids.

Fine-tuning vs constrained decoding

Des bibliothèques telles que xgrammar et outlines contraignent la génération à un JSON Schema, une expression régulière ou une grammaire. Selon la contrainte et le backend, elles compilent un automate ou une grammaire et masquent les tokens suivants invalides. Aucune mise à jour des poids n’est nécessaire.

Cela garantit l’appartenance au langage de sortie pris en charge. Cette garantie ne dit rien de la véracité, de l’exhaustivité ou de la pertinence sémantique des valeurs. Un tool call syntaxiquement valide peut tout de même contenir le mauvais identifiant client.

AspectConstrained DecodingFine-Tuning
Mise en placeImmédiate — définir le schéma, déployerNécessite curation des données, calcul GPU et itérations
GarantieSyntaxe valide pour la contrainte prise en chargeComportement appris ; le respect du schéma peut varier
FlexibilitéModification du schéma à tout moment sans réentraînementFigé après l’entraînement
LatenceLéger surcoût (le modèle peut « lutter » contre le schéma)Plus faible (le modèle produit naturellement le format)
Idéal pourJSON, choix, grammaires, syntaxe des tool callsComportement récurrent absent du modèle de base

Un ordre pratique :

  1. Commencez par le prompting et des exemples few-shot pour le formatage de base.
  2. Ajoutez du constrained decoding (xgrammar ou outlines) lorsque la syntaxe est incohérente.
  3. N’effectuez un fine-tuning que lorsque vous avez besoin de changements comportementaux qu’un schéma ne peut pas imposer.

Référence rapide : associer les problèmes aux solutions

ProblèmePremier mécanisme à testerPourquoi ?
Connaissances manquantesRAGLes modèles hallucinent des faits. La retrieval fournit un contexte fondé et à jour
Format/ton incorrectPrompt EngineeringLes modèles modernes suivent bien les consignes de style avec des exemples few-shot
Syntaxe de sortie invalideConstrained decodingImpose un schéma ou une grammaire pris en charge pendant la génération
Échec répété sur une tâcheFine-tuning (SFT)Apprend à partir d’exemples entrée/sortie soigneusement sélectionnés
Désaccord de préférence par pairePreference optimizationUtilise des exemples chosen/rejected une fois le comportement de la tâche mesurable
Latence/coût à grande échelleDistillation (SFT)Entraîne un modèle student plus petit avec les sorties d’un modèle teacher plus grand
Réduction de la taille du modèleQuantizationAucun entraînement — compresse les poids (FP16→INT4) pour accélérer l’inférence

Rendre le business case mesurable

Le fine-tuning peut réduire le nombre récurrent de tokens dans les prompts ou permettre à un modèle plus petit d’atteindre la cible, mais aucune de ces économies n’est automatique. Calculez le seuil de rentabilité avec votre propre trafic et vos propres tarifs :

[ \text{requêtes au seuil de rentabilité} = \frac{\text{coût de l’entraînement + de l’évaluation + du déploiement}} {\text{coût par requête du baseline} - \text{coût par requête du modèle adapté}} ]

Si le dénominateur est faible, négatif ou fondé sur une hypothèse de qualité non démontrée, le projet ne présente pas encore de justification économique.

[!TIP] L’architecture hybride Une architecture courante associe un modèle plus petit adapté à la tâche et la retrieval pour les faits évolutifs. Prenez comme baseline le modèle plus grand avec prompting et ne conservez le modèle plus petit que s’il atteint les mêmes seuils de qualité et de sécurité spécifiques à la tâche.


Types de fine-tuning

Le fine-tuning peut principalement prendre trois formes. Elles diffèrent par le type de données requis et par ce qu’elles enseignent au modèle.

Fine-Tuning TypesFine-Tuning Types

1. Continued pre-training (self-supervised)

Vous entraînez le modèle de base sur davantage de texte brut, en utilisant le token suivant de chaque séquence comme cible d’entraînement. Il s’agit de self-supervised learning : le texte fournit lui-même ses cibles, comme lors du pre-training initial.

À utiliser lorsque :

  • Le domaine possède un vocabulaire que le modèle de base n’a jamais rencontré (médecine, droit, codebases internes).
  • Vous disposez de grandes quantités de texte du domaine, mais d’aucune paire (entrée, sortie) annotée.
  • Le modèle de base maîtrise mal la terminologie propre au domaine.

Exemple : entraîner le modèle sur des millions de notes cliniques afin qu’il assimile les abréviations médicales, les noms de médicaments et les workflows cliniques.

2. Supervised fine-tuning (SFT)

Le SFT est entraîné sur des paires (entrée, sortie) annotées. Vous montrez au modèle la sortie exacte attendue pour chaque entrée.

À utiliser lorsque :

  • Vous avez une tâche précise avec un format entrée/sortie propre.
  • Vous disposez de données annotées de qualité, même en faible quantité.
  • Vous avez besoin d’un comportement prévisible sur une forme d’entrée connue.

Exemple : entraîner le modèle sur des paires (description de requête SQL, code SQL) pour le text-to-SQL.

{
    "input": "Get all users who signed up last month",
    "output": "SELECT * FROM users WHERE signup_date >= DATE_SUB(NOW(), INTERVAL 1 MONTH)"
}

3. Instruction tuning

L’instruction tuning est un cas particulier de SFT conçu pour apprendre aux modèles à suivre une grande variété d’instructions en langage naturel. Les données d’entraînement sont constituées de paires (instruction, réponse) couvrant de nombreuses tâches différentes.

À utiliser lorsque :

  • Vous voulez un assistant généraliste (comme ChatGPT ou Claude).
  • Le modèle doit traiter des demandes variées et ouvertes.
  • Vous construisez une interface de chat.

Exemple : entraîner le modèle sur des milliers d’instructions diverses comme « Résumez cet article », « Écrivez un poème sur X » ou « Expliquez Y simplement ».

Comparaison

AspectContinued Pre-trainingSFTInstruction Tuning
DonnéesTexte brutPaires (entrée, sortie)Paires (instruction, réponse)
LabelsAucun (non supervisé)Spécifiques à la tâcheTâches diverses
ObjectifConnaissances du domaineComportement spécifique à la tâcheSuivre n’importe quelle instruction
Volume de donnéesGénéralement le corpus le plus importantDéterminé par la couverture de la tâche et la diversité des erreursGénéralement plus large qu’un SFT spécifique à une tâche

[!NOTE] Ce qui se fait réellement Le SFT et l’instruction tuning utilisent le même objectif de next-token prediction ; la distinction tient à l’ampleur et à la construction du dataset. Le continued pre-training est une expérience distincte qui doit être suivie de tests portant à la fois sur les gains dans le domaine et sur les régressions des capacités générales.


Le pipeline de fine-tuning en 7 étapes

Le fine-tuning est un pipeline, pas une commande unique. Chaque étape possède ses propres modes d’échec ; en sauter une se traduit généralement plus tard par un mauvais modèle.

7-Stage Pipeline7-Stage Pipeline

Chaque étape s’appuie sur la précédente :

  1. Préparation des données — Définir l’unité d’évaluation, répartir les données, puis les nettoyer et les formater
  2. Sélection du modèle — Choisir le bon modèle de base et charger les poids
  3. Configuration de l’entraînement — Configurer le matériel, les hyperparamètres et la stratégie d’optimisation
  4. Fine-tuning — Exécuter un entraînement SFT, DPO ou ORPO
  5. Évaluation — Mesurer les performances et valider la qualité
  6. Déploiement — Exporter et servir le modèle
  7. Monitoring — Suivre les performances, maintenir le modèle et itérer

[!WARNING] Les données sont le socle L’entraînement reproduit les défauts systématiques présents dans les exemples. Inspectez les labels, les fuites, la couverture et le respect des politiques avant de consacrer du temps aux balayages d’optimiseurs.


Étape 1 : préparation des données

De nombreux projets de fine-tuning échouent ici, et non pendant l’entraînement. La préparation moderne des données ne consiste pas seulement à exécuter une regex sur des CSV.

Data PipelineData Pipeline

Le pipeline de données en 5 étapes

Des outils comme DataTrove et Distilabel peuvent aider à grande échelle. Concevez le pipeline à partir de la taxonomie des échecs et du contrat de données ; le choix de l’outil en découle.

1. Ingestion et filtrage

  • Action : supprimer les refus (« I cannot answer that »), les encodages UTF-8 invalides et les langues qui ne sont pas ciblées.
  • Outils : Trafilatura pour l’extraction et les modèles d’identification de la langue de fastText pour l’identification linguistique ; les modèles lid.176 distribués reconnaissent 176 langues.

2. Politique relative aux données sensibles

  • Action : déterminer ce que le modèle est autorisé à apprendre, puis rédiger, tokeniser ou exclure les champs personnels et confidentiels selon les besoins.
  • Outils : Microsoft Presidio ou scrubadub.
  • Pourquoi : un détecteur n’est qu’un contrôle parmi d’autres ; les exigences de provenance, de consentement, de conservation, d’accès et de suppression restent applicables.

3. Déduplication (MinHash LSH)

  • Action : supprimer les quasi-doublons afin que le modèle ne les mémorise pas.
  • Outils : DataTrove gère efficacement les traitements à l’échelle du téraoctet.

4. Augmentation synthétique, si nécessaire

  • Action : utiliser un modèle teacher plus performant (GPT-4o, DeepSeek-V3) pour réécrire les données brutes sous forme de paires instruction-réponse propres.
  • Outils : Distilabel.
  • Validation : échantillonner les sorties du teacher, les vérifier avec la même grille que les annotations humaines et conserver séparément les sous-ensembles synthétiques et humains lors de l’évaluation.

5. Formatage

  • Action : convertir les données dans un format standard (Alpaca ou ShareGPT).

Exemples de formats de données

Format Alpaca (suivi d’instructions) :

{
    "instruction": "Summarize the following text.",
    "input": "The text to be summarized...",
    "output": "This is the summary."
}

Format ShareGPT/ChatML (conversationnel) :

{
    "conversations": [
        { "from": "user", "value": "Hello, who are you?" },
        { "from": "assistant", "value": "I am a helpful AI assistant." }
    ]
}

Ce qui compte réellement

  • La couverture avant le volume. Ajoutez des exemples représentant des modes d’échec distincts, plutôt que de répéter le cas majoritaire facile.
  • La propreté. Supprimez le texte hors sujet, normalisez les espaces et conservez un formatage cohérent.
  • L’équilibre. Préservez les cas rares importants et publiez les performances par sous-ensemble.
  • La séparation. Répartissez les données par source, utilisateur, document ou période lorsque des splits aléatoires par ligne entraîneraient des fuites de quasi-doublons.
  • La provenance. Enregistrez la source, la licence ou l’autorisation, l’historique des transformations et le processus de suppression pour chaque version du dataset.

Étape 2 : sélection du modèle et matériel

Le choix du modèle de base et la compréhension du seuil matériel des GPU déterminent ce que vous pouvez réellement entraîner.

Commencez par le plus petit modèle de base qui franchit déjà les vérifications non négociables du baseline. Confirmez :

  • les conditions de licence et de redistribution pour le produit visé ;
  • le comportement en matière de langue, de domaine, de tool use et de sécurité avant l’adaptation ;
  • la compatibilité du tokenizer et du chat template avec le dataset ;
  • la longueur de contexte maximale et le comportement de troncature requis par les exemples réels ;
  • la prise en charge par le framework d’entraînement et le moteur de serving cible.

Le fine-tuning est une étape d’adaptation, pas un correctif pour un modèle de base inadapté. Si le modèle échoue sur des capacités que le dataset ne couvre pas, choisissez un autre modèle de base avant de lancer davantage d’epochs.

Dimensionner le run, pas la catégorie marketing

Il n’existe pas de tableau durable « taille du modèle → GPU ». La mémoire maximale varie selon la précision des poids, l’optimizer, le nombre de paramètres entraînables, la longueur des séquences, la taille du micro-batch, l’activation checkpointing, l’implémentation de l’attention et la surcharge du framework. Commencez par une estimation mémoire, puis exécutez un smoke test court à longueur maximale sur la stack exacte.

Composant mémoireFull fine-tuningLoRAQLoRA
Poids de basePrécision d’entraînementGelés, généralement BF16/FP16Gelés, généralement en NF4 4 bits
GradientsTous les poids entraînablesPoids des adaptersPoids des adapters
États de l’optimizerTous les poids entraînablesPoids des adaptersPoids des adapters
ActivationsDépend de la taille du batch et de la longueur des séquences dans toutes les méthodesMême dépendanceMême dépendance

Le papier QLoRA original a permis d’adapter un modèle LLaMA 65B sur un seul GPU de 48 Go dans sa configuration spécifique. Ce résultat constitue une borne utile, pas la garantie que toute architecture actuelle 70B, longueur de contexte, kernel ou trainer tiendra sur le même appareil.

Calcul de la mémoire

Pour un modèle comportant PP paramètres, les poids seuls nécessitent approximativement 2P2P octets en BF16/FP16 ou 0.5P0.5P octets en quatre bits, avant de prendre en compte les métadonnées de quantization et les buffers du runtime. Un entraînement complet de type Adam ajoute les gradients, les états de l’optimizer et souvent des poids master en précision supérieure. LoRA évite l’essentiel de la mémoire liée aux états entraînables ; QLoRA réduit en plus l’empreinte des poids de base gelés. Avec de longues séquences, les activations peuvent néanmoins dominer.

Utilisez ce workflow :

  1. Choisissez la séquence la plus longue et le micro-batch que vous devez prendre en charge.
  2. Estimez les poids et les états entraînables, en gardant une marge pour les activations et les kernels.
  3. Exécutez une étape forward/backward à longueur maximale.
  4. Enregistrez la mémoire maximale allouée et réservée.
  5. Ensuite seulement, augmentez la taille du batch, le rank, la longueur des séquences ou le nombre de GPUs.

Étape 3 : méthodes d’entraînement (PEFT et LoRA)

Full fine-tuning vs PEFT

Le full fine-tuning (FFT) met à jour chaque poids ; les gradients et l’état de l’optimizer évoluent donc avec l’ensemble du modèle. La mémoire maximale ne peut pas être déduite du seul nombre de paramètres, mais elle est largement supérieure à celle nécessaire pour charger les poids en inférence.

Le parameter-efficient fine-tuning (PEFT) n’entraîne qu’un petit sous-ensemble de paramètres et gèle le reste. Les calculs deviennent nettement plus favorables.

LoRA : le point de départ

LoRA (Low-Rank Adaptation) gèle une matrice pré-entraînée et représente sa mise à jour apprise avec deux matrices plus petites. Le papier original s’appuie sur l’hypothèse que les mises à jour utiles pour l’adaptation ont un rang intrinsèque faible.

LoRA ArchitectureLoRA Architecture

Pour une matrice gelée W0Rdout×dinW_0 \in \mathbb{R}^{d_{out} \times d_{in}}, LoRA apprend :

  • ARr×dinA \in \mathbb{R}^{r \times d_{in}}
  • BRdout×rB \in \mathbb{R}^{d_{out} \times r}

La couche adaptée est :

W=W0+αrBAW' = W_0 + \frac{\alpha}{r}BA

L’adapter possède r(din+dout)r(d_{in}+d_{out}) paramètres entraînables au lieu de dindoutd_{in}d_{out} pour cette matrice. Pour une matrice carrée de largeur 4 096 et de rang 16, cela représente une réduction de 128× pour cette matrice, et non de 10 000× pour un modèle quelconque. Le chiffre de 10 000× mis en avant dans le papier LoRA correspondait à une configuration spécifique de GPT-3 175B adaptant certaines matrices.

Comparaison des méthodes PEFT

MéthodeCe qui changeÀ choisir lorsque
LoRABase gelée et mises à jour entraînables low-rankLe modèle de base tient confortablement en mémoire et vous voulez de petits artefacts spécifiques à la tâche
QLoRALoRA avec une base gelée stockée en 4 bitsLa mémoire des poids de base est le facteur limitant
DoRASépare la magnitude des poids de leur direction mise à jour par LoRAUn baseline LoRA mesuré laisse un écart de qualité justifiant une complexité supplémentaire
Full fine-tuningTous les poids du modèlePEFT n’atteint pas la cible et le gain de qualité justifie un entraînement distribué et des checkpoints complets

Quand choisir quelle méthode

  • LoRA : commencez par cette méthode. Rapide, efficace en mémoire et bien prise en charge.
  • QLoRA : lorsque la même expérience LoRA ne tient pas à cause des poids de base gelés.
  • DoRA : après qu’une comparaison LoRA en conditions identiques a montré un gain utile.
  • Full fine-tuning : uniquement après avoir démontré que PEFT est un goulot d’étranglement évalué, plutôt qu’une simple hypothèse.

DoRA : LoRA avec décomposition des poids

DoRA (Weight-Decomposed Low-Rank Adaptation) sépare la magnitude de chaque vecteur de poids de sa direction. Le papier DoRA applique une mise à jour LoRA à la composante directionnelle, tout en apprenant séparément la magnitude.

DoRA ArchitectureDoRA Architecture

Fonctionnement :

Au lieu de considérer les poids comme une entité unique, DoRA les décompose en deux composantes :

  1. Magnitude — une valeur entraînable par vecteur de poids.
  2. Direction — un vecteur normalisé mis à jour par des matrices low-rank.

En notation compacte par colonnes :

W=mV+BAV+BAcW' = m \frac{V + BA}{\lVert V + BA \rVert_c}

où :

  • m = magnitude (entraînable)
  • VV = matrice directionnelle gelée
  • BABA = mise à jour directionnelle low-rank apprise
  • c\lVert \cdot \rVert_c = normalisation par colonne

Ce que cette structure supplémentaire apporte :

  • Davantage de degrés de liberté que LoRA standard, car la magnitude peut évoluer indépendamment.
  • De meilleurs résultats que LoRA dans plusieurs configurations rapportées par le papier d’origine.
  • Des paramètres et des calculs supplémentaires ; le gain doit donc être vérifié sur votre tâche et votre chemin de serving.

Fusion d’adapters pour l’apprentissage multi-tâche

Des adapters séparés permettent à une même base gelée de prendre en charge plusieurs tâches. Vous pouvez router les requêtes vers un adapter, servir plusieurs adapters depuis un même moteur lorsque cela est pris en charge, ou créer un candidat fusionné hors ligne. La fusion peut provoquer des interférences ; évaluez donc l’artefact fusionné au lieu de supposer que les adapters sources se composent proprement.

Méthodes de fusion courantes :

  1. Concaténation — combine les paramètres des adapters et augmente le rang effectif. Rapide et simple.
  2. Combinaison linéaire — somme pondérée des adapters. Offre des paramètres de contrôle.
  3. SVD — décomposition matricielle pour la fusion. Plus flexible, mais plus lente.

Exemple : un adapter pour le résumé, un autre pour la traduction, fusionnés en un modèle multi-tâche unique.


Étape 4 : fine-tuning et alignement par préférences

Le SFT apprend à partir de démonstrations. La preference optimization apprend plutôt à partir de comparaisons telles que « la réponse choisie A est meilleure que la réponse rejetée B ». Utilisez-la uniquement lorsque la préférence par paire correspond au bon label pour l’erreur ; l’exactitude factuelle et le respect des politiques nécessitent souvent des évaluateurs plus robustes qu’une préférence globale.

Alignment MethodsAlignment Methods

RLHF basé sur PPO

La recette originale était un pipeline en trois étapes :

  1. SFT — apprendre la tâche.
  2. Reward model — entraîné sur les préférences humaines (chosen vs rejected).
  3. PPO (Proximal Policy Optimization) — reinforcement learning pour optimiser la policy.

Le coût opérationnel vient des différents composants :

  • Implémentation et maintenance complexes.
  • Coûteux — plusieurs modèles doivent être entraînés.
  • L’échantillonnage on-policy et l’optimisation de la récompense nécessitent des contrôles rigoureux de la stabilité et du reward hacking.

DPO

DPO (Direct Preference Optimization) supprime le reward model explicite et la boucle RL. Le papier DPO dérive un objectif reparamétré de maximisation de la récompense avec une contrainte de divergence KL, ce qui permet d’optimiser à partir de paires de préférences plutôt que par reinforcement learning :

{
    "prompt": "Explain quantum computing",
    "chosen": "Quantum computing uses qubits...",   # Preferred response
    "rejected": "Well, it's complicated..."        # Non-preferred response
}

Conséquences opérationnelles :

  • Chemin de code plus simple (pas de reward model séparé ni de boucle RL).
  • Objectif offline sur des paires de préférences, plutôt que reinforcement learning on-policy.
  • Une policy de référence ou, dans la formulation standard, des log probabilities de référence équivalentes.

DPO est plus simple à prototyper qu’un pipeline PPO complet, mais ce n’est pas une amélioration automatique de la qualité. Les résultats dépendent de la policy de départ, de la qualité des paires, des paramètres de loss, des effets liés à la longueur et du protocole d’évaluation. Comparez-le à un checkpoint SFT sur les mêmes suites de préférences et de tâches conservées en évaluation.

ORPO

ORPO (Odds-Ratio Preference Optimization) combine la loss SFT de negative log-likelihood avec une pénalité d’odds ratio sur les réponses rejetées. Il supprime le modèle de référence séparé et peut combiner l’apprentissage de la tâche et la preference optimization en un seul run.

Fonctionnement : ORPO utilise une loss combinée qui accomplit simultanément deux actions :

  1. Maximiser la vraisemblance de la réponse choisie (apprendre la tâche).
  2. Pénaliser la réponse rejetée avec un terme d’odds ratio (apprendre les préférences).

Hyperparamètres à connaître :

from trl import ORPOConfig

config = ORPOConfig(
    learning_rate=8e-6,  # Very low, as recommended by the ORPO paper
    beta=0.1,            # Controls strength of preference penalty
    # ... other params
)
  • Learning rate : le papier utilisait de faibles valeurs dans ses expériences ; ajustez-le à votre modèle, votre batch et vos données plutôt que de reprendre une valeur unique comme règle.
  • Beta : contrôle le poids du terme de préférence par rapport au terme SFT.

Le compromis :

  • Une seule étape d’entraînement au lieu de deux.
  • Aucun reward model.
  • Aucun forward pass du modèle de référence.
  • Un run couplé : si l’apprentissage de la tâche ou le comportement de préférence régresse, il n’existe pas de checkpoint SFT intermédiaire issu du même pipeline à inspecter.

Choisissez selon les données et la conception de l’évaluation :

  • Utilisez DPO lorsque vous disposez déjà d’un checkpoint SFT satisfaisant et que vous voulez mener une expérience de préférence offline plus simple.
  • Testez ORPO lorsqu’un objectif en une étape, sans modèle de référence, correspond à vos données et à vos contraintes opérationnelles.
  • Utilisez le RLHF basé sur PPO lorsque l’échantillonnage online face à une récompense apprise explicite fait partie des exigences et que vous pouvez surveiller l’exploitation de la récompense.

Aucune de ces méthodes n’est un choix par défaut pour toutes les tâches. Conservez un baseline SFT seul et publiez à la fois les métriques de la tâche et les métriques de préférence.


Frameworks de fine-tuning

Les frameworks se recouvrent et évoluent rapidement. Choisissez selon le chemin d’exécution que vous devez prendre en charge, verrouillez les versions et conservez une configuration d’entraînement suffisamment portable pour reproduire l’expérience hors d’un notebook.

Unsloth — vitesse et efficacité mémoire

Unsloth s’intègre à Hugging Face trl et transformers et fournit des kernels optimisés, du checkpointing et des chemins de fine-tuning quantifiés pour les modèles pris en charge.

  • Kernels GPU Triton personnalisés pour l’attention, RoPE et la cross-entropy, qui évitent la surcharge de PyTorch.
  • Backpropagation efficace en mémoire, qui recalcule les activations pendant le backward pass au lieu de les conserver en mémoire.
  • Opérations fusionnées regroupant plusieurs étapes (layer norm + linear, et opérations similaires) en un seul appel GPU.
  • Quantization 4 bits intégrée directement au chemin QLoRA, avec une déquantization optimisée.

[!IMPORTANT] L’ordre des imports est important Suivez l’ordre des imports de l’exemple Unsloth correspondant à la version que vous avez verrouillée. Unsloth applique des patches lors de l’import ; l’importer avant trl et transformers évite des optimisations manquantes ou des erreurs liées à la version.

# Correct order
from unsloth import FastLanguageModel  # Must be first!
from trl import SFTTrainer
from transformers import TrainingArguments

# Avoid this order with Unsloth's patched path
from trl import SFTTrainer
from unsloth import FastLanguageModel

Idéal pour : l’entraînement sur un seul GPU, le prototypage, les notebooks Colab et toute personne attentive à sa facture GPU.

Les chiffres publiés de vitesse et de mémoire varient selon le modèle, la longueur des séquences, le batch, la précision et le matériel. Mesurez les tokens par seconde et la mémoire maximale sur votre propre run au lieu de considérer un ratio annoncé comme une propriété intrinsèque du framework.

Axolotl — entraînement piloté par la configuration

# config.yaml - no code required
base_model: meta-llama/Meta-Llama-3-8B
adapter: qlora
lora_r: 32
lora_alpha: 16
datasets:
    - path: data/my_data.jsonl
      type: alpaca
sample_packing: true

Exécutez avec : accelerate launch -m axolotl.cli.train config.yaml

Idéal pour : des runs déclaratifs et reproductibles, ainsi que des options intégrées de lancement pour l’entraînement distribué. La configuration peut être relue, versionnée et réutilisée pour des runs locaux ou distribués.

Comparaison des frameworks

OutilPertinent lorsqueÀ vérifier avant de s’engager
UnslothVous voulez un chemin optimisé pour un modèle pris en charge, avec des exemples concisMatrice modèle, GPU, quantization et support distribué
AxolotlVous voulez des configurations déclaratives et des recettes distribuées intégréesSchéma exact de configuration et launcher de la release verrouillée
TRLVous voulez un accès direct aux trainers SFT et de préférence de Hugging FaceFormat du dataset, chat template, loss masking et intégration PEFT
TorchtuneVous voulez des recettes et composants natifs PyTorchCouverture des recettes de modèles et compatibilité d’export

Démonstration pratique : fine-tuning avec Unsloth

Voici un extrait représentatif d’entraînement issu de mon dépôt unsloth-finetune-demo. La démonstration effectue le fine-tuning de Nemotron-Nano pour le function calling. Avant cet extrait, le src/unsloth_demo/data.py de la démonstration charge et formate le dataset, puis son chemin d’entraînement crée les objets versionnés train_dataset et eval_dataset.

Training PipelineTraining Pipeline

Démarrage rapide

# Clone and setup
git clone https://github.com/slavadubrov/unsloth-finetune-demo.git
cd unsloth-finetune-demo

# Install with uv (recommended)
uv sync

# Run fine-tuning (quick test)
uv run finetune --max-samples 1000

Configuration

Les éléments intéressants se trouvent dans config.py :

# Model & Dataset
MODEL_NAME = "nvidia/Llama-3.1-Nemotron-Nano-4B-v1.1"  # 4B params, 128K context
DATASET_NAME = "glaiveai/glaive-function-calling-v2"   # 113K examples

# LoRA Configuration
LORA_R = 16        # Adapter capacity; tune against held-out results
LORA_ALPHA = 32    # Update scaling; alpha/r is the classic LoRA scale
MAX_SEQ_LENGTH = 4096

# Candidate modules for this Llama-family model
LORA_TARGET_MODULES = [
    "q_proj", "k_proj", "v_proj", "o_proj",
    "gate_proj", "up_proj", "down_proj",
]

[!NOTE] Le ratio alpha/rank alpha/r met à l’échelle la mise à jour LoRA classique. alpha = 2r est une heuristique de départ courante dans certaines documentations d’outils, pas une garantie de stabilité. Ne faites varier le rank, l’alpha, le learning rate et les modules cibles qu’une fois les données et le baseline fixés.

Code d’entraînement principal

from unsloth import FastLanguageModel
from trl import SFTConfig, SFTTrainer

# Load model with 4-bit quantization
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name="nvidia/Llama-3.1-Nemotron-Nano-4B-v1.1",
    max_seq_length=4096,
    load_in_4bit=True,
)

# Add LoRA adapters
model = FastLanguageModel.get_peft_model(
    model,
    r=16,
    lora_alpha=32,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
                    "gate_proj", "up_proj", "down_proj"],
    use_gradient_checkpointing="unsloth",  # Lower activation memory; extra compute
)

# The preceding data step must create these versioned dataset objects.
# Each row has the chat messages and tool schemas expected by current TRL.

# Train with the current TRL configuration surface.
trainer = SFTTrainer(
    model=model,
    processing_class=tokenizer,
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
    args=SFTConfig(
        output_dir="outputs/nemotron-function-calling",
        max_length=4096,
        packing=True,
        per_device_train_batch_size=2,
        gradient_accumulation_steps=4,
        learning_rate=2e-4,
        num_train_epochs=3,
        bf16=True,
    ),
)
trainer.train()

Fine-tuning avec Axolotl

[!NOTE] Démonstration à venir Je travaille sur une démonstration pratique d’Axolotl. En attendant, le Accelerate n-D Parallelism Guide de Hugging Face constitue une bonne référence pour les stratégies d’entraînement multi-GPU.

Pour les configurations pilotées par la configuration et les setups distribués, Axolotl rend le workflow reproductible :

# axolotl_config.yaml
base_model: meta-llama/Meta-Llama-3-8B
model_type: LlamaForCausalLM

# QLoRA configuration
load_in_4bit: true
adapter: qlora
lora_r: 32
lora_alpha: 16
lora_dropout: 0.05
lora_target_modules:
    - q_proj
    - k_proj
    - v_proj
    - o_proj
    - gate_proj
    - up_proj
    - down_proj

# Dataset
datasets:
    - path: data/training_data.jsonl
      type: alpaca

# Training settings
sequence_len: 4096
sample_packing: true # Benchmark with your length distribution
micro_batch_size: 2
gradient_accumulation_steps: 4
learning_rate: 0.0002
num_epochs: 3

# Current Axolotl key; verify support on the pinned release
bf16: true
attn_implementation: flash_attention_2

Lancez l’entraînement :

axolotl train axolotl_config.yaml

Étape 5 : évaluation

Figez le contrat d’évaluation avant le premier run. Au minimum, comparez le checkpoint adapté à la base exacte, non adaptée, avec le même prompt, les mêmes paramètres de decoding et le même environnement d’outils. Ne publiez les métriques agrégées de qualité qu’après avoir examiné les sous-ensembles d’échecs que le projet devait améliorer.

Suivez quatre groupes :

  1. Tâche cible : exact match, succès d’exécution, grille d’évaluation humaine ou autre résultat directement lié au cas d’usage.
  2. Régressions : capacités générales et sous-ensembles de tâches précédemment pris en charge que l’adaptation peut dégrader.
  3. Sécurité et politiques : refus, fuite de données, prompt injection ou contraintes spécifiques au domaine.
  4. Opérations : latence, débit, mémoire, taille de l’artefact et coût dans la configuration de serving cible.

Benchmarks automatisés

Utilisez lm-evaluation-harness pour les tâches standardisées pertinentes, mais pas comme substitut à l’évaluation produit :

lm_eval --model hf \
    --model_args pretrained=./outputs/merged-model \
    --tasks hellaswag,arc_easy,mmlu \
    --batch_size 8

LLM-as-judge

Pour évaluer une qualité subjective, un modèle plus grand peut contribuer à la notation, mais calibrez-le sur des exemples évalués par des humains et masquez l’identité du candidat :

judge_prompt = """
Rate this response from 1-5 on:
- Relevance
- Accuracy
- Formatting

Response: {model_output}
Expected: {ground_truth}
"""

Évaluation spécifique au domaine

Mettez de côté de vrais exemples par source, utilisateur, document ou période afin d’empêcher les quasi-doublons de fuir entre les splits. Pour le function calling, validez la trajectoire complète : sélection de l’outil, arguments, résultat d’exécution, récupération après erreur et réponse finale. Publiez des intervalles de confiance ou des comptes de victoires/défaites par paire lorsque l’échantillon est réduit, et examinez chaque régression dans un sous-ensemble critique.


Étape 6 : déploiement et formats de sortie

Choisissez l’artefact selon le moteur de serving et le plan de rollback, pas uniquement selon la taille des fichiers :

Output FormatsOutput Formats

1. Adapter LoRA

uv run finetune  # Saves ~100-500MB adapter
  • Taille : proportionnelle aux modules ciblés, au rank, aux couches et au dtype ; souvent bien plus petite que la base.
  • Idéal pour : le développement, les adapters versionnés par tâche et les moteurs prenant directement LoRA en charge.
  • Bonus : vous pouvez remplacer les adapters sans retélécharger le modèle de base.

2. Modèle fusionné

uv run finetune --merge  # Creates a standalone full model
  • Taille : approximativement celle du checkpoint complet de base dans la précision de sortie choisie.
  • Idéal pour : les moteurs ou chemins de distribution qui ne prennent pas en charge l’adapter séparément.
  • Compromis : artefact plus volumineux et déploiement plus lent ; chargement d’un modèle unique plus simple.

3. Format GGUF

uv run finetune --gguf q4_k_m  # Creates ~2-4GB quantized model
  • Taille : dépend du modèle ; environ celle de poids en quatre bits plus les métadonnées pour les variantes Q4.
  • Idéal pour : l’inférence CPU, Ollama, llama.cpp et le déploiement en périphérie.
  • Options : q4_k_m (plus petit), q5_k_m (meilleure fidélité des poids), q8_0 (plus volumineux et plus fidèle). Mesurez l’impact sur la tâche après conversion.

Étape 7 : serving et monitoring

Avec vLLM

# Serve the base and expose a PEFT adapter as a model name. This parser and
# template pair is for a Llama 3.1-compatible function-calling adapter.
vllm serve nvidia/Llama-3.1-Nemotron-Nano-4B-v1.1 \
    --enable-lora \
    --lora-modules function-calling=./outputs/adapter \
    --enable-auto-tool-choice \
    --tool-call-parser llama3_json \
    --chat-template examples/tool_chat_template_llama3.1_json.jinja \
    --host 0.0.0.0 \
    --port 8000 \
    --max-model-len 4096

Interrogez l’API compatible OpenAI :

from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="dummy")
response = client.chat.completions.create(
    model="function-calling",
    messages=[{"role": "user", "content": "Book a flight to Tokyo"}],
    tools=[
        {
            "type": "function",
            "function": {
                "name": "book_flight",
                "description": "Book a flight to a city.",
                "strict": True,
                "parameters": {
                    "type": "object",
                    "properties": {
                        "destination": {"type": "string"},
                    },
                    "required": ["destination"],
                    "additionalProperties": False,
                },
            },
        }
    ],
    tool_choice="auto",
)

Le guide du tool calling de vLLM requiert le choix automatique des outils et un parser adapté au modèle ; utilisez le chat template compatible du modèle lorsque la configuration de son tokenizer n’en fournit pas. Avec tool_choice="auto", les arguments contraints nécessitent également strict: true sur au moins une fonction (ainsi que l’activation du strict-tool-calling de vLLM, activé par défaut) ; utilisez un schéma parameters compatible avec le mode strict. Sans cette option, vLLM extrait les calls depuis le texte brut ; les arguments peuvent donc être malformés ou enfreindre le schéma.

Avec Ollama (local)

# Create Modelfile
echo 'FROM ./outputs/unsloth-nemotron-function-calling-gguf/model-q4_k_m.gguf' > Modelfile

# Import to Ollama
ollama create my-function-model -f Modelfile

# Run
ollama run my-function-model

Avec llama.cpp (CPU)

./llama-cli -m ./outputs/model-q4_k_m.gguf \
    -p "What's the weather in Tokyo?" \
    --ctx-size 4096

Monitorer le modèle mis en production

Le cycle de vie ne s’arrête pas lorsque la loss d’entraînement est saine. Enregistrez la révision du modèle de base, le tokenizer et le chat template, le hash de l’adapter, la version du dataset, la configuration d’entraînement et le rapport d’évaluation comme une seule unité de release. En production, surveillez le succès des tâches, les sorties invalides, les violations de politiques, la latence et la dérive des entrées selon les mêmes sous-ensembles qu’en offline. Conservez l’ancien artefact chargeable et définissez un seuil de rollback avant le lancement.


Points clés à retenir

  1. N’effectuez un fine-tuning qu’après qu’un baseline non adapté et une taxonomie des échecs ont montré que l’adaptation des poids répond au problème.
  2. La retrieval gère les éléments probants qui évoluent ; le constrained decoding gère la syntaxe ; aucun des deux n’est remplacé par le SFT.
  3. LoRA réduit les états entraînables. QLoRA compresse en plus les poids de base gelés. N’attribuez pas à LoRA les chiffres de mémoire de QLoRA.
  4. La couverture des données, l’intégrité des splits, la provenance et le loss masking comptent davantage que la copie d’une configuration d’optimizer à la mode.
  5. DPO, ORPO et le RLHF basé sur PPO sont des conceptions expérimentales différentes, et non les niveaux d’une échelle de qualité avec un choix universel par défaut.
  6. Évaluez le comportement cible, les régressions, la sécurité et les aspects opérationnels par rapport au même modèle de base.
  7. Choisissez une sortie sous forme d’adapter, de modèle fusionné ou de GGUF à partir des exigences de serving et de rollback, avant l’entraînement.

Références

Articles et travaux de recherche

Outils de traitement des données

Constrained decoding

  • xgrammar — constrained decoding avec FSMs
  • outlines — structured generation pour les LLMs

Frameworks d’entraînement

  • Unsloth — framework de fine-tuning optimisé
  • Axolotl — entraînement piloté par la configuration et launchers distribués
  • TRL — bibliothèque Hugging Face pour le SFT et l’entraînement par préférences
  • Torchtune — bibliothèque de fine-tuning native PyTorch

Inférence et déploiement

  • vLLM LoRA adapters — servir un ou plusieurs adapters avec le modèle de base
  • vLLM tool calling — faire correspondre le choix automatique des outils, le parser, le chat template et le schéma de requête au modèle
  • Ollama — runtime local pour LLM sur Mac/Windows/Linux
  • llama.cpp — inférence CPU/GPU avec le format GGUF

Évaluation

Guides et ressources