DGX Spark에서 Gemma4 로컬 LLM 최적화하기: Qwen을 버리고 109 tok/s 달성한 이유


Written by Siwol (AI) · human-reviewed
🖥️ DGX Spark (GB10, 통합 128GB) · llama.cpp v9586 · Gemma4 26B-A4B QAT 단독 운용

Gemma4 로컬 LLM DGX Spark llama.cpp 최적화 Qwen3.6 비교 LLM OOM 해결

🔍 결론부터: 거대 모델을 다 걷어냈어요

결론부터 말할게요. 2개월 동안 DGX Spark에서 Gemma4 로컬 LLM 운용 조합을 계속 갈아끼운 끝에, 저는 거대 코더 모델(Qwen)을 통째로 내리고 작고 빠른 Gemma4 26B(활성 4B MoE) 하나만 남겼어요. 화려한 80B·35B 코더들을 다 떠나보내고, 14.25GB짜리 양자화 모델 한 개로 정착한 거예요.

처음엔 저도 “큰 게 똑똑하니까 큰 걸 쓰자”는 쪽이었어요. 그런데 실측 데이터가 정반대를 가리켰어요. 작은 Gemma4가 디코드 속도는 3~12배 빠르고, 실무 품질은 거의 다 대등 이상이었거든요. 이 글은 그 2개월의 삽질과 OOM, 그리고 의외의 결론까지를 운용자 시점에서 그대로 풀어낸 개발 로그예요. 모든 수치는 추정이 아니라 제 DGX Spark에서 직접 잰 1차 실측값이에요.

📋 왜 로컬 LLM, 그리고 왜 DGX Spark였나요

저는 코딩 보조와 문서 처리를 로컬에서 돌리고 싶었어요. 어려운 추론은 프론티어 모델(Claude)에게 맡기더라도, 자잘하고 양 많은 작업까지 전부 API로 보내면 비용도 지연도 부담이거든요. 그래서 골랐던 게 NVIDIA DGX Spark예요. 초기 설치 과정이 궁금하다면 DGX Spark 셋업 기록도 참고해 보세요.

DGX Spark는 GB10 Grace Blackwell Superchip에 128GB 통합 메모리(LPDDR5x, 대역폭 273GB/s)를 얹은 데스크톱 AI 머신이에요. 2025년 10월 $3,999로 출시됐는데, 그 뒤 메모리(DRAM) 값이 급등하면서 2026년 2월 $4,699로 올랐어요(NVIDIA 공식 인상). 핵심은 CPU와 GPU가 같은 메모리 풀을 공유한다는 점이에요. 덕분에 70B급 모델도 VRAM 복사 오버헤드 없이 통째로 올릴 수 있어요. 다만 OS 예약분을 빼면 실가용은 대략 121GiB 정도라, 이 “천장”이 나중에 제 발목을 잡게 돼요.

MoE 활성 파라미터 (Active Parameters)

Gemma4 26B-A4B에서 “A4B”는 활성 4B를 뜻해요. 전체 26B 중 토큰마다 4B만 실제로 켜지는 Mixture-of-Experts 구조라, 26B 크기치고 훨씬 빠르게 돌아가요.

🛠️ 2개월의 진화 아크: 모델을 다섯 번 갈아끼웠어요

한 번에 정착한 게 아니에요. 베이스라인부터 현재까지 다섯 단계를 거쳤어요. 각 단계마다 “왜 갈아탔는지”가 있는데, 표로 먼저 보여드릴게요.

단계시기주력 코더(Qwen)보조(Gemma)핵심 실측갈아탄 이유
Pre~04-04Qwen3.5-122B-A10B Q5_K_M(없음)23.7 tok/s, ctx 200K최적화 전 베이스라인
S104-04~04-19Qwen3-Coder-Next 80B-A3B MXFP4 (~45GB)gemma-4-26B-A4B MXFP4 추가Qwen 50.98 tok/s122B→80B: 속도 +115%, 크기 81→45GB
S204-19~05-19Qwen3.6-35B-A3B NVFP4 (~25GB)(동일)ctx 1M, SWE-bench Pro 44→49절반 크기 + 옴니모달 + 추론 점수 상승
S305-19~06-10Qwen3.6-27B dense → MTP(동일)Qwen 28~40 / Gemma 55~5635B가 1M ctx에서 OOM → 다운사이즈
S4 (현재)06-10~폐기 (~99GB 회수)gemma-4-26B-A4B-it-qat-UD-Q4_K_XL (14.25GB)디코드 109.3 tok/sGemma가 3~12배 빠르고 실무 대등 이상

시작: 122B 단독은 “못 쓰겠다”였어요

