← AIページの先頭へ

Inference: モデル推論の原理とパフォーマンス

LLM Inference は、モデルがトレーニングされた重みを使用して、入力 Token に基づいて出力 Token を自己回帰的に生成するプロセスです。

中心となる概念:

Inference
├── Execution
│   ├── Prefill
│   ├── Decode
│   └── KV Cache
├── Scheduling
│   ├── Batching
│   ├── Continuous Batching
│   └── Chunked Prefill
├── Memory
│   ├── Model Weights
│   ├── KV Cache
│   └── PagedAttention
└── Performance
    ├── TTFT
    ├── TPOT / ITL
    ├── Latency
    └── Throughput

1. Prefill: プロセス入力 Prompt

Prefill は推論の初期段階であり、入力 Prompt の処理と KV Cache の構築を担当します。

たとえば、入力には 2000 Token が含まれています。

Prompt(2000 Tokens)
          ↓
       Prefill
          ├── Token Embedding
          ├── Transformer Layers
          ├── Compute Q / K / V
          ├── Build KV Cache
          └── Generate First-token Logits
          ↓
       First Token

Prompt のすべての Token はすでに存在しているため、モデルは Causal Mask を介して複数の位置の表現を並行して計算できます。

主な特徴:

  • 通常、入力 Token の方が大きな数値になります。
  • 大規模な行列演算が多数あります。
  • GPUは並列性が高いです。
  • 通常は Compute-bound を好みます。

Compute-bound

実行速度が主に GPU の計算能力によって制限されることを示します。

たとえば:

GPU FLOPS が主なボトルネックです
コンピューティング能力の向上
       ↓
改善の可能性 Prefill 速度

ただし、実際のパフォーマンスはシーケンス長、Batch Size、Attention の実装、メモリ アクセスにも依存します。

Prefill は、Prompt を一度に完全に処理する必要はなく、Chunked Prefill を使用してチャンクで実行することもできます。

2. Decode: 1 つずつ生成 Token

Prefill が最初の出力 Token を生成した後、モデルは残りの Token を徐々に生成し続けます。

自己回帰生成では、次の Token が以前に生成された Token に依存する必要があります。

Previous Generated Token
           ↓
    Compute New Q/K/V
           ↓
  Read Historical KV Cache
           ↓
       Attention
           ↓
          MLP
           ↓
         Logits
           ↓
        Sampling
           ↓
      Next Token

通常、各 Decode Step は、生成されるシーケンスごとに新しい Token を 1 つだけ生成します。

Memory-bandwidth-bound

Decode では、モデルの重みを繰り返し読み取り、コンテキストとともに増加する KV Cache にアクセスする必要があります。

Batch が小さい場合、1 ラウンドあたりの計算量が比較的少なく、GPU の計算能力を十分に活用できないことがよくあります。

したがって、Decode は一般にメモリ帯域幅制限の影響を受けやすくなります。

Decode
   ↓
Read Model Weights
Read KV Cache
   ↓
Compute Next Token

Batch が増加すると、複数のリクエストでモデルの重みの読み取りをバッチで共有できるため、コンピューティング使用率が向上します。

そのため、Decode が常に Memory-bound になるとは限らず、より大きな Batch または長いコンテキストによってパフォーマンスのボトルネックが変化する可能性があります。

Prefill 対 Decode

コントラストPrefillDecode
主な業務プロセス入力 Prompt後続の Token を生成する
平行度Token 寸法平行度が高い単一のシーケンスが段階的に生成されます
コンピューティング機能大規模行列計算より小さな段階的計算
一般的なボトルネックGPU ComputeMemory Bandwidth
KV Cache作成して設定する読んで拡張する
主な影響指標TTFTTPOT / ITL

3. KV Cache: キャッシュ Attention ステータス

KV Cache は、処理した Token を Key と Value をそれぞれの Transformer Layer に保存します。

その効果は、新しい Token が生成されるたびに、すべての履歴 Token の K/V を再計算することを避けることです。

Prefill
   ↓
K/V for Prompt Tokens
   ↓
KV Cache
   ↓
Decode Step 1 → Append K/V
   ↓
Decode Step 2 → Append K/V
   ↓
Decode Step 3 → Append K/V

