2026年10月18日
要点
-
構成: 3値化した27B(Gated-DeltaNet ハイブリッド、フルアテンション16層)を、vLLM 0.31.0 のテンソル並列2で動かしています。KV は
turboquant_4bit_nc、MTP は予測1トークン、KV は RAM 2GiB + SSD に退避します。 - 速度: 単発 67〜76 tok/s、8並列で 352〜392 tok/s、16並列で 423〜486 tok/s。KV プールは 293K トークンです。
- 試して不採用: 2bit KV、KVarN、NVFP4 KV、fp8 KV、LMCache。理由は後述します。
- 採用: PR#53060(TurboQuant の融合 decode)、短い順の prefill 枠配分、ビジョンタワーの CPU オフロード、KV の SSD 退避。
ハードウェアと土台
| 項目 | 内容 |
|---|---|
| GPU | RTX 5070 12GB ×2(片方は PCIe x4) |
| OS | WSL2 |
| エンジン | vLLM 0.31.0(0.30.0 から 2026-10-12 に更新) |
| モデル | 3値27B。ベースは Qwen3.8-27B 系のハイブリッド |
| KV |
turboquant_4bit_nc、ブロック約1,584トークン |
| 投機デコード | MTP、予測1トークン、平均受理長 1.58 |
PCIe x4 側の GPU があるため、テンソル並列の通信(all-reduce)が混載ステップの約半分を占めます。そのため、計算を減らす工夫より、通信と待ち時間を減らす工夫の方が効きました。
採用したもの
1. TurboQuant の融合 decode(PR#53060)
未マージの PR を当てました。長文の decode が +28% 速くなりました。短文では変わりません。並列時は TQ_SIMT_CTAS_PER_SM=2 で従来並みに戻ります。代償は KV プールが約 11% 減ることでした。
2. prefill 枠を短い順に配る
長文の prefill が走っていると、後から来た短い質問が長く待たされます。prefill 枠を短い順に配る修正で、後着の TTFT が 26.1 秒 → 2.8 秒になりました。
3. vLLM 0.31.0 への更新
スケジューラは上流のままで、0.30.0 と同等以上でした。decode +1.8%、長文 prefill -27%、長文の最中に来た短文の TTFT 0.88 → 0.64 秒です。短時間に3回起動すると systemd の起動回数制限に掛かるので、再起動は1回ずつ見張ります。
4. ビジョンタワーの CPU オフロード
画像を読む部分(ビジョンタワー)の重みを GPU に置かず、CPU に逃がしました。KV プールが約 16.5% 増えました。
5. KV の RAM + SSD 退避(今日 11:56 から本番)
vLLM 標準の OffloadingConnector(TieringOffloadingSpec)で、GPU から追い出された KV を RAM(2GiB)→ SSD に退避します。
- 追い出された 16K トークン文書の再要求: 10.4 秒 → 約 1.75 秒。GPU に残っている文書は 0.16 秒です。
- 再起動後も SSD から復元できます(
PYTHONHASHSEED=0が必要)。 - 代償は、KV プール 312K → 293K(-6%)です。decode は測定のゆらぎの範囲でした(8並列 352〜392 tok/s、退避なしは 368〜400)。
- WSL2 では、ホスト側の番地と GPU から見た番地が違うために
illegal memory accessで落ちます。cudaHostGetDevicePointerで番地を取り直す小さなパッチで直しました。 -
expandable_segmentsは併用できないので外します。SSD 側には上限がないため、起動時に古いファイルを消して 150GB に収めています。 - 精度は、思考ありの 16K 問題 15 問で、通常 15/15、復元後も 15/15。ただしハイブリッドモデルは、復元後の出力がビット単位では一致しません。
試して採用しなかったもの
| 候補 | 結果 |
|---|---|
| 2bit KV | 実モデルで擬似量子化して評価。数値集計の問題で -19pt となり、見送り。誤差は V の量子化が主因で、K は影響が小さいことも分かりました |
| KVarN(HyperQwen 移植) | KV に確保できるメモリが足りず、起動できないまま断念 |
| NVFP4 KV | SM120 で上流の PR を当てて試したが、不採用 |
| fp8 KV | 検討して不採用 |
| LMCache | 複数プロセスの MP モードが CUDA IPC を使い、WSL2 では GPU 間の CUDA IPC が固まる。不採用 |
| MTP の予測数 2〜4 | 1〜4 を再測定し、1 が最良のため据え置き |
運用で踏んだこと
- 起動を監視せず再起動して、依存パッケージ不足でクラッシュループを4分続けたことがあります。本番の再起動は張り付いて見て、1回目の失敗で止めます。
- JIT コンパイルを監視なしで呼ぶと、並列実行で RAM が枯渇して本番が OOM kill されます。
MAX_JOBS=1と空きメモリの監視を付けています。 - 試験用の子プロセスが固まって1コアを占有し、decode が 30 tok/s に落ちたことがあります。GPU を使う試験は、終わったら子プロセスの終了を確認します。
- 負荷試験の前に、利用者の接続と実行中リクエストがゼロであることを確認します。
今後
- 実際の利用者のトラフィックでの、KV 退避の命中率と TTFT は、まだ測れていません。平日に測ります。
- SSD の容量管理は起動時だけなので、長く動かすなら定期実行を足す予定です。