Avancé
🧠 Fondamentaux
30 XP
0 personnes ont réussi
Pipeline complet de préparation fine-tuning
Tu es développeur IA dans une startup edtech. Ton boss te demande de fine-tuner GPT-4o-mini pour qu'il réponde aux questions des élèves sur Python, dans un style pédagogique bien précis. Tu as un fichier brut avec des paires question/réponse extraites d'un forum.
Le problème : les données sont sales. Il y a des doublons, des réponses trop courtes ("oui", "non"), des espaces partout, et aucune validation de format. Avant de dépenser de l'argent en fine-tuning, tu dois construire un pipeline complet qui fait tout le travail de préparation.
Écris une fonction pipeline_finetuning(donnees_brutes, system_prompt, config) qui orchestre tout le processus :
1. Formater : convertir chaque paire {"question": "...", "reponse": "..."} en format messages 2. Nettoyer : strip() sur tous les contenus, supprimer les doublons (même question), filtrer par longueur de réponse (min et max définis dans config) 3. Valider : vérifier que chaque exemple a bien les rôles system, user, assistant 4. Splitter : séparer en train/validation selon le ratio dans config 5. Estimer le coût : calculer le coût total du train set
Le paramètre config est un dictionnaire avec : - "min_length" : longueur minimale de la réponse assistant (défaut 10) - "max_length" : longueur maximale (défaut 2000) - "ratio_train" : ratio train/total (défaut 0.8) - "seed" : graine aléatoire (défaut 42) - "prix_par_million" : prix par million de tokens (défaut 3.0) - "epochs" : nombre d'epochs (défaut 3)
La fonction renvoie un dictionnaire avec : - "train" : la liste d'exemples d'entraînement - "validation" : la liste d'exemples de validation - "stats" : un dictionnaire avec "total_brut" (nombre initial), "doublons" (supprimés), "trop_courts", "trop_longs", "valides" (après nettoyage et validation), "cout_estime" (coût total du train set)
Exemple :
data = [ {"question": "C'est quoi Python ?", "reponse": "Python est un langage de programmation créé par Guido van Rossum."}, {"question": "C'est quoi Python ?", "reponse": "Un langage."}, {"question": "Boucle for ?", "reponse": "ok"}, ] config = {"min_length": 10, "seed": 42} r = pipeline_finetuning(data, "Tu es un prof Python.", config) r["stats"]["total_brut"] renvoie 3 r["stats"]["doublons"] renvoie 1 r["stats"]["trop_courts"] renvoie 1 len(r["train"]) + len(r["validation"]) renvoie 1
data = [{'question': f'Q{i}', 'reponse': f'Réponse longue numéro {i} avec du contenu'} for i in range(10)]
config = {'min_length': 5, 'ratio_train': 0.8, 'seed': 42}
r = pipeline_finetuning(data, 'sys', config)
assert len(r['train']) + len(r['validation']) == r['stats']['valides']
Coût estimé présent
data = [{'question': f'Q{i}', 'reponse': 'a' * 400} for i in range(100)]
config = {'min_length': 5, 'prix_par_million': 3.0, 'epochs': 3, 'ratio_train': 1.0, 'seed': 42}
r = pipeline_finetuning(data, 'sys', config)
assert r['stats']['cout_estime'] > 0
Espaces nettoyés
data = [{'question': ' Salut ', 'reponse': ' Bienvenue à toi cher élève '}]
config = {'min_length': 5, 'seed': 42}
r = pipeline_finetuning(data, ' Prof ', config)
ex = (r['train'] + r['validation'])[0]
assert ex['messages'][0]['content'] == 'Prof'
assert ex['messages'][1]['content'] == 'Salut'
assert ex['messages'][2]['content'] == 'Bienvenue à toi cher élève'
+ 0 tests cachés
Indices (3 disponibles)
Solution officielle
import json
import random
def pipeline_finetuning(donnees_brutes, system_prompt, config):
min_length = config.get('min_length', 10)
max_length = config.get('max_length', 2000)
ratio_train = config.get('ratio_train', 0.8)
seed = config.get('seed', 42)
prix_par_million = config.get('prix_par_million', 3.0)
epochs = config.get('epochs', 3)
stats = {
'total_brut': len(donnees_brutes),
'doublons': 0,
'trop_courts': 0,
'trop_longs': 0,
'valides': 0,
'cout_estime': 0,
}
exemples = []
for d in donnees_brutes:
exemple = {
'messages': [
{'role': 'system', 'content': system_prompt.strip()},
{'role': 'user', 'content': d['question'].strip()},
{'role': 'assistant', 'content': d['reponse'].strip()},
]
}
exemples.append(exemple)
vus = set()
sans_doublons = []
for ex in exemples:
question = ex['messages'][1]['content']
if question in vus:
stats['doublons'] += 1
continue
vus.add(question)
sans_doublons.append(ex)
propres = []
for ex in sans_doublons:
reponse = ex['messages'][2]['content']
if len(reponse) < min_length:
stats['trop_courts'] += 1
continue
if len(reponse) > max_length:
stats['trop_longs'] += 1
continue
propres.append(ex)
stats['valides'] = len(propres)
copie = list(propres)
random.seed(seed)
random.shuffle(copie)
index_coupe = int(len(copie) * ratio_train)
train = copie[:index_coupe]
validation = copie[index_coupe:]
total_chars = 0
for ex in train:
for msg in ex['messages']:
total_chars += len(msg['content'])
tokens = total_chars // 4
stats['cout_estime'] = round(tokens * (prix_par_million / 1_000_000) * epochs, 4)
return {
'train': train,
'validation': validation,
'stats': stats,
}