KV Cache メモリの見積もり

一般的な Decoder-only Transformer の場合:

M∗KV≈2×L×H∗kv×D×S×B×PM*{\mathrm{KV}} \approx 2 \times L \times H*{kv} \times D \times S \times B \times P

その中には:

パラメータ意味
(L)Transformer 層番号
(H_kv)KV Head番号
(D)Head Dimension
(S)シーケンスごとにキャッシュされた Token の数
(B)Batchのシーケンス番号
(P)要素あたりのバイト数

たとえば:

32 Layers
8 KV Heads
128 Head Dimension
4096 Cached Tokens
1 Sequence
BF16 = 2 Bytes

理論上の KV Cache サイズは約 512 MiB です。

これは、ページング割り当て、メモリ アラインメント、共有プレフィックス、その他の実行時のオーバーヘッドを考慮していない推定値です。

重要な結論:

  • 通常、Context Length が大きいほど、KV Cache も大きくなります。
  • 通常、Batch 内のシーケンスが多いほど、合計 KV Cache は大きくなります。
  • GQA/MQAはKV Cacheのサイズを小さくできます。
  • KV Cache Quantization では、メモリのオーバーヘッドをさらに削減できます。

4. Context Length

Context Length は、現在の推論プロセス中にモデルが使用できるコンテキスト Token の数の上限です。

通常:

Input Tokens+Generated Tokens≤Context Limit\text{Input Tokens}+\text{Generated Tokens}\leq\text{Context Limit}

次の点に注意する必要があります。

  • モデル アーキテクチャの理論上の位置の範囲は、確実にサポートできるコンテキストの長さと必ずしも同じではありません。
  • 推論エンジンは max_model_len をより小さく設定する可能性があります。
  • 通常、コンテキストが長いと、KV Cache の占有率と Attention のオーバーヘッドが増加します。
  • 実際には、モデルの精度、RoPE 構成、および GPU メモリによって制限される場合もあります。

Context Length は 1 つのリクエストで使用できるコンテキスト サイズに影響し、Batch Size は同時に処理されるリクエストの数に影響します。この 2 つを合わせて KV Cache の圧力を決定します。

5. Batching: バッチ処理

Batching は、複数のリクエストを組み合わせて GPU で計算を実行することを指します。

たとえば:

Request A ──┐
Request B ──┼── GPU Batch
Request C ──┘

利点:

  • GPU の使用率が向上します。
  • モデルの重み読み取りのオーバーヘッドを償却します。
  • サーバー全体のスループットが向上します。

短所:

  • 行列が増える可能性があります。
  • KV Cache メモリをより多く消費します。
  • Batch が大きすぎると、1 回のリクエストの応答速度が低下する可能性があります。

Static Batching

従来の静的 Batch では、通常、Batch 内のリクエストをグループとしてスケジュールする必要があります。

異なるリクエストの入力長と出力長は異なる場合があり、Padding が発生したり、待機による無駄が発生したりする可能性があります。

Continuous Batching

Continuous Batching (In-flight Batching とも) を使用すると、リクエストが実行中のバッチに動的に参加したり、バッチから離脱したりすることができます。

Step 1: A B C
Step 2: A B C
Step 3: A   C     ← B 完了
Step 4: A D C     ← D 参加する
Step 5:   D C     ← A 完了

基本的な価値観:

  • リクエストは同時に受信する必要はありません。
  • 完了したリクエストはリソースを直ちに解放します。
  • 新しいリクエストは、後続のスケジュール手順で追加できます。
  • GPU の使用率とサービス スループットが向上します。

Continuous Batching は、vLLM や SGLang などの最新の推論エンジンにとって重要なスケジューリング メカニズムです。

6. Chunked Prefill

長い Prompt を持つ Prefill は、大量の GPU コンピューティング リソースを占有する可能性があるため、Decode のリクエストに影響を与えます。

Chunked Prefill は、長い Prompt を複数の Token Chunk に分割して処理します。

たとえば:

Prompt: 4096 Tokens

Chunk 1: 1024
Chunk 2: 1024
Chunk 3: 1024
Chunk 4: 1024

これにより、スケジューラは複数のスケジュール ステップにわたって Prefill ジョブと Decode ジョブをスケジュールできるようになります。

