policybook / kv-cache

kv-cache

Policies for deciding which tokens to forget while a language model generates. A transformer's KV cache grows by one entry per token, per layer, per head. At a long context that is gigabytes, and the cost is linear in the sequence while the value of any individual token is not.

Run these side by side → Same trace, same seed, stepped in lockstep.

Choosing one

If you needUseBecause

A simple default that needs no attention weights

StreamingLLM

A ring buffer plus four pinned positions. 0.7862 retained mass at budget 512, from a policy with no arithmetic in it.

The best retained attention, and you can read weights

TOVA

0.8240 at budget 512, the highest here. Sizes its own recency protection from the data, so it has nothing to misconfigure.

To find old tokens that still matter

H2O

Best heavy-hitter recall at the wider budgets, 0.9137 at 512, because a cumulative score remembers what a current-step score cannot.

Importance to decay rather than accumulate

Scissorhands

Counts how often a token mattered, so a stale early spike stops defending its slot. A third less memory than H2O.

To keep phrases intact, not just their peaks

SnapKV

The only policy here whose scoring is neighbour-aware. Costs the most memory in the domain.

To divide a fixed budget across layers

PyramidKV

The only policy that answers “how many”, not “which”. Inert on this single-layer trace. See its README.

The baseline, to measure against

sliding window

Keep the most recent and forget the rest. Included to be measured, not recommended.

Benchmarks

Retained mass on each trace, measured by this repository's benchmarks.

Policy decode-4096@256 decode-4096@512 decode-4096@1024
TOVA 0.77810.82400.8859
PyramidKV 0.78340.82120.8880
SnapKV 0.78340.82120.8880
StreamingLLM 0.73670.78620.8662
H2O 0.64390.71490.7844
Scissorhands 0.64130.71140.7847
Sliding Window 0.59660.65550.7541

Every policy