← All posts

KV cache quantization hurts more at longer context: 4B model, 16K vs 64K

I repeated the KV cache quality test at a 64K context. Compared with the full f16 cache, the damage from a quantized cache roughly doubles or triples: KL divergence for q4_0 goes from 0.0166 at 16K to 0.0347 at 64K, and for q8_0 from 0.0072 to 0.0207. So a cache format for 1M tokens has to be judged at long context, not 16K. The 128K run did not happen because the measuring tool ran out of system memory.

ExperimentE21X
Date2026-10-30
Benchmarkllama-perplexity on the WikiText-2 raw test split, context 65,536, first 2 chunks. The f16 KV cache run is saved as the reference, and every other run reports perplexity, mean KL divergence from the reference and how often the top token matches. 16K numbers are from E21v on the same text.
ModelQwen3.5-4B, Q4_K_M GGUF, flash attention on, batch 2048, ubatch 512
HardwareOne of my dedicated test rigs: RTX 3080 10 GB, 128 GB system RAM
VerdictBASELINE

What I tested

K/V cache formats q8_0, q4_0, K q8_0 with V q4_0, and an f16 repeat as the noise floor, at context 65,536 and 131,072. llama.cpp built with upstream PR 29827.

Pass bar, set before the run

None (supporting measurement). Planned before the run: if q4_0 KL divergence at long context is more than about 1.5x its 16K value (0.0166), treat the error as growing with context.

Result

K / V formatKLD at 16KKLD at 64KSame top token 16K / 64KPPL vs f16 at 64K
f16 / f16 (repeat)0.00000.000099.998% / 99.997%+0.16%
q8_0 / q8_00.00720.0207 ± 0.001497.30% / 96.43%-3.11%
q8_0 / q4_00.01000.0254 ± 0.001696.69% / 95.80%-3.19%
q4_0 / q4_00.01660.0347 ± 0.002095.85% / 95.25%-2.91%

q4_0 KL divergence at 64K is 2.1x its 16K value and q8_0 is 2.9x, both above the 1.5x line set before the run. The order of the formats stays the same, and 8-bit keys with 4-bit values is still clearly better than full q4_0.

At 64K every quantized cache gave about 3% lower perplexity than the f16 cache (8.27 to 8.28 vs 8.53), while the f16 repeat matched the reference. I don't have an explanation yet and am not counting it as a gain. KL divergence and top-token agreement both say the quantized caches moved further from the reference.

The 131,072-token run failed for every format. The f16 reference run crashed right after starting the chunk, most likely because llama-perplexity keeps every position's logits in system RAM (context times vocabulary times 4 bytes, roughly 130 GB at 128K, more than the rig's 128 GB). It is a limit of the measuring tool, not of the GPU or the cache.

Only 2 chunks at 64K, so the 64K numbers rest on fewer scored tokens than the 16K ones. A 32K run to fill in the curve is next.

What happened

The 64K runs all finished and show that quantization damage grows with context length for every format tested. That raises the bar for the 1M-token goal: a smaller cache format has to hold up at long context, and its quality should be checked there. The 128K runs failed because the measuring tool needs more system memory than the rig has at that length.

How to rerun

powershell -ExecutionPolicy Bypass -File e21x_chain.ps1

Code

All code for E21X: e21x_chain.ps1, results.csv.

Prior work

No novelty claim. This is a standard llama.cpp quality measurement of existing cache formats at a longer context.

Written by Andrew Rose with help from AI tools. Every number comes from the run logs.

Questions or ideas? me@andrewroseit.com or @AndrewRoseIT.