고품질 학습 데이터셋 준비
Alpaca 및 ShareGPT 형식의 지시 따르기 데이터를 수집·정제·서식화하고, 데이터 중복을 제거한 뒤 학습 세트와 검증 세트로 나눕니다.
고품질 학습 데이터셋 준비은(는) CoddyKit의 무료 AI Engineering Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 AI Engineering Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. AI Engineering Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
데이터는 미세 조정에서 가장 중요한 요소입니다
미세 조정에서는 어떤 하이퍼파라미터, 아키텍처 선택 또는 학습 기법보다 학습 데이터의 품질이 중요합니다. 고품질 예시 100개가 평범한 예시 10,000개보다 뛰어납니다. 입력이 형편없으면 출력도 형편없습니다. 미세 조정된 모델은 실수, 편향, 형식 불일치를 포함하여 데이터에 존재하는 패턴을 무엇이든 충실하게 재현합니다. 데이터 품질에 투자하는 것은 모든 미세 조정 프로젝트에서 가장 큰 효과를 내는 활동입니다.
지시 따르기 형식
지시 따르기 작업을 위한 대부분의 미세 조정은 시스템, 사용자, 어시스턴트 역할을 사용하는 대화형 메시지 형식으로 이루어집니다. OpenAI의 미세 조정 API는 각 줄이 완전한 대화 예시인 JSONL 파일을 사용합니다. Alpaca 형식(지시/입력/출력)과 ShareGPT 형식(대화 목록)도 널리 사용됩니다. 사용하려는 미세 조정 프레임워크에 맞는 형식을 선택하십시오.
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...학습 데이터 수집: 세 가지 전략
미세 조정 데이터셋을 구축하는 주요 전략은 세 가지입니다. 사람이 생성하기: 전문가가 이상적인 예시를 직접 작성합니다. 품질은 가장 높지만 느리고 비용이 많이 듭니다. LLM으로 생성하기: 강력한 모델(GPT-4o)이 예시를 생성하고 사람이 이를 검증합니다. 훨씬 빠르고 저렴하며, 검증을 거치면 품질도 좋습니다. 로그에서 추출하기: 기존 운영 로그에서 입력-출력 쌍을 추출하고, 사용자 평가나 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}
]
}품질 필터링 및 검증
모든 학습 예시는 포함하기 전에 품질 검증 단계를 통과해야 합니다. 응답이 올바른 형식인지, 사실 기반 작업의 경우 응답이 정확한지, 환각이나 유해한 콘텐츠가 포함되지 않았는지, 지시와 응답의 쌍이 일관되는지, 예시가 실제 운영 사용 사례를 대표하는지 검증하십시오. 형식 검사는 자동 검증을 사용하고, 콘텐츠 품질은 LLM 심사 방식을 사용하되 일부는 사람이 검토하십시오.
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)}')데이터 중복 제거
학습 데이터에 중복되거나 거의 중복되는 예시가 있으면 해롭습니다. 이러한 예시에 모델이 과도하게 맞춰지고, 다양한 패턴을 학습하는 데 사용할 수 있는 학습 역량이 낭비됩니다. 데이터셋을 확정하기 전에 중복을 제거하십시오. 완전 중복 제거는 해시를 사용해 동일한 예시를 찾습니다. 유사 중복 제거는 MinHash 또는 임베딩 유사도를 사용해 사소한 부분만 다른 예시를 찾습니다.
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)]학습/검증 분할
미세 조정 실행을 시작하기 전에 데이터셋을 학습 세트와 검증 세트로 나누십시오. 검증 세트는 학습 중 과적합을 감시하는 데 사용됩니다(학습 손실은 감소하는데 검증 손실이 증가하면 모델이 과적합되고 있는 것입니다). 일반적인 분할은 학습 90%와 검증 10%입니다. 데이터셋에 의미 있는 범주가 있다면 분할이 무작위이면서 층화되도록 하십시오(예: 두 세트 모두 모든 의도 유형이 동일한 비율로 포함되도록 함).
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)})')데이터셋 균형 맞추기
불균형한 데이터셋은 미세 조정된 모델이 흔한 경우에 과도하게 특화되고 드물지만 중요한 경우에는 실패하게 만듭니다. 데이터셋에 범주 A의 예시가 900개, 범주 B의 예시가 100개 있다면 모델은 항상 A를 예측하도록 학습할 수 있습니다. 다음 방법으로 데이터셋의 균형을 맞추십시오. 소수 범주를 오버샘플링(드문 예시 복제)하거나, 다수 범주를 언더샘플링하거나, 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 balanced데이터 정리 및 정규화
학습 데이터에는 미세 조정을 방해하는 불일치가 자주 포함됩니다. 출력 필드의 대소문자 혼용, 뒤따르는 공백, 따옴표 사용 방식의 불일치, 숫자 형식 혼용, JSON 키 이름 지정 규칙의 차이 등이 그 예입니다. 학습 전에 이러한 요소를 정규화하십시오. 미세 조정된 모델은 데이터에 존재하는 정확한 형식을 학습하므로 데이터에 불일치가 있으면 모델도 이를 재현합니다.
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]데이터셋 품질 지표 측정
미세 조정을 위해 데이터를 제출하기 전에 데이터셋 전체에 대해 품질 지표를 계산하십시오. 예시당 평균 및 최대 토큰 수(긴 예시는 학습 비용이 더 많이 들고 잘릴 수 있음), 어휘 범위(데이터셋이 실제 운영 입력의 전체 다양성을 포함하는가?), 일관성 점수(유사한 입력에 유사한 출력이 나오는가?)를 확인하십시오. 대부분의 미세 조정 제공업체에는 실패한 학습 실행에 대한 비용이 청구되기 전에 형식 오류를 확인하는 데이터 검증 엔드포인트가 있습니다.
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 report반복적인 데이터셋 개선
데이터셋 준비는 반복적인 과정입니다. 초기 데이터셋으로 작은 모델을 미세 조정하고, 보류한 예시로 평가한 다음, 실패 유형을 파악하여 데이터셋의 누락이나 품질 문제까지 거슬러 올라가십시오. 그런 다음 데이터를 수정하고 다시 학습하십시오. 이러한 오류 기반 데이터 개선 순환은 실제 운영 환경의 미세 조정에서 표준적인 방법이며, 한 번에 완벽한 데이터셋을 수집하려는 것보다 훨씬 효과적입니다.
예시 전체에서 시스템 프롬프트의 일관성
미세 조정한 모델이 프로덕션에서 항상 동일한 시스템 프롬프트를 사용한다면, 모든 훈련 예시에 해당 시스템 프롬프트를 정확히 포함해야 합니다. 시스템 프롬프트 없이 모델을 작동시키려면 시스템 프롬프트 없이 훈련해야 합니다. 훈련 조건과 추론 조건이 일치하지 않는 것은 미세 조정이 기대에 미치지 못하는 주요 원인입니다. 모델은 훈련 중 접한 정확한 프롬프트 구조에 따라 조건화된 동작을 학습합니다.
빠른 확인
이 레슨에서 배운 미세 조정 훈련 데이터셋 준비 방법을 이해했는지 테스트해 보세요.
레슨 요약
이 레슨에서는 다음을 배웠습니다. 미세 조정에서는 데이터의 양보다 품질이 중요합니다. 뛰어난 예시 100개가 평범한 예시 10,000개보다 더 좋은 결과를 냅니다. 또한 훈련을 시작하기 전에 수행해야 할 네 가지 핵심 데이터 정제 단계는 중복 제거, 검증, 균형 조정, 정규화이며, 훈련/검증 분할은 실제 성능이 저하되기 전에 훈련 중 과적합을 감지하는 데 필수적입니다. 다음으로 Hugging Face PEFT를 사용해 LoRA 미세 조정을 실행합니다.
자주 묻는 질문
“고품질 학습 데이터셋 준비” 강의는 무료인가요?
네 — “고품질 학습 데이터셋 준비” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 AI Engineering Academy 강의 전체를 잠금 해제할 수 있습니다. AI Engineering Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“고품질 학습 데이터셋 준비”에서 뭘 배우나요?
Alpaca 및 ShareGPT 형식의 지시 따르기 데이터를 수집·정제·서식화하고, 데이터 중복을 제거한 뒤 학습 세트와 검증 세트로 나눕니다. 브라우저에서 직접 실행하는 실습 코드로 AI Engineering Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
AI Engineering Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 AI Engineering Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.
“고품질 학습 데이터셋 준비” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 AI Engineering Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 AI Engineering Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.