Source code for mlx_lattice.artifact.io
from __future__ import annotations
import json
from dataclasses import dataclass
from pathlib import Path
from typing import cast
import mlx.core as mx
import mlx.nn as mxnn
from lattice_contract import (
IRManifest,
load_manifest,
manifest_to_dict,
)
from mlx_lattice.artifact.builder import (
LatticeGraphBuilder,
build_lattice_graph_artifact,
build_lattice_module_artifact,
)
from mlx_lattice.artifact.model import LatticeModel
_MANIFEST_NAME = 'manifest.json'
_WEIGHTS_NAME = 'weights.safetensors'
[docs]
@dataclass(frozen=True, slots=True)
class LatticeArtifact:
"""Loaded lattice model artifact."""
manifest: IRManifest
weights: dict[str, mx.array]
[docs]
def model(self) -> LatticeModel:
"""Construct an executable in-memory MLX graph."""
return LatticeModel(self.manifest, self.weights)
[docs]
def load_lattice_artifact(path: str | Path) -> LatticeArtifact:
"""Load a lattice artifact directory.
The artifact directory must contain ``manifest.json`` and
``weights.safetensors``. Use :meth:`LatticeArtifact.model` or
:func:`load_lattice_model` when an executable graph runner is needed.
"""
return _load_artifact(path)
[docs]
def load_lattice_model(path: str | Path) -> LatticeModel:
"""Load a lattice artifact directory into an executable model.
The model-oriented name is the recommended deployment entry point.
"""
return load_lattice_artifact(path).model()
[docs]
def save_lattice_artifact(
path: str | Path,
manifest: IRManifest,
weights: dict[str, mx.array],
) -> None:
"""Write a lattice artifact directory.
This helper is intentionally strict and low level. It is useful for tests,
fixtures, and future producers that already own a valid manifest.
"""
LatticeModel(manifest, weights)
root = Path(path)
root.mkdir(parents=True, exist_ok=True)
manifest_path = root / _MANIFEST_NAME
weights_path = root / _WEIGHTS_NAME
with manifest_path.open('w', encoding='utf-8') as file:
json.dump(manifest_to_dict(manifest), file, indent=2)
file.write('\n')
mx.save_safetensors(str(weights_path), weights)
[docs]
def save_lattice_model(
path: str | Path,
manifest: IRManifest,
weights: dict[str, mx.array],
) -> None:
"""Alias for :func:`save_lattice_artifact`."""
save_lattice_artifact(path, manifest, weights)
[docs]
def save_lattice_module(
path: str | Path,
module: mxnn.Module,
**kwargs,
) -> None:
"""Build and save a serializable sparse NN module."""
artifact = build_lattice_module_artifact(module, **kwargs)
save_lattice_artifact(path, artifact.manifest, artifact.weights)
[docs]
def save_lattice_graph(
path: str | Path,
builder: LatticeGraphBuilder,
**kwargs,
) -> None:
"""Build and save an explicitly built lattice graph."""
artifact = build_lattice_graph_artifact(builder, **kwargs)
save_lattice_artifact(path, artifact.manifest, artifact.weights)
def _load_artifact(path: str | Path) -> LatticeArtifact:
root = Path(path)
if not root.is_dir():
raise ValueError(
f'lattice artifact directory does not exist: {root}'
)
manifest_path = root / _MANIFEST_NAME
weights_path = root / _WEIGHTS_NAME
if not manifest_path.is_file():
raise ValueError(f'lattice artifact is missing {_MANIFEST_NAME}.')
if not weights_path.is_file():
raise ValueError(f'lattice artifact is missing {_WEIGHTS_NAME}.')
weights = mx.load(str(weights_path))
if not isinstance(weights, dict):
raise ValueError(
'weights.safetensors must load as a tensor mapping.'
)
return LatticeArtifact(
load_manifest(manifest_path),
cast(dict[str, mx.array], weights),
)