kimi-k3-in-c: 2.78조 파라미터 모델을 GPU 없이 8GB 램에서 돌리는 C99 추론 엔진

kimi-k3-in-c 소개

큰 모델을 내 컴퓨터에서 돌리려 할 때 막는 것은 대개 연산 속도가 아니라 용량입니다. Moonshot AI가 공개한 Kimi K3는 파라미터가 2조 7,800억 개이고, 배포되는 체크포인트는 96개 샤드에 나뉜 1.56TB 입니다. 모든 가중치를 bfloat16으로 램에 올리면 5,560GB가 필요합니다. 이 숫자 앞에서는 더 빠른 GPU를 기다려도 소용이 없습니다. 벽이 속도가 아니라 용량이기 때문입니다.

kimi-k3-in-c는 이 모델을 GPU 없이, 프레임워크 없이, BLAS 없이 C99로 다시 구현한 추론 엔진입니다. 핵심 관찰은 Kimi K3가 전문가 혼합(Mixture of Experts) 모델이라는 점입니다. 93개 레이어 중 라우팅을 수행하는 92개 레이어는 토큰 하나마다 896개 전문가 중 16개만 깨우고 나머지 880개는 디스크에서 잠들어 있습니다. 항상 쓰이는 부분만 메모리에 두고 잠든 전문가는 필요할 때 읽어 오면, 측정된 최대 상주 메모리는 8.24GB까지 내려갑니다. 엔진 바이너리 자체는 179,736바이트, 176KB 짜리 파일 하나입니다.

이 저장소가 흥미로운 지점은 압축률보다 출력이 변하지 않는다는 조건을 지켰다는 데 있습니다. 저자는 8GB부터 224GB까지 12개 메모리 예산에서 같은 프롬프트를 돌려 생성된 토큰 ID가 전부 동일했다고 측정 결과를 공개했습니다. 메모리를 더 주면 답이 좋아지는 것이 아니라 시계만 빨라집니다. 가중치를 추가로 줄이거나 버린 것이 아니라 바이트를 어디에 둘지에 대한 결정만 바꿨기 때문입니다.

kimi-k3-in-c가 기존 로컬 실행 방식과 다른 점

로컬에서 대형 모델을 돌리는 흔한 접근은 양자화로 가중치를 더 낮은 정밀도로 줄여 램에 올리는 것으로 알려져 있습니다. 이 방식은 모델 전체가 메모리에 들어가야 한다는 전제를 유지한 채, 들어갈 수 있을 만큼 모델을 깎습니다. 정밀도를 깎으면 출력도 원본과 달라지고, 얼마나 달라지는지는 별도로 평가해야 합니다.

kimi-k3-in-c는 전제 쪽을 바꿉니다. 저자는 이를 네 번의 축소로 정리하는데, 각 단계에서 가중치를 손대지 않고 저장 위치만 옮깁니다.

단계 필요 메모리 무엇이 바뀌었나
모든 가중치를 bf16으로 상주 5,560 GB 출발점, 멀티 GPU 서버 클러스터
배포된 체크포인트 그대로 1,560 GB 전문가가 이미 4비트로 배포됨
라우팅으로 상주 집합만 남김 113.49 GB 전문가 1.45TB는 램에 올릴 필요가 없음
트렁크를 스트리밍 8.24 GB 상주 하한선이 조절 가능한 값이 됨

bfloat16 기준으로는 675배, 배포 체크포인트 기준으로는 189배 줄어든 값입니다. 저자는 "Nothing is approximated and no weight is dropped" 라고 명시하며, 이 사다리의 맨 아래 출력이 맨 위 출력과 바이트 단위로 같다고 밝히고 있습니다.

체크포인트 안에서 무엇이 자리를 차지하고 있는지 보면 이 전략이 왜 통하는지 분명해집니다.

라우팅 전문가는 82,432개이고 하나당 정확히 17,547,264바이트를 차지해 합계 1.447TB, 체크포인트의 92.7%입니다. 어텐션 투영, 라우터, 정규화, 임베딩을 합친 나머지가 7%에 불과합니다. 토큰 하나에 실제로 관여하는 파라미터는 약 1,040억 개로 전체의 3.7% 입니다.

