TrendShift 딥다이브 · 2026-07-11 · Daily #1

colibri 딥다이브
— 744B 프론티어 모델을 25GB 노트북에서: "전문가를 디스크에서 흘려보내는" 순수 C 추론 엔진

colibrì(콜리브리, 이탈리아어로 "벌새")는 7,440억 파라미터(744B) 규모의 거대 MoE 모델 GLM-5.2를, RAM이 25GB뿐인 평범한 소비자용 PC에서 돌리는 추론 엔진이다. 비결은 "매 토큰마다 실제로 바뀌는 전문가(expert)들만 디스크에서 필요할 때 스트리밍"하는 것 — 모델 전체(약 370GB)를 램에 올리지 않고, 항상 쓰이는 뼈대(~9.9GB)만 램에 상주시킨다. BLAS도, 파이썬 런타임도, GPU도 없이 단일 C 파일(glm.c, 약 2,500줄)로 구현했다. 빠르지는 않다(초당 0.05~1토큰). 하지만 "H100 팬 값보다 싼 컴퓨터에서 프론티어급 모델이 정확히 답하는" 것 자체가 목적이다. (저장소: JustVugg/colibri · 제작자 1인 · 순수 C + 소량 Python 툴 · Apache 2.0 · 대상 Linux/WSL2 + AVX2 CPU · TrendShift 오늘 Daily 1위 · New 2026)
목차
  1. 프로젝트 한줄 요약
  2. 왜 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트 (기술별)
  7. 하드웨어/시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한줄 요약

이 저장소가 대체 무엇인가.

colibrì거대한 언어 모델(GLM-5.2, 744B 파라미터)을 값싼 개인 컴퓨터에서 실행하기 위한 추론 엔진이다. 보통 이만한 모델은 수십만 달러짜리 GPU 서버 여러 대가 있어야 돌아간다. colibrì는 이걸 램 25GB짜리 노트북 한 대 + 넉넉한 디스크로 해낸다. 핵심 아이디어 한 줄: "모델의 대부분(전문가들)은 디스크에 두고, 지금 이 토큰에 실제로 필요한 조각만 그때그때 읽어 온다."

한 줄 개념
MoE 스트리밍 추론 (streaming Mixture-of-Experts inference)
744B짜리 "혼합 전문가(MoE)" 모델은 토큰 하나당 전체의 극히 일부(~40B, 그중 바뀌는 건 ~11GB)만 실제로 계산에 쓴다. colibrì는 이 성질을 이용해 항상 쓰는 부분만 램에 두고, 전문가는 디스크에서 필요할 때 흘려보내듯(stream) 읽는다. "전체를 램에 올려야 한다"는 상식을 깬 것이 이 프로젝트의 전부다.
비유로 이해하기

"거대한 도서관 사서 — 모든 책을 손에 들지 않고, 지금 필요한 책만 서가에서 꺼내 온다"

744B 모델을 통째로 램에 올리는 것은, 도서관의 모든 책을 두 팔에 다 안고 다니려는 것과 같다 — 불가능하다. colibrì는 사서처럼 일한다: 자주 쓰는 참고서(뼈대, dense part)만 책상에 펼쳐 두고(램 상주), 나머지 21,504권의 전문서(routed experts)는 서가(디스크)에 두었다가 질문이 들어올 때마다 해당 책만 후다닥 꺼내 온다.

단점은 명확하다 — 서가까지 왕복하는 시간(디스크 읽기)이 병목이다. 그래서 colibrì는 "자주 꺼내는 책은 책상 근처에 미리 쌓아 두고(핫 캐시·PIN), 다음에 꺼낼 책을 예측해 미리 걸어가는(프리페치)" 온갖 사서의 지혜를 코드로 구현했다.

라이선스는 관대한 Apache 2.0이며(GLM-5.2 가중치 자체는 Z.ai가 MIT로 공개), 이탈리아어 인터페이스가 인상적인 1인 개발 프로젝트다. 실제 저장소 구성은 순수 C 엔진(c/glm.c 약 2,547줄) + 헤더 몇 개 + 일회성 변환·벤치마크용 Python 툴 + 커뮤니티가 만든 웹 UI(React)로 이뤄져 있다. TrendShift에 "New 2026"으로 오늘 Daily 1위에 올라 있다.

먼저 짚고 갈 것 — 이 문서의 초점
"느린 챗봇"이 아니라 "메모리 계층·양자화·MoE의 실전 압축 교재"

"노트북에서 744B 모델이 돈다"는 건 겉모습이다. 이 레포의 진짜 가치는 MoE 라우팅과 전문가 스트리밍 · int4/int8/int2 양자화 커널(AVX2 정수 내적) · MLA 압축 KV 캐시 · 투기적 디코딩(MTP) · LRU 캐시와 프리페치로 디스크 병목 숨기기 · OS 페이지 캐시를 공짜 L2로 쓰기 · 램 예산 자동 산정2,500줄짜리 읽을 수 있는 단일 C 파일에서 통째로 볼 수 있다는 점이다. "추론 엔진이 실제로 어떻게 동작하는가"를 밑바닥부터 배우기에 이보다 밀도 높은 교재는 드물다.

