背景

Qwen3-Coder-Nextは約80BパラメータのMoEコーディング特化モデル。コード生成・レビュー・セキュリティ監査に強く、ローカルコーディングアシスタントとして期待できる。

問題は実行方法の選択肢が多すぎること。BF16無量子化のCPU推論、IQ4_NLのHybrid GPU offload(Expert CPUオフロード)、nvfp4のフルGPU推論。それぞれ速度・品質・VRAM消費が異なる。同一環境で3モード全てを実測し、用途別の選択基準を出した。

目的

  1. BF16 CPU推論の速度と品質を確認(精度最優先モード)
  2. IQ4_NL Hybrid構成でExpert Offloadの速度ペナルティを定量化
  3. nvfp4 GPU推論のスループットを計測
  4. コーディングタスクでの品質評価
  5. Qwen3-Next-80B-A3B-Thinking(Q4_K_M)のCPU推論時のSWAキャッシュ挙動を記録

実験環境

項目仕様
CPUAMD EPYC 9175F(Zen 5, 16C, L3 512MB)
GPUNVIDIA RTX PRO 6000 Blackwell Max-Q(96GB VRAM)
メモリDDR5-6400 768GB(12ch)
OSUbuntu 24.04 LTS

3構成の概要

構成Runtime量子化Expert配置ctx
A: CPU BF16llama.cppBF16(無量子化)全CPU16k
B: Hybrid offloadik_llama.cppIQ4_NLExpert=CPU, Attn=GPU65k
C: GPU nvfp4vLLMnvfp4全GPU32k

結果

構成A: BF16 CPU推論(th=13, ctx=16k)

指標実測値
PP速度(短prompt)33.37 tok/s
PP速度(287トークン)117.40 tok/s
TG速度(持続)7.59 tok/s
TTFT(287トークン)約2.58秒

2,233トークンの長い生成でもスループットは一定。KV cacheをq8_0にすることでメモリ圧を抑制。

BF16を選んだ理由は単純で、4-bit量子化よりもロジックと構文の崩れを避けたかったからだ。12チャネルDDR5-6400の帯域がBF16の巨大データ転送を支え、Zen 5のAVX-512 BF16ネイティブ演算が効いている。80B級では、CPU推論の可否は演算器そのものより帯域に左右されやすい。12チャネルDDR5が効いているからこそ、BF16でもdecodeが7.59 tok/sに届いた。

構成B: IQ4_NL Hybrid(Expert CPU offload, ctx=65k)

Run A: exps=CPU(Expert重みをCPUに配置)

指標実測値
GPU buffer(weights)1,403 MiB
CPU buffer(weights)41,472 MiB
graph_splits98
TG速度(加重平均)58.94 tok/s
PP速度(代表値)761-1,120 tok/s

Run B: exps=CPUなし(全重みGPU)

指標実測値
GPU buffer(weights)42,875 MiB
graph_splits2
TG速度(加重平均)85.36 tok/s
PP速度(代表値)880-3,572 tok/s

Expert Offloadの速度ペナルティ: -31%(58.94 -> 85.36 tok/s)

Run Aではweightsの大半がCPU側に寄り、GPU側は約1.4 GiBしか使っていない。GPU offloadを有効にしていても、実態としてはCPUとGPUの境界を頻繁に跨ぐ構成だった。graph_splitsが98まで増加しており、MoEのexps重みをCPU側に逃がした結果、前後の計算と中間のやり取りが細切れになっていた。

Run Bはどのtaskでも85 tok/s前後に揃い、極めて安定していた。GPU weightsが42.9 GiBまで伸び、graph_splitsは2に抑えられている。この差は実運用でも体感できるレベルで、コード生成や修正の反復回数にそのまま響く。

加重平均の算出方法

gen_tokens重み付き平均は、各taskのgen_tpsに対して、そのtaskのgen_tokens数を重みとして掛けるもの。たくさん生成したtaskほど平均に強く効くので、長文生成時の体感に近い。

  weighted_gen_tps = S(gen_tokens_i * gen_tps_i) / S(gen_tokens_i)
  

代表的なtask結果(Run A: exps=CPU)

taskprompt tokensprompt tpsgen tokensgen tpstotal ms
82100291.936659.141,458.59
2563,7571,045.8914159.715,953.40
6521,594761.226758.943,230.68
922908678.8118058.524,413.36
2,6632,284961.733,81058.8067,175.38

代表的なtask結果(Run B: exps=CPUなし)

taskprompt tokensprompt tpsgen tokensgen tpstotal ms
2121356.7147185.755,551.35
1,71876880.411,03685.4112,215.63
3,5396472,561.141,42185.5316,866.17
4,9611551,397.332,00785.2823,646.46
9,63830513.4547585.645,605.00

