KVキャッシュ最適化:本番LLMのためのメモリ効率化
2025年12月11日更新
2025年12月アップデート: 従来の推論ではフラグメンテーションと過剰割り当てによりKVキャッシュメモリの60〜80%が無駄になっている。vLLMのPagedAttentionは無駄を4%未満に削減し、スループットを2〜4倍向上させることで、本番推論の経済性を変革した。70Bモデルで8Kコンテキストの場合、リクエストあたり約20GBのキャッシュが必要で、バッチサイズ32では約640GBに達する。KVキャッシュはモデルウェイトを超えるメモリ消費量になることも多い。最適化技術により、既存ハードウェアでより長いコンテキストとより大きなバッチが可能になる。
LLM推論システムは、フラグメンテーションと過剰割り当てにより、割り当てられたKVキャッシュメモリの60〜80%を無駄にしている。¹ この無駄は、スループットの低下、コストの増加、コンテキスト長の人為的な制限に直結する。vLLMが導入したPagedAttentionは、KVキャッシュの無駄を4%未満に削減し、本番推論の経済性を変革する2〜4倍のスループット向上を実現した。² KVキャッシュ最適化技術を理解することで、組織はGPU利用率を最大化し、既存インフラからより多くのユーザーにサービスを提供できる。
KVキャッシュ管理は、本番LLMデプロイメントの重要なボトルネックとなっている。メモリ消費量はシーケンス長とバッチサイズに比例して増加し、H100やH200のような大容量メモリGPUでもすぐに枯渇する。キャッシュ最適化技術を習得することで、より長いコンテキスト、より大きなバッチ、そしてスケールでのより費用対効果の高い推論が可能になる。
KVキャッシングが重要な理由
Transformerモデルは、新しいトークンを生成するたびに、すべての前のトークンに対してattentionを計算する。キャッシングがなければ、1,000トークンを生成するには1,000回最初からattentionを再計算する必要があり、シーケンス長に対してコストが二次関数的に増加する。
KVキャッシングの解決策: 前のトークンのkeyとvalueテンソルを保存し、後続のattention計算で再利用する。新しい各トークンは、それらを再生成するのではなく、キャッシュされた値に対してattentionを計算する。
メモリへの影響: 70Bパラメータモデルが8,192トークンをバッチサイズ32で生成する場合、KVキャッシュメモリだけで約40〜50GBが必要となり、モデルウェイト自体を超えることも多い。³
スケーリングの問題: KVキャッシュメモリは以下のように増加する:
メモリ = batch_size × seq_length × num_layers × 2 × hidden_dim × precision_bytes
FP16のLlama 3.1-70Bの場合: - トークンあたりのキャッシュ: 約2.5MB - 8Kコンテキスト: リクエストあたり約20GB - バッチサイズ32: 合計約640GBのKVキャッシュ
PagedAttention:基盤となる最適化
vLLMのPagedAttentionは、GPUメモリをオペレーティングシステムの仮想メモリのように扱うことで、KVキャッシュ管理に革命をもたらした。⁴
仕組み
従来の割り当て: 最大可能シーケンス長のための連続メモリブロックを確保する。4K最大コンテキストは、100トークンのリクエストでも4K分のキャッシュを割り当て、確保されたメモリの97.5%を無駄にする。
ページ割り当て: KVキャッシュを固定サイズのブロック(ページ)に分割する。シーケンスが成長するにつれてオンデマンドでページを割り当てる。シーケンスが完了したらページを解放する。
ブロックテーブルマッピング: OSのページテーブルのように、PagedAttentionは論理的なシーケンス位置と物理メモリ位置の間のマッピングを維持する。シーケンスは連続したメモリを見るが、物理ストレージは非連続のままである。
パフォーマンスへの影響
- メモリの無駄: 60〜80% → 4%未満
- スループット: 従来の割り当てと比較して2〜4倍向上
- メモリフラグメンテーション: 実質的に排除⁵
vLLMでの実装
from vllm import LLM, SamplingParams
# PagedAttentionはデフォルトで有効
llm = LLM(
model="meta-llama/Llama-3.1-70B-Instruct",
tensor_parallel_size=4,
gpu_memory_utilization=0.90, # GPUメモリの90%を使用
max_model_len=32768,
)
vLLMは明示的な設定なしで、ページの割り当て、解放、メモリ共有を自動的に管理する。
プレフィックスキャッシングとメモリ共有
PagedAttentionは、共通のプレフィックスを持つリクエスト間で効率的なメモリ共有を可能にする:
共有システムプロンプト: 複数のリクエストが同一のシステムプロンプトを使用する場合、それらのトークンを保存する物理ページは複製されるのではなく共有される。
自動プレフィックスキャッシング: vLLMのAutomatic Prefix Caching(APC)は、リクエスト間の共通プレフィックスを検出し、KVキャッシュブロックを自動的に共有する:
llm = LLM(
model="meta-llama/Llama-3.1-8B-Instruct",
enable_prefix_caching=True,
)
本番への影響: 一貫したシステムプロンプトや繰り返しのコンテキスト(共通ドキュメントを使用するRAG、few-shotの例)を持つアプリケーションでは、劇的なメモリ節約とレイテンシ削減が見られる。適切に構造化されたプロンプトでは、87%以上のキャッシュヒット率が達成可能である。⁶
KVキャッシュの量子化
KVキャッシュ値を圧縮することで、わずかな精度低下と引き換えにメモリ要件を削減できる:
FP8 KVキャッシュ
HopperおよびBlackwell GPUはネイティブFP8 KVキャッシュをサポートする:
# vLLM FP8 KVキャッシュ
llm = LLM(
model="meta-llama/Llama-3.1-70B-Instruct",
kv_cache_dtype="fp8",
)
FP8はFP16と比較してKVキャッシュメモリを半減させ、ほとんどのアプリケーションで品質への影響は最小限である。この最適化は、キャッシュがメモリ消費を支配する長いコンテキストの推論において不可欠となる。
INT4 KVキャッシュ
実験的な4ビットKVキャッシュサポートにより、メモリをさらに削減できる:⁷ - メモリ削減: FP16と比較して4倍 - 品質への影響: タスク依存、評価が必要 - 最適な用途: メモリ制約のある長いコンテキストのアプリケーション
量子化の選択
| 精度 | メモリ節約 | 品質への影響 | ユースケース |
|---|---|---|---|
| FP16 | ベースライン | なし | デフォルト、品質重視 |
| FP8 | 50% | 最小限 | 本番推論 |
| INT8 | 50% | 低 | コスト重視のデプロイメント |
| INT4 | 75% | 中程度 | 極端なメモリ制約 |
キャッシュ追い出し戦略
メモリ圧力が利用可能な容量を超えた場合、キャッシュ追い出しポリシーがどのトークンを破棄するかを決定する:
スライディングウィンドウAttention
最近のトークンのみをキャッシュに維持し、古いコンテキストを破棄する:
# 概念的なスライディングウィンドウ
def sliding_window_cache(kv_cache, window_size):
if len(kv_cache) > window_size:
kv_cache = kv_cache[-window_size:]
return kv_cache
最近のコンテキストが最も重要なアプリケーションにはシンプルだが効果的である。アーキテクチャ的なスライディングウィンドウ(Mistralなど)はこれをネイティブに実装している。
Attentionベースの追い出し
attentionスコアが最も低いトークンを削除し、重要なコンテキストを保持する:
PagedEviction(2025年): CUDAカーネルを変更せずに重要度の低いブロックを特定して削除する、PagedAttention用に調整されたブロック単位の追い出しアルゴリズム。⁸
エントロピーガイドキャッシング: レイヤーのattentionエントロピーに基づいてキャッシュ予算を割り当てる。より広いattentionパターンを持つレイヤーはより多くのキャッシュを受け取り、フォーカスされたレイヤーはより少なく受け取る。⁹
Streaming LLM
無限長の生成のために、Streaming LLMは以下を維持する: - 初期の「attention sink」トークン(最初の4〜8トークン) - スライディングウィンドウ内の最近のトークン - 中間のコンテキストを破棄
このアプローチにより、固定メモリで理論上無制限の生成が可能になるが、長距離依存性を必要とするタスクでは品質が低下する。
KVキャッシュオフローディング
GPUメモリが不足した場合、より遅いストレージ層にキャッシュをオフロードする:
CPUオフローディング
非アクティブなシーケンスキャッシュをシステムRAMに移動する:
# オフローディング用のLMCache統合
from lmcache import LMCacheEngine
cache_engine = LMCacheEngine(
backend="cpu",
max_gpu_cache_size="20GB",
cpu_cache_size="100GB",
)
レイテンシへの影響: CPU-GPU転送はキャッシュ取得あたり10〜50msを追加する。バッチワークロードやGPUメモリ制限によりサービス提供自体ができない場合に適している。
パフォーマンス: vLLMと組み合わせたLMCacheは、再計算と比較して3〜10倍のレイテンシ削減を達成する。これは再生成するのではなくCPUメモリにキャッシュすることで実現される。¹⁰
ディスクオフローディング
極端なケースでは、NVMeストレージにキャッシュする: - レイテンシ: 取得あたり100〜500ms - ユースケース: 他の方法では不可能な非常に長いコンテキスト - インタラクティブなアプリケーションには不向き
階層型キャッシング
本番システムは多くの場合、マルチティアキャッシングを実装する:
- GPU HBM: アクティブに生成中のホットシーケンス
- CPU RAM: 最近アクティブだったウォームシーケンス
- NVMe SSD: 潜在的な再利用のためのコールドシーケンス
インテリジェントなプロモーションとデモーションポリシーが、アクセスパターンに基づいてキャッシュを層間で移動させる。
KVキャッシュ対応ルーティング
分散推論は、関連するキャッシュを保持するPodにリクエストをルーティングすることで恩恵を受ける:
llm-dフレームワーク
KVキャッシュ対応ルーティングを備えたKubernetesネイティブフレームワーク:¹¹
# llm-dキャッシュルーティング設定
routing:
strategy: kv_cache_aware
cache_hit_weight: 0.8
load_balance_weight: 0.2
パフォーマンス結果: - プレフィックス重視のワークロードで87%のキャッシュヒット率 - ウォームキャッシュヒットで88%高速なtime-to-first-token - クラスタ全体での冗長計算の大幅な削減
実装パターン
スティッキーセッション: 同じ会話からのリクエストを同じPodにルーティングする。
プレフィックスハッシング: システムプロンプトをハッシュ化してPodルーティングを決定し、プレフィックスキャッシュヒットを確保する。
負荷対応ルーティング: ホットスポットを防ぐために、キャッシュの局所性とPod使用率のバランスを取る。
本番サイジングガイド
メモリ推定
デプロイメント前にKVキャッシュ要件を計算する:
def estimate_kv_cache_memory(
num_layers: int,
hidden_dim: int,
num_kv_heads: int,
head_dim: int,
max_seq_len: int,
max_batch_size: int,
precision_bytes: int = 2, # FP16
) -> float:
"""KVキャッシュメモリをGBで推定"""
per_token = num_layers * 2 * num_kv_heads * head_dim * precision_bytes
total = per_token * max_seq_len * max_batch_size
return total / (1024 ** 3)
# Llama 3.1-70Bの例
memory_gb = estimate_kv_cache_memory(
num_layers=80,
hidden_dim=8192,
num_kv_heads=8, # GQA
head_dim=128,
max_seq_len=8192,
max_batch_size=32,
)
print(f"KVキャッシュメモリ: {memory_gb:.1f} GB")
キャパシティプランニング
経験則: GPUメモリの40〜60%をKVキャッシュ用に確保し、残りをモデルウェイトとactivationsに使用する。
H100 80GBの例: - モデルウェイト(70B FP16): 約140GB → テンソル並列で2GPU - GPU単位のキャッシュ利用可能容量: ウェイトとオーバーヘッド後約30〜35GB - 最大同時シーケンス数: 平均コンテキスト長に依存
最適化の優先順位
- PagedAttentionを有効化: vLLMではデフォルト、大きな効率向上
- プレフィックスキャッシングを有効化: ワークロードに共通プレフィックスがある場合
- FP8 KVキャッシュを実装: Hopper/Blackwell GPUを使用する場合
- キャッシュ対応ルーティングを追加: 分散推論を使用するクラスタスケールで
- オフローディングを検討: GPUメモリが不足した場合のみ
監視と可観測性
本番環境でKVキャッシュメトリクスを追跡する:
主要メトリクス: - キャッシュ使用率: 割り当てられたキャッシュの使用中の割合 - キャッシュヒット率: プレフィックスキャッシュの有効性 - 追い出し率: キャッシュオーバーフローの頻度 - メモリフラグメンテーション: 割り当てられたブロック内の無駄なスペース
vLLMメトリクスエンドポイント:
# /metricsでPrometheusメトリクスが利用可能
# kv_cache_usage_percent
# kv_cache_total_blocks
# kv_cache_used_blocks
# prefix_cache_hit_rate
アラートしきい値: - キャッシュ使用率 > 90%: 容量をスケールするかバッチサイズを削減 - ヒット率 < 50%: プレフィックスキャッシング設定を確認 - 追い出し率が高い: メモリ割り当てを増やすかプロンプトを最適化
本番LLM推論をデプロイする組織は、グローバルデプロイメント全体でのGPUキャパシティプランニングと最適化について、Introlのインフラストラクチャ専門知識を活用できる。
メモリ効率化の必然性
KVキャッシュ最適化は、本番LLMデプロイメントにとって最も影響の大きい改善の一つである。PagedAttentionだけで2〜4倍のスループット向上を実現し、追加のハードウェアコストなしでGPU投資を2倍または4倍にするのと同等の効果がある。
最適化の状況は進化し続けている。MicrosoftのFastGenは適応圧縮により50%のメモリ削減を実証した。エントロピーガイドキャッシングは層間でインテリジェントに予算を割り当てる。キャッシュ対応ルーティングは、以前は不可能だったクラスタスケールの効率向上を可能にする。
大規模に推論を実行する組織にとって、KVキャッシュ最適化は最初に評価すべき最適化の一つである。これらの技術は最小限の