
DDR5 대역폭이 APU에서의 Dual-LLM 추론을 망치는 이유 (벤치마크 포함)
요약
APU 환경에서 DDR5 대역폭 제한이 Dual-LLM 추론 성능에 미치는 영향을 분석합니다. MoE 모델의 연산 효율성과 공유 메모리 아키텍처의 병목 현상을 벤치마크를 통해 설명합니다.
핵심 포인트
- MoE 모델은 전체 파라미터 대비 낮은 연산 비용으로 토큰 생성 가능
- APU의 공유 메모리 구조는 CPU와 GPU 간 대역폭 경쟁 유발
- DDR5 대역폭 제한이 멀티 모델 에이전트 구현의 병목 원인
- Ollama를 활용한 CPU/GPU 추론 격리 테스트 방법 제시
350억 개의 파라미터(parameter)를 가진 모델이 40억(4B) 개의 파라미터를 가진 모델과 동일한 연산 비용으로 토큰을 생성할 수 있다는 사실을 알고 계셨나요? 이 단 하나의 사실 때문에 저는 주말 내내 공들여 만든 멀티 모델 에이전트 아키텍처(multi-model agent architecture)를 포기해야 했습니다. 하지만 왜 그런지 이해하기 위해서는 먼저 벤치마크(benchmarks)를 실행해 보아야 했습니다.
명령어, 수치, 그리고 공유 메모리 하드웨어(shared-memory hardware)에서 모든 것이 무너지는 아키텍처적 이유를 포함한 전체 분석 내용을 공개합니다.
모든 것을 바꾼 발견
저는 몇 주 동안 일상적인 코딩 어시스턴트로 Minisforum UM790Pro에서 qwen3.6:35b를 실행해 왔습니다. 초당 17.8개의 토큰(tokens/second) — 대화형 작업에 진정으로 사용 가능한 수준입니다. 하지만 저는 계속 궁금했습니다. 에이전트 파이프라인(agent pipeline)에서 빠른 분류(classification)와 도구 호출(tool-calling)을 위해 가벼운 사이드카(sidecar) 모델을 옆에 띄워 함께 실행할 수 있을까?
벤치마크를 시작하기도 전에, 저는 qwen3.6:35b가 내부적으로 실제로 어떻게 구성되어 있는지 파헤쳐 보았습니다. 이것은 전문가 혼합(Mixture of Experts, MoE) 모델입니다. 총 256개의 전문가(experts)가 있으며, 토큰당 오직 8개만 활성화됩니다. 또한 이 아키텍처는 전통적인 어텐션(attention)과 함께 SSM(State Space Model, 상태 공간 모델) 구성 요소를 포함하고 있습니다. 즉, 순수 트랜스포머(transformers)보다 특정 시퀀스 패턴을 더 효율적으로 처리하는 Mamba 스타일의 레이어(layers)가 포함되어 있습니다.
수학적 계산 결과가 저를 놀라게 했습니다. 256개 중 8개의 전문가를 사용한다는 것은 각 토큰이 대략 40억~50억(4-5B) 개의 파라미터에 해당하는 연산량만 사용한다는 것을 의미합니다. 모델은 360억 개의 파라미터에 달하는 '지식(knowledge)'을 보유하고 있지만
이 48GB의 GPU 풀은 엄청나게 들리지만, 이 메모리가 CPU도 함께 사용하는 DDR5에서 분할되었다는 것을 깨닫기 전까지는 그렇지 않습니다. 별도의 GDDR6 버스는 없습니다. CPU 추론, GPU 추론, KV 캐시(KV caches), OS 작업 등 모든 것이 단 하나의 80GB/s 파이프를 통해 흐릅니다.
Ollama을 통해 관리된 테스트 대상 모델 네 가지:
# 모델 다운로드
ollama pull qwen3.6:35b
ollama pull gemma4-e2b-abliterated
...
ollama ps는 어떤 모델이 메모리에 있는지, 그리고 GPU에 올라가 있는지 CPU에 올라가 있는지를 보여줍니다. CPU 전용 추론을 강제하려면(이 테스트에 매우 중요함), 모델 매개변수로 num_gpu를 전달합니다:
# 모델을 CPU로 강제 이동 -- GPU 레이어 0개
curl http://localhost:11434/api/generate -d '{
"model": "gemma4-e2b-abliterated", ...
num_gpu: 0으로 설정하면 Ollama이 레이어 0개를 GPU로 오프로드하도록 지시하여 전체 모델을 시스템 RAM에 유지하고 CPU 전용 추론을 수행하게 합니다. 저는 이 방식으로 CPU 대 GPU 성능을 격리하고 혼합 구성을 테스트했습니다.
VRAM 할당을 확인하려면, ollama ps가 세부 정보를 제공합니다:
NAME SIZE PROCESSOR UNTIL
qwen3.6:35b 32.2 GB 100% GPU 4 minutes from now
gemma4-e2b-abliterated:latest 4.1 GB 100% GPU 4 minutes from now
별도의 NVIDIA 카드의 경우 nvidia-smi로 교차 확인하지만, AMD APU의 경우 GTT 할당은 ollama ps를 통해서만 보이거나 /sys/kernel/debug/dri/0/amdgpu_gem_info 파일을 읽어서 확인할 수 있습니다.
벤치마크 결과
모든 테스트는 두 모델에 동시에 전달되는 동일한 프롬프트를 사용했습니다. 저는 단일 모델 실행과 이중 모델 실행(dual-model runs) 전반에 걸쳐 생성 처리량(generation throughput, tokens/second)을 측정했습니다.
단일 모델 기준점 (Solo Baselines)
| 모델 | 파라미터 (Parameters) | GPU (tok/s) | CPU (tok/s) |
|---|---|---|---|
| qwen3.6:35b | 36B (MoE) | 17.8 | -- |
| ... | |||
![]() |
이중 모델 실행 (Dual-Model Runs)
둘 다 GPU 사용 -- qwen3.6:35b + gemma4-e2b:
| 모델 | 단일 (Solo) | 이중 (Dual) | 성능 저하 (Performance Hit) |
|---|---|---|---|
| qwen3.6:35b (GPU) | 17.8 | 13.1 | -26% |
| gemma4-e2b (GPU) | 42.9 | 25.3 | -41% |
GPU + tiny CPU -- qwen3.6:35b (GPU) + qwen2.5:1.5b (CPU):
| 모델 | 단일 (Solo) | 이중 (Dual) | 성능 저하 (Performance Hit) |
|---|---|---|---|
| qwen3.6:35b (GPU) | 17.8 | 14.9 | -16% |
| qwen2.5:1.5b (CPU) | 53.4 | 26.2 | -51% |
GPU + medium CPU -- qwen3.6:35b (GPU) + gemma4-e2b (CPU, num_gpu=0):
| 모델 | 단일 (Solo) | 이중 (Dual) | 성능 저하 (Performance Hit) |
|---|---|---|---|
| qwen3.6:35b (GPU) | 17.8 | 13.0 | -27% |
| gemma4-e2b (CPU) | 28.7 | 13.4 | -53% |
GPU + large-context CPU -- qwen3.6:35b (GPU) + qwen3:4b-instruct (CPU, num_gpu=0):
| 모델 | 단일 (Solo) | 이중 (Dual) | 성능 저하 (Performance Hit) |
|---|---|---|---|
| qwen3.6:35b (GPU) | 17.8 | 11.6 | -35% |
| qwen3:4b-instruct (CPU) | 19.6 | 11.1 | -43% |
마지막 조합이 최악이었습니다. 4B instruct 모델은 256K 컨텍스트(context)를 지원하며, 이로 인해 KV 캐시(KV cache)가 24.2 GB까지 급증했습니다. 35B 모델의 32 GB GPU 할당량과 결합되어, 사용 가능한 모든 대역폭(bandwidth)의 바이트를 포화 상태로 만들었습니다.
발생하는 이유: 모든 것을 지배하는 하나의 버스 (One Bus to Rule Them All)
외장 GPU(discrete GPU) 설정에서는 CPU가 메모리 컨트롤러를 통해 DDR5에서 모델 가중치(weights)를 읽는 동안, GPU는 완전히 분리된 버스(보통 300+ GB/s)를 통해 자체 GDDR6에서 가중치를 읽습니다. 두 개의 독립적인 파이프라인이 존재하므로 경합(contention)이 발생하지 않습니다.
APU에서는 Zen 4 CPU 코어와 RDNA 3 컴퓨팅 유닛(Compute Units)이 동일한 DDR5 DIMM에 연결된 단일 메모리 컨트롤러(Memory Controller)를 공유합니다. 이론적 최대 대역폭은 약 80 GB/s이며, 이 대역폭은 모든 소비자(Consumer) 사이에서 분할됩니다.
DDR5-5600 (96 GB) -- ~80 GB/s 공유
|
+----+----+
...
LLM 추론(Inference)은 거의 전적으로 메모리 대역폭 제한(Memory-bound)을 받습니다. 생성되는 각 토큰은 모델의 가중치(Weights)를 컴퓨팅 유닛을 통해 스트리밍할 것을 요구합니다. 토큰당 8개의 전문가(Experts)를 활성화하는 35B MoE 모델은 매번 메모리로부터 해당 전문가 가중치를 읽어야(Read) 합니다. CPU 측 모델이 동시에 동일한 작업을 수행할 때, 두 스트림은 동일한 대역폭을 두고 경쟁하게 됩니다.
심지어 "최선"의 듀얼 모델 결과(35B GPU + 1.5B CPU)조차 큰 모델에서 16%의 비용이 발생했습니다. 1.5B 모델은 메모리 점유율(Memory footprint)이 대역폭에 거의 영향을 주지 않을 정도로 작지만, 35B 모델이 버스(Bus)를 점유하고 있었기 때문에 자체 처리량(Throughput)이 절반으로 줄어들었습니다.
에이전트 프레임워크(Agent Framework) 문제
저의 원래 목표는 플래너-실행자(Planner-Executor) 에이전트 설정이었습니다. 즉, 35B 모델이 무엇을 할지 추론하고, 작은 모델이 도구 호출(Tool calls)을 처리하는 방식입니다. 이론적으로는 효율적으로 들립니다.
하지만 실제로는 에이전트 프레임워크가 순차적(Sequential)입니다. 플래너가 계획을 생성하면, 그다음 실행자가 도구를 실행하고, 그다음 플래너가 결과를 평가합니다. 어느 특정 순간에도 오직 하나의 모델만이 활발하게 생성(Generating)하고 있습니다. 다른 모델은 메모리에서 유휴(Idle) 상태로 머물며, 활성 모델에 더 큰 컨텍스트 윈도우(Context window)를 제공할 수 있는 VRAM 또는 RAM을 소비하고 있을 뿐입니다.
MoE (Mixture-of-Experts)에 대한 통찰과 결합하면 — 35B 모델은 이미 소형 모델 수준의 속도로 실행되고 있습니다 — 이 듀얼 모델 아키텍처는 이 하드웨어에서는 존재하지 않는 문제를 해결하려 하고 있습니다.
보너스: Ollama에서 고아 블롭(Orphan Blobs) 찾기
이 프로젝트를 진행하며 모델 저장 공간을 조사하던 중, 12.9 GB의 낭비되는 디스크 공간을 발견했습니다. Ollama는 ~/.ollama/models/ 아래에서 콘텐츠 주소 지정 저장소 (Content-addressed storage)를 사용하므로, 여러 모델 태그가 동일한 가중치 블롭 (Weight blob)을 참조할 수 있습니다. 하지만 모델을 삭제할 때, 블롭이 가끔 그대로 남아 있는 경우가 있습니다.
고아 블롭을 찾는 방법은 다음과 같습니다:
# 1. 매니페스트(Manifest)에 의해 참조되는 모든 블롭 해시(Blob hash) 수집
find ~/.ollama/models/manifests -name '*' -type f \
-exec grep -oh 'sha256:[a-f0-9]*' {} \; | sort -u > /tmp/referenced_blobs.txt
...
3단계의 출력 결과에 나타나는 모든 해시는 고아 블롭입니다. 아직 ollama prune 명령어가 없으므로, 수동으로 삭제해야 합니다. 제 시스템에서는 잊혀진 단 하나의 블롭으로부터 거의 13 GB를 회수할 수 있었습니다.
또한 알아두면 좋은 점은, qwen3.6:35b, qwen3.6:latest, 그리고 qwen3.6:35b-nothink가 모두 동일한 23.9 GB 블롭으로 연결된다는 것입니다. Ollama의 콘텐츠 주소 지정 방식 덕분에, 동일한 가중치를 가진 여러 태그를 가져온다고 해서 실제로 디스크 사용량이 세 배로 늘어나지는 않습니다.
결론
공유 메모리 APU(모든 AMD APU, Arc iGPU가 탑재된 모든 Intel, 외장 GPU가 없는 모든 머신)에서 로컬 LLM을 실행하고 있다면, 핵심 요점은 다음과 같습니다:
- 한 번에 하나의 모델만 사용하세요. 메모리 버스 (Memory bus)가 병목 현상 (Bottleneck)의 원인이며, CPU/GPU 분할 방식과 관계없이 듀얼 모델 추론 (Dual-model inference)은 메모리 버스에 과부하를 줍니다.
- 이 하드웨어에서는 MoE 모델이 최고의 선택입니다. 작은 모델의 추론 비용으로 대형 모델 수준의 추론 품질 (Reasoning quality)을 얻을 수 있습니다. 사이드카 (Sidecar) 모델이 필요 없습니다.
- 여유 RAM은 추가 모델이 아닌 컨텍스트 (Context) 용도로 사용하세요. 대역폭 (Bandwidth)을 두고 싸우는 두 개의 모델보다, 64K 컨텍스트 윈도우 (Context window)를 가진 단일 35B MoE 모델이 훨씬 유용합니다.
- Ollama의 iGPU 메모리 보고 버그를 주의하세요 (#14953) -- Ollama가 사용 가능한 iGPU 메모리를 잘못 판단하기 때문에, 여러 모델을 로드하면 OOM (Out of Memory) 충돌이 발생할 수 있습니다.
- 블롭 스토리지 (Blob storage)를 점검하세요. 삭제된 모델에서 남겨진 고아 블롭 (Orphan blobs)들이 빠르게 쌓입니다.
96 GB의 DDR5를 탑재한 UM790Pro는 로컬 추론 (Local inference)을 위한 진정으로 인상적인 하드웨어입니다. 종이책 크기의 본체에서 내장 GPU (Integrated GPU)만으로 35B급 모델이 17.8 tok/s를 기록합니다. 다만, 한 번에 두 가지 일을 시키려고만 하지 마세요.
테스트 환경: Minisforum UM790Pro, Ryzen 9 7940HS, 96 GB DDR5-5600, Ollama v0.9.x, Ubuntu Linux.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기


