40B Denseモデルの現実:IQuest-Coder-V1-40BをCPU/GPU/Aiderで回して分かったこと
IQuest-Coder-V1-40B-Instruct(Dense 40B)をCPU Q5_K_M、GPU nvfp4、Aider whole-editの3構成で検証。CPU推論は構造的に破綻、nvfp4で25-28 tok/sが実用域、Aiderのwhole-editは40Bと相性が悪い。Performance Factorで111B系の6-7倍の効率を確認。40B Denseの実運用限界を実測データから整理した。
はじめに
日常的な開発パイプラインやエージェント用途において、LLMの推論環境をどう構築するかは常に悩ましい問題です。今回は、コーディング特化のモデルとして注目している「IQuest-Coder-V1-40B」を対象に、CPU(EPYC 9175F)のみを利用した推論と、GPU(vLLM環境・nvfp4)を利用した推論のパフォーマンスを実測し、さらにAider(AIコーディングエージェント)のwhole-edit形式での実用性まで検証しました。
結論から言えば、40BクラスのDenseモデルをCPUで動作させることはパイプライン用途には構造的に無理があります。GPU(特にnvfp4を活かした構成)へ移行することで圧倒的な効率と制御性を得られる一方、Aiderのwhole-editも40B Denseとは相性が悪いことが分かりました。本記事では、その具体的な挙動と評価のプロセスを、実測データとともに解説します。
実験環境
| 項目 | 仕様 |
|---|---|
| CPU | AMD EPYC 9175F(Zen 5, 16C, L3 512MB) |
| GPU | NVIDIA RTX PRO 6000 Blackwell Max-Q(96GB VRAM) |
| メモリ | DDR5-6400 768GB(12ch) |
| OS | Ubuntu 24.04 LTS |
検証構成
| 構成 | Runtime | 量子化 | 配置 |
|---|---|---|---|
| A: CPU推論 | llama.cpp server(Podman) | Q5_K_M(GGUF) | CPU RAM |
| B: GPU推論 | vLLM | nvfp4 | GPU VRAM |
| C: Aider利用 | vLLM(Loop-Instruct variant) | nvfp4 | GPU VRAM |
背景と課題:CPU推論の限界
IQuest-Coder-V1-40B-Instructは40B級のDense(非MoE)コーディング特化モデルです。MoEモデルと違い推論時に全パラメータを使うため、計算量がそのままモデルサイズに比例します。
最初に試したのは、IQuest-Coder-V1-40B-Instruct.q5_k_m.gguf を Podman 上の llama.cpp server を用いて、GPUを使わずにCPU(AMD EPYC 9175F, 16コア)のみで起動する構成です。コンテキスト長は 8192 に設定し、AiderやエージェントシステムなどTTFT(Time To First Token)と低レイテンシが求められる「待たない」パイプライン処理を想定していました。
しかし、実際に運用してみると以下のような致命的な問題が発生しました。
- 常にコアが張り付く: 40BのDenseモデルは全層を毎トークン計算するため、MoE(Mixture of Experts)モデルのように計算を省略できず、CPUに過大な負荷がかかります。
- TTFTの破綻: プロンプトが4k〜5kトークンを超えると(例:
task.n_tokens=4640)、Prompt evaluationの処理時間が支配的となり、生成(tok/s)が始まる前の時点で体感が破綻してしまいました。 - ストレージの恩恵がない: モデルをSSDに配置することでロード時間は短縮されましたが、生成速度やPrompt evalの速度にはほぼ無関係でした。
- スループット寄りの設定:
llama-serverの設定上、batch-size 2048やubatch-size 512といったスループット重視(バッチ大)の構成になっており、これが低レイテンシを求めるパイプライン用途と致命的に噛み合いませんでした。
NUMA bindやスレッド指定、mlockなど、基本的なチューニングは施しており、CPU性能自体は素直に使い切れていましたが、本質的には「40BのDenseモデルをCPUで回している」こと自体が最大のボトルネックでした。CPU環境では、体感の悪さは単なる設定不足ではなく「正常な挙動」です。
構成A 計測結果
| 項目 | 実測値 |
|---|---|
| TTFT(4k-5kプロンプト時) | 数十秒(体感破綻) |
| CPU使用率 | 全コア100%張り付き |
| 問題の本質 | 40B全層を毎トークン計算、省略不可 |
GPU(nvfp4)環境への移行と実測
CPUでの限界を踏まえ、GPUを利用した構成(vLLM + nvfp4)へと移行しました。比較対象として、111Bクラスの推論モデルである command-a-reasoning も並行して評価しています。
実測スループット
vLLMのログから得られた実測値は以下の通りです。
| 指標 | 実測値 |
|---|---|
| PP速度(Prompt throughput) | 1,100-2,300 tok/s |
| TG速度(Generation throughput) | 25-28 tok/s(安定) |
| KVキャッシュ使用率 | 2-12% |
| Prefixキャッシュヒット率 | 20-45% |
vLLMログからの連続計測(抜粋):
Engine 000: Avg generation throughput: 28.3 tokens/s, KV cache usage: 2.0%, Prefix cache hit rate: 22.8%
Engine 000: Avg generation throughput: 28.0 tokens/s, KV cache usage: 2.3%, Prefix cache hit rate: 22.8%
Engine 000: Avg generation throughput: 27.8 tokens/s, KV cache usage: 2.8%, Prefix cache hit rate: 22.8%
Engine 000: Avg generation throughput: 27.4 tokens/s, KV cache usage: 3.5%, Prefix cache hit rate: 22.8%
- Prompt throughputは約1100〜2300 tok/sで、入力処理は完全に問題なく、CPU、トークナイザ、IPCにも十分な余裕があります。
- Generation throughputは安定して25〜28 tok/sで、40Bクラスとしては非常に良好な数値です。111B(command-a-reasoning)と比較すると約2.3〜2.5倍の速度が出ています。
- KV cache usageは2〜12%程度で、長文の履歴や巨大なコンテキストに引きずられることなく、素直にデコードできています。
- Prefix cache hit rateは20〜45%で、システムプロンプトやツールスキーマを完全に固定化することで、さらなる改善の余地があります。
実行状態も非常に安定しており、Running: 1 reqs の間はスループットが落ちることなく出続けています。「0 tok/s」が記録される瞬間は単なる集計窓のタイミングであり、ハングやデッドロックといった兆候は一切ありませんでした。
TG速度25-28 tok/sの出力長別体感レイテンシ:
- 200トークン: 約7-8秒
- 400トークン: 約14-16秒
- 800トークン: 約30秒
これは111Bモデルの半分以下の待ち時間であり、Aiderなどのエージェントやテスト生成の場面で明確な差となって表れます。
Aider whole-edit形式での検証
GPU nvfp4環境でAider(whole-edit形式)を試したところ、また別の問題が浮上しました。
| 指標 | 実測値 |
|---|---|
| TG速度 | 0.6-8 tok/s(不安定) |
| KVキャッシュ使用率 | 7-13%(急激に増加) |
| Prefixキャッシュヒット率 | 6%(ほぼ無効) |
whole-edit形式はファイル全体を再生成するため出力トークン数が爆発します。repo-map + 複数ファイル添付でコンテキストが肥大し、KVキャッシュが急速に膨張します。Prefixキャッシュヒット率が6%しか出ないのは、コンテキストが毎回変動するためです。
比較サマリ
| 構成 | TG速度(tok/s) | 実用判定 | 用途 |
|---|---|---|---|
| A: CPU Q5_K_M | 測定不能(TTFT破綻) | 不可 | - |
| B: GPU nvfp4 | 25-28 | 実用 | agent/テスト生成/CI |
| C: Aider whole-edit | 0.6-8 | 非実用 | - |
Performance Factor:パラメータあたりの生成効率
実務での体感に直結する指標として、モデル規模(パラメータ数)あたりの生成トークン数を「PF(Performance Factor)」として定義しました。
PF ≒ generation tok/s ÷ モデル規模(B)
| モデル | パラメータ | TG速度 | tok/s per B | 相対PF |
|---|---|---|---|---|
| command-a-reasoning | 111B | ~11 tok/s | 0.10 | 1.0 |
| IQuest-Coder-40B nvfp4 | 40B | 26-28 tok/s | 0.65-0.70 | ≈6.5-7.0 |
| 小型7B fp16 | 7B | 60-80 tok/s | 9-11 | 別枠 |
「パラメータあたりの生成性能」において、IQuest-Coder-40Bは111B系の6〜7倍という圧倒的な効率を叩き出しています。これはnvfp4が正しく効いている証拠であり、「大モデルの知性 vs 実行速度」のトレードオフにおいて非常に優れた位置にあります。
考察
なぜDenseはCPUで厳しいのか
MoEモデル(例: Kimi-K2.5の活性32B)はトークンごとに一部のエキスパートだけ計算します。Denseは40B全層を毎回計算するため、計算量の削減が効きません。同じ「40B級」でもCPU推論の負荷は根本的に異なります。
EPYC 9175Fの12チャネルメモリ帯域でも、Denseの全層アクセスパターンではメモリ帯域が飽和します。MoEのようにL3キャッシュにエキスパートを載せる戦略も使えません。
| 項目 | Dense 40B | MoE 229B(活性10B) |
|---|---|---|
| 毎トークンの計算量 | 40B全層 | 10B相当 |
| L3キャッシュ活用 | 効かない(全層アクセス) | 効く(エキスパート局所性) |
| CPU推論のTG | 測定困難 | 10-37 tok/s |
| CPU推論の実用性 | 非実用 | バッチ用途で実用 |
Aider whole-editの構造的問題
whole-edit形式が遅い原因:
- ファイル全体を出力するためトークン数が膨大
- repo-map + 添付ファイルでpromptも肥大
- Prefixキャッシュヒット率が6%(変動するコンテキストのため)
- KVキャッシュが急速に膨張(7→13%)
対策はwhole-editを避けてdiff/patch形式に変更することです。出力トークン数を大幅に削減でき、生成速度の問題を構造的に回避できます。
モデル品質と制御性
長文で構造化されたGo言語のテストコード生成において破綻がなく、論理の崩れやハルシネーションは、場合によっては111BのReasoning系モデルよりも少ないケースがありました。「考えすぎないInstruct型」特有の素直なEOS(End of Sequence)や、stop・max_tokens の確実な効き具合が、自動化されたコード生成と極めて相性が良いのです。
深い推論や証明、長文思考においては確かに command-a-reasoning が上回りますが、実務では「速度」「止まりやすさ」「制御しやすさ」の方が価値を持つケースが多々あります。
安定運用できている理由
このモデルが安定している理由として四つ挙げられる。モデル単体ではなく、モデルとサービングと実装の相性まで含めて評価したうえでの結論だ。
nvfp4 × vLLM main/nightlyの組み合わせが成立しているstop / max_tokensが適切に効いている- Instruct 型らしく EOS が素直で、出力の終端制御がしやすい
agent-gatewayの設計と噛み合っている。特に non-stream 時だけ retrieval を差し込むような実装方針とも整合している
つまり、たまたまベンチマークが良かったのではなく、日常運用で問題になりやすい箇所が比較的きれいに揃っている。
改善策の優先順位
もし同様の構成で悩んでいる方がいれば、以下の順序で対策を検討してください。
- GPUを使う(最優先)
--device nvidia.com/gpu=allおよび--n-gpu-layers 999を指定し、GPUのVRAMをフル活用してください。RTX PRO 6000 MAX-Q 96GBのような大容量VRAMがあるなら、使わない理由はありません。 - CPUのまま運用する場合の応急処置
batch-sizeを 512〜1024 に下げる。ubatch-sizeを 128〜256 に下げる。- 履歴やリポジトリマップ(repo-map)などのプロンプトを削る。
- モデルをスケールダウンする パイプラインの制約でどうしてもCPUを使わざるを得ないなら、7B〜14Bクラスのモデルに落とすのが現実解です。
再現方法
GPU nvfp4(推奨構成)
vllm serve IQuestLab/IQuest-Coder-V1-40B-Instruct-nvfp4 \
--max-num-seqs 1 \
--max-model-len 32768
CPU Q5_K_M(参考: 非推奨)
podman run --rm -it \
-p 8081:8080 --shm-size 16g --cap-add=SYS_NICE \
-v "$MO":/models:ro,Z $IMG \
--host 0.0.0.0 --port 8080 -m "$MODEL" \
--jinja -c 8192 \
--threads 14 --threads-batch 14 \
-b 2048 -ub 512 \
--parallel 1 --flash-attn on
Aider設定の最適化
--edit-format diff: whole-editを避けて出力を削減temperature=0: greedy固定で生成を高速化- repo-mapと/add対象を最小限に
max_model_lenを必要最小に設定
結論と今後の展望
「IQuest-Coder-V1-40B」をnvfp4とvLLMで稼働させる構成は、速度・安定性・制御性のすべてにおいて実務の本命(デフォルト)として十二分に機能することが確認できました。40BクラスのDense モデルの位置づけが明確になった結果、使い分けは次のようになります。
- 日常(agent/aider/CI): IQuest-Coder-40B nvfp4(本命)
- 深い推論・設計レビュー: command-a-reasoning(サブ)
- バッチ処理(CPU常駐): MoEモデル(Kimi-K2.5等)
40Bクラスで安定して25–28 tok/sが出るのであれば、日常的なエージェント処理やCI、テスト生成で111Bモデルを常用する理由はほぼ消滅します。今後は、IQuest-Coder-40Bをメインのルーティング先に据え、難解な推論や設計レビューが求められる特異なケースのみ command-a-reasoning へ流すアーキテクチャが最も美しいと考えています。
次のステップとしては、Prefix cacheのヒット率を現在の40%から60%以上に引き上げるためのプロンプト固定化と、p95を基準としたSLOベースの最終チューニングを進めていく予定です。