kimi-k3-in-c는 누구에게 유용한가

실용적인 추론 서비스를 찾고 있다면 이 저장소는 답이 아닙니다. 8GB 구성에서 토큰 하나에 약 26.5초가 걸리고, 체크포인트를 받는 데만 1.56TB 다운로드와 약 1.7TB의 여유 저장 공간이 필요합니다. 챗 템플릿이 없는 베이스 모델 연속 생성이라 대화형으로 쓰기도 어렵습니다.

반대로 대형 언어 모델의 내부 동작을 코드 수준에서 이해하려는 사람, MoE 라우팅과 4비트 포맷 디코딩과 KV 캐시를 프레임워크 없이 직접 구현해 보려는 사람, 그리고 메모리 예산이 추론 시스템 설계를 어떻게 좌우하는지 실측 데이터로 보고 싶은 사람에게는 참고 자료로서 가치가 큽니다. 커널부터 스트리밍 캐시, safetensors 리더, 토크나이저까지 전부 읽을 수 있는 분량의 C 코드로 들어 있고, 체크포인트 없이도 make test 로 전체 테스트 스위트를 1분 안에 돌려볼 수 있습니다.

kimi-k3-in-c의 네 가지 축소 전략

MXFP4로 이미 4비트인 전문가

라우팅 전문가는 bfloat16이 아니라 MXFP4라는 마이크로스케일링 4비트 부동소수점 형식으로 배포됩니다. 가중치 하나가 4비트 니블이고 이 니블이 16개 항목짜리 조회 테이블을 가리키며, 연속된 32개 가중치가 8비트 지수 하나를 공유합니다. 가중치당 0.5바이트에 공유 스케일 몫 1/32바이트를 더하면 0.53125바이트가 되고, 전문가 하나의 파라미터 33,030,144개에 곱하면 17,547,264바이트가 정확히 나옵니다. 저자는 이 형식을 문서가 아니라 배포된 체크포인트의 실제 바이트와 대조해 확인했습니다.

문맥이 길어져도 커지지 않는 어텐션

93개 레이어 중 69개는 Kimi Delta Attention(KDA)을 씁니다. 일반적인 어텐션은 지금까지 본 모든 토큰의 키와 값을 저장하므로 캐시가 문맥 길이에 비례해 계속 자랍니다. KDA는 헤드마다 고정 크기 행렬 하나를 두고 토큰이 들어올 때마다 제자리에서 갱신합니다. 헤드 96개에 128 \times 128 행렬이면 레이어 하나의 메모리가 끝나고, 93개 레이어를 다 합쳐도 626.25MB로 고정입니다. 토큰을 10개 넣든 100만 개 넣든 같은 값입니다.

나머지 24개 레이어는 전역 어텐션이 필요해 게이트가 붙은 다중 헤드 잠재 어텐션(MLA)을 씁니다. 헤드마다 키와 값을 따로 저장하는 대신 토큰을 작은 잠재 벡터 하나로 투영해 그것만 캐시하고, 필요할 때 헤드별 키와 값을 다시 만들어 냅니다.

트렁크 스트리밍이 하한선을 다이얼로 바꾼다

전문가를 제외하고 남은 108.81GB의 덴스 트렁크는 토큰마다 모든 레이어가 쓰이므로 건너뛸 부분이 없습니다. 그래서 질문은 "어떻게 안 읽을까"가 아니라 "어디에 둘까"가 됩니다. 엔진은 예산에 들어가는 만큼의 앞쪽 레이어를 고정으로 붙박아 두고, 나머지는 회전하는 슬롯 하나를 통해 순환시킵니다.

여기서 캐시가 아니라 접두 고정 이라는 점이 중요합니다. 엔진은 토큰마다 0번부터 92번 레이어를 같은 순서로 훑는데, 이 순환 스캔은 LRU 방식이 가장 크게 실패하는 상황입니다. 0번 레이어 차례가 다시 돌아올 때쯤이면 그것이 가장 오래 안 쓰인 항목이 되어 이미 쫓겨나 있기 때문입니다. 저자는 93개 레이어 순환에 90슬롯 LRU를 쓰면 적중률이 정확히 0이 되지만, 앞의 N개를 고정하면 N/93이 결정적으로 보장된다고 설명합니다. N이 90이면 96.8%입니다.

