"""Load snapshots written by scripts/train.py (snap_*.pt / final.pt), full checkpoints, or an exported directory (model.safetensors + config.json, as published on Hugging Face).""" from __future__ import annotations import json import math import os import torch from tiny_agent.model import ModelConfig, TinyAgentLM def load_model(path: str, device="xpu", dtype=torch.float32, low_mem: bool = False) -> TinyAgentLM: """low_mem (serving): keep the Engram tables in bf16, memory-mapped read-only from model.safetensors, so only the rows a prompt touches become resident. Engram.forward upcasts the gathered rows to the compute dtype, so outputs match the full-upcast path exactly (bf16 -> fp32 is exact). Needs an exported directory and leaves the tables frozen (requires_grad=False): not for training. The mapping stays valid as long as model.safetensors is not rewritten in place (replacing it via rename is fine).""" if low_mem and os.path.isdir(path): return _load_low_mem(path, device, dtype) if os.path.isdir(path): from safetensors.torch import load_file st = {"model": load_file(os.path.join(path, "model.safetensors")), "config": json.load(open(os.path.join(path, "config.json")))} else: st = torch.load(path, map_location="cpu", weights_only=False) cfg_d = st.get("config") or st["meta"]["config"] for k in ("engram_layers", "engram_orders"): cfg_d[k] = tuple(cfg_d[k]) model = TinyAgentLM(ModelConfig(**cfg_d)) model.load_state_dict({k: v.float() if v.is_floating_point() else v for k, v in st["model"].items()}) return model.to(device=device, dtype=dtype) _ST_DTYPES = {"BF16": torch.bfloat16, "F16": torch.float16, "F32": torch.float32, "I64": torch.int64, "I32": torch.int32} def _st_view(mm, data_start: int, info: dict) -> torch.Tensor: """Zero-copy tensor over one safetensors entry of a read-only mmap (writing to it would fault).""" import warnings dt = _ST_DTYPES[info["dtype"]] start, end = info["data_offsets"] numel = math.prod(info["shape"]) assert end - start == numel * dt.itemsize with warnings.catch_warnings(): # "non-writable buffer": intended, nothing writes to these warnings.simplefilter("ignore", UserWarning) t = torch.frombuffer(mm, dtype=dt, count=numel, offset=data_start + start) # holds a ref to mm return t.view(info["shape"]) def _load_low_mem(path: str, device, dtype) -> TinyAgentLM: import mmap import struct file = os.path.join(path, "model.safetensors") cfg_d = json.load(open(os.path.join(path, "config.json"))) for k in ("engram_layers", "engram_orders"): cfg_d[k] = tuple(cfg_d[k]) # build without running the weight initialisers (every parameter is replaced from the file below), so the # torch.empty parameter storage is never touched and never becomes resident: no 1 GB fp32 table, and no # second copy of the backbone while loading. Buffers (rope, Engram hashing) don't use nn.init. init = torch.nn.init real = {n: getattr(init, n) for n in dir(init) if n.endswith("_") and not n.startswith("_")} for n in real: setattr(init, n, lambda t, *a, **k: t) try: model = TinyAgentLM(ModelConfig(**cfg_d)) finally: for n, fn in real.items(): setattr(init, n, fn) table_keys = {k for k, _ in model.named_parameters() if k.endswith(".engram.table.weight")} with open(file, "rb") as f: hlen = struct.unpack(" None: """Write a checkpoint as out_dir/model.safetensors (bf16) + out_dir/config.json.""" from safetensors.torch import save_file st = torch.load(path, map_location="cpu", weights_only=False) cfg_d = dict(st.get("config") or st["meta"]["config"]) sd = {k: (v.to(torch.bfloat16) if v.is_floating_point() else v).contiguous() for k, v in st["model"].items()} os.makedirs(out_dir, exist_ok=True) save_file(sd, os.path.join(out_dir, "model.safetensors")) json.dump({k: list(v) if isinstance(v, tuple) else v for k, v in cfg_d.items()}, open(os.path.join(out_dir, "config.json"), "w"), indent=1)