주의 — 현실 감각
"돈다"와 "쓸 만하다"는 다르다 — 이건 속도가 아니라 가능성의 증명

공식 수치조차 25GB 램 개발 PC에서 콜드 상태 초당 0.05~0.1토큰이다(한 문장에 수십 초~수 분). 저자 스스로 "This is not fast"라고 못 박는다. 디스크가 빠르고(PCIe5 NVMe) 램이 크면(128GB+) 초당 2~15토큰까지 오르지만, 이는 대부분 추정치다. 커뮤니티 측정으로 M5 Max 128GB에서 ~1.06 tok/s가 나온 정도. int4 양자화가 정확도를 얼마나 깎는지도 아직 측정되지 않았다(벤치 하네스는 있으나 느린 디스크로 하루가 걸려 미완). 즉 "학습·실험용 걸작"이지 "실사용 서빙 솔루션"은 아니다.

2왜 주목받는가

트렌딩 이유와, 기존 로컬 추론 도구(llama.cpp·ollama)와의 결정적 차이.

① "GPU가 있어야 프론티어 모델을 돌린다"는 전제를 깼다

지금까지 로컬 LLM의 상식은 "모델이 램/VRAM에 다 들어가야 한다"였다. 70B 모델도 양자화해서 겨우 48GB, 700B급은 사실상 개인은 손도 못 댔다. colibrì는 "MoE 모델은 한 토큰에 전체의 일부만 쓴다"는 구조적 성질을 파고들어, 모델 크기(370GB) ≫ 램(25GB)이라는 이제껏 불가능해 보이던 조합을 성립시켰다. "디스크가 곧 확장 램"이라는 발상의 전환이다.

핵심 통찰

744B MoE 모델 = 거대하지만 대부분이 "잠들어 있는" 뇌. 토큰 하나를 만들 때 실제로 깨어나는 뉴런(활성 파라미터)은 ~40B, 그중에서도 매번 바뀌는 부분은 ~11GB어치뿐이다. 나머지는 그 순간 안 쓰인다 → 굳이 램에 있을 이유가 없다. colibrì는 이 "안 쓰이는 대다수"를 디스크로 추방했다.

② llama.cpp·ollama와 무엇이 다른가

llama.cpp/ollama도 CPU 추론·양자화·GGUF 스트리밍(mmap)을 한다. 하지만 그들은 기본적으로 "모델이 (양자화 후) 메모리에 들어간다"를 전제로 최적화돼 있다. colibrì는 처음부터 "모델이 램보다 30배 크다"를 전제로 설계됐다 — 그래서 전문가 단위 LRU 캐시, 라우터 예측 프리페치, 핫 전문가 PIN, MoE 배치 유니온 같은 스트리밍 특화 machinery가 엔진의 중심에 있다. 또 llama.cpp가 범용 다중 모델·다중 백엔드를 지향하는 반면, colibrì는 GLM-5.2 한 모델에만 충실(faithful)하게 맞춰져 있다(MLA·DSA·MTP 등 GLM 고유 구조를 그대로 구현).

한눈에 비교
측면llama.cpp / ollamacolibrì
전제모델이 메모리에 들어감모델 ≫ 메모리 (30배)
대상범용(수백 종 모델)GLM-5.2 단일, 구조 충실 구현
전문가대개 상주(mmap 포함)디스크 스트리밍 + LRU + PIN
의존성다수 백엔드/BLAS 선택순수 C, 무의존(런타임 Python 0)
속도빠름(수십 tok/s)느림(0.05~수 tok/s, 디스크 바운드)
코드 규모수십만 줄핵심 ~2,500줄 단일 파일

③ "정직함"이 신뢰를 만든다

README가 이례적으로 솔직하다. 속도가 느리다는 것, MTP 투기가 콜드 캐시에서는 오히려 손해일 수 있다는 것, int4 정확도 손실을 아직 못 쟀다는 것을 전부 명시하고, 커뮤니티 측정치를 issue 번호까지 달아 인용한다. "help wanted — 더 좋은 하드웨어로 벤치 돌려 달라"고 공개적으로 요청한다. 과장 없는 엔지니어링 문서가 오히려 기술 커뮤니티의 강한 반응을 이끌어냈다.

④ 시의성 — GLM-5.2 같은 초대형 오픈 MoE의 등장

744B급 오픈 웨이트 MoE가 등장하면서 "이걸 개인이 어떻게든 돌려 보고 싶다"는 수요가 생겼다. colibrì는 그 수요에 "디스크만 넉넉하면 된다"는 가장 접근성 높은 답을 내놨다. FP8 체크포인트(756GB)를 한 번에 다 받지 않고 샤드 하나씩 받아 int4로 변환·삭제하는 변환기까지 붙여, 진입 장벽을 실질적으로 낮췄다.

3기술 스택 전체 지도

순수 C 엔진을 중심으로, 주변 툴이 어떻게 배치돼 있는가.

