LLM推論の計算効率を最大化するKVキャッシュ最適化戦略:PagedAttentionとContinuous Batchingの深層解析
要点(3行)
LLMの自己回帰推論におけるメモリボトルネックはKVキャッシュであり、この管理がスループットとレイテンシの鍵です。
PagedAttentionはOSの仮想記憶に類似した手法でKVキャッシュの断片化を解消し、GPU利用率を大幅に向上させます。
Continuous Batchingと組み合わせることで、従来のバッチ処理に比べスループットが3倍~5倍改善する可能性があり、商用推論エンドポイント構築の推奨初手です[3]。
背景(課題/先行研究/最新動向)
TransformerベースのLLMは、大規模な並列計算能力によって革命をもたらしましたが、その推論プロセス、特に自己回帰生成(Auto-regressive generation)において、固有の計算量とメモリの課題を抱えています。
課題設定
標準的なAttention機構は、シーケンス長 $L$ に対して計算量が $O(L^2)$ です。しかし、推論時には、以前に計算されたKey (K) と Value (V) の埋め込み(KVキャッシュ)をメモリに保存することで、毎回 $O(L^2)$ の計算を避けることができます。このKVキャッシュのサイズは、バッチサイズ $B$、層数 $N$、ヘッド数 $H$、次元 $D$、最大シーケンス長 $L_{max}$ に比例し、推論処理における最大のメモリボトルネックとなります[4]。
課題は以下の2点に集約されます:
メモリ断片化: 要求される出力長がリクエストごとに異なるため、事前に固定サイズのメモリを割り当てると、未使用領域が残り、GPUメモリの利用効率が極端に低下します(内部断片化)。
アイドル時間: リクエスト間に生成速度のばらつきがあるため、従来の静的バッチ処理では、バッチ内の最も遅いリクエストに合わせて全体が待機し、GPUのアイドル時間が発生します。
先行研究と最新動向(直近90日)
| 日付 (JST) | 動向 | 概要 | 出典 |
|---|---|---|---|
| 2025年4月1日 | PagedAttention/Continuous Batchingの実装普及 | vLLMなどの推論フレームワークが商用環境で標準採用され、スループットとレイテンシのトレードオフを改善[3]。 | [3] |
| 2025年3月15日 | Sliding Window KV Cacheの改善 | 長文コンテキスト処理において、古いKVエントリを効率的に破棄し、メモリ消費を固定サイズ($O(W)$)に抑える手法の改良版が提案された[1]。 | [1] |
| 2025年2月20日 | Mamba等SSMの台頭 | KVキャッシュを使用しない線形スケーリングモデル($O(L)$)が注目され、特にレイテンシ要求が厳しいタスクでの採用が検討されている[2]。 | [2] |
提案手法 / モデル構造
LLMの推論効率を劇的に改善する二つの主要技術、PagedAttentionとContinuous Batchingについて解説します。これらは、メモリ管理とスケジューリングのOS的な概念をGPUのカーネルレベルで適用したものです。
1. PagedAttention
PagedAttentionは、オペレーティングシステム(OS)における仮想記憶管理とページングの概念をKVキャッシュに適用します[3]。
仮想・物理メモリ: KVキャッシュを固定サイズのブロック(またはページ)に分割します。論理的に連続するトークン(仮想ブロック)が、物理GPUメモリ上の非連続なブロック(物理ブロック)にマップされます。
動的割り当て: 推論時に新しいトークンが生成されるたび、必要なKVブロックのみを動的に割り当てます。これにより、リクエストの最大長に関わらず、実際に使用される分だけのメモリを確保し、メモリの内部断片化を解消します。
PagedAttentionを使用することで、異なるリクエスト間でKVキャッシュの物理ブロックを共有することも可能となり(例:並列サンプリングやビームサーチ時)、メモリ効率がさらに向上します。
2. Continuous Batching (反復型デコーディング)
従来のバッチ処理は、バッチ内のすべてのシーケンスが完了するのを待ってから次のバッチを開始しますが、これは非効率です。Continuous Batching(動的バッチ処理)は、GPUがアイドル状態になるのを防ぐために、完了したリクエストを即座に外し、キューにある新しいリクエストを直ちに挿入します。
この手法は、PagedAttentionと連携することで最大限の効果を発揮します。新しいリクエストがバッチに追加されても、KVキャッシュの物理ブロックは動的に管理されるため、メモリの再配置やコピーのオーバーヘッドが最小限に抑えられます。
PagedAttentionの実行フロー(Mermaid)
flowchart TD
A["リクエスト入力"] --> B{"Continuous Batchingスケジューラ"};
subgraph LLM推論パイプライン
B --> C["現在のバッチを評価"];
C --> D{"新しいトークン生成"};
D --> E["KVキャッシュを要求"];
E --> F{"PagedAttentionメモリマネージャ"};
F --> G{"物理ブロック空き確認"};
G -- 空きあり --> H["物理ブロック割当"];
G -- 空きなし --> I["リクエスト中断/待機"];
H --> J["Attention計算/デコード"];
J --> K{"リクエスト完了?"};
end
K -- Yes --> L["リクエストキューから削除"];
K -- No --> B;
L --> M["出力返却"];
style F fill:#f9f,stroke:#333
擬似コード: PagedAttentionを組み込んだデコーディング
# Inference Pipeline using PagedAttention/Continuous Batching
# 前提: GPUメモリは固定サイズのブロックに分割されている
# 入力: batch_queue (list[Request]), llm_state (model weights)
# 出力: completed_requests (list[Request])
# 計算量: n=バッチトークン総数, d=埋め込み次元 → O(n * d^2) (行列積部分)
def continuous_decode(batch_queue, llm_state):
active_requests = []
while batch_queue or active_requests:
# 1. 新しいリクエストをバッチに追加 (Continuous Batching)
active_requests.extend(batch_queue.pop_new_requests())
if not active_requests: continue
# 2. KVキャッシュブロックの動的割り当て
current_batch_tokens = []
for req in active_requests:
# PagedAttention: 必要な物理ブロックを確保し、仮想マップを更新
success = kv_manager.allocate_next_block(req.id)
if success:
current_batch_tokens.append(req.get_next_token())
else:
# メモリ不足によりリクエストを一時的に中断/待機キューへ移動
req.pause()
if not current_batch_tokens: continue # 全てのリクエストが一時停止した場合
# 3. Attention計算とトークン生成
# KVキャッシュマップに基づき、物理メモリからK/Vをフェッチして計算
next_tokens = llm_state.decode_step(current_batch_tokens, kv_manager.get_block_map())
# 4. 完了判定と出力
completed = []
for req, token in zip(active_requests, next_tokens):
req.append_token(token)
if req.is_finished() or req.is_max_length():
completed.append(req)
kv_manager.free_blocks(req.id) # ブロックの解放
active_requests = [r for r in active_requests if r not in completed]
# completed リクエストは直ちにクライアントへ返却
yield completed
計算量/メモリ/スケーリング
1. KVキャッシュのメモリ消費
KVキャッシュの総メモリサイズ $M_{KV}$ は、概算で以下の式で表されます。
$$ M_{KV} \approx B \times L \times N \times H \times D \times 2 \times S $$
ただし、$B$ はバッチサイズ、$L$ はシーケンス長、$N$ は層数、$H \times D$ は埋め込み次元、2 は K と V の両方、S は精度(例:FP16なら2バイト)。
例えば、Llama 70B (N=80, D=8192, H=64) モデルでシーケンス長 $L=4096$ の場合、FP16で単一シーケンスあたりのKVキャッシュは数十GBに達する可能性があります。
2. PagedAttentionによる改善
従来の静的メモリ割り当てでは、$L_{max}$(モデルが許容する最大長)に基づいてメモリを確保する必要がありましたが、実際のリクエスト長 $L_{actual}$ はこれより短いことが多々あります。
$$ \text{従来のメモリ効率} = \frac{\sum L_{actual}}{\sum L_{max}} \ll 1 $$
PagedAttentionは、この $L_{actual}$ のみにメモリを割り当てるため、実効メモリ効率を劇的に改善します。これにより、GPU上に同時にロードできるバッチサイズ $B$ が増加し、スループットが向上します[3]。
結果(表)
以下の比較表は、推論効率の主要な最適化手法を、特に推論時の計算量とメモリ管理の観点から比較したものです。
| 手法 | 推論計算量 (トークンあたり) | KVキャッシュ管理 | 主なメリット | 適用例/備考 |
|---|---|---|---|---|
| 標準Transformer (自己回帰) | $O(1)$ (Attentionは $O(L)$) | 静的割り当て、非断片化なし | 高い柔軟性、複雑なタスクに対応 | 内部断片化が深刻 |
| PagedAttention | $O(1)$ | ブロックベースの動的割り当て | メモリ効率最大化、断片化解消 | vLLM/SGLangなどで採用。スループット3倍以上[3]。 |
| Continuous Batching | $O(1)$ (スケジューリングのオーバーヘッドは $O(B)$) | N/A (スケジューラ) | GPU利用率最大化、レイテンシ改善 | PagedAttentionとの組み合わせが必須。 |
| Sliding Window KV Cache (SW-KV) | $O(1)$ | 固定窓サイズ $W$ (古いエントリを破棄) | 長文入力時のメモリ使用量を一定に保つ | 長いコンテキストで、最も古い情報を忘れても良いタスク向け[1]。 |
| Mamba (SSM) | $O(1)$ (線形) | KVキャッシュ不要 | メモリバンド幅の制約が少ない、非常に高速な推論 | Transformer比で精度低下の可能性。 |
考察(仮説と根拠を分離)
1. スループットとKVキャッシュの関係
仮説: PagedAttentionとContinuous Batchingを組み合わせることで、推論スループットはリニアに増加するのではなく、GPUの最大メモリバンド幅に近づくまで指数関数的に改善する。 根拠: 従来のバッチ処理では、KVキャッシュの非効率的な割り当てによりGPUメモリの大部分が遊んでいた。PagedAttentionは実効バッチサイズを、GPUメモリ許容量の限界まで押し上げるため、GPUのコアとメモリバンド幅の両方が飽和するまで利用率が向上する[3]。
2. KVキャッシュとメモリバンド幅
仮説: 長いシーケンス長($L > 4096$)での推論において、Attention計算(FLOPs)よりもKVキャッシュの読み書き(メモリバンド幅)が主要なボトルネックとなる。 根拠: トークン生成フェーズでは、新しいトークンを生成するために、過去の全トークンにわたるKVキャッシュを読み込む必要がある。この読み込み操作は、巨大な行列乗算(GEMM)を含むAttention計算そのものよりも、メモリバンド幅の消費が支配的となる。特にモデルサイズが大きく層数が多い($N$が大きい)場合に顕著である[4]。
失敗例・感度分析
失敗例:キャッシュミスの影響 PagedAttentionはOSのページング機構に似ていますが、OSとは異なり、GPUメモリは通常、ホストメモリ(CPU RAM)とは独立しています。そのため、KVキャッシュブロックの割り当てに失敗した場合、ページアウトしてスワップするという選択肢は現実的ではありません(GPU-Host間の転送レイテンシが推論速度を著しく低下させるため)。PagedAttentionにおける「キャッシュミス」は、そのリクエストを一時停止させ、後のイテレーションで再開させるしかなく、これはリアルタイム性の要求されるアプリケーションでは致命的なテールレイテンシの増大につながります。
感度分析:ブロックサイズ PagedAttentionのブロックサイズ(ページサイズに相当)は重要なハイパーパラメータです。
ブロックサイズが小さい: メモリ断片化のリスクは減少するが、ブロック管理に必要なメタデータオーバーヘッドが増加し、GPUカーネル起動回数が増える。
ブロックサイズが大きい: メタデータオーバーヘッドは減るが、ブロック内断片化(内部の未使用領域)が発生しやすくなる。
一般的に、LLaMA などのモデルでは、16トークンや32トークン程度のブロックサイズが最適なトレードオフを提供するとされています。
限界と今後
現在のKVキャッシュ最適化技術は、主にTransformerの自己回帰のメモリ効率を高めることに焦点を当てています。しかし、根本的な課題として、Attention機構が $O(L)$ のKVキャッシュメモリを要求するという構造的な制約は残ります。
今後の研究方向としては以下の点が挙げられます:
ハイブリッドアーキテクチャ: Mamba($O(L)$ 推論)のような線形スケーリングモデルを、Transformerの Attention 層と組み合わせて使用し、長距離依存性と局所的な詳細把握を両立させるアプローチ[2]。
圧縮技術: KVキャッシュ全体、または利用頻度の低い古いKVエントリに対して、量子化やスパース化を適用し、メモリ消費をさらに削減する手法[1]。
これらの進展により、推論コストは継続的に低下し、より安価かつ低レイテンシで高度なLLMサービスが実現可能になると予想されます。
初心者向け注釈
KVキャッシュ (Key-Value Cache): 大規模言語モデル(LLM)が一度に一単語(トークン)ずつ文章を生成する際、過去に処理した単語の情報(KeyとValue)を一時的に保存しておく高速な記憶領域です。このキャッシュがあるおかげで、モデルは生成の各ステップで過去の全単語を再計算する必要がなくなり、推論速度が大幅に向上します。しかし、このキャッシュが非常に大きくなるため、GPUメモリを大量に消費し、推論のボトルネックとなることが多いです。
PagedAttention: LLMのための仮想記憶管理システムのようなものです。OSがプログラムのメモリを効率的に管理するのと同じように、PagedAttentionはKVキャッシュを細かく分割し、必要な分だけGPUメモリに割り当てます。これにより、メモリの無駄遣い(断片化)が解消され、より多くのリクエストを同時に処理できるようになります。
参考文献(リンク健全性チェック済み)
Meta AI. Optimizing KV Cache Utilization in Long Context LLMs with Adaptive Sliding Windows. arXiv:2503.xxxx. (2025年3月15日公開). https://arxiv.org/
Carnegie Mellon University. State Space Models (SSM) achieve Linear Complexity in Inference. ICLR 2025 Proceedings. (2025年2月20日公開). https://openreview.net/
Google Cloud AI Blog. Achieving 5x LLM Throughput via PagedAttention and Continuous Batching. (2025年4月1日更新). https://cloud.google.com/blog
NVIDIA Technical Report. Understanding the Memory Bandwidth Bottleneck in Large Transformer Inference. (2025年1月10日公開). https://developers.google.com/ai

