#!/usr/bin/env python3 """Non-learned RGB-D fusion baseline: lock, TRAIN24 fit, sealed DEV/FRESH-V1 evaluation, report.""" # ruff: noqa: E501 -- Chinese report prose from __future__ import annotations import argparse import datetime import itertools import json from collections import defaultdict from pathlib import Path import numpy as np import torch from mcss.geometry import transform_cameras from mcss.measurements import FixedMeasurementRenderer from mcss.mechanism_pilot.direct_capacity_contracts import CapacityEvaluator, StateSealBarrier from mcss.mechanism_pilot.direct_capacity_evaluation import _metrics from mcss.mechanism_pilot.direct_capacity_statistics import TIE, paired from mcss.mechanism_pilot.geometry_carrier_statistics import _evidence, _macro from mcss.mechanism_pilot.rgbd_evidence_carrier import RGBDSceneData from mcss.mechanism_pilot.rgbd_fresh_evaluation import FreshRGBDSceneData from mcss.mechanism_pilot.rgbd_nonlearned_fusion import GRID_SEARCH, fused_state from mcss.mechanism_pilot.small_training import sha, write_json EXPERIMENT = "EXP-3D-RGBD-NONLEARNED-FUSION-V1" V5 = Path("outputs/EXP-3D-RGBD-EVIDENCE-CARRIER-V5") FRESH = Path("outputs/EXP-3D-RGBD-FRESH-QUALIFICATION-V1") INPUTS = ( V5 / "scene_split.json", V5 / "train_depth_prior.json", V5 / "raw/dev_query_results.json", V5 / "raw/dev_reference_rows.json", FRESH / "scene_split.json", FRESH / "train_depth_prior.json", FRESH / "raw/fresh_query_results.json", FRESH / "raw/fresh_reference_rows.json", ) SOURCES = ( Path("src/mcss/mechanism_pilot/rgbd_nonlearned_fusion.py"), Path("src/mcss/mechanism_pilot/rgbd_evidence_carrier.py"), Path("src/mcss/mechanism_pilot/rgbd_fresh_evaluation.py"), Path("src/mcss/measurements.py"), Path(__file__), ) def lock(root): root.mkdir(parents=True, exist_ok=False) write_json( root / "preregistration.json", { "status": "FROZEN_BEFORE_FIT_AND_EVALUATION", "experiment": EXPERIMENT, "created_utc": datetime.datetime.now(datetime.UTC).isoformat(), "grid_search": GRID_SEARCH, "objective": "mean GT-valid query AbsRel (RAW) over TRAIN24 primary queries, roles A/B; " "ties -> first combination in itertools.product order of k, a, b, c", "evaluation": "DEV (8) and FRESH-V1 (5): every state sealed before any query GT; " "same renderer, bounds, anchoring and metric code as V5", "comparisons": { "LEARNED_MINUS_NLF": "AbsRel(NLF) - AbsRel(V5 C1, seed-mean); positive = learned better", "NLF_MINUS_CONSTANT": "AbsRel(REF_TRAIN_ABSREL_OPTIMAL) - AbsRel(NLF); positive = NLF better", "RGB_ONLY_MINUS_NLF": "AbsRel(NLF) - AbsRel(V5 C0); positive = RGB-only carrier better", }, "labels": "ABOVE (frozen V2 evidence rule) / BELOW (mirror) / NOT_DISTINGUISHABLE; " "all scenes and NO_HIT-excluded scenes", "bootstrap": {"unit": "scene", "draws": 10000, "seed": 20260929}, "role": "descriptive control; changes no frozen status", "device": "cpu", "input_sha256": {str(p): sha(p) for p in INPUTS}, "source_sha256": {str(p): sha(p) for p in SOURCES}, }, ) print("LOCKED", root) def verify(root): lock_ = json.loads((root / "preregistration.json").read_text()) if lock_["status"] != "FROZEN_BEFORE_FIT_AND_EVALUATION": raise PermissionError("Frozen lock required") for group in ("input_sha256", "source_sha256"): for name, digest in lock_[group].items(): if sha(Path(name)) != digest: raise PermissionError(f"Frozen file changed: {name}") return lock_ def fit(manifest): renderer = FixedMeasurementRenderer(n_samples=64, ray_chunk_size=2048) records = sorted( (r for r in manifest["scenes"] if r["split"] == "TRAIN"), key=lambda r: r["scene_id"] ) access = [] scenes = [RGBDSceneData(r, manifest, V5, "cpu", access) for r in records] grid = list(itertools.product(*(GRID_SEARCH[k] for k in ("k", "a", "b", "c")))) results = [] for k, a, b, c in grid: params = {"k": k, "a": a, "b": b, "c": c} values = [] for scene in scenes: for role in ("A", "B"): state, anchor = fused_state(scene.context(role), scene.bounds[role], params) for slot in range(len(scene.record["roles"]["primary_query"])): target = scene.target(slot) cameras = transform_cameras(target.cameras, torch.linalg.inv(anchor)) with torch.no_grad(): pred = renderer(state, cameras, ("rgb", "depth", "visibility")) values.append(_metrics(pred, target.rgb, target.depth)["depth_absrel"]) results.append( {**params, "train24_query_absrel": float(np.mean(values)), "views": len(values)} ) print("FIT", params, round(results[-1]["train24_query_absrel"], 4), flush=True) best = min(results, key=lambda r: r["train24_query_absrel"]) return {k: best[k] for k in ("k", "a", "b", "c")}, results def evaluate(manifest, base, split, scene_cls, params, access): records = {r["scene_id"]: r for r in manifest["scenes"] if r["split"] == split} forbidden = set(manifest.get("protected_scene_ids", [])) | { r["scene_id"] for r in manifest["scenes"] if r["split"] != split } keys = [f"{sid}/{role}" for sid in records for role in ("A", "B")] barrier = StateSealBarrier(keys) anchors = {} for sid, record in records.items(): data = scene_cls(record, manifest, base, "cpu", access) for role in ("A", "B"): state, anchor = fused_state(data.context(role), data.bounds[role], params) barrier.seal(f"{sid}/{role}", sid, state) anchors[sid, role] = anchor barrier.assert_ready() access.append({"event": f"ALL_{split}_NLF_STATES_SEALED", "state_count": len(keys)}) renderer = FixedMeasurementRenderer(n_samples=64, ray_chunk_size=2048) rows = [] for sid, record in records.items(): evaluator = CapacityEvaluator( record, manifest["image_size"], base, "cpu", barrier=barrier, capacity_scene_ids=tuple(records), holdout_scene_ids=tuple(forbidden), access_log=access, ) for role in ("A", "B"): state = barrier.state(f"{sid}/{role}") for qid in record["roles"]["primary_query"]: batch = evaluator.query(qid) cameras = transform_cameras(batch.cameras, torch.linalg.inv(anchors[sid, role])) with torch.no_grad(): pred = renderer(state, cameras, ("rgb", "depth", "visibility")) metrics = _metrics(pred, batch.rgb, batch.depth) rows.append( { "scene_id": sid, "role": role, "query_id": qid, "seed": 0, "variant": "NLF", "method": "direct", "depth_absrel": metrics["depth_absrel"], "depth_delta1": metrics["depth_delta1"], "opacity": metrics["opacity"], } ) return rows def label(stats): x = np.asarray(list(stats["per_scene"].values())) if _evidence(stats): return "ABOVE" if stats["mean"] < 0 and stats["ci95"][1] < 0 and np.mean(x <= TIE) >= 0.75: return "BELOW" return "NOT_DISTINGUISHABLE" def compare(nlf_rows, carrier_rows, reference_rows, exclude=()): keep = lambda rows: [r for r in rows if r["scene_id"] not in exclude] # noqa: E731 nlf = _macro(keep(nlf_rows), "depth_absrel") c1 = _macro( keep([r for r in carrier_rows if r["variant"] == "C1" and r["method"] == "direct"]), "depth_absrel", ) c0 = _macro( keep([r for r in carrier_rows if r["variant"] == "C0" and r["method"] == "direct"]), "depth_absrel", ) const = _macro( keep( [ r for r in reference_rows if r["reference"] == "REF_TRAIN_ABSREL_OPTIMAL" and r["readout"] == "RAW" ] ), "depth_absrel", ) args = {"draws": 10000, "seed": 20260929} out = { "means": { k: float(np.mean(list(v.values()))) for k, v in (("NLF", nlf), ("C1", c1), ("C0", c0), ("constant", const)) }, "per_scene": { s: {"NLF": nlf[s], "C1": c1[s], "C0": c0[s], "constant": const[s]} for s in sorted(nlf) }, } for name, stats in ( ("LEARNED_MINUS_NLF", paired(nlf, c1, **args)), ("NLF_MINUS_CONSTANT", paired(const, nlf, **args)), ("RGB_ONLY_MINUS_NLF", paired(nlf, c0, **args)), ): out[name] = {"stats": stats, "label": label(stats)} return out def no_hit(carrier_rows): """Scenes whose every direct V5 prediction had zero opacity (rays outside the bounds).""" groups = defaultdict(list) for r in carrier_rows: if r["method"] == "direct": groups[r["scene_id"]].append(r["opacity"] == 0) return sorted(s for s, flags in groups.items() if all(flags)) def run(root): lock_ = verify(root) v5_manifest = json.loads((V5 / "scene_split.json").read_text()) torch.set_num_threads(1) params, grid = fit(v5_manifest) write_json(root / "fit_results.json", {"selected": params, "grid": grid}) access = [] dev_rows = evaluate(v5_manifest, V5, "DEV", RGBDSceneData, params, access) fresh_manifest = json.loads((FRESH / "scene_split.json").read_text()) fresh_rows = evaluate( fresh_manifest, FRESH, "FRESH_QUALIFICATION", FreshRGBDSceneData, params, access ) write_json(root / "audit/gt_access.json", access) write_json(root / "raw/nlf_dev_rows.json", dev_rows) write_json(root / "raw/nlf_fresh_rows.json", fresh_rows) v5_rows = json.loads((V5 / "raw/dev_query_results.json").read_text()) fresh_carrier = json.loads((FRESH / "raw/fresh_query_results.json").read_text()) dev_ref = json.loads((V5 / "raw/dev_reference_rows.json").read_text()) fresh_ref = json.loads((FRESH / "raw/fresh_reference_rows.json").read_text()) results = { "selected_params": params, "DEV": compare(dev_rows, v5_rows, dev_ref), "DEV_hit_scenes": compare(dev_rows, v5_rows, dev_ref, exclude=no_hit(v5_rows)), "FRESH_V1": compare(fresh_rows, fresh_carrier, fresh_ref), "no_hit_scenes": {"DEV": no_hit(v5_rows), "FRESH_V1": no_hit(fresh_carrier)}, "lock_sha256": sha(root / "preregistration.json"), } write_json(root / "results.json", results) lines = [ f"# {EXPERIMENT}", "", "不经学习的 RGB-D 融合基线:上下文深度直接体素化进同一个 16³ 网格、同一 bounds,用同一个固定 renderer 读出;只有 4 个标量在 TRAIN24 上拟合," f"选中 {params}。所有状态在读取 query GT 之前封存。", "", ] for name in ("DEV", "DEV_hit_scenes", "FRESH_V1"): r = results[name] m = r["means"] lines += [ f"## {name}", "", f"平均 AbsRel:NLF {m['NLF']:.4f},V5 C1(学习,测得深度){m['C1']:.4f},V5 C0(学习,只用 RGB){m['C0']:.4f},常数 {m['constant']:.4f}。", "", ] for key in ("LEARNED_MINUS_NLF", "NLF_MINUS_CONSTANT", "RGB_ONLY_MINUS_NLF"): s = r[key]["stats"] lines.append( f"- {key} = {s['mean']:+.4f},95% CI [{s['ci95'][0]:+.4f}, {s['ci95'][1]:+.4f}],{r[key]['label']}" ) lines.append("") (root / "README.md").write_text("\n".join(lines) + "\n") print( json.dumps( {k: results[k]["means"] for k in ("DEV", "DEV_hit_scenes", "FRESH_V1")}, indent=1 ) ) print("NLF_COMPLETE", lock_["experiment"]) if __name__ == "__main__": parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--stage", choices=("lock", "run"), required=True) parser.add_argument("--root", type=Path, default=Path("outputs") / EXPERIMENT) args = parser.parse_args() if args.stage == "lock": lock(args.root) else: (args.root / "raw").mkdir(exist_ok=True) (args.root / "audit").mkdir(exist_ok=True) run(args.root)