Spaces:
Sleeping
Sleeping
Download quant_units.py from build-small-hackathon/neural-riscv: direct link, hf CLI and curl.
- Browser
- Download file 2.93 kB
-
https://huggingface.co/spaces/build-small-hackathon/neural-riscv/resolve/main/quant_units.py
- Command line
-
hf download hf://spaces/build-small-hackathon/neural-riscv/quant_units.py
-
curl -L -o quant_units.py https://huggingface.co/spaces/build-small-hackathon/neural-riscv/resolve/main/quant_units.py
2.93 kB
| """ | |
| quant_units.py -- load the int8-quantized datapath units shipped in | |
| `models_int8/`, and (re)verify any unit variant bit-exact over its full domain. | |
| The int8 files are produced by riscv/export_int8.py: the dominant 256x256 hidden | |
| weight is per-channel symmetric int8, everything else is fp16. Dequantizing | |
| reconstructs a normal BitMLP state_dict, so the rest of the stack (build_all / | |
| NeuralUnits / the rv32 core) is untouched -- this is purely an alternate weight | |
| source. All 13 units stay bit-exact, at ~28% of the fp32 size. | |
| """ | |
| import os | |
| import torch | |
| from x86_units import (BitMLP, u_ADC8, u_SBB8, u_logic, u_SHL1, u_SHR1, | |
| u_MASK8, u_NOT8, u_FLAGS8, u_prefix, u_modrm, u_sib) | |
| HERE = os.path.dirname(os.path.abspath(__file__)) | |
| INT8_DIR = os.path.join(HERE, "models_int8") | |
| # name -> truth-table generator, for exhaustive re-verification of either variant | |
| DOMAINS = { | |
| "ADC8": u_ADC8, "SBB8": u_SBB8, | |
| "AND8": lambda: u_logic(lambda a, b: a & b), | |
| "OR8": lambda: u_logic(lambda a, b: a | b), | |
| "XOR8": lambda: u_logic(lambda a, b: a ^ b), | |
| "SHL1": u_SHL1, "SHR1": u_SHR1, "MASK8": u_MASK8, "NOT8": u_NOT8, | |
| "FLAGS8": u_FLAGS8, "PREFIX": u_prefix, "MODRM": u_modrm, "SIB": u_sib, | |
| } | |
| def _dequant(blob): | |
| """int8 blob -> fp32 BitMLP state_dict.""" | |
| sd = {} | |
| for k, v in blob.items(): | |
| if k.endswith(".q"): | |
| sd[k[:-2]] = v.float() * blob[k[:-2] + ".s"].float() | |
| elif k.endswith(".s"): | |
| continue | |
| else: | |
| sd[k] = v.float() | |
| return sd | |
| def build_int8(int8_dir=INT8_DIR): | |
| """Like build_all(), but loads the int8 units (dequantized) -- no training.""" | |
| nets = {} | |
| for name in DOMAINS: | |
| blob = torch.load(os.path.join(int8_dir, f"{name}.pt"), weights_only=True) | |
| sd = _dequant(blob) | |
| nin = sd["net.0.weight"].shape[1] | |
| nout = sd["net.4.weight"].shape[0] | |
| net = BitMLP(nin, nout) | |
| net.load_state_dict(sd) | |
| net.eval() | |
| nets[name] = net | |
| return nets | |
| def verify(nets): | |
| """Exhaustively re-check every unit over its FULL domain. Returns | |
| (n_exact, n_total, list_of_failures).""" | |
| ok = 0; fails = [] | |
| for name, gen in DOMAINS.items(): | |
| X, Y = gen() | |
| Xt, Yt = torch.tensor(X), torch.tensor(Y) | |
| good = True | |
| with torch.no_grad(): | |
| for i in range(0, Xt.shape[0], 65536): | |
| if not bool(((nets[name](Xt[i:i+65536]) > 0).float() | |
| == Yt[i:i+65536]).all()): | |
| good = False; break | |
| ok += int(good) | |
| if not good: | |
| fails.append(name) | |
| return ok, len(DOMAINS), fails | |
| def dir_size(model_dir): | |
| """Total bytes of the 13 unit files in a model directory.""" | |
| tot = 0 | |
| for name in DOMAINS: | |
| p = os.path.join(model_dir, f"{name}.pt") | |
| if os.path.exists(p): | |
| tot += os.path.getsize(p) | |
| return tot | |