GPU Scheduling
       ↓
Decode Batch
       ↓
Prefill Chunk
       ↓
Decode Batch
       ↓
Prefill Chunk

主な目的:

  • 長い Prefill がコンピューティング リソースを長時間占有することを避けてください。
  • 他のリクエスト TPOT への影響を軽減します。
  • より柔軟なスループットとレイテンシのトレードオフを提供します。

ただし、ブロックすると、単一の Prompt が Prefill を完了するまでの時間が長くなる可能性があるため、スケジューリング戦略を適切に構成する必要があります。

vLLM の max_num_batched_tokens などのパラメーターは、各スケジューリング ステップの Token 予算に影響を与える可能性があります。

7. PagedAttention

KV Cache は、Token の数に応じて動的に増加します。

ビデオ メモリの連続した大きなブロックがリクエストごとに予約されている場合、メモリの無駄と断片化が発生する傾向があります。

PagedAttention は、KV Cache を固定サイズの Block に分割し、マッピング関係によって管理します。

Request A
Logical Blocks
  [0] [1] [2]
   ↓   ↓   ↓
Physical KV Blocks
  [7] [3] [9]

Request B
Logical Blocks
  [0] [1]
   ↓   ↓
Physical KV Blocks
  [2] [5]

主な利点:

  • KV Cache では、リクエストごとに完全な連続した物理スペースを予約する必要はありません。
  • ビデオメモリの断片化と予約の無駄を削減します。
  • KV Cache の割り当てとリサイクルの柔軟性が向上しました。
  • 特定の KV Block 共有ポリシーをサポートできます。

PagedAttention は主に KV Cache のメモリ管理の問題を解決し、Continuous Batching は主にリクエストのスケジューリングの問題を解決します。

この 2 つを組み合わせることで、推論サービスの同時実行機能を向上させることができます。

8. 推論パフォーマンス指標

インジケーター意味最適化目標
TTFTTime To First Token低いほど良い
TPOTTime Per Output Token低いほど良い
ITLInter-token Latency低いほど良い
Latency合計リクエスト時間低いほど良い
Throughput単位時間あたりに処理されるワークロード高いほど良い
Tokens/sTokenの処理速度または生成速度高いほど良い

TTFT

リクエストが行われてからクライアントが最初の出力 Token を受信するまでの時間。

Request
   ↓
Queue
   ↓
Prefill
   ↓
First Token

TTFT には、GPU Prefill 時間だけでなく、ネットワーク、リクエスト キューイング、Tokenization、および最初の出力転送オーバーヘッドも含まれる場合があります。

TPOT / ITL

TPOT は通常、ビルド フェーズの後続の各 Token に必要な平均時間を表します。

一般的な計算方法:

TPOT=Latency−TTFTN_output−1TPOT=\frac{Latency-TTFT}{N\_{\mathrm{output}}-1}

その中にはmath\(N\_{\mathrm{output}}>1\)mathがあります。

たとえば:

TTFT = 1.0 s
Total Latency = 5.0 s
Output Tokens = 101

次に:

TPOT = 40 ms/token

対応する後続世代の平均速度は約 25 tokens/s です。

注: Benchmark ツールが異なると、TPOT、ITL、最初の Token、およびストリーミング Chunk に対して異なる統計手法が使用される場合があります。結果を比較する場合は定義を確認する必要があります。

リクエストの開始から完了までのエンドツーエンド時間。

Request Start
      ↓
Queue + Prefill + Decode + Delivery
      ↓
Request Complete

ストリーミング ビルドの場合、リクエストの合計レイテンシーは通常、次のように分類できます。

Latency≈TTFT+(N_output−1)×TPOTLatency \approx TTFT+(N\_{\mathrm{output}}-1)\times TPOT

Throughput

単位時間当たりにサーバーによって処理されるワークロード。

一般的な指標:

Requests/s
Input Tokens/s
Output Tokens/s
Total Tokens/s

ここで、Output Tokens/s は通常、生成スループットの測定に使用されます。

単一ユーザーの Tokens/s とサーバー全体の Tokens/s は同じインジケーターではありません。

