コンテンツに移動
デベロッパー

vLLM のパフォーマンス チューニング: xPU 推論構成の徹底ガイド

2025年9月1日
https://storage.googleapis.com/gweb-cloudblog-publish/images/hero_v3.max-2500x2500.png
Eric Hanley

Field Solution Architect, AI Infrastructure

Brittany Rockwell

Product Manager, AI and Computing

※この投稿は米国時間 2025 年 8 月 26 日に、Google Cloud blog に投稿されたものの抄訳です。

このブログの執筆にあたり、Hossein Sarshar、Ashish Narasimham、Chenyang Li(敬称略)の協力を得ました。

大規模言語モデル(LLM)は私たちのテクノロジーとの関わり方を変革していますが、強力なモデルを効率的にサービングするのは難しい仕事です。オープンソースの LLM を大きなスケールでサービングする方法の第一候補として vLLM が急速に普及していますが、これで万事解決というわけではありません。ダウンストリーム アプリケーション向けに LLM をサービングするチームには、厳しいレイテンシとスループットの要件が課せられます。そのため、どのアクセラレータで実行するか、どのような構成が最も高いパフォーマンスにつながるかを徹底的に分析する必要があります。

このガイドでは、ユースケースに最適なアクセラレータを決定し、vLLM の構成を最適化することによって費用対効果の高い優れた結果を得るためのボトムアップ アプローチについて解説します。

: xPU、vLLM、および効果的なサービング フレームワークを実現する基盤的な機能についての基礎知識をお持ちの方を想定しています。

前提条件

始める前に、次のことを確認してください。

ユースケースに関する情報の収集

推論のユースケースにはそれぞれに独特の特徴があるため、適切なアクセラレータの選択は難しい作業に思えるかもしれません。費用対効果の観点から前もってわかる「理想的な組み合わせ」は存在せず、「モデル X は常にアクセラレータ Y で実行すべき」といった法則はありません。

最適な選択をするには、次のことを考慮する必要があります。

使用するモデル

この例で使用するモデルは google/gemma-3-27b-it です。これは、Google Gemma 3 ファミリーの、270 億パラメータの指示チューニング済みモデルです。

使用するモデルの数値精度

ここでは bfloat16(BF16)を使用します。

: モデルの数値精度によって、モデルの重みを保存するために使用されるバイト数が決まります。一般的なオプションは、float32(4 バイト)、float16(2 バイト)、bfloat16(2 バイト)です。現在、多くのモデルが 8 ビット、4 ビット(例: GPTQ、AWQ)またはそれ以下の量子化形式でも利用可能です。数値精度を低くすると、メモリ要件が下がるため速度が上がることがありますが、トレードオフとして精度(accuracy)が若干落ちる可能性があります。

ワークロードの特性: 1 秒あたりの想定リクエスト数

ここでは、1 秒あたり 100 件のリクエストのサポートを目標とします。

リクエストあたりの平均シーケンス長

  • 入力長: 1,500 トークン

  • 出力長: 200 トークン

  • したがって、リクエストあたりの合計シーケンス長は、平均で 1,500 + 200 = 1,700 トークンになります。

処理する必要がある最大合計シーケンス長

今回は、合計トークン数を 2,000 とします。

指定する GPU 使用率

vLLM の gpu_memory_utilization パラメータによって、xPU の VRAM のうち、KV キャッシュ用に事前に割り当てられる量を制御します(モデルの重みに割り当てられているメモリを前提とする)。デフォルトではこれは vLLM で 90% に設定されていますが、一般的には、メモリ不足を起こさない最大の値に設定することでパフォーマンスを最適化します。これは、auto_tune.sh スクリプトが担当します(この投稿の「vLLM 構成のベンチマーク評価、チューニング、最終決定」セクションで説明)。

プレフィックスのキャッシュ率

これはアプリケーション ログから判断しますが、今回の計算では 50% と推定します。

