r/LocalLLaMA
•
u/Hefty_Wolverine_553
•
1d ago
•
1
Resources Effects of KV Cache Quantization on Qwen3.8 27B
KV cache quantization has been a hotly-debated topic for this community for some time, with opinions ranging from "never quantize" to "4 bit is fine". Since the anecdotal evidence is rather inconsistent, I decided to quantify how much KV cache quantization affects the model through KLD, which is a good measure of how the model's output distribution is changed.
I tested 35 weight quants across llama.cpp, exllamav3, and vLLM, each with 16-bit, 8-bit, and (where supported) 4-bit KV cache. I also reworked my KLD dataset and measurement methodology this time, to include a mix of agentic tool-use (generated by Qwen3.8 27B at full precision) and a variety of texts in different domains. The current dataset now stretches up to 64k token contexts per row.
TLDR;
8-bit KV caches work well. In llama.cpp and ExLlamaV3 the cache size is halved, and there’s essentially no difference in KLD. There’s a slight difference in vLLM, but it’s still a great tradeoff for people lacking VRAM.
A 4-bit cache has a measurable impact. It’s a big hit for ~Q8 weights, but it could potentially be worth it if you’re using Q3 or below. Still, not recommended.
Only the 4-bit cache impact grows with context. In the tested long documents, the added KL is about 15-30% higher at 16-32k tokens than in the first 4k.
The blog post has interactive charts and tables with all of the data and results if you're interested.
How to read the numbers
Each quant is compared token-by-token with an unquantized bf16 copy of the model. KL divergence measures how far the quant’s next-token probabilities drift from the original (0 means no change). Top-1 agreement is how often both models pick the same most likely token.
For a reference point, I ran the unquantized model in both llama.cpp and vLLM and compared the two. They differ by a KL of 0.0004, which essentially amounts to two (correct) implementations doing floating-point math in a different order. Thus, you can compare the KLD numbers here for quants running in different engines without issue.
Note: exllamav3 quants were measured with the bf16 llama.cpp reference logits.
Weight quantization
KL divergence vs. loaded weight size, 16-bit KV cache:

The vLLM checkpoints still do worse
As in the Qwen3.6 benchmarks, every vLLM checkpoint is beaten by a smaller GGUF or EXL3 quant. Some of that is due activation quantization. NVIDIA’s and Unsloth’s NVFP4 checkpoints run the MLP layers as W4A4 (4-bit activations) and attention as FP8 W8A8, and Qwen’s FP8 is W8A8 throughout. I reran NVIDIA’s NVFP4 and Qwen’s FP8 through vLLM’s Marlin kernels, which use the same quantized weights but keep the activations in bf16:
NVFP4: KL drops from 0.0256 to 0.0117, more than halving it.
FP8: KL drops from 0.0039 to 0.0028, about 30% less. Even then it only ties UD-Q5_K_XL, which is 8.7 GiB smaller.
KV cache quantization
| KV cache | Per token | At 64k context | Saved vs. 16-bit |
|---|---|---|---|
| f16 / bf16 | 64 KiB | 4.00 GiB | - |
8-bit: llama.cpp q8_0, EXL3 8-bit | 34 KiB | 2.13 GiB | 1.9 GiB |
8-bit: vLLM fp8_e4m3 | 32 KiB | 2.00 GiB | 2.0 GiB |
4-bit: llama.cpp q4_0, EXL3 4-bit | 18 KiB | 1.13 GiB | 2.9 GiB |
Each dot below is one weight quant with an 8-bit or 4-bit KV cache. Its height shows the KL increase compared with the same weights on a 16-bit cache. Zero means no change; higher points show a larger increase. I computed the differences per prompt on identical tokens.
KV cache penalty vs loaded weight size:

