Add brains/sovereign-nano/upload_to_hf.py
Browse files
brains/sovereign-nano/upload_to_hf.py
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
upload_to_hf.py — one-shot upload of SOVEREIGN-nano deliverables to:
|
| 4 |
+
|
| 5 |
+
https://huggingface.co/amer224/botfromdeep (MODEL repo, public)
|
| 6 |
+
|
| 7 |
+
brains/sovereign-nano/ <- NEW folder (the v3 folder is NOT
|
| 8 |
+
model_nano.py touched or deleted)
|
| 9 |
+
nano_notes.md
|
| 10 |
+
README.md
|
| 11 |
+
sovereign_nano_init.pt (random-init weights; optional, ~13MB)
|
| 12 |
+
|
| 13 |
+
Usage:
|
| 14 |
+
pip install huggingface_hub # and torch, to export init weights
|
| 15 |
+
HF_TOKEN="hf_..." python upload_to_hf.py --with-weights
|
| 16 |
+
|
| 17 |
+
(No Python at hand? The SOVEREIGN website ships a one-click browser
|
| 18 |
+
uploader that pushes the same code/doc files to this repo with the
|
| 19 |
+
official Hugging Face JS SDK — paste the token, click once.)
|
| 20 |
+
|
| 21 |
+
Security: the token is read ONLY from the environment and is never written
|
| 22 |
+
to disk, logged, or embedded in any file. The owner rotates it after the
|
| 23 |
+
project ends — do not paste it anywhere except your shell environment.
|
| 24 |
+
"""
|
| 25 |
+
|
| 26 |
+
from __future__ import annotations
|
| 27 |
+
|
| 28 |
+
import os
|
| 29 |
+
import sys
|
| 30 |
+
from pathlib import Path
|
| 31 |
+
|
| 32 |
+
HERE = Path(__file__).resolve().parent
|
| 33 |
+
REPO = "amer224/botfromdeep" # MODEL repo (not dataset)
|
| 34 |
+
REPO_TYPE = "model"
|
| 35 |
+
FOLDER = "brains/sovereign-nano" # NEW folder — leaves brains/sovereign-v3/ intact
|
| 36 |
+
|
| 37 |
+
FILES = ["model_nano.py", "opt.py", "bench.py", "distill_nano.py",
|
| 38 |
+
"quantize_cpu.py", "nano_notes.md", "README.md"]
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def export_init_weights(path: Path) -> bool:
|
| 42 |
+
"""Random-init weights are acceptable per the brief; training happens
|
| 43 |
+
in the shared pipeline. Nano init is only ~13 MB (vs the 290M v3's
|
| 44 |
+
~1.1 GB) — cheap to include."""
|
| 45 |
+
try:
|
| 46 |
+
import torch
|
| 47 |
+
sys.path.insert(0, str(HERE))
|
| 48 |
+
from model_nano import make_nano, count_params # noqa: E402
|
| 49 |
+
torch.manual_seed(0)
|
| 50 |
+
m = make_nano()
|
| 51 |
+
torch.save({"config": m.cfg, "state_dict": m.state_dict()}, path)
|
| 52 |
+
print(f"[weights] exported {path.name} "
|
| 53 |
+
f"({count_params(m):,} params, random init, seed 0)")
|
| 54 |
+
return True
|
| 55 |
+
except ImportError as e:
|
| 56 |
+
print(f"[weights] skipped (torch unavailable): {e}")
|
| 57 |
+
return False
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def main() -> int:
|
| 61 |
+
token = os.environ.get("HF_TOKEN")
|
| 62 |
+
if not token:
|
| 63 |
+
print("ERROR: set HF_TOKEN in the environment first.")
|
| 64 |
+
print(" export HF_TOKEN=\"hf_...\" # rotating key, never commit it")
|
| 65 |
+
return 1
|
| 66 |
+
|
| 67 |
+
try:
|
| 68 |
+
from huggingface_hub import HfApi
|
| 69 |
+
except ImportError:
|
| 70 |
+
print("ERROR: pip install huggingface_hub first")
|
| 71 |
+
return 1
|
| 72 |
+
|
| 73 |
+
# optional: regenerate/export random-init checkpoint
|
| 74 |
+
weights = HERE / "sovereign_nano_init.pt"
|
| 75 |
+
if "--with-weights" in sys.argv and not weights.exists():
|
| 76 |
+
export_init_weights(weights)
|
| 77 |
+
|
| 78 |
+
# a short README inside the folder
|
| 79 |
+
readme = HERE / "README.md"
|
| 80 |
+
readme.write_text(
|
| 81 |
+
"# SOVEREIGN-nano (<=5M params)\n\n"
|
| 82 |
+
"The fast half of the SOVEREIGN system: rollout engine, "
|
| 83 |
+
"distillation student for the v3 teacher, and CPU-trainable "
|
| 84 |
+
"sanity baseline.\n\n"
|
| 85 |
+
"- `model_nano.py` — model + stage_a_loss + real-shard prep + "
|
| 86 |
+
"smoke test (run `python model_nano.py`; loads the real shard "
|
| 87 |
+
"via $HF_TOKEN). Same contract as SOVEREIGN v3.\n"
|
| 88 |
+
"- `nano_notes.md` — architecture, memory/speed math, the real "
|
| 89 |
+
"shard schema, the six fixed v3-review bugs, honest "
|
| 90 |
+
"limitations.\n"
|
| 91 |
+
"- `sovereign_nano_init.pt` — optional random-init checkpoint "
|
| 92 |
+
"(seed 0).\n\n"
|
| 93 |
+
"Training happens in the shared pipeline. No live-site "
|
| 94 |
+
"automation, no Kaggle quota use.\n")
|
| 95 |
+
|
| 96 |
+
api = HfApi(token=token)
|
| 97 |
+
uploads = FILES
|
| 98 |
+
if weights.exists():
|
| 99 |
+
uploads.append(weights.name)
|
| 100 |
+
for name in uploads:
|
| 101 |
+
api.upload_file(
|
| 102 |
+
path_or_fileobj=str(HERE / name),
|
| 103 |
+
path_in_repo=f"{FOLDER}/{name}",
|
| 104 |
+
repo_id=REPO,
|
| 105 |
+
repo_type=REPO_TYPE,
|
| 106 |
+
commit_message=f"sovereign-nano: add {name}",
|
| 107 |
+
)
|
| 108 |
+
print(f"[uploaded] {FOLDER}/{name}")
|
| 109 |
+
print(f"\nDone. Folder: https://huggingface.co/{REPO}/tree/main/{FOLDER}")
|
| 110 |
+
print("(brains/sovereign-v3/ was left untouched.)")
|
| 111 |
+
return 0
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
if __name__ == "__main__":
|
| 115 |
+
raise SystemExit(main())
|