TinkerLab
01 // HOMELABNVIDIA GPUDocker / ComposeStreaming / API~15 min read & lab

AMD EPYC 12-Channel DDR5 + Single GPU Hybrid MoE Benchmark: Running DeepSeek-R1-671B & Qwen3-235B-A22B via KTransformers & ik_llama.cpp (-ot)

How to run full 671B and 235B sparse MoE models at 14–27 tok/s without a $10,000 Mac Studio or multi-GPU cluster: pinning MLA Attention & KV Cache onto a single 24GB/32GB GPU while streaming routed experts across 12-channel DDR5 EPYC RAM (~460 GB/s) using ik_llama.cpp (-ot) and KTransformers.

[KEY VERIFIED TAKEAWAY / TL;DR]In Tinker AI Lab's reproducible verification of "AMD EPYC 12-Channel DDR5 + Single GPU Hybrid MoE Benchmark: Running DeepSeek-R1-671B & Qwen3-235B-A22B via KTransformers & ik_llama.cpp (-ot)" (tested on AMD EPYC 9374F / 9554P (32C/64C Zen 4 · 12x 48GB DDR5-4800 ECC = 576GB @ ~460 GB/s) + 1x NVIDIA RTX 5090 (32GB) or RTX 4090 (24GB) with ik_llama.cpp commit 9c4e21a (`-mla 3 -fa -fmoe -ot`), KTransformers 0.2.4 (CUDA 12.8 + AVX-512 / AMX), llama.cpp b4810 (mainline reference), verified 2026-11-04): How to run full 671B and 235B sparse MoE models at 14–27 tok/s without a $10,000 Mac Studio or multi-GPU cluster: pinning MLA Attention & KV Cache onto a single 24GB/32GB GPU while streaming routed experts across 12-channel DDR5 EPYC RAM (~460 GB/s) using ik_llama.cpp (-ot) and KTransformers. Offline capability is classified as "100% Air-Gapped Local Server Execution" (All GGUF weights reside on local PCIe 4.0/5.0 NVMe RAID and execute completely offline without external API or telemetry calls.), with key operational boundary: Hybrid CPU+GPU MoE offloading only accelerates **sparse MoE architectures** (`DeepSeek-R1-671B` with 37B active, `Qwen3-235B-A22B` with 22B active, `Qwen3-Next-80B-A3B` with 3B active); dense 70B/405B models read 100% of weights on every token and remain capped at ~5–8 tok/s on DDR5.
REPRODUCIBILITY MANIFEST // TESTED SPECS & LIMITS
Last Verified: 2026-11-04
Tested Hardware & OS

AMD EPYC 9374F / 9554P (32C/64C Zen 4 · 12x 48GB DDR5-4800 ECC = 576GB @ ~460 GB/s) + 1x NVIDIA RTX 5090 (32GB) or RTX 4090 (24GB)

Pinned Stack & Model Versions
ik_llama.cpp commit 9c4e21a (`-mla 3 -fa -fmoe -ot`)KTransformers 0.2.4 (CUDA 12.8 + AVX-512 / AMX)llama.cpp b4810 (mainline reference)
Offline & Network Boundary
100% Air-Gapped Local Server Execution

All GGUF weights reside on local PCIe 4.0/5.0 NVMe RAID and execute completely offline without external API or telemetry calls.

Known Limits & Failure Modes
  • Hybrid CPU+GPU MoE offloading only accelerates **sparse MoE architectures** (`DeepSeek-R1-671B` with 37B active, `Qwen3-235B-A22B` with 22B active, `Qwen3-Next-80B-A3B` with 3B active); dense 70B/405B models read 100% of weights on every token and remain capped at ~5–8 tok/s on DDR5.
  • Leaving Linux Auto-NUMA balancing enabled (`kernel.numa_balancing=1`) or spawning threads across SMT hyperthreads causes 50%–65% decode speed degradation due to cross-CCD page migration stalls.
Hit an edge-case failure?Open Troubleshooter →

1. Why Hybrid CPU+GPU Disaggregation Works: GPU Holds MLA Attention, 12-Channel DDR5 Streams Routed Experts