構成C: nvfp4 GPU(vLLM, ctx=32k)

指標実測値
TG速度(安定時)17-100 tok/s(変動大)
PP速度17-669 tok/s(バースト時)

vLLMのローリング平均ログのため、値の変動が大きい。安定的な生成時は58-100 tok/s程度。

3構成比較サマリ

構成TG速度(tok/s)VRAM使用品質用途
A: BF16 CPU7.590最高精密レビュー・監査
B: Hybrid exps=CPU58.94~3GB良好通常コーディング
B: Hybrid 全GPU85.36~43GB良好高速コーディング
C: nvfp4 GPU58-100~22GB良好vLLM統合環境

ライブ実演動画

Qwen3-Coder-Nextの実際の出力品質を確認するため、リアルタイム実行を撮影しました。以下の動画はコード生成と論理説明を行っている様子を示しています:

動画リンク: https://www.youtube.com/watch?v=Hm8e7864Fcw

この実演では以下を確認できます:

  • トークン生成の様子をリアルタイムで見ることで、「CPU推論が動いている」という実感が得られます
  • トークン生成の内容を確認できます

考察

BF16 CPU推論の価値

7.59 tok/sは対話用途には遅いが、コードレビューやセキュリティ監査では十分。BF16は量子化劣化がゼロのため、SQLインジェクション検出やパスワード平文リスクの指摘など、精密な判断が求められるタスクで信頼性が高い。

12チャネルDDR5-6400の帯域がBF16の巨大データ転送を支えており、Zen 5のAVX-512 BF16ネイティブ演算が効いている。

Expert Offloadの31%ペナルティ

exps=CPUはVRAMを40GB以上節約する代わりに、生成速度が31%低下する。graph_splitsが98(全GPUでは2)に増加しており、CPU-GPU間の頻繁なデータ転送が原因。

59 tok/sでも十分高速だが、VRAMに余裕がある場合は全GPUロードの方が明確に有利。Expert Offloadは「VRAMが足りない時の妥協策」であり、速度最適化の手段としては向いていない。

この測定条件(A3B / n_ctx=65536 / KV f16 / n_batch=2048 / -ngl 99)では、exps=CPUは「速くするための設定」ではなく「VRAMを節約する代わりに生成速度を落とす設定」だった。96GB級GPUなら、まずexps=CPUなしを基本線としてよい。

なぜ遅くなるか:構造的な観点

  1. 転送/分割のオーバーヘッド: graph_splits=98は、計算グラフが細かく分割され、GPUとCPUの間で同期や転送が頻発していることを示す
  2. VRAMに余裕がある環境ではメリットがない: Run BのGPU weightsは42.9 GiBで、96GB GPUならまだ余裕がある。exps=CPUでVRAM圧を下げる必要がなく、CPU計算と転送のコストだけを払っている
  3. KV f16 + 巨大コンテキスト: n_ctx=65536とKV f16が前提で、exps=CPUはKVコストを減らせないため、長コンテキスト運用では境界増加のデメリットが残りやすい

コーディング品質

BF16での評価:

  • セキュリティ監査: SQLi脆弱性、平文パスワードリスクを正確に検出し、修正コードとユニットテストを提供
  • ハルシネーション制御: スペック外の質問に対して「NOT IN SPEC」と正しく拒否
  • 複雑なロジック: Django要件の90%を満たすが、マルチテナント安全性の一部を見落とす。高品質なドラフト生成器 + エキスパートレビュー向け

SWAキャッシュ無効化の挙動(Qwen3-Next-80B-A3B-Thinking)