런타임 코어 (순수 C, 무의존)

구성파일역할
추론 엔진c/glm.c (~2,547줄)GLM-5.2 forward 전체 · 양자화 커널 · MoE 스트리밍 · KV 캐시 · 샘플링 · MTP
텐서 로더c/st.hsafetensors 파싱(헤더만 읽어 메모리 매핑)
토크나이저c/tok.h, tok_unicode.h바이트 단위 BPE(GPT-2식), 320k 병합, 유니코드 정규식
JSONc/json.h설정·API용 최소 JSON 파서(라이브러리 없이 손수)
메모리 계층c/tier.hDisk / RAM / VRAM 저장 계층 계획(resource plan)
CUDA 백엔드(선택)c/backend_cuda.cu/.h상주 텐서용 int8/int4/int2/f32 커스텀 커널(opt-in)
호환 계층c/compat.hOS/컴파일러 차이 흡수(Linux/WSL2/macOS)
왜 "무의존"이 중요한가
zero dependencies (BLAS·PyTorch·CUDA 없이도 동작)
런타임에 필요한 건 gcc + OpenMP + AVX2뿐. serde/json 라이브러리조차 안 쓰고 손으로 파싱한다. 덕분에 어떤 리눅스 박스에서도 ./setup.sh 한 번이면 빌드된다. 파이썬은 일회성 모델 변환에만 쓰이고, 추론 경로엔 전혀 없다.

도구 계층 (Python — 런타임 아님)

도구역할
coli (CLI, Python)사용자 진입점. chat/serve/run/plan/convert/bench/build 서브커맨드를 C 엔진(glm)에 위임하는 래퍼
tools/convert_fp8_to_int4.pyFP8 원본을 샤드 단위로 받아 int4 컨테이너로 재양자화 후 원본 삭제(756GB를 한 번에 두지 않음, 재개 가능)
tools/download_glm52.pyHuggingFace에서 GLM-5.2 체크포인트 내려받기
tools/convert_fp8_to_int4.py + MTP투기적 디코딩용 MTP 헤드를 int8로 변환(int4면 draft 채택률 붕괴)
openai_server.py표준 라이브러리만으로 만든 OpenAI 호환 HTTP 게이트웨이(추론은 여전히 C 엔진)
resource_plan.py / eval_glm.py / make_glm_oracle.py저장 계층 계획 · 품질 벤치(MMLU/HellaSwag/ARC) · transformers 대조용 오라클 생성
iobench.c"내 디스크가 엔진이 쓰는 방식(19MB 병렬 랜덤 읽기)으로 얼마나 빠른가" 측정

프론트엔드 (커뮤니티 기여, 선택)

web/React + TypeScript + Vite로 만든 브라우저 채팅 UI(~390줄). 엔진을 직접 건드리지 않고 순수 OpenAI Chat Completions 클라이언트로만 동작한다 — coli serve가 띄운 서버(또는 다른 호환 엔드포인트)에 SSE 스트리밍으로 붙는다. shadcn/ui 스타일 컴포넌트(button/input/badge/textarea)를 쓴다. 저자는 "터미널 coli chat이 여전히 1급 인터페이스"라고 명시한다.

전체 그림

C 엔진(glm.c)이 심장이고, coli(Python CLI)는 그 심장을 편하게 부르는 리모컨, openai_server.py는 표준 프로토콜 어댑터, web/는 그 프로토콜에 붙는 껍데기다. 심장만 있으면 나머지는 전부 옵션 — 이 계층 분리가 colibrì 설계의 뼈대다.

4아키텍처 심화 분석

"디스크가 램보다 30배 큰 모델을 어떻게 돌리는가"의 실제 메커니즘.

4-1. 저장 계층: dense는 램, expert는 디스크

colibrì 설계의 출발점은 GLM-5.2를 두 덩어리로 쪼개는 것이다.

GLM-5.2 (744B) 를 두 부분으로 분리 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [ DENSE PART · 항상 쓰임 · ~17B params ] [ ROUTED EXPERTS · 가끔 쓰임 ] ┌─────────────────────────────────┐ ┌──────────────────────────┐ │ 어텐션(MLA) · 공유 전문가 │ │ 75 MoE층 × 256 전문가 │ │ 임베딩 · 앞 3개 dense층 │ │ + MTP 헤드 │ │ │ │ = 21,504 전문가 │ │ int4 로 ~9.9 GB │ │ 각 ~19MB(int4) │ │ ➜ RAM 에 상주(resident) │ │ = 총 ~370 GB │ └─────────────────────────────────┘ │ ➜ DISK 에 보관 │ │ 필요할 때만 스트리밍 │ └──────────────────────────┘ 한 토큰이 실제로 건드리는 전문가: 층당 top-8 → 75층 × 8 × 19MB ≈ 11.4 GB 읽기(콜드)

매 토큰마다 라우터가 각 층에서 256명 중 8명의 전문가를 고른다. colibrì는 그 8명의 가중치만 디스크에서 읽어 계산하고, 안 쓰인 나머지는 건드리지 않는다. 그래서 "콜드"(캐시 비었을 때) 한 토큰의 비용이 약 11.4GB의 디스크 읽기다 — 이게 속도의 근본 병목이다.

