AI技術教材 · 基礎編 · KV Cache & Recursion

生成が遅いのは、計算が重いからではない。
GPUは、読み終わるのを待っている

LLM推論のボトルネックはほぼ KVキャッシュ に集約される。 この教材では前半で、KVキャッシュが何を貯めていて、なぜ膨らみ、なぜ帯域を食い潰すのかを 電卓で手を動かしながら確認する。後半は、その膨らみを畳むために持ち出される 「回帰」という言葉が、実は3つの別物を指していることを分解する—— 問題を作っている回帰、解いている回帰、それを成立させる条件としての回帰。

これは 前提編です。ここを踏まえると 富士通 PHOTON の解説 が読めるようになります。 姉妹編に Dense と MoE(パラメータとメモリの非対称)。
01 — what is cached

何を貯めているのか — なぜ Q は貯めないのか

Attention は、各トークンの隠れ状態 h から3本のベクトルを作る。

q = h·WQ クエリ … 私は何を探している
k = h·WK キー … 私は何として見つけられる
v = h·WV バリュー … 私が渡す中身

出力(位置 t) = softmax( qt · K≤tT / √d ) · V≤t

自分の q は1本、突き合わせる相手は 過去全部の K と V。 そしてここが要点で、因果マスクがあるため位置 t の k, v は それより後の情報に一切依存しない。つまり一度計算したら二度と変わらない。 ならば捨てずに取っておけばいい——これが KVキャッシュ。

Q をキャッシュしない理由

各ステップで使うクエリはいま生成している1トークンぶんだけで、使ったら用済み。 過去のクエリを取っておいても二度と参照しない。だから「QKVキャッシュ」ではなく KVキャッシュと呼ぶ。名前が非対称なのは、参照のされ方が非対称だから。

1ステップの計算Tトークン生成の総量代償
キャッシュなし過去全部の K,V を作り直す再計算が積み上がる計算が爆発
キャッシュあり新しい1トークンぶんだけattention 本来のコストのみメモリが膨らむ

KVキャッシュは計算をメモリに両替する装置である。そして現在の LLM 推論では、 この両替レートが悪いほうへ振れきっている。どれくらい悪いのかを、次の電卓で見る。

02 — the calculator

KVキャッシュ電卓

数式は単純だ。単純なのに、出てくる数字がGPUの使い方を決めてしまう。

KVキャッシュ量 = 2 × 層数 × KVヘッド数 × ヘッド次元 × 系列長 × 同時本数 × バイト数
↑ K と V の2本

MODEL & SERVING

RESULT

512 KiB1トークンあたりの KVキャッシュ
1本ぶん
(文脈を埋めたとき)
同時本数ぶんの合計
KVキャッシュ
このGPUに載る
同時本数の上限
演算強度 FLOP/byte
(300未満=メモリ律速)
モデル重み KVキャッシュ 空き

プリセットを往復すると見えること

MHA 7B級は 512 KiB/token、GQA 70B級は 320 KiB/token。 パラメータが10倍でも、KVキャッシュはむしろ小さい。 GQA(Grouped-Query Attention)が KVヘッドを 32→8 に削っているからで、 モデルの大きさと KVキャッシュの大きさは別の量だと分かる。 ここを混同していると、長文でメモリが死ぬ理由を永久に取り違える。

03 — why memory-bound

なぜ「メモリ律速」になるのか — 共有できるものと、できないもの

decode の1ステップで GPU がやることを分解する。

演算量 ≈ 2 × パラメータ数 × バッチ数 … 小さい
メモリ読出 = モデル重み(全部) + KVキャッシュ(全部) … 大きい

現代のGPUは、演算器の性能に対してメモリ帯域が相対的に細い。ざっくり 1バイト読むごとに300FLOPsほど計算しないと演算器が遊ぶ。 ところが decode は1トークンあたりの計算がごく小さいので、完全に読み出し待ちになる。 これが memory-bound の正体で、GPUを速い演算器に替えても効かない領域である。

決定的な非対称 — ここが全ての鍵

モデル重みはバッチ全体で共有できる。KVキャッシュはリクエストごとに固有で、共有できない。

だからバッチを増やすと、重みの読み出しコストは頭数で割られて薄まっていく。 ところが KVキャッシュのトラフィックだけは本数に比例して増え続ける。 電卓で同時本数のスライダーを動かすと、演算強度が一度上がってから頭打ちになるのが見えるはずだ。 頭打ちを作っている項が KVキャッシュで、マルチクエリ配信で最後に残る律速項がこれ。

効率指標として「速度」ではなく TPM=メモリあたりスループット が使われるのは、 分母のほうが効くこういう構造だからである。

