Forberede et opplæringsdatasett av høy kvalitet
Samle inn, rens og formater instruksjonsdata i formatene Alpaca og ShareGPT, fjern duplikater i dataene, og del dem inn i trenings- og valideringssett.
Forberede et opplæringsdatasett av høy kvalitet er en gratis leksjon i AI Engineering Academy på CoddyKit. Dette er leksjon 2 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i AI Engineering Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i AI Engineering Academy inneholder totalt 4 leksjoner.
Data er den viktigste faktoren ved fine-tuning
Ved fine-tuning betyr kvaliteten på treningsdataene mer enn noen hyperparameter, arkitekturvalg eller treningsteknikk. 100 eksempler av høy kvalitet gir bedre resultater enn 10 000 middelmådige. Søppel inn, søppel ut – den finjusterte modellen vil trofast gjenskape mønstrene i dataene, inkludert feil, skjevheter og inkonsekvenser i formatet. Å investere i datakvalitet er tiltaket med størst effekt i ethvert fine-tuning-prosjekt.
Formater for instruksjonsfølgning
Det meste av fine-tuning for oppgaver som følger instruksjoner, bruker et konversasjonelt meldingsformat med rollene system, user og assistant. OpenAIs fine-tuning-API bruker JSONL-filer der hver linje er et komplett samtaleeksempel. Alpaca-formatet (instruction/input/output) og ShareGPT-formatet (liste med samtaler) er også mye brukt. Velg formatet som samsvarer med rammeverket for fine-tuning De planlegger å bruke.
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...Innsamling av treningsdata: tre strategier
Det finnes tre hovedstrategier for å bygge et datasett for fine-tuning. Menneskeskapt innhold: eksperter skriver ideelle eksempler manuelt – høyest kvalitet, men langsomt og kostbart. LLM-generering: en kraftig modell (GPT-4o) genererer eksempler som deretter valideres av mennesker – mye raskere og billigere, med god kvalitet hvis eksemplene valideres. Uthenting fra logger: hent ut par av inndata og utdata fra eksisterende produksjonslogger, og filtrer frem eksempler av høy kvalitet ved hjelp av kvalitetssignaler som brukervurderinger eller LLM-as-judge-skåring.
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}
]
}Kvalitetsfiltrering og validering
Alle treningseksempler bør gjennomgå et kvalitetstrinn før de inkluderes. Kontroller at svaret har riktig format, at det er korrekt (for faktabaserte oppgaver), at det ikke inneholder hallusinasjoner eller skadelig innhold, at instruksjons- og svarparet henger sammen, og at eksempelet er representativt for produksjonsbruken. Bruk automatisert validering for formatsjekker og LLM-as-judge for innholdskvalitet, med menneskelig gjennomgang av et utvalg.
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)}')Fjerning av duplikater i dataene
Dupliserte eller nesten dupliserte eksempler i treningsdataene er skadelige. De får modellen til å overtilpasse seg disse bestemte eksemplene og sløser med treningskapasitet som kunne ha lært mer varierte mønstre. Kjør deduplisering før datasettet ferdigstilles. Eksakt deduplisering bruker hashing for å finne identiske eksempler. Nær-deduplisering bruker MinHash eller likhet mellom embedding-vektorer for å finne eksempler som bare skiller seg på trivielle måter.
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)]Oppdeling i trenings- og valideringssett
Del datasettet inn i trenings- og valideringssett før De starter en fine-tuning-kjøring. Valideringssettet brukes til å overvåke overtilpasning under treningen (hvis valideringstapet øker mens treningstapet synker, overtilpasser modellen seg). En vanlig fordeling er 90 % trening / 10 % validering. Sørg for at oppdelingen er tilfeldig og stratifisert hvis datasettet har meningsfulle kategorier (for eksempel lik representasjon av alle intensjonstyper i begge settene).
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)})')Balansering av datasettet
Ubalanserte datasett fører til at finjusterte modeller spesialiserer seg for mye på vanlige tilfeller og mislykkes på sjeldne, men viktige, tilfeller. Hvis datasettet Deres har 900 eksempler i kategori A og 100 eksempler i kategori B, kan modellen lære å alltid forutsi A. Balanser datasettet ved å: oversample minoritetskategorier (duplisere sjeldne eksempler), undersample majoritetskategorier eller generere syntetiske eksempler for underrepresenterte tilfeller ved hjelp av 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 balancedRensing og normalisering av data
Treningsdata inneholder ofte inkonsekvenser som svekker fine-tuning: blandet bruk av store og små bokstaver i utdatafelt, avsluttende mellomrom, inkonsekvent bruk av anførselstegn, blandede tallformater eller varierende navnekonvensjoner for JSON-nøkler. Normaliser dette før treningen. Den finjusterte modellen lærer det nøyaktige formatet som finnes i dataene Deres – hvis dataene er inkonsekvente, vil modellen gjenskape inkonsekvensene.
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]Måling av kvalitetsmåltall for datasett
Før De sender inn data til fine-tuning, bør De beregne kvalitetsmåltall for hele datasettet. Kontroller: gjennomsnittlig og maksimalt antall tokens per eksempel (lange eksempler koster mer å trene og kan bli avkortet), vokabulardekning (dekker datasettet hele variasjonen i inndata fra produksjon?) og konsistensskår (får lignende inndata lignende utdata?). De fleste leverandører av fine-tuning har et endepunkt for datavalidering som kontrollerer formatfeil før De blir fakturert for en mislykket treningskjøring.
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 reportIterativ forbedring av datasettet
Forberedelse av datasett er en iterativ prosess. Finjuster en liten modell på det første datasettet, evaluer den på eksempler som er holdt utenfor treningen, identifiser feilmønstrene og spor dem tilbake til mangler eller kvalitetsproblemer i datasettet. Rett deretter opp dataene og tren på nytt. Denne sløyfen for feildrevet dataforbedring er standard praksis ved fine-tuning i produksjon og er langt mer effektiv enn å forsøke å samle inn et perfekt datasett i én omgang.
Konsistent systemprompt på tvers av eksempler
Hvis den finjusterte modellen alltid skal bruke den samme systemprompten i produksjon, må De inkludere nøyaktig denne systemprompten i hvert treningseksempel. Hvis De ønsker at modellen skal fungere uten en systemprompt, må De trene den uten systemprompt. Uoverensstemmelser mellom trenings- og inferensbetingelsene er en hovedårsak til at finjustering ikke innfrir forventningene. Modellen lærer atferd som avhenger av den nøyaktige promptstrukturen den ser under treningen.
Hurtigsjekk
Test forståelsen Deres av hvordan man klargjør et treningsdatasett for finjustering basert på denne leksjonen.
Oppsummering av leksjonen
I denne leksjonen lærte De at datakvalitet er viktigere enn datamengde ved finjustering — 100 fremragende eksempler gir bedre resultater enn 10 000 middelmådige, deduplisering, validering, balansering og normalisering er de fire viktigste trinnene i datarensing før enhver treningskjøring, og inndelingen i trening og validering er avgjørende for å oppdage overtilpasning under treningen, før den svekker ytelsen i den virkelige verden. Neste trinn er å kjøre LoRA-finjustering med Hugging Face PEFT.
Lær deg Python med en AI-veileder – gratis
Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.
- Kurs
- 30
- Leksjoner
- 120
Ofte stilte spørsmål
Er leksjonen «Forberede et opplæringsdatasett av høy kvalitet» gratis?
Ja – hele teksten i «Forberede et opplæringsdatasett av høy kvalitet» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av AI Engineering Academy-kurset, kan du oppgradere til CoddyKit PRO. Kurset i AI Engineering Academy inneholder totalt 4 leksjoner.
Hva lærer jeg i «Forberede et opplæringsdatasett av høy kvalitet»?
Samle inn, rens og formater instruksjonsdata i formatene Alpaca og ShareGPT, fjern duplikater i dataene, og del dem inn i trenings- og valideringssett. Du øver på AI Engineering Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.
Trenger jeg erfaring for å begynne med AI Engineering Academy?
Ingen tidligere erfaring er nødvendig. AI Engineering Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 2 av 4.
Hvor lang tid tar leksjonen «Forberede et opplæringsdatasett av høy kvalitet»?
De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.
Kan jeg skrive og kjøre kode i denne AI Engineering Academy-leksjonen?
Ja. Alle AI Engineering Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.
Alle leksjonene i dette kurset
- Når finjustering er bedre enn prompting
- Forberede et opplæringsdatasett av høy kvalitet
- LoRA-finjustering med Hugging Face PEFT
- Evaluere og distribuere den finjusterte modellen