Przygotowanie wysokiej jakości zbioru treningowego
Zbieraj, oczyszczaj i formatuj dane do uczenia wykonywania instrukcji w formatach Alpaca i ShareGPT, usuwaj duplikaty oraz dziel dane na zbiory treningowy i walidacyjny.
Przygotowanie wysokiej jakości zbioru treningowego to bezpłatna lekcja AI Engineering Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej AI Engineering Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs AI Engineering Academy zawiera 4 lekcji w sumie.
Dane są najważniejszym czynnikiem w fine-tuningu
W fine-tuningu jakość danych treningowych ma większe znaczenie niż jakikolwiek hiperparametr, wybór architektury czy technika trenowania. 100 przykładów wysokiej jakości daje lepsze wyniki niż 10 000 przeciętnych przykładów. Zasada „śmieci na wejściu, śmieci na wyjściu” ma tu pełne zastosowanie — model po fine-tuningu wiernie odtworzy wzorce obecne w danych, w tym błędy, uprzedzenia i niespójności formatowania. Inwestowanie w jakość danych to działanie o największym wpływie w każdym projekcie fine-tuningu.
Formaty wykonywania instrukcji
Większość fine-tuningu zadań związanych z wykonywaniem instrukcji korzysta z konwersacyjnego formatu wiadomości z rolami system, user i assistant. API fine-tuningu OpenAI wykorzystuje pliki JSONL, w których każda linia zawiera kompletny przykład rozmowy. Szeroko stosowane są również format Alpaca (instruction/input/output) i format ShareGPT (lista conversations). Proszę wybrać format zgodny z planowanym frameworkiem fine-tuningu.
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...Gromadzenie danych treningowych: trzy strategie
Istnieją trzy główne strategie tworzenia zbioru danych do fine-tuningu. Generowanie przez ludzi: eksperci ręcznie piszą idealne przykłady — jakość jest najwyższa, ale proces powolny i kosztowny. Generowanie przez LLM: wydajny model (GPT-4o) tworzy przykłady, które następnie są weryfikowane przez ludzi — jest to znacznie szybsze i tańsze, a jakość jest dobra, jeśli przykłady zostaną sprawdzone. Wydobywanie z logów: należy wyodrębnić pary wejście–wyjście z istniejących logów produkcyjnych i odfiltrować przykłady wysokiej jakości na podstawie sygnałów jakości, takich jak oceny użytkowników lub punktacja 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}
]
}Filtrowanie i walidacja jakości
Każdy przykład treningowy powinien przejść walidację jakości przed uwzględnieniem go w zbiorze. Należy sprawdzić, czy odpowiedź ma właściwy format, jest poprawna (w przypadku zadań wymagających faktów), nie zawiera halucynacji ani szkodliwych treści, para instrukcja–odpowiedź jest spójna, a przykład reprezentuje produkcyjne zastosowanie. Do sprawdzania formatu należy używać automatycznej walidacji, a do oceny jakości treści LLM-as-judge; wybrane przykłady powinny zostać poddane weryfikacji przez człowieka.
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)}')Ded uplikacja danych
Duplikaty i niemal identyczne przykłady w danych treningowych są szkodliwe. Powodują nadmierne dopasowanie modelu do konkretnych przykładów i marnują potencjał treningu, który mógłby zostać wykorzystany do nauczenia się różnorodnych wzorców. Przed sfinalizowaniem zbioru należy przeprowadzić deduplikację. Ded uplikacja dokładna wykorzystuje haszowanie do znajdowania identycznych przykładów. Ded uplikacja przybliżona wykorzystuje MinHash lub podobieństwo embeddingów do znajdowania przykładów różniących się wyłącznie nieistotnymi szczegółami.
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)]Podział na zbiór treningowy i walidacyjny
Przed rozpoczęciem dowolnego uruchomienia fine-tuningu należy podzielić zbiór danych na zbiór treningowy i walidacyjny. Zbiór walidacyjny służy do monitorowania nadmiernego dopasowania podczas trenowania (jeśli strata walidacyjna rośnie, a strata treningowa maleje, model jest nadmiernie dopasowany). Typowy podział to 90% danych treningowych i 10% walidacyjnych. Podział powinien być losowy i stratyfikowany, jeśli zbiór ma istotne kategorie (np. oba zbiory powinny zawierać równą reprezentację wszystkich typów intencji).
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)})')Równoważenie zbioru danych
Niezrównoważone zbiory danych powodują, że modele po fine-tuningu nadmiernie specjalizują się w częstych przypadkach i zawodzą w przypadku rzadkich, ale ważnych sytuacji. Jeśli zbiór zawiera 900 przykładów kategorii A i 100 przykładów kategorii B, model może nauczyć się zawsze przewidywać A. Zbiór można zrównoważyć przez: oversampling mniejszościowych kategorii (duplikowanie rzadkich przykładów), undersampling większościowych kategorii lub generowanie przykładów syntetycznych dla niedostatecznie reprezentowanych przypadków za pomocą 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 balancedCzyszczenie i normalizacja danych
Dane treningowe często zawierają niespójności, które pogarszają fine-tuning: różną wielkość liter w polach wyjściowych, końcowe białe znaki, niespójne użycie cudzysłowów, różne formaty liczb lub różne konwencje nazewnictwa kluczy JSON. Przed trenowaniem należy je znormalizować. Model po fine-tuningu nauczy się dokładnego formatowania obecnego w danych — jeśli dane są niespójne, model będzie te niespójności odtwarzać.
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]Pomiar metryk jakości zbioru danych
Przed przesłaniem danych do fine-tuningu należy obliczyć metryki jakości dla całego zbioru. Proszę sprawdzić: średnią i maksymalną liczbę tokenów na przykład (długie przykłady kosztują więcej podczas trenowania i mogą zostać ucięte), pokrycie słownictwa (czy zbiór obejmuje pełną różnorodność danych wejściowych z produkcji?) oraz wynik spójności (czy podobne dane wejściowe otrzymują podobne dane wyjściowe?). Większość dostawców fine-tuningu udostępnia endpoint walidacji danych, który sprawdza błędy formatu, zanim zostanie naliczona opłata za nieudane trenowanie.
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 reportIteracyjne doskonalenie zbioru danych
Przygotowanie zbioru danych jest procesem iteracyjnym. Należy wytrenować mały model na początkowym zbiorze, ocenić go na odłożonych przykładach, zidentyfikować tryby błędów i prześledzić ich przyczyny w brakach lub problemach z jakością danych. Następnie należy poprawić dane i ponownie przeprowadzić trening. Ta pętla doskonalenia danych opartego na błędach jest standardową praktyką w produkcyjnym fine-tuningu i jest znacznie skuteczniejsza niż próba zebrania idealnego zbioru za jednym razem.
Spójność promptu systemowego między przykładami
Jeśli dostrajany model będzie zawsze używać tego samego promptu systemowego w środowisku produkcyjnym, należy uwzględnić ten dokładny prompt systemowy w każdym przykładzie treningowym. Jeśli model ma działać bez promptu systemowego, należy trenować go bez niego. Niezgodność między warunkami treningu a warunkami wnioskowania jest jedną z głównych przyczyn niespełnienia oczekiwań związanych z dostrajaniem. Model uczy się zachowań uwarunkowanych dokładną strukturą promptu, którą widzi podczas treningu.
Szybkie sprawdzenie
Sprawdź swoją wiedzę na temat przygotowywania zbioru danych treningowych do dostrajania na podstawie tej lekcji.
Podsumowanie lekcji
W tej lekcji poznali Państwo następujące zagadnienia: w dostrajaniu jakość danych jest ważniejsza niż ich ilość — 100 doskonałych przykładów daje lepsze rezultaty niż 10 000 przeciętnych; deduplikacja, walidacja, równoważenie i normalizacja to cztery kluczowe etapy czyszczenia danych przed każdym uruchomieniem treningu; a podział na zbiór treningowy i walidacyjny jest niezbędny do wykrywania przeuczenia podczas treningu, zanim pogorszy ono wydajność w rzeczywistych zastosowaniach. Następnie przeprowadzimy dostrajanie LoRA za pomocą Hugging Face PEFT.
Często zadawane pytania
Czy lekcja „Przygotowanie wysokiej jakości zbioru treningowego” jest bezpłatna?
Tak — pełny tekst „Przygotowanie wysokiej jakości zbioru treningowego” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu AI Engineering Academy, przejdź na CoddyKit PRO. Kurs AI Engineering Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Przygotowanie wysokiej jakości zbioru treningowego”?
Zbieraj, oczyszczaj i formatuj dane do uczenia wykonywania instrukcji w formatach Alpaca i ShareGPT, usuwaj duplikaty oraz dziel dane na zbiory treningowy i walidacyjny. Ćwiczysz AI Engineering Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć AI Engineering Academy?
Nie wymagamy żadnego doświadczenia. AI Engineering Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.
Ile czasu zajmuje lekcja „Przygotowanie wysokiej jakości zbioru treningowego”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji AI Engineering Academy?
Tak. Każda lekcja AI Engineering Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Kiedy fine-tuning przewyższa promptowanie
- Przygotowanie wysokiej jakości zbioru treningowego
- Fine-tuning LoRA z Hugging Face PEFT
- Ocena i wdrażanie dostrojonego modelu