| |
| """ |
| Print Gaussian count, timing, and VRAM for all our completed experiments. |
| |
| Data sources (in priority order): |
| - Gaussian count : PLY header (element vertex N) |
| - iter_time_ms : TensorBoard train/iter_time_ms (last value) |
| - peak_vram_GB : TensorBoard train/peak_vram_GB (max across run) |
| - timing fallback : timing.json cumulative_gpu_time_sec / iters |
| |
| Usage: |
| python scripts/print_efficiency.py |
| """ |
| import os |
| import json |
| import glob |
| import numpy as np |
|
|
| OUTPUTS_ROOT = "/root/autodl-tmp/SplatAtlas/outputs" |
| ITERS = 30000 |
|
|
| KNOWN = ("vanillasgf", "vanilla_3dgs", "vanilla_logged", "vanilla_thresh", |
| "absgs", "pixelgs", "edgeloss") |
|
|
| OUTDOOR_360 = {"bicycle", "flowers", "garden", "stump", "treehill"} |
| INDOOR_360 = {"bonsai", "counter", "kitchen", "room"} |
| TNT = { |
| "auditorium", "ballroom", "courtroom", "family", "francis", "horse", |
| "lighthouse", "m60", "museum", "palace", "panther", "playground", |
| "temple", "train" |
| } |
| ALL_SCENES = OUTDOOR_360 | INDOOR_360 | TNT |
|
|
|
|
| def is_ours(method): |
| return any(method == p or method.startswith(p) for p in KNOWN) |
|
|
|
|
| def parse_dir(d): |
| if d.startswith("vanilla_thresh_"): |
| rest = d[len("vanilla_thresh_"):] |
| for s in ALL_SCENES: |
| if rest == s or rest.startswith(s + "_"): |
| return "vanilla_thresh", s |
| return None, None |
| tok = d.split("_") |
| for i in range(len(tok) - 1, 0, -1): |
| sc = "_".join(tok[i:]) |
| me = "_".join(tok[:i]) |
| if sc in ALL_SCENES: |
| return me, sc |
| return None, None |
|
|
|
|
| def count_gaussians(ply_path): |
| try: |
| with open(ply_path, "rb") as f: |
| for line in f: |
| line = line.decode("ascii", errors="ignore").strip() |
| if line.startswith("element vertex"): |
| return int(line.split()[-1]) |
| if line == "end_header": |
| break |
| except Exception: |
| pass |
| return None |
|
|
|
|
| def read_tb(model_path): |
| """Read last iter_time_ms and max peak_vram_GB from TensorBoard events.""" |
| try: |
| from tensorboard.backend.event_processing.event_accumulator import EventAccumulator |
| ea = EventAccumulator(model_path, size_guidance={"scalars": 0}) |
| ea.Reload() |
| tags = ea.Tags().get("scalars", []) |
|
|
| it_ms = None |
| for tag in ["train/iter_time_ms", "iter_time_ms"]: |
| if tag in tags: |
| vals = ea.Scalars(tag) |
| if vals: |
| |
| n = max(1, len(vals) // 10) |
| it_ms = float(np.mean([v.value for v in vals[-n:]])) |
| break |
|
|
| vram = None |
| for tag in ["train/peak_vram_GB", "peak_vram_GB"]: |
| if tag in tags: |
| vals = ea.Scalars(tag) |
| if vals: |
| vram = float(max(v.value for v in vals)) |
| break |
|
|
| return it_ms, vram |
| except Exception: |
| return None, None |
|
|
|
|
| def read_timing_json(model_path, iters): |
| """Fallback: cumulative_gpu_time_sec from timing.json.""" |
| try: |
| p = os.path.join(model_path, "timing.json") |
| d = json.load(open(p)) |
| cgt = d.get("cumulative_gpu_time_sec") |
| if cgt: |
| return float(cgt) / iters * 1000 |
| except Exception: |
| pass |
| return None |
|
|
|
|
| def main(): |
| plys = sorted(glob.glob( |
| f"{OUTPUTS_ROOT}/*/point_cloud/iteration_{ITERS}/point_cloud.ply")) |
|
|
| rows = [] |
| for ply_path in plys: |
| parts = ply_path.split("/") |
| dirname = parts[-4] |
| method, scene = parse_dir(dirname) |
| if method is None or not is_ours(method): |
| continue |
|
|
| model_path = os.path.join(OUTPUTS_ROOT, dirname) |
| n_gauss = count_gaussians(ply_path) |
| it_ms, vram = read_tb(model_path) |
| if it_ms is None: |
| it_ms = read_timing_json(model_path, ITERS) |
|
|
| rows.append((dirname, method, scene, n_gauss, it_ms, vram)) |
|
|
| |
| print(f"\n{'Dir':<42} {'#Gauss':>10} {'ms/iter':>9} {'PeakGB':>8}") |
| print("-" * 73) |
|
|
| by_method = {} |
| for dirname, method, scene, n, t, v in rows: |
| ns = f"{n:,}" if n else "-" |
| ts = f"{t:.2f}" if t else "-" |
| vs = f"{v:.3f}" if v else "-" |
| print(f"{dirname:<42} {ns:>10} {ts:>9} {vs:>8}") |
| by_method.setdefault(method, []).append((n, t, v)) |
|
|
| |
| print(f"\n{'Method':<35} {'Avg #Gauss':>11} {'Avg ms/iter':>12} {'Avg PeakGB':>11} {'N':>4}") |
| print("-" * 67) |
| for m, vals in sorted(by_method.items()): |
| ns = [x[0] for x in vals if x[0] is not None] |
| ts = [x[1] for x in vals if x[1] is not None] |
| vs = [x[2] for x in vals if x[2] is not None] |
| nav = f"{int(np.mean(ns)):,}" if ns else "-" |
| tav = f"{np.mean(ts):.2f}" if ts else "-" |
| vav = f"{np.mean(vs):.3f}" if vs else "-" |
| print(f"{m:<35} {nav:>11} {tav:>12} {vav:>11} {len(vals):>4}") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|