: プレフィックス キャッシングは、計算済みの KV キャッシュをリクエスト間で共通しているプレフィックスに再利用する、vLLM の強力な最適化機能です。たとえば、多くのリクエストに共通する長いシステム プロンプトがある場合に、そのプロンプトの KV キャッシュが 1 回だけ計算されて共有されるため、コンピューティング リソースとメモリを大幅に節約できます。一致率はアプリケーションによって大きく異なります。共通の指示パターンやシステム プロンプトがないかリクエストログを調べることで推定可能です。

レイテンシの要件

リクエストから最後のトークンまでのエンドツーエンドのレイテンシが、10 秒(P99 E2E)を超えないようにします。これが今回の主なパフォーマンスの制約です。

アクセラレータ(xPU)の選択

リソースは常に不足しがちな状態であり、これはユースケースに関して次のようなことを意味します。最新のハードウェアを使用しさえすれば最高のレイテンシとスループットを実現できることは明白ですが、より優れた費用対効果で要件を満たせるのにもかかわらずそのような選択をするのは、エンジニアとしては避けるべきです。

候補となるアクセラレータの特定

Google Cloud インスタンスのアクセラレータ最適化マシン ファミリーを参照して、アクセラレータ向けに最適化されたインスタンスのうち、どれが有力な候補となるかを判断できます。

Cloud TPU の選択肢を参照して、どの TPU が有望な候補となるかを判断できます。

今回のワークロード(「メモリ要件の計算」セクションで説明)に使用できるアクセラレータの例を以下に示します。

以下のオプションでは、合計 VRAM に応じて異なるテンソル並列処理(TP)構成が必要です。テンソル並列処理の説明については、次のセクションをご覧ください。

アクセラレータ最適化オプション

  • g2-standard-48

    • 4 つのアクセラレータを提供(96 GB の GDDR6)

    • TP = 4

  • a2-ultragpu-1g

    • 1 つのアクセラレータを提供(80 GB の HBM)

    • TP = 1

  • a3-highgpu-1g

    • 1 つのアクセラレータを提供(80 GB の HBM)

    • TP = 1

TPU のオプション

  • TPU v5e(チップあたり 16 GB の HBM)

    • v5litepod-8 は 8 個の v5e TPU チップと合計 128 GB の HBM を提供

    • TP = 8

  • TPU v6e(Trillium)(チップあたり 32 GB の HBM)

    • v6e-4 は 4 個の v6e TPU チップと合計 128 GB の HBM を提供

    • TP = 4

メモリ要件の計算

まず、必要な最小 VRAM の合計を見積もる必要があります。これにより、モデルが単一のアクセラレータに収まるか、並列処理が必要となるかがわかります。メモリ使用率は、モデルの重み、アクティベーション、オーバーヘッドを扱う「静的メモリ」と「KV キャッシュメモリ」の 2 つの要素に大きく分類できます。

この見積もりを可能にするために、Colab: HBM Calculator というツールが作られました。

上記で特定した情報を入力して、モデルを実行するために必要な最低限の VRAM を見積もることができます。

  • Hugging Face API キー

  • Hugging Face のモデル名

  • アクティブなパラメータの数(10 億単位)

  • ワークロードの入力と出力の平均長(トークン数)

  • バッチサイズ 1

https://storage.googleapis.com/gweb-cloudblog-publish/images/calculator_image_1.max-800x800.png

計算そのものはおおむね今回の議論の範囲外ですが、必要なメモリは次の式から求めることができます。

必要な xPU メモリ = [(model_weight + non_torch_memory + pytorch_activation_peak_memory) + (kv_cache_memory_per_batch * batch_size)] ,

ここで

  • model_weight は、「パラメータ数 × パラメータのデータ型 ÷ 数値精度に応じた定数」に等しい

  • non_torch_memory はメモリ オーバーヘッド用のバッファ(推定 1 GB 程度)

  • pytorch_activation_peak_memory は、中間アクティベーションに必要なメモリ

  • kv_cache_memory_per_batch は、バッチごとの KV キャッシュに必要なメモリ

  • batch_size は、エンジンが同時に処理するシーケンスの数

    • バッチサイズが 1 というのは現実的な値ではありませんが、エンジンによる処理を開始するために必要な最小 VRAM を把握できます。計算ツールでこのパラメータを変更して、128 ~ 512 シーケンスという大きなバッチサイズをサポートするために必要な VRAM の量を正確に確認できます。

