Local LLMs / VIDEO COMPANION

KV Cache Quantization: What I Gained in Memory and What Changed in the Answers

8,000 graded answers on Qwen3.8-27B and Mistral Small 3.2: cache savings, answer churn, practical context and a build-specific mixed-cache slowdown.

BENCHMARK EDITIONSPaired synthetic retrieval; 7,800 core answers plus 200 MTP-off; separate guarded capacity checks

Video Source review

I’d start with Q8 KV cache on the two models I tested. It reduced the main cache allocation by about 47%, with no detectable accuracy difference after correcting for multiple comparisons. Q4 saved about 72% of the cache memory, but changed more individual answers. That’s a useful trade when context is running into your VRAM limit, provided you check the behavior your workflow depends on.

I graded 8,000 answers on one RTX 5090. The result wasn’t that every setting behaved the same. Scores were close, individual answers moved, and one mixed-cache setting ran noticeably slower. Those are three different things to consider before changing a dropdown.

I changed the cache while keeping each model’s weights fixed

The KV cache stores the keys and values an attention layer needs from text the model has already read. Keeping them avoids recalculating that work for each new token. The cache grows with context, while the model weights stay a fixed cost.

Cache quantization stores those keys and values with fewer bits. It changes a different part of the system from weight quantization. I kept both models’ main weights at Q6_K and varied their main KV cache format. Some runs used different allocated context sizes or boot sessions, which limits what the speed comparisons can isolate.

Main KV cache formats and memory savings
SettingKeys / valuesMain cache memory saved versus F16
F1616-bit floating point / 16-bit floating pointReference
Q8Q8 / Q846.9%
Q4Q4 / Q471.9%
K8V4Q8 / Q459.4%

The models were Unsloth’s Qwen3.8-27B UD-Q6_K and Mistral Small 3.2 24B Instruct 2506 Q6_K. Qwen is a hybrid: 16 of its 64 layers use full attention, with recurrent layers making up the rest. Mistral uses attention in all 40 layers. That gives them very different cache costs.

I used llama.cpp b11580, the Windows CUDA 13.4 build, on a display-attached RTX 5090 with 32 GB of VRAM, an i9-13900K and 128 GB of RAM. Flash attention and full GPU offload were enabled. Sampling was greedy, thinking was off, and answers were capped at 48 tokens.

Qwen also used an MTP draft head, which proposes tokens ahead for the main model to check. Its draft cache stayed F16 throughout the main comparison. Mistral ran without it.

The tests measured precise lookup and tracking the latest value

I used two synthetic document tasks. The asset registry asks the model to retrieve a specific field or identify a record from a site and room. Similar records and near-collision identifiers make guessing risky. The config change log asks for the final value of a setting after several updates, with older values and similar settings as distractions.

Every cache setting for a given model received the same documents and questions. Document lengths were measured with that model’s tokenizer. Each model/cache/context/task cell had 100 questions, spread evenly across five depth zones. At 4K, that meant 20 documents with five questions each; longer buckets used four documents with 25 questions each.

The buckets were 4K, 16K, 32K, 64K and 128K. Those labels describe the test sizes: the 128K bucket targeted a document of 120,000 tokens, leaving room for the instructions and answer. In the context figures below, K means 1,024 tokens.

Grading used a fixed parser and exact-match comparison, with no AI judge. The totals were 7,800 core answers plus 200 answers in an MTP-off check. Mistral F16 at 128K remained unavailable because its allocation exceeded this card’s VRAM. Priming requests, fit checks and repeatability checks weren’t counted as scored answers.

I found no detectable accuracy difference after correction

Across 62 paired accuracy comparisons, zero survived Holm correction. That correction accounts for running many comparisons, so isolated small p-values don’t become a headline just because I tested enough combinations. Two comparisons were below the usual threshold before correction; neither remained there afterward.

I also pooled the paired results over the buckets where F16 was available. These intervals resample whole documents, so questions sharing a document aren’t treated as completely independent observations.

Pooled paired accuracy differences versus F16
ModelCache versus F16Paired questionsAccuracy difference, percentage points95% document-bootstrap interval
Qwen3.8-27BQ81,000-0.70-1.76 to +0.33
Qwen3.8-27BQ41,000+0.40-1.07 to +1.91
Qwen3.8-27BK8V41,000+0.10-0.87 to +1.08
Mistral Small 3.2Q8800-0.13-0.83 to +0.63
Mistral Small 3.2Q4800+0.38-2.00 to +2.57
Mistral Small 3.2K8V4800-0.13-1.56 to +1.33

