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.
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-Tuning | RAG (Retrieval-Augmented Generation) |
|---|---|---|
| Fonction principale | Modifie les poids internes pour enseigner des compétences, des styles ou des comportements | Fournit 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 connaissances | Modifie le comportement statistique des poids ; la restitution exacte n’est pas garantie | Récupère des enregistrements ou des passages qui peuvent être mis à jour et cités |
| Fréquence des mises à jour | Nécessite un nouvel entraînement pour chaque mise à jour | Mise à 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.
| Aspect | Fine-Tuning | Prompt 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 release | Change avec le prompt |
| Format/style | Peut rendre un comportement récurrent plus probable | Souvent suffisant pour le style et les formats simples |
| Latence | Peut raccourcir les instructions répétées | Dépend de la longueur du prompt et du caching du fournisseur |
| Idéal pour | Comportements complexes, distillation, réduction des coûts à grande échelle | Ité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.
| Aspect | Constrained Decoding | Fine-Tuning |
|---|---|---|
| Mise en place | Immédiate — définir le schéma, déployer | Nécessite curation des données, calcul GPU et itérations |
| Garantie | Syntaxe valide pour la contrainte prise en charge | Comportement appris ; le respect du schéma peut varier |
| Flexibilité | Modification du schéma à tout moment sans réentraînement | Figé après l’entraînement |
| Latence | Léger surcoût (le modèle peut « lutter » contre le schéma) | Plus faible (le modèle produit naturellement le format) |
| Idéal pour | JSON, choix, grammaires, syntaxe des tool calls | Comportement récurrent absent du modèle de base |
Un ordre pratique :
- Commencez par le prompting et des exemples few-shot pour le formatage de base.
- Ajoutez du constrained decoding (
xgrammarououtlines) lorsque la syntaxe est incohérente. - 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ème | Premier mécanisme à tester | Pourquoi ? |
|---|---|---|
| Connaissances manquantes | RAG | Les modèles hallucinent des faits. La retrieval fournit un contexte fondé et à jour |
| Format/ton incorrect | Prompt Engineering | Les modèles modernes suivent bien les consignes de style avec des exemples few-shot |
| Syntaxe de sortie invalide | Constrained decoding | Impose un schéma ou une grammaire pris en charge pendant la génération |
| Échec répété sur une tâche | Fine-tuning (SFT) | Apprend à partir d’exemples entrée/sortie soigneusement sélectionnés |
| Désaccord de préférence par paire | Preference optimization | Utilise des exemples chosen/rejected une fois le comportement de la tâche mesurable |
| Latence/coût à grande échelle | Distillation (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èle | Quantization | Aucun 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.
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
| Aspect | Continued Pre-training | SFT | Instruction Tuning |
|---|---|---|---|
| Données | Texte brut | Paires (entrée, sortie) | Paires (instruction, réponse) |
| Labels | Aucun (non supervisé) | Spécifiques à la tâche | Tâches diverses |
| Objectif | Connaissances du domaine | Comportement spécifique à la tâche | Suivre n’importe quelle instruction |
| Volume de données | Généralement le corpus le plus important | Déterminé par la couverture de la tâche et la diversité des erreurs | Gé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.
Chaque étape s’appuie sur la précédente :
- Préparation des données — Définir l’unité d’évaluation, répartir les données, puis les nettoyer et les formater
- Sélection du modèle — Choisir le bon modèle de base et charger les poids
- Configuration de l’entraînement — Configurer le matériel, les hyperparamètres et la stratégie d’optimisation
- Fine-tuning — Exécuter un entraînement SFT, DPO ou ORPO
- Évaluation — Mesurer les performances et valider la qualité
- Déploiement — Exporter et servir le modèle
- 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.
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.176distribué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émoire | Full fine-tuning | LoRA | QLoRA |
|---|---|---|---|
| Poids de base | Précision d’entraînement | Gelés, généralement BF16/FP16 | Gelés, généralement en NF4 4 bits |
| Gradients | Tous les poids entraînables | Poids des adapters | Poids des adapters |
| États de l’optimizer | Tous les poids entraînables | Poids des adapters | Poids des adapters |
| Activations | Dépend de la taille du batch et de la longueur des séquences dans toutes les méthodes | Même dépendance | Mê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 paramètres, les poids seuls nécessitent approximativement octets en BF16/FP16 ou 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 :
- Choisissez la séquence la plus longue et le micro-batch que vous devez prendre en charge.
- Estimez les poids et les états entraînables, en gardant une marge pour les activations et les kernels.
- Exécutez une étape forward/backward à longueur maximale.
- Enregistrez la mémoire maximale allouée et réservée.
- 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.
Pour une matrice gelée , LoRA apprend :
La couche adaptée est :
L’adapter possède paramètres entraînables au lieu de 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éthode | Ce qui change | À choisir lorsque |
|---|---|---|
| LoRA | Base gelée et mises à jour entraînables low-rank | Le modèle de base tient confortablement en mémoire et vous voulez de petits artefacts spécifiques à la tâche |
| QLoRA | LoRA avec une base gelée stockée en 4 bits | La mémoire des poids de base est le facteur limitant |
| DoRA | Sépare la magnitude des poids de leur direction mise à jour par LoRA | Un baseline LoRA mesuré laisse un écart de qualité justifiant une complexité supplémentaire |
| Full fine-tuning | Tous les poids du modèle | PEFT 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.
Fonctionnement :
Au lieu de considérer les poids comme une entité unique, DoRA les décompose en deux composantes :
- Magnitude — une valeur entraînable par vecteur de poids.
- Direction — un vecteur normalisé mis à jour par des matrices low-rank.
En notation compacte par colonnes :
où :
m= magnitude (entraînable)- = matrice directionnelle gelée
- = mise à jour directionnelle low-rank apprise
- = 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 :
- Concaténation — combine les paramètres des adapters et augmente le rang effectif. Rapide et simple.
- Combinaison linéaire — somme pondérée des adapters. Offre des paramètres de contrôle.
- 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.
RLHF basé sur PPO
La recette originale était un pipeline en trois étapes :
- SFT — apprendre la tâche.
- Reward model — entraîné sur les préférences humaines (chosen vs rejected).
- 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 :
- Maximiser la vraisemblance de la réponse choisie (apprendre la tâche).
- 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
trlettransformersé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
| Outil | Pertinent lorsque | À vérifier avant de s’engager |
|---|---|---|
| Unsloth | Vous voulez un chemin optimisé pour un modèle pris en charge, avec des exemples concis | Matrice modèle, GPU, quantization et support distribué |
| Axolotl | Vous voulez des configurations déclaratives et des recettes distribuées intégrées | Schéma exact de configuration et launcher de la release verrouillée |
| TRL | Vous voulez un accès direct aux trainers SFT et de préférence de Hugging Face | Format du dataset, chat template, loss masking et intégration PEFT |
| Torchtune | Vous voulez des recettes et composants natifs PyTorch | Couverture 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.
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/rmet à l’échelle la mise à jour LoRA classique.alpha = 2rest 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 :
- Tâche cible : exact match, succès d’exécution, grille d’évaluation humaine ou autre résultat directement lié au cas d’usage.
- 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.
- Sécurité et politiques : refus, fuite de données, prompt injection ou contraintes spécifiques au domaine.
- 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 :
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
- 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.
- 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.
- 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.
- 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.
- 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.
- Évaluez le comportement cible, les régressions, la sécurité et les aspects opérationnels par rapport au même modèle de base.
- 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
- LoRA: Low-Rank Adaptation of Large Language Models
- QLoRA: Efficient Finetuning of Quantized LLMs
- DoRA: Weight-Decomposed Low-Rank Adaptation
- DPO: Direct Preference Optimization
- ORPO: Odds Ratio Preference Optimization
- PPO: Proximal Policy Optimization Algorithms — OpenAI, 2017
Outils de traitement des données
- DataTrove — traitement des données Hugging Face à grande échelle
- Distilabel — génération de données synthétiques (Argilla)
- Trafilatura — extraction et crawling de texte web
- fastText language identification — modèles
lid.176distribués pour 176 langues - Microsoft Presidio — détection et anonymisation des PII
- scrubadub — bibliothèque Python de suppression des PII
Constrained decoding
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
- lm-evaluation-harness — benchmark standardisé de LLMs par EleutherAI
Guides et ressources
- Demo Repository — exemple pratique de fine-tuning
- LLM Fine-Tuning. Theoretical Intuition and Practical Implementation — notebook de recherche NotebookLM
- Accelerate n-D Parallelism Guide — stratégies d’entraînement multi-GPU de Hugging Face