File size: 5,309 Bytes
f065e53 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | """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()
|