AvancéLLM
28 min de lecture22 vues

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 ?

SituationSolutionPourquoi
Tâche simple, peu de donnéesPrompting (few-shot)Pas besoin d''entraîner
Style/ton spécifiqueFine-tuningLe prompt ne suffit pas
Domaine très spécialiséFine-tuningLe modèle de base ne connaît pas
Données confidentiellesFine-tuning localLes données restent privées
Latence critiqueFine-tuning petit modèlePlus 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

FormatCréateurAvantagesUtilisation
GGUFllama.cppCPU + GPU, très répanduOllama, LM Studio
AWQMITRapide sur GPU, bonne qualitévLLM, TGI
GPTQIST-DASLabPionnier, large supportHuggingFace, vLLM
BnB (4-bit)HuggingFaceIntégré à transformersFine-tuning (QLoRA)

Niveaux de quantification

QuantificationTaille (7B)QualitéVRAM nécessaire
fp32 (original)28 Go100%28+ Go
fp1614 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 ?

BesoinSolutionCoût
Prototype rapideAPI (OpenRouter)~0.001€/requête
Production haute qualitéAPI GPT-4/Claude~0.01€/requête
Confidentialité, volume moyenOllama + Llama 3 (local)Gratuit (GPU requis)
Tâche spécialiséeFine-tuning QLoRAGPU pendant quelques heures
Production haute performancevLLM + 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.