| """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 |
| 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})") |
| |
| |
| 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 |
| |
| 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: |
| |
| sync_samples() |
| except Exception as e: |
| print(f"[watcher] error (๋ค์ ํด๋ง์ ์ฌ์๋): {str(e)[:200]}", flush=True) |
| time.sleep(POLL_SEC) |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|