- チューニングの順序を先に決める
- gpu_memory_utilization — 最初にいじる値
- テンソル並列とパイプライン並列
- 量子化の選択
- KVキャッシュのデータ型
- OOM診断の順序
- よくある落とし穴五つ
- 試してみる
- 参考資料
チューニングの順序を先に決める
六回にわたって内部を見てきたので、最後はデプロイだ。ただし、いじれる項目を並べる前に、まず順序を決めてから始める。チューニングが失敗するもっとも多い理由は、間違った値を選ぶことではなく、複数の値を一度に変えてしまい、何が効いたのか分からなくなることだ。
勧める順序はこうだ。第一に、モデルをGPUに収める。第二に、長さの上限をワークロードに合わせる。第三に、KVキャッシュの余裕を確保する。第四に、そこまで終えてから初めてバッチと遅延を調整する。前の三段階が固まっていない状態でバッチ引数をいじっても、たいていは何も起きない。
内容は 2026-08-12 に公式ドキュメントとソースで確認しました。vLLM は変化が速いため、設定値と挙動は使用中のバージョンのドキュメントで再確認してください。
# この記事で扱う引数が集まった典型的な形
vllm serve meta-llama/Llama-3.1-8B-Instruct \
--max-model-len 8192 \
--gpu-memory-utilization 0.92 \
--tensor-parallel-size 1 \
--max-num-seqs 128
gpu_memory_utilization — 最初にいじる値
公式ドキュメントの定義はこうだ。モデル実行器が使うGPUメモリの比率で、0から1の間の値を取る。そして2026-08-12に私がドキュメントとmainブランチのCacheConfigソースで確認した宣言上のデフォルト値は0.92だった。古い記事には別の数字が書かれている場合があるので、使用中のバージョンで直接確認する。
この値が重要な理由は、第1回と第6回で見た構造にある。vLLMはこの比率分のメモリを確保したあと、そこから重みとオーバーヘッドを引いた残り全部をKVキャッシュとして使う。つまりこの値を上げると、KVキャッシュはすぐさま大きくなり、より長いリクエストとより多くの同時リクエストに耐えられるようになる。
だからといって1に近づけて上げればよいかというと、そうではない。この比率はGPU全体を基準に計算されるため、同じGPUを使う別のプロセスがあると計算が狂う。KubernetesでGPUを共有する構成なら特にそうだ。また、断片化や一時的なアクティベーションテンソルのせいで、実際の使用量は計算より少し多く出るため、余裕を0にすると、普段は問題なく動いていても特定のリクエストの組み合わせでだけ落ちる。
値を上げてもスループットが伸びないなら、それは上限がメモリではなく別のところにあるという合図だ。max_num_seqsやmax_num_batched_tokensが先に効いている可能性がある。
テンソル並列とパイプライン並列
ここでまず、もっとも多い誤解を取り除いておく。テンソル並列は性能オプションではなく容量オプションだ。
公式ドキュメントの基準は明確だ。モデルがGPU一枚には収まらないが、一つのノードの複数GPUには収まるとき、テンソル並列を使う。一つのノードにも収まらないときは、パイプライン並列を合わせて使う。設定方法もドキュメントが直接示している。tensor_parallel_sizeをノードあたりのGPU数に、pipeline_parallel_sizeをノード数にする、というものだ。ドキュメントが挙げる例では、ノード2台にGPU8枚ずつなら、テンソル並列8、パイプライン並列2になる。
ドキュメントが言及している例外的な状況も知っておく価値がある。一つのノードの中でGPU数が均等に割り切れない場合には、テンソル並列を1にし、パイプライン並列をGPU数にすることで、層を不均等に分割できる。
tensor_parallel_sizeのデフォルト値は、ドキュメント上で1だと確認した。つまり何も与えなければGPU一枚だけを使う。サーバーにGPUが何枚挿さっていても、そうなる。マルチGPU構成のマシンで性能が期待に届かないなら、まずこの値を確認する。
一枚にすでに収まるモデルにテンソル並列をかけるとどうなるか。各GPUが自分の分のKVキャッシュを持つようになり、合計のキャッシュが増える利点はあるが、層ごとにGPU間の通信が追加される。だから、実測なしに無条件で得だとは言えない。第4回で見たように、公式ドキュメントがプリエンプションへの対策リストにテンソル並列の引き上げを挙げている理由は、処理速度のためではなくキャッシュ空間のためだ。
量子化の選択
量子化は重みをより少ないビットで表現してメモリを減らす。そして減った分がそのままKVキャッシュに回る。第6回の構造を思い出せば、この利点がなぜ大きいのかは明らかだ。同じGPUで、より長いコンテキストとより多くの同時リクエストが手に入る。
vLLMのドキュメントが扱う方式は複数ある。AutoAWQ、BitsAndBytes、GPTQModel、Intel Neural Compressor、LLM Compressor、NVIDIA Model Optimizer、AMD Quark、TorchAOなどがドキュメントに列挙されており、LLM Compressorの側ではFP8 W8A8、INT4 W4A16、INT8 W8A8といった組み合わせを扱う。ドキュメントは出発点としてLLM Compressorを案内している。
選ぶときに実際に重要なのは、方式の名前ではなく二つのことだ。
一つはハードウェア対応だ。ドキュメントは、量子化の実装ごとにハードウェアプラットフォームとの互換性が異なるという表を提供しつつ、この互換性表は今後も変わりうると明記している。だから名前だけを見て選ばず、自分のGPU世代で実際にサポートされているかを表で確認する。選び方を間違えると、そもそも起動しないか、起動しても高速化の恩恵を受けられず遅くなる。
もう一つは、すでに量子化されたモデルかどうかだ。--quantization引数の説明は、重みの量子化方式を指定するというもので、値を与えなければモデル設定ファイルの量子化設定を確認するとされている。つまりハブからすでに量子化されたチェックポイントを取得して使うなら、たいていは別途指定しなくてよい。
品質の話も欠かせない。量子化はただではなく、精度に影響を与える。どれだけ影響するかは、モデルと方式とタスクによって異なる。だからここで「4ビットなら問題ない」といった一般化はしない。自分の評価セットで直接測る以外に答えはない。
KVキャッシュのデータ型
減らせるのは重みだけではない。KVキャッシュ自体のデータ型も設定項目だ。--kv-cache-dtypeのドキュメント上の説明は、KVキャッシュの保存に使うデータ型であり、autoならモデルのデータ型に従うというものだ。デフォルト値はドキュメントとソースの両方でautoだと確認した。ソースには、CUDA 11.8以上でfp8系列に対応するという説明も付いている。
この項目が魅力的な理由は、効果が正確にKVキャッシュだけに効くからだ。重みはそのままにしてキャッシュだけを半分に減らせば、同じメモリで長さや同時実行数を増やせる。ただしこれも精度の低下であるため、評価なしに有効化しない。
OOM診断の順序
メモリ不足は、vLLMの運用でもっとも頻繁に出会う問題だ。診断の最初のボタンは、いつも一つしかない。起動中に起きたのか、運用中に起きたのかを、まず見分ける。
起動中に失敗したのなら、原因は二つのうちのどちらかだ。
重みが収まらない場合だ。モデルを読み込む段階で落ちる。解決策は量子化、テンソル並列、より小さいモデルだ。gpu_memory_utilizationを上げても大きな助けにはならない。すでにほとんどを割り当てているのに重みが収まらない、という状況だからだ。
KVキャッシュが不足している場合だ。第6回で見たあのエラーだ。最大シーケンス長がKVキャッシュに収められるトークン数より大きいというメッセージが出て、エラー自体が解決策を教えてくれる。gpu_memory_utilizationを上げるか、max_model_lenを減らすかだ。実務では後者が先になる。たいていは実際のワークロードに必要な長さより大きく開けてある状態だからだ。
運用中に起きたのなら、話は違う。vLLMは起動時点でキャッシュをあらかじめ確保しておくため、正常な状況であれば、リクエストが増えたからといって突然OOMになることはない。リクエストが増えると、OOMの代わりに第4回で見たプリエンプションが起きる。だから運用中のOOMは、たいていvLLMの外側に原因がある。同じGPUに別のプロセスが入ってきたか、gpu_memory_utilizationが実際の余裕より大きく設定されていたか、普段は出てこない大きさのマルチモーダル入力が来た場合だ。
そしてもう一つ、よく誤診される場合がある。OOMではないのに急に遅くなる状況だ。このときはメモリ関連の引数をいじる前に、プリエンプションの警告ログをまず確認する。プリエンプションが繰り返されているなら、それは性能の問題ではなく容量の問題だ。
よくある落とし穴五つ
シリーズ全体で繰り返し出てきた落とし穴をまとめておく。
| 落とし穴 | 結果 | 関連回 |
|---|---|---|
| 古い記事の設定をそのままコピー | 削除された引数を使ってしまう。特にスワップ関連の設定はV1で外された | 第4回 |
gpu_memory_utilizationを限界まで引き上げる | 普段は問題ないが、特定のリクエストの組み合わせでだけ落ちる | この記事 |
max_model_lenをモデルの最大値まで開放 | 誰も使わない長さを支えるために同時処理能力を失う | 第6回 |
| アプリケーション側で生成上限を定数で固定 | 長い入力が来た瞬間にリクエストが拒否される | 第6回 |
| プロンプトの先頭にタイムスタンプやセッション識別子 | プレフィックスキャッシュが丸ごと無効化。引数では解決不可 | 第5回 |
最後の行が特に重要だ。前の四つは設定を直せば解決するが、これはプロンプト設計の問題であるため、どの引数をいじっても改善しない。
七回を貫く結論は一つだ。vLLMにおける性能とは、おおむねKVキャッシュをどれだけ節約し再利用するかの問題である。ブロックに分割し、ステップごとに詰め直し、重なる先頭部分を共有し、長さの上限で最悪のケースを制限すること。そのすべてが同じ話の別の面にすぎない。
試してみる
- LLM GPUメモリ(VRAM)計算機 — 量子化とGPU数を変えながら、重みとKVキャッシュがどう変わるかを計算できる。この記事のチューニング順序を数字で予行演習できる。
- LLM APIコスト計算機 — 自前のサービング構成を決めたなら、同じワークロードをAPIで動かした場合と比較できる。
- K8s実習ラボ — Kubernetesにモデルサーバーを載せるなら、リソース上限とロールアウト、障害診断を手で身につけておくとよい。
- 前回: vLLM 内部構造 (6) — コンテキストウィンドウ、max_model_len、max_tokens 完全整理
- シリーズ最初: vLLM 内部構造 (1) — リクエスト一つがトークンになるまでの全経路
参考資料
- vLLM Engine Arguments (docs.vllm.ai) —
--gpu-memory-utilization、--tensor-parallel-size、--quantization、--kv-cache-dtypeの説明とデフォルト値を読んだ場所。 - vLLM CacheConfig ソース (GitHub main) —
gpu_memory_utilizationとキャッシュのデータ型の宣言上のデフォルト値を確認した場所。 - vLLM Parallelism and Scaling (docs.vllm.ai) — テンソル並列とパイプライン並列をいつ使うか、ノードとGPU数に合わせた設定方法の出典。
- vLLM Quantization (docs.vllm.ai) — 対応方式の一覧とハードウェア互換性表についての案内の出典。
- vLLM Optimization and Tuning (docs.vllm.ai) — プリエンプションへの対策と、関連引数の調整の方向性の出典。
- vLLM V1 Guide (docs.vllm.ai) — GPUとCPUの間のKVキャッシュスワップが削除されたという記述の出典。
현재 단락 (1/52)
六回にわたって内部を見てきたので、最後はデプロイだ。ただし、いじれる項目を並べる前に、まず順序を決めてから始める。チューニングが失敗するもっとも多い理由は、間違った値を選ぶことではなく、複数の値を一度...