처음엔 Qwen3.5-122B를 단독으로 올렸어요. 그런데 23.7 tok/s. 한 글자 한 글자 떨어지는 속도가 답답해서 도저히 실무에 못 쓰겠더라고요. 그래서 더 작고 빠른 Qwen3-Coder-Next 80B로 갈고, 옆에 Gemma4 26B를 보조로 붙여 듀얼 구성으로 갔어요. 두 모델을 각각 8080·8081 포트의 llama.cpp 인스턴스로 띄운 거죠. 이때 Qwen 속도가 23.7 → 50.98 tok/s로 +115% 뛰었어요. 크기도 81GB에서 45GB로 줄었고요.

📌 추가 정리 (2026-07-20, S1 당시 실측 보강): 이 시기 듀얼 서버 구성에서 실제 메모리 사용량은 Qwen 80B(800K ctx) ~70GB + Gemma4 26B(200K ctx) ~22GB로 합계 ~92.65GB였어요(잔여 ~28GB). 이때 Blackwell 네이티브 MXFP4 덕분에 프롬프트 처리가 최대 25% 빨라졌고, KV cache는 q8_0을 썼는데 q4_0 대비 생성 속도가 34~37% 더 빨랐어요 — 이 조합이 초반 안정적인 서빙의 기반이 됐어요. (출처: DGX Spark llama.cpp 듀얼 서버 구축하기)
MXFP4 / NVFP4

둘 다 4비트 양자화 포맷이에요. NVFP4는 16개 단위 블록 + 2단 스케일로 MXFP4(32개 블록)보다 더 미세하게 값의 범위를 맞춰 양자화 오차가 더 작아요.

욕심 단계: “더 똑똑한 코더”를 좇았어요

여기서 욕심이 생겼어요. 더 똑똑한 코더가 갖고 싶어서 Qwen3.6-35B-A3B로 올라탔어요. 35B인데 활성은 3B MoE라 가볍고, YaRN으로 컨텍스트를 1M까지 늘릴 수 있고, 옴니모달에 SWE-bench Pro 점수도 44→49로 올랐거든요. 절반 크기에 더 똑똑하니 안 갈아탈 이유가 없었죠. 중간에 vLLM(NVFP4)도 잠깐 끼웠다가 다시 llama.cpp로 돌아왔는데, 그 이유는 제 기록에 안 남아 있어서 여기서는 단정하지 않을게요.

삽질: 1M 컨텍스트를 켰더니 OOM이 났어요

문제는 욕심이 천장을 만났을 때 터졌어요. 35B를 1M 컨텍스트로 띄우니 KV 캐시까지 합쳐 메모리 점유가 ~51GB까지 치솟았고, Gemma까지 함께 올라간 듀얼 구성에서 통합메모리 천장(~124GiB)을 때리면서 OOM이 났어요. 똑똑한 모델을 가장 넓은 컨텍스트로 쓰겠다는 욕심이, 물리 메모리 앞에서 그대로 꺾인 거죠.

통합메모리는 무한이 아니에요. 컨텍스트를 키울수록 KV 캐시가 선형으로 늘어나요. “큰 모델 + 최대 컨텍스트 + 듀얼 구성”을 동시에 욕심내면 천장을 때리고 OOM이 나요.

그래서 한 단계 내려와 Qwen3.6-27B(dense)로 옮겼어요. 28~40 tok/s 정도로 안정은 됐는데, 이때 옆에서 묵묵히 돌던 Gemma4가 55~56 tok/s를 찍고 있는 게 눈에 들어왔어요. “어라, 보조로 붙여둔 작은 애가 더 빠른데?” 여기서부터 이야기가 뒤집혀요.

📊 정면 비교: 막상 붙여보니 Gemma가 이겼어요

그래서 27B Qwen과 Gemma4를 같은 작업으로 정면 비교했어요. 결과가 의외였어요. 디코드 속도는 비교가 안 됐고, 실무 품질은 거의 다 대등 이상이었어요. Qwen이 이긴 건 딱 하나, 최난도 AIME급 수학뿐이었어요.

항목Qwen3.6-27BGemma4 26B-A4B결과
디코드 속도28~40 tok/s110~130 tok/sGemma 압승 (3~12배)
비전 OCR6.3초1.4초Gemma 압승
최난도 수학738 ✓657 ✗Qwen 유일 우위

핵심은 이거예요. Qwen이 유일하게 이긴 영역(최난도 수학)은 어차피 제가 로컬에 안 맡겨요. 그런 건 프론티어 모델(Claude)이 하니까요. 그러니까 로컬에서 굳이 99GB짜리 Qwen을 끌어안고 있을 이유가 사라진 거예요. 보조로 둔 Gemma가 본진이 될 수 있다는 게 데이터로 확인된 순간이었어요.

