Mímisbrunnr知恵の泉

← MLOps 一覧

🎓 レベル:発展 | 重要度:B(推奨)

📎 前提:レイテンシとスループットのトレードオフ | 関連:推論の実務(機械学習)

⚠️ 要最新確認:LLM サービングエンジン・手法は最も進化が速い領域。具体名・数値は執筆時点(2026-06)の例。

要点(BLUF)

1. なぜ LLM 推論は特別なのか

LLM はテキストを1トークンずつ自己回帰的に生成します。N トークン生成するには N 回の前向き計算が必要で、各回で過去すべてのトークンに注意を払います。素朴に実装すると、毎回過去を全部計算し直すため、生成長の2乗に比例するコストになります。さらにモデル自体が巨大(数十〜数千億パラメータ)でメモリを食う。だから汎用サービングの常識(オンライン推論サービング)に、LLM 固有の最適化が要ります。

2. KVキャッシュ:過去の計算を再利用する

自己回帰生成では、各ステップで過去トークンの Key/Value(注意機構の中間表現)が必要です。これをキャッシュしておけば、新しいトークンを生成するとき過去分を計算し直さずに済みます。

flowchart LR
  T1["トークン1生成"] --> KV["KVキャッシュに保存"]
  KV --> T2["トークン2生成:過去のKVを再利用"]
  T2 --> KV
  KV --> T3["トークン3生成:過去のKVを再利用"]

KVキャッシュにより、各ステップの計算は「新トークン1個分」で済み、生成は実用速度になります。代わりにKVキャッシュがGPUメモリを大量に消費するため、メモリ管理(PagedAttention 等の手法・要最新確認)が運用の焦点になります。

3. 連続バッチング:GPUを遊ばせない

通常のバッチング(レイテンシとスループットのトレードオフ)は「同時に来たリクエストを束ねて一斉に処理」ですが、LLM はリクエストごとに生成長が違います。短い応答が終わってもバッチ全体が長い応答を待つと GPU が遊びます。**連続バッチング(continuous batching)**は、生成の途中でも、終わったリクエストを抜き新しいリクエストを差し込むことで GPU を常に埋めます。これが LLM サービングのスループットを大きく上げます。

4. 動く最小例:KVキャッシュが計算量をどれだけ減らすか

KVキャッシュの有無で、N トークン生成の計算量がどう変わるかを試算します(実モデルは使わず、計算ステップ数のオーダーを比較)。

def compute_steps(n_tokens, use_kv_cache):
    """N トークン生成の総計算ステップ数(注意計算の回数の代理)。
    KVキャッシュなし:各ステップで過去全トークンを再計算 -> 累積で O(N^2)
    KVキャッシュあり:各ステップは新トークン1個分 -> O(N)"""
    total = 0
    for step in range(1, n_tokens + 1):
        if use_kv_cache:
            total += 1            # 過去はキャッシュ済み、新規1個分
        else:
            total += step         # 過去 step 個を毎回再計算
    return total

for n in [128, 512, 2048]:
    without = compute_steps(n, use_kv_cache=False)
    with_kv = compute_steps(n, use_kv_cache=True)
    print(f"生成{n:>4}トークン : キャッシュ無={without:>9,}  "
          f"有={with_kv:>5,}  削減率={(1-with_kv/without)*100:.1f}%")

出力:

生成 128トークン : キャッシュ無=    8,256  有=  128  削減率=98.4%
生成 512トークン : キャッシュ無=  131,328  有=  512  削減率=99.6%
生成2048トークン : キャッシュ無=2,098,176  有=2,048  削減率=99.9%

出力の意味:KVキャッシュなしでは生成長の2乗で計算が膨らみ、2048トークンで約210万ステップ。KVキャッシュありなら2048ステップで済み、99.9%削減です。生成が長いほど効果が大きく、これなしに長文生成は実用になりません。代償は KVキャッシュのメモリ消費で、これをどう管理するか(メモリの断片化を防ぐ PagedAttention 等)が専用エンジンの腕の見せ所です(要最新確認)。連続バッチングと組み合わせて、はじめて LLM が本番の速度・コストで回ります。

5. 運用の勘所

なぜそうするのか

LLM サービングに専用の最適化が要るのは、自己回帰生成という構造が汎用サービングの前提を破るからです。通常のモデルは「入力1個→出力1個」を1回計算しますが、LLM は「1トークンずつ N 回」生成し、各回が過去全体に依存します。素朴な実装では計算が生成長の2乗で膨らみ、リクエストごとに生成長が違うのでバッチも揃いません。KVキャッシュが2乗を線形に落とし、連続バッチングが不揃いなリクエストで GPU を埋める——この2つがあって初めて、巨大な LLM が実用的なコストと速度で本番に乗ります。だから専用エンジンを使うのが合理的です。

⚠️ よくある落とし穴

対応 lab

関連ノート