Intermédiaire
🧠 Fondamentaux
20 XP
0 personnes ont réussi
Auditer la qualité d'un dataset
Avant d'envoyer ton dataset à OpenAI, tu ne vérifies pas juste le format. Tu vérifies la qualité. Un dataset qui passe la validation de format peut quand même produire un mauvais modèle si les données sont pourries : des exemples dupliqués, des réponses trop courtes pour que le modèle apprenne quoi que ce soit, un system prompt incohérent entre les exemples, ou une conversation où les rôles n'arrivent pas dans le bon ordre.
Dans un vrai pipeline de fine-tuning professionnel, l'audit qualité vérifie plusieurs choses au-delà du simple format :
Structure des rôles : les messages doivent suivre un ordre logique. Le premier message doit être "system" (le contexte), suivi d'au moins une paire "user" puis "assistant". Si le premier message est "assistant", ça n'a pas de sens : le modèle ne peut pas répondre avant qu'on lui pose une question.
Détection des doublons : si deux exemples ont exactement la même question user, le modèle va sur-apprendre sur cette question. C'est du gaspillage de tokens (et d'argent).
Longueur des réponses : une réponse assistant de 2 mots ("ok merci") n'apprend rien au modèle. OpenAI recommande des réponses d'au moins 20-30 mots pour que le fine-tuning soit efficace.
Écris une fonction auditer_dataset(exemples, min_tokens=10) qui prend une liste d'exemples au format messages et un nombre minimum de tokens (on approxime : 1 token = 4 caractères). La fonction renvoie un dictionnaire avec : - "total" : nombre total d'exemples - "valides" : nombre d'exemples sans aucun problème - "erreurs_structure" : nombre d'exemples avec un problème de structure (pas de clé messages, messages vide, rôles manquants, pas d'assistant) - "erreurs_ordre" : nombre d'exemples où le premier message n'est pas "system" ou où un "assistant" arrive avant tout "user" - "doublons" : nombre de doublons détectés (même contenu user) - "reponses_courtes" : nombre d'exemples où la réponse assistant fait moins de min_tokens tokens estimés - "details" : liste de dicts {"index": i, "problemes": ["..."]} pour chaque exemple problématique
Exemple :
data = [ {"messages": [{"role": "system", "content": "Tu es un expert."}, {"role": "user", "content": "Salut"}, {"role": "assistant", "content": "Bonjour, comment puis-je t'aider aujourd'hui ?"}]}, {"messages": [{"role": "user", "content": "Salut"}, {"role": "assistant", "content": "Ok"}]}, ] r = auditer_dataset(data, min_tokens=5) r["erreurs_ordre"] renvoie 1 (le deuxième exemple ne commence pas par system) r["doublons"] renvoie 1 (même question "Salut") r["reponses_courtes"] renvoie 1 (la réponse "Ok" est trop courte)
Tests (5/6)
Exemple parfait
data = [{'messages': [{'role': 'system', 'content': 'Tu es un expert.'}, {'role': 'user', 'content': 'Question ?'}, {'role': 'assistant', 'content': 'Voici une réponse détaillée qui fait au moins quarante caractères pour passer le filtre.'}]}]
r = auditer_dataset(data, min_tokens=5)
assert r['valides'] == 1
assert r['erreurs_structure'] == 0
assert r['erreurs_ordre'] == 0
Détecte les doublons
data = [
{'messages': [{'role': 'system', 'content': 's'}, {'role': 'user', 'content': 'Salut'}, {'role': 'assistant', 'content': 'Bonjour, comment vas-tu ? Bienvenue chez nous.'}]},
{'messages': [{'role': 'system', 'content': 's'}, {'role': 'user', 'content': 'Salut'}, {'role': 'assistant', 'content': 'Hey ! Comment ça va ? Tout roule pour toi ?'}]}
]
r = auditer_dataset(data, min_tokens=5)
assert r['doublons'] == 1
Détecte l'ordre des rôles
data = [{'messages': [{'role': 'user', 'content': 'Q'}, {'role': 'assistant', 'content': 'Réponse assez longue pour le test de tokens.'}]}]
r = auditer_dataset(data, min_tokens=3)
assert r['erreurs_ordre'] >= 1
assert any('system' in p.lower() for d in r['details'] for p in d['problemes'])
data = [{'data': 'mauvais'}, {'messages': []}]
r = auditer_dataset(data)
assert r['erreurs_structure'] == 2
assert r['valides'] == 0
+ 0 tests cachés
Indices (3 disponibles)
Solution officielle
def auditer_dataset(exemples, min_tokens=10):
stats = {
"total": len(exemples),
"valides": 0,
"erreurs_structure": 0,
"erreurs_ordre": 0,
"doublons": 0,
"reponses_courtes": 0,
"details": [],
}
questions_vues = set()
for idx, ex in enumerate(exemples):
problemes = []
# Vérifier la structure de base
if "messages" not in ex or not isinstance(ex.get("messages"), list) or len(ex.get("messages", [])) == 0:
problemes.append("Structure invalide : clé messages manquante ou vide")
stats["erreurs_structure"] += 1
stats["details"].append({"index": idx, "problemes": problemes})
continue
msgs = ex["messages"]
# Vérifier que chaque message a role et content
structure_ok = True
a_assistant = False
a_user = False
for m in msgs:
if "role" not in m or "content" not in m:
structure_ok = False
break
if m["role"] == "assistant":
a_assistant = True
if m["role"] == "user":
a_user = True
if not structure_ok:
problemes.append("Message sans clé role ou content")
stats["erreurs_structure"] += 1
stats["details"].append({"index": idx, "problemes": problemes})
continue
if not a_assistant:
problemes.append("Aucun message assistant")
stats["erreurs_structure"] += 1
# Vérifier l'ordre des rôles
if msgs[0]["role"] != "system":
problemes.append("Le premier message n'est pas system")
stats["erreurs_ordre"] += 1
else:
# Vérifier qu'un assistant ne parle pas avant un user
premier_user = None
premier_assistant = None
for i, m in enumerate(msgs):
if m["role"] == "user" and premier_user is None:
premier_user = i
if m["role"] == "assistant" and premier_assistant is None:
premier_assistant = i
if premier_assistant is not None and (premier_user is None or premier_assistant < premier_user):
problemes.append("Un message assistant arrive avant le premier message user")
stats["erreurs_ordre"] += 1
# Détecter les doublons (basé sur le contenu user)
question = None
for m in msgs:
if m["role"] == "user":
question = m["content"]
break
if question is not None:
if question in questions_vues:
problemes.append("Question user en doublon")
stats["doublons"] += 1
else:
questions_vues.add(question)
# Vérifier la longueur de la réponse assistant
reponse_assistant = ""
for m in reversed(msgs):
if m["role"] == "assistant":
reponse_assistant = m["content"]
break
tokens_estimes = len(reponse_assistant) // 4
if tokens_estimes < min_tokens and a_assistant:
problemes.append(f"Réponse trop courte ({tokens_estimes} tokens estimés, minimum {min_tokens})")
stats["reponses_courtes"] += 1
if problemes:
stats["details"].append({"index": idx, "problemes": problemes})
else:
stats["valides"] += 1
return stats