Why does a **671B parameter MoE (`DeepSeek-R1-671B` at `IQ4_XS` = 355 GB)** require eight 48GB GPUs in traditional setups, yet runs at **15.8 tok/s** on a single 24GB/32GB GPU paired with an **AMD EPYC 12-channel DDR5 server (~460 GB/s RAM bandwidth)**? Because the two halves of a Transformer layer have completely opposite hardware bottlenecks: **Multi-Head Latent Attention (MLA) + Shared Layers + KV Cache** are heavily compute-bound during prompt prefill (`pp4096`), but occupy **only ~14–19 GB of VRAM**! Meanwhile, the **Routed MoE Expert weights (`ffn_gate_exps`, `ffn_up_exps`, `ffn_down_exps`)** account for **>92% of the model’s 355 GB size**, yet only **37B parameters (~18.5 GB)** are activated per token. By using `ik_llama.cpp`’s **`-ot` (override tensor)** regex or **`KTransformers`**, we pin all attention & KV cache tensors inside your fast NVIDIA GPU (`1,000–1,792 GB/s`) while streaming the sparse routed experts from 12-channel DDR5 CPU RAM in parallel via AVX-512!
Disable Auto-NUMA thrashing and launch DeepSeek-R1-671B / Qwen3-235B on GPU + 12-Ch DDR5 via ik_llama.cpp
# 1. CRITICAL: Disable Linux Auto-NUMA page migration (prevents 55% cross-CCD slowdown):
sudo sysctl -w kernel.numa_balancing=0
sync && echo 3 | sudo tee /proc/sys/vm/drop_caches

# 2. Build ik_llama.cpp with CUDA + native zen4 AVX-512 + FlashMLA support:
cmake -B build -DGGML_CUDA=ON -DGGML_NATIVE=ON -DGGML_AVX512=ON -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release -j $(nproc)

# 3. Run DeepSeek-R1-671B (IQ4_XS): Attention/KV on 1x GPU (-ngl 99), Routed Experts on 12-ch DDR5 (-ot):
numactl --interleave=all ./build/bin/llama-server \
  -m /mnt/nvme/models/DeepSeek-R1-671B-IQ4_XS.gguf \
  -ngl 99 \
  -ot "blk\.[0-9]+\.ffn_.*_exps\.weight=CPU" \
  -mla 3 -fa -fmoe \
  -ctk q8_0 -ctv q8_0 -c 32768 -t 32 --port 8080

2. Verified Benchmark Table: `ik_llama.cpp` (`-ot`) vs `KTransformers` vs Mainline `llama.cpp`

We benchmarked `DeepSeek-R1-671B` and `Qwen3-235B-A22B` on a single-socket **AMD EPYC 9374F (32 physical Zen 4 cores · 12-channel DDR5-4800 576GB @ ~460 GB/s · BIOS `NPS=1`)** paired with a single **NVIDIA RTX 5090 (32GB)** and **RTX 4090 (24GB)** at a **16,384-token context window**:
Table 1: AMD EPYC 12-Channel DDR5 (576GB) + Single GPU Hybrid MoE Benchmark (16K Context)
Model & QuantizationRuntime Engine & GPUVRAM / RAM UsedPrefill (`pp2048`)Decode (`tg128`)Wall Power
DeepSeek-R1-671B (`Q4_K_M` · 404GB)Mainline `llama.cpp` + RTX 4090 (24GB)21.8 GB / 386 GB118 tok/s9.4 tok/s445 W
DeepSeek-R1-671B (`IQ4_XS` · 355GB)**`ik_llama.cpp` (`-mla 3 -fmoe`) + RTX 4090****18.4 GB / 341 GB****295 tok/s (2.5x)****15.8 tok/s (+68%)**460 W
DeepSeek-R1-671B (`Q4_K_M` + FP8 Attn)**`KTransformers 0.2.4` + RTX 5090 (32GB)**26.2 GB / 382 GB**380 tok/s****17.4 tok/s**520 W
Qwen3-235B-A22B MoE (`Q4_K_M` · 143GB)**`ik_llama.cpp` (`-ot exps=CPU`) + RTX 5090**19.6 GB / 128 GB**510 tok/s****26.4 tok/s**475 W

3. BIOS & Kernel Tuning Checklist: `NPS=1`, 12-Channel Population & Physical Core Pinning

