Preparare un dataset di addestramento di alta qualità
Raccolga, pulisca e formatti dati per il seguimento delle istruzioni nei formati Alpaca e ShareGPT, applichi la deduplicazione dei dati e suddivida il dataset in insiemi di addestramento e validazione.
Preparare un dataset di addestramento di alta qualità è una lezione AI Engineering Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento AI Engineering Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso AI Engineering Academy include 4 lezioni in totale.
I dati sono il fattore più importante del fine-tuning
Nel fine-tuning, la qualità dei dati di addestramento conta più di qualsiasi iperparametro, scelta architetturale o tecnica di addestramento. 100 esempi di alta qualità sono migliori di 10.000 esempi mediocri. Se i dati in ingresso sono scadenti, anche il risultato lo sarà: il modello sottoposto a fine-tuning riprodurrà fedelmente qualsiasi schema presente nei dati, inclusi errori, distorsioni e incoerenze di formato. Investire nella qualità dei dati è l’azione con il maggiore impatto in qualsiasi progetto di fine-tuning.
Formati per seguire le istruzioni
La maggior parte del fine-tuning per le attività di esecuzione delle istruzioni utilizza un formato di messaggi conversazionali con i ruoli system, user e assistant. L’API di fine-tuning di OpenAI utilizza file JSONL, in cui ogni riga contiene un esempio di conversazione completo. Anche i formati Alpaca (instruction/input/output) e ShareGPT (elenco conversations) sono ampiamente utilizzati. Scelga il formato compatibile con il framework di fine-tuning che intende usare.
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...Raccolta dei dati di addestramento: tre strategie
Esistono tre strategie principali per creare un dataset per il fine-tuning. Generazione umana: gli esperti scrivono manualmente esempi ideali: qualità massima, ma con tempi e costi elevati. Generazione tramite LLM: un modello potente (GPT-4o) genera esempi che vengono poi convalidati da persone: è molto più rapida ed economica e offre una buona qualità se gli esempi vengono convalidati. Estrazione dai log: si estraggono coppie input-output dai log di produzione esistenti, filtrando gli esempi di alta qualità tramite indicatori come le valutazioni degli utenti o il punteggio LLM-as-judge.
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}
]
}Filtraggio e convalida della qualità
Ogni esempio di addestramento dovrebbe superare un passaggio di convalida della qualità prima di essere incluso. Verifichi che: la risposta abbia il formato corretto, sia accurata (per le attività fattuali), non contenga allucinazioni o contenuti dannosi, che la coppia istruzione-risposta sia coerente e che l’esempio sia rappresentativo del caso d’uso in produzione. Utilizzi la convalida automatica per i controlli di formato e LLM-as-judge per la qualità dei contenuti, affiancandoli a una revisione umana su un campione.
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)}')Deduplicazione dei dati
Gli esempi duplicati o quasi duplicati nei dati di addestramento sono dannosi. Portano il modello a sovradattarsi a quegli esempi specifici, sprecando capacità di addestramento che avrebbe potuto apprendere schemi diversificati. Esegua la deduplicazione prima di finalizzare il dataset. La deduplicazione esatta utilizza l’hashing per trovare esempi identici. La quasi-deduplicazione utilizza MinHash o la similarità tra embedding per trovare esempi che differiscono solo per aspetti irrilevanti.
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)]Suddivisione tra addestramento e convalida
Suddivida il dataset in set di addestramento e di convalida prima di avviare qualsiasi sessione di fine-tuning. Il set di convalida serve a monitorare l’overfitting durante l’addestramento (se la loss di convalida aumenta mentre la loss di addestramento diminuisce, il modello è in overfitting). Una suddivisione tipica è 90% per l’addestramento e 10% per la convalida. Si assicuri che la suddivisione sia casuale e stratificata se il dataset contiene categorie significative (ad esempio, una rappresentazione equivalente di tutti i tipi di intent in entrambi i set).
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)})')Bilanciamento del dataset
I dataset sbilanciati portano i modelli sottoposti a fine-tuning a specializzarsi eccessivamente nei casi comuni e a fallire in quelli rari ma importanti. Se il dataset contiene 900 esempi della categoria A e 100 esempi della categoria B, il modello potrebbe imparare a predire sempre A. Bilanci il dataset tramite: oversampling delle categorie minoritarie (duplicando gli esempi rari), undersampling delle categorie maggioritarie oppure generazione di esempi sintetici per i casi sottorappresentati usando 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 balancedPulizia e normalizzazione dei dati
I dati di addestramento spesso contengono incoerenze che danneggiano il fine-tuning: maiuscole e minuscole miste nei campi di output, spazi bianchi finali, uso incoerente delle virgolette, formati numerici diversi o convenzioni variabili per i nomi delle chiavi JSON. Normalizzi questi elementi prima dell’addestramento. Il modello sottoposto a fine-tuning apprenderà l’esatta formattazione presente nei dati: se i dati contengono incoerenze, il modello le riprodurrà.
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]Misurazione delle metriche di qualità del dataset
Prima di inviare i dati per il fine-tuning, calcoli le metriche di qualità sull’intero dataset. Controlli: il numero medio e massimo di token per esempio (gli esempi lunghi costano di più da addestrare e potrebbero essere troncati), la copertura del vocabolario (il dataset copre tutta la diversità degli input di produzione?) e il punteggio di coerenza (input simili ricevono output simili?). La maggior parte dei provider di fine-tuning dispone di un endpoint di convalida dei dati che verifica la presenza di errori di formato prima di addebitare i costi per una sessione di addestramento non riuscita.
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 reportMiglioramento iterativo del dataset
La preparazione del dataset è iterativa. Sottoponga un modello di piccole dimensioni a fine-tuning sul dataset iniziale, lo valuti su esempi messi da parte, identifichi i tipi di errore e li riconduca alle lacune o ai problemi di qualità del dataset. Corregga quindi i dati e ripeta l’addestramento. Questo ciclo di miglioramento dei dati guidato dagli errori è la pratica standard nel fine-tuning in produzione e risulta molto più efficace del tentativo di raccogliere il dataset perfetto in un’unica fase.
Coerenza del prompt di sistema tra gli esempi
Se il Suo modello sottoposto a fine-tuning utilizzerà sempre lo stesso prompt di sistema in produzione, includa esattamente quel prompt di sistema in ogni esempio di addestramento. Se desidera che il modello funzioni senza alcun prompt di sistema, esegua l'addestramento senza prompt. Le discrepanze tra le condizioni di addestramento e quelle di inferenza sono una delle principali cause del mancato raggiungimento delle aspettative nel fine-tuning. Il modello apprende comportamenti condizionati dall'esatta struttura del prompt che vede durante l'addestramento.
Verifica rapida
Verifichi la Sua comprensione della preparazione di un dataset di addestramento per il fine-tuning trattata in questa lezione.
Riepilogo della lezione
In questa lezione ha imparato che, nel fine-tuning, la qualità dei dati è più importante della quantità: 100 esempi eccellenti sono migliori di 10.000 esempi mediocri; deduplicazione, convalida, bilanciamento e normalizzazione sono i quattro passaggi fondamentali di pulizia dei dati prima di qualsiasi esecuzione dell'addestramento; inoltre, la suddivisione in addestramento/validazione è essenziale per rilevare l'overfitting durante l'addestramento, prima che comprometta le prestazioni nel mondo reale. Nel prossimo argomento eseguiremo il fine-tuning LoRA con Hugging Face PEFT.
Domande Frequenti
La lezione «Preparare un dataset di addestramento di alta qualità» è gratuita?
Sì — il testo completo di «Preparare un dataset di addestramento di alta qualità» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso AI Engineering Academy, passa a CoddyKit PRO. Il corso AI Engineering Academy include 4 lezioni in totale.
Cosa imparerò in «Preparare un dataset di addestramento di alta qualità»?
Raccolga, pulisca e formatti dati per il seguimento delle istruzioni nei formati Alpaca e ShareGPT, applichi la deduplicazione dei dati e suddivida il dataset in insiemi di addestramento e validazion… Eserciti AI Engineering Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare AI Engineering Academy?
Non è richiesta alcuna esperienza precedente. AI Engineering Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.
Quanto tempo richiede la lezione «Preparare un dataset di addestramento di alta qualità»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione AI Engineering Academy?
Sì. Ogni lezione AI Engineering Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Quando il fine-tuning supera il prompting
- Preparare un dataset di addestramento di alta qualità
- Fine-tuning LoRA con Hugging Face PEFT
- Valutare e distribuire il modello sottoposto a fine-tuning