# FRANKENSTALLM ![Phase 3](https://img.shields.io/badge/Phase_3_ORPO-본_학습_중-blue) ![Model](https://img.shields.io/badge/Model-3B_Korean_LLM-green) ![GPU](https://img.shields.io/badge/GPU-8×_NVIDIA_B200-76b900) ![FP8](https://img.shields.io/badge/Precision-MXFP8-orange) ![SFT](https://img.shields.io/badge/SFT-완료_val__loss_1.8851-success) ![Status](https://img.shields.io/badge/Status-ORPO_Full_Training-ff9900) > **한국어 3B LLM을 8× NVIDIA B200 위에서 처음부터 직접 만든다.** > Frankenstein처럼 조각을 이어 붙이고, 철강처럼 단단하게 단련한다. GitHub: [`pathcosmos/FRANKENSTALLM`](https://github.com/pathcosmos/FRANKENSTALLM) --- ## 목차 1. [왜 이 프로젝트인가](#1-왜-이-프로젝트인가) 2. [현재 상태 — 한눈에 보기](#2-현재-상태--한눈에-보기) 3. [하드웨어 환경](#3-하드웨어-환경) 4. [프로젝트 구조](#4-프로젝트-구조) 5. [프로젝트 여정 타임라인](#5-프로젝트-여정-타임라인) 6. [모델 아키텍처](#6-모델-아키텍처) 7. [학습 데이터](#7-학습-데이터) 8. [학습 설정 및 최적화](#8-학습-설정-및-최적화) 9. [실험 결과 — 1B 베이스라인](#9-실험-결과--1b-베이스라인) 10. [실험 결과 — 3B Base 종합 평가 (v2)](#10-실험-결과--3b-base-종합-평가-v2) - [10.1 학습 커브](#101-학습-커브) - [10.2 PPL (Perplexity) — 19개 데이터셋](#102-ppl-perplexity--19개-데이터셋) - [10.3 한국어 벤치마크](#103-한국어-벤치마크) - [10.4 영어 벤치마크](#104-영어-벤치마크) - [10.5 Calibration](#105-calibration) - [10.6 0-shot vs 5-shot 비교](#106-0-shot-vs-5-shot-비교) - [10.7 참고 모델 비교](#107-참고-모델-비교) - [10.8 생성 품질 및 파라미터 그리드 서치](#108-생성-품질-및-파라미터-그리드-서치) - [10.9 평가 파이프라인](#109-평가-파이프라인) 11. [실험 결과 — 3B SFT 종합 평가](#11-실험-결과--3b-sft-종합-평가) - [11.1 SFT 학습 결과](#111-sft-학습-결과) - [11.2 6차원 평가 요약](#112-6차원-평가-요약) - [11.3 Base vs SFT 비교](#113-base-vs-sft-비교) - [11.4 코드 개선 사항](#114-코드-개선-사항) - [11.5 ORPO 진행 판정](#115-orpo-진행-판정) 12. [Phase 3 — ORPO (선호도 정렬)](#12-phase-3--orpo-선호도-정렬) - [12.1 ORPO 선택 배경](#121-orpo-선택-배경) - [12.2 데이터](#122-데이터) - [12.3 HP Sweep 설계](#123-hp-sweep-설계-6-config) - [12.4 시도 이력](#124-시도-이력--5번의-실패) - [12.5 스윕 결과](#125-스윕-결과-진행-중) - [12.7 ORPO 본 학습](#127-orpo-본-학습-진행-중-2026-03-09) - [12.8 ORPO 종합 평가 파이프라인](#128-orpo-종합-평가-파이프라인) 13. [실행 방법](#13-실행-방법) 14. [로드맵](#14-로드맵) 15. [참고 문서](#15-참고-문서) 16. [기술 스택 요약](#16-기술-스택-요약) 17. [관련 프로젝트](#관련-프로젝트) 18. [다음 최적화 계획](#18-다음-최적화-계획--mfu-335--47-목표) 19. [GPU 하드웨어 & 비용 분석](#19-gpu-하드웨어--비용-분석--3b--60b-프리트레인) --- ## 1. 왜 이 프로젝트인가 한국어 LLM 생태계는 빠르게 성장하고 있다. 그러나 대부분의 공개 모델은 영어 기반 사전학습 위에 한국어 파인튜닝을 얹은 형태거나, 학습 과정이 공개되지 않아 재현이 불가능하다. 이 프로젝트는 다르다. - **처음부터(from scratch)**: 토크나이저 학습부터 프리트레인, SFT, 선호도 정렬까지 모든 단계를 직접 구현한다. - **완전 공개 빌더 로그**: 성공만 기록하지 않는다. 버그, 실패, 판단 착오, 그리고 그 원인 분석까지 모두 기록한다. - **실용적인 규모**: 학술 논문용 장난감 모델(125M)도 아니고, 연구소가 아니면 재현 불가능한 70B도 아닌, **3B 규모**의 실용적 한국어 모델이 목표다. - **B200 최적화**: NVIDIA B200의 FP8 Tensor Core, NVLink 5.0, FlashAttention-2를 최대한 활용한다. 최신 하드웨어를 최대로 쥐어짜는 과정 자체가 학습이다. 이 README는 완성된 결과물의 발표가 아니라, **현재 진행 중인 빌더의 로그**다. --- ## 2. 현재 상태 — 한눈에 보기 ``` 2026-03-09 기준 ``` | 단계 | 상태 | 세부 내용 | |------|------|-----------| | Phase 0: 기반 구축 | ✅ 완료 | OOM 수정, GQA FA 최적화, NCCL NVLS, 파이프라인 준비 | | Phase 1: 3B Pretrain | ✅ 완료 | 57,000 steps, loss 1.466, ~63시간 | | Phase 2: SFT | ✅ 완료 | 25,500 steps (early stop), val_loss 1.8851, ~15.5시간 | | Phase 2.5: SFT 평가 | ✅ 완료 | 6차원 평가 4/6 PASS, ORPO 진행 결정 | | Phase 3: ORPO Sweep | ✅ 완료 | 6-config sweep 완료, best: lr=1.2e-5, beta=0.25 | | **Phase 3: ORPO 본 학습** | **🔄 진행 중** | **630K pairs, 2 epochs, ~9,840 steps, ~4.8시간** | | Phase 4: 배포 | 📋 대기 | GGUF 변환 → Ollama 서빙 | ### Phase 2 (SFT) 최종 결과 | 항목 | 값 | |------|-----| | 최종 step | **25,500 / 33,000** (77.3%, early stopping) | | **Val loss (best)** | **1.8851** (step 23,000) | | 학습 시간 | **~15시간 41분** (2026-03-05 22:15 ~ 2026-03-06 13:56) | | VRAM 사용 | **24.2GB** / 183GB per GPU (13.2%) | | Base 모델 | checkpoint-0057000 (pretrain loss 1.466) | | SFT 데이터 | **2,439,397 samples** (24개 소스, 7.48 GB) | | 사고 | 0건 (OOM, NCCL, NaN 없음) | **SFT Val Loss 전체 추이**: ``` Step 500: 2.073 Step 2,000: 1.956 (-0.117) Step 5,000: 1.911 (-0.045) Step 10,000: 1.892 (-0.019) Step 15,000: 1.886 (-0.006) Step 20,000: 1.885 (-0.001) Step 23,000: 1.8851 ← BEST Step 25,500: 1.8851 → Early Stop (patience 5/5) ``` ### SFT 6차원 평가 요약 | 차원 | 결과 | 핵심 수치 | |------|------|-----------| | Perplexity (지식 보존) | **PASS** | forgetting 0.9% | | 생성 품질 | **FAIL** | Greedy 반복률 72.97% | | 한국어 벤치마크 | **FAIL** | KoBEST 평균 43.26% | | 영어 벤치마크 | **PASS** | 전 태스크 하한 초과 | | Calibration | **PASS** | Top-1 68.59% | | SFT Chat 능력 | **PASS** | EOS 종료율 60% (Base 0%) | > **판정: ORPO 진행** — 지식 보존 우수(0.9%), 반복률은 선호도 정렬로 해결. > 상세: `reports/2026-03-06_3B_SFT_COMPLETION_AND_EVAL_SUMMARY.md` --- ## 3. 하드웨어 환경 ### GPU | 항목 | 사양 | |------|------| | 모델 | 8× NVIDIA B200 | | VRAM | 183GB HBM3e per GPU (~1.47TB 합계) | | FP8 Tensor Core | 2,250 TFLOPS/GPU (총 18,000 TFLOPS) | | BF16 | 1,125 TFLOPS/GPU | | HBM3e 대역폭 | ~7.67 TB/s per GPU | | 인터커넥트 | NVLink 5.0 (900 GB/s bidirectional per GPU) | | 토폴로지 | NVSwitch — 모든 GPU↔GPU 단일 홉 All-to-All Mesh | | 전력 | 940W 실측 / 1000W cap | B200은 FP8 네이티브 지원 모델이다. `torch.float8_e4m3fn` 을 TransformerEngine의 MXFP8 레시피와 결합해 학습한다. BF16 대비 연산량이 이론상 2배이며, 메모리 효율도 향상된다. ### CPU 및 시스템 메모리 | 항목 | 사양 | |------|------| | CPU | 2× AMD EPYC 9365 (Turin / Zen 5) | | 물리 코어 | 72개 (36코어 × 2소켓) | | NUMA 구성 | 2노드: node0 (core 0-35) / node1 (core 36-71) | | GPU↔NUMA 매핑 | GPU 0-3 → NUMA node 0, GPU 4-7 → NUMA node 1 | | RAM | 2.21TB DDR5 (~2.03TB 여유) | | L3 캐시 | 384MB (12 CCX × 32MB) | **NUMA 주의**: 초기 DDP 런칭 시 5/8 rank가 잘못된 NUMA 노드에서 실행되는 문제 발생. 69%의 DataLoader worker가 크로스-NUMA였다. NUMA affinity 최적화는 미적용 상태(로드맵 항목). ### 스토리지 | 경로 | 용도 | 여유 공간 | |------|------|-----------| | `/PROJECT/0325120031_A/ghong/taketimes/llm-bang/` | 메인 작업 (체크포인트, 데이터) | 2.2TB | | `/home/ghong/` | 소규모 코드 | 5GB (제한) | > **주의**: 체크포인트(수십 GB), 학습 데이터(82GB+), 중간 산출물은 모두 `/PROJECT/...` 경로에 저장한다. 홈 디렉토리 용량 초과 위험. ### 소프트웨어 환경 | 패키지 | 버전 | |--------|------| | PyTorch | `2.10.0a0+b4e4ee81d3.nv25.12` (NVIDIA 커스텀) | | FlashAttention | 2.7.4.post1+25.12 | | TransformerEngine | 2.10.0 | | NCCL | 2.28.9 | | Triton | 3.5.1 | | CUDA | 13.1 | | Driver | 580.95.05 | > **경고**: PyTorch는 NVIDIA B200 최적화 커스텀 빌드다. `pip install torch`로 재설치하면 B200 최적화가 깨진다. **절대 재설치 금지.** --- ## 4. 프로젝트 구조 ``` llm-bang/ ├── CLAUDE.md # Claude Code 가이드 ├── README.md # 이 파일 ├── PROGRESS.md # 진행 기록 (날짜별 로그) ├── Modelfile.3b # Ollama 모델 파일 │ ├── configs/ │ ├── korean_3b_fp8.yaml # 3B FP8 학습 설정 (현재 사용 중) │ ├── 3b_pretrain.yaml # 3B 프리트레인 설정 (대체) │ ├── korean_1b_fp8.yaml # 1B FP8 설정 (아카이브) │ ├── korean_3b_sft.yaml # 3B SFT v1 설정 (완료) │ ├── korean_3b_sft_v2.yaml # 3B SFT v2 설정 (lr=5e-5, data mixing) │ ├── korean_3b_orpo.yaml # 3B ORPO 설정 (lr=5e-6, beta=0.1) │ ├── hybrid_3b.yaml # Hybrid 3B (Mamba-2 + Attention) │ ├── small_fp8.yaml # 125M FP8 검증용 │ ├── medium.yaml # 중형 모델 설정 │ └── small.yaml # 소형 모델 설정 │ ├── data/ │ ├── 3b_train.bin # 프리트레인 학습 데이터 (82GB, 41.12B tokens) │ ├── 3b_val.bin # 검증 데이터 (151MB) │ ├── cc100_ko_train.bin # CC100 한국어 (4.5GB) │ ├── cosmo_auto_math_text_train.bin # 수학 텍스트 (2.6GB) │ └── build scripts, __init__.py │ ├── model/ │ ├── attention.py # GQA FlashAttention (Phase 0 최적화 적용) │ ├── transformer.py # 트랜스포머 메인 아키텍처 │ ├── config.py # 모델 설정 dataclass │ └── layers.py # 커스텀 레이어 (RMSNorm, SwiGLU 등) │ ├── train/ │ ├── pretrain.py # 프리트레인 스크립트 (DDP 최적화) │ ├── sft.py # SFT 학습 │ ├── orpo.py # ORPO 학습 │ ├── trainer.py # 통합 트레이너 (loss sync 최적화) │ └── utils.py # 유틸리티 (NCCL 7200s timeout 등) │ ├── scripts/ │ ├── launch_3b_pretrain.sh # 3B 프리트레인 런처 (NCCL 환경변수 포함) │ ├── launch_3b_sft.sh # 3B SFT v1 런처 │ ├── launch_3b_sft_v2.sh # 3B SFT v2 런처 (data mixing) │ ├── launch_3b_orpo.sh # 3B ORPO 런처 │ ├── monitor_3b.sh # 실시간 학습 모니터 │ ├── training_watchdog.sh # 워치독 (10분 간격, 크론) │ ├── convert_3b_gguf.sh # GGUF 변환 스크립트 │ ├── deploy_3b_ollama.sh # Ollama 배포 │ ├── quality_gate.sh # 배포 전 품질 게이트 │ ├── telegram_notify.py # 텔레그램 알림 (urllib 사용, curl 차단) │ └── hourly_status.sh # 1시간 간격 상태 리포트 │ ├── eval/ │ ├── debate/ │ │ └── justice_league_3b_case.md # 3B 전환 논증 (저스티스리그 멀티에이전트) │ ├── decision/ │ │ └── FINAL_DECISION_REPORT.md # SFT 재시작 판결문 │ ├── plan/ │ │ └── 3B_MASTER_PLAN.md # 3B 마스터 플랜 │ ├── tasks/ # 모듈화된 평가 태스크 │ │ ├── task_runner.py # 8-GPU 병렬 태스크 실행기 │ │ ├── ppl_task.py # Perplexity 평가 태스크 │ │ ├── lm_eval_task.py # lm-evaluation-harness 래퍼 │ │ ├── calibration_task.py # Calibration 분석 │ │ ├── generation_task.py # 생성 품질 + 파라미터 그리드 서치 │ │ └── token_nll_task.py # Token NLL 분포 분석 │ ├── outputs/ # 평가 결과 (자동 생성, .gitignore) │ ├── full_eval_pipeline.py # v2 종합 평가 파이프라인 (8-GPU 병렬) │ ├── sft_eval_pipeline.py # SFT 6차원 평가 파이프라인 │ ├── reeval_pipeline.py # 재평가 파이프라인 (0+5-shot 연속) │ ├── report_generator.py # 마크다운 리포트 자동 생성 │ ├── comprehensive_eval.py # v1 종합 평가 (레거시) │ └── test_generation_params.py # 생성 파라미터 탐색 │ ├── tokenizer/ │ ├── korean_sp/ # SentencePiece 64K 모델 파일 │ ├── tokenizer.json # HuggingFace 포맷 (2.4MB) │ ├── train_sp_tokenizer.py # 토크나이저 학습 스크립트 │ └── convert_sp_to_hf.py # SentencePiece → HF 변환 │ ├── checkpoints/ # 모델 체크포인트 (대용량, .gitignore) │ ├── docs/ │ ├── PROJECT_HISTORY.md # 프로젝트 전체 여정 상세 기록 │ └── 3B_WORKPLAN.md # 3B 작업 계획 │ └── reports/ ├── 2026-03-02_0200_FRANKENSTALLM_phase0_optimization_report.md ├── 2026-03-05_3B_BASE_EVALUATION_REPORT.md ├── 2026-03-05_3B_SFT_PROGRESS_REPORT.md # SFT 학습 보고서 (Phase 2) ├── 2026-03-05_3B_NEXT_STEPS_REFERENCE.md ├── 2026-03-05_NEMOTRON_NANO_FEASIBILITY_STUDY.md ├── 2026-03-05_PPL_EVALUATION.md ├── 2026-03-05_BENCHMARK_RESULTS.md ├── 2026-03-05_GENERATION_QUALITY.md ├── 2026-03-06_3B_SFT_EVAL_PLAN.md # SFT 6차원 평가 계획서 ├── 2026-03-06_3B_SFT_EVALUATION_REPORT.md # SFT 6차원 평가 결과 └── 2026-03-06_3B_SFT_COMPLETION_AND_EVAL_SUMMARY.md # SFT 완료 + 코드 개선 종합 ``` --- ## 5. 프로젝트 여정 타임라인 이 섹션이 이 README의 핵심이다. 결과만이 아니라 **왜** 그런 결정을 내렸는지, **어디서** 실패했는지를 솔직하게 기록한다. --- ### Day 1 (Feb 25) — 첫 불씨: 125M FP8 검증 프로젝트의 시작은 작은 의문에서 출발했다. B200에서 FP8이 실제로 안정적으로 학습되는가? TransformerEngine의 MXFP8 레시피를 125M 소형 모델에 적용해 검증했다. 결론은 **안정적으로 동작한다**. loss 수렴도 정상이었고, VRAM 효율도 BF16 대비 확연한 개선이 있었다. 이 검증이 전체 파이프라인의 첫 번째 녹색 신호였다. 같은 날, 인프라 세팅도 완료했다. DDP 8-GPU 환경, NCCL 환경변수, 체크포인트 저장 경로, 텔레그램 알림 시스템의 초안이 이날 갖춰졌다. --- ### Day 1~2 (Feb 25~26) — 1B 프리트레인: 34K 스텝, PPL 5.67 125M 검증 직후 1B 모델 프리트레인에 돌입했다. - **아키텍처**: d_model=2048, 24 layers, GQA 4:1, SwiGLU, RoPE - **데이터**: C4 Korean 기반 - **학습**: 34,000 스텝, FP8, 8× B200 DDP 최종 결과: - **Loss: 1.904** - **PPL (C4 Korean): 5.67** 수치만 보면 그럭저럭 괜찮다. 그러나 실제 텍스트 생성을 시켜보면 문제가 보였다. 반복 패턴, 어색한 문장 구조, 맥락 이탈. 프리트레인 모델이니 당연하다. 이제 SFT 차례였다. --- ### Day 2 (Feb 26) — SFT v1: 0.0이라는 재앙 SFT를 돌렸다. 학습이 시작되자마자 loss가 빠르게 떨어지기 시작했다. 처음엔 좋은 신호라고 생각했다. 그런데 loss가 **0.0**이 됐다. val loss도 0.0. 생성 결과는 완전한 쓰레기였다. 원인을 찾았다: **label off-by-one 버그**. 입력 토큰과 레이블 토큰이 한 칸씩 밀려 있었다. 모델이 실제로 다음 토큰을 예측하는 것이 아니라, 이미 알고 있는 정답을 맞추는 구조가 돼 있었다. loss가 0이 된 건 "완벽한 학습"이 아니라 **데이터 누수(label leakage)** 였다. 하루를 날렸다. --- ### Day 3 (Feb 27) — 5가지 버그, 루트 코즈 분석 실패를 분석하기 위해 **5-에이전트 루트 코즈 분석**을 수행했다. 결론은 버그 하나가 아니었다. SFT 파이프라인 전체에 문제가 있었다. 발견된 5가지 핵심 버그: | 버그 | 증상 | 영향 | |------|------|------| | Static padding (no packing) | 짧은 샘플도 max_len으로 패딩 | GPU 낭비, 학습 비효율 | | EOS 토큰 절단 | 응답 끝에 EOS가 없음 | 모델이 "문장 끝"을 못 배움 | | 단일 에폭 | 데이터를 한 번만 봄 | 언더피팅 | | 검증 분리 없음 | val_loss 측정 불가 | 오버피팅 감지 불가 | | 데이터 품질 | 노이즈, 중복, 불균형 | 반복 생성 패턴 유도 | 특히 EOS 절단 버그는 subtle하다. 모델이 응답을 마치는 시점을 배우지 못하면, 생성 시 끊임없이 같은 패턴을 반복하거나 의미 없는 토큰을 이어붙인다. 18% 반복률의 원인 중 하나였다. --- ### Day 3 (Feb 27) — SFT v2: 성공이지만 18% 반복 5가지 버그를 모두 수정하고 SFT v2를 돌렸다. - **val_loss: 2.2062** — 합리적 수준 - **반복률: 18%** (rep_penalty=1.1 적용 후) 생성 품질은 v1에 비해 확연히 개선됐다. 하지만 18% 반복률은 여전히 높다. `rep_penalty`를 높이면 반복은 줄지만 생성 다양성도 줄고 어색해진다. 디코딩 파라미터로 해결하기엔 구조적 한계가 있다. kobest_copa 기준 0.646. 괜찮은 수치이지만 목표에는 미치지 못한다. --- ### Day 3 (Feb 27) — "저스티스리그 vs 어벤저스": 3B 전환 결정 반복률 18%를 놓고 팀 내부 토론이 벌어졌다. 핵심 질문은 하나였다: > **ORPO로 반복을 잡을 수 있는가, 아니면 3B로 가야 하는가?** 이 질문에 답하기 위해 **멀티에이전트 토론**을 수행했다 (코드명: "저스티스리그 vs 어벤저스"). 각 에이전트가 다른 입장을 맡아 논증했다. 토론의 핵심 발견: 1. **18% 반복은 1B 파라미터의 구조적 한계**다. 1B 모델은 장거리 의존성(long-range dependency)을 충분히 포착하지 못한다. ORPO 같은 선호도 정렬은 반복을 줄이는 데 일부 도움이 되지만, 근본 원인(파라미터 부족)을 해결하지는 못한다. 2. **스케일링 법칙 분석**: Chinchilla 법칙과 실험 데이터를 기반으로 3B 모델은 동일 데이터에서 반복률을 5~8%까지 낮출 수 있다는 추정이 나왔다. 3. **비용-편익 분석**: ORPO를 1B에 투자하는 것보다 3B 프리트레인에 투자하는 것이 최종 모델 품질 측면에서 우월하다. **결론: 3B 전환**. 1B는 아카이브하고 3B 프리트레인을 시작한다. 이 결정은 `eval/debate/justice_league_3b_case.md`에 전체 논증과 함께 기록돼 있다. --- ### Day 3 (Feb 27) — 640GB+ 데이터 조립 3B 전환이 결정되자마자 데이터 파이프라인을 가동했다. 1B에 비해 훨씬 많은 데이터가 필요하다 (Chinchilla 최적 비율: 3B 모델 × 20 = 60B tokens). 최종적으로 조립한 데이터: - **총 토큰**: 41.12B tokens (최종 이진 파일) - **원시 데이터**: 640GB+ 다국어 텍스트 - **소스**: C4 Korean, 나무위키, Wikipedia Korean, korean_extra 데이터셋 데이터 전처리(토크나이즈, 셔플, 이진 변환)가 완료된 `data/3b_train.bin`은 82GB다. 검증셋 `data/3b_val.bin`은 151MB. --- ### Mar 2 — Phase 0: OOM 격퇴 및 최적화 3B 학습을 처음 시작하자 OOM(Out of Memory)이 발생했다. 183GB VRAM인데 3B 모델이 OOM이 난다는 게 이상하지만, 원인은 있었다. **GQA FlashAttention 구현 문제**였다. GQA(Grouped-Query Attention)에서 KV 캐시를 expand하는 방식이 메모리를 불필요하게 복사하고 있었다. FlashAttention의 native GQA support를 제대로 활용하지 않은 것이다. Phase 0에서 수행한 최적화 목록: | 최적화 | 방법 | 효과 | |--------|------|------| | GQA FA Native | `flash_attn_varlen_func` native GQA 경로 사용 | VRAM 60.4GB → 48.3GB (**-20%**) | | DDP 최적화 | `gradient_as_bucket_view=True` | GPU-CPU 동기화 오버헤드 -87.5% | | NCCL NVLS | Ring+Tree 토폴로지, NVLS 활성화 | AllReduce 효율 개선 | | 배치 크기 분석 | GPU 2,4,6의 NCCL relay node 역할 파악 | bs=5 최적, bs=6 위험 판정 | | SIGHUP 방어 | nohup+setsid + Python signal handler + emergency ckpt | 3중 보호 | | 모니터링 | Telegram Bot (B200Bot) + cron | 10분 워치독, 1시간 상태 리포트 | **torch.compile 테스트**: 효과 없음(1.00x). 원인은 TransformerEngine의 opaque kernel이 graph break를 유발하고, `/tmp` 디렉토리에 noexec 플래그가 걸려 있어 컴파일된 kernel 캐시가 쓰이지 않았다. 시간 낭비를 한 셈이지만, "효과 없다"는 것을 실측으로 확인한 것도 성과다. **bs=5의 이유**: NCCL ring topology에서 GPU 2, 4, 6이 relay node 역할을 맡는다. 이 GPU들은 다른 GPU보다 약 11GB를 더 사용한다. bs=5에서는 여유가 있지만, bs=6으로 올리면 이 relay GPU들이 183GB 경계에 너무 가까워진다. 안전 마진을 위해 bs=5를 유지한다. --- ### Mar 2~Mar 5 — Phase 1: 3B 프리트레인 완료 Phase 0 최적화가 완료된 후 Phase 1이 시작됐다. 초기 지표 (step 3150): - Loss: 2.38 - 처리 속도: 36K tok/s per rank - 시스템 전체: ~292K tok/s (8 GPU) - MFU: ~33.5% MFU 33.5%는 처음에는 낮아 보일 수 있다. 하지만 TE MXFP8가 이미 최적화된 상태에서 나온 수치다. 이론적 피크(18,000 TFLOPS) 대비 실효율이다. 추가 최적화 여지로 QKV fusion (+8~12%), NUMA affinity (+4~9%), FA2 native RoPE (+3~5%)가 남아있다. **Phase 1 완료 (2026-03-05)**: - **57,000 steps 완료**, 최종 loss **1.466** - 41.12B 토큰 처리, 총 학습 시간 약 63시간 - 무사고 완료 (SIGHUP, OOM, NCCL 이상 없음) 종합 평가 결과 요약 (v2 재평가 반영): | 항목 | 결과 | |------|------| | PPL (통합 검증셋) | 5.2263 (초기 v1 평가: 5.709) | | PPL (C4 Korean) | 5.717 | | KoBEST 평균 (5태스크) | 43.69% | | MMLU-KO 평균 (6카테고리) | 22.75% | | HAE-RAE | 19.71% | | winogrande / piqa | 50.59% / 52.50% | | Calibration Top-1 | 68.75% | | Greedy 3-gram 반복률 | 60.99% (SFT 후 개선 예정) | | 최적 생성 파라미터 | temp=0.7, rep_penalty=1.3 → 반복률 0% | **SFT 진행 결정**: loss 1.466은 건강한 학습 완료 시그널. PPL/반복률/벤치마크 모두 SFT가 해결할 영역. 모델 구조 문제 징후 없음. → Phase 2 SFT 진행. --- ### Mar 5~ — Phase 2: 3B SFT 시작 — 2.44M 샘플, val_loss 1.956 Phase 1 완료 직후, 대규모 SFT 데이터를 준비하고 학습을 시작했다. **데이터 파이프라인**: - **24개 소스**에서 6.59M raw samples 수집 - `prepare_sft_combined.sh`: 포맷 통일(6가지 포맷 → messages), MD5 중복 제거, 98:2 split - `filter_sft_v2.py`: 5단계 품질 필터 (EOS strip, QA marker 제거, 길이 필터, 4-gram 반복 필터) - 최종: **2,439,397 train + 49,801 val** (7.48 GB) 데이터 구성은 추론/CoT(38%), 한국어 지시(22.5%), 영어 다목적(16%), 수학(12%), 대화/코드(11.5%)로 균형을 맞췄다. 1B SFT의 161K에서 **15배 확대**한 규모다. **SFT 설계 — 1B 실패에서 배운 교훈 반영**: | 1B 교훈 | 3B SFT 적용 | |---------|-------------| | Label off-by-one → loss=0 | Loss masking 검증 (prompt=-1, response만 학습) | | EOS 절단 → 종료 불가 | Chat template `<\|user\|>...<\|assistant\|>...` EOS 포함 | | Static padding → GPU 낭비 | Dynamic padding (64-token 정렬) | | 검증 없음 → 오버피팅 미감지 | 49,801 val samples, 500 step 간격 eval | | 데이터 노이즈 | 5단계 품질 필터 (1B에는 없었음) | | 반복률 18% | **NEFTune alpha=5.0** 추가 (임베딩 노이즈 주입) | **학습 설정**: - LR: **1e-5** (pretrain의 1/15 — catastrophic forgetting 방지) - Effective batch: 2 × 8 GPU × 4 accum = 64 sequences - 33,000 steps (~3.3 epochs) - MXFP8, gradient checkpointing, NCCL Ring+Tree **초기 결과** (step 2,000, 6%): - Val loss: 2.073 → 2.004 → 1.975 → **1.956** (단조 감소) - Train-Val 갭 ~0.1 (오버피팅 징후 없음) - VRAM 24.2 GB (13.2%) — pretrain의 절반, 매우 안정 - Grad norm 1.0 일정 (학습률 적절) 상세 보고서: `reports/2026-03-05_3B_SFT_PROGRESS_REPORT.md` --- ### Mar 6 — Phase 2 완료: SFT Early Stopping (val_loss 1.8851) SFT는 33,000 steps 중 **25,500 steps**에서 early stopping으로 종료되었다. Val loss는 step 23,000에서 1.8851에 도달한 뒤, 5회 연속 개선 없이 학습이 자동 중단되었다. **총 학습 시간**: ~15시간 41분 (2026-03-05 22:15 ~ 2026-03-06 13:56) 이 결과는 LR 1e-5의 cosine decay가 step 20K 이후 사실상 0에 수렴한 것과 일치한다. 모델은 주어진 LR schedule 하에서 학습 가능한 만큼 완전히 학습했다. --- ### Mar 6 — SFT 6차원 종합 평가: 4/6 PASS → ORPO 결정 SFT 체크포인트(`checkpoint-best`, step 23000)에 대해 6차원 종합 평가를 수행했다. 49분 27초 소요. **핵심 결과**: - **Perplexity**: forgetting 0.9% (19개 데이터셋 전체 PASS) — 지식 보존 우수 - **반복률**: greedy 72.97% (Base 60.99%보다 **악화**) — FAIL - **EOS 종료율**: 0% → 60% — 개선됐지만 목표(90%) 미달 - **KoBEST**: 43.26% (Base 43.69%와 거의 동일) — FAIL - **MMLU-KO**: 22.75% → 26.00% (+3.2pp) — 부분 개선 - **Calibration**: Top-1 68.59% — PASS **결정**: greedy 반복률 72.97%는 SFT만으로 해결 불가. 그러나 `rep_penalty=1.2` 적용 시 반복률 0%가 달성되므로, ORPO(선호도 정렬)로 이 행동을 내재화하는 것이 올바른 경로다. --- ### Mar 6 — 코드 개선 및 ORPO 준비 SFT 평가와 병행하여 다수의 코드 개선 및 Phase 3 준비를 완료했다: | 변경 | 내용 | 영향 | |------|------|------| | `train/sft.py` +238줄 | MixingDataLoader (SFT+pretrain 인터리빙), DDP rank 0 토크나이징 | forgetting 방지, 메모리 8배 절감 | | `train/trainer.py` +17줄 | DDP early stopping broadcast (hang 방지), patience 5→10 | DDP 안정성 | | `train/orpo.py` +30줄 | YAML config 지원, 3B 기본값 | ORPO 실행 준비 | | `eval/report_generator.py` +831줄 | Base vs SFT 비교 보고서 자동 생성 | 평가 자동화 | | `eval/sft_eval_pipeline.py` 신규 | SFT 6차원 평가 파이프라인 | 종합 평가 | | `eval/tasks/generation_task.py` +75줄 | Chat template, 다양성 메트릭 | SFT 평가 | | `configs/korean_3b_sft_v2.yaml` 신규 | SFT v2 설정 (lr=5e-5, data mixing 70/30) | 백업 경로 | | `configs/korean_3b_orpo.yaml` 신규 | ORPO 설정 (lr=5e-6, beta=0.1) | Phase 3 | 상세: `reports/2026-03-06_3B_SFT_COMPLETION_AND_EVAL_SUMMARY.md` --- ## 6. 모델 아키텍처 ### 1B (아카이브) | 항목 | 값 | |------|-----| | vocab_size | 64,000 | | d_model | 2,048 | | n_layers | 24 | | n_heads | 16 | | n_kv_heads | 4 (GQA 4:1) | | d_ffn | 5,461 (SwiGLU) | | 파라미터 수 | ~1.19B | | context | 2,048 | | rope_theta | 500,000 | ### 3B (현재) | 항목 | 값 | |------|-----| | vocab_size | 64,000 | | d_model | 3,072 | | n_layers | 28 | | n_heads | 24 | | n_kv_heads | 8 (GQA 3:1) | | d_ffn | 8,192 (SwiGLU) | | 파라미터 수 | ~3.0B | | context | 2,048 | | rope_theta | 500,000 | ### 공통 설계 원칙 | 컴포넌트 | 선택 | 이유 | |----------|------|------| | 정규화 | Pre-norm RMSNorm | Post-norm보다 학습 안정적 | | 활성화 | SwiGLU FFN | Llama 계열에서 검증된 선택 | | 위치 인코딩 | RoPE (θ=500K) | 긴 컨텍스트 확장 가능성 | | 어텐션 | GQA (Grouped-Query Attention) | KV 캐시 메모리 절감 | | 구현 | FlashAttention-2 | IO-aware, VRAM 효율 | | 정밀도 | FP8 (MXFP8 via TransformerEngine) | B200 최적 활용 | ### GQA 비율 선택 근거 1B는 GQA 4:1 (head 16개, kv_head 4개), 3B는 GQA 3:1 (head 24개, kv_head 8개)을 선택했다. 3B에서 비율을 다소 완화한 이유는, 파라미터 수가 늘어나면서 어텐션 품질을 다소 희생하는 것이 3B 규모에서는 손해라는 판단이었다. Mistral 7B (GQA 8:1)와 Llama 3 (GQA 8:1)를 참고했다. ### rope_theta=500,000의 의미 표준 RoPE의 θ=10,000에서 500,000으로 늘린 것은 긴 컨텍스트에서 주파수 간섭을 줄이기 위해서다. Code Llama, Llama 3 등이 채택한 방식이다. 현재 max_seq_len=2048이므로 당장 효과를 보기는 어렵지만, 향후 컨텍스트 확장 파인튜닝을 위한 기반이다. --- ## 7. 학습 데이터 ### 7.1 토크나이저 | 항목 | 값 | |------|-----| | 종류 | SentencePiece Unigram | | 어휘 크기 | 64,000 | | 한국어 문자 커버리지 | 99.95% | | 위치 | `tokenizer/korean_sp/` | | HF 포맷 | `tokenizer/tokenizer.json` (2.4MB) | 64K 어휘는 32K(너무 작음, 한국어 서브워드 단편화 심함)와 128K(너무 큼, 임베딩 레이어 오버헤드 증가) 사이의 균형이다. Llama 3(128K)와 GPT-4(100K)가 큰 어휘를 사용하는 추세지만, 3B 모델에서 128K 어휘는 임베딩 레이어만으로도 파라미터 비중이 지나치게 커진다. ### 7.2 프리트레인 데이터 — 전체 구성 최종 학습 파일: `data/3b_train.bin` (77GB, ~38.5B tokens) + `data/3b_val.bin` (145MB) Chinchilla 법칙 기준: 3B × 20 = **60B 토큰**이 최적이다. 현재 38.5B 토큰을 57,000 스텝(batch 5 × accum 8 × seq 2048 × 8 GPU)으로 반복 소비하며, 처음 3B 학습으로서 합리적인 범위다. #### 한국어 — 웹크롤 (Web Crawl) | 데이터셋 | HuggingFace ID | 토큰화 파일 | 크기 | 추정 토큰 | 설명 | |----------|---------------|------------|------|----------|------| | C4 Korean | `allenai/c4` (ko subset) | `korean_c4_train.bin` | 15GB | ~7.5B | Google C4 한국어 필터링, 대규모 클린 웹 텍스트 | | CC-100 Korean | `cc100` (ko subset) | `cc100_ko_train.bin` | 4.3GB | ~2.15B | Common Crawl 기반 단일언어 코퍼스 | | HPLT Korean | `HPLT/hplt_monolingual_v2` (ko) | `hplt_ko_train.bin` | 15GB | ~7.5B | High Performance Language Technologies 웹 데이터 | #### 한국어 — 백과사전 (Encyclopedia) | 데이터셋 | HuggingFace ID | 토큰화 파일 | 크기 | 추정 토큰 | 설명 | |----------|---------------|------------|------|----------|------| | 위키백과 한국어 | `wikimedia/wikipedia` (20231101.ko) | `wikipedia_ko_train.bin` | 566MB | ~283M | 한국어 위키백과 전체, 구조화된 문어체 | | 위키백과 한국어 (v2) | `wikimedia/wikipedia` (ko) | `korean_wiki_train.bin` | 500MB | ~250M | 위키백과 별도 버전 | | 나무위키 | `heegyu/namuwiki-extracted` | `korean_namuwiki_train.bin` | 2.1GB | ~1.05B | 나무위키 추출본, 서브컬처·시사 풍부 | | 나무위키 2023b | `heegyu/namuwiki-extracted` (2023b) | `namuwiki_2023b_train.bin` | 2.5GB | ~1.25B | 2023년 업데이트 스냅샷 | #### 영어/다국어 — 교육 (Educational) | 데이터셋 | HuggingFace ID | 토큰화 파일 | 크기 | 추정 토큰 | 설명 | |----------|---------------|------------|------|----------|------| | Cosmopedia Stories | `HuggingFaceTB/cosmopedia` | `cosmo_stories_train.bin` | 5.9GB | ~2.95B | 합성 교육용 스토리 | | Cosmopedia Web v2 | `HuggingFaceTB/cosmopedia` | `cosmo_web_v2_train.bin` | 2.7GB | ~1.35B | 웹 기반 교육 텍스트 | | Cosmopedia Stanford | `HuggingFaceTB/cosmopedia` | `cosmo_stanford_train.bin` | 2.1GB | ~1.05B | Stanford 강의 기반 | | Cosmopedia WikiHow | `HuggingFaceTB/cosmopedia` | `cosmo_wikihow_train.bin` | 382MB | ~191M | WikiHow 가이드 | | Cosmopedia OpenStax | `HuggingFaceTB/cosmopedia` | `cosmo_openstax_train.bin` | 224MB | ~112M | 오픈 교과서 | | Cosmopedia Khan Academy | `HuggingFaceTB/cosmopedia` | `cosmo_khanacademy_train.bin` | 46MB | ~23M | 칸 아카데미 | #### 영어/다국어 — 수학·과학 (Math & Science) | 데이터셋 | HuggingFace ID | 토큰화 파일 | 크기 | 추정 토큰 | 설명 | |----------|---------------|------------|------|----------|------| | Open Web Math | `open-web-math/open-web-math` | `open_web_math_train.bin` | 4.8GB | ~2.4B | 웹에서 추출한 수학 텍스트 | | MathPile | `GAIR/MathPile` | `mathpile_train.bin` | 2.9GB | ~1.45B | 수학 교과서·논문·포럼 | | Cosmopedia AutoMath | `HuggingFaceTB/cosmopedia` | `cosmo_auto_math_text_train.bin` | 2.5GB | ~1.25B | 합성 수학 문제·풀이 | #### 한국어 — 혼합 (Legacy Merged) | 데이터셋 | 토큰화 파일 | 크기 | 추정 토큰 | 설명 | |----------|------------|------|----------|------| | 초기 혼합 (C4+나무+위키) | `korean_train.bin` | 17GB | ~8.5B | 1B 학습에 사용된 원본 혼합 데이터 | | 125M 검증용 | `train.bin` | 1.2GB | ~600M | 최초 FP8 검증에 사용 | #### 미사용 수집 데이터 (korean_extra/ — 640GB+) `data/korean_extra/` 에 39개 서브디렉토리로 수집되었으나, 토큰화·병합은 일부만 완료된 대규모 원시 데이터: | 분류 | 데이터셋 | 설명 | 비고 | |------|----------|------|------| | 웹크롤 | CulturaX Korean | 대규모 다국어 웹 코퍼스 한국어 | ~50B+ tokens | | 웹크롤 | FineWeb2 Educational Korean | 교육적 품질 필터링 웹 데이터 | 234GB raw | | 웹크롤 | Korean Web Collection | KORMo 웹 컬렉션 | 175GB raw | | 웹크롤 | OSCAR Korean | 다국어 웹 코퍼스 한국어 | | | 교육 | Korean Textbooks | 한국어 교과서 텍스트 | 45개 서브카테고리 | | 교육 | FinePDFs Educational Korean | PDF 기반 교육 자료 | | | 법률 | Korean Law | 한국 법률 텍스트 | 15GB | | 뉴스 | Korean News Archive | 한국어 뉴스 아카이브 | | | 공개코퍼스 | Korean Public Corpus | KORMo 공개 코퍼스 | 26GB | | 코드 | Code Pretrain | 프로그래밍 코드 | | | 학술 | Academic Pretrain | 학술 논문·리포트 | | | 범용 | SlimPajama | RedPajama 경량 버전 | | > 이 데이터는 Extended Pretrain (80-100B tokens) 단계에서 활용 예정이다. #### 프리트레인 데이터 분야별 비율 ``` ┌─────────────────────────────────────────────────────────┐ │ 3b_train.bin 토큰 구성 (~38.5B) │ ├─────────────────────────────────────────────────────────┤ │ ████████████████████░░░░░░░░░░ 한국어 웹크롤 44.7% │ │ ██████████░░░░░░░░░░░░░░░░░░░░ 혼합 레거시 22.1% │ │ ██████░░░░░░░░░░░░░░░░░░░░░░░░ 교육 (EN) 14.7% │ │ █████░░░░░░░░░░░░░░░░░░░░░░░░░ 수학·과학 13.2% │ │ ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 백과사전 (KO) 5.3% │ └─────────────────────────────────────────────────────────┘ ``` ### 7.3 SFT 데이터 — 2.44M 샘플 (현재 학습 중) **24개 소스**에서 6.59M raw → 통합·중복 제거 → 품질 필터링 → **2,439,397 train + 49,801 val** #### 주요 SFT 소스 (상위 12, 전체의 96%) | # | 데이터셋 | 샘플 수 | 크기 | 도메인 | |---|---------|---------|------|--------| | 1 | reasoning_r1_1.4m | 1,400,000 | 14.77 GB | 추론 (CoT) | | 2 | openhermes_2.5 | 1,001,551 | 1.82 GB | 영어 다목적 | | 3 | AI-MO_NuminaMath-CoT | 859,494 | 2.51 GB | 수학 CoT | | 4 | korean_instruction_mix | 515,911 | 1.39 GB | 한국어 혼합 | | 5 | lemon-mint_smol-koreantalk | 460,281 | 5.23 GB | 한국어 대화 | | 6 | open_korean_instructions | 375,159 | 0.73 GB | 한국어 지시 | | 7 | magpie_reasoning_v2 | 249,922 | 3.99 GB | 추론 (영어) | | 8 | magpie_reasoning_ko | 224,929 | 3.19 GB | 추론 (한국어) | | 9 | ultrachat_200k | 207,865 | 1.34 GB | 대화 | | 10 | kuotient_orca-math-ko | 193,789 | 0.61 GB | 수학 (한국어) | | 11 | data/sft/train.jsonl (원본) | 161,848 | 0.27 GB | 원본 SFT | | 12 | kullm_v2 | 152,630 | 0.42 GB | 한국어 지시 | 기타 12개 소스: DeepMath-103K, Evol-Instruct-Code-80k-ko, ShareGPT-74k-ko, evol-instruct-korean, alpaca-gpt4-korean, ko_wikidata_QA, Ko.WizardLM, KOR-OpenOrca-Platypus-v3, korean-writing-style-instruct, ko_lima, koalpaca_v1_1a, OpenAssistant_oasst1_ko #### 데이터 처리 파이프라인 ``` 24개 소스 (6.59M raw) ↓ prepare_sft_combined.sh (포맷 통일, MD5 중복 제거, 98:2 split) 통합: 2,559,492 train + 52,234 val (7.95 GB) ↓ filter_sft_v2.py (5단계: EOS strip, QA marker 제거, 길이 50~20K, 4-gram 반복 >30% 제거) 최종: 2,439,397 train + 49,801 val (7.63 GB) ← 제거율 4.69% ``` #### 도메인 비율 ``` 추론/CoT 38.0% ████████████████████████ 한국어 지시 22.5% ██████████████ 영어 다목적 16.0% ██████████ 수학 12.0% ████████ 대화/코드/기타 11.5% ███████ ``` ### 7.4 선호도 데이터 (ORPO용) — 795K 쌍 총 **795,468 preference pairs** (7.9GB, `data/preference/combined_preference.jsonl`) | HuggingFace ID | 크기 | 분야 | 포맷 | |---------------|------|------|------| | `nayohan/preference-collection-ko-full` | 4.9GB | 범용 선호도 평가 | instruction + response_A/B + preference | | `heegyu/orca-math-korean-preference-cleaned` | 1.6GB | 수학 추론 | prompt + chosen + rejected | | `kuotient/orca-math-korean-dpo-pairs` | 750MB | 수학 DPO | prompt + chosen + rejected | | `maywell/ko_Ultrafeedback_binarized` | 394MB | 피드백 기반 정렬 | prompt + winning/losing response | | `tellang/yeji-preference-ko-v1` | 171MB | 범용 선호도 | prompt + chosen + rejected | | `jojo0217/korean_rlhf_dataset` | 137MB | RLHF 쌍 | prompt + chosen + rejected | | `lemon-mint/korean-realqa-reasoning-v01-preference` | 58MB | QA 추론 | prompt + chosen + rejected | **필터링 기준**: 최소 길이 20자, EOS 제거, 포맷 정규화 후 통합 > ORPO는 Phase 3에서 반복률이 5% 초과할 경우에만 실행한다. 3B 모델이 1B의 구조적 반복 문제를 스스로 해결한다면 ORPO 없이 배포할 수 있다. ### 7.5 데이터 파이프라인 요약 ``` [HuggingFace / 웹 수집] │ ▼ ┌─── 원시 수집 ───────────────────────────────────────────┐ │ korean_extra/ (39개 디렉토리, 640GB+) │ │ sft_extra/ (27개 디렉토리, 1.08M 샘플) │ │ preference/ (7개 JSONL, 795K 쌍) │ └─────────────────────────────────────────────────────────┘ │ ▼ ┌─── 토큰화 (SentencePiece 64K) ──────────────────────────┐ │ tokenize_extra.py — 자동 포맷 감지 (Arrow/Parquet/JSONL) │ │ 8 workers 병렬 처리, uint16 memmap (.bin) 출력 │ └─────────────────────────────────────────────────────────┘ │ ▼ ┌─── 최종 병합 ───────────────────────────────────────────┐ │ Pretrain: 3b_train.bin (77GB, ~38.5B tokens) │ │ SFT: sft_combined/train_filtered.jsonl (7.48GB, 2.44M 샘플) │ │ ORPO: preference/combined_preference.jsonl (7.9GB) │ └─────────────────────────────────────────────────────────┘ ``` --- ## 8. 학습 설정 및 최적화 ### 현재 학습 설정 (`configs/korean_3b_fp8.yaml`) ```yaml model: vocab_size: 64000 d_model: 3072 n_layers: 28 n_heads: 24 n_kv_heads: 8 d_ffn: 8192 max_seq_len: 2048 rope_theta: 500000.0 training: batch_size: 5 gradient_accumulation_steps: 8 learning_rate: 1.5e-4 min_lr: 1.5e-5 warmup_steps: 2000 max_steps: 57000 weight_decay: 0.1 grad_clip: 1.0 optimizer: adamw scheduler: cosine fp8: enabled: true recipe: "mxfp8" use_transformer_engine: true distributed: strategy: ddp gradient_as_bucket_view: true find_unused_parameters: false nccl: timeout_seconds: 7200 nvls_enabled: true ``` 유효 배치 크기 = `batch_size(5) × grad_accum(8) × num_gpus(8)` = **320** LR 스케줄: warmup 2000 스텝 → cosine decay → min_lr=1.5e-5 (max_lr의 10%) ### Phase 0에서 배운 최적화 교훈 #### GQA FlashAttention Native 가장 큰 VRAM 절감을 가져온 최적화. 핵심은 FlashAttention이 GQA를 native로 지원한다는 점이다. KV head를 expand하여 MHA처럼 처리하면 메모리 복사가 발생하지만, native path를 쓰면 내부에서 직접 처리한다. ```python # Before (비효율적): KV expand → MHA처럼 처리 k = k.repeat_interleave(n_heads // n_kv_heads, dim=1) v = v.repeat_interleave(n_heads // n_kv_heads, dim=1) out = flash_attn_func(q, k, v) # After (native GQA): flash_attn이 내부에서 GQA 처리 out = flash_attn_func(q, k, v) # q: [B, S, H, D], k/v: [B, S, Hkv, D] # VRAM 60.4GB → 48.3GB (-20%) ``` #### DDP 최적화 ```python # gradient_as_bucket_view=True: gradient tensor를 bucket 메모리의 view로 직접 매핑 # → 불필요한 메모리 복사 제거, GPU-CPU 동기화 오버헤드 -87.5% model = torch.nn.parallel.DistributedDataParallel( model, device_ids=[local_rank], gradient_as_bucket_view=True, find_unused_parameters=False, # 모든 파라미터가 사용됨 ) ``` **주의**: `static_graph=True`는 사용하지 않는다. TransformerEngine의 `te.Linear`가 일부 케이스에서 dynamic graph를 요구하는데, static_graph를 켜면 런타임 에러가 발생한다. #### NCCL NVLS ```bash export NCCL_ALGO=NVLSTree # NVLink SHARP (NVLS) 활성화 export NCCL_PROTO=Simple export NCCL_P2P_DISABLE=0 export NCCL_TIMEOUT=7200 # 긴 backward에 대비한 타임아웃 여유 ``` NVSwitch가 All-to-All single hop을 지원하므로 Ring topology보다 NVLSTree가 효율적이다. #### SIGHUP 3중 방어 장시간 학습에서 세션 연결 끊김(SIGHUP)은 치명적이다. 3중 보호를 구축했다: ```bash # 1중: nohup + setsid (새 세션 그룹) nohup setsid torchrun --nproc_per_node=8 train/pretrain.py ... & # 2중: Python signal handler (Python 레벨 SIGHUP 무시) import signal signal.signal(signal.SIGHUP, signal.SIG_IGN) # 3중: emergency checkpoint (SIGTERM에도 체크포인트 저장) def emergency_save(signum, frame): save_checkpoint(model, optimizer, step, "emergency") sys.exit(0) signal.signal(signal.SIGTERM, emergency_save) ``` #### torch.compile — 테스트 결과: 효과 없음 `torch.compile`을 적용해 speedup을 기대했지만 실측 결과 **1.00x (효과 없음)**이었다. 두 가지 이유: 1. TransformerEngine의 kernel이 opaque하여 graph break가 발생한다. `torch.compile`은 Python 연산 그래프를 최적화하는데, TE kernel은 그 그래프 밖에 있다. 2. `/tmp` 디렉토리에 `noexec` 마운트 플래그가 있어 컴파일된 kernel을 캐시하지 못한다. **교훈**: "일단 써보자"보다 "왜 효과가 있는지 먼저 이해하자"가 중요하다. ### 모니터링 시스템 ``` 텔레그램 알림 시스템 ├── B200Bot (token 설정됨) ├── training_watchdog.sh → 10분 간격 cron │ └── loss 이상, 프로세스 종료 감지 → 즉시 알림 └── hourly_status.sh → 1시간 간격 cron └── step, loss, 속도, VRAM, eta → 정기 리포트 ``` ```python # curl이 차단돼 있어 urllib 사용 import urllib.request, json def send_telegram(message): url = f"https://api.telegram.org/bot{TOKEN}/sendMessage" data = json.dumps({"chat_id": CHAT_ID, "text": message}).encode() req = urllib.request.Request(url, data=data, headers={"Content-Type": "application/json"}) urllib.request.urlopen(req) ``` --- ## 9. 실험 결과 — 1B 베이스라인 1B 모델의 실험 결과를 정직하게 기록한다. 성공과 실패 모두. ### 프리트레인 결과 | 지표 | 값 | |------|-----| | 최종 Loss | 1.904 | | PPL (C4 Korean) | 5.67 | | 학습 스텝 | 34,000 | | 학습 시간 | ~2일 | ### SFT v1 결과 — 실패 | 지표 | 값 | |------|-----| | val_loss | 0.0 (비정상) | | 원인 | label off-by-one 버그 (데이터 누수) | | 결론 | 전면 폐기 | ### SFT v2 결과 — 부분 성공 | 지표 | 값 | |------|-----| | val_loss | 2.2062 | | 반복률 | 18% (rep_penalty=1.1 적용) | | kobest_copa | 0.646 | | 결론 | 기능하지만 구조적 한계 존재 | ### 3B 기대 목표치 (스케일링 법칙 기반 예측) | 벤치마크 | 1B 현재 | 3B 목표 | |----------|---------|---------| | kobest_copa | 0.646 | >0.72 | | kobest_hellaswag | ~0.42 | >0.52 | | 반복률 | 18% | <5% | | PPL (C4 Korean) | 5.67 | <4.5 | 1B에서 3B로의 스케일업은 단순히 파라미터를 늘리는 것이 아니다. 모델이 더 긴 맥락을 기억하고, 더 다양한 패턴을 학습할 수 있어야 반복률이 구조적으로 낮아진다. 3B 목표치는 Chinchilla 스케일링 곡선과 유사 규모 모델들의 벤치마크를 참고한 예측값이다. --- ## 10. 실험 결과 — 3B Base 종합 평가 (v2) 3B 사전학습 완료 후 checkpoint-0057000 기준으로 수행한 종합 평가. v2 재평가는 8-GPU 병렬 파이프라인으로 13+ 벤치마크, 0/5-shot 비교, calibration, 참고모델 비교를 포함한다. 총 소요 시간 256.6초. > **v1 → v2 변경점**: v1(초기 평가)에서는 PPL 3개 데이터셋 + belebele/MMLU 2개 벤치마크만 측정했다. v2는 PPL 19개 데이터셋, KoBEST 5개, HAE-RAE 전체, MMLU-KO 6카테고리, MMLU-EN 61과목, 영어 5대 벤치마크, Calibration, 0/5-shot 비교, 12조합 파라미터 그리드 서치를 포함한다. ### 10.1 학습 커브 | Step | Loss | LR | 비고 | |------|------|----|------| | 10 | 11.657 | 1.50e-06 | 초기 (warmup 시작) | | 500 | 5.047 | 7.50e-05 | warmup 진행 | | 2,000 | 2.851 | 3.00e-04 | warmup 완료, peak LR | | 10,000 | 2.057 | 2.86e-04 | 안정 하강 | | 30,000 | 1.789 | 1.61e-04 | 중반, epoch 1 진입 | | 57,000 | 1.466 | 3.00e-05 | 최종 (cosine min) | > 처리 속도는 전 구간 36~38K tok/s로 안정. 총 학습 시간 약 63시간. ### Base Model 백업 | 항목 | 값 | |------|-----| | 원본 체크포인트 | `checkpoints/korean_3b_fp8_run1/checkpoint-0057000/` (34GB) | | 백업 | `checkpoints/korean_3b_fp8_run1/checkpoint-0057000_BASE_BACKUP/` | | MD5 검증 | `4f493d7bcc843727d32453bb3a4e6b7d` (일치 확인) | | HF 변환 | `eval/outputs/hf_3b_base/` (11GB safetensors) | ### 10.2 PPL (Perplexity) — 19개 데이터셋 **주요 PPL (3b_val 통합): 5.2263** (초기 v1 평가: 5.709) | 데이터셋 | PPL | Bits/Token | 평가 토큰 | 소요 시간 | |---------|-----|-----------|---------|---------| | korean_namuwiki | 25.88 | 4.694 | 6.5M | 63.7s | | cc100_ko | 21.78 | 4.445 | 13.6M | 133.2s | | namuwiki_2023b | 18.92 | 4.242 | 7.7M | 75.1s | | val | 18.30 | 4.194 | 9.1M | 89.4s | | korean_wiki | 11.84 | 3.565 | 1.6M | 15.5s | | wikipedia_ko | 10.71 | 3.420 | 1.8M | 17.4s | | korean | 7.02 | 2.811 | 53.5M | 521.6s | | open_web_math | 6.93 | 2.792 | 15.7M | 153.5s | | **korean_c4** | **5.72** | **2.515** | **45.4M** | **443.1s** | | **3b (통합)** | **5.23** | **2.386** | **226.9M** | **2227.3s** | | cosmo_web_v2 | 4.17 | 2.059 | 8.6M | 84.6s | | cosmo_stories | 3.96 | 1.984 | 18.9M | 185.2s | | cosmo_openstax | 3.87 | 1.951 | 0.7M | 7.2s | | cosmo_stanford | 3.36 | 1.750 | 6.6M | 65.3s | | cosmo_wikihow | 3.31 | 1.727 | 1.2M | 11.8s | | cosmo_auto_math_text | 3.15 | 1.655 | 7.9M | 77.3s | | cosmo_khanacademy | 2.93 | 1.552 | 0.1M | 1.5s | | mathpile | 2.72 | 1.446 | 7.1M | 69.9s | | hplt_ko | 2.40 | 1.265 | 48.5M | 475.9s | > **해석**: in-distribution(학습에 포함된) 데이터(hplt_ko: 2.40, mathpile: 2.72)가 낮고, OOD(학습 비중 낮은) 데이터(cc100_ko: 21.78, namuwiki: 25.88)가 높은 것은 예상된 패턴. korean_c4 5.72는 v1의 5.717과 일치하여 평가 재현성을 확인. ### 10.3 한국어 벤치마크 #### KoBEST (0-shot) — 평균 43.69% | 태스크 | Accuracy | F1 | |--------|----------|-----| | kobest_boolq | 50.28% | 0.3457 | | kobest_copa | 49.30% | 0.4921 | | kobest_hellaswag | 21.60% | 0.2153 | | kobest_sentineg | 48.61% | 0.4737 | | kobest_wic | 48.65% | 0.3286 | | **평균** | **43.69%** | | #### HAE-RAE (0-shot) — 전체 19.71% | 서브태스크 | Accuracy | |-----------|----------| | haerae_general_knowledge | 21.59% | | haerae_history | 23.40% | | haerae_loan_word | 21.30% | | haerae_rare_word | 18.77% | | haerae_standard_nomenclature | 13.73% | | **전체** | **19.71%** | #### MMLU-KO (0-shot) — 6카테고리 평균 22.75% | 카테고리 | Accuracy | |----------|----------| | medical | 30.56% | | humanities | 24.51% | | business | 24.14% | | social_sciences | 20.59% | | other | 19.64% | | stem | 19.57% | | **평균** | **22.75%** | > Base model은 instruction-following 없이 4지선다 형식 벤치마크를 풀도록 최적화되지 않음. KoBEST boolq/copa/sentineg/wic는 ~50% 수준으로 2지/4지선다 랜덤 기준 부근이며, SFT 후 향상 기대. ### 10.4 영어 벤치마크 #### 주요 벤치마크 (0-shot) | 태스크 | Accuracy | Acc (norm) | |--------|----------|-----------| | hellaswag | 26.00% | 26.15% | | arc_easy | 25.63% | 26.64% | | arc_challenge | 21.67% | 27.90% | | winogrande | 50.59% | — | | piqa | 52.50% | 48.31% | > winogrande(50.59%)와 piqa(52.50%)는 2지선다로 랜덤 기준 50%에 근접. hellaswag/arc는 4지선다로 랜덤 기준 25%. #### MMLU-EN (0-shot) — 61과목 평균 25.81% **상위 10개 과목**: | 과목 | Accuracy | |------|----------| | college_physics | 37.25% | | college_computer_science | 34.00% | | high_school_statistics | 33.80% | | us_foreign_policy | 32.00% | | security_studies | 31.43% | | world_religions | 30.99% | | professional_medicine | 30.88% | | high_school_government_and_politics | 30.57% | | jurisprudence | 30.56% | | human_sexuality | 30.53% | **하위 5개 과목**: | 과목 | Accuracy | |------|----------| | human_aging | 19.73% | | college_biology | 19.44% | | anatomy | 17.04% | | global_facts | 17.00% | | abstract_algebra | 15.00% | ### 10.5 Calibration | 메트릭 | 값 | |--------|-----| | Top-1 Accuracy | 68.75% | | Top-5 Accuracy | 81.64% | | Top-10 Accuracy | 85.93% | | Mean Correct Prob | 0.6152 | | Mean Entropy | 1.5682 | **Token NLL 분포**: | 통계 | 값 | |------|-----| | 평균 NLL | 1.5561 | | 표준편차 | 2.4926 | | 중앙값 | 0.1221 | | p95 | 7.0312 | | p99 | 10.3125 | | NLL > 5 비율 | 10.86% | | NLL > 10 비율 | 1.18% | > Top-1 68.75%는 모델이 가장 확신하는 예측이 ~69% 확률로 정확하다는 의미. 중앙값 NLL 0.12 (≈ e^0.12 = 1.13 PPL)로 대부분의 토큰을 매우 높은 확신도로 예측하고, 소수의 고난이도 토큰이 평균 NLL을 끌어올리는 전형적인 분포. ### 10.6 0-shot vs 5-shot 비교 18개 한국어 태스크에서 0-shot과 5-shot 성능을 비교했다. | 태스크 | 0-shot | 5-shot | 변화 | |--------|--------|--------|------| | global_mmlu_ko | 22.75% | 26.75% | **+4.00pp** | | global_mmlu_ko_business | 24.14% | 31.03% | **+6.90pp** | | global_mmlu_ko_humanities | 24.51% | 28.43% | +3.92pp | | global_mmlu_ko_medical | 30.56% | 36.11% | **+5.56pp** | | global_mmlu_ko_other | 19.64% | 23.21% | +3.57pp | | global_mmlu_ko_social_sciences | 20.59% | 23.53% | +2.94pp | | global_mmlu_ko_stem | 19.57% | 21.74% | +2.17pp | | haerae | 19.71% | 20.26% | +0.55pp | | haerae_general_knowledge | 21.59% | 22.73% | +1.14pp | | haerae_history | 23.40% | 14.89% | -8.51pp | | haerae_loan_word | 21.30% | 24.26% | +2.96pp | | haerae_rare_word | 18.77% | 18.02% | -0.74pp | | haerae_standard_nomenclature | 13.73% | 25.49% | **+11.76pp** | | kobest_boolq | 50.28% | 50.21% | -0.07pp | | kobest_copa | 49.30% | 46.80% | -2.50pp | | kobest_hellaswag | 21.60% | 20.80% | -0.80pp | | kobest_sentineg | 48.61% | 47.86% | -0.76pp | | kobest_wic | 48.65% | 48.97% | +0.32pp | **평균 변화: +1.80pp** | 개선: 12 | 하락: 6 > MMLU-KO는 5-shot에서 일관되게 개선(+2~7pp)되어 in-context learning 능력이 작동함을 확인. KoBEST는 거의 변동 없거나 소폭 하락—이미 0-shot에서 패턴 매칭을 잘하고 있어 few-shot 예시가 오히려 방해가 되는 패턴. haerae_standard_nomenclature의 +11.76pp는 이 태스크의 특수한 포맷을 few-shot에서 학습한 결과. ### 10.7 참고 모델 비교 | 모델 | 파라미터 | MMLU-KO | MMLU-EN | KoBEST 평균 | PPL | |------|---------|---------|---------|------------|-----| | **FRANKENSTALLM 3B** | **3B** | **22.75%** | **25.81%** | **43.69%** | **5.2263** | | Llama-3.2-3B | 3B | ~42% | ~58% | ~55% | — | | Qwen2.5-3B | 3B | ~48% | ~65% | ~60% | — | | EXAONE-3.5-2.4B | 2.4B | ~35% | ~50% | ~50% | — | > 참고 모델들은 수조 토큰 규모의 학습 데이터와 수천 GPU-hour를 투입한 결과. FRANKENSTALLM 3B는 41.12B 토큰(Chinchilla 최적의 ~68%), 63시간, 8 GPU로 학습한 점을 감안해야 한다. SFT + 확장 프리트레인(80-100B 토큰) 이후 격차 축소 예상. ### 10.8 생성 품질 및 파라미터 그리드 서치 #### 반복률 요약 | 설정 | 3-gram 반복률 | 4-gram 반복률 | |------|--------------|--------------| | greedy (temp=0.0) | 60.99% | 57.02% | | temp=0.5 | 60.12% | 58.68% | | temp=0.7 | 47.69% | 43.40% | | temp=1.0 | 3.58% | 2.81% | > 초기 v1 평가의 greedy 71.1% 반복률은 `no_repeat_ngram_size=3` 적용 기준이었다. v2에서는 미적용 기준(raw)으로 통일하여 60.99%를 기록. #### 12조합 파라미터 그리드 서치 결과 | 설정 | Temp | Rep Pen | 3-gram | 4-gram | 비고 | |------|------|---------|--------|--------|------| | **t0.7_rep1.3** | **0.70** | **1.30** | **0.00%** | **0.00%** | **최적** | | t0.9_rep1.2 | 0.90 | 1.20 | 0.00% | 0.00% | 차선 | | t0.7_rep1.2 | 0.70 | 1.20 | 0.88% | 0.00% | | | t0.9_rep1.1 | 0.90 | 1.10 | 0.94% | 0.13% | | | t1.0_rep1.1 | 1.00 | 1.10 | 1.21% | 0.48% | | | t0.5_rep1.1 | 0.50 | 1.10 | 1.92% | 1.19% | | | t1.0 | 1.00 | 1.00 | 3.58% | 2.81% | | | t0.9 | 0.90 | 1.00 | 8.39% | 4.64% | | | t0.7_rep1.1 | 0.70 | 1.10 | 8.51% | 5.51% | | | t0.7 | 0.70 | 1.00 | 47.69% | 43.40% | | | t0.5 | 0.50 | 1.00 | 60.12% | 58.68% | | | greedy | 0.00 | 1.00 | 60.99% | 57.02% | | #### 권장 추론 파라미터 (base 실험용) ```python # v2 그리드 서치 최적값 temp=0.7, repetition_penalty=1.3 # 또는 (더 다양한 생성) temp=0.9, repetition_penalty=1.2 ``` > 초기 v1 권장값(`temp=0.9, top_p=0.9, no_repeat_ngram=3, repetition_penalty=1.1`)에서 `repetition_penalty=1.3`으로 상향 조정. `no_repeat_ngram_size`는 그리드 서치에서 `repetition_penalty`만으로 충분히 반복 제거가 가능함을 확인하여 불필요. ### 10.9 평가 파이프라인 v2 재평가는 모듈화된 8-GPU 병렬 파이프라인(`eval/reeval_pipeline.py`)으로 수행되었다. #### 아키텍처 ``` reeval_pipeline.py ├── 모델 1회 로드 (GPU 0에 HF 모델) ├── Phase 1: PPL 평가 (19개 데이터셋, 순차) ├── Phase 2: Calibration + Token NLL ├── Phase 3: 생성 품질 + 파라미터 그리드 서치 (12조합) ├── Phase 4: lm-evaluation-harness (0-shot, 8-GPU 병렬) ├── Phase 5: lm-evaluation-harness (5-shot, 8-GPU 병렬) └── Phase 6: 리포트 자동 생성 (5개 개별 + 1개 종합) ``` #### Pipeline Mode 모델을 1회 로드하여 0-shot과 5-shot을 연속 실행한다. 기존 방식(별도 프로세스 2회)에 비해 모델 로딩 시간을 절반으로 줄인다. #### GPU별 태스크 분배 | GPU | 0-shot 태스크 | 5-shot 태스크 | |-----|--------------|--------------| | 0 | kobest_boolq, kobest_copa, kobest_hellaswag | 동일 | | 1 | kobest_sentineg, kobest_wic | 동일 | | 2 | haerae (전체 + 5개 서브) | 동일 | | 3 | global_mmlu_ko (6카테고리) | 동일 | | 4 | hellaswag, arc_easy | 동일 | | 5 | arc_challenge, winogrande | 동일 | | 6 | piqa, global_mmlu_en (61과목) | 동일 | | 7 | (예비 — PPL/calibration 전담) | — | NUMA affinity 적용: GPU 0-3은 NUMA node 0 (cores 0-35), GPU 4-7은 NUMA node 1 (cores 36-71). **총 소요 시간: 256.6초** (모델 로드 포함) ### SFT 진행 판단 **결론: SFT 진행** — loss 1.466 건강한 완료 시그널, 구조 문제 없음. → **Phase 2 SFT 시작 (2026-03-05)** 상세 보고서: - v2 종합: `eval/outputs/3b_reeval_20260305_1451/reports/` (5개 개별 리포트 + 종합) - v1 레거시: `reports/2026-03-05_3B_BASE_EVALUATION_REPORT.md` --- ## 11. 실험 결과 — 3B SFT 종합 평가 Phase 2 SFT가 early stopping으로 완료된 후 수행한 6차원 종합 평가. ### 11.1 SFT 학습 결과 | 항목 | 값 | |------|-----| | 최종 Step | 25,500 / 33,000 (77.3%, early stopping) | | Best val_loss | **1.8851** (step 23,000) | | 학습 시간 | ~15시간 41분 | | 데이터 | 24개 소스 → 2,439,397 samples (7.48 GB) | | 설정 | LR=1e-5, eff_batch=64, NEFTune alpha=5.0 | **Val Loss 추이**: ``` Step 500: 2.0732 (warmup 완료) Step 2,000: 1.9558 (급속 하강) Step 5,000: 1.9107 (안정 수렴) Step 10,000: 1.8917 (미세 감소) Step 15,000: 1.8864 (plateau 진입) Step 20,000: 1.8853 (변동 < 0.001) Step 23,000: 1.8851 ← BEST (early stopping 기준점) Step 25,500: Early Stop (patience 5/5 소진) ``` ### 11.2 6차원 평가 요약 | # | 차원 | 결과 | 핵심 수치 | |---|------|------|-----------| | 1 | Perplexity (지식 보존) | **PASS** | 최대 forgetting 0.9%, 19개 데이터셋 전체 PASS | | 2 | 생성 품질 | **FAIL** | Greedy 반복률 72.97% (목표 <5%), EOS 60% (목표 >90%) | | 3 | 한국어 벤치마크 | **FAIL** | KoBEST 평균 43.26% (목표 >55%) | | 4 | 영어 벤치마크 | **PASS** | hellaswag 26.1%, winogrande 50.8%, piqa 52.6% (전 항목 하한 초과) | | 5 | Calibration | **PASS** | Top-1 68.59%, Top-5 81.55%, Entropy 1.54 | | 6 | SFT Chat 능력 | **PASS** | EOS 종료율 0%→60%, Chat template 응답 | ### 11.3 Base vs SFT 비교 | 지표 | Base | SFT | 변화 | 판정 | |------|------|-----|------|------| | PPL (통합) | 5.2263 | 5.2529 | +0.5% forgetting | PASS | | Greedy 3-gram 반복률 | 60.99% | 72.97% | +12pp (악화) | FAIL | | EOS 종료율 | 0% | 60% | +60pp (대폭 개선) | 부분 PASS | | KoBEST 평균 | 43.69% | 43.26% | -0.4pp | FAIL | | MMLU-KO | 22.75% | 26.00% | +3.2pp | 부분 개선 | | 영어 벤치마크 | — | — | ±0.3pp 이내 | PASS (유지) | | Calibration Top-1 | 68.75% | 68.59% | -0.2pp | PASS (유지) | **Repetition 파라미터 검색** (희망적): | 설정 | 반복률 | EOS Rate | |------|--------|----------| | t0.7_rep1.2 | **0.00%** | **100%** | | t1.0_rep1.1 | **0.00%** | **100%** | | greedy (raw) | 72.97% | 60% | > rep_penalty 1.1~1.3 적용 시 반복률 0% 달성 → 모델이 반복하지 않는 능력 자체는 보유. ORPO로 내재화 가능. ### 11.4 코드 개선 사항 이번 Phase에서 수행한 주요 코드 변경: | 파일 | 변경 | 줄 수 | 목적 | |------|------|-------|------| | `train/sft.py` | MixingDataLoader, DDP rank 0 토크나이징 | +238 | SFT+pretrain 인터리빙, 메모리 8배 절감 | | `train/trainer.py` | DDP early stop broadcast | +17 | DDP hang 방지, patience 5→10 | | `train/orpo.py` | YAML config, 3B 기본값 | +30 | ORPO 실행 준비 | | `eval/report_generator.py` | SFT 비교 보고서 자동 생성 | +831 | 평가 자동화 | | `eval/sft_eval_pipeline.py` | 6차원 평가 파이프라인 | 신규 | SFT 종합 평가 | | `eval/tasks/generation_task.py` | Chat template, diversity metrics | +75 | SFT 평가 지원 | ### 11.5 ORPO 진행 판정 **판정: Phase 3 ORPO 진행** | 근거 | 상세 | |------|------| | 지식 보존 양호 | forgetting 0.9% — SFT가 base 지식을 파괴하지 않음 | | 반복 미해결 | greedy 72.97% — 선호도 정렬이 직접적 해결 경로 | | 희망적 신호 | rep_penalty 적용 시 0% → ORPO가 내재화 가능 | | 데이터 준비 완료 | 795,468 preference pairs (7.9 GB) | | 코드/설정 완비 | `train/orpo.py` + `configs/korean_3b_orpo.yaml` | **ORPO 후 판정 기준**: - 반복률 < 5% AND KoBEST > 50% → GGUF + Ollama 배포 - 반복률 5~15% → 하이퍼파라미터 조정 후 재시도 - 반복률 > 15% → SFT v2 (lr=5e-5, data mixing) 후 재도전 상세: `reports/2026-03-06_3B_SFT_COMPLETION_AND_EVAL_SUMMARY.md` --- ## 12. Phase 3 — ORPO (선호도 정렬) ### 12.1 ORPO 선택 배경 SFT 6차원 평가에서 greedy 반복률 72.97%, EOS 종료율 0%라는 치명적 문제가 발견됐다. SFT는 "좋은 응답만 모방"하는 학습이므로, "나쁜 응답을 억제"하는 신호가 없다. 반복 문제 해결에는 preference optimization이 필수적이다. **ORPO vs DPO**: | 항목 | ORPO | DPO | |------|------|-----| | Reference model | 불필요 | 필요 (VRAM 2배) | | 구현 복잡도 | 낮음 | 중간 | | 메모리 효율 | 높음 (3B 1개만 로드) | 낮음 (3B 2개 로드) | | 학습 안정성 | 중간 | 높음 | ORPO를 1차 선택, DPO를 Plan B로 설정했다. ### 12.2 데이터 - **원본**: 683,181 preference pairs (7개 소스 통합) - **필터 후**: ~630,000 pairs (NaN 방지 필터 적용) - **Eval split**: 5% (~31,500 pairs, seed=42) - **Effective batch**: 4 × 8 GPU × 4 accum = 128 ### 12.3 HP Sweep 설계 (6-Config) 3개 축(beta, LR, max_length)을 중심축 고정 방식으로 6개 조합 선정: | Run | Name | Beta | LR | Max Length | 목적 | |-----|------|------|----|-----------|------| | 1 | baseline_b015 | 0.15 | 8e-6 | 1536 | 약한 beta 베이스라인 | | 2 | baseline_b025 | 0.25 | 8e-6 | 1536 | 중간 beta 베이스라인 | | 3 | strong_b035 | 0.35 | 8e-6 | 1536 | 강한 beta — 적극적 반복 억제 | | 4 | fast_lr12e6 | 0.25 | 1.2e-5 | 1536 | 높은 LR — 빠른 수렴 | | 5 | conserv_lr5e6 | 0.25 | 5e-6 | 1536 | 보수적 LR — 안정성 | | 6 | short_1024 | 0.25 | 8e-6 | 1024 | 짧은 max_length — VRAM 절약 | 각 200 steps, eval_steps=100, 8×B200 DDP. ### 12.4 시도 이력 — 5번의 실패 | # | 문제 | 원인 | 수정 | |---|------|------|------| | 1 | NCCL Timeout | 토크나이징 30분 > timeout 1800s | ddp_timeout=7200, num_proc=64 | | 2 | Config 충돌 | save_steps ≠ eval_steps 배수 | --no_load_best --save_steps 200 | | 3 | 포트 충돌 + QKV 누락 | 좀비 프로세스 + fused QKV 미분리 | pkill + QKV split 로직 | | 4 | TRL NaN 버그 | tokenize_row 양쪽 response 동시 잘림 | 3중 패치 (clamp, truncation) | | 5 | Tokenizer 호환 | zip(strict=True) + 한국어 merge ops | TRL 소스 8건 패치 | 가장 심각했던 것은 TRL NaN 버그로, 0 response tokens → log(0) = -inf → NaN 전파 체인을 일으켰다. 상세: `reports/2026-03-08_ORPO_TRAINING_JOURNEY.md` ### 12.5 스윕 최종 결과 | Run | Name | Beta | LR | MaxLen | Train Loss | Eval Loss | Margin | Status | |-----|------|------|----|--------|-----------|-----------|--------|--------| | 1 | baseline_b015 | 0.15 | 8e-6 | 1536 | 1.811 | 1.827 | 0.004 | ✅ | | 2 | baseline_b025 | 0.25 | 8e-6 | 1536 | 1.890 | 1.906 | 0.009 | ✅ | | 3 | strong_b035 | 0.35 | 8e-6 | 1536 | 2.055 | 1.985 | 0.007 | ✅ | | **4** | **fast_lr12e6** | **0.25** | **1.2e-5** | **1536** | **1.917** | **1.862** | **0.009** | **🏆 Best** | | 5 | conserv_lr5e6 | 0.25 | 5e-6 | 1536 | 1.833 | 1.910 | 0.004 | ✅ | | 6 | short_1024 | 0.25 | 8e-6 | 1024 | 1.664 | 1.695 | 0.007 | ✅ | **Best config: Run 4** (eval_loss 1.862 최저, margin 0.009 최고, 빠른 수렴). ### 12.6 Throughput 벤치마크 → 본 학습 설정 본 학습 전 batch/grad_accum 조합의 throughput을 측정하여 최적 설정을 결정: | batch_size | grad_accum | eff_batch | Throughput | 비고 | |-----------|-----------|----------|-----------|------| | **4** | **4** | **128** | **80.63 samples/s** | **선정** | | 2 | 8 | 128 | 73.14 samples/s | 기존 설정 | | 8 | 2 | 128 | OOM | | ### 12.7 ORPO 본 학습 (진행 중, 2026-03-09) | 파라미터 | 값 | |---------|-----| | Beta / LR | 0.25 / 1.2e-5 (Sweep Run 4) | | Batch / Accum / Eff | 4 / 4 / 128 (벤치마크 최적) | | Max length | 1536 | | Epochs | 2 (~9,840 steps) | | GPU VRAM | ~52GB / 183GB (28%) | | 속도 | ~1.75 s/step | | 예상 시간 | ~4.8시간 | **학습 지표 추이 (step ~1,660 기준)**: | Step | Eval Loss | Pref Accuracy | Reward Margin | NLL Loss | |-----:|----------:|--------------:|--------------:|---------:| | ~1,000 | 1.791 | 66.8% | 0.107 | 1.647 | | ~2,000 | 1.713 | 70.1% | 0.293 | 1.591 | | ~3,000 | 1.681 | 71.9% | 0.372 | 1.567 | - Train loss: 2.34 → **1.68** (-0.66) - rewards/accuracies: 0.43 → **0.74** (chosen/rejected 구분 능력 급상승) - rewards/margins: -0.005 → **0.387** (preference signal 학습 확인) - 속도 ~1.76 s/step, GPU 92~100% utilization, 안정적 진행 중 **학습 완료 후 자동 평가**: `scripts/orpo_eval_watchdog.sh` 가 학습 프로세스를 감시하며, 완료 시 자동으로 10차원 종합 평가 파이프라인 실행 ### 12.8 ORPO 종합 평가 파이프라인 SFT v2 평가의 6차원에 ORPO 고유 4차원을 추가한 **10차원 종합 평가**. 학습 완료 시 `eval/orpo_eval_pipeline.py`가 자동 실행되어 Base vs SFT vs ORPO 3-way 비교 보고서를 생성한다. **평가 구조**: | Phase | 내용 | GPU | 예상 시간 | |-------|------|-----|----------| | Pre-phase | train.log에서 학습 곡선 추출 | - | ~1초 | | Phase 1 | 내부 평가 (PPL 19셋, Calibration, Generation, Repetition Grid) | 8 GPU 병렬 | ~30분 | | Phase 2 | 벤치마크 (KoBEST, HAE-RAE, MMLU-KO/EN, hellaswag, arc, piqa) | 8 GPU 병렬 | ~1시간 | | Phase 3 | 3-way 비교 보고서 자동 생성 | - | ~10초 | **10차원 평가 항목**: | # | 차원 | 기준 | SFT v2 결과 | ORPO 목표 | |---|------|------|------------|----------| | 1 | 지식 보존 (PPL) | forgetting < 15% | 0.9% | < 5% | | 2 | 생성 품질 | greedy 반복률 < 5%, EOS > 90% | **72.97% / 60%** | **< 5% / > 90%** | | 3 | 한국어 벤치마크 | KoBEST 평균 > 55% | 43.26% | ≥ 43% | | 4 | 영어 벤치마크 | 하한 초과 | PASS | 유지 | | 5 | Calibration | Top-1 ≥ 65% | 68.59% | ≥ 65% | | 6 | Chat 능력 | EOS 종료율 | 60% | > 90% | | 7 | Preference Accuracy | > 65% | — | > 65% | | 8 | Reward Margins | > 0.1 | — | > 0.1 | | 9 | 반복 파라미터 민감도 | rep_penalty=1.0에서도 < 5% | — | PASS | | 10 | SFT→ORPO 개선 | 반복률↓ + EOS↑ | — | PASS | **핵심 파일**: - `eval/orpo_eval_pipeline.py` — ORPO 평가 오케스트레이터 - `eval/report_generator.py` — 3-way 비교 보고서 생성기 (`generate_three_way_report()`) - `scripts/orpo_eval_watchdog.sh` — 학습 완료 감지 + 자동 평가 실행 **배포 기준**: greedy 반복률 < 5% AND EOS > 90% AND forgetting < 5% AND KoBEST ≥ 43% → **DEPLOY** --- ## 13. 실행 방법 ### 사전 요구사항 ```bash # PyTorch는 재설치 금지 (NVIDIA 커스텀 빌드) # 아래 패키지만 추가 설치 pip install transformers accelerate peft trl deepspeed \ bitsandbytes sentencepiece wandb ``` ### 3B 프리트레인 ```bash # NCCL 환경변수와 함께 8-GPU 학습 실행 bash scripts/launch_3b_pretrain.sh # 수동 실행 (직접 제어) torchrun --nproc_per_node=8 \ --master_port=29500 \ train/pretrain.py \ --config configs/korean_3b_fp8.yaml ``` ### SFT ```bash bash scripts/launch_3b_sft.sh # 또는 직접 실행 torchrun --nproc_per_node=8 \ train/sft.py \ --config configs/korean_3b_sft.yaml \ --pretrain_ckpt checkpoints/3b_pretrain_best.pt ``` ### ORPO (선호도 정렬) ```bash # ORPO 학습 bash scripts/launch_3b_orpo.sh # 학습 완료 후 자동 평가 (watchdog) nohup bash scripts/orpo_eval_watchdog.sh \ > checkpoints/korean_3b_orpo_v1/watchdog.log 2>&1 & ``` ### 평가 ```bash # Base 모델 전체 평가 (8 GPU 병렬) python eval/full_eval_pipeline.py # SFT 모델 평가 (Base vs SFT 2-way 비교) python eval/sft_eval_pipeline.py --skip-phase0 \ --hf-model-path eval/outputs/hf_3b_sft_best # ORPO 모델 평가 (Base vs SFT vs ORPO 3-way 비교) python eval/orpo_eval_pipeline.py # 자동으로 최신 checkpoint 감지 python eval/orpo_eval_pipeline.py --dry-run # 실행 계획만 확인 # 빠른 평가 (kobest_copa + PPL) bash scripts/run_eval_quick.sh # 생성 파라미터 탐색 python eval/test_generation_params.py \ --checkpoint checkpoints/3b_best.pt ``` ### 배포 ```bash # Step 1: GGUF 변환 (llama.cpp 포맷) bash scripts/convert_3b_gguf.sh # Step 2: Ollama 모델 등록 및 서빙 bash scripts/deploy_3b_ollama.sh # Ollama로 테스트 ollama run frankenstallm-3b "한국의 철강 산업에 대해 설명해줘." ``` ### 학습 모니터링 ```bash # 실시간 모니터 (tail -f 방식) bash scripts/monitor_3b.sh # 프로세스 상태 확인 ps aux | grep pretrain # GPU 상태 nvidia-smi --query-gpu=index,name,memory.used,memory.total,utilization.gpu \ --format=csv -l 5 ``` ### 단일 GPU 테스트 (개발/디버그) ```bash python train/pretrain.py \ --config configs/korean_3b_fp8.yaml \ --device cuda:0 \ --max_steps 100 \ --debug ``` --- ## 14. 로드맵 ### 단기 (2026년 3월) | 항목 | 상태 | 비고 | |------|------|------| | Phase 1 (3B Pretrain) 완료 | ✅ 완료 | 57K steps, loss 1.466, 2026-03-05 | | Phase 2 (SFT) 완료 | ✅ 완료 | 25.5K steps, val_loss 1.8851, 2026-03-06 | | SFT 6차원 평가 | ✅ 완료 | 4/6 PASS, ORPO 판정 | | Phase 3 (ORPO Sweep) | ✅ 완료 | 6-config sweep 완료, best config 선정 | | **Phase 3 (ORPO 본 학습)** | **🔄 진행 중** | **lr=1.2e-5, beta=0.25, 2 epochs, ~9,840 steps** | | Phase 3.5 (ORPO 종합 평가) | 📋 대기 | 10차원 평가 (6 기본 + 4 ORPO 고유), 3-way 비교 보고서 | | GGUF 변환 + Ollama 배포 | 📋 대기 | Phase 4 (ORPO 평가 PASS 시) | ### 중기 (2026년 2분기) | 항목 | 비고 | |------|------| | 확장 프리트레인 (80~100B 토큰) | Chinchilla 최적점 달성 | | QKV Fusion | +8~12% MFU 기대 | | NUMA Affinity 설정 | +4~9% 예상 | | FA2 native RoPE | +3~5% 예상 | | Context length 확장 (4096) | RoPE θ=500K 기반 | ### 장기 (2026년 하반기) | 항목 | 비고 | |------|------| | 7B 실험 | FSDP 전략 필요 | | vLLM serving | PagedAttention 기반 추론 서버 | | 도메인 특화 파인튜닝 | 철강/제조업 도메인 | | 공개 배포 | HuggingFace Hub 업로드 | ### 알려진 미적용 최적화 Phase 0 분석에서 발견했지만 아직 적용하지 않은 최적화들: | 최적화 | 예상 효과 | 구현 복잡도 | |--------|-----------|-------------| | QKV Fusion | +8~12% MFU | 중간 | | NUMA Affinity | +4~9% | 낮음 | | FA2 Native RoPE | +3~5% | 낮음 | | HugePages | +1~3% (TLB 최적화) | 낮음 (sysctl) | 이 최적화들을 모두 적용하면 현재 33.5% MFU에서 45~50%까지 도달할 가능성이 있다. --- ## 15. 참고 문서 | 문서 | 위치 | 내용 | |------|------|------| | 프로젝트 전체 여정 | `docs/PROJECT_HISTORY.md` | 일별 상세 진행 기록 | | 3B 작업 계획 | `docs/3B_WORKPLAN.md` | 3B 단계별 작업 계획 상세 | | 저스티스리그 논증 | `eval/debate/justice_league_3b_case.md` | 1B→3B 전환 멀티에이전트 토론 전문 | | SFT 재시작 판결 | `eval/decision/FINAL_DECISION_REPORT.md` | SFT v1 실패 → v2 설계 판결문 | | 3B 마스터 플랜 | `eval/plan/3B_MASTER_PLAN.md` | 전체 학습 파이프라인 마스터 플랜 | | Phase 0 최적화 보고서 | `reports/2026-03-02_0200_FRANKENSTALLM_phase0_optimization_report.md` | VRAM/MFU 최적화 전체 보고 | | 3B Base 평가 보고서 (v1) | `reports/2026-03-05_3B_BASE_EVALUATION_REPORT.md` | 초기 PPL/벤치마크/반복률 평가 | | PPL 평가 보고서 (v1) | `reports/2026-03-05_PPL_EVALUATION.md` | 4개 검증셋 PPL 상세 | | 벤치마크 결과 (v1) | `reports/2026-03-05_BENCHMARK_RESULTS.md` | belebele, MMLU 상세 | | 생성 품질 분석 (v1) | `reports/2026-03-05_GENERATION_QUALITY.md` | 반복률, 디코딩 파라미터 | | SFT 학습 보고서 | `reports/2026-03-05_3B_SFT_PROGRESS_REPORT.md` | Phase 2 SFT 학습 과정 기록 | | **SFT 완료 종합 보고서** | `reports/2026-03-06_3B_SFT_COMPLETION_AND_EVAL_SUMMARY.md` | **SFT 완료 + 평가 + 코드 개선 + ORPO 결정 (최신)** | | SFT 평가 계획서 | `reports/2026-03-06_3B_SFT_EVAL_PLAN.md` | 6차원 평가 설계 | | SFT 평가 결과 | `reports/2026-03-06_3B_SFT_EVALUATION_REPORT.md` | 6차원 평가 상세 결과 | | 3B 후속 단계 참조 | `reports/2026-03-05_3B_NEXT_STEPS_REFERENCE.md` | SFT 후 방향성 | | Nemotron Nano 타당성 | `reports/2026-03-05_NEMOTRON_NANO_FEASIBILITY_STUDY.md` | Hybrid 아키텍처 검토 | | **v2 종합 평가 리포트** | `eval/outputs/3b_reeval_20260305_1451/full_eval_report.md` | **13+ 벤치마크 종합** | | v2 PPL 리포트 | `eval/outputs/3b_reeval_20260305_1451/reports/01_perplexity_report.md` | 19개 데이터셋 PPL 상세 | | v2 Calibration 리포트 | `eval/outputs/3b_reeval_20260305_1451/reports/02_calibration_report.md` | Top-K 정확도, NLL 분포 | | v2 생성 품질 리포트 | `eval/outputs/3b_reeval_20260305_1451/reports/03_generation_quality.md` | 12조합 파라미터 그리드 서치 | | v2 벤치마크 리포트 | `eval/outputs/3b_reeval_20260305_1451/reports/04_benchmark_report.md` | KoBEST, HAE-RAE, MMLU, 0/5-shot | | 진행 기록 | `PROGRESS.md` | 날짜별 체크포인트, 지표, 결정 로그 | | **ORPO 분석 및 계획** | `reports/2026-03-07_ORPO_ANALYSIS_AND_PLAN.md` | **ORPO 진행 근거, HP 설계, 실행 절차** | | **ORPO Sweep 디버그** | `reports/2026-03-08_ORPO_SWEEP_DEBUG_REPORT.md` | **QKV 버그, NCCL timeout, TRL 패치 상세** | | **ORPO 학습 여정** | `reports/2026-03-08_ORPO_TRAINING_JOURNEY.md` | **ORPO 전체 과정: 5번의 실패와 HP sweep (최신)** | --- ## 16. 기술 스택 요약 | 영역 | 기술 | 버전 | |------|------|------| | 딥러닝 프레임워크 | PyTorch (NVIDIA 커스텀 빌드) | nv25.12 | | 어텐션 | FlashAttention-2 | 2.7.4.post1+25.12 | | FP8 / 혼합 정밀도 | TransformerEngine (MXFP8) | 2.10.0 | | 분산 학습 | DDP + NCCL (NVLS) | NCCL 2.28.9 | | 커널 컴파일 | Triton | 3.5.1 | | 토크나이저 | SentencePiece Unigram 64K | - | | 모니터링 | Telegram Bot (B200Bot) + cron watchdog | - | | 추론 서빙 | GGUF + Ollama | - | | GPU | 8× NVIDIA B200 (NVLink 5.0, NVSwitch) | CUDA 13.1 | | CPU | 2× AMD EPYC 9365 (Zen 5) | - | --- ## 관련 프로젝트 ### [EVAFRILL-Mo](https://github.com/pathcosmos/EVAFRILL-Mo) **하이브리드 Mamba-2 + Transformer 언어 모델** — FRANKENSTALLM의 자매 프로젝트. NVIDIA [Nemotron-H](https://arxiv.org/abs/2504.03624) 아키텍처에서 영감을 받아 밑바닥부터 직접 구현한 3B 하이브리드 모델이다. FRANKENSTALLM이 순수 Transformer 기반이라면, EVAFRILL-Mo는 **Mamba-2 SSM + 희소 Transformer 어텐션** 하이브리드 구조를 채택했다. | 항목 | FRANKENSTALLM | EVAFRILL-Mo | |------|:---:|:---:| | 아키텍처 | 순수 Transformer (28L) | Mamba-2 24L + Attention 2L | | 파라미터 | 3.17B | 2.94B | | 핵심 기술 | GQA, FP8, FlashAttention-2 | Selective Scan, SwiGLU FFN in Mamba, GQA | | 설계 원칙 | 검증된 Transformer 아키텍처 | Nemotron-H 단편화 도입 | | GPU | 8× B200 | 7× B200 | | 학습 전략 | Chinchilla-optimal | Chinchilla 93% 달성 목표 | 두 프로젝트는 동일한 토크나이저(64K SentencePiece), 학습 데이터 파이프라인, DDP/FP8 인프라를 공유한다. "같은 재료, 다른 레시피"로 아키텍처 차이가 성능에 미치는 영향을 비교 실험할 수 있다. > *이름의 유래: Bride **Eva** (프랑켄슈타인의 신부) + **FRI**DAY (아이언맨 AI 비서) + **LL**M + Nemotron의 **Mo*** --- ## 18. 다음 최적화 계획 — MFU 33.5% → 47% 목표 > 상세 문서: [`docs/NEXT_OPTIMIZATION_PLAN.md`](docs/NEXT_OPTIMIZATION_PLAN.md) ### 현재 성능 진단 Phase 1 프리트레인 실측: - **57,000 steps**, ~38.5B tokens, **약 63시간** - 처리 속도: 36~38K tok/s per rank → 전체 **~292K tok/s** (8GPU) - **MFU: ~33.5%** ### 핵심 병목: NUMA Misalignment ``` AMD EPYC 9365 × 2소켓: GPU 0~3 → NUMA node 0 (core 0-35) GPU 4~7 → NUMA node 1 (core 36-71) 초기 DDP 런칭 시 5/8 rank가 잘못된 NUMA 노드에서 실행. 69%의 DataLoader worker가 크로스-NUMA — ~2배 지연 발생. ``` ### 최적화 항목별 예상 효과 | 최적화 | 예상 MFU 개선 | 난이도 | |--------|-------------|--------| | NUMA affinity 고정 | +4~9% | 낮음 (launch script 수정) | | QKV fusion (TransformerEngine) | +8~12% | 중간 (모델 코드 수정) | | FA2 native RoPE | +3~5% | 중간 (FA2 버전 의존) | | NCCL 환경변수 튜닝 | +1~2% | 낮음 (한 줄 추가) | ### 최적화 전후 예상 비교 | 항목 | 현재 | 최적화 후 | |------|------|----------| | MFU | 33.5% | ~45~47% | | 처리속도 | 292K tok/s | ~390~410K tok/s | | 50B 토큰 학습 | ~47시간 | ~34~36시간 | ### 즉시 적용 가능한 코드 **NUMA affinity (launch script):** ```bash numactl --cpunodebind=0 --membind=0 torchrun \ --nproc_per_node=4 --node_rank=0 train/pretrain.py ... & numactl --cpunodebind=1 --membind=1 torchrun \ --nproc_per_node=4 --node_rank=1 train/pretrain.py ... & ``` **NCCL 환경변수:** ```bash export NCCL_MIN_NCHANNELS=4 export NCCL_SOCKET_NTHREADS=4 export CUDA_DEVICE_MAX_CONNECTIONS=1 ``` > Phase 3 ORPO 완료 후, 다음 프리트레인 런 전에 NUMA affinity를 먼저 적용하면 학습 시간을 ~30% 단축할 수 있다. --- ## 19. GPU 하드웨어 & 비용 분석 — 3B × 60B 프리트레인 > 상세 문서: [`docs/GPU_COST_ANALYSIS.md`](docs/GPU_COST_ANALYSIS.md) ### 실측 기준 베이스라인 ``` FRANKENSTALLM Phase 1 실측: B200 × 8, MFU 33.5%, 292K tok/s 38.5B 토큰 → 63시간 60B 토큰 환산 → 약 98시간 ``` ### 클라우드 가성비 Top 3 (60B 토큰, 최적화 후) | 순위 | 구성 | 소요시간 | 총 비용 | |------|------|---------|--------| | 1 | H100×8 Cudo | 44.8hr | **$645** (~93만원) | | 2 | H100×8 Vast.ai | 44.8hr | $670 (~97만원) | | 3 | H100×8 RunPod | 44.8hr | $713 (~103만원) | > B200 Blackwell이 빠르지만, 클라우드 단가가 H100의 3배 → **H100이 총비용 4.3배 저렴** ### 개인 GPU 구성 추천 | 구성 | VRAM | NVLink | 가격 | 추천도 | |------|------|--------|------|--------| | A6000 Ada × 2 중고 | 96GB (통합) | ✅ | ~1,000만원 | ⭐⭐⭐⭐⭐ | | L40S × 2 | 96GB (통합) | ✅ | ~1,400만원 | ⭐⭐⭐⭐ | | RTX Pro 6000 Blackwell | 96GB (단일) | ❌ | ~1,200만원 | ⭐⭐⭐ | > 소비자용 GPU(RTX 5090/4090)는 NVLink 미지원. 80GB+ 통합 메모리 필요 시 전문가용 필수. ### 추천 전략: 로컬 + 클라우드 하이브리드 ``` [로컬] RTX 4090 × 4 (880만원) — 데이터 전처리, 실험, SFT/ORPO [클라우드] H100×8 (런당 ~103만원) — 본 프리트레인만 ``` --- ## 마치며 이 프로젝트의 모토는 하나다: > **"망하는 것도 기록한다."** SFT v1의 loss=0.0 실패, torch.compile이 효과 없었던 것, 18% 반복률의 좌절 — 이 모든 것이 기록에 남아 있다. 그리고 이제 Phase 3 ORPO에서도 그 전통은 이어진다. **5번의 실패** — NCCL timeout, config 충돌, QKV 변환 버그, 포트 충돌, TRL NaN 버그 — 를 거쳐 마침내 6-config HP sweep이 돌아가고 있다. Frankenstein이 조각들을 이어 붙여 생명을 만들었듯, 우리도 다양한 소스의 데이터와 기술을 이어 붙여 한국어를 이해하고 말하는 모델을 만들어가고 있다. 아직 완성되지 않았지만, 그 과정 자체가 이 프로젝트의 가치다. Phase 1 프리트레인은 57,000 steps, loss 1.466으로 완료됐다. Phase 2 SFT는 25,500 steps에서 early stopping (val_loss 1.8851). 6차원 종합 평가에서 4/6을 통과했다. **좋은 소식**: 지식 보존이 거의 완벽하다 (forgetting 0.9%). SFT가 base 모델의 지식을 파괴하지 않았다. EOS 종료율은 0%에서 60%로 올라갔다. MMLU-KO도 +3.2pp 개선되었다. **아쉬운 소식**: greedy 반복률 72.97%. SFT만으로는 반복 문제가 해결되지 않았다. 오히려 악화되었다 (Base 60.99% → SFT 72.97%). 하지만 `rep_penalty=1.2`만 적용하면 반복률 0%가 달성된다. 모델은 반복하지 않는 능력을 가지고 있다. 다만 그것을 "기본 행동"으로 학습하지 못했을 뿐이다. **현재**: Phase 3 ORPO 본 학습이 진행 중이다. 6-config HP sweep을 모두 완료하고, eval_loss 기준 최적 config (lr=1.2e-5, beta=0.25)를 선정했다. Throughput 벤치마크로 batch_size=4, grad_accum=4 조합이 80.63 samples/s로 최적임을 확인하고, 8×B200 전체 GPU로 본 학습을 시작했다. ~9,840 steps, 예상 ~4.8시간. 학습 완료 시 watchdog이 자동으로 10차원 종합 평가(Base vs SFT vs ORPO 3-way 비교)를 실행한다. > **ORPO가 greedy 반복률을 5% 미만으로 끌어내릴 수 있는가?** 그 답이 곧 나온다. 학습이 끝나면 6차원 재평가를 수행하고, 통과하면 GGUF로 변환되어 Ollama 위에서 돌아가게 된다. 한국어를 이해하고 말하는 3B 모델, 처음부터 만든 것. --- *최종 업데이트: 2026-03-09* *현재 상태: Phase 3 ORPO 본 학습 진행 중 (lr=1.2e-5, beta=0.25, step ~1,660/9,840, 17%) — 학습 완료 시 10차원 종합 평가 자동 실행 대기*