SNAPKITTYWEST's picture
October 2026 main drop: mirror from GitHub
9e551a1 verified
Raw History Blame Contribute Delete
15.9 kB
# Tensor Roll — Recursive CUDA-Q Model Quantizer
# Copyright (C) 2026 SnapKitty Collective
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Quantization formats: FP16 / BF16 / INT8 / INT4.
All quantizers are implemented here from first principles (no external
quantizer libraries). Every quantize() returns (payload, meta) and every
meta carries enough information for an exact dequantize() round-trip.
"""
from __future__ import annotations
import numpy as np
def to_fp16(W: np.ndarray):
W = np.asarray(W, dtype=np.float32)
return W.astype(np.float16), {"fmt": "fp16"}
def from_fp16(q: np.ndarray) -> np.ndarray:
return np.asarray(q, dtype=np.float32)
def to_bf16(W: np.ndarray):
"""Round-to-nearest-even float32 -> bfloat16 (stored as uint16)."""
a = np.asarray(W, dtype=np.float32)
i = a.view(np.int32).copy()
finite = np.isfinite(a)
lsb = (i >> 16) & 1
i[finite] += (0x7FFF + lsb[finite]).astype(np.int32)
return (i >> 16).astype(np.uint16), {"fmt": "bf16"}
def from_bf16(q: np.ndarray) -> np.ndarray:
return (np.asarray(q, dtype=np.int32) << 16).view(np.float32)
def quantize_int8(W: np.ndarray):
"""Asymmetric per-tensor INT8."""
W = np.asarray(W, dtype=np.float64)
wmin, wmax = float(W.min()), float(W.max())
if wmax == wmin:
return np.zeros(W.shape, dtype=np.int8), {
"fmt": "int8", "scale": 1.0, "zero": 0.0}
scale = (wmax - wmin) / 255.0
q = np.clip(np.round((W - wmin) / scale), 0, 255).astype(np.int64) - 128
return q.astype(np.int8), {"fmt": "int8", "scale": scale, "zero": wmin}
def dequantize_int8(q: np.ndarray, meta: dict) -> np.ndarray:
return (q.astype(np.float64) + 128.0) * meta["scale"] + meta["zero"]
def quantize_int4(W: np.ndarray, group: int = 32):
"""Group-wise asymmetric INT4, two nibbles packed per byte (low nibble
first). Groups run along the last axis; ragged tail is zero-padded and
the pad is recorded so dequantize() restores the exact shape."""
W = np.asarray(W, dtype=np.float64)
shape = list(W.shape)
last = shape[-1]
rows = int(np.prod(shape[:-1])) if len(shape) > 1 else 1
flat = W.reshape(rows, last)
pad = (-last) % group
if pad:
flat = np.concatenate([flat, np.zeros((rows, pad))], axis=1)
G = flat.reshape(-1, group)
gmin = G.min(axis=1)
gmax = G.max(axis=1)
scale = np.maximum(gmax - gmin, 1e-300) / 15.0
q = np.clip(np.round((G - gmin[:, None]) / scale[:, None]), 0, 15).astype(np.uint8)
packed = (q[:, 0::2] | (q[:, 1::2] << 4)).astype(np.uint8)
meta = {"fmt": "int4", "group": group, "shape": shape,
"scales": scale.astype(np.float64), "zeros": gmin.astype(np.float64),
"rows": rows, "last": last}
return packed, meta
def dequantize_int4(packed: np.ndarray, meta: dict) -> np.ndarray:
group, rows, last = meta["group"], meta["rows"], meta["last"]
p = np.asarray(packed).reshape(-1, group // 2)
q = np.empty((p.shape[0], group), dtype=np.float64)
q[:, 0::2] = p & 0x0F
q[:, 1::2] = (p >> 4) & 0x0F
G = q * np.asarray(meta["scales"])[:, None] + np.asarray(meta["zeros"])[:, None]
flat = G.reshape(rows, -1)[:, :last]
return flat.reshape(meta["shape"]).astype(np.float32)
def quantize_tensor(W: np.ndarray, fmt: str):
"""Dispatch: fmt in {fp32, fp16, bf16, int8, int4}."""
if fmt == "fp32":
return np.asarray(W, dtype=np.float32), {"fmt": "fp32"}
if fmt == "fp16":
return to_fp16(W)
if fmt == "bf16":
return to_bf16(W)
if fmt == "int8":
return quantize_int8(W)
if fmt == "int4":
return quantize_int4(W)
raise ValueError(f"unknown format {fmt!r}")
def dequantize_tensor(q: np.ndarray, meta: dict) -> np.ndarray:
fmt = meta["fmt"]
if fmt == "fp32":
return np.asarray(q, dtype=np.float32)
if fmt == "fp16":
return from_fp16(q)
if fmt == "bf16":
return from_bf16(q)
if fmt == "int8":
return dequantize_int8(q, meta).astype(np.float32)
if fmt == "int4":
return dequantize_int4(q, meta)
raise ValueError(f"unknown format {fmt!r}")
def payload_nbytes(q: np.ndarray, fmt: str) -> int:
return int(np.asarray(q).nbytes)
# ---------------------------------------------------------------------------
# INT4 failure resolution (F6): per-tensor error instrumentation, advanced
# schemes, mixed precision, and quantization-aware recovery.
# ---------------------------------------------------------------------------
def quantize_int4_per_tensor(W: np.ndarray):
"""Whole-tensor asymmetric INT4: ONE scale/zero over the entire tensor."""
W = np.asarray(W, dtype=np.float64)
shape = list(W.shape)
flat = W.ravel()
gmin, gmax = float(flat.min()), float(flat.max())
scale = max(gmax - gmin, 1e-300) / 15.0
q = np.clip(np.round((flat - gmin) / scale), 0, 15).astype(np.uint8)
if q.size % 2:
q = np.concatenate([q, np.zeros(1, dtype=np.uint8)])
packed = (q[0::2] | (q[1::2] << 4)).astype(np.uint8)
meta = {"fmt": "int4", "scheme": "per-tensor", "shape": shape,
"scales": np.array([scale]), "zeros": np.array([gmin]),
"size": flat.size}
return packed, meta
def dequantize_int4_per_tensor(packed: np.ndarray, meta: dict) -> np.ndarray:
q = np.asarray(packed)
flat = np.empty(q.size * 2, dtype=np.float64)
flat[0::2] = q & 0x0F
flat[1::2] = (q >> 4) & 0x0F
flat = flat[:meta["size"]]
W = flat * float(meta["scales"][0]) + float(meta["zeros"][0])
return W.reshape(meta["shape"]).astype(np.float32)
def quantize_int4_per_channel(W: np.ndarray):
"""Per-channel (per-row) asymmetric INT4: one scale/zero per row instead
of per group-of-32. Returns (packed, meta) with the same nibble layout
as quantize_int4 so dequantize_int4-style unpacking applies."""
W = np.asarray(W, dtype=np.float64)
shape = list(W.shape)
last = shape[-1]
rows = int(np.prod(shape[:-1])) if len(shape) > 1 else 1
flat = W.reshape(rows, last)
gmin = flat.min(axis=1)
gmax = flat.max(axis=1)
scale = np.maximum(gmax - gmin, 1e-300) / 15.0
q = np.clip(np.round((flat - gmin[:, None]) / scale[:, None]), 0, 15)
q = q.astype(np.uint8)
# pad last dim to even for nibble packing
if last % 2:
q = np.concatenate([q, np.zeros((rows, 1), dtype=np.uint8)], axis=1)
packed = (q[:, 0::2] | (q[:, 1::2] << 4)).astype(np.uint8)
meta = {"fmt": "int4", "scheme": "per-channel", "shape": shape,
"scales": scale.astype(np.float64),
"zeros": gmin.astype(np.float64),
"rows": rows, "last": last}
return packed, meta
def dequantize_int4_per_channel(packed: np.ndarray, meta: dict) -> np.ndarray:
rows, last = meta["rows"], meta["last"]
p = np.asarray(packed).reshape(rows, -1)
q = np.empty((rows, p.shape[1] * 2), dtype=np.float64)
q[:, 0::2] = p & 0x0F
q[:, 1::2] = (p >> 4) & 0x0F
q = q[:, :last]
W = q * np.asarray(meta["scales"])[:, None] + np.asarray(meta["zeros"])[:, None]
return W.reshape(meta["shape"]).astype(np.float32)
def search_group_size(W: np.ndarray,
groups: tuple = (16, 32, 64, 128)) -> dict:
"""Search the INT4 group size by MEASURED reconstruction MSE — the
winner is the argmin of measured error, never a hard-coded default."""
W = np.asarray(W, dtype=np.float64)
results = []
for g in groups:
if g < 2:
continue
q, meta = quantize_int4(W, group=g)
back = dequantize_int4(q, meta).astype(np.float64)
err = float(np.mean((W - back) ** 2))
results.append({"group": g, "mse": err,
"bytes": int(np.asarray(q).nbytes)})
results.sort(key=lambda r: r["mse"])
return {"results": results, "best_group": results[0]["group"],
"best_mse": results[0]["mse"]}
def quant_error_map(W: np.ndarray, Wd: np.ndarray) -> dict:
"""Instrument quantization error per tensor. All values measured."""
W = np.asarray(W, dtype=np.float64)
Wd = np.asarray(Wd, dtype=np.float64)
err = W - Wd
flat = err.ravel()
sd = float(flat.std()) if flat.size else 0.0
per_channel = []
if W.ndim == 2:
for r in range(W.shape[0]):
e = err[r]
per_channel.append(float(np.mean(e ** 2)))
# per-group error at group=32 along the last axis
per_group = []
if W.ndim >= 1 and W.shape[-1] >= 32:
G = err.reshape(-1, 32)
per_group = [float(np.mean(g ** 2)) for g in G]
denom = float(np.linalg.norm(W))
return {
"min": float(err.min()) if err.size else 0.0,
"max": float(err.max()) if err.size else 0.0,
"mean": float(err.mean()) if err.size else 0.0,
"variance": float(err.var()) if err.size else 0.0,
"std": sd,
"outlier_frac": float(np.mean(np.abs(flat) > 3 * sd)) if sd > 0 else 0.0,
"mse": float(np.mean(flat ** 2)) if flat.size else 0.0,
"cosine_sim": float(np.dot(W.ravel(), Wd.ravel())
/ (np.linalg.norm(W.ravel())
* np.linalg.norm(Wd.ravel()) + 1e-300)),
"rel_err": float(np.linalg.norm(err) / (denom + 1e-300)),
"per_channel_mse": per_channel,
"per_group_mse": per_group,
}
def int4_scheme_report(W: np.ndarray) -> dict:
"""Benchmark per-tensor / per-channel / group-wise INT4 on one tensor.
Returns measured MSE + byte size for each scheme; the caller picks the
winner from measurements."""
W = np.asarray(W, dtype=np.float64)
out = {}
qt, mt = quantize_int4_per_tensor(W)
backt = dequantize_int4_per_tensor(qt, mt).astype(np.float64)
out["per-tensor"] = {"mse": float(np.mean((W - backt) ** 2)),
"bytes": int(np.asarray(qt).nbytes),
"meta_bytes": 16}
qp, mp = quantize_int4_per_channel(W)
backp = dequantize_int4_per_channel(qp, mp).astype(np.float64)
out["per-channel"] = {"mse": float(np.mean((W - backp) ** 2)),
"bytes": int(np.asarray(qp).nbytes),
"meta_bytes": int(mp["scales"].nbytes
+ mp["zeros"].nbytes)}
gs = search_group_size(W)
out["group-wise"] = {"mse": gs["best_mse"],
"bytes": next(r["bytes"] for r in gs["results"]
if r["group"] == gs["best_group"]),
"best_group": gs["best_group"],
"all": gs["results"]}
# int8 reference for the mixed-precision gain computation
qi, mi = quantize_int8(W)
backi = dequantize_int8(qi, mi).astype(np.float64)
out["int8"] = {"mse": float(np.mean((W - backi) ** 2)),
"bytes": int(np.asarray(qi).nbytes)}
return out
def mixed_precision_plan(params: dict, size_budget_bytes: int) -> dict:
"""Assign INT4 vs INT8 per tensor under a physical size budget.
Tensors where INT8 buys the most error reduction per extra byte stay
INT8; the rest go INT4 (best measured scheme per tensor). Sensitive
tensors are thereby protected by measurement, not by fiat.
"""
rows = []
for k, v in params.items():
v = np.asarray(v)
if v.ndim != 2 or v.size < 64:
rows.append({"tensor": k, "fmt": "fp32",
"bytes": int(v.nbytes), "gain_per_byte": 0.0,
"int4_mse": 0.0, "int8_mse": 0.0})
continue
rep = int4_scheme_report(v)
best4 = min(rep["per-tensor"], rep["per-channel"],
rep["group-wise"], key=lambda r: r["mse"])
b4 = best4["bytes"] + best4.get("meta_bytes", 0)
b8 = rep["int8"]["bytes"]
gain = max(0.0, best4["mse"] - rep["int8"]["mse"])
gpb = gain / max(1, b8 - b4)
rows.append({"tensor": k, "fmt": "int4", "bytes": b4,
"gain_per_byte": gpb, "int4_mse": best4["mse"],
"int8_mse": rep["int8"]["mse"],
"int4_scheme": "per-tensor"
if best4 is rep["per-tensor"] else
("per-channel" if best4 is rep["per-channel"]
else f"group-{rep['group-wise']['best_group']}")})
# start all-int4, upgrade highest gain/byte to int8 while budget allows
total4 = sum(r["bytes"] for r in rows)
cands = sorted([r for r in rows if r["fmt"] == "int4"
and r["gain_per_byte"] > 0],
key=lambda r: -r["gain_per_byte"])
plan, used = {}, total4
for r in rows:
plan[r["tensor"]] = "int4"
for r in cands:
v = np.asarray(params[r["tensor"]])
qi, _ = quantize_int8(v)
b8 = int(np.asarray(qi).nbytes)
if used - r["bytes"] + b8 <= size_budget_bytes:
plan[r["tensor"]] = "int8"
used = used - r["bytes"] + b8
return {"plan": plan, "total_bytes": used,
"budget_bytes": int(size_budget_bytes),
"within_budget": used <= size_budget_bytes,
"n_int8": sum(1 for v in plan.values() if v == "int8"),
"n_int4": sum(1 for v in plan.values() if v == "int4"),
"rows": rows}
def dequantize_dispatch(q: np.ndarray, meta: dict) -> np.ndarray:
"""Dequantize honoring per-tensor / per-channel int4 metadata."""
if meta.get("fmt") == "int4" and meta.get("scheme") == "per-tensor":
return dequantize_int4_per_tensor(q, meta)
if meta.get("fmt") == "int4" and meta.get("scheme") == "per-channel":
return dequantize_int4_per_channel(q, meta)
return dequantize_tensor(q, meta)
def recovery_train(s_qparams: dict, s_cfg, t_params: dict, t_cfg,
*, steps: int = 30, batch: int = 64, lr: float = 1e-3,
seed: int = 0) -> dict:
"""Quantization-aware recovery (spec section 9):
INT4-dequantized student -> distillation (task + logit KL)
vs the teacher -> requantize INT4 -> evaluate.
Returns measured ppl before/after and the gap delta. Improvement is
reported ONLY if measured; otherwise the (non-)result stands.
"""
from .model import (Adam, backward, ce_loss, eval_metrics, forward,
gen_data, kl_loss)
rng = np.random.default_rng(seed)
# start from the dequantized INT4 weights (float working copy)
params = {k: v.astype(np.float32) for k, v in s_qparams.items()}
before = eval_metrics(params, s_cfg, batches=4, batch=batch, seed=911)
opt = Adam(params, lr=lr)
for _ in range(steps):
ids = gen_data(rng, batch, s_cfg)
tl, _ = forward(t_params, t_cfg, ids[:, :-1])
sl, cache = forward(params, s_cfg, ids[:, :-1])
lt, dl_t = ce_loss(sl, ids[:, 1:])
lk, dl_k = kl_loss(sl, tl, tau=2.0)
grads = backward(params, s_cfg, cache, dl_t + 0.5 * dl_k)
opt.step(params, grads)
after = eval_metrics(params, s_cfg, batches=4, batch=batch, seed=911)
# requantize and measure the real INT4 artifact quality
re_q = {}
for k, v in params.items():
if v.ndim == 2 and v.size >= 64:
q, m = quantize_int4(v)
re_q[k] = dequantize_int4(q, m).astype(np.float32)
else:
re_q[k] = v
re_eval = eval_metrics(re_q, s_cfg, batches=4, batch=batch, seed=911)
return {
"steps": steps,
"ppl_before": float(np.exp(before["loss"])),
"ppl_after_train": float(np.exp(after["loss"])),
"ppl_after_requant": float(np.exp(re_eval["loss"])),
"gap_before": float(np.exp(before["loss"]) - np.exp(after["loss"])),
"gap_delta": float(np.exp(before["loss"])
- np.exp(re_eval["loss"])),
"improved": bool(np.exp(re_eval["loss"]) < np.exp(before["loss"])),
}