Instructions to use zenlm/zen-router with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use zenlm/zen-router with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-classification", model="zenlm/zen-router")# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("zenlm/zen-router", dtype="auto") - Notebooks
- Google Colab
- Kaggle
Quantized deployment: heads safetensors + llama.cpp embedding recipe (parity 95% route @ Q4_K_M)
61e77cc verified | """Export the trained heads-only checkpoint to safetensors for quantized serving. | |
| The deployment recipe splits the router in two: | |
| * backbone -> runs quantized in llama.cpp EMBEDDING mode. The last-token | |
| pooled hidden state (`--pooling last --embd-normalize -1`, i.e. the raw | |
| post-final-norm hidden state, NOT L2-normalized) reproduces the torch | |
| `ZenRouter.embed` output to within quantization error. | |
| * heads -> three tiny linear maps (task/route/feature) applied by the | |
| caller in numpy. A 1024x28 matmul is microseconds; no torch at serve time. | |
| This script reads `out/zen-router/zen-router.pt` (head weights only, from the | |
| frozen-backbone run) and writes `heads.safetensors` + `router_config.json` next | |
| to it (or to --out). Nothing here touches the backbone: it stays the public | |
| `zenlm/zen-nano-0.6b` GGUF. | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| from pathlib import Path | |
| import torch | |
| from safetensors.torch import save_file | |
| HEAD_KEYS = ( | |
| "task_head.weight", "task_head.bias", | |
| "route_head.weight", "route_head.bias", | |
| "feature_head.weight", "feature_head.bias", | |
| ) | |
| def main() -> None: | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--model", type=Path, default=Path("out/zen-router"), | |
| help="dir with zen-router.pt + router_config.json") | |
| ap.add_argument("--out", type=Path, default=None, help="output dir (default: export/)") | |
| args = ap.parse_args() | |
| out = args.out or Path(__file__).resolve().parent | |
| out.mkdir(parents=True, exist_ok=True) | |
| sd = torch.load(args.model / "zen-router.pt", map_location="cpu") | |
| missing = [k for k in HEAD_KEYS if k not in sd] | |
| if missing: | |
| raise SystemExit(f"checkpoint missing head keys {missing}; not a heads-only run?") | |
| if any(k.startswith("backbone.") for k in sd): | |
| raise SystemExit("checkpoint carries backbone weights; expected a --freeze-backbone run") | |
| heads = {k: sd[k].contiguous().float() for k in HEAD_KEYS} | |
| save_file(heads, str(out / "heads.safetensors")) | |
| cfg = json.loads((args.model / "router_config.json").read_text()) | |
| hidden = heads["route_head.weight"].shape[1] | |
| cfg["hidden_size"] = hidden | |
| cfg["feature_dim"] = heads["feature_head.weight"].shape[0] | |
| cfg["pooling"] = "last" | |
| cfg["embd_normalize"] = -1 # raw hidden state; heads carry their own scale | |
| (out / "router_config.json").write_text(json.dumps(cfg, indent=2)) | |
| total = sum(v.numel() for v in heads.values()) | |
| print(f"wrote {out/'heads.safetensors'} ({total} params, " | |
| f"{(out/'heads.safetensors').stat().st_size} bytes)") | |
| print(f"wrote {out/'router_config.json'} " | |
| f"(hidden={hidden}, tasks={len(cfg['tasks'])}, routes={len(cfg['catalog'])})") | |
| if __name__ == "__main__": | |
| main() | |