Fine-Tuning & Adaptation
Adapter un LLM via adapters/LoRA/QLoRA, instruction tuning (SFT) ou préférences (RLHF/RLAIF) — avec données maîtrisées, évaluation rigoureuse et déploiement optimisé.
Adapters / LoRA / QLoRA Instruction Tuning (SFT) RLHF / RLAIF (DPO/ORPO) Données & pipeline Évaluation avant/après Serving (vLLM / TensorRT-LLM)
1) Adapters / LoRA / QLoRA
Concepts
- Adapters : petites couches insérées → trempe rapide, peu de paramètres.
- LoRA : décomposer ΔW en basses-rangs (A·B), gèle W, apprend A/B.
- QLoRA : quantif. 4-bit (NF4) + LoRA sur activations → VRAM ÷(4-6).
Use-cases
- Style/ton, terminologie métier, extraction structurée, formats stricts.
Paramètres clés
r(rank),alpha(échelle),target_modules(q_proj/k_proj/...)- BNB 4-bit :
nf4, double quant,llm_int8_threshold.
KPI entraînement
- Loss/epoch stable, overfit (train≪dev) à éviter.
- Temps/epoch, VRAM, tokens/s.
Anti-patterns
- Rank trop élevé → sur-ajustement/coût.
- Quantization agressive sans calibration.
- Adapter sur trop de modules → instabilité.
2) Instruction Tuning (SFT)
Principe
- Affiner sur paires
{instruction, input?, output}de haute qualité. - SFT = supervision directe (formatage/ton JSON strict, consignes).
Données
- JSONL : un item/ligne ; équilibre tâches/domaine.
- RAG-aware : inclure contexte + sortie attendue.
Qualité des consignes
- Claires, atomiques, critères d’acceptation, contre-exemples.
- Règles de sécurité : “pas de PII”, “sources obligatoires”.
Étiquetage
- Relecture par 2 réviseurs ; guidelines ; inter-annotator agreement.
Sorties strictes
{"instruction":"Résume en JSON","input":"...","output":{"title":"...","bullets":["..."]}}Mesurer JSON validity (parseable %) + exact-match champs.
3) RLHF / RLAIF (préférences)
Concepts
- RLHF : feedback humain (paires préférées) → ajuste la politique.
- RLAIF : feedback généré/filtré par modèle (coût réduit).
Algorithmes
- PPO (classique), DPO, ORPO (stables/rapides en pratique).
Use-cases
- Ton/politesse, sécurité, refus appropriés, helpfulness vs harmlessness.
Données
- Paires (A préféré à B) ou récompense notée (0..1).
Risques
- Sur-conformité (réponses trop prudentes), drift comportemental.
- Biais annotateur ; besoin de calibration/contrôle.
4) Données & pipeline
Sourcing
- Docs internes (FAQ/playbooks/style guides), tickets, code, emails.
- Logs chat (après anonymisation/consentement).
- Données publiques conformes licences.
Curation
- Dédup, nettoyage HTML/PDF, anonymisation PII.
- Contrôles : schémas, longueurs, toxicité, “golden” tests.
Structuration
- SFT : JSONL
{instruction,input?,output}. - RAG-aware : contexte + sortie attendue.
- RL : paires comparatives (A≻B) ou scores.
Splits
- Train/Dev/Test stratifiés par tâche/domaine.
- Hold-out “hors domaine” (généralisation).
Schémas exemples
// SFT
{"instruction":"Extraire JSON","input":"texte...","output":{"field":"..."}}
// DPO
{"prompt":"...", "chosen":"réponse A", "rejected":"réponse B"}Logguer provenance, licence, version de l’ontologie/prompt.
5) 🧪 Évaluation (avant/après)
Métriques
- Exact match / F1 / Rouge (QA/extraction).
- JSON validity (% parseable), groundedness (avec contexte).
- Safety : toxicité, PII leak, jailbreaks.
- Coûts & latence (tokens, ms, VRAM), Human-Eval 1–5.
Snippet (validation JSON)
ok=0
for y in outputs:
try: json.loads(y); ok+=1
except: pass
json_valid = ok/len(outputs)Exact match (ex.)
em = sum(int(p.strip()==g.strip()) for p,g in pairs)/len(pairs)Expérimentation
- A/B sur jeux gelés ; seed & versions fixées.
- Diff-tests à chaque changement (embeddings/index/prompt).
6) Choix modèles & infra
Bases candidates
- LLaMA-3.x, Mistral-7B/8x7B, Mixtral-8x22B (selon budget).
- Licences & contraintes (usage/commercialisation).
Quantization
- NF4 4-bit (QLoRA) : VRAM 24–48GB suffisent souvent.
- Int8 pour stabilité si 4-bit trop bruité.
Frameworks
- HF Transformers + PEFT, bitsandbytes.
- TRL (PPO/DPO/ORPO), DeepSpeed/FSDP, W&B (suivi).
Serving
- vLLM / TensorRT-LLM, gguf (CPU) si nécessaire.
Deepspeed (ex. config)
{
"train_micro_batch_size_per_gpu": 4,
"gradient_accumulation_steps": 8,
"zero_optimization": {"stage":2},
"bf16": {"enabled": true}
}7) 🧰 Recette — SFT with LoRA (texte → réponse)
from transformers import (AutoModelForCausalLM, AutoTokenizer,
TrainingArguments, DataCollatorForLanguageModeling)
from peft import LoraConfig, get_peft_model
from datasets import load_dataset
from transformers import BitsAndBytesConfig
base = "mistral-7b-instruct"
bnb = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4",
bnb_4bit_use_double_quant=True)
tok = AutoTokenizer.from_pretrained(base, use_fast=True)
model = AutoModelForCausalLM.from_pretrained(base, quantization_config=bnb, device_map="auto")
lora = LoraConfig(r=16, lora_alpha=32, lora_dropout=0.05,
target_modules=["q_proj","v_proj","k_proj","o_proj"], bias="none", task_type="CAUSAL_LM")
model = get_peft_model(model, lora)
ds = load_dataset("json", data_files={"train":"sft_train.jsonl","eval":"sft_dev.jsonl"})
def fmt(x): return tok.apply_chat_template([{"role":"user","content":x["instruction"] + "\n" + (x.get("input") or "")},
{"role":"assistant","content":x["output"]}], tokenize=False)
ds = ds.map(lambda x: {"text": fmt(x)})
collator = DataCollatorForLanguageModeling(tokenizer=tok, mlm=False)
args = TrainingArguments(output_dir="ft-lora", per_device_train_batch_size=1, gradient_accumulation_steps=16,
learning_rate=2e-4, num_train_epochs=2, logging_steps=10, eval_strategy="steps",
save_steps=500, bf16=True)
from transformers import Trainer
trainer = Trainer(model=model, args=args, data_collator=collator,
train_dataset=ds["train"], eval_dataset=ds["eval"])
trainer.train()
model.save_pretrained("ft-lora/checkpoint")⚠️ Vérifier JSON validity, balance des tâches, et contrôler l’overfit (dev loss).
8) 🧰 Recette — DPO / ORPO (préférences)
from trl import DPOTrainer, ORPOTrainer
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments
import datasets
base = "mistral-7b-instruct"
tok = AutoTokenizer.from_pretrained(base)
model = AutoModelForCausalLM.from_pretrained(base, device_map="auto")
data = datasets.load_dataset("json", data_files={"train":"dpo_train.jsonl","eval":"dpo_dev.jsonl"})
# JSONL: {"prompt":"...","chosen":"...","rejected":"..."}
args = TrainingArguments(output_dir="ft-dpo", per_device_train_batch_size=1,
gradient_accumulation_steps=16, learning_rate=5e-6, bf16=True,
num_train_epochs=1, logging_steps=10, save_steps=500, eval_strategy="steps")
trainer = DPOTrainer(model=model, args=args, tokenizer=tok,
beta=0.1, train_dataset=data["train"], eval_dataset=data["eval"])
# ORPO: ORPOTrainer(..., gamma=0.5)
trainer.train()
trainer.save_model("ft-dpo/checkpoint")Mesurer helpfulness/harmlessness, refus appropriés, et surveiller la dérive de style.
9) Déploiement & Serving
vLLM (ex.)
python -m vllm.entrypoints.api_server --model mistral-7b-instruct \
--lora-modules ft-lora/checkpoint --max-num-batched-tokens 16384 \
--tensor-parallel-size 2 --port 8000TensorRT-LLM
- Build engine + plugins LoRA ; profil latence ; batch.
Quantized / gguf (CPU)
- Quantization 4-bit pour CPU déployables (latence ↑ mais coût ↓).
- Adapter fusionné vs chargé dynamiquement.
Observabilité prod
- OpenTelemetry, W&B, budgets coût; canary release.
