Day 21: 파인튜닝 데이터셋 준비
파인튜닝의 성패는 데이터 품질에 달려 있습니다. 아무리 좋은 모델과 기법을 써도 데이터가 나쁘면 결과도 나쁩니다. 오늘은 실무에서 가장 많이 쓰이는 두 가지 데이터 형식과 준비 과정을 배웁니다.
Alpaca 형식 (Instruction Tuning)
Alpaca 형식은 instruction/input/output 3개 필드로 구성됩니다. 단일 턴 질의응답에 적합합니다.
import json
# Alpaca 형식 데이터 예시
alpaca_data = [
{
"instruction": "주어진 텍스트를 한국어로 번역하세요.",
"input": "The weather is beautiful today.",
"output": "오늘 날씨가 아름답습니다."
},
{
"instruction": "다음 코드의 버그를 찾아 수정하세요.",
"input": "def add(a, b):\n return a - b",
"output": "연산자가 잘못되었습니다. `a - b`를 `a + b`로 수정해야 합니다.\n\n```python\ndef add(a, b):\n return a + b\n```"
},
{
"instruction": "파이썬의 리스트 컴프리헨션을 설명하세요.",
"input": "", # input이 없는 경우 빈 문자열
"output": "리스트 컴프리헨션은 기존 리스트를 기반으로 새 리스트를 간결하게 만드는 문법입니다. `[표현식 for 요소 in 반복가능객체 if 조건]` 형태로 사용합니다."
},
]
# JSON 파일로 저장
with open("train_alpaca.json", "w", encoding="utf-8") as f:
json.dump(alpaca_data, f, ensure_ascii=False, indent=2)
print(f"저장 완료: {len(alpaca_data)}개 샘플")
ShareGPT 형식 (Multi-turn Conversation)
ShareGPT 형식은 여러 턴의 대화를 기록합니다. 챗봇 파인튜닝에 적합합니다.
# ShareGPT 형식 데이터 예시
sharegpt_data = [
{
"conversations": [
{"from": "system", "value": "당신은 파이썬 전문가입니다. 코드와 함께 설명하세요."},
{"from": "human", "value": "딕셔너리와 리스트의 차이점이 뭔가요?"},
{"from": "gpt", "value": "딕셔너리는 키-값 쌍으로 데이터를 저장하고, 리스트는 순서가 있는 값의 모음입니다.\n\n```python\n# 리스트: 인덱스로 접근\nfruits = ['사과', '바나나', '체리']\nprint(fruits[0]) # 사과\n\n# 딕셔너리: 키로 접근\nprices = {'사과': 1000, '바나나': 500}\nprint(prices['사과']) # 1000\n```"},
{"from": "human", "value": "딕셔너리의 키로 리스트를 사용할 수 있나요?"},
{"from": "gpt", "value": "아니요, 리스트는 변경 가능(mutable)하므로 딕셔너리의 키로 사용할 수 없습니다. 키는 반드시 해시 가능(hashable)한 불변 객체여야 합니다. 대신 튜플을 사용할 수 있습니다."},
]
},
]
with open("train_sharegpt.json", "w", encoding="utf-8") as f:
json.dump(sharegpt_data, f, ensure_ascii=False, indent=2)
데이터 정제와 검증
수집한 데이터는 반드시 정제 과정을 거쳐야 합니다. 중복 제거, 품질 필터링, 형식 검증이 핵심입니다.
from datasets import Dataset
import hashlib
def validate_and_clean(data):
"""데이터 품질 검증 및 정제"""
cleaned = []
seen_hashes = set()
issues = {"duplicate": 0, "too_short": 0, "empty_output": 0}
for item in data:
# 빈 출력 제거
if not item.get("output", "").strip():
issues["empty_output"] += 1
continue
# 너무 짧은 출력 제거 (10자 미만)
if len(item["output"].strip()) < 10:
issues["too_short"] += 1
continue
# 중복 제거 (해시 기반)
content_hash = hashlib.md5(
(item["instruction"] + item["output"]).encode()
).hexdigest()
if content_hash in seen_hashes:
issues["duplicate"] += 1
continue
seen_hashes.add(content_hash)
cleaned.append(item)
print(f"원본: {len(data)}개 -> 정제 후: {len(cleaned)}개")
print(f"제거 사유: {issues}")
return cleaned
# 정제 실행
cleaned_data = validate_and_clean(alpaca_data)
# Hugging Face datasets로 변환
dataset = Dataset.from_list(cleaned_data)
print(dataset)
# 학습/검증 분할
split_dataset = dataset.train_test_split(test_size=0.1, seed=42)
print(f"학습: {len(split_dataset['train'])}개, 검증: {len(split_dataset['test'])}개")
datasets 라이브러리로 허브 데이터 로드
from datasets import load_dataset
# Hugging Face Hub에서 공개 데이터셋 로드
dataset = load_dataset("tatsu-lab/alpaca", split="train")
print(f"Alpaca 데이터셋: {len(dataset)}개 샘플")
print(f"컬럼: {dataset.column_names}")
print(f"\n첫 번째 샘플:\n{dataset[0]}")
# 한국어 데이터셋 예시
ko_dataset = load_dataset("heegyu/ko-chatgpt-qa", split="train")
print(f"\n한국어 Q&A: {len(ko_dataset)}개 샘플")
오늘의 연습문제
- 본인의 전문 분야에서 Alpaca 형식으로 20개 이상의 instruction-output 쌍을 직접 작성하고,
validate_and_clean()함수로 검증해보세요. - ShareGPT 형식으로 3턴 이상의 대화 데이터 5개를 작성하고,
datasets라이브러리로 로드하여 학습/검증 세트로 분할해보세요. - Hugging Face Hub에서 한국어 instruction 데이터셋을 3개 이상 찾고, 각각의 크기, 형식, 라이선스, 품질을 비교 분석해보세요.