Qwen includes 4K through 128K; Mistral includes 4K through 64K. Every interval includes zero. That supports no detectable difference on these tests, while leaving room for small effects. It doesn’t establish equivalence, and pooling can conceal differences on a particular task or context size.

For a concrete long-context example, Qwen’s 128K asset accuracy was 97% with F16, 95% with Q8, 98% with Q4 and 97% with K8V4. On config tracking, those scores were 67%, 64%, 68% and 66%. There were 100 questions behind each percentage, so I wouldn’t read a one-point gap as a practical ranking.

The much larger descriptive change was the difficulty of the task at longer context. Mistral F16 config accuracy fell from 78% at 4K to 36% at 16K. Choosing a different cache format didn’t resolve that drop.

Similar scores still hid different answers

Answer churn is the share of questions whose parsed answer changes relative to F16, whether either answer is correct. Accuracy only counts the correct answers. A setting can fix one question, break another and change several wrong answers without moving its total score much.

Q8 churn reached at most 5% per cell on Mistral and 8% on Qwen. Q4 moved more answers: on Mistral it changed 20% at 64K on the asset task and 21% at 32K on config tracking. Neither of those comparisons had format failures muddying the result.

In the limited repeat check, 25 F16/32K asset questions from one document per model matched byte for byte. Both separate five-question continuity checks also matched. That’s observed agreement on those samples, not a guarantee of zero variation across every configuration or workflow.

If your application depends on a particular response, a stable average score is only part of the decision. I’d test those cases again after changing cache precision.

Formatting also explains some of the apparent score improvements. Across the 8,000 answers, 145 failed the required format. Of those, 39 stopped at or reached the output cap; 106 lacked a parseable answer line without that cap classification.

Format failures in the two concentrated task cells
Concentrated format failuresF16Q8Q4K8V4
Qwen 4K config121127
Mistral 32K asset3230833

Qwen Q4 scored 94% versus F16’s 86% in that config cell; Mistral Q4 scored 73% versus F16’s 62% in that asset cell. Fewer format failures account for much of those gaps. They don’t establish better retrieval from Q4, and neither comparison survived correction.

A separate parser sensitivity check changed zero outcomes. I kept the official grades. The test therefore captures both retrieving the value and delivering it in the required format.

The cache savings are substantial, but total VRAM savings are smaller

At an allocated context of 131,072 tokens, the main cache requires the following memory, calculated from the verified per-token cache sizes. The Mistral F16 entry was unavailable for the accepted benchmark. Allocations here use GiB, with 1 GiB equal to 1,024 MiB; the graphics card is sold as a 32 GB model.

Main KV cache requirement at 131,072 tokens
CacheQwen3.8-27B main cacheMistral Small 3.2 main cache
F168.0 GiB20.0 GiB
Q84.3 GiB10.6 GiB
Q42.3 GiB5.6 GiB
K8V43.3 GiB8.1 GiB

Qwen’s separate F16 draft cache isn’t included in that table. The weights, recurrent state and compute workspace also need memory. That’s why a 72% reduction in the main cache doesn’t mean 72% less total VRAM.

For Qwen at that context allocation, the logged CUDA buffer total fell from 29.8 GiB with F16 to 24.5 GiB with Q4, a reduction of about 17.8%. Those are allocated model/runtime buffers, excluding desktop use; they aren’t the GPU’s sampled peak usage.

Mistral made the context trade especially clear. Q4 at 131,072 tokens allocated about 23.8 GiB, compared with 27.8 GiB for F16 at 65,536 tokens. That’s twice the allocated context with about 4.0 GiB less in CUDA buffers.

Quantization gave me more room for context

These are the verified practical context allocations under my guarded setup. They are not exhaustive hardware limits, and the larger allocations were checked with a short input rather than a full document at their limit.

Verified practical context allocations under this setup
ModelCacheVerified contextLimiting condition
Mistral Small 3.2F1677,824 tokens / 76KVRAM budget
Mistral Small 3.2Q8131,072 tokens / 128KModel's trained limit
Mistral Small 3.2Q4131,072 tokens / 128KModel's trained limit
Mistral Small 3.2K8V4131,072 tokens / 128KModel's trained limit
Qwen3.8-27BF16131,072 tokens / 128KVRAM budget
Qwen3.8-27BQ8208,896 tokens / 204KVRAM budget
Qwen3.8-27BQ4262,144 tokens / 256KModel's trained limit
Qwen3.8-27BK8V4253,952 tokens / 248KVRAM budget

