Spaces:
Running
Running
| from __future__ import annotations | |
| from pathlib import Path | |
| import numpy as np | |
| import torch | |
| from model import BitMLP | |
| def pack_binary_model(model: BitMLP, destination: Path) -> dict: | |
| payload = {} | |
| payload_bytes = 0 | |
| for name in ["hidden", "output"]: | |
| layer = getattr(model, name) | |
| weight = layer.weight.detach().cpu().numpy() | |
| scales = np.mean(np.abs(weight), axis=1).astype(np.float32) | |
| signs = np.packbits((weight >= 0).reshape(-1), bitorder="little") | |
| shape = np.asarray(weight.shape, dtype=np.int32) | |
| bias = layer.bias.detach().cpu().numpy().astype(np.float32) | |
| payload[f"{name}_signs"] = signs | |
| payload[f"{name}_scales"] = scales | |
| payload[f"{name}_shape"] = shape | |
| payload[f"{name}_bias"] = bias | |
| payload_bytes += signs.nbytes + scales.nbytes + bias.nbytes | |
| np.savez(destination, **payload) | |
| return { | |
| "packed_payload_bytes": int(payload_bytes), | |
| "container_bytes": int(destination.stat().st_size), | |
| } | |
| def load_binary_model(source: Path) -> BitMLP: | |
| packed = np.load(source) | |
| model = BitMLP(bits="binary") | |
| with torch.no_grad(): | |
| for name in ["hidden", "output"]: | |
| layer = getattr(model, name) | |
| shape = tuple(packed[f"{name}_shape"].astype(int)) | |
| total = int(np.prod(shape)) | |
| bits = np.unpackbits( | |
| packed[f"{name}_signs"], bitorder="little" | |
| )[:total] | |
| signs = np.where(bits.reshape(shape) == 1, 1.0, -1.0) | |
| scales = packed[f"{name}_scales"][:, None] | |
| layer.weight.copy_( | |
| torch.from_numpy((signs * scales).astype(np.float32)) | |
| ) | |
| layer.bias.copy_(torch.from_numpy(packed[f"{name}_bias"])) | |
| return model | |