https://youtu.be/HTBl142x9GI?si=Jp1Sl2pisGmNxIJr
🎓 카카오 LLM 개발기로 배우는 실전 언어모델 학습 로드맵
📚 학습 주제 체계
카카오의 개발 과정을 분석하면, LLM 개발은 크게 4개의 핵심 영역으로 구성됩니다:
1. 데이터 엔지니어링 (Data Engineering)
└─ 수집, 정제, 품질 평가, 라이선스 관리
2. 프리트레이닝 전략 (Pre-training Strategy)
└─ 학습 설계, 아키텍처, 최적화
3. 포스트트레이닝 (Post-training)
└─ SFT, 선호도 학습, 얼라인먼트
4. 모델 최적화 (Model Optimization)
└─ Pruning, Distillation, 경량화
📖 Part 1: 데이터 엔지니어링 - LLM의 숨은 90%
핵심 통찰
"모델 구조 개선보다는 데이터 품질 및 구성을 개선하는 데 집중하고 있다" - 카카오 개발팀
1.1 데이터 수집과 라이선스 관리
왜 중요한가?
- 상용 서비스를 위해서는 법적으로 안전한 데이터만 사용 가능
- 데이터 출처가 모델의 법적 리스크를 결정
학습 포인트:
# 라이선스 분류 체계
PERMISSIVE_LICENSES = [
'Apache-2.0',
'MIT',
'BSD-3-Clause',
'Creative Commons (상업적 이용 허용)'
]
RESTRICTIVE_LICENSES = [
'GPL-3.0', # 파생 작품도 같은 라이선스
'CC-BY-NC', # 비상업적 이용만 허용
'저작권 보호 콘텐츠'
]
# 실제 판단 기준
def is_safe_for_commercial(license_type):
"""
상용 서비스에 안전한 데이터인가?
카카오의 선택:
- 나무위키 제외 (CC-BY-NC-SA)
- 뉴스 기사 제외 (저작권)
- The Stack v2에서 MIT 등만 필터링
"""
return license_type in PERMISSIVE_LICENSES
실전 과제:
- Hugging Face의 공개 데이터셋 100개를 조사하여 라이선스 분류표 작성
- Common Crawl에서 특정 도메인 데이터 수집 시 고려사항 정리
1.2 데이터 품질 평가: Educational Score 시스템
카카오의 3단계 파이프라인:
[Stage 1] GPT-4로 샘플 평가
↓
[Stage 2] 경량 평가 모델 학습
↓
[Stage 3] 전체 말뭉치 스코어링
구체적 구현 예시:
# Stage 1: GPT-4를 이용한 Educational Score 측정
EVAL_PROMPT = """
다음 문서가 언어 모델 학습에 얼마나 교육적인지 평가하세요.
평가 기준:
1. 정보의 정확성과 신뢰성
2. 문장 구조와 문법의 정확성
3. 논리적 흐름과 일관성
4. 전문성과 깊이
5. 학습 가치 (일반 상식 vs 전문 지식)
점수: 1-10 (10이 가장 교육적)
이유: [간단한 설명]
문서:
{document}
"""
# Stage 2: 경량 평가 모델 학습
from transformers import AutoModelForSequenceClassification
# FastText 기반 또는 작은 BERT 모델
model = AutoModelForSequenceClassification.from_pretrained(
'bert-base-uncased', # 또는 distilbert
num_labels=10 # 1-10 점수 회귀
)
# GPT-4가 평가한 샘플로 학습
training_data = [
{"text": doc, "score": gpt4_score}
for doc, gpt4_score in scored_samples
]
# Stage 3: 대규모 평가
def filter_high_quality_data(corpus, threshold=7.0):
"""
경량 모델로 전체 말뭉치 평가
카카오의 결과:
"교육 점수 기반 선별이 무작위 선별보다
벤치마크 성능 향상에 효과적"
"""
scores = quality_model.predict(corpus)
return corpus[scores >= threshold]
학습 실습:
- FineWeb-Edu 데이터셋의 평가 방식 분석
- DataComp-LM의 FastText 기반 필터링 재현
- 한국어 문서 1000개에 대해 품질 평가 모델 직접 학습
1.3 도메인별 데이터 전처리
Case Study 1: Wikipedia 수식 복원
문제 발견:
# 기존 공개 데이터 (수식 손실)
코리올리 효과: F = -2mΩ×v
→ 실제 렌더링: "F = -2m?�v" (깨짐)
# 카카오의 해결책
원본 Wikipedia에서 직접 파싱
→ LaTeX 수식 보존
→ 올바른 렌더링: F = -2m\Omega \times v
구현 방향:
import mwparserfromhell
import wikitextparser
def parse_wikipedia_with_formulas(wiki_text):
"""
Wikipedia 원본에서 수식을 보존하여 파싱
핵심:
- <math> 태그 감지
- LaTeX 구문 유지
- 주변 컨텍스트와 통합
"""
wikicode = mwparserfromhell.parse(wiki_text)
# math 태그 추출
for tag in wikicode.filter_tags():
if tag.tag == "math":
latex_formula = tag.contents
# LaTeX를 그대로 유지하거나 적절히 변환
return cleaned_text_with_formulas
Case Study 2: Code 데이터 필터링
# Stage 1: 대규모 다양성 확보
sources = [
"The Stack v2 (MIT license only)", # 433B → 217B tokens
"StarCoder data"
]
# Stage 2: 집중 강화
stage2_code_data = {
"python_only": filter_by_language(stage1_data, "python"),
"code_with_explanation": get_mixed_nl_code_data(),
"sft_data": load_code_instruction_data()
}
# 카카오의 발견:
# → Stage 2에서 Python만 집중하는 것이
# 코드 벤치마크 성능 향상에 효과적
학습 과제:
- Hugging Face의 Wikipedia 데이터 품질 직접 검증
- The Stack v2에서 라이선스별 토큰 수 분석
- 코드 + 자연어 혼합 데이터셋 3개 이상 찾기
📖 Part 2: 프리트레이닝 전략 - 효율적 학습 설계
핵심 통찰
"Llama 3.1 8B의 20% 데이터로 더 강력한 성능 달성"
2.1 Two-Stage Pre-training 철학
설계 원칙:
Stage 1 (Foundation) Stage 2 (Specialization)
├─ 목표: Broad Knowledge ├─ 목표: Deep Expertise
├─ 데이터: 2.7T tokens ├─ 데이터: 0.3T tokens
├─ 전략: Diversity + Quantity ├─ 전략: Quality + Goal
└─ 비유: "뇌 근육 키우기" └─ 비유: "명석한 두뇌 만들기"
Data Mixing Ratios (예시):
# Stage 1 분포 (광범위한 기초)
stage1_distribution = {
"Common Sense & General Knowledge": 40%,
"Code": 15%,
"Wikipedia": 10%,
"Academic Papers": 15%,
"Books": 10%,
"Conversations": 10%
}
# Stage 2 분포 (목표 중심)
stage2_distribution = {
"High-quality filtered general": 30%,
"STEM focused": 25%, # 성능 약점 보완
"Code (Python)": 20%,
"Math + SFT instruction": 15%, # 수학 성능 향상
"Wikipedia": 10%
}
# 카카오의 발견:
# "Stage 1의 goal별 distribution을 유지하고,
# data quality만 개선해도 성능 향상됨"
2.2 Ablation Study: 체계적 실험 설계
Stage 1 최적화 (4개 실험, 250B tokens)
# 목표: MMLU(영어) + KMMLU/HELLM(한국어) 동시 최대화
ablation_configs = {
"ablation_1": {
"focus": "MMLU 최적화",
"english_general": "높음",
"korean_cultural": "보통"
},
"ablation_2": {
"focus": "균형",
"english_general": "보통",
"korean_cultural": "보통"
},
"ablation_3": {
"focus": "HELLM 최적화",
"english_general": "보통",
"korean_cultural": "높음"
},
"ablation_4": {
"focus": "저품질 영어 제거",
"english_general": "낮음 (고품질만)",
"korean_cultural": "보통"
}
}
# 최종 선택:
# ablation_1 + ablation_3 장점 결합 + 저품질 데이터 제거
Stage 2 최적화 (17개 실험!)
카카오가 발견한 3대 성능 향상 요소:
# 1. Goal별 데이터 분포 조정
key_finding_1 = """
데이터의 목표(Goal) 분포를 미세 조정하는 것이
특정 벤치마크 성능을 끌어올리는 핵심
"""
# 2. Learning Rate 최적화
key_finding_2 = """
고품질 데이터 사용 시
상대적으로 높은 learning rate가 효과적
"""
# 3. Instruction Data 추가
key_finding_3 = """
소량의 명령어(instruction) 데이터 추가가
특히 수학 벤치마크 성능 향상에 기여
"""
# 최종 채택: Ablation 12
# → 56.56점 (가장 높은 성능)
2.3 학습 안정화 기법
Multi-step Learning Rate Scheduler
from torch.optim.lr_scheduler import MultiStepLR
# DeepSeek-LLM 연구에서 입증된 기법
optimizer = AdamW(model.parameters(), lr=3e-4)
scheduler = MultiStepLR(
optimizer,
milestones=[
int(0.8 * total_steps), # 80% 지점
int(0.9 * total_steps) # 90% 지점
],
gamma=0.1 # 각 milestone에서 lr을 1/10로
)
# 효과: 학습 후반 안정화 + 수렴 개선
Annealing Checkpoint Averaging (SWA 변형)
def average_checkpoints(checkpoint_paths, output_path):
"""
여러 체크포인트의 가중치를 평균
카카오의 적용:
- 'Stage 3'처럼 활용
- 코드 벤치마크 성능 추가 향상
- 일반화 성능 개선
"""
averaged_state = {}
for ckpt_path in checkpoint_paths:
state_dict = torch.load(ckpt_path)
for key, param in state_dict.items():
if key not in averaged_state:
averaged_state[key] = param / len(checkpoint_paths)
else:
averaged_state[key] += param / len(checkpoint_paths)
torch.save(averaged_state, output_path)
return averaged_state
# 사용 시점: 학습 마지막 단계의 여러 체크포인트
학습 실습:
- 작은 모델로 2-Stage 학습 직접 구현
- 4개 ablation 실험으로 데이터 분포 최적화
- SWA 적용 전후 벤치마크 비교
📖 Part 3: 포스트트레이닝 - 말 잘 듣는 모델 만들기
핵심 통찰
"좋은 LLM을 만들기 위해서도 서비스는 중요하다"
3.1 SFT (Supervised Fine-Tuning) 전략
Lesson 1: 실제 서비스 형태의 프롬프트
# ❌ 인위적인 데이터 (비효과적)
poor_example = {
"prompt": "히스토그램을 그리는 파이썬 코드를 작성하시오.",
"response": "[코드 블록]"
}
# ✅ 실제 사용자 대화 (효과적)
good_example = {
"conversation": [
{
"role": "user",
"content": "파이썬 코드" # 간결하고 자연스러움
},
{
"role": "assistant",
"content": "[히스토그램 코드 + 간단한 설명]"
},
{
"role": "user",
"content": "주피터 노트북에서 하려면?" # 연속적 대화
},
{
"role": "assistant",
"content": "[주피터 환경 맞춤 설명]"
}
]
}
# Multi-turn의 핵심: 맥락이 이어지는 자연스러운 소통
데이터 수집 프로세스 구축:
class ServiceBasedDataCollection:
"""
실제 서비스에서 데이터 수집
카카오의 접근:
- 사용자 동의 하에 대화 로그 수집
- 자연스러운 multi-turn 대화 확보
- 서비스 → 데이터 → 모델 개선의 선순환
"""
def collect_conversation(self, user_session):
# 1. 사용자 동의 확인
# 2. 개인정보 익명화
# 3. 대화 맥락 보존하며 저장
pass
def generate_synthetic_multiturn(self, seed_prompt):
"""
모델이 스스로 자연스러운 대화 생성
향후 방향:
"사람이 직접 만들지 않고 모델이 스스로
자연스러운 멀티턴 대화 데이터를 생성"
"""
pass
Lesson 2: 응답 품질의 중요성
# 고품질 응답 업데이트 시스템
class ResponseQualityManager:
def __init__(self):
self.quality_criteria = {
"accuracy": 0.3, # 정확성
"helpfulness": 0.3, # 유용성
"naturalness": 0.2, # 자연스러움
"safety": 0.2 # 안전성
}
def continuous_improvement(self):
"""
카카오의 접근:
"'좋은 답변'의 기준이 변할 수 있으므로,
지속적으로 업데이트할 수 있는 프로세스 구축"
"""
# 1. 최신 모델로 재생성
# 2. 품질 평가
# 3. 기존 데이터 교체
pass
Lesson 3: 도메인별 독립 구축
# 도메인별 데이터셋 구성
sft_datasets = {
"general_conversation": {
"size": "large",
"focus": "자연스러운 대화"
},
"code": {
"size": "medium",
"focus": "실행 가능한 코드 생성"
},
"math": {
"size": "medium",
"focus": "정확한 풀이 과정"
},
"creative_writing": {
"size": "small",
"focus": "창의성과 스타일"
}
}
# 카카오의 발견:
# "여러 도메인 데이터를 섞어도
# 유의미한 간섭 현상이 거의 없음"
# → 모든 도메인 통합 학습 가능
3.2 Preference-Based Learning
Lesson 1: 도메인별 선호도 기준
# 수학 도메인: 정확성 최우선
math_preference_criteria = {
"correct_answer": 0.5, # 최종 답의 정확성
"correct_process": 0.4, # 풀이 과정의 정확성
"explanation_quality": 0.1 # 설명의 친절함
}
# 잘못된 예시
bad_math_response = """
[매우 친절하고 자세한 설명]
하지만 계산 과정에서 실수 발생
→ 오답 도출
"""
# → 이것은 "나쁜 응답"으로 분류해야 함!
# 코드 도메인: 실행 가능성 중요
code_preference_criteria = {
"executable": 0.4, # 실행 가능 여부
"correctness": 0.3, # 의도한 기능 수행
"code_quality": 0.2, # 가독성, 효율성
"explanation": 0.1
}
def evaluate_code_response(code):
"""실제로 실행해서 테스트"""
try:
exec(code)
test_results = run_unit_tests(code)
return test_results.pass_rate
except Exception as e:
return 0 # 실행 불가 = 나쁜 응답
Lesson 2: Online Preference Learning
class OnlinePreferenceLearning:
"""
오프라인 vs 온라인 학습
오프라인: 미리 구축된 정적 데이터셋
온라인: 현재 모델의 출력으로 데이터셋 구성
"""
def offline_learning(self):
"""
장점: 안정적
단점: 모델 개선에 따른 데이터 업데이트 어려움
"""
static_dataset = load_prebuilt_preference_data()
train(model, static_dataset)
def online_learning(self, model, prompts):
"""
카카오의 접근:
"학습 시점의 모델이 직접 여러 응답을 생성하고,
리워드 모델이 평가한 정보를 기반으로 학습"
효과: 반복 적용 시 성능 점진적 향상
"""
for iteration in range(num_iterations):
# 1. 현재 모델로 응답 생성
responses = []
for prompt in prompts:
response_candidates = model.generate(
prompt,
num_return_sequences=4
)
responses.append(response_candidates)
# 2. 리워드 모델로 평가
scores = reward_model.score(prompts, responses)
# 3. 선호도 쌍 구성
preference_pairs = construct_pairs(responses, scores)
# 4. 모델 학습 (DPO, PPO 등)
model.update(preference_pairs)
# 5. 성능 향상 확인
evaluate(model)
리워드 모델 구축:
class RewardModelTraining:
"""
온라인 학습의 핵심: 좋은 리워드 모델
카카오의 우선순위:
"리워드 모델 학습을 최우선으로 진행"
"""
def train_reward_model(self, preference_data):
"""
선호도 데이터로 리워드 모델 학습
입력: (prompt, better_response, worse_response)
출력: 응답 품질 점수 (0-1)
"""
# Bradley-Terry 모델 등 사용
pass
def domain_specific_reward(self, domain):
"""
도메인별 리워드 모델
- 수학: 정확성 검증기
- 코드: 실행 + 테스트
- 일반: 종합 품질 평가
"""
if domain == "math":
return MathCorrectnessVerifier()
elif domain == "code":
return CodeExecutionTester()
else:
return GeneralQualityScorer()
학습 실습:
- 수학/코드 도메인별 선호도 기준 설계
- 작은 모델로 Online DPO 직접 구현
- 리워드 모델 학습 파이프라인 구축
📖 Part 4: 모델 최적화 - Pruning & Distillation
핵심 통찰
"처음부터 학습 대비 1/9의 데이터로 더 높은 성능 달성"
4.1 Pruning & Distillation 전략
전체 프로세스:
[Teacher Model]
Karuna Essence (Large)
↓
[Pruning] 모델 구조 축소
↓
[Student Model] (초기)
Karuna Nano (Small, pruned structure)
↓
[Distillation] Teacher 지식 전달 (0.3T tokens)
↓
[Final Model]
Karuna Nano (High Performance)
구체적 구현:
# Step 1: Structured Pruning
def prune_model(teacher_model, pruning_ratio=0.3):
"""
구조적 가지치기
카카오의 방식 (추정):
- Attention head 제거
- Layer 제거
- Hidden dimension 축소
"""
pruned_config = {
"num_layers": int(teacher_model.num_layers * (1 - pruning_ratio)),
"num_attention_heads": int(teacher_model.num_heads * (1 - pruning_ratio)),
"hidden_size": teacher_model.hidden_size # 유지 또는 축소
}
student_model = initialize_model(pruned_config)
# Teacher의 가중치에서 중요한 부분만 student에 이식
transfer_important_weights(teacher_model, student_model)
return student_model
# Step 2: Knowledge Distillation
def distillation_training(teacher, student, data_0_3T, temperature=2.0):
"""
지식 증류 학습
카카오의 데이터: 0.3T tokens (Stage 2와 동일한 고품질 데이터)
"""
for batch in data_0_3T:
# Teacher의 출력 (soft labels)
with torch.no_grad():
teacher_logits = teacher(batch.input_ids)
teacher_probs = F.softmax(teacher_logits / temperature, dim=-1)
# Student 학습
student_logits = student(batch.input_ids)
student_probs = F.softmax(student_logits / temperature, dim=-1)
# Distillation Loss
loss_distill = KL_divergence(teacher_probs, student_probs)
# Hard Label Loss (원본 데이터도 함께 학습)
loss_hard = cross_entropy(student_logits, batch.labels)
# 총 손실
alpha = 0.5 # 균형 조정
loss = alpha * loss_hard + (1 - alpha) * loss_distill
loss.backward()
optimizer.step()
# Step 3: 결과 비교
performance_comparison = {
"from_scratch": {
"data_used": "2.7T tokens",
"kmmlu_score": 48.81,
"training_time": "long"
},
"pruning_distillation": {
"data_used": "0.3T tokens", # 1/9 데이터!
"kmmlu_score": 52.07, # 더 높은 성능!
"training_time": "short"
}
}
4.2 효율성 극대화 전략
class EfficientModelDevelopment:
"""
카카오의 2단계 검증 전략
"""
def stage1_validation(self):
"""
1단계: 레시피 검증
- 작은 모델 from scratch 학습
- 라마 대비 성능 확인
→ 학습 방식의 우수성 입증
"""
nano_from_scratch = train_from_scratch(
data="2.7T + 0.3T",
model_size="small"
)
assert nano_from_scratch.performance > llama_baseline
print("✓ 우리 레시피가 효과적임을 검증")
def stage2_optimization(self):
"""
2단계: 효율 극대화
- 큰 모델 (Essence) 활용
- Pruning & Distillation 적용
→ 1/3 데이터로 더 좋은 성능
"""
nano_optimized = pruning_and_distillation(
teacher=essence_model,
data="0.3T only"
)
assert nano_optimized.performance > nano_from_scratch
assert nano_optimized.data_used < nano_from_scratch.data_used / 3
print("✓ 최대 효율 달성")
학습 실습:
- 작은 Transformer 모델에 직접 Pruning 적용
- Knowledge Distillation 코드 구현
- From scratch vs Distillation 성능 비교 실험
🎯 종합 학습 로드맵
단계별 실전 프로젝트
[입문] 3개월 과정
Week 1-4: 데이터 파이프라인 구축
├─ Hugging Face 데이터셋 100개 라이선스 분석
├─ Educational Score 평가 모델 학습
└─ Wikipedia 수식 보존 파싱 구현
Week 5-8: 작은 모델로 프리트레이닝
├─ 2-Stage 학습 구현 (1B 모델)
├─ 4개 ablation 실험 수행
└─ Learning rate schedule 최적화
Week 9-10: SFT 데이터 구축
├─ Multi-turn 대화 데이터 수집
├─ 도메인별 데이터셋 구성
└─ 품질 평가 기준 설계
Week 11-12: 선호도 학습
├─ 리워드 모델 학습
├─ Online DPO 구현
└─ 도메인별 선호도 기준 적용
[중급] 추가 3개월
├─ Pruning & Distillation 마스터
├─ 대규모 데이터 처리 (10B+ tokens)
├─ 멀티 GPU 학습 최적화
└─ 프로덕션 배포 파이프라인
[고급] 실전 프로젝트
├─ 특정 도메인 전문 LLM 개발
├─ 커뮤니티 기여 (오픈소스 모델 공개)
└─ 논문 작성 및 발표
💡 핵심 Takeaways
카카오 개발팀의 5대 교훈:
- Data Quality > Data Quantity
- "20%의 데이터로 거인을 이기다"
- Educational Score 기반 선별의 위력
- Constraints Drive Innovation
- 라이선스 제약 → 고품질 데이터 집중
- 제한된 자원 → 효율적 전략 개발
- Smart Curation Beats Brute Force
- GPT-4 → 경량 모델 파이프라인
- 비용 절감 + 일관성 확보
- Service Data is Gold
- 실제 multi-turn 대화의 중요성
- 서비스 ↔ 모델 선순환
- Efficiency Through Transfer
- Pruning & Distillation
- 1/9 데이터로 더 높은 성능
📚 추천 학습 자료
필수 논문:
- FineWeb-Edu (데이터 품질 평가)
- DataComp-LM (품질 필터링)
- DeepSeek-LLM (Multi-step LR Scheduler)
- DPO (Direct Preference Optimization)
- Model Pruning & Distillation 서베이
실습 리소스:
- Hugging Face Transformers 라이브러리
- Axolotl (파인튜닝 프레임워크)
- TRL (Transformer Reinforcement Learning)
- PEFT (Parameter-Efficient Fine-Tuning)
커뮤니티:
- EleutherAI (오픈소스 LLM 연구)
- HuggingFace Hub (모델 & 데이터)
- Papers with Code (최신 연구 동향)
🚀 마무리: AI 개발의 새로운 패러다임
카카오의 사례가 보여주는 것은 **'전략의 승리'**입니다:
규모의 경쟁 (Old) 전략의 경쟁 (New)
├─ 더 많은 데이터 ├─ 더 좋은 데이터 선별
├─ 더 큰 모델 ├─ 효율적인 모델 설계
├─ 더 긴 학습 시간 ├─ 스마트한 학습 전략
└─ 무한한 자본 └─ 창의적 문제 해결
이제 여러분의 차례입니다.
이 로드맵을 따라 하나씩 실습하며, 자신만의 언어 모델을 개발해보세요. 카카오가 3개월 만에 이룬 성과는, 올바른 방향과 체계적인 실행이 있다면 누구나 달성할 수 있다는 것을 증명합니다.
Happy Learning! 🎓✨
추가 관련 영상:
https://youtu.be/wSawG3VklFU?si=XMI9Qz-ZeWSlv3uj
'앱개발' 카테고리의 다른 글
| AI에게 일을 시키는 두 가지 방법: 바이브 코딩 vs 바이브 엔지니어링 (1) | 2025.12.15 |
|---|---|
| [에이전트 평가] 서론 (0) | 2025.12.05 |
| MCP의 숨겨진 보석: Tool Discovery와 자동 API 스키마 생성의 마법 ✨ (1) | 2025.09.08 |
| 뒤처지기 전에 배워두면 좋을 AI 툴 모음 (업데이트중) (3) | 2025.08.15 |
| RAG 평가 항목 정리-ver. 1.0 (11) | 2025.08.06 |
