NVIDIA의 새로운 120B Nemotron-3.5-Super를 8GB GPU에서 실행하기: 제로(zeros) 건너뛰기와 실제 병목 지점 찾기
요약
본 글은 120B 규모의 Nemotron-3.5-Super 모델을 RTX 5060 (8GB)와 같은 저사양 GPU에서 구동하는 방법을 제시합니다. 핵심 아이디어는 Mixture-of-Experts(MoE) 구조를 활용하여, 전체 가중치 크기 대신 '토큰당 필요한 전문가'의 양만 계산하고 NVMe 드라이브에 나머지 데이터를 저장하는 것입니다. 이를 통해 메모리 제약을 극복하고 실제 추론 속도를 확보했습니다.
핵심 포인트
- MoE 모델은 전체 크기가 아닌 토큰당 필요 자원을 고려해야 합니다.
- NVMe 드라이브를 활용하여 전문가(experts) 가중치를 스트리밍할 수 있습니다.
- 8GB GPU에서도 최적화된 트릭을 통해 대규모 MoE 모델 구동이 가능합니다.
NVIDIA는 10월 15일, 120B 규모의 mixture-of-experts 모델인 Nemotron-3.5-Super를 출시했습니다. 이 모델은 4비트 NVFP4 형식으로도 75GB에 달합니다. 일반적으로 8GB 카드에 대한 답변은 '사용자 하드웨어에서는 불가능하다'입니다. 하지만 저는 이틀 만에 제 집 PC, 즉 **RTX 5060 (8GB)**에서 일반적인 채팅 모델로 Open WebUI를 통해 ~8 토큰/초의 속도로 실행하는 데 성공했으며, 이미지도 읽고 답변 내용 역시 Hugging Face 레퍼런스 구현과 일치했습니다.
코드: https://github.com/helgard-orlm/nemotron-super-8gb
누가 무엇을 했는지 먼저 말씀드리자면: 제가 모델을 선택하고 목표를 설정하며 호출(아래 ReLU² 이후의 제로를 활용하는 아이디어 포함)했습니다. 엔진, 커널, 서버 및 측정은 Claude(Anthropic)가 저와 함께 세션에서 작성했습니다. 여기서 '우리'는 저희 둘을 의미합니다.
이것은 같은 장비에서 실행한 시리즈 중 세 번째 모델입니다. 이전에는 Qwen3.8-Flash-Next (133GB, 11 tok/s)와 DeepSeek-V4.1-Flash (510GB, 2.4 tok/s)를 실행했습니다. 아이디어는 같고, 모델만 다릅니다. 그리고 두 가지 새로운 트릭이 추가되었습니다.
장비 사양 (The machine)
RTX 5060 8 GB (Blackwell, PCIe 5.0 ×8), Core Ultra 5 225F, DDR5 32 GB, 모델 파일 전용으로 사용된 Gen5 NVMe 드라이브. 특별할 것 없습니다.
가장 중요한 유일한 수치: 토큰당 바이트 (bytes per token)
mixture-of-experts 모델에서는 가중치의 대부분이 전문가(experts)로 구성되어 있으며, 각 토큰은 그 중 일부만 사용합니다. 따라서 질문은 '75GB가 8GB에 들어갈까?'가 아니라 **'하나의 토큰이 몇 바이트의 전문가를 필요로 하는가'**입니다.
Nemotron-3.5-Super: 88 레이어 (40 Mamba-2, 40 MoE, 8 attention), MoE 레이어당 512개의 전문가, top-22. 비싸게 들릴 수 있지만, NVIDIA는 전문가들을 작게 만들었습니다. 전체 4096 대신 1024 폭의 '잠재(latent)' 공간에서 작동합니다. 하나의 전문가는 up 2688×1024 + down 1024×2688, ReLU², 게이트 없음 — NVFP4로 3.10 MB입니다.
22개의 전문가(experts) × 40개 레이어(layers) × 3.10 MB ≈ 토큰당 2.7 GB
Qwen (토큰당 1.3 GB)과 DeepSeek (토큰당 4.2 GB) 사이입니다. 라우팅된 전문가가 아닌 모든 부분 — Mamba, 어텐션(attention), 공유 전문가(shared experts), 라우터(router), 잠재 투영(latent projections), 출력 헤드(output head) — 은 GPU에서 6.6 GiB를 차지하며, 체크포인트 자체의 FP8/NVFP4 형식으로 유지되고 자체 Triton 커널을 통해 곱해집니다. 라우팅된 전문가 59 GiB는 NVMe 드라이브에 보관됩니다.
엔진 작동 방식 (step by step)
기존에는 이 아키텍처의 전문가를 스트리밍하는 런타임이 없었기 때문에, PyTorch + Triton 엔진을 사용하며 transformers의 NemotronH 코드를 골격(Mamba 믹서, 어텐션, 라우터)으로 활용했습니다. 저희는 전문가, 밀집 레이어(dense layers), 그리고 토큰당 MoE 단계를 대체했습니다.
1. 디스크에 전문가별로 블록 구성. 각 전문가의 네 개의 텐서(up, 스케일링 값, down, 스케일링 값)는 하나의 3,096,576바이트 블록으로 재작성됩니다 — 정확히 4 KiB 페이지 756개입니다. 전문가 하나 = 고정 메모리(pinned RAM)로의 O_DIRECT를 사용한 단일 pread. 59 GiB를 다시 패킹하는 데는 약 2.5분이 걸립니다.
2. 디스크 앞에 배치된 RAM 캐시. 고정 메모리 위에서 LRU(Least Recently Used) 방식으로 작동하며, 리더 스레드는 32개입니다. 라우팅은 집중적으로 이루어지는데, 전문가 중 24%를 RAM에 보관함으로써 조회(lookups)의 81–84%가 적중합니다.
3. 간극으로 사전 가져오기 (Prefetch into the gap). 현재 입력에 대해 다음 MoE 레이어의 라우터를 실행합니다: 이는 다음 레이어의 전문가를 약 72% 정확도로 예측합니다. 누락된 예측값은 GPU가 바쁜 동안 읽어옵니다.
4. 제로 값 건너뛰기 (Skip the zeros) (신규). ReLU² 이후, 주어진 토큰에 대해 전문가 뉴런의 92.5%는 정확히 0입니다. 0인 뉴런은 down 열이 필요하지 않으므로, 왜 PCIe를 통해 전송할까요? 문제는 NVFP4가 연속된 16개 값당 하나의 스케일을 공유한다는 것이므로, 원래 레이아웃에서 단순히 뉴런을 선택할 수 없다는 것입니다. 저희는 down을 디스크에 한 번 재배치했습니다 (순수한 바이트 순열로, 파일 크기는 동일): 각 뉴런의 4비트 값은 연속적이며, 스케일링 값은 16개 뉴런 단위로 그룹화됩니다. 이제 GPU로 복사되는 것은 오직 up (1.55 MB)뿐이며, down 커널은 PCIe를 통해 고정 메모리에서 직접 읽어오고, 활성 뉴런을 포함하는 16개 뉴런 그룹만 처리합니다. +12%, 속도가 6.6 → 7.3–7.6 tok/s로 향상됩니다.
5. 채팅 서버(Chat server). 스트리밍을 지원하는 OpenAI 호환 /v1/chat/completions, 추론 모드를 위한 -think 모델 ID, 그리고 다음 메시지가 새로운 꼬리 부분만 처리할 수 있도록 하는 대화 스냅샷(~170 MB: 8 attention KV 레이어 + 40 Mamba 상태).
실제로 시간이 어디에 쓰였는지—그리고 내가 틀렸던 부분
7.3 tok/s에서 토큰 하나는 약 137ms가 걸립니다. 계획은 CUDA 그래프를 사용하는 것이었습니다: 토큰당 수천 개의 작은 커널(kernel) 실행이 필요했으므로, 분명 파이썬 오버헤드가 문제일 것입니다. 그래프 작성을 하기 전에 Nsight Systems로 프로파일링을 수행했습니다:
- GPU 사용 시간 약 92ms, 유휴 시간(idle) 약 54ms가 토큰당 발생;
- 이 유휴 시간 중, 실행 간의 간격(CUDA 그래프가 해결할 수 있는 부분)은 단지 약 13ms에 불과했습니다.
다음으로 남은 대기 시간(wait)에 대해 두 가지 "당연한" 해결책을 시도했습니다: 공유 전문가(shared expert)가 라우터 결과가 돌아오기 전에 실행되도록 작업 순서를 재배열하는 것, 그리고 예측된(predicted) 전문가를 일찍 복사하는 것이었습니다. 둘 다 비트 단위로 정확했지만, 어느 것도 도움이 되지 않았습니다. 잘못된 추측이 올바른 추측보다 버스에 먼저 큐잉되었기 때문에 투기적 복사(speculative copies)는 속도를 7% 더 느리게 만들었습니다.
그래서 CPU가 무엇을 기다리고 있었는지 시간을 측정했습니다:
| 토큰당 대기 시간 | ms |
|---|---|
| NVMe 읽기 (RAM 캐시에서 전문가 누락) | 50–55 |
| ... | |
| 디스크가 가장 큰 병목이었습니다. 이전 측정에서는 "디스크 ~3ms"라고 했지만, 그 실행은 GPU 복사 기능을 꺼둔 상태였고, 이로 인해 디스크의 존재감이 사라졌습니다. 첫 번째 README에 그렇게 적혀 있었는데, 이제 수정되었습니다. (잘못된 수치는 제가 아니라 README를 검토하던 두 번째 에이전트가 지적했습니다.) |
해결책은 지루했습니다: 더 큰 RAM 캐시. 라이브 서버를 건드리기 전에 우리는 5개의 대화 라우팅을 기록하고 오프라인으로 LRU 캐시(Least Recently Used cache)를 재실행했습니다. 시뮬레이션 결과는 토큰당 ±0.4 읽기 범위 내에서 실제 누락 카운트와 일치했으므로, 종이 위에서 크기를 선택할 수 있었습니다:
| RAM 캐시 | 토큰당 디스크 읽기 횟수 |
|---|---|
| 14 GB | 156 |
| ... | |
| 20GB 라이브 환경: 토큰당 136.9 → 121.5ms, 7.3 → 8.2 tokens/s. 이는 32GB 시스템의 나머지 부분에 약 7GB의 RAM을 남기므로, 여기서 멈추는 것입니다. |
결과
이미지도 읽습니다
Nemotron-3.5-Super-VL은 비전 타워(vision tower) (C-RADIO, 1.3 GB)를 탑재하고 있습니다. 엔진 자체의 6.6 GiB에 이 타워까지 더하면 한 번에 카드에 들어가지 않기 때문에, 타워의 가중치(weights)는 고정 RAM(pinned RAM)에 저장되어 실행 중에 레이어별로 GPU로 스트리밍됩니다 (이미지당 0.4–1.6초 소요, CPU 사용 시에는 10–31초 소요). Open WebUI에서는 사진을 첨부하기만 하면 됩니다.
가짜로 만들기 쉽지만 통과하기 어려운 테스트: 15pt 글꼴의 60줄 분량 송장에 대해 2130번째 줄의 코드, 수량(quantity), 가격을 요청했습니다. 일반 해상도(1047 이미지 토큰)에서는 필드당 10개 중 79개를 맞혔고, 알파벳이 바뀌거나 임의로 만들어낸 줄이 있었습니다. NVIDIA의 최대 해상도(2204 토큰, 별도의 -doc 모델 ID 사용): 세 필드 모두 10/10을 달성했으며, 총 116초가 소요되었습니다. 비전 코드는 리포지토리에도 있습니다 (vision/, tests/vision/에서 송장과 그 정답(ground truth)으로 테스트).
정확성을 확인하는 방법
모델이 다른 것을 말하면 속도는 의미가 없습니다. 기준은 CPU의 fp32 환경에서 transformers의 NemotronHForCausalLM이며, 가중치는 원본 체크포인트(our repack이 아닌)에서 읽어와 transformers 자체의 FP4 코드로 언팩킹되었습니다:
| 텍스트 | PPL 기준치 | PPL 엔진 | 엔진의 탐욕적 답변 = 기준치 |
|---|---|---|---|
| 영어 단락 | 5.233 | 5.280 | — |
| ... |
평균 KL ≤ 0.003입니다. 다른 토큰이 하나 있는 경우는 실제 동점(tie) 상황으로, 기준치 자체도 -layer와 layer가 0.11 차이로 점수가 나뉘어 BF16 단계보다 적습니다.
게다가 반드시 실패해야 하는 테스트까지 추가했습니다: 각 바이트의 두 4비트 절반을 교체하면 PPL이 18,784로 급증합니다. 따라서 언팩킹 순서가 가정되는 것이 아니라 테스트됩니다. 리패킹 및 재배치는 각각 200개의 전문가(experts)에 대해 원본과 바이트별로 비교되었습니다.
저희의 버그 중 하나는 동일한 입력을 세 번 실행해 봄으로써 발견되었습니다: perplexity가 5.19에서 5.29 사이를 오갔습니다. 원인: 반복된 인덱스를 사용하는 index_add_는 무작위 순서로 아토믹(atomics)을 사용합니다. 이는 고정된 순서로 합산되는 per-(token, expert) 버퍼로 수정되었습니다. 두 번째 실행 간 차이의 원인은 버그가 아니었습니다: mamba-ssm Triton 커널은 타이밍에 따라 설정을 가져오기 때문에 별도의 프로세스에서 반올림 방식이 달랐고; TRITON_CACHE_AUTOTUNING=1을 사용하면 비트 단위로 동일해집니다.
작동하지 않은 것들
- 프롬프트의 expert들을 RAM 캐시에 넣기 — 프롬프트가 느려졌고, 디코딩 속도는 개선되지 않았습니다.
- 4개가 아닌 6개의 추측을 미리 가져오기(Prefetching) — 읽기가 더 많이 낭비되었습니다.
- 단일 뉴런당 제로 건너뛰기(Skipping zeros per single neuron) — 뉴런별 스케일을 재읽는 것이 전체 블록을 복사하는 것보다 느렸습니다. 16개 뉴런 그룹 단위가 효과적이었습니다.
- 추측적 초기 복사(Speculative early copies) (위 내용) — 정확했지만, 더 느렸습니다.
- 최근에 사용된 expert들을 GPU에 유지하기 — 레이어의 전문가 중 40%가 다음 토큰에서 반복되지만, 이를 유지하려면 8GB 카드에 있는 6.6GB 밀집(dense) 부분 옆으로 약 2.7GB의 VRAM이 필요합니다.
시도해 볼 것들
저장소에는 엔진, Triton 커널, 서버, 패키징/검증 도구, 그리고 위 수치에 사용된 모든 측정 스크립트가 있습니다. 솔직한 주의사항: 아직 깨끗하게 클론(fresh clone)하여 엔드투엔드로 실행되지는 않았습니다 — README에는 제 기계에서 사용된 정확한 단계들이 나열되어 있습니다. 블랙웰 GPU(커널이 NVFP4 하드웨어 경로를 사용함), 빠르고 빠른 NVMe 드라이브에 70GB의 여유 공간, 그리고 32GB의 RAM이 필요합니다.
핵심은 이전 게시물과 같습니다: mixture-of-experts 모델의 경우,
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기