4×3090 + 192GB 환경에서 GLM-5.2 (744B, 2-bit) 7.3 tok/s 달성 — 그리고 왜 IQ1_M이 더 빠르지 않았는가
요약
4개의 RTX 3090과 192GB RAM 환경에서 GLM-5.2(744B) 모델을 구동한 성능 테스트 결과입니다. 양자화 비트를 낮추는 것보다 CPU 코어 수를 늘리는 것이 디코딩 속도 향상에 더 효과적임을 확인했습니다.
핵심 포인트
- GLM-5.2 744B 모델을 4×3090 환경에서 약 7.3 tok/s로 실행
- 오프로드된 전문가 디코딩은 메모리 대역폭이 아닌 CPU 연산 능력에 의해 제한됨
- 양자화 크기 축소(IQ2->IQ1)는 디코딩 속도에 영향을 주지 않음
- CPU 스레드 증가(6개에서 12개) 시 성능이 약 22% 향상됨
- MLA 아키텍처는 연산량을 줄이지만 KV 캐시 크기 자체를 줄이지는 않음
요약(TLDR): 처음으로 클라우드 서비스가 종료되어도 괜찮겠다는 안도감을 느꼈습니다. 4번째 3090을 구했는데, 그 직후 unsloth에서 Q2와 Q1을 출시했습니다. 여기에는 다른 내용을 적지 않겠습니다. 이 내용은 CC(Community Content)에서 가져온 것이라 틀릴 수도 있습니다. GLM-5.2 UD-IQ2_M은 4×3090 + RAM expert offload 환경에서 약 7.3 tok/s로 실행됩니다. 두 가지 디코딩(decode) A/B 테스트 결과: 양자화(quant)를 절반으로 줄여도(IQ2->IQ1) 아무런 변화가 없었으며, CPU 스레드를 6개에서 12개로 늘렸을 때 +22%의 성능 향상이 있었습니다. 오프로드된 전문가(offloaded-expert) 디코딩은 메모리 대역폭(memory bandwidth)이 아닌 CPU 연산 능력(compute)에 의해 제한됩니다.
하드웨어
- Ryzen 9900X, 192GB DDR5-5600
- 4× RTX 3090 (1 Ti + 3 FE), 총 96GB. 카드 한 장은 PCIe x1 링크로 연결됨 (부팅용 NVMe를 x4로 유지하기 위한 칩셋 레인(chipset-lane) 트레이드오프).
설정 (Config)
- unsloth GLM-5.2 UD-IQ2_M, 디스크 용량 223GB (총 744B / 활성 40B)
- llama.cpp master 버전. 아키텍처는 glm-dsa (MLA + DeepSeek sparse attn + nextn)입니다. 이전 릴리스에서는 로드되지 않으므로 최신 빌드가 필요합니다.
- 4개의 GPU에 걸쳐 약 83GB (75개의 MoE 레이어 중 19개 전문가) + 상주 RAM(resident RAM) 약 166GB (나머지 56개 레이어, CPU에서 계산됨). MLA 덕분에 q8_0 KV는 거의 비용이 들지 않습니다.
--n-cpu-moe 사용 시 OOM(Out of Memory) 발생 주의
-sm layer를 사용하면 GPU에 유지되는 전문가들이 모두 마지막(LAST) 카드에 배치되어, 24GB GPU에 54GB를 할당하려고 시도합니다. 해결책: 전문가를 장치별로 명시적으로 배치하십시오 —
-ot "blk.(3|4|5).ffn_(gate|up|down)_exps=CUDA0" ... CUDA1/2/3를 사용하고, 마지막에 a=CPU를 사용하여 전체를 처리합니다. 균등하게 분산하십시오. 출력/임베딩(output/embeddings)을 보유한 카드가 가장 여유가 없습니다.
실제로 디코딩 속도를 변화시키는 요소 (두 가지 A/B 테스트, 각 변수 하나씩)
- IQ1_M (213GB) vs IQ2_M (238GB), 동일한 분할: 7.30 vs 7.29 tok/s. 동일합니다.
- 6 스레드 vs 12 스레드, 나머지 동일: 5.83 vs 7.14 tok/s. +22% 향상.
디코딩은 대역폭(bandwidth)이 아니라, 활성화된 오프로드 전문가의 CPU 연산(dequant + matmul)에 의해 제한됩니다. 더 작은 양자화(Smaller quant) = 동일한 matmul 형태 = 동일한 FLOPs = 이득 없음. 더 많은 코어 = 이득, 물리적 코어 수까지. (Prefill은 스레드에 관계없이 135 tok/s로 일정했습니다 — 코어 제한적이지 않음.) 효과가 있는 조절 요소: 더 많은 코어, GPU에 더 많은 전문가 배치(더 적은 오프로드 레이어). 양자화 크기는 효과가 없습니다.
MLA는 긴 문맥 (long ctx)에 도움을 주지만, 1M를 공짜로 만들어주지는 않습니다
KV 캐시는 128K에서 약 6GB이지만, 선형적으로 증가합니다: 1M에서 ~50GB (q8), ~29GB (q4_1). 약 15GB의 여유 VRAM으로는 1M를 구현할 수 없습니다. q4_1은 약 360K, q8_0은 약 200K까지 가능합니다. DSA는 긴 문맥에서 어텐션 연산 (attention COMPUTE)을 줄여주지만, 캐시 크기 자체를 줄여주지는 않습니다.
x1 카드: 분할(splits)에는 무용지물, 사이드카(sidecar)로는 완벽함
만약 7 tok/s 대신 5 tok/s 정도도 괜찮다면 약간의 보너스가 있습니다. 3개의 카드에 걸쳐 Q1을 사용하면 GPU 하나를 확보할 수 있습니다. x1 링크는 텐서/레이어 분할 (tensor/layer split)을 방해하지만, 단일 카드 모델은 추론 시 링크를 가로지르지 않습니다 — x1은 오직 로딩 시간(load time)에만 영향을 미칩니다. GLM을 3개의 카드로 줄이고 x1 카드에 단독으로 Qwen3.6-35B-A3B를 배치했을 때: 116 tok/s, 풀 스피드로 작동했습니다.
아직 MTP는 없음
glmdsa는 nextn/MTP 헤드를 포함하고 있지만, llama.cpp에서는 구현되지 않은 스텁 (unimplemented stub) 상태입니다 (텐서는 로드하지만 그래프를 구축하지 않음 — 오직 Qwen만이 MTP가 병합되어 있습니다). ngram self-speculative가 대체 수단이며, 산문(prose)이 아닌 코드/구조화된 출력 (structured output)에서 도움이 됩니다.
가장 큰 실제 속도 조절 레버: 사고(thinking) 기능 끄기
디코딩 속도 (Decode rate)는 고정되어 있지만, 사고 과정은 토큰을 소모합니다. 동일한 프롬프트, 동일한 정답 기준: 사고를 하지 않을 때 13.5초 vs reasoning_effort high/max 설정 시 60-80초 — 실제 시간 (wall-clock) 기준 약 5-6배 차이가 납니다. 요청당 조절 가능한 다이얼입니다; 기본적으로는 꺼두고, 어려운 문제에 대해서만 선택적으로 사용하세요.
비용
192GB DDR5 + 사용 중인 3090 4개 + 9900X. 클라우드도, 구독도 없습니다. 운영 비용은 전기료뿐입니다 (각 카드는 200W로 제한됨).
이것은 검증된 첫 번째 구성입니다 (카드당 5개 레이어, ubatch 512 기준). 설명하기 가장 간단한 방법은 다음과 같습니다:
#!/usr/bin/env bash
4x 24GB GPU + ~190GB RAM 환경에서 llama.cpp expert offload를 이용한 GLM-5.2 UD-IQ2_M (2-bit) 실행.
아키텍처는 glm-dsa이며 -> 최신(CURRENT) llama.cpp 빌드가 필요합니다. 이전 릴리스 버전은 로드할 수 없습니다.
llama.cpp master를 먼저 빌드합니다 (static으로 하면 RUNPATH 문제를 피할 수 있습니다):
git clone https://github.com/ggml-org/llama.cpp
cmake llama.cpp -B llama.cpp/build -DBUILD_SHARED_LIBS=OFF -DGGML_CUDA=ON \
-DCMAKE_CUDA_ARCHITECTURES=86 # 86=Ampere/3090; 사용자의 아키텍처로 설정
cmake --build llama.cpp/build -j --target llama-server
다운로드: hf download unsloth/GLM-5.2-GGUF --include "UD-IQ2_M" --local-dir GLM-5.2
SERVER=./llama.cpp/build/bin/llama-server
MODEL=./GLM-5.2/UD-IQ2_M/GLM-5.2-UD-IQ2_M-00001-of-00006.gguf
핵심 부분: GPU에 있는 전문가(experts)를 카드별로 명시적으로 분산시키고, 나머지는 CPU에 둡니다.
여기서는 --n-cpu-moe를 사용하지 마세요. -- with -sm layer는 유지되는 모든 전문가를 마지막 카드에 모두 넣어서 OOM을 유발합니다 (24GB 카드에서 54GB 시도). 대신, -ot을 통해 카드당 약 5개의 MoE 레이어 전문가를 고정하고, 나머지는 catch-all로 CPU에 보냅니다.
VRAM에 맞춰 레이어 개수를 조정하세요: GPU에 더 많이 올릴수록 빠르지만 (CPU 왕복 횟수 감소), 출력+임베딩을 보유하는 카드(CUDA0)가 가장 부하를 많이 받습니다 -- OOM이 발생하면 이 값을 줄이세요.
blk.0-2는 밀집(dense, 전문가 없음); MoE 레이어는 3-77입니다.
CUDA_VISIBLE_DEVICES=0,1,2,3 CUDA_DEVICE_ORDER=PCI_BUS_ID "$SERVER"
--model "$MODEL"
--host 0.0.0.0 --port 8001
--ctx-size 131072
--n-predict -1
--n-gpu-layers 999
--split-mode layer --tensor-split 1,1,1,1
-ot "blk.(3|4|5|6|7).ffn_(gate|up|down)exps.=$CUDA0"
-ot "blk.(8|9|10|11|12).ffn(gate|up|down)exps.=$CUDA1"
-ot "blk.(13|14|15|16|17).ffn(gate|up|down)exps.=$CUDA2"
-ot "blk.(18|19|20|21|22).ffn(gate|up|down)exps.=$CUDA3"
-ot "ffn(gate|up|down)_exps.=$CPU"
--threads 12
--batch-size 2048 --ubatch-size 512
--flash-attn on
--cache-type-k q8_0 --cache-type-v q8_0
--no-mmap
--jinja
--reasoning off # default non-thinking (~5-6x faster wall-clock); # 호출자는 chat_template_kwargs:{"enable_thinking":true}로 요청별 옵트인 가능
Notes for whoever reads it:
- 75개 MoE 레이어 중 GPU에서 20개, CPU에서 55개 사용 → 약 83 GB VRAM + 약 166 GB RAM, ~7.3 tok/s 디코딩.
- 일반 경로(./llama.cpp, ./GLM-5.2)를 사용하여 두 줄만 수정하면 끝남.
- -ot 블록이 핵심입니다. 이것이 OOM을 피하는 트릭이며 주석에 튜닝 방법이 설명되어 있습니다. 모든 경우를 포괄하는 =CPU는 반드시 마지막에 와야 합니다.
- ngram/--spec-type 라인(틈새적, 선택 사항)과 모든 환경 변수 설정은 제거했습니다.
제공: /u/Important_Quote_1180
[링크] [댓글]
AI 자동 생성 콘텐츠
본 콘텐츠는 r/LocalLLaMA의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기