たとえば:

  • シングルユーザー速度: 30 tokens/s。
  • サーバーは 20 個のリクエストを同時に処理します。
  • サーバー全体で生成されるスループットは、おそらく 30 tokens/s よりもはるかに高くなります。

ただし、全体的なスループットは、同時リクエストの数に応じて単純に直線的に増加するわけではありません。

9. Latency と Throughput のトレードオフ

推論サービスは通常、次の両方を追求します。

  • 下位TTFT。
  • 下位TPOT。
  • Throughputの上位。
  • GPU の使用率が向上しました。

しかし、これらの目標は互いに矛盾する可能性があります。

Smaller Batch
     ↓
通常、キューイングとスケジューリングのオーバーヘッドが低い
     ↓
全体的なスループットリスクの低下

Larger Batch
     ↓
より高い GPU 活用
     ↓
全体的なスループットの向上
     ↓
単一リクエストのレイテンシが増加する可能性がある

たとえば、同時実行性を高めます。

  • GPU 使用率が増加する可能性があります。
  • 合計Output Tokens/sが上昇する可能性があります。
  • Queue Timeも上昇する可能性があります。
  • TTFT、TPOTが悪化する可能性があります。

したがって、Tokens/s だけに集中することはできません。

P50 / P95 / P99

パフォーマンス ベンチマークは通常、レイテンシの分位数を報告します。

  • P50: リクエストの 50% のレイテンシーはこの値以下です。
  • P95: リクエストの 95% のレイテンシーはこの値以下です。
  • P99: リクエストの 99% のレイテンシーはこの値以下です。

平均レイテンシが低いということは、高負荷時に重大なテール レイテンシが存在しないことを意味するわけではありません。

10. 推論パフォーマンスの最適化のアイデア

質問考えられる最適化の方向性
TTFT高待ち時間を短縮し、Prefill、Prefix Cachingを最適化
TPOT高Continuous Batching、Attention Kernel、メモリ効率の向上
KV Cache ビデオメモリが不足していますGQA、KV Cache Quantization、PagedAttention
GPU 使用率が低いBatch Size、Continuous Batchingを調整してください
長い Prompt は他のリクエストに影響を与えますChunked Prefill
モデルの重み占有率が高すぎますWeight Quantization
高い同時実行性と深刻なキューイングスケジューリングパラメータを調整し、レプリカまたはコンピューティングリソースを追加します

Prefix Caching

複数のリクエストが同じ Prompt プレフィックスを持つ場合、条件が満たされると、すでに計算された KV Cache Block を再利用できます。

たとえば:

Request A:
[System Prompt] + [Question A]

Request B:
[System Prompt] + [Question B]

システムが共通の System Prompt プレフィックスを再利用できる場合、Prefill の繰り返し計算を減らすことができます。

ただし、Prefix Caching の利点はプレフィックスの繰り返し率、キャッシュ ヒット、メモリ容量によって異なり、すべてのリクエストが大幅に高速化されるという保証はありません。

概要

LLM の推論は次の構造で理解できます。

Incoming Requests
        ↓
Request Queue / Scheduler
        ↓
Continuous Batching
        │
        ├── Prefill
        │    └── Build KV Cache
        │
        └── Decode
             ├── Read KV Cache
             ├── Generate Token
             └── Extend KV Cache
        ↓
Streaming Response

マスターする必要がある人間関係:

コンセプト核となる理解
Prefill入力 Prompt を並列処理し、通常はより多くの計算量を必要とします。
Decode自己回帰 Token 生成。通常はメモリ帯域幅がより集中します
KV Cache繰り返しの計算は減りますが、グラフィックス メモリのオーバーヘッドは増加します
Continuous Batching処理中のリクエストを動的に管理する
Chunked Prefill他のリクエストに対する長い Prompt のブロックを軽減します。
PagedAttention効率的な割り当てと管理 KV Cache
TTFTToken初の応答速度
TPOT後続のTokenの平均生成間隔
Latency単一リクエストのエンドツーエンドの所要時間
Throughput推論サービス全体の処理能力

実際のパフォーマンス テスト中は、モデル、入力および出力 Token の長さ、ハードウェアおよび同時実行条件を固定する必要があります。固定しないと、異なるテスト結果を比較できない可能性があります。


参考資料