From 079021ed0b26d1e90c17e81a00cabed0bb531949 Mon Sep 17 00:00:00 2001 From: Jon Froehlich Date: Tue, 18 Aug 2026 15:02:19 -0700 Subject: [PATCH 01/17] Vistas at resolution parity: the handicap was real, and it was recall (#126) The published Vistas richmond numbers were measured with the checkpoint's own 384x384 preprocessor in force, so every 1024x1024 view was downsized to ~1/7 the pixel area while every other tiled leg sees the full view. That made the 0.338 F1 gap to RampNet an upper bound rather than a measurement. #129 added --vistas-input-size for exactly this run; this is it. Read pre-registered on #126 before the scored output was read: gap closes by < 0.05 F1 => "transfers but does not compete" stands, one split, stop. Result: it stands, and not narrowly. F1 0.516 -> 0.534 (+0.018), about a third of the bar. RampNet's lead goes 0.339 -> 0.321. The mechanism is the actual finding, and it is not what the caveat predicted. The handicap was large but almost entirely a RECALL handicap: recall 0.694 -> 0.884 (+0.190; misses 95 -> 36, a 62% reduction) AP 0.510 -> 0.649 (+0.139, 27% relative) precision 0.411 -> 0.383 (-0.028, slightly worse) At parity this arm out-recalls RampNet (0.884 vs 0.768) while never having seen one of our labels. F1 stayed flat only because precision is the binding constraint and resolution does nothing for it -- which sharpens the conclusion #126 was built to test: "the concept is findable, the discrimination is not" now holds against the supervised arm at equal input, no longer confounded with pixels. Also ran a same-env 384 control, which was not in the plan and earned its place. The published run was on an RTX 3070 on an older transformers; makelab2 is a major version on, and the transformers version is not in the detection signature -- a hazard this document already flags. So parity-vs-published would have differed in two things. The control lands within ONE detection out of 523 of the published run (215/308/95 vs 216/309/94), so the 4.x->5.15 jump is benign for this checkpoint and the whole delta is attributable to input size. That retires the "an upgrade could have changed every mask under an unchanged cache key" worry as a measurement. Two claims stated at 384 are corrected: y26_pano's richmond AP 0.536 no longer clears this arm at 0.649 (the YOLO sentence's conclusion holds, its arithmetic does not), and min_area_px=16 is inert at 384 but sits exactly at the smallest achievable blob at 1024, so the two rows do not share that setting's meaning. Parity detections are deliberately not published: --vistas-input-size does not change the arm's label, so exporting would overwrite the published richmond file. Publishing them needs a distinct name (the --publish-as pattern from #123). Measured cost, since the estimate going in was 3-4x and wrong in the cheap direction: the full 124-pano run is 3m38s on one A40, GPU forward 0.078 -> 0.092 s per view (1.17x). Verified before the run that the override reaches the model (pixel_values 384 -> 1024, mask logits 96x96 -> 256x256) rather than silently no-opping on a new major version. Docs only; no code, no detection artifacts, no roster change. Co-Authored-By: Claude Opus 5 --- docs/model_comparison.md | 124 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 120 insertions(+), 4 deletions(-) diff --git a/docs/model_comparison.md b/docs/model_comparison.md index e1fe7a91..1de84857 100644 --- a/docs/model_comparison.md +++ b/docs/model_comparison.md @@ -1175,6 +1175,14 @@ upsample can produce is on the order of 114 px and the 16 px floor drops nothing at 16 rather than recalibrated because it sits in the cache signature — changing it would orphan both arms' published detections to no effect. +**That inertness is a property of 384×384, not of the floor, and it does not carry to the +parity run below.** At 1024×1024 input the mask logits arrive at 256×256 and are upsampled +only 4×, so the smallest component the upsample can produce is about **16 px — exactly the +floor**. `min_area_px=16` is therefore marginally *binding* at parity where it was provably +inert at 384, and it is the one setting shared by both that does not mean the same thing in +each. It was still left untouched, because changing it would confound the single variable the +parity run exists to isolate. + The **rig** is the identical six-view one every other tiled leg uses (`equirect_tiling.default_views()`: 6 yaws, 90°×90°, pitch −30°, 1024×1024, source capped at 4096) — but **the rig is not what the model sees, and that is a real caveat on the headline @@ -1190,10 +1198,10 @@ upgrade could have changed every mask under an unchanged cache key. What changed here: `--vistas-input-size H W` now overrides the processor, and `--vistas-revision` pins the checkpoint. Both are recorded in the signature **only when set**, so the published richmond detections keep their key and nothing already paid for is orphaned — -and a future run at parity is a distinct, self-describing cache entry. **The parity run has not -been done**, so every number in this section is at 384×384 and the gap to RampNet is an upper -bound on this arm, not a measurement of it at equal input. That is the first thing to try if -this arm is ever revisited. +and a future run at parity is a distinct, self-describing cache entry. **The parity run has now +been done** — see *Resolution parity* below. Every number in the table that follows is still at +384×384, and the parity numbers are reported separately rather than replacing them, because the +384 run is the one whose detections are published. Note for anyone reading #126: that issue says `scripts/box_gallery.py` already cuts perspective views. **It does not** — its `--fov` sizes an axis-aligned crop of the @@ -1282,6 +1290,114 @@ AP at all, emitting boxes without scores, so they are pinned at one operating po be tuned, and a tunable model at AP 0.513 is a more useful starting point than an untunable one at F1 0.664. +#### Resolution parity: the handicap was real, and it was not the problem (2026-08-18) + +Everything above is measured at 384×384. This section removes that handicap and changes one +variable. Read fixed in advance and posted to #126 **before** the scored output was read: the +gap closes by **< 0.05 F1** ⇒ *"transfers but does not compete"* stands and this stays a +one-split arm; more than that ⇒ the write-up is revised and 3–4 further splits get costed. + +Run on **makelab2 (A40, fp16, transformers 5.15.0 / torch 2.13.0+cu130)**, in a scratch worktree +with a private `--cache-dir`, so nothing here shares a cache directory with the published +detections. RampNet is re-run alongside as the comparability check and **reproduces its committed +richmond row to every digit** (0.964 / 0.768 / 0.855, AP 0.763, 238/9/72). + +| arm | model input | P | R | F1 | AP | tp/fp/fn | +|---|---|---:|---:|---:|---:|---| +| rampnet (committed, reproduced) | — | 0.964 | 0.768 | **0.855** | 0.763 | 238/9/72 | +| vistas curb-cut — **published** (RTX 3070) | 384×384 | 0.411 | 0.697 | 0.517 | 0.513 | 216/309/94 | +| vistas curb-cut — **same-env control** (A40) | 384×384 | 0.411 | 0.694 | 0.516 | 0.510 | 215/308/95 | +| vistas curb-cut — **parity** (A40) | **1024×1024** | 0.383 | **0.884** | **0.534** | **0.649** | 274/442/36 | + +At conf ≥ 0.30: control **0.419 / 0.694 / 0.522** (published: 0.419 / 0.697 / 0.524), parity +**0.384 / 0.884 / 0.536**. Note the threshold barely bites at parity — it removes 3 false +positives against 10 at 384 — because the higher-resolution masks are more confident. + +**The env control was not in the original plan and it earns its place.** The published run was on +Jon's RTX 3070 on an older `transformers`; makelab2 is a major version on. Since the +`transformers` version is *not* in the detection signature — a hazard this document already flags +— parity-vs-published would have differed in **two** things. Re-running 384 in the parity env +separates them: it lands within **one detection out of 523** of the published run (215/308/95 vs +216/309/94, F1 0.516 vs 0.517). So the 4.x→5.15 jump is benign for this checkpoint, the residual +is fp16 kernel nondeterminism rather than a version break, and **the whole parity delta is +attributable to input size.** That also retires the "an upgrade could have changed every mask +under an unchanged cache key" worry for this arm, as a measurement rather than an assurance. + +**The decision rule returns "stands", and it is not close.** Against the same-env control, parity +moves F1 **0.516 → 0.534, +0.018** — about a third of the 0.05 bar. RampNet's lead goes 0.339 → +**0.321**. One split, and no case for costing more. + +**But the mechanism underneath that flat F1 is the actual finding, and it is not the one the +caveat predicted.** The handicap was real and it was large — it was just almost entirely a +*recall* handicap: + +- **Recall 0.694 → 0.884 (+0.190).** Misses fall from 95 to **36**, a 62% reduction. At parity + this arm **out-recalls RampNet** (0.884 vs 0.768) while remaining a model that has never seen a + curb ramp label of ours. +- **AP 0.510 → 0.649 (+0.139)**, a 27% relative gain — the ranking, not just the operating point, + is substantially better. +- **Precision 0.411 → 0.383 (−0.028)**: slightly *worse*. False positives rise 308 → 442, faster + than true positives rise 215 → 274. + +So resolution was buying recall the whole time, and F1 stayed flat only because precision is the +binding constraint and resolution does nothing for it. **That sharpens rather than softens the +conclusion #126 was built to test.** The original framing — *the concept is findable, the +discrimination is not* — was stated against OWLv2 and Grounding DINO; it now holds against the +supervised arm at equal input too, and it is no longer confounded with how many pixels the model +was given. Vistas' curb-cut labels **find** curb ramps on deployment panoramas better than our own +model does; what they cannot do is tell a curb ramp from the things that look like one, which is +exactly the failure the RampNet paper predicted when it rejected this class as a supervision +source for being *"overly broad"*. + +**What this changes above.** Two claims in this section were stated at 384 and do not survive +parity unqualified: + +- The AP comparison against the YOLO baseline said richmond AP **0.748** (`y11x_pano_h200`), + **0.724** (`y11l_pano`) and **0.536** (`y26_pano`) are *"all above 0.513"*. At parity the arm is + at **0.649**, so **`y26_pano` no longer clears it** — somebody else's labels for a neighbouring + class, at equal input, beat one of our own three YOLO arms on AP. The two stronger YOLO arms + still lead, so the sentence's conclusion holds; its arithmetic does not. +- "Best *zero-training* model on AP" is unchanged and strengthened: 0.649 against OWLv2's 0.104. + +**Caveats that travel with these numbers.** `min_area_px=16` is inert at 384 but sits exactly at +the smallest achievable blob at 1024 (see above), so the two rows do not share that setting's +meaning even though they share its value. The parity detections are **deliberately not +published**: `--vistas-input-size` does not change the arm's label, so exporting them would +overwrite `mask2former-vistas-curb-cut__richmond.json` — publishing them needs a distinct +published name (the `--publish-as` pattern from #123), which was out of scope here. And this is +still **richmond only**. + +**The follow-up this result argues for is not more splits.** It is complementarity: at parity +this arm misses **36** ramps where RampNet misses **72**, so the question worth asking is how much +of RampNet's miss set a free, zero-training model already covers. That is a recall-first question +and it bears directly on the north star; it is scoring-side work on detections that are already +cached, and it is not costed here. + +##### Reproducing it + +```bash +# parity (the measurement) +python scripts/model_comparison/compare.py benchmark/richmond \ + --models rampnet,vistas:curb-cut --vistas-input-size 1024 1024 + +# same-env control (the attribution) -- default 384, no override +python scripts/model_comparison/compare.py benchmark/richmond --models vistas:curb-cut + +# either, re-scored at the deployment threshold (free, reads the cache) +python scripts/model_comparison/compare.py benchmark/richmond \ + --models vistas:curb-cut --vistas-input-size 1024 1024 --op-threshold 0.30 +``` + +Cost, measured rather than guessed, because the estimate going in was 3–4× and it was wrong in +the cheap direction: **the full 124-pano parity run takes 3m38s** on one A40, and the GPU forward +goes 0.078 s → 0.092 s per view, only **1.17×**. Swin's windowed attention scales far better than +pixel count, and the documented "2.3 s/view" is dominated by reprojection and CPU work, not the +encoder. Peak GPU memory is 1.64 GB. Verified before the run rather than assumed: the override +reaches the model — `pixel_values` (1, 3, 384, 384) → (1, 3, 1024, 1024) and mask logits +(1, 100, 96, 96) → (1, 100, 256, 256) — which a silently no-opping `processor.size` assignment on +a new major version would not have done, and which would have made "parity" a second 384 run +wearing a different cache key. + Two mechanisms, both measured rather than assumed: - **The `curb-cut+curb` union is a clean negative result.** It was run to test whether recall From 20b767eb6190978862e83a42552aa4759f39cb12 Mon Sep 17 00:00:00 2001 From: Jon Froehlich Date: Tue, 18 Aug 2026 15:48:42 -0700 Subject: [PATCH 02/17] complementarity.py: any provider, not just Gemini (#126) The #35 gate script was hardcoded to build_detector("gemini", ...), so the parity Vistas arm could not be run through it at all. Generalized to a model spec (provider or provider:model_id), with the documented positional form preserved -- a bare non-provider token still reads as a Gemini model id, which is how three call sites in docs/model_comparison.md spell it. Verified against the committed paterson numbers: 36 of 124 misses recovered (29%), 88 found by no model, oracle-union 0.777, all reproduced exactly. Provider defaults now come from roster.PROVIDER_DEFAULTS via the same shim shape fp_taxonomy and null_recall use, so the reconstructed cache key cannot drift from the one compare.py wrote under -- a wrong default there does not crash, it silently misses every entry and reports zero detections. Also added the --vistas-* args to null_recall.py. build_detector reads them off the namespace with getattr, so without them the vistas arm there was silently the published 384x384 one even when the run being analysed was at parity -- a wrong-arm read that looks like a valid answer. And printed the counterweight to the oracle-union number: the FP bill a naive union actually pays, with the resulting precision/F1 against rampnet alone. The oracle ceiling assumes a combiner that keeps every right call, which does not exist; on paterson/gemini-pro the union genuinely wins (0.821 vs 0.805), which is the check that the line is not hardcoded to one verdict. Co-Authored-By: Claude Opus 5 --- scripts/analysis/complementarity.py | 257 ++++++++++++++++++++-------- scripts/analysis/null_recall.py | 13 ++ 2 files changed, 203 insertions(+), 67 deletions(-) diff --git a/scripts/analysis/complementarity.py b/scripts/analysis/complementarity.py index 4525d662..f3b4db6a 100644 --- a/scripts/analysis/complementarity.py +++ b/scripts/analysis/complementarity.py @@ -1,40 +1,61 @@ -"""RampNet vs Gemini-3.6-flash complementarity on richmond (read-only, from cache). +"""Do RampNet and a challenger miss *different* ramps? (issue #35 gate) -Answers issue #35's decision gate: do the two models miss *different* ramps? -For each GT ramp on recall-eligible panos, record whether RampNet found it, Gemini -found it, both, or neither -> oracle-union recall + the RampNet-miss n Gemini-hit set. +For each GT ramp on a recall-eligible pano, record whether RampNet found it, the +challenger found it, both, or neither -> oracle-union recall, and the set that +matters: **RampNet-miss n challenger-hit**. + +Read-only: RampNet's side comes from the bundle's committed detections and the +challenger's from ``.model_cache``, so this never runs a model or spends anything. + +**The oracle-union recall is a ceiling, not a proposal.** It assumes you could +keep every right call and discard every wrong one, which no combiner can do. The +FP arithmetic printed at the end is the counterweight, and for a low-precision +challenger it is usually decisive -- see the union precision line. Pair this with +``null_recall.py`` before believing any union number from a model that emits many +boxes per pano: at high density a share of "hits" are what the match radius hands +out for free, and that share inflates the complementary set too. + +Usage -- the positional form is the one three call sites in +``docs/model_comparison.md`` use, and it still means what it did: + + python scripts/analysis/complementarity.py # gemini-3.6-flash, richmond + python scripts/analysis/complementarity.py gemini-3.1-pro-preview paterson + python scripts/analysis/complementarity.py vistas:curb-cut richmond \ + --vistas-input-size 1024 1024 + +The first positional is a **model spec** (``provider`` or ``provider:model_id``, +as ``compare.py --models`` takes them). A bare token that is not a known provider +is read as a Gemini model id, which is how the #35 gate was invoked before this +script grew past one provider. """ -import os as _os, sys as _sys -REPO = _os.path.dirname(_os.path.dirname(_os.path.dirname(_os.path.abspath(__file__)))) -OUT = _os.environ.get("RAMPNET_ANALYSIS_OUT", _os.path.join(REPO, "analysis_out")) -_os.makedirs(OUT, exist_ok=True) -DA3_SRC = _os.environ.get("DA3_SRC") # path to Depth-Anything-3/src (see README) -import os, sys +import argparse +import os +import sys + +REPO = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) sys.path.insert(0, REPO) sys.path.insert(0, os.path.join(REPO, "scripts", "model_comparison")) -from rampnet.detection_eval import ( - build_ground_truth, score_pano, radius_sq_for, PANO_SCALE_X, PANO_SCALE_Y, _xy, prediction_confidence) -from compare import load_bundle, DetectionCache, cache_key -from detectors import build_detector +from rampnet import roster # noqa: E402 +from rampnet.detection_eval import ( # noqa: E402 + build_ground_truth, score_pano, radius_sq_for, PANO_SCALE_X, PANO_SCALE_Y, + _xy, prediction_confidence) +from compare import load_bundle, DetectionCache, cache_key # noqa: E402 +from detectors import build_detector, parse_model_spec, PROVIDERS # noqa: E402 -MODEL = sys.argv[1] if len(sys.argv) > 1 else "gemini-3.6-flash" -BUNDLE = sys.argv[2] if len(sys.argv) > 2 else "richmond" # benchmark/ name -class Args: - gemini_model = MODEL; qwen_model = "Qwen/Qwen3-VL"; tiling = "perspective" - -RSQ = radius_sq_for() - -def matched_gt(preds, gt_points): +def matched_gt(preds, gt_points, radius_sq): """Greedy 1:1 match (mirrors score_pano); return the set of GT indices covered.""" confs = [prediction_confidence(p) for p in preds] - order = (sorted(range(len(preds)), key=lambda i: confs[i] if confs[i] is not None else float("-inf"), - reverse=True) if any(c is not None for c in confs) else range(len(preds))) + order = (sorted(range(len(preds)), + key=lambda i: confs[i] if confs[i] is not None else float("-inf"), + reverse=True) + if any(c is not None for c in confs) else range(len(preds))) claimed, hit = [False] * len(gt_points), set() for i in order: - pxn, pyn = _xy(preds[i]); px, py = pxn * PANO_SCALE_X, pyn * PANO_SCALE_Y - best_k, best = -1, RSQ + pxn, pyn = _xy(preds[i]) + px, py = pxn * PANO_SCALE_X, pyn * PANO_SCALE_Y + best_k, best = -1, radius_sq for k, (gx, gy) in enumerate(gt_points): if claimed[k]: continue @@ -42,46 +63,148 @@ def matched_gt(preds, gt_points): if d < best: best, best_k = d, k if best_k >= 0: - claimed[best_k] = True; hit.add(best_k) + claimed[best_k] = True + hit.add(best_k) return hit -records, verdicts, _ = load_bundle(os.path.join(REPO, "benchmark", BUNDLE)) -label, gem = build_detector("gemini", MODEL, records, Args()) -sig, cache = gem.signature(), DetectionCache(os.path.join(REPO, ".model_cache")) - -N = both = r_only = g_only = neither = 0 -r_fp = g_fp = 0 -panos = missing = 0 -for pid, entry in verdicts.items(): - gt = build_ground_truth(records[pid]["detections"], entry["dets"], entry["missed"], entry["no_missed"]) - if not gt.fn_confirmed: - continue - gp = cache.get(cache_key(label, sig, BUNDLE, pid)) - if gp is None: - missing += 1; continue - rp = [(d["x_normalized"], d["y_normalized"], d["confidence"]) for d in records[pid]["detections"]] - mr, mg = matched_gt(rp, gt.gt_points), matched_gt(gp, gt.gt_points) - for i in range(len(gt.gt_points)): - r, g = i in mr, i in mg - both += r and g; r_only += r and not g; g_only += g and not r; neither += not r and not g - N += len(gt.gt_points) - r_fp += score_pano(rp, gt).fp - g_fp += score_pano(gp, gt).fp - panos += 1 - -r_tp, g_tp, union = both + r_only, both + g_only, both + r_only + g_only -rampnet_misses = g_only + neither -print(f"{BUNDLE} complementarity — RampNet vs {MODEL} ({panos} recall-eligible panos, {N} GT ramps" - + (f"; {missing} panos missing from cache" if missing else "") + ")\n") -print(f" RampNet recall {r_tp/N:.3f} ({r_tp}/{N})") -print(f" Gemini recall {g_tp/N:.3f} ({g_tp}/{N})") -print(f" ORACLE-UNION recall{union/N:.3f} ({union}/{N}) <- ceiling if you could keep every right call") -print() -print(f" found by BOTH {both:4d} ({both/N:.1%})") -print(f" RampNet ONLY {r_only:4d} ({r_only/N:.1%})") -print(f" Gemini ONLY {g_only:4d} ({g_only/N:.1%}) <- complementary gain (RampNet-miss n Gemini-hit)") -print(f" found by NEITHER {neither:4d} ({neither/N:.1%}) <- hard misses, no model helps") -print() -print(f" Union recall lift over RampNet: +{(union - r_tp)/N:.3f} ({g_only} ramps)") -print(f" Of RampNet's {rampnet_misses} misses, Gemini recovers {g_only} ({g_only/rampnet_misses:.0%}); {neither} nobody finds") -print(f" FP cost on these panos: RampNet {r_fp} | Gemini {g_fp} (a naive union pays ~both)") + +def model_spec(token): + """``provider``/``provider:model_id``, or a legacy bare Gemini model id.""" + provider, model_id = parse_model_spec(token) + if provider in PROVIDERS: + return provider, model_id + # Legacy positional form: a bare model id meant gemini. Keep it working -- + # reading it as a provider would raise on strings that used to be valid. + return "gemini", token + + +def compare_args(args): + """A namespace matching ``compare.py``'s parser defaults, so the cache key this + script reconstructs is the one ``compare.py`` wrote under. + + Provider defaults come from ``rampnet.roster.PROVIDER_DEFAULTS`` -- one + definition, the same source ``fp_taxonomy``'s shim and ``null_recall`` read -- + because a wrong default here does not crash, it silently misses every cache + entry and reports zero detections. The deviation-only knobs + (``vistas_input_size``, ``vistas_revision``) are threaded through from the CLI: + they enter the signature ONLY when set, so leaving them off reproduces the + published arm and setting one addresses a distinct cache entry. + """ + import argparse as _a + ns = _a.Namespace() + for k, v in dict( + roster.PROVIDER_DEFAULTS, + owlv2_query=None, gdino_query=None, + gdino_text_threshold=None, score_threshold=None, + yolo_model=None, tiling=args.tiling, + radius=args.radius, op_threshold=0.0, limit=None, + cache_dir=args.cache_dir, no_cache=False, + vistas_input_size=args.vistas_input_size, + vistas_revision=args.vistas_revision).items(): + setattr(ns, k, v) + return ns + + +def main(): + ap = argparse.ArgumentParser(description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + ap.add_argument("model", nargs="?", default=roster.PROVIDER_DEFAULTS["gemini_model"], + help="Model spec (provider or provider:model_id). A bare " + "non-provider token is read as a Gemini model id.") + ap.add_argument("split", nargs="?", default="richmond", + help="Benchmark split name (default richmond).") + ap.add_argument("--cache-dir", default=os.path.join(REPO, ".model_cache")) + ap.add_argument("--radius", type=float, default=0.022) + ap.add_argument("--tiling", choices=["perspective", "none"], default="perspective") + ap.add_argument("--vistas-input-size", type=int, nargs=2, metavar=("H", "W"), + default=None, + help="Override what the Vistas checkpoint actually sees. In the " + "signature only when set, so this addresses a DIFFERENT " + "cache entry than the published 384x384 arm (#126).") + ap.add_argument("--vistas-revision", default=None) + args = ap.parse_args() + + provider, model_id = model_spec(args.model) + bundle = os.path.join(REPO, "benchmark", args.split) + records, verdicts, _ = load_bundle(bundle) + if verdicts is None: + sys.exit(f"{bundle}: no verdicts.json -- this gate needs a reviewed split.") + label, detector = build_detector(provider, model_id, records, compare_args(args)) + sig = detector.signature() + cache = DetectionCache(args.cache_dir) + radius_sq = radius_sq_for(args.radius) + + n = both = r_only = c_only = neither = 0 + r_fp = c_fp = 0 + panos = missing = 0 + for pid, entry in verdicts.items(): + gt = build_ground_truth(records[pid]["detections"], entry["dets"], + entry["missed"], entry["no_missed"]) + if not gt.fn_confirmed: + continue + cp = cache.get(cache_key(label, sig, args.split, pid)) + if cp is None: + missing += 1 + continue + rp = [(d["x_normalized"], d["y_normalized"], d["confidence"]) + for d in records[pid]["detections"]] + mr, mc = matched_gt(rp, gt.gt_points, radius_sq), matched_gt(cp, gt.gt_points, radius_sq) + for i in range(len(gt.gt_points)): + r, c = i in mr, i in mc + both += r and c + r_only += r and not c + c_only += c and not r + neither += not r and not c + n += len(gt.gt_points) + r_fp += score_pano(rp, gt).fp + c_fp += score_pano(cp, gt).fp + panos += 1 + + if not n: + sys.exit("No recall-eligible panos with cached detections -- nothing to compare. " + "Run compare.py for this model/split first (and pass the SAME " + "--vistas-input-size, which is part of the cache key).") + + r_tp, c_tp, union = both + r_only, both + c_only, both + r_only + c_only + r_miss = c_only + neither + print(f"{args.split} complementarity — rampnet vs {label} " + f"({panos} recall-eligible panos, {n} GT ramps" + + (f"; {missing} panos missing from cache" if missing else "") + ")\n") + print(f" rampnet recall {r_tp / n:.3f} ({r_tp}/{n})") + print(f" {label[:18]:18s} recall {c_tp / n:.3f} ({c_tp}/{n})") + print(f" ORACLE-UNION recall {union / n:.3f} ({union}/{n}) " + f"<- ceiling if you could keep every right call") + print() + print(f" found by BOTH {both:4d} ({both / n:.1%})") + print(f" rampnet ONLY {r_only:4d} ({r_only / n:.1%})") + print(f" {label[:14]:14s} ONLY {c_only:4d} ({c_only / n:.1%}) " + f"<- complementary gain (rampnet-miss n challenger-hit)") + print(f" found by NEITHER {neither:4d} ({neither / n:.1%}) " + f"<- hard misses, no model helps") + print() + print(f" Union recall lift over rampnet: +{(union - r_tp) / n:.3f} ({c_only} ramps)") + if r_miss: + print(f" Of rampnet's {r_miss} misses, {label} recovers {c_only} " + f"({c_only / r_miss:.0%}); {neither} nobody finds") + + # The counterweight to the oracle number. A naive union keeps every box from + # both models, so it pays both FP bills; co-located FPs would dedup, which is + # why this is an upper bound on the cost and therefore a LOWER bound on the + # union's precision. + u_p = union / (union + r_fp + c_fp) if union + r_fp + c_fp else 0.0 + u_r = union / n + u_f1 = 2 * u_p * u_r / (u_p + u_r) if u_p + u_r else 0.0 + r_p = r_tp / (r_tp + r_fp) if r_tp + r_fp else 0.0 + r_f1 = 2 * r_p * (r_tp / n) / (r_p + r_tp / n) if r_p + r_tp / n else 0.0 + print() + print(f" FP cost on these panos: rampnet {r_fp} | {label} {c_fp}" + f" (a naive union pays ~both)") + print(f" rampnet alone: P {r_p:.3f} R {r_tp / n:.3f} F1 {r_f1:.3f}") + print(f" NAIVE UNION: P {u_p:.3f} R {u_r:.3f} F1 {u_f1:.3f}" + f" <- precision is a lower bound (no FP dedup)") + print(f" => a naive union {'BEATS' if u_f1 > r_f1 else 'LOSES TO'} rampnet alone " + f"on F1 ({u_f1:.3f} vs {r_f1:.3f})") + + +if __name__ == "__main__": + main() diff --git a/scripts/analysis/null_recall.py b/scripts/analysis/null_recall.py index ee8a5587..602f4ddc 100644 --- a/scripts/analysis/null_recall.py +++ b/scripts/analysis/null_recall.py @@ -139,6 +139,19 @@ def main(): ap.add_argument("--molmo-model", default=_D["molmo_model"]) ap.add_argument("--molmo-coord-scale", choices=["auto", "100", "1000"], default=_D["molmo_coord_scale"]) + ap.add_argument("--vistas-class-set", default=_D["vistas_class_set"]) + ap.add_argument("--vistas-model", default=_D["vistas_model"]) + ap.add_argument("--vistas-min-area-px", type=int, + default=_D["vistas_min_area_px"]) + ap.add_argument("--vistas-dtype", choices=["float16", "float32"], + default=_D["vistas_dtype"]) + # Deviation-only, exactly as in compare.py: absent from the signature + # unless set. Without these two the vistas arm here would silently be the + # published 384x384 one even when the run being analysed was at parity -- + # a wrong-arm read that looks like a valid answer (#126). + ap.add_argument("--vistas-input-size", type=int, nargs=2, metavar=("H", "W"), + default=None) + ap.add_argument("--vistas-revision", default=None) args = ap.parse_args() records, verdicts, panos_dir = compare.load_bundle(args.bundle) From 2d79bb063c82b9a28a3f993e2f43c6617a205693 Mon Sep 17 00:00:00 2001 From: Jon Froehlich Date: Tue, 18 Aug 2026 15:56:19 -0700 Subject: [PATCH 03/17] complementarity.py: null the complementary set, do not extrapolate one (#126) The headline of a complementarity run is "the challenger recovers N of rampnet%s M misses". At any real box density some of that N is the match radius handing out hits for free, and the repo doctrine is to discount every recall-ceiling and union-oracle claim before believing it. null_recall.py already measures that, but over the WHOLE split. Applying its number to the miss subset assumes the coincidence rate is uniform across GT, and it need not be: rampnet%s misses are a biased sample (far-field, adjacent pairs) and those are exactly where box density differs. So this measures the null on the subset the claim is about, using null_recall%s own cyclic-shift construction -- pano A%s missed GT against pano B%s predictions, averaged over every non-identity shift, so box count and clustering stay real and only the pairing is wrong. On the paterson/gemini-pro regression case the committed numbers are unchanged (36 of 124, 88 found by no model) and the new line reads: null 0.081, so ~10 of the 36 are coincidence and ~26 attributable. Co-Authored-By: Claude Opus 5 --- scripts/analysis/complementarity.py | 39 +++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/scripts/analysis/complementarity.py b/scripts/analysis/complementarity.py index f3b4db6a..ab7591a1 100644 --- a/scripts/analysis/complementarity.py +++ b/scripts/analysis/complementarity.py @@ -68,6 +68,37 @@ def matched_gt(preds, gt_points, radius_sq): return hit +def complementary_null(rows, radius_sq): + """How many of rampnet's misses would the challenger "recover" by coincidence? + + Same null as ``null_recall.py`` -- score pano A's ground truth against pano + B's predictions, averaged over every non-identity cyclic shift -- but + restricted to the GT rampnet MISSED, because that is the subset the + complementary-gain headline is about. Both sides stay real model output on + real imagery, so box count and spatial clustering are preserved; only the + pairing is wrong, so every match is chance. + + Applying the whole-split null from ``null_recall.py`` to this subset instead + would assume the coincidence rate is uniform across GT. It need not be: + rampnet's misses are a biased sample (far-field, adjacent pairs), and those + are exactly the places box density differs. Hence measuring it here. + + Returns (mean, max) as a fraction of the missed GT. + """ + preds = [p for p, _ in rows] + missed = [m for _, m in rows] + n = len(rows) + total = sum(len(m) for m in missed) + if not total or n < 2: + return 0.0, 0.0 + shifted = [] + for k in range(1, n): + hit = sum(len(matched_gt(preds[(i + k) % n], missed[i], radius_sq)) + for i in range(n)) + shifted.append(hit / total) + return sum(shifted) / len(shifted), max(shifted) + + def model_spec(token): """``provider``/``provider:model_id``, or a legacy bare Gemini model id.""" provider, model_id = parse_model_spec(token) @@ -137,6 +168,8 @@ def main(): n = both = r_only = c_only = neither = 0 r_fp = c_fp = 0 panos = missing = 0 + # (challenger preds, GT points rampnet MISSED) per pano, for the null below + shift_rows = [] for pid, entry in verdicts.items(): gt = build_ground_truth(records[pid]["detections"], entry["dets"], entry["missed"], entry["no_missed"]) @@ -158,6 +191,7 @@ def main(): n += len(gt.gt_points) r_fp += score_pano(rp, gt).fp c_fp += score_pano(cp, gt).fp + shift_rows.append((cp, [g for i, g in enumerate(gt.gt_points) if i not in mr])) panos += 1 if not n: @@ -186,6 +220,11 @@ def main(): if r_miss: print(f" Of rampnet's {r_miss} misses, {label} recovers {c_only} " f"({c_only / r_miss:.0%}); {neither} nobody finds") + mean_null, max_null = complementary_null(shift_rows, radius_sq) + exp = mean_null * r_miss + print(f" null (same boxes, wrong pano): {mean_null:.3f} " + f"=> ~{exp:.0f} of those {c_only} are coincidence, " + f"~{c_only - exp:.0f} attributable (worst shift {max_null:.3f})") # The counterweight to the oracle number. A naive union keeps every box from # both models, so it pays both FP bills; co-located FPs would dedup, which is From 9d6f8f811feef73a5acd428604b19475a246c9db Mon Sep 17 00:00:00 2001 From: Jon Froehlich Date: Tue, 18 Aug 2026 16:00:05 -0700 Subject: [PATCH 04/17] Complementarity at parity: 61% of RampNet-misses recoverable, union still loses (#126) Runs the #35 gate on the parity arm, plus the 384 arm as the control. Answers the recall-first question the parity result raised, and answers it against chance rather than at face value. Discounted for the null, a free zero-training model finds ~44 of the 72 ramps RampNet misses on richmond (61%). Raw is 54 of 72 (75%); the null on that subset is 0.143. The recall is real detection, not density -- at 6.2 boxes/pano the arm above-chances 0.864, higher than RampNet own 0.754, nothing like OWLv2 0.733 at 74 boxes/pano. The control is the interesting half. Parity moved F1 by +0.018 and was correctly judged not to change the ranking -- but it nearly TRIPLED the attributable complementary gain (~15 -> ~44 ramps) and shrank the found-by-nobody core from 51 to 18. A flat headline metric hid a large change in the structure underneath it, and only the complementarity read surfaced it. A naive union stays dead and it is not close: F1 0.555 against RampNet 0.855. The 54 ramps arrive with 442 false positives, ~8.2 FP per recovered ramp against the 9 FP RampNet pays for 238 TP. Recorded the oracle-union 0.942 as the ceiling it is, with the real union arithmetic beside it so the two cannot be confused. What is left open is a gated cascade -- this arm candidates as a spatial prior to locally relax RampNet threshold -- which is decidable but NOT run: #131 measured most silent misses as adjacent-tail or faint, but nobody has checked whether sub-threshold signal exists at these 54 locations specifically. Co-Authored-By: Claude Opus 5 --- docs/model_comparison.md | 66 +++++++++++++++++++++++++++++++++++--- scripts/analysis/README.md | 2 +- 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/docs/model_comparison.md b/docs/model_comparison.md index 1de84857..7e32dca6 100644 --- a/docs/model_comparison.md +++ b/docs/model_comparison.md @@ -1367,11 +1367,67 @@ overwrite `mask2former-vistas-curb-cut__richmond.json` — publishing them needs published name (the `--publish-as` pattern from #123), which was out of scope here. And this is still **richmond only**. -**The follow-up this result argues for is not more splits.** It is complementarity: at parity -this arm misses **36** ramps where RampNet misses **72**, so the question worth asking is how much -of RampNet's miss set a free, zero-training model already covers. That is a recall-first question -and it bears directly on the north star; it is scoring-side work on detections that are already -cached, and it is not costed here. +#### Complementarity: 61% of RampNet's misses are recoverable, and a union still loses + +Parity raised the obvious recall-first question — this arm misses 36 ramps where RampNet misses +72, so how much of *RampNet's* miss set does a free, zero-training model already cover? Run +through the #35 gate (`scripts/analysis/complementarity.py`, generalized past its Gemini-only +form for this), on the same cached detections, scoring-side only: + +| | vistas @384 | **vistas @1024 (parity)** | +|---|---:|---:| +| found by BOTH | 194 | 220 | +| rampnet ONLY | 44 | 18 | +| **challenger ONLY** (rampnet-miss ∩ hit) | 21 | **54** | +| found by NEITHER | 51 | **18** | +| of rampnet's 72 misses, recovered | 21 (29%) | **54 (75%)** | +| null on that subset (same boxes, wrong pano) | 0.090 | 0.143 | +| **attributable after the null** | **~15** | **~44** | +| oracle-union recall | 0.835 | **0.942** | +| boxes/pano · above chance (`null_recall.py`) | 4.5 · 0.657 | 6.2 · **0.864** | + +**Discounted for chance, a free zero-training model finds ~44 of the 72 ramps RampNet misses — +61%.** The null here is measured on the miss subset rather than extrapolated from the split-wide +one, because RampNet's misses are a biased sample (far-field, adjacent pairs) and that is exactly +where density differs; it lands at 0.143 against the split-wide 0.145, so in this case the +extrapolation would have been fair. And the recall is real detection, not density: at 6.2 +boxes/pano the arm's **above-chance is 0.864, higher than RampNet's own 0.754** — nothing like +OWLv2's 0.733 null at 74 boxes/pano. + +**The resolution fix mattered far more here than the headline suggested.** Parity moved F1 by ++0.018 and was correctly judged not to change the ranking — but it nearly **tripled** the +attributable complementary gain (~15 → ~44 ramps) and shrank the found-by-nobody core from 51 to +**18**, 5.8% of GT. That core is much smaller than paterson's 88 (22%) or gainesville's 55 (20%), +though those are different splits against a different challenger, so read it as suggestive rather +than a like-for-like. The general lesson is worth keeping: **a flat headline metric hid a large +change in the structure underneath it**, and only the complementarity read surfaced it. + +**A naive union is nonetheless dead, and it is not close.** The oracle-union recall of 0.942 is a +*ceiling* — it assumes a combiner that keeps every right call and discards every wrong one, which +does not exist. What a real union pays is both FP bills: + +| | P | R | F1 | +|---|---:|---:|---:| +| rampnet alone | 0.964 | 0.768 | **0.855** | +| naive union with vistas @1024 | 0.393 | 0.942 | 0.555 | +| naive union with vistas @384 | 0.450 | 0.835 | 0.585 | + +The economics are the whole story: those 54 ramps arrive with 442 false positives, about **8.2 FPs +per recovered ramp**, against the 9 FPs RampNet currently pays for 238 true positives. So +ensembling by union is not a close call at any operating point on this arm's PR curve. + +**What that leaves is a gated cascade, and it is a real open question rather than a plan.** The +useful form is not "take both models' boxes" but "use this arm's candidates as a *spatial prior* +to locally relax RampNet's threshold", which would keep RampNet's precision and buy back some of +the 54. Whether it can work is empirical and decidable: #131 measured RampNet's silent misses as +8% absent / 62% adjacent-tail / 30% faint, so most misses *do* have sub-threshold heatmap signal — +but nobody has checked whether that holds at these 54 locations specifically. If the signal is +absent there, the miss is genuine and the cascade has nothing to work with. `silent_activation.py` +is the instrument. **Not run, not costed here.** + +**Caveats.** richmond only, one imagery tier. The 442 FPs are not free even in a recall-first +framing — at 3.6 FP/pano against RampNet's 0.07 they are a ~50× review burden, so "FPs are cheap" +is a claim about the labeling workflow that would need its own justification at this ratio. ##### Reproducing it diff --git a/scripts/analysis/README.md b/scripts/analysis/README.md index 2ca0526d..155926ed 100644 --- a/scripts/analysis/README.md +++ b/scripts/analysis/README.md @@ -26,7 +26,7 @@ checkout. | script | GPU | what it answers | |---|---|---| | `miss_analysis.py` | no | Are misses localization near-misses or blind? Are they hard (a VLM also missed) or RampNet-specific? | -| `complementarity.py [model] [split]` | no | Oracle-union recall + the RampNet-miss ∩ VLM-hit set (issue #35 gate). Reads cached VLM detections from `.model_cache`; split defaults to richmond. | +| `complementarity.py [model] [split]` | no | Oracle-union recall + the RampNet-miss ∩ challenger-hit set, with a chance null on that subset and the FP bill a naive union would actually pay (issue #35 gate). Takes any model spec (`provider` or `provider:model_id`); a bare non-provider token is read as a Gemini model id. Reads cached detections from `.model_cache`; split defaults to richmond. Pass the same `--vistas-input-size` the run used — it is part of the cache key. | | `precision_by_distance.py` | no | Is precision worse at distance — i.e. is culling far detections worth it? (No.) | | `threshold_sweep.py` | **yes** | Re-runs inference on all benchmark panos and sweeps `threshold_abs` × `min_distance`. | | `peak_nms_check.py` | no | Would suppressing peaks closer than the match radius help? (No — 6 of the 10 within-R pairs in the reviewed records are real ramp pairs; issue #62.) Reads all seven splits' committed records, no panos needed. | From 448512d654b6a0d39ae6310c0a9116f6a258a8eb Mon Sep 17 00:00:00 2001 From: Jon Froehlich Date: Tue, 18 Aug 2026 16:10:09 -0700 Subject: [PATCH 05/17] cascade_gate.py: is the gated cascade even possible? (#126) The complementarity result rules out a union but leaves a gated cascade -- the challenger candidates as a spatial prior to locally relax RampNet threshold. That has one precondition and it is measurable without building anything: RampNet must already produce sub-threshold response AT those ramps. If the heatmap is flat there the miss is genuine absence and no prior can raise it. Partitions every GT ramp into the four complementarity cells and reads the heatmap at each, with #46 Phase 1 instrument imported rather than reimplemented -- site_profile, null_percentile, nearest_peak, class_of and its ABSENT_MAX/PEAK_FLOOR cutoffs -- so the numbers are directly comparable to that phase 8% absent / 62% adjacent-tail / 30% faint decomposition, and a fix to the probe fixes both analyses. The three-way class is the point, not the raw activation. faint_local with the argmax at the site is signal a prior could raise. tail is an ADJACENT mode reaching in, so relaxing a threshold there fires on the neighbour rather than the ramp -- that argues for sigma/NMS work, not for a prior, even though it reads as "signal present" if you only look at act. Read pre-registered on #126 before running. Nulls computed only for the two RampNet-miss cells; the hit cells are high by construction and are the positive control. Co-Authored-By: Claude Opus 5 --- .gitignore | 2 + scripts/analysis/cascade_gate.py | 263 +++++++++++++++++++++++++++++++ 2 files changed, 265 insertions(+) create mode 100644 scripts/analysis/cascade_gate.py diff --git a/.gitignore b/.gitignore index 37fb92d5..26a53f29 100644 --- a/.gitignore +++ b/.gitignore @@ -90,6 +90,8 @@ analysis_out/op/* !analysis_out/crop_window_eval_*.json !analysis_out/farfield_forensics.json !analysis_out/silent_activation.json +# The #126 cascade go/no-go: rampnet's heatmap at the ramps a challenger recovers. +!analysis_out/cascade_gate.json # Generated tagging pages live next to their (committed) galleries; regenerate with # scripts/analysis/make_tagger.py rather than tracking a build artifact. diff --git a/scripts/analysis/cascade_gate.py b/scripts/analysis/cascade_gate.py new file mode 100644 index 00000000..f165af12 --- /dev/null +++ b/scripts/analysis/cascade_gate.py @@ -0,0 +1,263 @@ +"""Is a gated cascade live? Does RampNet already *see* the ramps a challenger recovers? (#126) + +The complementarity gate (``complementarity.py``) says a Vistas-supervised segmenter at +input parity finds 54 of the 72 richmond ramps RampNet misses, ~44 of them after the +chance null. A naive union is nonetheless dead — those 54 arrive with 442 false +positives, ~8.2 FP per recovered ramp, and the union scores F1 0.555 against RampNet's +0.855. + +What that leaves is a **gated cascade**: use the challenger's candidates as a spatial +prior and locally relax RampNet's threshold, keeping RampNet's precision everywhere +else. That has one precondition, and it is measurable without building anything — +**RampNet must already produce sub-threshold response at those ramps.** If the heatmap +is flat there, the miss is genuine absence and no prior can raise what is not there. + +So: partition every GT ramp into the four complementarity cells, and read RampNet's +heatmap at each. + + cell rampnet challenger role + both hit hit positive control + rampnet_only hit miss positive control + challenger_only MISS hit the recoverable set -- the question + neither MISS miss hard core + +**The instrument is #46 Phase 1's, imported rather than reimplemented** — +``site_profile``, ``null_percentile``, ``nearest_peak``, ``class_of`` and its two +cutoffs (``ABSENT_MAX`` 0.01, ``PEAK_FLOOR`` 0.05) all come from +``silent_activation.py``. That is deliberate: it makes these numbers directly +comparable to that phase's 8% absent / 62% adjacent-tail / 30% faint decomposition, +and it means a fix to the probe fixes both analyses. + +**Three outcomes, and the middle one is not the interesting one.** ``faint_local`` with +the in-window argmax *at* the site is signal a prior could raise. ``absent`` is nothing +to raise. ``tail`` — the in-window maximum at or above the peak floor — is an adjacent +mode reaching in, and for a *missed* ramp it means relaxing a threshold there would fire +on the neighbour, not on the ramp. ``tail`` therefore argues for sigma/NMS work (#46's +adjacent-pair merge), **not** for a threshold prior, even though it looks like "signal +is present" if you only read ``act``. + +**Sub-threshold signal is necessary, not sufficient.** A positive here says the cascade +is not ruled out and is worth costing; it does not demonstrate one works. Any realisable +gain is bounded above by the ~44 attributable ramps, not the raw 54. + +Inputs: the native-resolution panoramas at ``benchmark//panos/`` (git-ignored, +published as ``projectsidewalk/rampnet-benchmark``) — ``--panos-root`` points at +whichever checkout holds them, since a worktree will not. The challenger's detections +must already be in ``--cache-dir``; **pass the same ``--vistas-input-size`` the run +used, it is part of the cache key.** A GPU: ~124 panos, one forward each. + + python scripts/analysis/cascade_gate.py --panos-root /path/to/RampNet \\ + --model vistas:curb-cut --vistas-input-size 1024 1024 \\ + --json-out analysis_out/cascade_gate.json +""" +import argparse +import json +import os +import random +import sys + +REPO = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +OUT = os.environ.get("RAMPNET_ANALYSIS_OUT", os.path.join(REPO, "analysis_out")) +sys.path.insert(0, REPO) +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, os.path.join(REPO, "scripts", "model_comparison")) + +from rampnet.detection_eval import build_ground_truth, radius_sq_for # noqa: E402 +from compare import load_bundle, DetectionCache, cache_key # noqa: E402 +from detectors import build_detector # noqa: E402 +from complementarity import matched_gt, model_spec, compare_args # noqa: E402 +from silent_activation import ( # noqa: E402 + NULL_SEED, NULL_TRIALS, class_of, nearest_peak, null_percentile, seam_of, + site_profile) +from farfield_forensics import quartiles # noqa: E402 + +CELLS = ("both", "rampnet_only", "challenger_only", "neither") +#: Cells where RampNet did NOT find the ramp -- the only ones a null is meaningful for. +MISS_CELLS = ("challenger_only", "neither") + + +def cell_of(rampnet_hit, challenger_hit): + if rampnet_hit: + return "both" if challenger_hit else "rampnet_only" + return "challenger_only" if challenger_hit else "neither" + + +def summarize(rows, cell): + """Per-cell summary. ``None`` for null stats on the hit cells, which have none.""" + sel = [r for r in rows if r["cell"] == cell] + if not sel: + return {"cell": cell, "n": 0} + acts = [r["act"] for r in sel] + classes = {c: sum(1 for r in sel if r["class"] == c) + for c in ("absent", "faint_local", "tail")} + out = { + "cell": cell, + "n": len(sel), + "act_median": round(quartiles(acts)[1], 4), + "center_median": round(quartiles([r["center"] for r in sel])[1], 4), + "argmax_off_px_median": round(quartiles([r["argmax_off_px"] for r in sel])[1], 1), + "nearest_peak_px_median": round( + quartiles([r["nearest_peak_px"] for r in sel + if r["nearest_peak_px"] is not None])[1], 1) + if any(r["nearest_peak_px"] is not None for r in sel) else None, + "classes": classes, + "class_share": {c: round(v / len(sel), 3) for c, v in classes.items()}, + "seam": sum(1 for r in sel if r["seam"]), + } + nulls = [r["null_pct"] for r in sel if r["null_pct"] is not None] + if nulls: + out["null_pct_median"] = round(quartiles(nulls)[1], 3) + out["above_null_p95"] = sum(1 for r in sel + if r["null_pct"] is not None and r["act"] > r["null_p95"]) + out["null_med_median"] = round( + quartiles([r["null_med"] for r in sel if r["null_med"] is not None])[1], 4) + return out + + +def main(argv=None): + p = argparse.ArgumentParser(description=__doc__.split("\n")[0], + formatter_class=argparse.RawDescriptionHelpFormatter) + p.add_argument("--split", default="richmond") + p.add_argument("--model", default="vistas:curb-cut", + help="Challenger model spec, as compare.py --models takes it.") + p.add_argument("--panos-root", default=REPO, + help="Checkout holding benchmark//panos/ (a worktree will not).") + p.add_argument("--cache-dir", default=os.path.join(REPO, ".model_cache")) + p.add_argument("--radius", type=float, default=0.022) + p.add_argument("--tiling", choices=["perspective", "none"], default="perspective") + p.add_argument("--vistas-input-size", type=int, nargs=2, metavar=("H", "W"), default=None, + help="Must match the run being analysed -- it is part of the cache key.") + p.add_argument("--vistas-revision", default=None) + p.add_argument("--limit", type=int, default=None, help="Smoke test: first N panos.") + p.add_argument("--json-out", default=None) + args = p.parse_args(argv) + + if args.json_out and args.limit: + p.error("--limit truncates the run; refusing to write it to --json-out") + + import torch + import threshold_sweep as ts + from miss_gallery import pano_path + + bundle = os.path.join(REPO, "benchmark", args.split) + records, verdicts, _ = load_bundle(bundle) + if verdicts is None: + sys.exit(f"{bundle}: no verdicts.json -- this needs a reviewed split.") + provider, model_id = model_spec(args.model) + label, detector = build_detector(provider, model_id, records, compare_args(args)) + sig = detector.signature() + cache = DetectionCache(args.cache_dir) + radius_sq = radius_sq_for(args.radius) + + # ---- partition every GT ramp into a complementarity cell ------------------ + sites, missing = [], 0 + for pid, entry in verdicts.items(): + gt = build_ground_truth(records[pid]["detections"], entry["dets"], + entry["missed"], entry["no_missed"]) + if not gt.fn_confirmed: + continue + cp = cache.get(cache_key(label, sig, args.split, pid)) + if cp is None: + missing += 1 + continue + rp = [(d["x_normalized"], d["y_normalized"], d["confidence"]) + for d in records[pid]["detections"]] + mr = matched_gt(rp, gt.gt_points, radius_sq) + mc = matched_gt(cp, gt.gt_points, radius_sq) + for i, (gx, gy) in enumerate(gt.gt_points): + sites.append({"pano": pid, "x": gx, "y": gy, + "cell": cell_of(i in mr, i in mc)}) + if missing: + print(f"WARNING: {missing} panos had no cached {label} detections and were " + f"skipped. Pass the --vistas-input-size the run used.", flush=True) + if not sites: + sys.exit("No sites -- is the challenger cached for this split/input size?") + + by_pano = {} + for s in sites: + by_pano.setdefault(s["pano"], []).append(s) + panos = sorted(by_pano) + if args.limit: + panos = panos[:args.limit] + + counts = {c: sum(1 for s in sites if s["cell"] == c) for c in CELLS} + print(f"=== Cascade gate: rampnet heatmap at {label}'s recoveries " + f"({args.split}, {len(sites)} GT ramps in {len(by_pano)} panos) ===") + print(" cells: " + " ".join(f"{c}={counts[c]}" for c in CELLS), flush=True) + + device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + model = ts.load_model().to(device) + print(f" device={device} model=projectsidewalk/rampnet-model " + f"(single-pass fp32, as op_cache)", flush=True) + + rng = random.Random(NULL_SEED) + rows, skipped = [], 0 + for i, pid in enumerate(panos, 1): + path = pano_path(args.split, pid, args.panos_root) + if not os.path.exists(path): + skipped += len(by_pano[pid]) + continue + heat = ts.heatmap_for(model, device, path, use_fp16=False) + preds = [(d["x_normalized"], d["y_normalized"], d["confidence"]) + for d in records[pid]["detections"]] + for s in by_pano[pid]: + act, off_px, center = site_profile(heat, s["x"], s["y"], radius_sq) + npx, nscore = nearest_peak(preds, s["x"], s["y"]) + row = {**s, "act": round(act, 6), "center": round(center, 6), + "argmax_off_px": round(off_px, 1), + "nearest_peak_px": None if npx == float("inf") else round(npx, 1), + "nearest_peak_score": nscore, + "class": class_of(act), "seam": seam_of(s["x"], radius_sq), + "null_pct": None, "null_med": None, "null_p95": None} + # The null is only meaningful where rampnet did NOT find the ramp; the + # hit cells are high by construction and are here as a positive control. + if s["cell"] in MISS_CELLS: + a, pct, med, p95 = null_percentile(heat, s["x"], s["y"], rng, + radius_sq=radius_sq) + row.update(null_pct=round(pct, 4), null_med=round(med, 6), + null_p95=round(p95, 6)) + rows.append(row) + if i % 20 == 0 or i == len(panos): + print(f" {i}/{len(panos)} panos", flush=True) + if skipped: + print(f"WARNING: {skipped} sites skipped -- pano jpg not found under " + f"--panos-root {args.panos_root}", flush=True) + + summaries = [summarize(rows, c) for c in CELLS] + print() + hdr = (f"{'cell':17s} {'n':>4s} {'act med':>8s} {'centre':>8s} {'argmax off':>11s} " + f"{'absent':>7s} {'faint':>6s} {'tail':>5s} {'null pct':>9s}") + print(hdr) + print("-" * len(hdr)) + for s in summaries: + if not s["n"]: + continue + sh = s["class_share"] + print(f"{s['cell']:17s} {s['n']:4d} {s['act_median']:8.4f} " + f"{s['center_median']:8.4f} {s['argmax_off_px_median']:10.1f}p " + f"{sh['absent']:7.0%} {sh['faint_local']:6.0%} {sh['tail']:5.0%} " + + (f"{s['null_pct_median']:9.3f}" if "null_pct_median" in s else f"{'—':>9s}")) + print() + print(" faint_local = a real sub-threshold response AT the site -> a prior could raise it.") + print(" tail = in-window max at/above the 0.05 peak floor, i.e. an ADJACENT mode") + print(" reaching in; relaxing a threshold there fires on the neighbour,") + print(" not the ramp. Argues for sigma/NMS (#46), not for a prior.") + print(" absent = flat heatmap; nothing to raise.") + + if args.json_out: + payload = {"split": args.split, "challenger": label, + "vistas_input_size": args.vistas_input_size, + "radius": args.radius, "null_trials": NULL_TRIALS, + "null_seed": NULL_SEED, "n_sites": len(rows), + "n_panos": len(panos), "skipped_sites": skipped, + "cells": summaries, "sites": rows} + os.makedirs(os.path.dirname(os.path.abspath(args.json_out)), exist_ok=True) + # newline="" so a Windows re-run does not emit CRLF and break byte-comparison. + with open(args.json_out, "w", encoding="utf-8", newline="") as f: + json.dump(payload, f, indent=2, sort_keys=True) + f.write("\n") + print(f"\nwrote {args.json_out}") + + +if __name__ == "__main__": + main() From dcb9c325e6533c8620f3615fb5e87a7a9ac944f3 Mon Sep 17 00:00:00 2001 From: Jon Froehlich Date: Tue, 18 Aug 2026 16:21:45 -0700 Subject: [PATCH 06/17] cascade_gate: read floor peaks from op_cache, not the shipped detections (#126) Self-inflicted, caught before the write-up. nearest_peak expects peak_local_max output down to the 0.05 floor. I fed it records[pid]["detections"], which on richmond are all >= 0.5519 -- the SHIPPED operating point. So "is there a peak near this missed ramp?" was really asking "is there a 0.55+ detection near it?", which for a missed ramp is close to definitionally no, and it made every miss look peakless with the nearest peak a median 104 px away. analysis_out/op_cache/richmond.json is committed and holds the floor peaks: 537 for richmond, 270 of them below 0.55. That is the input the sub-threshold question needs. The greedy match that DEFINED the miss set still uses the bundle records, because that is what produced the published 238/9/72 -- two different inputs to two different questions, now documented as such. Also replaced the class_of column in the printed table with peak_in_radius. class_of is #46 Phase 1 cutoffs, and there "tail" could only mean an outside mode reaching in because that population was SILENT misses by definition. This population is every RampNet miss, so act >= 0.05 has two causes the class cannot separate: a floor peak inside the radius (the model localized it and the detection was lost downstream -- recoverable WITHOUT a second model) versus unpeaked heatmap mass (nothing for a prior to promote). The old table also printed "100% tail" for the two hit cells, which is meaningless there. Co-Authored-By: Claude Opus 5 --- analysis_out/cascade_gate.json | 5060 ++++++++++++++++++++++++++++++ scripts/analysis/cascade_gate.py | 90 +- 2 files changed, 5132 insertions(+), 18 deletions(-) create mode 100644 analysis_out/cascade_gate.json diff --git a/analysis_out/cascade_gate.json b/analysis_out/cascade_gate.json new file mode 100644 index 00000000..bfca91e3 --- /dev/null +++ b/analysis_out/cascade_gate.json @@ -0,0 +1,5060 @@ +{ + "cells": [ + { + "act_median": 0.8893, + "argmax_off_px_median": 0.0, + "cell": "both", + "center_median": 0.8893, + "class_share": { + "absent": 0.0, + "faint_local": 0.0, + "tail": 1.0 + }, + "classes": { + "absent": 0, + "faint_local": 0, + "tail": 220 + }, + "n": 220, + "nearest_peak_px_median": 0.0, + "seam": 5 + }, + { + "act_median": 0.8449, + "argmax_off_px_median": 0.0, + "cell": "rampnet_only", + "center_median": 0.8431, + "class_share": { + "absent": 0.0, + "faint_local": 0.0, + "tail": 1.0 + }, + "classes": { + "absent": 0, + "faint_local": 0, + "tail": 18 + }, + "n": 18, + "nearest_peak_px_median": 0.0, + "seam": 0 + }, + { + "above_null_p95": 12, + "act_median": 0.3386, + "argmax_off_px_median": 10.7, + "cell": "challenger_only", + "center_median": 0.142, + "class_share": { + "absent": 0.0, + "faint_local": 0.056, + "tail": 0.944 + }, + "classes": { + "absent": 0, + "faint_local": 3, + "tail": 51 + }, + "n": 54, + "nearest_peak_px_median": 104.9, + "null_med_median": 0.0091, + "null_pct_median": 0.895, + "seam": 1 + }, + { + "above_null_p95": 7, + "act_median": 0.4973, + "argmax_off_px_median": 19.2, + "cell": "neither", + "center_median": 0.182, + "class_share": { + "absent": 0.0, + "faint_local": 0.0, + "tail": 1.0 + }, + "classes": { + "absent": 0, + "faint_local": 0, + "tail": 18 + }, + "n": 18, + "nearest_peak_px_median": 56.1, + "null_med_median": 0.0065, + "null_pct_median": 0.92, + "seam": 0 + } + ], + "challenger": "mask2former-vistas-curb-cut", + "n_panos": 92, + "n_sites": 310, + "null_seed": 20260731, + "null_trials": 200, + "radius": 0.022, + "sites": [ + { + "act": 0.913488, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.913488, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.913480281829834, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1002881108606016", + "seam": false, + "x": 0.4326171875, + "y": 0.5078125 + }, + { + "act": 0.895599, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.895599, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8956112265586853, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1002881108606016", + "seam": false, + "x": 0.7216796875, + "y": 0.583984375 + }, + { + "act": 0.618312, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.618312, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6183195114135742, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1002881108606016", + "seam": false, + "x": 0.58203125, + "y": 0.521484375 + }, + { + "act": 0.596123, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.596123, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.59613037109375, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1023400645666420", + "seam": false, + "x": 0.53515625, + "y": 0.552734375 + }, + { + "act": 0.202505, + "argmax_off_px": 16.0, + "cell": "challenger_only", + "center": 0.10486, + "class": "tail", + "nearest_peak_px": 266.1, + "nearest_peak_score": 0.59613037109375, + "null_med": 0.006787, + "null_p95": 0.124406, + "null_pct": 0.995, + "pano": "1023400645666420", + "seam": false, + "x": 0.7919191857540246, + "y": 0.6331313069661458 + }, + { + "act": 0.236865, + "argmax_off_px": 22.4, + "cell": "challenger_only", + "center": 0.017964, + "class": "tail", + "nearest_peak_px": 313.6, + "nearest_peak_score": 0.59613037109375, + "null_med": 0.014093, + "null_p95": 0.367628, + "null_pct": 0.88, + "pano": "1023400645666420", + "seam": false, + "x": 0.2294949433297822, + "y": 0.5919191857540246 + }, + { + "act": 0.392091, + "argmax_off_px": 2.3, + "cell": "challenger_only", + "center": 0.371854, + "class": "tail", + "nearest_peak_px": 103.4, + "nearest_peak_score": 0.59613037109375, + "null_med": 0.013856, + "null_p95": 0.581377, + "null_pct": 0.94, + "pano": "1023400645666420", + "seam": false, + "x": 0.43434342817826704, + "y": 0.5419191857540246 + }, + { + "act": 0.876577, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.876577, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8765917420387268, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1041352537628655", + "seam": false, + "x": 0.2216796875, + "y": 0.5703125 + }, + { + "act": 0.835651, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.835651, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8356579542160034, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1041352537628655", + "seam": false, + "x": 0.93359375, + "y": 0.5546875 + }, + { + "act": 0.697017, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.697017, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6970375776290894, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1041352537628655", + "seam": false, + "x": 0.78515625, + "y": 0.630859375 + }, + { + "act": 0.94323, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.94323, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9432597160339355, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1044606157061812", + "seam": false, + "x": 0.30078125, + "y": 0.5546875 + }, + { + "act": 0.895965, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.895965, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8959958553314209, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1044606157061812", + "seam": false, + "x": 0.94140625, + "y": 0.568359375 + }, + { + "act": 0.891897, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.891897, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8919112682342529, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1044606157061812", + "seam": false, + "x": 0.64453125, + "y": 0.599609375 + }, + { + "act": 0.841396, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.841396, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8414136171340942, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1044606157061812", + "seam": false, + "x": 0.1201171875, + "y": 0.552734375 + }, + { + "act": 0.909499, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.909499, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.909525990486145, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1050503583329955", + "seam": false, + "x": 0.35546875, + "y": 0.599609375 + }, + { + "act": 0.869249, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.869249, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8692640662193298, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1050503583329955", + "seam": false, + "x": 0.66015625, + "y": 0.6015625 + }, + { + "act": 0.738541, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.738541, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7385543584823608, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1050503583329955", + "seam": false, + "x": 0.42578125, + "y": 0.5390625 + }, + { + "act": 0.946644, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.946644, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9466584920883179, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1051211967136526", + "seam": false, + "x": 0.4091796875, + "y": 0.5390625 + }, + { + "act": 0.904591, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.904591, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9046050310134888, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1051211967136526", + "seam": false, + "x": 0.55859375, + "y": 0.568359375 + }, + { + "act": 0.878982, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.878982, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8789999485015869, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1051211967136526", + "seam": false, + "x": 0.26171875, + "y": 0.5859375 + }, + { + "act": 0.816361, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.816361, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8163886070251465, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1071700701728910", + "seam": false, + "x": 0.8544921875, + "y": 0.5859375 + }, + { + "act": 0.766434, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.766434, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7664440870285034, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1071700701728910", + "seam": false, + "x": 0.12109375, + "y": 0.552734375 + }, + { + "act": 0.675663, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.675663, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6756789088249207, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1071700701728910", + "seam": false, + "x": 0.95703125, + "y": 0.5390625 + }, + { + "act": 0.938291, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.938291, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9382998943328857, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1073049581231056", + "seam": true, + "x": 0.9873046875, + "y": 0.583984375 + }, + { + "act": 0.843096, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.843096, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8431106805801392, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1073049581231056", + "seam": false, + "x": 0.16796875, + "y": 0.6171875 + }, + { + "act": 0.614511, + "argmax_off_px": 11.0, + "cell": "both", + "center": 0.421524, + "class": "tail", + "nearest_peak_px": 11.0, + "nearest_peak_score": 0.6145117878913879, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1089573432664131", + "seam": false, + "x": 0.9536616099964488, + "y": 0.5459090909090908 + }, + { + "act": 0.801695, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.801695, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.801726222038269, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1092133469495462", + "seam": false, + "x": 0.5419921875, + "y": 0.537109375 + }, + { + "act": 0.800788, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.800788, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8008056879043579, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1092133469495462", + "seam": false, + "x": 0.41796875, + "y": 0.5234375 + }, + { + "act": 0.748474, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.748474, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.748491644859314, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1092133469495462", + "seam": false, + "x": 0.69921875, + "y": 0.6328125 + }, + { + "act": 0.800788, + "argmax_off_px": 15.0, + "cell": "both", + "center": 0.711291, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.711294412612915, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1092133469495462", + "seam": false, + "x": 0.4326171875, + "y": 0.5234375 + }, + { + "act": 0.646609, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.646609, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6466131210327148, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1092133469495462", + "seam": false, + "x": 0.30078125, + "y": 0.568359375 + }, + { + "act": 0.646609, + "argmax_off_px": 22.0, + "cell": "challenger_only", + "center": 0.097523, + "class": "tail", + "nearest_peak_px": 22.0, + "nearest_peak_score": 0.6466131210327148, + "null_med": 0.010539, + "null_p95": 0.603415, + "null_pct": 0.98, + "pano": "1092133469495462", + "seam": false, + "x": 0.28282827666311555, + "y": 0.5919191903779001 + }, + { + "act": 0.889245, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.889245, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8892737627029419, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1107064934776754", + "seam": false, + "x": 0.10546875, + "y": 0.5859375 + }, + { + "act": 0.880806, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.880806, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8808392286300659, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1107064934776754", + "seam": false, + "x": 0.58203125, + "y": 0.5859375 + }, + { + "act": 0.851676, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.851676, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8517063856124878, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1107064934776754", + "seam": false, + "x": 0.8857421875, + "y": 0.615234375 + }, + { + "act": 0.824314, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.824314, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8243341445922852, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1107064934776754", + "seam": false, + "x": 0.3935546875, + "y": 0.568359375 + }, + { + "act": 1.0, + "argmax_off_px": 0.0, + "cell": "both", + "center": 1.0, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 1.0072057247161865, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1108131584865233", + "seam": false, + "x": 0.8388671875, + "y": 0.568359375 + }, + { + "act": 0.961798, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.961798, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9618116617202759, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1108131584865233", + "seam": false, + "x": 0.1904296875, + "y": 0.537109375 + }, + { + "act": 0.730985, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.730985, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7309937477111816, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1110314244387816", + "seam": false, + "x": 0.79296875, + "y": 0.4921875 + }, + { + "act": 0.364537, + "argmax_off_px": 10.2, + "cell": "challenger_only", + "center": 0.277798, + "class": "tail", + "nearest_peak_px": 321.4, + "nearest_peak_score": 0.7309937477111816, + "null_med": 0.005449, + "null_p95": 0.302846, + "null_pct": 0.97, + "pano": "1110314244387816", + "seam": false, + "x": 0.4819725424417728, + "y": 0.5769238621475898 + }, + { + "act": 0.085844, + "argmax_off_px": 5.2, + "cell": "challenger_only", + "center": 0.080359, + "class": "tail", + "nearest_peak_px": 99.3, + "nearest_peak_score": 0.7309937477111816, + "null_med": 0.003516, + "null_p95": 0.730985, + "null_pct": 0.89, + "pano": "1110314244387816", + "seam": false, + "x": 0.6961413694097003, + "y": 0.5019622085748252 + }, + { + "act": 0.075016, + "argmax_off_px": 16.3, + "cell": "neither", + "center": 0.047331, + "class": "tail", + "nearest_peak_px": 274.7, + "nearest_peak_score": 0.7309937477111816, + "null_med": 0.006771, + "null_p95": 0.513768, + "null_pct": 0.765, + "pano": "1110314244387816", + "seam": false, + "x": 0.5260899962249893, + "y": 0.5462150503817342 + }, + { + "act": 0.997578, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.997578, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9975988864898682, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1119718896242677", + "seam": false, + "x": 0.1748046875, + "y": 0.583984375 + }, + { + "act": 0.887822, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.887822, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8878290057182312, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1119718896242677", + "seam": false, + "x": 0.82421875, + "y": 0.646484375 + }, + { + "act": 0.893696, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.893696, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8937223553657532, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1126712375884972", + "seam": false, + "x": 0.5576171875, + "y": 0.5546875 + }, + { + "act": 0.889458, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.889458, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8894680738449097, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1126712375884972", + "seam": false, + "x": 0.2294921875, + "y": 0.5546875 + }, + { + "act": 0.865858, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.865858, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8658739924430847, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1126712375884972", + "seam": false, + "x": 0.75390625, + "y": 0.630859375 + }, + { + "act": 1.0, + "argmax_off_px": 0.0, + "cell": "both", + "center": 1.0, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 1.0111504793167114, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1130501775077894", + "seam": false, + "x": 0.51953125, + "y": 0.5390625 + }, + { + "act": 0.961628, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.961628, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9616416096687317, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1130501775077894", + "seam": false, + "x": 0.96484375, + "y": 0.583984375 + }, + { + "act": 0.939102, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.939102, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9391264915466309, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1130501775077894", + "seam": false, + "x": 0.90234375, + "y": 0.5703125 + }, + { + "act": 0.925147, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.925147, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9251975417137146, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1130501775077894", + "seam": false, + "x": 0.1279296875, + "y": 0.5234375 + }, + { + "act": 0.913486, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.913486, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9135084748268127, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1130501775077894", + "seam": false, + "x": 0.43359375, + "y": 0.5234375 + }, + { + "act": 0.895101, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.895101, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8951044678688049, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1130501775077894", + "seam": false, + "x": 0.5810546875, + "y": 0.5546875 + }, + { + "act": 0.746246, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.746246, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7462716102600098, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1130501775077894", + "seam": false, + "x": 0.29296875, + "y": 0.5234375 + }, + { + "act": 0.672215, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.672215, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6722154021263123, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1130501775077894", + "seam": false, + "x": 0.16796875, + "y": 0.5234375 + }, + { + "act": 0.362796, + "argmax_off_px": 8.1, + "cell": "challenger_only", + "center": 0.305334, + "class": "tail", + "nearest_peak_px": 153.4, + "nearest_peak_score": 0.9391264915466309, + "null_med": 0.040755, + "null_p95": 0.936522, + "null_pct": 0.8, + "pano": "1130501775077894", + "seam": false, + "x": 0.7537373675722064, + "y": 0.6080808142459754 + }, + { + "act": 0.134065, + "argmax_off_px": 22.5, + "cell": "challenger_only", + "center": 0.014528, + "class": "tail", + "nearest_peak_px": 111.9, + "nearest_peak_score": 0.9391264915466309, + "null_med": 0.105939, + "null_p95": 0.939102, + "null_pct": 0.55, + "pano": "1130501775077894", + "seam": false, + "x": 0.7943434281782671, + "y": 0.6032323293974905 + }, + { + "act": 0.977259, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.977259, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9772834777832031, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1179500609797636", + "seam": true, + "x": 0.98046875, + "y": 0.5546875 + }, + { + "act": 0.969846, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.969846, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9698507189750671, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1179500609797636", + "seam": false, + "x": 0.58203125, + "y": 0.599609375 + }, + { + "act": 0.891798, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.891798, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8918266296386719, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1179500609797636", + "seam": false, + "x": 0.2919921875, + "y": 0.568359375 + }, + { + "act": 0.891928, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.891928, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8919466733932495, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1180673306331763", + "seam": false, + "x": 0.6591796875, + "y": 0.5859375 + }, + { + "act": 0.872, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.872, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8720241785049438, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1180673306331763", + "seam": false, + "x": 0.3154296875, + "y": 0.537109375 + }, + { + "act": 0.813617, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.813617, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8136365413665771, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1185319949364085", + "seam": false, + "x": 0.4013671875, + "y": 0.537109375 + }, + { + "act": 0.240679, + "argmax_off_px": 19.4, + "cell": "challenger_only", + "center": 0.086301, + "class": "tail", + "nearest_peak_px": 115.2, + "nearest_peak_score": 0.8136365413665771, + "null_med": 0.002236, + "null_p95": 0.783489, + "null_pct": 0.915, + "pano": "1185319949364085", + "seam": false, + "x": 0.5131313069661458, + "y": 0.5119191857540246 + }, + { + "act": 0.886741, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.886741, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8867697715759277, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1187483045673326", + "seam": false, + "x": 0.3232421875, + "y": 0.537109375 + }, + { + "act": 0.761366, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.761366, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7614015936851501, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1187483045673326", + "seam": false, + "x": 0.39453125, + "y": 0.521484375 + }, + { + "act": 0.543558, + "argmax_off_px": 6.6, + "cell": "challenger_only", + "center": 0.402944, + "class": "tail", + "nearest_peak_px": 452.5, + "nearest_peak_score": 0.8867697715759277, + "null_med": 0.00272, + "null_p95": 0.143654, + "null_pct": 1.0, + "pano": "1187483045673326", + "seam": false, + "x": 0.8828282766631156, + "y": 0.6088888827237215 + }, + { + "act": 0.128579, + "argmax_off_px": 4.5, + "cell": "neither", + "center": 0.125675, + "class": "tail", + "nearest_peak_px": 380.2, + "nearest_peak_score": 0.8867697715759277, + "null_med": 0.002928, + "null_p95": 0.828798, + "null_pct": 0.845, + "pano": "1187483045673326", + "seam": false, + "x": 0.9519191857540246, + "y": 0.5419191857540246 + }, + { + "act": 0.927118, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.927118, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.92713463306427, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1237376427883773", + "seam": false, + "x": 0.53515625, + "y": 0.5546875 + }, + { + "act": 0.902633, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.902633, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9026480913162231, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1237376427883773", + "seam": false, + "x": 0.4248046875, + "y": 0.552734375 + }, + { + "act": 0.902577, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.902577, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9025876522064209, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1237376427883773", + "seam": false, + "x": 0.3310546875, + "y": 0.615234375 + }, + { + "act": 0.215176, + "argmax_off_px": 14.8, + "cell": "challenger_only", + "center": 0.107466, + "class": "tail", + "nearest_peak_px": 148.2, + "nearest_peak_score": 0.92713463306427, + "null_med": 0.000984, + "null_p95": 0.032863, + "null_pct": 1.0, + "pano": "1237376427883773", + "seam": false, + "x": 0.6525252463600852, + "y": 0.7240403978752368 + }, + { + "act": 0.20581, + "argmax_off_px": 9.2, + "cell": "neither", + "center": 0.060418, + "class": "tail", + "nearest_peak_px": 107.5, + "nearest_peak_score": 0.92713463306427, + "null_med": 0.007954, + "null_p95": 0.902577, + "null_pct": 0.815, + "pano": "1237376427883773", + "seam": false, + "x": 0.6355555493903883, + "y": 0.6161616099964489 + }, + { + "act": 0.557275, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.557275, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.5572798252105713, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1260990361757674", + "seam": false, + "x": 0.9091796875, + "y": 0.5546875 + }, + { + "act": 0.403434, + "argmax_off_px": 2.9, + "cell": "neither", + "center": 0.378516, + "class": "tail", + "nearest_peak_px": 453.0, + "nearest_peak_score": 0.5572798252105713, + "null_med": 0.00175, + "null_p95": 0.312931, + "null_pct": 0.955, + "pano": "1260990361757674", + "seam": false, + "x": 0.46702477127592434, + "y": 0.5269179634248174 + }, + { + "act": 0.278159, + "argmax_off_px": 2.9, + "cell": "challenger_only", + "center": 0.253053, + "class": "tail", + "nearest_peak_px": 358.4, + "nearest_peak_score": 0.5572798252105713, + "null_med": 0.001615, + "null_p95": 0.557275, + "null_pct": 0.85, + "pano": "1260990361757674", + "seam": false, + "x": 0.5593004053574665, + "y": 0.5336089345216305 + }, + { + "act": 0.958944, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.958944, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9589544534683228, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1263975528308076", + "seam": false, + "x": 0.62109375, + "y": 0.552734375 + }, + { + "act": 0.893724, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.893724, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8937392234802246, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1263975528308076", + "seam": false, + "x": 0.9404296875, + "y": 0.552734375 + }, + { + "act": 0.888867, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.888867, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8888925313949585, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1263975528308076", + "seam": false, + "x": 0.0966796875, + "y": 0.5390625 + }, + { + "act": 0.881899, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.881899, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.88192218542099, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1263975528308076", + "seam": false, + "x": 0.3388671875, + "y": 0.5234375 + }, + { + "act": 0.523525, + "argmax_off_px": 22.4, + "cell": "challenger_only", + "center": 0.073007, + "class": "tail", + "nearest_peak_px": 33.1, + "nearest_peak_score": 0.8937392234802246, + "null_med": 0.054433, + "null_p95": 0.958944, + "null_pct": 0.74, + "pano": "1263975528308076", + "seam": false, + "x": 0.9712878880356297, + "y": 0.5335353504527698 + }, + { + "act": 0.954889, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.954889, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9549100399017334, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1273933840289887", + "seam": false, + "x": 0.28515625, + "y": 0.5859375 + }, + { + "act": 0.931501, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.931501, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9315147399902344, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1273933840289887", + "seam": false, + "x": 0.8154296875, + "y": 0.5703125 + }, + { + "act": 0.930736, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.930736, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9307556748390198, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1273933840289887", + "seam": false, + "x": 0.7841796875, + "y": 0.5859375 + }, + { + "act": 0.92701, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.92701, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9269956946372986, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1273933840289887", + "seam": false, + "x": 0.8935546875, + "y": 0.5546875 + }, + { + "act": 0.914886, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.914886, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9149086475372314, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1273933840289887", + "seam": false, + "x": 0.73828125, + "y": 0.5703125 + }, + { + "act": 0.911319, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.911319, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9113526940345764, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1273933840289887", + "seam": false, + "x": 0.09765625, + "y": 0.5546875 + }, + { + "act": 0.909138, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.909138, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9091572761535645, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1273933840289887", + "seam": false, + "x": 0.2216796875, + "y": 0.630859375 + }, + { + "act": 0.86909, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.86909, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8690925240516663, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1273933840289887", + "seam": false, + "x": 0.6123046875, + "y": 0.5390625 + }, + { + "act": 0.866255, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.866255, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8662667274475098, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1273933840289887", + "seam": false, + "x": 0.4248046875, + "y": 0.5390625 + }, + { + "act": 0.858303, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.858303, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8583229184150696, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1273933840289887", + "seam": false, + "x": 0.17578125, + "y": 0.599609375 + }, + { + "act": 0.86909, + "argmax_off_px": 19.2, + "cell": "neither", + "center": 0.250927, + "class": "tail", + "nearest_peak_px": 19.2, + "nearest_peak_score": 0.8690925240516663, + "null_med": 0.374923, + "null_p95": 0.92701, + "null_pct": 0.8, + "pano": "1273933840289887", + "seam": false, + "x": 0.5935664064174488, + "y": 0.5384636678464564 + }, + { + "act": 0.948001, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.948001, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9480153322219849, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1279553583800599", + "seam": false, + "x": 0.0810546875, + "y": 0.5546875 + }, + { + "act": 0.809171, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.809171, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8091651797294617, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1279553583800599", + "seam": false, + "x": 0.8857421875, + "y": 0.583984375 + }, + { + "act": 0.8919, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.8919, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8919329643249512, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1288163659019705", + "seam": false, + "x": 0.4404296875, + "y": 0.5390625 + }, + { + "act": 0.8919, + "argmax_off_px": 17.0, + "cell": "rampnet_only", + "center": 0.857872, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8578888773918152, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1288163659019705", + "seam": false, + "x": 0.45703125, + "y": 0.5390625 + }, + { + "act": 0.126263, + "argmax_off_px": 22.4, + "cell": "neither", + "center": 0.010458, + "class": "tail", + "nearest_peak_px": 175.2, + "nearest_peak_score": 0.8919329643249512, + "null_med": 0.002314, + "null_p95": 0.400246, + "null_pct": 0.825, + "pano": "1288163659019705", + "seam": false, + "x": 0.2791919130267519, + "y": 0.6537373675722065 + }, + { + "act": 0.512223, + "argmax_off_px": 7.6, + "cell": "neither", + "center": 0.378504, + "class": "tail", + "nearest_peak_px": 125.4, + "nearest_peak_score": 0.8919329643249512, + "null_med": 0.011752, + "null_p95": 0.4375, + "null_pct": 0.99, + "pano": "1288163659019705", + "seam": false, + "x": 0.32282827666311553, + "y": 0.6076767615116003 + }, + { + "act": 0.929079, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.929079, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9291057586669922, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1294684158910702", + "seam": false, + "x": 0.83984375, + "y": 0.505859375 + }, + { + "act": 0.961136, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.961136, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9611420035362244, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1294705618516185", + "seam": false, + "x": 0.58203125, + "y": 0.537109375 + }, + { + "act": 0.916376, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.916376, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9164056777954102, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1294705618516185", + "seam": false, + "x": 0.68359375, + "y": 0.599609375 + }, + { + "act": 0.96603, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.96603, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9660662412643433, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1309093164014619", + "seam": false, + "x": 0.35546875, + "y": 0.5234375 + }, + { + "act": 0.963532, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.963532, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9635652303695679, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1309093164014619", + "seam": false, + "x": 0.5576171875, + "y": 0.568359375 + }, + { + "act": 0.896823, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.896823, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8967987298965454, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1309093164014619", + "seam": false, + "x": 0.32421875, + "y": 0.5234375 + }, + { + "act": 0.890193, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.890193, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.89020836353302, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1309093164014619", + "seam": false, + "x": 0.92578125, + "y": 0.599609375 + }, + { + "act": 0.799142, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.799142, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7991482019424438, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1309093164014619", + "seam": false, + "x": 0.8701171875, + "y": 0.583984375 + }, + { + "act": 0.799142, + "argmax_off_px": 15.0, + "cell": "both", + "center": 0.768035, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7680552005767822, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1309093164014619", + "seam": false, + "x": 0.8701171875, + "y": 0.5546875 + }, + { + "act": 0.671669, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.671669, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6716945171356201, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1309093164014619", + "seam": false, + "x": 0.7919921875, + "y": 0.5390625 + }, + { + "act": 0.799142, + "argmax_off_px": 17.2, + "cell": "neither", + "center": 0.116021, + "class": "tail", + "nearest_peak_px": 17.2, + "nearest_peak_score": 0.7991482019424438, + "null_med": 0.102378, + "null_p95": 0.963532, + "null_pct": 0.885, + "pano": "1309093164014619", + "seam": false, + "x": 0.8864646402994791, + "y": 0.5765656627308239 + }, + { + "act": 0.749987, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.749987, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7499932050704956, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1315788070079167", + "seam": false, + "x": 0.5888671875, + "y": 0.5234375 + }, + { + "act": 0.265718, + "argmax_off_px": 22.1, + "cell": "challenger_only", + "center": 0.220484, + "class": "tail", + "nearest_peak_px": 38.4, + "nearest_peak_score": 0.7499932050704956, + "null_med": 0.002646, + "null_p95": 0.439927, + "null_pct": 0.91, + "pano": "1315788070079167", + "seam": false, + "x": 0.5610100948449337, + "y": 0.47313130696614586 + }, + { + "act": 0.770554, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.770554, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7705703973770142, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1315844333300588", + "seam": false, + "x": 0.1904296875, + "y": 0.5859375 + }, + { + "act": 0.89899, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.89899, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8990136384963989, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1327023138707493", + "seam": false, + "x": 0.41015625, + "y": 0.5546875 + }, + { + "act": 0.698635, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.698635, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6986466646194458, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1327023138707493", + "seam": false, + "x": 0.6201171875, + "y": 0.5703125 + }, + { + "act": 0.132289, + "argmax_off_px": 1.6, + "cell": "challenger_only", + "center": 0.129971, + "class": "tail", + "nearest_peak_px": 72.5, + "nearest_peak_score": 0.6986466646194458, + "null_med": 0.011101, + "null_p95": 0.872345, + "null_pct": 0.825, + "pano": "1327023138707493", + "seam": false, + "x": 0.5511111542672822, + "y": 0.5386869118430397 + }, + { + "act": 0.929298, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.929298, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9293081760406494, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1335429861397399", + "seam": false, + "x": 0.24609375, + "y": 0.646484375 + }, + { + "act": 0.914961, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.914961, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9149634838104248, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1335429861397399", + "seam": false, + "x": 0.9013671875, + "y": 0.5546875 + }, + { + "act": 0.896301, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.896301, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8963165879249573, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1335429861397399", + "seam": false, + "x": 0.02734375, + "y": 0.568359375 + }, + { + "act": 0.895466, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.895466, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8955129384994507, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1335429861397399", + "seam": false, + "x": 0.74609375, + "y": 0.5703125 + }, + { + "act": 0.874735, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.874735, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8747516870498657, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1338631107629110", + "seam": false, + "x": 0.5576171875, + "y": 0.5234375 + }, + { + "act": 0.745411, + "argmax_off_px": 22.4, + "cell": "challenger_only", + "center": 0.207195, + "class": "tail", + "nearest_peak_px": 29.0, + "nearest_peak_score": 0.8747516870498657, + "null_med": 0.002086, + "null_p95": 0.402981, + "null_pct": 1.0, + "pano": "1338631107629110", + "seam": false, + "x": 0.5325252463600852, + "y": 0.4973737312085701 + }, + { + "act": 0.866864, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.866864, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8668623566627502, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1408179757063785", + "seam": false, + "x": 0.3779296875, + "y": 0.630859375 + }, + { + "act": 1.0, + "argmax_off_px": 0.0, + "cell": "both", + "center": 1.0, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 1.003684401512146, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1427673368387929", + "seam": false, + "x": 0.59765625, + "y": 0.537109375 + }, + { + "act": 0.948419, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.948419, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9484301805496216, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1427673368387929", + "seam": false, + "x": 0.4873046875, + "y": 0.5234375 + }, + { + "act": 0.863412, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.863412, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8634457588195801, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1427673368387929", + "seam": false, + "x": 0.33984375, + "y": 0.5859375 + }, + { + "act": 0.772906, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.772906, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7728960514068604, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1441274599876577", + "seam": false, + "x": 0.0654296875, + "y": 0.5390625 + }, + { + "act": 0.772906, + "argmax_off_px": 16.8, + "cell": "challenger_only", + "center": 0.231996, + "class": "tail", + "nearest_peak_px": 16.8, + "nearest_peak_score": 0.7728960514068604, + "null_med": 0.009665, + "null_p95": 0.35217, + "null_pct": 1.0, + "pano": "1441274599876577", + "seam": false, + "x": 0.05026338366770002, + "y": 0.5263919001449772 + }, + { + "act": 0.303654, + "argmax_off_px": 22.4, + "cell": "neither", + "center": 0.171911, + "class": "tail", + "nearest_peak_px": 124.4, + "nearest_peak_score": 0.7728960514068604, + "null_med": 0.009683, + "null_p95": 0.678158, + "null_pct": 0.915, + "pano": "1441274599876577", + "seam": false, + "x": 0.9440247579367571, + "y": 0.5328431364003076 + }, + { + "act": 0.757466, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.757466, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7574822306632996, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1473003156922360", + "seam": false, + "x": 0.9560546875, + "y": 0.5234375 + }, + { + "act": 0.625056, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.625056, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6250661611557007, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1473003156922360", + "seam": false, + "x": 0.0498046875, + "y": 0.521484375 + }, + { + "act": 0.851548, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.851548, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8515617251396179, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1483585545954157", + "seam": false, + "x": 0.51171875, + "y": 0.5390625 + }, + { + "act": 0.844852, + "argmax_off_px": 22.0, + "cell": "rampnet_only", + "center": 0.790555, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7905715703964233, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1483585545954157", + "seam": false, + "x": 0.53515625, + "y": 0.5390625 + }, + { + "act": 0.716116, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.716116, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7161297798156738, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1483585545954157", + "seam": false, + "x": 0.6669921875, + "y": 0.552734375 + }, + { + "act": 0.601094, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.601094, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.601104199886322, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1589004208714002", + "seam": false, + "x": 0.9716796875, + "y": 0.5390625 + }, + { + "act": 0.594131, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.594131, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.5941709280014038, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1589004208714002", + "seam": false, + "x": 0.06640625, + "y": 0.5390625 + }, + { + "act": 0.978302, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.978302, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9783142805099487, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1599497457585207", + "seam": false, + "x": 0.60546875, + "y": 0.552734375 + }, + { + "act": 0.955378, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.955378, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9554139375686646, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1599497457585207", + "seam": false, + "x": 0.7607421875, + "y": 0.6171875 + }, + { + "act": 0.91067, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.91067, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9106926918029785, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1701172050581812", + "seam": false, + "x": 0.1044921875, + "y": 0.5546875 + }, + { + "act": 0.744185, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.744185, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7442018985748291, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1701172050581812", + "seam": true, + "x": 0.9794921875, + "y": 0.568359375 + }, + { + "act": 0.652255, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.652255, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6522689461708069, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1701172050581812", + "seam": false, + "x": 0.6904296875, + "y": 0.7421875 + }, + { + "act": 0.712292, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.712292, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7123180627822876, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1739689546844035", + "seam": false, + "x": 0.13671875, + "y": 0.615234375 + }, + { + "act": 0.947448, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.947448, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.947451114654541, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1759178911495771", + "seam": false, + "x": 0.3935546875, + "y": 0.5546875 + }, + { + "act": 0.692712, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.692712, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.692729651927948, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1759178911495771", + "seam": false, + "x": 0.5498046875, + "y": 0.5703125 + }, + { + "act": 0.459476, + "argmax_off_px": 11.2, + "cell": "neither", + "center": 0.222914, + "class": "tail", + "nearest_peak_px": 56.1, + "nearest_peak_score": 0.947451114654541, + "null_med": 0.003831, + "null_p95": 0.947448, + "null_pct": 0.875, + "pano": "1759178911495771", + "seam": false, + "x": 0.4460757821051315, + "y": 0.5233485093778587 + }, + { + "act": 0.459476, + "argmax_off_px": 2.2, + "cell": "challenger_only", + "center": 0.430928, + "class": "tail", + "nearest_peak_px": 69.1, + "nearest_peak_score": 0.947451114654541, + "null_med": 0.003468, + "null_p95": 0.696784, + "null_pct": 0.9, + "pano": "1759178911495771", + "seam": false, + "x": 0.459005214757595, + "y": 0.5217732532878832 + }, + { + "act": 0.185813, + "argmax_off_px": 22.5, + "cell": "neither", + "center": 0.036292, + "class": "tail", + "nearest_peak_px": 39.5, + "nearest_peak_score": 0.692729651927948, + "null_med": 0.003468, + "null_p95": 0.762892, + "null_pct": 0.84, + "pano": "1759178911495771", + "seam": false, + "x": 0.5197303339935238, + "y": 0.5219953845879944 + }, + { + "act": 0.973626, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.973626, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9736382961273193, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1828524234403425", + "seam": false, + "x": 0.19140625, + "y": 0.615234375 + }, + { + "act": 0.857854, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.857854, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8578647375106812, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1828524234403425", + "seam": false, + "x": 0.8779296875, + "y": 0.662109375 + }, + { + "act": 0.957361, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.957361, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.957377016544342, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1847752429062443", + "seam": false, + "x": 0.31640625, + "y": 0.5390625 + }, + { + "act": 0.955378, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.955378, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.955399215221405, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1847752429062443", + "seam": false, + "x": 0.1826171875, + "y": 0.5390625 + }, + { + "act": 0.944535, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.944535, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9445477724075317, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1847752429062443", + "seam": false, + "x": 0.91015625, + "y": 0.552734375 + }, + { + "act": 0.934892, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.934892, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9348896741867065, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1847752429062443", + "seam": false, + "x": 0.38671875, + "y": 0.537109375 + }, + { + "act": 0.922957, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.922957, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9229707717895508, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1847752429062443", + "seam": false, + "x": 0.55859375, + "y": 0.552734375 + }, + { + "act": 0.921211, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.921211, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9212089776992798, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1847752429062443", + "seam": false, + "x": 0.80859375, + "y": 0.5703125 + }, + { + "act": 0.751652, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.751652, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7516857385635376, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1847752429062443", + "seam": false, + "x": 0.1044921875, + "y": 0.5390625 + }, + { + "act": 0.740659, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.740659, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7406735420227051, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1847752429062443", + "seam": false, + "x": 0.65234375, + "y": 0.5703125 + }, + { + "act": 0.762745, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.762745, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7627651691436768, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1905003193597285", + "seam": false, + "x": 0.36328125, + "y": 0.552734375 + }, + { + "act": 0.64667, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.64667, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6466811895370483, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1905003193597285", + "seam": false, + "x": 0.63671875, + "y": 0.5546875 + }, + { + "act": 0.481772, + "argmax_off_px": 6.1, + "cell": "challenger_only", + "center": 0.473058, + "class": "tail", + "nearest_peak_px": 172.3, + "nearest_peak_score": 0.6466811895370483, + "null_med": 0.015273, + "null_p95": 0.722935, + "null_pct": 0.875, + "pano": "1905003193597285", + "seam": false, + "x": 0.8046464584812973, + "y": 0.5749494887843276 + }, + { + "act": 0.093554, + "argmax_off_px": 21.4, + "cell": "challenger_only", + "center": 0.059961, + "class": "tail", + "nearest_peak_px": 234.8, + "nearest_peak_score": 0.6466811895370483, + "null_med": 0.009791, + "null_p95": 0.64667, + "null_pct": 0.72, + "pano": "1905003193597285", + "seam": false, + "x": 0.8658585796934185, + "y": 0.5693939578894412 + }, + { + "act": 0.093554, + "argmax_off_px": 5.9, + "cell": "challenger_only", + "center": 0.085348, + "class": "tail", + "nearest_peak_px": 259.9, + "nearest_peak_score": 0.6466811895370483, + "null_med": 0.024054, + "null_p95": 0.64667, + "null_pct": 0.67, + "pano": "1905003193597285", + "seam": false, + "x": 0.8905050936612215, + "y": 0.5596969881924716 + }, + { + "act": 0.079862, + "argmax_off_px": 21.8, + "cell": "challenger_only", + "center": 0.076573, + "class": "tail", + "nearest_peak_px": 290.5, + "nearest_peak_score": 0.6466811895370483, + "null_med": 0.024054, + "null_p95": 0.666264, + "null_pct": 0.655, + "pano": "1905003193597285", + "seam": false, + "x": 0.9204040342388731, + "y": 0.5475757760712595 + }, + { + "act": 0.901254, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.901254, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9012807011604309, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1991198475040883", + "seam": false, + "x": 0.5810546875, + "y": 0.568359375 + }, + { + "act": 0.924785, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.924785, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.924778938293457, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1991876994661275", + "seam": false, + "x": 0.2294921875, + "y": 0.568359375 + }, + { + "act": 0.539202, + "argmax_off_px": 4.0, + "cell": "challenger_only", + "center": 0.498044, + "class": "tail", + "nearest_peak_px": 213.1, + "nearest_peak_score": 0.924778938293457, + "null_med": 0.044088, + "null_p95": 0.471416, + "null_pct": 0.96, + "pano": "1991876994661275", + "seam": false, + "x": 0.022222216057054923, + "y": 0.531313125147964 + }, + { + "act": 0.287739, + "argmax_off_px": 3.8, + "cell": "challenger_only", + "center": 0.264974, + "class": "tail", + "nearest_peak_px": 114.9, + "nearest_peak_score": 0.924778938293457, + "null_med": 0.083931, + "null_p95": 0.539202, + "null_pct": 0.765, + "pano": "1991876994661275", + "seam": false, + "x": 0.1188302236550056, + "y": 0.5312825529464339 + }, + { + "act": 0.954275, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.954275, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9542931318283081, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2067733823644753", + "seam": false, + "x": 0.0966796875, + "y": 0.568359375 + }, + { + "act": 0.950191, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.950191, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9501867294311523, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2067733823644753", + "seam": false, + "x": 0.23828125, + "y": 0.599609375 + }, + { + "act": 0.928207, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.928207, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9282107353210449, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2067733823644753", + "seam": false, + "x": 0.94140625, + "y": 0.5546875 + }, + { + "act": 0.87734, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.87734, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8773713707923889, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2067733823644753", + "seam": false, + "x": 0.7841796875, + "y": 0.615234375 + }, + { + "act": 0.889261, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.889261, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8892773389816284, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2111278956050786", + "seam": false, + "x": 0.3779296875, + "y": 0.568359375 + }, + { + "act": 0.668602, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.668602, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.668611466884613, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2111278956050786", + "seam": false, + "x": 0.64453125, + "y": 0.5703125 + }, + { + "act": 0.878634, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.878634, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8786584138870239, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2141681583023863", + "seam": false, + "x": 0.49609375, + "y": 0.5546875 + }, + { + "act": 0.819354, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.819354, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8193663954734802, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2141681583023863", + "seam": false, + "x": 0.80078125, + "y": 0.6015625 + }, + { + "act": 0.69882, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.69882, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6988358497619629, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2147631415757748", + "seam": false, + "x": 0.1201171875, + "y": 0.5390625 + }, + { + "act": 0.910001, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.910001, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9100374579429626, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2184370012043145", + "seam": true, + "x": 0.9794921875, + "y": 0.5703125 + }, + { + "act": 0.906266, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.906266, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9062710404396057, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2184370012043145", + "seam": false, + "x": 0.2919921875, + "y": 0.583984375 + }, + { + "act": 0.627935, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.627935, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6279417872428894, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2184370012043145", + "seam": false, + "x": 0.1982421875, + "y": 0.537109375 + }, + { + "act": 0.979381, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.979381, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9793874621391296, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2263954690670646", + "seam": false, + "x": 0.37109375, + "y": 0.5390625 + }, + { + "act": 0.898989, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.898989, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8989967107772827, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2263954690670646", + "seam": false, + "x": 0.1748046875, + "y": 0.5390625 + }, + { + "act": 0.881651, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.881651, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8816700577735901, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2263954690670646", + "seam": false, + "x": 0.06640625, + "y": 0.537109375 + }, + { + "act": 0.788486, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.788486, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.788508415222168, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2263954690670646", + "seam": true, + "x": 0.01953125, + "y": 0.5234375 + }, + { + "act": 0.749173, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.749173, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7491846680641174, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2263954690670646", + "seam": false, + "x": 0.94140625, + "y": 0.599609375 + }, + { + "act": 0.721463, + "argmax_off_px": 22.4, + "cell": "both", + "center": 0.653083, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6530851721763611, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2263954690670646", + "seam": false, + "x": 0.9482421875, + "y": 0.5546875 + }, + { + "act": 0.929437, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.929437, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9294503927230835, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "27724402107145083", + "seam": false, + "x": 0.56640625, + "y": 0.5390625 + }, + { + "act": 0.825894, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.825894, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8259216547012329, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "27724402107145083", + "seam": false, + "x": 0.41796875, + "y": 0.5390625 + }, + { + "act": 0.356553, + "argmax_off_px": 5.4, + "cell": "challenger_only", + "center": 0.307763, + "class": "tail", + "nearest_peak_px": 38.5, + "nearest_peak_score": 0.9294503927230835, + "null_med": 0.003167, + "null_p95": 0.764083, + "null_pct": 0.9, + "pano": "27724402107145083", + "seam": false, + "x": 0.5995960027521307, + "y": 0.574242461233428 + }, + { + "act": 0.665317, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.665317, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6653203368186951, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "372149922554566", + "seam": false, + "x": 0.91015625, + "y": 0.5546875 + }, + { + "act": 0.648446, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.648446, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6484609246253967, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "372149922554566", + "seam": false, + "x": 0.0576171875, + "y": 0.552734375 + }, + { + "act": 0.210347, + "argmax_off_px": 4.9, + "cell": "challenger_only", + "center": 0.182823, + "class": "tail", + "nearest_peak_px": 44.9, + "nearest_peak_score": 0.6653203368186951, + "null_med": 0.00067, + "null_p95": 0.648446, + "null_pct": 0.905, + "pano": "372149922554566", + "seam": false, + "x": 0.9527272912227747, + "y": 0.533838426994555 + }, + { + "act": 0.607845, + "argmax_off_px": 22.2, + "cell": "challenger_only", + "center": 0.08643, + "class": "tail", + "nearest_peak_px": 26.8, + "nearest_peak_score": 0.6484609246253967, + "null_med": 0.000944, + "null_p95": 0.665317, + "null_pct": 0.935, + "pano": "372149922554566", + "seam": false, + "x": 0.03474748091264204, + "y": 0.5273737312085701 + }, + { + "act": 0.962026, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.962026, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9620377421379089, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "383880874806933", + "seam": false, + "x": 0.84765625, + "y": 0.5859375 + }, + { + "act": 0.895772, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.895772, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.895784318447113, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "383880874806933", + "seam": false, + "x": 0.94140625, + "y": 0.5546875 + }, + { + "act": 0.343733, + "argmax_off_px": 1.5, + "cell": "challenger_only", + "center": 0.337857, + "class": "tail", + "nearest_peak_px": 277.8, + "nearest_peak_score": 0.895784318447113, + "null_med": 0.020841, + "null_p95": 0.873995, + "null_pct": 0.89, + "pano": "383880874806933", + "seam": false, + "x": 0.21252524636008524, + "y": 0.5361616099964489 + }, + { + "act": 0.343733, + "argmax_off_px": 20.7, + "cell": "challenger_only", + "center": 0.142017, + "class": "tail", + "nearest_peak_px": 258.9, + "nearest_peak_score": 0.895784318447113, + "null_med": 0.025784, + "null_p95": 0.709031, + "null_pct": 0.865, + "pano": "383880874806933", + "seam": false, + "x": 0.19393941243489585, + "y": 0.5297979736328124 + }, + { + "act": 0.858318, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.858318, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8583464026451111, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "386363531219281", + "seam": false, + "x": 0.66015625, + "y": 0.5546875 + }, + { + "act": 0.847305, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.847305, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8473024964332581, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "386363531219281", + "seam": false, + "x": 0.4482421875, + "y": 0.568359375 + }, + { + "act": 0.053441, + "argmax_off_px": 22.5, + "cell": "challenger_only", + "center": 0.044115, + "class": "tail", + "nearest_peak_px": 51.3, + "nearest_peak_score": 0.8473024964332581, + "null_med": 0.006155, + "null_p95": 0.618636, + "null_pct": 0.82, + "pano": "386363531219281", + "seam": false, + "x": 0.4905050936612216, + "y": 0.5144444876006156 + }, + { + "act": 0.059287, + "argmax_off_px": 2.8, + "cell": "challenger_only", + "center": 0.056529, + "class": "tail", + "nearest_peak_px": 106.5, + "nearest_peak_score": 0.8583464026451111, + "null_med": 0.006155, + "null_p95": 0.751092, + "null_pct": 0.84, + "pano": "386363531219281", + "seam": false, + "x": 0.5579797918146306, + "y": 0.5160606245561079 + }, + { + "act": 0.796538, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.796538, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7965537309646606, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "3901547360084831", + "seam": false, + "x": 0.2138671875, + "y": 0.5390625 + }, + { + "act": 0.890949, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.890949, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8909704685211182, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "3956582084664486", + "seam": false, + "x": 0.44140625, + "y": 0.5390625 + }, + { + "act": 0.846316, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.846316, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8463200330734253, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "3956582084664486", + "seam": false, + "x": 0.55078125, + "y": 0.552734375 + }, + { + "act": 0.828984, + "argmax_off_px": 21.7, + "cell": "neither", + "center": 0.333811, + "class": "tail", + "nearest_peak_px": 26.2, + "nearest_peak_score": 0.8909704685211182, + "null_med": 0.000476, + "null_p95": 0.633645, + "null_pct": 0.98, + "pano": "3956582084664486", + "seam": false, + "x": 0.46505054820667613, + "y": 0.5192929169625947 + }, + { + "act": 0.846316, + "argmax_off_px": 20.7, + "cell": "challenger_only", + "center": 0.077748, + "class": "tail", + "nearest_peak_px": 20.7, + "nearest_peak_score": 0.8463200330734253, + "null_med": 0.000518, + "null_p95": 0.890949, + "null_pct": 0.93, + "pano": "3956582084664486", + "seam": false, + "x": 0.5402850979625293, + "y": 0.5182507727523443 + }, + { + "act": 0.410306, + "argmax_off_px": 6.4, + "cell": "challenger_only", + "center": 0.378829, + "class": "tail", + "nearest_peak_px": 86.8, + "nearest_peak_score": 0.5525027513504028, + "null_med": 0.025696, + "null_p95": 0.497308, + "null_pct": 0.905, + "pano": "3980741912187626", + "seam": false, + "x": 0.3773737312085701, + "y": 0.5846464584812974 + }, + { + "act": 0.497308, + "argmax_off_px": 12.0, + "cell": "challenger_only", + "center": 0.332233, + "class": "tail", + "nearest_peak_px": 93.7, + "nearest_peak_score": 0.5958422422409058, + "null_med": 0.009084, + "null_p95": 0.410306, + "null_pct": 1.0, + "pano": "3980741912187626", + "seam": false, + "x": 0.6088888827237215, + "y": 0.6064646402994792 + }, + { + "act": 0.497308, + "argmax_off_px": 20.0, + "cell": "neither", + "center": 0.153297, + "class": "tail", + "nearest_peak_px": 88.9, + "nearest_peak_score": 0.5958422422409058, + "null_med": 0.062561, + "null_p95": 0.495448, + "null_pct": 0.955, + "pano": "3980741912187626", + "seam": false, + "x": 0.6108941345557353, + "y": 0.5709128544012171 + }, + { + "act": 0.807756, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.807756, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8077545762062073, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "4102292636718018", + "seam": false, + "x": 0.32421875, + "y": 0.5390625 + }, + { + "act": 0.555799, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.555799, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.5558204054832458, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "4102292636718018", + "seam": false, + "x": 0.61328125, + "y": 0.662109375 + }, + { + "act": 0.78927, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.78927, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7892700433731079, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "4116269558691031", + "seam": false, + "x": 0.48828125, + "y": 0.6015625 + }, + { + "act": 0.507915, + "argmax_off_px": 13.9, + "cell": "challenger_only", + "center": 0.342678, + "class": "tail", + "nearest_peak_px": 68.9, + "nearest_peak_score": 0.7892700433731079, + "null_med": 0.002889, + "null_p95": 0.244408, + "null_pct": 1.0, + "pano": "4116269558691031", + "seam": false, + "x": 0.4294949433297822, + "y": 0.6670707009055398 + }, + { + "act": 0.860736, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.860736, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8607585430145264, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "423989957171190", + "seam": false, + "x": 0.5341796875, + "y": 0.568359375 + }, + { + "act": 0.85772, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.85772, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.857740044593811, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "423989957171190", + "seam": false, + "x": 0.37109375, + "y": 0.5390625 + }, + { + "act": 0.037643, + "argmax_off_px": 2.1, + "cell": "challenger_only", + "center": 0.035938, + "class": "faint_local", + "nearest_peak_px": 57.4, + "nearest_peak_score": 0.857740044593811, + "null_med": 0.00442, + "null_p95": 0.704602, + "null_pct": 0.885, + "pano": "423989957171190", + "seam": false, + "x": 0.42667711943494924, + "y": 0.5250655456146334 + }, + { + "act": 0.73131, + "argmax_off_px": 22.5, + "cell": "challenger_only", + "center": 0.112684, + "class": "tail", + "nearest_peak_px": 30.9, + "nearest_peak_score": 0.8607585430145264, + "null_med": 0.004899, + "null_p95": 0.764398, + "null_pct": 0.95, + "pano": "423989957171190", + "seam": false, + "x": 0.5133691152905883, + "y": 0.5247863607532633 + }, + { + "act": 0.860098, + "argmax_off_px": 21.7, + "cell": "neither", + "center": 0.296156, + "class": "tail", + "nearest_peak_px": 22.7, + "nearest_peak_score": 0.8607585430145264, + "null_med": 0.004897, + "null_p95": 0.792231, + "null_pct": 1.0, + "pano": "423989957171190", + "seam": false, + "x": 0.5291509811918936, + "y": 0.5252428801194406 + }, + { + "act": 0.860736, + "argmax_off_px": 18.5, + "cell": "neither", + "center": 0.18202, + "class": "tail", + "nearest_peak_px": 18.5, + "nearest_peak_score": 0.8607585430145264, + "null_med": 0.006464, + "null_p95": 0.45834, + "null_pct": 1.0, + "pano": "423989957171190", + "seam": false, + "x": 0.5474366110477303, + "y": 0.5438915753113823 + }, + { + "act": 1.0, + "argmax_off_px": 0.0, + "cell": "both", + "center": 1.0, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 1.011204481124878, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "424364943656028", + "seam": false, + "x": 0.8935546875, + "y": 0.583984375 + }, + { + "act": 0.960924, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.960924, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9609276056289673, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "424364943656028", + "seam": false, + "x": 0.62890625, + "y": 0.599609375 + }, + { + "act": 0.92905, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.92905, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.929057776927948, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "424364943656028", + "seam": false, + "x": 0.32421875, + "y": 0.568359375 + }, + { + "act": 0.905062, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.905062, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9050841927528381, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "424364943656028", + "seam": false, + "x": 0.1435546875, + "y": 0.5546875 + }, + { + "act": 0.927581, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.927581, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9276226162910461, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "432356313302579", + "seam": false, + "x": 0.62109375, + "y": 0.552734375 + }, + { + "act": 0.741996, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.741996, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7420302033424377, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "432356313302579", + "seam": false, + "x": 0.26171875, + "y": 0.5390625 + }, + { + "act": 0.221399, + "argmax_off_px": 22.4, + "cell": "neither", + "center": 0.05043, + "class": "tail", + "nearest_peak_px": 42.8, + "nearest_peak_score": 0.7420302033424377, + "null_med": 0.003259, + "null_p95": 0.130003, + "null_pct": 0.965, + "pano": "432356313302579", + "seam": false, + "x": 0.2701010039358428, + "y": 0.6210100948449337 + }, + { + "act": 0.083431, + "argmax_off_px": 18.9, + "cell": "challenger_only", + "center": 0.026902, + "class": "tail", + "nearest_peak_px": 61.4, + "nearest_peak_score": 0.7420302033424377, + "null_med": 0.003368, + "null_p95": 0.024563, + "null_pct": 1.0, + "pano": "432356313302579", + "seam": false, + "x": 0.271313125147964, + "y": 0.6573737312085701 + }, + { + "act": 0.354652, + "argmax_off_px": 6.0, + "cell": "challenger_only", + "center": 0.302204, + "class": "tail", + "nearest_peak_px": 77.5, + "nearest_peak_score": 0.7420302033424377, + "null_med": 0.01, + "null_p95": 0.927581, + "null_pct": 0.87, + "pano": "432356313302579", + "seam": false, + "x": 0.33737373120857006, + "y": 0.5325252463600852 + }, + { + "act": 0.953798, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.953798, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9538203477859497, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "433987753066526", + "seam": false, + "x": 0.64453125, + "y": 0.6171875 + }, + { + "act": 0.943145, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.943145, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9431686997413635, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "433987753066526", + "seam": false, + "x": 0.5498046875, + "y": 0.5390625 + }, + { + "act": 0.901868, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.901868, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9018926620483398, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "433987753066526", + "seam": false, + "x": 0.23828125, + "y": 0.5703125 + }, + { + "act": 0.769861, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.769861, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7698575258255005, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "433987753066526", + "seam": false, + "x": 0.79296875, + "y": 0.7265625 + }, + { + "act": 0.901868, + "argmax_off_px": 13.5, + "cell": "neither", + "center": 0.307144, + "class": "tail", + "nearest_peak_px": 13.5, + "nearest_peak_score": 0.9018926620483398, + "null_med": 0.011079, + "null_p95": 0.943145, + "null_pct": 0.92, + "pano": "433987753066526", + "seam": false, + "x": 0.2419418948972789, + "y": 0.5450309172089488 + }, + { + "act": 0.566707, + "argmax_off_px": 22.2, + "cell": "neither", + "center": 0.422349, + "class": "tail", + "nearest_peak_px": 32.1, + "nearest_peak_score": 0.9431686997413635, + "null_med": 0.005618, + "null_p95": 0.7758, + "null_pct": 0.935, + "pano": "433987753066526", + "seam": false, + "x": 0.5186392928059769, + "y": 0.532458711270457 + }, + { + "act": 0.956546, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.956546, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9565637111663818, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "461898606342872", + "seam": false, + "x": 0.91015625, + "y": 0.5703125 + }, + { + "act": 0.949037, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.949037, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9491065144538879, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "461898606342872", + "seam": false, + "x": 0.96484375, + "y": 0.5546875 + }, + { + "act": 0.941207, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.941207, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9412210583686829, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "461898606342872", + "seam": false, + "x": 0.5576171875, + "y": 0.5703125 + }, + { + "act": 0.8879, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.8879, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8879169821739197, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "461898606342872", + "seam": false, + "x": 0.1279296875, + "y": 0.5390625 + }, + { + "act": 0.870732, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.870732, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8707573413848877, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "461898606342872", + "seam": false, + "x": 0.26953125, + "y": 0.537109375 + }, + { + "act": 0.678699, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.678699, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6787121891975403, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "461898606342872", + "seam": false, + "x": 0.3154296875, + "y": 0.537109375 + }, + { + "act": 0.266242, + "argmax_off_px": 13.7, + "cell": "challenger_only", + "center": 0.140927, + "class": "tail", + "nearest_peak_px": 171.4, + "nearest_peak_score": 0.9565637111663818, + "null_med": 0.203494, + "null_p95": 0.956546, + "null_pct": 0.52, + "pano": "461898606342872", + "seam": false, + "x": 0.7428282766631156, + "y": 0.5668686930338541 + }, + { + "act": 0.929726, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.929726, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9297599196434021, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "514363767744061", + "seam": false, + "x": 0.1201171875, + "y": 0.5390625 + }, + { + "act": 0.927487, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.927487, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9274894595146179, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "514363767744061", + "seam": false, + "x": 0.9248046875, + "y": 0.5546875 + }, + { + "act": 0.668966, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.668966, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6689717769622803, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "514363767744061", + "seam": false, + "x": 0.5576171875, + "y": 0.5234375 + }, + { + "act": 0.915187, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.915187, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9151908159255981, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "522346373509256", + "seam": false, + "x": 0.6513671875, + "y": 0.583984375 + }, + { + "act": 0.846816, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.846816, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8468331098556519, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "522346373509256", + "seam": false, + "x": 0.91796875, + "y": 0.5390625 + }, + { + "act": 0.83454, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.83454, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8345710635185242, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "522346373509256", + "seam": false, + "x": 0.33203125, + "y": 0.5546875 + }, + { + "act": 0.776125, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.776125, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7761362791061401, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "552315380916113", + "seam": false, + "x": 0.40234375, + "y": 0.552734375 + }, + { + "act": 0.272278, + "argmax_off_px": 22.5, + "cell": "challenger_only", + "center": 0.127528, + "class": "tail", + "nearest_peak_px": 118.2, + "nearest_peak_score": 0.7761362791061401, + "null_med": 0.000963, + "null_p95": 0.639182, + "null_pct": 0.915, + "pano": "552315380916113", + "seam": false, + "x": 0.5164770785435311, + "y": 0.517956004077946 + }, + { + "act": 0.8889, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.8889, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8888956308364868, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "559372759847379", + "seam": false, + "x": 0.2060546875, + "y": 0.5859375 + }, + { + "act": 0.558839, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.558839, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.5588424205780029, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "563961506051153", + "seam": false, + "x": 0.53515625, + "y": 0.5234375 + }, + { + "act": 0.763808, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.763808, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7638235092163086, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "591584463734236", + "seam": false, + "x": 0.09765625, + "y": 0.5390625 + }, + { + "act": 0.990258, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.990258, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9902909994125366, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "593421160518191", + "seam": false, + "x": 0.23046875, + "y": 0.6015625 + }, + { + "act": 0.915084, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.915084, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9150998592376709, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "593421160518191", + "seam": false, + "x": 0.11328125, + "y": 0.5546875 + }, + { + "act": 0.908996, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.908996, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9090192317962646, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "593421160518191", + "seam": false, + "x": 0.9560546875, + "y": 0.5390625 + }, + { + "act": 0.89842, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.89842, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.898432195186615, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "593421160518191", + "seam": false, + "x": 0.44921875, + "y": 0.6171875 + }, + { + "act": 0.891586, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.891586, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8915951251983643, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "593421160518191", + "seam": false, + "x": 0.07421875, + "y": 0.552734375 + }, + { + "act": 0.830302, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.830302, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8303124904632568, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "593421160518191", + "seam": false, + "x": 0.63671875, + "y": 0.5390625 + }, + { + "act": 0.166348, + "argmax_off_px": 6.5, + "cell": "challenger_only", + "center": 0.163392, + "class": "tail", + "nearest_peak_px": 47.9, + "nearest_peak_score": 0.898432195186615, + "null_med": 0.182783, + "null_p95": 0.990258, + "null_pct": 0.485, + "pano": "593421160518191", + "seam": false, + "x": 0.4114586336281223, + "y": 0.5620670533370702 + }, + { + "act": 0.012545, + "argmax_off_px": 3.5, + "cell": "challenger_only", + "center": 0.009512, + "class": "faint_local", + "nearest_peak_px": 137.2, + "nearest_peak_score": 0.8303124904632568, + "null_med": 0.093093, + "null_p95": 0.915084, + "null_pct": 0.12, + "pano": "593421160518191", + "seam": false, + "x": 0.7702458544241675, + "y": 0.5173858634506956 + }, + { + "act": 0.338576, + "argmax_off_px": 3.1, + "cell": "challenger_only", + "center": 0.306003, + "class": "tail", + "nearest_peak_px": 118.3, + "nearest_peak_score": 0.9090192317962646, + "null_med": 0.057044, + "null_p95": 0.893013, + "null_pct": 0.705, + "pano": "593421160518191", + "seam": false, + "x": 0.8414141845703125, + "y": 0.5112121397076231 + }, + { + "act": 0.980652, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.980652, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9806796312332153, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "639645829096010", + "seam": false, + "x": 0.69921875, + "y": 0.6015625 + }, + { + "act": 0.940881, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.940881, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9408648014068604, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "639645829096010", + "seam": false, + "x": 0.75390625, + "y": 0.599609375 + }, + { + "act": 0.833894, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.833894, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8338943719863892, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "639645829096010", + "seam": false, + "x": 0.04296875, + "y": 0.552734375 + }, + { + "act": 0.828106, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.828106, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8281292915344238, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "639645829096010", + "seam": false, + "x": 0.1044921875, + "y": 0.5390625 + }, + { + "act": 0.028439, + "argmax_off_px": 10.7, + "cell": "challenger_only", + "center": 0.023782, + "class": "faint_local", + "nearest_peak_px": 133.7, + "nearest_peak_score": 0.8281292915344238, + "null_med": 0.091109, + "null_p95": 0.833894, + "null_pct": 0.465, + "pano": "639645829096010", + "seam": false, + "x": 0.23492423780036692, + "y": 0.5502974155481681 + }, + { + "act": 0.834619, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.834619, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8346372842788696, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "662385816800591", + "seam": false, + "x": 0.40234375, + "y": 0.5234375 + }, + { + "act": 0.604542, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.604542, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6045513153076172, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "662385816800591", + "seam": false, + "x": 0.5576171875, + "y": 0.5390625 + }, + { + "act": 0.146852, + "argmax_off_px": 22.3, + "cell": "challenger_only", + "center": 0.008665, + "class": "tail", + "nearest_peak_px": 44.1, + "nearest_peak_score": 0.8346372842788696, + "null_med": 0.008319, + "null_p95": 0.604542, + "null_pct": 0.825, + "pano": "662385816800591", + "seam": false, + "x": 0.44464645848129736, + "y": 0.5070707009055397 + }, + { + "act": 0.425702, + "argmax_off_px": 22.4, + "cell": "challenger_only", + "center": 0.219653, + "class": "tail", + "nearest_peak_px": 36.0, + "nearest_peak_score": 0.6045513153076172, + "null_med": 0.011196, + "null_p95": 0.631353, + "null_pct": 0.935, + "pano": "662385816800591", + "seam": false, + "x": 0.5236363821318656, + "y": 0.5209091094045928 + }, + { + "act": 0.682507, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.682507, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6825149059295654, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "681333794968062", + "seam": false, + "x": 0.7060546875, + "y": 0.537109375 + }, + { + "act": 0.06853, + "argmax_off_px": 19.0, + "cell": "challenger_only", + "center": 0.040765, + "class": "tail", + "nearest_peak_px": 108.4, + "nearest_peak_score": 0.6825149059295654, + "null_med": 0.007319, + "null_p95": 0.682507, + "null_pct": 0.895, + "pano": "681333794968062", + "seam": false, + "x": 0.6004040342388731, + "y": 0.5500000184955018 + }, + { + "act": 0.47872, + "argmax_off_px": 7.1, + "cell": "challenger_only", + "center": 0.455115, + "class": "tail", + "nearest_peak_px": 165.7, + "nearest_peak_score": 0.621621310710907, + "null_med": 0.004715, + "null_p95": 0.600249, + "null_pct": 0.935, + "pano": "700668799338315", + "seam": false, + "x": 0.5558273567679088, + "y": 0.5642667296707485 + }, + { + "act": 0.983572, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.983572, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9836001396179199, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "723487737079243", + "seam": false, + "x": 0.23046875, + "y": 0.5546875 + }, + { + "act": 0.944982, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.944982, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9450165629386902, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "723487737079243", + "seam": false, + "x": 0.12109375, + "y": 0.5234375 + }, + { + "act": 0.884595, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.884595, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8846012353897095, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "723487737079243", + "seam": false, + "x": 0.88671875, + "y": 0.6328125 + }, + { + "act": 0.945872, + "argmax_off_px": 7.4, + "cell": "challenger_only", + "center": 0.779342, + "class": "tail", + "nearest_peak_px": 117.4, + "nearest_peak_score": 0.9450165629386902, + "null_med": 0.012038, + "null_p95": 0.944982, + "null_pct": 0.975, + "pano": "723487737079243", + "seam": true, + "x": 0.006868693033854166, + "y": 0.5435353966915246 + }, + { + "act": 0.869796, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.869796, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8698008060455322, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "780391337668333", + "seam": false, + "x": 0.08203125, + "y": 0.583984375 + }, + { + "act": 0.737678, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.737678, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7376946806907654, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "780391337668333", + "seam": false, + "x": 0.90234375, + "y": 0.5390625 + }, + { + "act": 0.152524, + "argmax_off_px": 7.0, + "cell": "challenger_only", + "center": 0.097303, + "class": "tail", + "nearest_peak_px": 61.6, + "nearest_peak_score": 0.7376946806907654, + "null_med": 0.001456, + "null_p95": 0.737678, + "null_pct": 0.845, + "pano": "780391337668333", + "seam": false, + "x": 0.9624242609197443, + "y": 0.5322222345525568 + }, + { + "act": 0.840681, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.840681, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8406943082809448, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "822353906794602", + "seam": false, + "x": 0.45703125, + "y": 0.521484375 + }, + { + "act": 0.790651, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.790651, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7906746864318848, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "839655921736413", + "seam": false, + "x": 0.73828125, + "y": 0.568359375 + }, + { + "act": 0.421252, + "argmax_off_px": 2.3, + "cell": "challenger_only", + "center": 0.408036, + "class": "tail", + "nearest_peak_px": 104.9, + "nearest_peak_score": 0.7906746864318848, + "null_med": 0.000473, + "null_p95": 0.787073, + "null_pct": 0.945, + "pano": "839655921736413", + "seam": false, + "x": 0.8406462580343929, + "y": 0.5744880586392555 + }, + { + "act": 0.58873, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.58873, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.5887415409088135, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "843075271274817", + "seam": false, + "x": 0.33984375, + "y": 0.5390625 + }, + { + "act": 0.852076, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.852076, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8520925641059875, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "8726984263984099", + "seam": false, + "x": 0.87109375, + "y": 0.5546875 + }, + { + "act": 0.93903, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.93903, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9390338659286499, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "872856994942214", + "seam": false, + "x": 0.24609375, + "y": 0.537109375 + }, + { + "act": 0.931913, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.931913, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9319180250167847, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "872856994942214", + "seam": false, + "x": 0.8466796875, + "y": 0.568359375 + }, + { + "act": 0.928921, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.928921, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9289493560791016, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "872856994942214", + "seam": false, + "x": 0.65234375, + "y": 0.599609375 + }, + { + "act": 0.918721, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.918721, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9187254905700684, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "872856994942214", + "seam": false, + "x": 0.71484375, + "y": 0.583984375 + }, + { + "act": 0.804447, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.804447, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8044468760490417, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "872856994942214", + "seam": false, + "x": 0.19140625, + "y": 0.5390625 + }, + { + "act": 0.920193, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.920193, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9202104806900024, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "893023542323690", + "seam": false, + "x": 0.6044921875, + "y": 0.599609375 + }, + { + "act": 0.899801, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.899801, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8998149633407593, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "893023542323690", + "seam": false, + "x": 0.55078125, + "y": 0.552734375 + }, + { + "act": 0.920857, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.920857, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.920896053314209, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "911337534530260", + "seam": false, + "x": 0.6123046875, + "y": 0.6015625 + }, + { + "act": 0.856427, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.856427, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8564420342445374, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "911337534530260", + "seam": false, + "x": 0.91015625, + "y": 0.583984375 + }, + { + "act": 0.808182, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.808182, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8081934452056885, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "911337534530260", + "seam": false, + "x": 0.2763671875, + "y": 0.5234375 + }, + { + "act": 0.635044, + "argmax_off_px": 22.5, + "cell": "challenger_only", + "center": 0.176682, + "class": "tail", + "nearest_peak_px": 23.5, + "nearest_peak_score": 0.6433027982711792, + "null_med": 0.016102, + "null_p95": 0.856427, + "null_pct": 0.885, + "pano": "911337534530260", + "seam": false, + "x": 0.7846464584812973, + "y": 0.6185858524206913 + }, + { + "act": 1.0, + "argmax_off_px": 0.0, + "cell": "both", + "center": 1.0, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 1.0076472759246826, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "925077602773417", + "seam": false, + "x": 0.70703125, + "y": 0.599609375 + }, + { + "act": 0.895271, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.895271, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8952727317810059, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "925077602773417", + "seam": false, + "x": 0.25390625, + "y": 0.5703125 + }, + { + "act": 0.706292, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.706292, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7063033580780029, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "925077602773417", + "seam": false, + "x": 0.35546875, + "y": 0.6171875 + }, + { + "act": 0.681016, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.681016, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6810370683670044, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "925077602773417", + "seam": false, + "x": 0.7529296875, + "y": 0.5703125 + }, + { + "act": 0.965541, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.965541, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9655765295028687, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "934739365184374", + "seam": false, + "x": 0.58984375, + "y": 0.599609375 + }, + { + "act": 0.943558, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.943558, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9435607194900513, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "934739365184374", + "seam": false, + "x": 0.6669921875, + "y": 0.599609375 + }, + { + "act": 0.927461, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.927461, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9274734258651733, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "934739365184374", + "seam": false, + "x": 0.12890625, + "y": 0.5859375 + }, + { + "act": 0.922892, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.922892, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9229074716567993, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "934739365184374", + "seam": false, + "x": 0.39453125, + "y": 0.583984375 + }, + { + "act": 0.898126, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.898126, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8981457948684692, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "934739365184374", + "seam": false, + "x": 0.4326171875, + "y": 0.583984375 + }, + { + "act": 0.823908, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.823908, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8239241242408752, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "934739365184374", + "seam": false, + "x": 0.9169921875, + "y": 0.599609375 + }, + { + "act": 0.810013, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.810013, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8100234270095825, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "934739365184374", + "seam": false, + "x": 0.0966796875, + "y": 0.583984375 + }, + { + "act": 0.8086, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.8086, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8086158037185669, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "934739365184374", + "seam": false, + "x": 0.87109375, + "y": 0.599609375 + }, + { + "act": 0.899075, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.899075, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8990710973739624, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "996959015535106", + "seam": false, + "x": 0.38671875, + "y": 0.5546875 + }, + { + "act": 0.877263, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.877263, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8773050904273987, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "996959015535106", + "seam": false, + "x": 0.6044921875, + "y": 0.552734375 + }, + { + "act": 0.634536, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.634536, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6345473527908325, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "996959015535106", + "seam": false, + "x": 0.5498046875, + "y": 0.5078125 + }, + { + "act": 0.098079, + "argmax_off_px": 4.9, + "cell": "challenger_only", + "center": 0.092798, + "class": "tail", + "nearest_peak_px": 62.9, + "nearest_peak_score": 0.8990710973739624, + "null_med": 0.007513, + "null_p95": 0.877263, + "null_pct": 0.81, + "pano": "996959015535106", + "seam": false, + "x": 0.44606062455610795, + "y": 0.5233333703243371 + } + ], + "skipped_sites": 0, + "split": "richmond", + "vistas_input_size": [ + 1024, + 1024 + ] +} diff --git a/scripts/analysis/cascade_gate.py b/scripts/analysis/cascade_gate.py index f165af12..87c06246 100644 --- a/scripts/analysis/cascade_gate.py +++ b/scripts/analysis/cascade_gate.py @@ -28,18 +28,36 @@ comparable to that phase's 8% absent / 62% adjacent-tail / 30% faint decomposition, and it means a fix to the probe fixes both analyses. -**Three outcomes, and the middle one is not the interesting one.** ``faint_local`` with -the in-window argmax *at* the site is signal a prior could raise. ``absent`` is nothing -to raise. ``tail`` — the in-window maximum at or above the peak floor — is an adjacent -mode reaching in, and for a *missed* ramp it means relaxing a threshold there would fire -on the neighbour, not on the ramp. ``tail`` therefore argues for sigma/NMS work (#46's -adjacent-pair merge), **not** for a threshold prior, even though it looks like "signal -is present" if you only read ``act``. +**``class_of`` is imported for comparability, but the load-bearing column here is +``peak_in_radius``, not the class.** #46 Phase 1 applied those cutoffs to *silent* +misses — defined as no floor peak within the radius — so there ``tail`` (act >= 0.05) +could only mean an outside mode reaching in. This population is every RampNet miss, not +just the silent ones, so ``act >= 0.05`` here has two very different causes and the +class alone cannot separate them: + +* **a floor peak inside the radius** — the model localized the ramp and the detection + was lost *downstream*, either to the shipped threshold or to the greedy matcher giving + that peak to an adjacent GT. Recoverable, and recoverable **without a second model**. +* **no floor peak inside the radius** — ``act`` is unpeaked heatmap mass that + ``peak_local_max`` never called a local maximum. A threshold prior has nothing to + promote, because promotion operates on peaks. + +``peak_in_radius`` is therefore reported per cell and is what the read below turns on. **Sub-threshold signal is necessary, not sufficient.** A positive here says the cascade is not ruled out and is worth costing; it does not demonstrate one works. Any realisable gain is bounded above by the ~44 attributable ramps, not the raw 54. +**The floor peaks come from ``analysis_out/op_cache/.json``, NOT from the +bundle records.** The bundle's committed detections are the published operating point +— on richmond every one of them scores >= 0.5519 — so asking "is there a peak near this +missed ramp?" of *those* answers a different question and makes every miss look +peakless. The op_cache holds ``peak_local_max`` output down to the 0.05 floor, which is +what "did the model say anything here, below the threshold we ship?" actually needs. +The greedy match that DEFINED the miss still uses the bundle records, because that is +what produced the published 238/9/72 — the two are deliberately different inputs to +two different questions. + Inputs: the native-resolution panoramas at ``benchmark//panos/`` (git-ignored, published as ``projectsidewalk/rampnet-benchmark``) — ``--panos-root`` points at whichever checkout holds them, since a worktree will not. The challenger's detections @@ -70,6 +88,7 @@ NULL_SEED, NULL_TRIALS, class_of, nearest_peak, null_percentile, seam_of, site_profile) from farfield_forensics import quartiles # noqa: E402 +from operating_point_curve import CACHE_DIR, read_cache # noqa: E402 CELLS = ("both", "rampnet_only", "challenger_only", "neither") #: Cells where RampNet did NOT find the ramp -- the only ones a null is meaningful for. @@ -104,6 +123,12 @@ def summarize(rows, cell): "class_share": {c: round(v / len(sel), 3) for c, v in classes.items()}, "seam": sum(1 for r in sel if r["seam"]), } + inr = [r for r in sel if r["peak_in_radius"]] + out["peak_in_radius"] = len(inr) + out["peak_in_radius_share"] = round(len(inr) / len(sel), 3) + if inr: + out["peak_in_radius_score_median"] = round( + quartiles([r["nearest_peak_score"] for r in inr])[1], 4) nulls = [r["null_pct"] for r in sel if r["null_pct"] is not None] if nulls: out["null_pct_median"] = round(quartiles(nulls)[1], 3) @@ -173,6 +198,18 @@ def main(argv=None): if not sites: sys.exit("No sites -- is the challenger cached for this split/input size?") + # Floor peaks (>= 0.05) for the "did the model say anything sub-threshold here?" + # question. See the docstring: the bundle records are the SHIPPED operating point + # and would answer a different question. + floor_peaks, floor_src = {}, "op_cache" + try: + cached, _ = read_cache(os.path.join(CACHE_DIR, f"{args.split}.json")) + for pd in cached: + floor_peaks[pd["pano"]] = pd["preds"] + except (OSError, ValueError, KeyError): + floor_src = "MISSING (fell back to bundle records -- distances are to the "\ + "shipped operating point, not the 0.05 floor)" + by_pano = {} for s in sites: by_pano.setdefault(s["pano"], []).append(s) @@ -189,6 +226,7 @@ def main(argv=None): model = ts.load_model().to(device) print(f" device={device} model=projectsidewalk/rampnet-model " f"(single-pass fp32, as op_cache)", flush=True) + print(f" floor peaks (>=0.05) from: {floor_src}", flush=True) rng = random.Random(NULL_SEED) rows, skipped = [], 0 @@ -198,15 +236,23 @@ def main(argv=None): skipped += len(by_pano[pid]) continue heat = ts.heatmap_for(model, device, path, use_fp16=False) - preds = [(d["x_normalized"], d["y_normalized"], d["confidence"]) - for d in records[pid]["detections"]] + preds = floor_peaks.get(pid) or [ + (d["x_normalized"], d["y_normalized"], d["confidence"]) + for d in records[pid]["detections"]] for s in by_pano[pid]: act, off_px, center = site_profile(heat, s["x"], s["y"], radius_sq) npx, nscore = nearest_peak(preds, s["x"], s["y"]) + r_px = radius_sq ** 0.5 row = {**s, "act": round(act, 6), "center": round(center, 6), "argmax_off_px": round(off_px, 1), "nearest_peak_px": None if npx == float("inf") else round(npx, 1), "nearest_peak_score": nscore, + # A floor peak inside the match radius on a MISSED ramp means the + # model did localize it and the detection was lost downstream -- + # either to the shipped threshold, or to the greedy matcher giving + # the peak to an adjacent GT. That is recoverable without a second + # model; a peak outside the radius is not. + "peak_in_radius": bool(npx < r_px), "class": class_of(act), "seam": seam_of(s["x"], radius_sq), "null_pct": None, "null_med": None, "null_p95": None} # The null is only meaningful where rampnet did NOT find the ramp; the @@ -226,23 +272,31 @@ def main(argv=None): summaries = [summarize(rows, c) for c in CELLS] print() hdr = (f"{'cell':17s} {'n':>4s} {'act med':>8s} {'centre':>8s} {'argmax off':>11s} " - f"{'absent':>7s} {'faint':>6s} {'tail':>5s} {'null pct':>9s}") + f"{'floor peak in R':>16s} {'its score':>10s} {'null pct':>9s}") print(hdr) print("-" * len(hdr)) for s in summaries: if not s["n"]: continue - sh = s["class_share"] + miss = s["cell"] in MISS_CELLS print(f"{s['cell']:17s} {s['n']:4d} {s['act_median']:8.4f} " f"{s['center_median']:8.4f} {s['argmax_off_px_median']:10.1f}p " - f"{sh['absent']:7.0%} {sh['faint_local']:6.0%} {sh['tail']:5.0%} " - + (f"{s['null_pct_median']:9.3f}" if "null_pct_median" in s else f"{'—':>9s}")) + f"{s['peak_in_radius']:9d} ({s['peak_in_radius_share']:3.0%}) " + + (f"{s.get('peak_in_radius_score_median', float('nan')):10.3f}" + if s.get("peak_in_radius") else f"{'—':>10s}") + + (f"{s['null_pct_median']:9.3f}" if miss else f"{'—':>9s}")) + print() + print(" The hit cells are the positive control: a matched detection is inside the") + print(" radius by definition, so their act/centre ~0.85+ and 100% peak-in-R are what") + print(" a working probe MUST show, not a finding.") print() - print(" faint_local = a real sub-threshold response AT the site -> a prior could raise it.") - print(" tail = in-window max at/above the 0.05 peak floor, i.e. an ADJACENT mode") - print(" reaching in; relaxing a threshold there fires on the neighbour,") - print(" not the ramp. Argues for sigma/NMS (#46), not for a prior.") - print(" absent = flat heatmap; nothing to raise.") + print(" For the two MISS cells, 'floor peak in R' is the whole question:") + print(" - peak inside R -> the model DID localize the ramp and the detection was") + print(" lost downstream, to the shipped threshold or to the greedy matcher handing") + print(" the peak to an adjacent GT. Recoverable WITHOUT a second model.") + print(" - peak outside R -> nothing was extracted there even at the 0.05 floor, so a") + print(" threshold prior has no peak to promote. 'act' can still be non-zero: that is") + print(" unpeaked heatmap mass, which peak_local_max did not call a local maximum.") if args.json_out: payload = {"split": args.split, "challenger": label, From b7342dc9251b3480dd5a98f4dada7e5ab0b8020f Mon Sep 17 00:00:00 2001 From: Jon Froehlich Date: Tue, 18 Aug 2026 16:28:51 -0700 Subject: [PATCH 07/17] complementarity: ask it at the operating point we would deploy (#126) The committed bundle detections are the SHIPPED operating point -- on richmond every one scores >= 0.5519 -- while this document own recommendation since #54/#55 (PR #79) is 0.30. For a complementarity read those are different models, and the difference decides who gets credit for a recovery. Verified the op_cache is the same source before trusting it: filtered to >= 0.5519 it reproduces the published richmond row exactly (P 0.9636 R 0.7677 F1 0.8546, 238/9/72). At 0.30 the same peaks give P 0.9018 R 0.8290 F1 0.8639, 257/28/53 -- matching the committed corrected_at_0.3.csv. So RampNet at the recommended point already finds 19 of the ramps the shipped point misses. --rampnet-op-threshold re-sources RampNet from analysis_out/op_cache/.json at a given threshold. Default is the bundle records, so the published roster numbers and the committed #35 gate results are unchanged -- paterson/gemini-pro still reproduces 36 of 124, 88 nobody finds, oracle-union 0.777. Also regenerates analysis_out/cascade_gate.json, which was first committed from a run whose nearest_peak input was the shipped detections rather than the floor peaks. Co-Authored-By: Claude Opus 5 --- analysis_out/cascade_gate.json | 1050 +++++++++++++++++---------- scripts/analysis/complementarity.py | 52 +- 2 files changed, 728 insertions(+), 374 deletions(-) diff --git a/analysis_out/cascade_gate.json b/analysis_out/cascade_gate.json index bfca91e3..b0e31666 100644 --- a/analysis_out/cascade_gate.json +++ b/analysis_out/cascade_gate.json @@ -17,6 +17,9 @@ }, "n": 220, "nearest_peak_px_median": 0.0, + "peak_in_radius": 220, + "peak_in_radius_score_median": 0.8893, + "peak_in_radius_share": 1.0, "seam": 5 }, { @@ -36,6 +39,9 @@ }, "n": 18, "nearest_peak_px_median": 0.0, + "peak_in_radius": 18, + "peak_in_radius_score_median": 0.8431, + "peak_in_radius_share": 1.0, "seam": 0 }, { @@ -55,9 +61,12 @@ "tail": 51 }, "n": 54, - "nearest_peak_px_median": 104.9, + "nearest_peak_px_median": 13.7, "null_med_median": 0.0091, "null_pct_median": 0.895, + "peak_in_radius": 39, + "peak_in_radius_score_median": 0.3386, + "peak_in_radius_share": 0.722, "seam": 1 }, { @@ -77,9 +86,12 @@ "tail": 18 }, "n": 18, - "nearest_peak_px_median": 56.1, + "nearest_peak_px_median": 16.3, "null_med_median": 0.0065, "null_pct_median": 0.92, + "peak_in_radius": 14, + "peak_in_radius_score_median": 0.4595, + "peak_in_radius_share": 0.778, "seam": 0 } ], @@ -97,11 +109,12 @@ "center": 0.913488, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.913480281829834, + "nearest_peak_score": 0.9134649634361267, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1002881108606016", + "peak_in_radius": true, "seam": false, "x": 0.4326171875, "y": 0.5078125 @@ -113,11 +126,12 @@ "center": 0.895599, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8956112265586853, + "nearest_peak_score": 0.89559006690979, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1002881108606016", + "peak_in_radius": true, "seam": false, "x": 0.7216796875, "y": 0.583984375 @@ -129,11 +143,12 @@ "center": 0.618312, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.6183195114135742, + "nearest_peak_score": 0.6183094382286072, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1002881108606016", + "peak_in_radius": true, "seam": false, "x": 0.58203125, "y": 0.521484375 @@ -145,11 +160,12 @@ "center": 0.596123, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.59613037109375, + "nearest_peak_score": 0.5961191654205322, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1023400645666420", + "peak_in_radius": true, "seam": false, "x": 0.53515625, "y": 0.552734375 @@ -160,12 +176,13 @@ "cell": "challenger_only", "center": 0.10486, "class": "tail", - "nearest_peak_px": 266.1, - "nearest_peak_score": 0.59613037109375, + "nearest_peak_px": 16.0, + "nearest_peak_score": 0.20250369608402252, "null_med": 0.006787, "null_p95": 0.124406, "null_pct": 0.995, "pano": "1023400645666420", + "peak_in_radius": true, "seam": false, "x": 0.7919191857540246, "y": 0.6331313069661458 @@ -176,12 +193,13 @@ "cell": "challenger_only", "center": 0.017964, "class": "tail", - "nearest_peak_px": 313.6, - "nearest_peak_score": 0.59613037109375, + "nearest_peak_px": 24.3, + "nearest_peak_score": 0.24167664349079132, "null_med": 0.014093, "null_p95": 0.367628, "null_pct": 0.88, "pano": "1023400645666420", + "peak_in_radius": false, "seam": false, "x": 0.2294949433297822, "y": 0.5919191857540246 @@ -192,12 +210,13 @@ "cell": "challenger_only", "center": 0.371854, "class": "tail", - "nearest_peak_px": 103.4, - "nearest_peak_score": 0.59613037109375, + "nearest_peak_px": 2.3, + "nearest_peak_score": 0.3920925259590149, "null_med": 0.013856, "null_p95": 0.581377, "null_pct": 0.94, "pano": "1023400645666420", + "peak_in_radius": true, "seam": false, "x": 0.43434342817826704, "y": 0.5419191857540246 @@ -209,11 +228,12 @@ "center": 0.876577, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8765917420387268, + "nearest_peak_score": 0.8765838742256165, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1041352537628655", + "peak_in_radius": true, "seam": false, "x": 0.2216796875, "y": 0.5703125 @@ -225,11 +245,12 @@ "center": 0.835651, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8356579542160034, + "nearest_peak_score": 0.8356412649154663, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1041352537628655", + "peak_in_radius": true, "seam": false, "x": 0.93359375, "y": 0.5546875 @@ -241,11 +262,12 @@ "center": 0.697017, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.6970375776290894, + "nearest_peak_score": 0.6970109343528748, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1041352537628655", + "peak_in_radius": true, "seam": false, "x": 0.78515625, "y": 0.630859375 @@ -257,11 +279,12 @@ "center": 0.94323, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9432597160339355, + "nearest_peak_score": 0.9432406425476074, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1044606157061812", + "peak_in_radius": true, "seam": false, "x": 0.30078125, "y": 0.5546875 @@ -273,11 +296,12 @@ "center": 0.895965, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8959958553314209, + "nearest_peak_score": 0.895974338054657, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1044606157061812", + "peak_in_radius": true, "seam": false, "x": 0.94140625, "y": 0.568359375 @@ -289,11 +313,12 @@ "center": 0.891897, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8919112682342529, + "nearest_peak_score": 0.8918793201446533, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1044606157061812", + "peak_in_radius": true, "seam": false, "x": 0.64453125, "y": 0.599609375 @@ -305,11 +330,12 @@ "center": 0.841396, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8414136171340942, + "nearest_peak_score": 0.8413959741592407, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1044606157061812", + "peak_in_radius": true, "seam": false, "x": 0.1201171875, "y": 0.552734375 @@ -321,11 +347,12 @@ "center": 0.909499, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.909525990486145, + "nearest_peak_score": 0.9094994068145752, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1050503583329955", + "peak_in_radius": true, "seam": false, "x": 0.35546875, "y": 0.599609375 @@ -337,11 +364,12 @@ "center": 0.869249, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8692640662193298, + "nearest_peak_score": 0.869255781173706, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1050503583329955", + "peak_in_radius": true, "seam": false, "x": 0.66015625, "y": 0.6015625 @@ -353,11 +381,12 @@ "center": 0.738541, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7385543584823608, + "nearest_peak_score": 0.738539457321167, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1050503583329955", + "peak_in_radius": true, "seam": false, "x": 0.42578125, "y": 0.5390625 @@ -369,11 +398,12 @@ "center": 0.946644, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9466584920883179, + "nearest_peak_score": 0.9466462135314941, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1051211967136526", + "peak_in_radius": true, "seam": false, "x": 0.4091796875, "y": 0.5390625 @@ -385,11 +415,12 @@ "center": 0.904591, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9046050310134888, + "nearest_peak_score": 0.9045884609222412, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1051211967136526", + "peak_in_radius": true, "seam": false, "x": 0.55859375, "y": 0.568359375 @@ -401,11 +432,12 @@ "center": 0.878982, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8789999485015869, + "nearest_peak_score": 0.8789879679679871, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1051211967136526", + "peak_in_radius": true, "seam": false, "x": 0.26171875, "y": 0.5859375 @@ -417,11 +449,12 @@ "center": 0.816361, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8163886070251465, + "nearest_peak_score": 0.8163682818412781, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1071700701728910", + "peak_in_radius": true, "seam": false, "x": 0.8544921875, "y": 0.5859375 @@ -433,11 +466,12 @@ "center": 0.766434, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7664440870285034, + "nearest_peak_score": 0.7664359211921692, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1071700701728910", + "peak_in_radius": true, "seam": false, "x": 0.12109375, "y": 0.552734375 @@ -449,11 +483,12 @@ "center": 0.675663, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.6756789088249207, + "nearest_peak_score": 0.6756716966629028, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1071700701728910", + "peak_in_radius": true, "seam": false, "x": 0.95703125, "y": 0.5390625 @@ -465,11 +500,12 @@ "center": 0.938291, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9382998943328857, + "nearest_peak_score": 0.9382756948471069, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1073049581231056", + "peak_in_radius": true, "seam": true, "x": 0.9873046875, "y": 0.583984375 @@ -481,11 +517,12 @@ "center": 0.843096, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8431106805801392, + "nearest_peak_score": 0.8430953621864319, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1073049581231056", + "peak_in_radius": true, "seam": false, "x": 0.16796875, "y": 0.6171875 @@ -497,11 +534,12 @@ "center": 0.421524, "class": "tail", "nearest_peak_px": 11.0, - "nearest_peak_score": 0.6145117878913879, + "nearest_peak_score": 0.6145032644271851, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1089573432664131", + "peak_in_radius": true, "seam": false, "x": 0.9536616099964488, "y": 0.5459090909090908 @@ -513,11 +551,12 @@ "center": 0.801695, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.801726222038269, + "nearest_peak_score": 0.8017029166221619, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1092133469495462", + "peak_in_radius": true, "seam": false, "x": 0.5419921875, "y": 0.537109375 @@ -529,11 +568,12 @@ "center": 0.800788, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8008056879043579, + "nearest_peak_score": 0.8007755875587463, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1092133469495462", + "peak_in_radius": true, "seam": false, "x": 0.41796875, "y": 0.5234375 @@ -545,11 +585,12 @@ "center": 0.748474, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.748491644859314, + "nearest_peak_score": 0.7484796643257141, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1092133469495462", + "peak_in_radius": true, "seam": false, "x": 0.69921875, "y": 0.6328125 @@ -561,11 +602,12 @@ "center": 0.711291, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.711294412612915, + "nearest_peak_score": 0.7112849354743958, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1092133469495462", + "peak_in_radius": true, "seam": false, "x": 0.4326171875, "y": 0.5234375 @@ -577,11 +619,12 @@ "center": 0.646609, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.6466131210327148, + "nearest_peak_score": 0.6466015577316284, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1092133469495462", + "peak_in_radius": true, "seam": false, "x": 0.30078125, "y": 0.568359375 @@ -593,11 +636,12 @@ "center": 0.097523, "class": "tail", "nearest_peak_px": 22.0, - "nearest_peak_score": 0.6466131210327148, + "nearest_peak_score": 0.6466015577316284, "null_med": 0.010539, "null_p95": 0.603415, "null_pct": 0.98, "pano": "1092133469495462", + "peak_in_radius": true, "seam": false, "x": 0.28282827666311555, "y": 0.5919191903779001 @@ -609,11 +653,12 @@ "center": 0.889245, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8892737627029419, + "nearest_peak_score": 0.8892554044723511, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1107064934776754", + "peak_in_radius": true, "seam": false, "x": 0.10546875, "y": 0.5859375 @@ -625,11 +670,12 @@ "center": 0.880806, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8808392286300659, + "nearest_peak_score": 0.8808186054229736, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1107064934776754", + "peak_in_radius": true, "seam": false, "x": 0.58203125, "y": 0.5859375 @@ -641,11 +687,12 @@ "center": 0.851676, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8517063856124878, + "nearest_peak_score": 0.851691722869873, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1107064934776754", + "peak_in_radius": true, "seam": false, "x": 0.8857421875, "y": 0.615234375 @@ -657,11 +704,12 @@ "center": 0.824314, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8243341445922852, + "nearest_peak_score": 0.8243358731269836, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1107064934776754", + "peak_in_radius": true, "seam": false, "x": 0.3935546875, "y": 0.568359375 @@ -673,11 +721,12 @@ "center": 1.0, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 1.0072057247161865, + "nearest_peak_score": 1.0071896314620972, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1108131584865233", + "peak_in_radius": true, "seam": false, "x": 0.8388671875, "y": 0.568359375 @@ -689,11 +738,12 @@ "center": 0.961798, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9618116617202759, + "nearest_peak_score": 0.9617979526519775, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1108131584865233", + "peak_in_radius": true, "seam": false, "x": 0.1904296875, "y": 0.537109375 @@ -705,11 +755,12 @@ "center": 0.730985, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7309937477111816, + "nearest_peak_score": 0.7309690713882446, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1110314244387816", + "peak_in_radius": true, "seam": false, "x": 0.79296875, "y": 0.4921875 @@ -720,12 +771,13 @@ "cell": "challenger_only", "center": 0.277798, "class": "tail", - "nearest_peak_px": 321.4, - "nearest_peak_score": 0.7309937477111816, + "nearest_peak_px": 10.2, + "nearest_peak_score": 0.36452651023864746, "null_med": 0.005449, "null_p95": 0.302846, "null_pct": 0.97, "pano": "1110314244387816", + "peak_in_radius": true, "seam": false, "x": 0.4819725424417728, "y": 0.5769238621475898 @@ -736,12 +788,13 @@ "cell": "challenger_only", "center": 0.080359, "class": "tail", - "nearest_peak_px": 99.3, - "nearest_peak_score": 0.7309937477111816, + "nearest_peak_px": 5.2, + "nearest_peak_score": 0.08584265410900116, "null_med": 0.003516, "null_p95": 0.730985, "null_pct": 0.89, "pano": "1110314244387816", + "peak_in_radius": true, "seam": false, "x": 0.6961413694097003, "y": 0.5019622085748252 @@ -752,12 +805,13 @@ "cell": "neither", "center": 0.047331, "class": "tail", - "nearest_peak_px": 274.7, - "nearest_peak_score": 0.7309937477111816, + "nearest_peak_px": 16.3, + "nearest_peak_score": 0.07500965893268585, "null_med": 0.006771, "null_p95": 0.513768, "null_pct": 0.765, "pano": "1110314244387816", + "peak_in_radius": true, "seam": false, "x": 0.5260899962249893, "y": 0.5462150503817342 @@ -769,11 +823,12 @@ "center": 0.997578, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9975988864898682, + "nearest_peak_score": 0.9975808262825012, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1119718896242677", + "peak_in_radius": true, "seam": false, "x": 0.1748046875, "y": 0.583984375 @@ -785,11 +840,12 @@ "center": 0.887822, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8878290057182312, + "nearest_peak_score": 0.8878064155578613, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1119718896242677", + "peak_in_radius": true, "seam": false, "x": 0.82421875, "y": 0.646484375 @@ -801,11 +857,12 @@ "center": 0.893696, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8937223553657532, + "nearest_peak_score": 0.8937026858329773, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1126712375884972", + "peak_in_radius": true, "seam": false, "x": 0.5576171875, "y": 0.5546875 @@ -817,11 +874,12 @@ "center": 0.889458, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8894680738449097, + "nearest_peak_score": 0.8894655704498291, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1126712375884972", + "peak_in_radius": true, "seam": false, "x": 0.2294921875, "y": 0.5546875 @@ -833,11 +891,12 @@ "center": 0.865858, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8658739924430847, + "nearest_peak_score": 0.8658657073974609, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1126712375884972", + "peak_in_radius": true, "seam": false, "x": 0.75390625, "y": 0.630859375 @@ -849,11 +908,12 @@ "center": 1.0, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 1.0111504793167114, + "nearest_peak_score": 1.0111336708068848, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1130501775077894", + "peak_in_radius": true, "seam": false, "x": 0.51953125, "y": 0.5390625 @@ -865,11 +925,12 @@ "center": 0.961628, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9616416096687317, + "nearest_peak_score": 0.9616304636001587, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1130501775077894", + "peak_in_radius": true, "seam": false, "x": 0.96484375, "y": 0.583984375 @@ -881,11 +942,12 @@ "center": 0.939102, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9391264915466309, + "nearest_peak_score": 0.9391024112701416, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1130501775077894", + "peak_in_radius": true, "seam": false, "x": 0.90234375, "y": 0.5703125 @@ -897,11 +959,12 @@ "center": 0.925147, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9251975417137146, + "nearest_peak_score": 0.9251697063446045, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1130501775077894", + "peak_in_radius": true, "seam": false, "x": 0.1279296875, "y": 0.5234375 @@ -913,11 +976,12 @@ "center": 0.913486, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9135084748268127, + "nearest_peak_score": 0.9134843349456787, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1130501775077894", + "peak_in_radius": true, "seam": false, "x": 0.43359375, "y": 0.5234375 @@ -929,11 +993,12 @@ "center": 0.895101, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8951044678688049, + "nearest_peak_score": 0.8950980305671692, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1130501775077894", + "peak_in_radius": true, "seam": false, "x": 0.5810546875, "y": 0.5546875 @@ -945,11 +1010,12 @@ "center": 0.746246, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7462716102600098, + "nearest_peak_score": 0.7462441325187683, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1130501775077894", + "peak_in_radius": true, "seam": false, "x": 0.29296875, "y": 0.5234375 @@ -961,11 +1027,12 @@ "center": 0.672215, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.6722154021263123, + "nearest_peak_score": 0.6722085475921631, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1130501775077894", + "peak_in_radius": true, "seam": false, "x": 0.16796875, "y": 0.5234375 @@ -976,12 +1043,13 @@ "cell": "challenger_only", "center": 0.305334, "class": "tail", - "nearest_peak_px": 153.4, - "nearest_peak_score": 0.9391264915466309, + "nearest_peak_px": 8.1, + "nearest_peak_score": 0.3628003001213074, "null_med": 0.040755, "null_p95": 0.936522, "null_pct": 0.8, "pano": "1130501775077894", + "peak_in_radius": true, "seam": false, "x": 0.7537373675722064, "y": 0.6080808142459754 @@ -992,12 +1060,13 @@ "cell": "challenger_only", "center": 0.014528, "class": "tail", - "nearest_peak_px": 111.9, - "nearest_peak_score": 0.9391264915466309, + "nearest_peak_px": 35.0, + "nearest_peak_score": 0.3628003001213074, "null_med": 0.105939, "null_p95": 0.939102, "null_pct": 0.55, "pano": "1130501775077894", + "peak_in_radius": false, "seam": false, "x": 0.7943434281782671, "y": 0.6032323293974905 @@ -1009,11 +1078,12 @@ "center": 0.977259, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9772834777832031, + "nearest_peak_score": 0.9772588014602661, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1179500609797636", + "peak_in_radius": true, "seam": true, "x": 0.98046875, "y": 0.5546875 @@ -1025,11 +1095,12 @@ "center": 0.969846, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9698507189750671, + "nearest_peak_score": 0.9698506593704224, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1179500609797636", + "peak_in_radius": true, "seam": false, "x": 0.58203125, "y": 0.599609375 @@ -1041,11 +1112,12 @@ "center": 0.891798, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8918266296386719, + "nearest_peak_score": 0.8918161392211914, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1179500609797636", + "peak_in_radius": true, "seam": false, "x": 0.2919921875, "y": 0.568359375 @@ -1057,11 +1129,12 @@ "center": 0.891928, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8919466733932495, + "nearest_peak_score": 0.8919258117675781, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1180673306331763", + "peak_in_radius": true, "seam": false, "x": 0.6591796875, "y": 0.5859375 @@ -1073,11 +1146,12 @@ "center": 0.872, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8720241785049438, + "nearest_peak_score": 0.87200927734375, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1180673306331763", + "peak_in_radius": true, "seam": false, "x": 0.3154296875, "y": 0.537109375 @@ -1089,11 +1163,12 @@ "center": 0.813617, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8136365413665771, + "nearest_peak_score": 0.8136162161827087, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1185319949364085", + "peak_in_radius": true, "seam": false, "x": 0.4013671875, "y": 0.537109375 @@ -1104,12 +1179,13 @@ "cell": "challenger_only", "center": 0.086301, "class": "tail", - "nearest_peak_px": 115.2, - "nearest_peak_score": 0.8136365413665771, + "nearest_peak_px": 19.4, + "nearest_peak_score": 0.24068093299865723, "null_med": 0.002236, "null_p95": 0.783489, "null_pct": 0.915, "pano": "1185319949364085", + "peak_in_radius": true, "seam": false, "x": 0.5131313069661458, "y": 0.5119191857540246 @@ -1121,11 +1197,12 @@ "center": 0.886741, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8867697715759277, + "nearest_peak_score": 0.8867541551589966, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1187483045673326", + "peak_in_radius": true, "seam": false, "x": 0.3232421875, "y": 0.537109375 @@ -1137,11 +1214,12 @@ "center": 0.761366, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7614015936851501, + "nearest_peak_score": 0.7613849639892578, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1187483045673326", + "peak_in_radius": true, "seam": false, "x": 0.39453125, "y": 0.521484375 @@ -1152,12 +1230,13 @@ "cell": "challenger_only", "center": 0.402944, "class": "tail", - "nearest_peak_px": 452.5, - "nearest_peak_score": 0.8867697715759277, + "nearest_peak_px": 6.6, + "nearest_peak_score": 0.5435474514961243, "null_med": 0.00272, "null_p95": 0.143654, "null_pct": 1.0, "pano": "1187483045673326", + "peak_in_radius": true, "seam": false, "x": 0.8828282766631156, "y": 0.6088888827237215 @@ -1168,12 +1247,13 @@ "cell": "neither", "center": 0.125675, "class": "tail", - "nearest_peak_px": 380.2, - "nearest_peak_score": 0.8867697715759277, + "nearest_peak_px": 4.5, + "nearest_peak_score": 0.1285785734653473, "null_med": 0.002928, "null_p95": 0.828798, "null_pct": 0.845, "pano": "1187483045673326", + "peak_in_radius": true, "seam": false, "x": 0.9519191857540246, "y": 0.5419191857540246 @@ -1185,11 +1265,12 @@ "center": 0.927118, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.92713463306427, + "nearest_peak_score": 0.9271089434623718, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1237376427883773", + "peak_in_radius": true, "seam": false, "x": 0.53515625, "y": 0.5546875 @@ -1201,11 +1282,12 @@ "center": 0.902633, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9026480913162231, + "nearest_peak_score": 0.9026328921318054, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1237376427883773", + "peak_in_radius": true, "seam": false, "x": 0.4248046875, "y": 0.552734375 @@ -1217,11 +1299,12 @@ "center": 0.902577, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9025876522064209, + "nearest_peak_score": 0.9025586843490601, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1237376427883773", + "peak_in_radius": true, "seam": false, "x": 0.3310546875, "y": 0.615234375 @@ -1232,12 +1315,13 @@ "cell": "challenger_only", "center": 0.107466, "class": "tail", - "nearest_peak_px": 148.2, - "nearest_peak_score": 0.92713463306427, + "nearest_peak_px": 14.8, + "nearest_peak_score": 0.21517597138881683, "null_med": 0.000984, "null_p95": 0.032863, "null_pct": 1.0, "pano": "1237376427883773", + "peak_in_radius": true, "seam": false, "x": 0.6525252463600852, "y": 0.7240403978752368 @@ -1248,12 +1332,13 @@ "cell": "neither", "center": 0.060418, "class": "tail", - "nearest_peak_px": 107.5, - "nearest_peak_score": 0.92713463306427, + "nearest_peak_px": 9.2, + "nearest_peak_score": 0.2058081030845642, "null_med": 0.007954, "null_p95": 0.902577, "null_pct": 0.815, "pano": "1237376427883773", + "peak_in_radius": true, "seam": false, "x": 0.6355555493903883, "y": 0.6161616099964489 @@ -1265,11 +1350,12 @@ "center": 0.557275, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.5572798252105713, + "nearest_peak_score": 0.5572665333747864, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1260990361757674", + "peak_in_radius": true, "seam": false, "x": 0.9091796875, "y": 0.5546875 @@ -1280,12 +1366,13 @@ "cell": "neither", "center": 0.378516, "class": "tail", - "nearest_peak_px": 453.0, - "nearest_peak_score": 0.5572798252105713, + "nearest_peak_px": 2.9, + "nearest_peak_score": 0.40343689918518066, "null_med": 0.00175, "null_p95": 0.312931, "null_pct": 0.955, "pano": "1260990361757674", + "peak_in_radius": true, "seam": false, "x": 0.46702477127592434, "y": 0.5269179634248174 @@ -1296,12 +1383,13 @@ "cell": "challenger_only", "center": 0.253053, "class": "tail", - "nearest_peak_px": 358.4, - "nearest_peak_score": 0.5572798252105713, + "nearest_peak_px": 2.9, + "nearest_peak_score": 0.27815479040145874, "null_med": 0.001615, "null_p95": 0.557275, "null_pct": 0.85, "pano": "1260990361757674", + "peak_in_radius": true, "seam": false, "x": 0.5593004053574665, "y": 0.5336089345216305 @@ -1313,11 +1401,12 @@ "center": 0.958944, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9589544534683228, + "nearest_peak_score": 0.9589390754699707, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1263975528308076", + "peak_in_radius": true, "seam": false, "x": 0.62109375, "y": 0.552734375 @@ -1329,11 +1418,12 @@ "center": 0.893724, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8937392234802246, + "nearest_peak_score": 0.8937307000160217, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1263975528308076", + "peak_in_radius": true, "seam": false, "x": 0.9404296875, "y": 0.552734375 @@ -1345,11 +1435,12 @@ "center": 0.888867, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8888925313949585, + "nearest_peak_score": 0.8888674378395081, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1263975528308076", + "peak_in_radius": true, "seam": false, "x": 0.0966796875, "y": 0.5390625 @@ -1361,11 +1452,12 @@ "center": 0.881899, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.88192218542099, + "nearest_peak_score": 0.8819018006324768, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1263975528308076", + "peak_in_radius": true, "seam": false, "x": 0.3388671875, "y": 0.5234375 @@ -1377,11 +1469,12 @@ "center": 0.073007, "class": "tail", "nearest_peak_px": 33.1, - "nearest_peak_score": 0.8937392234802246, + "nearest_peak_score": 0.8937307000160217, "null_med": 0.054433, "null_p95": 0.958944, "null_pct": 0.74, "pano": "1263975528308076", + "peak_in_radius": false, "seam": false, "x": 0.9712878880356297, "y": 0.5335353504527698 @@ -1393,11 +1486,12 @@ "center": 0.954889, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9549100399017334, + "nearest_peak_score": 0.9548981785774231, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1273933840289887", + "peak_in_radius": true, "seam": false, "x": 0.28515625, "y": 0.5859375 @@ -1409,11 +1503,12 @@ "center": 0.931501, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9315147399902344, + "nearest_peak_score": 0.9314848780632019, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1273933840289887", + "peak_in_radius": true, "seam": false, "x": 0.8154296875, "y": 0.5703125 @@ -1425,11 +1520,12 @@ "center": 0.930736, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9307556748390198, + "nearest_peak_score": 0.9307392239570618, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1273933840289887", + "peak_in_radius": true, "seam": false, "x": 0.7841796875, "y": 0.5859375 @@ -1441,11 +1537,12 @@ "center": 0.92701, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9269956946372986, + "nearest_peak_score": 0.9269824624061584, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1273933840289887", + "peak_in_radius": true, "seam": false, "x": 0.8935546875, "y": 0.5546875 @@ -1457,11 +1554,12 @@ "center": 0.914886, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9149086475372314, + "nearest_peak_score": 0.9148976802825928, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1273933840289887", + "peak_in_radius": true, "seam": false, "x": 0.73828125, "y": 0.5703125 @@ -1473,11 +1571,12 @@ "center": 0.911319, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9113526940345764, + "nearest_peak_score": 0.9113284349441528, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1273933840289887", + "peak_in_radius": true, "seam": false, "x": 0.09765625, "y": 0.5546875 @@ -1489,11 +1588,12 @@ "center": 0.909138, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9091572761535645, + "nearest_peak_score": 0.9091401696205139, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1273933840289887", + "peak_in_radius": true, "seam": false, "x": 0.2216796875, "y": 0.630859375 @@ -1505,11 +1605,12 @@ "center": 0.86909, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8690925240516663, + "nearest_peak_score": 0.8690751791000366, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1273933840289887", + "peak_in_radius": true, "seam": false, "x": 0.6123046875, "y": 0.5390625 @@ -1521,11 +1622,12 @@ "center": 0.866255, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8662667274475098, + "nearest_peak_score": 0.8662526607513428, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1273933840289887", + "peak_in_radius": true, "seam": false, "x": 0.4248046875, "y": 0.5390625 @@ -1537,11 +1639,12 @@ "center": 0.858303, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8583229184150696, + "nearest_peak_score": 0.8582978844642639, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1273933840289887", + "peak_in_radius": true, "seam": false, "x": 0.17578125, "y": 0.599609375 @@ -1553,11 +1656,12 @@ "center": 0.250927, "class": "tail", "nearest_peak_px": 19.2, - "nearest_peak_score": 0.8690925240516663, + "nearest_peak_score": 0.8690751791000366, "null_med": 0.374923, "null_p95": 0.92701, "null_pct": 0.8, "pano": "1273933840289887", + "peak_in_radius": true, "seam": false, "x": 0.5935664064174488, "y": 0.5384636678464564 @@ -1569,11 +1673,12 @@ "center": 0.948001, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9480153322219849, + "nearest_peak_score": 0.9479978680610657, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1279553583800599", + "peak_in_radius": true, "seam": false, "x": 0.0810546875, "y": 0.5546875 @@ -1585,11 +1690,12 @@ "center": 0.809171, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8091651797294617, + "nearest_peak_score": 0.8091638088226318, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1279553583800599", + "peak_in_radius": true, "seam": false, "x": 0.8857421875, "y": 0.583984375 @@ -1601,11 +1707,12 @@ "center": 0.8919, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8919329643249512, + "nearest_peak_score": 0.8919243812561035, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1288163659019705", + "peak_in_radius": true, "seam": false, "x": 0.4404296875, "y": 0.5390625 @@ -1617,11 +1724,12 @@ "center": 0.857872, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8578888773918152, + "nearest_peak_score": 0.8578627705574036, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1288163659019705", + "peak_in_radius": true, "seam": false, "x": 0.45703125, "y": 0.5390625 @@ -1632,12 +1740,13 @@ "cell": "neither", "center": 0.010458, "class": "tail", - "nearest_peak_px": 175.2, - "nearest_peak_score": 0.8919329643249512, + "nearest_peak_px": 42.9, + "nearest_peak_score": 0.5122259855270386, "null_med": 0.002314, "null_p95": 0.400246, "null_pct": 0.825, "pano": "1288163659019705", + "peak_in_radius": false, "seam": false, "x": 0.2791919130267519, "y": 0.6537373675722065 @@ -1648,12 +1757,13 @@ "cell": "neither", "center": 0.378504, "class": "tail", - "nearest_peak_px": 125.4, - "nearest_peak_score": 0.8919329643249512, + "nearest_peak_px": 7.6, + "nearest_peak_score": 0.5122259855270386, "null_med": 0.011752, "null_p95": 0.4375, "null_pct": 0.99, "pano": "1288163659019705", + "peak_in_radius": true, "seam": false, "x": 0.32282827666311553, "y": 0.6076767615116003 @@ -1665,11 +1775,12 @@ "center": 0.929079, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9291057586669922, + "nearest_peak_score": 0.9290652871131897, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1294684158910702", + "peak_in_radius": true, "seam": false, "x": 0.83984375, "y": 0.505859375 @@ -1681,11 +1792,12 @@ "center": 0.961136, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9611420035362244, + "nearest_peak_score": 0.9611213207244873, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1294705618516185", + "peak_in_radius": true, "seam": false, "x": 0.58203125, "y": 0.537109375 @@ -1697,11 +1809,12 @@ "center": 0.916376, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9164056777954102, + "nearest_peak_score": 0.9163845777511597, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1294705618516185", + "peak_in_radius": true, "seam": false, "x": 0.68359375, "y": 0.599609375 @@ -1713,11 +1826,12 @@ "center": 0.96603, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9660662412643433, + "nearest_peak_score": 0.9660443067550659, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1309093164014619", + "peak_in_radius": true, "seam": false, "x": 0.35546875, "y": 0.5234375 @@ -1729,11 +1843,12 @@ "center": 0.963532, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9635652303695679, + "nearest_peak_score": 0.9635457992553711, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1309093164014619", + "peak_in_radius": true, "seam": false, "x": 0.5576171875, "y": 0.568359375 @@ -1745,11 +1860,12 @@ "center": 0.896823, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8967987298965454, + "nearest_peak_score": 0.8967732191085815, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1309093164014619", + "peak_in_radius": true, "seam": false, "x": 0.32421875, "y": 0.5234375 @@ -1761,11 +1877,12 @@ "center": 0.890193, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.89020836353302, + "nearest_peak_score": 0.8901859521865845, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1309093164014619", + "peak_in_radius": true, "seam": false, "x": 0.92578125, "y": 0.599609375 @@ -1777,11 +1894,12 @@ "center": 0.799142, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7991482019424438, + "nearest_peak_score": 0.7991349101066589, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1309093164014619", + "peak_in_radius": true, "seam": false, "x": 0.8701171875, "y": 0.583984375 @@ -1793,11 +1911,12 @@ "center": 0.768035, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7680552005767822, + "nearest_peak_score": 0.768044114112854, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1309093164014619", + "peak_in_radius": true, "seam": false, "x": 0.8701171875, "y": 0.5546875 @@ -1809,11 +1928,12 @@ "center": 0.671669, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.6716945171356201, + "nearest_peak_score": 0.6716797351837158, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1309093164014619", + "peak_in_radius": true, "seam": false, "x": 0.7919921875, "y": 0.5390625 @@ -1825,11 +1945,12 @@ "center": 0.116021, "class": "tail", "nearest_peak_px": 17.2, - "nearest_peak_score": 0.7991482019424438, + "nearest_peak_score": 0.7991349101066589, "null_med": 0.102378, "null_p95": 0.963532, "null_pct": 0.885, "pano": "1309093164014619", + "peak_in_radius": true, "seam": false, "x": 0.8864646402994791, "y": 0.5765656627308239 @@ -1841,11 +1962,12 @@ "center": 0.749987, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7499932050704956, + "nearest_peak_score": 0.7499725222587585, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1315788070079167", + "peak_in_radius": true, "seam": false, "x": 0.5888671875, "y": 0.5234375 @@ -1856,12 +1978,13 @@ "cell": "challenger_only", "center": 0.220484, "class": "tail", - "nearest_peak_px": 38.4, - "nearest_peak_score": 0.7499932050704956, + "nearest_peak_px": 3.9, + "nearest_peak_score": 0.24537207186222076, "null_med": 0.002646, "null_p95": 0.439927, "null_pct": 0.91, "pano": "1315788070079167", + "peak_in_radius": true, "seam": false, "x": 0.5610100948449337, "y": 0.47313130696614586 @@ -1873,11 +1996,12 @@ "center": 0.770554, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7705703973770142, + "nearest_peak_score": 0.7705532312393188, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1315844333300588", + "peak_in_radius": true, "seam": false, "x": 0.1904296875, "y": 0.5859375 @@ -1889,11 +2013,12 @@ "center": 0.89899, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8990136384963989, + "nearest_peak_score": 0.8989949822425842, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1327023138707493", + "peak_in_radius": true, "seam": false, "x": 0.41015625, "y": 0.5546875 @@ -1905,11 +2030,12 @@ "center": 0.698635, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.6986466646194458, + "nearest_peak_score": 0.6986407041549683, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1327023138707493", + "peak_in_radius": true, "seam": false, "x": 0.6201171875, "y": 0.5703125 @@ -1920,12 +2046,13 @@ "cell": "challenger_only", "center": 0.129971, "class": "tail", - "nearest_peak_px": 72.5, - "nearest_peak_score": 0.6986466646194458, + "nearest_peak_px": 1.6, + "nearest_peak_score": 0.13228851556777954, "null_med": 0.011101, "null_p95": 0.872345, "null_pct": 0.825, "pano": "1327023138707493", + "peak_in_radius": true, "seam": false, "x": 0.5511111542672822, "y": 0.5386869118430397 @@ -1937,11 +2064,12 @@ "center": 0.929298, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9293081760406494, + "nearest_peak_score": 0.9292899370193481, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1335429861397399", + "peak_in_radius": true, "seam": false, "x": 0.24609375, "y": 0.646484375 @@ -1953,11 +2081,12 @@ "center": 0.914961, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9149634838104248, + "nearest_peak_score": 0.9149394035339355, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1335429861397399", + "peak_in_radius": true, "seam": false, "x": 0.9013671875, "y": 0.5546875 @@ -1969,11 +2098,12 @@ "center": 0.896301, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8963165879249573, + "nearest_peak_score": 0.8962975144386292, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1335429861397399", + "peak_in_radius": true, "seam": false, "x": 0.02734375, "y": 0.568359375 @@ -1985,11 +2115,12 @@ "center": 0.895466, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8955129384994507, + "nearest_peak_score": 0.8954881429672241, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1335429861397399", + "peak_in_radius": true, "seam": false, "x": 0.74609375, "y": 0.5703125 @@ -2001,11 +2132,12 @@ "center": 0.874735, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8747516870498657, + "nearest_peak_score": 0.8747368454933167, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1338631107629110", + "peak_in_radius": true, "seam": false, "x": 0.5576171875, "y": 0.5234375 @@ -2017,11 +2149,12 @@ "center": 0.207195, "class": "tail", "nearest_peak_px": 29.0, - "nearest_peak_score": 0.8747516870498657, + "nearest_peak_score": 0.8747368454933167, "null_med": 0.002086, "null_p95": 0.402981, "null_pct": 1.0, "pano": "1338631107629110", + "peak_in_radius": false, "seam": false, "x": 0.5325252463600852, "y": 0.4973737312085701 @@ -2033,11 +2166,12 @@ "center": 0.866864, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8668623566627502, + "nearest_peak_score": 0.8668447732925415, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1408179757063785", + "peak_in_radius": true, "seam": false, "x": 0.3779296875, "y": 0.630859375 @@ -2049,11 +2183,12 @@ "center": 1.0, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 1.003684401512146, + "nearest_peak_score": 1.0036526918411255, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1427673368387929", + "peak_in_radius": true, "seam": false, "x": 0.59765625, "y": 0.537109375 @@ -2065,11 +2200,12 @@ "center": 0.948419, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9484301805496216, + "nearest_peak_score": 0.9484100937843323, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1427673368387929", + "peak_in_radius": true, "seam": false, "x": 0.4873046875, "y": 0.5234375 @@ -2081,11 +2217,12 @@ "center": 0.863412, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8634457588195801, + "nearest_peak_score": 0.8634290099143982, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1427673368387929", + "peak_in_radius": true, "seam": false, "x": 0.33984375, "y": 0.5859375 @@ -2097,11 +2234,12 @@ "center": 0.772906, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7728960514068604, + "nearest_peak_score": 0.7728797793388367, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1441274599876577", + "peak_in_radius": true, "seam": false, "x": 0.0654296875, "y": 0.5390625 @@ -2113,11 +2251,12 @@ "center": 0.231996, "class": "tail", "nearest_peak_px": 16.8, - "nearest_peak_score": 0.7728960514068604, + "nearest_peak_score": 0.7728797793388367, "null_med": 0.009665, "null_p95": 0.35217, "null_pct": 1.0, "pano": "1441274599876577", + "peak_in_radius": true, "seam": false, "x": 0.05026338366770002, "y": 0.5263919001449772 @@ -2128,12 +2267,13 @@ "cell": "neither", "center": 0.171911, "class": "tail", - "nearest_peak_px": 124.4, - "nearest_peak_score": 0.7728960514068604, + "nearest_peak_px": 4.3, + "nearest_peak_score": 0.18528473377227783, "null_med": 0.009683, "null_p95": 0.678158, "null_pct": 0.915, "pano": "1441274599876577", + "peak_in_radius": true, "seam": false, "x": 0.9440247579367571, "y": 0.5328431364003076 @@ -2145,11 +2285,12 @@ "center": 0.757466, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7574822306632996, + "nearest_peak_score": 0.7574731707572937, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1473003156922360", + "peak_in_radius": true, "seam": false, "x": 0.9560546875, "y": 0.5234375 @@ -2161,11 +2302,12 @@ "center": 0.625056, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.6250661611557007, + "nearest_peak_score": 0.6250497102737427, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1473003156922360", + "peak_in_radius": true, "seam": false, "x": 0.0498046875, "y": 0.521484375 @@ -2177,11 +2319,12 @@ "center": 0.851548, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8515617251396179, + "nearest_peak_score": 0.8515517711639404, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1483585545954157", + "peak_in_radius": true, "seam": false, "x": 0.51171875, "y": 0.5390625 @@ -2193,11 +2336,12 @@ "center": 0.790555, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7905715703964233, + "nearest_peak_score": 0.7905554175376892, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1483585545954157", + "peak_in_radius": true, "seam": false, "x": 0.53515625, "y": 0.5390625 @@ -2209,11 +2353,12 @@ "center": 0.716116, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7161297798156738, + "nearest_peak_score": 0.7161192893981934, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1483585545954157", + "peak_in_radius": true, "seam": false, "x": 0.6669921875, "y": 0.552734375 @@ -2225,11 +2370,12 @@ "center": 0.601094, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.601104199886322, + "nearest_peak_score": 0.6010903716087341, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1589004208714002", + "peak_in_radius": true, "seam": false, "x": 0.9716796875, "y": 0.5390625 @@ -2241,11 +2387,12 @@ "center": 0.594131, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.5941709280014038, + "nearest_peak_score": 0.5941601395606995, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1589004208714002", + "peak_in_radius": true, "seam": false, "x": 0.06640625, "y": 0.5390625 @@ -2257,11 +2404,12 @@ "center": 0.978302, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9783142805099487, + "nearest_peak_score": 0.9783031940460205, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1599497457585207", + "peak_in_radius": true, "seam": false, "x": 0.60546875, "y": 0.552734375 @@ -2273,11 +2421,12 @@ "center": 0.955378, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9554139375686646, + "nearest_peak_score": 0.955389142036438, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1599497457585207", + "peak_in_radius": true, "seam": false, "x": 0.7607421875, "y": 0.6171875 @@ -2289,11 +2438,12 @@ "center": 0.91067, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9106926918029785, + "nearest_peak_score": 0.9106754064559937, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1701172050581812", + "peak_in_radius": true, "seam": false, "x": 0.1044921875, "y": 0.5546875 @@ -2305,11 +2455,12 @@ "center": 0.744185, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7442018985748291, + "nearest_peak_score": 0.744189977645874, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1701172050581812", + "peak_in_radius": true, "seam": true, "x": 0.9794921875, "y": 0.568359375 @@ -2321,11 +2472,12 @@ "center": 0.652255, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.6522689461708069, + "nearest_peak_score": 0.6522653698921204, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1701172050581812", + "peak_in_radius": true, "seam": false, "x": 0.6904296875, "y": 0.7421875 @@ -2337,11 +2489,12 @@ "center": 0.712292, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7123180627822876, + "nearest_peak_score": 0.7122933268547058, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1739689546844035", + "peak_in_radius": true, "seam": false, "x": 0.13671875, "y": 0.615234375 @@ -2353,11 +2506,12 @@ "center": 0.947448, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.947451114654541, + "nearest_peak_score": 0.9474393129348755, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1759178911495771", + "peak_in_radius": true, "seam": false, "x": 0.3935546875, "y": 0.5546875 @@ -2369,11 +2523,12 @@ "center": 0.692712, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.692729651927948, + "nearest_peak_score": 0.692719578742981, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1759178911495771", + "peak_in_radius": true, "seam": false, "x": 0.5498046875, "y": 0.5703125 @@ -2384,12 +2539,13 @@ "cell": "neither", "center": 0.222914, "class": "tail", - "nearest_peak_px": 56.1, - "nearest_peak_score": 0.947451114654541, + "nearest_peak_px": 11.2, + "nearest_peak_score": 0.45948725938796997, "null_med": 0.003831, "null_p95": 0.947448, "null_pct": 0.875, "pano": "1759178911495771", + "peak_in_radius": true, "seam": false, "x": 0.4460757821051315, "y": 0.5233485093778587 @@ -2400,12 +2556,13 @@ "cell": "challenger_only", "center": 0.430928, "class": "tail", - "nearest_peak_px": 69.1, - "nearest_peak_score": 0.947451114654541, + "nearest_peak_px": 2.2, + "nearest_peak_score": 0.45948725938796997, "null_med": 0.003468, "null_p95": 0.696784, "null_pct": 0.9, "pano": "1759178911495771", + "peak_in_radius": true, "seam": false, "x": 0.459005214757595, "y": 0.5217732532878832 @@ -2417,11 +2574,12 @@ "center": 0.036292, "class": "tail", "nearest_peak_px": 39.5, - "nearest_peak_score": 0.692729651927948, + "nearest_peak_score": 0.692719578742981, "null_med": 0.003468, "null_p95": 0.762892, "null_pct": 0.84, "pano": "1759178911495771", + "peak_in_radius": false, "seam": false, "x": 0.5197303339935238, "y": 0.5219953845879944 @@ -2433,11 +2591,12 @@ "center": 0.973626, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9736382961273193, + "nearest_peak_score": 0.9736160635948181, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1828524234403425", + "peak_in_radius": true, "seam": false, "x": 0.19140625, "y": 0.615234375 @@ -2449,11 +2608,12 @@ "center": 0.857854, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8578647375106812, + "nearest_peak_score": 0.8578392267227173, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1828524234403425", + "peak_in_radius": true, "seam": false, "x": 0.8779296875, "y": 0.662109375 @@ -2465,11 +2625,12 @@ "center": 0.957361, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.957377016544342, + "nearest_peak_score": 0.9573454260826111, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1847752429062443", + "peak_in_radius": true, "seam": false, "x": 0.31640625, "y": 0.5390625 @@ -2481,11 +2642,12 @@ "center": 0.955378, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.955399215221405, + "nearest_peak_score": 0.955374538898468, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1847752429062443", + "peak_in_radius": true, "seam": false, "x": 0.1826171875, "y": 0.5390625 @@ -2497,11 +2659,12 @@ "center": 0.944535, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9445477724075317, + "nearest_peak_score": 0.9445435404777527, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1847752429062443", + "peak_in_radius": true, "seam": false, "x": 0.91015625, "y": 0.552734375 @@ -2513,11 +2676,12 @@ "center": 0.934892, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9348896741867065, + "nearest_peak_score": 0.9348766207695007, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1847752429062443", + "peak_in_radius": true, "seam": false, "x": 0.38671875, "y": 0.537109375 @@ -2529,11 +2693,12 @@ "center": 0.922957, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9229707717895508, + "nearest_peak_score": 0.9229496717453003, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1847752429062443", + "peak_in_radius": true, "seam": false, "x": 0.55859375, "y": 0.552734375 @@ -2545,11 +2710,12 @@ "center": 0.921211, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9212089776992798, + "nearest_peak_score": 0.9212049245834351, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1847752429062443", + "peak_in_radius": true, "seam": false, "x": 0.80859375, "y": 0.5703125 @@ -2561,11 +2727,12 @@ "center": 0.751652, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7516857385635376, + "nearest_peak_score": 0.7516688108444214, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1847752429062443", + "peak_in_radius": true, "seam": false, "x": 0.1044921875, "y": 0.5390625 @@ -2577,11 +2744,12 @@ "center": 0.740659, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7406735420227051, + "nearest_peak_score": 0.7406595349311829, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1847752429062443", + "peak_in_radius": true, "seam": false, "x": 0.65234375, "y": 0.5703125 @@ -2593,11 +2761,12 @@ "center": 0.762745, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7627651691436768, + "nearest_peak_score": 0.7627561688423157, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1905003193597285", + "peak_in_radius": true, "seam": false, "x": 0.36328125, "y": 0.552734375 @@ -2609,11 +2778,12 @@ "center": 0.64667, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.6466811895370483, + "nearest_peak_score": 0.6466679573059082, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1905003193597285", + "peak_in_radius": true, "seam": false, "x": 0.63671875, "y": 0.5546875 @@ -2624,12 +2794,13 @@ "cell": "challenger_only", "center": 0.473058, "class": "tail", - "nearest_peak_px": 172.3, - "nearest_peak_score": 0.6466811895370483, + "nearest_peak_px": 6.1, + "nearest_peak_score": 0.4817718267440796, "null_med": 0.015273, "null_p95": 0.722935, "null_pct": 0.875, "pano": "1905003193597285", + "peak_in_radius": true, "seam": false, "x": 0.8046464584812973, "y": 0.5749494887843276 @@ -2640,12 +2811,13 @@ "cell": "challenger_only", "center": 0.059961, "class": "tail", - "nearest_peak_px": 234.8, - "nearest_peak_score": 0.6466811895370483, + "nearest_peak_px": 21.4, + "nearest_peak_score": 0.09355422854423523, "null_med": 0.009791, "null_p95": 0.64667, "null_pct": 0.72, "pano": "1905003193597285", + "peak_in_radius": true, "seam": false, "x": 0.8658585796934185, "y": 0.5693939578894412 @@ -2656,12 +2828,13 @@ "cell": "challenger_only", "center": 0.085348, "class": "tail", - "nearest_peak_px": 259.9, - "nearest_peak_score": 0.6466811895370483, + "nearest_peak_px": 5.9, + "nearest_peak_score": 0.09355422854423523, "null_med": 0.024054, "null_p95": 0.64667, "null_pct": 0.67, "pano": "1905003193597285", + "peak_in_radius": true, "seam": false, "x": 0.8905050936612215, "y": 0.5596969881924716 @@ -2672,12 +2845,13 @@ "cell": "challenger_only", "center": 0.076573, "class": "tail", - "nearest_peak_px": 290.5, - "nearest_peak_score": 0.6466811895370483, + "nearest_peak_px": 3.6, + "nearest_peak_score": 0.07805923372507095, "null_med": 0.024054, "null_p95": 0.666264, "null_pct": 0.655, "pano": "1905003193597285", + "peak_in_radius": true, "seam": false, "x": 0.9204040342388731, "y": 0.5475757760712595 @@ -2689,11 +2863,12 @@ "center": 0.901254, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9012807011604309, + "nearest_peak_score": 0.9012539386749268, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1991198475040883", + "peak_in_radius": true, "seam": false, "x": 0.5810546875, "y": 0.568359375 @@ -2705,11 +2880,12 @@ "center": 0.924785, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.924778938293457, + "nearest_peak_score": 0.9247885346412659, "null_med": null, "null_p95": null, "null_pct": null, "pano": "1991876994661275", + "peak_in_radius": true, "seam": false, "x": 0.2294921875, "y": 0.568359375 @@ -2720,12 +2896,13 @@ "cell": "challenger_only", "center": 0.498044, "class": "tail", - "nearest_peak_px": 213.1, - "nearest_peak_score": 0.924778938293457, + "nearest_peak_px": 4.0, + "nearest_peak_score": 0.539199948310852, "null_med": 0.044088, "null_p95": 0.471416, "null_pct": 0.96, "pano": "1991876994661275", + "peak_in_radius": true, "seam": false, "x": 0.022222216057054923, "y": 0.531313125147964 @@ -2736,12 +2913,13 @@ "cell": "challenger_only", "center": 0.264974, "class": "tail", - "nearest_peak_px": 114.9, - "nearest_peak_score": 0.924778938293457, + "nearest_peak_px": 3.8, + "nearest_peak_score": 0.2877284288406372, "null_med": 0.083931, "null_p95": 0.539202, "null_pct": 0.765, "pano": "1991876994661275", + "peak_in_radius": true, "seam": false, "x": 0.1188302236550056, "y": 0.5312825529464339 @@ -2753,11 +2931,12 @@ "center": 0.954275, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9542931318283081, + "nearest_peak_score": 0.9542726278305054, "null_med": null, "null_p95": null, "null_pct": null, "pano": "2067733823644753", + "peak_in_radius": true, "seam": false, "x": 0.0966796875, "y": 0.568359375 @@ -2769,11 +2948,12 @@ "center": 0.950191, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9501867294311523, + "nearest_peak_score": 0.950171172618866, "null_med": null, "null_p95": null, "null_pct": null, "pano": "2067733823644753", + "peak_in_radius": true, "seam": false, "x": 0.23828125, "y": 0.599609375 @@ -2785,11 +2965,12 @@ "center": 0.928207, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9282107353210449, + "nearest_peak_score": 0.9281997680664062, "null_med": null, "null_p95": null, "null_pct": null, "pano": "2067733823644753", + "peak_in_radius": true, "seam": false, "x": 0.94140625, "y": 0.5546875 @@ -2801,11 +2982,12 @@ "center": 0.87734, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8773713707923889, + "nearest_peak_score": 0.8773458003997803, "null_med": null, "null_p95": null, "null_pct": null, "pano": "2067733823644753", + "peak_in_radius": true, "seam": false, "x": 0.7841796875, "y": 0.615234375 @@ -2817,11 +2999,12 @@ "center": 0.889261, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8892773389816284, + "nearest_peak_score": 0.8892724514007568, "null_med": null, "null_p95": null, "null_pct": null, "pano": "2111278956050786", + "peak_in_radius": true, "seam": false, "x": 0.3779296875, "y": 0.568359375 @@ -2833,11 +3016,12 @@ "center": 0.668602, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.668611466884613, + "nearest_peak_score": 0.6686080098152161, "null_med": null, "null_p95": null, "null_pct": null, "pano": "2111278956050786", + "peak_in_radius": true, "seam": false, "x": 0.64453125, "y": 0.5703125 @@ -2849,11 +3033,12 @@ "center": 0.878634, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8786584138870239, + "nearest_peak_score": 0.8786442875862122, "null_med": null, "null_p95": null, "null_pct": null, "pano": "2141681583023863", + "peak_in_radius": true, "seam": false, "x": 0.49609375, "y": 0.5546875 @@ -2865,11 +3050,12 @@ "center": 0.819354, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8193663954734802, + "nearest_peak_score": 0.8193565607070923, "null_med": null, "null_p95": null, "null_pct": null, "pano": "2141681583023863", + "peak_in_radius": true, "seam": false, "x": 0.80078125, "y": 0.6015625 @@ -2881,11 +3067,12 @@ "center": 0.69882, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.6988358497619629, + "nearest_peak_score": 0.69881272315979, "null_med": null, "null_p95": null, "null_pct": null, "pano": "2147631415757748", + "peak_in_radius": true, "seam": false, "x": 0.1201171875, "y": 0.5390625 @@ -2897,11 +3084,12 @@ "center": 0.910001, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9100374579429626, + "nearest_peak_score": 0.9100123643875122, "null_med": null, "null_p95": null, "null_pct": null, "pano": "2184370012043145", + "peak_in_radius": true, "seam": true, "x": 0.9794921875, "y": 0.5703125 @@ -2913,11 +3101,12 @@ "center": 0.906266, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9062710404396057, + "nearest_peak_score": 0.9062591791152954, "null_med": null, "null_p95": null, "null_pct": null, "pano": "2184370012043145", + "peak_in_radius": true, "seam": false, "x": 0.2919921875, "y": 0.583984375 @@ -2929,11 +3118,12 @@ "center": 0.627935, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.6279417872428894, + "nearest_peak_score": 0.6279332041740417, "null_med": null, "null_p95": null, "null_pct": null, "pano": "2184370012043145", + "peak_in_radius": true, "seam": false, "x": 0.1982421875, "y": 0.537109375 @@ -2945,11 +3135,12 @@ "center": 0.979381, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9793874621391296, + "nearest_peak_score": 0.9793581366539001, "null_med": null, "null_p95": null, "null_pct": null, "pano": "2263954690670646", + "peak_in_radius": true, "seam": false, "x": 0.37109375, "y": 0.5390625 @@ -2961,11 +3152,12 @@ "center": 0.898989, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8989967107772827, + "nearest_peak_score": 0.8989763259887695, "null_med": null, "null_p95": null, "null_pct": null, "pano": "2263954690670646", + "peak_in_radius": true, "seam": false, "x": 0.1748046875, "y": 0.5390625 @@ -2977,11 +3169,12 @@ "center": 0.881651, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8816700577735901, + "nearest_peak_score": 0.8816595077514648, "null_med": null, "null_p95": null, "null_pct": null, "pano": "2263954690670646", + "peak_in_radius": true, "seam": false, "x": 0.06640625, "y": 0.537109375 @@ -2993,11 +3186,12 @@ "center": 0.788486, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.788508415222168, + "nearest_peak_score": 0.7884945273399353, "null_med": null, "null_p95": null, "null_pct": null, "pano": "2263954690670646", + "peak_in_radius": true, "seam": true, "x": 0.01953125, "y": 0.5234375 @@ -3009,11 +3203,12 @@ "center": 0.749173, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7491846680641174, + "nearest_peak_score": 0.7491685152053833, "null_med": null, "null_p95": null, "null_pct": null, "pano": "2263954690670646", + "peak_in_radius": true, "seam": false, "x": 0.94140625, "y": 0.599609375 @@ -3025,11 +3220,12 @@ "center": 0.653083, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.6530851721763611, + "nearest_peak_score": 0.6530662775039673, "null_med": null, "null_p95": null, "null_pct": null, "pano": "2263954690670646", + "peak_in_radius": true, "seam": false, "x": 0.9482421875, "y": 0.5546875 @@ -3041,11 +3237,12 @@ "center": 0.929437, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9294503927230835, + "nearest_peak_score": 0.9294414520263672, "null_med": null, "null_p95": null, "null_pct": null, "pano": "27724402107145083", + "peak_in_radius": true, "seam": false, "x": 0.56640625, "y": 0.5390625 @@ -3057,11 +3254,12 @@ "center": 0.825894, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8259216547012329, + "nearest_peak_score": 0.8258990049362183, "null_med": null, "null_p95": null, "null_pct": null, "pano": "27724402107145083", + "peak_in_radius": true, "seam": false, "x": 0.41796875, "y": 0.5390625 @@ -3072,12 +3270,13 @@ "cell": "challenger_only", "center": 0.307763, "class": "tail", - "nearest_peak_px": 38.5, - "nearest_peak_score": 0.9294503927230835, + "nearest_peak_px": 5.4, + "nearest_peak_score": 0.35654979944229126, "null_med": 0.003167, "null_p95": 0.764083, "null_pct": 0.9, "pano": "27724402107145083", + "peak_in_radius": true, "seam": false, "x": 0.5995960027521307, "y": 0.574242461233428 @@ -3089,11 +3288,12 @@ "center": 0.665317, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.6653203368186951, + "nearest_peak_score": 0.6653231978416443, "null_med": null, "null_p95": null, "null_pct": null, "pano": "372149922554566", + "peak_in_radius": true, "seam": false, "x": 0.91015625, "y": 0.5546875 @@ -3105,11 +3305,12 @@ "center": 0.648446, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.6484609246253967, + "nearest_peak_score": 0.6484498381614685, "null_med": null, "null_p95": null, "null_pct": null, "pano": "372149922554566", + "peak_in_radius": true, "seam": false, "x": 0.0576171875, "y": 0.552734375 @@ -3120,12 +3321,13 @@ "cell": "challenger_only", "center": 0.182823, "class": "tail", - "nearest_peak_px": 44.9, - "nearest_peak_score": 0.6653203368186951, + "nearest_peak_px": 4.9, + "nearest_peak_score": 0.21032880246639252, "null_med": 0.00067, "null_p95": 0.648446, "null_pct": 0.905, "pano": "372149922554566", + "peak_in_radius": true, "seam": false, "x": 0.9527272912227747, "y": 0.533838426994555 @@ -3137,11 +3339,12 @@ "center": 0.08643, "class": "tail", "nearest_peak_px": 26.8, - "nearest_peak_score": 0.6484609246253967, + "nearest_peak_score": 0.6484498381614685, "null_med": 0.000944, "null_p95": 0.665317, "null_pct": 0.935, "pano": "372149922554566", + "peak_in_radius": false, "seam": false, "x": 0.03474748091264204, "y": 0.5273737312085701 @@ -3153,11 +3356,12 @@ "center": 0.962026, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9620377421379089, + "nearest_peak_score": 0.9620198011398315, "null_med": null, "null_p95": null, "null_pct": null, "pano": "383880874806933", + "peak_in_radius": true, "seam": false, "x": 0.84765625, "y": 0.5859375 @@ -3169,11 +3373,12 @@ "center": 0.895772, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.895784318447113, + "nearest_peak_score": 0.8957797288894653, "null_med": null, "null_p95": null, "null_pct": null, "pano": "383880874806933", + "peak_in_radius": true, "seam": false, "x": 0.94140625, "y": 0.5546875 @@ -3184,12 +3389,13 @@ "cell": "challenger_only", "center": 0.337857, "class": "tail", - "nearest_peak_px": 277.8, - "nearest_peak_score": 0.895784318447113, + "nearest_peak_px": 1.5, + "nearest_peak_score": 0.3437323570251465, "null_med": 0.020841, "null_p95": 0.873995, "null_pct": 0.89, "pano": "383880874806933", + "peak_in_radius": true, "seam": false, "x": 0.21252524636008524, "y": 0.5361616099964489 @@ -3200,12 +3406,13 @@ "cell": "challenger_only", "center": 0.142017, "class": "tail", - "nearest_peak_px": 258.9, - "nearest_peak_score": 0.895784318447113, + "nearest_peak_px": 20.7, + "nearest_peak_score": 0.3437323570251465, "null_med": 0.025784, "null_p95": 0.709031, "null_pct": 0.865, "pano": "383880874806933", + "peak_in_radius": true, "seam": false, "x": 0.19393941243489585, "y": 0.5297979736328124 @@ -3217,11 +3424,12 @@ "center": 0.858318, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8583464026451111, + "nearest_peak_score": 0.8583197593688965, "null_med": null, "null_p95": null, "null_pct": null, "pano": "386363531219281", + "peak_in_radius": true, "seam": false, "x": 0.66015625, "y": 0.5546875 @@ -3233,11 +3441,12 @@ "center": 0.847305, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8473024964332581, + "nearest_peak_score": 0.8473037481307983, "null_med": null, "null_p95": null, "null_pct": null, "pano": "386363531219281", + "peak_in_radius": true, "seam": false, "x": 0.4482421875, "y": 0.568359375 @@ -3249,11 +3458,12 @@ "center": 0.044115, "class": "tail", "nearest_peak_px": 51.3, - "nearest_peak_score": 0.8473024964332581, + "nearest_peak_score": 0.8473037481307983, "null_med": 0.006155, "null_p95": 0.618636, "null_pct": 0.82, "pano": "386363531219281", + "peak_in_radius": false, "seam": false, "x": 0.4905050936612216, "y": 0.5144444876006156 @@ -3264,12 +3474,13 @@ "cell": "challenger_only", "center": 0.056529, "class": "tail", - "nearest_peak_px": 106.5, - "nearest_peak_score": 0.8583464026451111, + "nearest_peak_px": 2.8, + "nearest_peak_score": 0.05928492546081543, "null_med": 0.006155, "null_p95": 0.751092, "null_pct": 0.84, "pano": "386363531219281", + "peak_in_radius": true, "seam": false, "x": 0.5579797918146306, "y": 0.5160606245561079 @@ -3281,11 +3492,12 @@ "center": 0.796538, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7965537309646606, + "nearest_peak_score": 0.7965390086174011, "null_med": null, "null_p95": null, "null_pct": null, "pano": "3901547360084831", + "peak_in_radius": true, "seam": false, "x": 0.2138671875, "y": 0.5390625 @@ -3297,11 +3509,12 @@ "center": 0.890949, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8909704685211182, + "nearest_peak_score": 0.8909416794776917, "null_med": null, "null_p95": null, "null_pct": null, "pano": "3956582084664486", + "peak_in_radius": true, "seam": false, "x": 0.44140625, "y": 0.5390625 @@ -3313,11 +3526,12 @@ "center": 0.846316, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8463200330734253, + "nearest_peak_score": 0.846308708190918, "null_med": null, "null_p95": null, "null_pct": null, "pano": "3956582084664486", + "peak_in_radius": true, "seam": false, "x": 0.55078125, "y": 0.552734375 @@ -3329,11 +3543,12 @@ "center": 0.333811, "class": "tail", "nearest_peak_px": 26.2, - "nearest_peak_score": 0.8909704685211182, + "nearest_peak_score": 0.8909416794776917, "null_med": 0.000476, "null_p95": 0.633645, "null_pct": 0.98, "pano": "3956582084664486", + "peak_in_radius": false, "seam": false, "x": 0.46505054820667613, "y": 0.5192929169625947 @@ -3345,11 +3560,12 @@ "center": 0.077748, "class": "tail", "nearest_peak_px": 20.7, - "nearest_peak_score": 0.8463200330734253, + "nearest_peak_score": 0.846308708190918, "null_med": 0.000518, "null_p95": 0.890949, "null_pct": 0.93, "pano": "3956582084664486", + "peak_in_radius": true, "seam": false, "x": 0.5402850979625293, "y": 0.5182507727523443 @@ -3360,12 +3576,13 @@ "cell": "challenger_only", "center": 0.378829, "class": "tail", - "nearest_peak_px": 86.8, - "nearest_peak_score": 0.5525027513504028, + "nearest_peak_px": 6.4, + "nearest_peak_score": 0.4103164076805115, "null_med": 0.025696, "null_p95": 0.497308, "null_pct": 0.905, "pano": "3980741912187626", + "peak_in_radius": true, "seam": false, "x": 0.3773737312085701, "y": 0.5846464584812974 @@ -3376,12 +3593,13 @@ "cell": "challenger_only", "center": 0.332233, "class": "tail", - "nearest_peak_px": 93.7, - "nearest_peak_score": 0.5958422422409058, + "nearest_peak_px": 12.0, + "nearest_peak_score": 0.4973132610321045, "null_med": 0.009084, "null_p95": 0.410306, "null_pct": 1.0, "pano": "3980741912187626", + "peak_in_radius": true, "seam": false, "x": 0.6088888827237215, "y": 0.6064646402994792 @@ -3392,12 +3610,13 @@ "cell": "neither", "center": 0.153297, "class": "tail", - "nearest_peak_px": 88.9, - "nearest_peak_score": 0.5958422422409058, + "nearest_peak_px": 20.0, + "nearest_peak_score": 0.4973132610321045, "null_med": 0.062561, "null_p95": 0.495448, "null_pct": 0.955, "pano": "3980741912187626", + "peak_in_radius": true, "seam": false, "x": 0.6108941345557353, "y": 0.5709128544012171 @@ -3409,11 +3628,12 @@ "center": 0.807756, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8077545762062073, + "nearest_peak_score": 0.8077345490455627, "null_med": null, "null_p95": null, "null_pct": null, "pano": "4102292636718018", + "peak_in_radius": true, "seam": false, "x": 0.32421875, "y": 0.5390625 @@ -3425,11 +3645,12 @@ "center": 0.555799, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.5558204054832458, + "nearest_peak_score": 0.5557992458343506, "null_med": null, "null_p95": null, "null_pct": null, "pano": "4102292636718018", + "peak_in_radius": true, "seam": false, "x": 0.61328125, "y": 0.662109375 @@ -3441,11 +3662,12 @@ "center": 0.78927, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7892700433731079, + "nearest_peak_score": 0.7892580032348633, "null_med": null, "null_p95": null, "null_pct": null, "pano": "4116269558691031", + "peak_in_radius": true, "seam": false, "x": 0.48828125, "y": 0.6015625 @@ -3456,12 +3678,13 @@ "cell": "challenger_only", "center": 0.342678, "class": "tail", - "nearest_peak_px": 68.9, - "nearest_peak_score": 0.7892700433731079, + "nearest_peak_px": 13.9, + "nearest_peak_score": 0.5079110264778137, "null_med": 0.002889, "null_p95": 0.244408, "null_pct": 1.0, "pano": "4116269558691031", + "peak_in_radius": true, "seam": false, "x": 0.4294949433297822, "y": 0.6670707009055398 @@ -3473,11 +3696,12 @@ "center": 0.860736, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8607585430145264, + "nearest_peak_score": 0.8607470393180847, "null_med": null, "null_p95": null, "null_pct": null, "pano": "423989957171190", + "peak_in_radius": true, "seam": false, "x": 0.5341796875, "y": 0.568359375 @@ -3489,11 +3713,12 @@ "center": 0.85772, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.857740044593811, + "nearest_peak_score": 0.8577241897583008, "null_med": null, "null_p95": null, "null_pct": null, "pano": "423989957171190", + "peak_in_radius": true, "seam": false, "x": 0.37109375, "y": 0.5390625 @@ -3505,11 +3730,12 @@ "center": 0.035938, "class": "faint_local", "nearest_peak_px": 57.4, - "nearest_peak_score": 0.857740044593811, + "nearest_peak_score": 0.8577241897583008, "null_med": 0.00442, "null_p95": 0.704602, "null_pct": 0.885, "pano": "423989957171190", + "peak_in_radius": false, "seam": false, "x": 0.42667711943494924, "y": 0.5250655456146334 @@ -3521,11 +3747,12 @@ "center": 0.112684, "class": "tail", "nearest_peak_px": 30.9, - "nearest_peak_score": 0.8607585430145264, + "nearest_peak_score": 0.8607470393180847, "null_med": 0.004899, "null_p95": 0.764398, "null_pct": 0.95, "pano": "423989957171190", + "peak_in_radius": false, "seam": false, "x": 0.5133691152905883, "y": 0.5247863607532633 @@ -3537,11 +3764,12 @@ "center": 0.296156, "class": "tail", "nearest_peak_px": 22.7, - "nearest_peak_score": 0.8607585430145264, + "nearest_peak_score": 0.8607470393180847, "null_med": 0.004897, "null_p95": 0.792231, "null_pct": 1.0, "pano": "423989957171190", + "peak_in_radius": false, "seam": false, "x": 0.5291509811918936, "y": 0.5252428801194406 @@ -3553,11 +3781,12 @@ "center": 0.18202, "class": "tail", "nearest_peak_px": 18.5, - "nearest_peak_score": 0.8607585430145264, + "nearest_peak_score": 0.8607470393180847, "null_med": 0.006464, "null_p95": 0.45834, "null_pct": 1.0, "pano": "423989957171190", + "peak_in_radius": true, "seam": false, "x": 0.5474366110477303, "y": 0.5438915753113823 @@ -3569,11 +3798,12 @@ "center": 1.0, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 1.011204481124878, + "nearest_peak_score": 1.0111994743347168, "null_med": null, "null_p95": null, "null_pct": null, "pano": "424364943656028", + "peak_in_radius": true, "seam": false, "x": 0.8935546875, "y": 0.583984375 @@ -3585,11 +3815,12 @@ "center": 0.960924, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9609276056289673, + "nearest_peak_score": 0.9609200358390808, "null_med": null, "null_p95": null, "null_pct": null, "pano": "424364943656028", + "peak_in_radius": true, "seam": false, "x": 0.62890625, "y": 0.599609375 @@ -3601,11 +3832,12 @@ "center": 0.92905, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.929057776927948, + "nearest_peak_score": 0.9290398955345154, "null_med": null, "null_p95": null, "null_pct": null, "pano": "424364943656028", + "peak_in_radius": true, "seam": false, "x": 0.32421875, "y": 0.568359375 @@ -3617,11 +3849,12 @@ "center": 0.905062, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9050841927528381, + "nearest_peak_score": 0.9050771594047546, "null_med": null, "null_p95": null, "null_pct": null, "pano": "424364943656028", + "peak_in_radius": true, "seam": false, "x": 0.1435546875, "y": 0.5546875 @@ -3633,11 +3866,12 @@ "center": 0.927581, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9276226162910461, + "nearest_peak_score": 0.9276049137115479, "null_med": null, "null_p95": null, "null_pct": null, "pano": "432356313302579", + "peak_in_radius": true, "seam": false, "x": 0.62109375, "y": 0.552734375 @@ -3649,11 +3883,12 @@ "center": 0.741996, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7420302033424377, + "nearest_peak_score": 0.7420047521591187, "null_med": null, "null_p95": null, "null_pct": null, "pano": "432356313302579", + "peak_in_radius": true, "seam": false, "x": 0.26171875, "y": 0.5390625 @@ -3664,12 +3899,13 @@ "cell": "neither", "center": 0.05043, "class": "tail", - "nearest_peak_px": 42.8, - "nearest_peak_score": 0.7420302033424377, + "nearest_peak_px": 15.3, + "nearest_peak_score": 0.08342893421649933, "null_med": 0.003259, "null_p95": 0.130003, "null_pct": 0.965, "pano": "432356313302579", + "peak_in_radius": true, "seam": false, "x": 0.2701010039358428, "y": 0.6210100948449337 @@ -3680,12 +3916,13 @@ "cell": "challenger_only", "center": 0.026902, "class": "tail", - "nearest_peak_px": 61.4, - "nearest_peak_score": 0.7420302033424377, + "nearest_peak_px": 18.9, + "nearest_peak_score": 0.08342893421649933, "null_med": 0.003368, "null_p95": 0.024563, "null_pct": 1.0, "pano": "432356313302579", + "peak_in_radius": true, "seam": false, "x": 0.271313125147964, "y": 0.6573737312085701 @@ -3696,12 +3933,13 @@ "cell": "challenger_only", "center": 0.302204, "class": "tail", - "nearest_peak_px": 77.5, - "nearest_peak_score": 0.7420302033424377, + "nearest_peak_px": 6.0, + "nearest_peak_score": 0.35465723276138306, "null_med": 0.01, "null_p95": 0.927581, "null_pct": 0.87, "pano": "432356313302579", + "peak_in_radius": true, "seam": false, "x": 0.33737373120857006, "y": 0.5325252463600852 @@ -3713,11 +3951,12 @@ "center": 0.953798, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9538203477859497, + "nearest_peak_score": 0.9537891149520874, "null_med": null, "null_p95": null, "null_pct": null, "pano": "433987753066526", + "peak_in_radius": true, "seam": false, "x": 0.64453125, "y": 0.6171875 @@ -3729,11 +3968,12 @@ "center": 0.943145, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9431686997413635, + "nearest_peak_score": 0.9431560635566711, "null_med": null, "null_p95": null, "null_pct": null, "pano": "433987753066526", + "peak_in_radius": true, "seam": false, "x": 0.5498046875, "y": 0.5390625 @@ -3745,11 +3985,12 @@ "center": 0.901868, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9018926620483398, + "nearest_peak_score": 0.9018669128417969, "null_med": null, "null_p95": null, "null_pct": null, "pano": "433987753066526", + "peak_in_radius": true, "seam": false, "x": 0.23828125, "y": 0.5703125 @@ -3761,11 +4002,12 @@ "center": 0.769861, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7698575258255005, + "nearest_peak_score": 0.7698437571525574, "null_med": null, "null_p95": null, "null_pct": null, "pano": "433987753066526", + "peak_in_radius": true, "seam": false, "x": 0.79296875, "y": 0.7265625 @@ -3777,11 +4019,12 @@ "center": 0.307144, "class": "tail", "nearest_peak_px": 13.5, - "nearest_peak_score": 0.9018926620483398, + "nearest_peak_score": 0.9018669128417969, "null_med": 0.011079, "null_p95": 0.943145, "null_pct": 0.92, "pano": "433987753066526", + "peak_in_radius": true, "seam": false, "x": 0.2419418948972789, "y": 0.5450309172089488 @@ -3792,12 +4035,13 @@ "cell": "neither", "center": 0.422349, "class": "tail", - "nearest_peak_px": 32.1, - "nearest_peak_score": 0.9431686997413635, + "nearest_peak_px": 3.5, + "nearest_peak_score": 0.4569861888885498, "null_med": 0.005618, "null_p95": 0.7758, "null_pct": 0.935, "pano": "433987753066526", + "peak_in_radius": true, "seam": false, "x": 0.5186392928059769, "y": 0.532458711270457 @@ -3809,11 +4053,12 @@ "center": 0.956546, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9565637111663818, + "nearest_peak_score": 0.956540584564209, "null_med": null, "null_p95": null, "null_pct": null, "pano": "461898606342872", + "peak_in_radius": true, "seam": false, "x": 0.91015625, "y": 0.5703125 @@ -3825,11 +4070,12 @@ "center": 0.949037, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9491065144538879, + "nearest_peak_score": 0.9490841031074524, "null_med": null, "null_p95": null, "null_pct": null, "pano": "461898606342872", + "peak_in_radius": true, "seam": false, "x": 0.96484375, "y": 0.5546875 @@ -3841,11 +4087,12 @@ "center": 0.941207, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9412210583686829, + "nearest_peak_score": 0.9412018656730652, "null_med": null, "null_p95": null, "null_pct": null, "pano": "461898606342872", + "peak_in_radius": true, "seam": false, "x": 0.5576171875, "y": 0.5703125 @@ -3857,11 +4104,12 @@ "center": 0.8879, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8879169821739197, + "nearest_peak_score": 0.8878974318504333, "null_med": null, "null_p95": null, "null_pct": null, "pano": "461898606342872", + "peak_in_radius": true, "seam": false, "x": 0.1279296875, "y": 0.5390625 @@ -3873,11 +4121,12 @@ "center": 0.870732, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8707573413848877, + "nearest_peak_score": 0.8707470893859863, "null_med": null, "null_p95": null, "null_pct": null, "pano": "461898606342872", + "peak_in_radius": true, "seam": false, "x": 0.26953125, "y": 0.537109375 @@ -3889,11 +4138,12 @@ "center": 0.678699, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.6787121891975403, + "nearest_peak_score": 0.6786937713623047, "null_med": null, "null_p95": null, "null_pct": null, "pano": "461898606342872", + "peak_in_radius": true, "seam": false, "x": 0.3154296875, "y": 0.537109375 @@ -3904,12 +4154,13 @@ "cell": "challenger_only", "center": 0.140927, "class": "tail", - "nearest_peak_px": 171.4, - "nearest_peak_score": 0.9565637111663818, + "nearest_peak_px": 13.7, + "nearest_peak_score": 0.26626038551330566, "null_med": 0.203494, "null_p95": 0.956546, "null_pct": 0.52, "pano": "461898606342872", + "peak_in_radius": true, "seam": false, "x": 0.7428282766631156, "y": 0.5668686930338541 @@ -3921,11 +4172,12 @@ "center": 0.929726, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9297599196434021, + "nearest_peak_score": 0.9297019839286804, "null_med": null, "null_p95": null, "null_pct": null, "pano": "514363767744061", + "peak_in_radius": true, "seam": false, "x": 0.1201171875, "y": 0.5390625 @@ -3937,11 +4189,12 @@ "center": 0.927487, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9274894595146179, + "nearest_peak_score": 0.927476704120636, "null_med": null, "null_p95": null, "null_pct": null, "pano": "514363767744061", + "peak_in_radius": true, "seam": false, "x": 0.9248046875, "y": 0.5546875 @@ -3953,11 +4206,12 @@ "center": 0.668966, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.6689717769622803, + "nearest_peak_score": 0.6689603924751282, "null_med": null, "null_p95": null, "null_pct": null, "pano": "514363767744061", + "peak_in_radius": true, "seam": false, "x": 0.5576171875, "y": 0.5234375 @@ -3969,11 +4223,12 @@ "center": 0.915187, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9151908159255981, + "nearest_peak_score": 0.9151651263237, "null_med": null, "null_p95": null, "null_pct": null, "pano": "522346373509256", + "peak_in_radius": true, "seam": false, "x": 0.6513671875, "y": 0.583984375 @@ -3985,11 +4240,12 @@ "center": 0.846816, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8468331098556519, + "nearest_peak_score": 0.8468133807182312, "null_med": null, "null_p95": null, "null_pct": null, "pano": "522346373509256", + "peak_in_radius": true, "seam": false, "x": 0.91796875, "y": 0.5390625 @@ -4001,11 +4257,12 @@ "center": 0.83454, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8345710635185242, + "nearest_peak_score": 0.8345542550086975, "null_med": null, "null_p95": null, "null_pct": null, "pano": "522346373509256", + "peak_in_radius": true, "seam": false, "x": 0.33203125, "y": 0.5546875 @@ -4017,11 +4274,12 @@ "center": 0.776125, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7761362791061401, + "nearest_peak_score": 0.776122510433197, "null_med": null, "null_p95": null, "null_pct": null, "pano": "552315380916113", + "peak_in_radius": true, "seam": false, "x": 0.40234375, "y": 0.552734375 @@ -4032,12 +4290,13 @@ "cell": "challenger_only", "center": 0.127528, "class": "tail", - "nearest_peak_px": 118.2, - "nearest_peak_score": 0.7761362791061401, + "nearest_peak_px": 32.2, + "nearest_peak_score": 0.35814863443374634, "null_med": 0.000963, "null_p95": 0.639182, "null_pct": 0.915, "pano": "552315380916113", + "peak_in_radius": false, "seam": false, "x": 0.5164770785435311, "y": 0.517956004077946 @@ -4049,11 +4308,12 @@ "center": 0.8889, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8888956308364868, + "nearest_peak_score": 0.8888728618621826, "null_med": null, "null_p95": null, "null_pct": null, "pano": "559372759847379", + "peak_in_radius": true, "seam": false, "x": 0.2060546875, "y": 0.5859375 @@ -4065,11 +4325,12 @@ "center": 0.558839, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.5588424205780029, + "nearest_peak_score": 0.5588347911834717, "null_med": null, "null_p95": null, "null_pct": null, "pano": "563961506051153", + "peak_in_radius": true, "seam": false, "x": 0.53515625, "y": 0.5234375 @@ -4081,11 +4342,12 @@ "center": 0.763808, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7638235092163086, + "nearest_peak_score": 0.7638033032417297, "null_med": null, "null_p95": null, "null_pct": null, "pano": "591584463734236", + "peak_in_radius": true, "seam": false, "x": 0.09765625, "y": 0.5390625 @@ -4097,11 +4359,12 @@ "center": 0.990258, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9902909994125366, + "nearest_peak_score": 0.9902709126472473, "null_med": null, "null_p95": null, "null_pct": null, "pano": "593421160518191", + "peak_in_radius": true, "seam": false, "x": 0.23046875, "y": 0.6015625 @@ -4113,11 +4376,12 @@ "center": 0.915084, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9150998592376709, + "nearest_peak_score": 0.9151037931442261, "null_med": null, "null_p95": null, "null_pct": null, "pano": "593421160518191", + "peak_in_radius": true, "seam": false, "x": 0.11328125, "y": 0.5546875 @@ -4129,11 +4393,12 @@ "center": 0.908996, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9090192317962646, + "nearest_peak_score": 0.9090004563331604, "null_med": null, "null_p95": null, "null_pct": null, "pano": "593421160518191", + "peak_in_radius": true, "seam": false, "x": 0.9560546875, "y": 0.5390625 @@ -4145,11 +4410,12 @@ "center": 0.89842, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.898432195186615, + "nearest_peak_score": 0.8984121680259705, "null_med": null, "null_p95": null, "null_pct": null, "pano": "593421160518191", + "peak_in_radius": true, "seam": false, "x": 0.44921875, "y": 0.6171875 @@ -4161,11 +4427,12 @@ "center": 0.891586, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8915951251983643, + "nearest_peak_score": 0.8915766477584839, "null_med": null, "null_p95": null, "null_pct": null, "pano": "593421160518191", + "peak_in_radius": true, "seam": false, "x": 0.07421875, "y": 0.552734375 @@ -4177,11 +4444,12 @@ "center": 0.830302, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8303124904632568, + "nearest_peak_score": 0.8302949070930481, "null_med": null, "null_p95": null, "null_pct": null, "pano": "593421160518191", + "peak_in_radius": true, "seam": false, "x": 0.63671875, "y": 0.5390625 @@ -4192,12 +4460,13 @@ "cell": "challenger_only", "center": 0.163392, "class": "tail", - "nearest_peak_px": 47.9, - "nearest_peak_score": 0.898432195186615, + "nearest_peak_px": 6.5, + "nearest_peak_score": 0.16634616255760193, "null_med": 0.182783, "null_p95": 0.990258, "null_pct": 0.485, "pano": "593421160518191", + "peak_in_radius": true, "seam": false, "x": 0.4114586336281223, "y": 0.5620670533370702 @@ -4208,12 +4477,13 @@ "cell": "challenger_only", "center": 0.009512, "class": "faint_local", - "nearest_peak_px": 137.2, - "nearest_peak_score": 0.8303124904632568, + "nearest_peak_px": 70.4, + "nearest_peak_score": 0.33857864141464233, "null_med": 0.093093, "null_p95": 0.915084, "null_pct": 0.12, "pano": "593421160518191", + "peak_in_radius": false, "seam": false, "x": 0.7702458544241675, "y": 0.5173858634506956 @@ -4224,12 +4494,13 @@ "cell": "challenger_only", "center": 0.306003, "class": "tail", - "nearest_peak_px": 118.3, - "nearest_peak_score": 0.9090192317962646, + "nearest_peak_px": 3.1, + "nearest_peak_score": 0.33857864141464233, "null_med": 0.057044, "null_p95": 0.893013, "null_pct": 0.705, "pano": "593421160518191", + "peak_in_radius": true, "seam": false, "x": 0.8414141845703125, "y": 0.5112121397076231 @@ -4241,11 +4512,12 @@ "center": 0.980652, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9806796312332153, + "nearest_peak_score": 0.980664849281311, "null_med": null, "null_p95": null, "null_pct": null, "pano": "639645829096010", + "peak_in_radius": true, "seam": false, "x": 0.69921875, "y": 0.6015625 @@ -4257,11 +4529,12 @@ "center": 0.940881, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9408648014068604, + "nearest_peak_score": 0.9408555030822754, "null_med": null, "null_p95": null, "null_pct": null, "pano": "639645829096010", + "peak_in_radius": true, "seam": false, "x": 0.75390625, "y": 0.599609375 @@ -4273,11 +4546,12 @@ "center": 0.833894, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8338943719863892, + "nearest_peak_score": 0.8338901996612549, "null_med": null, "null_p95": null, "null_pct": null, "pano": "639645829096010", + "peak_in_radius": true, "seam": false, "x": 0.04296875, "y": 0.552734375 @@ -4289,11 +4563,12 @@ "center": 0.828106, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8281292915344238, + "nearest_peak_score": 0.8281025290489197, "null_med": null, "null_p95": null, "null_pct": null, "pano": "639645829096010", + "peak_in_radius": true, "seam": false, "x": 0.1044921875, "y": 0.5390625 @@ -4304,12 +4579,13 @@ "cell": "challenger_only", "center": 0.023782, "class": "faint_local", - "nearest_peak_px": 133.7, - "nearest_peak_score": 0.8281292915344238, + "nearest_peak_px": 42.5, + "nearest_peak_score": 0.14262360334396362, "null_med": 0.091109, "null_p95": 0.833894, "null_pct": 0.465, "pano": "639645829096010", + "peak_in_radius": false, "seam": false, "x": 0.23492423780036692, "y": 0.5502974155481681 @@ -4321,11 +4597,12 @@ "center": 0.834619, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8346372842788696, + "nearest_peak_score": 0.8346166610717773, "null_med": null, "null_p95": null, "null_pct": null, "pano": "662385816800591", + "peak_in_radius": true, "seam": false, "x": 0.40234375, "y": 0.5234375 @@ -4337,11 +4614,12 @@ "center": 0.604542, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.6045513153076172, + "nearest_peak_score": 0.6045317649841309, "null_med": null, "null_p95": null, "null_pct": null, "pano": "662385816800591", + "peak_in_radius": true, "seam": false, "x": 0.5576171875, "y": 0.5390625 @@ -4353,11 +4631,12 @@ "center": 0.008665, "class": "tail", "nearest_peak_px": 44.1, - "nearest_peak_score": 0.8346372842788696, + "nearest_peak_score": 0.8346166610717773, "null_med": 0.008319, "null_p95": 0.604542, "null_pct": 0.825, "pano": "662385816800591", + "peak_in_radius": false, "seam": false, "x": 0.44464645848129736, "y": 0.5070707009055397 @@ -4369,11 +4648,12 @@ "center": 0.219653, "class": "tail", "nearest_peak_px": 36.0, - "nearest_peak_score": 0.6045513153076172, + "nearest_peak_score": 0.6045317649841309, "null_med": 0.011196, "null_p95": 0.631353, "null_pct": 0.935, "pano": "662385816800591", + "peak_in_radius": false, "seam": false, "x": 0.5236363821318656, "y": 0.5209091094045928 @@ -4385,11 +4665,12 @@ "center": 0.682507, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.6825149059295654, + "nearest_peak_score": 0.6825098991394043, "null_med": null, "null_p95": null, "null_pct": null, "pano": "681333794968062", + "peak_in_radius": true, "seam": false, "x": 0.7060546875, "y": 0.537109375 @@ -4400,12 +4681,13 @@ "cell": "challenger_only", "center": 0.040765, "class": "tail", - "nearest_peak_px": 108.4, - "nearest_peak_score": 0.6825149059295654, + "nearest_peak_px": 19.0, + "nearest_peak_score": 0.06853001564741135, "null_med": 0.007319, "null_p95": 0.682507, "null_pct": 0.895, "pano": "681333794968062", + "peak_in_radius": true, "seam": false, "x": 0.6004040342388731, "y": 0.5500000184955018 @@ -4416,12 +4698,13 @@ "cell": "challenger_only", "center": 0.455115, "class": "tail", - "nearest_peak_px": 165.7, - "nearest_peak_score": 0.621621310710907, + "nearest_peak_px": 7.1, + "nearest_peak_score": 0.4787115454673767, "null_med": 0.004715, "null_p95": 0.600249, "null_pct": 0.935, "pano": "700668799338315", + "peak_in_radius": true, "seam": false, "x": 0.5558273567679088, "y": 0.5642667296707485 @@ -4433,11 +4716,12 @@ "center": 0.983572, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9836001396179199, + "nearest_peak_score": 0.9835737347602844, "null_med": null, "null_p95": null, "null_pct": null, "pano": "723487737079243", + "peak_in_radius": true, "seam": false, "x": 0.23046875, "y": 0.5546875 @@ -4449,11 +4733,12 @@ "center": 0.944982, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9450165629386902, + "nearest_peak_score": 0.9449897408485413, "null_med": null, "null_p95": null, "null_pct": null, "pano": "723487737079243", + "peak_in_radius": true, "seam": false, "x": 0.12109375, "y": 0.5234375 @@ -4465,11 +4750,12 @@ "center": 0.884595, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8846012353897095, + "nearest_peak_score": 0.8845933079719543, "null_med": null, "null_p95": null, "null_pct": null, "pano": "723487737079243", + "peak_in_radius": true, "seam": false, "x": 0.88671875, "y": 0.6328125 @@ -4481,11 +4767,12 @@ "center": 0.779342, "class": "tail", "nearest_peak_px": 117.4, - "nearest_peak_score": 0.9450165629386902, + "nearest_peak_score": 0.9449897408485413, "null_med": 0.012038, "null_p95": 0.944982, "null_pct": 0.975, "pano": "723487737079243", + "peak_in_radius": false, "seam": true, "x": 0.006868693033854166, "y": 0.5435353966915246 @@ -4497,11 +4784,12 @@ "center": 0.869796, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8698008060455322, + "nearest_peak_score": 0.8697847127914429, "null_med": null, "null_p95": null, "null_pct": null, "pano": "780391337668333", + "peak_in_radius": true, "seam": false, "x": 0.08203125, "y": 0.583984375 @@ -4513,11 +4801,12 @@ "center": 0.737678, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7376946806907654, + "nearest_peak_score": 0.7376779317855835, "null_med": null, "null_p95": null, "null_pct": null, "pano": "780391337668333", + "peak_in_radius": true, "seam": false, "x": 0.90234375, "y": 0.5390625 @@ -4528,12 +4817,13 @@ "cell": "challenger_only", "center": 0.097303, "class": "tail", - "nearest_peak_px": 61.6, - "nearest_peak_score": 0.7376946806907654, + "nearest_peak_px": 7.0, + "nearest_peak_score": 0.15252767503261566, "null_med": 0.001456, "null_p95": 0.737678, "null_pct": 0.845, "pano": "780391337668333", + "peak_in_radius": true, "seam": false, "x": 0.9624242609197443, "y": 0.5322222345525568 @@ -4545,11 +4835,12 @@ "center": 0.840681, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8406943082809448, + "nearest_peak_score": 0.8406736254692078, "null_med": null, "null_p95": null, "null_pct": null, "pano": "822353906794602", + "peak_in_radius": true, "seam": false, "x": 0.45703125, "y": 0.521484375 @@ -4561,11 +4852,12 @@ "center": 0.790651, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7906746864318848, + "nearest_peak_score": 0.7906543016433716, "null_med": null, "null_p95": null, "null_pct": null, "pano": "839655921736413", + "peak_in_radius": true, "seam": false, "x": 0.73828125, "y": 0.568359375 @@ -4576,12 +4868,13 @@ "cell": "challenger_only", "center": 0.408036, "class": "tail", - "nearest_peak_px": 104.9, - "nearest_peak_score": 0.7906746864318848, + "nearest_peak_px": 2.3, + "nearest_peak_score": 0.4212449789047241, "null_med": 0.000473, "null_p95": 0.787073, "null_pct": 0.945, "pano": "839655921736413", + "peak_in_radius": true, "seam": false, "x": 0.8406462580343929, "y": 0.5744880586392555 @@ -4593,11 +4886,12 @@ "center": 0.58873, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.5887415409088135, + "nearest_peak_score": 0.588718831539154, "null_med": null, "null_p95": null, "null_pct": null, "pano": "843075271274817", + "peak_in_radius": true, "seam": false, "x": 0.33984375, "y": 0.5390625 @@ -4609,11 +4903,12 @@ "center": 0.852076, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8520925641059875, + "nearest_peak_score": 0.8520784974098206, "null_med": null, "null_p95": null, "null_pct": null, "pano": "8726984263984099", + "peak_in_radius": true, "seam": false, "x": 0.87109375, "y": 0.5546875 @@ -4625,11 +4920,12 @@ "center": 0.93903, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9390338659286499, + "nearest_peak_score": 0.939026951789856, "null_med": null, "null_p95": null, "null_pct": null, "pano": "872856994942214", + "peak_in_radius": true, "seam": false, "x": 0.24609375, "y": 0.537109375 @@ -4641,11 +4937,12 @@ "center": 0.931913, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9319180250167847, + "nearest_peak_score": 0.9319252967834473, "null_med": null, "null_p95": null, "null_pct": null, "pano": "872856994942214", + "peak_in_radius": true, "seam": false, "x": 0.8466796875, "y": 0.568359375 @@ -4657,11 +4954,12 @@ "center": 0.928921, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9289493560791016, + "nearest_peak_score": 0.9289323091506958, "null_med": null, "null_p95": null, "null_pct": null, "pano": "872856994942214", + "peak_in_radius": true, "seam": false, "x": 0.65234375, "y": 0.599609375 @@ -4673,11 +4971,12 @@ "center": 0.918721, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9187254905700684, + "nearest_peak_score": 0.9186991453170776, "null_med": null, "null_p95": null, "null_pct": null, "pano": "872856994942214", + "peak_in_radius": true, "seam": false, "x": 0.71484375, "y": 0.583984375 @@ -4689,11 +4988,12 @@ "center": 0.804447, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8044468760490417, + "nearest_peak_score": 0.8044247627258301, "null_med": null, "null_p95": null, "null_pct": null, "pano": "872856994942214", + "peak_in_radius": true, "seam": false, "x": 0.19140625, "y": 0.5390625 @@ -4705,11 +5005,12 @@ "center": 0.920193, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9202104806900024, + "nearest_peak_score": 0.9201868176460266, "null_med": null, "null_p95": null, "null_pct": null, "pano": "893023542323690", + "peak_in_radius": true, "seam": false, "x": 0.6044921875, "y": 0.599609375 @@ -4721,11 +5022,12 @@ "center": 0.899801, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8998149633407593, + "nearest_peak_score": 0.8997887372970581, "null_med": null, "null_p95": null, "null_pct": null, "pano": "893023542323690", + "peak_in_radius": true, "seam": false, "x": 0.55078125, "y": 0.552734375 @@ -4737,11 +5039,12 @@ "center": 0.920857, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.920896053314209, + "nearest_peak_score": 0.9208822250366211, "null_med": null, "null_p95": null, "null_pct": null, "pano": "911337534530260", + "peak_in_radius": true, "seam": false, "x": 0.6123046875, "y": 0.6015625 @@ -4753,11 +5056,12 @@ "center": 0.856427, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8564420342445374, + "nearest_peak_score": 0.8564238548278809, "null_med": null, "null_p95": null, "null_pct": null, "pano": "911337534530260", + "peak_in_radius": true, "seam": false, "x": 0.91015625, "y": 0.583984375 @@ -4769,11 +5073,12 @@ "center": 0.808182, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8081934452056885, + "nearest_peak_score": 0.8081760406494141, "null_med": null, "null_p95": null, "null_pct": null, "pano": "911337534530260", + "peak_in_radius": true, "seam": false, "x": 0.2763671875, "y": 0.5234375 @@ -4785,11 +5090,12 @@ "center": 0.176682, "class": "tail", "nearest_peak_px": 23.5, - "nearest_peak_score": 0.6433027982711792, + "nearest_peak_score": 0.6432969570159912, "null_med": 0.016102, "null_p95": 0.856427, "null_pct": 0.885, "pano": "911337534530260", + "peak_in_radius": false, "seam": false, "x": 0.7846464584812973, "y": 0.6185858524206913 @@ -4801,11 +5107,12 @@ "center": 1.0, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 1.0076472759246826, + "nearest_peak_score": 1.0076181888580322, "null_med": null, "null_p95": null, "null_pct": null, "pano": "925077602773417", + "peak_in_radius": true, "seam": false, "x": 0.70703125, "y": 0.599609375 @@ -4817,11 +5124,12 @@ "center": 0.895271, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8952727317810059, + "nearest_peak_score": 0.8952723145484924, "null_med": null, "null_p95": null, "null_pct": null, "pano": "925077602773417", + "peak_in_radius": true, "seam": false, "x": 0.25390625, "y": 0.5703125 @@ -4833,11 +5141,12 @@ "center": 0.706292, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.7063033580780029, + "nearest_peak_score": 0.7062855958938599, "null_med": null, "null_p95": null, "null_pct": null, "pano": "925077602773417", + "peak_in_radius": true, "seam": false, "x": 0.35546875, "y": 0.6171875 @@ -4849,11 +5158,12 @@ "center": 0.681016, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.6810370683670044, + "nearest_peak_score": 0.6810267567634583, "null_med": null, "null_p95": null, "null_pct": null, "pano": "925077602773417", + "peak_in_radius": true, "seam": false, "x": 0.7529296875, "y": 0.5703125 @@ -4865,11 +5175,12 @@ "center": 0.965541, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9655765295028687, + "nearest_peak_score": 0.9655410051345825, "null_med": null, "null_p95": null, "null_pct": null, "pano": "934739365184374", + "peak_in_radius": true, "seam": false, "x": 0.58984375, "y": 0.599609375 @@ -4881,11 +5192,12 @@ "center": 0.943558, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9435607194900513, + "nearest_peak_score": 0.9435520768165588, "null_med": null, "null_p95": null, "null_pct": null, "pano": "934739365184374", + "peak_in_radius": true, "seam": false, "x": 0.6669921875, "y": 0.599609375 @@ -4897,11 +5209,12 @@ "center": 0.927461, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9274734258651733, + "nearest_peak_score": 0.9274592399597168, "null_med": null, "null_p95": null, "null_pct": null, "pano": "934739365184374", + "peak_in_radius": true, "seam": false, "x": 0.12890625, "y": 0.5859375 @@ -4913,11 +5226,12 @@ "center": 0.922892, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.9229074716567993, + "nearest_peak_score": 0.9228776693344116, "null_med": null, "null_p95": null, "null_pct": null, "pano": "934739365184374", + "peak_in_radius": true, "seam": false, "x": 0.39453125, "y": 0.583984375 @@ -4929,11 +5243,12 @@ "center": 0.898126, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8981457948684692, + "nearest_peak_score": 0.8981223106384277, "null_med": null, "null_p95": null, "null_pct": null, "pano": "934739365184374", + "peak_in_radius": true, "seam": false, "x": 0.4326171875, "y": 0.583984375 @@ -4945,11 +5260,12 @@ "center": 0.823908, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8239241242408752, + "nearest_peak_score": 0.8239020109176636, "null_med": null, "null_p95": null, "null_pct": null, "pano": "934739365184374", + "peak_in_radius": true, "seam": false, "x": 0.9169921875, "y": 0.599609375 @@ -4961,11 +5277,12 @@ "center": 0.810013, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8100234270095825, + "nearest_peak_score": 0.8100091814994812, "null_med": null, "null_p95": null, "null_pct": null, "pano": "934739365184374", + "peak_in_radius": true, "seam": false, "x": 0.0966796875, "y": 0.583984375 @@ -4977,11 +5294,12 @@ "center": 0.8086, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8086158037185669, + "nearest_peak_score": 0.8086097240447998, "null_med": null, "null_p95": null, "null_pct": null, "pano": "934739365184374", + "peak_in_radius": true, "seam": false, "x": 0.87109375, "y": 0.599609375 @@ -4993,11 +5311,12 @@ "center": 0.899075, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8990710973739624, + "nearest_peak_score": 0.8990524411201477, "null_med": null, "null_p95": null, "null_pct": null, "pano": "996959015535106", + "peak_in_radius": true, "seam": false, "x": 0.38671875, "y": 0.5546875 @@ -5009,11 +5328,12 @@ "center": 0.877263, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.8773050904273987, + "nearest_peak_score": 0.8772670030593872, "null_med": null, "null_p95": null, "null_pct": null, "pano": "996959015535106", + "peak_in_radius": true, "seam": false, "x": 0.6044921875, "y": 0.552734375 @@ -5025,11 +5345,12 @@ "center": 0.634536, "class": "tail", "nearest_peak_px": 0.0, - "nearest_peak_score": 0.6345473527908325, + "nearest_peak_score": 0.6345356106758118, "null_med": null, "null_p95": null, "null_pct": null, "pano": "996959015535106", + "peak_in_radius": true, "seam": false, "x": 0.5498046875, "y": 0.5078125 @@ -5040,12 +5361,13 @@ "cell": "challenger_only", "center": 0.092798, "class": "tail", - "nearest_peak_px": 62.9, - "nearest_peak_score": 0.8990710973739624, + "nearest_peak_px": 4.9, + "nearest_peak_score": 0.09808053821325302, "null_med": 0.007513, "null_p95": 0.877263, "null_pct": 0.81, "pano": "996959015535106", + "peak_in_radius": true, "seam": false, "x": 0.44606062455610795, "y": 0.5233333703243371 diff --git a/scripts/analysis/complementarity.py b/scripts/analysis/complementarity.py index ab7591a1..905124c8 100644 --- a/scripts/analysis/complementarity.py +++ b/scripts/analysis/complementarity.py @@ -7,6 +7,17 @@ Read-only: RampNet's side comes from the bundle's committed detections and the challenger's from ``.model_cache``, so this never runs a model or spends anything. +**Which RampNet, though?** The committed bundle detections are the *shipped* operating +point — on richmond every one scores >= 0.5519 — while this document's own +recommendation since #54/#55 (PR #79) is **0.30**. Those are different models for this +purpose: at 0.30 RampNet finds 257 of richmond's 310 ramps instead of 238, so 19 of the +"misses" a challenger gets credit for recovering are ramps RampNet already has and the +shipped threshold is discarding. ``--rampnet-op-threshold`` re-sources RampNet's side +from the committed ``analysis_out/op_cache/.json`` floor peaks at a given +threshold, which is how you ask "what is the complementary gain at the operating point +we would actually deploy?". Default is the bundle records, so the published roster +numbers and the #35 gate's committed results are unchanged. + **The oracle-union recall is a ceiling, not a proposal.** It assumes you could keep every right call and discard every wrong one, which no combiner can do. The FP arithmetic printed at the end is the counterweight, and for a low-precision @@ -42,6 +53,7 @@ _xy, prediction_confidence) from compare import load_bundle, DetectionCache, cache_key # noqa: E402 from detectors import build_detector, parse_model_spec, PROVIDERS # noqa: E402 +from operating_point_curve import CACHE_DIR, read_cache # noqa: E402 def matched_gt(preds, gt_points, radius_sq): @@ -145,6 +157,13 @@ def main(): ap.add_argument("split", nargs="?", default="richmond", help="Benchmark split name (default richmond).") ap.add_argument("--cache-dir", default=os.path.join(REPO, ".model_cache")) + ap.add_argument("--rampnet-op-threshold", type=float, default=None, + help="Score RampNet from analysis_out/op_cache/.json floor " + "peaks at this threshold instead of the bundle's committed " + "detections. The bundle is the SHIPPED point (>=0.5519 on " + "richmond); this document recommends 0.30, and the gap " + "changes who gets credit for a recovery. Default: the bundle, " + "so published numbers are unchanged.") ap.add_argument("--radius", type=float, default=0.022) ap.add_argument("--tiling", choices=["perspective", "none"], default="perspective") ap.add_argument("--vistas-input-size", type=int, nargs=2, metavar=("H", "W"), @@ -165,6 +184,13 @@ def main(): cache = DetectionCache(args.cache_dir) radius_sq = radius_sq_for(args.radius) + floor_peaks = None + if args.rampnet_op_threshold is not None: + cached, _ = read_cache(os.path.join(CACHE_DIR, f"{args.split}.json")) + floor_peaks = {pd["pano"]: pd["preds"] for pd in cached} + print(f"rampnet re-sourced from op_cache at >= {args.rampnet_op_threshold} " + f"(bundle records are the shipped point and are NOT used)\n") + n = both = r_only = c_only = neither = 0 r_fp = c_fp = 0 panos = missing = 0 @@ -179,8 +205,12 @@ def main(): if cp is None: missing += 1 continue - rp = [(d["x_normalized"], d["y_normalized"], d["confidence"]) - for d in records[pid]["detections"]] + if floor_peaks is not None: + rp = [p for p in floor_peaks.get(pid, []) + if p[2] >= args.rampnet_op_threshold] + else: + rp = [(d["x_normalized"], d["y_normalized"], d["confidence"]) + for d in records[pid]["detections"]] mr, mc = matched_gt(rp, gt.gt_points, radius_sq), matched_gt(cp, gt.gt_points, radius_sq) for i in range(len(gt.gt_points)): r, c = i in mr, i in mc @@ -201,24 +231,26 @@ def main(): r_tp, c_tp, union = both + r_only, both + c_only, both + r_only + c_only r_miss = c_only + neither - print(f"{args.split} complementarity — rampnet vs {label} " + rn = ("rampnet" if floor_peaks is None + else f"rampnet@{args.rampnet_op_threshold:g}") + print(f"{args.split} complementarity — {rn} vs {label} " f"({panos} recall-eligible panos, {n} GT ramps" + (f"; {missing} panos missing from cache" if missing else "") + ")\n") - print(f" rampnet recall {r_tp / n:.3f} ({r_tp}/{n})") + print(f" {rn:18s} recall {r_tp / n:.3f} ({r_tp}/{n})") print(f" {label[:18]:18s} recall {c_tp / n:.3f} ({c_tp}/{n})") print(f" ORACLE-UNION recall {union / n:.3f} ({union}/{n}) " f"<- ceiling if you could keep every right call") print() print(f" found by BOTH {both:4d} ({both / n:.1%})") - print(f" rampnet ONLY {r_only:4d} ({r_only / n:.1%})") + print(f" {rn[:14]:14s} ONLY {r_only:4d} ({r_only / n:.1%})") print(f" {label[:14]:14s} ONLY {c_only:4d} ({c_only / n:.1%}) " f"<- complementary gain (rampnet-miss n challenger-hit)") print(f" found by NEITHER {neither:4d} ({neither / n:.1%}) " f"<- hard misses, no model helps") print() - print(f" Union recall lift over rampnet: +{(union - r_tp) / n:.3f} ({c_only} ramps)") + print(f" Union recall lift over {rn}: +{(union - r_tp) / n:.3f} ({c_only} ramps)") if r_miss: - print(f" Of rampnet's {r_miss} misses, {label} recovers {c_only} " + print(f" Of {rn}'s {r_miss} misses, {label} recovers {c_only} " f"({c_only / r_miss:.0%}); {neither} nobody finds") mean_null, max_null = complementary_null(shift_rows, radius_sq) exp = mean_null * r_miss @@ -236,12 +268,12 @@ def main(): r_p = r_tp / (r_tp + r_fp) if r_tp + r_fp else 0.0 r_f1 = 2 * r_p * (r_tp / n) / (r_p + r_tp / n) if r_p + r_tp / n else 0.0 print() - print(f" FP cost on these panos: rampnet {r_fp} | {label} {c_fp}" + print(f" FP cost on these panos: {rn} {r_fp} | {label} {c_fp}" f" (a naive union pays ~both)") - print(f" rampnet alone: P {r_p:.3f} R {r_tp / n:.3f} F1 {r_f1:.3f}") + print(f" {rn} alone: P {r_p:.3f} R {r_tp / n:.3f} F1 {r_f1:.3f}") print(f" NAIVE UNION: P {u_p:.3f} R {u_r:.3f} F1 {u_f1:.3f}" f" <- precision is a lower bound (no FP dedup)") - print(f" => a naive union {'BEATS' if u_f1 > r_f1 else 'LOSES TO'} rampnet alone " + print(f" => a naive union {'BEATS' if u_f1 > r_f1 else 'LOSES TO'} {rn} alone " f"on F1 ({u_f1:.3f} vs {r_f1:.3f})") From 4c192ca45a325a1768c88df8a28b1a7ce875a465 Mon Sep 17 00:00:00 2001 From: Jon Froehlich Date: Tue, 18 Aug 2026 16:31:25 -0700 Subject: [PATCH 08/17] cascade_gate: --rampnet-op-threshold, so the gate can be read at 0.30 too (#126) same reasoning as the complementarity flag: the bundle detections are the shipped point and the recommendation is 0.30, and the cells move between them. peak_in_radius and the heatmap probe are threshold-independent, but which cell a ramp lands in is not. Co-Authored-By: Claude Opus 5 --- scripts/analysis/cascade_gate.py | 48 ++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/scripts/analysis/cascade_gate.py b/scripts/analysis/cascade_gate.py index 87c06246..f24ebc47 100644 --- a/scripts/analysis/cascade_gate.py +++ b/scripts/analysis/cascade_gate.py @@ -148,6 +148,12 @@ def main(argv=None): p.add_argument("--panos-root", default=REPO, help="Checkout holding benchmark//panos/ (a worktree will not).") p.add_argument("--cache-dir", default=os.path.join(REPO, ".model_cache")) + p.add_argument("--rampnet-op-threshold", type=float, default=None, + help="Define RampNet's hits from op_cache floor peaks at this " + "threshold instead of the bundle's shipped detections " + "(>=0.5519 on richmond). This document recommends 0.30, and " + "the cells move: 19 of the shipped point's misses are ramps " + "RampNet already has. Default: the bundle, as published.") p.add_argument("--radius", type=float, default=0.022) p.add_argument("--tiling", choices=["perspective", "none"], default="perspective") p.add_argument("--vistas-input-size", type=int, nargs=2, metavar=("H", "W"), default=None, @@ -174,6 +180,20 @@ def main(argv=None): cache = DetectionCache(args.cache_dir) radius_sq = radius_sq_for(args.radius) + # Floor peaks (>= 0.05). Used for the sub-threshold probe always, and to + # DEFINE rampnet's hits when --rampnet-op-threshold is given. + floor_peaks, floor_src = {}, "op_cache" + try: + cached, _ = read_cache(os.path.join(CACHE_DIR, f"{args.split}.json")) + for pd in cached: + floor_peaks[pd["pano"]] = pd["preds"] + except (OSError, ValueError, KeyError): + floor_src = ("MISSING (fell back to bundle records -- distances are to the " + "shipped operating point, not the 0.05 floor)") + if args.rampnet_op_threshold is not None: + sys.exit("--rampnet-op-threshold needs analysis_out/op_cache/" + f"{args.split}.json, which could not be read.") + # ---- partition every GT ramp into a complementarity cell ------------------ sites, missing = [], 0 for pid, entry in verdicts.items(): @@ -185,8 +205,12 @@ def main(argv=None): if cp is None: missing += 1 continue - rp = [(d["x_normalized"], d["y_normalized"], d["confidence"]) - for d in records[pid]["detections"]] + if args.rampnet_op_threshold is not None: + rp = [q for q in floor_peaks.get(pid, []) + if q[2] >= args.rampnet_op_threshold] + else: + rp = [(d["x_normalized"], d["y_normalized"], d["confidence"]) + for d in records[pid]["detections"]] mr = matched_gt(rp, gt.gt_points, radius_sq) mc = matched_gt(cp, gt.gt_points, radius_sq) for i, (gx, gy) in enumerate(gt.gt_points): @@ -198,18 +222,6 @@ def main(argv=None): if not sites: sys.exit("No sites -- is the challenger cached for this split/input size?") - # Floor peaks (>= 0.05) for the "did the model say anything sub-threshold here?" - # question. See the docstring: the bundle records are the SHIPPED operating point - # and would answer a different question. - floor_peaks, floor_src = {}, "op_cache" - try: - cached, _ = read_cache(os.path.join(CACHE_DIR, f"{args.split}.json")) - for pd in cached: - floor_peaks[pd["pano"]] = pd["preds"] - except (OSError, ValueError, KeyError): - floor_src = "MISSING (fell back to bundle records -- distances are to the "\ - "shipped operating point, not the 0.05 floor)" - by_pano = {} for s in sites: by_pano.setdefault(s["pano"], []).append(s) @@ -218,7 +230,9 @@ def main(argv=None): panos = panos[:args.limit] counts = {c: sum(1 for s in sites if s["cell"] == c) for c in CELLS} - print(f"=== Cascade gate: rampnet heatmap at {label}'s recoveries " + rn = ("rampnet" if args.rampnet_op_threshold is None + else f"rampnet@{args.rampnet_op_threshold:g}") + print(f"=== Cascade gate: {rn} heatmap at {label}'s recoveries " f"({args.split}, {len(sites)} GT ramps in {len(by_pano)} panos) ===") print(" cells: " + " ".join(f"{c}={counts[c]}" for c in CELLS), flush=True) @@ -227,6 +241,9 @@ def main(argv=None): print(f" device={device} model=projectsidewalk/rampnet-model " f"(single-pass fp32, as op_cache)", flush=True) print(f" floor peaks (>=0.05) from: {floor_src}", flush=True) + print(f" rampnet hits defined by: " + + ("bundle records (shipped point)" if args.rampnet_op_threshold is None + else f"op_cache >= {args.rampnet_op_threshold:g}"), flush=True) rng = random.Random(NULL_SEED) rows, skipped = [], 0 @@ -300,6 +317,7 @@ def main(argv=None): if args.json_out: payload = {"split": args.split, "challenger": label, + "rampnet_op_threshold": args.rampnet_op_threshold, "vistas_input_size": args.vistas_input_size, "radius": args.radius, "null_trials": NULL_TRIALS, "null_seed": NULL_SEED, "n_sites": len(rows), From 730baffaa243b4e907ef63238d6cf64ff228d928 Mon Sep 17 00:00:00 2001 From: Jon Froehlich Date: Tue, 18 Aug 2026 16:37:33 -0700 Subject: [PATCH 09/17] Cascade gate: live, but the ceiling is ~19 ramps -- and a third of the gain was ours (#126) Two findings, one of which corrects my own headline from earlier in this PR. 1. THE OPERATING-POINT CORRECTION. The complementarity read scored RampNet from the committed bundle detections, which are the SHIPPED point (>=0.5519 on richmond), while this document has recommended 0.30 since #54/#55 (PR #79). Verified op_cache is the same source before re-basing: filtered at 0.5519 it reproduces the published row exactly (238/9/72). At 0.30 it gives 257/28/53, P 0.9018 R 0.8290 F1 0.8639, matching committed corrected_at_0.3.csv. Re-based, the challenger recovers 38 of 53 misses, ~30 after the null -- not 54 of 72 / ~44. About 14 of the ramps it got credit for are ramps RampNet already has at the point we recommend. The recovery RATE barely moves (75% -> 72%), which is the honest read: there are simply fewer misses to find. 2. THE CASCADE CEILING. Of the 38 genuinely-complementary ramps at 0.30: 19 floor peak in radius at 0.05-0.30 -> promotable, the real target 4 floor peak >=0.30 but unmatched -> greedy matcher gave it to an adjacent GT; a matcher/sigma problem (#130), not a threshold one 15 no floor peak at all -> nothing to promote; act 0.215 is unpeaked mass So the cascade is LIVE with a ceiling of ~19 ramps, +6.1 recall points (0.829 -> 0.890), before an unmeasured FP cost. A long way below the 54 the raw complementarity suggested. Also a negative worth keeping: RampNet activation does NOT discriminate. challenger_only sits at null percentile 0.88 and the hard core at 0.925 -- the ramps nobody finds look stronger on raw heatmap mass. There is no self-gating shortcut that skips the second model. Co-Authored-By: Claude Opus 5 --- .gitignore | 1 + analysis_out/cascade_gate_op030.json | 5383 ++++++++++++++++++++++++++ docs/model_comparison.md | 71 + 3 files changed, 5455 insertions(+) create mode 100644 analysis_out/cascade_gate_op030.json diff --git a/.gitignore b/.gitignore index 26a53f29..d8e4814f 100644 --- a/.gitignore +++ b/.gitignore @@ -92,6 +92,7 @@ analysis_out/op/* !analysis_out/silent_activation.json # The #126 cascade go/no-go: rampnet's heatmap at the ramps a challenger recovers. !analysis_out/cascade_gate.json +!analysis_out/cascade_gate_op030.json # Generated tagging pages live next to their (committed) galleries; regenerate with # scripts/analysis/make_tagger.py rather than tracking a build artifact. diff --git a/analysis_out/cascade_gate_op030.json b/analysis_out/cascade_gate_op030.json new file mode 100644 index 00000000..1a5be6f5 --- /dev/null +++ b/analysis_out/cascade_gate_op030.json @@ -0,0 +1,5383 @@ +{ + "cells": [ + { + "act_median": 0.8819, + "argmax_off_px_median": 0.0, + "cell": "both", + "center_median": 0.8819, + "class_share": { + "absent": 0.0, + "faint_local": 0.0, + "tail": 1.0 + }, + "classes": { + "absent": 0, + "faint_local": 0, + "tail": 236 + }, + "n": 236, + "nearest_peak_px_median": 0.0, + "peak_in_radius": 236, + "peak_in_radius_score_median": 0.8819, + "peak_in_radius_share": 1.0, + "seam": 5 + }, + { + "act_median": 0.8407, + "argmax_off_px_median": 0.0, + "cell": "rampnet_only", + "center_median": 0.8086, + "class_share": { + "absent": 0.0, + "faint_local": 0.0, + "tail": 1.0 + }, + "classes": { + "absent": 0, + "faint_local": 0, + "tail": 21 + }, + "n": 21, + "nearest_peak_px_median": 0.0, + "peak_in_radius": 21, + "peak_in_radius_score_median": 0.8086, + "peak_in_radius_share": 1.0, + "seam": 0 + }, + { + "above_null_p95": 9, + "act_median": 0.2152, + "argmax_off_px_median": 19.0, + "cell": "challenger_only", + "center_median": 0.0973, + "class_share": { + "absent": 0.0, + "faint_local": 0.079, + "tail": 0.921 + }, + "classes": { + "absent": 0, + "faint_local": 3, + "tail": 35 + }, + "n": 38, + "nearest_peak_px_median": 20.7, + "null_med_median": 0.0087, + "null_pct_median": 0.88, + "peak_in_radius": 23, + "peak_in_radius_score_median": 0.2025, + "peak_in_radius_share": 0.605, + "seam": 1 + }, + { + "above_null_p95": 5, + "act_median": 0.4595, + "argmax_off_px_median": 19.2, + "cell": "neither", + "center_median": 0.1533, + "class_share": { + "absent": 0.0, + "faint_local": 0.0, + "tail": 1.0 + }, + "classes": { + "absent": 0, + "faint_local": 0, + "tail": 15 + }, + "n": 15, + "nearest_peak_px_median": 17.2, + "null_med_median": 0.0054, + "null_pct_median": 0.925, + "peak_in_radius": 11, + "peak_in_radius_score_median": 0.4595, + "peak_in_radius_share": 0.733, + "seam": 0 + } + ], + "challenger": "mask2former-vistas-curb-cut", + "n_panos": 92, + "n_sites": 310, + "null_seed": 20260731, + "null_trials": 200, + "radius": 0.022, + "rampnet_op_threshold": 0.3, + "sites": [ + { + "act": 0.913488, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.913488, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9134649634361267, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1002881108606016", + "peak_in_radius": true, + "seam": false, + "x": 0.4326171875, + "y": 0.5078125 + }, + { + "act": 0.895599, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.895599, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.89559006690979, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1002881108606016", + "peak_in_radius": true, + "seam": false, + "x": 0.7216796875, + "y": 0.583984375 + }, + { + "act": 0.618312, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.618312, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6183094382286072, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1002881108606016", + "peak_in_radius": true, + "seam": false, + "x": 0.58203125, + "y": 0.521484375 + }, + { + "act": 0.596123, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.596123, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.5961191654205322, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1023400645666420", + "peak_in_radius": true, + "seam": false, + "x": 0.53515625, + "y": 0.552734375 + }, + { + "act": 0.202505, + "argmax_off_px": 16.0, + "cell": "challenger_only", + "center": 0.10486, + "class": "tail", + "nearest_peak_px": 16.0, + "nearest_peak_score": 0.20250369608402252, + "null_med": 0.006787, + "null_p95": 0.124406, + "null_pct": 0.995, + "pano": "1023400645666420", + "peak_in_radius": true, + "seam": false, + "x": 0.7919191857540246, + "y": 0.6331313069661458 + }, + { + "act": 0.236865, + "argmax_off_px": 22.4, + "cell": "challenger_only", + "center": 0.017964, + "class": "tail", + "nearest_peak_px": 24.3, + "nearest_peak_score": 0.24167664349079132, + "null_med": 0.014093, + "null_p95": 0.367628, + "null_pct": 0.88, + "pano": "1023400645666420", + "peak_in_radius": false, + "seam": false, + "x": 0.2294949433297822, + "y": 0.5919191857540246 + }, + { + "act": 0.392091, + "argmax_off_px": 2.3, + "cell": "both", + "center": 0.371854, + "class": "tail", + "nearest_peak_px": 2.3, + "nearest_peak_score": 0.3920925259590149, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1023400645666420", + "peak_in_radius": true, + "seam": false, + "x": 0.43434342817826704, + "y": 0.5419191857540246 + }, + { + "act": 0.876577, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.876577, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8765838742256165, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1041352537628655", + "peak_in_radius": true, + "seam": false, + "x": 0.2216796875, + "y": 0.5703125 + }, + { + "act": 0.835651, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.835651, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8356412649154663, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1041352537628655", + "peak_in_radius": true, + "seam": false, + "x": 0.93359375, + "y": 0.5546875 + }, + { + "act": 0.697017, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.697017, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6970109343528748, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1041352537628655", + "peak_in_radius": true, + "seam": false, + "x": 0.78515625, + "y": 0.630859375 + }, + { + "act": 0.94323, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.94323, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9432406425476074, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1044606157061812", + "peak_in_radius": true, + "seam": false, + "x": 0.30078125, + "y": 0.5546875 + }, + { + "act": 0.895965, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.895965, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.895974338054657, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1044606157061812", + "peak_in_radius": true, + "seam": false, + "x": 0.94140625, + "y": 0.568359375 + }, + { + "act": 0.891897, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.891897, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8918793201446533, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1044606157061812", + "peak_in_radius": true, + "seam": false, + "x": 0.64453125, + "y": 0.599609375 + }, + { + "act": 0.841396, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.841396, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8413959741592407, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1044606157061812", + "peak_in_radius": true, + "seam": false, + "x": 0.1201171875, + "y": 0.552734375 + }, + { + "act": 0.909499, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.909499, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9094994068145752, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1050503583329955", + "peak_in_radius": true, + "seam": false, + "x": 0.35546875, + "y": 0.599609375 + }, + { + "act": 0.869249, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.869249, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.869255781173706, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1050503583329955", + "peak_in_radius": true, + "seam": false, + "x": 0.66015625, + "y": 0.6015625 + }, + { + "act": 0.738541, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.738541, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.738539457321167, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1050503583329955", + "peak_in_radius": true, + "seam": false, + "x": 0.42578125, + "y": 0.5390625 + }, + { + "act": 0.946644, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.946644, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9466462135314941, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1051211967136526", + "peak_in_radius": true, + "seam": false, + "x": 0.4091796875, + "y": 0.5390625 + }, + { + "act": 0.904591, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.904591, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9045884609222412, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1051211967136526", + "peak_in_radius": true, + "seam": false, + "x": 0.55859375, + "y": 0.568359375 + }, + { + "act": 0.878982, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.878982, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8789879679679871, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1051211967136526", + "peak_in_radius": true, + "seam": false, + "x": 0.26171875, + "y": 0.5859375 + }, + { + "act": 0.816361, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.816361, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8163682818412781, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1071700701728910", + "peak_in_radius": true, + "seam": false, + "x": 0.8544921875, + "y": 0.5859375 + }, + { + "act": 0.766434, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.766434, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7664359211921692, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1071700701728910", + "peak_in_radius": true, + "seam": false, + "x": 0.12109375, + "y": 0.552734375 + }, + { + "act": 0.675663, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.675663, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6756716966629028, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1071700701728910", + "peak_in_radius": true, + "seam": false, + "x": 0.95703125, + "y": 0.5390625 + }, + { + "act": 0.938291, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.938291, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9382756948471069, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1073049581231056", + "peak_in_radius": true, + "seam": true, + "x": 0.9873046875, + "y": 0.583984375 + }, + { + "act": 0.843096, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.843096, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8430953621864319, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1073049581231056", + "peak_in_radius": true, + "seam": false, + "x": 0.16796875, + "y": 0.6171875 + }, + { + "act": 0.614511, + "argmax_off_px": 11.0, + "cell": "both", + "center": 0.421524, + "class": "tail", + "nearest_peak_px": 11.0, + "nearest_peak_score": 0.6145032644271851, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1089573432664131", + "peak_in_radius": true, + "seam": false, + "x": 0.9536616099964488, + "y": 0.5459090909090908 + }, + { + "act": 0.801695, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.801695, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8017029166221619, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1092133469495462", + "peak_in_radius": true, + "seam": false, + "x": 0.5419921875, + "y": 0.537109375 + }, + { + "act": 0.800788, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.800788, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8007755875587463, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1092133469495462", + "peak_in_radius": true, + "seam": false, + "x": 0.41796875, + "y": 0.5234375 + }, + { + "act": 0.748474, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.748474, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7484796643257141, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1092133469495462", + "peak_in_radius": true, + "seam": false, + "x": 0.69921875, + "y": 0.6328125 + }, + { + "act": 0.800788, + "argmax_off_px": 15.0, + "cell": "both", + "center": 0.711291, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7112849354743958, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1092133469495462", + "peak_in_radius": true, + "seam": false, + "x": 0.4326171875, + "y": 0.5234375 + }, + { + "act": 0.646609, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.646609, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6466015577316284, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1092133469495462", + "peak_in_radius": true, + "seam": false, + "x": 0.30078125, + "y": 0.568359375 + }, + { + "act": 0.646609, + "argmax_off_px": 22.0, + "cell": "challenger_only", + "center": 0.097523, + "class": "tail", + "nearest_peak_px": 22.0, + "nearest_peak_score": 0.6466015577316284, + "null_med": 0.010383, + "null_p95": 0.64478, + "null_pct": 0.955, + "pano": "1092133469495462", + "peak_in_radius": true, + "seam": false, + "x": 0.28282827666311555, + "y": 0.5919191903779001 + }, + { + "act": 0.889245, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.889245, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8892554044723511, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1107064934776754", + "peak_in_radius": true, + "seam": false, + "x": 0.10546875, + "y": 0.5859375 + }, + { + "act": 0.880806, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.880806, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8808186054229736, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1107064934776754", + "peak_in_radius": true, + "seam": false, + "x": 0.58203125, + "y": 0.5859375 + }, + { + "act": 0.851676, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.851676, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.851691722869873, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1107064934776754", + "peak_in_radius": true, + "seam": false, + "x": 0.8857421875, + "y": 0.615234375 + }, + { + "act": 0.824314, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.824314, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8243358731269836, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1107064934776754", + "peak_in_radius": true, + "seam": false, + "x": 0.3935546875, + "y": 0.568359375 + }, + { + "act": 1.0, + "argmax_off_px": 0.0, + "cell": "both", + "center": 1.0, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 1.0071896314620972, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1108131584865233", + "peak_in_radius": true, + "seam": false, + "x": 0.8388671875, + "y": 0.568359375 + }, + { + "act": 0.961798, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.961798, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9617979526519775, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1108131584865233", + "peak_in_radius": true, + "seam": false, + "x": 0.1904296875, + "y": 0.537109375 + }, + { + "act": 0.730985, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.730985, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7309690713882446, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1110314244387816", + "peak_in_radius": true, + "seam": false, + "x": 0.79296875, + "y": 0.4921875 + }, + { + "act": 0.364537, + "argmax_off_px": 10.2, + "cell": "both", + "center": 0.277798, + "class": "tail", + "nearest_peak_px": 10.2, + "nearest_peak_score": 0.36452651023864746, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1110314244387816", + "peak_in_radius": true, + "seam": false, + "x": 0.4819725424417728, + "y": 0.5769238621475898 + }, + { + "act": 0.085844, + "argmax_off_px": 5.2, + "cell": "challenger_only", + "center": 0.080359, + "class": "tail", + "nearest_peak_px": 5.2, + "nearest_peak_score": 0.08584265410900116, + "null_med": 0.007227, + "null_p95": 0.643009, + "null_pct": 0.905, + "pano": "1110314244387816", + "peak_in_radius": true, + "seam": false, + "x": 0.6961413694097003, + "y": 0.5019622085748252 + }, + { + "act": 0.075016, + "argmax_off_px": 16.3, + "cell": "neither", + "center": 0.047331, + "class": "tail", + "nearest_peak_px": 16.3, + "nearest_peak_score": 0.07500965893268585, + "null_med": 0.011157, + "null_p95": 0.429158, + "null_pct": 0.77, + "pano": "1110314244387816", + "peak_in_radius": true, + "seam": false, + "x": 0.5260899962249893, + "y": 0.5462150503817342 + }, + { + "act": 0.997578, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.997578, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9975808262825012, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1119718896242677", + "peak_in_radius": true, + "seam": false, + "x": 0.1748046875, + "y": 0.583984375 + }, + { + "act": 0.887822, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.887822, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8878064155578613, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1119718896242677", + "peak_in_radius": true, + "seam": false, + "x": 0.82421875, + "y": 0.646484375 + }, + { + "act": 0.893696, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.893696, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8937026858329773, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1126712375884972", + "peak_in_radius": true, + "seam": false, + "x": 0.5576171875, + "y": 0.5546875 + }, + { + "act": 0.889458, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.889458, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8894655704498291, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1126712375884972", + "peak_in_radius": true, + "seam": false, + "x": 0.2294921875, + "y": 0.5546875 + }, + { + "act": 0.865858, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.865858, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8658657073974609, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1126712375884972", + "peak_in_radius": true, + "seam": false, + "x": 0.75390625, + "y": 0.630859375 + }, + { + "act": 1.0, + "argmax_off_px": 0.0, + "cell": "both", + "center": 1.0, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 1.0111336708068848, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1130501775077894", + "peak_in_radius": true, + "seam": false, + "x": 0.51953125, + "y": 0.5390625 + }, + { + "act": 0.961628, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.961628, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9616304636001587, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1130501775077894", + "peak_in_radius": true, + "seam": false, + "x": 0.96484375, + "y": 0.583984375 + }, + { + "act": 0.939102, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.939102, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9391024112701416, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1130501775077894", + "peak_in_radius": true, + "seam": false, + "x": 0.90234375, + "y": 0.5703125 + }, + { + "act": 0.925147, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.925147, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9251697063446045, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1130501775077894", + "peak_in_radius": true, + "seam": false, + "x": 0.1279296875, + "y": 0.5234375 + }, + { + "act": 0.913486, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.913486, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9134843349456787, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1130501775077894", + "peak_in_radius": true, + "seam": false, + "x": 0.43359375, + "y": 0.5234375 + }, + { + "act": 0.895101, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.895101, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8950980305671692, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1130501775077894", + "peak_in_radius": true, + "seam": false, + "x": 0.5810546875, + "y": 0.5546875 + }, + { + "act": 0.746246, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.746246, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7462441325187683, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1130501775077894", + "peak_in_radius": true, + "seam": false, + "x": 0.29296875, + "y": 0.5234375 + }, + { + "act": 0.672215, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.672215, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6722085475921631, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1130501775077894", + "peak_in_radius": true, + "seam": false, + "x": 0.16796875, + "y": 0.5234375 + }, + { + "act": 0.362796, + "argmax_off_px": 8.1, + "cell": "both", + "center": 0.305334, + "class": "tail", + "nearest_peak_px": 8.1, + "nearest_peak_score": 0.3628003001213074, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1130501775077894", + "peak_in_radius": true, + "seam": false, + "x": 0.7537373675722064, + "y": 0.6080808142459754 + }, + { + "act": 0.134065, + "argmax_off_px": 22.5, + "cell": "challenger_only", + "center": 0.014528, + "class": "tail", + "nearest_peak_px": 35.0, + "nearest_peak_score": 0.3628003001213074, + "null_med": 0.117679, + "null_p95": 0.939102, + "null_pct": 0.52, + "pano": "1130501775077894", + "peak_in_radius": false, + "seam": false, + "x": 0.7943434281782671, + "y": 0.6032323293974905 + }, + { + "act": 0.977259, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.977259, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9772588014602661, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1179500609797636", + "peak_in_radius": true, + "seam": true, + "x": 0.98046875, + "y": 0.5546875 + }, + { + "act": 0.969846, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.969846, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9698506593704224, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1179500609797636", + "peak_in_radius": true, + "seam": false, + "x": 0.58203125, + "y": 0.599609375 + }, + { + "act": 0.891798, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.891798, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8918161392211914, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1179500609797636", + "peak_in_radius": true, + "seam": false, + "x": 0.2919921875, + "y": 0.568359375 + }, + { + "act": 0.891928, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.891928, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8919258117675781, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1180673306331763", + "peak_in_radius": true, + "seam": false, + "x": 0.6591796875, + "y": 0.5859375 + }, + { + "act": 0.872, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.872, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.87200927734375, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1180673306331763", + "peak_in_radius": true, + "seam": false, + "x": 0.3154296875, + "y": 0.537109375 + }, + { + "act": 0.813617, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.813617, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8136162161827087, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1185319949364085", + "peak_in_radius": true, + "seam": false, + "x": 0.4013671875, + "y": 0.537109375 + }, + { + "act": 0.240679, + "argmax_off_px": 19.4, + "cell": "challenger_only", + "center": 0.086301, + "class": "tail", + "nearest_peak_px": 19.4, + "nearest_peak_score": 0.24068093299865723, + "null_med": 0.001617, + "null_p95": 0.722342, + "null_pct": 0.905, + "pano": "1185319949364085", + "peak_in_radius": true, + "seam": false, + "x": 0.5131313069661458, + "y": 0.5119191857540246 + }, + { + "act": 0.886741, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.886741, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8867541551589966, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1187483045673326", + "peak_in_radius": true, + "seam": false, + "x": 0.3232421875, + "y": 0.537109375 + }, + { + "act": 0.761366, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.761366, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7613849639892578, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1187483045673326", + "peak_in_radius": true, + "seam": false, + "x": 0.39453125, + "y": 0.521484375 + }, + { + "act": 0.543558, + "argmax_off_px": 6.6, + "cell": "both", + "center": 0.402944, + "class": "tail", + "nearest_peak_px": 6.6, + "nearest_peak_score": 0.5435474514961243, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1187483045673326", + "peak_in_radius": true, + "seam": false, + "x": 0.8828282766631156, + "y": 0.6088888827237215 + }, + { + "act": 0.128579, + "argmax_off_px": 4.5, + "cell": "neither", + "center": 0.125675, + "class": "tail", + "nearest_peak_px": 4.5, + "nearest_peak_score": 0.1285785734653473, + "null_med": 0.00193, + "null_p95": 0.886741, + "null_pct": 0.845, + "pano": "1187483045673326", + "peak_in_radius": true, + "seam": false, + "x": 0.9519191857540246, + "y": 0.5419191857540246 + }, + { + "act": 0.927118, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.927118, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9271089434623718, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1237376427883773", + "peak_in_radius": true, + "seam": false, + "x": 0.53515625, + "y": 0.5546875 + }, + { + "act": 0.902633, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.902633, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9026328921318054, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1237376427883773", + "peak_in_radius": true, + "seam": false, + "x": 0.4248046875, + "y": 0.552734375 + }, + { + "act": 0.902577, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.902577, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9025586843490601, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1237376427883773", + "peak_in_radius": true, + "seam": false, + "x": 0.3310546875, + "y": 0.615234375 + }, + { + "act": 0.215176, + "argmax_off_px": 14.8, + "cell": "challenger_only", + "center": 0.107466, + "class": "tail", + "nearest_peak_px": 14.8, + "nearest_peak_score": 0.21517597138881683, + "null_med": 0.001364, + "null_p95": 0.052586, + "null_pct": 1.0, + "pano": "1237376427883773", + "peak_in_radius": true, + "seam": false, + "x": 0.6525252463600852, + "y": 0.7240403978752368 + }, + { + "act": 0.20581, + "argmax_off_px": 9.2, + "cell": "neither", + "center": 0.060418, + "class": "tail", + "nearest_peak_px": 9.2, + "nearest_peak_score": 0.2058081030845642, + "null_med": 0.00619, + "null_p95": 0.856748, + "null_pct": 0.795, + "pano": "1237376427883773", + "peak_in_radius": true, + "seam": false, + "x": 0.6355555493903883, + "y": 0.6161616099964489 + }, + { + "act": 0.557275, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.557275, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.5572665333747864, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1260990361757674", + "peak_in_radius": true, + "seam": false, + "x": 0.9091796875, + "y": 0.5546875 + }, + { + "act": 0.403434, + "argmax_off_px": 2.9, + "cell": "rampnet_only", + "center": 0.378516, + "class": "tail", + "nearest_peak_px": 2.9, + "nearest_peak_score": 0.40343689918518066, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1260990361757674", + "peak_in_radius": true, + "seam": false, + "x": 0.46702477127592434, + "y": 0.5269179634248174 + }, + { + "act": 0.278159, + "argmax_off_px": 2.9, + "cell": "challenger_only", + "center": 0.253053, + "class": "tail", + "nearest_peak_px": 2.9, + "nearest_peak_score": 0.27815479040145874, + "null_med": 0.002536, + "null_p95": 0.403434, + "null_pct": 0.88, + "pano": "1260990361757674", + "peak_in_radius": true, + "seam": false, + "x": 0.5593004053574665, + "y": 0.5336089345216305 + }, + { + "act": 0.958944, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.958944, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9589390754699707, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1263975528308076", + "peak_in_radius": true, + "seam": false, + "x": 0.62109375, + "y": 0.552734375 + }, + { + "act": 0.893724, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.893724, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8937307000160217, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1263975528308076", + "peak_in_radius": true, + "seam": false, + "x": 0.9404296875, + "y": 0.552734375 + }, + { + "act": 0.888867, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.888867, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8888674378395081, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1263975528308076", + "peak_in_radius": true, + "seam": false, + "x": 0.0966796875, + "y": 0.5390625 + }, + { + "act": 0.881899, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.881899, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8819018006324768, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1263975528308076", + "peak_in_radius": true, + "seam": false, + "x": 0.3388671875, + "y": 0.5234375 + }, + { + "act": 0.523525, + "argmax_off_px": 22.4, + "cell": "challenger_only", + "center": 0.073007, + "class": "tail", + "nearest_peak_px": 33.1, + "nearest_peak_score": 0.8937307000160217, + "null_med": 0.017581, + "null_p95": 0.958944, + "null_pct": 0.755, + "pano": "1263975528308076", + "peak_in_radius": false, + "seam": false, + "x": 0.9712878880356297, + "y": 0.5335353504527698 + }, + { + "act": 0.954889, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.954889, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9548981785774231, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1273933840289887", + "peak_in_radius": true, + "seam": false, + "x": 0.28515625, + "y": 0.5859375 + }, + { + "act": 0.931501, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.931501, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9314848780632019, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1273933840289887", + "peak_in_radius": true, + "seam": false, + "x": 0.8154296875, + "y": 0.5703125 + }, + { + "act": 0.930736, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.930736, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9307392239570618, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1273933840289887", + "peak_in_radius": true, + "seam": false, + "x": 0.7841796875, + "y": 0.5859375 + }, + { + "act": 0.92701, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.92701, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9269824624061584, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1273933840289887", + "peak_in_radius": true, + "seam": false, + "x": 0.8935546875, + "y": 0.5546875 + }, + { + "act": 0.914886, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.914886, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9148976802825928, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1273933840289887", + "peak_in_radius": true, + "seam": false, + "x": 0.73828125, + "y": 0.5703125 + }, + { + "act": 0.911319, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.911319, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9113284349441528, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1273933840289887", + "peak_in_radius": true, + "seam": false, + "x": 0.09765625, + "y": 0.5546875 + }, + { + "act": 0.909138, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.909138, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9091401696205139, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1273933840289887", + "peak_in_radius": true, + "seam": false, + "x": 0.2216796875, + "y": 0.630859375 + }, + { + "act": 0.86909, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.86909, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8690751791000366, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1273933840289887", + "peak_in_radius": true, + "seam": false, + "x": 0.6123046875, + "y": 0.5390625 + }, + { + "act": 0.866255, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.866255, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8662526607513428, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1273933840289887", + "peak_in_radius": true, + "seam": false, + "x": 0.4248046875, + "y": 0.5390625 + }, + { + "act": 0.858303, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.858303, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8582978844642639, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1273933840289887", + "peak_in_radius": true, + "seam": false, + "x": 0.17578125, + "y": 0.599609375 + }, + { + "act": 0.86909, + "argmax_off_px": 19.2, + "cell": "neither", + "center": 0.250927, + "class": "tail", + "nearest_peak_px": 19.2, + "nearest_peak_score": 0.8690751791000366, + "null_med": 0.366385, + "null_p95": 0.92701, + "null_pct": 0.8, + "pano": "1273933840289887", + "peak_in_radius": true, + "seam": false, + "x": 0.5935664064174488, + "y": 0.5384636678464564 + }, + { + "act": 0.948001, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.948001, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9479978680610657, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1279553583800599", + "peak_in_radius": true, + "seam": false, + "x": 0.0810546875, + "y": 0.5546875 + }, + { + "act": 0.809171, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.809171, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8091638088226318, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1279553583800599", + "peak_in_radius": true, + "seam": false, + "x": 0.8857421875, + "y": 0.583984375 + }, + { + "act": 0.8919, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.8919, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8919243812561035, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1288163659019705", + "peak_in_radius": true, + "seam": false, + "x": 0.4404296875, + "y": 0.5390625 + }, + { + "act": 0.8919, + "argmax_off_px": 17.0, + "cell": "rampnet_only", + "center": 0.857872, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8578627705574036, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1288163659019705", + "peak_in_radius": true, + "seam": false, + "x": 0.45703125, + "y": 0.5390625 + }, + { + "act": 0.126263, + "argmax_off_px": 22.4, + "cell": "neither", + "center": 0.010458, + "class": "tail", + "nearest_peak_px": 42.9, + "nearest_peak_score": 0.5122259855270386, + "null_med": 0.002576, + "null_p95": 0.400246, + "null_pct": 0.835, + "pano": "1288163659019705", + "peak_in_radius": false, + "seam": false, + "x": 0.2791919130267519, + "y": 0.6537373675722065 + }, + { + "act": 0.512223, + "argmax_off_px": 7.6, + "cell": "rampnet_only", + "center": 0.378504, + "class": "tail", + "nearest_peak_px": 7.6, + "nearest_peak_score": 0.5122259855270386, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1288163659019705", + "peak_in_radius": true, + "seam": false, + "x": 0.32282827666311553, + "y": 0.6076767615116003 + }, + { + "act": 0.929079, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.929079, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9290652871131897, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1294684158910702", + "peak_in_radius": true, + "seam": false, + "x": 0.83984375, + "y": 0.505859375 + }, + { + "act": 0.961136, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.961136, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9611213207244873, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1294705618516185", + "peak_in_radius": true, + "seam": false, + "x": 0.58203125, + "y": 0.537109375 + }, + { + "act": 0.916376, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.916376, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9163845777511597, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1294705618516185", + "peak_in_radius": true, + "seam": false, + "x": 0.68359375, + "y": 0.599609375 + }, + { + "act": 0.96603, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.96603, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9660443067550659, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1309093164014619", + "peak_in_radius": true, + "seam": false, + "x": 0.35546875, + "y": 0.5234375 + }, + { + "act": 0.963532, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.963532, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9635457992553711, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1309093164014619", + "peak_in_radius": true, + "seam": false, + "x": 0.5576171875, + "y": 0.568359375 + }, + { + "act": 0.896823, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.896823, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8967732191085815, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1309093164014619", + "peak_in_radius": true, + "seam": false, + "x": 0.32421875, + "y": 0.5234375 + }, + { + "act": 0.890193, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.890193, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8901859521865845, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1309093164014619", + "peak_in_radius": true, + "seam": false, + "x": 0.92578125, + "y": 0.599609375 + }, + { + "act": 0.799142, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.799142, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7991349101066589, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1309093164014619", + "peak_in_radius": true, + "seam": false, + "x": 0.8701171875, + "y": 0.583984375 + }, + { + "act": 0.799142, + "argmax_off_px": 15.0, + "cell": "both", + "center": 0.768035, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.768044114112854, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1309093164014619", + "peak_in_radius": true, + "seam": false, + "x": 0.8701171875, + "y": 0.5546875 + }, + { + "act": 0.671669, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.671669, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6716797351837158, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1309093164014619", + "peak_in_radius": true, + "seam": false, + "x": 0.7919921875, + "y": 0.5390625 + }, + { + "act": 0.799142, + "argmax_off_px": 17.2, + "cell": "neither", + "center": 0.116021, + "class": "tail", + "nearest_peak_px": 17.2, + "nearest_peak_score": 0.7991349101066589, + "null_med": 0.151077, + "null_p95": 0.963532, + "null_pct": 0.85, + "pano": "1309093164014619", + "peak_in_radius": true, + "seam": false, + "x": 0.8864646402994791, + "y": 0.5765656627308239 + }, + { + "act": 0.749987, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.749987, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7499725222587585, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1315788070079167", + "peak_in_radius": true, + "seam": false, + "x": 0.5888671875, + "y": 0.5234375 + }, + { + "act": 0.265718, + "argmax_off_px": 22.1, + "cell": "challenger_only", + "center": 0.220484, + "class": "tail", + "nearest_peak_px": 3.9, + "nearest_peak_score": 0.24537207186222076, + "null_med": 0.003268, + "null_p95": 0.439927, + "null_pct": 0.925, + "pano": "1315788070079167", + "peak_in_radius": true, + "seam": false, + "x": 0.5610100948449337, + "y": 0.47313130696614586 + }, + { + "act": 0.770554, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.770554, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7705532312393188, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1315844333300588", + "peak_in_radius": true, + "seam": false, + "x": 0.1904296875, + "y": 0.5859375 + }, + { + "act": 0.89899, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.89899, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8989949822425842, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1327023138707493", + "peak_in_radius": true, + "seam": false, + "x": 0.41015625, + "y": 0.5546875 + }, + { + "act": 0.698635, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.698635, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6986407041549683, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1327023138707493", + "peak_in_radius": true, + "seam": false, + "x": 0.6201171875, + "y": 0.5703125 + }, + { + "act": 0.132289, + "argmax_off_px": 1.6, + "cell": "challenger_only", + "center": 0.129971, + "class": "tail", + "nearest_peak_px": 1.6, + "nearest_peak_score": 0.13228851556777954, + "null_med": 0.011101, + "null_p95": 0.738474, + "null_pct": 0.8, + "pano": "1327023138707493", + "peak_in_radius": true, + "seam": false, + "x": 0.5511111542672822, + "y": 0.5386869118430397 + }, + { + "act": 0.929298, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.929298, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9292899370193481, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1335429861397399", + "peak_in_radius": true, + "seam": false, + "x": 0.24609375, + "y": 0.646484375 + }, + { + "act": 0.914961, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.914961, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9149394035339355, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1335429861397399", + "peak_in_radius": true, + "seam": false, + "x": 0.9013671875, + "y": 0.5546875 + }, + { + "act": 0.896301, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.896301, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8962975144386292, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1335429861397399", + "peak_in_radius": true, + "seam": false, + "x": 0.02734375, + "y": 0.568359375 + }, + { + "act": 0.895466, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.895466, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8954881429672241, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1335429861397399", + "peak_in_radius": true, + "seam": false, + "x": 0.74609375, + "y": 0.5703125 + }, + { + "act": 0.874735, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.874735, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8747368454933167, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1338631107629110", + "peak_in_radius": true, + "seam": false, + "x": 0.5576171875, + "y": 0.5234375 + }, + { + "act": 0.745411, + "argmax_off_px": 22.4, + "cell": "challenger_only", + "center": 0.207195, + "class": "tail", + "nearest_peak_px": 29.0, + "nearest_peak_score": 0.8747368454933167, + "null_med": 0.000814, + "null_p95": 0.406619, + "null_pct": 0.985, + "pano": "1338631107629110", + "peak_in_radius": false, + "seam": false, + "x": 0.5325252463600852, + "y": 0.4973737312085701 + }, + { + "act": 0.866864, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.866864, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8668447732925415, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1408179757063785", + "peak_in_radius": true, + "seam": false, + "x": 0.3779296875, + "y": 0.630859375 + }, + { + "act": 1.0, + "argmax_off_px": 0.0, + "cell": "both", + "center": 1.0, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 1.0036526918411255, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1427673368387929", + "peak_in_radius": true, + "seam": false, + "x": 0.59765625, + "y": 0.537109375 + }, + { + "act": 0.948419, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.948419, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9484100937843323, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1427673368387929", + "peak_in_radius": true, + "seam": false, + "x": 0.4873046875, + "y": 0.5234375 + }, + { + "act": 0.863412, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.863412, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8634290099143982, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1427673368387929", + "peak_in_radius": true, + "seam": false, + "x": 0.33984375, + "y": 0.5859375 + }, + { + "act": 0.772906, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.772906, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7728797793388367, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1441274599876577", + "peak_in_radius": true, + "seam": false, + "x": 0.0654296875, + "y": 0.5390625 + }, + { + "act": 0.772906, + "argmax_off_px": 16.8, + "cell": "challenger_only", + "center": 0.231996, + "class": "tail", + "nearest_peak_px": 16.8, + "nearest_peak_score": 0.7728797793388367, + "null_med": 0.009552, + "null_p95": 0.35217, + "null_pct": 1.0, + "pano": "1441274599876577", + "peak_in_radius": true, + "seam": false, + "x": 0.05026338366770002, + "y": 0.5263919001449772 + }, + { + "act": 0.303654, + "argmax_off_px": 22.4, + "cell": "neither", + "center": 0.171911, + "class": "tail", + "nearest_peak_px": 4.3, + "nearest_peak_score": 0.18528473377227783, + "null_med": 0.009665, + "null_p95": 0.627325, + "null_pct": 0.925, + "pano": "1441274599876577", + "peak_in_radius": true, + "seam": false, + "x": 0.9440247579367571, + "y": 0.5328431364003076 + }, + { + "act": 0.757466, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.757466, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7574731707572937, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1473003156922360", + "peak_in_radius": true, + "seam": false, + "x": 0.9560546875, + "y": 0.5234375 + }, + { + "act": 0.625056, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.625056, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6250497102737427, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1473003156922360", + "peak_in_radius": true, + "seam": false, + "x": 0.0498046875, + "y": 0.521484375 + }, + { + "act": 0.851548, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.851548, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8515517711639404, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1483585545954157", + "peak_in_radius": true, + "seam": false, + "x": 0.51171875, + "y": 0.5390625 + }, + { + "act": 0.844852, + "argmax_off_px": 22.0, + "cell": "rampnet_only", + "center": 0.790555, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7905554175376892, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1483585545954157", + "peak_in_radius": true, + "seam": false, + "x": 0.53515625, + "y": 0.5390625 + }, + { + "act": 0.716116, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.716116, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7161192893981934, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1483585545954157", + "peak_in_radius": true, + "seam": false, + "x": 0.6669921875, + "y": 0.552734375 + }, + { + "act": 0.601094, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.601094, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6010903716087341, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1589004208714002", + "peak_in_radius": true, + "seam": false, + "x": 0.9716796875, + "y": 0.5390625 + }, + { + "act": 0.594131, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.594131, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.5941601395606995, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1589004208714002", + "peak_in_radius": true, + "seam": false, + "x": 0.06640625, + "y": 0.5390625 + }, + { + "act": 0.978302, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.978302, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9783031940460205, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1599497457585207", + "peak_in_radius": true, + "seam": false, + "x": 0.60546875, + "y": 0.552734375 + }, + { + "act": 0.955378, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.955378, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.955389142036438, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1599497457585207", + "peak_in_radius": true, + "seam": false, + "x": 0.7607421875, + "y": 0.6171875 + }, + { + "act": 0.91067, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.91067, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9106754064559937, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1701172050581812", + "peak_in_radius": true, + "seam": false, + "x": 0.1044921875, + "y": 0.5546875 + }, + { + "act": 0.744185, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.744185, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.744189977645874, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1701172050581812", + "peak_in_radius": true, + "seam": true, + "x": 0.9794921875, + "y": 0.568359375 + }, + { + "act": 0.652255, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.652255, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6522653698921204, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1701172050581812", + "peak_in_radius": true, + "seam": false, + "x": 0.6904296875, + "y": 0.7421875 + }, + { + "act": 0.712292, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.712292, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7122933268547058, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1739689546844035", + "peak_in_radius": true, + "seam": false, + "x": 0.13671875, + "y": 0.615234375 + }, + { + "act": 0.947448, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.947448, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9474393129348755, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1759178911495771", + "peak_in_radius": true, + "seam": false, + "x": 0.3935546875, + "y": 0.5546875 + }, + { + "act": 0.692712, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.692712, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.692719578742981, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1759178911495771", + "peak_in_radius": true, + "seam": false, + "x": 0.5498046875, + "y": 0.5703125 + }, + { + "act": 0.459476, + "argmax_off_px": 11.2, + "cell": "neither", + "center": 0.222914, + "class": "tail", + "nearest_peak_px": 11.2, + "nearest_peak_score": 0.45948725938796997, + "null_med": 0.002985, + "null_p95": 0.614296, + "null_pct": 0.935, + "pano": "1759178911495771", + "peak_in_radius": true, + "seam": false, + "x": 0.4460757821051315, + "y": 0.5233485093778587 + }, + { + "act": 0.459476, + "argmax_off_px": 2.2, + "cell": "both", + "center": 0.430928, + "class": "tail", + "nearest_peak_px": 2.2, + "nearest_peak_score": 0.45948725938796997, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1759178911495771", + "peak_in_radius": true, + "seam": false, + "x": 0.459005214757595, + "y": 0.5217732532878832 + }, + { + "act": 0.185813, + "argmax_off_px": 22.5, + "cell": "neither", + "center": 0.036292, + "class": "tail", + "nearest_peak_px": 39.5, + "nearest_peak_score": 0.692719578742981, + "null_med": 0.003468, + "null_p95": 0.622932, + "null_pct": 0.85, + "pano": "1759178911495771", + "peak_in_radius": false, + "seam": false, + "x": 0.5197303339935238, + "y": 0.5219953845879944 + }, + { + "act": 0.973626, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.973626, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9736160635948181, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1828524234403425", + "peak_in_radius": true, + "seam": false, + "x": 0.19140625, + "y": 0.615234375 + }, + { + "act": 0.857854, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.857854, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8578392267227173, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1828524234403425", + "peak_in_radius": true, + "seam": false, + "x": 0.8779296875, + "y": 0.662109375 + }, + { + "act": 0.957361, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.957361, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9573454260826111, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1847752429062443", + "peak_in_radius": true, + "seam": false, + "x": 0.31640625, + "y": 0.5390625 + }, + { + "act": 0.955378, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.955378, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.955374538898468, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1847752429062443", + "peak_in_radius": true, + "seam": false, + "x": 0.1826171875, + "y": 0.5390625 + }, + { + "act": 0.944535, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.944535, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9445435404777527, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1847752429062443", + "peak_in_radius": true, + "seam": false, + "x": 0.91015625, + "y": 0.552734375 + }, + { + "act": 0.934892, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.934892, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9348766207695007, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1847752429062443", + "peak_in_radius": true, + "seam": false, + "x": 0.38671875, + "y": 0.537109375 + }, + { + "act": 0.922957, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.922957, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9229496717453003, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1847752429062443", + "peak_in_radius": true, + "seam": false, + "x": 0.55859375, + "y": 0.552734375 + }, + { + "act": 0.921211, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.921211, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9212049245834351, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1847752429062443", + "peak_in_radius": true, + "seam": false, + "x": 0.80859375, + "y": 0.5703125 + }, + { + "act": 0.751652, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.751652, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7516688108444214, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1847752429062443", + "peak_in_radius": true, + "seam": false, + "x": 0.1044921875, + "y": 0.5390625 + }, + { + "act": 0.740659, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.740659, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7406595349311829, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1847752429062443", + "peak_in_radius": true, + "seam": false, + "x": 0.65234375, + "y": 0.5703125 + }, + { + "act": 0.762745, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.762745, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7627561688423157, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1905003193597285", + "peak_in_radius": true, + "seam": false, + "x": 0.36328125, + "y": 0.552734375 + }, + { + "act": 0.64667, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.64667, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6466679573059082, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1905003193597285", + "peak_in_radius": true, + "seam": false, + "x": 0.63671875, + "y": 0.5546875 + }, + { + "act": 0.481772, + "argmax_off_px": 6.1, + "cell": "both", + "center": 0.473058, + "class": "tail", + "nearest_peak_px": 6.1, + "nearest_peak_score": 0.4817718267440796, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1905003193597285", + "peak_in_radius": true, + "seam": false, + "x": 0.8046464584812973, + "y": 0.5749494887843276 + }, + { + "act": 0.093554, + "argmax_off_px": 21.4, + "cell": "challenger_only", + "center": 0.059961, + "class": "tail", + "nearest_peak_px": 21.4, + "nearest_peak_score": 0.09355422854423523, + "null_med": 0.019526, + "null_p95": 0.718048, + "null_pct": 0.645, + "pano": "1905003193597285", + "peak_in_radius": true, + "seam": false, + "x": 0.8658585796934185, + "y": 0.5693939578894412 + }, + { + "act": 0.093554, + "argmax_off_px": 5.9, + "cell": "challenger_only", + "center": 0.085348, + "class": "tail", + "nearest_peak_px": 5.9, + "nearest_peak_score": 0.09355422854423523, + "null_med": 0.024104, + "null_p95": 0.737122, + "null_pct": 0.61, + "pano": "1905003193597285", + "peak_in_radius": true, + "seam": false, + "x": 0.8905050936612215, + "y": 0.5596969881924716 + }, + { + "act": 0.079862, + "argmax_off_px": 21.8, + "cell": "challenger_only", + "center": 0.076573, + "class": "tail", + "nearest_peak_px": 3.6, + "nearest_peak_score": 0.07805923372507095, + "null_med": 0.024054, + "null_p95": 0.64667, + "null_pct": 0.645, + "pano": "1905003193597285", + "peak_in_radius": true, + "seam": false, + "x": 0.9204040342388731, + "y": 0.5475757760712595 + }, + { + "act": 0.901254, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.901254, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9012539386749268, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1991198475040883", + "peak_in_radius": true, + "seam": false, + "x": 0.5810546875, + "y": 0.568359375 + }, + { + "act": 0.924785, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.924785, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9247885346412659, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1991876994661275", + "peak_in_radius": true, + "seam": false, + "x": 0.2294921875, + "y": 0.568359375 + }, + { + "act": 0.539202, + "argmax_off_px": 4.0, + "cell": "both", + "center": 0.498044, + "class": "tail", + "nearest_peak_px": 4.0, + "nearest_peak_score": 0.539199948310852, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "1991876994661275", + "peak_in_radius": true, + "seam": false, + "x": 0.022222216057054923, + "y": 0.531313125147964 + }, + { + "act": 0.287739, + "argmax_off_px": 3.8, + "cell": "challenger_only", + "center": 0.264974, + "class": "tail", + "nearest_peak_px": 3.8, + "nearest_peak_score": 0.2877284288406372, + "null_med": 0.045838, + "null_p95": 0.769939, + "null_pct": 0.735, + "pano": "1991876994661275", + "peak_in_radius": true, + "seam": false, + "x": 0.1188302236550056, + "y": 0.5312825529464339 + }, + { + "act": 0.954275, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.954275, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9542726278305054, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2067733823644753", + "peak_in_radius": true, + "seam": false, + "x": 0.0966796875, + "y": 0.568359375 + }, + { + "act": 0.950191, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.950191, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.950171172618866, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2067733823644753", + "peak_in_radius": true, + "seam": false, + "x": 0.23828125, + "y": 0.599609375 + }, + { + "act": 0.928207, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.928207, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9281997680664062, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2067733823644753", + "peak_in_radius": true, + "seam": false, + "x": 0.94140625, + "y": 0.5546875 + }, + { + "act": 0.87734, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.87734, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8773458003997803, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2067733823644753", + "peak_in_radius": true, + "seam": false, + "x": 0.7841796875, + "y": 0.615234375 + }, + { + "act": 0.889261, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.889261, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8892724514007568, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2111278956050786", + "peak_in_radius": true, + "seam": false, + "x": 0.3779296875, + "y": 0.568359375 + }, + { + "act": 0.668602, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.668602, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6686080098152161, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2111278956050786", + "peak_in_radius": true, + "seam": false, + "x": 0.64453125, + "y": 0.5703125 + }, + { + "act": 0.878634, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.878634, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8786442875862122, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2141681583023863", + "peak_in_radius": true, + "seam": false, + "x": 0.49609375, + "y": 0.5546875 + }, + { + "act": 0.819354, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.819354, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8193565607070923, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2141681583023863", + "peak_in_radius": true, + "seam": false, + "x": 0.80078125, + "y": 0.6015625 + }, + { + "act": 0.69882, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.69882, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.69881272315979, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2147631415757748", + "peak_in_radius": true, + "seam": false, + "x": 0.1201171875, + "y": 0.5390625 + }, + { + "act": 0.910001, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.910001, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9100123643875122, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2184370012043145", + "peak_in_radius": true, + "seam": true, + "x": 0.9794921875, + "y": 0.5703125 + }, + { + "act": 0.906266, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.906266, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9062591791152954, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2184370012043145", + "peak_in_radius": true, + "seam": false, + "x": 0.2919921875, + "y": 0.583984375 + }, + { + "act": 0.627935, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.627935, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6279332041740417, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2184370012043145", + "peak_in_radius": true, + "seam": false, + "x": 0.1982421875, + "y": 0.537109375 + }, + { + "act": 0.979381, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.979381, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9793581366539001, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2263954690670646", + "peak_in_radius": true, + "seam": false, + "x": 0.37109375, + "y": 0.5390625 + }, + { + "act": 0.898989, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.898989, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8989763259887695, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2263954690670646", + "peak_in_radius": true, + "seam": false, + "x": 0.1748046875, + "y": 0.5390625 + }, + { + "act": 0.881651, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.881651, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8816595077514648, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2263954690670646", + "peak_in_radius": true, + "seam": false, + "x": 0.06640625, + "y": 0.537109375 + }, + { + "act": 0.788486, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.788486, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7884945273399353, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2263954690670646", + "peak_in_radius": true, + "seam": true, + "x": 0.01953125, + "y": 0.5234375 + }, + { + "act": 0.749173, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.749173, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7491685152053833, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2263954690670646", + "peak_in_radius": true, + "seam": false, + "x": 0.94140625, + "y": 0.599609375 + }, + { + "act": 0.721463, + "argmax_off_px": 22.4, + "cell": "both", + "center": 0.653083, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6530662775039673, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "2263954690670646", + "peak_in_radius": true, + "seam": false, + "x": 0.9482421875, + "y": 0.5546875 + }, + { + "act": 0.929437, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.929437, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9294414520263672, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "27724402107145083", + "peak_in_radius": true, + "seam": false, + "x": 0.56640625, + "y": 0.5390625 + }, + { + "act": 0.825894, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.825894, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8258990049362183, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "27724402107145083", + "peak_in_radius": true, + "seam": false, + "x": 0.41796875, + "y": 0.5390625 + }, + { + "act": 0.356553, + "argmax_off_px": 5.4, + "cell": "both", + "center": 0.307763, + "class": "tail", + "nearest_peak_px": 5.4, + "nearest_peak_score": 0.35654979944229126, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "27724402107145083", + "peak_in_radius": true, + "seam": false, + "x": 0.5995960027521307, + "y": 0.574242461233428 + }, + { + "act": 0.665317, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.665317, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6653231978416443, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "372149922554566", + "peak_in_radius": true, + "seam": false, + "x": 0.91015625, + "y": 0.5546875 + }, + { + "act": 0.648446, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.648446, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6484498381614685, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "372149922554566", + "peak_in_radius": true, + "seam": false, + "x": 0.0576171875, + "y": 0.552734375 + }, + { + "act": 0.210347, + "argmax_off_px": 4.9, + "cell": "challenger_only", + "center": 0.182823, + "class": "tail", + "nearest_peak_px": 4.9, + "nearest_peak_score": 0.21032880246639252, + "null_med": 0.000273, + "null_p95": 0.456761, + "null_pct": 0.935, + "pano": "372149922554566", + "peak_in_radius": true, + "seam": false, + "x": 0.9527272912227747, + "y": 0.533838426994555 + }, + { + "act": 0.607845, + "argmax_off_px": 22.2, + "cell": "challenger_only", + "center": 0.08643, + "class": "tail", + "nearest_peak_px": 26.8, + "nearest_peak_score": 0.6484498381614685, + "null_med": 0.000351, + "null_p95": 0.561605, + "null_pct": 0.955, + "pano": "372149922554566", + "peak_in_radius": false, + "seam": false, + "x": 0.03474748091264204, + "y": 0.5273737312085701 + }, + { + "act": 0.962026, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.962026, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9620198011398315, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "383880874806933", + "peak_in_radius": true, + "seam": false, + "x": 0.84765625, + "y": 0.5859375 + }, + { + "act": 0.895772, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.895772, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8957797288894653, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "383880874806933", + "peak_in_radius": true, + "seam": false, + "x": 0.94140625, + "y": 0.5546875 + }, + { + "act": 0.343733, + "argmax_off_px": 1.5, + "cell": "both", + "center": 0.337857, + "class": "tail", + "nearest_peak_px": 1.5, + "nearest_peak_score": 0.3437323570251465, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "383880874806933", + "peak_in_radius": true, + "seam": false, + "x": 0.21252524636008524, + "y": 0.5361616099964489 + }, + { + "act": 0.343733, + "argmax_off_px": 20.7, + "cell": "challenger_only", + "center": 0.142017, + "class": "tail", + "nearest_peak_px": 20.7, + "nearest_peak_score": 0.3437323570251465, + "null_med": 0.025784, + "null_p95": 0.895772, + "null_pct": 0.85, + "pano": "383880874806933", + "peak_in_radius": true, + "seam": false, + "x": 0.19393941243489585, + "y": 0.5297979736328124 + }, + { + "act": 0.858318, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.858318, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8583197593688965, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "386363531219281", + "peak_in_radius": true, + "seam": false, + "x": 0.66015625, + "y": 0.5546875 + }, + { + "act": 0.847305, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.847305, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8473037481307983, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "386363531219281", + "peak_in_radius": true, + "seam": false, + "x": 0.4482421875, + "y": 0.568359375 + }, + { + "act": 0.053441, + "argmax_off_px": 22.5, + "cell": "challenger_only", + "center": 0.044115, + "class": "tail", + "nearest_peak_px": 51.3, + "nearest_peak_score": 0.8473037481307983, + "null_med": 0.006155, + "null_p95": 0.69524, + "null_pct": 0.785, + "pano": "386363531219281", + "peak_in_radius": false, + "seam": false, + "x": 0.4905050936612216, + "y": 0.5144444876006156 + }, + { + "act": 0.059287, + "argmax_off_px": 2.8, + "cell": "challenger_only", + "center": 0.056529, + "class": "tail", + "nearest_peak_px": 2.8, + "nearest_peak_score": 0.05928492546081543, + "null_med": 0.008044, + "null_p95": 0.720775, + "null_pct": 0.835, + "pano": "386363531219281", + "peak_in_radius": true, + "seam": false, + "x": 0.5579797918146306, + "y": 0.5160606245561079 + }, + { + "act": 0.796538, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.796538, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7965390086174011, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "3901547360084831", + "peak_in_radius": true, + "seam": false, + "x": 0.2138671875, + "y": 0.5390625 + }, + { + "act": 0.890949, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.890949, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8909416794776917, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "3956582084664486", + "peak_in_radius": true, + "seam": false, + "x": 0.44140625, + "y": 0.5390625 + }, + { + "act": 0.846316, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.846316, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.846308708190918, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "3956582084664486", + "peak_in_radius": true, + "seam": false, + "x": 0.55078125, + "y": 0.552734375 + }, + { + "act": 0.828984, + "argmax_off_px": 21.7, + "cell": "neither", + "center": 0.333811, + "class": "tail", + "nearest_peak_px": 26.2, + "nearest_peak_score": 0.8909416794776917, + "null_med": 0.000376, + "null_p95": 0.653422, + "null_pct": 0.96, + "pano": "3956582084664486", + "peak_in_radius": false, + "seam": false, + "x": 0.46505054820667613, + "y": 0.5192929169625947 + }, + { + "act": 0.846316, + "argmax_off_px": 20.7, + "cell": "challenger_only", + "center": 0.077748, + "class": "tail", + "nearest_peak_px": 20.7, + "nearest_peak_score": 0.846308708190918, + "null_med": 0.00034, + "null_p95": 0.815717, + "null_pct": 0.96, + "pano": "3956582084664486", + "peak_in_radius": true, + "seam": false, + "x": 0.5402850979625293, + "y": 0.5182507727523443 + }, + { + "act": 0.410306, + "argmax_off_px": 6.4, + "cell": "both", + "center": 0.378829, + "class": "tail", + "nearest_peak_px": 6.4, + "nearest_peak_score": 0.4103164076805115, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "3980741912187626", + "peak_in_radius": true, + "seam": false, + "x": 0.3773737312085701, + "y": 0.5846464584812974 + }, + { + "act": 0.497308, + "argmax_off_px": 12.0, + "cell": "both", + "center": 0.332233, + "class": "tail", + "nearest_peak_px": 12.0, + "nearest_peak_score": 0.4973132610321045, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "3980741912187626", + "peak_in_radius": true, + "seam": false, + "x": 0.6088888827237215, + "y": 0.6064646402994792 + }, + { + "act": 0.497308, + "argmax_off_px": 20.0, + "cell": "neither", + "center": 0.153297, + "class": "tail", + "nearest_peak_px": 20.0, + "nearest_peak_score": 0.4973132610321045, + "null_med": 0.021576, + "null_p95": 0.410306, + "null_pct": 0.97, + "pano": "3980741912187626", + "peak_in_radius": true, + "seam": false, + "x": 0.6108941345557353, + "y": 0.5709128544012171 + }, + { + "act": 0.807756, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.807756, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8077345490455627, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "4102292636718018", + "peak_in_radius": true, + "seam": false, + "x": 0.32421875, + "y": 0.5390625 + }, + { + "act": 0.555799, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.555799, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.5557992458343506, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "4102292636718018", + "peak_in_radius": true, + "seam": false, + "x": 0.61328125, + "y": 0.662109375 + }, + { + "act": 0.78927, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.78927, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7892580032348633, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "4116269558691031", + "peak_in_radius": true, + "seam": false, + "x": 0.48828125, + "y": 0.6015625 + }, + { + "act": 0.507915, + "argmax_off_px": 13.9, + "cell": "both", + "center": 0.342678, + "class": "tail", + "nearest_peak_px": 13.9, + "nearest_peak_score": 0.5079110264778137, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "4116269558691031", + "peak_in_radius": true, + "seam": false, + "x": 0.4294949433297822, + "y": 0.6670707009055398 + }, + { + "act": 0.860736, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.860736, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8607470393180847, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "423989957171190", + "peak_in_radius": true, + "seam": false, + "x": 0.5341796875, + "y": 0.568359375 + }, + { + "act": 0.85772, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.85772, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8577241897583008, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "423989957171190", + "peak_in_radius": true, + "seam": false, + "x": 0.37109375, + "y": 0.5390625 + }, + { + "act": 0.037643, + "argmax_off_px": 2.1, + "cell": "challenger_only", + "center": 0.035938, + "class": "faint_local", + "nearest_peak_px": 57.4, + "nearest_peak_score": 0.8577241897583008, + "null_med": 0.005353, + "null_p95": 0.857546, + "null_pct": 0.88, + "pano": "423989957171190", + "peak_in_radius": false, + "seam": false, + "x": 0.42667711943494924, + "y": 0.5250655456146334 + }, + { + "act": 0.73131, + "argmax_off_px": 22.5, + "cell": "challenger_only", + "center": 0.112684, + "class": "tail", + "nearest_peak_px": 30.9, + "nearest_peak_score": 0.8607470393180847, + "null_med": 0.00628, + "null_p95": 0.809841, + "null_pct": 0.945, + "pano": "423989957171190", + "peak_in_radius": false, + "seam": false, + "x": 0.5133691152905883, + "y": 0.5247863607532633 + }, + { + "act": 0.860098, + "argmax_off_px": 21.7, + "cell": "neither", + "center": 0.296156, + "class": "tail", + "nearest_peak_px": 22.7, + "nearest_peak_score": 0.8607470393180847, + "null_med": 0.005091, + "null_p95": 0.719732, + "null_pct": 1.0, + "pano": "423989957171190", + "peak_in_radius": false, + "seam": false, + "x": 0.5291509811918936, + "y": 0.5252428801194406 + }, + { + "act": 0.860736, + "argmax_off_px": 18.5, + "cell": "neither", + "center": 0.18202, + "class": "tail", + "nearest_peak_px": 18.5, + "nearest_peak_score": 0.8607470393180847, + "null_med": 0.005358, + "null_p95": 0.711683, + "null_pct": 1.0, + "pano": "423989957171190", + "peak_in_radius": true, + "seam": false, + "x": 0.5474366110477303, + "y": 0.5438915753113823 + }, + { + "act": 1.0, + "argmax_off_px": 0.0, + "cell": "both", + "center": 1.0, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 1.0111994743347168, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "424364943656028", + "peak_in_radius": true, + "seam": false, + "x": 0.8935546875, + "y": 0.583984375 + }, + { + "act": 0.960924, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.960924, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9609200358390808, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "424364943656028", + "peak_in_radius": true, + "seam": false, + "x": 0.62890625, + "y": 0.599609375 + }, + { + "act": 0.92905, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.92905, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9290398955345154, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "424364943656028", + "peak_in_radius": true, + "seam": false, + "x": 0.32421875, + "y": 0.568359375 + }, + { + "act": 0.905062, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.905062, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9050771594047546, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "424364943656028", + "peak_in_radius": true, + "seam": false, + "x": 0.1435546875, + "y": 0.5546875 + }, + { + "act": 0.927581, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.927581, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9276049137115479, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "432356313302579", + "peak_in_radius": true, + "seam": false, + "x": 0.62109375, + "y": 0.552734375 + }, + { + "act": 0.741996, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.741996, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7420047521591187, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "432356313302579", + "peak_in_radius": true, + "seam": false, + "x": 0.26171875, + "y": 0.5390625 + }, + { + "act": 0.221399, + "argmax_off_px": 22.4, + "cell": "neither", + "center": 0.05043, + "class": "tail", + "nearest_peak_px": 15.3, + "nearest_peak_score": 0.08342893421649933, + "null_med": 0.002676, + "null_p95": 0.139837, + "null_pct": 0.955, + "pano": "432356313302579", + "peak_in_radius": true, + "seam": false, + "x": 0.2701010039358428, + "y": 0.6210100948449337 + }, + { + "act": 0.083431, + "argmax_off_px": 18.9, + "cell": "challenger_only", + "center": 0.026902, + "class": "tail", + "nearest_peak_px": 18.9, + "nearest_peak_score": 0.08342893421649933, + "null_med": 0.00296, + "null_p95": 0.024563, + "null_pct": 1.0, + "pano": "432356313302579", + "peak_in_radius": true, + "seam": false, + "x": 0.271313125147964, + "y": 0.6573737312085701 + }, + { + "act": 0.354652, + "argmax_off_px": 6.0, + "cell": "both", + "center": 0.302204, + "class": "tail", + "nearest_peak_px": 6.0, + "nearest_peak_score": 0.35465723276138306, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "432356313302579", + "peak_in_radius": true, + "seam": false, + "x": 0.33737373120857006, + "y": 0.5325252463600852 + }, + { + "act": 0.953798, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.953798, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9537891149520874, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "433987753066526", + "peak_in_radius": true, + "seam": false, + "x": 0.64453125, + "y": 0.6171875 + }, + { + "act": 0.943145, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.943145, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9431560635566711, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "433987753066526", + "peak_in_radius": true, + "seam": false, + "x": 0.5498046875, + "y": 0.5390625 + }, + { + "act": 0.901868, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.901868, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9018669128417969, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "433987753066526", + "peak_in_radius": true, + "seam": false, + "x": 0.23828125, + "y": 0.5703125 + }, + { + "act": 0.769861, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.769861, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7698437571525574, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "433987753066526", + "peak_in_radius": true, + "seam": false, + "x": 0.79296875, + "y": 0.7265625 + }, + { + "act": 0.901868, + "argmax_off_px": 13.5, + "cell": "neither", + "center": 0.307144, + "class": "tail", + "nearest_peak_px": 13.5, + "nearest_peak_score": 0.9018669128417969, + "null_med": 0.011079, + "null_p95": 0.941769, + "null_pct": 0.945, + "pano": "433987753066526", + "peak_in_radius": true, + "seam": false, + "x": 0.2419418948972789, + "y": 0.5450309172089488 + }, + { + "act": 0.566707, + "argmax_off_px": 22.2, + "cell": "rampnet_only", + "center": 0.422349, + "class": "tail", + "nearest_peak_px": 3.5, + "nearest_peak_score": 0.4569861888885498, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "433987753066526", + "peak_in_radius": true, + "seam": false, + "x": 0.5186392928059769, + "y": 0.532458711270457 + }, + { + "act": 0.956546, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.956546, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.956540584564209, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "461898606342872", + "peak_in_radius": true, + "seam": false, + "x": 0.91015625, + "y": 0.5703125 + }, + { + "act": 0.949037, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.949037, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9490841031074524, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "461898606342872", + "peak_in_radius": true, + "seam": false, + "x": 0.96484375, + "y": 0.5546875 + }, + { + "act": 0.941207, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.941207, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9412018656730652, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "461898606342872", + "peak_in_radius": true, + "seam": false, + "x": 0.5576171875, + "y": 0.5703125 + }, + { + "act": 0.8879, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.8879, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8878974318504333, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "461898606342872", + "peak_in_radius": true, + "seam": false, + "x": 0.1279296875, + "y": 0.5390625 + }, + { + "act": 0.870732, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.870732, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8707470893859863, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "461898606342872", + "peak_in_radius": true, + "seam": false, + "x": 0.26953125, + "y": 0.537109375 + }, + { + "act": 0.678699, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.678699, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6786937713623047, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "461898606342872", + "peak_in_radius": true, + "seam": false, + "x": 0.3154296875, + "y": 0.537109375 + }, + { + "act": 0.266242, + "argmax_off_px": 13.7, + "cell": "challenger_only", + "center": 0.140927, + "class": "tail", + "nearest_peak_px": 13.7, + "nearest_peak_score": 0.26626038551330566, + "null_med": 0.278529, + "null_p95": 0.956546, + "null_pct": 0.49, + "pano": "461898606342872", + "peak_in_radius": true, + "seam": false, + "x": 0.7428282766631156, + "y": 0.5668686930338541 + }, + { + "act": 0.929726, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.929726, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9297019839286804, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "514363767744061", + "peak_in_radius": true, + "seam": false, + "x": 0.1201171875, + "y": 0.5390625 + }, + { + "act": 0.927487, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.927487, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.927476704120636, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "514363767744061", + "peak_in_radius": true, + "seam": false, + "x": 0.9248046875, + "y": 0.5546875 + }, + { + "act": 0.668966, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.668966, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6689603924751282, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "514363767744061", + "peak_in_radius": true, + "seam": false, + "x": 0.5576171875, + "y": 0.5234375 + }, + { + "act": 0.915187, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.915187, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9151651263237, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "522346373509256", + "peak_in_radius": true, + "seam": false, + "x": 0.6513671875, + "y": 0.583984375 + }, + { + "act": 0.846816, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.846816, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8468133807182312, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "522346373509256", + "peak_in_radius": true, + "seam": false, + "x": 0.91796875, + "y": 0.5390625 + }, + { + "act": 0.83454, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.83454, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8345542550086975, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "522346373509256", + "peak_in_radius": true, + "seam": false, + "x": 0.33203125, + "y": 0.5546875 + }, + { + "act": 0.776125, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.776125, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.776122510433197, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "552315380916113", + "peak_in_radius": true, + "seam": false, + "x": 0.40234375, + "y": 0.552734375 + }, + { + "act": 0.272278, + "argmax_off_px": 22.5, + "cell": "challenger_only", + "center": 0.127528, + "class": "tail", + "nearest_peak_px": 32.2, + "nearest_peak_score": 0.35814863443374634, + "null_med": 0.001067, + "null_p95": 0.678281, + "null_pct": 0.89, + "pano": "552315380916113", + "peak_in_radius": false, + "seam": false, + "x": 0.5164770785435311, + "y": 0.517956004077946 + }, + { + "act": 0.8889, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.8889, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8888728618621826, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "559372759847379", + "peak_in_radius": true, + "seam": false, + "x": 0.2060546875, + "y": 0.5859375 + }, + { + "act": 0.558839, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.558839, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.5588347911834717, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "563961506051153", + "peak_in_radius": true, + "seam": false, + "x": 0.53515625, + "y": 0.5234375 + }, + { + "act": 0.763808, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.763808, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7638033032417297, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "591584463734236", + "peak_in_radius": true, + "seam": false, + "x": 0.09765625, + "y": 0.5390625 + }, + { + "act": 0.990258, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.990258, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9902709126472473, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "593421160518191", + "peak_in_radius": true, + "seam": false, + "x": 0.23046875, + "y": 0.6015625 + }, + { + "act": 0.915084, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.915084, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9151037931442261, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "593421160518191", + "peak_in_radius": true, + "seam": false, + "x": 0.11328125, + "y": 0.5546875 + }, + { + "act": 0.908996, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.908996, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9090004563331604, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "593421160518191", + "peak_in_radius": true, + "seam": false, + "x": 0.9560546875, + "y": 0.5390625 + }, + { + "act": 0.89842, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.89842, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8984121680259705, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "593421160518191", + "peak_in_radius": true, + "seam": false, + "x": 0.44921875, + "y": 0.6171875 + }, + { + "act": 0.891586, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.891586, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8915766477584839, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "593421160518191", + "peak_in_radius": true, + "seam": false, + "x": 0.07421875, + "y": 0.552734375 + }, + { + "act": 0.830302, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.830302, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8302949070930481, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "593421160518191", + "peak_in_radius": true, + "seam": false, + "x": 0.63671875, + "y": 0.5390625 + }, + { + "act": 0.166348, + "argmax_off_px": 6.5, + "cell": "challenger_only", + "center": 0.163392, + "class": "tail", + "nearest_peak_px": 6.5, + "nearest_peak_score": 0.16634616255760193, + "null_med": 0.182783, + "null_p95": 0.915084, + "null_pct": 0.485, + "pano": "593421160518191", + "peak_in_radius": true, + "seam": false, + "x": 0.4114586336281223, + "y": 0.5620670533370702 + }, + { + "act": 0.012545, + "argmax_off_px": 3.5, + "cell": "challenger_only", + "center": 0.009512, + "class": "faint_local", + "nearest_peak_px": 70.4, + "nearest_peak_score": 0.33857864141464233, + "null_med": 0.120356, + "null_p95": 0.908996, + "null_pct": 0.07, + "pano": "593421160518191", + "peak_in_radius": false, + "seam": false, + "x": 0.7702458544241675, + "y": 0.5173858634506956 + }, + { + "act": 0.338576, + "argmax_off_px": 3.1, + "cell": "both", + "center": 0.306003, + "class": "tail", + "nearest_peak_px": 3.1, + "nearest_peak_score": 0.33857864141464233, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "593421160518191", + "peak_in_radius": true, + "seam": false, + "x": 0.8414141845703125, + "y": 0.5112121397076231 + }, + { + "act": 0.980652, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.980652, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.980664849281311, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "639645829096010", + "peak_in_radius": true, + "seam": false, + "x": 0.69921875, + "y": 0.6015625 + }, + { + "act": 0.940881, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.940881, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9408555030822754, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "639645829096010", + "peak_in_radius": true, + "seam": false, + "x": 0.75390625, + "y": 0.599609375 + }, + { + "act": 0.833894, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.833894, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8338901996612549, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "639645829096010", + "peak_in_radius": true, + "seam": false, + "x": 0.04296875, + "y": 0.552734375 + }, + { + "act": 0.828106, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.828106, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8281025290489197, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "639645829096010", + "peak_in_radius": true, + "seam": false, + "x": 0.1044921875, + "y": 0.5390625 + }, + { + "act": 0.028439, + "argmax_off_px": 10.7, + "cell": "challenger_only", + "center": 0.023782, + "class": "faint_local", + "nearest_peak_px": 42.5, + "nearest_peak_score": 0.14262360334396362, + "null_med": 0.065379, + "null_p95": 0.847071, + "null_pct": 0.46, + "pano": "639645829096010", + "peak_in_radius": false, + "seam": false, + "x": 0.23492423780036692, + "y": 0.5502974155481681 + }, + { + "act": 0.834619, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.834619, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8346166610717773, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "662385816800591", + "peak_in_radius": true, + "seam": false, + "x": 0.40234375, + "y": 0.5234375 + }, + { + "act": 0.604542, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.604542, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6045317649841309, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "662385816800591", + "peak_in_radius": true, + "seam": false, + "x": 0.5576171875, + "y": 0.5390625 + }, + { + "act": 0.146852, + "argmax_off_px": 22.3, + "cell": "challenger_only", + "center": 0.008665, + "class": "tail", + "nearest_peak_px": 44.1, + "nearest_peak_score": 0.8346166610717773, + "null_med": 0.008725, + "null_p95": 0.673454, + "null_pct": 0.805, + "pano": "662385816800591", + "peak_in_radius": false, + "seam": false, + "x": 0.44464645848129736, + "y": 0.5070707009055397 + }, + { + "act": 0.425702, + "argmax_off_px": 22.4, + "cell": "challenger_only", + "center": 0.219653, + "class": "tail", + "nearest_peak_px": 36.0, + "nearest_peak_score": 0.6045317649841309, + "null_med": 0.010706, + "null_p95": 0.673454, + "null_pct": 0.945, + "pano": "662385816800591", + "peak_in_radius": false, + "seam": false, + "x": 0.5236363821318656, + "y": 0.5209091094045928 + }, + { + "act": 0.682507, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.682507, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6825098991394043, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "681333794968062", + "peak_in_radius": true, + "seam": false, + "x": 0.7060546875, + "y": 0.537109375 + }, + { + "act": 0.06853, + "argmax_off_px": 19.0, + "cell": "challenger_only", + "center": 0.040765, + "class": "tail", + "nearest_peak_px": 19.0, + "nearest_peak_score": 0.06853001564741135, + "null_med": 0.007561, + "null_p95": 0.682507, + "null_pct": 0.885, + "pano": "681333794968062", + "peak_in_radius": true, + "seam": false, + "x": 0.6004040342388731, + "y": 0.5500000184955018 + }, + { + "act": 0.47872, + "argmax_off_px": 7.1, + "cell": "both", + "center": 0.455115, + "class": "tail", + "nearest_peak_px": 7.1, + "nearest_peak_score": 0.4787115454673767, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "700668799338315", + "peak_in_radius": true, + "seam": false, + "x": 0.5558273567679088, + "y": 0.5642667296707485 + }, + { + "act": 0.983572, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.983572, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9835737347602844, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "723487737079243", + "peak_in_radius": true, + "seam": false, + "x": 0.23046875, + "y": 0.5546875 + }, + { + "act": 0.944982, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.944982, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9449897408485413, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "723487737079243", + "peak_in_radius": true, + "seam": false, + "x": 0.12109375, + "y": 0.5234375 + }, + { + "act": 0.884595, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.884595, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8845933079719543, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "723487737079243", + "peak_in_radius": true, + "seam": false, + "x": 0.88671875, + "y": 0.6328125 + }, + { + "act": 0.945872, + "argmax_off_px": 7.4, + "cell": "challenger_only", + "center": 0.779342, + "class": "tail", + "nearest_peak_px": 117.4, + "nearest_peak_score": 0.9449897408485413, + "null_med": 0.009236, + "null_p95": 0.944982, + "null_pct": 0.96, + "pano": "723487737079243", + "peak_in_radius": false, + "seam": true, + "x": 0.006868693033854166, + "y": 0.5435353966915246 + }, + { + "act": 0.869796, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.869796, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8697847127914429, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "780391337668333", + "peak_in_radius": true, + "seam": false, + "x": 0.08203125, + "y": 0.583984375 + }, + { + "act": 0.737678, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.737678, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7376779317855835, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "780391337668333", + "peak_in_radius": true, + "seam": false, + "x": 0.90234375, + "y": 0.5390625 + }, + { + "act": 0.152524, + "argmax_off_px": 7.0, + "cell": "challenger_only", + "center": 0.097303, + "class": "tail", + "nearest_peak_px": 7.0, + "nearest_peak_score": 0.15252767503261566, + "null_med": 0.001615, + "null_p95": 0.526786, + "null_pct": 0.895, + "pano": "780391337668333", + "peak_in_radius": true, + "seam": false, + "x": 0.9624242609197443, + "y": 0.5322222345525568 + }, + { + "act": 0.840681, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.840681, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8406736254692078, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "822353906794602", + "peak_in_radius": true, + "seam": false, + "x": 0.45703125, + "y": 0.521484375 + }, + { + "act": 0.790651, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.790651, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7906543016433716, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "839655921736413", + "peak_in_radius": true, + "seam": false, + "x": 0.73828125, + "y": 0.568359375 + }, + { + "act": 0.421252, + "argmax_off_px": 2.3, + "cell": "both", + "center": 0.408036, + "class": "tail", + "nearest_peak_px": 2.3, + "nearest_peak_score": 0.4212449789047241, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "839655921736413", + "peak_in_radius": true, + "seam": false, + "x": 0.8406462580343929, + "y": 0.5744880586392555 + }, + { + "act": 0.58873, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.58873, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.588718831539154, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "843075271274817", + "peak_in_radius": true, + "seam": false, + "x": 0.33984375, + "y": 0.5390625 + }, + { + "act": 0.852076, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.852076, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8520784974098206, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "8726984263984099", + "peak_in_radius": true, + "seam": false, + "x": 0.87109375, + "y": 0.5546875 + }, + { + "act": 0.93903, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.93903, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.939026951789856, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "872856994942214", + "peak_in_radius": true, + "seam": false, + "x": 0.24609375, + "y": 0.537109375 + }, + { + "act": 0.931913, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.931913, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9319252967834473, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "872856994942214", + "peak_in_radius": true, + "seam": false, + "x": 0.8466796875, + "y": 0.568359375 + }, + { + "act": 0.928921, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.928921, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9289323091506958, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "872856994942214", + "peak_in_radius": true, + "seam": false, + "x": 0.65234375, + "y": 0.599609375 + }, + { + "act": 0.918721, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.918721, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9186991453170776, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "872856994942214", + "peak_in_radius": true, + "seam": false, + "x": 0.71484375, + "y": 0.583984375 + }, + { + "act": 0.804447, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.804447, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8044247627258301, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "872856994942214", + "peak_in_radius": true, + "seam": false, + "x": 0.19140625, + "y": 0.5390625 + }, + { + "act": 0.920193, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.920193, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9201868176460266, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "893023542323690", + "peak_in_radius": true, + "seam": false, + "x": 0.6044921875, + "y": 0.599609375 + }, + { + "act": 0.899801, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.899801, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8997887372970581, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "893023542323690", + "peak_in_radius": true, + "seam": false, + "x": 0.55078125, + "y": 0.552734375 + }, + { + "act": 0.920857, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.920857, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9208822250366211, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "911337534530260", + "peak_in_radius": true, + "seam": false, + "x": 0.6123046875, + "y": 0.6015625 + }, + { + "act": 0.856427, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.856427, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8564238548278809, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "911337534530260", + "peak_in_radius": true, + "seam": false, + "x": 0.91015625, + "y": 0.583984375 + }, + { + "act": 0.808182, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.808182, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8081760406494141, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "911337534530260", + "peak_in_radius": true, + "seam": false, + "x": 0.2763671875, + "y": 0.5234375 + }, + { + "act": 0.635044, + "argmax_off_px": 22.5, + "cell": "challenger_only", + "center": 0.176682, + "class": "tail", + "nearest_peak_px": 23.5, + "nearest_peak_score": 0.6432969570159912, + "null_med": 0.025113, + "null_p95": 0.920857, + "null_pct": 0.875, + "pano": "911337534530260", + "peak_in_radius": false, + "seam": false, + "x": 0.7846464584812973, + "y": 0.6185858524206913 + }, + { + "act": 1.0, + "argmax_off_px": 0.0, + "cell": "both", + "center": 1.0, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 1.0076181888580322, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "925077602773417", + "peak_in_radius": true, + "seam": false, + "x": 0.70703125, + "y": 0.599609375 + }, + { + "act": 0.895271, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.895271, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8952723145484924, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "925077602773417", + "peak_in_radius": true, + "seam": false, + "x": 0.25390625, + "y": 0.5703125 + }, + { + "act": 0.706292, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.706292, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.7062855958938599, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "925077602773417", + "peak_in_radius": true, + "seam": false, + "x": 0.35546875, + "y": 0.6171875 + }, + { + "act": 0.681016, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.681016, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6810267567634583, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "925077602773417", + "peak_in_radius": true, + "seam": false, + "x": 0.7529296875, + "y": 0.5703125 + }, + { + "act": 0.965541, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.965541, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9655410051345825, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "934739365184374", + "peak_in_radius": true, + "seam": false, + "x": 0.58984375, + "y": 0.599609375 + }, + { + "act": 0.943558, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.943558, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9435520768165588, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "934739365184374", + "peak_in_radius": true, + "seam": false, + "x": 0.6669921875, + "y": 0.599609375 + }, + { + "act": 0.927461, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.927461, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9274592399597168, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "934739365184374", + "peak_in_radius": true, + "seam": false, + "x": 0.12890625, + "y": 0.5859375 + }, + { + "act": 0.922892, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.922892, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.9228776693344116, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "934739365184374", + "peak_in_radius": true, + "seam": false, + "x": 0.39453125, + "y": 0.583984375 + }, + { + "act": 0.898126, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.898126, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8981223106384277, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "934739365184374", + "peak_in_radius": true, + "seam": false, + "x": 0.4326171875, + "y": 0.583984375 + }, + { + "act": 0.823908, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.823908, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8239020109176636, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "934739365184374", + "peak_in_radius": true, + "seam": false, + "x": 0.9169921875, + "y": 0.599609375 + }, + { + "act": 0.810013, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.810013, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8100091814994812, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "934739365184374", + "peak_in_radius": true, + "seam": false, + "x": 0.0966796875, + "y": 0.583984375 + }, + { + "act": 0.8086, + "argmax_off_px": 0.0, + "cell": "rampnet_only", + "center": 0.8086, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8086097240447998, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "934739365184374", + "peak_in_radius": true, + "seam": false, + "x": 0.87109375, + "y": 0.599609375 + }, + { + "act": 0.899075, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.899075, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8990524411201477, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "996959015535106", + "peak_in_radius": true, + "seam": false, + "x": 0.38671875, + "y": 0.5546875 + }, + { + "act": 0.877263, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.877263, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.8772670030593872, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "996959015535106", + "peak_in_radius": true, + "seam": false, + "x": 0.6044921875, + "y": 0.552734375 + }, + { + "act": 0.634536, + "argmax_off_px": 0.0, + "cell": "both", + "center": 0.634536, + "class": "tail", + "nearest_peak_px": 0.0, + "nearest_peak_score": 0.6345356106758118, + "null_med": null, + "null_p95": null, + "null_pct": null, + "pano": "996959015535106", + "peak_in_radius": true, + "seam": false, + "x": 0.5498046875, + "y": 0.5078125 + }, + { + "act": 0.098079, + "argmax_off_px": 4.9, + "cell": "challenger_only", + "center": 0.092798, + "class": "tail", + "nearest_peak_px": 4.9, + "nearest_peak_score": 0.09808053821325302, + "null_med": 0.005705, + "null_p95": 0.634536, + "null_pct": 0.84, + "pano": "996959015535106", + "peak_in_radius": true, + "seam": false, + "x": 0.44606062455610795, + "y": 0.5233333703243371 + } + ], + "skipped_sites": 0, + "split": "richmond", + "vistas_input_size": [ + 1024, + 1024 + ] +} diff --git a/docs/model_comparison.md b/docs/model_comparison.md index 7e32dca6..c45574c1 100644 --- a/docs/model_comparison.md +++ b/docs/model_comparison.md @@ -1429,6 +1429,77 @@ is the instrument. **Not run, not costed here.** framing — at 3.6 FP/pano against RampNet's 0.07 they are a ~50× review burden, so "FPs are cheap" is a claim about the labeling workflow that would need its own justification at this ratio. +#### The operating-point correction: a third of that gain is RampNet's own + +**Everything above scores RampNet from the committed bundle detections, which are the *shipped* +operating point — on richmond every one of them is ≥ 0.5519. This document has recommended +**0.30** since #54/#55 (PR #79).** For a complementarity read those are different models, and the +difference decides who gets credit for a recovery. + +Checked before relying on it: `analysis_out/op_cache/richmond.json` filtered at ≥ 0.5519 +reproduces the published row **exactly** (P 0.9636 / R 0.7677 / F1 0.8546, 238/9/72), so it is the +same source. At 0.30 those same peaks give **P 0.9018 / R 0.8290 / F1 0.8639, 257/28/53** — +matching the committed `analysis_out/op/corrected_at_0.3.csv`. `complementarity.py +--rampnet-op-threshold 0.30` re-bases the gate on it: + +| | rampnet @0.55 (published) | **rampnet @0.30 (recommended)** | +|---|---:|---:| +| rampnet recall | 0.768 (238) | **0.829 (257)** | +| rampnet F1 | 0.855 | **0.864** | +| rampnet misses | 72 | **53** | +| challenger recovers | 54 (75%) | **38 (72%)** | +| **attributable after the null** | ~44 | **~30** | +| found by NEITHER | 18 | **15** | +| oracle-union recall | 0.942 | 0.952 | +| naive union F1 | 0.555 | 0.549 | + +**So ~14 of the ramps the challenger got credit for recovering are ramps RampNet already has at +the operating point we recommend — the shipped threshold was discarding them.** The deployable +complementary gain is **~30, not ~44**. The recovery *rate* barely moves (75% → 72%), which is the +honest way to read it: the challenger is not preferentially finding the easy sub-threshold ones, +there are simply fewer misses to find. And a naive union stays dead against the stronger baseline +(0.549 vs 0.864). + +#### The cascade gate: live, but the ceiling is ~19 ramps, not 54 + +`scripts/analysis/cascade_gate.py` (new) asks the one question that decides whether a gated +cascade is possible at all: **at the ramps the challenger recovers, does RampNet already produce +something a prior could promote?** It partitions all 310 GT ramps into the four cells and reads +RampNet's heatmap at each, reusing #46 Phase 1's instrument verbatim (`site_profile`, +`null_percentile`, `nearest_peak`, `class_of`) so the numbers are comparable to that phase. +Read pre-registered on #126 before running. Artifacts: `analysis_out/cascade_gate.json` (shipped +point) and `analysis_out/cascade_gate_op030.json` (recommended point). + +At **rampnet@0.30**, of the 38 genuinely-complementary ramps: + +| what RampNet has there | n | what it means | +|---|---:|---| +| floor peak in radius, **0.05–0.30** | **19** | **promotable** — a peak exists, below threshold. This is the cascade's real target. | +| floor peak in radius, ≥0.30 but unmatched | 4 | the greedy matcher gave that peak to an **adjacent GT**. A matcher/σ problem (#130), not a threshold one. | +| no floor peak in radius | 15 | nothing to promote. `act` is 0.215 median — unpeaked heatmap mass `peak_local_max` never called a maximum. | + +**So the cascade is live and its ceiling is ~19 ramps on richmond — +6.1 recall points (0.829 → +0.890) before any false-positive cost, which is unmeasured.** That is a real number and it is a +long way below the 54 the raw complementarity suggested. Two-fifths of the recoverable set has no +peak to raise, and a further tenth is a matching bug wearing a threshold costume. + +**A negative worth recording: RampNet's own activation does not tell you which misses are +recoverable.** `challenger_only` sits at null percentile **0.88** and the hard-core `neither` at +**0.925** — the ramps *nobody* finds look, if anything, *stronger* on raw heatmap mass than the +ones the challenger recovers (they contain 6 of 15 matcher-claimed peaks ≥0.30, which inflates +it). Median argmax offset is 19.0 px inside a 22.5 px radius, i.e. near the window edge rather +than on the ramp. So there is no cheap self-gating shortcut: you cannot skip the second model and +find these by looking harder at RampNet's confidence. Against the pre-registered rule this is the +**PARTIAL** branch — signal present, but not at the site — and the peak-level column, not the +activation, is what supplies the bounded answer. + +**What would have to be true for the cascade to pay.** Promoting sub-0.30 peaks gated on +challenger candidates also promotes them wherever the challenger fires on a driveway and RampNet +has a faint bump — and 442 of the challenger's 716 boxes are false positives. That cost is **not +measured here**, so "+6.1 recall points" is a ceiling on the benefit with the cost still blank. +The next step, if this is ever picked up, is to build the gate and score it, not to reason further +about it. + ##### Reproducing it ```bash From 54a98c62130ce13dc980f665e66daac2f55bd299 Mon Sep 17 00:00:00 2001 From: Jon Froehlich Date: Tue, 18 Aug 2026 16:59:12 -0700 Subject: [PATCH 10/17] Record the seam exposure: bounded at 1 ramp in 38 (#126, #132) This work branched at 5e20d11, before eccadda (wrap the 360 seam in the matcher) and f4c71c8 (peaks_to_dets dropped peaks beside the seam) landed on main. Rather than argue that away, measured it. The greedy match used here does not wrap. score_pano own docstring records that wrapping moves no metric on any committed split while #130 duplicate ground truth masks it, so aggregates are safe -- but a cell assignment is finer-grained than an aggregate. And analysis_out/op_cache/richmond.json is UNCHANGED by those commits, so it was never regenerated after the peaks_to_dets fix and can still be missing peaks beside the seam; that can only UNDERSTATE the promotable count. Measured: 6 of richmond 310 GT ramps straddle the seam, and only ONE is in challenger_only. The other five are in both, where neither fix can move the partition in a direction that matters. Worst case for the headline is one ramp in 38 and no conclusion turns on it. Re-running on a post-#140 main retires the caveat instead of bounding it. Co-Authored-By: Claude Opus 5 --- docs/model_comparison.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/model_comparison.md b/docs/model_comparison.md index c45574c1..087ccc0f 100644 --- a/docs/model_comparison.md +++ b/docs/model_comparison.md @@ -1500,6 +1500,25 @@ measured here**, so "+6.1 recall points" is a ceiling on the benefit with the co The next step, if this is ever picked up, is to build the gate and score it, not to reason further about it. +**Seam exposure, stated because these numbers predate the #132 seam fixes.** This work branched at +`5e20d11`, before `eccadda` (wrap the 360° seam in the matcher) and `f4c71c8` (`peaks_to_dets` +dropped peaks beside the seam) landed. Two consequences, both bounded by measurement rather than +argued away: + +* The greedy match used here does not wrap. `score_pano`'s own docstring records that wrapping + *"moves no metric on any committed split"* while #130's duplicate ground truth masks it, so the + aggregate P/R/F1 are unaffected — but a cell assignment is finer-grained than an aggregate. +* `analysis_out/op_cache/richmond.json` is **unchanged by those commits**, i.e. it was not + regenerated after the `peaks_to_dets` fix, so it can still be missing peaks that sit beside the + seam. That would make a site read "no floor peak in radius" when one exists — it can only + *understate* the promotable count, never inflate it. + +**Measured exposure: 6 of richmond's 310 GT ramps straddle the seam, and only 1 of them is in +`challenger_only`** (the other 5 are in `both`, where neither fix can move the partition in a +direction that matters). So the worst case for the headline is one ramp in 38, and no conclusion +here turns on it. Re-running on a post-#140 main is the clean way to retire the caveat rather than +bound it. + ##### Reproducing it ```bash From a3ebe3751634dca688f2bfa6c2aaf6cba6d845f1 Mon Sep 17 00:00:00 2001 From: Jon Froehlich Date: Thu, 3 Sep 2026 06:26:03 -0700 Subject: [PATCH 11/17] complementarity: one matcher for the cells and the FP counts (#126, #132) F3 from the #137 review. matched_gt re-derived the pano distance inline and did not wrap, while score_pano -- which supplies the r_fp / c_fp and the union P/R/F1 printed in the same table -- wraps by default since #132. It now calls rampnet.metrics.greedy_match with wrap_x=True, the same core score_pano uses. Measured effect, cells (both / rampnet-only / challenger-only / neither): richmond vistas 384 rampnet bundle 194/44/22/50 identical wrapped richmond vistas 384 rampnet@0.30 202/55/14/39 identical wrapped richmond vistas 384 rampnet@0.05 213/66/3/28 identical wrapped paterson gemini-pro rampnet bundle 188/83/36/88 identical wrapped paterson gemini-pro rampnet@0.30 194/90/30/81 identical wrapped paterson gemini-pro rampnet@0.05 201/98/23/73 identical wrapped Zero flips, so the committed #35 gate numbers and this PR's 384 column are unchanged. The parity 1024 arm cannot be re-checked -- those detections are not published -- so its bound stays the doc's own count of 1 seam site in 38. Co-Authored-By: Claude Opus 5 --- scripts/analysis/complementarity.py | 38 +++++++++++++++++------------ 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/scripts/analysis/complementarity.py b/scripts/analysis/complementarity.py index 905124c8..af98c477 100644 --- a/scripts/analysis/complementarity.py +++ b/scripts/analysis/complementarity.py @@ -51,33 +51,39 @@ from rampnet.detection_eval import ( # noqa: E402 build_ground_truth, score_pano, radius_sq_for, PANO_SCALE_X, PANO_SCALE_Y, _xy, prediction_confidence) +from rampnet.metrics import greedy_match # noqa: E402 from compare import load_bundle, DetectionCache, cache_key # noqa: E402 from detectors import build_detector, parse_model_spec, PROVIDERS # noqa: E402 from operating_point_curve import CACHE_DIR, read_cache # noqa: E402 def matched_gt(preds, gt_points, radius_sq): - """Greedy 1:1 match (mirrors score_pano); return the set of GT indices covered.""" + """Which GT ramps a model covers: greedy 1:1, exactly as ``score_pano`` matches. + + Ordering and geometry are ``score_pano``'s -- highest confidence first when the + predictions carry one, else input order, then ``rampnet.metrics.greedy_match`` + with ``wrap_x=True``, which measures the x separation the shorter way round the + panorama (``rampnet.geometry.fold``, #132). Calling the shared matcher rather than + re-deriving the distance here is what keeps the four cells below and the FP counts + from ``score_pano`` on the same matcher: this script prints both in one table, and + ``score_pano`` wraps by default, so an inline non-wrapping distance here would put + two matchers in one output. + + Measured effect of the wrap on this script's cells: zero flips on RampNet's side + at >= 0.5519, >= 0.30 and >= 0.05, and zero on the published Vistas 384 arm + (richmond); the paterson #35 gate reproduces unchanged. The parity 1024 arm could + not be re-checked -- its detections are not published (see the note beside the + parity table in ``docs/model_comparison.md``) -- so the bound there is the doc's + own seam count, 1 site in 38. + """ confs = [prediction_confidence(p) for p in preds] order = (sorted(range(len(preds)), key=lambda i: confs[i] if confs[i] is not None else float("-inf"), reverse=True) if any(c is not None for c in confs) else range(len(preds))) - claimed, hit = [False] * len(gt_points), set() - for i in order: - pxn, pyn = _xy(preds[i]) - px, py = pxn * PANO_SCALE_X, pyn * PANO_SCALE_Y - best_k, best = -1, radius_sq - for k, (gx, gy) in enumerate(gt_points): - if claimed[k]: - continue - d = (px - gx * PANO_SCALE_X) ** 2 + (py - gy * PANO_SCALE_Y) ** 2 - if d < best: - best, best_k = d, k - if best_k >= 0: - claimed[best_k] = True - hit.add(best_k) - return hit + assignments = greedy_match([_xy(preds[i]) for i in order], gt_points, + radius_sq, PANO_SCALE_X, PANO_SCALE_Y, wrap_x=True) + return {gt_index for gt_index, _ in assignments if gt_index >= 0} def complementary_null(rows, radius_sq): From 7e8c9d0a992429860d99ef21b44bacce0d6762a8 Mon Sep 17 00:00:00 2001 From: Jon Froehlich Date: Thu, 3 Sep 2026 06:45:09 -0700 Subject: [PATCH 12/17] Test the complementarity gate and the cascade gate, and close two silent paths (#126) F5, F6 and F10 from the #137 review. F6 -- tests/test_complementarity.py (26) and tests/test_cascade_gate.py (18). Both read only committed files: benchmark/richmond, benchmark/model_detections and the two analysis_out/cascade_gate JSONs. No GPU, no .model_cache, no network. They cover matched_gt (including the seam case, so the inline non-wrapping distance cannot come back), model_spec, compare_args against the signature recorded in the published export, complementary_null on cases with an arithmetic answer, cell_of, summarize, and the published 384 richmond column cell for cell (194/44/22/50). model_spec("foo:bar") -- an unknown provider WITH a colon -- was read as the Gemini model id "foo:bar". That builds a detector whose signature nothing ever cached, so the run reported a model with zero detections instead of a mistyped argument. A colon now means provider:model_id and an unrecognised provider there is rejected; a bare token still means a Gemini model id, which is the #35 gate's committed form. F10 -- cascade_gate.py: panos absent from analysis_out/op_cache/.json under --rampnet-op-threshold scored as RampNet-blank, turning every GT ramp on them into a miss with no warning. They are now counted and reported. And the per-pano `floor_peaks.get(pid) or ` fallback substituted the shipped detections whenever the op_cache listed a pano with zero floor peaks, while the header still said the floor came from op_cache; the source is now one per run. All 124 richmond panos are present with peaks, so neither changes a committed number. F5 -- the 19 misses RampNet gains going 0.55 -> 0.30 are 16 out of challenger_only and 3 out of neither, so the complementary-gain headline falls by 16, not 19. Corrected in complementarity.py's docstring and cascade_gate.py's --rampnet-op-threshold help. Co-Authored-By: Claude Opus 5 --- scripts/analysis/cascade_gate.py | 33 +++- scripts/analysis/complementarity.py | 25 ++- tests/test_cascade_gate.py | 226 ++++++++++++++++++++++++ tests/test_complementarity.py | 263 ++++++++++++++++++++++++++++ 4 files changed, 534 insertions(+), 13 deletions(-) create mode 100644 tests/test_cascade_gate.py create mode 100644 tests/test_complementarity.py diff --git a/scripts/analysis/cascade_gate.py b/scripts/analysis/cascade_gate.py index f24ebc47..de7cdd6e 100644 --- a/scripts/analysis/cascade_gate.py +++ b/scripts/analysis/cascade_gate.py @@ -2,7 +2,7 @@ The complementarity gate (``complementarity.py``) says a Vistas-supervised segmenter at input parity finds 54 of the 72 richmond ramps RampNet misses, ~44 of them after the -chance null. A naive union is nonetheless dead — those 54 arrive with 442 false +chance null. A naive union of the two still loses — those 54 arrive with 442 false positives, ~8.2 FP per recovered ramp, and the union scores F1 0.555 against RampNet's 0.855. @@ -28,7 +28,7 @@ comparable to that phase's 8% absent / 62% adjacent-tail / 30% faint decomposition, and it means a fix to the probe fixes both analyses. -**``class_of`` is imported for comparability, but the load-bearing column here is +**``class_of`` is imported for comparability, but the column the read turns on here is ``peak_in_radius``, not the class.** #46 Phase 1 applied those cutoffs to *silent* misses — defined as no floor peak within the radius — so there ``tail`` (act >= 0.05) could only mean an outside mode reaching in. This population is every RampNet miss, not @@ -153,7 +153,8 @@ def main(argv=None): "threshold instead of the bundle's shipped detections " "(>=0.5519 on richmond). This document recommends 0.30, and " "the cells move: 19 of the shipped point's misses are ramps " - "RampNet already has. Default: the bundle, as published.") + "RampNet already has, 16 of them from challenger_only. " + "Default: the bundle, as published.") p.add_argument("--radius", type=float, default=0.022) p.add_argument("--tiling", choices=["perspective", "none"], default="perspective") p.add_argument("--vistas-input-size", type=int, nargs=2, metavar=("H", "W"), default=None, @@ -182,12 +183,13 @@ def main(argv=None): # Floor peaks (>= 0.05). Used for the sub-threshold probe always, and to # DEFINE rampnet's hits when --rampnet-op-threshold is given. - floor_peaks, floor_src = {}, "op_cache" + floor_peaks, floor_src, have_op_cache = {}, "op_cache", True try: cached, _ = read_cache(os.path.join(CACHE_DIR, f"{args.split}.json")) for pd in cached: floor_peaks[pd["pano"]] = pd["preds"] except (OSError, ValueError, KeyError): + have_op_cache = False floor_src = ("MISSING (fell back to bundle records -- distances are to the " "shipped operating point, not the 0.05 floor)") if args.rampnet_op_threshold is not None: @@ -195,7 +197,7 @@ def main(argv=None): f"{args.split}.json, which could not be read.") # ---- partition every GT ramp into a complementarity cell ------------------ - sites, missing = [], 0 + sites, missing, no_floor = [], 0, 0 for pid, entry in verdicts.items(): gt = build_ground_truth(records[pid]["detections"], entry["dets"], entry["missed"], entry["no_missed"]) @@ -206,6 +208,11 @@ def main(argv=None): missing += 1 continue if args.rampnet_op_threshold is not None: + # A pano the op_cache does not list would score as RampNet-blank, which + # turns every GT on it into a miss. That is a silent shift of the whole + # partition, so it is counted and reported rather than absorbed. + if pid not in floor_peaks: + no_floor += 1 rp = [q for q in floor_peaks.get(pid, []) if q[2] >= args.rampnet_op_threshold] else: @@ -219,6 +226,11 @@ def main(argv=None): if missing: print(f"WARNING: {missing} panos had no cached {label} detections and were " f"skipped. Pass the --vistas-input-size the run used.", flush=True) + if no_floor: + print(f"WARNING: {no_floor} panos are absent from analysis_out/op_cache/" + f"{args.split}.json, so RampNet scored blank on them and every GT ramp " + f"there counts as a miss. Regenerate the op_cache for this split before " + f"reading the cells.", flush=True) if not sites: sys.exit("No sites -- is the challenger cached for this split/input size?") @@ -253,9 +265,14 @@ def main(argv=None): skipped += len(by_pano[pid]) continue heat = ts.heatmap_for(model, device, path, use_fp16=False) - preds = floor_peaks.get(pid) or [ - (d["x_normalized"], d["y_normalized"], d["confidence"]) - for d in records[pid]["detections"]] + # One source per run, not per pano. `floor_peaks.get(pid) or ` would + # substitute the shipped detections for any pano the op_cache lists with zero + # floor peaks, while the header still says the floor came from op_cache -- and + # a pano with no peak at the 0.05 floor genuinely has nothing to promote, which + # is the answer, not a gap to fill. + preds = (floor_peaks.get(pid, []) if have_op_cache else + [(d["x_normalized"], d["y_normalized"], d["confidence"]) + for d in records[pid]["detections"]]) for s in by_pano[pid]: act, off_px, center = site_profile(heat, s["x"], s["y"], radius_sq) npx, nscore = nearest_peak(preds, s["x"], s["y"]) diff --git a/scripts/analysis/complementarity.py b/scripts/analysis/complementarity.py index af98c477..df94f190 100644 --- a/scripts/analysis/complementarity.py +++ b/scripts/analysis/complementarity.py @@ -11,8 +11,10 @@ point — on richmond every one scores >= 0.5519 — while this document's own recommendation since #54/#55 (PR #79) is **0.30**. Those are different models for this purpose: at 0.30 RampNet finds 257 of richmond's 310 ramps instead of 238, so 19 of the -"misses" a challenger gets credit for recovering are ramps RampNet already has and the -shipped threshold is discarding. ``--rampnet-op-threshold`` re-sources RampNet's side +misses the shipped threshold reports are ramps RampNet already has. 16 of those 19 are +in the challenger-recovered cell, which is what the complementary-gain headline counts, +so that headline falls from 54 to 38 (~44 to ~30 after the chance null); the other 3 come +out of the found-by-nobody cell. ``--rampnet-op-threshold`` re-sources RampNet's side from the committed ``analysis_out/op_cache/.json`` floor peaks at a given threshold, which is how you ask "what is the complementary gain at the operating point we would actually deploy?". Default is the bundle records, so the published roster @@ -118,12 +120,25 @@ def complementary_null(rows, radius_sq): def model_spec(token): - """``provider``/``provider:model_id``, or a legacy bare Gemini model id.""" + """``provider``/``provider:model_id``, or a legacy bare Gemini model id. + + A colon means the caller wrote ``provider:model_id``, so an unrecognised provider + there is a typo and is rejected. Without a colon the token is read as a Gemini + model id: that is the form the #35 gate was invoked with before this script grew + past one provider, and reading it as a provider would reject strings that used to + be valid. + + Rejecting the colon form matters because a bad spec does not fail loudly on its + own. It builds a detector whose signature nothing ever cached, every lookup + misses, and the script reports a model with zero cached detections -- which reads + as a missing run rather than a mistyped argument. + """ provider, model_id = parse_model_spec(token) if provider in PROVIDERS: return provider, model_id - # Legacy positional form: a bare model id meant gemini. Keep it working -- - # reading it as a provider would raise on strings that used to be valid. + if ":" in token: + sys.exit(f"unknown provider {provider!r} in model spec {token!r} " + f"(choose from: {', '.join(PROVIDERS)})") return "gemini", token diff --git a/tests/test_cascade_gate.py b/tests/test_cascade_gate.py new file mode 100644 index 00000000..7f6d3e40 --- /dev/null +++ b/tests/test_cascade_gate.py @@ -0,0 +1,226 @@ +"""Unit tests for the cascade gate (#126). + +Pure logic plus a drift guard on the committed artifacts — no GPU, no imagery, no +``.model_cache``. The heavy half (one RampNet forward per pano) is exercised by running +the script; what these protect is the bookkeeping the write-up quotes. + +``summarize`` is the whole reporting surface: every number in the cascade tables in +``docs/model_comparison.md`` is one of its keys, and it is re-derivable from the +``sites`` list committed alongside it. So the guard here is that ``summarize`` applied +to a committed run's ``sites`` reproduces that run's ``cells`` exactly — which also +pins which *subset* each figure is a median of, the thing a hand-copied number gets +wrong (the cell's ``act_median`` is not the no-peak rows' median). + +The parity (1024x1024) detections behind those two artifacts are not published, so a +clean clone cannot regenerate these files. It can still check them against themselves, +which is what the second half of this file does. +""" +import json +import os +import sys + +REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, REPO) +sys.path.insert(0, os.path.join(REPO, "scripts", "analysis")) +sys.path.insert(0, os.path.join(REPO, "scripts", "model_comparison")) + +import cascade_gate as cg # noqa: E402 +from farfield_forensics import quartiles # noqa: E402 + +OUT = os.path.join(REPO, "analysis_out") +SHIPPED = os.path.join(OUT, "cascade_gate.json") +OP030 = os.path.join(OUT, "cascade_gate_op030.json") + + +def _row(cell, **kw): + """One site row, with the fields ``summarize`` reads and neutral defaults.""" + row = {"cell": cell, "act": 0.5, "center": 0.5, "argmax_off_px": 0.0, + "nearest_peak_px": 0.0, "nearest_peak_score": 0.5, "class": "tail", + "peak_in_radius": True, "seam": False, + "null_pct": None, "null_med": None, "null_p95": None} + row.update(kw) + return row + + +# --------------------------------------------------------------------------- # +# cell_of — the 2x2 that names the recoverable set +# --------------------------------------------------------------------------- # +def test_the_four_cells(): + assert cg.cell_of(True, True) == "both" + assert cg.cell_of(True, False) == "rampnet_only" + assert cg.cell_of(False, True) == "challenger_only" + assert cg.cell_of(False, False) == "neither" + + +def test_only_the_two_rampnet_miss_cells_get_a_null(): + # The null is meaningless where RampNet found the ramp: the activation is high by + # construction there, which is why those cells are the positive control. So the + # cells a null is reported for are exactly the two cell_of returns on a miss. + assert set(cg.CELLS) == {"both", "rampnet_only", "challenger_only", "neither"} + assert set(cg.MISS_CELLS) == {cg.cell_of(False, True), cg.cell_of(False, False)} + + +# --------------------------------------------------------------------------- # +# summarize — the reporting surface +# --------------------------------------------------------------------------- # +def test_an_empty_cell_reports_n_zero_and_nothing_else(): + out = cg.summarize([_row("both")], "neither") + assert out == {"cell": "neither", "n": 0} + + +def test_it_selects_only_its_own_cell(): + rows = [_row("both", act=0.9), _row("challenger_only", act=0.1), + _row("challenger_only", act=0.3), _row("challenger_only", act=0.4)] + out = cg.summarize(rows, "challenger_only") + assert out["n"] == 3 + assert out["act_median"] == 0.3 + + +def test_peak_in_radius_is_counted_and_shared(): + rows = [_row("challenger_only", peak_in_radius=True), + _row("challenger_only", peak_in_radius=True), + _row("challenger_only", peak_in_radius=False, nearest_peak_px=40.0), + _row("challenger_only", peak_in_radius=False, nearest_peak_px=60.0)] + out = cg.summarize(rows, "challenger_only") + assert out["peak_in_radius"] == 2 + assert out["peak_in_radius_share"] == 0.5 + + +def test_the_peak_score_median_covers_only_the_rows_that_have_a_peak(): + # This is the distinction a hand-copied number loses: a per-row column's median is + # over the rows that have that column, not over the cell. + rows = [_row("challenger_only", peak_in_radius=True, nearest_peak_score=0.10), + _row("challenger_only", peak_in_radius=True, nearest_peak_score=0.20), + _row("challenger_only", peak_in_radius=True, nearest_peak_score=0.30), + _row("challenger_only", peak_in_radius=False, nearest_peak_score=0.99)] + out = cg.summarize(rows, "challenger_only") + # The 0.99 belongs to a row with no peak in radius, so it is out of this median. + assert out["peak_in_radius_score_median"] == 0.2 + + +def test_a_cell_with_no_peak_anywhere_reports_no_peak_score(): + rows = [_row("neither", peak_in_radius=False, nearest_peak_px=None, + nearest_peak_score=None)] + out = cg.summarize(rows, "neither") + assert out["peak_in_radius"] == 0 + assert "peak_in_radius_score_median" not in out + assert out["nearest_peak_px_median"] is None + + +def test_the_hit_cells_carry_no_null_statistics(): + out = cg.summarize([_row("both"), _row("both")], "both") + for key in ("null_pct_median", "above_null_p95", "null_med_median"): + assert key not in out + + +def test_above_null_p95_counts_sites_over_their_own_shifted_p95(): + rows = [_row("challenger_only", act=0.5, null_pct=0.99, null_med=0.01, null_p95=0.2), + _row("challenger_only", act=0.1, null_pct=0.40, null_med=0.02, null_p95=0.2), + _row("challenger_only", act=0.3, null_pct=0.70, null_med=0.03, null_p95=0.2)] + out = cg.summarize(rows, "challenger_only") + # act > this site's own p95 on the 0.5 and 0.3 rows, not on the 0.1 one. + assert out["above_null_p95"] == 2 + assert out["null_pct_median"] == 0.7 + assert out["null_med_median"] == 0.02 + + +def test_seam_sites_are_counted_per_cell(): + rows = [_row("challenger_only", seam=True), _row("challenger_only", seam=False), + _row("both", seam=True)] + assert cg.summarize(rows, "challenger_only")["seam"] == 1 + assert cg.summarize(rows, "both")["seam"] == 1 + + +def test_the_class_shares_sum_to_one(): + rows = [_row("neither", **{"class": "absent"}), + _row("neither", **{"class": "faint_local"}), + _row("neither", **{"class": "tail"}), + _row("neither", **{"class": "tail"})] + out = cg.summarize(rows, "neither") + assert out["classes"] == {"absent": 1, "faint_local": 1, "tail": 2} + assert sum(out["class_share"].values()) == 1.0 + + +# --------------------------------------------------------------------------- # +# the committed artifacts — every cell figure re-derives from the sites list +# --------------------------------------------------------------------------- # +def _payload(path): + with open(path, encoding="utf-8") as fh: + return json.load(fh) + + +def test_the_committed_cells_re_derive_from_the_committed_sites(): + for path in (SHIPPED, OP030): + payload = _payload(path) + assert [cg.summarize(payload["sites"], c) for c in cg.CELLS] == payload["cells"], ( + f"{os.path.basename(path)}: cells no longer match summarize(sites)") + + +def test_the_two_artifacts_partition_the_same_310_richmond_ramps(): + for path in (SHIPPED, OP030): + payload = _payload(path) + assert payload["split"] == "richmond" + assert payload["challenger"] == "mask2former-vistas-curb-cut" + assert payload["vistas_input_size"] == [1024, 1024] + assert payload["n_sites"] == 310 + assert sum(c["n"] for c in payload["cells"]) == 310 + assert payload["skipped_sites"] == 0 + + +def test_only_the_op030_artifact_records_the_threshold_key(): + # cascade_gate.json was written before --rampnet-op-threshold entered the payload, + # so a regeneration would add "rampnet_op_threshold": null and change its bytes + # even with identical results. Stated in docs/model_comparison.md beside it. + assert "rampnet_op_threshold" not in _payload(SHIPPED) + assert _payload(OP030)["rampnet_op_threshold"] == 0.3 + + +def test_the_cascade_ceiling_is_nineteen_promotable_ramps(): + # docs/model_comparison.md, "The cascade gate": of the 38 genuinely-complementary + # ramps at rampnet@0.30, 19 carry a floor peak in radius scoring 0.05-0.30 (the + # promotable set), 4 carry one at >= 0.30 that the greedy matcher gave to an + # adjacent GT, and 15 carry none. + sites = [s for s in _payload(OP030)["sites"] if s["cell"] == "challenger_only"] + assert len(sites) == 38 + peaked = [s for s in sites if s["peak_in_radius"]] + no_peak = [s for s in sites if not s["peak_in_radius"]] + assert len(no_peak) == 15 + assert sum(1 for s in peaked if 0.05 <= s["nearest_peak_score"] < 0.30) == 19 + assert sum(1 for s in peaked if s["nearest_peak_score"] >= 0.30) == 4 + + +def test_the_no_peak_rows_have_their_own_activation_median(): + # The row in the cascade table is about the 15 sites with nothing to promote, so + # its activation figure is those 15 sites' median (0.2723) -- not the whole + # challenger_only cell's (0.2152, which is what cells[].act_median reports). + payload = _payload(OP030) + cell = next(c for c in payload["cells"] if c["cell"] == "challenger_only") + sites = [s for s in payload["sites"] if s["cell"] == "challenger_only"] + no_peak = [s["act"] for s in sites if not s["peak_in_radius"]] + assert round(quartiles(no_peak)[1], 4) == 0.2723 + assert cell["act_median"] == 0.2152 + + +def test_moving_to_the_recommended_threshold_takes_sixteen_from_the_recovered_cell(): + # docs/model_comparison.md: RampNet gains 19 hits going 0.55 -> 0.30 (72 -> 53 + # misses), of which 16 come out of challenger_only and 3 out of neither. The + # complementary-gain headline is the challenger_only figure, so it falls by 16. + shipped = {c["cell"]: c["n"] for c in _payload(SHIPPED)["cells"]} + op030 = {c["cell"]: c["n"] for c in _payload(OP030)["cells"]} + assert shipped["challenger_only"] == 54 and op030["challenger_only"] == 38 + assert shipped["neither"] == 18 and op030["neither"] == 15 + gained = ((shipped["challenger_only"] + shipped["neither"]) + - (op030["challenger_only"] + op030["neither"])) + assert gained == 19 + assert shipped["challenger_only"] - op030["challenger_only"] == 16 + assert shipped["neither"] - op030["neither"] == 3 + + +def test_the_seam_exposure_is_one_ramp_in_the_recovered_cell(): + # The bound on the pre-#132 non-wrapping match: 6 of richmond's 310 GT ramps + # straddle the seam, and only 1 of them is in challenger_only. + payload = _payload(OP030) + assert sum(1 for s in payload["sites"] if s["seam"]) == 6 + by_cell = {c["cell"]: c["seam"] for c in payload["cells"]} + assert by_cell["challenger_only"] == 1 + assert by_cell["both"] == 5 diff --git a/tests/test_complementarity.py b/tests/test_complementarity.py new file mode 100644 index 00000000..e330d131 --- /dev/null +++ b/tests/test_complementarity.py @@ -0,0 +1,263 @@ +"""Unit tests for the complementarity gate (#35, generalized past Gemini in #126). + +Pure logic plus two drift guards — no GPU, no ``.model_cache``, no network. Every +detection these read comes from ``benchmark/model_detections/``, the published export, +so a clean clone runs them. + +What they protect: + +* **``matched_gt`` and ``score_pano`` must agree.** This script prints the four + complementarity cells (from ``matched_gt``) and the false-positive counts and union + P/R/F1 (from ``score_pano``) in one table. ``score_pano`` wraps the 360° seam by + default since #132; ``matched_gt`` re-derived the distance inline and did not, which + put two matchers in one output. It now calls the shared matcher, and the wrap test + below fails if the inline form comes back. +* **``model_spec`` must reject a mistyped provider.** A bad spec does not raise: it + addresses a cache entry nothing ever wrote, and the script reports a model with zero + detections, which reads as a missing run. +* **``compare_args`` must reconstruct the signature ``compare.py`` cached under.** + Same silent failure. Checked against the signature recorded inside the published + export rather than against a copy of the defaults. +* **``complementary_null``** is the discount every attributable-gain number in + ``docs/model_comparison.md`` is quoted after, so it is checked against cases whose + answer is arithmetic rather than measurement. +* the published 384 richmond column, cell for cell. +""" +import argparse +import json +import os +import sys + +import pytest + +REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, REPO) +sys.path.insert(0, os.path.join(REPO, "scripts", "analysis")) +sys.path.insert(0, os.path.join(REPO, "scripts", "model_comparison")) + +import complementarity as cx # noqa: E402 +from compare import DetectionCache, cache_key, load_bundle # noqa: E402 +from detectors import PROVIDERS, build_detector # noqa: E402 +from rampnet.detection_eval import ( # noqa: E402 + PANO_SCALE_X, build_ground_truth, radius_sq_for, score_pano) + +RSQ = radius_sq_for() +R_NORM = RSQ ** 0.5 / PANO_SCALE_X # match radius in normalized x, ~0.022 +PUBLISHED = os.path.join(REPO, "benchmark", "model_detections", + "mask2former-vistas-curb-cut__richmond.json") + + +def _args(**kw): + """The namespace ``compare_args`` reads, with this script's own CLI defaults.""" + ns = argparse.Namespace(tiling="perspective", radius=0.022, + cache_dir=os.path.join(REPO, ".model_cache"), + vistas_input_size=None, vistas_revision=None) + for k, v in kw.items(): + setattr(ns, k, v) + return ns + + +# --------------------------------------------------------------------------- # +# matched_gt — the same matcher score_pano uses, wrap included +# --------------------------------------------------------------------------- # +def test_a_prediction_on_the_ramp_claims_it(): + assert cx.matched_gt([(0.5, 0.5, 0.9)], [(0.5, 0.5)], RSQ) == {0} + + +def test_a_prediction_out_of_radius_claims_nothing(): + assert cx.matched_gt([(0.5 + 2 * R_NORM, 0.5, 0.9)], [(0.5, 0.5)], RSQ) == set() + + +def test_two_predictions_cannot_both_claim_one_ramp(): + # The 1:1 rule: the second is a false positive, not a second hit, so the covered + # set stays one ramp. score_pano counts it as an FP on the same input. + covered = cx.matched_gt([(0.5, 0.5, 0.9), (0.5, 0.5, 0.8)], [(0.5, 0.5)], RSQ) + assert covered == {0} + + +def test_the_highest_confidence_prediction_claims_first(): + # Two ramps, both in range of both predictions: the order decides which pairs with + # which, and score_pano orders by confidence. Both end up covered either way, so + # the guard is that the ordering path runs at all rather than raising. + gt = [(0.5, 0.5), (0.5 + R_NORM / 2, 0.5)] + assert cx.matched_gt([(0.5, 0.5, 0.2), (0.5 + R_NORM / 2, 0.5, 0.9)], gt, RSQ) == {0, 1} + + +def test_predictions_without_confidence_are_matched_in_input_order(): + # The chat VLMs emit boxes with no score. Nothing to sort by, so input order. + assert cx.matched_gt([(0.5, 0.5, None)], [(0.5, 0.5)], RSQ) == {0} + + +def test_a_prediction_across_the_seam_claims_the_ramp(): + # x=0.998 and x=0.002 are ~4 px apart the short way round and ~1020 px apart the + # long way. score_pano wraps (#132); an inline non-wrapping distance here would + # score this as a miss AND as a false positive in the same table. + assert cx.matched_gt([(0.998, 0.5, 0.9)], [(0.002, 0.5)], RSQ) == {0} + + +def test_the_cells_and_the_fp_counts_come_from_one_matcher(): + # The seam case, read through both halves of the script's output: matched_gt says + # the ramp is covered, so score_pano must call the same prediction a true positive + # rather than a false one. + gt = build_ground_truth([{"x_normalized": 0.002, "y_normalized": 0.5, + "confidence": 0.9}], [True], [], True) + preds = [(0.998, 0.5, 0.9)] + assert cx.matched_gt(preds, gt.gt_points, RSQ) == {0} + assert score_pano(preds, gt, RSQ).fp == 0 + + +# --------------------------------------------------------------------------- # +# model_spec — the legacy positional form, and the typo that used to be silent +# --------------------------------------------------------------------------- # +def test_a_bare_provider_uses_that_provider_default_model(): + assert cx.model_spec("vistas") == ("vistas", None) + + +def test_provider_colon_model_id_is_passed_through(): + assert cx.model_spec("vistas:curb-cut") == ("vistas", "curb-cut") + assert cx.model_spec("gemini:gemini-3.6-flash") == ("gemini", "gemini-3.6-flash") + + +def test_a_bare_non_provider_token_is_still_a_gemini_model_id(): + # The #35 gate's committed invocation. Keep it working. + assert cx.model_spec("gemini-3.1-pro-preview") == ("gemini", "gemini-3.1-pro-preview") + + +def test_an_unknown_provider_with_a_colon_is_rejected(): + # Used to be read as the Gemini model id "foo:bar", which builds a detector whose + # signature nothing cached: the run then reports zero detections instead of a typo. + with pytest.raises(SystemExit) as e: + cx.model_spec("foo:bar") + assert "foo" in str(e.value) + + +def test_every_provider_name_survives_a_round_trip(): + for provider in PROVIDERS: + assert cx.model_spec(provider) == (provider, None) + + +# --------------------------------------------------------------------------- # +# compare_args — the cache signature this script has to reconstruct +# --------------------------------------------------------------------------- # +def test_the_vistas_signature_matches_the_published_export(): + # The published richmond arm records the signature it was cached under. If + # compare_args drifts from compare.py's defaults, this reconstruction stops + # matching and every cache lookup silently misses. + published = json.load(open(PUBLISHED, encoding="utf-8")) + label, det = build_detector("vistas", "curb-cut", {}, cx.compare_args(_args())) + assert label == published["model"] + assert det.signature() == published["signature"] + + +def test_the_input_size_override_addresses_a_different_cache_entry(): + published = json.load(open(PUBLISHED, encoding="utf-8")) + _, parity = build_detector("vistas", "curb-cut", {}, + cx.compare_args(_args(vistas_input_size=[1024, 1024]))) + sig = parity.signature() + assert sig["input_size"] == [1024, 1024] + assert sig != published["signature"] + # Deviation-only: the key the 384 arm was paid for is untouched by the flag existing. + assert "input_size" not in published["signature"] + assert (cache_key("mask2former-vistas-curb-cut", sig, "richmond", "p") + != cache_key("mask2former-vistas-curb-cut", published["signature"], + "richmond", "p")) + + +# --------------------------------------------------------------------------- # +# complementary_null — the chance discount every "attributable" number is quoted after +# --------------------------------------------------------------------------- # +def _row(pred_xy, missed_xy): + return ([(pred_xy[0], pred_xy[1], 1.0)], [missed_xy]) + + +def test_no_missed_ramps_means_no_null(): + # Nothing for the challenger to recover, so there is no coincidence rate to report. + rows = [([(0.2, 0.2, 1.0)], []), ([(0.5, 0.5, 1.0)], [])] + assert cx.complementary_null(rows, RSQ) == (0.0, 0.0) + + +def test_one_pano_has_no_shift_to_take(): + # Every shift is the identity with n=1, so there is nothing to measure. + assert cx.complementary_null([_row((0.2, 0.2), (0.2, 0.2))], RSQ) == (0.0, 0.0) + + +def test_boxes_that_never_line_up_give_a_zero_null(): + rows = [_row((0.1, 0.1), (0.1, 0.1)), + _row((0.5, 0.5), (0.5, 0.5)), + _row((0.9, 0.9), (0.9, 0.9))] + assert cx.complementary_null(rows, RSQ) == (0.0, 0.0) + + +def test_identical_boxes_on_every_pano_give_a_null_of_one(): + # The degenerate high-density case: every shift matches every missed ramp, so all + # of the "recovery" is what the radius gives away. + rows = [_row((0.3, 0.3), (0.3, 0.3)) for _ in range(3)] + assert cx.complementary_null(rows, RSQ) == (1.0, 1.0) + + +def test_the_null_averages_over_every_non_identity_shift(): + # 3 panos, 3 missed ramps, so shifts k=1 and k=2. k=1 lands 2 of 3 (panos 0 and 2 + # both miss a ramp at (0.2, 0.2), and panos 1 and 0 both predict there); k=2 lands + # 1 of 3. Mean 0.5, worst shift 2/3. + rows = [_row((0.2, 0.2), (0.2, 0.2)), + _row((0.2, 0.2), (0.7, 0.7)), + _row((0.9, 0.1), (0.2, 0.2))] + mean, worst = cx.complementary_null(rows, RSQ) + assert mean == pytest.approx(0.5) + assert worst == pytest.approx(2 / 3) + + +# --------------------------------------------------------------------------- # +# regression — the published 384 richmond column, read from committed files only +# --------------------------------------------------------------------------- # +def _published_cells(tmp_path): + """The four cells for the published Vistas 384 arm on richmond. + + Rebuilds a ``.model_cache``-shaped directory from the published export and reads it + back through ``DetectionCache``/``cache_key``, i.e. the path the script itself + takes. That is deliberate: the lookup only succeeds if the signature reconstructed + from ``compare_args`` is the one the export was written under. + """ + published = json.load(open(PUBLISHED, encoding="utf-8")) + cache = DetectionCache(str(tmp_path / "cache")) + for pid, points in published["detections"].items(): + cache.put(cache_key(published["model"], published["signature"], + published["city"], pid), points) + + label, det = build_detector("vistas", "curb-cut", {}, cx.compare_args(_args())) + sig = det.signature() + records, verdicts, _ = load_bundle(os.path.join(REPO, "benchmark", "richmond")) + counts = {"both": 0, "rampnet_only": 0, "challenger_only": 0, "neither": 0} + for pid, entry in verdicts.items(): + gt = build_ground_truth(records[pid]["detections"], entry["dets"], + entry["missed"], entry["no_missed"]) + if not gt.fn_confirmed: + continue + cp = cache.get(cache_key(label, sig, "richmond", pid)) + assert cp is not None, f"{pid}: signature drifted from the published export" + rp = [(d["x_normalized"], d["y_normalized"], d["confidence"]) + for d in records[pid]["detections"]] + mr = cx.matched_gt(rp, gt.gt_points, RSQ) + mc = cx.matched_gt(cp, gt.gt_points, RSQ) + for i in range(len(gt.gt_points)): + r, c = i in mr, i in mc + key = ("both" if r and c else "rampnet_only" if r else + "challenger_only" if c else "neither") + counts[key] += 1 + return counts + + +def test_the_published_384_column_reproduces(tmp_path): + # docs/model_comparison.md, "Complementarity" table, the vistas @384 column. + # RampNet's side is the bundle's shipped detections (>= 0.5519 on richmond). + assert _published_cells(tmp_path) == {"both": 194, "rampnet_only": 44, + "challenger_only": 22, "neither": 50} + + +def test_the_384_column_adds_up_to_richmond_s_recall_eligible_ground_truth(tmp_path): + counts = _published_cells(tmp_path) + assert sum(counts.values()) == 310 + # 22 of RampNet's 72 misses recovered, 31%; and 216 of 310 for the challenger, + # which is the recall its published row reports. + assert counts["challenger_only"] + counts["neither"] == 72 + assert counts["both"] + counts["challenger_only"] == 216 From 70ce26523a4e7f43077e63dbb1116b4080d79a25 Mon Sep 17 00:00:00 2001 From: Jon Froehlich Date: Thu, 3 Sep 2026 06:57:44 -0700 Subject: [PATCH 13/17] Vistas parity write-up: correct the 384 column, and say what a clean clone cannot rebuild (#126) F1, F2, F4, F7, F8, F9, F11 and the documentation half of F3 from the #137 review. F2 -- the "vistas @384" complementarity column was the unpublished same-env A40 control, not the published arm, and it was not labelled either way. Replaced with the published arm's own numbers, re-run here against benchmark/model_detections/mask2former-vistas-curb-cut__richmond.json: challenger-only 22 (31%) not 21 (29%), found-by-nobody 50 not 51, oracle-union 0.839 not 0.835, above-chance 0.661 not 0.657, naive-union F1 0.586 not 0.585. The control differs by one detection in 523; that is now stated rather than left as the unmarked source. F1 -- neither A40 run's detections are published, so five things re-derive only from the private makelab2 cache: the parity and control rows, the 1024 complementarity column, the whole operating-point-correction table, both cascade tables and both cascade_gate JSONs, and the seam-exposure count. Each now says so where it appears, and export_model_cache.py --publish-as (#123, on main) is named as what closes it. F3 (doc half) -- score_pano's docstring was quoted as "moves no metric on any committed split"; the full sentence is "Wrapping moves no RampNet or YOLO metric on any committed split -- but it does move the challengers", and the challenger is the side being partitioned. Quoted in full, with the measurement that replaces the citation: zero cell flips on the published 384 arm and on the paterson #35 gate, at all three RampNet thresholds. The parity arm cannot be re-checked, so its bound stays 1 seam ramp in 38. F4 -- the no-peak row's activation median is 0.272 over those 15 sites (0.369 mean); 0.215 was the whole 38-ramp cell's, and the 19 promotable sites are at 0.153. F5 (doc half) -- "~14 of the ramps the challenger got credit for recovering" is 16 raw and ~14 after the null; 16 of the 19 hits RampNet gains at 0.30 come out of challenger_only and 3 out of neither. F7 -- cascade_gate.json predates the rampnet_op_threshold key, so a regeneration changes its bytes with identical results. Stated beside the artifact list. F8 -- the five missing invocations (complementarity at parity and at 0.30, null_recall at parity, both cascade_gate runs) added to "Reproducing it", with the step a clean clone needs first: complementarity.py and null_recall.py read .model_cache rather than the published export, so the export has to be written into a cache directory. cascade_gate.py now has a row in scripts/analysis/README.md. F9 -- cost in both units: $0 on lab-owned hardware, and 3m38s for the one leg of three that was timed. The 384 control was not timed and RampNet's row uses no GPU, so there is no session total to quote. F11 -- plain statements in place of six phrases. Co-Authored-By: Claude Opus 5 --- docs/model_comparison.md | 245 ++++++++++++++++++++++++++++--------- scripts/analysis/README.md | 1 + 2 files changed, 186 insertions(+), 60 deletions(-) diff --git a/docs/model_comparison.md b/docs/model_comparison.md index 6e75474c..f8057b0f 100644 --- a/docs/model_comparison.md +++ b/docs/model_comparison.md @@ -1347,15 +1347,16 @@ At conf ≥ 0.30: control **0.419 / 0.694 / 0.522** (published: 0.419 / 0.697 / **0.384 / 0.884 / 0.536**. Note the threshold barely bites at parity — it removes 3 false positives against 10 at 384 — because the higher-resolution masks are more confident. -**The env control was not in the original plan and it earns its place.** The published run was on -Jon's RTX 3070 on an older `transformers`; makelab2 is a major version on. Since the -`transformers` version is *not* in the detection signature — a hazard this document already flags -— parity-vs-published would have differed in **two** things. Re-running 384 in the parity env -separates them: it lands within **one detection out of 523** of the published run (215/308/95 vs -216/309/94, F1 0.516 vs 0.517). So the 4.x→5.15 jump is benign for this checkpoint, the residual -is fp16 kernel nondeterminism rather than a version break, and **the whole parity delta is -attributable to input size.** That also retires the "an upgrade could have changed every mask -under an unchanged cache key" worry for this arm, as a measurement rather than an assurance. +**The env control was not in the original plan, and it is what makes the parity delta +attributable.** The published run was on Jon's RTX 3070 on an older `transformers`; makelab2 is a +major version on. Since the `transformers` version is *not* in the detection signature — a hazard +this document already flags — parity-vs-published would have differed in **two** things. +Re-running 384 in the parity env separates them: it lands within **one detection out of 523** of +the published run (215/308/95 vs 216/309/94, F1 0.516 vs 0.517). So the 4.x→5.15 jump is benign +for this checkpoint, the residual is fp16 kernel nondeterminism rather than a version break, and +**the whole parity delta is attributable to input size.** That also retires the "an upgrade could +have changed every mask under an unchanged cache key" worry for this arm, as a measurement rather +than an assurance. **The decision rule returns "stands", and it is not close.** Against the same-env control, parity moves F1 **0.516 → 0.534, +0.018** — about a third of the 0.05 bar. RampNet's lead goes 0.339 → @@ -1395,30 +1396,57 @@ parity unqualified: **Caveats that travel with these numbers.** `min_area_px=16` is inert at 384 but sits exactly at the smallest achievable blob at 1024 (see above), so the two rows do not share that setting's -meaning even though they share its value. The parity detections are **deliberately not -published**: `--vistas-input-size` does not change the arm's label, so exporting them would -overwrite `mask2former-vistas-curb-cut__richmond.json` — publishing them needs a distinct -published name (the `--publish-as` pattern from #123), which was out of scope here. And this is -still **richmond only**. +meaning even though they share its value. And this is still **richmond only**. + +**Neither A40 run's detections are published, so the bottom two rows of that table are not +re-derivable from a clean clone.** The parity (1024×1024) and same-env control (384×384) +detections live in a private `--cache-dir` on makelab2 and nowhere else; only the published 384 +row and RampNet's row come from committed files. `--vistas-input-size` does not change the arm's +label, so exporting either one would overwrite +`benchmark/model_detections/mask2former-vistas-curb-cut__richmond.json`. Publishing them needs a +distinct published name — `scripts/analysis/export_model_cache.py --publish-as` (#123, on `main`), +e.g. `mask2former-vistas-curb-cut-1024` — which was out of scope here. **Everything downstream of +those detections carries the same limit**: the 1024 column of the complementarity table, the whole +operating-point-correction table, both cascade tables, both `analysis_out/cascade_gate*.json`, and +the seam-exposure count. Each says so where it appears. #### Complementarity: 61% of RampNet's misses are recoverable, and a union still loses Parity raised the obvious recall-first question — this arm misses 36 ramps where RampNet misses 72, so how much of *RampNet's* miss set does a free, zero-training model already cover? Run through the #35 gate (`scripts/analysis/complementarity.py`, generalized past its Gemini-only -form for this), on the same cached detections, scoring-side only: +form for this), scoring-side only: -| | vistas @384 | **vistas @1024 (parity)** | +| | vistas @384 (published) | **vistas @1024 (parity)** | |---|---:|---:| | found by BOTH | 194 | 220 | | rampnet ONLY | 44 | 18 | -| **challenger ONLY** (rampnet-miss ∩ hit) | 21 | **54** | -| found by NEITHER | 51 | **18** | -| of rampnet's 72 misses, recovered | 21 (29%) | **54 (75%)** | +| **challenger ONLY** (rampnet-miss ∩ hit) | 22 | **54** | +| found by NEITHER | 50 | **18** | +| of rampnet's 72 misses, recovered | 22 (31%) | **54 (75%)** | | null on that subset (same boxes, wrong pano) | 0.090 | 0.143 | | **attributable after the null** | **~15** | **~44** | -| oracle-union recall | 0.835 | **0.942** | -| boxes/pano · above chance (`null_recall.py`) | 4.5 · 0.657 | 6.2 · **0.864** | +| oracle-union recall | 0.839 | **0.942** | +| boxes/pano · above chance (`null_recall.py`) | 4.5 · 0.661 | 6.2 · **0.864** | + +**Which 384 run each column is.** The 384 column is the **published** arm, so both sides of it +are committed: `benchmark/model_detections/mask2former-vistas-curb-cut__richmond.json` for the +challenger and `benchmark/richmond/records.jsonl` for RampNet. One wrinkle in reading it back — +`complementarity.py` and `null_recall.py` take their challenger detections from `.model_cache` +rather than from the published export the way `fp_taxonomy.py` and `silent_witness.py` do, so on a +clean clone the export has to be written into a cache directory first (*Reproducing it* below). +`tests/test_complementarity.py` does that in a temporary directory and asserts this column cell +for cell, so `pytest tests/test_complementarity.py` checks it with no setup at all. + +An earlier version of this column was the same-env A40 control rather than the published run. The +two differ by one detection in 523, which moved two cells by one ramp each: challenger-only 22 → +21 and found-by-nobody 50 → 51. Nothing turned on it, but the control is not published either, so +the column as printed was not re-derivable and did not say which run it was. + +**The 1024 column cannot be re-derived from a clean clone.** The parity detections are not +published (see the caveat under *Resolution parity*), so that column exists only against the +private makelab2 cache. Closing that needs `scripts/analysis/export_model_cache.py --publish-as` +(#123) to give the parity arm its own published name. **Discounted for chance, a free zero-training model finds ~44 of the 72 ramps RampNet misses — 61%.** The null here is measured on the miss subset rather than extrapolated from the split-wide @@ -1430,25 +1458,26 @@ OWLv2's 0.733 null at 74 boxes/pano. **The resolution fix mattered far more here than the headline suggested.** Parity moved F1 by +0.018 and was correctly judged not to change the ranking — but it nearly **tripled** the -attributable complementary gain (~15 → ~44 ramps) and shrank the found-by-nobody core from 51 to +attributable complementary gain (~15 → ~44 ramps) and shrank the found-by-nobody core from 50 to **18**, 5.8% of GT. That core is much smaller than paterson's 88 (22%) or gainesville's 55 (20%), though those are different splits against a different challenger, so read it as suggestive rather than a like-for-like. The general lesson is worth keeping: **a flat headline metric hid a large change in the structure underneath it**, and only the complementarity read surfaced it. -**A naive union is nonetheless dead, and it is not close.** The oracle-union recall of 0.942 is a -*ceiling* — it assumes a combiner that keeps every right call and discards every wrong one, which -does not exist. What a real union pays is both FP bills: +**A naive union of the two loses to RampNet alone, and it is not close.** The oracle-union recall +of 0.942 is a *ceiling* — it assumes a combiner that keeps every right call and discards every +wrong one, which does not exist. What a real union pays is both FP bills: | | P | R | F1 | |---|---:|---:|---:| | rampnet alone | 0.964 | 0.768 | **0.855** | | naive union with vistas @1024 | 0.393 | 0.942 | 0.555 | -| naive union with vistas @384 | 0.450 | 0.835 | 0.585 | +| naive union with vistas @384 | 0.450 | 0.839 | 0.586 | -The economics are the whole story: those 54 ramps arrive with 442 false positives, about **8.2 FPs -per recovered ramp**, against the 9 FPs RampNet currently pays for 238 true positives. So -ensembling by union is not a close call at any operating point on this arm's PR curve. +The false-positive bill decides it: those 54 ramps arrive with 442 false positives, about +**8.2 FPs per recovered ramp**, against the 9 FPs RampNet currently pays for 238 true +positives. So ensembling by union is not a close call at any operating point on this arm's +PR curve. **What that leaves is a gated cascade, and it is a real open question rather than a plan.** The useful form is not "take both models' boxes" but "use this arm's candidates as a *spatial prior* @@ -1487,12 +1516,19 @@ matching the committed `analysis_out/op/corrected_at_0.3.csv`. `complementarity. | oracle-union recall | 0.942 | 0.952 | | naive union F1 | 0.555 | 0.549 | -**So ~14 of the ramps the challenger got credit for recovering are ramps RampNet already has at -the operating point we recommend — the shipped threshold was discarding them.** The deployable -complementary gain is **~30, not ~44**. The recovery *rate* barely moves (75% → 72%), which is the -honest way to read it: the challenger is not preferentially finding the easy sub-threshold ones, -there are simply fewer misses to find. And a naive union stays dead against the stronger baseline -(0.549 vs 0.864). +**Both columns are the parity arm, so neither re-derives from a clean clone** — the challenger +side is the unpublished 1024 cache (see *Resolution parity*). RampNet's side is committed on both +columns: `benchmark/richmond/records.jsonl` at 0.55 and `analysis_out/op_cache/richmond.json` at +0.30. + +**So 16 of the 54 ramps the challenger got credit for recovering are ramps RampNet already has at +the operating point we recommend — the shipped threshold was discarding them.** That is 16 raw, +**~14 after the chance null** (~44 → ~30). RampNet gains 19 hits going 0.55 → 0.30 (72 misses → +53); 16 of the 19 come out of the challenger-recovered cell and the other 3 out of the +found-by-nobody cell, which is why the headline falls by 16 and not by 19. The deployable +complementary gain is **~30, not ~44**. The recovery *rate* barely moves (75% → 72%): the +challenger is not preferentially finding the easy sub-threshold ones, there are simply fewer +misses to find. And a naive union still loses against the stronger baseline (0.549 vs 0.864). #### The cascade gate: live, but the ceiling is ~19 ramps, not 54 @@ -1504,18 +1540,38 @@ RampNet's heatmap at each, reusing #46 Phase 1's instrument verbatim (`site_prof Read pre-registered on #126 before running. Artifacts: `analysis_out/cascade_gate.json` (shipped point) and `analysis_out/cascade_gate_op030.json` (recommended point). +**Both artifacts are committed and neither can be regenerated from a clean clone.** The four-cell +partition inside them was computed against the parity detections, which are not published (see +*Resolution parity*); the RampNet half — one forward per pano — needs the native-res panoramas +from `projectsidewalk/rampnet-benchmark` and a GPU. What a clean clone *can* do is check each file +against itself: `tests/test_cascade_gate.py` re-derives every `cells[]` figure from the same +file's `sites` list, so a hand-copied number in the tables below fails the build. + +**Two things about `cascade_gate.json` specifically, so a regenerated copy is not mistaken for a +changed result.** It was written at `b7342dc`, before `4c192ca` added `rampnet_op_threshold` to the +payload, so it lacks that key while `cascade_gate_op030.json` carries it: a re-run would add +`"rampnet_op_threshold": null` and change the bytes with identical results, which is exactly the +comparison the `newline=""` pinning exists to make possible. And both were written before this +branch took the #132 seam wrap (below). Regenerate both when the parity detections are published. + At **rampnet@0.30**, of the 38 genuinely-complementary ramps: | what RampNet has there | n | what it means | |---|---:|---| | floor peak in radius, **0.05–0.30** | **19** | **promotable** — a peak exists, below threshold. This is the cascade's real target. | | floor peak in radius, ≥0.30 but unmatched | 4 | the greedy matcher gave that peak to an **adjacent GT**. A matcher/σ problem (#130), not a threshold one. | -| no floor peak in radius | 15 | nothing to promote. `act` is 0.215 median — unpeaked heatmap mass `peak_local_max` never called a maximum. | +| no floor peak in radius | 15 | nothing to promote. `act` across these 15 is 0.272 median (0.369 mean) — unpeaked heatmap mass `peak_local_max` never called a maximum. | + +The activation figure in the last row is the median over those **15 rows**, not over the 38-ramp +cell. The cell's own median — `cells[].act_median` in `analysis_out/cascade_gate_op030.json` — is +0.2152, and the 19 promotable rows sit lower still at 0.153. Three subsets, three medians, which +is why the row says which one it is. **So the cascade is live and its ceiling is ~19 ramps on richmond — +6.1 recall points (0.829 → 0.890) before any false-positive cost, which is unmeasured.** That is a real number and it is a long way below the 54 the raw complementarity suggested. Two-fifths of the recoverable set has no -peak to raise, and a further tenth is a matching bug wearing a threshold costume. +peak to raise, and a further tenth is a matching problem (#130) that no threshold prior can +reach. **A negative worth recording: RampNet's own activation does not tell you which misses are recoverable.** `challenger_only` sits at null percentile **0.88** and the hard-core `neither` at @@ -1534,27 +1590,54 @@ measured here**, so "+6.1 recall points" is a ceiling on the benefit with the co The next step, if this is ever picked up, is to build the gate and score it, not to reason further about it. -**Seam exposure, stated because these numbers predate the #132 seam fixes.** This work branched at -`5e20d11`, before `eccadda` (wrap the 360° seam in the matcher) and `f4c71c8` (`peaks_to_dets` -dropped peaks beside the seam) landed. Two consequences, both bounded by measurement rather than -argued away: - -* The greedy match used here does not wrap. `score_pano`'s own docstring records that wrapping - *"moves no metric on any committed split"* while #130's duplicate ground truth masks it, so the - aggregate P/R/F1 are unaffected — but a cell assignment is finer-grained than an aggregate. -* `analysis_out/op_cache/richmond.json` is **unchanged by those commits**, i.e. it was not - regenerated after the `peaks_to_dets` fix, so it can still be missing peaks that sit beside the - seam. That would make a site read "no floor peak in radius" when one exists — it can only - *understate* the promotable count, never inflate it. - -**Measured exposure: 6 of richmond's 310 GT ramps straddle the seam, and only 1 of them is in -`challenger_only`** (the other 5 are in `both`, where neither fix can move the partition in a -direction that matters). So the worst case for the headline is one ramp in 38, and no conclusion -here turns on it. Re-running on a post-#140 main is the clean way to retire the caveat rather than -bound it. +**Seam exposure: the two committed artifacts predate the #132 seam fixes, and the effect has now +been measured rather than bounded.** This work branched at `5e20d11`, before `eccadda` (wrap the +360° seam in the matcher) and `f4c71c8` (`peaks_to_dets` dropped peaks beside the seam) landed. +The branch has since merged `main`, so both fixes are in it, and `complementarity.py`'s own +`matched_gt` — which produces the four cells — now calls the shared wrapping matcher instead of +re-deriving the distance inline. That matters here because `score_pano` supplies the false-positive +counts and union P/R/F1 printed in the same tables and wraps by default, so the two halves of one +output were on different matchers. + +The earlier version of this paragraph quoted `score_pano`'s docstring as saying wrapping *"moves +no metric on any committed split"*. **That is half the sentence.** In full: *"Wrapping moves no +RampNet or YOLO metric on any committed split — but it does move the challengers."* The challenger +is the side being partitioned here, so the half that was dropped is the one that applies, and the +right way to settle it is to measure rather than to cite. + +**Measured, on the cells themselves** (both / rampnet-only / challenger-only / neither), wrapping +against not wrapping: + +| arm | RampNet's side | cells | wrapped | +|---|---|---|---| +| vistas 384 (published) | bundle, ≥ 0.5519 | 194 / 44 / 22 / 50 | identical | +| vistas 384 (published) | op_cache ≥ 0.30 | 202 / 55 / 14 / 39 | identical | +| vistas 384 (published) | op_cache ≥ 0.05 | 213 / 66 / 3 / 28 | identical | +| gemini-3.1-pro-preview, paterson (#35 gate) | bundle | 188 / 83 / 36 / 88 | identical | +| gemini-3.1-pro-preview, paterson (#35 gate) | op_cache ≥ 0.30 | 194 / 90 / 30 / 81 | identical | +| gemini-3.1-pro-preview, paterson (#35 gate) | op_cache ≥ 0.05 | 201 / 98 / 23 / 73 | identical | + +**Zero cell flips, at every threshold, on both arms.** So the published 384 column and the +committed #35 gate numbers are unchanged by the wrap. **The parity arm cannot be re-checked** — +its detections are not published — so for the 1024 columns and both `cascade_gate*.json` the bound +is still the count below rather than a measurement. + +One residual, unchanged by the merge: `analysis_out/op_cache/richmond.json` was last written at +`c7098be` (2026-07-28), i.e. **before** `f4c71c8`, so it can still be missing peaks that sit +beside the seam. That would make a site read "no floor peak in radius" when one exists — it can +only *understate* the promotable count, never inflate it. + +**Measured exposure on the artifacts: 6 of richmond's 310 GT ramps straddle the seam, and only 1 +of them is in `challenger_only`** (the other 5 are in `both`, where neither fix can move the +partition in a direction that matters). So the worst case for the ~19-ramp ceiling is one ramp in +38, and no conclusion here turns on it. Regenerating both artifacts once the parity detections are +published is the clean way to retire that bound. ##### Reproducing it +The scored runs. These need a GPU and the native-resolution panoramas +(`projectsidewalk/rampnet-benchmark`), and they are what produced the parity table: + ```bash # parity (the measurement) python scripts/model_comparison/compare.py benchmark/richmond \ @@ -1568,15 +1651,57 @@ python scripts/model_comparison/compare.py benchmark/richmond \ --models vistas:curb-cut --vistas-input-size 1024 1024 --op-threshold 0.30 ``` -Cost, measured rather than guessed, because the estimate going in was 3–4× and it was wrong in -the cheap direction: **the full 124-pano parity run takes 3m38s** on one A40, and the GPU forward -goes 0.078 s → 0.092 s per view, only **1.17×**. Swin's windowed attention scales far better than +The complementarity, null and cascade reads. Every one of these re-scores detections that are +already cached, so they cost nothing; only `cascade_gate.py` needs a GPU, because it runs +RampNet. `--vistas-input-size` is part of the cache key, so it is also what selects which run +is being read: drop it to read the **published 384** arm instead of the parity arm. + +```bash +# the four cells at parity, with the chance null measured on the miss subset +python scripts/analysis/complementarity.py vistas:curb-cut richmond \ + --vistas-input-size 1024 1024 + +# the same, re-based on the operating point this document recommends +python scripts/analysis/complementarity.py vistas:curb-cut richmond \ + --vistas-input-size 1024 1024 --rampnet-op-threshold 0.30 + +# density vs detection: boxes/pano, the shifted-pano null, above-chance +python scripts/analysis/null_recall.py benchmark/richmond \ + --models rampnet,vistas:curb-cut --vistas-input-size 1024 1024 + +# the cascade gate, at the shipped point and at the recommended one. Needs a GPU +# and the native-res panos; --panos-root is the checkout that holds them. +python scripts/analysis/cascade_gate.py --panos-root /path/to/RampNet \ + --model vistas:curb-cut --vistas-input-size 1024 1024 \ + --json-out analysis_out/cascade_gate.json +python scripts/analysis/cascade_gate.py --panos-root /path/to/RampNet \ + --model vistas:curb-cut --vistas-input-size 1024 1024 \ + --rampnet-op-threshold 0.30 --json-out analysis_out/cascade_gate_op030.json +``` + +`complementarity.py` and `null_recall.py` read `--cache-dir` (default `.model_cache`), which is +git-ignored, so on a clean clone the published detections have to be written into one first. +`benchmark/model_detections/__.json` records the signature they were cached under +and `compare.cache_key(model, signature, city, pano_id)` is the shard name; +`tests/test_complementarity.py` does the whole thing in eight lines and is the shortest working +example. For the **parity** arm there is nothing to write — those detections are not published +(see *Resolution parity*) — so the 1024 commands above run only where that private cache exists. + +**Cost, in both units.** Money: **$0** — makelab2 is lab-owned hardware with no metered +billing, and every read above is free. Time: one leg of three was timed, and **the full 124-pano +parity run takes 3m38s** on one A40. That was measured rather than guessed because the estimate +going in was 3–4× and it was wrong in the cheap direction: the GPU forward goes 0.078 s → +0.092 s per view, only **1.17×**. Swin's windowed attention scales far better than pixel count, and the documented "2.3 s/view" is dominated by reprojection and CPU work, not the -encoder. Peak GPU memory is 1.64 GB. Verified before the run rather than assumed: the override +encoder. Peak GPU memory is 1.64 GB. The same-env 384 control was **not timed** (the same 124 +panos at 1/7 the pixel area, so it is the cheaper of the two), and RampNet's row in that table +costs no GPU at all — `--models rampnet` scores the bundle's committed detections without loading +a model. **So there is no session total to quote; what is recorded is 3m38s for the one leg that +was measured.** Verified before the run rather than assumed: the override reaches the model — `pixel_values` (1, 3, 384, 384) → (1, 3, 1024, 1024) and mask logits (1, 100, 96, 96) → (1, 100, 256, 256) — which a silently no-opping `processor.size` assignment on a new major version would not have done, and which would have made "parity" a second 384 run -wearing a different cache key. +under a different cache key. Two mechanisms, both measured rather than assumed: diff --git a/scripts/analysis/README.md b/scripts/analysis/README.md index 155926ed..f21f0e4c 100644 --- a/scripts/analysis/README.md +++ b/scripts/analysis/README.md @@ -35,6 +35,7 @@ checkout. | `depth_analysis.py` | no | Recall vs true distance / apparent size + the resolution forecast. Needs `gt_depth_da3.json`. | | `farfield_forensics.py` | no | Is the far-field `visible` verdict deck a representative sample, and does apparent size actually separate a far-field hit from a far-field silent miss? (#46 Phase 0.) Committed caches, witness list, gallery verdicts and imagery manifests only. | | `silent_activation.py` | **yes** | Is a `silent` miss attenuated or absent? Reads the heatmap inside each silent miss's match window plus a per-pano azimuth null (#46 Phase 1). Needs the native-res `panos/` (HF `projectsidewalk/rampnet-benchmark`); `--panos-root` points at the checkout holding them. | +| `cascade_gate.py` | **yes** | Is a gated cascade possible? Partitions every GT ramp into `complementarity.py`'s four cells, then reads RampNet's heatmap at each with #46 Phase 1's instrument, so the question "does RampNet already produce something a prior could promote at the ramps the challenger recovers?" gets a bounded answer (#126). Floor peaks come from `analysis_out/op_cache/.json`, not the bundle records. Needs the native-res `panos/` and the challenger already cached — pass the same `--vistas-input-size` the run used. | | `size_analysis.py` | no | Geometry-only size stratification (no depth model) + the hard-miss montage figure. | | `overlap_test.py` | **yes** | Do the threshold and resolution levers target the same ramps? Needs `gt_depth_da3.json`. | | `operating_point_curve.py extract` | **yes** | Inference once → all peaks down to a low score floor → per-pano cache (issue #54). Handles both bundle kinds, so `manual_gold` (independent YOLO GT, no verdict review) is covered too. `--tta` extracts the horizontal-flip-TTA arm instead (#78) — two passes per pano, mirrored heatmap un-flipped and maxed exactly as `stage_two/evaluate.py`; each arm must live in its own `--cache` dir (mixing is refused). | From d1860e54c8d79341c2eaf543df43eb481d78b306 Mon Sep 17 00:00:00 2001 From: Jon Froehlich Date: Thu, 17 Sep 2026 06:55:34 -0700 Subject: [PATCH 14/17] complementarity: one partition loop, one radius, and say when the op_cache has gaps (#126) Review round 1 on #137, findings S3, S4, S5, S6, S7 and S8. S6: the four-cell partition was copied three times -- complementarity.py's main loop, cascade_gate.py, and the regression test's _published_cells -- so the test re-implemented the loop instead of exercising it. It is now one function, partition_cells, called from both scripts and from the tests. The published 384 column is now also pinned at the two op_cache thresholds the doc quotes (202/55/14/39 at 0.30, 213/66/3/28 at 0.05), both from committed inputs. S3: --radius reached matched_gt but not the two score_pano calls, which fell back to the default 0.022. With a non-default radius the cells and the FP bill were on two different matchers, in the one script whose docstring says keeping them on one is the point. Both calls now take radius_sq. No committed number is affected (every one was at the default); the test that would have caught it moves both detections 1.5 R off the ramp and checks that the cells and the FP counts move together when the radius doubles. S4: under --rampnet-op-threshold a pano the op_cache does not list scored as RampNet-blank -- every GT ramp on it a miss -- with no warning in complementarity.py, and cascade_gate.py's probe path (which reads the op_cache whatever the flag) never warned either. Both now count and print it; cascade_gate.py records the count in the payload. richmond's op_cache lists all 124 panos, so nothing committed moves. S5: cascade_gate.py drew every site's null from one random.Random(NULL_SEED) stream in pano order, so a site's null_pct depended on which sites came before it. The miss set differs between the two committed artifacts (19 cell transitions): of the 53 sites carrying a null in both, 43 differ, by up to 0.075, with act and nearest_peak_px identical on all 53. Seeded per site now (site_rng); the committed artifacts predate this and are unchanged, the doc says so beside the 0.88 / 0.925 medians, and a test pins the 43-of-53 drift so the reason is demonstrable rather than remembered. silent_activation.py has the same shape and is left alone: its committed #46 Phase 1 artifacts were written from that stream. S7: --rampnet-op-threshold on a split without an op_cache was a raw FileNotFoundError; it now exits with a message, as cascade_gate.py already did. S8: complementary_null's docstring now states the one construction difference from null_recall.py -- the shifted pano's whole prediction set against only the missed GT -- and why that makes it a slight over-estimate of chance, so the attributable figures are conservative. Tests: 13 new, all CPU-only on committed files. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01E58bhyukgYXphE47jsnA29 --- docs/model_comparison.md | 10 ++ scripts/analysis/cascade_gate.py | 103 ++++++++++-------- scripts/analysis/complementarity.py | 163 ++++++++++++++++++++++------ tests/test_cascade_gate.py | 84 ++++++++++++++ tests/test_complementarity.py | 130 ++++++++++++++++++---- 5 files changed, 389 insertions(+), 101 deletions(-) diff --git a/docs/model_comparison.md b/docs/model_comparison.md index f8057b0f..e0ef96ed 100644 --- a/docs/model_comparison.md +++ b/docs/model_comparison.md @@ -1583,6 +1583,16 @@ find these by looking harder at RampNet's confidence. Against the pre-registered **PARTIAL** branch — signal present, but not at the site — and the peak-level column, not the activation, is what supplies the bounded answer. +One caveat on those two null percentiles, and on any per-site null read across the two +artifacts. Both files were written with **one** random stream consumed in pano order over the +miss-cell sites only, so a site's draw depended on which sites came before it; the miss set +differs between the files (19 cell transitions), and of the 53 sites that carry a null in both, +**43 differ, by up to 0.075**, while `act` and `nearest_peak_px` agree on every one +(`test_the_committed_nulls_came_from_one_stream_and_say_so`). The within-file comparison above +stands. `cascade_gate.py` now seeds per site (`site_rng`), so a regeneration will move individual +`null_pct` values by that much, and the two medians slightly, for reasons that have nothing to do +with the heatmap; that is a reason to regenerate both files together, not a change in the result. + **What would have to be true for the cascade to pay.** Promoting sub-0.30 peaks gated on challenger candidates also promotes them wherever the challenger fires on a driveway and RampNet has a faint bump — and 442 of the challenger's 716 boxes are false positives. That cost is **not diff --git a/scripts/analysis/cascade_gate.py b/scripts/analysis/cascade_gate.py index de7cdd6e..ef686632 100644 --- a/scripts/analysis/cascade_gate.py +++ b/scripts/analysis/cascade_gate.py @@ -80,25 +80,44 @@ class alone cannot separate them: sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, os.path.join(REPO, "scripts", "model_comparison")) -from rampnet.detection_eval import build_ground_truth, radius_sq_for # noqa: E402 +from rampnet.detection_eval import radius_sq_for # noqa: E402 from compare import load_bundle, DetectionCache, cache_key # noqa: E402 from detectors import build_detector # noqa: E402 -from complementarity import matched_gt, model_spec, compare_args # noqa: E402 +from complementarity import ( # noqa: E402 + CELLS, cell_of, compare_args, floor_gap_warning, load_floor_peaks, model_spec, + partition_cells) from silent_activation import ( # noqa: E402 NULL_SEED, NULL_TRIALS, class_of, nearest_peak, null_percentile, seam_of, site_profile) from farfield_forensics import quartiles # noqa: E402 -from operating_point_curve import CACHE_DIR, read_cache # noqa: E402 -CELLS = ("both", "rampnet_only", "challenger_only", "neither") #: Cells where RampNet did NOT find the ramp -- the only ones a null is meaningful for. MISS_CELLS = ("challenger_only", "neither") -def cell_of(rampnet_hit, challenger_hit): - if rampnet_hit: - return "both" if challenger_hit else "rampnet_only" - return "challenger_only" if challenger_hit else "neither" +def site_rng(pid, x, y): + """One RNG per site, seeded from ``NULL_SEED`` and the site's identity. + + A single stream consumed in pano order made a site's ``null_pct`` depend on which + sites preceded it: the miss set differs between the shipped-point and the 0.30 + artifacts (19 cell transitions), so the same site drew different azimuths in + each — 43 of the 53 sites carrying a null in both files differed, by up to 0.075, + with ``act`` and ``nearest_peak_px`` identical on all of them. Seeding per site + makes a site's null a function of its heatmap and nothing else, so a per-site + comparison across runs measures the heatmap rather than the neighbours. + """ + return random.Random(f"{NULL_SEED}:{pid}:{x!r}:{y!r}") + + +def panos_without_floor(panos, floor_peaks): + """Panos the op_cache does not list, in the order given. + + On the probe path a missing pano reads ``peak_in_radius: false`` and + ``nearest_peak_px: null`` for every site on it while the header still says the + floor came from the op_cache — the same silent shift ``partition_cells`` counts + under ``--rampnet-op-threshold``, on the path that did not warn. + """ + return [pid for pid in panos if pid not in floor_peaks] def summarize(rows, cell): @@ -185,9 +204,7 @@ def main(argv=None): # DEFINE rampnet's hits when --rampnet-op-threshold is given. floor_peaks, floor_src, have_op_cache = {}, "op_cache", True try: - cached, _ = read_cache(os.path.join(CACHE_DIR, f"{args.split}.json")) - for pd in cached: - floor_peaks[pd["pano"]] = pd["preds"] + floor_peaks = load_floor_peaks(args.split) except (OSError, ValueError, KeyError): have_op_cache = False floor_src = ("MISSING (fell back to bundle records -- distances are to the " @@ -197,40 +214,19 @@ def main(argv=None): f"{args.split}.json, which could not be read.") # ---- partition every GT ramp into a complementarity cell ------------------ - sites, missing, no_floor = [], 0, 0 - for pid, entry in verdicts.items(): - gt = build_ground_truth(records[pid]["detections"], entry["dets"], - entry["missed"], entry["no_missed"]) - if not gt.fn_confirmed: - continue - cp = cache.get(cache_key(label, sig, args.split, pid)) - if cp is None: - missing += 1 - continue - if args.rampnet_op_threshold is not None: - # A pano the op_cache does not list would score as RampNet-blank, which - # turns every GT on it into a miss. That is a silent shift of the whole - # partition, so it is counted and reported rather than absorbed. - if pid not in floor_peaks: - no_floor += 1 - rp = [q for q in floor_peaks.get(pid, []) - if q[2] >= args.rampnet_op_threshold] - else: - rp = [(d["x_normalized"], d["y_normalized"], d["confidence"]) - for d in records[pid]["detections"]] - mr = matched_gt(rp, gt.gt_points, radius_sq) - mc = matched_gt(cp, gt.gt_points, radius_sq) - for i, (gx, gy) in enumerate(gt.gt_points): - sites.append({"pano": pid, "x": gx, "y": gy, - "cell": cell_of(i in mr, i in mc)}) + # The same loop complementarity.py's table comes from, so the two cannot drift. + part = partition_cells( + records, verdicts, + lambda pid: cache.get(cache_key(label, sig, args.split, pid)), + radius_sq, args.rampnet_op_threshold, + floor_peaks if args.rampnet_op_threshold is not None else None) + sites, missing = part.sites, part.missing if missing: print(f"WARNING: {missing} panos had no cached {label} detections and were " f"skipped. Pass the --vistas-input-size the run used.", flush=True) - if no_floor: - print(f"WARNING: {no_floor} panos are absent from analysis_out/op_cache/" - f"{args.split}.json, so RampNet scored blank on them and every GT ramp " - f"there counts as a miss. Regenerate the op_cache for this split before " - f"reading the cells.", flush=True) + warning = floor_gap_warning(part.no_floor, args.split) + if warning: + print(warning, flush=True) if not sites: sys.exit("No sites -- is the challenger cached for this split/input size?") @@ -240,6 +236,15 @@ def main(argv=None): panos = sorted(by_pano) if args.limit: panos = panos[:args.limit] + # The probe path reads the op_cache for every pano regardless of the threshold + # flag, so a pano it does not list is a gap here too -- and until now this path + # said nothing about it. + no_floor_probe = panos_without_floor(panos, floor_peaks) if have_op_cache else [] + if no_floor_probe: + print(f"WARNING: {len(no_floor_probe)} pano(s) are absent from analysis_out/" + f"op_cache/{args.split}.json, so every site on them reads 'no floor peak' " + f"(nearest_peak_px null) whatever the heatmap says. Regenerate the " + f"op_cache for this split before reading the peak columns.", flush=True) counts = {c: sum(1 for s in sites if s["cell"] == c) for c in CELLS} rn = ("rampnet" if args.rampnet_op_threshold is None @@ -257,7 +262,7 @@ def main(argv=None): + ("bundle records (shipped point)" if args.rampnet_op_threshold is None else f"op_cache >= {args.rampnet_op_threshold:g}"), flush=True) - rng = random.Random(NULL_SEED) + r_px = radius_sq ** 0.5 rows, skipped = [], 0 for i, pid in enumerate(panos, 1): path = pano_path(args.split, pid, args.panos_root) @@ -276,7 +281,6 @@ def main(argv=None): for s in by_pano[pid]: act, off_px, center = site_profile(heat, s["x"], s["y"], radius_sq) npx, nscore = nearest_peak(preds, s["x"], s["y"]) - r_px = radius_sq ** 0.5 row = {**s, "act": round(act, 6), "center": round(center, 6), "argmax_off_px": round(off_px, 1), "nearest_peak_px": None if npx == float("inf") else round(npx, 1), @@ -291,8 +295,13 @@ def main(argv=None): "null_pct": None, "null_med": None, "null_p95": None} # The null is only meaningful where rampnet did NOT find the ramp; the # hit cells are high by construction and are here as a positive control. + # Seeded per site (site_rng), so the draw does not depend on which sites + # came before it -- the committed artifacts predate this and were written + # from one stream, so a regeneration moves individual null_pct values by + # up to 0.075 without any change in the heatmap. if s["cell"] in MISS_CELLS: - a, pct, med, p95 = null_percentile(heat, s["x"], s["y"], rng, + a, pct, med, p95 = null_percentile(heat, s["x"], s["y"], + site_rng(pid, s["x"], s["y"]), radius_sq=radius_sq) row.update(null_pct=round(pct, 4), null_med=round(med, 6), null_p95=round(p95, 6)) @@ -337,8 +346,10 @@ def main(argv=None): "rampnet_op_threshold": args.rampnet_op_threshold, "vistas_input_size": args.vistas_input_size, "radius": args.radius, "null_trials": NULL_TRIALS, - "null_seed": NULL_SEED, "n_sites": len(rows), + "null_seed": NULL_SEED, "null_rng": "per-site", + "n_sites": len(rows), "n_panos": len(panos), "skipped_sites": skipped, + "panos_without_floor_peaks": len(no_floor_probe), "cells": summaries, "sites": rows} os.makedirs(os.path.dirname(os.path.abspath(args.json_out)), exist_ok=True) # newline="" so a Windows re-run does not emit CRLF and break byte-comparison. diff --git a/scripts/analysis/complementarity.py b/scripts/analysis/complementarity.py index df94f190..f5d8687d 100644 --- a/scripts/analysis/complementarity.py +++ b/scripts/analysis/complementarity.py @@ -42,6 +42,7 @@ script grew past one provider. """ import argparse +from collections import namedtuple import os import sys @@ -58,6 +59,106 @@ from detectors import build_detector, parse_model_spec, PROVIDERS # noqa: E402 from operating_point_curve import CACHE_DIR, read_cache # noqa: E402 +#: The four complementarity cells, in table order. +CELLS = ("both", "rampnet_only", "challenger_only", "neither") + + +def cell_of(rampnet_hit, challenger_hit): + """Which of the four cells a GT ramp falls in.""" + if rampnet_hit: + return "both" if challenger_hit else "rampnet_only" + return "challenger_only" if challenger_hit else "neither" + + +def load_floor_peaks(split): + """``{pano_id: [(x, y, score), ...]}`` from ``analysis_out/op_cache/.json``. + + Raises ``OSError`` / ``ValueError`` / ``KeyError`` exactly as ``read_cache`` does; + callers decide whether a missing op_cache is fatal (this script: it is, the + threshold has nothing to apply to) or a fallback (``cascade_gate.py``). + """ + cached, _ = read_cache(os.path.join(CACHE_DIR, f"{split}.json")) + return {pd["pano"]: pd["preds"] for pd in cached} + + +def floor_gap_warning(no_floor, split): + """The warning both scripts print when the op_cache is missing panos, or ``None``. + + A pano the op_cache does not list scores as RampNet-blank -- every GT ramp on it + becomes a miss -- while the header still says RampNet came from the op_cache. + That is a silent shift of the whole partition in the direction that under-states + the cascade, so it is counted and said out loud rather than absorbed. + """ + if not no_floor: + return None + return (f"WARNING: {no_floor} pano(s) are absent from analysis_out/op_cache/" + f"{split}.json, so RampNet scored blank on them and every GT ramp there " + f"counts as a miss. Regenerate the op_cache for this split before reading " + f"the cells.") + + +#: What ``partition_cells`` returns. ``sites`` is one row per GT ramp +#: (``pano``, ``x``, ``y``, ``cell``); ``counts`` is the four cells; ``r_fp``/``c_fp`` +#: are RampNet's and the challenger's false positives on the same panos, from the same +#: matcher; ``shift_rows`` feeds ``complementary_null``; ``no_floor`` counts panos the +#: op_cache did not list (only meaningful when it was the source). +Partition = namedtuple( + "Partition", "sites counts r_fp c_fp shift_rows panos missing no_floor") + + +def partition_cells(records, verdicts, challenger_for, radius_sq, + rampnet_op_threshold=None, floor_peaks=None): + """Partition every recall-eligible GT ramp into the four complementarity cells. + + The one loop behind this script's table, ``cascade_gate.py``'s partition and the + regression tests -- it used to be copied into all three, so a change to the + threshold filter or the op_cache fallback in one did not fail the others. + + ``challenger_for(pano_id)`` returns the challenger's cached predictions for a pano + or ``None`` when it has none (the pano is then skipped and counted in + ``missing``). RampNet's side is the bundle's shipped detections unless + ``rampnet_op_threshold`` is given, in which case it is ``floor_peaks`` (from + ``load_floor_peaks``) filtered at that threshold. + + The cells and the false-positive counts come from one matcher at one radius: + ``matched_gt`` and ``score_pano`` are both handed ``radius_sq``. Before that, + ``--radius`` reached the cells but ``score_pano`` fell back to its default, so a + non-default radius printed cells and an FP bill measured two different ways. + """ + if (rampnet_op_threshold is None) != (floor_peaks is None): + raise ValueError("rampnet_op_threshold and floor_peaks go together: the " + "threshold is applied to the floor peaks and to nothing else") + sites, shift_rows = [], [] + counts = dict.fromkeys(CELLS, 0) + r_fp = c_fp = panos = missing = no_floor = 0 + for pid, entry in verdicts.items(): + gt = build_ground_truth(records[pid]["detections"], entry["dets"], + entry["missed"], entry["no_missed"]) + if not gt.fn_confirmed: + continue + cp = challenger_for(pid) + if cp is None: + missing += 1 + continue + if floor_peaks is not None: + if pid not in floor_peaks: + no_floor += 1 + rp = [q for q in floor_peaks.get(pid, []) if q[2] >= rampnet_op_threshold] + else: + rp = [(d["x_normalized"], d["y_normalized"], d["confidence"]) + for d in records[pid]["detections"]] + mr = matched_gt(rp, gt.gt_points, radius_sq) + mc = matched_gt(cp, gt.gt_points, radius_sq) + for i, (gx, gy) in enumerate(gt.gt_points): + cell = cell_of(i in mr, i in mc) + counts[cell] += 1 + sites.append({"pano": pid, "x": gx, "y": gy, "cell": cell}) + r_fp += score_pano(rp, gt, radius_sq).fp + c_fp += score_pano(cp, gt, radius_sq).fp + shift_rows.append((cp, [g for i, g in enumerate(gt.gt_points) if i not in mr])) + panos += 1 + return Partition(sites, counts, r_fp, c_fp, shift_rows, panos, missing, no_floor) + def matched_gt(preds, gt_points, radius_sq): """Which GT ramps a model covers: greedy 1:1, exactly as ``score_pano`` matches. @@ -103,6 +204,16 @@ def complementary_null(rows, radius_sq): rampnet's misses are a biased sample (far-field, adjacent pairs), and those are exactly the places box density differs. Hence measuring it here. + One construction difference from ``null_recall.py``, stated so the two are not + read as the same number: the shifted pano's *whole* prediction set is matched + against only the missed GT, whereas the real ``c_only`` cell was matched against + all GT on the pano (a box that lands on a found ramp there is spent). Each box + therefore has more targets here than it had in the real pairing, so this null is + a slight over-estimate of chance and the "attributable" figures quoted after it + are conservative. ``null_recall.py`` matches against all GT; that the two land + close on richmond (0.143 here against 0.145 there) is the evidence the bias is + small, not a sign they are the same measurement. + Returns (mean, max) as a fraction of the missed GT. """ preds = [p for p, _ in rows] @@ -207,48 +318,32 @@ def main(): floor_peaks = None if args.rampnet_op_threshold is not None: - cached, _ = read_cache(os.path.join(CACHE_DIR, f"{args.split}.json")) - floor_peaks = {pd["pano"]: pd["preds"] for pd in cached} + try: + floor_peaks = load_floor_peaks(args.split) + except (OSError, ValueError, KeyError) as e: + sys.exit("--rampnet-op-threshold needs analysis_out/op_cache/" + f"{args.split}.json, which could not be read ({e}). Generate it " + "with scripts/analysis/operating_point_curve.py, or drop the " + "flag to score RampNet from the bundle's shipped detections.") print(f"rampnet re-sourced from op_cache at >= {args.rampnet_op_threshold} " f"(bundle records are the shipped point and are NOT used)\n") - n = both = r_only = c_only = neither = 0 - r_fp = c_fp = 0 - panos = missing = 0 - # (challenger preds, GT points rampnet MISSED) per pano, for the null below - shift_rows = [] - for pid, entry in verdicts.items(): - gt = build_ground_truth(records[pid]["detections"], entry["dets"], - entry["missed"], entry["no_missed"]) - if not gt.fn_confirmed: - continue - cp = cache.get(cache_key(label, sig, args.split, pid)) - if cp is None: - missing += 1 - continue - if floor_peaks is not None: - rp = [p for p in floor_peaks.get(pid, []) - if p[2] >= args.rampnet_op_threshold] - else: - rp = [(d["x_normalized"], d["y_normalized"], d["confidence"]) - for d in records[pid]["detections"]] - mr, mc = matched_gt(rp, gt.gt_points, radius_sq), matched_gt(cp, gt.gt_points, radius_sq) - for i in range(len(gt.gt_points)): - r, c = i in mr, i in mc - both += r and c - r_only += r and not c - c_only += c and not r - neither += not r and not c - n += len(gt.gt_points) - r_fp += score_pano(rp, gt).fp - c_fp += score_pano(cp, gt).fp - shift_rows.append((cp, [g for i, g in enumerate(gt.gt_points) if i not in mr])) - panos += 1 + part = partition_cells( + records, verdicts, + lambda pid: cache.get(cache_key(label, sig, args.split, pid)), + radius_sq, args.rampnet_op_threshold, floor_peaks) + both, r_only, c_only, neither = (part.counts[c] for c in CELLS) + n = sum(part.counts.values()) + r_fp, c_fp, shift_rows = part.r_fp, part.c_fp, part.shift_rows + panos, missing = part.panos, part.missing if not n: sys.exit("No recall-eligible panos with cached detections -- nothing to compare. " "Run compare.py for this model/split first (and pass the SAME " "--vistas-input-size, which is part of the cache key).") + warning = floor_gap_warning(part.no_floor, args.split) + if warning: + print(warning + "\n") r_tp, c_tp, union = both + r_only, both + c_only, both + r_only + c_only r_miss = c_only + neither diff --git a/tests/test_cascade_gate.py b/tests/test_cascade_gate.py index 7f6d3e40..692015c5 100644 --- a/tests/test_cascade_gate.py +++ b/tests/test_cascade_gate.py @@ -17,19 +17,26 @@ """ import json import os +import random import sys +import pytest + REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, REPO) sys.path.insert(0, os.path.join(REPO, "scripts", "analysis")) sys.path.insert(0, os.path.join(REPO, "scripts", "model_comparison")) import cascade_gate as cg # noqa: E402 +import silent_activation as sa # noqa: E402 from farfield_forensics import quartiles # noqa: E402 +from rampnet.detection_eval import radius_sq_for # noqa: E402 OUT = os.path.join(REPO, "analysis_out") SHIPPED = os.path.join(OUT, "cascade_gate.json") OP030 = os.path.join(OUT, "cascade_gate_op030.json") +RSQ = radius_sq_for() +R_PX = RSQ ** 0.5 # 22.5 heatmap px def _row(cell, **kw): @@ -141,6 +148,62 @@ def test_the_class_shares_sum_to_one(): assert sum(out["class_share"].values()) == 1.0 +# --------------------------------------------------------------------------- # +# site_rng — a site's null must not depend on which sites came before it +# --------------------------------------------------------------------------- # +def _heat_with_bump(): + # A ramp along the site's row, so every azimuth draws a different value and the + # null's median and p95 depend on which azimuths were drawn. + h = [[0.0] * 1024 for _ in range(512)] + for c in range(1024): + h[256][c] = 0.03 * c / 1024 + h[256][512] = 0.04 + return h + + +def test_a_sites_null_is_the_same_whatever_ran_before_it(): + h = _heat_with_bump() + x, y = 512 / 1024, 256 / 512 + first = sa.null_percentile(h, x, y, cg.site_rng("p", x, y), trials=50) + # Consume a different amount of "other sites" work, then ask again. + for other in range(3): + sa.null_percentile(h, 0.1 * (other + 1), y, cg.site_rng("p", 0.1 * (other + 1), y), + trials=50) + again = sa.null_percentile(h, x, y, cg.site_rng("p", x, y), trials=50) + assert first == again + + +def test_one_stream_shared_across_sites_did_depend_on_order(): + # The shape being replaced: the same site, read second instead of first from one + # stream, draws different azimuths. Guarded so the reason for site_rng stays + # demonstrable rather than remembered. + h = _heat_with_bump() + x, y = 512 / 1024, 256 / 512 + rng = random.Random(sa.NULL_SEED) + alone = sa.null_percentile(h, x, y, rng, trials=50)[2:] + rng = random.Random(sa.NULL_SEED) + sa.null_percentile(h, 0.1, y, rng, trials=50) + after_another = sa.null_percentile(h, x, y, rng, trials=50)[2:] + assert alone != after_another + + +def test_different_sites_get_different_streams(): + a = cg.site_rng("p", 0.5, 0.5).random() + assert a != cg.site_rng("p", 0.5, 0.6).random() + assert a != cg.site_rng("q", 0.5, 0.5).random() + assert a == cg.site_rng("p", 0.5, 0.5).random() + + +# --------------------------------------------------------------------------- # +# panos_without_floor — the probe path's op_cache gap, which used to be silent +# --------------------------------------------------------------------------- # +def test_a_pano_the_op_cache_does_not_list_is_named(): + floor = {"a": [(0.5, 0.5, 0.2)], "b": []} + assert cg.panos_without_floor(["a", "b", "c"], floor) == ["c"] + # Listed with zero floor peaks is an answer, not a gap. + assert cg.panos_without_floor(["b"], floor) == [] + + # --------------------------------------------------------------------------- # # the committed artifacts — every cell figure re-derives from the sites list # --------------------------------------------------------------------------- # @@ -201,6 +264,27 @@ def test_the_no_peak_rows_have_their_own_activation_median(): assert cell["act_median"] == 0.2152 +def test_the_committed_nulls_came_from_one_stream_and_say_so(): + # Both artifacts predate site_rng: their nulls were drawn from one stream in pano + # order, so a site carries a different draw in each file (43 of the 53 sites with + # a null in both differ, by up to 0.075) while act and nearest_peak_px agree on + # every one. A regeneration with per-site seeding moves those values without any + # change in the heatmap, which is why neither file records "null_rng". + shipped, op030 = _payload(SHIPPED), _payload(OP030) + assert "null_rng" not in shipped and "null_rng" not in op030 + key = lambda s: (s["pano"], s["x"], s["y"]) # noqa: E731 + a = {key(s): s for s in shipped["sites"]} + both = [(a[key(s)], s) for s in op030["sites"] + if key(s) in a and a[key(s)]["null_pct"] is not None + and s["null_pct"] is not None] + assert len(both) == 53 + differ = [(x, y) for x, y in both if x["null_pct"] != y["null_pct"]] + assert len(differ) == 43 + assert max(abs(x["null_pct"] - y["null_pct"]) for x, y in differ) == pytest.approx(0.075) + assert all(x["act"] == y["act"] and x["nearest_peak_px"] == y["nearest_peak_px"] + for x, y in both) + + def test_moving_to_the_recommended_threshold_takes_sixteen_from_the_recovered_cell(): # docs/model_comparison.md: RampNet gains 19 hits going 0.55 -> 0.30 (72 -> 53 # misses), of which 16 come out of challenger_only and 3 out of neither. The diff --git a/tests/test_complementarity.py b/tests/test_complementarity.py index e330d131..f8d8442f 100644 --- a/tests/test_complementarity.py +++ b/tests/test_complementarity.py @@ -21,7 +21,12 @@ * **``complementary_null``** is the discount every attributable-gain number in ``docs/model_comparison.md`` is quoted after, so it is checked against cases whose answer is arithmetic rather than measurement. -* the published 384 richmond column, cell for cell. +* **``partition_cells``** is the one loop behind this script's table, the cascade + gate's partition and the regression tests below — the tests call it rather than + re-implementing it, so a bug in the threshold filter or the op_cache fallback fails + here instead of being copied into a third place. +* the published 384 richmond column, cell for cell, at the shipped point and at the + two op_cache thresholds the doc quotes. """ import argparse import json @@ -106,6 +111,87 @@ def test_the_cells_and_the_fp_counts_come_from_one_matcher(): assert score_pano(preds, gt, RSQ).fp == 0 +def _one_pano(rampnet_x, challenger_x): + """A single recall-eligible pano with one GT ramp at x=0.5, RampNet's shipped + detection at ``rampnet_x`` and the challenger's at ``challenger_x``.""" + records = {"p": {"detections": [{"x_normalized": rampnet_x, "y_normalized": 0.5, + "confidence": 0.9}]}} + verdicts = {"p": {"dets": [False], "missed": [{"x": 0.5, "y": 0.5}], + "no_missed": False}} + return records, verdicts, {"p": [(challenger_x, 0.5, 0.9)]} + + +def test_a_non_default_radius_reaches_the_cells_and_the_fp_counts_alike(): + # Both models' detections sit 1.5 default radii from the ramp. At the default + # radius each is a miss AND a false positive; at twice the radius each is a hit + # and no false positive. `--radius` used to reach matched_gt only, so the cells + # moved to "both" while score_pano, still at its default, kept billing two FPs. + records, verdicts, challenger = _one_pano(0.5 + 1.5 * R_NORM, 0.5 - 1.5 * R_NORM) + tight = cx.partition_cells(records, verdicts, challenger.get, RSQ) + assert tight.counts["neither"] == 1 and (tight.r_fp, tight.c_fp) == (1, 1) + wide = cx.partition_cells(records, verdicts, challenger.get, radius_sq_for(0.044)) + assert wide.counts["both"] == 1 and (wide.r_fp, wide.c_fp) == (0, 0) + + +# --------------------------------------------------------------------------- # +# partition_cells — the loop three places used to carry a copy of +# --------------------------------------------------------------------------- # +def test_the_threshold_filters_the_floor_peaks_and_nothing_else(): + records, verdicts, challenger = _one_pano(0.5, 0.5) + floor = {"p": [(0.5, 0.5, 0.20)]} # a peak below 0.30 + at_030 = cx.partition_cells(records, verdicts, challenger.get, RSQ, 0.30, floor) + at_005 = cx.partition_cells(records, verdicts, challenger.get, RSQ, 0.05, floor) + assert at_030.counts["challenger_only"] == 1 + assert at_005.counts["both"] == 1 + # The shipped detection in records.jsonl is not consulted under the flag. + assert at_030.sites == [{"pano": "p", "x": 0.5, "y": 0.5, "cell": "challenger_only"}] + + +def test_the_threshold_and_the_floor_peaks_go_together(): + records, verdicts, challenger = _one_pano(0.5, 0.5) + with pytest.raises(ValueError): + cx.partition_cells(records, verdicts, challenger.get, RSQ, 0.30, None) + with pytest.raises(ValueError): + cx.partition_cells(records, verdicts, challenger.get, RSQ, None, {"p": []}) + + +def test_a_pano_the_challenger_never_cached_is_skipped_and_counted(): + records, verdicts, _ = _one_pano(0.5, 0.5) + part = cx.partition_cells(records, verdicts, lambda pid: None, RSQ) + assert part.missing == 1 and part.panos == 0 and sum(part.counts.values()) == 0 + + +def test_a_pano_missing_from_the_op_cache_is_counted_not_absorbed(): + # Under --rampnet-op-threshold a pano the op_cache does not list scores as + # RampNet-blank: every GT ramp on it becomes a miss. It used to do so silently in + # this script (cascade_gate.py warned; this one did not). + records, verdicts, challenger = _one_pano(0.5, 0.5) + part = cx.partition_cells(records, verdicts, challenger.get, RSQ, 0.30, {}) + assert part.no_floor == 1 + assert part.counts["challenger_only"] == 1 # RampNet's shipped hit is gone + assert "1 pano(s) are absent" in cx.floor_gap_warning(part.no_floor, "richmond") + assert cx.floor_gap_warning(0, "richmond") is None + + +def test_the_missed_gt_handed_to_the_null_is_what_rampnet_missed(): + records, verdicts, challenger = _one_pano(0.5 + 2 * R_NORM, 0.5) + part = cx.partition_cells(records, verdicts, challenger.get, RSQ) + assert part.shift_rows == [([(0.5, 0.5, 0.9)], [(0.5, 0.5)])] + + +def test_a_split_without_an_op_cache_exits_with_a_message_not_a_traceback( + tmp_path, monkeypatch): + # --rampnet-op-threshold on a split whose op_cache is missing used to be a raw + # FileNotFoundError. cascade_gate.py already exits with a message; this mirrors it. + monkeypatch.setattr(cx, "CACHE_DIR", str(tmp_path / "no_op_cache")) + monkeypatch.setattr(sys, "argv", [ + "complementarity.py", "vistas:curb-cut", "richmond", + "--rampnet-op-threshold", "0.3", "--cache-dir", str(tmp_path / "no_model_cache")]) + with pytest.raises(SystemExit) as e: + cx.main() + assert "op_cache" in str(e.value) and "richmond" in str(e.value) + + # --------------------------------------------------------------------------- # # model_spec — the legacy positional form, and the typo that used to be silent # --------------------------------------------------------------------------- # @@ -210,13 +296,15 @@ def test_the_null_averages_over_every_non_identity_shift(): # --------------------------------------------------------------------------- # # regression — the published 384 richmond column, read from committed files only # --------------------------------------------------------------------------- # -def _published_cells(tmp_path): +def _published_cells(tmp_path, rampnet_op_threshold=None): """The four cells for the published Vistas 384 arm on richmond. Rebuilds a ``.model_cache``-shaped directory from the published export and reads it back through ``DetectionCache``/``cache_key``, i.e. the path the script itself takes. That is deliberate: the lookup only succeeds if the signature reconstructed - from ``compare_args`` is the one the export was written under. + from ``compare_args`` is the one the export was written under. The partition is + the script's own ``partition_cells``, not a copy of it, so the threshold filter + and the op_cache fallback are under test here too. """ published = json.load(open(PUBLISHED, encoding="utf-8")) cache = DetectionCache(str(tmp_path / "cache")) @@ -227,24 +315,14 @@ def _published_cells(tmp_path): label, det = build_detector("vistas", "curb-cut", {}, cx.compare_args(_args())) sig = det.signature() records, verdicts, _ = load_bundle(os.path.join(REPO, "benchmark", "richmond")) - counts = {"both": 0, "rampnet_only": 0, "challenger_only": 0, "neither": 0} - for pid, entry in verdicts.items(): - gt = build_ground_truth(records[pid]["detections"], entry["dets"], - entry["missed"], entry["no_missed"]) - if not gt.fn_confirmed: - continue - cp = cache.get(cache_key(label, sig, "richmond", pid)) - assert cp is not None, f"{pid}: signature drifted from the published export" - rp = [(d["x_normalized"], d["y_normalized"], d["confidence"]) - for d in records[pid]["detections"]] - mr = cx.matched_gt(rp, gt.gt_points, RSQ) - mc = cx.matched_gt(cp, gt.gt_points, RSQ) - for i in range(len(gt.gt_points)): - r, c = i in mr, i in mc - key = ("both" if r and c else "rampnet_only" if r else - "challenger_only" if c else "neither") - counts[key] += 1 - return counts + floor = (cx.load_floor_peaks("richmond") if rampnet_op_threshold is not None + else None) + part = cx.partition_cells( + records, verdicts, lambda pid: cache.get(cache_key(label, sig, "richmond", pid)), + RSQ, rampnet_op_threshold, floor) + assert part.missing == 0, "signature drifted from the published export" + assert part.no_floor == 0 + return part.counts def test_the_published_384_column_reproduces(tmp_path): @@ -261,3 +339,13 @@ def test_the_384_column_adds_up_to_richmond_s_recall_eligible_ground_truth(tmp_p # which is the recall its published row reports. assert counts["challenger_only"] + counts["neither"] == 72 assert counts["both"] + counts["challenger_only"] == 216 + + +def test_the_384_column_at_the_two_op_cache_thresholds_reproduces(tmp_path): + # docs/model_comparison.md, the seam-exposure table: the published 384 arm with + # RampNet re-sourced from analysis_out/op_cache/richmond.json at the recommended + # 0.30 and at the 0.05 floor. Both sides committed, so a clean clone checks them. + assert _published_cells(tmp_path, 0.30) == {"both": 202, "rampnet_only": 55, + "challenger_only": 14, "neither": 39} + assert _published_cells(tmp_path, 0.05) == {"both": 213, "rampnet_only": 66, + "challenger_only": 3, "neither": 28} From cc2299e132b30701348ef2920b4d2c2e8bfc2124 Mon Sep 17 00:00:00 2001 From: Jon Froehlich Date: Thu, 17 Sep 2026 06:56:29 -0700 Subject: [PATCH 15/17] Cascade gate: the "no floor peak" row is a neighbour's shoulder, not unpeaked mass (#126) Review round 1 on #137, finding S1. This changes a scientific reading in docs/model_comparison.md; the counts do not move, the interpretation does. The cascade table said of the 15 challenger_only sites with no floor peak in radius: "nothing to promote -- unpeaked heatmap mass peak_local_max never called a maximum", and the text below it read them as "two-fifths of the recoverable set has no peak to raise". The committed artifact's own columns contradict that. Joining analysis_out/cascade_gate_op030.json to analysis_out/op_cache/richmond.json (R = 22.5 px): - 11 of 15 have a floor peak 1-2 R away (nearest-peak median 35.0 px), and 11 of 15 have the in-window maximum on the window edge (argmax_off_px median 22.4). That is a neighbouring mode's shoulder reaching into the window -- #46 Phase 1's `tail` -- and class_of puts the 15 at 12 tail / 3 faint_local / 0 absent. - For 11 of 15 the nearest peak is >= 0.30 and the greedy match at 0.30 already gave it to another GT on the pano (7 of those within 2 R). That is the #130 mechanism the table assigned only to its 4-row; all 4 of that row are claimed the same way. One cause, not two. - Only 4 have no floor peak within 2 R, and one of those is the seam site 723487737079243 (x = 0.0069): act 0.946 at 7.4 px, centre 0.78, no op_cache peak within 117 px -- the pre-f4c71c8 seam dropout made concrete. A regenerated op_cache would list that peak, making it a RampNet hit at 0.30 and taking it out of challenger_only (38 -> 37). The doc now re-cuts the 38 exhaustively -- 19 promotable / 11 claimed by an adjacent GT (4 in R + 7 at 1-2 R) / 4 unclaimed at 1-2 R / 4 nothing within 2 R -- reports the nearest-peak and argmax medians for the row, adds the class_of shares the #126 pre-registration promised for comparability with Phase 1's 8 / 62 / 30, and withdraws "unpeaked heatmap mass" from the table, the script's docstring and its printed footer. The 19-ramp ceiling and the 15 count stand. cascade_gate.py gains no_peak_profile (the row's own medians, edge count, within/beyond 2 R, classes) and claimed_by_adjacent (re-runs the greedy match at the run's threshold and asks whether each site's nearest floor peak went to a different GT), prints both per miss cell, and writes nearest_peak_claimed per site on new runs. The committed artifacts are not regenerated (no GPU here, and the parity detections are unpublished); the tests re-derive every figure above from them plus the committed op_cache, so the doc's reading of that row is pinned: median 35.0 / 22.4, 11 on the edge, 11 within 2 R, 4 beyond, 12/3/0, 11 claimed (7 within 2 R), 4 of 4 in the >= 0.30 row claimed, and the seam site's 0.946-at-7.4-px profile. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01E58bhyukgYXphE47jsnA29 --- docs/model_comparison.md | 41 ++++++-- scripts/analysis/cascade_gate.py | 118 ++++++++++++++++++++-- tests/test_cascade_gate.py | 161 ++++++++++++++++++++++++++++++- 3 files changed, 303 insertions(+), 17 deletions(-) diff --git a/docs/model_comparison.md b/docs/model_comparison.md index e0ef96ed..96f06778 100644 --- a/docs/model_comparison.md +++ b/docs/model_comparison.md @@ -1560,18 +1560,44 @@ At **rampnet@0.30**, of the 38 genuinely-complementary ramps: |---|---:|---| | floor peak in radius, **0.05–0.30** | **19** | **promotable** — a peak exists, below threshold. This is the cascade's real target. | | floor peak in radius, ≥0.30 but unmatched | 4 | the greedy matcher gave that peak to an **adjacent GT**. A matcher/σ problem (#130), not a threshold one. | -| no floor peak in radius | 15 | nothing to promote. `act` across these 15 is 0.272 median (0.369 mean) — unpeaked heatmap mass `peak_local_max` never called a maximum. | +| no floor peak in radius | 15 | nothing *of this ramp's* to promote — but not, for most of them, nothing nearby. `act` across these 15 is 0.272 median (0.369 mean); the nearest floor peak is a median **35.0 px** away (R = 22.5 px) and the in-window maximum sits on the window edge (median `argmax_off_px` **22.4**, 11 of 15 within 0.5 px of R). That is a neighbouring mode's shoulder reaching into the window, not mass the extractor overlooked. See the re-cut below. | The activation figure in the last row is the median over those **15 rows**, not over the 38-ramp cell. The cell's own median — `cells[].act_median` in `analysis_out/cascade_gate_op030.json` — is 0.2152, and the 19 promotable rows sit lower still at 0.153. Three subsets, three medians, which is why the row says which one it is. +**What the 15 "no peak in radius" sites are, from the artifact's own columns.** An earlier version +of this table called them "unpeaked heatmap mass `peak_local_max` never called a maximum", and +that reading is withdrawn: the committed `sites[]` rows, joined to `analysis_out/op_cache/richmond.json`, +say the opposite for most of them. Re-cutting the 38 exhaustively, by where each site's nearest +floor peak is and whether the greedy match at 0.30 already gave that peak to another GT on the +pano (`cascade_gate.claimed_by_adjacent`, pinned in `tests/test_cascade_gate.py`): + +| the 38 recoverable ramps at rampnet@0.30 | n | mechanism | +|---|---:|---| +| floor peak in radius, 0.05–0.30 | **19** | promotable — the cascade's target, unchanged | +| nearest floor peak ≥0.30 and **claimed by an adjacent GT** — 4 inside R, 7 at 1–2 R (26.8–44.1 px) | **11** | the #130 matcher/σ mechanism; the old "4" row and most of the old "15" row are one cause | +| nearest floor peak at 1–2 R, unclaimed (23.5 px @0.643, 24.3 px @0.242, 32.2 px @0.358, 42.5 px @0.143) | 4 | a peak just outside the window; would need a wider radius, not a lower threshold | +| no floor peak within 2 R (51–117 px) | 4 | genuinely nothing near — and one of the 4 is the seam site below, where the heatmap *has* a peak the op_cache dropped | + +So the row that read as "two-fifths of the recoverable set has no peak to raise" is 11 parts +matching problem, 4 parts near-miss geometry and 4 parts absence. `class_of`, the #46 Phase 1 +decomposition the pre-registration promised for comparability, puts the 15 at **12 `tail` / 3 +`faint_local` / 0 `absent`** (80 / 20 / 0%, against Phase 1's 62 / 30 / 8% over silent misses); +over the whole 38-ramp cell it is 35 / 3 / 0, and the 15-ramp `neither` cell is 15 / 0 / 0. Both +artifacts carry these in `cells[].classes`. The seam site is the one case of a different kind: +`723487737079243` at x = 0.0069 has `act` 0.946 **7.4 px** from the ramp, centre 0.78, and no +op_cache peak within 117 px — the `f4c71c8` seam dropout bounded abstractly further down, made +concrete. A regenerated op_cache would almost certainly list that peak, which makes the site a +RampNet **hit** at 0.30 and moves it out of `challenger_only` (38 → 37) rather than into any +row of this table. + **So the cascade is live and its ceiling is ~19 ramps on richmond — +6.1 recall points (0.829 → 0.890) before any false-positive cost, which is unmeasured.** That is a real number and it is a -long way below the 54 the raw complementarity suggested. Two-fifths of the recoverable set has no -peak to raise, and a further tenth is a matching problem (#130) that no threshold prior can -reach. +long way below the 54 the raw complementarity suggested. Of the other 19, eleven are a matching +problem (#130) that no threshold prior can reach — a σ or matcher change is what would act on +them — four sit just outside the window, and four have nothing near them. **A negative worth recording: RampNet's own activation does not tell you which misses are recoverable.** `challenger_only` sits at null percentile **0.88** and the hard-core `neither` at @@ -1640,8 +1666,11 @@ only *understate* the promotable count, never inflate it. **Measured exposure on the artifacts: 6 of richmond's 310 GT ramps straddle the seam, and only 1 of them is in `challenger_only`** (the other 5 are in `both`, where neither fix can move the partition in a direction that matters). So the worst case for the ~19-ramp ceiling is one ramp in -38, and no conclusion here turns on it. Regenerating both artifacts once the parity detections are -published is the clean way to retire that bound. +38, and no conclusion here turns on it. That one ramp is now identified rather than bounded: +`723487737079243` at x = 0.0069 (see the re-cut of the 38 above) has a 0.946 heatmap peak 7.4 px +from the ramp and no op_cache peak within 117 px, so on a regenerated op_cache it is a RampNet hit +at 0.30 and leaves `challenger_only` (38 → 37) — the ceiling of 19 does not move. Regenerating +both artifacts once the parity detections are published is the clean way to retire that bound. ##### Reproducing it diff --git a/scripts/analysis/cascade_gate.py b/scripts/analysis/cascade_gate.py index ef686632..103365e2 100644 --- a/scripts/analysis/cascade_gate.py +++ b/scripts/analysis/cascade_gate.py @@ -38,9 +38,16 @@ class alone cannot separate them: * **a floor peak inside the radius** — the model localized the ramp and the detection was lost *downstream*, either to the shipped threshold or to the greedy matcher giving that peak to an adjacent GT. Recoverable, and recoverable **without a second model**. -* **no floor peak inside the radius** — ``act`` is unpeaked heatmap mass that - ``peak_local_max`` never called a local maximum. A threshold prior has nothing to - promote, because promotion operates on peaks. +* **no floor peak inside the radius** — a threshold prior has nothing *of this ramp's* + to promote, because promotion operates on peaks. ``act`` there is usually **not** + unpeaked mass: on the committed richmond run the nearest floor peak sits a median + 35 px away (1-2 R) and the in-window maximum sits on the window edge (median + ``argmax_off_px`` 22.4 of 22.5), i.e. a neighbouring mode's shoulder reaching in — + #46 Phase 1's ``tail``, and that peak is mostly one the matcher already gave to an + adjacent GT (#130). ``no_peak_profile`` reports this per cell so the row is read as + what it is. Genuinely peakless mass — no floor peak within 2 R — is the minority + (4 of 15 on richmond), and one of those 4 is a peak the op_cache dropped beside the + seam (pre-``f4c71c8``), not a peak the model never made. ``peak_in_radius`` is therefore reported per cell and is what the read below turns on. @@ -80,7 +87,9 @@ class alone cannot separate them: sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, os.path.join(REPO, "scripts", "model_comparison")) -from rampnet.detection_eval import radius_sq_for # noqa: E402 +from rampnet.detection_eval import ( # noqa: E402 + radius_sq_for, PANO_SCALE_X, PANO_SCALE_Y) +from rampnet.metrics import greedy_match # noqa: E402 from compare import load_bundle, DetectionCache, cache_key # noqa: E402 from detectors import build_detector # noqa: E402 from complementarity import ( # noqa: E402 @@ -120,6 +129,76 @@ def panos_without_floor(panos, floor_peaks): return [pid for pid in panos if pid not in floor_peaks] +def nearest_peak_index(preds, x, y): + """Index into ``preds`` of the closest floor peak (``nearest_peak``'s geometry).""" + best, best_i = float("inf"), None + for i, p in enumerate(preds): + dx = abs(p[0] - x) * PANO_SCALE_X + dx = min(dx, PANO_SCALE_X - dx) + d = (dx * dx + ((p[1] - y) * PANO_SCALE_Y) ** 2) ** 0.5 + if d < best: + best, best_i = d, i + return best_i + + +def claimed_by_adjacent(pano_sites, preds, threshold, radius_sq): + """For each site, is its nearest floor peak one the matcher gave to a DIFFERENT GT? + + Re-runs the greedy match that defines RampNet's hits at ``threshold`` (highest + score first, wrapped, as ``matched_gt``) over all GT on the pano, then asks of + each site's nearest floor peak whether it was assigned to some other GT. That is + the #130 mechanism — a neighbouring ramp's detection sitting 1-2 R from this one + — and it is what most of the "no floor peak in radius" rows turn out to be. + Returns one bool per site; ``False`` when there is no peak at all. + """ + gt_points = [(s["x"], s["y"]) for s in pano_sites] + kept = [i for i, p in enumerate(preds) if p[2] >= threshold] + order = sorted(kept, key=lambda i: preds[i][2], reverse=True) + assignments = greedy_match([(preds[i][0], preds[i][1]) for i in order], gt_points, + radius_sq, PANO_SCALE_X, PANO_SCALE_Y, wrap_x=True) + claimed = {order[k]: gi for k, (gi, _) in enumerate(assignments) if gi >= 0} + out = [] + for si, s in enumerate(pano_sites): + ni = nearest_peak_index(preds, s["x"], s["y"]) + out.append(ni is not None and ni in claimed and claimed[ni] != si) + return out + + +def no_peak_profile(rows, cell, radius_px): + """Where the nearest floor peak actually is, for the rows of ``cell`` that have + none inside the radius. + + The cell summary's medians are over the whole cell; the table row in + ``docs/model_comparison.md`` is about this subset, and what it says the subset + *is* turns on these columns: a nearest peak 1-2 R away with the in-window + maximum on the window edge is a neighbour's shoulder (``tail``), not mass the + extractor overlooked. ``argmax_on_edge`` counts rows whose maximum is within + 0.5 px of the radius; ``claimed`` counts rows whose nearest peak the matcher gave + to another GT (only present on rows that carry ``nearest_peak_claimed``, i.e. + runs since this key was added). + """ + sel = [r for r in rows if r["cell"] == cell and not r["peak_in_radius"]] + if not sel: + return {"cell": cell, "n": 0} + near = [r["nearest_peak_px"] for r in sel if r["nearest_peak_px"] is not None] + out = { + "cell": cell, + "n": len(sel), + "act_median": round(quartiles([r["act"] for r in sel])[1], 4), + "argmax_off_px_median": round(quartiles([r["argmax_off_px"] for r in sel])[1], 1), + "argmax_on_edge": sum(1 for r in sel if r["argmax_off_px"] >= radius_px - 0.5), + "nearest_peak_px_median": round(quartiles(near)[1], 1) if near else None, + "peak_within_2r": sum(1 for d in near if d <= 2 * radius_px), + "peak_beyond_2r": len(sel) - sum(1 for d in near if d <= 2 * radius_px), + "classes": {c: sum(1 for r in sel if r["class"] == c) + for c in ("absent", "faint_local", "tail")}, + "seam": sum(1 for r in sel if r["seam"]), + } + if all("nearest_peak_claimed" in r for r in sel): + out["claimed"] = sum(1 for r in sel if r["nearest_peak_claimed"]) + return out + + def summarize(rows, cell): """Per-cell summary. ``None`` for null stats on the hit cells, which have none.""" sel = [r for r in rows if r["cell"] == cell] @@ -262,6 +341,12 @@ def main(argv=None): + ("bundle records (shipped point)" if args.rampnet_op_threshold is None else f"op_cache >= {args.rampnet_op_threshold:g}"), flush=True) + # The threshold that defines RampNet's hits, for the "did the matcher give this + # site's nearest peak to a neighbour" column. At the shipped point that is the + # bundle's floor, 0.5519 on richmond, which is the lowest committed score. + claim_threshold = (args.rampnet_op_threshold if args.rampnet_op_threshold is not None + else min((d["confidence"] for r in records.values() + for d in r["detections"]), default=0.0)) r_px = radius_sq ** 0.5 rows, skipped = [], 0 for i, pid in enumerate(panos, 1): @@ -278,7 +363,8 @@ def main(argv=None): preds = (floor_peaks.get(pid, []) if have_op_cache else [(d["x_normalized"], d["y_normalized"], d["confidence"]) for d in records[pid]["detections"]]) - for s in by_pano[pid]: + claimed = claimed_by_adjacent(by_pano[pid], preds, claim_threshold, radius_sq) + for s, is_claimed in zip(by_pano[pid], claimed): act, off_px, center = site_profile(heat, s["x"], s["y"], radius_sq) npx, nscore = nearest_peak(preds, s["x"], s["y"]) row = {**s, "act": round(act, 6), "center": round(center, 6), @@ -291,6 +377,10 @@ def main(argv=None): # the peak to an adjacent GT. That is recoverable without a second # model; a peak outside the radius is not. "peak_in_radius": bool(npx < r_px), + # ...and whether that nearest peak is one the matcher already handed + # to a different GT on this pano (#130), which is what most of the + # "no peak in radius" rows are. + "nearest_peak_claimed": bool(is_claimed), "class": class_of(act), "seam": seam_of(s["x"], radius_sq), "null_pct": None, "null_med": None, "null_p95": None} # The null is only meaningful where rampnet did NOT find the ramp; the @@ -337,9 +427,21 @@ def main(argv=None): print(" - peak inside R -> the model DID localize the ramp and the detection was") print(" lost downstream, to the shipped threshold or to the greedy matcher handing") print(" the peak to an adjacent GT. Recoverable WITHOUT a second model.") - print(" - peak outside R -> nothing was extracted there even at the 0.05 floor, so a") - print(" threshold prior has no peak to promote. 'act' can still be non-zero: that is") - print(" unpeaked heatmap mass, which peak_local_max did not call a local maximum.") + print(" - peak outside R -> nothing of THIS ramp's to promote. 'act' there is usually") + print(" a neighbouring peak's shoulder reaching into the window (nearest peak 1-2 R") + print(" away, argmax on the window edge), not mass the extractor overlooked -- the") + print(" profile below says which, per cell.") + print() + print(f" no floor peak in R, by where the nearest peak is (R = {r_px:.1f} px):") + for cell in MISS_CELLS: + prof = no_peak_profile(rows, cell, r_px) + if not prof["n"]: + continue + print(f" {cell:16s} n={prof['n']:<3d} nearest peak median " + f"{prof['nearest_peak_px_median']} px; within 2R {prof['peak_within_2r']}, " + f"beyond {prof['peak_beyond_2r']}; argmax on edge {prof['argmax_on_edge']}; " + f"nearest peak claimed by another GT {prof.get('claimed', '?')}; " + f"classes {prof['classes']}; seam {prof['seam']}") if args.json_out: payload = {"split": args.split, "challenger": label, diff --git a/tests/test_cascade_gate.py b/tests/test_cascade_gate.py index 692015c5..f4ace4ff 100644 --- a/tests/test_cascade_gate.py +++ b/tests/test_cascade_gate.py @@ -13,7 +13,10 @@ The parity (1024x1024) detections behind those two artifacts are not published, so a clean clone cannot regenerate these files. It can still check them against themselves, -which is what the second half of this file does. +which is what the second half of this file does — including what the "no floor peak in +radius" row *is*: the committed ``op_cache`` says where each such site's nearest peak +sits and whether the matcher already gave it to a neighbour, and the doc's reading of +that row is pinned to those columns here. """ import json import os @@ -30,13 +33,14 @@ import cascade_gate as cg # noqa: E402 import silent_activation as sa # noqa: E402 from farfield_forensics import quartiles # noqa: E402 -from rampnet.detection_eval import radius_sq_for # noqa: E402 +from rampnet.detection_eval import PANO_SCALE_X, radius_sq_for # noqa: E402 OUT = os.path.join(REPO, "analysis_out") SHIPPED = os.path.join(OUT, "cascade_gate.json") OP030 = os.path.join(OUT, "cascade_gate_op030.json") RSQ = radius_sq_for() R_PX = RSQ ** 0.5 # 22.5 heatmap px +R_NORM = R_PX / PANO_SCALE_X # the same radius in normalized x def _row(cell, **kw): @@ -148,6 +152,76 @@ def test_the_class_shares_sum_to_one(): assert sum(out["class_share"].values()) == 1.0 +# --------------------------------------------------------------------------- # +# no_peak_profile — what the "no floor peak in radius" row is made of +# --------------------------------------------------------------------------- # +def test_the_profile_covers_only_the_rows_with_no_peak_in_radius(): + rows = [_row("challenger_only", peak_in_radius=True, nearest_peak_px=5.0), + _row("challenger_only", peak_in_radius=False, nearest_peak_px=30.0, + argmax_off_px=22.4, act=0.3), + _row("challenger_only", peak_in_radius=False, nearest_peak_px=60.0, + argmax_off_px=3.0, act=0.1, **{"class": "faint_local"}), + _row("neither", peak_in_radius=False, nearest_peak_px=30.0)] + out = cg.no_peak_profile(rows, "challenger_only", R_PX) + assert out["n"] == 2 + assert out["nearest_peak_px_median"] == 60.0 # quartiles: v[n // 2] + assert out["peak_within_2r"] == 1 and out["peak_beyond_2r"] == 1 + assert out["argmax_on_edge"] == 1 # 22.4 is within 0.5 px of R + assert out["classes"] == {"absent": 0, "faint_local": 1, "tail": 1} + assert "claimed" not in out # rows predate the column + + +def test_the_profile_reports_the_claimed_count_only_when_every_row_carries_it(): + rows = [_row("neither", peak_in_radius=False, nearest_peak_px=30.0, + nearest_peak_claimed=True), + _row("neither", peak_in_radius=False, nearest_peak_px=30.0, + nearest_peak_claimed=False)] + assert cg.no_peak_profile(rows, "neither", R_PX)["claimed"] == 1 + + +def test_an_empty_profile_reports_n_zero(): + assert cg.no_peak_profile([_row("both")], "neither", R_PX) == {"cell": "neither", + "n": 0} + + +def test_a_row_with_no_peak_anywhere_counts_as_beyond_two_radii(): + rows = [_row("neither", peak_in_radius=False, nearest_peak_px=None, + nearest_peak_score=None)] + out = cg.no_peak_profile(rows, "neither", R_PX) + assert out["nearest_peak_px_median"] is None + assert out["peak_within_2r"] == 0 and out["peak_beyond_2r"] == 1 + + +# --------------------------------------------------------------------------- # +# claimed_by_adjacent — the #130 mechanism, per site +# --------------------------------------------------------------------------- # +def test_a_neighbours_detection_between_two_ramps_is_claimed_by_the_nearer_one(): + # Two ramps 1.5 R apart, one peak on the left ramp. The left ramp's nearest peak + # is its own (not claimed by another); the right ramp's nearest peak is that same + # one, and the matcher gave it to the left ramp. + sites = [{"x": 0.5, "y": 0.5}, {"x": 0.5 + 1.5 * R_NORM, "y": 0.5}] + preds = [(0.5, 0.5, 0.9)] + assert cg.claimed_by_adjacent(sites, preds, 0.30, RSQ) == [False, True] + + +def test_a_peak_below_the_threshold_claims_nothing(): + sites = [{"x": 0.5, "y": 0.5}, {"x": 0.5 + 1.5 * R_NORM, "y": 0.5}] + assert cg.claimed_by_adjacent(sites, [(0.5, 0.5, 0.2)], 0.30, RSQ) == [False, False] + + +def test_no_peaks_means_nothing_is_claimed(): + assert cg.claimed_by_adjacent([{"x": 0.5, "y": 0.5}], [], 0.30, RSQ) == [False] + + +def test_nearest_peak_index_agrees_with_nearest_peak_across_the_seam(): + preds = [(0.5, 0.5, 0.9), (0.998, 0.5, 0.4)] + x, y = 0.002, 0.5 + i = cg.nearest_peak_index(preds, x, y) + assert i == 1 + assert sa.nearest_peak(preds, x, y)[1] == preds[i][2] + assert cg.nearest_peak_index([], x, y) is None + + # --------------------------------------------------------------------------- # # site_rng — a site's null must not depend on which sites came before it # --------------------------------------------------------------------------- # @@ -242,7 +316,7 @@ def test_the_cascade_ceiling_is_nineteen_promotable_ramps(): # docs/model_comparison.md, "The cascade gate": of the 38 genuinely-complementary # ramps at rampnet@0.30, 19 carry a floor peak in radius scoring 0.05-0.30 (the # promotable set), 4 carry one at >= 0.30 that the greedy matcher gave to an - # adjacent GT, and 15 carry none. + # adjacent GT, and 15 carry none inside the radius. sites = [s for s in _payload(OP030)["sites"] if s["cell"] == "challenger_only"] assert len(sites) == 38 peaked = [s for s in sites if s["peak_in_radius"]] @@ -264,6 +338,87 @@ def test_the_no_peak_rows_have_their_own_activation_median(): assert cell["act_median"] == 0.2152 +def _claimed_at_030(payload): + """``{(pano, x, y): bool}`` -- is the site's nearest floor peak one the greedy + match at 0.30 gave to a different GT? From the committed op_cache, the same + source the artifact's peak columns were read from.""" + floor = cg.load_floor_peaks(payload["split"]) + rsq = radius_sq_for(payload["radius"]) + by_pano = {} + for s in payload["sites"]: + by_pano.setdefault(s["pano"], []).append(s) + out = {} + for pid, sites in by_pano.items(): + flags = cg.claimed_by_adjacent(sites, floor.get(pid, []), + payload["rampnet_op_threshold"], rsq) + for s, flag in zip(sites, flags): + out[(pid, s["x"], s["y"])] = flag + return out + + +def test_the_no_peak_row_is_mostly_a_neighbours_shoulder_not_unpeaked_mass(): + # docs/model_comparison.md, the "no floor peak in radius" row of the cascade + # table. The first write-up read these 15 as "unpeaked heatmap mass + # peak_local_max never called a maximum". The artifact's own columns say + # otherwise: for 11 of the 15 the nearest floor peak is 1-2 R away (median 35.0 + # px against R = 22.5), and for 11 the in-window maximum sits on the window edge + # (median argmax_off_px 22.4) -- a neighbouring mode's shoulder reaching in, #46 + # Phase 1's `tail`, which is where class_of puts 12 of the 15. Only 4 have no + # floor peak within 2 R, and one of those is the seam site whose peak the + # pre-f4c71c8 op_cache dropped. + payload = _payload(OP030) + r_px = radius_sq_for(payload["radius"]) ** 0.5 + prof = cg.no_peak_profile(payload["sites"], "challenger_only", r_px) + assert prof["n"] == 15 + assert prof["nearest_peak_px_median"] == 35.0 + assert prof["argmax_off_px_median"] == 22.4 + assert prof["argmax_on_edge"] == 11 + assert prof["peak_within_2r"] == 11 + assert prof["peak_beyond_2r"] == 4 + assert prof["classes"] == {"absent": 0, "faint_local": 3, "tail": 12} + assert prof["seam"] == 1 + assert prof["act_median"] == 0.2723 + + +def test_the_no_peak_rows_nearest_peaks_are_mostly_claimed_by_an_adjacent_ramp(): + # ...and that neighbouring peak is, for 11 of the 15, one the matcher already + # gave to another GT at 0.30 (7 of them within 2 R) -- the same #130 mechanism + # the table's "4 in radius at >= 0.30" row names, so those two rows are one + # cause, not two. All 4 of that row are claimed too, which is what "unmatched" + # there meant. + payload = _payload(OP030) + r_px = radius_sq_for(payload["radius"]) ** 0.5 + claimed = _claimed_at_030(payload) + co = [s for s in payload["sites"] if s["cell"] == "challenger_only"] + no_peak = [s for s in co if not s["peak_in_radius"]] + assert sum(claimed[(s["pano"], s["x"], s["y"])] for s in no_peak) == 11 + assert sum(claimed[(s["pano"], s["x"], s["y"])] for s in no_peak + if s["nearest_peak_px"] <= 2 * r_px) == 7 + in_r_high = [s for s in co if s["peak_in_radius"] and s["nearest_peak_score"] >= 0.30] + assert len(in_r_high) == 4 + assert all(claimed[(s["pano"], s["x"], s["y"])] for s in in_r_high) + # The re-cut of the 38 the doc now prints, exhaustive and disjoint. + promotable = sum(1 for s in co if s["peak_in_radius"] and s["nearest_peak_score"] < 0.30) + within_2r_unclaimed = sum(1 for s in no_peak if s["nearest_peak_px"] <= 2 * r_px + and not claimed[(s["pano"], s["x"], s["y"])]) + beyond_2r = sum(1 for s in no_peak if s["nearest_peak_px"] > 2 * r_px) + assert (promotable, len(in_r_high) + 7, within_2r_unclaimed, beyond_2r) == (19, 11, 4, 4) + assert promotable + 11 + within_2r_unclaimed + beyond_2r == 38 + + +def test_the_seam_site_in_the_recovered_cell_has_a_peak_the_op_cache_lacks(): + # 723487737079243 at x = 0.0069: act 0.946 at 7.4 px from the ramp, centre 0.78, + # and the committed op_cache's nearest peak 117 px away. That is the f4c71c8 seam + # dropout made concrete -- a regenerated op_cache would list this peak, making + # the site a RampNet hit at 0.30 and taking it out of challenger_only (38 -> 37). + payload = _payload(OP030) + site = next(s for s in payload["sites"] + if s["cell"] == "challenger_only" and s["seam"]) + assert site["pano"] == "723487737079243" + assert not site["peak_in_radius"] and site["nearest_peak_px"] > 100 + assert site["act"] > 0.9 and site["center"] > 0.7 and site["argmax_off_px"] < 10 + + def test_the_committed_nulls_came_from_one_stream_and_say_so(): # Both artifacts predate site_rng: their nulls were drawn from one stream in pano # order, so a site carries a different draw in each file (43 of the 53 sites with From 5d0c05e8a5513cfcb40fa60626a7624d39bc3762 Mon Sep 17 00:00:00 2001 From: Jon Froehlich Date: Thu, 17 Sep 2026 06:57:10 -0700 Subject: [PATCH 16/17] docs: the private cache behind the A40 Vistas rows cannot be found on makelab2 (#126) Review round 1 on #137, finding S2 -- recorded, not fixed. The finding was that the parity (1024) and same-env control (384) detections lived only in a private --cache-dir in a scratch worktree on makelab2, and asked for them to be exported under a roster pin. Before exporting them I looked for them on 2026-09-17: the checkout at /homes/gws/jonf/RampNet has no worktree registered, its .model_cache holds no shard written 2026-08-17..20, and the parity run's shard names (compare.cache_key over the 1024 signature) are absent from /homes/gws/jonf, /tmp, /var, the root filesystem and the lab mounts. The cache went with the scratch worktree. So the doc now says that, beside the numbers, instead of "lives in a private cache on makelab2": the two A40 rows, the 1024 complementarity column, the operating-point table, both cascade tables and both cascade_gate*.json rest on the committed artifacts alone; every cascade figure still re-derives from the committed sites[] (tests/test_cascade_gate.py), the partition and the parity P/R/F1/AP do not. The numbers are as-run on 2026-08-18 and are not changed. Retiring it is a 3m38s A40 re-run plus a publishing decision the roster's own rules do not settle, which is why nothing was guessed at here: - a pinned 1024 leg requires every leg of the model to be qualified (rampnet/roster.py, test_every_leg_of_a_pinned_model_is_qualified), so the published 384 file would be renamed too; and the pin-naming rule expects a scalar value in the published name, this pin is a 2-element size; - the 384 control shares the published run's signature and cache key by design, so it cannot be a pinned leg at all; - export_model_cache.py does not take --vistas-input-size yet. Those three are listed in the doc where the gap is stated. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01E58bhyukgYXphE47jsnA29 --- docs/model_comparison.md | 60 +++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/docs/model_comparison.md b/docs/model_comparison.md index 96f06778..8c9583ac 100644 --- a/docs/model_comparison.md +++ b/docs/model_comparison.md @@ -1399,16 +1399,43 @@ the smallest achievable blob at 1024 (see above), so the two rows do not share t meaning even though they share its value. And this is still **richmond only**. **Neither A40 run's detections are published, so the bottom two rows of that table are not -re-derivable from a clean clone.** The parity (1024×1024) and same-env control (384×384) -detections live in a private `--cache-dir` on makelab2 and nowhere else; only the published 384 -row and RampNet's row come from committed files. `--vistas-input-size` does not change the arm's -label, so exporting either one would overwrite -`benchmark/model_detections/mask2former-vistas-curb-cut__richmond.json`. Publishing them needs a -distinct published name — `scripts/analysis/export_model_cache.py --publish-as` (#123, on `main`), -e.g. `mask2former-vistas-curb-cut-1024` — which was out of scope here. **Everything downstream of -those detections carries the same limit**: the 1024 column of the complementarity table, the whole -operating-point-correction table, both cascade tables, both `analysis_out/cascade_gate*.json`, and -the seam-exposure count. Each says so where it appears. +re-derivable from a clean clone — and as of 2026-09-17 the private cache they lived in cannot be +found either.** The parity (1024×1024) and same-env control (384×384) detections were written to +a private `--cache-dir` in a scratch worktree on makelab2 and nowhere else; only the published 384 +row and RampNet's row come from committed files. Looked for on 2026-09-17 before publishing them: +the checkout at `/homes/gws/jonf/RampNet` has no worktree registered, its `.model_cache` holds no +shard written 2026-08-17..20, and the parity run's shard names (`compare.cache_key` over the +1024 signature, e.g. `f2acf1b1…`) are absent from `/homes/gws/jonf`, `/tmp`, `/var`, the root +filesystem and the lab mounts. The cache went with the scratch worktree, so **the two A40 +rows, the 1024 complementarity column, the operating-point-correction table, both cascade tables, +both `analysis_out/cascade_gate*.json` and the seam-exposure count now rest on the committed +artifacts alone.** The cascade artifacts carry their full per-site input (`sites[]`), so every +figure in those tables still re-derives from committed files (`tests/test_cascade_gate.py`); +what cannot be re-derived is the partition itself, and the parity row's P/R/F1/AP. + +**Retiring that takes one decision and one 3m38s GPU run, not a rescue.** The run is cheap to +repeat (`compare.py … --vistas-input-size 1024 1024`, one A40, timed above), and a repeat +should land within a detection or so of the original — the control-vs-published pair did, across +a `transformers` major version, with fp16 kernel nondeterminism the only residual. What is not +settled is how it publishes, and the roster's own rules leave three +things open rather than one: + +- `--vistas-input-size` does not change the arm's label, so the export needs a distinct published + name (`export_model_cache.py --publish-as`, #123) and a roster leg pinned on it. But + `rampnet/roster.py` requires that **once one leg of a model is qualified, every leg is** — so + the published 384 file would be renamed too (e.g. `mask2former-vistas-curb-cut-384`), which + touches every reference to it here and in `tests/`. The registry's pin naming also expects a + scalar (`str(value)` appears in the published name), and this pin is a 2-element size. +- The same-env 384 control has the **same** signature and cache key as the published 384 run — + that was the point of it — so it cannot be a pinned leg at all; the roster has no notion of + "same detector, different host". Publishing it means either a new kind of entry or recording + it as an unregistered replicate beside the published file. +- `export_model_cache.py` does not yet take `--vistas-input-size`, so it cannot address the 1024 + cache entry even where one exists. + +Until those are decided, this section states the gap rather than guessing at the layout; the +numbers above are as-run on 2026-08-18 and are not being changed. Each downstream table says so +where it appears. #### Complementarity: 61% of RampNet's misses are recoverable, and a union still loses @@ -1443,10 +1470,10 @@ two differ by one detection in 523, which moved two cells by one ramp each: chal 21 and found-by-nobody 50 → 51. Nothing turned on it, but the control is not published either, so the column as printed was not re-derivable and did not say which run it was. -**The 1024 column cannot be re-derived from a clean clone.** The parity detections are not -published (see the caveat under *Resolution parity*), so that column exists only against the -private makelab2 cache. Closing that needs `scripts/analysis/export_model_cache.py --publish-as` -(#123) to give the parity arm its own published name. +**The 1024 column cannot be re-derived from a clean clone, or from anywhere.** The parity +detections are not published, and the private makelab2 cache that held them could not be found +on 2026-09-17 (see the caveat under *Resolution parity*), so that column now rests on this +table alone. Closing that needs a 3m38s re-run and a publishing decision, both spelled out there. **Discounted for chance, a free zero-training model finds ~44 of the 72 ramps RampNet misses — 61%.** The null here is measured on the miss subset rather than extrapolated from the split-wide @@ -1723,8 +1750,9 @@ git-ignored, so on a clean clone the published detections have to be written int `benchmark/model_detections/__.json` records the signature they were cached under and `compare.cache_key(model, signature, city, pano_id)` is the shard name; `tests/test_complementarity.py` does the whole thing in eight lines and is the shortest working -example. For the **parity** arm there is nothing to write — those detections are not published -(see *Resolution parity*) — so the 1024 commands above run only where that private cache exists. +example. For the **parity** arm there is nothing to write — those detections are not published, +and the private cache that held them is gone (see *Resolution parity*) — so the 1024 commands +above need the `compare.py --vistas-input-size 1024 1024` run first, which regenerates them. **Cost, in both units.** Money: **$0** — makelab2 is lab-owned hardware with no metered billing, and every read above is free. Time: one leg of three was timed, and **the full 124-pano From 5af6c5378835e4240c76af31a8840ca1249af854 Mon Sep 17 00:00:00 2001 From: Jon Froehlich Date: Thu, 17 Sep 2026 07:21:17 -0700 Subject: [PATCH 17/17] docs: the 15-row is 7 / 4 / 4, and three other corrections from review round 2 (#126) Review round 2 on #137, findings S1-S4. Doc only; no number, test or artifact changes. S1: the sentence under the re-cut table said the 15 "no floor peak" sites were "11 parts matching problem, 4 parts near-miss geometry and 4 parts absence", which sums to 19 -- that is the 38 minus the 19 promotable, not the 15. By the table's own membership the 11 claimed peaks are 4 inside R (the old 4-row) plus 7 at 1-2 R, so the 15-row is 7 / 4 / 4 and the 38 are 19 / 11 / 4 / 4. Also "most of the old 15 row" -> "7 of the old 15 row", and a note that the 4 "absence" sites have a claimed nearest peak too, just beyond 2 R. S2: the "so a regenerated copy is not mistaken for a changed result" paragraph listed one expected difference (rampnet_op_threshold). After d1860e5 and cc2299e a re-run also adds null_rng and panos_without_floor_peaks to the payload, nearest_peak_claimed per site, and moves every miss-cell null by up to 0.075 (per-site seeding). All listed now, with the two tests that pin the pre-fix state named, so a regeneration edits them in the same commit. S3: the same-env control command had no cache flag. It shares the published 384 run's signature and cache key by design, so on a clone that has written the published detections into .model_cache -- which the same section tells you to do -- compare.py finds all 124 panos cached and never runs the model, making the attribution arm silently the published arm. --no-cache added, with why. S4: the "unclaimed at 1-2 R" row said a wider radius would recover them "not a lower threshold"; two of the four score 0.242 and 0.143, below the 0.30 operating point, so they need both. The row now says so. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01E58bhyukgYXphE47jsnA29 --- docs/model_comparison.md | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/docs/model_comparison.md b/docs/model_comparison.md index 8c9583ac..b882d160 100644 --- a/docs/model_comparison.md +++ b/docs/model_comparison.md @@ -1574,12 +1574,20 @@ from `projectsidewalk/rampnet-benchmark` and a GPU. What a clean clone *can* do against itself: `tests/test_cascade_gate.py` re-derives every `cells[]` figure from the same file's `sites` list, so a hand-copied number in the tables below fails the build. -**Two things about `cascade_gate.json` specifically, so a regenerated copy is not mistaken for a -changed result.** It was written at `b7342dc`, before `4c192ca` added `rampnet_op_threshold` to the -payload, so it lacks that key while `cascade_gate_op030.json` carries it: a re-run would add -`"rampnet_op_threshold": null` and change the bytes with identical results, which is exactly the -comparison the `newline=""` pinning exists to make possible. And both were written before this -branch took the #132 seam wrap (below). Regenerate both when the parity detections are published. +**What a regenerated copy of either artifact will differ in, so it is not mistaken for a changed +result.** `cascade_gate.json` was written at `b7342dc`, before `4c192ca` added +`rampnet_op_threshold` to the payload, so it lacks that key while `cascade_gate_op030.json` carries +it. Since the round-1 review fixes (`d1860e5`, `cc2299e`) a re-run of *either* file also adds two +payload keys, `null_rng: "per-site"` and `panos_without_floor_peaks`, and one per-site key, +`nearest_peak_claimed`; and because the null is now seeded per site, every miss-cell `null_pct`, +`null_med` and `null_p95` moves — by up to 0.075 on the committed files, see the caveat under *A +negative worth recording* below — with `act`, `argmax_off_px`, `nearest_peak_px` and the cells +unchanged. Both were also written before this branch took the #132 seam wrap (below). Two tests pin +the *pre-fix* state and will need editing in the same commit as a regeneration: +`test_only_the_op030_artifact_records_the_threshold_key` and +`test_the_committed_nulls_came_from_one_stream_and_say_so`. The `newline=""` pinning is what makes +that comparison a byte diff rather than a guess. Regenerate both when the parity detections are +published. At **rampnet@0.30**, of the 38 genuinely-complementary ramps: @@ -1604,12 +1612,15 @@ pano (`cascade_gate.claimed_by_adjacent`, pinned in `tests/test_cascade_gate.py` | the 38 recoverable ramps at rampnet@0.30 | n | mechanism | |---|---:|---| | floor peak in radius, 0.05–0.30 | **19** | promotable — the cascade's target, unchanged | -| nearest floor peak ≥0.30 and **claimed by an adjacent GT** — 4 inside R, 7 at 1–2 R (26.8–44.1 px) | **11** | the #130 matcher/σ mechanism; the old "4" row and most of the old "15" row are one cause | -| nearest floor peak at 1–2 R, unclaimed (23.5 px @0.643, 24.3 px @0.242, 32.2 px @0.358, 42.5 px @0.143) | 4 | a peak just outside the window; would need a wider radius, not a lower threshold | +| nearest floor peak ≥0.30 and **claimed by an adjacent GT** — 4 inside R, 7 at 1–2 R (26.8–44.1 px) | **11** | the #130 matcher/σ mechanism; the old "4" row and 7 of the old "15" row are one cause | +| nearest floor peak at 1–2 R, unclaimed (23.5 px @0.643, 24.3 px @0.242, 32.2 px @0.358, 42.5 px @0.143) | 4 | a peak just outside the window; would need a wider radius (and, for the two below 0.30, a lower threshold as well) | | no floor peak within 2 R (51–117 px) | 4 | genuinely nothing near — and one of the 4 is the seam site below, where the heatmap *has* a peak the op_cache dropped | -So the row that read as "two-fifths of the recoverable set has no peak to raise" is 11 parts -matching problem, 4 parts near-miss geometry and 4 parts absence. `class_of`, the #46 Phase 1 +So the 15-row that read as "two-fifths of the recoverable set has no peak to raise" is 7 parts +matching problem, 4 parts near-miss geometry and 4 parts absence; with the old 4-row folded in, the +38 are 19 / 11 / 4 / 4. (The 4 "absence" sites also have a claimed nearest peak, just beyond 2 R — +51–117 px away, scores 0.85 / 0.86 / 0.34 / 0.94 — which is why the 11 in the table are 4 + 7 and +not 4 + 11.) `class_of`, the #46 Phase 1 decomposition the pre-registration promised for comparability, puts the 15 at **12 `tail` / 3 `faint_local` / 0 `absent`** (80 / 20 / 0%, against Phase 1's 62 / 30 / 8% over silent misses); over the whole 38-ramp cell it is 35 / 3 / 0, and the 15-ramp `neither` cell is 15 / 0 / 0. Both @@ -1709,8 +1720,12 @@ The scored runs. These need a GPU and the native-resolution panoramas python scripts/model_comparison/compare.py benchmark/richmond \ --models rampnet,vistas:curb-cut --vistas-input-size 1024 1024 -# same-env control (the attribution) -- default 384, no override -python scripts/model_comparison/compare.py benchmark/richmond --models vistas:curb-cut +# same-env control (the attribution) -- default 384, no override. It has the SAME +# signature and cache key as the published 384 run, so on a clone that has written +# the published detections into .model_cache (below) compare.py would find all 124 +# panos cached and never run the model: --no-cache (or a fresh --cache-dir) is what +# makes this an actual re-inference rather than a re-score of the published arm. +python scripts/model_comparison/compare.py benchmark/richmond --models vistas:curb-cut --no-cache # either, re-scored at the deployment threshold (free, reads the cache) python scripts/model_comparison/compare.py benchmark/richmond \