3단 메모리 계층
VRAM(핫) → RAM(LRU 캐시 + PIN) → Disk(원본) + OS 페이지 캐시(공짜 L2)
PIN: 자주 쓰는 전문가를 램/VRAM에 못 박아 둠. LRU 캐시: 최근 쓴 전문가를 층별로 유지(cap이 램 예산에 맞춰 자동 조절). OS 페이지 캐시: 리눅스가 이미 읽은 파일을 램에 캐싱하므로, 같은 전문가 재읽기는 공짜 — colibrì는 이걸 L2 캐시로 활용한다.

4-2. 디스크 병목을 숨기는 다섯 가지 기법

기법 ①

학습 캐시 (learning cache · .coli_usage)

엔진이 "당신의 사용 패턴이 실제로 어떤 전문가를 부르는지"를 매 턴 기록한다. 재시작 시 그 가장 자주 쓰인 전문가들을 남는 램에 자동 PIN한다. 문자 그대로 쓸수록 빨라진다. Framework 13(128GB)에서 이 학습 PIN으로 전문가 히트율 28%→66%까지 올라 속도가 붙었다(측정치).

기법 ②

라우터 예측 프리페치 (router-lookahead, PILOT=1)

놀랍게도 다음 층의 라우팅은 미리 71.6% 예측 가능하다(층 L의 어텐션 후 상태에 층 L+1의 라우터를 적용하면 실제 top-8의 71.6%를 맞춘다 — "직전 토큰과 같은 전문가"의 41.3%보다 훨씬 높다). 이를 이용해 현재 층을 계산하는 동안 별도 I/O 스레드가 다음 층 전문가를 미리 디스크에서 읽어 둔다.

기법 ③

MTP 투기적 디코딩 (native multi-token prediction)

GLM-5.2 자체의 MTP 헤드(78층)가 다음 토큰들을 미리 초안(draft)으로 뽑고, 본 모델이 한 번의 배치 forward로 검증한다. 채택되면 여러 토큰을 한 번에 확정 → forward당 2.2~2.8토큰. 단 헤드는 반드시 int8이어야 한다(int4면 채택률 0~4%로 붕괴). 무손실(rejection sampling으로 샘플링에서도 손실 없음)이지만, 콜드 캐시에선 오히려 전문가 로드가 늘어 시간상 손해일 수 있어 적응형 가드로 켜고 끈다.

기법 ④

MLA 압축 KV 캐시 + 가중치 흡수

GLM-5.2는 64헤드에 GQA가 없어 KV 캐시가 원래 거대하다(토큰당 32,768 float). MLA(q/kv-LoRA)로 이를 토큰당 576 float로 압축(57배 작게). 게다가 디코드 시 DeepSeek식 "가중치 흡수"로 토큰마다 k/v를 재구성하지 않는다 — 쿼리가 kv_b를 흡수하고 문맥은 어텐션 후 투영. 정확도는 token-exact로 검증됨.

기법 ⑤

배치 유니온 MoE + 비동기 readahead

프리필(그리고 MTP 검증)에서 배치의 각 고유 전문가를 디스크에서 딱 한 번만 읽어 그 전문가로 라우팅된 모든 위치에 적용한다(같은 책을 여러 번 안 꺼냄). 동시에 한 블록의 전문가를 곱하는 동안 커널이 이미 WILLNEED로 다음 블록을 읽고 있다(비동기 선読).

4-3. 양자화 커널 — 정수 내적으로 CPU에서 빠르게

colibrì는 가중치를 int8 / packed int4 / packed int2로 저장하고, 활성값도 int8로 양자화해(Q8_0식) 정수 내적(AVX2 maddubs)으로 곱한다. 측정상 int8 matmul이 1.4~2.5배(119 GFLOP/s), int4가 배치에서 1.8배 빠르다. 재밌는 디테일: 어떤 커널을 쓸지 모양(shape)별로 실측으로 결정한다 — int4 단일 행(디코드)은 오히려 f32가 빨라서 그렇게 둔다.

한 토큰 생성 파이프라인 (decode, 개념도) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 입력 토큰 │ ▼ [임베딩] ──► [층 0..2: dense] ──► [층 3..77: MoE] │ ┌───────────┴───────────┐ │ 1) MLA 어텐션(압축 KV) │ ← 램 상주 │ 2) 라우터: 256중 top-8 │ │ 3) 전문가 8명 로드: │ │ RAM캐시? → 히트(빠름) │ │ 없으면 → 디스크 읽기 │ ← 병목 │ 4) int4/int8 정수 matmul │ └───────────┬───────────┘ ▼ [MTP 헤드(int8): 다음 토큰 초안] ──► 본 모델이 배치 검증 ▼ [샘플링: temp 0.7 + nucleus 0.90] ──► 출력 토큰 ▼ [압축 KV를 .coli_kv 에 append (warm 재개용)]

