Fine-tuning et Modèles Locaux
Personnalisez des LLMs avec LoRA/QLoRA, exécutez des modèles en local avec Ollama et maîtrisez la quantification (GGUF, AWQ).
Pourquoi Fine-tuner un LLM ?
Les modèles comme GPT-4 ou Claude sont excellents en généraliste. Mais pour des tâches spécifiques, un modèle fine-tuné sur vos données peut être :
- Plus précis sur votre domaine (médical, juridique, technique)
- Plus rapide (un petit modèle spécialisé vs un gros généraliste)
- Moins cher (modèle 7B fine-tuné vs API GPT-4)
- Privé (vos données ne quittent jamais votre serveur)
Quand fine-tuner vs quand utiliser le prompting ?
| Situation | Solution | Pourquoi |
|---|---|---|
| Tâche simple, peu de données | Prompting (few-shot) | Pas besoin d''entraîner |
| Style/ton spécifique | Fine-tuning | Le prompt ne suffit pas |
| Domaine très spécialisé | Fine-tuning | Le modèle de base ne connaît pas |
| Données confidentielles | Fine-tuning local | Les données restent privées |
| Latence critique | Fine-tuning petit modèle | Plus rapide qu''un gros modèle |
LoRA : Fine-tuner Sans Tout Réentraîner
Le problème du fine-tuning classique
Fine-tuner tous les paramètres d''un LLM de 7 milliards de paramètres nécessite :
- ~28 Go de VRAM (en fp32)
- Des heures de calcul sur GPU A100
- Un stockage du modèle complet pour chaque version
LoRA (Low-Rank Adaptation)
Au lieu de modifier tous les poids, LoRA gèle le modèle original et ajoute de petites matrices entraînables (adapters) sur certaines couches.
Avantages :
- 99.9% des poids restent gelés → très peu de VRAM
- L''adapter ne fait que quelques Mo (vs des Go pour le modèle complet)
- On peut avoir plusieurs adapters pour différentes tâches sur le même modèle de base
QLoRA : LoRA + Quantification
QLoRA combine LoRA avec la quantification en 4 bits du modèle de base. Résultat : fine-tuner un modèle 7B sur un GPU de 6 Go de VRAM (une RTX 3060).
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from peft import LoraConfig, get_peft_model
from trl import SFTTrainer, SFTConfig
# Configuration de quantification en 4 bits
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype="float16",
bnb_4bit_use_double_quant=True,
)
# Charger le modèle quantifié
model_name = "mistralai/Mistral-7B-v0.3"
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=bnb_config,
device_map="auto"
)
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token
# Configuration LoRA
lora_config = LoraConfig(
r=16, # Rang de la décomposition (plus grand = plus expressif)
lora_alpha=32, # Facteur de scaling
lora_dropout=0.05,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj"], # Couches ciblées
bias="none",
task_type="CAUSAL_LM"
)
# Appliquer LoRA au modèle
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# → trainable params: 4,194,304 || all params: 3,756,513,280 || trainable%: 0.11%
0.11% des paramètres entraînés ! C''est la magie de LoRA : des résultats proches du fine-tuning complet avec une fraction des ressources.
Préparer les Données de Fine-tuning
Format de conversation
Le format standard est une liste de conversations au format JSON Lines :
{"messages": [
{"role": "system", "content": "Tu es un expert en droit français."},
{"role": "user", "content": "Quels sont les délais de préavis pour un CDI ?"},
{"role": "assistant", "content": "Selon l''article L1234-1 du Code du travail, les délais de préavis pour un CDI sont..."}
]}
Créer un dataset d''entraînement
from datasets import Dataset
# Vos données d''entraînement
conversations = [
{
"text": """<s>[INST] Tu es un assistant culinaire expert.
Donne-moi une recette de ratatouille. [/INST]
Voici la recette de la ratatouille provençale :
**Ingrédients (4 personnes) :**
- 2 aubergines
- 3 courgettes
- 2 poivrons
- 4 tomates
- 2 oignons
- Huile d''olive, thym, laurier
**Préparation :**
1. Coupez tous les légumes en dés
2. Faites revenir les oignons dans l''huile d''olive
3. Ajoutez les aubergines et poivrons (5 min)
4. Ajoutez les courgettes et tomates
5. Laissez mijoter 45 min à feu doux
6. Assaisonnez avec thym et laurier</s>"""
},
# ... plus d''exemples (idéalement 100-1000)
]
dataset = Dataset.from_list(conversations)
print(f"Dataset : {len(dataset)} exemples")
Lancer le fine-tuning
training_config = SFTConfig(
output_dir="./mistral-cuisine",
num_train_epochs=3,
per_device_train_batch_size=2,
gradient_accumulation_steps=4,
learning_rate=2e-4,
logging_steps=10,
save_steps=100,
max_seq_length=2048,
)
trainer = SFTTrainer(
model=model,
train_dataset=dataset,
args=training_config,
tokenizer=tokenizer,
)
# Lancer l''entraînement
trainer.train()
# Sauvegarder l''adapter LoRA (quelques Mo)
trainer.model.save_pretrained("./mistral-cuisine-lora")
Qualité > Quantité. 200 exemples de haute qualité valent mieux que 10 000 exemples médiocres. Nettoyez et vérifiez vos données manuellement.
Exécuter des Modèles en Local avec Ollama
Pourquoi du local ?
- Confidentialité : aucune donnée n''est envoyée à un serveur externe
- Coût zéro : pas de facturation par token
- Latence : pas de latence réseau
- Offline : fonctionne sans internet
Installation et premier modèle
# Installer Ollama (macOS/Linux/Windows)
# https://ollama.com
# Télécharger et lancer un modèle
ollama pull llama3.1:8b # Llama 3.1 8B (4.7 Go)
ollama pull mistral:7b # Mistral 7B (4.1 Go)
ollama pull gemma2:9b # Gemma 2 9B (5.5 Go)
# Lancer un chat
ollama run llama3.1:8b
Utiliser Ollama comme API locale
Ollama expose une API compatible OpenAI sur le port 11434 :
from openai import OpenAI
# Client local (aucune clé API nécessaire)
client = OpenAI(
base_url="http://localhost:11434/v1",
api_key="ollama" # Valeur ignorée mais requise
)
response = client.chat.completions.create(
model="llama3.1:8b",
messages=[
{"role": "system", "content": "Tu es un assistant qui répond en français."},
{"role": "user", "content": "Explique les réseaux de neurones en 3 phrases."}
],
temperature=0.5
)
print(response.choices[0].message.content)
Le même code fonctionne avec OpenAI, OpenRouter et Ollama. Il suffit de changer le base_url. C''est la puissance du standard d''API OpenAI.
Charger votre modèle fine-tuné
# Créer un Modelfile
cat > Modelfile << 'EOF'
FROM mistral:7b
ADAPTER ./mistral-cuisine-lora
SYSTEM "Tu es un assistant culinaire expert en cuisine française."
PARAMETER temperature 0.5
PARAMETER top_p 0.9
EOF
# Créer le modèle dans Ollama
ollama create cuisine-expert -f Modelfile
# Le tester
ollama run cuisine-expert
La Quantification : Réduire la Taille des Modèles
Pourquoi quantifier ?
Un modèle de 7B paramètres en fp32 (32 bits par paramètre) pèse 28 Go. En le quantifiant en 4 bits, il ne pèse plus que 4 Go, tout en gardant ~95% de ses performances.
Les formats de quantification
| Format | Créateur | Avantages | Utilisation |
|---|---|---|---|
| GGUF | llama.cpp | CPU + GPU, très répandu | Ollama, LM Studio |
| AWQ | MIT | Rapide sur GPU, bonne qualité | vLLM, TGI |
| GPTQ | IST-DASLab | Pionnier, large support | HuggingFace, vLLM |
| BnB (4-bit) | HuggingFace | Intégré à transformers | Fine-tuning (QLoRA) |
Niveaux de quantification
| Quantification | Taille (7B) | Qualité | VRAM nécessaire |
|---|---|---|---|
| fp32 (original) | 28 Go | 100% | 28+ Go |
| fp16 | 14 Go | ~100% | 14+ Go |
| Q8 (8-bit) | 7 Go | ~99% | 8+ Go |
| Q5 (5-bit) | 5 Go | ~97% | 6+ Go |
| Q4 (4-bit) | 4 Go | ~95% | 5+ Go |
| Q2 (2-bit) | 2 Go | ~85% | 3+ Go |
En dessous de Q4, la qualité se dégrade significativement. Q4 est généralement considéré comme le meilleur compromis taille/qualité.
Comparatif : Quel Setup Choisir ?
| Besoin | Solution | Coût |
|---|---|---|
| Prototype rapide | API (OpenRouter) | ~0.001€/requête |
| Production haute qualité | API GPT-4/Claude | ~0.01€/requête |
| Confidentialité, volume moyen | Ollama + Llama 3 (local) | Gratuit (GPU requis) |
| Tâche spécialisée | Fine-tuning QLoRA | GPU pendant quelques heures |
| Production haute performance | vLLM + modèle quantifié | Serveur GPU dédié |
Exercice : Benchmark Local vs API
import time
# Test avec API (OpenRouter)
api_client = OpenAI(base_url="https://openrouter.ai/api/v1", api_key="sk-or-...")
# Test avec Ollama (local)
local_client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
question = "Quels sont les 3 piliers du développement durable ?"
for name, client_instance, model in [
("API (GPT-4o-mini)", api_client, "openai/gpt-4o-mini"),
("Local (Llama 3.1)", local_client, "llama3.1:8b"),
]:
start = time.time()
response = client_instance.chat.completions.create(
model=model,
messages=[{"role": "user", "content": question}],
temperature=0,
max_tokens=200
)
elapsed = time.time() - start
answer = response.choices[0].message.content
print(f"\n--- {name} ({elapsed:.2f}s) ---")
print(answer[:200])
Ce que vous observerez : Le modèle local a une latence de premier token plus faible (pas de réseau) mais peut être plus lent pour les longues réponses si votre GPU est modeste.
Pour Aller Plus Loin
- Explorez Hugging Face pour trouver des modèles pré-entraînés sur votre domaine
- Testez LM Studio pour une interface graphique de modèles locaux
- Essayez de fine-tuner un modèle sur le dataset Alpaca-French traduit en français
- Pour la production, explorez vLLM pour servir des modèles avec du batching optimisé
Specialiste IA — Master Intelligence Artificielle
Diplome d'un Master en Intelligence Artificielle, je travaille au quotidien sur des projets IA en entreprise. J'ai cree IwanttolearnAI pour rendre l'apprentissage de l'IA accessible a tous, gratuitement.
Continuer a apprendre
Gérer le Context Window et la Mémoire des LLMs
Comprenez les limites de mémoire des LLMs, le phénomène lost-in-the-middle, et maîtrisez les stratégies pour gérer efficacement de longs contextes en production.
Faire Tourner un LLM en Local avec Ollama
Installez et utilisez des LLMs directement sur votre machine avec Ollama : confidentialité totale, coût zéro, et intégration Python en quelques lignes.
Tokenisation : Comment l'IA Lit le Texte
Découvrez comment les LLMs décomposent le texte en tokens, pourquoi le français coûte plus cher que l'anglais, et comment maîtriser vos coûts d'API avec tiktoken.