Introduction
Les grands modĂšles de langage (LLM) comme GPT-4, Claude ou Gemini sont impressionnants, mais leur taille et leur coĂ»t les rendent difficiles Ă utiliser dans des contextes spĂ©cialisĂ©s. Heureusement, il existe une alternative puissante et Ă©conomique : le fine-tuning d’un petit LLM open-source avec LoRA (Low-Rank Adaptation).
Dans ce tutoriel, nous allons voir comment adapter un modĂšle comme Mistral 7B ou Llama 3.2 (3B) Ă vos propres donnĂ©es, en utilisant Hugging Face et la bibliothĂšque PEFT. L’objectif : obtenir un modĂšle spĂ©cialisĂ© qui comprend votre domaine, sans nĂ©cessiter de cluster GPU coĂ»teux.
Prérequis
- Python 3.10+ installé
- Un environnement virtuel (venv ou conda)
- Un GPU avec au moins 8 Go de VRAM (ou Google Colab)
- pip installé à jour
1. Mise en place de l’environnement
Commençons par installer les dépendances nécessaires :
pip install torch transformers datasets accelerate peft trl bitsandbytesConnectez-vous à Hugging Face pour télécharger les modÚles :
huggingface-cli login
# Entrez votre token d'accĂšs2. Choix du modĂšle de base
Pour un fine-tuning efficace avec des ressources limitées, privilégiez des modÚles entre 1B et 8B paramÚtres. Voici les meilleurs choix actuels :
- Mistral 7B â excellent rapport qualitĂ©/performance
- Llama 3.2 3B â lĂ©ger et performant
- Phi-3 Mini (3.8B) â idĂ©al pour les tĂąches de raisonnement
- Gemma 2 2B/9B â bonne alternative Google
Dans cet article, nous utiliserons Mistral 7B via le checkpoint mistralai/Mistral-7B-v0.1.
3. Préparation du jeu de données
Nous allons créer un jeu de données au format instruct. Chaque entrée contient un prompt et une réponse attendue :
from datasets import Dataset
data = [
{
"instruction": "Qu'est-ce que le fine-tuning LoRA ?",
"output": "Le fine-tuning LoRA (Low-Rank Adaptation) est une technique qui consiste à adapter un modÚle pré-entraßné en entraßnant uniquement des matrices de faible rang, réduisant drastiquement le nombre de paramÚtres à ajuster."
},
{
"instruction": "Explique le concept d'attention en NLP",
"output": "Le mécanisme d'attention permet à un modÚle de pondérer l'importance relative de chaque mot d'une séquence, capturant ainsi les dépendances à longue portée."
}
]
dataset = Dataset.from_list(data)Pour un usage réel, vous pouvez charger un fichier JSON ou CSV :
from datasets import load_dataset
dataset = load_dataset("json", data_files="mes_donnees.json")["train"]Structure attendue du JSON :
[
{"instruction": "...", "output": "..."},
{"instruction": "...", "output": "..."}
]4. Tokenization et formatage
Nous devons formater les données dans le style attendu par le modÚle :
def format_instruction(example):
return {
"text": f"### Instruction:\n{example['instruction']}\n\n### Réponse:\n{example['output']}"
}
dataset = dataset.map(format_instruction)
def tokenize_function(examples):
return tokenizer(
examples["text"],
truncation=True,
padding="max_length",
max_length=512
)
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1")
tokenizer.pad_token = tokenizer.eos_token
tokenized_dataset = dataset.map(tokenize_function, batched=True)5. Configuration de LoRA avec PEFT
Voici la configuration LoRA que nous allons utiliser :
from peft import LoraConfig, get_peft_model
lora_config = LoraConfig(
r=8, # Rang de la matrice
lora_alpha=32, # Facteur d'échelle
target_modules=["q_proj", "v_proj"], # Couches Ă adapter
lora_dropout=0.05, # Dropout pour régularisation
bias="none",
task_type="CAUSAL_LM"
)Explication des paramĂštres :
r(rang) : plus il est Ă©levĂ©, plus le modĂšle peut apprendre, mais plus il consomme de mĂ©moire. 8-16 est un bon compromis.lora_alpha: facteur d’Ă©chelle. Une valeur 2x supĂ©rieure Ă r est courante.target_modules: les couches d’attention Ă adapter. Pour les modĂšles Llama/Mistral,q_projetv_projsuffisent souvent.
6. EntraĂźnement avec SFTTrainer
Utilisons le SFTTrainer de la bibliothÚque TRL pour un fine-tuning supervisé optimal :
from trl import SFTTrainer
from transformers import AutoModelForCausalLM, TrainingArguments
import torch
model = AutoModelForCausalLM.from_pretrained(
"mistralai/Mistral-7B-v0.1",
load_in_4bit=True, # Quantification 4-bit pour économiser la mémoire
torch_dtype=torch.bfloat16,
device_map="auto"
)
training_args = TrainingArguments(
output_dir="./mistral-lora-finetuned",
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
num_train_epochs=3,
learning_rate=2e-4,
fp16=False,
bf16=True,
logging_steps=10,
save_strategy="epoch",
report_to="none"
)
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=tokenized_dataset,
peft_config=lora_config,
tokenizer=tokenizer,
max_seq_length=512
)
trainer.train()Conseil mémoire : avec load_in_4bit=True et LoRA (rang 8), ce fine-tuning consomme environ 6-8 Go de VRAM pour un modÚle 7B, ce qui tient sur une RTX 3080 ou un T4 (Google Colab).
7. Sauvegarde et chargement du modÚle adapté
# Sauvegarder les poids LoRA
trainer.model.save_pretrained("./mon-modele-lora")
tokenizer.save_pretrained("./mon-modele-lora")
# Charger le modÚle adapté
from peft import PeftModel
base_model = AutoModelForCausalLM.from_pretrained(
"mistralai/Mistral-7B-v0.1",
load_in_4bit=True,
device_map="auto"
)
model = PeftModel.from_pretrained(base_model, "./mon-modele-lora")8. Inférence : tester le modÚle fine-tuné
def generate_response(prompt):
inputs = tokenizer(
f"### Instruction:\n{prompt}\n\n### Réponse:\n",
return_tensors="pt"
).to("cuda")
outputs = model.generate(
**inputs,
max_new_tokens=256,
temperature=0.7,
do_sample=True
)
return tokenizer.decode(outputs[0], skip_special_tokens=True)
# Test
print(generate_response("Comment déployer un modÚle fine-tuné en production ?"))9. Fusion des poids LoRA (optionnel)
Pour déployer sans dépendance PEFT, vous pouvez fusionner les poids LoRA dans le modÚle de base :
merged_model = model.merge_and_unload()
merged_model.save_pretrained("./mon-modele-merged")
tokenizer.save_pretrained("./mon-modele-merged")Le modĂšle fusionnĂ© peut ĂȘtre chargĂ© comme un modĂšle standard Hugging Face, sans avoir besoin d’importer PEFT :
model = AutoModelForCausalLM.from_pretrained("./mon-modele-merged")10. Bonnes pratiques et conseils
- Qualité des données : 500 à 2000 exemples bien rédigés valent mieux que 10 000 exemples bruités.
- Sur-apprentissage : Si la loss d’entraĂźnement continue de baisser mais que les performances en validation stagnent, rĂ©duisez le nombre d’Ă©poques (1-3 suffisent souvent).
- Template de prompt : Utilisez le mĂȘme format de prompt lors de l’infĂ©rence que celui utilisĂ© pour l’entraĂźnement.
- Mixed precision : Activez bf16 (si supporté) ou fp16 pour réduire la mémoire GPU.
- Ăvaluation : Gardez 10-20% de vos donnĂ©es pour la validation croisĂ©e.
Conclusion
Le fine-tuning d’un petit LLM avec LoRA et Hugging Face est accessible Ă tout dĂ©veloppeur possĂ©dant un GPU grand public. Cette approche vous permet de crĂ©er des modĂšles spĂ©cialisĂ©s pour vos cas d’usage â support client, documentation technique, gĂ©nĂ©ration de code interne â sans dĂ©pendre d’API externes coĂ»teuses.
Les techniques présentées ici (quantification 4-bit, LoRA, SFTTrainer) forment la base de nombreux pipelines de production. Avec un budget inférieur à 10⏠de crédits Colab, vous pouvez obtenir un modÚle adapté à vos données spécifiques.
Prochaine étape : explorez DPO (Direct Preference Optimization) pour aligner votre modÚle sur des préférences humaines, ou utilisez Ollama pour déployer votre modÚle fine-tuné en local.