4-4. FP8 → int4 오프라인 변환 (디스크 절약의 묘수)

원본 GLM-5.2는 FP8로 756GB다. 이걸 한 번에 디스크에 두는 건 부담이다. 변환기는 샤드 하나(~5GB)만 받아 → 역양자화(128×128 블록 스케일) → 엔진 컨테이너로 재양자화 → 그 샤드 삭제를 반복한다. 그래서 756GB가 동시에 존재할 필요가 없다. 중단 후 재개도 된다. 결과물은 int4로 ~370GB.

4-5. 서빙 모델 — 하나의 KV 컨텍스트, 정직한 큐

coli serve는 744B 모델을 한 프로세스에 한 번만 올려 두고 OpenAI 호환 HTTP를 연다. 동시 요청은 병렬로 "척"하지 않고 경계형 FIFO 큐에 넣는다(--max-queue 8). 엔진이 가변 KV 컨텍스트 하나를 소유하기 때문이다. 포화·타임아웃 요청엔 OpenAI 형식 HTTP 429를 반환하고, --kv-slots N으로 최대 16개 독립 시퀀스 컨텍스트를 둘 수 있다(각 슬롯이 자기 KV·MTP·.coli_kv 소유). "스레드로 돌리니 연속 배치인 척"하지 않는 정직한 설계다.

5디렉토리 구조 해부

런타임 경로는 일부러 평평하고 읽기 쉽게, 도구는 따로.

colibri/ ├── Makefile 루트 빌드/체크 진입점(c/Makefile에 위임) ├── README.md ~25KB, 이례적으로 솔직한 설계 문서 ├── ref.json 참조 설정 ├── c/ ◆ 엔진 본체 │ ├── glm.c ★ 단일 파일 GLM 엔진 (~2,547줄) │ ├── st.h safetensors 로더 │ ├── tok.h 바이트 BPE 토크나이저 │ ├── tok_unicode.h 유니코드 속성 테이블(gen_unicode.py 생성) │ ├── json.h 최소 JSON 파서 │ ├── tier.h Disk/RAM/VRAM 저장 계층 계획 │ ├── compat.h OS/컴파일러 호환 흡수 │ ├── backend_cuda.cu 선택적 CUDA 커널(q8/q4/q2/f32) │ ├── backend_cuda.h │ ├── coli ★ 사용자 CLI (Python 래퍼) │ ├── openai_server.py OpenAI 호환 HTTP 게이트웨이(stdlib만) │ ├── setup.sh 원커맨드 빌드+자가검증(32/32 기대) │ ├── iobench.c 디스크 랜덤읽기 벤치 │ ├── olmoe.c (다른 MoE 실험/참고 구현) │ ├── resource_plan.py 저장 계층 계획 산출 │ ├── ref_glm.json GLM 참조 스펙 │ ├── tools/ ◆ 오프라인 변환·픽스처·벤치 (런타임 아님) │ │ ├── convert_fp8_to_int4.py FP8→int4 샤드단위 변환 │ │ ├── download_glm52.py 체크포인트 다운로드 │ │ ├── convert_fp8_to_int4.py (+MTP 헤드 int8 변환) │ │ ├── eval_glm.py MMLU/HellaSwag/ARC 벤치 │ │ ├── make_glm_oracle.py transformers 대조 오라클 │ │ ├── make_glm_bench_model.py 313M 결정적 픽스처(구조만 보존) │ │ ├── benchmark_cuda_fixture.py CPU vs CUDA A/B │ │ └── gen_unicode.py 유니코드 테이블 생성 │ ├── scripts/ run.sh / supervisor.sh (장시간 변환 헬퍼) │ └── tests/ 무의존 C·Python 테스트 │ ├── test_json.c test_st.c test_tier.c test_tok.c │ ├── test_openai_server.py test_resource_plan.py │ └── test_backend_cuda.cu test_benchmark_cuda_fixture.py └── web/ ◆ 커뮤니티 브라우저 UI (순수 OpenAI 클라이언트) ├── src/App.tsx 채팅 화면(~390줄 소스) ├── src/lib/api.ts OpenAI SSE 스트리밍 클라이언트 + api.test.ts └── src/components/ui/ badge/button/input/textarea (shadcn 스타일)
읽기 순서 추천
이 레포를 처음 열었다면

README.md로 설계 철학과 수치를 잡고 → ② c/coli(Python CLI)로 사용자가 무엇을 부를 수 있는지 보고 → ③ c/glm.c 상단의 typedef struct들(텐서 QT, 전문가 slab, Model 구조체)로 데이터 모델을 파악한 뒤 → ④ matmul_i4_idot/dot_i4i8 같은 양자화 커널과 MoE 라우팅 부분을 정독하는 순서가 가장 빠르다. 테스트(c/tests/)가 무의존이라 각 부품을 독립 실행해 보며 이해하기 좋다.

6학습 포인트 (기술별)

이 레포에서 무엇을, 어떻게 배울 수 있는가.

① MoE(혼합 전문가) 구조를 코드로 이해하기

