9.4 KiB
9.4 KiB
SFT 데이터 품질 감사 보고서
날짜: 2026-02-26
데이터: data/sft/train.jsonl (159,125 샘플)
소스: 6개 HuggingFace 데이터셋 (KOR-OpenOrca-Platypus-v3, kullm-v2, ko-alpaca-12k, korean_safe_conversation, evol-instruct-korean, kovast)
1. 데이터 기본 통계
| 항목 | 값 |
|---|---|
| 총 샘플 수 | 159,125 |
| Output 평균 길이 | 608 chars |
| Output 중앙값 | 468 chars |
| Output 최소/최대 | 10 / 7,393 chars |
| 중복 (instruction+output) | 0 (dedup 적용됨) |
| 중복 (instruction only) | 0 |
Output 길이 분포
| 구간 | 수량 | 비율 |
|---|---|---|
| < 50 chars | 16,519 | 10.4% |
| 50-100 | 11,112 | 7.0% |
| 100-500 | 55,550 | 34.9% |
| 500-1000 | 47,023 | 29.6% |
| 1000-2000 | 23,731 | 14.9% |
| 2000-4000 | 5,049 | 3.2% |
| > 4000 | 141 | 0.1% |
2. 발견된 품질 문제
🔴 심각 (반복 루프 직접 원인 가능성)
문제 1: 특수 토큰 오염 — </s> 113건
- Output 텍스트 안에
</s>문자열이 리터럴로 포함된 샘플 113건 - 영향: 학습 시 chat template이
{output}</s>를 붙이므로, output 내부의</s>는 premature EOS를 학습시킴. 이후 모델이 EOS를 제대로 생성하지 못하거나, EOS 이후에도 계속 생성하는 패턴을 학습 - 기타:
<|endoftext|>1건,EOS44건,[PAD]3건
문제 2: Output 내 질문/답변 마커 — 약 550건
"질문:"503건,"답변:"430건 (output 내부)"### 답변:"141건,"### 질문:"10건"### Instruction:"4건,"### Response:"2건- 영향: 모델이 답변 중에 "질문:" → "답변:" 패턴을 학습하여 자체적으로 Q/A 루프를 생성
문제 3: Self-repetition 패턴 — 57건
- 10-gram 기준 50% 이상 반복되는 output 57건
- 영향: 반복 생성 패턴을 직접 학습
🟡 중간 (품질 저하)
문제 4: 짧은 Output — 16,519건 (10.4%)
- 50자 미만 output이 전체의 10.4%
- 30자 미만은 8,833건
- 영향: 모델이 충분히 긴 답변을 생성하는 능력 저하. 짧게 끝내야 할 곳에서 EOS를 배우지만, 대부분의 질문에서는 너무 짧은 답변 → EOS 미생성 → 계속 생성 → 루프
문제 5: 낮은 한국어 비율 — 21,774건 (13.7%)
- 한글 문자 비율 30% 미만인 샘플 (코드, 영어, 중국어 등 혼재)
prepare_sft_data.py의 필터가 이미 30% 기준을 적용하지만, 가중치 샘플링 이후 적용 순서 문제 가능성- 영향: 한국어 LLM으로서의 일관성 저하
3. 가설 검증 결과
가설 A: Output에 Q/A 루프 패턴 존재 → ⚠️ 부분 확인
### 질문: ... ### 답변:정확한 패턴: 4건 (0.003%)질문: ... 답변:비공식 패턴: 119건 (0.07%)- 단순 "질문:" 또는 "답변:" 포함: ~550건
- 결론: 정확한 루프 패턴은 극소수이나, "질문/답변" 키워드가 output에 포함된 샘플이 수백 건 존재. 이것만으로 루프의 주 원인이라 보기 어려움.
가설 B: 짧은 Output → ✅ 유력 원인
- 50자 미만 16,519건 (10.4%)이 output 분포의 상당 부분
- 모델이 짧은 답변 후 EOS를 생성하지 못하고 계속 토큰을 생성할 가능성
- 특히
</s>토큰 오염(113건)과 결합하면: 모델이 EOS 경계를 정확히 학습하지 못함
가설 C: 소스별 품질 편차 → ✅ 확인 (간접)
prepare_sft_data.py기준: KOR-OpenOrca-Platypus-v3 5배 업샘플링, kovast 0.8배 다운샘플링- 가중치가 매우 공격적 (5.0배는 동일 데이터 5회 반복 = 과적합 위험)
- kovast는 멀티턴 대화에서 첫 턴만 추출 → 문맥 부족으로 이상한 output 가능
- 결론: 5배 업샘플링된 OpenOrca-Platypus가 주 학습 데이터를 지배. 해당 소스에 문제가 있으면 전체 모델에 직접 영향.
🔍 추가 발견: 반복 루프의 진짜 원인 추정
EOS 학습 실패가 핵심. 원인 조합:
- Output 내
</s>리터럴 (113건) → EOS 경계 혼란 - 짧은 output 10.4% → EOS 타이밍 학습 불안정
- 5000 steps로 159K 데이터 학습 → 각 샘플 평균 1.6 epoch도 안 됨 → underfitting 가능
- inference 시 repetition_penalty 미적용 (eval 코드에는 top_p/top_k만 있고 repetition_penalty 없음)
4. 즉시 적용 가능한 데이터 필터링 코드
"""
enhanced_quality_filter.py — SFT 데이터 품질 강화 필터
Usage: python enhanced_quality_filter.py data/sft/train.jsonl data/sft/train_cleaned.jsonl
"""
import json
import re
import sys
def enhanced_filter(sample: dict) -> bool:
instruction = sample.get("instruction", "").strip()
output = sample.get("output", "").strip()
# 1. 기본 길이 필터 (강화)
if len(output) < 80: # 50 → 80으로 상향
return False
if len(output) > 3000: # 4000 → 3000으로 하향
return False
if len(instruction) < 15:
return False
# 2. 특수 토큰 제거
BAD_TOKENS = ["</s>", "<|endoftext|>", "<|end|>", "<s>", "<pad>", "[PAD]", "<unk>"]
for tok in BAD_TOKENS:
if tok in output:
return False
# 3. Q/A 마커 오염 제거
QA_PATTERNS = [
r"###\s*(질문|답변|Instruction|Response|Input|Output)\s*:",
r"^(질문|답변)\s*:", # 줄 시작에서 "질문:" "답변:"
]
for pat in QA_PATTERNS:
if re.search(pat, output, re.MULTILINE):
return False
# 4. 한국어 비율 강화 (30% → 40%)
ko_chars = sum(1 for c in output if '\uac00' <= c <= '\ud7a3')
if len(output) > 0 and ko_chars / len(output) < 0.4:
return False
# 5. N-gram 반복 필터 (강화)
words = output.split()
if len(words) > 15:
# 5-gram 반복 체크
fivegrams = [tuple(words[i:i+5]) for i in range(len(words) - 4)]
if fivegrams:
unique_ratio = len(set(fivegrams)) / len(fivegrams)
if unique_ratio < 0.7: # 30% 이상 반복이면 제거
return False
# 6. "EOS" 리터럴 제거
if re.search(r'\bEOS\b', output):
return False
return True
def main():
input_path = sys.argv[1]
output_path = sys.argv[2]
kept, dropped = 0, 0
with open(input_path) as fin, open(output_path, "w") as fout:
for line in fin:
sample = json.loads(line)
if enhanced_filter(sample):
fout.write(line)
kept += 1
else:
dropped += 1
print(f"Kept: {kept:,} | Dropped: {dropped:,} | Drop rate: {dropped/(kept+dropped)*100:.1f}%")
if __name__ == "__main__":
main()
5. 데이터 파이프라인 개선 권장사항
5.1 가중치 재조정
현재 가중치가 너무 공격적. 권장 변경:
DATASET_WEIGHTS = {
"KOR-OpenOrca-Platypus-v3": 2.0, # 5.0 → 2.0 (과적합 방지)
"kullm-v2": 1.0,
"ko-alpaca-12k": 1.5, # 2.0 → 1.5
"korean_safe_conversation": 1.0, # 1.5 → 1.0
"evol-instruct-korean": 1.5,
"kovast": 0.5, # 0.8 → 0.5 (품질 이슈)
}
5.2 학습 설정 수정
# 현재: 5000 steps, batch 4×8×2 = 64
# 159K samples / 64 = 2,486 steps/epoch → 현재 약 2 epochs
# 권장: 필터링 후 ~120K 데이터로 3 epochs
MAX_STEPS=6000
5.3 Inference 시 repetition_penalty 추가
# eval/comprehensive_eval.py 수정
repetition_penalty = 1.2 # 반복 억제
6. 추천 고품질 데이터셋 (HuggingFace)
| 데이터셋 | URL | 설명 | 예상 크기 |
|---|---|---|---|
| Open-Orca Korean | kyujinpy/KOR-OpenOrca-Platypus-v3 |
이미 사용 중 | - |
| ShareGPT Korean | junelee/sharegpt_deepl_ko |
ShareGPT 한국어 번역 | ~90K |
| KoAlpaca v1.1 | beomi/KoAlpaca-v1.1a |
고품질 한국어 Alpaca | ~21K |
| LIMA Korean | HAERAE-HUB/KMMLU |
한국어 벤치마크 (평가용) | - |
| Korean HC3 | heegyu/korean_chatgpt_corpus |
ChatGPT 한국어 대화 | ~12K |
| Orca DPO Korean | kyujinpy/orca_dpo_pairs_ko |
DPO 페어 (SFT+DPO 가능) | ~12K |
| OpenHermes 2.5 Ko | maywell/ko_Ultrafeedback_binarized |
한국어 Ultrafeedback | ~60K |
| KOpen-platypus | kyujinpy/KOpen-platypus |
한국어 Platypus | ~25K |
가장 추천하는 추가 데이터:
junelee/sharegpt_deepl_ko— 다양한 주제의 멀티턴 대화, 충분히 긴 outputheegyu/korean_chatgpt_corpus— ChatGPT 품질 한국어 답변beomi/KoAlpaca-v1.1a— 검증된 한국어 instruction 데이터
7. 요약: 즉시 조치 사항
| 우선순위 | 조치 | 예상 효과 |
|---|---|---|
| 🔴 P0 | </s>, `< |
endoftext |
| 🔴 P0 | Output 최소 길이 80자로 상향 | 짧은 답변으로 인한 EOS 미학습 방지 |
| 🔴 P0 | Inference에 repetition_penalty=1.2 추가 |
즉시 반복 루프 완화 |
| 🟡 P1 | Q/A 마커 포함 샘플 제거 (~550건) | 자체 Q/A 루프 패턴 학습 방지 |
| 🟡 P1 | OpenOrca 가중치 5.0 → 2.0 | 과적합 방지, 다양성 확보 |
| 🟡 P1 | 한국어 비율 필터 40%로 강화 | 한국어 일관성 향상 |
| 🟢 P2 | 추가 고품질 데이터셋 수집 | 전반적 품질 향상 |
| 🟢 P2 | Self-repetition 필터 강화 (5-gram, 70% threshold) | 반복 패턴 원천 차단 |
예상 필터링 후 데이터: ~120,000-130,000 샘플 (현재 대비 18-25% 제거)