디스크 읽기 방식도 측정으로 결정했습니다. 저자의 워크스테이션에서는 페이지 캐시를 우회하는 O_DIRECT 읽기가 3.2GB/s로, 버퍼드 읽기의 2.3GB/s보다 빨랐습니다. 일반적인 예상과 반대인 이 측정 하나가 엔진의 I/O 설계를 정했습니다.

kimi-k3-in-c가 정확성을 확인하는 방법

이 저장소에서 가장 눈여겨볼 부분은 검증 장치입니다. 저장소를 클론해 make test 를 실행하면 체크포인트도 네트워크도 파이썬도 없이 세 개의 게이트를 통과합니다. 교사 강요(teacher forcing) 위치 일치, 그리디 디코딩 토큰 일치, 그리고 KV 캐시와 KDA 상태를 이어 가는 증분 모드 토큰 일치입니다. 대조 기준은 저장소에 커밋된 픽스처에서 나온 PyTorch 레퍼런스이고, 대상은 공개 모델과 같은 텐서 그래프를 가진 13레이어 축소 모델입니다. 1.56TB를 내려받기 전에 엔진이 레퍼런스와 일치하는지 먼저 확인할 수 있다는 뜻입니다.

빌드 플래그에도 같은 의도가 들어 있습니다. -ffp-contract=off 는 컴파일러가 곱셈과 덧셈을 FMA 하나로 합치지 못하게 막는데, 보통은 손해인 이 선택을 한 이유는 스칼라 경로와 OpenMP 경로와 AVX2 경로가 비트 단위로 같은 결과를 내야 하기 때문입니다. 그래야 성능 개선이 조용히 정확도 변화로 바뀌는 일이 생기지 않습니다.

헤더에 적힌 세 가지 불변 조건도 같은 성격입니다. 예를 들어 MLA는 회전 위치 인코딩을 적용하지 않지만 64개 rope 차원 자체는 여전히 존재하고 캐시됩니다. 이 슬롯을 없애면 헤드 폭이 192에서 128로 바뀌고 소프트맥스 스케일이 약 22% 어긋나는데, 이렇게 틀려도 모델은 크래시 없이 그럴듯하게 읽히는 문장을 계속 뱉습니다. 저자는 이런 자리마다 틀리면 출력이 달라지도록 설계한 픽스처를 붙여 두었습니다.

kimi-k3-in-c 설치 및 실행

빌드에 필요한 것은 C99 컴파일러와 libm, OpenMP뿐입니다. 체크포인트 없이 여기까지는 1분이면 끝납니다.

git clone https://github.com/FareedKhan-dev/kimi-k3-in-c.git
cd kimi-k3-in-c

make -j            # 몇 초
make test          # 1분 이내

실제 생성까지 가려면 체크포인트가 필요합니다. scripts/k3-doctor.sh 가 툴체인과 램, 디스크를 점검해 다음에 실행할 명령을 알려 줍니다.

export HF_TOKEN=hf_your_token_here
./scripts/download-model.sh ~/k3model     # 1.56TB, 이어받기 지원
./scripts/pack-trunk.sh ~/k3model ~/k3trunk   # 약 4분, 109GB 파일 생성

pack-trunk.sh 는 93개 덴스 레이어를 하나의 109GB 파일로 다시 써서 레이어 L이 알려진 오프셋에 놓이게 만듭니다. 이 단계가 메모리 요구량을 조절 가능한 값으로 바꾸는 지점이므로, 출력물은 가장 빠른 디스크에 두는 편이 좋습니다.

./bin/k3 ~/k3model --trunk ~/k3trunk --preset laptop \
         --tok ~/k3model --prompt "The capital of France is" --gen 8 --incremental

프리셋은 트렁크와 전문가 캐시 예산을 한 번에 정하는 단축 표기입니다.

