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
| コントラスト | Prefill | Decode |
|---|---|---|
| 主な業務 | プロセス入力 Prompt | 後続の Token を生成する |
| 平行度 | Token 寸法平行度が高い | 単一のシーケンスが段階的に生成されます |
| コンピューティング機能 | 大規模行列計算 | より小さな段階的計算 |
| 一般的なボトルネック | GPU Compute | Memory Bandwidth |
| KV Cache | 作成して設定する | 読んで拡張する |
| 主な影響指標 | TTFT | TPOT / 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 の場合:
その中には:
| パラメータ | 意味 |
|---|---|
| (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 の数の上限です。
通常:
次の点に注意する必要があります。
- モデル アーキテクチャの理論上の位置の範囲は、確実にサポートできるコンテキストの長さと必ずしも同じではありません。
- 推論エンジンは
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. 推論パフォーマンス指標
| インジケーター | 意味 | 最適化目標 |
|---|---|---|
| TTFT | Time To First Token | 低いほど良い |
| TPOT | Time Per Output Token | 低いほど良い |
| ITL | Inter-token Latency | 低いほど良い |
| Latency | 合計リクエスト時間 | 低いほど良い |
| Throughput | 単位時間あたりに処理されるワークロード | 高いほど良い |
| Tokens/s | Tokenの処理速度または生成速度 | 高いほど良い |
TTFT
リクエストが行われてからクライアントが最初の出力 Token を受信するまでの時間。
Request
↓
Queue
↓
Prefill
↓
First Token
TTFT には、GPU Prefill 時間だけでなく、ネットワーク、リクエスト キューイング、Tokenization、および最初の出力転送オーバーヘッドも含まれる場合があります。
TPOT / ITL
TPOT は通常、ビルド フェーズの後続の各 Token に必要な平均時間を表します。
一般的な計算方法:
その中には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
ストリーミング ビルドの場合、リクエストの合計レイテンシーは通常、次のように分類できます。
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 |
| TTFT | Token初の応答速度 |
| TPOT | 後続のTokenの平均生成間隔 |
| Latency | 単一リクエストのエンドツーエンドの所要時間 |
| Throughput | 推論サービス全体の処理能力 |
実際のパフォーマンス テスト中は、モデル、入力および出力 Token の長さ、ハードウェアおよび同時実行条件を固定する必要があります。固定しないと、異なるテスト結果を比較できない可能性があります。