Préparer un jeu de données d’entraînement de haute qualité
Collectez, nettoyez et mettez en forme des données de suivi d’instructions aux formats Alpaca et ShareGPT, dédupliquez les données, puis séparez-les en ensembles d’entraînement et de validation.
Préparer un jeu de données d’entraînement de haute qualité est une leçon AI Engineering Academy gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage AI Engineering Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours AI Engineering Academy comprend 4 leçons au total.
Les données sont le facteur le plus important du réglage fin
Dans le réglage fin, la qualité de vos données d’entraînement compte davantage que n’importe quel hyperparamètre, choix d’architecture ou technique d’entraînement. 100 exemples de haute qualité donnent de meilleurs résultats que 10 000 exemples médiocres. « Données médiocres en entrée, résultats médiocres en sortie » : le modèle réglé finement reproduira fidèlement tous les schémas présents dans vos données, y compris les erreurs, les biais et les incohérences de format. Investir dans la qualité des données est l’action offrant le meilleur effet de levier dans tout projet de réglage fin.
Formats de suivi des instructions
La plupart des réglages fins pour les tâches de suivi des instructions utilisent un format de messages conversationnels avec des rôles système, utilisateur et assistant. L’API de réglage fin d’OpenAI utilise des fichiers JSONL dont chaque ligne constitue un exemple de conversation complet. Le format Alpaca (instruction/entrée/sortie) et le format ShareGPT (liste de conversations) sont également très répandus. Choisissez le format correspondant au cadre de réglage fin que vous prévoyez d’utiliser.
import json
# OpenAI fine-tuning format (JSONL)
# Each line is one training example
openai_example = {
'messages': [
{'role': 'system', 'content': 'You are a JSON extraction agent.'},
{'role': 'user', 'content': 'Extract: "John Smith, age 32, from Seattle, joined 2023-01-15"'},
{'role': 'assistant', 'content': '{"name": "John Smith", "age": 32, "city": "Seattle", "join_date": "2023-01-15"}'}
]
}
# Alpaca format
alpaca_example = {
'instruction': 'Extract structured data from the following text.',
'input': 'John Smith, age 32, from Seattle, joined 2023-01-15',
'output': '{"name": "John Smith", "age": 32, "city": "Seattle", "join_date": "2023-01-15"}'
}
# Write as JSONL
with open('train.jsonl', 'w') as f:
f.write(json.dumps(openai_example) + '\n')
# Add more examples here...Collecte des données d’entraînement : trois stratégies
Il existe trois stratégies principales pour constituer un jeu de données de réglage fin. Génération humaine : des experts rédigent manuellement des exemples idéaux — qualité maximale, mais processus lent et coûteux. Génération par LLM : un modèle puissant (GPT-4o) génère des exemples qui sont ensuite validés par des humains — processus bien plus rapide et moins coûteux, avec une bonne qualité si les exemples sont validés. Extraction depuis les journaux : extraire des paires entrée-sortie de journaux de production existants, en filtrant les exemples de haute qualité à l’aide de signaux comme les évaluations des utilisateurs ou une notation effectuée par un LLM.
from openai import OpenAI
client = OpenAI()
def generate_training_example_with_gpt4o(task_description: str, example_input: str) -> dict:
'''Use GPT-4o to generate a training example for a smaller model.'''
prompt = f'''You are creating a training example for fine-tuning a smaller model.
Task: {task_description}
Given this input:
{example_input}
Write the ideal assistant response that demonstrates the correct behavior for this task.
Be specific, accurate, and follow the expected format precisely.'''
response = client.chat.completions.create(
model='gpt-4o', # teacher model
messages=[{'role': 'user', 'content': prompt}]
)
return {
'messages': [
{'role': 'system', 'content': task_description},
{'role': 'user', 'content': example_input},
{'role': 'assistant', 'content': response.choices[0].message.content}
]
}Filtrage et validation de la qualité
Chaque exemple d’entraînement doit passer par une étape de validation de la qualité avant d’être inclus. Vérifiez que : la réponse respecte le format correct, la réponse est exacte (pour les tâches factuelles), la réponse ne contient ni hallucinations ni contenu nuisible, la paire instruction-réponse est cohérente et l’exemple est représentatif du cas d’utilisation en production. Utilisez une validation automatisée pour les contrôles de format et un LLM comme évaluateur pour la qualité du contenu, avec une vérification humaine sur un échantillon.
import json
def validate_training_example(example: dict, schema_validator=None) -> dict:
issues = []
# Format check
if 'messages' not in example:
issues.append('Missing messages field')
return {'valid': False, 'issues': issues}
messages = example['messages']
if not any(m['role'] == 'assistant' for m in messages):
issues.append('No assistant message found')
# Check assistant message quality
assistant_content = next((m['content'] for m in messages if m['role'] == 'assistant'), '')
if len(assistant_content) < 5:
issues.append('Assistant response too short')
# Schema validation for JSON output tasks
if schema_validator:
try:
parsed = json.loads(assistant_content)
schema_validator(parsed) # raises if invalid
except json.JSONDecodeError:
issues.append('Assistant response is not valid JSON')
except Exception as e:
issues.append(f'Schema validation failed: {str(e)}')
return {'valid': len(issues) == 0, 'issues': issues}
# Run validation on all examples before training
examples = load_training_examples('raw_dataset.jsonl')
valid_examples = [e for e in examples if validate_training_example(e)['valid']]
print(f'Valid examples: {len(valid_examples)}/{len(examples)}')Déduplication des données
Les exemples dupliqués ou presque dupliqués dans les données d’entraînement sont nuisibles. Ils amènent le modèle à se surajuster à ces exemples précis, gaspillant une capacité d’entraînement qui aurait pu servir à apprendre des schémas variés. Effectuez une déduplication avant de finaliser votre jeu de données. La déduplication exacte utilise le hachage pour trouver les exemples identiques. La déduplication approximative utilise MinHash ou la similarité entre représentations vectorielles pour trouver les exemples qui ne diffèrent que par des détails insignifiants.
import hashlib
from datasketch import MinHash, MinHashLSH
def exact_deduplicate(examples: list[dict]) -> list[dict]:
seen_hashes = set()
unique = []
for ex in examples:
# Hash the user and assistant messages
content = str(ex['messages'])
h = hashlib.md5(content.encode()).hexdigest()
if h not in seen_hashes:
seen_hashes.add(h)
unique.append(ex)
print(f'Exact dedup: {len(examples)} -> {len(unique)} ({len(examples)-len(unique)} removed)')
return unique
def near_deduplicate_by_input(examples: list[dict], similarity_threshold=0.85) -> list[dict]:
# Build index of input texts
inputs = [next((m['content'] for m in ex['messages'] if m['role'] == 'user'), '') for ex in examples]
lsh = MinHashLSH(threshold=similarity_threshold, num_perm=128)
unique_indices = set()
for i, text in enumerate(inputs):
m = MinHash(num_perm=128)
for word in text.lower().split():
m.update(word.encode('utf-8'))
if not lsh.query(m): # no similar items found
lsh.insert(str(i), m)
unique_indices.add(i)
return [examples[i] for i in sorted(unique_indices)]Séparation entraînement/validation
Divisez votre jeu de données en ensembles d’entraînement et de validation avant de commencer toute session de réglage fin. L’ensemble de validation sert à surveiller le surapprentissage pendant l’entraînement (si la perte de validation augmente tandis que la perte d’entraînement diminue, le modèle est en situation de surapprentissage). Une séparation courante est de 90 % pour l’entraînement et 10 % pour la validation. Veillez à ce que la séparation soit aléatoire et stratifiée si votre jeu de données comporte des catégories pertinentes (par exemple, une représentation équivalente de tous les types d’intention dans les deux ensembles).
import random
import json
def split_dataset(examples: list[dict], val_fraction=0.1, seed=42) -> tuple[list, list]:
random.seed(seed) # reproducible split
shuffled = examples.copy()
random.shuffle(shuffled)
n_val = max(1, int(len(shuffled) * val_fraction))
val_set = shuffled[:n_val]
train_set = shuffled[n_val:]
print(f'Train: {len(train_set)} examples, Validation: {len(val_set)} examples')
return train_set, val_set
def save_jsonl(examples: list[dict], path: str):
with open(path, 'w') as f:
for ex in examples:
f.write(json.dumps(ex) + '\n')
# Split and save
examples = load_training_examples('clean_dataset.jsonl')
train, val = split_dataset(examples, val_fraction=0.1)
save_jsonl(train, 'train.jsonl')
save_jsonl(val, 'validation.jsonl')
print(f'Saved train.jsonl ({len(train)}) and validation.jsonl ({len(val)})')Équilibrage du jeu de données
Les jeux de données déséquilibrés amènent les modèles réglés finement à se spécialiser excessivement dans les cas fréquents et à échouer sur les cas rares mais importants. Si votre jeu de données contient 900 exemples de la catégorie A et 100 exemples de la catégorie B, le modèle peut apprendre à toujours prédire A. Équilibrez le jeu de données en : suréchantillonnant les catégories minoritaires (en dupliquant les exemples rares), sous-échantillonnant les catégories majoritaires ou en générant des exemples synthétiques pour les cas sous-représentés à l’aide de GPT-4o.
from collections import Counter
import random
def analyze_distribution(examples: list[dict], category_extractor) -> dict:
categories = [category_extractor(ex) for ex in examples]
counts = Counter(categories)
print('Category distribution:')
for cat, count in counts.most_common():
print(f' {cat}: {count} ({100*count/len(examples):.1f}%)')
return counts
def oversample_minority(examples: list[dict], category_extractor, target_count: int) -> list[dict]:
by_category = {}
for ex in examples:
cat = category_extractor(ex)
by_category.setdefault(cat, []).append(ex)
balanced = []
for cat, cat_examples in by_category.items():
if len(cat_examples) < target_count:
# Oversample with replacement
oversampled = random.choices(cat_examples, k=target_count)
balanced.extend(oversampled)
else:
# Undersample to target_count
balanced.extend(random.sample(cat_examples, target_count))
random.shuffle(balanced)
return balancedNettoyage et normalisation des données
Les données d’entraînement contiennent souvent des incohérences qui nuisent au réglage fin : majuscules et minuscules mélangées dans les champs de sortie, espaces en fin de ligne, utilisation incohérente des guillemets, formats de nombres différents ou conventions variables pour nommer les clés JSON. Normalisez ces éléments avant l’entraînement. Le modèle réglé finement apprendra exactement le format présent dans vos données : si vos données sont incohérentes, le modèle les reproduira.
import json
import re
def normalize_json_output_example(example: dict) -> dict:
'''Normalize JSON output in assistant messages for consistency.'''
messages = example.get('messages', [])
normalized = []
for msg in messages:
if msg['role'] == 'assistant':
content = msg['content'].strip()
# Try to parse and re-serialize JSON for consistent formatting
try:
parsed = json.loads(content)
# Normalize: sort keys, consistent spacing
content = json.dumps(parsed, ensure_ascii=False, sort_keys=True)
except json.JSONDecodeError:
pass # Not JSON output - leave as is
normalized.append({'role': 'assistant', 'content': content})
else:
normalized.append(msg)
return {'messages': normalized}
def normalize_dataset(examples: list[dict]) -> list[dict]:
return [normalize_json_output_example(ex) for ex in examples]Mesure des indicateurs de qualité du jeu de données
Avant de soumettre les données au réglage fin, calculez des indicateurs de qualité sur l’ensemble du jeu de données. Vérifiez : le nombre moyen et maximal de jetons par exemple (les exemples longs coûtent plus cher à entraîner et peuvent être tronqués), la couverture du vocabulaire (le jeu de données couvre-t-il toute la diversité des entrées de production ?) et le score de cohérence (des entrées similaires produisent-elles des sorties similaires ?). La plupart des fournisseurs de réglage fin disposent d’un point de terminaison de validation des données qui détecte les erreurs de format avant de vous facturer une session d’entraînement échouée.
import tiktoken
def analyze_dataset_quality(examples: list[dict], model='gpt-4o-mini') -> dict:
encoder = tiktoken.encoding_for_model(model)
token_counts = []
for ex in examples:
total_tokens = sum(
len(encoder.encode(m['content']))
for m in ex['messages']
)
token_counts.append(total_tokens)
report = {
'total_examples': len(examples),
'avg_tokens_per_example': sum(token_counts) / len(token_counts),
'max_tokens': max(token_counts),
'min_tokens': min(token_counts),
'examples_over_4k_tokens': sum(1 for t in token_counts if t > 4096),
'estimated_training_tokens': sum(token_counts),
'estimated_cost': sum(token_counts) / 1_000_000 * 8.0 # ~$8/1M tokens for gpt-4o-mini
}
for key, value in report.items():
print(f'{key}: {value}')
return reportAmélioration itérative du jeu de données
La préparation du jeu de données est un processus itératif. Réglez finement un petit modèle sur votre jeu de données initial, évaluez-le sur des exemples mis de côté, identifiez les modes d’échec et remontez jusqu’aux lacunes ou aux problèmes de qualité du jeu de données. Corrigez ensuite les données et relancez l’entraînement. Cette boucle d’amélioration des données guidée par les erreurs est la pratique standard du réglage fin en production et elle est bien plus efficace que d’essayer de recueillir un jeu de données parfait en une seule fois.
Cohérence du prompt système entre les exemples
Si votre modèle affiné utilise toujours le même message système en production, incluez exactement ce message système dans chaque exemple d'entraînement. Si vous souhaitez que le modèle fonctionne sans message système, entraînez-le sans message système. Les écarts entre les conditions d'entraînement et d'inférence sont l'une des principales causes de déception lors de l'affinage. Le modèle apprend des comportements conditionnés par la structure exacte du message qu'il voit pendant l'entraînement.
Vérification rapide
Vérifiez votre compréhension de la préparation d'un jeu de données d'entraînement pour l'affinage à partir de cette leçon.
Récapitulatif de la leçon
Dans cette leçon, vous avez appris que, pour l'affinage, la qualité des données prime sur leur quantité : 100 excellents exemples sont plus performants que 10 000 exemples médiocres ; la déduplication, la validation, l'équilibrage et la normalisation sont les quatre étapes essentielles du nettoyage des données avant tout entraînement ; et la séparation entraînement/validation est indispensable pour détecter le surapprentissage pendant l'entraînement, avant qu'il ne dégrade les performances en conditions réelles. Nous allons maintenant effectuer un affinage LoRA avec Hugging Face PEFT.
Questions Fréquemment Posées
La leçon « Préparer un jeu de données d’entraînement de haute qualité » est-elle gratuite ?
Oui — le texte complet de « Préparer un jeu de données d’entraînement de haute qualité » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours AI Engineering Academy, passe à CoddyKit PRO. Le cours AI Engineering Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Préparer un jeu de données d’entraînement de haute qualité » ?
Collectez, nettoyez et mettez en forme des données de suivi d’instructions aux formats Alpaca et ShareGPT, dédupliquez les données, puis séparez-les en ensembles d’entraînement et de validation. Tu pratiques AI Engineering Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer AI Engineering Academy ?
Aucune expérience préalable n'est requise. AI Engineering Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.
Combien de temps prend la leçon « Préparer un jeu de données d’entraînement de haute qualité » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon AI Engineering Academy ?
Oui. Chaque leçon AI Engineering Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Quand l’ajustement fin est plus efficace que les invites
- Préparer un jeu de données d’entraînement de haute qualité
- Ajustement fin LoRA avec Hugging Face PEFT
- Évaluer et déployer votre modèle ajusté