spatial-semanticist-L-migration / code /hf_ckpt_watcher.py
a12s12's picture
Super-squash branch 'main' using huggingface_hub
f065e53
Raw
History Blame Contribute Delete
5.31 kB
"""HF ckpt watcher โ€” rate-limit ์นœํ™” ๋ฒ„์ „ (HF ์ปค๋ฐ‹ 128/hour ์ œํ•œ ๋Œ€์‘).
ํ•ต์‹ฌ: ์ปค๋ฐ‹ ์ˆ˜ ์ตœ์†Œํ™”.
- ๋ฌด๊ฑฐ์šด ๋™๊ธฐํ™”(ckpt+logs+plot)๋Š” '์ƒˆ 10k ckpt๊ฐ€ ์ƒ๊ฒผ์„ ๋•Œ๋งŒ' ์ˆ˜ํ–‰.
- ์ƒ˜ํ”Œ/ckpt๋Š” upload_folder๋กœ 'ํด๋”๋‹น 1์ปค๋ฐ‹' (ํŒŒ์ผ๋ณ„ ์ปค๋ฐ‹ ๊ธˆ์ง€ โ€” ์ด์ „ ๋ฒ„์ „์ด 429 ์œ ๋ฐœ).
- ckpt: ์ตœ์‹  KEEP๊ฐœ๋งŒ ์œ ์ง€ (๋กœํ…Œ์ด์…˜). ์ƒ˜ํ”Œ: ์ „๋ถ€ ์œ ์ง€.
usage: python hf_ckpt_watcher.py (setsid nohup / harness background)
"""
import os, re, time
from huggingface_hub import HfApi
TOKEN = os.environ.get("HF_TOKEN", "<SET_HF_TOKEN_ENV>")
REPO = "a12s12/spatial-semanticist-L-migration"
BASE = "/NHNHOME/WORKSPACE/0226010398_A/sr_diffusion/clevr_sudoku/semanticist/output/tokenizer/models_l_spatial"
MODELS_DIR = os.path.join(BASE, "models")
IMAGES_DIR = os.path.join(BASE, "images")
LOGDIR = os.path.join(BASE, "logs/semanticist")
KEEP = 2
POLL_SEC = 300 # 5๋ถ„ ํด๋ง (์ปค๋ฐ‹ ์ ˆ์•ฝ)
REQUIRED = ["model.safetensors", "optimizer.bin"]
api = HfApi(token=TOKEN)
def local_complete_steps():
out = []
if not os.path.isdir(MODELS_DIR):
return out
for name in os.listdir(MODELS_DIR):
m = re.fullmatch(r"step(\d+)", name)
if m:
d = os.path.join(MODELS_DIR, name)
if all(os.path.exists(os.path.join(d, r)) for r in REQUIRED):
out.append(int(m.group(1)))
return sorted(out)
def hf_steps():
steps = set()
for f in api.list_repo_files(REPO):
m = re.match(r"step(\d+)/", f)
if m:
steps.add(int(m.group(1)))
return sorted(steps)
def sync_samples():
"""IMAGES_DIR ์ „์ฒด๋ฅผ samples_all_steps/ ๋กœ upload_folder (๋ณ€๊ฒฝ๋ถ„๋งŒ 1์ปค๋ฐ‹)."""
if os.path.isdir(IMAGES_DIR):
api.upload_folder(folder_path=IMAGES_DIR, path_in_repo="samples_all_steps",
repo_id=REPO, repo_type="model",
allow_patterns=["*.jpg"],
commit_message="sync recon samples")
def sync_logs():
"""loss ๊ทธ๋ž˜ํ”„ ๊ฐฑ์‹  + tensorboard event (์ƒˆ ckpt milestone์—์„œ๋งŒ ํ˜ธ์ถœ)."""
try:
import make_loss_plot
make_loss_plot.main()
png = os.path.join(BASE, "loss_curves.png")
if os.path.exists(png):
api.upload_file(path_or_fileobj=png, path_in_repo="loss_curves.png",
repo_id=REPO, repo_type="model",
commit_message="update loss curves")
except Exception as e:
print(f"[watcher] plot skip: {e}", flush=True)
if os.path.isdir(LOGDIR):
api.upload_folder(folder_path=LOGDIR, path_in_repo="logs",
repo_id=REPO, repo_type="model",
allow_patterns=["events*"],
commit_message="update tb logs")
def sync_ckpts():
"""์ตœ์‹  KEEP๊ฐœ ๋กœ์ปฌ ckpt๋งŒ HF์— ์œ ์ง€. ๋ฐ˜ํ™˜: ์ตœ์‹  step (์—†์œผ๋ฉด None)."""
local = local_complete_steps()
if not local:
return None
on_hf = set(hf_steps())
target = set(local[-KEEP:])
for s in sorted(target - on_hf):
print(f"[watcher] uploading step{s} ...", flush=True)
api.upload_folder(folder_path=os.path.join(MODELS_DIR, f"step{s}"),
path_in_repo=f"step{s}", repo_id=REPO, repo_type="model",
commit_message=f"ckpt step{s}")
print(f"[watcher] step{s} uploaded", flush=True)
pruned = sorted(on_hf - target)
for old in pruned:
print(f"[watcher] pruning HF step{old}", flush=True)
api.delete_folder(path_in_repo=f"step{old}", repo_id=REPO, repo_type="model",
commit_message=f"prune step{old} (keep newest {KEEP})")
# โ˜… private repo ์ €์žฅํ•œ๋„ ๋Œ€์‘: ๋กœํ…Œ์ด์…˜์œผ๋กœ ์ง€์šด ckpt๋Š” git history์— LFS blob์ด
# ๋‚จ์•„ ์šฉ๋Ÿ‰์„ ์žก์•„๋จน๋Š”๋‹ค. prune์ด ์žˆ์—ˆ์œผ๋ฉด history๋ฅผ squashํ•ด์„œ ์‹ค์ œ๋กœ ํšŒ์ˆ˜.
if pruned:
try:
api.super_squash_history(repo_id=REPO, repo_type="model")
print(f"[watcher] squashed history (freed rotated ckpt LFS)", flush=True)
except Exception as e:
print(f"[watcher] squash skip: {str(e)[:120]}", flush=True)
return local[-1]
def main():
print(f"[watcher] start (rate-safe). keep={KEEP} poll={POLL_SEC}s repo={REPO}", flush=True)
last_milestone = None
while True:
try:
local = local_complete_steps()
newest = local[-1] if local else None
# ์ƒˆ 10k ckpt๊ฐ€ ์ƒ๊ฒผ์„ ๋•Œ๋งŒ ๋ฌด๊ฑฐ์šด ์ „์ฒด ๋™๊ธฐํ™” (์ปค๋ฐ‹ ์ ˆ์•ฝ)
if newest is not None and newest != last_milestone:
print(f"[watcher] new milestone step{newest} -> full sync", flush=True)
new_top = sync_ckpts()
sync_samples()
sync_logs()
last_milestone = new_top
print(f"[watcher] synced. HF ckpt newest {KEEP} up to step{new_top}", flush=True)
else:
# milestone ์‚ฌ์ด์—” ์ƒ˜ํ”Œ๋งŒ ๊ฐ€๋ณ๊ฒŒ (upload_folder=๋ณ€๊ฒฝ๋ถ„ 1์ปค๋ฐ‹)
sync_samples()
except Exception as e:
print(f"[watcher] error (๋‹ค์Œ ํด๋ง์— ์žฌ์‹œ๋„): {str(e)[:200]}", flush=True)
time.sleep(POLL_SEC)
if __name__ == "__main__":
main()