Files
frankenstallm/source/eval/plan/3B_MASTER_PLAN.md
ModelHub XC d4abdb70fa 初始化项目,由ModelHub XC社区提供模型
Model: pathcosmos/frankenstallm
Source: Original Platform
2026-07-14 04:21:16 +08:00

590 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 🚀 3B 한국어 LLM 마스터 플랜
**작성일**: 2026-02-27 04:27 KST
**프로젝트**: `/PROJECT/0325120031_A/ghong/taketimes/llm-bang/`
**결정**: 1B → 3B 전환 (1B 구조적 한계 확인)
**총 예상 기간**: ~35시간
---
## 0. 현황 요약
### 1B에서 확인된 것
| 항목 | 결과 |
|------|------|
| 반복률 (raw, 올바른 포맷) | 30.7% |
| 반복률 (rep_penalty=1.1) | 18.0% |
| val_loss | 2.2062 |
| 자연 종료율 | 60% |
| 짧은 QA 품질 | ✅ 양호 (수도, 김치 등) |
| 복잡한 질문 품질 | ❌ 반복 퇴화 심각 |
### 3B 전환 근거
1. **반복률 18%는 1B 구조적 한계** — d_model=2048, 24 layers로는 긴 시퀀스에서 hidden state 붕괴 불가피
2. **Scaling law 예측**: 3B는 loss ~7% 감소 → 반복률 5~8% 예상
3. **ORPO 없이도 목표 달성 가능**: 3B SFT만으로 <10%, +ORPO로 <3%
4. **총 소요시간 ORPO 실패→3B (39h) vs 3B 직행 (30h)** 직행이 빠름
---
## 1. 3B 모델 아키텍처
| 파라미터 | 1B (현재) | 3B (목표) | 변화 |
|---------|----------|----------|------|
| d_model | 2048 | **3072** | 1.5× |
| n_layers | 24 | **32** | 1.33× |
| n_heads | 16 | **24** | 1.5× |
| n_kv_heads (GQA) | 4 | **8** | 2× (GQA 3:1) |
| d_ffn (SwiGLU) | 5472 | **8192** | 1.5× |
| vocab_size | 64000 | **64000** | 동일 |
| max_seq_len | 4096 | **4096** | 동일 |
| rope_theta | 500000 | **500000** | 동일 |
| **총 파라미터** | **1.19B** | **~3.42B** | 2.9× |
### 파라미터 수 상세
```
Embedding: 64000 × 3072 = 196.6M
Attention/layer: Q(3072×3072) + K(3072×1024) + V(3072×1024) + O(3072×3072) = 25.1M
FFN/layer: SwiGLU gate(3072×8192) + up(3072×8192) + down(8192×3072) = 75.5M
Layer total: 25.1 + 75.5 = 100.6M × 32 layers = 3,219M
LM Head: tied with embedding
총계: 196.6M + 3,219M ≈ 3.42B
```
### GPU 메모리 예상 (8× B200 183GB)
```
모델 (FP8): 3.42 GB
Optimizer (FP32): 27.4 GB (DDP 분산 → ~3.4 GB/GPU)
Gradients (BF16): 6.84 GB (분산 → ~0.86 GB/GPU)
Activations (bs=4): ~15-25 GB (gradient checkpointing)
Per GPU 합계: ~28 GB → B200의 15% → 매우 여유
```
### Config 파일
```yaml
# configs/korean_3b_fp8.yaml
model:
vocab_size: 64000
d_model: 3072
n_layers: 32
n_heads: 24
n_kv_heads: 8
d_ffn: 8192
max_seq_len: 4096
rope_theta: 500000.0
dropout: 0.0
bias: false
use_flash_attn: true
use_fp8: true
train:
max_steps: 34000 # 8.91B × 4 epoch
batch_size: 4
grad_accum_steps: 8 # eff_batch: 4 × 8 × 8GPU × 4096 ≈ 1M tok/step
lr: 1.5e-4
min_lr: 1.5e-5
weight_decay: 0.1
warmup_steps: 2000
max_grad_norm: 1.0
log_interval: 10
save_interval: 500
eval_interval: 200
fp8_format: "MXFP8"
tokenizer:
vocab_size: 64000
type: sentencepiece_unigram
```
---
## 2. 데이터 파이프라인
### 즉시 사용 가능
| 소스 | 크기 | 토큰 | 상태 |
|------|------|---------|------|
| korean_c4_train.bin | 15.1 GB | 7.56B | 토큰화 완료 |
| korean_namuwiki_train.bin | 2.2 GB | 1.08B | 토큰화 완료 |
| korean_wiki_train.bin | 0.5 GB | 0.26B | 토큰화 완료 |
| **합계 (korean_train.bin)** | **17.8 GB** | **8.91B** | **즉시 시작 가능** |
### 추가 준비 필요 (병렬 토큰화)
| 소스 | 크기 | 추정 토큰 | 작업 | 예상 소요 |
|------|------|----------|------|----------|
| culturax_ko | 60 GB | ~30-40B | parquet토큰화 | 4-6h |
| hplt_ko | 23 GB | ~12-15B | 토큰화 | 2-3h |
| cc100_ko | 14 GB | ~8-10B | xz해제+토큰화 | 2h |
| oscar_ko | 9.2 GB | ~5-6B | 토큰화 | 1-2h |
| korean_textbooks | 6.4 GB | ~3-4B | 토큰화 | 1h |
| **합계** | **~123 GB** | **~70-80B** | | **8-12h (병렬)** |
### Chinchilla 분석
```
3.42B × 20 = 68.4B tokens (최적)
즉시 사용 가능: 8.91B × 4 epoch = 35.6B (최적의 52%)
extra 포함 시: ~80-90B → 충분 (131%)
```
### 데이터 타임라인
| 시점 | 행동 |
|------|------|
| **지금** | korean_train.bin 8.91B로 사전학습 시작 (4 epoch) |
| **병렬** | korean_extra 토큰화 + MinHash 중복제거 + PPL 필터 진행 |
| **Phase 2** | 전체 60-80B 토큰으로 extended pretrain (선택) |
### SFT 데이터
| 항목 | |
|------|-----|
| 현재 클린 데이터 | ~120-135K 샘플 (필터링 ) |
| Val split | 10% (~12-13K) |
| 3B에 충분? | (7B Alpaca도 52K로 학습) |
### 추가 고품질 SFT 소스 (선택)
- `hPark/orca-ko` (~200K)
- `maywell/synatra-orca` (~300K)
- `HAERAE-HUB/qarv-instruct-100k` (100K)
- 필터링 200-300K 사용 가능
---
## 3. 사전학습 계획
### 하이퍼파라미터
| 파라미터 | | 근거 |
|---------|-----|------|
| LR | 1.5e-4 | 3B 표준 (1B의 3e-4 대비 보수적) |
| Min LR | 1.5e-5 | LR의 10% |
| Warmup | 2,000 steps | ~6% |
| Weight Decay | 0.1 | Pretrain 표준 |
| Batch Size | 4/GPU × 8GPU × 8 grad_accum = 256 | eff ~1M tok/step |
| Max Steps | 34,000 | 8.91B × 4 epoch |
| Precision | MXFP8 | B200 최적화 |
| Grad Clip | 1.0 | 표준 |
### 예상 소요 시간
```
1B 실측: ~75,700 tok/s (단일 B200)
3B 예상: 파라미터 3× → throughput ~40-50% 감소
BUT batch 최적화 + FP8 → 보정
보수적 추정:
8.91B × 4 epoch = 35.6B tokens
처리량: ~400K tok/s (8× B200, FP8, 최적 배치)
소요: 35.6B / 400K = 89,000초 ≈ 24.7시간
낙관적 추정:
처리량: ~600K tok/s → 16.5시간
채택 추정: ~26시간
```
### 모니터링
```bash
# 실시간 로그
tail -f checkpoints/korean_3b_fp8/train.log
# TensorBoard
tensorboard --logdir checkpoints/korean_3b_fp8/tensorboard --port 6007
# GPU 상태
watch -n 10 nvidia-smi
```
**핵심 관찰 수치**:
| 수치 | 정상 범위 | 경고 | 즉시 중단 |
|------|----------|------|----------|
| Train Loss | 시작 ~10, 수렴 ~3-4 | 정체 5000+ steps | 발산 (상승) |
| GNorm | 0.5-2.0 | >5.0 | >50 |
| PPL | 하강 추세 | 정체 | 상승 |
| GPU Util | >90% | <70% | <50% (병목) |
| tok/s | >300K | <200K | <100K |
### 체크포인트 전략
| Step | 행동 |
|------|------|
| 500 | Sanity check loss 하강 ? OOM 없나? |
| 5,000 | 1 epoch 완료 PPL 측정, 한국어 텍스트 perplexity <20? |
| 10,000 | 중간점 loss 추세 확인, 과적합 징후? |
| 17,000 | 2 epoch PPL < 15? |
| 25,000 | 3 epoch PPL < 12? |
| 34,000 | 최종 PPL < 10 목표 |
**디스크**: 체크포인트 1개 ~27GB (모델 7GB + optimizer 20GB) × save_interval=500 68개 = ~1.8TB
**save_interval=2000으로 변경 권장** 17개 = ~460GB
---
## 4. SFT 계획
### 1B 교훈 전부 적용
| 교훈 | 1B에서 발견 | 3B에 적용 |
|------|------------|-----------|
| Dynamic padding 필수 | 4096 고정으로 90% 낭비 | sft_dataset.py 수정 완료, 그대로 사용 |
| EOS 보존 | 트렁케이션 EOS 손실 | `response_ids[-1] = eos_id` 강제 |
| Val split 필수 | 과적합 모니터링 불가했음 | 10% split |
| 3-4 epoch | 2 epoch은 underfitting | max_steps 계산 |
| OpenOrca 과대표집 방지 | 5× 가중치로 과적합 | 2.0× 이하 |
| 데이터 품질 필터 | `</s>` 리터럴, Q/A 마커 오염 | 필터 스크립트 완성 |
| 올바른 포맷 통일 | 학습/추론 포맷 불일치 | `<\|user\|>/<\|assistant\|>` 일관 |
| Early stopping | val_loss 상승해도 학습 계속됨 | patience=5 구현 |
| NEFTune alpha | 10.0은 과도 | 5.0으로 조정 |
### 하이퍼파라미터
| 파라미터 | | 근거 |
|---------|-----|------|
| LR | 2e-5 | SFT 표준 (Alpaca, Vicuna 동일) |
| Warmup | 300 steps | ~3% |
| Max Steps | 10,000 | ~3-4 epoch (데이터 크기 따라 조정) |
| Batch Size | 4/GPU × 2 grad_accum × 8GPU = 64 | SFT 표준 |
| Weight Decay | 0.01 | SFT 표준 (pretrain 0.1보다 낮게) |
| NEFTune | alpha=5.0 | 과적합 방지 |
| Eval Interval | 500 steps | |
| Early Stopping | patience=5 | 2,500 steps 무개선 중단 |
| Dropout | 0.05 | 과적합 방지 (1B에서 0.0이었음) |
### 실행 명령어
```bash
RUN_NAME=korean_3b_sft \
BASE_CHECKPOINT=checkpoints/korean_3b_fp8/checkpoint-BEST \
SFT_DATA=data/sft_v2/train.jsonl \
VAL_DATA=data/sft_v2/val.jsonl \
MAX_STEPS=10000 \
LR=2.0e-5 \
WARMUP_STEPS=300 \
bash scripts/launch_sft.sh
```
**예상 시간**: ~2시간 (3B는 1B 대비 ~2.5× 느림)
### 성공 기준
| 지표 | 목표 | 실패 기준 |
|------|------|----------|
| Train Loss | < 1.85 | > 2.00 |
| Val Loss | Train의 1.1배 이내 | 1.2배 초과 |
| 반복률 (raw) | < 10% | > 15% |
| 반복률 (rep_penalty=1.1) | < 3% | > 8% |
| EOS 종료율 | > 80% | < 60% |
---
## 5. ORPO 계획
### 타이밍: SFT 완료 후, 반복률 >5%일 때만
### 데이터
| 소스 | 샘플 | 유형 |
|------|---------|------|
| maywell/ko_Ultrafeedback_binarized | ~60K | 일반 도메인 preference |
| kuotient/orca-math-korean-dpo-pairs | 수천 | 수학 도메인 |
| **자체 생성** (3B SFT 모델로) | ~2-5K | 반복 타겟 preference |
**자체 생성 방법**:
1. 3B SFT 모델로 1000 프롬프트 × 4 temperature 생성
2. 반복 출력 rejected, 깨끗한 출력 chosen
3. 3B에서는 반복률 낮으므로 **1B보다 훨씬 편향 적음**
### 하이퍼파라미터
```python
ORPOConfig(
learning_rate=5e-7, # 매우 낮은 LR (정렬 학습)
num_train_epochs=1, # 1 epoch 충분
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
beta=0.1, # ORPO coefficient
)
```
### 예상 시간: 1-2시간
### 목표: 반복률 <3% (raw), <1% (rep_penalty=1.1)
---
## 6. 평가 계획
### 벤치마크
| 벤치마크 | 도구 | 1B 예상 | 3B 목표 |
|---------|------|---------|---------|
| ko_ifeval | lm-eval-harness | 15-25% | **35-45%** |
| ko_winogrande | lm-eval-harness | 53-58% | **60-68%** |
| KoBEST (5 tasks avg) | lm-eval-harness | 55-60% | **65-75%** |
| 반복률 (raw) | test_generation_params.py | 18% | **<8%** |
| 반복률 (+rep_penalty) | test_generation_params.py | ~5-8% | **<3%** |
### 실행 명령어
```bash
# ko_ifeval
lm_eval --model hf \
--model_args pretrained=checkpoints/korean_3b_sft/checkpoint-BEST,dtype=bfloat16 \
--tasks ko_ifeval --device cuda:0
# KoBEST
lm_eval --model hf \
--model_args pretrained=checkpoints/korean_3b_sft/checkpoint-BEST,dtype=bfloat16 \
--tasks kobest_boolq,kobest_copa,kobest_wic,kobest_hellaswag,kobest_sentineg \
--device cuda:0
```
### 판단 기준
```
[3B SFT 평가 결과]
┌─────────────────────┼─────────────────────┐
│ │ │
✅ PASS ⚠️ PARTIAL ❌ FAIL
반복률<5% 반복률 5-10% 반복률>10%
ko_ifeval>35% ko_ifeval 25-35% ko_ifeval<25%
│ │ │
▼ ▼ ▼
배포 준비 ORPO 적용 원인 분석
(Phase 배포) (Phase 5) (데이터/아키텍처 점검)
```
---
## 7. 전체 타임라인
### 한눈에 보기
```
Day 0 (지금, 04:30)
├── [04:30] Config 작성 + sanity check 30분
├── [05:00] 🔥 사전학습 시작 ← 오늘 밤 시작
├── [05:00] (병렬) korean_extra 토큰화 시작 8-12h
Day 1 (내일)
├── [~07:00] 사전학습 진행 중... (~26시간)
├── [중간] 체크포인트 PPL 확인
Day 1.5
├── [~07:00+26h = Day 2 07:00] 사전학습 완료
├── [07:00] SFT 시작 2시간
├── [09:00] SFT 완료 → 평가
├── [09:30] 반복률 <5%? → 배포
├── [09:30] 반복률 5-10%? → ORPO 1-2시간
├── [11:30] ORPO 완료 → 최종 평가
Day 2
├── 벤치마크 풀 스위트 2시간
├── HuggingFace 업로드 1시간
├── vLLM 서빙 테스트 1시간
└── 🎉 배포 완료
```
### 표 형식
| 단계 | 시작 | 소요 | 완료 | 의존성 |
|------|------|------|------|--------|
| **0. Config + Sanity** | Day 0 04:30 | 30분 | 05:00 | 없음 |
| **1. 사전학습** | Day 0 05:00 | **26시간** | Day 1 ~07:00 | Config |
| **(병렬) Extra 토큰화** | Day 0 05:00 | 8-12시간 | Day 0 ~17:00 | 없음 |
| **2. SFT** | Day 1 07:00 | **2시간** | Day 1 09:00 | 사전학습 완료 |
| **3. 1차 평가** | Day 1 09:00 | 30분 | Day 1 09:30 | SFT 완료 |
| **4. ORPO (조건부)** | Day 1 09:30 | 1-2시간 | Day 1 11:30 | 반복률 >5% |
| **5. 풀 벤치마크** | Day 1 11:30 | 2시간 | Day 1 13:30 | |
| **6. 배포** | Day 1 13:30 | 2시간 | Day 1 15:30 | 벤치마크 통과 |
---
## 8. 의사결정 트리
### Phase 1: 사전학습 중 (Step 5000, 10000, ...)
```
Loss 하강 중?
├── YES → 계속
└── NO (정체 3000+ steps)
├── 데이터 품질 문제? → PPL 필터 강화 + 재시작
├── LR 문제? → LR 반감 후 resume
└── 모델 아키텍처? → d_model/n_layers 조정 (최후 수단)
PPL (한국어 텍스트)?
├── < 15 at 2 epoch → 정상
├── 15-20 at 2 epoch → 주의 (데이터 부족?)
└── > 20 at 2 epoch → 문제 (데이터 품질 or 하이퍼파라미터)
OOM?
├── batch_size 4→2, grad_accum 8→16
└── gradient checkpointing 확인
```
### Phase 2: SFT 후
```
반복률 (raw)?
├── < 5% → ✅ 배포 가능! (ORPO 건너뜀)
├── 5-10% → ⚠️ ORPO 적용
├── 10-15% → 🟠 SFT 하이퍼파라미터 조정 후 재시도
└── > 15% → ❌ 사전학습 품질 문제 → Phase 1 재점검
ko_ifeval?
├── > 35% → ✅ 목표 달성
├── 25-35% → 🟡 데이터 augmentation 고려
└── < 25% → 🔴 3B에서도 이러면 데이터 문제 심각
```
### Phase 3: ORPO 후
```
반복률?
├── < 3% → ✅ 완료
├── 3-5% → 🟡 서빙 시 rep_penalty=1.05로 보완
└── > 5% → 🔴 preference 데이터 재검토
```
---
## 9. 예외 대응
| 시나리오 | 확률 | 대응 |
|---------|------|------|
| **OOM** | 5% | batch_size 4→2, grad_accum 2× |
| **Loss 발산** | 5% | LR 반감, grad_clip 0.5로 강화 |
| **GPU Hang / NCCL** | 10% | `pkill torchrun` → latest checkpoint에서 resume |
| **디스크 부족** | 3% | save_interval 2000→5000, 오래된 ckpt 삭제 |
| **사전학습 후 PPL >20** | 10% | 데이터 추가 (korean_extra) + extended training |
| **SFT 후 반복률 >15%** | 10% | 데이터 필터 재강화 + LR/epoch 조정 |
| **ORPO 후 품질 퇴행** | 15% | ORPO LR 낮추기 (5e-7 → 1e-7), beta 조정 |
| **FP8 수치 불안정** | 5% | BF16으로 폴백 (시간 1.5× 증가) |
### NCCL/GPU 복구 스크립트
```bash
# 프로세스 정리
pkill -f torchrun && sleep 5
# 최신 체크포인트 찾기
LATEST=$(ls -d checkpoints/korean_3b_fp8/checkpoint-[0-9]* 2>/dev/null \
| sort -t- -k2 -n | tail -1)
# 재시작
bash scripts/run_pretrain.sh --config configs/korean_3b_fp8.yaml --resume "${LATEST}"
```
---
## 10. 1B에서 배운 교훈 체크리스트
### 학습 전 필수 확인
- [ ] **Dynamic padding 작동 확인**: `SFTDataset.__getitem__`이 가변 길이 텐서 반환, `dynamic_collate_fn` 배치별 패딩
- [ ] **EOS 보존 확인**: `grep -n "eos_token_id" data/sft_dataset.py` — 트렁케이션 시 강제 부착
- [ ] **Val split 존재**: `wc -l data/sft_v2/val.jsonl` → 10K+ 확인
- [ ] **데이터 오염 제거**: `</s>` 리터럴, Q/A 마커, 자체 반복 패턴 필터 적용됨
- [ ] **OpenOrca 가중치 ≤ 2.0**: prepare_sft_data.py에서 확인
- [ ] **프롬프트 포맷 통일**: 학습 = 추론 = `<|user|>/<|assistant|>`
- [ ] **Labels shift 정상**: trainer.py에서 `logits[t]``targets[t]` 직접 비교, labels에서 shift 처리
### 학습 중 필수 모니터링
- [ ] **Val loss 추적**: 매 eval_interval마다 기록, 3연속 상승 시 주의
- [ ] **Early stopping 활성화**: patience=5
- [ ] **Loss 0 감지**: 3 step 연속 loss < 0.01 labels 버그 즉시 확인
- [ ] **Grad norm**: > 10이면 경고, > 50이면 중단
### 학습 후 필수 확인
- [ ] **올바른 포맷으로 생성 테스트**: `<|user|>\n{질문}\n<|assistant|>\n`
- [ ] **rep_penalty 없이 반복률 측정**: 목표 <10%
- [ ] **rep_penalty=1.1로 반복률**: 목표 <3%
- [ ] **벤치마크 실행**: ko_ifeval, KoBEST
### 절대 반복하지 말 것
- 학습/추론 포맷 불일치 상태로 평가하지
- Val split 없이 학습하지
- 특정 소스 5× 이상 업샘플링하지
- 2 epoch 미만으로 학습하지
- Dynamic padding 미작동 상태로 학습하지
- 반복률 측정 없이 "loss 낮으니 OK" 판단하지
---
## 🔥 오늘 밤 지금 당장 시작할 첫 번째 명령어
```bash
cd /PROJECT/0325120031_A/ghong/taketimes/llm-bang
# 1. 3B config 작성
cat > configs/korean_3b_fp8.yaml << 'YAML'
model:
vocab_size: 64000
d_model: 3072
n_layers: 32
n_heads: 24
n_kv_heads: 8
d_ffn: 8192
max_seq_len: 4096
rope_theta: 500000.0
dropout: 0.0
bias: false
use_flash_attn: true
use_fp8: true
train:
max_steps: 34000
batch_size: 4
grad_accum_steps: 8
lr: 1.5e-4
min_lr: 1.5e-5
weight_decay: 0.1
warmup_steps: 2000
max_grad_norm: 1.0
log_interval: 10
save_interval: 2000
eval_interval: 500
fp8_format: "MXFP8"
YAML
# 2. 사전학습 시작!
bash scripts/run_pretrain.sh --config configs/korean_3b_fp8.yaml
```
---
## ⚡ 가장 중요한 판단 포인트 3개
### 1⃣ 사전학습 Step 5,000 (1 epoch 완료) — "기초 체력 확인"
- **PPL < 20?** 정상, 계속
- **PPL > 20?** → 데이터 품질 or 하이퍼파라미터 문제. 즉시 진단
### 2⃣ SFT 후 반복률 측정 — "3B의 진짜 실력"
- **<5%?** 🎉 ORPO 없이 바로 배포. 대성공
- **5-10%?** ORPO 1라운드로 해결 가능
- **>10%?** → 사전학습 품질 재검토 필요 (이 확률은 낮음)
### 3⃣ ko_ifeval 점수 — "실사용 가능 수준?"
- **>35%?** → 3B 한국어 모델로서 경쟁력 있음. 배포
- **25-35%?** → 추가 SFT 데이터로 개선 여지 있음
- **<25%?** 사전학습 데이터가 부족했을 가능성 extended pretrain 고려
---
*"1B에서 배웠고, 3B에서 증명한다."*
*이 문서는 각 Phase 완료 시 실측 결과로 업데이트할 것.*