프리셋 트렁크 / 캐시 (GB) 측정된 최대 상주 메모리
laptop 3.0 / 1.0 8.2 GB
desktop 16.0 / 10.0 31.9 GB
workstation 60.0 / 30.0 95.5 GB
server 110.0 / 13.0 약 128 GB
max 110.0 / 109.0 약 224 GB

메모리를 늘리면 얼마나 빨라지는지는 저자가 표로 정리해 두었습니다. 8GB에서 토큰당 26.5초, 32GB에서 24.2초, 64GB에서 19.8초, 128GB 이상에서 5.6초입니다. 앞의 세 구간은 매 스텝 모델을 디스크에서 읽으므로 디스크 속도가 그대로 반영되고, 마지막 구간은 모델이 전부 메모리에 들어가 디스크 대기가 사라집니다. 저자는 maxserver 보다 빠르지 않았고, 추가된 96GB는 잡음 수준의 차이만 만들었다고 적고 있습니다.

길이가 있는 생성에는 --incremental 을 붙여야 합니다. 이 옵션이 없으면 매 스텝이 전체 프리픽스를 다시 계산해 O(T^2) 가 됩니다. 두 경로 모두 같은 토큰을 내도록 게이트가 걸려 있으므로 순수한 속도 선택입니다.

kimi-k3-in-c가 다루지 않는 것

저자가 범위를 명시적으로 적어 두었습니다. 챗 템플릿이 없어 베이스 모델 연속 생성만 가능하고, 디코딩은 그리디 전용입니다. 온도나 top-p, top-k가 없는 이유는 그리디가 예산을 바꿔도 출력이 같게 유지되는 조건이기 때문입니다. 청크 프리필이 없어 프롬프트 상한 32,768 토큰은 한 번의 이차 패스로 처리되고, 문맥 한계는 엔진이 아니라 메모리가 정합니다. 27개 레이어로 설정에 명시된 비전 인코더 MoonViT-V2는 구현되어 있지 않으며, KDA 순환 부분에는 SIMD 경로가 없습니다. 품질 벤치마크도 없는데, 토큰당 11초에서 퍼플렉시티나 태스크 평가를 돌리면 며칠이 걸리는 데다 그것은 이 엔진이 아니라 Kimi K3를 측정하는 일이 되기 때문입니다.

동작 환경은 Linux x86-64이고 O_DIRECTposix_memalign, getrusage 를 사용합니다. CPU는 AVX2와 FMA만 있으면 되며 AVX-512는 필요하지 않습니다. 저자의 측정 장비는 124코어 AMD EPYC 7763 두 소켓에 램 228GB, NVMe 3.2TB 구성이었고, 장착된 NVIDIA L40 4장은 이 엔진에 GPU 경로가 없어 전 과정에서 놀고 있었습니다.

kimi-k3-in-c의 라이선스

kimi-k3-in-c는 Apache 2.0 라이선스로 공개되어 있어 개인 및 상업적 목적으로 자유롭게 사용할 수 있습니다. 벤더링된 서드파티 구성 요소와 그에 대한 수정 사항은 NOTICE 파일에 정리되어 있습니다. 다만 저장소에는 모델 가중치가 포함되어 있지 않고 그에 대한 권리도 부여하지 않습니다. Kimi K3 자체는 Moonshot AI가 자체 라이선스로 배포합니다.

:memo: kimi-k3-in-c 개발 과정 소개 글

https://medium.com/@fareedkhandev/building-kimi-k3-in-c-to-run-a-2-8t-model-on-consumer-hardware-a5792cbf3b59

:github: kimi-k3-in-c 프로젝트 GitHub 저장소

:hugs: Kimi K3 모델 다운로드

더 읽어보기




이 글은 GPT 모델로 정리한 초안을 바탕으로 한 것으로, 원문의 내용 또는 의도와 다르게 정리된 내용이 있을 수 있습니다. 관심있는 내용이시라면 원문도 함께 참고해주세요! 읽으시면서 어색하거나 잘못된 내용을 발견하시면 댓글로 알려주시기를 부탁드립니다. :hugs:

이 도구를 직접 설치해 사용해보셨다면, :pytorch:파이토치 한국 사용자 모임:south_korea: 회원들을 위해 경험이나 팁을 댓글로 남겨주세요! :folded_hands: