EPYC 9175FでKimi-K2.5を動かし、L3仮説を見直す
EPYC 9175Fと768GB RAMでKimi-K2.5を実測。スレッド数、128K文脈、prompt cacheから、LLM導入のCPU基盤とL3仮説を検討します。
背景
Kimi-K2.5(総パラメータ1.04T、トークンあたり32B活性)を EPYC 9175F で動かしました。2025年後半から2026年に登場した1Tクラスの Mixture-of-Experts(MoE)を、CPUでバッチ処理に使えるか確かめます。
当時の見積もりでは、NVIDIA H200 4枚は$150k〜$200k、768GB DDR5のCPUサーバーは約$15kでした。個人や小規模チームのLLM導入を考え、CPUの実用性を調べました。
手元の EPYC 9175F は16コア、L3キャッシュ512MBです。大きなL3がMoE推論に有利ではないかと考え、スレッド数と速度を測りました。
目的
調べる点は3つです。
- 「巨大L3キャッシュにMoEのアクティブエキスパートが収まることで推論が加速する」という仮説は正しいか
- EPYC 9175FでKimi-K2.5(Q4_K_S)を実行した場合のスループットはバッチ処理に実用的か
- スレッド数とメモリ帯域の関係から、運用上の最適設定はどこか
実験環境
ハードウェア
| 項目 | 仕様 |
|---|---|
| CPU | AMD EPYC 9175F(Zen 5, 16C/16T, SMT=OFF) |
| L3キャッシュ | 512MB(コアあたり32MB) |
| メモリ | DDR5-6400 64GB x 12ch = 768GB |
| GPU | RTX PRO 6000 MAX-Q 96GB(本検証では未使用) |
| TDP | 320W(cTDP 400W) |
ソフトウェア
| 項目 | バージョン |
|---|---|
| OS | Ubuntu 24.04 LTS |
| Runtime | llama.cpp(server mode) |
| コンテナ | Podman rootless |
モデル
| 項目 | 仕様 |
|---|---|
| Model | Kimi-K2.5(Moonshot AI) |
| 総パラメータ | 1.04T(61層:60 MoE + 1 Dense) |
| 活性パラメータ | 32B(384エキスパート中8個選択) |
| 量子化 | Q4_K_S(GGUF) |
| KVキャッシュ量子化 | Q8_0 |
| コンテキスト長 | 最大256K(本検証は8K〜128K) |
CPUトポロジ確認
ksh3@compute-server:~$ lscpu | egrep 'CPU\(s\)|Thread|Core|Socket|NUMA'
CPU(s): 16
On-line CPU(s) list: 0-15
Model name: AMD EPYC 9175F 16-Core Processor
Thread(s) per core: 1
Core(s) per socket: 16
Socket(s): 1
NUMA node(s): 1
NUMA node0 CPU(s): 0-15
ksh3@compute-server:~$ cat /sys/devices/system/cpu/smt/active
0
SMTはOFFで、物理16コアが論理16コアとして見えます。NUMAノードは1つです。
実施内容
llama.cpp起動パラメータ
スレッド数を16、14、13、12に変え、Prefill(入力処理)と Decode(トークン生成)を測りました。
th=13 の起動例です。
podman run --rm -p 8081:8080 --shm-size 16g --cap-add=SYS_NICE \
-v /mnt/data/hf/hub/models--unsloth--Kimi-K2.5-GGUF:/models:Z \
compute.home.arpa/llamacpp-zen5:latest \
-m /models/snapshots/386fed8b054275941d6a495a9a7010fbf31b560d/Q4_K_S/Kimi-K2.5-Q4_K_S-00001-of-00013.gguf \
--cache-type-k q8_0 --cache-type-v q8_0 --flash-attn on \
--ctx-size 131072 --parallel 1 --threads 13 --threads-batch 13 \
--batch-size 2048 --ubatch-size 512 --jinja --host 0.0.0.0 --port 8080
各パラメータの目的です。
--cache-type-k q8_0 --cache-type-v q8_0:KVキャッシュをQ8_0にしてメモリを抑えます。--flash-attn on:CPUのFlash Attentionを有効にし、長文脈の帯域負荷を減らします。--cap-add=SYS_NICE:スレッド優先度の調整を許可します。--batch-size 2048 --ubatch-size 512:Zen 5のAVX-512 VNNIでPrefill速度を狙った設定です。
プロンプトキャッシュの検証
同じprefixでリクエストを繰り返し、selected slot by LCP similarity によるキャッシュ効果も測りました。
結果
スレッド数別スループット(ctx=8K, Q4_K_S)
| スレッド数 | Prefill (tok/s) | Decode (tok/s) | Latency (ms/tok) | 備考 |
|---|---|---|---|---|
| 16(全コア) | 24.43 | 12.94 | 77.28 | 最大スループット |
| 14 | 21.32 | 12.50 | 79.97 | 帯域飽和が顕在化 |
| 13(推奨) | 21.58 | 11.67 | 85.70 | 効率と余力のバランス |
| 12 | 14.58 | 11.86 | 84.32 | 演算リソース不足の兆候 |
Decodeはth=13〜16で11.67〜12.94 tok/sとほぼ横ばいでした。メモリ帯域の制約を示す結果です。Prefillはth=12で急落し、この設定では演算用のスレッドを減らしすぎると遅くなりました。
128Kコンテキストでの長時間安定性(th=13)
| 項目 | 測定値 | 評価 |
|---|---|---|
| Prefill | 22.39 tok/s | AVX-512 VNNIの最適点 |
| Decode | 9.34 tok/s | 長文脈でも人間の読書速度(約6 tok/s)を上回る |
| TTFT(39トークン新規入力) | 1,741 ms | LCPキャッシュが効いた結果 |
| KV Cache Latency | 107.10 ms/tok | 12ch DDR5による安定した帯域制御 |
128Kでも9.34 tok/sを維持し、急な速度低下は見られませんでした。
プロンプトキャッシュ効果(ctx=16K)
| リクエスト | 条件 | Prompt処理 | Generation | 備考 |
|---|---|---|---|---|
| 1st | キャッシュなし | 22.24 tok/s (823tok/37s) | 10.27 tok/s (438tok/42.7s) | コールドスタート |
| 2nd | キャッシュ保存中 | 19.98 tok/s | 8.76 tok/s | 保存オーバーヘッド込 |
| 3rd | LCP similarity hit | 62 ms (キャッシュルックアップ) | 10.0+ tok/s | TTFTが劇的に短縮 |
1260トークンのキャッシュは159.5 MiBでした。3回目以降はprefixの再計算が省かれ、TTFTは秒単位から62msへ短くなりました。
メモリ消費
| 項目 | 測定値 | 備考 |
|---|---|---|
| モデル本体(ウェイト) | 約522 GB | Q4_K_S量子化 |
| KVキャッシュ(16K ctx) | 約2.0 GB | K:1098MiB / V:976MiB |
| プロンプトキャッシュ | 約160 MB | 1.2Kトークン時 |
| 合計RSS | 約523 GiB / 755 GiB | スワップ発生なし |
768GB環境でスワップせずに動きました。OSと背景処理を除いても200GB以上空いています。
考察
当初仮説の検証結果
当初の仮説:
MoEモデルはアクティブパラメータが10〜30B程度なので、EPYC 9175Fの512MB L3キャッシュにエキスパート全体が収まり、高速化する。
結果:エキスパート全体が収まるという仮説は棄却しました。
活性パラメータ32Bは、Q4でも1トークン生成あたり約16GBです。512MBのL3に全体は収まりません。
修正版仮説: 部分的・確率的キャッシュヒット
修正版の仮説では、L3に残る候補を次のように考えました。
- Router / Gatingロジック: どのエキスパートを活性化するか決定する高頻度アクセス層。全トークンで参照されるため、L3に常駐しやすい
- Projection / Biasテンソル: 各レイヤーの入出力境界。サイズが小さく再利用頻度が高い
- 直前レイヤのweight / 中間テンソル: 時間的局所性により一時的にL3に残る
- KVキャッシュの再利用部分: 特にアテンション計算で頻繁にアクセスされる部分
全体ではなく、再利用の多い作業領域がL3に当たるという仮説です。EPYC 9175Fのコアあたり32MBのL3が、そのヒット率を高めると考えています。今回の速度測定だけではヒット率自体を確定できません。
なぜ「少コア・多キャッシュ」がMoEに向くのか
128コアで512MBなら単純計算でコアあたり4MBです。MoEの不規則なアクセスでは、コア間の競合でキャッシュが入れ替わる可能性があります。
16コアに512MBを持つ EPYC 9175F では、次の効果を仮定しています。
- コア間のL3競合が減る
- 再利用の多い領域が残りやすい
- メモリコントローラへの要求集中を減らせる
メモリ帯域がボトルネックになる境界
Decodeはth=13〜16で飽和しました。12チャンネルDDR5-6400の理論帯域は614 GB/sです。th=13付近で実効帯域が制約になるという解釈で、推論が memory-bound であることを示唆します。
Zen 5 AVX-512の寄与
Zen 5は512ビットのデータパスを持ち、Zen 4までの256ビットx2とは異なります。BF16とAVX-512 VNNIがQ4_K_Sのデ量子化と内積に寄与すると考えました。最大5.0GHzのクロックと、Prefill 24.43 tok/sの結果を踏まえた解釈です。
感想
L3に全体が収まる仮説は成立しませんでした。MoEのアクセスの局所性を部分的に使うという仮説へ修正しました。DenseよりCPUに合うかどうかも、この解釈の範囲です。
運用にはth=13を選びました。推論性能の90%を維持し、残る3コアをDagster、Trino、ネットワークIOに使えるためです。
128Kで9.34 tok/sは想定以上でした。MLA(Multi-head Latent Attention)のKV圧縮が寄与したと考えています。
再現方法
1. ハードウェア要件
- AMD EPYC 9175F搭載サーバー(768GB DDR5-6400推奨)
- ストレージ: モデルファイルに約600GB必要(NVMe推奨)
2. モデル取得
# Hugging Faceからダウンロード
huggingface-cli download unsloth/Kimi-K2.5-GGUF \
--include "Q4_K_S/*" \
--local-dir /mnt/data/hf/hub/models--unsloth--Kimi-K2.5-GGUF
3. llama.cppコンテナビルド(Zen 5最適化)
AVX-512 VNNI / BF16を有効にします。-march=znver5 または -DGGML_NATIVE=ON を指定します。
4. 実行(推奨設定: th=13, ctx=128K)
podman run --rm -p 8081:8080 --shm-size 16g --cap-add=SYS_NICE \
-v /mnt/data/hf/hub/models--unsloth--Kimi-K2.5-GGUF:/models:Z \
compute.home.arpa/llamacpp-zen5:latest \
-m /models/snapshots/386fed8b054275941d6a495a9a7010fbf31b560d/Q4_K_S/Kimi-K2.5-Q4_K_S-00001-of-00013.gguf \
--cache-type-k q8_0 --cache-type-v q8_0 --flash-attn on \
--ctx-size 131072 --parallel 1 --threads 13 --threads-batch 13 \
--batch-size 2048 --ubatch-size 512 --jinja --host 0.0.0.0 --port 8080
5. 動作確認
curl -s http://localhost:8081/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"kimi-k2.5","messages":[{"role":"user","content":"Hello"}],"max_tokens":100}'
補足ノウハウ
SMT(Hyper-Threading)はOFFが推奨
この構成ではSMTをOFFにしています。ONなら論理32コアですが、L3の利用効率を落とさず物理16コアを使う方針です。/sys/devices/system/cpu/smt/active が 0 か確認します。
Dense 70BクラスではL3の恩恵が薄れる
Dense 70Bはアクセスが均一で、MoEのエキスパート選択による局所性とは異なります。このL3の解釈をDenseへそのまま当てはめず、MoE向けの構成として考えています。
CPU推論でprompt cacheを使う
遅いPrefillはprompt cacheで補います。Dagsterで数千件の文書を処理する場合、共通のSystem Promptを再利用する方法が考えられます。
コスト比較
| プラットフォーム | 構成 | 推定Decode速度 | ハードウェアコスト |
|---|---|---|---|
| AMD EPYC 9175F | 1x CPU, 768GB RAM | 10〜13 tok/s | 約$15k |
| Mac Studio M3 Ultra | 2台構成 (512GB) | 約21 tok/s | 約$20k |
| NVIDIA GPUクラスター | 4x H200 | 40+ tok/s | $150k〜$200k |
当時の見積もりではGPUクラスターの1/10以下です。対話用途には遅いものの、夜間バッチやデータセット生成には使える速度でした。
