Download reference.py from CompressedGemma/HPC-Quantize-V2: direct link, hf CLI and curl.
- Browser
- Download file 4.91 kB
-
https://huggingface.co/CompressedGemma/HPC-Quantize-V2/resolve/main/reference.py
- Command line
-
hf download hf://CompressedGemma/HPC-Quantize-V2/reference.py
-
curl -L -o reference.py https://huggingface.co/CompressedGemma/HPC-Quantize-V2/resolve/main/reference.py
4.91 kB
| """Faithful Python port of the original C factored solver. | |
| This module is intentionally not on the production path. It exists so the | |
| V2 improvements can be measured against the exact reference trajectory: | |
| fixed six-iteration 1-D Lloyd, single range initialisation, no fp16-domain | |
| polish and no spectral shaping inside the solver. | |
| """ | |
| from __future__ import annotations | |
| import numpy as np | |
| from .config import HPCConfig | |
| from .fp16 import from_fp16_bits, nearest_int, to_fp16_bits | |
| from .q2k import QK_K, codes_from_params, dequantize_params, weighted_sse | |
| from .spectral import objective, spectral_penalty | |
| def reference_factor_1d(v, w, nmax: int = 15): | |
| v = np.maximum(np.asarray(v, dtype=np.float64), 0.0) | |
| w = np.maximum(np.asarray(w, dtype=np.float64), 0.0) | |
| vmax = float(np.max(v)) | |
| if vmax < 1.0e-30: | |
| return 0.0, np.zeros(v.size, dtype=np.uint8) | |
| d = vmax / nmax | |
| for _ in range(6): | |
| codes = np.clip(nearest_int(v / d), 0, nmax) | |
| den = float(np.sum(w * codes * codes)) | |
| if den < 1.0e-30: | |
| break | |
| dn = float(np.sum(w * v * codes) / den) | |
| conv = abs(dn - d) <= 1.0e-7 * abs(d) + 1.0e-30 | |
| d = dn | |
| if conv: | |
| break | |
| codes = np.clip(nearest_int(v / d), 0, nmax) | |
| return d, codes.astype(np.uint8) | |
| def reference_sub_ls(x, w, codes): | |
| NS = 16 | |
| q = np.asarray(codes, dtype=np.float64).reshape(NS, 16) | |
| xb = np.asarray(x, dtype=np.float64).reshape(NS, 16) | |
| wb = np.asarray(w, dtype=np.float64).reshape(NS, 16) | |
| s = np.zeros(NS) | |
| t = np.zeros(NS) | |
| for j in range(NS): | |
| ww, qq, xx = wb[j], q[j], xb[j] | |
| Sqq = float(np.sum(ww * qq * qq)) | |
| Swq = float(np.sum(ww * qq)) | |
| Sw = float(np.sum(ww)) | |
| Sqx = float(np.sum(ww * qq * xx)) | |
| Sx = float(np.sum(ww * xx)) | |
| det = Sqq * Sw - Swq * Swq | |
| if det > 1.0e-30: | |
| sj = (Sqx * Sw - Swq * Sx) / det | |
| tj = (sj * Swq - Sx) / Sw | |
| else: | |
| sj = tj = 0.0 | |
| if sj < 0.0: | |
| sj = 0.0 | |
| if tj < 0.0: | |
| tj = 0.0 | |
| sj = Sqx / Sqq if Sqq > 1.0e-30 else 0.0 | |
| if sj < 0.0: | |
| sj = 0.0 | |
| s[j], t[j] = sj, tj | |
| return s, t | |
| def reference_solve(x, w, cfg: HPCConfig, use_spectral: bool) -> tuple[float, float]: | |
| NS = 16 | |
| xb = np.asarray(x, dtype=np.float64).reshape(NS, 16) | |
| wb = np.asarray(w, dtype=np.float64).reshape(NS, 16) | |
| s = np.zeros(NS) | |
| t = np.zeros(NS) | |
| codes = np.zeros(QK_K, dtype=np.uint8) | |
| for j in range(NS): | |
| sub = xb[j] | |
| xmin = min(float(sub.min()), 0.0) | |
| xmax = float(sub.max()) | |
| span = xmax - xmin | |
| sj = span / 3.0 if span > 1.0e-30 else 0.0 | |
| tj = -xmin | |
| s[j], t[j] = sj, tj | |
| if sj > 1.0e-30: | |
| codes[16 * j : 16 * (j + 1)] = np.clip( | |
| nearest_int((sub + tj) / sj), 0, 3 | |
| ).astype(np.uint8) | |
| sw = wb.sum(axis=1) | |
| d, ls = reference_factor_1d(s, sw) | |
| m, lm = reference_factor_1d(t, sw) | |
| L = codes_from_params(x, d, m, ls, lm) | |
| obj, _ = objective(x, w, d, m, ls, lm, L, cfg) | |
| best = (obj, d, m, ls.copy(), lm.copy(), L.copy()) | |
| stall = 0 | |
| for _ in range(16): | |
| L = codes_from_params(x, d, m, ls, lm) | |
| s, t = reference_sub_ls(x, w, L) | |
| ws = np.sum(wb * L.astype(np.float64).reshape(NS, 16) ** 2, axis=1) | |
| wt = wb.sum(axis=1) | |
| d, ls = reference_factor_1d(s, ws) | |
| m, lm = reference_factor_1d(t, wt) | |
| L = codes_from_params(x, d, m, ls, lm) | |
| cur, _ = objective(x, w, d, m, ls, lm, L, cfg) | |
| if cur < best[0]: | |
| best = (cur, d, m, ls.copy(), lm.copy(), L.copy()) | |
| stall = 0 | |
| else: | |
| stall += 1 | |
| if stall >= 2: | |
| break | |
| _, d, m, ls, lm, L = best | |
| d = float(from_fp16_bits(to_fp16_bits(np.float32(d)))) | |
| m = float(from_fp16_bits(to_fp16_bits(np.float32(m)))) | |
| L = codes_from_params(x, d, m, ls, lm) | |
| e = np.asarray(x, dtype=np.float64) - dequantize_params(d, m, ls, lm, L).astype(np.float64) | |
| sse = weighted_sse(x, w, d, m, ls, lm, L) | |
| obj = sse + (spectral_penalty(e, cfg) if use_spectral else 0.0) | |
| return obj, sse | |
| def synthetic_cases(seed: int = 123, per_kind: int = 12): | |
| rng = np.random.default_rng(seed) | |
| cases = [] | |
| for _ in range(per_kind): | |
| cases.append(("gaussian", rng.normal(0, 0.02, QK_K).astype(np.float32))) | |
| for _ in range(per_kind): | |
| cases.append(("student-t", (rng.standard_t(3, QK_K) * 0.01).astype(np.float32))) | |
| for _ in range(per_kind): | |
| mask = rng.random(QK_K) < 0.1 | |
| cases.append(("sparse", (rng.normal(0, 0.02, QK_K) * mask).astype(np.float32))) | |
| for _ in range(per_kind): | |
| mask = rng.random(QK_K) < 0.5 | |
| cases.append(("offset-sparse", (rng.normal(0, 0.02, QK_K) * mask + 0.01).astype(np.float32))) | |
| return cases | |