llama.cpp/tools/kv-mean-center #
Compute a per-layer, per-(kv-head, channel) K-cache mean-centering bias from a text calibration
corpus, for use with the --kv-mean-center flag (GGML_TYPE_Q4_0 K cache only).
See docs/kv-mean-center.md for the full description of the
feature. In short: GGML_TYPE_Q4_0 is a symmetric quantizer, so a K channel with a real,
consistent nonzero mean across tokens wastes some of its dynamic range encoding that constant
bias. Subtracting a fixed per-(head, channel) bias before quantization removes that waste; because
the same bias is subtracted from every cached key, it shifts every attention logit in a query's row
by the same constant, which softmax is invariant to. Nothing else about attention changes.
This tool measures that bias by running calibration text through the model and averaging the K values right before they would be written into the cache.
Usage #
./llama-kv-mean-center \
-m model.gguf -f calibration-data.txt -o kv-mean-center.gguf \
[-c 512] [--chunks N] [-ngl 99]
-m | --modelthe model to calibrate against (mandatory).-f | --filea plain text calibration corpus (mandatory). A few hundred KB of representative text is enough to get a stable per-channel mean; the same kind of corpus used forllama-imatrixworks well here too.-o | --output-filewhere to write the bias file (default:kv-mean-center.gguf).-c | --ctx-sizechunk size in tokens (default: 512). Each chunk is scored independently with a cleared cache, matchingllama-imatrix's chunking.--chunksmaximum number of chunks to process (default: all available).-ngl | --n-gpu-layersoffload layers to GPU for faster calibration.
If you do not have a calibration corpus at hand, make-calib-corpus.sh generates one from the
model itself, so no external data file is needed:
./tools/kv-mean-center/make-calib-corpus.sh \
-s ./llama-server -m model.gguf -o calib-corpus.txt
It starts a temporary llama-server, generates one response per built-in seed prompt (a mix of
expository, narrative, technical, code and dialogue prompts) with thinking disabled, and refuses
to write a corpus that looks degenerate (checked via gzip compression ratio). The per-channel K
mean is dominated by model-intrinsic channel structure rather than corpus content, so
self-generated text measures the same bias as an external corpus: in an A/B test, a self-generated
corpus and a standard multi-domain calibration set produced biases agreeing to within the
calibration sampling noise (cosine similarity above 0.95 on every layer).
The output is a small GGUF file with one F32 tensor per layer, named kv_bar.blk.<il>.k. Load it
at inference time with:
./llama-cli -m model.gguf -ctk q4_0 --kv-mean-center kv-mean-center.gguf -p "..."
--kv-mean-center requires --cache-type-k q4_0; loading fails with a clear error otherwise
(centering is currently only implemented/validated for GGML_TYPE_Q4_0).
Interaction with the Hadamard K-cache rotation: calibrate with matching cache settings #
This fork's optional Hadamard rotation is active for quantized K caches whose head dimension is a
multiple of 64 (unless LLAMA_ATTN_ROT_DISABLE=1). The bias measured by this tool lives in
whatever basis the calibration run's K cache used: the collector taps the exact tensor cpy_k()
writes, after any rotation. Since the rotation is gated on the K cache being quantized, a
calibration run with the default F16 cache measures the unrotated basis, and that bias must not be
applied to a rotated (quantized) cache: measured end to end the mismatch is worse than either
feature alone, because the subtracted vector no longer matches the channel means of the basis
being quantized.
Rule: calibrate with the same --cache-type-k (and LLAMA_ATTN_ROT_DISABLE, if any) that you
will serve with. For the common case that is:
./llama-kv-mean-center -m model.gguf -f calib.txt -o kv-mean-center.gguf -ctk q4_0 [-fa on]
The tool records the calibration basis in the output file (kv_mean_center.k_rot) and the loader
refuses a bias whose basis does not match the inference-time rotation state, so a mismatch fails
fast instead of silently degrading quality. Measured on a hybrid-attention model, Q4_0 K cache,
logit KL divergence vs an F16-cache baseline over 12x512-token held-out chunks:
| configuration | mean KLD |
|---|---|
| rotation alone (uncentered) | 0.00144 |
| centering alone (rotation disabled, matched basis) | 0.00149 |
| rotation + pre-rotation bias (the mismatch, now rejected) | 0.0020-0.0021 |
rotation + rotated-basis bias (calibrated with -ctk q4_0) |
0.00111 |
The two features compose once the basis matches, and the composed configuration is the best of the four.