이론으로만 듣던 "라우터가 전문가를 고른다"를 실제 C 코드로 본다: DeepSeek-V3식 sigmoid 라우터(noaux_tc, routed_scaling_factor), 공유 전문가, 앞 3개 dense층, top-k 선택. 왜 MoE가 "크지만 활성은 작다"인지, 왜 이게 스트리밍을 가능하게 하는지 몸으로 익힌다.

실습 아이디어
라우팅 로그 찍어 보기
STATS=stats.txt ./coli chat로 실제 어떤 전문가가 얼마나 불리는지 기록하고, 분포를 시각화해 보라. "몇몇 전문가가 압도적으로 자주 쓰인다"는 걸 눈으로 확인하면 PIN/학습 캐시가 왜 효과적인지 이해된다.

② 양자화 커널 — 정수 SIMD의 실전

dot_i8i8, dot_i4i8, matmul_i4_idot를 읽으면 AVX2 _mm256_maddubs_epi16로 int8×int8을 어떻게 누산하는지, 왜 활성값도 양자화(per-row scale)하는지, packed int4를 어떻게 언패킹하며 곱하는지가 보인다. "양자화 = 정확도 손실"만 알던 사람이 "양자화 = 정수 SIMD로 CPU에서 몇 배 빠르게"라는 반대 면을 배운다.

③ 메모리 계층 설계 (캐싱의 정수)

LRU 캐시, PIN(핫 세트), OS 페이지 캐시를 L2로 재활용, 램 예산에서 캐시 cap 자동 산정 — 이건 사실상 운영체제 캐싱 이론의 응용 사례다. CS 교과서의 "캐시 계층·지역성(locality)"이 실제 성능을 어떻게 좌우하는지 살아 있는 코드로 확인할 수 있다.

④ 투기적 디코딩(speculative decoding)의 실제

MTP 헤드로 초안을 뽑고 본 모델이 검증하는 흐름, rejection sampling으로 무손실을 유지하는 법, "콜드 캐시에선 오히려 손해"라는 현실적 트레이드오프까지. 논문에서만 보던 speculative decoding이 왜 항상 이득이 아닌지 체감한다.

⑤ "라이브러리 없이 손으로" 짜는 시스템 프로그래밍

JSON 파서·BPE 토크나이저·safetensors 로더·SSE 스트리밍을 외부 의존성 0으로 구현한 코드를 본다. 무엇이 정말로 "필수 의존성"이고 무엇이 습관적으로 끌어다 쓰는 것인지 판단하는 감각이 길러진다.

기술 → 배울 것 요약
기술이 레포에서 배우는 것
MoE라우터·전문가·활성 파라미터, 스트리밍이 가능한 이유
양자화int8/int4/int2 패킹, AVX2 정수 내적, shape별 커널 선택
캐싱LRU·PIN·페이지 캐시·예산 기반 자동 cap
KV 캐시MLA 압축(57배), 가중치 흡수, 디스크 영속화(warm 재개)
디코딩MTP 투기, rejection sampling 무손실, 적응형 가드
I/OWILLNEED 선読, O_DIRECT, 병렬 랜덤 읽기 벤치(iobench)
서빙OpenAI 호환 API, FIFO 큐, KV 슬롯 격리

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

"돌리려면" 최소 무엇이, "쓸 만하려면" 무엇이 필요한가.

최소 요구사항 (엔진 기준)

항목요구
OSLinux 또는 WSL2 (macOS도 커뮤니티 검증됨)
컴파일러gcc + OpenMP
CPUAVX2 지원 (정수 커널 필수)
RAM≥16GB (dense int4 ~9.9GB 상주 + 여유)
디스크로컬 NVMe에 int4 모델 ~370GB (ext4 권장, 네트워크/9p 마운트 불가)
변환 시(1회)python + torch·safetensors·huggingface_hub·numpy, ~400GB 여유
중요 — 디스크가 전부다
속도를 결정하는 건 GPU가 아니라 "디스크 랜덤 읽기 속도"와 "램 크기"

콜드 디코드는 토큰당 ~11GB 랜덤 읽기 → 디스크 대역폭이 곧 속도 상한. 램이 작으면(24GB) 전문가 캐시가 층당 2슬롯으로 자동 축소돼, 디스크가 아무리 빨라도 캐시 미스로 콜드에 머문다(램이 binding 제약). 반대로 램이 크면 콜드 읽기가 공짜 캐시 히트로 바뀐다. SSD 수명 주의: 스트리밍은 읽기 전용이라 마모는 적으나, 램 부족 시 swap 쓰기와 장시간 발열이 진짜 위험이다 — 합리적 --ram 예산을 지켜라.

기대 성능 (하드웨어별)

