File size: 5,023 Bytes
9d6c005 | 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 | """Make publication figures from recorded measurements; never simulated gains."""
from pathlib import Path
import argparse,csv,json
import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
ROOT=Path(__file__).resolve().parents[1]
plt.rcParams.update({"font.family":"DejaVu Sans","font.size":10,"axes.spines.top":False,"axes.spines.right":False})
COLORS={"raw_importance":"#788995","screen_cv":"#ca8845","world_cv":"#116e83","world_active_cv":"#9a4966","world_guarded_cv":"#298653","constant_world_cv":"#555e62","neural_cv":"#6d6dc4"}
LABELS={"raw_importance":"Raw importance","screen_cv":"Screen memory","world_cv":"World memory","world_active_cv":"Active world","world_guarded_cv":"Guarded active","constant_world_cv":"Constant prior","neural_cv":"Neural prior"}
FIGURES=ROOT/"figures_reproduced"
def save(fig,name):
FIGURES.mkdir(parents=True,exist_ok=True)
for ext in ("png","pdf"):fig.savefig(FIGURES/f"{name}.{ext}",dpi=180,bbox_inches="tight")
plt.close(fig)
def run(results="results",output="figures_reproduced"):
global FIGURES
FIGURES=ROOT/output;result_dir=ROOT/results
initial=json.loads((result_dir/"rendering_report.json").read_text())
follow=json.loads((result_dir/"followup_report.json").read_text())
fig,axes=plt.subplots(1,2,figsize=(11,4.3))
for ax,report,phase,methods,title in [
(axes[0],initial,"revisit",["raw_importance","screen_cv","world_cv","world_active_cv"],"Initial study: revisit"),
(axes[1],follow,"hidden_change",["raw_importance","screen_cv","world_cv","world_active_cv","world_guarded_cv"],"Independent scenes: hidden change")]:
values=[next(s for s in report["summary"] if s["phase"]==phase and s["method"]==m) for m in methods]
y=np.array([v["expected_mse"] for v in values]);ci=np.array([v["expected_mse_scene_bootstrap_95"] for v in values])
ax.bar(np.arange(len(methods)),y,color=[COLORS[m] for m in methods],width=.68)
ax.errorbar(np.arange(len(methods)),y,yerr=np.stack([y-ci[:,0],ci[:,1]-y]),fmt="none",color="#243746",capsize=3)
ax.set_xticks(np.arange(len(methods)),[LABELS[m] for m in methods],rotation=25,ha="right",fontsize=9)
ax.set_title(title,fontweight="bold");ax.set_ylabel("Expected linear RGB MSE")
ax.ticklabel_format(axis="y",style="sci",scilimits=(0,0));ax.grid(axis="y",alpha=.18)
fig.suptitle("Two shadow rays per receiver per frame; 95% scene-bootstrap intervals",y=1.01,fontsize=12)
fig.tight_layout();save(fig,"physical_results")
rows=list(csv.DictReader((result_dir/"followup_raw.csv").open()))
fig,ax=plt.subplots(figsize=(8,4))
for method in ["raw_importance","screen_cv","world_cv","world_active_cv","world_guarded_cv"]:
y=[np.mean([float(r["conditional_expected_mse"]) for r in rows if r["phase"]=="hidden_change" and int(r["phase_frame"])==i and r["method"]==method]) for i in range(8)]
ax.plot(range(8),y,marker="o",label=LABELS[method],color=COLORS[method],lw=2)
ax.set(xlabel="Frame after unannounced geometry change",ylabel="Expected linear RGB MSE",title="Trust revocation cannot prevent the first surprise frame")
ax.set_xticks(range(8));ax.grid(alpha=.2)
ax.legend(fontsize=9,ncol=3,loc="upper center",bbox_to_anchor=(.5,-.2))
fig.tight_layout();save(fig,"change_recovery")
snapshots=np.load(result_dir/"rendering_example_frames.npz",allow_pickle=False)
fig,axes=plt.subplots(2,4,figsize=(10,5.6))
for row,phase in enumerate(("revisit","hidden_change")):
for col,method in enumerate(("reference","raw_importance","screen_cv","world_cv")):
im=snapshots[f"{phase}_{method}"]
axes[row,col].imshow(np.clip(im,0,1)**(1/2.2),origin="lower",interpolation="nearest")
axes[row,col].set_title("Exact finite-light" if method=="reference" else LABELS[method],fontsize=10)
axes[row,col].set_xticks([]);axes[row,col].set_yticks([])
axes[row,0].set_ylabel("Revisit" if row==0 else "First change frame",fontsize=10)
fig.suptitle("One recorded scene/seed; preview clipping is excluded from reported error metrics",fontsize=11)
fig.tight_layout();save(fig,"physical_frames")
training=json.loads((ROOT/"results/training.json").read_text())
fig,ax=plt.subplots(figsize=(6,3.1))
ax.plot([v["epoch"] for v in training["history"]],[v["validation_bce"] for v in training["history"]],color="#116e83",lw=2)
ax.axvline(training["selected_epoch"],color="#ca8845",linestyle="--",label=f"Selected epoch {training['selected_epoch']}")
ax.set(xlabel="Epoch",ylabel="Validation binary cross-entropy",title="Later training overfits this small scene collection")
ax.legend();ax.grid(alpha=.2);fig.tight_layout();save(fig,"training_curve")
if __name__=="__main__":
parser=argparse.ArgumentParser();parser.add_argument("--results",default="results")
parser.add_argument("--output",default="figures_reproduced")
args=parser.parse_args();run(args.results,args.output)
|