| |
| """Generation diversity: spread of generated poses ACROSS sampling seeds, per clip. |
| |
| FGD only *implies* mode collapse (its source paper calls it a diversity measure). This |
| measures it directly: for each clip, take the N sampled generations, resample to a common |
| length, and take the per-frame/per-joint sd across seeds. Falling = the conditional |
| distribution is narrowing, i.e. decoding is becoming deterministic. Reported alongside |
| mean length and length sd so a pure length collapse can be told apart from a real one. |
| """ |
| import argparse |
| import glob |
| import os |
| import re |
|
|
| import numpy as np |
|
|
|
|
| def load(p): |
| d = np.load(p, allow_pickle=True) |
| return {n: q for n, q in zip(d["names"], d["poses"])} |
|
|
|
|
| def resamp(x, T): |
| idx = np.linspace(0, len(x) - 1, T) |
| lo, hi = np.floor(idx).astype(int), np.ceil(idx).astype(int) |
| w = (idx - lo)[:, None, None] |
| return x[lo] * (1 - w) + x[hi] * w |
|
|
|
|
| def diversity(paths): |
| ds = [load(p) for p in paths] |
| if len(ds) < 2: |
| return None |
| common = set(ds[0]) |
| for d in ds[1:]: |
| common &= set(d) |
| sds, lsd, mlen = [], [], [] |
| for n in sorted(common): |
| seqs = [np.asarray(d[n], np.float32) for d in ds] |
| L = [len(s) for s in seqs] |
| T = int(np.median(L)) |
| if T < 2: |
| continue |
| lsd.append(float(np.std(L, ddof=1))) |
| mlen.append(float(np.mean(L))) |
| st = np.stack([resamp(s, T) for s in seqs]) |
| sds.append(float(st.std(axis=0, ddof=1).mean())) |
| return {"n_clips": len(sds), "cross_seed_sd": float(np.mean(sds)), |
| "len_sd": float(np.mean(lsd)), "mean_len": float(np.mean(mlen))} |
|
|
|
|
| def main(): |
| ap = argparse.ArgumentParser() |
| ap.add_argument("--dump-dir", required=True) |
| ap.add_argument("--pattern", default="it{it}_s*.npz", |
| help="{it} is substituted with each --iters value") |
| ap.add_argument("--iters", nargs="+", type=int, required=True) |
| args = ap.parse_args() |
| print(f"{'iter':>8} {'cross-seed sd':>14} {'len sd':>9} {'mean len':>9} {'clips':>6}") |
| for it in args.iters: |
| ps = sorted(glob.glob(os.path.join(args.dump_dir, args.pattern.format(it=it)))) |
| r = diversity(ps) |
| if r: |
| print(f"{it:>8} {r['cross_seed_sd']:>14.5f} {r['len_sd']:>9.2f} " |
| f"{r['mean_len']:>9.1f} {r['n_clips']:>6}") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|