File size: 7,604 Bytes
1a18f22 | 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 130 131 | """FID (1-2k samples) per backbone x dataset + clear same-mask aligned viz.
A) fid-sample: train_fraction=1.0, mask_aug, n_per_mask -> ~1.6-2.6k synth; FID vs real train.
B) align-sample: f50 masks, NO aug, 1/mask -> all backbones share identical real masks -> aligned grid.
Then pytorch_fid per pair + build [mask|real|4 backbones] grids. GPU0-5 pool."""
import os, time, json, re, subprocess
import numpy as np
import matplotlib; matplotlib.use("Agg")
import matplotlib.pyplot as plt
from PIL import Image
ROOT = "/home/wzhang/LSC/Code/NPJ"; DR = "/home/wzhang/LSC/Dataset/Segmentation/processed_unified"
PY = "/opt/anaconda3/envs/seggen/bin/python"; GPUS = [0, 1, 2, 3, 4, 5]
os.chdir(ROOT); LOGD = os.path.join(ROOT, "logs", "fidviz"); os.makedirs(LOGD, exist_ok=True)
def log(m):
line = f"[{time.strftime('%F %T')}] {m}"; open(os.path.join(LOGD, "status.md"), "a").write(line + "\n"); print(line, flush=True)
# (ds, proto, total, npm_for_fid)
DSETS = {"isic": ("medsegdb_isic2018", "holdout", 2582, 1),
"kvasir": ("kvasir_seg", "official", 800, 2),
"busi": ("busi", "fold01", 545, 3)}
BKS = ["jit", "pixelgen", "deco", "pixeldit"]; LAB = {"jit": "JiT", "pixelgen": "PixelGen", "deco": "DeCo", "pixeldit": "PixelDiT"}
jobs = {}
def add(jid, cmd, deps=(), done_path=None, done_min=1):
jobs[jid] = {"cmd": cmd, "deps": list(deps), "done_path": done_path, "done_min": done_min, "state": "pending", "tries": 0, "gpu": None}
for bk in BKS:
for dk, (ds, proto, tot, npm) in DSETS.items():
ck = f"pretrained/pixdiff/p1_{bk}_{dk}.pt"
fsd = f"{DR}/{ds}/{proto}/synth_fid_{bk}_{dk}"
add(f"fidsamp_{bk}_{dk}",
f"{PY} -m framework.synth.pixdiff.sample --ckpt {ck} --data_root {DR} --dataset {ds} --protocol {proto} "
f"--train_fraction 1.0 --fraction_seed 0 --n_per_mask {npm} --mask_aug --num_steps 50 --out_dir {fsd}",
done_path=os.path.join(fsd, "images"), done_min=int(0.8 * tot * npm))
real = f"{DR}/{ds}/{proto}/train/images"
flog = os.path.join(LOGD, f"fid_{bk}_{dk}.log"); fok = os.path.join(LOGD, f"fid_{bk}_{dk}.ok")
add(f"fid_{bk}_{dk}",
f"{PY} -m pytorch_fid {real} {fsd}/images --device cuda --batch-size 64 > {flog} 2>&1 && grep -q FID {flog} && touch {fok}",
deps=[f"fidsamp_{bk}_{dk}"], done_path=fok)
f50 = 50 / tot; asd = f"{DR}/{ds}/{proto}/synth_align_{bk}_{dk}"
add(f"alignsamp_{bk}_{dk}",
f"{PY} -m framework.synth.pixdiff.sample --ckpt {ck} --data_root {DR} --dataset {ds} --protocol {proto} "
f"--train_fraction {f50} --fraction_seed 0 --n_per_mask 1 --num_steps 50 --out_dir {asd}",
done_path=os.path.join(asd, "images"), done_min=40)
def is_done(j):
p = j["done_path"]
if not p or not os.path.exists(p): return False
if os.path.isdir(p):
try: return len(os.listdir(p)) >= j["done_min"]
except OSError: return False
return True
for jid, j in jobs.items():
if is_done(j): j["state"] = "done"
def deps_done(j): return all(jobs[d]["state"] == "done" for d in j["deps"])
running = {}; free = set(GPUS); last = 0
log(f"START {len(jobs)} jobs on {GPUS}")
while True:
if all(j["state"] in ("done", "failed") for j in jobs.values()): break
for jid, j in jobs.items():
if not free: break
if j["state"] == "pending" and deps_done(j):
if is_done(j): j["state"] = "done"; continue
g = free.pop()
env = dict(os.environ, CUDA_DEVICE_ORDER="PCI_BUS_ID", CUDA_VISIBLE_DEVICES=str(g), TORCHDYNAMO_DISABLE="1", PYTHONPATH=".", OMP_NUM_THREADS="4")
lf = open(os.path.join(LOGD, jid + ".log"), "a")
p = subprocess.Popen(j["cmd"], shell=True, env=env, stdout=lf, stderr=subprocess.STDOUT, cwd=ROOT)
running[g] = (jid, p, lf); j["state"] = "running"; j["gpu"] = g; j["tries"] += 1
log(f"LAUNCH {jid} GPU{g} try{j['tries']}")
for g, (jid, p, lf) in list(running.items()):
rc = p.poll()
if rc is None: continue
lf.close(); del running[g]; free.add(g); j = jobs[jid]
if is_done(j): j["state"] = "done"; log(f"DONE {jid}")
elif j["tries"] < 2: j["state"] = "pending"; log(f"RETRY {jid} rc={rc}")
else: j["state"] = "failed"; log(f"FAILED {jid} rc={rc}")
if time.time() - last > 180:
cnt = {s: sum(1 for j in jobs.values() if j["state"] == s) for s in ("done", "running", "pending", "failed")}; log(f"SUMMARY {cnt}"); last = time.time()
time.sleep(8)
# ---- parse FID ----
fid = {}
for bk in BKS:
for dk in DSETS:
lg = os.path.join(LOGD, f"fid_{bk}_{dk}.log")
if os.path.exists(lg):
m = re.findall(r"FID:\s*([0-9.]+)", open(lg).read())
if m: fid[f"{dk}_{bk}"] = float(m[-1])
json.dump(fid, open(os.path.join(LOGD, "fid_results.json"), "w"), indent=2)
log(f"FID: {fid}")
# ---- aligned grids ([mask | real | 4 backbones], same real mask per column) ----
def rgb(p): return np.asarray(Image.open(p).convert("RGB").resize((256, 256)))
def gray(p): return np.asarray(Image.open(p).convert("L").resize((256, 256)))
def fmap(d):
p = os.path.join(d, "images"); m = {}
if os.path.isdir(p):
for f in sorted(os.listdir(p)):
if f.endswith(".png"): m.setdefault(f[:-4].split("__")[0], os.path.join(p, f))
return m
for dk, (ds, proto, tot, npm) in DSETS.items():
base = f"{DR}/{ds}/{proto}"; ri, rm = f"{base}/train/images", f"{base}/train/masks"
maps = {bk: fmap(f"{base}/synth_align_{bk}_{dk}") for bk in BKS}
common = set(os.path.splitext(f)[0] for f in os.listdir(ri) if f.endswith(".png"))
for bk in BKS: common &= set(maps[bk].keys())
common = sorted(common); ncol = min(6, len(common))
if ncol == 0: continue
idx = [round(i * (len(common) - 1) / (ncol - 1)) for i in range(ncol)] if ncol > 1 else [0]
cases = [common[i] for i in idx]
rows = [("Conditioning mask", "mask"), ("Real image", "real")] + [(LAB[bk], bk) for bk in BKS]
fig, ax = plt.subplots(len(rows), ncol, figsize=(ncol * 1.9, len(rows) * 1.95))
for r, (labr, kind) in enumerate(rows):
for c, bs in enumerate(cases):
a = ax[r][c]
try:
mk = gray(f"{rm}/{bs}.png")
if kind == "mask":
a.imshow(mk, cmap="gray")
elif kind == "real":
a.imshow(rgb(f"{ri}/{bs}.png")); a.contour((mk > 127).astype(float), levels=[0.5], colors=["#19f04b"], linewidths=1.0)
else:
a.imshow(rgb(maps[kind][bs])); a.contour((mk > 127).astype(float), levels=[0.5], colors=["#19f04b"], linewidths=1.0)
except Exception:
a.imshow(np.ones((256, 256, 3))); a.text(0.5, 0.5, "n/a", ha="center", va="center", transform=a.transAxes, fontsize=8)
a.set_xticks([]); a.set_yticks([])
for s in a.spines.values(): s.set_visible(False)
if c == 0: a.set_ylabel(labr, fontsize=10, rotation=90, va="center", labelpad=8, color=("#111" if r < 2 else "#1a3b8b"))
fig.suptitle(f"{dk.upper()} — same-mask aligned: every backbone generates the SAME real mask (row 1)\n"
f"Row2=real image; rows 3-6=each backbone's mask-conditioned synthesis (green=that mask). Proves mask guidance.", fontsize=10)
plt.tight_layout(rect=[0.02, 0, 1, 0.94]); plt.savefig(f"/tmp/p1_aligned_{dk}.png", dpi=145, bbox_inches="tight", facecolor="white")
log(f"aligned grid saved /tmp/p1_aligned_{dk}.png")
log("ALL DONE"); print("FIDVIZ_DONE", flush=True)
|