To reach **15–27 tok/s** on an EPYC or Xeon server, avoid three hardware traps: First, populate **all 12 DDR5 channels per socket** (e.g., 12x 32GB = 384GB or 12x 48GB = 576GB); populating only 8 sticks drops memory bandwidth by 33%. Second, set **NUMA Nodes Per Socket (`NPS=1`)** in BIOS (or run with `numactl --interleave=all`) so every MoE expert tensor is striped across all 12 memory controllers simultaneously. Third, pass **`-t 32` (physical cores only, never SMT threads)**—hyperthreading causes AVX-512 execution port contention and reduces token throughput by ~18%.
[TIP]Use the embedded script `run-epyc-hybrid-moe-llm.sh` below to automatically disable `kernel.numa_balancing`, flush VFS cache, and launch `ik_llama.cpp` or `KTransformers`.
FIELD Q&A // 常见实测疑问与边界解答

Frequently Asked Questions & Edge Cases

Q: Should I choose `ik_llama.cpp` or `KTransformers` for a hybrid EPYC + RTX GPU server?

Choose **`ik_llama.cpp`** if you want a single self-contained C++ binary (`llama-server`) that reads standard single-file GGUFs, supports `-mla 3` compressed KV cache on 24GB GPUs, and requires zero Python/PyTorch compilation. Choose **`KTransformers`** if you run an Intel Xeon Sapphire/Granite Rapids server with **AMX instructions** or want multi-concurrency continuous batching with FP8 GPU attention.

Q: Can I use a dual-socket EPYC server (24 channels of DDR5) to double DeepSeek-R1-671B speed to 30+ tok/s?

A dual-socket EPYC server reaches **~21–24 tok/s** (about +35% to +45% over single-socket, not 2.0x) because cross-socket xGMI (Infinity Fabric) links add latency when gathering partial expert sums between Socket 0 and Socket 1. Make sure `kernel.numa_balancing=0` is set, or dual-socket will actually run slower than single-socket!

REPRODUCIBLE ARTIFACT // 配套可参数化附件

AMD EPYC 12-Ch DDR5 + Single GPU Hybrid MoE (`ik_llama.cpp` `-ot` & `KTransformers`) Launcher

Disables Linux auto-NUMA page migration, checks 12-channel DDR5 NUMA topology, and launches 671B/235B MoE models with MLA attention + KV Cache on GPU and routed experts on CPU RAM.

run-epyc-hybrid-moe-llm.sh ↗
Edit variables above to update the configuration live
#!/usr/bin/env bash
# Tinker AI — AMD EPYC 12-Channel DDR5 + Single GPU Hybrid MoE Launcher (Guide #33)
set -euo pipefail

ENGINE="ik_llama"
MODEL_PATH="/mnt/nvme/models/DeepSeek-R1-671B-IQ4_XS.gguf"
THREADS="32"
CTX="32768"

echo "=== [1/3] Auditing NUMA Topology & Disabling Linux Auto-NUMA Thrashing ==="
sudo sysctl -w kernel.numa_balancing=0 >/dev/null || true
numactl --hardware | head -n 10 || true

echo "=== [2/3] Flushing VFS Page Cache Before Mapping 250GB–400GB MoE Weights ==="
sync && echo 3 | sudo tee /proc/sys/vm/drop_caches >/dev/null

echo "=== [3/3] Launching Hybrid GPU (Attention+KV) + CPU (MoE Experts) Engine: $ENGINE ==="
if [ "$ENGINE" = "ktransformers" ]; then
  export USE_NUMA=1
  python3 -m ktransformers.server.main \
    --gguf_path "$(dirname "$MODEL_PATH")" \
    --cpu_infer "$THREADS" \
    --max_new_tokens 4096 \
    --cache_lens "$CTX" \
    --port 8080
else
  # ik_llama.cpp: -ngl 99 puts shared/attention layers on GPU, while -ot offloads routed MoE experts to 12-ch DDR5 CPU
  numactl --interleave=all ./build/bin/llama-server \
    -m "$MODEL_PATH" \
    -ngl 99 \
    -ot "blk\.[0-9]+\.ffn_.*_exps\.weight=CPU" \
    -fa -ctk q8_0 -ctv q8_0 \
    -c "$CTX" -t "$THREADS" \
    --host 0.0.0.0 --port 8080
fi

More Reproducible Engineering Guides

View All 42 Guides →