GitHub 트렌딩 딥다이브 · 2026-06-23

AdaptiveTrainingSystem 딥다이브
— HuggingFace로 '완성된 모델'을 내려받는 대신, 토크나이저부터 CUDA 커널까지 LLM 학습 전 과정을 밑바닥부터 짓는 '1인 제철소'

MatN23/AdaptiveTrainingSystem. 요즘 대부분은 HuggingFace에서 '다 구워진 모델'을 내려받아 미세조정만 합니다. 이 프로젝트는 정반대로, 트랜스포머 LLM을 밑바닥부터(토크나이저 → 모델 구조 → 학습 루프 → GPU 커널 → C++ 추론 엔진) 직접 만드는 PyTorch 프레임워크입니다. 특히 Mixture-of-Experts(MoE)·Mixture-of-Depths(MoD) 같은 희소(sparse) 구조를 지원하고, 남들은 PyTorch 기본 연산에 맡기는 부분까지 손으로 짠 CUDA·Apple Metal 커널로 가속합니다. 게다가 학습 중 손실 곡선을 감시하며 스스로 개입하는 자율 오케스트레이터까지 들어 있습니다. 별 21개의 1인 개발 프로젝트라 '대규모 검증된 도구'는 아니지만, 현대 LLM의 내부와 GPU 성능 엔지니어링을 한 저장소에서 통째로 공부하기에는 보기 드물게 알찬 교본입니다. (저장소: MatN23/AdaptiveTrainingSystem · 언어 Python(+CUDA/Metal/C++) · PyTorch + DeepSpeed/FSDP/ColossalAI · Apache-2.0 · ★21 · TrendShift 라이브 멘션 #62135)

목차
  1. 프로젝트 한줄 요약
  2. 왜 주목받는가 (그리고 솔직한 주의점)
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석 (설정 한 줄이 학습된 모델이 되기까지)
  5. 디렉토리 구조 해부
  6. 학습 포인트 (기술별)
  7. 하드웨어 / 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한줄 요약

"완성차를 사 오는 대신, 엔진 피스톤까지 직접 깎아 차를 만드는 1인 공장."

한 줄로

AdaptiveTrainingSystem은 트랜스포머 LLM을 밑바닥부터 직접 굽는 'LLM 제철소'로, 토크나이저·모델 구조·학습 루프·GPU 커널·추론 엔진을 전부 손으로 구현해 둔 학습용 풀스택이다.

대부분의 사람은 HuggingFace에서 이미 학습된 모델을 내려받아 씁니다(= 완성차 구매). 이 프로젝트는 정반대로, 모델의 첫 단추인 토크나이저부터, GPU가 실제로 돌리는 연산 커널까지 직접 만듭니다(= 엔진 피스톤을 손으로 깎는 공장). 그래서 "LLM이 안에서 진짜 어떻게 도는가"를 가려진 부분 없이 들여다볼 수 있습니다.

핵심 특징 셋: ① MoE·MoD 희소 구조(필요한 부분만 켜서 계산량 절약), ② 손으로 짠 CUDA·Metal 커널(PyTorch 기본 연산보다 빠른 길을 직접 깔되, 안 되면 PyTorch로 자동 우회), ③ 자율 오케스트레이터(학습이 발산하는지 감시하고 하이퍼파라미터를 스스로 조정).

용어
MoE (Mixture of Experts, 전문가 혼합)
하나의 거대한 신경망 대신 여러 명의 '전문가' 작은 신경망을 두고, 입력 토큰마다 가장 알맞은 전문가 몇 명(top-k)에게만 일을 맡기는 구조입니다. 전체 파라미터는 많지만 한 번에 켜지는 건 일부라, "덩치는 큰데 계산은 가벼운" 모델을 만들 수 있습니다. 누구에게 맡길지 정하는 부분을 라우터(router)라고 부릅니다.
용어
MoD (Mixture of Depths, 깊이 혼합)
트랜스포머의 모든 층을 모든 토큰이 거치는 게 보통인데, MoD는 "쉬운 토큰은 일부 층을 건너뛰게" 학습으로 정합니다. 고속도로의 하이패스 차로처럼, 간단한 입력은 빠른 길로 빼서 전체 계산량(FLOPs)을 줄입니다. 2024년 DeepMind가 제안했고, MoE와 함께 쓰는 경우는 아직 드뭅니다.
용어
CUDA 커널 · Metal 셰이더
커널(kernel)은 GPU 수천 개의 코어가 동시에 실행하는 작은 함수입니다. NVIDIA GPU용 언어가 CUDA, 애플 실리콘(M1~M4)용이 Metal입니다. 보통은 PyTorch가 내부적으로 알아서 호출해 주지만, 이 프로젝트는 RMSNorm·RoPE·SwiGLU·MoE 라우팅 같은 핵심 연산의 커널을 직접 작성해 2~7배 빠른 길을 노립니다(안 되면 PyTorch로 자동 우회).

좀 더 구체적으로, 저장소의 실제 코드는 모두 Src/Main_Scripts/ 아래에 있습니다. 작성자(덴마크 개발자 Matias Nielsen, 1인) 본인 코드는 파이썬 약 3.2만 줄 + GPU 커널 약 5천 줄 규모이고, 모델 전체 구조가 들어 있는 core/model.py 한 파일만 2,710줄입니다. 학습 루프(trainer.py)는 4,321줄, 자율 오케스트레이터(orchestrator.py)는 2,503줄로, "README만 화려한 빈 껍데기"가 아니라 실제로 동작하는 구현이 핵심입니다(78개의 pytest 테스트도 포함).

이 문서가 파고드는 건 "어떻게 설치하나"가 아니라 그 안의 설계입니다 — "MoE 라우팅을 CUDA로 가속하면서 어떻게 역전파(미분)를 안 깨뜨렸나", "왜 RMSNorm은 fp32로 계산하나", "백엔드 3종(DeepSpeed·FSDP·ColossalAI)을 어떻게 하나의 인터페이스로 갈아끼우나", "학습을 스스로 감시하는 오케스트레이터는 무엇을 보나". 현대 LLM 내부와 GPU 프로그래밍을 동시에 공부하려는 사람에게 작지만 밀도 높은 실전 교본입니다.

2왜 주목받는가 (그리고 솔직한 주의점)

"래퍼(wrapper)가 아니라 진짜 구현"이라는 점, 그리고 1인 프로젝트라 과장도 섞여 있다는 점.

비슷한 'LLM 학습 코드'는 많지만, 이 저장소가 라이브 멘션을 타고 화제가 된 이유는 대부분이 흉내만 내는 어려운 부분을 실제로 짜 놨기 때문입니다. 다섯 가지로 정리하면:

① API 래퍼가 아니라 '완성 스택'

README가 스스로 못 박습니다 — "이건 모델 동물원(model zoo)이나 API 래퍼가 아니라, 커스텀 CUDA 커널을 갖춘 완전한 학습 시스템이다." 토크나이저, 모델, MoE 라우팅, 손실 함수, 분산 학습, 추론까지 한 저장소 안에서 손으로 이어집니다.

② 손으로 짠 GPU 커널 (진짜 차별점)

대부분의 취미·학습용 프레임워크는 GPU 연산을 PyTorch에 떠넘깁니다. 이 프로젝트는 .cu(CUDA)·.metal(애플) 소스를 실제로 포함하고, 실행 시점에 nvcc로 컴파일해서 RMSNorm·RoPE·SwiGLU·MoE 라우팅을 가속합니다(안 되면 PyTorch로 자동 우회). moe_cuda_ops.cu 1,207줄, transformer_ops.cu 981줄 — "커널을 직접 짠다"는 말이 빈말이 아닙니다.

③ MoE + MoD 하이브리드

MoE(전문가 혼합)는 비교적 흔하지만, 여기에 2024년 DeepMind의 MoD(깊이 혼합)까지 결합해 한 모델에서 학습 가능하게 한 오픈 구현은 드뭅니다. "어떤 전문가에게 보낼까"와 "이 층을 아예 건너뛸까"를 동시에 학습합니다.

④ 애플 실리콘(Metal/MPS) 지원

대부분의 학습 프레임워크가 NVIDIA 전용인데, 이 프로젝트는 M1~M4 맥에서도 MoE 학습·추론이 되도록 Metal 셰이더와 MPS 경로를 따로 갖췄습니다.

⑤ 정직한 벤치마크

BENCHMARKS.md가 측정 환경을 NVIDIA T4 1장으로 명시하고, A100/H100 같은 대형 GPU 수치는 "검증되지 않음 … 구조적 추정치일 뿐"이라고 스스로 라벨을 붙입니다. 과대광고가 흔한 분야에서 이런 자기 고지는 드문 신뢰 신호입니다.

다른 도구와의 비교

비교 대상성격AdaptiveTrainingSystem과의 차이
nanoGPT / litGPT교육용 미니 GPT이쪽이 범위가 훨씬 넓다(MoE·MoD·다중 백엔드·오케스트레이터). 대신 더 무겁고 'minimal'하진 않다.
Megatron-LM / DeepSpeed대규모 분산 학습 엔진1인 프로젝트라 규모는 작고, 대규모 병렬화는 직접 만들지 않고 DeepSpeed·FSDP·ColossalAI 백엔드에 위임한다.
HuggingFace Transformers사전학습 모델 허브철학이 정반대. 사전학습 가중치 없음, 밑바닥부터 학습 전용, 저수준 제어 중심.
솔직한 주의점 — 공부 전에 알고 가기
1. 저장소 크기는 부풀려져 보인다 (벤더링된 ColossalAI)

GitHub가 보여 주는 거대한 코드량의 대부분은 Src/Main_Scripts/ColossalAI/통째로 복사된 외부 프레임워크(약 24만 줄)입니다. 이건 작성자의 코드가 아닙니다. 작성자 본인 기여분은 파이썬 약 3.2만 줄 + 커널 약 5천 줄로 봐야 정확합니다.

2. package.json은 이 프로젝트와 무관하다

최상위 package.json·일부 Dockerfile"LuminaAI Desktop"이라는 별개의 Electron 앱 흔적이고, 거기서 가리키는 main.js·train.py 같은 파일은 저장소에 없습니다. 이전 프로젝트의 잔재이니 Electron을 학습 시스템의 일부로 오해하지 마세요. 진짜 프로젝트는 Src/ 아래 파이썬입니다.

3. 별 21개 · 1인 · 대규모 주장은 미검증

"최대 300B 파라미터"·"2~7배 가속" 같은 수치는 작성자 본인도 대형 GPU에서는 검증하지 못했다고 밝힙니다. '검증된 프로덕션 도구'가 아니라 '잘 만든 학습 교본'으로 접근하는 게 맞습니다.

3기술 스택 전체 지도

한 저장소 안에 파이썬·CUDA·Metal·C++가 공존한다. 각 층이 무엇을 담당하는지 펼쳐 보자.

이 프로젝트는 웹 서비스가 아니라 '모델 학습 엔진'이라, 보통의 백엔드/프론트엔드 구분 대신 ① 모델·학습 코어(파이썬) ② GPU 가속(CUDA/Metal) ③ 분산·인프라로 나누어 보는 게 자연스럽습니다.

언어 구성

한눈에

Python(약 3.2만 줄, 본체) — 모델 구조·학습 루프·오케스트레이터·데이터 처리. / CUDA C++(.cu) — NVIDIA GPU용 손코딩 커널. / Apple Metal(.metal) + Objective-C++(.mm) — 애플 실리콘용 커널. / C++(.cpp/.hpp) — 파이썬과 분리된 독립 추론 런타임. "학습은 파이썬에서 지휘하되, 무거운 계산은 손으로 짠 저수준 커널이 처리"하는 구조입니다.

① 모델·학습 코어 (핵심 파이썬 의존성)

패키지역할
torch ≥ 2.1딥러닝 기반 프레임워크 — 텐서·자동미분·기본 GPU 연산
transformers / datasets토크나이저 유틸·데이터셋 로딩 (사전학습 가중치는 안 씀)
einops · safetensors텐서 형태 변환 · 안전한 가중치 직렬화
sentencepiece서브워드 토크나이저 학습/적용
numpy · scipy수치 연산 보조

② 분산 학습 · 성능

패키지역할
deepspeed ≥ 0.11ZeRO 1~3 · CPU/NVMe 오프로딩 — 큰 모델을 여러 GPU·CPU 메모리에 쪼개 담는 핵심 백엔드
triton ≥ 2.1파이썬으로 GPU 커널을 쓰는 DSL — FP8 경로에 사용
ray · mpi4py분산 작업 오케스트레이션 · MPI 통신
ninja · cmake · pybind11네이티브 커널 빌드 · C++↔파이썬 바인딩

③ 양자화 · 데이터 · 관측

분류패키지
양자화(4/8bit)bitsandbytes · auto-gptq · optimum · optimum-quanto
데이터(고속)pyarrow · polars (제로카피·메모리맵 데이터셋), datasets
추적·UXwandb(실험 추적) · loguru · rich · click · tqdm · PyYAML
애플pyobjc-framework-Metal (파이썬에서 Metal 커널 디스패치)
서빙·보안PyJWT(인증) · 자체 rate limiter · input validator

④ 빌드 · 인프라

네이티브 커널은 실행 시점에 컴파일됩니다. cuda_kernels.py가 현재 GPU의 SM 아키텍처를 감지해 nvcc를 호출하고, 만들어진 .soctypes로 불러옵니다(이게 핵심 트릭, §4·§6에서 자세히). 그 밖에 Dockerfile.backend(python:3.10-slim, Flask 헬스체크 포트 5001), docker-compose.dev.yml(Jupyter 8888 포함), makefile, GitHub Actions CI(test.yml)가 있습니다.

함정
Dockerfile.backend의 COPY 경로는 일부 깨져 있다

Dockerfile.backendtrain.py·lumina_desktop.py·ChatAI.py 같은 최상위 파일을 COPY하는데, 이 파일들은 Src/에 없습니다(위 §2의 LuminaAI 잔재와 같은 맥락). 도커 빌드를 그대로 따라 하면 실패할 수 있으니, 실제 학습은 Src/Main_Scripts/Main.py를 직접 실행하는 쪽으로 접근하세요.

4아키텍처 심화 분석

설정(config) 객체 하나가 모델 → 학습 루프 → GPU 커널 → 분산 백엔드를 타고 흐른다.

전체 구조의 핵심은 "설정이 모든 걸 결정하고, 무거운 계산은 손코딩 커널로 내려가되, 실패하면 항상 PyTorch로 우회한다"입니다. 실제 코드(Src/Main_Scripts/)의 흐름을 그림으로 보면:

┌─────────────────────────────────────────────────────────────┐ │ config/config_manager.py — DeepSeekConfig │ │ 모델 크기 프리셋 · 파라미터 수 계산 · 설정 검증 │ └───────────────────────────────┬─────────────────────────────┘ │ config 객체 ┌───────────────────────┼────────────────────────┐ ▼ ▼ ▼ ┌────────────────┐ ┌────────────────────┐ ┌───────────────────┐ │ core/model.py │ │ training/ │ │ backend/ │ │ 트랜스포머 본체│◄──│ trainer.py(4321) │──►│ deepspeed / fsdp /│ │ RMSNorm·RoPE │ │ orchestrator.py │ │ colossalai │ │ GQA·SwiGLU │ │ chinchilla_scaler │ │ (ZeRO·FSDP·플러그)│ │ MoE·MoD·블록 │ │ cuda_kernels.py │ └───────────────────┘ └───────┬────────┘ └─────────┬──────────┘ │ 가속 요청 │ 커널 호출 ▼ ▼ ┌──────────────────────────────────────────┐ │ core/*_wrapper.py + unified_ops.py │ ← 백엔드 선택기 │ "CUDA → Metal → PyTorch" 순서로 시도 │ (항상 안전 우회 포함) └──────────────────┬───────────────────────┘ ▼ ┌──────────────────────────────────────────┐ │ 손으로 짠 커널 │ │ transformer_ops.cu · moe_cuda_ops.cu │ (NVIDIA) │ transformer_ops.metal · moe_ops.metal │ (Apple) │ fused_grad_clip.cu · fused_loss.cu │ └──────────────────────────────────────────┘ [데이터 평면] datasets/ · tokenizer.py · multi_source_dataset.py (Wikipedia·ArXiv·StackOverflow·PubMed → Arrow/메모리맵) [추론 평면] moe_inference_runtime/ (학습과 분리된 독립 C++/Metal 엔진) core/runtime.cpp + backends/{cpu,cuda,mps}_kernels

핵심 설계 패턴 5가지

① 3단 가속 폴백 (fast path + safe fallback)

가장 자주 등장하는 패턴입니다. 모든 가속 연산(RMSNorm·RoPE·SwiGLU·MoE 라우팅)은 통합 백엔드 → 직접 CUDA/Metal → PyTorch 순으로 시도하고, 각 단계를 try/except로 감쌉니다. "빠른 길이 막히면 느려도 확실한 길로 자동 우회"라, 어떤 하드웨어에서도 일단 돌아가게 만드는 실전적 안전장치입니다.

def forward(self, x):
    input_dtype = x.dtype
    if USE_UNIFIED_BACKEND and self._impl is not None:
        try: return self._impl(x)            # 1순위: 통합 백엔드
        except Exception: pass
    if self._cuda_impl is not None and x.is_cuda:
        try: return self._cuda_impl(x)       # 2순위: 직접 CUDA
        except Exception: pass
    x_normed = self._norm_pytorch(x)         # 3순위: PyTorch 우회(내부 fp32)
    if self.elementwise_affine:
        x_normed = x_normed * self.weight.float()
    return x_normed.to(input_dtype)

core/model.py RMSNorm.forward (약 L311) — 같은 모양의 폴백이 모델 전반에 반복됩니다.

② 백엔드 전략 패턴 (Strategy)

backend/backend_deepspeed.py·backend_fsdp.py·backend_colossalai.py동일한 표면(인터페이스)을 제공하고, 오케스트레이터가 use_deepspeed() 같은 플래그로 하나를 고릅니다. "큰 모델을 어떻게 여러 GPU에 쪼갤까"라는 어려운 문제를 직접 재구현하지 않고 검증된 라이브러리에 위임하되, 갈아끼우기 쉽게 추상화한 영리한 선택입니다.

③ 자율 제어 루프 (orchestrator)

training/orchestrator.py(2,503줄)는 학습을 지켜보는 '관제탑'입니다. 백그라운드 스레드 monitoring_loop()가 돌면서:

구성요소역할
MetaLearningEngine과거 학습 기록에서 패턴을 학습
AdaptiveHyperparameterOptimizer학습률·배치 크기를 실시간 조정
ArchitectureEvolutionMoE 전문가를 학습 중에 추가/제거(가지치기)
RealTimeAnalytics손실 곡선 분석 · 이상(발산) 감지
ProductionMonitoring운영 지표 모니터링

"학습이 발산하면 멈추거나 학습률을 낮추고, 전문가가 놀고 있으면 가지치기한다" — 이런 피드백 컨트롤러를 직접 만드는 법을 통째로 공부할 수 있는 부분입니다.

④ 런타임 커널 JIT 컴파일

커널을 미리 빌드해 두는 게 아니라, 처음 쓰는 순간 현재 GPU에 맞춰 nvcc로 컴파일합니다. torch.cuda.get_device_properties로 SM 아키텍처(예: sm_75)를 알아내 컴파일 옵션을 맞추죠(§6에 코드).

⑤ 수치 안정성 규율

저정밀(fp16/bf16) 학습에서 터지기 쉬운 부분을 의도적으로 고정밀로 계산합니다. RMSNorm은 fp32로 계산한 뒤 원래 타입으로 되돌리고, RoPE의 cos/sin 테이블은 fp64로 만들어 캐시합니다. "어디서 정밀도를 지켜야 학습이 안 터지는가"의 좋은 예시입니다.

설계에서 배울 점
"빠른 길 + 안전한 우회"는 실전 ML 시스템의 기본기

성능 최적화는 종종 특정 하드웨어에서만 동작합니다. 이 프로젝트처럼 가속 경로를 try로 감싸고 항상 순정 PyTorch 폴백을 두면, 최적화의 이득은 챙기면서도 "그 GPU에선 안 돌아가요" 문제를 피할 수 있습니다. 분산 백엔드를 직접 만들지 않고 위임한 것도 같은 철학 — "어려운 건 검증된 것에 맡기고, 내가 통제할 부분만 손으로 짠다."

5디렉토리 구조 해부

진짜 코드는 전부 Src/Main_Scripts/ 아래. 그 안을 역할별로 펼쳐 본다.

AdaptiveTrainingSystem/ ├── Readme.md 80KB — 사실상의 설계 명세서(매우 상세) ├── BENCHMARKS.md T4 측정치 + "대형 GPU는 미검증" 정직한 고지 ├── Performance_Overhead.md 오케스트레이터의 오버헤드 분석 ├── requirements.txt ML 의존성(torch·deepspeed·triton·bitsandbytes…) ├── Dockerfile.backend python:3.10-slim (⚠ 깨진 COPY 경로 주의) ├── package.json ⚠ 무관한 Electron "LuminaAI Desktop" 잔재 └── Src/ ├── tests/ 78개 pytest(model·trainer·chinchilla·e2e…) └── Main_Scripts/ ├── Main.py 3425줄 — 최상위 CLI / 학습 진입점 ├── Chat.py 968줄 — 채팅/서빙 프런트 ├── multi_source_dataset.py — 합법 코퍼스 수집(위키·ArXiv·SO·PubMed) ├── router_training_system.py 775 — MoE 라우터 미세조정/어댑터 ├── config/ │ └── config_manager.py 2145 — DeepSeekConfig·프리셋·파라미터 수학 ├── core/ │ ├── model.py 2710 — 트랜스포머 전체(RMSNorm·RoPE·GQA· │ │ SwiGLUExpert·MoEFFNLayer·MoDRouter·블록) │ ├── tokenizer.py 665 · dataset.py 1022 · benchmark.py 623 │ ├── cuda_opt_wrapper.py / moe_cuda_wrapper.py — CUDA 디스패치 │ ├── metal_opt_wrapper.py / moe_metal_wrapper.py — Metal 디스패치 │ ├── unified_ops.py 539 — 백엔드 선택기(CUDA/Metal/PyTorch) │ ├── transformer_ops.cu (981) / moe_cuda_ops.cu (1207) ← 진짜 CUDA │ └── transformer_ops.metal / moe_ops.metal ← 진짜 Metal ├── training/ │ ├── trainer.py 4321 — 메인 학습 루프·AMP·그래드 클립·체크포인트 │ ├── orchestrator.py 2503 — 자율 제어 시스템(§4 참고) │ ├── chinchilla_scaler.py 575 — 컴퓨트 최적 학습량 계산·수렴 감지 │ ├── cuda_kernels.py 484 — nvcc 컴파일·로드 하니스(ctypes) │ └── fused_grad_clip.cu (220) / fused_loss.cu (417) ← 진짜 CUDA ├── backend/ backend_fsdp 613 / deepspeed 464 / colossalai 161 ├── moe_inference_runtime/ ← 독립 C++/Metal 추론 엔진 │ ├── core/runtime.cpp (733) + runtime.hpp │ ├── backends/cpu_kernels.cpp / cuda_kernels.cu / mps_kernels.mm │ └── chat.py · export/export_model.py · compile.sh ├── security/ auth.py(JWT) · rate_limiter.py · input_validator.py ├── monitoring/ logger.py 639 (레벨별 상세 로깅) └── utils/ environment.py 551 · data_processing · reporting └── ColossalAI/ ⚠ 외부 프레임워크 통째 복사(~24만 줄, 작성자 코드 아님)

읽는 순서를 추천하자면: config/config_manager.py(무엇을 만드는지) → core/model.py(모델이 어떻게 생겼는지) → training/trainer.py(어떻게 학습하는지) → core/moe_cuda_ops.cu(GPU에서 실제로 어떻게 도는지) 순입니다. ColossalAI/ 폴더는 외부 코드이니 처음엔 건너뛰세요.

6학습 포인트 (기술별)

이 저장소의 진짜 가치는 "현대 LLM 내부 + GPU 성능 엔지니어링"을 한곳에서 코드로 볼 수 있다는 것.

① 트랜스포머 내부를 밑바닥부터 — core/model.py

요즘 LLM의 표준 부품들이 한 파일에 다 구현돼 있습니다. 읽을 위치까지 적어 두면: RMSNorm(L260), RotaryEmbedding/RoPE(L366), DenseGroupedQueryAttention/GQA(L613), SwiGLUExpert(L1006), TransformerBlock(L1578). LayerNorm 대신 RMSNorm, 절대 위치 임베딩 대신 RoPE, 모든 헤드가 KV를 따로 갖는 대신 GQA로 공유 — "왜 요즘 모델은 이렇게 바뀌었나"를 코드로 체득하기 좋습니다.

② Mixture-of-Experts — 라우팅을 CUDA로 가속하되 미분을 안 깨뜨리기

MoEFFNLayer(L1068)는 top-k 게이팅, 온도(temperature) 스케일링, capacity factor, 그리고 전문가에게 일이 골고루 가도록 하는 보조 부하분산 손실(auxiliary load-balancing loss)을 모두 구현합니다. 가장 영리한 부분은 "CUDA로 top-k를 빠르게 고르되, 미분은 PyTorch로 흐르게" 한 점입니다:

if self.use_cuda_ops and MoECUDAOps is not None and x.is_cuda:
    try:
        top_k_indices, cuda_probs = MoECUDAOps.topk_gating(
            gate_logits, self.top_k,
            temperature=self.routing_temperature, use_cuda=True)
        # 인덱스는 CUDA가 고르고, 확률은 PyTorch로 다시 계산 →
        top_k_logits = torch.gather(scaled_logits, -1, top_k_indices)
        top_k_probs  = F.softmax(top_k_logits, dim=-1)  # 게이트로 가는 미분 경로 유지
    except Exception as e:
        top_k_indices, top_k_probs = self._pytorch_routing(gate_logits)
else:
    top_k_indices, top_k_probs = self._pytorch_routing(gate_logits)

커널은 "누구를 뽑을지"(인덱스)만 빠르게 정하고, 실제 확률은 F.softmax로 다시 계산해 역전파가 라우터 가중치까지 흐르게 합니다. "선택은 가속하되 학습은 안 깨뜨린다" — MoE를 직접 짤 때 가장 헷갈리는 지점의 모범답안입니다.

③ Mixture-of-Depths — 쉬운 토큰은 층을 건너뛰기

MoDRouter(L907)와 DenseSwiGLUWithMoD(L1362)는 토큰별로 "이 층을 거칠지/건너뛸지"를 학습합니다. capacity_factor를 낮출수록 더 많이 건너뛰어 FLOPs가 줄어듭니다. MoE(가로로 전문가 나눔)와 MoD(세로로 층 건너뜀)를 같이 쓰는 흔치 않은 조합을 실제 코드로 볼 수 있습니다.

④ CUDA 커널 프로그래밍 — core/moe_cuda_ops.cu

여기가 이 저장소의 백미입니다. GPU 한 워프(32 스레드) 안에서 레지스터만으로 최댓값을 구하는 워프 셔플 리덕션, 정렬 없이 top-k를 뽑는 바이토닉 정렬, 한 번에 4개 float를 읽는 float4 벡터화 같은 실전 기법이 들어 있습니다:

// 워프 셔플로 32개 값의 최댓값을 동기화 없이 구하기
__device__ __forceinline__ float warp_reduce_max(float val) {
    for (int offset = WARP_SIZE/2; offset > 0; offset >>= 1)
        val = fmaxf(val, __shfl_xor_sync(FULL_MASK, val, offset));
    return val;
}
// 각 레인이 자기 몫의 float4를 로드 → 메모리 대역폭 최대화
const float4 *logits_vec = reinterpret_cast<const float4 *>(token_logits);
// __launch_bounds__(256, 4): T4(SM당 1024스레드)에 맞춘 점유율 튜닝

그리고 SwiGLU 활성화는 이렇게 한 줄짜리 커널로 융합합니다(빠른 __expf intrinsic 사용):

__global__ void __launch_bounds__(256)
swiglu_kernel_simple_fp32(const float* __restrict__ gate,
                          const float* __restrict__ up,
                          float* __restrict__ output, const int n) {
    const int idx = blockIdx.x * blockDim.x + threadIdx.x;
    if (idx >= n) return;
    float silu_u = up[idx] / (1.0f + __expf(-up[idx]));  // SiLU
    output[idx] = gate[idx] * silu_u;                    // gate로 곱셈
}

CUDA를 처음 보더라도, "스레드 인덱스 계산 → 범위 체크 → 자기 원소 처리"라는 기본 골격과 __restrict__·__launch_bounds__ 같은 최적화 힌트를 실제 맥락에서 익힐 수 있습니다.

⑤ 런타임 커널 컴파일 — training/cuda_kernels.py

커널을 미리 빌드하지 않고, 현재 GPU 아키텍처를 감지해 nvcc를 그 자리에서 호출합니다. "C 소스를 파이썬에서 컴파일해 불러오는" 패턴을 통째로 보여 줍니다:

prop = torch.cuda.get_device_properties(0)
sm   = f"sm_{prop.major}{prop.minor}"          # 예: sm_75 (T4)
arch = f"compute_{prop.major}{prop.minor}"
cmd = ["nvcc", "-O3", "-shared", "-fPIC", "--use_fast_math",
       f"--generate-code=arch={arch},code={sm}",
       "-o", _SO_FILE, _CU_FILE]
subprocess.run(cmd, capture_output=True, text=True, timeout=180)
# 만들어진 .so는 ctypes로 로드
코드 속 숨은 함정 / 영리한 트릭 (직접 짤 때 꼭 알아둘 것)
ctypes 라이브러리 핸들은 모듈 전역에 둬야 한다

cuda_kernels.py에는 _lib_loss모듈 전역으로 두고 "지역 변수로 두면 함수 반환 후 GC돼 버린다"는 주석이 있습니다. 로드한 .so 핸들이 가비지 컬렉션되면 커널 호출이 깨지는 실제 ctypes 함정입니다.

동기화 회피로 속도를 번다

CUDA 인덱스 검증 플래그(validate_cuda_indices)가 기본 꺼짐입니다. 켜면 매 스텝 .item() 호출로 호스트-디바이스 동기화가 생겨 느려지기 때문 — "안전 검사 vs 속도"를 켜고 끄는 손잡이로 만든 좋은 예입니다.

⑥ 분산 학습 백엔드 3종 비교 — backend/

같은 인터페이스 뒤에서 DeepSpeed(ZeRO 1~3·오프로딩), FSDP, ColossalAI를 갈아끼울 수 있습니다. "큰 모델을 여러 GPU에 어떻게 쪼개나(ZeRO가 옵티마이저 상태·그래디언트·파라미터를 단계별로 분산)"를 세 방식으로 비교 학습하기에 좋습니다.

⑦ 컴퓨트 최적 학습량 — training/chinchilla_scaler.py

Chinchilla 법칙(모델 크기 대비 최적 토큰 수)을 코드로 구현합니다. ConvergenceDetector(정체·발산 감지), ComputeEfficiencyTracker(토큰당 FLOPs)로 "지금 더 학습할 가치가 있나"를 판단합니다.

⑧ 파이썬 밖으로 — C++ 추론 런타임 moe_inference_runtime/

학습된 MoE 모델을 파이썬 없이 C++로 서빙하는 별도 엔진입니다(runtime.cpp + CPU/CUDA/MPS 백엔드). "학습 코드와 추론 코드는 분리된다"는 실무 패턴을 보여 줍니다.

⑨ ML 코드 테스트 — Src/tests/

78개 pytest가 있습니다 — test_chinchilla.py(9개), test_checkpointing.py(7개), test_adaptive_logic.py(7개), test_e2e.py. "확률적이라 테스트가 어렵다는" ML 코드를 어떻게 검증하는지 참고할 만합니다.

7하드웨어 / 시스템 요구사항

"300B 파라미터"라는 말에 겁먹지 말 것 — 작은 설정은 평범한 GPU에서도 돈다.

경로요구사항 / 메모
NVIDIA (CUDA)Volta~Hopper(sm_70~sm_90). 커널을 nvcc로 즉석 컴파일하므로 CUDA Toolkit + nvcc 설치 필수. 벤치마크는 T4(16GB) 기준.
Apple SiliconM1~M4, MPS + pyobjc-framework-Metal로 Metal 커널 디스패치.
CPU 전용동작은 하지만 Flash Attention·DeepSpeed·커스텀 커널이 꺼져 느림(학습 구조 확인용).
작은 모델(입문)디버그 설정은 약 1.6GB VRAM에서 돌아 입문용 GPU로 충분.
정밀도FP32 / FP16 / BF16 / 혼합. FP8(e4m3)은 H100+에서만(Triton 경로, 실험적).
대규모(수십억+)DeepSpeed ZeRO-3 + CPU/NVMe 오프로딩 + 다중 GPU 필요. 단, 이 영역 수치는 README가 "미검증"이라 명시.
OSCUDA/Docker는 리눅스(python:3.10-slim 기반), Metal은 macOS.
현실적인 조언

공부가 목적이라면 "300B"는 잊고 가장 작은 디버그 설정으로 시작하세요. 무료 Colab(T4)이나 입문용 GPU에서 작은 모델을 몇 스텝 돌려 보며 손실이 줄어드는지, MoE 라우팅 통계가 찍히는지를 관찰하는 것만으로도 이 코드의 80%를 이해할 수 있습니다.

8직접 해볼 수 있는 실습 과제

읽기만 하면 금방 잊는다. 난이도별로 손을 움직여 보자.

실습 1 · 난이도 ★☆☆☆☆ (입문)

가장 작은 모델을 몇 스텝 학습시켜 손실 곡선 보기

디버그/소형 설정으로 Src/Main_Scripts/Main.py를 돌려, 손실이 실제로 줄어드는지 관찰하세요. 목표는 결과물이 아니라 "학습 루프가 도는 걸 내 눈으로 보는 것"입니다.

관찰 포인트: 스텝마다 loss·grad_norm·learning_rate 로그가 어떻게 변하는가? VRAM은 얼마나 쓰는가?
실습 2 · 난이도 ★★☆☆☆ (초급)

모델 프리셋을 바꿔 파라미터 수가 어떻게 변하는지 계산

config/config_manager.pyDeepSeekConfig에서 층 수·은닉 차원·전문가 수를 바꿔 보고, 내장된 파라미터 수 계산이 어떻게 달라지는지 보세요. "무엇이 모델 크기를 키우나"를 수식이 아니라 손으로 체감하게 됩니다.

실험: 전문가 수(num_experts)를 2배로 늘리면 총 파라미터와 '활성' 파라미터는 각각 어떻게 변하는가?
실습 3 · 난이도 ★★★☆☆ (중급)

MoE top-k와 전문가 수를 조절하며 부하분산 손실 관찰

MoEFFNLayertop_k·routing_temperature를 바꿔 보고, 보조 부하분산 손실과 전문가별 사용 빈도(라우팅 통계)가 어떻게 변하는지 보세요. top_k=1과 top_k=2의 차이, 온도를 높였을 때 라우팅이 고르게 퍼지는지를 확인합니다.

가설 검증: 부하분산 손실 가중치를 0으로 두면 특정 전문가에게만 일이 몰리는('expert collapse') 현상이 보이는가?
실습 4 · 난이도 ★★★★☆ (고급)

커스텀 CUDA 커널 빌드 후 PyTorch 폴백과 속도 비교

NVIDIA GPU에서 training/cuda_kernels.py로 커널을 nvcc 빌드한 뒤, core/benchmark.py / benchmark_cuda_kernels.py커스텀 커널 vs 순정 PyTorch 속도를 직접 재 보세요. README의 "2~7배" 주장을 내 GPU에서 검증하는 셈입니다.

주의: 빌드 실패 시 폴백으로 조용히 PyTorch가 돌 수 있음 — 정말 커스텀 커널이 쓰였는지 로그로 확인할 것.
실습 5 · 난이도 ★★★★★ (심화)

MoD capacity_factor로 FLOPs 절감 측정 + 오케스트레이터 관찰

MoDRoutercapacity_factor를 낮춰 가며 "몇 %의 토큰이 층을 건너뛰는지", 그때 토큰당 FLOPs(ComputeEfficiencyTracker)와 품질이 어떻게 절충되는지 측정하세요. 동시에 orchestrator.pymonitoring_loop가 발산을 감지하면 무엇을 하는지 로그로 추적합니다.

탐구: 건너뛰는 비율을 너무 높이면 어느 지점에서 손실이 망가지는가? 그 임계점은 모델 크기에 따라 달라지는가?

9관련 기술 심화 학습 로드맵

이 저장소를 '교과서'로 삼아 6주간 현대 LLM 학습을 정복하는 코스.

주차주제이 저장소에서 볼 곳 + 곁들일 자료
1주트랜스포머 기초 부품core/model.py의 RMSNorm·RoPE·GQA·SwiGLU 읽기. 곁들임: nanoGPT, "Attention is All You Need".
2주MoE / MoD 희소 구조MoEFFNLayer·MoDRouter + 라우터 학습. 논문: Switch Transformer(MoE), Mixture-of-Depths(2024).
3주분산 학습 · 메모리backend/ 3종 비교. 개념: DeepSpeed ZeRO 1~3, FSDP, CPU/NVMe 오프로딩, 그래디언트 체크포인팅.
4주GPU 커널 프로그래밍moe_cuda_ops.cu·transformer_ops.cu. 개념: 워프·셰어드 메모리·셔플·점유율(occupancy). 곁들임: NVIDIA CUDA C++ Programming Guide.
5주추론 · 양자화moe_inference_runtime/(C++ 서빙) + 4/8bit 양자화(bitsandbytes·GPTQ). 학습 후 모델을 가볍게 배포하기.
6주스케일링 · 자동화chinchilla_scaler.py·orchestrator.py. 개념: Chinchilla 컴퓨트 최적, 수렴 감지, 자율 하이퍼파라미터 튜닝.
학습 전략

한 번에 다 이해하려 하지 마세요. 1~2주(모델 구조)만 제대로 소화해도 "요즘 LLM이 어떻게 생겼나"를 코드로 아는 사람이 됩니다. CUDA(4주)는 어렵지만, §6의 두 커널 스니펫만 줄 단위로 따라가도 GPU 프로그래밍의 감을 잡을 수 있습니다.

10핵심 키워드 사전

이 문서·저장소에 나온 용어를 한 줄씩 정리. 모르면 여기로 돌아오기.

용어한 줄 뜻
MoE전문가 혼합 — 토큰마다 일부 전문가에게만 일을 맡겨 '덩치 큰데 가벼운' 모델을 만드는 구조.
MoD깊이 혼합 — 쉬운 토큰이 일부 층을 건너뛰게 학습해 FLOPs를 줄이는 기법(2024, DeepMind).
top-k 게이팅라우터가 점수 상위 k명의 전문가만 골라 토큰을 보내는 방식.
부하분산 손실특정 전문가에게만 일이 몰리지(expert collapse) 않도록 균형을 강제하는 보조 손실.
capacity factor전문가/층이 받아들이는 토큰 용량 배수 — 낮추면 계산↓ 품질 절충.
RMSNormLayerNorm의 경량 버전(평균 빼기 생략). 요즘 LLM 표준. 안정성 위해 fp32로 계산.
RoPE회전 위치 임베딩 — 위치 정보를 회전 변환으로 주입. cos/sin 테이블을 fp64로 캐시.
GQA그룹 쿼리 어텐션 — 여러 쿼리 헤드가 KV 헤드를 공유해 메모리·속도 절약.
SwiGLUSiLU 게이팅을 쓴 FFN 활성화 — 요즘 LLM이 즐겨 쓰는 구조.
Chinchilla 법칙주어진 컴퓨트에서 '모델 크기 vs 학습 토큰 수'의 최적 비율.
DeepSpeed ZeRO옵티마이저 상태·그래디언트·파라미터를 GPU들에 단계(1~3)별로 쪼개 담는 분산 기법.
FSDPPyTorch 기본 제공 완전 샤딩 데이터 병렬 — ZeRO와 유사한 메모리 절약.
오프로딩GPU에 안 들어가는 텐서를 CPU RAM·NVMe로 잠시 내려 두는 기법.
양자화가중치를 4/8bit로 줄여 메모리·속도를 버는 기법(bitsandbytes·GPTQ).
CUDA 워프(warp)GPU에서 동시에 한 명령을 실행하는 32개 스레드 묶음.
__shfl_xor_sync워프 안 스레드끼리 메모리 없이 레지스터 값을 교환하는 셔플 명령(리덕션에 사용).
바이토닉 정렬병렬 친화적 정렬 알고리즘 — 워프 안 top-k 선택에 활용.
float4 벡터화4개의 float를 한 번에 읽어 메모리 대역폭을 끌어올리는 기법.
nvccNVIDIA CUDA 컴파일러 — 이 프로젝트는 실행 시점에 호출해 커널을 빌드.
Triton파이썬으로 GPU 커널을 작성하는 DSL — FP8 경로에 사용.
Metal / MPS애플 GPU용 셰이딩 언어와 PyTorch 백엔드 — 맥에서 학습/추론 가능.
Apache Arrow제로카피·메모리맵 가능한 열 지향 데이터 포맷(polars·pyarrow).
혼합 정밀도(AMP)fp16/bf16로 계산하되 민감한 부분만 fp32로 — 속도·메모리 절약.

11참고 링크

원본 저장소와, 각 개념을 더 깊이 팔 때의 출발점.