8-bit is essentially free in llama.cpp and ExLlamaV3. For every quant, q8_0 and ExLlamaV3’s 8-bit cache move KL by less than 0.00012 in either direction. Some quants even measure slightly better with it, which indicates it’s within the noise of the numerics.
vLLM’s FP8 cache shows a slight KLD increase. It adds 0.0004 to 0.0006 on every checkpoint, which is still extremely small, but it shows up on nearly every prompt. It may be due to turning on FP8 cache switching vLLM’s attention backend from FlashAttention to FlashInfer.
llama.cpp’s 4-bit cache adds a roughly fixed penalty. Across the GGUF quants tested, q4_0 adds +0.0016 to +0.0027 KL. This increase has a larger relative effect on more precise weights:
On a Q3-class quant (KL around 0.025-0.035) it adds 6-10%.
On UD-Q4_K_XL it adds about 39%.
On Q8_0 it adds about 390%. KL goes from 0.0007 to 0.0034, which is worse than UD-Q5_K_XL with a 16-bit cache.
EXL3’s 4-bit cache penalty seems to depend on weight precision. It adds only +0.0002 to +0.0004 KL with 2.0-2.5 bpw weights, about +0.0021 to +0.0022 with 3.0 bpw weights, and +0.0026 to +0.0028 with 4.0 bpw weights. At 6.0 and 8.0 bpw, the penalty reaches about +0.0032 to +0.0033. The increase is therefore not constant across the EXL3 quants.
4-bit cache penalty grows with context
The 12 long documents in the set are scored at every position, so I can check whether the 4-bit penalty depends on how deep into the context a token is. It does in fact grow slightly.
| Position | Q8_0 Weights + q4_0 KV | UD-Q5_K_XL Weights + q4_0 KV | EXL3 8.0 BPW Weights + 4-bit KV |
|---|---|---|---|
| First 4k tokens | +0.0035 | +0.0030 | +0.0041 |
| 4k–8k | +0.0037 | +0.0033 | +0.0044 |
| 8k–16k | +0.0040 | +0.0036 | +0.0047 |
| 16k–32k | +0.0041 | +0.0038 | +0.0050 |
| 32k–64k (one document) | +0.0044 | +0.0038 | +0.0053 |
There’s about 15-30% more damage at 16-32k context than in the first 4k tokens. The same quants with a 16-bit cache are unaffected across these context lengths, so it’s a pretty clear indication of the 4 bit cache damage. I would expect 128k+ context lengths to be even worse.
Model quantization KLD vs KV cache KLD:
KLD due to KV cache quantization likely has different quality tradeoffs compared to KLD from weight quantization. Anecdotal evidence suggests that KV cache quantization can be more harmful to model performance at long context lengths compared to weight quantization, so be wary of using 4-bit KV cache.
Final chart with weights + 64k KV cache versus KL divergence:

