File size: 5,389 Bytes
23e73f9 | 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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | #!/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()
|