SplatAtlas / scripts /print_efficiency.py
KCBtheone's picture
Upload SplatAtlas benchmark pipeline code
23e73f9 verified
Raw
History Blame Contribute Delete
5.39 kB
#!/usr/bin/env python3
"""
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:
# mean of last 10% steps (stable phase)
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 # ms/iter
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 ──────────────────────────────────────────────────────────────
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))
# ── Per-method averages ────────────────────────────────────────────────
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()