「サイズ」と「読み出し総量」は別物 — 長文が二乗で効く理由

ここは電卓が答えてくれない部分なので、原理として押さえておきたい。 上の電卓が出しているのはある瞬間のキャッシュのサイズで、これは文脈長 T に比例して伸びる。 しかし本当に効いてくるのは、T トークンを生成しきるまでに読み出す総量のほうである。

1トークン目は 1 個ぶん、2トークン目は 2 個ぶん…… t トークン目は t 個ぶんの状態を読む。足し上げると、

サイズ : O(T) … 瞬間の占有。電卓が出している値
読み出し総量 : 1 + 2 + … + T = O(T²) … 生成しきるまでの累計トラフィック

文脈が2倍になれば、占有は2倍だが、読み出し総量は4倍になる。 「長文にすると急に重くなる」という体感の正体はこの二乗の項で、 メモリ律速の議論で本当に効いているのはサイズではなく帯域を流れる総量のほうだ。

だから対策も2種類ある——サイズを削る(量子化、ヘッド削減)のと、 読み出しの回数・範囲を削る(window、階層化)のは、同じ「KV対策」でも効き方が違う。 前者は係数を下げるだけで二乗という形は変わらない。後者だけが形を変えられる。

対処法の見取り図

手法式のどこを削るか既存モデルに後付け
ヘッド構成MQA / GQA / MLAKVヘッド数(幅)✕ 事前学習が要る
数値表現KV量子化(fp8 / int4)バイト数
注意範囲Sliding window / Sparse系列長(見る範囲を切る)
取捨選択eviction(H2O, StreamingLLM 等)系列長(重要でないものを捨てる)
メモリ管理PagedAttention(vLLM)断片化を直す(量は減らない
系列そのもの階層化(PHOTON 等)キャッシュが張られる列の解像度✕ 事前学習が要る

上から5つは「できあがったキャッシュをどう安くするか」という後付けの工夫。 最後の一行だけが、そもそもキャッシュが小さくなる形にモデルを学習し直すという別の階層の話になっている。 強みでもあり、既存の重みに適用できないという障壁でもある。

04 — three recursions

「回帰」は3つある

論文でも記事でも同じ字が3つの別物に使われる。混ぜると読めなくなるので分ける。カードを押すと図が変わる。

① AUTOREGRESSIVE

自己回帰性

問題を作っている側
② RECURRENCE

再帰的生成

解いている側
③ CONSISTENCY

再帰整合性

成立の条件

③ が効く一般原理 — 覚えて帰る価値があるのはここ

2つの計算経路が同じ結果に到達すると証明できるなら、実行時は安いほうを選んでよい。

高い経路(生成したトークンを上げ直して要約を作る)と、安い経路(デコーダの途中に出ている再構成をそのまま使う)。 両者の一致を訓練時に損失として作り込んでおいて、推論時に安いほうへ差し替える。 近似による手抜きではなく、等式の利用である。この型は KVキャッシュに限らず応用が効く。

05 — the spectrum

畳むか、残すか — RNN と Transformer のあいだ

「履歴を状態に畳む(回帰)」と「履歴を全部残して毎回引く(注意)」は、メモリと表現力の交換レートを決める根本の選択。

RNN は履歴を固定サイズの状態に畳むのでメモリは O(1)。そのかわり 「300トークン前のあの単語」に戻って参照することができない。 Transformer は全部残すのでどこへでも参照できるが、メモリは O(T)。 階層化は、この線分の上に目盛りを1本打つ試みだと読める—— 粗い粒度でならランダムアクセスできる状態を O(T/C) で持つ

畳むと、何が失われるのか

固定サイズの状態にすべてを押し込む方式には、構造的な性質がひとつある。 新しい情報が入るたびに状態は上書き・混合されていくので、 古い情報ほど薄まっていく。容量が一定である以上これは避けられず、 「1万トークン前に一度だけ出てきた固有名詞」を取り出せる保証は原理的にない。

階層化が違うのは、畳むが、畳んだものを捨てない点にある。 粗い要約の列そのものを保持しているので、 粗い粒度でならいつでも過去へ戻れる。 失われるのは「遠い過去の細部」であって「遠い過去そのもの」ではない—— 圧縮率 C が、何を失ってよいかのダイヤルになっている。

そして、二乗の「形」が変わる

前節で見たとおり、読み出し総量は O(T²) だった。 グローバルに保持する列が 1/C に縮むと、この項は

Transformer : 読み出し総量 O(T²)
階層化 : 読み出し総量 O( (T/C)² ) + 局所ぶん(T に比例

へ置き換わる。C=16 なら二乗の項が 256分の1。 量子化や KVヘッド削減が係数を下げる手であるのに対し、 これは二乗が乗る対象そのものを短くする手である。 効き方の質が違い、しかも長くなるほど差が開く。 「長文と多並列でこそ効く」と言われるのは、この形の違いに由来している。

06 — the cost of recursion

回帰には代償がある

自分の出力を自分に食わせ続ける構造である以上、ズレがあれば累積する。 教師強制(正解を与えながら)で訓練したモデルを自由生成させると壊れていく、 いわゆる exposure bias と同じ形の問題が、 再帰的な生成手続きにはそのまま乗ってくる。

だから評価が難しくなる

再帰的な生成はモデル自身が作った再構成を次の入力にするので、 正解トークンを与えながら測る標準的な teacher-forcing の評価パイプラインに素直に乗らない。 結果として「効率は新しい手続きで測り、品質は従来の手続きで測る」という 非対称が生じやすい。数字を引用するときは、どちらの手続きで測られた数字かを 確認する癖をつけておくといい——実際、PHOTON の論文はこの点を自ら限界として明記している。

第一部の言葉に戻すと、KVキャッシュという「読み直し」を「持ち回る状態」に両替した以上、 両替レートは生成が長くなるほど悪化しうる。 回帰にした瞬間に引き受ける、構造的なリスクである。

07 — questions

よくある疑問

KVキャッシュはprefillとdecodeのどちらで作られますか?
prefill で一気に作られ、decode で1トークンずつ追記される。 prefill はプロンプト全体を並列処理できるので計算律速(compute-bound)、 decode は1トークンずつしか進めないので読み出し律速(memory-bound)。 同じモデルでも局面によって詰まる場所が違う、というのが設計を考えるうえで重要。
KVキャッシュを量子化すれば解決では?
効きますが線形にしか効きません。fp16→fp8 で半分、int4 で1/4。 一方系列長は青天井なので、掛け算の別の項が伸び続ける限り追いつけない。 しかも K は量子化に敏感(softmax前の内積に効く)で、品質劣化が V より出やすい。 電卓で数値表現を切り替えつつ文脈長も伸ばしてみると、勝負がついていないことが見えます。
MQA / GQA / MLA の違いは?
いずれもKVヘッド数を削る方向の工夫。MHA はクエリヘッドと同数の KV を持ち、 MQA は KV を1組だけに共有、GQA はその中間でグループごとに共有する。 MLA(DeepSeek系)はさらに踏み込んで、KV を低次元の潜在ベクトルに圧縮して保持し、 使うときに展開する。電卓の「KVヘッド数」を 32 → 8 → 1 と動かすと効き幅が体感できます。
そもそも回帰をやめて、一発で答えを出せばいいのでは?
最も素直な疑問で、実際に非自己回帰生成(non-autoregressive generation)という研究分野があります。 全トークンを一度に並列で出せれば、逐次性も KVキャッシュの積み上がりも消える——理屈のうえでは最も速い。

ただし一般に、品質が自己回帰方式に届きにくいことが知られています。 直観的な理由は、トークン間の依存を同時に満たすのが難しいから。 「晴れのち曇り」と「晴れときどき曇り」はどちらも妥当ですが、 各位置を独立に決めると「晴れのちどき曇り」のような混線が起きうる。 自己回帰は、前の決定を見てから次を決めることでこの整合を自然に取っている。

だから実用系はほぼ自己回帰のままで、改善は「回帰をやめる」ではなく 回帰の1周あたりを安くする方向に進んでいる。本教材で見た階層化も、 自己回帰そのものは保ったまま1周の中身を軽くするアプローチです。
結局、長い文脈は諦めるしかない?
諦めではなく配分の問題です。全トークンを同じ解像度で保持する必要はない、 というのが最近の共通した見立てで、捨てる(eviction)・縮める(量子化)・切る(window)・ 粗くする(階層化)のどれかを選ぶことになる。 どれを選ぶかは「何を失ってよいか」の判断であって、技術の優劣ではありません。
08 — next

この続き

応用編 →

富士通 PHOTON — 「475倍」の正体と、横に読むか縦に読むか

ここで見た KVキャッシュの膨らみを「列の解像度を粗くする」ことで畳みにいった実例。 本教材の ②再帰的生成 と ③再帰整合性 が、そのまま RecGen という具体的な仕掛けとして出てきます。 報道の「475倍」を スループット×メモリ に分解し、どこまでが階層化一般の効果でどこからが固有の貢献かを切り分けた記事。

姉妹編 →

Dense と MoE — 総パラメータ大・活性化小の謎

こちらはパラメータ側の非対称の話。「MoE は軽い」の軽さが計算だけで、 メモリは軽くないのはなぜか。本教材の「共有できるもの/できないもの」の議論と対になります。