https://storage.googleapis.com/gweb-cloudblog-publish/images/calculator_image_2_1.max-1100x1100.png

このケースでは、今回のワークロードで vLLM 上で gemma-3-27b-it を実行するには、最低でも約 57 GB の VRAM が必要であることがわかりました。

テンソル並列処理は必要か?

今回の場合、並列処理は必ずしも必要ではないものの、コスト パフォーマンスの観点からいくつかのオプションを検討できるし、検討すべきであるといえます。なぜこれが重要なのでしょうか。

テンソル並列処理とは何かを簡単に説明します。ざっくりといえば、テンソル並列処理は、大規模なモデルを複数のアクセラレータ(xPU)に分割して、モデルが必要なハードウェアに収まるようにする方法です。詳細については、こちらを参照してください。

vLLM はテンソル並列処理(TP)をサポートしています。テンソル並列処理では、モデルを機能させるために、アクセラレータがネットワークを介して互いに常に通信し同期する必要があります。このアクセラレータ間の通信によってオーバーヘッドが増加し、レイテンシに悪影響が及ぶ可能性があります。つまり、このケースでは費用とレイテンシにトレードオフの関係があります。

: このモデルのサイズでは、TPU にテンソル並列処理が必要です。前述のとおり v5e と v6e の HBM はそれぞれ 16 GB と 32 GB であり、モデルサイズをサポートするには複数のチップが必要です。今回のケースでは、この通信オーバーヘッドのために v6e-4 のパフォーマンスがわずかに低下しますが、単一のアクセラレータ インスタンスを使用する場合は低下しません。

vLLM 構成のベンチマーク評価、チューニング、最終決定

アクセラレータ候補を絞り込めたら、それぞれの候補で実現できる最高のパフォーマンスがどの程度かを確認します。このセクションでは、匿名化されたアクセラレータ最適化インスタンスおよび Trillium(v6e)のベンチマーク評価とチューニングの概要のみを説明しますが、他のアクセラレータでもプロセスはほぼ同じです。

  • VM を起動し、SSH 接続して更新する

  • vLLM Docker イメージを pull する

  • 自動チューニング スクリプトを更新して起動する

  • 結果を分析する

アクセラレータ最適化マシンタイプ

プロジェクトで Cloud Shell を開き、次のコマンドを入力して、選択したインスタンスと対応するアクセラレータおよびアクセラレータ数を起動します。プロジェクト ID を置き換え、割り当てがあるマシンタイプをサポートするゾーンを選択してください。

読み込んでいます...

インスタンスに SSH 接続します。

読み込んでいます...

インスタンスが実行されたので、最新の vLLM Docker イメージを pull して、インタラクティブに実行します。最後に、ゲーテッド モデルを使用している場合(このデモでは使用しています)、コンテナに HF_TOKEN を指定する必要があります。

読み込んでいます...

実行中のコンテナには、vllm-workspace/benchmarks/auto_tune/auto_tune.sh というファイルがあります。このファイルを、上記で特定した情報で更新して、できるだけ高いスループットと低いレイテンシを実現できるように vLLM 構成をチューニングする必要があります。

読み込んでいます...

auto_tune.sh スクリプトで、次の更新を行う必要があります。

読み込んでいます...

  • 使用するモデルを指定します。

  • インスタンス タイプを選択したときに GPU を使用することにした場合は、ここでそのことを指定します。

  • アクセラレータが 1 つしかないマシンタイプを使用する場合、テンソル並列処理は 1 に設定します。

  • 入力と出力を指定します。

  • 50% の min_cache_hit_pct を指定します。

  • レイテンシ要件を指定します。

  • num_seqs_list を更新して、高パフォーマンスを実現する一般的な値の範囲を反映します。

  • 必要に応じて num_batched_tokens_list を更新します。

    • このステップは不要な可能性が高いですが、ユースケースが特に小規模な場合や、入出力が特に大きい場合は必要になることがあります。

  • BASE、DOWNLOAD_DIR、cd “$BASE” ステートメントは、必ず示されているとおりに指定してください。

