"""INT4-vs-NVFP4 KV-cache quantization sweep on Laguna-XS.2. For each layer's real K and V activations, measures reconstruction RMSE across the grid {nvfp4, int4} × {headdim-block, per-channel-block} × {absmax, mse}. The baseline cell (nvfp4 / headdim / absmax) is what vLLM's NVFP4 KV kernel ships today. Every cell has identical memory (4-bit data + one scale per 16 elements), so this isolates reconstruction quality. K and V are reported separately to expose any KIVI-style asymmetry (per-channel K, per-token V). Usage: python -m scripts.quant_sweep [--max-new 200] [--n-alphas 32] """ from __future__ import annotations import argparse import sys import torch from transformers import AutoModelForCausalLM, AutoTokenizer, DynamicCache sys.path.insert(0, "/home/alex/poolside-hackathon-kv-quant") from kv_quant import BLOCK, SWEEP_CELLS, SWEEP_BASELINE, sweep_tensor MODEL = "poolside/Laguna-XS.2" PROMPT = ( "Solve step by step. A train leaves city A at 60 km/h. Two hours later a second " "train leaves the same station on the same track at 90 km/h. How many hours after " "the second train departs will it catch up to the first train? Show your reasoning." ) def _cell_label(cell) -> str: return f"{cell[0]:<6} {cell[1]:<8} {cell[2]:<6}" def _print_table(title: str, abs_rmse: dict, ratio: dict) -> None: base = SWEEP_BASELINE print(f"\n{title}") print(f" {'format':<6} {'layout':<8} {'calib':<6} {'avg RMSE':>10} {'vs vLLM':>10}") print(f" {'-'*6} {'-'*8} {'-'*6} {'-'*10} {'-'*10}") for c in [base] + [c for c in SWEEP_CELLS if c != base]: tag = "baseline" if c == base else f"{(1.0 - ratio[c]) * 100.0:+.1f}%" print(f" {_cell_label(c)} {abs_rmse[c]:>10.5f} {tag:>10}") best = min(SWEEP_CELLS, key=lambda c: ratio[c]) print(f" best: {best[0]}/{best[1]}/{best[2]} " f"({(1.0 - ratio[best]) * 100.0:+.1f}% vs baseline)") def run_sweep(per_layer_kv, n_alphas, device): """per_layer_kv: list of (K, V) [n_kv, seq, head_dim]. Returns means + ratios.""" base = SWEEP_BASELINE k_abs = {c: [] for c in SWEEP_CELLS} k_rat = {c: [] for c in SWEEP_CELLS} v_abs = {c: [] for c in SWEEP_CELLS} v_rat = {c: [] for c in SWEEP_CELLS} n_used = 0 for K, V in per_layer_kv: if K.shape[1] < BLOCK: continue n_used += 1 ks = sweep_tensor(K.to(device), n_alphas) vs = sweep_tensor(V.to(device), n_alphas) for c in SWEEP_CELLS: k_abs[c].append(ks[c]); k_rat[c].append(ks[c] / max(ks[base], 1e-12)) v_abs[c].append(vs[c]); v_rat[c].append(vs[c] / max(vs[base], 1e-12)) mean = lambda d: {c: sum(x) / max(len(x), 1) for c, x in d.items()} return n_used, mean(k_abs), mean(k_rat), mean(v_abs), mean(v_rat) def main(): ap = argparse.ArgumentParser() ap.add_argument("--max-new", type=int, default=200) ap.add_argument("--n-alphas", type=int, default=32) args = ap.parse_args() print(f"[load] {MODEL} ...", flush=True) tok = AutoTokenizer.from_pretrained(MODEL) model = AutoModelForCausalLM.from_pretrained( MODEL, torch_dtype=torch.bfloat16, device_map="auto") model.eval() device = next(model.parameters()).device cfg = model.config print(f"[load] layers={cfg.num_hidden_layers} kv_heads={cfg.num_key_value_heads} " f"head_dim={getattr(cfg, 'head_dim', None)} device={device}", flush=True) msgs = [{"role": "user", "content": PROMPT}] input_ids = tok.apply_chat_template( msgs, add_generation_prompt=True, return_tensors="pt", return_dict=False, ).to(device) cache = DynamicCache() with torch.no_grad(): model.generate(input_ids, max_new_tokens=args.max_new, past_key_values=cache, use_cache=True, do_sample=False) per_layer = [(layer.keys[0].float().cpu(), layer.values[0].float().cpu()) for layer in cache.layers] seq = per_layer[0][0].shape[1] if per_layer else 0 print(f"[seq] {seq} tokens cached across {len(per_layer)} layers", flush=True) n_used, k_abs, k_rat, v_abs, v_rat = run_sweep(per_layer, args.n_alphas, device) print(f"\n{'='*56}") print(f"INT4 vs NVFP4 KV sweep — {n_used} layers, seq cropped to /{BLOCK}") print("All cells: identical memory (4-bit + 1 scale per 16 elems, ~3.56x vs BF16).") _print_table("KEY cache (avg RMSE over layers):", k_abs, k_rat) _print_table("VALUE cache (avg RMSE over layers):", v_abs, v_rat) if __name__ == "__main__": main()