Download training/scripts/ccslm/export.py from Samonte/mt_slm_ctx_compress: direct link, hf CLI and curl.
- Browser
- Download file 3.54 kB
-
https://huggingface.co/Samonte/mt_slm_ctx_compress/resolve/main/training/scripts/ccslm/export.py
- Command line
-
hf download hf://Samonte/mt_slm_ctx_compress/training/scripts/ccslm/export.py
-
curl -L -o export.py https://huggingface.co/Samonte/mt_slm_ctx_compress/resolve/main/training/scripts/ccslm/export.py
3.54 kB
| """Merge a numbered training checkpoint into a servable bf16 model, like the end of `ccslm.train`. | |
| python -m ccslm.export --run out/runs/A --list # checkpoints with step, loss, eval loss | |
| python -m ccslm.export --run out/runs/A --step 100 # -> out/runs/A/merged-step-00100 | |
| python -m ccslm.export --run out/runs/A --step latest --out /somewhere/model | |
| The output has the base's tokenizer files byte for byte and its own config.json, so the pipeline's | |
| eval, speed and package stages take it as they take `merged` (`--step` on the pipeline). | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| from pathlib import Path | |
| from typing import Any | |
| from ccslm.common import base_dir as pinned | |
| from ccslm.common import log, read_json | |
| def snapshots(run: Path) -> list[Path]: | |
| root = run / "checkpoints" | |
| return sorted(p for p in root.glob("step-*") if p.is_dir() and not p.name.endswith(".tmp")) | |
| def find(run: Path, step: str) -> Path: | |
| found = snapshots(run) | |
| if not found: | |
| raise SystemExit(f"no checkpoints under {run / 'checkpoints'}") | |
| if step == "latest": | |
| return found[-1] | |
| where = run / "checkpoints" / f"step-{int(step):05d}" | |
| if not where.is_dir(): | |
| raise SystemExit(f"no checkpoint {where.name}; have {', '.join(p.name for p in found)}") | |
| return where | |
| def merged_dir(run: Path, step: int) -> Path: | |
| return run / f"merged-step-{step:05d}" | |
| def export_snapshot(run: Path, snapshot: Path, out: Path, device: str = "cpu") -> Path: | |
| import torch | |
| from transformers import AutoModelForCausalLM | |
| from ccslm.train import export | |
| config = read_json(run / "config.json", {}) | |
| state = read_json(snapshot / "state.json", {}) | |
| method = state.get("method") or config.get("method") or "lora" | |
| start = Path(config["start_from"]) if config.get("start_from") else pinned() | |
| if method == "lora": | |
| from peft import PeftModel | |
| model = AutoModelForCausalLM.from_pretrained(str(start), dtype=torch.bfloat16) | |
| model = PeftModel.from_pretrained(model, str(snapshot)) | |
| else: | |
| model = AutoModelForCausalLM.from_pretrained(str(snapshot), dtype=torch.bfloat16) | |
| model.to(device) | |
| export(model, method, start, pinned(), out) | |
| log(f"step {state.get('step')} ({method}) merged into {out}") | |
| return out | |
| def main() -> None: | |
| parser = argparse.ArgumentParser(description="merge a numbered checkpoint into a servable model") | |
| parser.add_argument("--run", required=True, help="the training run folder, e.g. out/runs/A") | |
| parser.add_argument("--step", default="latest", help="step number or latest") | |
| parser.add_argument("--out", default="", help="default: <run>/merged-step-NNNNN") | |
| parser.add_argument("--device", default="cpu") | |
| parser.add_argument("--list", action="store_true") | |
| args = parser.parse_args() | |
| run = Path(args.run) | |
| if args.list: | |
| for snap in snapshots(run): | |
| state: dict[str, Any] = read_json(snap / "state.json", {}) | |
| merged = merged_dir(run, int(state.get("step", 0))) | |
| print(json.dumps({"checkpoint": snap.name, **{k: state.get(k) for k in ("step", "loss", "eval_loss", "seen_tokens")}, "merged": merged.is_dir()})) | |
| return | |
| snapshot = find(run, args.step) | |
| step = int(read_json(snapshot / "state.json", {}).get("step") or snapshot.name.split("-")[-1]) | |
| export_snapshot(run, snapshot, Path(args.out) if args.out else merged_dir(run, step), args.device) | |
| if __name__ == "__main__": | |
| main() | |