パラメータを更新したら、auto_tune.sh スクリプトを起動します。

読み込んでいます...

次のプロセスが発生します。

  • auto_tune.sh スクリプトによって、必要なモデルがダウンロードされ、可能な限り高い gpu_utilization(デフォルトでは 0.98)で vLLM サーバーの起動が試行されます。CUDA メモリ不足(OOM)が発生した場合は、安定した構成が見つかるまで 1% ずつ減らしてください

    • トラブルシューティングの注意点: まれに、最初の gpu_utilization テスト中には vLLM サーバーを起動できても、次のベンチマーク評価の開始時に CUDA OOM が発生して失敗することがあります。あるいは、最初のテストが失敗し、後続のサーバーが生成されず、処理がハングしたように見えることもあります。いずれかの状況が発生した場合は、ファイルの最後付近にある auto_tune.sh を編集して、gpu_utilization が 0.98 ではなく 0.95 以下の値から始まるようにします。

  • 次に、num_seqs_list と num_batched_tokens の組み合わせごとにサーバーがスピンアップされ、ワークロードがシミュレートされます。

    • ベンチマーク評価はまず無限のリクエスト レートで実行されます。

    • 結果として得られた P99 エンドツーエンド レイテンシが MAX_LATENCY_ALLOWED_MS の制限内であれば、これがこの構成の最大スループットと見なされます。

    • レイテンシが高すぎる場合、スクリプトはレイテンシの制約が満たされるまでリクエスト レートを段階的に減らして、適切なレイテンシを探します。これにより、指定されたパラメータとレイテンシの要件に対する維持可能な最大スループットが検出されます。

  • /vllm-workspace/auto-benchmark/$TAG/result.txtresults.txt ファイルで、どのパラメータの組み合わせが最も効率的であるかを確認し、その実行を詳しく調べます。
読み込んでいます...

最もパフォーマンスの高い結果を見て、状況を把握しましょう。

  • max_num_seqs: 256, max_num_batched_tokens: 512

    • これは、今回実行したテストにおける vLLM サーバーの設定です。

  • request_rate: 6

    • これは、スクリプトのループからの最後の入力であり、このサーバー構成で 10,000 ミリ秒未満のレイテンシを維持しながら処理できる最大レートは 1 秒あたり 6 リクエストであると判定されたことを意味します。1 秒あたり 7 リクエストを試すと、レイテンシが高くなりすぎました。

  • e2el: 7612.31

    • これは、サーバーに 6 リクエスト/秒の負荷をかけたときに測定された P99 レイテンシです。7,612.31 は 10,000 より小さいため、スクリプトによって成功と判定されました。

  • throughput: 4.17 

    • これは実際に測定された出力です。1 秒あたり 6 件のリクエストを送信していましたが、サーバーによって正常に処理されたのは 1 秒あたり 4.17 件のみでした。

TPU v6e(別名 Trillium)

TPU でも同じ最適化プロセスを実行しましょう。vLLM には TPU ベースの推論をサポートする堅牢なエコシステムがあり、TPU のベンチマーク評価の方法は前述のプロセスとほとんど同じです。

まず、TPU インスタンスを起動してネットワークを構成する必要があります。今回は、キューに格納されたリソースを使用します。Cloud Shell に戻り、次のコマンドを使用して v6e-4 インスタンスをデプロイします。このとき、必ず v6e が利用可能なゾーンを選択してください。

読み込んでいます...

リクエストのステータスをモニタリングします。

読み込んでいます...

TPU VM がアクティブになるまで待ちます(ステータスが PROVISIONING から ACTIVE に更新されます)。選択したゾーンのリソースの状況によっては、この処理にしばらく時間がかかることがあります。

