{"id":50325003,"url":"https://github.com/pathcosmos/frankenstallm","last_synced_at":"2026-05-29T05:04:28.644Z","repository":{"id":342106681,"uuid":"1172700674","full_name":"pathcosmos/FRANKENSTALLM","owner":"pathcosmos","description":"Korean 3B LLM (pure Transformer) pretrained from scratch on 8× NVIDIA B200 GPUs with SFT + ORPO alignment","archived":false,"fork":false,"pushed_at":"2026-03-26T06:54:55.000Z","size":5346,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-26T23:35:05.012Z","etag":null,"topics":["flash-attention","fp8","gguf","gqa","korean-llm","nvidia-b200","orpo","pretraining","sft","transformer"],"latest_commit_sha":null,"homepage":"https://huggingface.co/pathcosmos/frankenstallm","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pathcosmos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-04T15:50:06.000Z","updated_at":"2026-03-26T06:54:58.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/pathcosmos/FRANKENSTALLM","commit_stats":null,"previous_names":["pathcosmos/frankenstallm"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/pathcosmos/FRANKENSTALLM","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pathcosmos%2FFRANKENSTALLM","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pathcosmos%2FFRANKENSTALLM/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pathcosmos%2FFRANKENSTALLM/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pathcosmos%2FFRANKENSTALLM/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pathcosmos","download_url":"https://codeload.github.com/pathcosmos/FRANKENSTALLM/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pathcosmos%2FFRANKENSTALLM/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33637491,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-29T02:00:06.066Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["flash-attention","fp8","gguf","gqa","korean-llm","nvidia-b200","orpo","pretraining","sft","transformer"],"created_at":"2026-05-29T05:04:16.012Z","updated_at":"2026-05-29T05:04:28.625Z","avatar_url":"https://github.com/pathcosmos.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FRANKENSTALLM\n\n\u003e 🌍 [English Version](./README_en.md)\n\n![Phase 4](https://img.shields.io/badge/Phase_4-배포_완료-brightgreen)\n[![Model](https://img.shields.io/badge/Model-3B_Korean_LLM-green)](https://huggingface.co/pathcosmos/frankenstallm)\n![GPU](https://img.shields.io/badge/GPU-8×_NVIDIA_B200-76b900)\n![FP8](https://img.shields.io/badge/Precision-MXFP8-orange)\n![ORPO](https://img.shields.io/badge/ORPO-완료_eval__loss_1.625-success)\n[![HuggingFace](https://img.shields.io/badge/🤗_HuggingFace-배포_완료-ff9900)](https://huggingface.co/pathcosmos/frankenstallm)\n\n\u003e **한국어 3B LLM을 8× NVIDIA B200 위에서 처음부터 직접 만든다.**\n\u003e Frankenstein처럼 조각을 이어 붙이고, 철강처럼 단단하게 단련한다.\n\nGitHub: [`pathcosmos/FRANKENSTALLM`](https://github.com/pathcosmos/FRANKENSTALLM)  \n🤗 HuggingFace: [`pathcosmos/frankenstallm`](https://huggingface.co/pathcosmos/frankenstallm) — **모델 배포 완료 (GGUF + safetensors)**\n\n---\n\n## 목차\n\n1. [왜 이 프로젝트인가](#1-왜-이-프로젝트인가)\n2. [현재 상태 — 한눈에 보기](#2-현재-상태--한눈에-보기)\n3. [하드웨어 환경](#3-하드웨어-환경)\n4. [프로젝트 구조](#4-프로젝트-구조)\n5. [프로젝트 여정 타임라인](#5-프로젝트-여정-타임라인)\n6. [모델 아키텍처](#6-모델-아키텍처)\n7. [학습 데이터](#7-학습-데이터)\n8. [학습 설정 및 최적화](#8-학습-설정-및-최적화)\n9. [실험 결과 — 1B 베이스라인](#9-실험-결과--1b-베이스라인)\n10. [실험 결과 — 3B Base 종합 평가 (v2)](#10-실험-결과--3b-base-종합-평가-v2)\n    - [10.1 학습 커브](#101-학습-커브)\n    - [10.2 PPL (Perplexity) — 19개 데이터셋](#102-ppl-perplexity--19개-데이터셋)\n    - [10.3 한국어 벤치마크](#103-한국어-벤치마크)\n    - [10.4 영어 벤치마크](#104-영어-벤치마크)\n    - [10.5 Calibration](#105-calibration)\n    - [10.6 0-shot vs 5-shot 비교](#106-0-shot-vs-5-shot-비교)\n    - [10.7 참고 모델 비교](#107-참고-모델-비교)\n    - [10.8 생성 품질 및 파라미터 그리드 서치](#108-생성-품질-및-파라미터-그리드-서치)\n    - [10.9 평가 파이프라인](#109-평가-파이프라인)\n11. [실험 결과 — 3B SFT 종합 평가](#11-실험-결과--3b-sft-종합-평가)\n    - [11.1 SFT 학습 결과](#111-sft-학습-결과)\n    - [11.2 6차원 평가 요약](#112-6차원-평가-요약)\n    - [11.3 Base vs SFT 비교](#113-base-vs-sft-비교)\n    - [11.4 코드 개선 사항](#114-코드-개선-사항)\n    - [11.5 ORPO 진행 판정](#115-orpo-진행-판정)\n12. [Phase 3 — ORPO (선호도 정렬)](#12-phase-3--orpo-선호도-정렬)\n20. [HuggingFace 배포 현황](#20-huggingface-배포-현황)\n21. [Ollama 사용법 — 상세 설명 및 주의사항](#21-ollama-사용법--상세-설명-및-주의사항)\n22. [모델 성능 비교](#22-모델-성능-비교--base--sft--orpo--ollama)\n23. [재현 가이드 — 전 단계 설정 상세](#23-재현-가이드--전-단계-설정-상세)\n    - [12.1 ORPO 선택 배경](#121-orpo-선택-배경)\n    - [12.2 데이터](#122-데이터)\n    - [12.3 HP Sweep 설계](#123-hp-sweep-설계-6-config)\n    - [12.4 시도 이력](#124-시도-이력--5번의-실패)\n    - [12.5 스윕 결과 (완료)](#125-스윕-결과-진행-중)\n    - [12.7 ORPO 본 학습 (완료)](#127-orpo-본-학습-진행-중-2026-03-09)\n    - [12.8 ORPO 종합 평가 파이프라인](#128-orpo-종합-평가-파이프라인)\n13. [실행 방법](#13-실행-방법)\n14. [로드맵](#14-로드맵)\n15. [참고 문서](#15-참고-문서)\n16. [기술 스택 요약](#16-기술-스택-요약)\n17. [관련 프로젝트](#관련-프로젝트)\n18. [다음 최적화 계획](#18-다음-최적화-계획--mfu-335--47-목표)\n19. [GPU 하드웨어 \u0026 비용 분석](#19-gpu-하드웨어--비용-분석--3b--60b-프리트레인)\n\n---\n\n## 1. 왜 이 프로젝트인가\n\n한국어 LLM 생태계는 빠르게 성장하고 있다. 그러나 대부분의 공개 모델은 영어 기반 사전학습 위에 한국어 파인튜닝을 얹은 형태거나, 학습 과정이 공개되지 않아 재현이 불가능하다.\n\n이 프로젝트는 다르다.\n\n- **처음부터(from scratch)**: 토크나이저 학습부터 프리트레인, SFT, 선호도 정렬까지 모든 단계를 직접 구현한다.\n- **완전 공개 빌더 로그**: 성공만 기록하지 않는다. 버그, 실패, 판단 착오, 그리고 그 원인 분석까지 모두 기록한다.\n- **실용적인 규모**: 학술 논문용 장난감 모델(125M)도 아니고, 연구소가 아니면 재현 불가능한 70B도 아닌, **3B 규모**의 실용적 한국어 모델이 목표다.\n- **B200 최적화**: NVIDIA B200의 FP8 Tensor Core, NVLink 5.0, FlashAttention-2를 최대한 활용한다. 최신 하드웨어를 최대로 쥐어짜는 과정 자체가 학습이다.\n\n\n이 README는 **처음부터 끝까지의 빌더 로그**다. 실패와 성공을 모두 기록했다.\n\n---\n\n## 2. 현재 상태 — 한눈에 보기\n\n```\n2026-03-26 기준 (전 단계 완료)\n```\n\n| 단계 | 상태 | 세부 내용 |\n|------|------|-----------|\n| Phase 0: 기반 구축 | ✅ 완료 | OOM 수정, GQA FA 최적화, NCCL NVLS, 파이프라인 준비 |\n| Phase 1: 3B Pretrain | ✅ 완료 | 57,000 steps, loss 1.466, ~63시간 |\n| Phase 2: SFT | ✅ 완료 | 25,500 steps (early stop), val_loss 1.8851, ~15.5시간 |\n| Phase 2.5: SFT 평가 | ✅ 완료 | 6차원 평가 4/6 PASS, ORPO 진행 결정 |\n| Phase 3: ORPO Sweep | ✅ 완료 | 6-config sweep 완료, best: lr=1.2e-5, beta=0.25 |\n| **Phase 3: ORPO 본 학습** | **✅ 완료** | **9,997 steps 조기수렴, eval_loss 1.625, pref_acc 76.02%, 7/10 PASS** |\n| **Phase 4: GGUF 변환·배포** | **✅ 완료** | **byte-fallback 수정, v1/v2 각 3종 양자화, HuggingFace + Ollama 배포** |\n\n### Phase 2 (SFT) 최종 결과\n\n| 항목 | 값 |\n|------|-----|\n| 최종 step | **25,500 / 33,000** (77.3%, early stopping) |\n| **Val loss (best)** | **1.8851** (step 23,000) |\n| 학습 시간 | **~15시간 41분** (2026-03-05 22:15 ~ 2026-03-06 13:56) |\n| VRAM 사용 | **24.2GB** / 183GB per GPU (13.2%) |\n| Base 모델 | checkpoint-0057000 (pretrain loss 1.466) |\n| SFT 데이터 | **2,439,397 samples** (24개 소스, 7.48 GB) |\n| 사고 | 0건 (OOM, NCCL, NaN 없음) |\n\n**SFT Val Loss 전체 추이**:\n```\nStep     500: 2.073\nStep   2,000: 1.956  (-0.117)\nStep   5,000: 1.911  (-0.045)\nStep  10,000: 1.892  (-0.019)\nStep  15,000: 1.886  (-0.006)\nStep  20,000: 1.885  (-0.001)\nStep  23,000: 1.8851 ← BEST\nStep  25,500: 1.8851 → Early Stop (patience 5/5)\n```\n\n### SFT 6차원 평가 요약\n\n| 차원 | 결과 | 핵심 수치 |\n|------|------|-----------|\n| Perplexity (지식 보존) | **PASS** | forgetting 0.9% |\n| 생성 품질 | **FAIL** | Greedy 반복률 72.97% |\n| 한국어 벤치마크 | **FAIL** | KoBEST 평균 43.26% |\n| 영어 벤치마크 | **PASS** | 전 태스크 하한 초과 |\n| Calibration | **PASS** | Top-1 68.59% |\n| SFT Chat 능력 | **PASS** | EOS 종료율 60% (Base 0%) |\n\n\u003e **판정: ORPO 진행** — 지식 보존 우수(0.9%), 반복률은 선호도 정렬로 해결.\n\u003e 상세: `reports/2026-03-06_3B_SFT_COMPLETION_AND_EVAL_SUMMARY.md`\n\n---\n\n## 3. 하드웨어 환경\n\n### GPU\n\n| 항목 | 사양 |\n|------|------|\n| 모델 | 8× NVIDIA B200 |\n| VRAM | 183GB HBM3e per GPU (~1.47TB 합계) |\n| FP8 Tensor Core | 2,250 TFLOPS/GPU (총 18,000 TFLOPS) |\n| BF16 | 1,125 TFLOPS/GPU |\n| HBM3e 대역폭 | ~7.67 TB/s per GPU |\n| 인터커넥트 | NVLink 5.0 (900 GB/s bidirectional per GPU) |\n| 토폴로지 | NVSwitch — 모든 GPU↔GPU 단일 홉 All-to-All Mesh |\n| 전력 | 940W 실측 / 1000W cap |\n\nB200은 FP8 네이티브 지원 모델이다. `torch.float8_e4m3fn` 을 TransformerEngine의 MXFP8 레시피와 결합해 학습한다. BF16 대비 연산량이 이론상 2배이며, 메모리 효율도 향상된다.\n\n### CPU 및 시스템 메모리\n\n| 항목 | 사양 |\n|------|------|\n| CPU | 2× AMD EPYC 9365 (Turin / Zen 5) |\n| 물리 코어 | 72개 (36코어 × 2소켓) |\n| NUMA 구성 | 2노드: node0 (core 0-35) / node1 (core 36-71) |\n| GPU↔NUMA 매핑 | GPU 0-3 → NUMA node 0, GPU 4-7 → NUMA node 1 |\n| RAM | 2.21TB DDR5 (~2.03TB 여유) |\n| L3 캐시 | 384MB (12 CCX × 32MB) |\n\n**NUMA 주의**: 초기 DDP 런칭 시 5/8 rank가 잘못된 NUMA 노드에서 실행되는 문제 발생. 69%의 DataLoader worker가 크로스-NUMA였다. NUMA affinity 최적화는 미적용 상태(로드맵 항목).\n\n### 스토리지\n\n| 경로 | 용도 | 여유 공간 |\n|------|------|-----------|\n| `/PROJECT/0325120031_A/ghong/taketimes/llm-bang/` | 메인 작업 (체크포인트, 데이터) | 2.2TB |\n| `/home/ghong/` | 소규모 코드 | 5GB (제한) |\n\n\u003e **주의**: 체크포인트(수십 GB), 학습 데이터(82GB+), 중간 산출물은 모두 `/PROJECT/...` 경로에 저장한다. 홈 디렉토리 용량 초과 위험.\n\n### 소프트웨어 환경\n\n| 패키지 | 버전 |\n|--------|------|\n| PyTorch | `2.10.0a0+b4e4ee81d3.nv25.12` (NVIDIA 커스텀) |\n| FlashAttention | 2.7.4.post1+25.12 |\n| TransformerEngine | 2.10.0 |\n| NCCL | 2.28.9 |\n| Triton | 3.5.1 |\n| CUDA | 13.1 |\n| Driver | 580.95.05 |\n\n\u003e **경고**: PyTorch는 NVIDIA B200 최적화 커스텀 빌드다. `pip install torch`로 재설치하면 B200 최적화가 깨진다. **절대 재설치 금지.**\n\n---\n\n## 4. 프로젝트 구조\n\n```\nllm-bang/\n├── CLAUDE.md                          # Claude Code 가이드\n├── README.md                          # 이 파일\n├── PROGRESS.md                        # 진행 기록 (날짜별 로그)\n├── Modelfile.3b                       # Ollama 모델 파일\n│\n├── configs/\n│   ├── korean_3b_fp8.yaml             # 3B FP8 학습 설정 (현재 사용 중)\n│   ├── 3b_pretrain.yaml               # 3B 프리트레인 설정 (대체)\n│   ├── korean_1b_fp8.yaml             # 1B FP8 설정 (아카이브)\n│   ├── korean_3b_sft.yaml             # 3B SFT v1 설정 (완료)\n│   ├── korean_3b_sft_v2.yaml          # 3B SFT v2 설정 (lr=5e-5, data mixing)\n│   ├── korean_3b_orpo.yaml            # 3B ORPO 설정 (lr=5e-6, beta=0.1)\n│   ├── hybrid_3b.yaml                 # Hybrid 3B (Mamba-2 + Attention)\n│   ├── small_fp8.yaml                 # 125M FP8 검증용\n│   ├── medium.yaml                    # 중형 모델 설정\n│   └── small.yaml                     # 소형 모델 설정\n│\n├── data/\n│   ├── 3b_train.bin                   # 프리트레인 학습 데이터 (82GB, 41.12B tokens)\n│   ├── 3b_val.bin                     # 검증 데이터 (151MB)\n│   ├── cc100_ko_train.bin             # CC100 한국어 (4.5GB)\n│   ├── cosmo_auto_math_text_train.bin # 수학 텍스트 (2.6GB)\n│   └── build scripts, __init__.py\n│\n├── model/\n│   ├── attention.py                   # GQA FlashAttention (Phase 0 최적화 적용)\n│   ├── transformer.py                 # 트랜스포머 메인 아키텍처\n│   ├── config.py                      # 모델 설정 dataclass\n│   └── layers.py                      # 커스텀 레이어 (RMSNorm, SwiGLU 등)\n│\n├── train/\n│   ├── pretrain.py                    # 프리트레인 스크립트 (DDP 최적화)\n│   ├── sft.py                         # SFT 학습\n│   ├── orpo.py                        # ORPO 학습\n│   ├── trainer.py                     # 통합 트레이너 (loss sync 최적화)\n│   └── utils.py                       # 유틸리티 (NCCL 7200s timeout 등)\n│\n├── scripts/\n│   ├── launch_3b_pretrain.sh          # 3B 프리트레인 런처 (NCCL 환경변수 포함)\n│   ├── launch_3b_sft.sh               # 3B SFT v1 런처\n│   ├── launch_3b_sft_v2.sh            # 3B SFT v2 런처 (data mixing)\n│   ├── launch_3b_orpo.sh              # 3B ORPO 런처\n│   ├── monitor_3b.sh                  # 실시간 학습 모니터\n│   ├── training_watchdog.sh           # 워치독 (10분 간격, 크론)\n│   ├── convert_3b_gguf.sh             # GGUF 변환 스크립트\n│   ├── deploy_3b_ollama.sh            # Ollama 배포\n│   ├── quality_gate.sh                # 배포 전 품질 게이트\n│   ├── telegram_notify.py             # 텔레그램 알림 (urllib 사용, curl 차단)\n│   └── hourly_status.sh               # 1시간 간격 상태 리포트\n│\n├── eval/\n│   ├── debate/\n│   │   └── justice_league_3b_case.md  # 3B 전환 논증 (저스티스리그 멀티에이전트)\n│   ├── decision/\n│   │   └── FINAL_DECISION_REPORT.md   # SFT 재시작 판결문\n│   ├── plan/\n│   │   └── 3B_MASTER_PLAN.md          # 3B 마스터 플랜\n│   ├── tasks/                         # 모듈화된 평가 태스크\n│   │   ├── task_runner.py             # 8-GPU 병렬 태스크 실행기\n│   │   ├── ppl_task.py                # Perplexity 평가 태스크\n│   │   ├── lm_eval_task.py            # lm-evaluation-harness 래퍼\n│   │   ├── calibration_task.py        # Calibration 분석\n│   │   ├── generation_task.py         # 생성 품질 + 파라미터 그리드 서치\n│   │   └── token_nll_task.py          # Token NLL 분포 분석\n│   ├── outputs/                       # 평가 결과 (자동 생성, .gitignore)\n│   ├── full_eval_pipeline.py          # v2 종합 평가 파이프라인 (8-GPU 병렬)\n│   ├── sft_eval_pipeline.py           # SFT 6차원 평가 파이프라인\n│   ├── reeval_pipeline.py             # 재평가 파이프라인 (0+5-shot 연속)\n│   ├── report_generator.py            # 마크다운 리포트 자동 생성\n│   ├── comprehensive_eval.py          # v1 종합 평가 (레거시)\n│   └── test_generation_params.py      # 생성 파라미터 탐색\n│\n├── tokenizer/\n│   ├── korean_sp/                     # SentencePiece 64K 모델 파일\n│   ├── tokenizer.json                 # HuggingFace 포맷 (2.4MB)\n│   ├── train_sp_tokenizer.py          # 토크나이저 학습 스크립트\n│   └── convert_sp_to_hf.py            # SentencePiece → HF 변환\n│\n├── checkpoints/                       # 모델 체크포인트 (대용량, .gitignore)\n│\n├── docs/\n│   ├── PROJECT_HISTORY.md             # 프로젝트 전체 여정 상세 기록\n│   └── 3B_WORKPLAN.md                 # 3B 작업 계획\n│\n└── reports/\n    ├── 2026-03-02_0200_FRANKENSTALLM_phase0_optimization_report.md\n    ├── 2026-03-05_3B_BASE_EVALUATION_REPORT.md\n    ├── 2026-03-05_3B_SFT_PROGRESS_REPORT.md   # SFT 학습 보고서 (Phase 2)\n    ├── 2026-03-05_3B_NEXT_STEPS_REFERENCE.md\n    ├── 2026-03-05_NEMOTRON_NANO_FEASIBILITY_STUDY.md\n    ├── 2026-03-05_PPL_EVALUATION.md\n    ├── 2026-03-05_BENCHMARK_RESULTS.md\n    ├── 2026-03-05_GENERATION_QUALITY.md\n    ├── 2026-03-06_3B_SFT_EVAL_PLAN.md         # SFT 6차원 평가 계획서\n    ├── 2026-03-06_3B_SFT_EVALUATION_REPORT.md  # SFT 6차원 평가 결과\n    └── 2026-03-06_3B_SFT_COMPLETION_AND_EVAL_SUMMARY.md  # SFT 완료 + 코드 개선 종합\n```\n\n---\n\n## 5. 프로젝트 여정 타임라인\n\n이 섹션이 이 README의 핵심이다. 결과만이 아니라 **왜** 그런 결정을 내렸는지, **어디서** 실패했는지를 솔직하게 기록한다.\n\n---\n\n### Day 1 (Feb 25) — 첫 불씨: 125M FP8 검증\n\n프로젝트의 시작은 작은 의문에서 출발했다. B200에서 FP8이 실제로 안정적으로 학습되는가?\n\nTransformerEngine의 MXFP8 레시피를 125M 소형 모델에 적용해 검증했다. 결론은 **안정적으로 동작한다**. loss 수렴도 정상이었고, VRAM 효율도 BF16 대비 확연한 개선이 있었다. 이 검증이 전체 파이프라인의 첫 번째 녹색 신호였다.\n\n같은 날, 인프라 세팅도 완료했다. DDP 8-GPU 환경, NCCL 환경변수, 체크포인트 저장 경로, 텔레그램 알림 시스템의 초안이 이날 갖춰졌다.\n\n---\n\n### Day 1~2 (Feb 25~26) — 1B 프리트레인: 34K 스텝, PPL 5.67\n\n125M 검증 직후 1B 모델 프리트레인에 돌입했다.\n\n- **아키텍처**: d_model=2048, 24 layers, GQA 4:1, SwiGLU, RoPE\n- **데이터**: C4 Korean 기반\n- **학습**: 34,000 스텝, FP8, 8× B200 DDP\n\n최종 결과:\n- **Loss: 1.904**\n- **PPL (C4 Korean): 5.67**\n\n수치만 보면 그럭저럭 괜찮다. 그러나 실제 텍스트 생성을 시켜보면 문제가 보였다. 반복 패턴, 어색한 문장 구조, 맥락 이탈. 프리트레인 모델이니 당연하다. 이제 SFT 차례였다.\n\n---\n\n### Day 2 (Feb 26) — SFT v1: 0.0이라는 재앙\n\nSFT를 돌렸다. 학습이 시작되자마자 loss가 빠르게 떨어지기 시작했다. 처음엔 좋은 신호라고 생각했다.\n\n그런데 loss가 **0.0**이 됐다.\n\nval loss도 0.0. 생성 결과는 완전한 쓰레기였다.\n\n원인을 찾았다: **label off-by-one 버그**. 입력 토큰과 레이블 토큰이 한 칸씩 밀려 있었다. 모델이 실제로 다음 토큰을 예측하는 것이 아니라, 이미 알고 있는 정답을 맞추는 구조가 돼 있었다. loss가 0이 된 건 \"완벽한 학습\"이 아니라 **데이터 누수(label leakage)** 였다.\n\n하루를 날렸다.\n\n---\n\n### Day 3 (Feb 27) — 5가지 버그, 루트 코즈 분석\n\n실패를 분석하기 위해 **5-에이전트 루트 코즈 분석**을 수행했다. 결론은 버그 하나가 아니었다. SFT 파이프라인 전체에 문제가 있었다.\n\n발견된 5가지 핵심 버그:\n\n| 버그 | 증상 | 영향 |\n|------|------|------|\n| Static padding (no packing) | 짧은 샘플도 max_len으로 패딩 | GPU 낭비, 학습 비효율 |\n| EOS 토큰 절단 | 응답 끝에 EOS가 없음 | 모델이 \"문장 끝\"을 못 배움 |\n| 단일 에폭 | 데이터를 한 번만 봄 | 언더피팅 |\n| 검증 분리 없음 | val_loss 측정 불가 | 오버피팅 감지 불가 |\n| 데이터 품질 | 노이즈, 중복, 불균형 | 반복 생성 패턴 유도 |\n\n특히 EOS 절단 버그는 subtle하다. 모델이 응답을 마치는 시점을 배우지 못하면, 생성 시 끊임없이 같은 패턴을 반복하거나 의미 없는 토큰을 이어붙인다. 18% 반복률의 원인 중 하나였다.\n\n---\n\n### Day 3 (Feb 27) — SFT v2: 성공이지만 18% 반복\n\n5가지 버그를 모두 수정하고 SFT v2를 돌렸다.\n\n- **val_loss: 2.2062** — 합리적 수준\n- **반복률: 18%** (rep_penalty=1.1 적용 후)\n\n생성 품질은 v1에 비해 확연히 개선됐다. 하지만 18% 반복률은 여전히 높다. `rep_penalty`를 높이면 반복은 줄지만 생성 다양성도 줄고 어색해진다. 디코딩 파라미터로 해결하기엔 구조적 한계가 있다.\n\nkobest_copa 기준 0.646. 괜찮은 수치이지만 목표에는 미치지 못한다.\n\n---\n\n### Day 3 (Feb 27) — \"저스티스리그 vs 어벤저스\": 3B 전환 결정\n\n반복률 18%를 놓고 팀 내부 토론이 벌어졌다. 핵심 질문은 하나였다:\n\n\u003e **ORPO로 반복을 잡을 수 있는가, 아니면 3B로 가야 하는가?**\n\n이 질문에 답하기 위해 **멀티에이전트 토론**을 수행했다 (코드명: \"저스티스리그 vs 어벤저스\"). 각 에이전트가 다른 입장을 맡아 논증했다.\n\n토론의 핵심 발견:\n\n1. **18% 반복은 1B 파라미터의 구조적 한계**다. 1B 모델은 장거리 의존성(long-range dependency)을 충분히 포착하지 못한다. ORPO 같은 선호도 정렬은 반복을 줄이는 데 일부 도움이 되지만, 근본 원인(파라미터 부족)을 해결하지는 못한다.\n\n2. **스케일링 법칙 분석**: Chinchilla 법칙과 실험 데이터를 기반으로 3B 모델은 동일 데이터에서 반복률을 5~8%까지 낮출 수 있다는 추정이 나왔다.\n\n3. **비용-편익 분석**: ORPO를 1B에 투자하는 것보다 3B 프리트레인에 투자하는 것이 최종 모델 품질 측면에서 우월하다.\n\n**결론: 3B 전환**. 1B는 아카이브하고 3B 프리트레인을 시작한다.\n\n이 결정은 `eval/debate/justice_league_3b_case.md`에 전체 논증과 함께 기록돼 있다.\n\n---\n\n### Day 3 (Feb 27) — 640GB+ 데이터 조립\n\n3B 전환이 결정되자마자 데이터 파이프라인을 가동했다. 1B에 비해 훨씬 많은 데이터가 필요하다 (Chinchilla 최적 비율: 3B 모델 × 20 = 60B tokens).\n\n최종적으로 조립한 데이터:\n- **총 토큰**: 41.12B tokens (최종 이진 파일)\n- **원시 데이터**: 640GB+ 다국어 텍스트\n- **소스**: C4 Korean, 나무위키, Wikipedia Korean, korean_extra 데이터셋\n\n데이터 전처리(토크나이즈, 셔플, 이진 변환)가 완료된 `data/3b_train.bin`은 82GB다. 검증셋 `data/3b_val.bin`은 151MB.\n\n---\n\n### Mar 2 — Phase 0: OOM 격퇴 및 최적화\n\n3B 학습을 처음 시작하자 OOM(Out of Memory)이 발생했다. 183GB VRAM인데 3B 모델이 OOM이 난다는 게 이상하지만, 원인은 있었다.\n\n**GQA FlashAttention 구현 문제**였다. GQA(Grouped-Query Attention)에서 KV 캐시를 expand하는 방식이 메모리를 불필요하게 복사하고 있었다. FlashAttention의 native GQA support를 제대로 활용하지 않은 것이다.\n\nPhase 0에서 수행한 최적화 목록:\n\n| 최적화 | 방법 | 효과 |\n|--------|------|------|\n| GQA FA Native | `flash_attn_varlen_func` native GQA 경로 사용 | VRAM 60.4GB → 48.3GB (**-20%**) |\n| DDP 최적화 | `gradient_as_bucket_view=True` | GPU-CPU 동기화 오버헤드 -87.5% |\n| NCCL NVLS | Ring+Tree 토폴로지, NVLS 활성화 | AllReduce 효율 개선 |\n| 배치 크기 분석 | GPU 2,4,6의 NCCL relay node 역할 파악 | bs=5 최적, bs=6 위험 판정 |\n| SIGHUP 방어 | nohup+setsid + Python signal handler + emergency ckpt | 3중 보호 |\n| 모니터링 | Telegram Bot (B200Bot) + cron | 10분 워치독, 1시간 상태 리포트 |\n\n**torch.compile 테스트**: 효과 없음(1.00x). 원인은 TransformerEngine의 opaque kernel이 graph break를 유발하고, `/tmp` 디렉토리에 noexec 플래그가 걸려 있어 컴파일된 kernel 캐시가 쓰이지 않았다. 시간 낭비를 한 셈이지만, \"효과 없다\"는 것을 실측으로 확인한 것도 성과다.\n\n**bs=5의 이유**: NCCL ring topology에서 GPU 2, 4, 6이 relay node 역할을 맡는다. 이 GPU들은 다른 GPU보다 약 11GB를 더 사용한다. bs=5에서는 여유가 있지만, bs=6으로 올리면 이 relay GPU들이 183GB 경계에 너무 가까워진다. 안전 마진을 위해 bs=5를 유지한다.\n\n---\n\n### Mar 2~Mar 5 — Phase 1: 3B 프리트레인 완료\n\nPhase 0 최적화가 완료된 후 Phase 1이 시작됐다.\n\n초기 지표 (step 3150):\n- Loss: 2.38\n- 처리 속도: 36K tok/s per rank\n- 시스템 전체: ~292K tok/s (8 GPU)\n- MFU: ~33.5%\n\nMFU 33.5%는 처음에는 낮아 보일 수 있다. 하지만 TE MXFP8가 이미 최적화된 상태에서 나온 수치다. 이론적 피크(18,000 TFLOPS) 대비 실효율이다. 추가 최적화 여지로 QKV fusion (+8~12%), NUMA affinity (+4~9%), FA2 native RoPE (+3~5%)가 남아있다.\n\n**Phase 1 완료 (2026-03-05)**:\n\n- **57,000 steps 완료**, 최종 loss **1.466**\n- 41.12B 토큰 처리, 총 학습 시간 약 63시간\n- 무사고 완료 (SIGHUP, OOM, NCCL 이상 없음)\n\n종합 평가 결과 요약 (v2 재평가 반영):\n\n| 항목 | 결과 |\n|------|------|\n| PPL (통합 검증셋) | 5.2263 (초기 v1 평가: 5.709) |\n| PPL (C4 Korean) | 5.717 |\n| KoBEST 평균 (5태스크) | 43.69% |\n| MMLU-KO 평균 (6카테고리) | 22.75% |\n| HAE-RAE | 19.71% |\n| winogrande / piqa | 50.59% / 52.50% |\n| Calibration Top-1 | 68.75% |\n| Greedy 3-gram 반복률 | 60.99% (SFT 후 개선 예정) |\n| 최적 생성 파라미터 | temp=0.7, rep_penalty=1.3 → 반복률 0% |\n\n**SFT 진행 결정**: loss 1.466은 건강한 학습 완료 시그널. PPL/반복률/벤치마크 모두 SFT가 해결할 영역. 모델 구조 문제 징후 없음. → Phase 2 SFT 진행.\n\n---\n\n### Mar 5~ — Phase 2: 3B SFT 시작 — 2.44M 샘플, val_loss 1.956\n\nPhase 1 완료 직후, 대규모 SFT 데이터를 준비하고 학습을 시작했다.\n\n**데이터 파이프라인**:\n- **24개 소스**에서 6.59M raw samples 수집\n- `prepare_sft_combined.sh`: 포맷 통일(6가지 포맷 → messages), MD5 중복 제거, 98:2 split\n- `filter_sft_v2.py`: 5단계 품질 필터 (EOS strip, QA marker 제거, 길이 필터, 4-gram 반복 필터)\n- 최종: **2,439,397 train + 49,801 val** (7.48 GB)\n\n데이터 구성은 추론/CoT(38%), 한국어 지시(22.5%), 영어 다목적(16%), 수학(12%), 대화/코드(11.5%)로 균형을 맞췄다. 1B SFT의 161K에서 **15배 확대**한 규모다.\n\n**SFT 설계 — 1B 실패에서 배운 교훈 반영**:\n\n| 1B 교훈 | 3B SFT 적용 |\n|---------|-------------|\n| Label off-by-one → loss=0 | Loss masking 검증 (prompt=-1, response만 학습) |\n| EOS 절단 → 종료 불가 | Chat template `\u003c\\|user\\|\u003e...\u003c\\|assistant\\|\u003e...\u003c/s\u003e` EOS 포함 |\n| Static padding → GPU 낭비 | Dynamic padding (64-token 정렬) |\n| 검증 없음 → 오버피팅 미감지 | 49,801 val samples, 500 step 간격 eval |\n| 데이터 노이즈 | 5단계 품질 필터 (1B에는 없었음) |\n| 반복률 18% | **NEFTune alpha=5.0** 추가 (임베딩 노이즈 주입) |\n\n**학습 설정**:\n- LR: **1e-5** (pretrain의 1/15 — catastrophic forgetting 방지)\n- Effective batch: 2 × 8 GPU × 4 accum = 64 sequences\n- 33,000 steps (~3.3 epochs)\n- MXFP8, gradient checkpointing, NCCL Ring+Tree\n\n**초기 결과** (step 2,000, 6%):\n- Val loss: 2.073 → 2.004 → 1.975 → **1.956** (단조 감소)\n- Train-Val 갭 ~0.1 (오버피팅 징후 없음)\n- VRAM 24.2 GB (13.2%) — pretrain의 절반, 매우 안정\n- Grad norm 1.0 일정 (학습률 적절)\n\n상세 보고서: `reports/2026-03-05_3B_SFT_PROGRESS_REPORT.md`\n\n---\n\n### Mar 6 — Phase 2 완료: SFT Early Stopping (val_loss 1.8851)\n\nSFT는 33,000 steps 중 **25,500 steps**에서 early stopping으로 종료되었다. Val loss는 step 23,000에서 1.8851에 도달한 뒤, 5회 연속 개선 없이 학습이 자동 중단되었다.\n\n**총 학습 시간**: ~15시간 41분 (2026-03-05 22:15 ~ 2026-03-06 13:56)\n\n이 결과는 LR 1e-5의 cosine decay가 step 20K 이후 사실상 0에 수렴한 것과 일치한다. 모델은 주어진 LR schedule 하에서 학습 가능한 만큼 완전히 학습했다.\n\n---\n\n### Mar 6 — SFT 6차원 종합 평가: 4/6 PASS → ORPO 결정\n\nSFT 체크포인트(`checkpoint-best`, step 23000)에 대해 6차원 종합 평가를 수행했다. 49분 27초 소요.\n\n**핵심 결과**:\n- **Perplexity**: forgetting 0.9% (19개 데이터셋 전체 PASS) — 지식 보존 우수\n- **반복률**: greedy 72.97% (Base 60.99%보다 **악화**) — FAIL\n- **EOS 종료율**: 0% → 60% — 개선됐지만 목표(90%) 미달\n- **KoBEST**: 43.26% (Base 43.69%와 거의 동일) — FAIL\n- **MMLU-KO**: 22.75% → 26.00% (+3.2pp) — 부분 개선\n- **Calibration**: Top-1 68.59% — PASS\n\n**결정**: greedy 반복률 72.97%는 SFT만으로 해결 불가. 그러나 `rep_penalty=1.2` 적용 시 반복률 0%가 달성되므로, ORPO(선호도 정렬)로 이 행동을 내재화하는 것이 올바른 경로다.\n\n---\n\n### Mar 6 — 코드 개선 및 ORPO 준비\n\nSFT 평가와 병행하여 다수의 코드 개선 및 Phase 3 준비를 완료했다:\n\n| 변경 | 내용 | 영향 |\n|------|------|------|\n| `train/sft.py` +238줄 | MixingDataLoader (SFT+pretrain 인터리빙), DDP rank 0 토크나이징 | forgetting 방지, 메모리 8배 절감 |\n| `train/trainer.py` +17줄 | DDP early stopping broadcast (hang 방지), patience 5→10 | DDP 안정성 |\n| `train/orpo.py` +30줄 | YAML config 지원, 3B 기본값 | ORPO 실행 준비 |\n| `eval/report_generator.py` +831줄 | Base vs SFT 비교 보고서 자동 생성 | 평가 자동화 |\n| `eval/sft_eval_pipeline.py` 신규 | SFT 6차원 평가 파이프라인 | 종합 평가 |\n| `eval/tasks/generation_task.py` +75줄 | Chat template, 다양성 메트릭 | SFT 평가 |\n| `configs/korean_3b_sft_v2.yaml` 신규 | SFT v2 설정 (lr=5e-5, data mixing 70/30) | 백업 경로 |\n| `configs/korean_3b_orpo.yaml` 신규 | ORPO 설정 (lr=5e-6, beta=0.1) | Phase 3 |\n\n상세: `reports/2026-03-06_3B_SFT_COMPLETION_AND_EVAL_SUMMARY.md`\n\n---\n\n## 6. 모델 아키텍처\n\n### 1B (아카이브)\n\n| 항목 | 값 |\n|------|-----|\n| vocab_size | 64,000 |\n| d_model | 2,048 |\n| n_layers | 24 |\n| n_heads | 16 |\n| n_kv_heads | 4 (GQA 4:1) |\n| d_ffn | 5,461 (SwiGLU) |\n| 파라미터 수 | ~1.19B |\n| context | 2,048 |\n| rope_theta | 500,000 |\n\n### 3B (현재)\n\n| 항목 | 값 |\n|------|-----|\n| vocab_size | 64,000 |\n| d_model | 3,072 |\n| n_layers | 28 |\n| n_heads | 24 |\n| n_kv_heads | 8 (GQA 3:1) |\n| d_ffn | 8,192 (SwiGLU) |\n| 파라미터 수 | ~3.0B |\n| context | 2,048 |\n| rope_theta | 500,000 |\n\n### 공통 설계 원칙\n\n| 컴포넌트 | 선택 | 이유 |\n|----------|------|------|\n| 정규화 | Pre-norm RMSNorm | Post-norm보다 학습 안정적 |\n| 활성화 | SwiGLU FFN | Llama 계열에서 검증된 선택 |\n| 위치 인코딩 | RoPE (θ=500K) | 긴 컨텍스트 확장 가능성 |\n| 어텐션 | GQA (Grouped-Query Attention) | KV 캐시 메모리 절감 |\n| 구현 | FlashAttention-2 | IO-aware, VRAM 효율 |\n| 정밀도 | FP8 (MXFP8 via TransformerEngine) | B200 최적 활용 |\n\n### GQA 비율 선택 근거\n\n1B는 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)를 참고했다.\n\n### rope_theta=500,000의 의미\n\n표준 RoPE의 θ=10,000에서 500,000으로 늘린 것은 긴 컨텍스트에서 주파수 간섭을 줄이기 위해서다. Code Llama, Llama 3 등이 채택한 방식이다. 현재 max_seq_len=2048이므로 당장 효과를 보기는 어렵지만, 향후 컨텍스트 확장 파인튜닝을 위한 기반이다.\n\n---\n\n## 7. 학습 데이터\n\n### 7.1 토크나이저\n\n| 항목 | 값 |\n|------|-----|\n| 종류 | SentencePiece Unigram |\n| 어휘 크기 | 64,000 |\n| 한국어 문자 커버리지 | 99.95% |\n| 위치 | `tokenizer/korean_sp/` |\n| HF 포맷 | `tokenizer/tokenizer.json` (2.4MB) |\n\n64K 어휘는 32K(너무 작음, 한국어 서브워드 단편화 심함)와 128K(너무 큼, 임베딩 레이어 오버헤드 증가) 사이의 균형이다. Llama 3(128K)와 GPT-4(100K)가 큰 어휘를 사용하는 추세지만, 3B 모델에서 128K 어휘는 임베딩 레이어만으로도 파라미터 비중이 지나치게 커진다.\n\n### 7.2 프리트레인 데이터 — 전체 구성\n\n최종 학습 파일: `data/3b_train.bin` (77GB, ~38.5B tokens) + `data/3b_val.bin` (145MB)\n\nChinchilla 법칙 기준: 3B × 20 = **60B 토큰**이 최적이다. 현재 38.5B 토큰을 57,000 스텝(batch 5 × accum 8 × seq 2048 × 8 GPU)으로 반복 소비하며, 처음 3B 학습으로서 합리적인 범위다.\n\n#### 한국어 — 웹크롤 (Web Crawl)\n\n| 데이터셋 | HuggingFace ID | 토큰화 파일 | 크기 | 추정 토큰 | 설명 |\n|----------|---------------|------------|------|----------|------|\n| C4 Korean | `allenai/c4` (ko subset) | `korean_c4_train.bin` | 15GB | ~7.5B | Google C4 한국어 필터링, 대규모 클린 웹 텍스트 |\n| CC-100 Korean | `cc100` (ko subset) | `cc100_ko_train.bin` | 4.3GB | ~2.15B | Common Crawl 기반 단일언어 코퍼스 |\n| HPLT Korean | `HPLT/hplt_monolingual_v2` (ko) | `hplt_ko_train.bin` | 15GB | ~7.5B | High Performance Language Technologies 웹 데이터 |\n\n#### 한국어 — 백과사전 (Encyclopedia)\n\n| 데이터셋 | HuggingFace ID | 토큰화 파일 | 크기 | 추정 토큰 | 설명 |\n|----------|---------------|------------|------|----------|------|\n| 위키백과 한국어 | `wikimedia/wikipedia` (20231101.ko) | `wikipedia_ko_train.bin` | 566MB | ~283M | 한국어 위키백과 전체, 구조화된 문어체 |\n| 위키백과 한국어 (v2) | `wikimedia/wikipedia` (ko) | `korean_wiki_train.bin` | 500MB | ~250M | 위키백과 별도 버전 |\n| 나무위키 | `heegyu/namuwiki-extracted` | `korean_namuwiki_train.bin` | 2.1GB | ~1.05B | 나무위키 추출본, 서브컬처·시사 풍부 |\n| 나무위키 2023b | `heegyu/namuwiki-extracted` (2023b) | `namuwiki_2023b_train.bin` | 2.5GB | ~1.25B | 2023년 업데이트 스냅샷 |\n\n#### 영어/다국어 — 교육 (Educational)\n\n| 데이터셋 | HuggingFace ID | 토큰화 파일 | 크기 | 추정 토큰 | 설명 |\n|----------|---------------|------------|------|----------|------|\n| Cosmopedia Stories | `HuggingFaceTB/cosmopedia` | `cosmo_stories_train.bin` | 5.9GB | ~2.95B | 합성 교육용 스토리 |\n| Cosmopedia Web v2 | `HuggingFaceTB/cosmopedia` | `cosmo_web_v2_train.bin` | 2.7GB | ~1.35B | 웹 기반 교육 텍스트 |\n| Cosmopedia Stanford | `HuggingFaceTB/cosmopedia` | `cosmo_stanford_train.bin` | 2.1GB | ~1.05B | Stanford 강의 기반 |\n| Cosmopedia WikiHow | `HuggingFaceTB/cosmopedia` | `cosmo_wikihow_train.bin` | 382MB | ~191M | WikiHow 가이드 |\n| Cosmopedia OpenStax | `HuggingFaceTB/cosmopedia` | `cosmo_openstax_train.bin` | 224MB | ~112M | 오픈 교과서 |\n| Cosmopedia Khan Academy | `HuggingFaceTB/cosmopedia` | `cosmo_khanacademy_train.bin` | 46MB | ~23M | 칸 아카데미 |\n\n#### 영어/다국어 — 수학·과학 (Math \u0026 Science)\n\n| 데이터셋 | HuggingFace ID | 토큰화 파일 | 크기 | 추정 토큰 | 설명 |\n|----------|---------------|------------|------|----------|------|\n| Open Web Math | `open-web-math/open-web-math` | `open_web_math_train.bin` | 4.8GB | ~2.4B | 웹에서 추출한 수학 텍스트 |\n| MathPile | `GAIR/MathPile` | `mathpile_train.bin` | 2.9GB | ~1.45B | 수학 교과서·논문·포럼 |\n| Cosmopedia AutoMath | `HuggingFaceTB/cosmopedia` | `cosmo_auto_math_text_train.bin` | 2.5GB | ~1.25B | 합성 수학 문제·풀이 |\n\n#### 한국어 — 혼합 (Legacy Merged)\n\n| 데이터셋 | 토큰화 파일 | 크기 | 추정 토큰 | 설명 |\n|----------|------------|------|----------|------|\n| 초기 혼합 (C4+나무+위키) | `korean_train.bin` | 17GB | ~8.5B | 1B 학습에 사용된 원본 혼합 데이터 |\n| 125M 검증용 | `train.bin` | 1.2GB | ~600M | 최초 FP8 검증에 사용 |\n\n#### 미사용 수집 데이터 (korean_extra/ — 640GB+)\n\n`data/korean_extra/` 에 39개 서브디렉토리로 수집되었으나, 토큰화·병합은 일부만 완료된 대규모 원시 데이터:\n\n| 분류 | 데이터셋 | 설명 | 비고 |\n|------|----------|------|------|\n| 웹크롤 | CulturaX Korean | 대규모 다국어 웹 코퍼스 한국어 | ~50B+ tokens |\n| 웹크롤 | FineWeb2 Educational Korean | 교육적 품질 필터링 웹 데이터 | 234GB raw |\n| 웹크롤 | Korean Web Collection | KORMo 웹 컬렉션 | 175GB raw |\n| 웹크롤 | OSCAR Korean | 다국어 웹 코퍼스 한국어 | |\n| 교육 | Korean Textbooks | 한국어 교과서 텍스트 | 45개 서브카테고리 |\n| 교육 | FinePDFs Educational Korean | PDF 기반 교육 자료 | |\n| 법률 | Korean Law | 한국 법률 텍스트 | 15GB |\n| 뉴스 | Korean News Archive | 한국어 뉴스 아카이브 | |\n| 공개코퍼스 | Korean Public Corpus | KORMo 공개 코퍼스 | 26GB |\n| 코드 | Code Pretrain | 프로그래밍 코드 | |\n| 학술 | Academic Pretrain | 학술 논문·리포트 | |\n| 범용 | SlimPajama | RedPajama 경량 버전 | |\n\n\u003e 이 데이터는 Extended Pretrain (80-100B tokens) 단계에서 활용 예정이다.\n\n#### 프리트레인 데이터 분야별 비율\n\n```\n┌─────────────────────────────────────────────────────────┐\n│              3b_train.bin 토큰 구성 (~38.5B)              │\n├─────────────────────────────────────────────────────────┤\n│ ████████████████████░░░░░░░░░░  한국어 웹크롤    44.7%  │\n│ ██████████░░░░░░░░░░░░░░░░░░░░  혼합 레거시      22.1%  │\n│ ██████░░░░░░░░░░░░░░░░░░░░░░░░  교육 (EN)       14.7%  │\n│ █████░░░░░░░░░░░░░░░░░░░░░░░░░  수학·과학       13.2%  │\n│ ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░  백과사전 (KO)    5.3%  │\n└─────────────────────────────────────────────────────────┘\n```\n\n### 7.3 SFT 데이터 — 2.44M 샘플 (현재 학습 중)\n\n**24개 소스**에서 6.59M raw → 통합·중복 제거 → 품질 필터링 → **2,439,397 train + 49,801 val**\n\n#### 주요 SFT 소스 (상위 12, 전체의 96%)\n\n| # | 데이터셋 | 샘플 수 | 크기 | 도메인 |\n|---|---------|---------|------|--------|\n| 1 | reasoning_r1_1.4m | 1,400,000 | 14.77 GB | 추론 (CoT) |\n| 2 | openhermes_2.5 | 1,001,551 | 1.82 GB | 영어 다목적 |\n| 3 | AI-MO_NuminaMath-CoT | 859,494 | 2.51 GB | 수학 CoT |\n| 4 | korean_instruction_mix | 515,911 | 1.39 GB | 한국어 혼합 |\n| 5 | lemon-mint_smol-koreantalk | 460,281 | 5.23 GB | 한국어 대화 |\n| 6 | open_korean_instructions | 375,159 | 0.73 GB | 한국어 지시 |\n| 7 | magpie_reasoning_v2 | 249,922 | 3.99 GB | 추론 (영어) |\n| 8 | magpie_reasoning_ko | 224,929 | 3.19 GB | 추론 (한국어) |\n| 9 | ultrachat_200k | 207,865 | 1.34 GB | 대화 |\n| 10 | kuotient_orca-math-ko | 193,789 | 0.61 GB | 수학 (한국어) |\n| 11 | data/sft/train.jsonl (원본) | 161,848 | 0.27 GB | 원본 SFT |\n| 12 | kullm_v2 | 152,630 | 0.42 GB | 한국어 지시 |\n\n기타 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\n\n#### 데이터 처리 파이프라인\n\n```\n24개 소스 (6.59M raw)\n    ↓ prepare_sft_combined.sh (포맷 통일, MD5 중복 제거, 98:2 split)\n통합: 2,559,492 train + 52,234 val (7.95 GB)\n    ↓ filter_sft_v2.py (5단계: EOS strip, QA marker 제거, 길이 50~20K, 4-gram 반복 \u003e30% 제거)\n최종: 2,439,397 train + 49,801 val (7.63 GB)  ← 제거율 4.69%\n```\n\n#### 도메인 비율\n\n```\n추론/CoT         38.0%  ████████████████████████\n한국어 지시       22.5%  ██████████████\n영어 다목적       16.0%  ██████████\n수학             12.0%  ████████\n대화/코드/기타    11.5%  ███████\n```\n\n### 7.4 선호도 데이터 (ORPO용) — 795K 쌍\n\n총 **795,468 preference pairs** (7.9GB, `data/preference/combined_preference.jsonl`)\n\n| HuggingFace ID | 크기 | 분야 | 포맷 |\n|---------------|------|------|------|\n| `nayohan/preference-collection-ko-full` | 4.9GB | 범용 선호도 평가 | instruction + response_A/B + preference |\n| `heegyu/orca-math-korean-preference-cleaned` | 1.6GB | 수학 추론 | prompt + chosen + rejected |\n| `kuotient/orca-math-korean-dpo-pairs` | 750MB | 수학 DPO | prompt + chosen + rejected |\n| `maywell/ko_Ultrafeedback_binarized` | 394MB | 피드백 기반 정렬 | prompt + winning/losing response |\n| `tellang/yeji-preference-ko-v1` | 171MB | 범용 선호도 | prompt + chosen + rejected |\n| `jojo0217/korean_rlhf_dataset` | 137MB | RLHF 쌍 | prompt + chosen + rejected |\n| `lemon-mint/korean-realqa-reasoning-v01-preference` | 58MB | QA 추론 | prompt + chosen + rejected |\n\n**필터링 기준**: 최소 길이 20자, EOS 제거, 포맷 정규화 후 통합\n\n\u003e ORPO는 Phase 3에서 반복률이 5% 초과할 경우에만 실행한다. 3B 모델이 1B의 구조적 반복 문제를 스스로 해결한다면 ORPO 없이 배포할 수 있다.\n\n### 7.5 데이터 파이프라인 요약\n\n```\n[HuggingFace / 웹 수집]\n        │\n        ▼\n┌─── 원시 수집 ───────────────────────────────────────────┐\n│  korean_extra/ (39개 디렉토리, 640GB+)                    │\n│  sft_extra/ (27개 디렉토리, 1.08M 샘플)                   │\n│  preference/ (7개 JSONL, 795K 쌍)                        │\n└─────────────────────────────────────────────────────────┘\n        │\n        ▼\n┌─── 토큰화 (SentencePiece 64K) ──────────────────────────┐\n│  tokenize_extra.py — 자동 포맷 감지 (Arrow/Parquet/JSONL) │\n│  8 workers 병렬 처리, uint16 memmap (.bin) 출력           │\n└─────────────────────────────────────────────────────────┘\n        │\n        ▼\n┌─── 최종 병합 ───────────────────────────────────────────┐\n│  Pretrain: 3b_train.bin (77GB, ~38.5B tokens)           │\n│  SFT:     sft_combined/train_filtered.jsonl (7.48GB, 2.44M 샘플) │\n│  ORPO:    preference/combined_preference.jsonl (7.9GB)  │\n└─────────────────────────────────────────────────────────┘\n```\n\n---\n\n## 8. 학습 설정 및 최적화\n\n### 현재 학습 설정 (`configs/korean_3b_fp8.yaml`)\n\n```yaml\nmodel:\n  vocab_size: 64000\n  d_model: 3072\n  n_layers: 28\n  n_heads: 24\n  n_kv_heads: 8\n  d_ffn: 8192\n  max_seq_len: 2048\n  rope_theta: 500000.0\n\ntraining:\n  batch_size: 5\n  gradient_accumulation_steps: 8\n  learning_rate: 1.5e-4\n  min_lr: 1.5e-5\n  warmup_steps: 2000\n  max_steps: 57000\n  weight_decay: 0.1\n  grad_clip: 1.0\n  optimizer: adamw\n  scheduler: cosine\n\nfp8:\n  enabled: true\n  recipe: \"mxfp8\"\n  use_transformer_engine: true\n\ndistributed:\n  strategy: ddp\n  gradient_as_bucket_view: true\n  find_unused_parameters: false\n\nnccl:\n  timeout_seconds: 7200\n  nvls_enabled: true\n```\n\n유효 배치 크기 = `batch_size(5) × grad_accum(8) × num_gpus(8)` = **320**\n\nLR 스케줄: warmup 2000 스텝 → cosine decay → min_lr=1.5e-5 (max_lr의 10%)\n\n### Phase 0에서 배운 최적화 교훈\n\n#### GQA FlashAttention Native\n\n가장 큰 VRAM 절감을 가져온 최적화. 핵심은 FlashAttention이 GQA를 native로 지원한다는 점이다. KV head를 expand하여 MHA처럼 처리하면 메모리 복사가 발생하지만, native path를 쓰면 내부에서 직접 처리한다.\n\n```python\n# Before (비효율적): KV expand → MHA처럼 처리\nk = k.repeat_interleave(n_heads // n_kv_heads, dim=1)\nv = v.repeat_interleave(n_heads // n_kv_heads, dim=1)\nout = flash_attn_func(q, k, v)\n\n# After (native GQA): flash_attn이 내부에서 GQA 처리\nout = flash_attn_func(q, k, v)  # q: [B, S, H, D], k/v: [B, S, Hkv, D]\n# VRAM 60.4GB → 48.3GB (-20%)\n```\n\n#### DDP 최적화\n\n```python\n# gradient_as_bucket_view=True: gradient tensor를 bucket 메모리의 view로 직접 매핑\n# → 불필요한 메모리 복사 제거, GPU-CPU 동기화 오버헤드 -87.5%\nmodel = torch.nn.parallel.DistributedDataParallel(\n    model,\n    device_ids=[local_rank],\n    gradient_as_bucket_view=True,\n    find_unused_parameters=False,  # 모든 파라미터가 사용됨\n)\n```\n\n**주의**: `static_graph=True`는 사용하지 않는다. TransformerEngine의 `te.Linear`가 일부 케이스에서 dynamic graph를 요구하는데, static_graph를 켜면 런타임 에러가 발생한다.\n\n#### NCCL NVLS\n\n```bash\nexport NCCL_ALGO=NVLSTree    # NVLink SHARP (NVLS) 활성화\nexport NCCL_PROTO=Simple\nexport NCCL_P2P_DISABLE=0\nexport NCCL_TIMEOUT=7200     # 긴 backward에 대비한 타임아웃 여유\n```\n\nNVSwitch가 All-to-All single hop을 지원하므로 Ring topology보다 NVLSTree가 효율적이다.\n\n#### SIGHUP 3중 방어\n\n장시간 학습에서 세션 연결 끊김(SIGHUP)은 치명적이다. 3중 보호를 구축했다:\n\n```bash\n# 1중: nohup + setsid (새 세션 그룹)\nnohup setsid torchrun --nproc_per_node=8 train/pretrain.py ... \u0026\n\n# 2중: Python signal handler (Python 레벨 SIGHUP 무시)\nimport signal\nsignal.signal(signal.SIGHUP, signal.SIG_IGN)\n\n# 3중: emergency checkpoint (SIGTERM에도 체크포인트 저장)\ndef emergency_save(signum, frame):\n    save_checkpoint(model, optimizer, step, \"emergency\")\n    sys.exit(0)\nsignal.signal(signal.SIGTERM, emergency_save)\n```\n\n#### torch.compile — 테스트 결과: 효과 없음\n\n`torch.compile`을 적용해 speedup을 기대했지만 실측 결과 **1.00x (효과 없음)**이었다. 두 가지 이유:\n\n1. TransformerEngine의 kernel이 opaque하여 graph break가 발생한다. `torch.compile`은 Python 연산 그래프를 최적화하는데, TE kernel은 그 그래프 밖에 있다.\n2. `/tmp` 디렉토리에 `noexec` 마운트 플래그가 있어 컴파일된 kernel을 캐시하지 못한다.\n\n**교훈**: \"일단 써보자\"보다 \"왜 효과가 있는지 먼저 이해하자\"가 중요하다.\n\n### 모니터링 시스템\n\n```\n텔레그램 알림 시스템\n├── B200Bot (token 설정됨)\n├── training_watchdog.sh → 10분 간격 cron\n│   └── loss 이상, 프로세스 종료 감지 → 즉시 알림\n└── hourly_status.sh → 1시간 간격 cron\n    └── step, loss, 속도, VRAM, eta → 정기 리포트\n```\n\n```python\n# curl이 차단돼 있어 urllib 사용\nimport urllib.request, json\n\ndef send_telegram(message):\n    url = f\"https://api.telegram.org/bot{TOKEN}/sendMessage\"\n    data = json.dumps({\"chat_id\": CHAT_ID, \"text\": message}).encode()\n    req = urllib.request.Request(url, data=data,\n                                  headers={\"Content-Type\": \"application/json\"})\n    urllib.request.urlopen(req)\n```\n\n---\n\n## 9. 실험 결과 — 1B 베이스라인\n\n1B 모델의 실험 결과를 정직하게 기록한다. 성공과 실패 모두.\n\n### 프리트레인 결과\n\n| 지표 | 값 |\n|------|-----|\n| 최종 Loss | 1.904 |\n| PPL (C4 Korean) | 5.67 |\n| 학습 스텝 | 34,000 |\n| 학습 시간 | ~2일 |\n\n### SFT v1 결과 — 실패\n\n| 지표 | 값 |\n|------|-----|\n| val_loss | 0.0 (비정상) |\n| 원인 | label off-by-one 버그 (데이터 누수) |\n| 결론 | 전면 폐기 |\n\n### SFT v2 결과 — 부분 성공\n\n| 지표 | 값 |\n|------|-----|\n| val_loss | 2.2062 |\n| 반복률 | 18% (rep_penalty=1.1 적용) |\n| kobest_copa | 0.646 |\n| 결론 | 기능하지만 구조적 한계 존재 |\n\n### 3B 기대 목표치 (스케일링 법칙 기반 예측)\n\n| 벤치마크 | 1B 현재 | 3B 목표 |\n|----------|---------|---------|\n| kobest_copa | 0.646 | \u003e0.72 |\n| kobest_hellaswag | ~0.42 | \u003e0.52 |\n| 반복률 | 18% | \u003c5% |\n| PPL (C4 Korean) | 5.67 | \u003c4.5 |\n\n1B에서 3B로의 스케일업은 단순히 파라미터를 늘리는 것이 아니다. 모델이 더 긴 맥락을 기억하고, 더 다양한 패턴을 학습할 수 있어야 반복률이 구조적으로 낮아진다. 3B 목표치는 Chinchilla 스케일링 곡선과 유사 규모 모델들의 벤치마크를 참고한 예측값이다.\n\n---\n\n## 10. 실험 결과 — 3B Base 종합 평가 (v2)\n\n3B 사전학습 완료 후 checkpoint-0057000 기준으로 수행한 종합 평가.\nv2 재평가는 8-GPU 병렬 파이프라인으로 13+ 벤치마크, 0/5-shot 비교, calibration, 참고모델 비교를 포함한다.\n총 소요 시간 256.6초.\n\n\u003e **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조합 파라미터 그리드 서치를 포함한다.\n\n### 10.1 학습 커브\n\n| Step | Loss | LR | 비고 |\n|------|------|----|------|\n| 10 | 11.657 | 1.50e-06 | 초기 (warmup 시작) |\n| 500 | 5.047 | 7.50e-05 | warmup 진행 |\n| 2,000 | 2.851 | 3.00e-04 | warmup 완료, peak LR |\n| 10,000 | 2.057 | 2.86e-04 | 안정 하강 |\n| 30,000 | 1.789 | 1.61e-04 | 중반, epoch 1 진입 |\n| 57,000 | 1.466 | 3.00e-05 | 최종 (cosine min) |\n\n\u003e 처리 속도는 전 구간 36~38K tok/s로 안정. 총 학습 시간 약 63시간.\n\n### Base Model 백업\n\n| 항목 | 값 |\n|------|-----|\n| 원본 체크포인트 | `checkpoints/korean_3b_fp8_run1/checkpoint-0057000/` (34GB) |\n| 백업 | `checkpoints/korean_3b_fp8_run1/checkpoint-0057000_BASE_BACKUP/` |\n| MD5 검증 | `4f493d7bcc843727d32453bb3a4e6b7d` (일치 확인) |\n| HF 변환 | `eval/outputs/hf_3b_base/` (11GB safetensors) |\n\n### 10.2 PPL (Perplexity) — 19개 데이터셋\n\n**주요 PPL (3b_val 통합): 5.2263** (초기 v1 평가: 5.709)\n\n| 데이터셋 | PPL | Bits/Token | 평가 토큰 | 소요 시간 |\n|---------|-----|-----------|---------|---------|\n| korean_namuwiki | 25.88 | 4.694 | 6.5M | 63.7s |\n| cc100_ko | 21.78 | 4.445 | 13.6M | 133.2s |\n| namuwiki_2023b | 18.92 | 4.242 | 7.7M | 75.1s |\n| val | 18.30 | 4.194 | 9.1M | 89.4s |\n| korean_wiki | 11.84 | 3.565 | 1.6M | 15.5s |\n| wikipedia_ko | 10.71 | 3.420 | 1.8M | 17.4s |\n| korean | 7.02 | 2.811 | 53.5M | 521.6s |\n| open_web_math | 6.93 | 2.792 | 15.7M | 153.5s |\n| **korean_c4** | **5.72** | **2.515** | **45.4M** | **443.1s** |\n| **3b (통합)** | **5.23** | **2.386** | **226.9M** | **2227.3s** |\n| cosmo_web_v2 | 4.17 | 2.059 | 8.6M | 84.6s |\n| cosmo_stories | 3.96 | 1.984 | 18.9M | 185.2s |\n| cosmo_openstax | 3.87 | 1.951 | 0.7M | 7.2s |\n| cosmo_stanford | 3.36 | 1.750 | 6.6M | 65.3s |\n| cosmo_wikihow | 3.31 | 1.727 | 1.2M | 11.8s |\n| cosmo_auto_math_text | 3.15 | 1.655 | 7.9M | 77.3s |\n| cosmo_khanacademy | 2.93 | 1.552 | 0.1M | 1.5s |\n| mathpile | 2.72 | 1.446 | 7.1M | 69.9s |\n| hplt_ko | 2.40 | 1.265 | 48.5M | 475.9s |\n\n\u003e **해석**: in-distribution(학습에 포함된) 데이터(hplt_ko: 2.40, mathpile: 2.72)가 낮고, OOD(학습 비중 낮은) 데이터(cc100_ko: 21.78, namuwiki: 25.88)가 높은 것은 예상된 패턴. korean_c4 5.72는 v1의 5.717과 일치하여 평가 재현성을 확인.\n\n### 10.3 한국어 벤치마크\n\n#### KoBEST (0-shot) — 평균 43.69%\n\n| 태스크 | Accuracy | F1 |\n|--------|----------|-----|\n| kobest_boolq | 50.28% | 0.3457 |\n| kobest_copa | 49.30% | 0.4921 |\n| kobest_hellaswag | 21.60% | 0.2153 |\n| kobest_sentineg | 48.61% | 0.4737 |\n| kobest_wic | 48.65% | 0.3286 |\n| **평균** | **43.69%** | |\n\n#### HAE-RAE (0-shot) — 전체 19.71%\n\n| 서브태스크 | Accuracy |\n|-----------|----------|\n| haerae_general_knowledge | 21.59% |\n| haerae_history | 23.40% |\n| haerae_loan_word | 21.30% |\n| haerae_rare_word | 18.77% |\n| haerae_standard_nomenclature | 13.73% |\n| **전체** | **19.71%** |\n\n#### MMLU-KO (0-shot) — 6카테고리 평균 22.75%\n\n| 카테고리 | Accuracy |\n|----------|----------|\n| medical | 30.56% |\n| humanities | 24.51% |\n| business | 24.14% |\n| social_sciences | 20.59% |\n| other | 19.64% |\n| stem | 19.57% |\n| **평균** | **22.75%** |\n\n\u003e Base model은 instruction-following 없이 4지선다 형식 벤치마크를 풀도록 최적화되지 않음. KoBEST boolq/copa/sentineg/wic는 ~50% 수준으로 2지/4지선다 랜덤 기준 부근이며, SFT 후 향상 기대.\n\n### 10.4 영어 벤치마크\n\n#### 주요 벤치마크 (0-shot)\n\n| 태스크 | Accuracy | Acc (norm) |\n|--------|----------|-----------|\n| hellaswag | 26.00% | 26.15% |\n| arc_easy | 25.63% | 26.64% |\n| arc_challenge | 21.67% | 27.90% |\n| winogrande | 50.59% | — |\n| piqa | 52.50% | 48.31% |\n\n\u003e winogrande(50.59%)와 piqa(52.50%)는 2지선다로 랜덤 기준 50%에 근접. hellaswag/arc는 4지선다로 랜덤 기준 25%.\n\n#### MMLU-EN (0-shot) — 61과목 평균 25.81%\n\n**상위 10개 과목**:\n\n| 과목 | Accuracy |\n|------|----------|\n| college_physics | 37.25% |\n| college_computer_science | 34.00% |\n| high_school_statistics | 33.80% |\n| us_foreign_policy | 32.00% |\n| security_studies | 31.43% |\n| world_religions | 30.99% |\n| professional_medicine | 30.88% |\n| high_school_government_and_politics | 30.57% |\n| jurisprudence | 30.56% |\n| human_sexuality | 30.53% |\n\n**하위 5개 과목**:\n\n| 과목 | Accuracy |\n|------|----------|\n| human_aging | 19.73% |\n| college_biology | 19.44% |\n| anatomy | 17.04% |\n| global_facts | 17.00% |\n| abstract_algebra | 15.00% |\n\n### 10.5 Calibration\n\n| 메트릭 | 값 |\n|--------|-----|\n| Top-1 Accuracy | 68.75% |\n| Top-5 Accuracy | 81.64% |\n| Top-10 Accuracy | 85.93% |\n| Mean Correct Prob | 0.6152 |\n| Mean Entropy | 1.5682 |\n\n**Token NLL 분포**:\n\n| 통계 | 값 |\n|------|-----|\n| 평균 NLL | 1.5561 |\n| 표준편차 | 2.4926 |\n| 중앙값 | 0.1221 |\n| p95 | 7.0312 |\n| p99 | 10.3125 |\n| NLL \u003e 5 비율 | 10.86% |\n| NLL \u003e 10 비율 | 1.18% |\n\n\u003e Top-1 68.75%는 모델이 가장 확신하는 예측이 ~69% 확률로 정확하다는 의미. 중앙값 NLL 0.12 (≈ e^0.12 = 1.13 PPL)로 대부분의 토큰을 매우 높은 확신도로 예측하고, 소수의 고난이도 토큰이 평균 NLL을 끌어올리는 전형적인 분포.\n\n### 10.6 0-shot vs 5-shot 비교\n\n18개 한국어 태스크에서 0-shot과 5-shot 성능을 비교했다.\n\n| 태스크 | 0-shot | 5-shot | 변화 |\n|--------|--------|--------|------|\n| global_mmlu_ko | 22.75% | 26.75% | **+4.00pp** |\n| global_mmlu_ko_business | 24.14% | 31.03% | **+6.90pp** |\n| global_mmlu_ko_humanities | 24.51% | 28.43% | +3.92pp |\n| global_mmlu_ko_medical | 30.56% | 36.11% | **+5.56pp** |\n| global_mmlu_ko_other | 19.64% | 23.21% | +3.57pp |\n| global_mmlu_ko_social_sciences | 20.59% | 23.53% | +2.94pp |\n| global_mmlu_ko_stem | 19.57% | 21.74% | +2.17pp |\n| haerae | 19.71% | 20.26% | +0.55pp |\n| haerae_general_knowledge | 21.59% | 22.73% | +1.14pp |\n| haerae_history | 23.40% | 14.89% | -8.51pp |\n| haerae_loan_word | 21.30% | 24.26% | +2.96pp |\n| haerae_rare_word | 18.77% | 18.02% | -0.74pp |\n| haerae_standard_nomenclature | 13.73% | 25.49% | **+11.76pp** |\n| kobest_boolq | 50.28% | 50.21% | -0.07pp |\n| kobest_copa | 49.30% | 46.80% | -2.50pp |\n| kobest_hellaswag | 21.60% | 20.80% | -0.80pp |\n| kobest_sentineg | 48.61% | 47.86% | -0.76pp |\n| kobest_wic | 48.65% | 48.97% | +0.32pp |\n\n**평균 변화: +1.80pp** | 개선: 12 | 하락: 6\n\n\u003e MMLU-KO는 5-shot에서 일관되게 개선(+2~7pp)되어 in-context learning 능력이 작동함을 확인. KoBEST는 거의 변동 없거나 소폭 하락—이미 0-shot에서 패턴 매칭을 잘하고 있어 few-shot 예시가 오히려 방해가 되는 패턴. haerae_standard_nomenclature의 +11.76pp는 이 태스크의 특수한 포맷을 few-shot에서 학습한 결과.\n\n### 10.7 참고 모델 비교\n\n| 모델 | 파라미터 | MMLU-KO | MMLU-EN | KoBEST 평균 | PPL |\n|------|---------|---------|---------|------------|-----|\n| **FRANKENSTALLM 3B** | **3B** | **22.75%** | **25.81%** | **43.69%** | **5.2263** |\n| Llama-3.2-3B | 3B | ~42% | ~58% | ~55% | — |\n| Qwen2.5-3B | 3B | ~48% | ~65% | ~60% | — |\n| EXAONE-3.5-2.4B | 2.4B | ~35% | ~50% | ~50% | — |\n\n\u003e 참고 모델들은 수조 토큰 규모의 학습 데이터와 수천 GPU-hour를 투입한 결과. FRANKENSTALLM 3B는 41.12B 토큰(Chinchilla 최적의 ~68%), 63시간, 8 GPU로 학습한 점을 감안해야 한다. SFT + 확장 프리트레인(80-100B 토큰) 이후 격차 축소 예상.\n\n### 10.8 생성 품질 및 파라미터 그리드 서치\n\n#### 반복률 요약\n\n| 설정 | 3-gram 반복률 | 4-gram 반복률 |\n|------|--------------|--------------|\n| greedy (temp=0.0) | 60.99% | 57.02% |\n| temp=0.5 | 60.12% | 58.68% |\n| temp=0.7 | 47.69% | 43.40% |\n| temp=1.0 | 3.58% | 2.81% |\n\n\u003e 초기 v1 평가의 greedy 71.1% 반복률은 `no_repeat_ngram_size=3` 적용 기준이었다. v2에서는 미적용 기준(raw)으로 통일하여 60.99%를 기록.\n\n#### 12조합 파라미터 그리드 서치 결과\n\n| 설정 | Temp | Rep Pen | 3-gram | 4-gram | 비고 |\n|------|------|---------|--------|--------|------|\n| **t0.7_rep1.3** | **0.70** | **1.30** | **0.00%** | **0.00%** | **최적** |\n| t0.9_rep1.2 | 0.90 | 1.20 | 0.00% | 0.00% | 차선 |\n| t0.7_rep1.2 | 0.70 | 1.20 | 0.88% | 0.00% | |\n| t0.9_rep1.1 | 0.90 | 1.10 | 0.94% | 0.13% | |\n| t1.0_rep1.1 | 1.00 | 1.10 | 1.21% | 0.48% | |\n| t0.5_rep1.1 | 0.50 | 1.10 | 1.92% | 1.19% | |\n| t1.0 | 1.00 | 1.00 | 3.58% | 2.81% | |\n| t0.9 | 0.90 | 1.00 | 8.39% | 4.64% | |\n| t0.7_rep1.1 | 0.70 | 1.10 | 8.51% | 5.51% | |\n| t0.7 | 0.70 | 1.00 | 47.69% | 43.40% | |\n| t0.5 | 0.50 | 1.00 | 60.12% | 58.68% | |\n| greedy | 0.00 | 1.00 | 60.99% | 57.02% | |\n\n#### 권장 추론 파라미터 (base 실험용)\n\n```python\n# v2 그리드 서치 최적값\ntemp=0.7, repetition_penalty=1.3\n# 또는 (더 다양한 생성)\ntemp=0.9, repetition_penalty=1.2\n```\n\n\u003e 초기 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`만으로 충분히 반복 제거가 가능함을 확인하여 불필요.\n\n### 10.9 평가 파이프라인\n\nv2 재평가는 모듈화된 8-GPU 병렬 파이프라인(`eval/reeval_pipeline.py`)으로 수행되었다.\n\n#### 아키텍처\n\n```\nreeval_pipeline.py\n├── 모델 1회 로드 (GPU 0에 HF 모델)\n├── Phase 1: PPL 평가 (19개 데이터셋, 순차)\n├── Phase 2: Calibration + Token NLL\n├── Phase 3: 생성 품질 + 파라미터 그리드 서치 (12조합)\n├── Phase 4: lm-evaluation-harness (0-shot, 8-GPU 병렬)\n├── Phase 5: lm-evaluation-harness (5-shot, 8-GPU 병렬)\n└── Phase 6: 리포트 자동 생성 (5개 개별 + 1개 종합)\n```\n\n#### Pipeline Mode\n\n모델을 1회 로드하여 0-shot과 5-shot을 연속 실행한다. 기존 방식(별도 프로세스 2회)에 비해 모델 로딩 시간을 절반으로 줄인다.\n\n#### GPU별 태스크 분배\n\n| GPU | 0-shot 태스크 | 5-shot 태스크 |\n|-----|--------------|--------------|\n| 0 | kobest_boolq, kobest_copa, kobest_hellaswag | 동일 |\n| 1 | kobest_sentineg, kobest_wic | 동일 |\n| 2 | haerae (전체 + 5개 서브) | 동일 |\n| 3 | global_mmlu_ko (6카테고리) | 동일 |\n| 4 | hellaswag, arc_easy | 동일 |\n| 5 | arc_challenge, winogrande | 동일 |\n| 6 | piqa, global_mmlu_en (61과목) | 동일 |\n| 7 | (예비 — PPL/calibration 전담) | — |\n\nNUMA affinity 적용: GPU 0-3은 NUMA node 0 (cores 0-35), GPU 4-7은 NUMA node 1 (cores 36-71).\n\n**총 소요 시간: 256.6초** (모델 로드 포함)\n\n### SFT 진행 판단\n\n**결론: SFT 진행** — loss 1.466 건강한 완료 시그널, 구조 문제 없음. → **Phase 2 SFT 시작 (2026-03-05)**\n\n상세 보고서:\n- v2 종합: `eval/outputs/3b_reeval_20260305_1451/reports/` (5개 개별 리포트 + 종합)\n- v1 레거시: `reports/2026-03-05_3B_BASE_EVALUATION_REPORT.md`\n\n---\n\n## 11. 실험 결과 — 3B SFT 종합 평가\n\nPhase 2 SFT가 early stopping으로 완료된 후 수행한 6차원 종합 평가.\n\n### 11.1 SFT 학습 결과\n\n| 항목 | 값 |\n|------|-----|\n| 최종 Step | 25,500 / 33,000 (77.3%, early stopping) |\n| Best val_loss | **1.8851** (step 23,000) |\n| 학습 시간 | ~15시간 41분 |\n| 데이터 | 24개 소스 → 2,439,397 samples (7.48 GB) |\n| 설정 | LR=1e-5, eff_batch=64, NEFTune alpha=5.0 |\n\n**Val Loss 추이**:\n```\nStep     500: 2.0732 (warmup 완료)\nStep   2,000: 1.9558 (급속 하강)\nStep   5,000: 1.9107 (안정 수렴)\nStep  10,000: 1.8917 (미세 감소)\nStep  15,000: 1.8864 (plateau 진입)\nStep  20,000: 1.8853 (변동 \u003c 0.001)\nStep  23,000: 1.8851 ← BEST (early stopping 기준점)\nStep  25,500: Early Stop (patience 5/5 소진)\n```\n\n### 11.2 6차원 평가 요약\n\n| # | 차원 | 결과 | 핵심 수치 |\n|---|------|------|-----------|\n| 1 | Perplexity (지식 보존) | **PASS** | 최대 forgetting 0.9%, 19개 데이터셋 전체 PASS |\n| 2 | 생성 품질 | **FAIL** | Greedy 반복률 72.97% (목표 \u003c5%), EOS 60% (목표 \u003e90%) |\n| 3 | 한국어 벤치마크 | **FAIL** | KoBEST 평균 43.26% (목표 \u003e55%) |\n| 4 | 영어 벤치마크 | **PASS** | hellaswag 26.1%, winogrande 50.8%, piqa 52.6% (전 항목 하한 초과) |\n| 5 | Calibration | **PASS** | Top-1 68.59%, Top-5 81.55%, Entropy 1.54 |\n| 6 | SFT Chat 능력 | **PASS** | EOS 종료율 0%→60%, Chat template 응답 |\n\n### 11.3 Base vs SFT 비교\n\n| 지표 | Base | SFT | 변화 | 판정 |\n|------|------|-----|------|------|\n| PPL (통합) | 5.2263 | 5.2529 | +0.5% forgetting | PASS |\n| Greedy 3-gram 반복률 | 60.99% | 72.97% | +12pp (악화) | FAIL |\n| EOS 종료율 | 0% | 60% | +60pp (대폭 개선) | 부분 PASS |\n| KoBEST 평균 | 43.69% | 43.26% | -0.4pp | FAIL |\n| MMLU-KO | 22.75% | 26.00% | +3.2pp | 부분 개선 |\n| 영어 벤치마크 | — | — | ±0.3pp 이내 | PASS (유지) |\n| Calibration Top-1 | 68.75% | 68.59% | -0.2pp | PASS (유지) |\n\n**Repetition 파라미터 검색** (희망적):\n\n| 설정 | 반복률 | EOS Rate |\n|------|--------|----------|\n| t0.7_rep1.2 | **0.00%** | **100%** |\n| t1.0_rep1.1 | **0.00%** | **100%** |\n| greedy (raw) | 72.97% | 60% |\n\n\u003e rep_penalty 1.1~1.3 적용 시 반복률 0% 달성 → 모델이 반복하지 않는 능력 자체는 보유. ORPO로 내재화 가능.\n\n### 11.4 코드 개선 사항\n\n이번 Phase에서 수행한 주요 코드 변경:\n\n| 파일 | 변경 | 줄 수 | 목적 |\n|------|------|-------|------|\n| `train/sft.py` | MixingDataLoader, DDP rank 0 토크나이징 | +238 | SFT+pretrain 인터리빙, 메모리 8배 절감 |\n| `train/trainer.py` | DDP early stop broadcast | +17 | DDP hang 방지, patience 5→10 |\n| `train/orpo.py` | YAML config, 3B 기본값 | +30 | ORPO 실행 준비 |\n| `eval/report_generator.py` | SFT 비교 보고서 자동 생성 | +831 | 평가 자동화 |\n| `eval/sft_eval_pipeline.py` | 6차원 평가 파이프라인 | 신규 | SFT 종합 평가 |\n| `eval/tasks/generation_task.py` | Chat template, diversity metrics | +75 | SFT 평가 지원 |\n\n### 11.5 ORPO 진행 판정\n\n**판정: Phase 3 ORPO 진행**\n\n| 근거 | 상세 |\n|------|------|\n| 지식 보존 양호 | forgetting 0.9% — SFT가 base 지식을 파괴하지 않음 |\n| 반복 미해결 | greedy 72.97% — 선호도 정렬이 직접적 해결 경로 |\n| 희망적 신호 | rep_penalty 적용 시 0% → ORPO가 내재화 가능 |\n| 데이터 준비 완료 | 795,468 preference pairs (7.9 GB) |\n| 코드/설정 완비 | `train/orpo.py` + `configs/korean_3b_orpo.yaml` |\n\n**ORPO 후 판정 기준**:\n- 반복률 \u003c 5% AND KoBEST \u003e 50% → GGUF + Ollama 배포\n- 반복률 5~15% → 하이퍼파라미터 조정 후 재시도\n- 반복률 \u003e 15% → SFT v2 (lr=5e-5, data mixing) 후 재도전\n\n상세: `reports/2026-03-06_3B_SFT_COMPLETION_AND_EVAL_SUMMARY.md`\n\n---\n\n## 12. Phase 3 — ORPO (선호도 정렬)\n\n### 12.1 ORPO 선택 배경\n\nSFT 6차원 평가에서 greedy 반복률 72.97%, EOS 종료율 0%라는 치명적 문제가 발견됐다. SFT는 \"좋은 응답만 모방\"하는 학습이므로, \"나쁜 응답을 억제\"하는 신호가 없다. 반복 문제 해결에는 preference optimization이 필수적이다.\n\n**ORPO vs DPO**:\n| 항목 | ORPO | DPO |\n|------|------|-----|\n| Reference model | 불필요 | 필요 (VRAM 2배) |\n| 구현 복잡도 | 낮음 | 중간 |\n| 메모리 효율 | 높음 (3B 1개만 로드) | 낮음 (3B 2개 로드) |\n| 학습 안정성 | 중간 | 높음 |\n\nORPO를 1차 선택, DPO를 Plan B로 설정했다.\n\n### 12.2 데이터\n\n- **원본**: 683,181 preference pairs (7개 소스 통합)\n- **필터 후**: ~630,000 pairs (NaN 방지 필터 적용)\n- **Eval split**: 5% (~31,500 pairs, seed=42)\n- **Effective batch**: 4 × 8 GPU × 4 accum = 128\n\n### 12.3 HP Sweep 설계 (6-Config)\n\n3개 축(beta, LR, max_length)을 중심축 고정 방식으로 6개 조합 선정:\n\n| Run | Name | Beta | LR | Max Length | 목적 |\n|-----|------|------|----|-----------|------|\n| 1 | baseline_b015 | 0.15 | 8e-6 | 1536 | 약한 beta 베이스라인 |\n| 2 | baseline_b025 | 0.25 | 8e-6 | 1536 | 중간 beta 베이스라인 |\n| 3 | strong_b035 | 0.35 | 8e-6 | 1536 | 강한 beta — 적극적 반복 억제 |\n| 4 | fast_lr12e6 | 0.25 | 1.2e-5 | 1536 | 높은 LR — 빠른 수렴 |\n| 5 | conserv_lr5e6 | 0.25 | 5e-6 | 1536 | 보수적 LR — 안정성 |\n| 6 | short_1024 | 0.25 | 8e-6 | 1024 | 짧은 max_length — VRAM 절약 |\n\n각 200 steps, eval_steps=100, 8×B200 DDP.\n\n### 12.4 시도 이력 — 5번의 실패\n\n| # | 문제 | 원인 | 수정 |\n|---|------|------|------|\n| 1 | NCCL Timeout | 토크나이징 30분 \u003e timeout 1800s | ddp_timeout=7200, num_proc=64 |\n| 2 | Config 충돌 | save_steps ≠ eval_steps 배수 | --no_load_best --save_steps 200 |\n| 3 | 포트 충돌 + QKV 누락 | 좀비 프로세스 + fused QKV 미분리 | pkill + QKV split 로직 |\n| 4 | TRL NaN 버그 | tokenize_row 양쪽 response 동시 잘림 | 3중 패치 (clamp, truncation) |\n| 5 | Tokenizer 호환 | zip(strict=True) + 한국어 merge ops | TRL 소스 8건 패치 |\n\n가장 심각했던 것은 TRL NaN 버그로, 0 response tokens → log(0) = -inf → NaN 전파 체인을 일으켰다. 상세: `reports/2026-03-08_ORPO_TRAINING_JOURNEY.md`\n\n### 12.5 스윕 최종 결과\n\n| Run | Name | Beta | LR | MaxLen | Train Loss | Eval Loss | Margin | Status |\n|-----|------|------|----|--------|-----------|-----------|--------|--------|\n| 1 | baseline_b015 | 0.15 | 8e-6 | 1536 | 1.811 | 1.827 | 0.004 | ✅ |\n| 2 | baseline_b025 | 0.25 | 8e-6 | 1536 | 1.890 | 1.906 | 0.009 | ✅ |\n| 3 | strong_b035 | 0.35 | 8e-6 | 1536 | 2.055 | 1.985 | 0.007 | ✅ |\n| **4** | **fast_lr12e6** | **0.25** | **1.2e-5** | **1536** | **1.917** | **1.862** | **0.009** | **🏆 Best** |\n| 5 | conserv_lr5e6 | 0.25 | 5e-6 | 1536 | 1.833 | 1.910 | 0.004 | ✅ |\n| 6 | short_1024 | 0.25 | 8e-6 | 1024 | 1.664 | 1.695 | 0.007 | ✅ |\n\n**Best config: Run 4** (eval_loss 1.862 최저, margin 0.009 최고, 빠른 수렴).\n\n### 12.6 Throughput 벤치마크 → 본 학습 설정\n\n본 학습 전 batch/grad_accum 조합의 throughput을 측정하여 최적 설정을 결정:\n\n| batch_size | grad_accum | eff_batch | Throughput | 비고 |\n|-----------|-----------|----------|-----------|------|\n| **4** | **4** | **128** | **80.63 samples/s** | **선정** |\n| 2 | 8 | 128 | 73.14 samples/s | 기존 설정 |\n| 8 | 2 | 128 | OOM | |\n\n### 12.7 ORPO 본 학습 (완료)\n\n| 파라미터 | 값 |\n|---------|-----|\n| Beta / LR | 0.25 / 1.2e-5 (Sweep Run 4) |\n| Batch / Accum / Eff | 4 / 4 / 128 (벤치마크 최적) |\n| Max length | 1536 |\n| Epochs | 2 (~9,840 steps) |\n| GPU VRAM | ~52GB / 183GB (28%) |\n| 속도 | ~1.75 s/step |\n| 예상 시간 | ~4.8시간 |\n\n**학습 지표 추이 (step ~1,660 기준)**:\n\n| Step | Eval Loss | Pref Accuracy | Reward Margin | NLL Loss |\n|-----:|----------:|--------------:|--------------:|---------:|\n| ~1,000 | 1.791 | 66.8% | 0.107 | 1.647 |\n| ~2,000 | 1.713 | 70.1% | 0.293 | 1.591 |\n| ~3,000 | 1.681 | 71.9% | 0.372 | 1.567 |\n\n- Train loss: 2.34 → **1.68** (-0.66)\n- rewards/accuracies: 0.43 → **0.74** (chosen/rejected 구분 능력 급상승)\n- rewards/margins: -0.005 → **0.387** (preference signal 학습 확인)\n- 속도 ~1.76 s/step, GPU 92~100% utilization, 안정적 진행 중\n\n**학습 완료 후 자동 평가**: `scripts/orpo_eval_watchdog.sh` 가 학습 프로세스를 감시하며, 완료 시 자동으로 10차원 종합 평가 파이프라인 실행\n\n### 12.8 ORPO 종합 평가 파이프라인\n\nSFT v2 평가의 6차원에 ORPO 고유 4차원을 추가한 **10차원 종합 평가**.\n학습 완료 시 `eval/orpo_eval_pipeline.py`가 자동 실행되어 Base vs SFT vs ORPO 3-way 비교 보고서를 생성한다.\n\n**평가 구조**:\n\n| Phase | 내용 | GPU | 예상 시간 |\n|-------|------|-----|----------|\n| Pre-phase | train.log에서 학습 곡선 추출 | - | ~1초 |\n| Phase 1 | 내부 평가 (PPL 19셋, Calibration, Generation, Repetition Grid) | 8 GPU 병렬 | ~30분 |\n| Phase 2 | 벤치마크 (KoBEST, HAE-RAE, MMLU-KO/EN, hellaswag, arc, piqa) | 8 GPU 병렬 | ~1시간 |\n| Phase 3 | 3-way 비교 보고서 자동 생성 | - | ~10초 |\n\n**10차원 평가 항목**:\n\n| # | 차원 | 기준 | SFT v2 결과 | ORPO 목표 |\n|---|------|------|------------|----------|\n| 1 | 지식 보존 (PPL) | forgetting \u003c 15% | 0.9% | \u003c 5% |\n| 2 | 생성 품질 | greedy 반복률 \u003c 5%, EOS \u003e 90% | **72.97% / 60%** | **\u003c 5% / \u003e 90%** |\n| 3 | 한국어 벤치마크 | KoBEST 평균 \u003e 55% | 43.26% | ≥ 43% |\n| 4 | 영어 벤치마크 | 하한 초과 | PASS | 유지 |\n| 5 | Calibration | Top-1 ≥ 65% | 68.59% | ≥ 65% |\n| 6 | Chat 능력 | EOS 종료율 | 60% | \u003e 90% |\n| 7 | Preference Accuracy | \u003e 65% | — | \u003e 65% |\n| 8 | Reward Margins | \u003e 0.1 | — | \u003e 0.1 |\n| 9 | 반복 파라미터 민감도 | rep_penalty=1.0에서도 \u003c 5% | — | PASS |\n| 10 | SFT→ORPO 개선 | 반복률↓ + EOS↑ | — | PASS |\n\n**핵심 파일**:\n- `eval/orpo_eval_pipeline.py` — ORPO 평가 오케스트레이터\n- `eval/report_generator.py` — 3-way 비교 보고서 생성기 (`generate_three_way_report()`)\n- `scripts/orpo_eval_watchdog.sh` — 학습 완료 감지 + 자동 평가 실행\n\n**배포 기준**: greedy 반복률 \u003c 5% AND EOS \u003e 90% AND forgetting \u003c 5% AND KoBEST ≥ 43% → **DEPLOY**\n\n---\n\n## 13. 실행 방법\n\n### 사전 요구사항\n\n```bash\n# PyTorch는 재설치 금지 (NVIDIA 커스텀 빌드)\n# 아래 패키지만 추가 설치\npip install transformers accelerate peft trl deepspeed \\\n            bitsandbytes sentencepiece wandb\n```\n\n### 3B 프리트레인\n\n```bash\n# NCCL 환경변수와 함께 8-GPU 학습 실행\nbash scripts/launch_3b_pretrain.sh\n\n# 수동 실행 (직접 제어)\ntorchrun --nproc_per_node=8 \\\n  --master_port=29500 \\\n  train/pretrain.py \\\n  --config configs/korean_3b_fp8.yaml\n```\n\n### SFT\n\n```bash\nbash scripts/launch_3b_sft.sh\n\n# 또는 직접 실행\ntorchrun --nproc_per_node=8 \\\n  train/sft.py \\\n  --config configs/korean_3b_sft.yaml \\\n  --pretrain_ckpt checkpoints/3b_pretrain_best.pt\n```\n\n### ORPO (선호도 정렬)\n\n```bash\n# ORPO 학습\nbash scripts/launch_3b_orpo.sh\n\n# 학습 완료 후 자동 평가 (watchdog)\nnohup bash scripts/orpo_eval_watchdog.sh \\\n  \u003e checkpoints/korean_3b_orpo_v1/watchdog.log 2\u003e\u00261 \u0026\n```\n\n### 평가\n\n```bash\n# Base 모델 전체 평가 (8 GPU 병렬)\npython eval/full_eval_pipeline.py\n\n# SFT 모델 평가 (Base vs SFT 2-way 비교)\npython eval/sft_eval_pipeline.py --skip-phase0 \\\n  --hf-model-path eval/outputs/hf_3b_sft_best\n\n# ORPO 모델 평가 (Base vs SFT vs ORPO 3-way 비교)\npython eval/orpo_eval_pipeline.py           # 자동으로 최신 checkpoint 감지\npython eval/orpo_eval_pipeline.py --dry-run  # 실행 계획만 확인\n\n# 빠른 평가 (kobest_copa + PPL)\nbash scripts/run_eval_quick.sh\n\n# 생성 파라미터 탐색\npython eval/test_generation_params.py \\\n  --checkpoint checkpoints/3b_best.pt\n```\n\n### 배포\n\n```bash\n# Step 1: GGUF 변환 (llama.cpp 포맷)\nbash scripts/convert_3b_gguf.sh\n\n# Step 2: Ollama 모델 등록 및 서빙\nbash scripts/deploy_3b_ollama.sh\n\n# Ollama로 테스트\nollama run frankenstallm-3b \"한국의 철강 산업에 대해 설명해줘.\"\n```\n\n### 학습 모니터링\n\n```bash\n# 실시간 모니터 (tail -f 방식)\nbash scripts/monitor_3b.sh\n\n# 프로세스 상태 확인\nps aux | grep pretrain\n\n# GPU 상태\nnvidia-smi --query-gpu=index,name,memory.used,memory.total,utilization.gpu \\\n  --format=csv -l 5\n```\n\n### 단일 GPU 테스트 (개발/디버그)\n\n```bash\npython train/pretrain.py \\\n  --config configs/korean_3b_fp8.yaml \\\n  --device cuda:0 \\\n  --max_steps 100 \\\n  --debug\n```\n\n---\n\n## 14. 로드맵\n\n### 단기 (2026년 3월)\n\n| 항목 | 상태 | 비고 |\n|------|------|------|\n| Phase 1 (3B Pretrain) 완료 | ✅ 완료 | 57K steps, loss 1.466, 2026-03-05 |\n| Phase 2 (SFT) 완료 | ✅ 완료 | 25.5K steps, val_loss 1.8851, 2026-03-06 |\n| SFT 6차원 평가 | ✅ 완료 | 4/6 PASS, ORPO 판정 |\n| Phase 3 (ORPO Sweep) | ✅ 완료 | 6-config sweep 완료, best config 선정 |\n| **Phase 3 (ORPO 본 학습)** | **✅ 완료** | **9,997 steps, eval_loss 1.625, pref_acc 76.02%** |\n| Phase 3.5 (ORPO 종합 평가) | ✅ 완료 | 7/10 PASS, 3-way 비교 완료 |\n| GGUF 변환 + Ollama 배포 | ✅ 완료 | byte-fallback 수정, Q4_K_M/Q8_0/f16, HF + Ollama 배포 |\n\n### 중기 (2026년 2분기)\n\n| 항목 | 비고 |\n|------|------|\n| 확장 프리트레인 (80~100B 토큰) | Chinchilla 최적점 달성 |\n| QKV Fusion | +8~12% MFU 기대 |\n| NUMA Affinity 설정 | +4~9% 예상 |\n| FA2 native RoPE | +3~5% 예상 |\n| Context length 확장 (4096) | RoPE θ=500K 기반 |\n\n### 장기 (2026년 하반기)\n\n| 항목 | 비고 |\n|------|------|\n| 7B 실험 | FSDP 전략 필요 |\n| vLLM serving | PagedAttention 기반 추론 서버 |\n| 도메인 특화 파인튜닝 | 철강/제조업 도메인 |\n| 공개 배포 | HuggingFace Hub 업로드 |\n\n### 알려진 미적용 최적화\n\nPhase 0 분석에서 발견했지만 아직 적용하지 않은 최적화들:\n\n| 최적화 | 예상 효과 | 구현 복잡도 |\n|--------|-----------|-------------|\n| QKV Fusion | +8~12% MFU | 중간 |\n| NUMA Affinity | +4~9% | 낮음 |\n| FA2 Native RoPE | +3~5% | 낮음 |\n| HugePages | +1~3% (TLB 최적화) | 낮음 (sysctl) |\n\n이 최적화들을 모두 적용하면 현재 33.5% MFU에서 45~50%까지 도달할 가능성이 있다.\n\n---\n\n## 15. 참고 문서\n\n| 문서 | 위치 | 내용 |\n|------|------|------|\n| 프로젝트 전체 여정 | `docs/PROJECT_HISTORY.md` | 일별 상세 진행 기록 |\n| 3B 작업 계획 | `docs/3B_WORKPLAN.md` | 3B 단계별 작업 계획 상세 |\n| 저스티스리그 논증 | `eval/debate/justice_league_3b_case.md` | 1B→3B 전환 멀티에이전트 토론 전문 |\n| SFT 재시작 판결 | `eval/decision/FINAL_DECISION_REPORT.md` | SFT v1 실패 → v2 설계 판결문 |\n| 3B 마스터 플랜 | `eval/plan/3B_MASTER_PLAN.md` | 전체 학습 파이프라인 마스터 플랜 |\n| Phase 0 최적화 보고서 | `reports/2026-03-02_0200_FRANKENSTALLM_phase0_optimization_report.md` | VRAM/MFU 최적화 전체 보고 |\n| 3B Base 평가 보고서 (v1) | `reports/2026-03-05_3B_BASE_EVALUATION_REPORT.md` | 초기 PPL/벤치마크/반복률 평가 |\n| PPL 평가 보고서 (v1) | `reports/2026-03-05_PPL_EVALUATION.md` | 4개 검증셋 PPL 상세 |\n| 벤치마크 결과 (v1) | `reports/2026-03-05_BENCHMARK_RESULTS.md` | belebele, MMLU 상세 |\n| 생성 품질 분석 (v1) | `reports/2026-03-05_GENERATION_QUALITY.md` | 반복률, 디코딩 파라미터 |\n| SFT 학습 보고서 | `reports/2026-03-05_3B_SFT_PROGRESS_REPORT.md` | Phase 2 SFT 학습 과정 기록 |\n| **SFT 완료 종합 보고서** | `reports/2026-03-06_3B_SFT_COMPLETION_AND_EVAL_SUMMARY.md` | **SFT 완료 + 평가 + 코드 개선 + ORPO 결정 (최신)** |\n| SFT 평가 계획서 | `reports/2026-03-06_3B_SFT_EVAL_PLAN.md` | 6차원 평가 설계 |\n| SFT 평가 결과 | `reports/2026-03-06_3B_SFT_EVALUATION_REPORT.md` | 6차원 평가 상세 결과 |\n| 3B 후속 단계 참조 | `reports/2026-03-05_3B_NEXT_STEPS_REFERENCE.md` | SFT 후 방향성 |\n| Nemotron Nano 타당성 | `reports/2026-03-05_NEMOTRON_NANO_FEASIBILITY_STUDY.md` | Hybrid 아키텍처 검토 |\n| **v2 종합 평가 리포트** | `eval/outputs/3b_reeval_20260305_1451/full_eval_report.md` | **13+ 벤치마크 종합** |\n| v2 PPL 리포트 | `eval/outputs/3b_reeval_20260305_1451/reports/01_perplexity_report.md` | 19개 데이터셋 PPL 상세 |\n| v2 Calibration 리포트 | `eval/outputs/3b_reeval_20260305_1451/reports/02_calibration_report.md` | Top-K 정확도, NLL 분포 |\n| v2 생성 품질 리포트 | `eval/outputs/3b_reeval_20260305_1451/reports/03_generation_quality.md` | 12조합 파라미터 그리드 서치 |\n| v2 벤치마크 리포트 | `eval/outputs/3b_reeval_20260305_1451/reports/04_benchmark_report.md` | KoBEST, HAE-RAE, MMLU, 0/5-shot |\n| 진행 기록 | `PROGRESS.md` | 날짜별 체크포인트, 지표, 결정 로그 |\n| **ORPO 분석 및 계획** | `reports/2026-03-07_ORPO_ANALYSIS_AND_PLAN.md` | **ORPO 진행 근거, HP 설계, 실행 절차** |\n| **ORPO Sweep 디버그** | `reports/2026-03-08_ORPO_SWEEP_DEBUG_REPORT.md` | **QKV 버그, NCCL timeout, TRL 패치 상세** |\n| **ORPO 학습 여정** | `reports/2026-03-08_ORPO_TRAINING_JOURNEY.md` | **ORPO 전체 과정: 5번의 실패와 HP sweep (최신)** |\n\n---\n\n## 16. 기술 스택 요약\n\n| 영역 | 기술 | 버전 |\n|------|------|------|\n| 딥러닝 프레임워크 | PyTorch (NVIDIA 커스텀 빌드) | nv25.12 |\n| 어텐션 | FlashAttention-2 | 2.7.4.post1+25.12 |\n| FP8 / 혼합 정밀도 | TransformerEngine (MXFP8) | 2.10.0 |\n| 분산 학습 | DDP + NCCL (NVLS) | NCCL 2.28.9 |\n| 커널 컴파일 | Triton | 3.5.1 |\n| 토크나이저 | SentencePiece Unigram 64K | - |\n| 모니터링 | Telegram Bot (B200Bot) + cron watchdog | - |\n| 추론 서빙 | GGUF + Ollama | - |\n| GPU | 8× NVIDIA B200 (NVLink 5.0, NVSwitch) | CUDA 13.1 |\n| CPU | 2× AMD EPYC 9365 (Zen 5) | - |\n\n---\n\n## 관련 프로젝트\n\n### [EVAFRILL-Mo](https://github.com/pathcosmos/EVAFRILL-Mo) | [🤗 HuggingFace](https://huggingface.co/pathcosmos/EVAFRILL-Mo-3B)\n\n**하이브리드 Mamba-2 + Transformer 언어 모델** — FRANKENSTALLM의 자매 프로젝트.\n\nNVIDIA [Nemotron-H](https://arxiv.org/abs/2504.03624) 아키텍처에서 영감을 받아 밑바닥부터 직접 구현한 3B 하이브리드 모델이다. FRANKENSTALLM이 순수 Transformer 기반이라면, EVAFRILL-Mo는 **Mamba-2 SSM + 희소 Transformer 어텐션** 하이브리드 구조를 채택했다.\n\n| 항목 | FRANKENSTALLM | EVAFRILL-Mo |\n|------|:---:|:---:|\n| 아키텍처 | 순수 Transformer (28L) | Mamba-2 24L + Attention 2L |\n| 파라미터 | 3.17B | 2.94B |\n| 핵심 기술 | GQA, FP8, FlashAttention-2 | Selective Scan, SwiGLU FFN in Mamba, GQA |\n| 설계 원칙 | 검증된 Transformer 아키텍처 | Nemotron-H 단편화 도입 |\n| GPU | 8× B200 | 7× B200 |\n| 학습 전략 | Chinchilla-optimal | Chinchilla 93% 달성 목표 |\n\n두 프로젝트는 동일한 토크나이저(64K SentencePiece), 학습 데이터 파이프라인, DDP/FP8 인프라를 공유한다. \"같은 재료, 다른 레시피\"로 아키텍처 차이가 성능에 미치는 영향을 비교 실험할 수 있다.\n\n\u003e *이름의 유래: Bride **Eva** (프랑켄슈타인의 신부) + **FRI**DAY (아이언맨 AI 비서) + **LL**M + Nemotron의 **Mo***\n\n---\n\n## 18. 다음 최적화 계획 — MFU 33.5% → 47% 목표\n\n\u003e 상세 문서: [`docs/NEXT_OPTIMIZATION_PLAN.md`](docs/NEXT_OPTIMIZATION_PLAN.md)\n\n### 현재 성능 진단\n\nPhase 1 프리트레인 실측:\n- **57,000 steps**, ~38.5B tokens, **약 63시간**\n- 처리 속도: 36~38K tok/s per rank → 전체 **~292K tok/s** (8GPU)\n- **MFU: ~33.5%**\n\n### 핵심 병목: NUMA Misalignment\n\n```\nAMD EPYC 9365 × 2소켓:\n  GPU 0~3 → NUMA node 0 (core 0-35)\n  GPU 4~7 → NUMA node 1 (core 36-71)\n\n초기 DDP 런칭 시 5/8 rank가 잘못된 NUMA 노드에서 실행.\n69%의 DataLoader worker가 크로스-NUMA — ~2배 지연 발생.\n```\n\n### 최적화 항목별 예상 효과\n\n| 최적화 | 예상 MFU 개선 | 난이도 |\n|--------|-------------|--------|\n| NUMA affinity 고정 | +4~9% | 낮음 (launch script 수정) |\n| QKV fusion (TransformerEngine) | +8~12% | 중간 (모델 코드 수정) |\n| FA2 native RoPE | +3~5% | 중간 (FA2 버전 의존) |\n| NCCL 환경변수 튜닝 | +1~2% | 낮음 (한 줄 추가) |\n\n### 최적화 전후 예상 비교\n\n| 항목 | 현재 | 최적화 후 |\n|------|------|----------|\n| MFU | 33.5% | ~45~47% |\n| 처리속도 | 292K tok/s | ~390~410K tok/s |\n| 50B 토큰 학습 | ~47시간 | ~34~36시간 |\n\n### 즉시 적용 가능한 코드\n\n**NUMA affinity (launch script):**\n\n```bash\nnumactl --cpunodebind=0 --membind=0 torchrun \\\n  --nproc_per_node=4 --node_rank=0 train/pretrain.py ... \u0026\nnumactl --cpunodebind=1 --membind=1 torchrun \\\n  --nproc_per_node=4 --node_rank=1 train/pretrain.py ... \u0026\n```\n\n**NCCL 환경변수:**\n\n```bash\nexport NCCL_MIN_NCHANNELS=4\nexport NCCL_SOCKET_NTHREADS=4\nexport CUDA_DEVICE_MAX_CONNECTIONS=1\n```\n\n\u003e Phase 3 ORPO 완료 후, 다음 프리트레인 런 전에 NUMA affinity를 먼저 적용하면 학습 시간을 ~30% 단축할 수 있다.\n\n---\n\n## 19. GPU 하드웨어 \u0026 비용 분석 — 3B × 60B 프리트레인\n\n\u003e 상세 문서: [`docs/GPU_COST_ANALYSIS.md`](docs/GPU_COST_ANALYSIS.md)\n\n### 실측 기준 베이스라인\n\n```\nFRANKENSTALLM Phase 1 실측:\n  B200 × 8, MFU 33.5%, 292K tok/s\n  38.5B 토큰 → 63시간\n  60B 토큰 환산 → 약 98시간\n```\n\n### 클라우드 가성비 Top 3 (60B 토큰, 최적화 후)\n\n| 순위 | 구성 | 소요시간 | 총 비용 |\n|------|------|---------|--------|\n| 1 | H100×8 Cudo | 44.8hr | **$645** (~93만원) |\n| 2 | H100×8 Vast.ai | 44.8hr | $670 (~97만원) |\n| 3 | H100×8 RunPod | 44.8hr | $713 (~103만원) |\n\n\u003e B200 Blackwell이 빠르지만, 클라우드 단가가 H100의 3배 → **H100이 총비용 4.3배 저렴**\n\n### 개인 GPU 구성 추천\n\n| 구성 | VRAM | NVLink | 가격 | 추천도 |\n|------|------|--------|------|--------|\n| A6000 Ada × 2 중고 | 96GB (통합) | ✅ | ~1,000만원 | ⭐⭐⭐⭐⭐ |\n| L40S × 2 | 96GB (통합) | ✅ | ~1,400만원 | ⭐⭐⭐⭐ |\n| RTX Pro 6000 Blackwell | 96GB (단일) | ❌ | ~1,200만원 | ⭐⭐⭐ |\n\n\u003e 소비자용 GPU(RTX 5090/4090)는 NVLink 미지원. 80GB+ 통합 메모리 필요 시 전문가용 필수.\n\n### 추천 전략: 로컬 + 클라우드 하이브리드\n\n```\n[로컬] RTX 4090 × 4 (880만원) — 데이터 전처리, 실험, SFT/ORPO\n[클라우드] H100×8 (런당 ~103만원) — 본 프리트레인만\n```\n\n---\n\n## 20. HuggingFace 배포 현황\n\n\u003e **배포 URL**: https://huggingface.co/pathcosmos/frankenstallm\n\n### 모델 파일 목록\n\n| 파일 | 크기 | 설명 |\n|------|------|------|\n| `model.safetensors` | 4.76GB | v2 ORPO 베스트 (byte-fallback 수정) — Transformers 직접 로드용 |\n| `gguf/frankenstallm-3b-v2-Q4_K_M.gguf` | 757MB | **Ollama 권장** |\n| `gguf/frankenstallm-3b-v2-Q8_0.gguf` | 1.2GB | 고품질 |\n| `gguf/frankenstallm-3b-v2-f16.gguf` | 2.3GB | 최고품질 |\n| `gguf/frankenstallm-3b-Q4_K_M.gguf` | 1.9GB | v1 Q4_K_M |\n| `gguf/frankenstallm-3b-Q8_0.gguf` | 3.2GB | v1 Q8_0 |\n| `gguf/frankenstallm-3b-f16.gguf` | 6.0GB | v1 f16 |\n\n각 GGUF 파일에 대응하는 `Modelfile.*` (sampling config 포함)이 함께 제공됩니다.\n\n---\n\n## 21. Ollama 사용법 — 상세 설명 및 주의사항\n\n### 빠른 시작 (권장 방법)\n\n```bash\n# 1. GGUF + Modelfile 다운로드\nhuggingface-cli download pathcosmos/frankenstallm   gguf/frankenstallm-3b-v2-Q4_K_M.gguf   gguf/Modelfile.3b-v2-Q4_K_M   --local-dir ./frankenstallm\n\n# 2. Modelfile의 FROM 경로 수정\n# FROM ./outputs/gguf/frankenstallm-3b-v2-Q4_K_M.gguf\n# → FROM ./frankenstallm/gguf/frankenstallm-3b-v2-Q4_K_M.gguf\n\n# 3. Ollama 모델 등록\nollama create frankenstallm-3b-v2 -f ./frankenstallm/gguf/Modelfile.3b-v2-Q4_K_M\n\n# 4. 실행\nollama run frankenstallm-3b-v2\n```\n\n### 검증된 샘플링 파라미터\n\n| 파라미터 | 권장값 | 설명 |\n|---------|--------|------|\n| `temperature` | **0.7** | 낮을수록 반복, 높을수록 무작위. 0.7이 한국어 품질 최적 |\n| `repeat_penalty` | **1.2** | **필수** — 이 값 없이는 greedy 시 30.89% 반복 발생 |\n| `top_p` | **0.9** | nucleus sampling, 0.9 이상 권장 |\n| `top_k` | **50** | 상위 50개 토큰 후보 |\n| `num_predict` | **512** | 최대 생성 토큰 수 |\n| `num_ctx` | **4096** | 컨텍스트 윈도우 (최대 4096) |\n\n### ⚠️ 주의사항\n\n**1. repeat_penalty는 반드시 설정하세요**\n```\nORPO 학습 후에도 greedy(temp=0) 시 30.89% 3-gram 반복률이 남아 있습니다.\nrepeat_penalty=1.2 설정 시 반복률 0%로 완전 억제됩니다.\nModelfile에 이미 설정되어 있으므로, Modelfile을 사용하면 자동 적용됩니다.\n```\n\n**2. temperature=0 (greedy) 사용 주의**\n```\ngreedy 디코딩은 반복 억제 없이 30.89% 3-gram 반복이 발생합니다.\n반드시 temperature \u003e= 0.5 이상 + repeat_penalty \u003e= 1.1 이상을 함께 사용하세요.\n```\n\n**3. num_ctx 초과 시 성능 저하**\n```\n학습 시 max_position_embeddings=4096이었습니다.\n4096 토큰을 초과하는 컨텍스트를 넣으면 성능이 크게 저하됩니다.\n```\n\n**4. 한국어 중심 모델입니다**\n```\n영어 능력: MMLU 42.0%, HellaSwag 27.9% — 영어 태스크에서 기대치를 낮추세요.\n한국어: KoBEST 0-shot 52.75%, korean_nlu 100.0% (Ollama 벤치마크)\n```\n\n**5. v2 vs v1 선택**\n```\nv2 권장: byte-fallback 수정으로 \n 등 특수문자 포함 입력이 안전합니다.\nv1은 \n 포함 입력 시 llama.cpp가 크래시할 수 있습니다.\n```\n\n### Transformers로 직접 실행\n\n```python\nfrom transformers import AutoModelForCausalLM, AutoTokenizer\nimport torch\n\nmodel_id = \"pathcosmos/frankenstallm\"\ntokenizer = AutoTokenizer.from_pretrained(model_id)\nmodel = AutoModelForCausalLM.from_pretrained(\n    model_id,\n    torch_dtype=torch.bfloat16,\n    device_map=\"auto\"\n)\n\n# ⚠️ do_sample=True + repetition_penalty 반드시 설정\ninputs = tokenizer(\n    \"한국의 전통 음식 중 김치에 대해 설명해주세요.\",\n    return_tensors=\"pt\"\n).to(model.device)\n\nwith torch.no_grad():\n    outputs = model.generate(\n        **inputs,\n        do_sample=True,        # ← greedy 사용 시 반복 발생\n        temperature=0.7,       # ← 핵심 파라미터\n        repetition_penalty=1.2, # ← 반드시 설정\n        top_p=0.9,\n        top_k=50,\n        max_new_tokens=512,\n        pad_token_id=tokenizer.eos_token_id,\n    )\n\nprint(tokenizer.decode(outputs[0], skip_special_tokens=True))\n```\n\n### API 서빙 (Ollama)\n\n```bash\n# 백그라운드 서버 실행 (기본 포트 11434)\nollama serve \u0026\n\n# REST API 호출\ncurl http://localhost:11434/api/generate -d '{\n  \"model\": \"frankenstallm-3b-v2\",\n  \"prompt\": \"한국어로 자기소개를 해줘.\",\n  \"stream\": false,\n  \"options\": {\n    \"temperature\": 0.7,\n    \"repeat_penalty\": 1.2,\n    \"top_p\": 0.9,\n    \"num_predict\": 512\n  }\n}'\n```\n\n---\n\n## 22. 모델 성능 비교 — Base / SFT / ORPO / Ollama\n\n### 핵심 지표 3-Way 비교\n\n| 지표 | Base | SFT v2 | ORPO (v2) |\n|------|------|--------|-----------|\n| **greedy 3-gram 반복률** | 60.99% | 72.97% | **30.89%** |\n| **EOS 종료율 (greedy)** | 0% | 60% | 67% |\n| **sampling 반복률** (temp=0.7, rep=1.2) | — | — | **0%** |\n| **KoBEST 0-shot 평균** | ~44% | 43.26%¹ | **52.75%** |\n| **MMLU-KO 0-shot** | 38.8% | 42.0% | — |\n| **Hellaswag EN** | 33.3% | — | 27.9% |\n| **Calibration Top-1** | ~65% | 68.59% | 67.99% |\n| **PPL forgetting** | 0% (기준) | 0.9% | 4.1% |\n| **Preference Accuracy** | — | — | **76.02%** |\n| **Reward Margin** | — | — | **0.6100** |\n\n\u003e ¹ SFT 초기 평가 시 43.26%, 이후 재평가에서 52.75% (평가 환경 차이).\n\n### KoBEST 세부 비교 (0-shot)\n\n| 태스크 | Base | ORPO |\n|--------|------|------|\n| BoolQ | ~48% | 54.3% |\n| COPA | ~52% | 56.2% |\n| WiC | ~49% | 51.8% |\n| SentiNeg | ~44% | 51.4% |\n| HellaSwag-KO | ~38% | 49.9% |\n| **평균** | ~46% | **52.75%** |\n\n### Ollama 벤치마크 (frankenstallm-3b-v2:Q4_K_M, 35 tests)\n\n| 카테고리 | 점수 |\n|----------|------|\n| korean_nlu | **100.0** |\n| knowledge | 75.0 |\n| instruction_following | 66.7 |\n| reasoning | 50.0 |\n| safety | 10.0 |\n| repetition_resistance | 2.2 |\n| **자동 채점 평균** | **46.7** |\n| 평균 TPS | 142.5 tok/s |\n| 평균 TTFT | 16.7 ms |\n\n\u003e repetition_resistance 2.2%는 Ollama 기본 파라미터(sampling 없이 실행)로 측정된 값.  \n\u003e `repeat_penalty=1.2` + `temperature=0.7` 적용 시 **반복률 0%** 달성.\n\n### 3B급 모델 성능 비교 — Ollama 벤치마크\n\n동일 환경(Ollama, 35개 테스트)에서 3B급 오픈소스 모델들과 직접 비교한 결과입니다.\n\n#### 종합 점수\n\n| 모델 | 파라미터 | 자동 채점 평균 | 비고 |\n|------|---------|---------------|------|\n| **Qwen 2.5 3B** | 3B | **63.4** | 종합 1위 |\n| **Phi-4 Mini** | 3.8B | **60.6** | 추론 특화 |\n| **FRANKENSTALLM 3B v2** | 3B | **46.7** | 본 모델 (ORPO) |\n| FRANKENSTALLM 3B v1 | 3B | 37.9 | SFT only |\n\n#### 카테고리별 상세 비교\n\n| 카테고리 | FRANKENSTALLM v2 | Qwen 2.5 3B | Phi-4 Mini 3.8B | 비고 |\n|----------|:---:|:---:|:---:|------|\n| **Korean NLU** | **100.0** | **100.0** | 66.7 | 한국어 이해력 동급 |\n| **Knowledge** | **75.0** | 20.8 | 29.2 | 한국어 지식에서 압도적 우위 |\n| **Instruction Following** | **66.7** | 55.6 | 33.3 | 지시 따르기 우수 |\n| **Reasoning** | 50.0 | 62.5 | **87.5** | Phi-4 추론 특화 |\n| **Code** | 0.0 | **100.0** | 83.3 | 코드 능력 부족 |\n| **Safety** | 10.0 | 35.0 | **70.0** | 안전성 약점 |\n| **Repetition Resistance** | 2.2 | **75.0** | 58.9 | 기본 파라미터 기준¹ |\n\n\u003e ¹ FRANKENSTALLM의 반복 저항 2.2%는 Ollama 기본 설정 기준. `repeat_penalty=1.2` 적용 시 0% 달성.\n\n#### 추론 속도 비교\n\n| 모델 | Avg TTFT (ms) | P95 TTFT (ms) | Avg TPS | 비고 |\n|------|:---:|:---:|:---:|------|\n| **FRANKENSTALLM 3B v2** | **16.7** | **26.2** | **142.5** | 최고 속도 |\n| Phi-4 Mini 3.8B | 25.6 | 44.9 | 100.4 | |\n| Qwen 2.5 3B | 28.2 | 46.5 | 93.8 | |\n\n\u003e FRANKENSTALLM은 동일 아키텍처(LlamaForCausalLM)와 64K vocab으로 Ollama 추론에 최적화됨.\n\n#### lm-eval 벤치마크 비교 (Base → SFT → ORPO)\n\n| 벤치마크 | Base | SFT | ORPO | 변화 (Base→ORPO) |\n|----------|:---:|:---:|:---:|:---:|\n| **KoBEST COPA** | 49.3% | 48.6% | **63.9%** | **+14.6pp** |\n| **KoBEST HellaSwag** | 21.6% | 19.8% | **38.0%** | **+16.4pp** |\n| **KoBEST SentiNeg** | 48.6% | 49.1% | **62.5%** | **+13.9pp** |\n| **KoBEST BoolQ** | 50.3% | 50.1% | 50.6% | +0.3pp |\n| **KoBEST WiC** | 48.7% | 48.7% | 48.8% | +0.2pp |\n| **KoBEST 평균** | 43.7% | 43.3% | **52.8%** | **+9.1pp** |\n| **HAE-RAE** | 19.7% | 19.9% | 21.8% | +2.1pp |\n| **PIQA** | 52.5% | 52.6% | **59.9%** | **+7.3pp** |\n| **ARC-Easy** | 25.6% | 25.9% | **36.0%** | **+10.4pp** |\n| **HellaSwag EN** | 26.2% | 26.1% | 29.2% | +3.0pp |\n| **Winogrande** | 50.6% | 50.8% | 51.0% | +0.4pp |\n| **PPL forgetting** | 기준 | 0.9% | 4.1% | 임계 15% 이내 ✅ |\n\n#### 해석 및 위치\n\n**강점**:\n- **한국어 NLU 100%** — Qwen 2.5 3B와 동급, Phi-4를 압도\n- **한국어 지식 75.0** — 비교 모델 중 최고 (Qwen 20.8, Phi-4 29.2)\n- **추론 속도 최고** — TTFT 16.7ms, TPS 142.5로 실시간 서빙에 유리\n- **ORPO 효과 극대** — KoBEST +9.1pp, COPA/HellaSwag/SentiNeg에서 각 13~16pp 향상\n\n**약점 및 개선 방향**:\n- **코드 생성 0%** — 코드 SFT 데이터 부족. 코드 특화 데이터 추가 필요\n- **안전성 10%** — safety alignment 데이터 미반영. RLHF/DPO 추가 학습 고려\n- **반복 문제** — 기본 설정에서 반복 발생하나, `repeat_penalty=1.2`로 완전 해결\n- **종합 점수 gap** — Qwen 대비 -16.7pp. 학습 데이터 품질 및 규모 차이가 주 원인\n\n---\n\n## 23. 재현 가이드 — 전 단계 설정 상세\n\n\u003e 이 섹션은 동일 환경에서 재현 시 참고용입니다.\n\n### 환경 설정\n\n```bash\n# NVIDIA 커스텀 PyTorch는 재설치 금지 (B200 최적화 깨짐)\n# 아래 패키지만 추가 설치\npip install transformers==4.40.0 accelerate peft trl deepspeed \\\n            bitsandbytes sentencepiece wandb\n\n# 전체 환경 재현\npip install -r requirements.txt\n```\n\n**소프트웨어 버전 (실측)**:\n```\ntorch          2.10.0a0+b4e4ee81d3.nv25.12\nflash_attn     2.7.4.post1+25.12\ntransformers   4.40.x\ndatasets       4.4.1\ntokenizers     0.22.1\nhuggingface_hub 1.2.3\ntrl            (ORPO NaN 버그 패치 적용본 — scripts/trl_patch.py 참고)\nCUDA           13.1 / Driver 580.95.05\n```\n\n### Phase 1 — Pretrain 핵심 하이퍼파라미터\n\n```yaml\n# configs/korean_3b_fp8.yaml 기준\nmodel:\n  hidden_size: 2048\n  num_hidden_layers: 24\n  num_attention_heads: 16\n  num_key_value_heads: 4\n  intermediate_size: 5632\n  max_position_embeddings: 4096\n  vocab_size: 64000\n\ntrain:\n  batch_size: 5\n  gradient_accumulation_steps: 8\n  # effective batch = 5 × 8 × 8GPU = 320\n  learning_rate: 1.5e-4\n  min_lr: 1.5e-5          # cosine decay 하한 (max_lr의 10%)\n  warmup_steps: 2000\n  weight_decay: 0.1\n  max_grad_norm: 1.0\n  scheduler: cosine\n  precision: bf16          # FP8 Tensor Core 활용 (B200)\n  total_tokens: ~38.5B\n```\n\n### Phase 2 — SFT v2 핵심 하이퍼파라미터\n\n```yaml\n# configs/korean_3b_sft_v2.yaml 기준\ntrain:\n  learning_rate: 5.0e-5\n  batch_size: 4\n  gradient_accumulation_steps: 8\n  # effective batch = 4 × 8 × 8GPU = 256\n  warmup_ratio: 0.03\n  weight_decay: 0.01\n  lr_scheduler_type: cosine\n  max_steps: 33000          # early stop at 25,500 (patience=5)\n  early_stopping_patience: 5\n  fp16: false\n  bf16: true\n\ndata:\n  total_samples: 2439397    # train\n  val_samples: 49801\n  num_sources: 24\n  total_size_gb: 7.48\n  mixing: \"70% instruction / 30% general\"\n```\n\n### Phase 3 — ORPO 핵심 하이퍼파라미터\n\n```yaml\n# configs/korean_3b_orpo.yaml 기준 (본 학습)\ntrain:\n  beta: 0.25                # ORPO preference weight\n  learning_rate: 1.2e-5    # HP sweep 최적값\n  batch_size: 4\n  gradient_accumulation_steps: 4\n  # effective batch = 4 × 4 × 8GPU = 128\n  warmup_ratio: 0.1\n  weight_decay: 0.01\n  lr_scheduler_type: cosine\n  max_length: 1536          # prompt + response 합산 최대 길이\n  max_prompt_length: 512\n  num_train_epochs: 2       # 실제 ~9,997 steps에서 조기 수렴\n  bf16: true\n  optim: adamw_torch_fused\n\ndata:\n  raw_pairs: 683181\n  filtered_pairs: ~630000   # NaN 방지 필터 후\n  eval_split: 0.05          # seed=42\n  eval_pairs: ~31500\n```\n\n### Phase 4 — GGUF 변환 파이프라인\n\n```bash\n# Step 1: byte-fallback 토크나이저 수정\npython scripts/fix_tokenizer_byte_fallback.py \\\n  --input  outputs/hf_checkpoint-best \\\n  --output outputs/hf_checkpoint-best-fixed\n\n# Step 2: f16 GGUF 변환 (llama.cpp)\npython outputs/llama.cpp/convert_hf_to_gguf.py \\\n  outputs/hf_checkpoint-best-fixed \\\n  --outfile outputs/gguf/frankenstallm-3b-v2-f16.gguf \\\n  --outtype f16\n\n# Step 3: 양자화\nQUANTIZE=outputs/llama.cpp/build/bin/llama-quantize\n$QUANTIZE outputs/gguf/frankenstallm-3b-v2-f16.gguf \\\n          outputs/gguf/frankenstallm-3b-v2-Q4_K_M.gguf Q4_K_M\n$QUANTIZE outputs/gguf/frankenstallm-3b-v2-f16.gguf \\\n          outputs/gguf/frankenstallm-3b-v2-Q8_0.gguf Q8_0\n\n# Step 4: Ollama 등록\nollama create frankenstallm-3b-v2:Q4_K_M -f Modelfile.3b-v2-Q4\nollama create frankenstallm-3b-v2:Q8_0   -f Modelfile.3b-v2-Q8\nollama create frankenstallm-3b-v2:f16    -f Modelfile.3b-v2-f16\n```\n\n### 토크나이저 재현\n\n```\n학습 방식: SentencePiece Unigram\nvocab_size: 64,000 (원본) → 64,256 (byte-fallback 수정 후)\n학습 스크립트: tokenizer/train_sp_tokenizer.py\n학습 데이터: C4 Korean + 나무위키 + Wikipedia Korean 혼합\nbyte_fallback: True (v2에서 추가)\n추가 토큰: \u003c0x00\u003e ~ \u003c0xFF\u003e 256개\n```\n\n---\n\n## 마치며\n\n이 프로젝트의 모토는 하나다:\n\n\u003e **\"망하는 것도 기록한다.\"**\n\nSFT v1의 loss=0.0 실패, torch.compile이 효과 없었던 것, 18% 반복률의 좌절 — 이 모든 것이 기록에 남아 있다. Phase 3 ORPO에서도 **5번의 실패** — NCCL timeout, config 충돌, QKV 변환 버그, 포트 충돌, TRL NaN 버그 — 를 거쳐 마침내 완주했다.\n\nPhase 1 프리트레인은 57,000 steps, loss 1.466으로 완료됐다. Phase 2 SFT는 25,500 steps에서 early stopping (val_loss 1.8851). Phase 3 ORPO는 9,997 steps에서 조기 수렴 — eval_loss 1.625, Preference Accuracy 76.02%. Phase 4로 GGUF 변환 후 HuggingFace와 Ollama에 배포 완료.\n\n**결국 해냈다**: greedy 반복률 72.97% → 30.89% (ORPO), sampling+rep_penalty 적용 시 0%. TPS 142.5, TTFT 16.7ms. 한국어를 이해하고 말하는 3B 모델, 처음부터 만든 것.\n\nFrankenstein이 조각들을 이어 붙여 생명을 만들었듯, FRANKENSTALLM도 그렇게 만들어졌다.\n\n**🤗 모델 다운로드**: https://huggingface.co/pathcosmos/frankenstallm\n\n---\n\n## Acknowledgment\n\n이 프로젝트는 **과학기술정보통신부**의 **「첨단 GPU 활용 지원 사업」** (과학기술정보통신부 공고 제2025-1068호)을 통해 제공된 GPU 컴퓨팅 자원을 활용하여 수행되었습니다.\n\n\u003e **국가 AI컴퓨팅자원 지원포털**: https://aiinfrahub.kr\n\u003e\n\u003e - 주관: 과학기술정보통신부 (MSIT), 정보통신산업진흥원 (NIPA)\n\u003e - 운영: 한국정보통신진흥협회 (KAIT)\n\n대한민국 정부의 AI 인프라 지원 사업 덕분에 8× NVIDIA B200 GPU 환경에서 한국어 3B LLM을 처음부터 학습할 수 있었습니다. 국가 차원의 AI 컴퓨팅 자원 지원에 깊이 감사드립니다.\n\n---\n\n*최종 업데이트: 2026-03-26*\n*현재 상태: **전 단계 완료** — Phase 1 Pretrain ✅ | Phase 2 SFT ✅ | Phase 3 ORPO ✅ | Phase 4 배포 ✅*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpathcosmos%2Ffrankenstallm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpathcosmos%2Ffrankenstallm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpathcosmos%2Ffrankenstallm/lists"}