CPU推論でQwen3-Next-80B-A3B-Thinking(Q4_K_M)を走らせた際、Sliding Window Attention(SWA)やハイブリッド/リカレントメモリに起因するキャッシュの強制的な完全再処理が発生した。

  slot update_slots: id  1 | task 6686 | forcing full prompt re-processing due to lack of cache data (likely due to SWA or hybrid/recurrent memory, see https://github.com/ggml-org/llama.cpp/pull/13194#issuecomment-2868343055)

slot update_slots: id  1 | task 6686 | erased invalidated context checkpoint (pos_min = 223, pos_max = 223, n_swa = 1, size = 75.376 MiB)
  

約75MiBのコンテキストチェックポイントが破棄され、プロンプトの完全再処理が行われた。Qwen3-Coder-Next IQ4_NLのGPUオフロード検証時には見られなかった特有の挙動で、SWAを持つアーキテクチャをCPU推論する際の注意点として記録しておく。

感想

3モードの使い分けが明確になった:

  • 精密作業(BF16 CPU): セキュリティ監査、最終レビュー。速度は犠牲にするが量子化劣化ゼロ
  • 通常コーディング(Hybrid / GPU): 日常の開発作業。59-85 tok/sで体感的に速い
  • vLLM統合(nvfp4): tool-call-parser対応、prefix caching、API統合が必要な場合

Expert Offloadの31%ペナルティは想像より大きかった。「VRAMに載らないから仕方なく使う」設定であることが実測で確認できた。

再現方法

BF16 CPU

  podman run --rm -it \
  -p 8081:8080 --shm-size 16g --cap-add=SYS_NICE \
  -v /mnt/data/hf/hub/models--unsloth--Qwen3-Coder-Next-GGUF:/models:Z \
  compute.home.arpa/llamacpp-zen5:qwen3-coder-next \
  -m /models/snapshots/.../BF16/Qwen3-Coder-Next-BF16-00001-of-00004.gguf \
  --cache-type-k q8_0 --cache-type-v q8_0 \
  --flash-attn on --ctx-size 16384 \
  --parallel 1 --threads 13 --threads-batch 13 \
  --batch-size 2048 --ubatch-size 512 \
  --jinja --host 0.0.0.0 --port 8080
  

IQ4_NL Hybrid(Expert CPU offload)

  IMG=compute.home.arpa/ik_llama-cuda
MO=/mnt/data/hf/hub/models--ubergarm--Qwen3-Coder-Next-GGUF
MODEL=/models/snapshots/.../Qwen3-Coder-Next-IQ4_KSS.gguf

podman run --rm -it --device nvidia.com/gpu=all \
  -p 8001:8080 --shm-size 16g --cap-add=SYS_NICE \
  -v "$MO":/models:ro,Z $IMG \
  --host 0.0.0.0 --port 8080 -m "$MODEL" \
  -c 65536 --threads 13 --threads-batch 23 \
  -b 2048 -ub 2048 -ngl 99 \
  -ot exps=CPU -fa on --no-mmap --jinja
  

IQ4_NL全GPU(Expert GPUロード)

  podman run --rm -it --device nvidia.com/gpu=all \
  -p 8001:8080 --shm-size 16g --cap-add=SYS_NICE \
  -v "$MO":/models:ro,Z $IMG \
  --host 0.0.0.0 --port 8080 -m "$MODEL" \
  -c 65536 --threads 13 --threads-batch 23 \
  -b 2048 -ub 2048 -ngl 99 \
  -fa on --no-mmap --jinja
  

nvfp4 GPU(vLLM)

  podman run --rm --device nvidia.com/gpu=all \
  --security-opt seccomp=unconfined --cap-add SYS_NICE --shm-size=16g \
  -v /mnt/data/hf:/data/hf:Z \
  -v /opt/containers/runtime/vllm/data/gpu_cache:/data/cache:Z \
  -p 8000:8000 \
  -e HF_HOME=/data/hf -e HF_DATASETS_CACHE=/data/hf \
  -e VLLM_CACHE_ROOT=/data/cache -e HF_HUB_OFFLINE=1 \
  -e FLASHINFER_DISABLE_VERSION_CHECK=1 \
  compute.home.arpa/vllm-gpu:nightly vincentzed-hf/Qwen3-Coder-Next-NVFP4 \
  --dtype auto --gpu-memory-utilization 0.88 \
  --max-num-seqs 1 --max-model-len 32768 \
  --enable-prefix-caching --trust-remote-code \
  --enable-auto-tool-choice --tool-call-parser qwen3_coder \
  --reasoning-parser qwen3 --served-model-name qwen3-coder-next-nvfp4
  

Qwen3-Next-80B-A3B-Thinking(CPU推論)

  podman run --rm \
  -p 8081:8080 --shm-size 1g \
  -v /opt/containers/runtime/llamacpp/data/models:/models:Z \
  compute.home.arpa/llamacpp-zen5:latest \
  -m /models/Qwen3-Next-80B-A3B-Thinking-Q4_K_M.gguf \
  --ctx-size 16384 --threads 15 \
  --jinja --reasoning-budget 512 \
  --host 0.0.0.0 --port 8080
  

補足ノウハウ

256kコンテキスト設定

IQ4_NL構成ではctx=262144まで設定可能だが、Expert Offload + 256kの組み合わせはKVキャッシュが巨大になるため現実的ではない。実運用はctx=65536程度が上限。

graph_splitsの意味

graph_splitsはCPU-GPU間のデータ転送回数の指標。exps=CPUでは98(毎層のExpert計算でCPUに戻る)、全GPUでは2(入出力のみ)。この差がそのまま速度差に反映される。

運用指針

  • 96GB級GPUでは、基本はexps=CPUなしをデフォルトにする
  • exps=CPUはVRAMが溢れる、または不安定になる場面だけで使う
  • 次の改善余地はexps=CPUよりもKV量子化とコンテキスト設計にある
  • BF16 CPU推論は精度重視のバックグラウンド処理レーンとして使い分ける