次のコマンドを使用して、インスタンスに直接 SSH 接続します。

読み込んでいます...

接続したら、vLLM-TPU Docker イメージを pull し、コンテナを起動して、コンテナに入ります。

読み込んでいます...

ここでも先ほどの他のマシンタイプの場合と同様に、依存関係をインストールし、HF_TOKEN を指定して、自動チューニング スクリプトを更新する必要があります。

読み込んでいます...

vllm/benchmarks/auto_tune.sh ファイルに次の更新を加えます。

読み込んでいます...

次のコマンドを実行します。

読み込んでいます...

auto_tune.sh の実行中に、サーバーで実行できる最大の gpu_utilization 値を確認し、さまざまな num_batched_tokens パラメータを順に試して、最も効率的なものを特定します。

トラブルシューティングの注意点: 必要なコンパイル ステップが複数あるため、TPU で vLLM エンジンを起動するには前回よりも時間がかかることがあります。場合によっては 10 分以上かかることもあり、その場合、auto_tune.sh スクリプトによってプロセスが強制終了する可能性があります。この場合は、次の例のように、for ループが 10 秒ではなく 30 秒スリープするように start_server() 関数を更新します。

読み込んでいます...

出力はプログラムの実行中にプリントされ、ログファイル $BASE/auto-benchmark/TAG にも保存されます。これらのログから、現在の構成でもレイテンシ要件を満たせることがわかります。

results.txt ファイルをもう一度見てみましょう。

読み込んでいます...

最適な実行のときの対応する指標は次のとおりです。

読み込んでいます...

最もパフォーマンスの高い結果を見て、状況を把握しましょう。

  • max_num_seqs: 256, max_num_batched_tokens: 512

    • これは、今回実行したテストにおける vLLM サーバーの設定です。

  • request_rate: 9

    • これは、スクリプトのループからの最後の入力であり、このサーバー構成でレイテンシを 10,000 ミリ秒未満に保ちながら処理できる最大レートは 1 秒あたり 9 リクエストであると判定されたことを意味します。1 秒あたり 10 リクエストを試すと、レイテンシが高くなりすぎました。

  • e2el: 8423.40

    • これは、サーバーに 9 リクエスト/秒の負荷をかけたときに測定された P99 レイテンシです。8,423.40 は 10,000 より小さいため、スクリプトによって成功と判定されました。

  • throughput: 5.63

    • これは実際に測定された出力です。1 秒あたり 9 件のリクエストを送信していましたが、サーバーによって正常に処理されたのは 1 秒あたり 5.63 件のみでした。

パフォーマンスと費用の比率の計算

2 つの主要なアクセラレータ候補をチューニングしてベンチマーク評価したので、次はデータを突き合わせて、費用に基づく最終的な決定を行いましょう。目標は、1 秒あたり 100 件のリクエストというワークロード要件を満たし、かつ P99 エンドツーエンド レイテンシが上限の 10,000 ミリ秒を下回る、最も経済的な構成を見つけることです。

匿名化された候補と TPU v6e の両方で最もパフォーマンスの高い構成を使用して、100 リクエスト/秒の目標を達成するための費用を分析します。

匿名化されたアクセラレータ最適化オプションの候補

  • 測定されたスループット: ベンチマークでは、単一の vLLM エンジンで 4.17 リクエスト/秒のスループットが達成されました。

  • 必要なインスタンス: 100 リクエスト/秒の目標を達成するには、複数のインスタンスを実行する必要があります。計算式は次のとおりです。

    • 目標スループット ÷ インスタンスあたりのスループット ​= 100 リクエスト/秒 ÷ 4.17 リクエスト/秒 ​≈ 23.98

    • インスタンスの一部だけをプロビジョニングすることはできないため、24 インスタンスに切り上げる必要があります。

  • 推定費用: 2025 年 7 月時点で、us-central1 の匿名化されたマシンタイプの Spot インスタンス料金は 1 時間あたり約 2.25 ドルです。クラスタの 1 時間あたりの合計費用は、24 インスタンス × 2.25 ドル/時間 = 54.00 ドル/時間となります。

    • : シンプルな費用を示すために Spot インスタンスの料金を選択していますが、このタイプのワークロードではこのようなプロビジョニングは一般的ではありません。