Scope: practical max under this setup (display-attached, fresh-reboot baseline); allocation + 4K speed verified; long-context accuracy not tested beyond 128K.

Each accepted capacity launch retained at least 1,640 MiB of logged buffer-plus-baseline headroom and passed the short-input speed screen. Compute workspace also grew with context, so predicting capacity from weights and cache alone was insufficient.

The desktop mattered too. An early Qwen F16/128K launch loaded but failed the speed screen with only 46.6 MiB of logged headroom. After a fresh reboot, the unloaded desktop baseline was 423 MiB and the configuration passed qualification. Loading successfully wasn’t enough to make a run usable. Memory pressure was a plausible explanation for the earlier slowdown, but I didn’t isolate its cause.

Mixed K8V4 hit a slower generation path in this build

Reading the documents and generating the answers showed different behavior. For Mistral through 64K, cold document-processing medians stayed within roughly 3.1% of F16. Generation exposed a much larger K8V4 penalty as context grew.

Mistral generation rate in tokens per second
Mistral context bucketF16 generationQ8 generationQ4 generationK8V4 generation
4K72.3 tok/s69.6 tok/s69.6 tok/s65.7 tok/s
16K66.4 tok/s65.1 tok/s65.1 tok/s54.4 tok/s
32K59.8 tok/s59.5 tok/s59.2 tok/s48.1 tok/s
64K49.7 tok/s51.0 tok/s50.6 tok/s34.1 tok/s
128KUnavailable39.6 tok/s38.7 tok/s21.5 tok/s

These are median rates from short answers, not a sustained long-output benchmark. At 128K, K8V4 was about 46% slower than Q8. That comparison spans boot sessions. At the 64K test bucket, K8V4 was about 33% slower than Q8 in the same session, but K8V4 allocated 131,072 tokens while Q8 allocated 65,536.

The tested b11580 CUDA build logged that its mixed Q8-key/Q4-value vector flash-attention kernel was missing and that keys and values were being converted to F16 instead. Flash attention remained enabled and every model layer stayed on the GPU.

That extra conversion is a likely major contributor to the slowdown. I didn’t profile its exact share of latency or test a rebuilt binary, so I can’t promise how much speed compiling the mixed kernel would recover. This finding applies to the tested build, not every current llama.cpp package or app bundling it.

Qwen’s matched Q8 and Q4 caches had native kernels, yet their 64K generation medians were about 103 tok/s against F16’s 116 tok/s. F16 allocated 65,536 tokens; Q8 and Q4 allocated 131,072, so this also isn’t an isolated cache-precision comparison. The missing mixed-pair kernel doesn’t explain these matched-cache rates. The 128K F16 comparison also came from a later boot session. I wouldn’t turn these measurements into a claim that quantized cache always preserves generation speed.

MTP was useful, with a comparison caveat

On the Qwen F16/32K questions, the MTP-on run generated at a median 124.4 tok/s, versus 55.6 tok/s with MTP off: an observed 2.24x ratio. All 200 paired answers agreed at both parsed and byte level.

MTP on allocated 65,536 tokens; MTP off allocated 36,864, and the runs came from different boot sessions. That makes the ratio an observed comparison rather than a clean measurement of MTP alone. It also doesn’t establish that MTP will preserve every answer on other workloads.

What I’d use, and where I’d test again

For these models, Q8 is my starting point: substantial cache savings and relatively little answer churn. Q4 is my choice when I need more room, with a check of the specific responses I rely on. F16 remains useful when VRAM allows it and I want the reference behavior. I’d avoid K8V4 on the tested build unless I had verified its kernel support and performance.

The limits of this result matter. I tested two Q6_K model packages, one GPU and one runtime build, using synthetic retrieval tasks with short answers. This doesn’t establish behavior on coding, extended reasoning, long outputs, other weight formats, other runtimes or accuracy above 128K. Four documents per longer-context task cell also provide limited coverage, even with 100 questions. The repeat checks establish observed agreement on their samples, not a universal zero-noise guarantee.

For my use, the memory savings are worth testing. I’d start with Q8, move to Q4 when context needs the space, and check both correctness and answer stability on the work I actually do.

In the companion KV-cache video, I walk through the results and memory tradeoffs. Tell me in the YouTube comments which model and cache setting you’re using, and subscribe if you’d like more local-model tests like this one.

BRING YOUR SETUP TO THE CONVERSATION

What are you running?

Watch the comparison, then share your hardware and workload in the YouTube comments.

Watch & discuss on YouTube (opens in a new tab)
Back to the blog

DEEPWAKELABS