Skip to main content
issue 2026-09-01Inference40 minarXiv 2023interactive

H₂O: Heavy-Hitter Oracle for Efficient Generative Inference

This research paper shows that attention mass concentrates on a few heavy-hitter tokens, and that an eviction policy balancing those hitters with a local window can slash KV memory while preserving accuracy on OPT, LLaMA, and GPT-NeoX.

H₂O keeps heavy-hitter and recent KV states inside a fixed cache budgetLeft: accumulate Softmax attention mass so a few tokens light up as heavy hitters. Middle: fill a size-k cache with local recent cubes plus high-score H2 cubes. Right: lowest-score non-local KV states leave while decode continues.ENTER · SCOREACCUMULATE MASSPOWER-LAW H₂ SPIKESRUN · KEEP kLOCAL + H₂ SLOTSH₂SCOREH₂LOCRECENTLOCFIXED BUDGET CACHELEAVE · EVICTLOW SCORE OUTKVDROPKEEPDECODENOT OLDEST-FIRST ONLYSCORE MASS · FILL LOCAL+H₂ · EVICT THE RESTH₂O score → keep → evictStacked flow: accumulate attention scores, keep local plus heavy-hitter KVs in a fixed budget, evict low-score states.ENTER · KEEP · LEAVEENTER · ACCUMULATE SCORESsparse heavy-hitter spikesRUN · LOCAL + H₂ IN BUDGET kfixed-size KV working setLEAVE · DROP LOW SCOREnot pure oldest-first LocalHEAVY HITTERS EARN THEIR SLOTSSCORE → KEEP → EVICT

Long chat and story generation do not only pay for model weights. Every past token parks a key/value state in the KV cache, so GPU memory grows with sequence length and batch size. Once that cache dominates the working set, throughput stalls and serving systems start swapping or OOM.

Zhang et al. start from a sparse fact about Softmax attention: a small subset of tokens carries most of the accumulated attention mass. They call those tokens Heavy Hitters (H2\mathrm{H}_{2}). Drop them and quality falls. Keep only a recent window (Local) and you still miss the same sparse peaks. Heavy Hitter Oracle (H2O\mathrm{H}_{2}\mathrm{O}) is the eviction policy that dynamically retains a balance of recent tokens and H2\mathrm{H}_{2} tokens inside a fixed budget kk.

What this paper explains

Autoregressive Transformers cache KK and VV for every past position so decode steps can attend without recomputing the prompt. For length nn the cache is Θ(n)\Theta(n) per layer and grows again with batch size.

The authors ask: can we evict KV states aggressively — down to a small constant budget — without pretending every past token was equally useful?

Their answer has three layers:

  1. Empirically show that accumulated attention scores follow a power-law and that the heavy tail aligns with frequent co-occurrence in text.
  2. Prove that removing H2\mathrm{H}_{2} tokens hurts; a pure Local baseline that keeps only the newest KVs is not enough.
  3. Ship H2O\mathrm{H}_{2}\mathrm{O}: a greedy eviction policy that fills a size-kk cache with recent tokens plus high accumulated-score tokens, with a dynamic-submodular analysis under mild assumptions.
Full vs Local vs H₂O cache policiesThree columns of token slots. Full keeps every past KV. Local keeps only a trailing recent window. H₂O keeps recent slots plus sparse heavy-hitter slots inside a fixed budget.FULLkeep all · growmemory → ∞LOCALrecent onlyH₂ droppedH₂Olocal + heavy hittersH₂H₂budget k fixedSame k: Local loses sparse peaks · H₂O re-ranks who stays
Full stores every past KV. Local keeps a trailing window and can drop high-mass positions. H₂O fills a fixed budget with recent tokens plus accumulated-score heavy hitters.

Prior limits

  • Full cache. Exact attention over the entire prefix. Accuracy ceiling — and a memory wall once nn or the batch is large.
  • Local / sliding window. Keep only the most recent kk KVs. Cheap and simple; the paper’s comparisons show it loses the sparse high-mass positions that still matter later in generation.
  • Static Top-KK without H2\mathrm{H}_{2} dynamics. Selecting important tokens once (or ignoring score accumulation bias) fails to track which positions remain influential as decoding proceeds.
  • Orthogonal serving tricks. Offloading (FlexGen-style), paging (PagedAttention), and quantization shrink how KVs are stored; they do not answer which tokens to keep when the logical cache must shrink.

The mechanism

Heavy Hitters. Sum Softmax attention weights into each past key across the generation trace. The paper finds these accumulated attention scores are highly skewed: a few tokens dominate. They name that set H2\mathrm{H}_{2}. Scatter plots in the paper further show accumulated score tracks token co-occurrence frequency in the data — H2\mathrm{H}_{2} is not an accident of one prompt.

Why Local fails. Oldest-first eviction quietly deletes early high-mass positions. Later Softmax steps redistribute over a cache that no longer contains the tokens the model learned to lean on, and task accuracy drops in their OPT / LLaMA / GPT-NeoX sweeps.

H2O\mathrm{H}_{2}\mathrm{O} eviction. Maintain a cache set SiS_i of size kk at step ii:

  • When S<k|S| < k, admit new KV states.
  • When full, admit the newest token and evict the member with lowest score under FscoreF_{\mathrm{score}}, where the practical score is accumulated attention (with care for the bias that older tokens have had more steps to accumulate — the paper discusses this and balances with an explicit recent quota).

Informally (Definition 4.3): Si=k|S_i| = k and at most one membership change per step (SiSi11|S_i \setminus S_{i-1}| \le 1). The implementation skeleton keeps a running score vector, protects a local block of recent tokens, and fills the remaining slots with the current H2\mathrm{H}_{2} set.

