veloxquant_mlx.quantizers.cachegen module¶
CacheGen quantizer — delta-locality group quant + entropy-coded byte model.
Inspired by “CacheGen: KV Cache Compression and Streaming for Fast Large Language Model Serving” (Liu et al., SIGCOMM 2024, arXiv:2310.07240). Documented as “CacheGen-adapted (VeloxQuant-MLX implementation)” — not a faithful port.
What CacheGen adds that the repo did not have: entropy coding of the quantized KV. Every other method in the suite packs codes at a fixed bit-width; CacheGen exploits the KV cache’s distributional structure to encode the codes into a smaller bitstream. Its three observations:
Token-wise locality — adjacent tokens’ KV vectors are similar, so the delta between consecutive tokens’ quantized codes is concentrated near zero and is far more compressible than the raw codes.
Layer-wise sensitivity — deeper layers tolerate coarser quantization; CacheGen spends fewer bits on later layers.
Arithmetic coding — the delta symbol stream, being low-entropy, is compressed with an entropy coder down toward its Shannon entropy.
Channel/layer grouping — fitting a separate symbol distribution per channel (§5.1.3) yields much lower entropy than pooling all channels together; layer separation is already implicit (each cache instance owns one layer).
- Adaptation:
The reconstruction path is the existing asymmetric min/max group quant — the values the model sees are identical to KIVI-style quant (no extra loss from the entropy layer; entropy coding is lossless over the codes).
We do not ship a per-step arithmetic codec (a serial range coder would bottleneck MLX’s parallel decode and add no quality). Instead we model the entropy-coded byte size from the measured Shannon entropy of the delta-coded symbol stream — an honest lower-ish bound on what a real arithmetic coder achieves, reported through
compressed_*_bytes.Layer-wise bit selection is exposed via config (
cachegen_bitsplus an optional per-depth schedule applied by the builder).
This module holds the pure numerics: group quant exposing integer codes, token-delta transform, and the entropy/byte estimator. The cache wrapper owns the per-layer state and accounting.
- class veloxquant_mlx.quantizers.cachegen.CodeStream(codes, scale, zero, n_rows, bits)[source]¶
Bases:
NamedTupleQuantized codes plus the params needed to dequantize them.
- Variables:
codes – [n_groups, group_size, D] fp32 integer codes in [0, 2^bits-1].
scale – [n_groups, 1, D] fp32 per-group step.
zero – [n_groups, 1, D] fp32 per-group min.
n_rows – int original (pre-pad) token count.
bits – int bit-width.
- Parameters:
- codes: mlx.core.array¶
Alias for field number 0
- scale: mlx.core.array¶
Alias for field number 1
- zero: mlx.core.array¶
Alias for field number 2
- veloxquant_mlx.quantizers.cachegen.quantize_to_codes(x, bits, group_size=32)[source]¶
Asymmetric min/max group quant exposing the integer codes.
- Parameters:
- Return type:
- Returns:
CodeStream (codes + dequant params).
- veloxquant_mlx.quantizers.cachegen.dequant_codes(stream)[source]¶
Reconstruct fp16 [n_rows, D] from a CodeStream.
- Return type:
array- Parameters:
stream (CodeStream)
- veloxquant_mlx.quantizers.cachegen.token_delta(codes_flat)[source]¶
Token-wise delta of a flattened code matrix [N, D].
Row 0 is kept as-is; row i (i>0) becomes
codes[i] - codes[i-1]. Because adjacent tokens’ KV are similar, the deltas concentrate near zero — the locality CacheGen exploits. Reversible: a prefix-sum recovers the codes.- Return type:
array- Parameters:
codes_flat (mlx.core.array)
- veloxquant_mlx.quantizers.cachegen.symbol_entropy_bits(symbols)[source]¶
Shannon entropy (bits/symbol) of an integer symbol array.
This is the per-symbol size an ideal arithmetic coder approaches. Computed over the empirical distribution of the (delta) code values.
- Return type:
- Parameters:
symbols (mlx.core.array)
- veloxquant_mlx.quantizers.cachegen.entropy_coded_bytes(stream, use_delta=True, per_channel=True)[source]¶
Estimate the entropy-coded size (bytes) of a CodeStream’s codes.
Models a real arithmetic coder by measuring the Shannon entropy of the (optionally delta-transformed) code symbols and multiplying by the symbol count. Params (scale/zero) are added at fp16 like every other method.
- Parameters:
stream (
CodeStream) – the quantized CodeStream.use_delta (
bool) – apply the token-delta transform before measuring entropy.per_channel (
bool) – fit a separate probability distribution per channel before measuring entropy (§5.1.3: grouping by channel/layer gives much lower entropy than pooling all channels together — the paper reports up to 53% smaller bitstreams from this). If False, all channels are pooled into one distribution (the coarser estimate).
- Return type:
- Returns:
Estimated compressed size in bytes (codes via entropy + fp16 params). Capped at the fixed-width packed size: a real arithmetic coder never stores more than the raw codes (it falls back to raw packing when the symbol stream is incompressible), so neither does this estimate.
- veloxquant_mlx.quantizers.cachegen.fixed_width_bytes(stream)[source]¶
Naive fixed-bit-width packed size (bytes) for the same codes — baseline.
- Return type:
- Parameters:
stream (CodeStream)
- veloxquant_mlx.quantizers.cachegen.layer_group_bits(n_layers, base_bits, n_groups=3)[source]¶
Per-layer bit-width schedule from the paper’s layer-wise sensitivity insight (§5.1.2/§5.2).
Splits the
n_layerstransformer layers inton_groupscontiguous groups (earliest first) and assigns progressively fewer bits to deeper groups:base_bitsto the first third,base_bits - 1to the middle third,base_bits - 2to the last third (floored at 2 bits). This mirrors the paper’s finding that output quality is far more sensitive to precision loss in shallow layers than in deep ones (Figure 4), so shallow layers get conservative (higher-bit) quantization and deep layers get coarser quantization.- Parameters:
- Return type:
- Returns:
Length-
n_layerslist of per-layer bit-widths, non-increasing with depth.
- veloxquant_mlx.quantizers.cachegen.cachegen_quant_dequant(x, bits, group_size=32)[source]¶
Drop-in quant→dequant (values identical to plain group quant).
The entropy layer is storage-only; the reconstructed tensor is exactly the group-quant reconstruction, so this is a drop-in for
_group_quant_dequant.
- veloxquant_mlx.quantizers.cachegen.quantize_to_codes_batched(x, bits, group_size=32)[source]¶
Batched
quantize_to_codesover a leadingG = B*Haxis.- Parameters:
- Return type:
- Returns:
CodeStream whose fields carry the extra leading
Gaxis –codes/scale/zeroare[G, n_groups, group_size (or 1), D].
- veloxquant_mlx.quantizers.cachegen.dequant_codes_batched(stream)[source]¶
Batched
dequant_codes: reconstruct fp16[G, n_rows, D].- Return type:
array- Parameters:
stream (CodeStream)
- veloxquant_mlx.quantizers.cachegen.token_delta_batched(codes_flat)[source]¶
Batched
token_deltaover[G, N, D]— delta along axis 1.- Return type:
array- Parameters:
codes_flat (mlx.core.array)
- veloxquant_mlx.quantizers.cachegen.entropy_coded_bytes_batched(stream, use_delta=True, per_channel=True)[source]¶
Batched
entropy_coded_bytesover the CodeStream’s leadingGaxis.Same estimate as
entropy_coded_bytes(), computed for allGheads (and, ifper_channel, allDchannels) in one vectorized pass with a single final host read, instead ofentropy_coded_bytescalled once per head with its own internal per-channel Python loop and two.item()calls per channel (G * Dhost syncs total there).- Return type:
- Returns:
Length-
Glist of estimated compressed sizes in bytes (codes via entropy + fp16 params), each capped at that head’s fixed-width size.- Parameters:
stream (CodeStream)
use_delta (bool)
per_channel (bool)
- veloxquant_mlx.quantizers.cachegen.fixed_width_bytes_batched(stream)[source]¶
Batched
fixed_width_bytesover the CodeStream’s leadingGaxis.- Return type:
- Parameters:
stream (CodeStream)