Shapequant / shapequant /memory.py
Angshul's picture
Upload 17 files
c675b8d verified
Raw History Blame Contribute Delete
2.35 kB
"""Peak-memory estimate for quantize_model from a config (no weights needed)."""
import json, os
from .arch import from_config
def estimate(config, n_samples=16384, batch=2048, method="shaped"):
"""config: dict, path to config.json, or a directory. Returns bytes for the accelerator and for host RAM."""
if isinstance(config, str):
p = os.path.join(config, "config.json") if os.path.isdir(config) else config
config = json.load(open(p))
a = from_config(config)
f32, f64 = 4, 8
lin = sum(_numel(a, l) for l in a.layers[0]) # one decoder layer, fp32 on device
ins = {"ln1": a.d, "attn_out": a.n_head * a.head_dim, "ln2": a.d, "act": a.inter}
# quantizing the largest input group: stacked W (fp32) + H + Cholesky chain (2 alive) + error buffer
worst = 0
for key, n in ins.items():
rows = sum(_out(a, l) for l in a.layers[0] if l.input_key == key)
worst = max(worst, rows * n * f32 * 2 + 2 * n * n * f32 + rows * 128 * f32 * 2)
shaped = 0
if method == "shaped":
shaped = (3 * a.d * a.d * f64 # residual Sig, moments
+ 2 * a.inter * a.inter * f32 # S_act accumulator + H
+ batch * (a.d + 2 * a.inter) * f32 # Monte Carlo batch
+ 4 * (a.n_head * a.head_dim) ** 2 * f64) # attention-output S
embed = a.vocab * a.d * f32
device_peak = lin * f32 + max(worst + shaped, embed + 2 * a.d * a.d * f64)
n_params = a.n_layer * lin + a.vocab * a.d * (1 if a.lm_head is None else 2)
out_bytes = a.n_layer * lin * (4.25 / 8) + a.vocab * a.d * 2 * (1 if a.lm_head is None else 2)
return {"model_type": a.model_type, "params_B": n_params / 1e9, "device_peak_GB": device_peak / 2 ** 30,
"host_buffer_GB": 4 + lin * 2 / 2 ** 30, "int4_checkpoint_GB": out_bytes / 2 ** 30,
"largest_H_dim": max(ins.values())}
def _out(a, l):
return {"q": a.n_head * a.head_dim, "k": a.n_kv * a.head_dim, "v": a.n_kv * a.head_dim, "qkv": 3 * a.d,
"o": a.d, "gate": a.inter, "up": a.inter, "down": a.d}[l.role]
def _in(a, l):
return {"ln1": a.d, "attn_out": a.n_head * a.head_dim, "ln2": a.d, "act": a.inter}[l.input_key]
def _numel(a, l):
return _out(a, l) * _in(a, l)