Upload a100_train.py with huggingface_hub
Browse files- a100_train.py +94 -0
a100_train.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
clankerDiffusion — single 80GB A100 training launcher.
|
| 3 |
+
|
| 4 |
+
Target: 0.8B model (~08b config), 8k train context with NTK RoPE scaling
|
| 5 |
+
(rope_scale=16) so it extends to 128k at inference. Trains up to --hours
|
| 6 |
+
(12h/session, interruptible) and RESUMES from the latest checkpoint, so you
|
| 7 |
+
can chain several 12h sessions to reach the 20h budget.
|
| 8 |
+
|
| 9 |
+
Run on the A100 box (after `pip install torch ... numpy tokenizers datasets
|
| 10 |
+
safetensors huggingface_hub` and `export HF_TOKEN=...`):
|
| 11 |
+
python a100_train.py --hours 12 --size 08b --scale 4
|
| 12 |
+
|
| 13 |
+
Data is regenerated in-container by prep.py (fast HF egress); the scale is
|
| 14 |
+
chosen so the 0.8B model sees enough tokens within the budget.
|
| 15 |
+
"""
|
| 16 |
+
import os
|
| 17 |
+
import subprocess
|
| 18 |
+
import argparse
|
| 19 |
+
|
| 20 |
+
HERE = os.path.dirname(os.path.abspath(__file__))
|
| 21 |
+
DATA_DIR = os.path.join(HERE, "data")
|
| 22 |
+
CKPT_DIR = os.path.join(HERE, "checkpoints")
|
| 23 |
+
|
| 24 |
+
# 0.8B config (also in modal_train.py SIZES["08b"]).
|
| 25 |
+
SIZES = {
|
| 26 |
+
"08b": dict(d_model=1536, n_layers=20, n_heads=16, d_ff=4096, batch=12),
|
| 27 |
+
"base": dict(d_model=768, n_layers=12, n_heads=12, d_ff=2048, batch=24),
|
| 28 |
+
"large": dict(d_model=2048, n_layers=24, n_heads=16, d_ff=5504, batch=8),
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def main(hours=12.0, size="08b", scale=4.0, batch=None, ckpt_every=250,
|
| 33 |
+
seq_len=8192, rope_scale=16.0):
|
| 34 |
+
os.makedirs(DATA_DIR, exist_ok=True)
|
| 35 |
+
os.makedirs(CKPT_DIR, exist_ok=True)
|
| 36 |
+
|
| 37 |
+
# pull latest code so cloud + local stay in sync (optional; needs HF_TOKEN)
|
| 38 |
+
tok_path = os.path.join(DATA_DIR, "tokenizer.json")
|
| 39 |
+
if not os.path.exists(tok_path) and os.environ.get("HF_TOKEN"):
|
| 40 |
+
try:
|
| 41 |
+
from huggingface_hub import hf_hub_download
|
| 42 |
+
hf_hub_download(repo_id="coderofpears/clankerDiffusion-base",
|
| 43 |
+
filename="data/tokenizer.json", repo_type="model",
|
| 44 |
+
local_dir=DATA_DIR, token=os.environ.get("HF_TOKEN"))
|
| 45 |
+
except Exception as e:
|
| 46 |
+
print(f"[a100] tokenizer fetch skipped: {e}")
|
| 47 |
+
|
| 48 |
+
# (re)generate data if incomplete
|
| 49 |
+
meta_path = os.path.join(DATA_DIR, "meta.json")
|
| 50 |
+
if not os.path.exists(meta_path):
|
| 51 |
+
stale = os.path.join(DATA_DIR, "train.bin")
|
| 52 |
+
if os.path.exists(stale):
|
| 53 |
+
os.remove(stale)
|
| 54 |
+
print(f"[a100] generating data (scale={scale}) ...")
|
| 55 |
+
subprocess.run(["python", "prep.py", "--out-dir", DATA_DIR,
|
| 56 |
+
"--scale", str(scale)], check=True)
|
| 57 |
+
|
| 58 |
+
spec = dict(SIZES.get(size, SIZES["08b"]))
|
| 59 |
+
if batch:
|
| 60 |
+
spec["batch"] = batch
|
| 61 |
+
|
| 62 |
+
cmd = [
|
| 63 |
+
"python", "train.py",
|
| 64 |
+
"--hours", str(hours),
|
| 65 |
+
"--batch", str(spec["batch"]),
|
| 66 |
+
"--ckpt-every", str(ckpt_every),
|
| 67 |
+
"--data-dir", DATA_DIR,
|
| 68 |
+
"--ckpt-dir", CKPT_DIR,
|
| 69 |
+
"--hf-repo", "coderofpears/clankerDiffusion-checkpoints",
|
| 70 |
+
"--d-model", str(spec["d_model"]),
|
| 71 |
+
"--n-layers", str(spec["n_layers"]),
|
| 72 |
+
"--n-heads", str(spec["n_heads"]),
|
| 73 |
+
"--d-ff", str(spec["d_ff"]),
|
| 74 |
+
"--seq-len", str(seq_len),
|
| 75 |
+
"--rope-scale", str(rope_scale),
|
| 76 |
+
]
|
| 77 |
+
print("[a100] launching:", " ".join(cmd), flush=True)
|
| 78 |
+
subprocess.run(cmd, check=True)
|
| 79 |
+
print("[a100] session finished (resume next session with same command)",
|
| 80 |
+
flush=True)
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
if __name__ == "__main__":
|
| 84 |
+
ap = argparse.ArgumentParser()
|
| 85 |
+
ap.add_argument("--hours", type=float, default=12.0)
|
| 86 |
+
ap.add_argument("--size", default="08b")
|
| 87 |
+
ap.add_argument("--scale", type=float, default=4.0)
|
| 88 |
+
ap.add_argument("--batch", type=int, default=None)
|
| 89 |
+
ap.add_argument("--ckpt-every", type=int, default=250)
|
| 90 |
+
ap.add_argument("--seq-len", type=int, default=8192)
|
| 91 |
+
ap.add_argument("--rope-scale", type=float, default=16.0)
|
| 92 |
+
a = ap.parse_args()
|
| 93 |
+
main(hours=a.hours, size=a.size, scale=a.scale, batch=a.batch,
|
| 94 |
+
ckpt_every=a.ckpt_every, seq_len=a.seq_len, rope_scale=a.rope_scale)
|