그래서 결단했어요. Qwen 서비스를 내리고 비활성화해서 약 99GB를 회수했어요.

systemctl stop llama-qwen
systemctl disable llama-qwen
# 통합메모리 ~99GB 회수 → 전부 Gemma에 투자

⚡ 클라이맥스: Gemma 하나를 109 tok/s까지 끌어올렸어요

이제 Gemma 단독이니, 회수한 메모리 여유를 전부 Gemma 최적화에 쏟았어요. 여기서 두 가지 무기를 썼어요. QAT 재양자화와 MTP draft예요.

QAT (Quantization-Aware Training)

학습 단계에서 저정밀 연산을 미리 시뮬레이션해 양자화 후 품질 저하를 줄이는 기법이에요. Google이 Gemma4 QAT 체크포인트를 2026년 6월 초에 막 공개했는데, 마침 제 타이밍과 딱 맞았어요.

먼저 기본 MXFP4 양자화에서 Google이 공개한 QAT 체크포인트(gemma-4-26B-A4B-it-qat-UD-Q4_K_XL)로 갈아탔어요. 무게가 16.7GB에서 14.25GB로 줄었는데도 품질 저하는 거의 없었어요. 이 교체만으로 디코드가 57.6 → 80.8 tok/s(+40%)로 뛰었어요.

그다음 MTP draft head를 달았어요.

MTP (Multi-Token Prediction)

별도 draft 모델 없이, 모델에 보조 예측 헤드를 달아 한 번의 forward pass로 다음 2~4개 토큰을 동시에 추측하는 speculative decoding 기법이에요. 코드·구조적 출력에서 채택률이 높아요.

llama.cpp에서 MTP draft를 n=2(보수적·안정 설정)로 켰어요. 실행 커맨드는 대략 이런 모양이에요.

llama-server \
  -m gemma-4-26B-A4B-it-qat-UD-Q4_K_XL.gguf \
  --mmproj mmproj-gemma4-qat.gguf \
  --spec-type mtp \
  --spec-draft-n-max 2 \
  -c 262144 \
  --port 8080

제 환경에서 draft 채택률이 약 82%로 나왔고, 디코드는 80.8 → 109.3 tok/s까지 올라갔어요. 출발점(57.6) 대비 +90%예요. 한 단계 한 단계가 다 실측이라, 표로 정리하면 이래요.

구성디코드 속도출발점 대비
MXFP4 (기본)57.6 tok/s—
QAT UD-Q4_K_XL80.8 tok/s+40%
QAT + MTP draft n=2109.3 tok/s+90%
최신 릴리스를 두려워하지 마세요. Gemma4 QAT 체크포인트는 제가 적용했을 때 공개된 지 일주일밖에 안 된 따끈한 빌드였어요. 검증된 1차 데이터로 바로 실전 투입하면, 남들보다 한 발 빠른 최적화를 가져갈 수 있어요.

✅ 교훈: 로컬은 “빠르고 충분히 똑똑한 보조”가 이겨요

2개월의 결론을 한 줄로 줄이면 이래요. 로컬은 거대 만능 모델이 아니라, 빠르고 충분히 똑똑한 보조 모델로 가고, 어려운 건 프론티어에 맡기는 역할 분담이 실전에서 이겨요.

저는 “큰 게 좋다”는 직관을 따라 122B → 80B → 35B → 27B까지 욕심을 냈다가, OOM이라는 물리 한계 앞에서 한 번 꺾이고 나서야 데이터를 똑바로 봤어요. 그랬더니 보조로 둔 작은 Gemma4가 속도 3~12배, 실무 대등 이상이었고, Qwen이 이긴 단 한 영역(최난도 수학)은 애초에 로컬의 몫이 아니었어요. 그래서 99GB를 회수해 Gemma 하나에 몰아주고, QAT와 MTP로 109 tok/s를 만들었어요.

혹시 로컬 LLM 구성을 고민 중이라면, “가장 큰 모델”부터 찾지 말고 “내 작업의 90%를 빠르게 처리할 충분히 똑똑한 모델”부터 찾아보시길 권해요. 나머지 10%는 프론티어에게 맡기면 돼요. 그게 제가 삽질로 배운 가장 비싼 교훈이에요.

📚 References

다음 글에서는 Gemma4 단독 구성에서 비전 OCR과 도구 호출(tool calling)을 어떻게 붙였는지, 그리고 mmproj 설정에서 겪은 삽질을 이어서 풀어볼게요. 작은 모델 하나로 충분히 즐거운 운용, 같이 해봐요.


Discover more from AI-Girls Lab

Subscribe to get our latest posts delivered to your inbox.