Bonsai-JEV-mlx / runtime /artifact.py
dakebakery's picture
Add files using upload-large-folder tool
3b57fd1 verified
Raw History Blame Contribute Delete
5.62 kB
"""Save and reload MLX packs with an explicit matching-runtime requirement."""
import json
import shutil
from pathlib import Path
import mlx.core as mx
from mlx.utils import tree_flatten
from mlx_lm.models.qwen3_5 import TextModel, TextModelArgs
from runtime import Packed
from mlx import nn
def save_model(model, info, tokenizer_path, directory):
directory = Path(directory)
modules = []
for name, module in model.named_modules():
if isinstance(module, Packed):
if module.dtype != mx.float16:
raise ValueError("Only float16 packed artifacts are supported")
modules.append(
{
"path": name,
"block": module.block,
"embedding": module.embedding,
"dtype": "float16",
}
)
config = {
"schema_version": 1,
"model_type": "prism_hadamard_qwen35",
"requires_runtime": "examples/python/hadamard/artifact.py",
"text_config": info["config"],
"modules": modules,
"quantization": {"bits": 2, "group_size": 128, "mode": "affine"},
}
directory.mkdir(parents=True, exist_ok=False)
mx.save_safetensors(
str(directory / "model.safetensors"),
dict(tree_flatten(model.parameters())),
metadata={"format": "mlx"},
)
(directory / "config.json").write_text(json.dumps(config, indent=2))
shutil.copyfile(tokenizer_path, directory / "tokenizer.json")
(directory / "README.md").write_text(
"# Experimental folded MLX pack\n\nRequires the accompanying Hadamard-aware loader. Do not load as an ordinary affine Qwen checkpoint: that would omit activation and inverse-embedding transforms. The source numerical and performance reports are separate from serialization integrity.\n"
)
return config
def validate_record(original, record, arrays, signs):
if not isinstance(original, (nn.Linear, nn.Embedding)):
raise ValueError("Unsupported packed module target")
if record["embedding"] != isinstance(original, nn.Embedding):
raise ValueError("Packed module kind mismatch")
rows, width = original.weight.shape
if width % 128:
raise ValueError("Invalid packed width")
expected = [(rows, width // 16), (rows, width // 128), (rows, width // 128)]
if [a.shape for a in arrays] != expected or arrays[0].dtype != mx.uint32:
raise ValueError("Invalid packed tensor shapes or storage dtype")
for array in arrays[1:]:
if array.dtype not in (mx.float16, mx.float32, mx.bfloat16):
raise ValueError("Invalid affine dtype")
if not mx.all(mx.isfinite(array)).item():
raise ValueError("Non-finite affine parameters")
block = record["block"]
if block:
if width % block or signs is None or signs.shape != (width,):
raise ValueError("Invalid transform dimensions")
if not mx.all((signs == 1) | (signs == -1)).item():
raise ValueError("Invalid sign values")
elif signs is not None:
raise ValueError("Unexpected sign vector")
def load_model(directory):
directory = Path(directory)
config = json.loads((directory / "config.json").read_text())
if (
config.get("schema_version") != 1
or config.get("model_type") != "prism_hadamard_qwen35"
):
raise ValueError("Unsupported packed model schema")
model = TextModel(TextModelArgs.from_dict(config["text_config"]))
weights = mx.load(str(directory / "model.safetensors"))
seen = set()
for record in config["modules"]:
if record["path"] in seen:
raise ValueError("Duplicate packed module")
seen.add(record["path"])
parts = record["path"].split(".")
parent = model
for part in parts[:-1]:
parent = parent[int(part)] if part.isdigit() else getattr(parent, part)
name = record["path"]
arrays = [
weights[name + "." + suffix] for suffix in ("weight", "scales", "biases")
]
if record["dtype"] != "float16":
raise ValueError("Unsupported activation dtype")
block = record["block"]
if block and block not in (512, 1024, 2048, 4096):
raise ValueError("Unsupported block size")
signs = weights.get(name + ".signs")
if block and signs is None:
raise ValueError("Missing sign vector")
original = getattr(parent, parts[-1])
validate_record(original, record, arrays, signs)
setattr(
parent,
parts[-1],
Packed(arrays, block, signs, record["embedding"], mx.float16),
)
model.load_weights(list(weights.items()), strict=True)
model.eval()
mx.eval(model.parameters())
return model, config
def save_and_verify(model, info, tokenizer_path, directory, input_ids):
import numpy as np
config = save_model(model, info, tokenizer_path, directory)
reloaded, _ = load_model(directory)
x = mx.array([input_ids], dtype=mx.int32)
def evaluate(m):
hidden = m.model(x, cache=m.make_cache())
y = m.lm_head(hidden[:, -1:, :])
mx.eval(y)
return np.asarray(y)
expected = evaluate(model)
actual = evaluate(reloaded)
np.testing.assert_array_equal(actual, expected)
result = {
"reload_logits_exact": True,
"checked_logits": actual.size,
"packed_modules": len(config["modules"]),
}
Path(directory, "reload-validation.json").write_text(json.dumps(result, indent=2))
return result