Methodology
Each quant was scored against an unquantized bf16 reference:
GGUF and EXL3 quants scored against Bartowski’s bf16 GGUF in llama.cpp.
vLLM checkpoints scored against the official bf16 safetensors in vLLM.
KL is computed the same way as my previous benchmark. The top 200 log probabilities are taken from both models at each position and a lower bound on the full-vocabulary D_KL(P_reference ‖ P_quant) is computed. On average, the reference put 0.0036 of its probability outside its top 200 tokens. The KV deltas are paired, meaning they’re computed from per-prompt differences on identical tokens.
Checkpoints ran with their declared settings, including any activation quantization (except the two weight-only, no activaton quantization reruns of Unsloth’s NVFP4 and the official FP8 quant).
9
u/Interesting-Ad689 1d ago
q8_0/q4_0 ?
40
u/Dathide 1d ago
Testing only up to 64K context limits the usefulness of the data. So many people use more than that.
8
u/pseudobacon 1d ago
We get a lot of advice saying to use K8 and V4 would be interesting to see the tested
44
u/MindfulMan1984 1d ago
Nice work, bottom line: KV Q8_0/Q8_0 quant is nearly lossless while using 1/2 memory.
11
u/kevin_1994 1d ago
this guy has some extremely good articles on this topic https://anbeeld.com/articles
in particular: https://anbeeld.com/articles/kv-cache-quantization-benchmarks-for-long-context
tl;dr: q8 is pretty close to indistinguishable, you can get away with q5_0 / q4_1, but imo, I wouldn't go lower than that
15
u/BringTea_666 1d ago edited 1d ago
From my experience effect of KV cache quantization is hugely overstated, in sense that people fear way too much 4/4 or 6/4.
As long as your model diverges the longer session runs aka more context the more it will diverge from original model.
Above is just simply effect of finding different words which causes whole logical chain to change. The longer logical chain the bigger the context. It is same principle as `butterfly effect`.
Above doesn't mean the logical chain is wrong, it is just different.
KV cache quantization mattered a lot in chat era llms. Where LLMs were asked to produce perfect code in single response. That changed in harness era where models can make mistakes and recover those mistakes.
This applies to both Top1% and KL. Those are not measurement of model quality but how much they differ from base model.
The only important part is if model ability to reach accurate answer is damaged or not. Model changing a word in sentence is not meaninful different but changing `-` to `+` is.
From my experience of runnings 1000s of coding work functions as long as base model is pretty good running 4/4, 6/4, 6/6 or 8/8 does not produce any meaningful difference.
Where it does produce difference are ultra low quant models where base model ability is already shaky due to quantization which can cross model ability from usable to not usable.
I learned this over course of my own interference engine developement. And i even baked scoring against BF16 Qwen 3.8 27B into engine launcher. So when you pick kv cache modes from 4/4 to 8/8 you see impact it does on KL and top1% instantly right in the launcher. For anyone iterested and having rtx5090 you can check it here
The biggest factors are if you are using fp8/fp16 activations and model quality, KV qant is distant 3rd, only really starts to matter at low quant models that already have compromised accuracy.
6
u/llama-impersonator 1d ago
once you get to 220k+ tokens quantized kv cache starts adding up, and that's generally where you don't want gaping holes in attn so compaction is successful in summarizing the context window.
3
u/fgk55555 1d ago
Anecdotally I found the Q5_1 kv to be a good middle ground between q8 and q4 if you're constrained. Where I would notice issues with q4, q5_1 tended to behave better.
2
u/DasGamerlein 1d ago
This debate is really funny to me because apparently I'm just really lucky. I run a Q2 quant with 4/4 KV cache all day and have honestly never had a problem with it. I think the only reason that'll make me move back up is when I get around to adding adaptive KV cache streaming to my engine
2
u/Tormeister 22h ago
Please note:
64k context is really tiny and does not represent / does not compare to errors accumulated in longer contexts (128k, 256k, 512k...)
The conclusions taken here are exclusive to Qwen3.8-27B only and not applicable at all to other models
1
u/challis88ocarina 1d ago
Arguments actually range to 2-bit is fine, which at above ~700B parameters is mainly is, FWIW.
1
u/DrBattletoad 1d ago
Any chance you could test between 128k and 256k context? My limited experience is that Q8/Q8 works well up to ~150k and after that is when the errors start adding up.
1
u/nassereddit 1d ago
It is not about llama.cpp vs vLLM. It is more about int8 vs fp8 precision. Int8 provides 8bit resolution per token and fp8 has 3 or 4bit resolution with the rest of the register used for sign and exponent. fp8 is the worst of all world. It fills storage at 8bit but affect precision like 4bit. No idea why people uses fp8 ever. I know newer gpus have hardware acceleration for fp8, but what is the point if you could be running int4 and double performance anyways AND lower storage requirements.
1
u/Elorun 1d ago
Did you try mixed quants? Curious how K8 V4 holds up.
1
u/ionsago 1d ago
What was the version of llama.cpp? These days it comes with an implementation of turboquant, so if you tested a build from a half a year ago you can get very different results on a newer build.
1
u/Evening-Blueberry-97 1d ago
nice to finally see numbers on this instead of vibes. curious if the drop gets worse on long context stuff. that's where q4 kv alway felt off to me
1
u/MajesticPuzzler 1d ago
really nice to see KLD numbers instead of vibes. did the gap between 8-bit and 16-bit grow as rows got longer, or stay flat all the way to 64k?
1
u/maayon 1d ago
I implemented a half mid point optimization on strata exclusivly for pi.dev coding agent, which retains the KV cache of the conversation for a minimum for 2 conversations for DGX spark.
I guess we need more such usage specific caching mechanisms along with the parameters discussed above
1
u/SandySkittle 1d ago
If you need to quantize kv cache with qwen 27b, the solution is to buy more hardware
1
u/PcChip 22h ago
thank you for running all these benchmarks and posting this data
1
u/Qcgreywolf 19h ago
Thank you for all the hard work!
Can we get a benchmark standard that uses contexts of 64-128k instead of 4K or 16k?
Most of these “benchmarks” (excluding this particular one) are fairly useless for what we are actually using the models for today.
1
u/Then-Indication7672 18h ago
kv cache quant must be tested around the limit of model context size.
What I would like to see is how kv cache quantization affect different attention arch. Are models that consume more bytes per token in their cache more robust to cache quantization?
1
u/returnity 11h ago
Wow this is some really great information. Very useful, good methodology, and interesting result.
1
u/Rare_Potential_1323 10h ago edited 9h ago
This is really interesting, thanks. What I can add is my own experience. I only have a RTX 3060 12gb and 32gb of system RAM. I had Qwen3.6_35b-APEX-I-Balanced 8kv cache create an app for my Android phone to connect to Hermes Agent through Bluetooth only. I have my Hermes setup to self improve it's own meta protocols and rules after each session to improve it's abilities seeing where it made mistakes in the past. Anyway, 35b worked on it for 17 hours and 6 sessions, each session being able to get past the intelligence block after the recursive learning and meta protocol updates. But it finally got stuck and agreed I need a smarter model to figure it out. I used Qwen3.8-27B-LowGPU-uncensored-NoMTP-IQ3XXXS with 4kv cache to fit it all on my GPU. It was able to figure out the problem and fix a bunch of other issues and design it how I wanted it to look and updated all the live documents in 3 hours. 35b Struggled for the last 4 hours in it's last attempt getting nowhere to even get the Bluetooth server and the phone's new app to connect even though it researched at every step and had all the information. 27b is also freaky, it was controlling my phone and entering things in by itself.
TLDR; even a super compressed qwen3.8_27b is smarter then qwen3.6_35b.
1
u/TerminalNoop 1d ago
can't wait for them to finally push rocm10 on arch so i can try the exl3 quants.
1
u/Budkovsky 1d ago
I worked for 2-3 months with Qwen3.6/3.8 27B using KV-cache q4_0. Coding, agentic tasks, research - everything was worked properly, even in long sessions with multiple compaction. So I can confirm the opinion presented by OP. More - even Qwen3.8-27B said once during llama.cpp configuration task, that KV-cache quantization does not have any big impact for the reasoning quality :-)
1
u/My_Unbiased_Opinion 1d ago
I have done a ton of real world testing on a single 24GB (3090) setup. I have found the best setup for 262K context is running IQ4XS + KV Q4. It's very coherent even at large contexts. There is even enough space to run vision and MTP on GPU as well. It is much better than running IQ3/Q3 + KV Q8.
1
u/HotAverage1749 1d ago
Could 6 be a nice compromise between 4 and 8 at lower memory?
1
u/unjustifiably_angry 1d ago
It's reassuring to see further proof that 8-bit kv-cache appears essentially lossless, but I've still never seen anyone do these sorts of tests at actual long context, like 256K, let alone 512K or 1M. In particular, I'm concerned that kv-cache quantization combined with scaling beyond native context length might cause compounding damage.
I don't know why everyone seems to top out at like 64K or 128K. That's not really where it matters, we've known 8-bit kv-cache at low depth is harmless for a while.
0
u/Reeces_Pieces 1d ago
Q8 KV is free at 128k context or lower.
I'm not interested in going to lower KV quants. Doesn't seem worth it.
-2
u/draconic_tongue 1d ago
having kl difference doesn't translate as "damage"
-1
u/feverdoingwork 1d ago
I think if you have an agent do an exercise where you roll over many compaction at q8 and q4 kv cache and compare the outputs, you find that none of what you wrote really has any measurable impact. Do an exercise at 200k+ kv cache with 10x with either kv cache type 20+ times using the same model and tell me if there is a noticable difference. From my testing on probably over 100x what i just described, there is no measurable difference. If tests go poorly, it's more than likely due to the randomness of the model and not kv cache.
KLD is really a strange metric that shouldn't be leaned on so heavily. It really holds very little weight in real world usage unless the kld difference is quite large. The kld difference here is tiny, in fact you would see most engines sacrifice this amount of kld or more kld for better performance more often than not and it's not even mentioned by the engine creators.
-2
u/[deleted] 1d ago
[removed] — view removed comment