veloxquant_mlx.quantizers.zipcache module¶
ZipCache-adapted quantizer — saliency-adaptive per-token mixed-precision.
Inspired by “ZipCache: Accurate and Efficient KV Cache Quantization with Salient Token Identification” (He et al., NeurIPS 2024, arXiv:2405.14256). Documented as “ZipCache-adapted (VeloxQuant-MLX implementation)” — not a faithful port.
What ZipCache adds that the repo did not have: per-token mixed bit-width within the quantized space. Three existing methods use the key-norm proxy for token importance; this is the fourth use and the first with a different decision:
KIVI-Sink — top-k norm tokens → fp16 (binary: quantized vs not) AdaKV-proxy — mean norm per head → head-level budget reallocation Kitty — per-channel variance → channel-level bit allocation ZipCache-adapted → per-token norm → hi_bits vs lo_bits (both quantized)
Every token stays quantized. High-norm tokens (salient, top hi_fraction
by key L2-norm) are quantized at hi_bits; the rest at lo_bits. The
effective average key rate is hi_frac·hi_bits + (1-hi_frac)·lo_bits bits
per element — explicitly between lo_bits and hi_bits.
Honest proxy limitation: the paper’s true saliency signal is the normalized attention score, which is not observable by a cache wrapper. Key L2-norm is a proxy: attention-sink tokens (highest importance) also exhibit large key norms. This proxy is weaker than true attention scores — reported plainly, never hidden. See the KIVI-Sink docs for the proxy derivation.
- Adaptation decisions:
Per-group min/max quantization (not per-channel as in the paper’s ideal). Reuses the same group-quant logic as KIVI/CacheGen/GEAR for consistency and test-coverage inheritance.
Values are quantized uniformly at
hi_bits(no saliency routing for values — the paper focuses on keys;quantize_values=Truecan be set to compress values too at a single bit-width).Saliency is computed once per incoming block. No retroactive reclassification of already-quantized tokens.
This module holds the pure numerics: norm computation, saliency masking, per-group channel quant, full compress/reconstruct, and honest byte accounting. The cache wrapper owns the per-layer prefill/decode state.
- class veloxquant_mlx.quantizers.zipcache.ZipCacheState(hi_codes, hi_scales, hi_zeros, lo_codes, lo_scales, lo_zeros, hi_mask, hi_bits, lo_bits, seq_len, head_dim, group_size)[source]¶
Bases:
NamedTupleA ZipCache-compressed key or value matrix with per-token bit routing.
- Variables:
hi_codes – [n_hi, D] uint8 high-bit key codes for salient tokens.
hi_scales – [n_hi_groups, D] fp32 per-group scale (hi-bit path).
hi_zeros – [n_hi_groups, D] fp32 per-group zero-point (hi-bit path).
lo_codes – [n_lo, D] uint8 low-bit key codes for non-salient tokens.
lo_scales – [n_lo_groups, D] fp32 per-group scale (lo-bit path).
lo_zeros – [n_lo_groups, D] fp32 per-group zero-point (lo-bit path).
hi_mask – [S] bool saliency mask; True = salient (hi-bit) token.
hi_bits – int bit-width for salient tokens.
lo_bits – int bit-width for non-salient tokens.
seq_len – int original token count (= S).
head_dim – int feature dimension (= D).
group_size – int token group size used for min/max quantization at compress time; must be reused by
zipcache_reconstructfor the dequant grouping to match.
- Parameters:
- hi_codes: mlx.core.array¶
Alias for field number 0
- hi_scales: mlx.core.array¶
Alias for field number 1
- hi_zeros: mlx.core.array¶
Alias for field number 2
- lo_codes: mlx.core.array¶
Alias for field number 3
- lo_scales: mlx.core.array¶
Alias for field number 4
- lo_zeros: mlx.core.array¶
Alias for field number 5
- hi_mask: mlx.core.array¶
Alias for field number 6
- veloxquant_mlx.quantizers.zipcache.token_key_norms(keys)[source]¶
L2 norm of each token’s key vector,
[S, D] → [S]fp32.- Return type:
array- Parameters:
keys (mlx.core.array)
- veloxquant_mlx.quantizers.zipcache.saliency_mask(norms, hi_fraction)[source]¶
Top-
hi_fractiontokens by key-norm are marked salient (True).- Parameters:
norms (
array) –[S]fp32 key L2-norms.hi_fraction (
float) – Fraction of tokens to mark as salient (0 → all lo-bit; 1 → all hi-bit).
- Return type:
array- Returns:
[S]bool array; True = salient token → hi_bits path.
- veloxquant_mlx.quantizers.zipcache.channel_quant(x, bits, group_size=32)[source]¶
Asymmetric per-group min/max quantization along the token axis.
Groups partition the token (row) axis into blocks of
group_size. Within each group, a shared (scale, zero) is fitted per channel.
- veloxquant_mlx.quantizers.zipcache.channel_dequant(codes, scales, zeros, group_size=32)[source]¶
Reconstruct
[N, D]fp32 from codes + per-group (scales, zeros).- Return type:
array- Parameters:
codes (mlx.core.array)
scales (mlx.core.array)
zeros (mlx.core.array)
group_size (int)
- veloxquant_mlx.quantizers.zipcache.zipcache_compress(x, hi_bits=4, lo_bits=2, hi_fraction=0.2, group_size=32)[source]¶
Compress
[S, D]with per-token saliency-adaptive mixed bit-width.- Parameters:
x (
array) –[S, D]fp16/fp32 key or value matrix for one head.hi_bits (
int) – Bit-width for salient (high-norm) tokens.lo_bits (
int) – Bit-width for non-salient tokens.hi_fraction (
float) – Fraction of tokens routed to hi_bits (by key L2-norm).group_size (
int) – Token group size for min/max quantization.
- Return type:
- Returns:
ZipCacheStatecarrying split codes and the saliency mask.
- veloxquant_mlx.quantizers.zipcache.zipcache_reconstruct(state)[source]¶
Reconstruct fp16
[S, D]from a ZipCacheState.Dequantizes the hi and lo groups and scatters them back into their original token positions using the stored saliency mask.
- Return type:
array- Parameters:
state (ZipCacheState)
- veloxquant_mlx.quantizers.zipcache.zipcache_bytes(state, group_size=None)[source]¶
Honest stored size (bytes) of a ZipCacheState.
Counts: packed codes (ceil(n * D * bits / 8)) + fp32 params (scale + zero). The saliency mask is stored as bool (1 byte/token).
group_sizedefaults tostate.group_size(the size the state was compressed with); pass it only to model a different grouping (#641).- Return type:
- Parameters:
state (ZipCacheState)
group_size (int | None)
- veloxquant_mlx.quantizers.zipcache.base_only_bytes(S, D, bits, group_size=32)[source]¶
Uniform baseline size: all S tokens at a single bit-width (fp16 params).