Interactive

Budget k: local seats vs heavy hitters

Teaching toy with fixed accumulated scores (taller = more Softmax mass). Vary cache budget k and the local fraction. Pure Local with the same k can drop high-score tokens that H₂O would keep — label this as a pedagogy demo, not a paper table.

Submodular lens. They cast eviction as a dynamic submodular problem and argue the greedy H2\mathrm{H}_{2} policy inherits approximation-style guidance under mild assumptions — useful as a design rationale, not something you need to re-derive to use the system.

Algorithm / figure walkthrough

  1. Prefill the prompt; materialize full KV for the prefix until the budget kk fills (or immediately begin scoring if the prompt already exceeds kk).
  2. For each new decode token, compute attention over the current cached keys and add those Softmax weights into a per-token accumulated score.
  3. Append the new KV. If size exceeds kk, evict the lowest-scoring non-protected (non-local) entry so the cache again holds local + H2\mathrm{H}_{2} slots.
  4. Attend only over the surviving kk KVs on the next step.
  5. Repeat — memory stays O(k)O(k) while generated length grows.
One H₂O eviction stepFlow from left to right: new token arrives, accumulated scores update, local block is protected, lowest-score non-local KV is evicted to restore budget k.NEW TOKENappend KVUPDATE SCORESSoftmax mass +=into past keysPROTECTlocal blockDROPlowscore|S| returns to k · at most one eviction per step
Each decode step appends a KV, adds Softmax mass into accumulated scores, protects the local recent block, and evicts the lowest-scoring non-local entry if the budget overflows.

Contrast the three policies in the first figure: Full never evicts; Local keeps a trailing window only; H2O\mathrm{H}_{2}\mathrm{O} re-ranks who deserves the non-local slots using accumulated mass.

What to notice when reading

  • H2\mathrm{H}_{2} is defined by attention mass, not by “being the first tokens.” That is the clean contrast with StreamingLLM’s attention sinks, which pin early positions because Softmax needs a denominator home. H₂O may keep early tokens when they score as hitters, and may keep mid-sequence spikes too.
  • The default story in the abstract is a 20%20\% heavy-hitter-oriented budget relative to the full cache in their main throughput claims — treat 20%20\% as the authors’ reported operating point, not a universal constant.
  • Score accumulation favors tokens that have been present longer; the local + H2\mathrm{H}_{2} split is how they avoid a pure “oldest always wins” bias.
  • H₂O is a content policy for which KVs survive. It composes with quantization and with system stacks (their tables include compressed-weight variants).

Results and evidence

Numbers below are from the paper’s reported experiments (arXiv:2306.14048), not independent re-runs.

Accuracy vs Local / Full. Across zero- and few-shot style evaluations on OPT, LLaMA, and GPT-NeoX families, H2O\mathrm{H}_{2}\mathrm{O} tracks Full much more closely than Local at matched cache budgets (Figure 4 and Table 1 narrative). Ablations that strip H2\mathrm{H}_{2} while keeping sparse/Local structure degrade (Table 2: OPT-30B at 20%20\% KV budget).

Throughput (T4). With a 20%20\% heavy-hitter-oriented cache, their H2O\mathrm{H}_{2}\mathrm{O} implementation improves generation throughput over DeepSpeed ZeRO-Inference, Hugging Face Accelerate, and FlexGen by up to 29×29\times, 29×29\times, and 3×3\times on OPT-6.7B and OPT-30B (abstract / Table 3 setting). Same-batch-size latency improves by up to 1.9×1.9\times.

Long streams. Figure 5 shows streaming with H2O\mathrm{H}_{2}\mathrm{O} on inputs on the order of four million tokens, and compares perplexity against StreamLLM-style baselines under matched start/heavy-hitter vs local budgets (see also Figure 9’s H2O-256-style budget labels).

Compatibility. Table 6 reports composition with weight quantization; compressed H2O\mathrm{H}_{2}\mathrm{O}-c variants appear in the throughput appendices.

Limitations

Compressed from the paper’s scope and what it does not claim:

  • Eviction is irreversible for that decode: once a KV leaves, mid-context facts living only there are gone unless you add retrieval or recomputation.
  • Matching Full on their task suite at a given budget is not a claim of parity with infinite dense attention on every downstream metric.
  • Accumulated-score bookkeeping and the local/H2\mathrm{H}_{2} split need careful implementation; naive Top-KK each step is not the same algorithm.
  • End-to-end speedups depend on the baseline stack (offload vs in-GPU). Gains vs FlexGen (3×3\times) differ in kind from gains vs ZeRO-Inference / Accelerate (29×29\times) in their tables.
  • Complementary to — not a replacement for — paged allocators, continuous batching, or speculative decoding.

How to read the paper

  1. Abstract — 20%20\% budget teaser and the 29×29\times / 3×3\times / 1.9×1.9\times claims.
  2. Figure 1 — Full vs Local vs H2O\mathrm{H}_{2}\mathrm{O} cartoons and the accuracy–memory sketch.
  3. §3 + Figure 2 — sparsity, power-law accumulated scores, co-occurrence correlation.
  4. §4 + Algorithm 1 / Figure 3 — eviction loop and the dynamic-submodular framing.
  5. §5 Figures 4–5 + Tables 1–5 — accuracy, throughput, long-stream behavior.
  6. Appendix comparisons with StreamLLM / SpAtten / Top-KK — place H₂O among sibling sparse-KV ideas.

Knowledge check

What primarily defines a Heavy Hitter (H₂) token in this paper?

Why is a pure Local (recent-only) KV cache a weak eviction baseline here?

In the abstract’s main throughput claim, what cache budget do the authors highlight for H₂O?

Keep reading / Sources