Google Cloud TPU v6e(v6e-4)

  • 測定されたスループット: ベンチマークでは、単一の v6e-4 vLLM エンジンで 5.63 リクエスト/秒という、上記よりも高いスループットが達成されました。

  • 必要なインスタンス: TPU クラスタに関して同じ計算を行います。

    • 目標スループット ÷ インスタンスあたりのスループット ​= 100 リクエスト/秒 ÷ 5.63 リクエスト/秒 ​≈ 17.76

    • ここでも、100 リクエスト/秒の要件を厳密に満たすには、18 インスタンスに切り上げる必要があります。

  • 推定費用: 2025 年 7 月時点で、us-central1 のキューに格納されている v6e-4 リソースの Spot インスタンス料金は、チップ 1 個が 1 時間あたり約 0.56 ドルです。このクラスタの 1 時間あたりの合計費用は次のようになります。

    •  18 インスタンス × 4 チップ × 0.56 ドル/時間 = 40.32 ドル/時間

結論: 最も費用対効果の高い選択肢

対比をわかりやすくするために、調査結果を表にまとめましょう。

 

指標

匿名化された候補

TPU(v6e-4)

インスタンスあたりのスループット

4.17 リクエスト/秒

5.63 リクエスト/秒

必要なインスタンス数(100 リクエスト/秒)

24

18

Spot インスタンスの 1 時間あたりの費用

2.25 ドル/時間

0.56 ドル × 4 チップ = 2.24 ドル/時間

Spot インスタンスの合計費用

54.00 ドル/時間

40.32 ドル/時間

月額合計費用(730 時間)

約 39,400 ドル

約 29,400 ドル

 

結果は決定的です。この特定のワークロード(長いコンテキストで gemma-3-27b-it モデルをサービング)では、v6e-4 構成が最も優れています。

v6e-4 インスタンスを使用すると、アクセラレータ最適化インスタンスよりも高いスループットが実現するだけでなく、費用も削減できます。規模が大きくなるほど、大幅な費用削減につながります。

1 ドルあたりのパフォーマンスを見ると、その優位性は明らかです。

  • 匿名化された候補: 4.17 リクエスト/秒 ÷ 54.00 ドル/時間 ≈ 0.08 リクエスト/秒/ドル時間

  • TPU v6e: 5.63 リクエスト/秒 ÷ 40.32 ドル/時間 ≈ 0.14 リクエスト/秒/ドル時間

v6e-4 構成では、1 ドルあたりのパフォーマンスがほぼ 2 倍になるため、このワークロードのデプロイにより適した効率的な選択肢であるといえます。

終わりに

このベンチマークとチューニングのプロセスは、特定の AI ワークロードにおけるパフォーマンスと費用の最適なバランスを見つけるために、さまざまなハードウェア オプションを評価することの重要性を示しています。これらのワークロードのサイズ設定では、次の点に留意する必要があります。

  • ワークロードが変化した場合(入力長、出力長、プレフィックス キャッシュの割合、要件など)、このガイドも異なる結果になる可能性があります。ワークロードによっては、匿名化された候補が v6e を上回るシナリオもあり得ます。

  • 上記で説明した他のアクセラレータも検討すれば、要件を満たす、より費用対効果の高いアプローチが見つかる可能性もあります。

  • 最後に、この例の auto_tune.sh スクリプトでは比較的狭いパラメータ空間を対象としました。より広い空間を対象にすれば、さらに大きな費用削減を実現できる構成が見つかった可能性もあります。

参考情報

以下は、このガイドの手順を完了し、説明されているコンセプトをより深く理解するうえで役立つ追加リソースです。

 

ー AI Infrastructure 担当フィールド ソリューション アーキテクト Eric Hanley

ー AI およびコンピューティング担当プロダクト マネージャー Brittany Rockwell

投稿先