머신기대 속도
개발 PC (WSL2 VHDX ~1GB/s, 25GB RAM)~0.05~0.1 tok/s 콜드 (검증된 기준선)
네이티브 리눅스, PCIe4 NVMe(~3~5GB/s), 32GB~0.5~1 tok/s (추정)
PCIe5 NVMe/2×NVMe RAID0(~8~12GB/s), 64GB + PIN 40GB~2~4 tok/s (추정)
128~256GB RAM, 12코어 (핫 전문가 캐시)~2~4 tok/s, matmul 바운드 (추정)
+ 24~32코어 또는 AVX-512/VNNI 커널~5~15 tok/s, 대화형 (추정)

실측 커뮤니티 수치: Apple M5 Max(128GB unified, 14.2GB/s SSD)에서 ~1.06 tok/s(전문가 히트 23%), Framework 13 Ryzen AI 9(128GB, 학습 PIN 46.7GB)에서 0.37 tok/s(히트 66%, MTP 채택 52%). 램이 클수록 병목이 디스크에서 커널로 넘어간다.

CUDA는 어떤가
GPU는 "전문가 가속기"가 아니라 "상주 텐서용"(선택)
전문가를 매번 GPU로 복사하면 디스크 병목이 PCIe 병목으로 바뀔 뿐이라, 스트리밍 전문가는 CPU 경로에 남는다. CUDA 백엔드는 상주 양자 텐서와 핫 전문가 PIN(VRAM 계층)에만 opt-in으로 쓰인다. 아직 end-to-end 속도 향상은 주장하지 않는(측정 전) 실험 단계다.

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

모델 없이도 할 수 있는 것부터, 전체를 돌리는 것까지.

난이도 ★☆☆ — 모델 다운로드 없이

1. 엔진 빌드 + 자가검증 읽기

cd c && ./setup.sh로 gcc/OpenMP 확인·빌드·자가검증(32/32)을 돌린다. 그다음 c/tests/test_json.c, test_tok.c를 직접 컴파일·실행해 JSON 파서와 BPE 토크나이저가 어떻게 동작하는지 입력을 바꿔 가며 관찰한다. 모델 가중치가 전혀 필요 없다.

난이도 ★☆☆

2. 내 디스크 실측 (iobench)

gcc -O2 -fopenmp iobench.c -o iobench 후 아무 큰 파일에 대해 ./iobench <file> 19 64 8 0(버퍼드)과 ... 8 1(O_DIRECT)을 돌려, 엔진이 실제로 쓰는 방식(19MB 병렬 랜덤 읽기)으로 내 SSD가 몇 GB/s인지 잰다. 이 숫자로 위 성능표의 어느 행에 내 머신이 앉는지 예측할 수 있다.

난이도 ★★☆ — 픽스처로

3. 313M 결정적 픽스처로 백엔드 A/B

python tools/make_glm_bench_model.py --output ... 실제 언어모델은 아니지만 MLA/MoE/스트리밍 shape를 똑같이 보존한 313M 랜덤 가중치 모델을 만든다. 그다음 benchmark_cuda_fixture.py로 CPU 스트리밍 vs CUDA 상주 vs 핫 전문가 실행을 같은 토큰으로 비교한다. 744GB 체크포인트 없이 아키텍처를 실험하는 정석 루트.

난이도 ★★★ — 전체 모델

4. GLM-5.2 int4 받아서 실제 채팅

HuggingFace의 사전 변환된 jlnsrk/GLM-5.2-colibri-int4를 받아(변환 단계 생략) COLI_MODEL=... ./coli chat으로 대화한다. 한 턴 뒤 stats 라인(tok/s·전문가 히트율·RSS)을 읽고, --topp 0.7을 켜 디스크 읽기 30~40% 절감 효과를 직접 측정해 본다. (MTP 헤드는 int8 버전을 써야 투기가 동작.)

난이도 ★★★ — 프로젝트가 가장 원하는 것

5. 품질 벤치마크 돌려 issue에 올리기

./coli bench로 MMLU/HellaSwag/ARC를 돌린다. int4 양자화가 정확도를 얼마나 깎는지는 아직 아무도 못 쟀다 — 저자가 공개적으로 "help wanted"로 요청한 그 측정이다. 빠른 디스크가 있다면 이 한 번의 실행이 프로젝트에 가장 큰 기여가 된다(풀 정밀도 GLM-5.2는 이 태스크들에서 85~95%대).

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

colibrì를 완전히 소화하기 위한 4주 코스.

1주차 — Transformer & MoE 기초

어텐션·KV 캐시의 개념을 잡고, MoE가 "왜 크지만 활성은 작은가"를 이해한다. GLM-5.2의 MLA(다중 헤드 잠재 어텐션)DeepSeek식 sigmoid 라우터 논문을 훑는다. 목표: glm.c의 forward 흐름을 위→아래로 따라 읽을 수 있게 되기.

2주차 — 양자화 & SIMD

int8/int4/int2 양자화(per-row scale, 블록 스케일), Q8_0 포맷, AVX2 정수 명령(maddubs, madd)을 공부한다. dot_i8i8/dot_i4i8를 손으로 따라 계산해 본다. 목표: "왜 정수 내적이 f32보다 빠른가"를 수치로 설명하기.

3주차 — 메모리 계층 & I/O

