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)