가상 메모리·페이지 캐시·madvise(WILLNEED)·O_DIRECT·mmap을 익힌다. LRU/캐시 지역성 이론과 colibrì의 PIN·학습 캐시를 연결한다. iobench.c로 버퍼드 vs O_DIRECT 차이를 실측한다. 목표: "디스크가 램의 확장이 되는" 조건을 설명하기.

4주차 — 디코딩 최적화 & 서빙

투기적 디코딩(draft-verify, rejection sampling), nucleus/temperature 샘플링, KV 압축·영속화를 파고든다. openai_server.py로 OpenAI 호환 API·SSE 스트리밍·FIFO 큐를 이해한다. 목표: colibrì의 성능 트레이드오프(콜드/웜, MTP on/off)를 스스로 튜닝하기.

더 넓게

colibrì를 이해하면 llama.cpp / vLLM / DeepSeek·GLM 계열 논문이 훨씬 잘 읽힌다. 이 레포는 그 큰 세계로 들어가는 "작지만 완결된" 관문이다. 반대로 각 부품(양자화·KV 압축·투기 디코딩)은 독립적으로도 깊은 주제라, 관심 가는 하나를 골라 논문→구현으로 파고들기 좋다.

10핵심 키워드 사전

문서에 나온 용어를 한자리에.

용어
MoE (Mixture-of-Experts, 혼합 전문가)
층마다 여러 "전문가" 신경망을 두고, 라우터가 토큰별로 그중 소수(top-k)만 골라 쓰는 구조. 전체는 크지만 토큰당 활성 파라미터는 작다 → 스트리밍이 가능해지는 근본 이유.
용어
routed expert vs dense part
routed expert=토큰마다 라우팅으로 골라 쓰는 전문가(21,504개, 디스크). dense part=어텐션·공유전문가·임베딩 등 항상 쓰는 뼈대(~17B, 램 상주).
용어
전문가 스트리밍 (expert streaming)
전문가 가중치를 램에 상주시키지 않고 필요한 순간 디스크에서 읽어 오는 것. colibrì의 핵심. 병목은 디스크 랜덤 읽기 속도.
용어
int4 / int8 / int2 양자화
가중치를 4/8/2비트 정수로 압축해 용량·연산을 줄이는 기법. colibrì는 컨테이너로 저장하고 AVX2 정수 내적으로 곱한다. 정밀도↓ ↔ 속도·용량↑ 트레이드오프.
용어
MLA (Multi-head Latent Attention)
KV를 저차원 잠재공간(LoRA)으로 압축해 KV 캐시를 대폭 줄이는 어텐션. GLM-5.2에서 토큰당 32,768→576 float(57배). "가중치 흡수"로 디코드 시 재구성도 생략.
용어
KV 캐시 (key-value cache)
이미 처리한 토큰의 어텐션 키/값을 저장해 재계산을 피하는 캐시. colibrì는 이를 압축(MLA)하고 디스크에 영속화(.coli_kv)해 재시작 후에도 대화를 warm하게 이어간다.
용어
MTP (Multi-Token Prediction) / 투기적 디코딩
모델의 MTP 헤드가 다음 토큰들을 미리 초안으로 뽑고, 본 모델이 한 번에 검증해 여러 토큰을 확정하는 가속 기법. 헤드는 int8 필수. rejection sampling으로 무손실.
용어
PIN / 학습 캐시 (learning cache)
PIN=자주 쓰는 전문가를 램/VRAM에 못 박아 두기. 학습 캐시=사용 패턴(.coli_usage)을 기록해 가장 자주 쓰는 전문가를 자동 PIN → "쓸수록 빨라짐".
용어
라우터 예측 프리페치 (PILOT)
다음 층 라우팅이 71.6% 예측 가능하다는 성질을 이용해, 현재 층 계산 중에 별도 I/O 스레드가 다음 층 전문가를 미리 디스크에서 읽는 실험 기능.
용어
DSA (lightning indexer, sparse attention)
GLM-5.2의 희소 어텐션 — 층별로 인과적 top-2048 키만 선택. 모든 키를 유지하도록 강제하면 dense 어텐션과 token-exact로 일치(검증됨). DSA=0으로 끌 수 있다.
용어
O_DIRECT / WILLNEED / OS 페이지 캐시
O_DIRECT=커널 캐시 우회 직접 읽기. WILLNEED=madvise로 "곧 필요"를 알려 선読. 페이지 캐시=이미 읽은 파일을 램에 캐싱하는 OS 기능 → colibrì가 공짜 L2로 활용.
용어
safetensors
가중치를 안전·고속으로 저장하는 텐서 포맷. colibrì는 헤더만 읽어 dense/expert 크기를 파악하고(coli plan), 텐서는 필요할 때 매핑한다.
용어
tok/s · 콜드/웜 · 전문가 히트율
tok/s=초당 생성 토큰 수. 콜드=캐시 비어 디스크 읽기 많음, =캐시 채워져 빠름. 히트율=필요한 전문가가 램 캐시에 있던 비율(높을수록 빠름).

11참고 링크

더 깊이 파고들 곳.