Commit History
-
Add vertex POSITION REGRESSOR (DINOv2) on top of edge classifier
xsponenta +1: Claude Opus 4.7Per-vertex DINOv2 patch features + geometric features -> 3D offset predicted by MLP (60K head params). Trained on 800 samples to regress toward the nearest GT vertex within 0.5m. Applied AFTER orphan-drop, BEFORE the edge classifier in the production pipeline. Offset clamped at 0.3m magnitude for safety; vertices visible in fewer than 2 views are not moved (avoid moving low-confidence verts). Local 200-sample A/B results: vr + edge_v4 vs baseline: +0.0095 hss_mean (t=+3.84, 116w/70l) vr + edge_v4 vs edge_v4: +0.0065 hss_mean (t=+2.39, 109w/79l) Strongly significant signal. First positive ON TOP of edge classifier. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>9bb88ff -
Upload vertex_regressor_v4_800.pt (DINOv2-based vertex position regressor)
Verified signature55ba9bc -
Add DINOv2 edge classifier (v4) for post-processing edge filtering
xsponenta +1: Claude Opus 4.7Trained head: 128K params, frozen DINOv2-small (22M params) backbone. Operates as a final post-processing step: for each predicted edge, sample DINOv2 patch features at projected edge midpoint per view, mean+max pool across views (768-dim), concat with 40-dim geometric+mask features (808-dim), pass through 4-layer MLP head -> P(keep). Best val acc 82.1% (vs 70-75% for hand-engineered features alone). Operating point: thresh=0.15, min_keep=0.85 - drop only the bottom ~15% of edges where the classifier is most confident they are wrong. Re-runs orphan drop after to clean up any stranded vertices. Local A/B vs production: 100 samples: +0.0032 hss_mean (t=+1.07, 46 wins / 44 losses) 200 samples: +0.0030 hss_mean (t=+1.26, 100 wins / 77 losses) DINOv2 weights download automatically on first run via torch.hub. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>0c54114 -
Upload edge_classifier_v4_400.pt (DINOv2 head, 82.1% val acc)
Verified signature2a5c52a
-
Revert TTA: 3x inference timed out on HF Space (b6bc99a -> all zeros)
xsponenta +1: Claude Opus 4.7Set USE_TTA=False. The TTA strict variant locally showed +0.003 mean and +0.029 q5, but the 3x inference cost exceeded HF Space's evaluation time limit, returning 0.0 for every sample. Pipeline now runs the single-seed fast path it used in 2df06c6 (the proven 0.4815 leaderboard config). Also leaves USE_ENSEMBLE=False with infrastructure preserved: a fine-tune attempt with heavy augmentation (jitter 0.01 + drop 0.1) produced a model 0.040 hss_mean WORSE than the original on local 50-sample A/B, so the ensemble code in script.py + ensemble.py + tta.py is wired but disabled pending a better-trained 2nd checkpoint. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>bd280f7
-
TTA: Hungarian-matched multi-seed inference with strict 3-pass agreement
xsponenta +1: Claude Opus 4.7Three priority-sample seeds (2718, 31415, 42), Hungarian-match segments across passes via flip-invariant endpoint distance, drop anchor segments that don't appear in BOTH supporting passes (min_passes_for_keep=2). Surviving segments are orientation-aligned and averaged across the 2-3 passes that saw them. The previous TTA (857514e, reverted) picked one pass's output - that's why it failed. This version aggregates and filters. Local 100-sample A/B vs orphan_refine baseline: baseline (orphan_refine): mean=0.3856 q5=0.0620 q50=0.3946 TTA simple concat-and-merge: mean=0.3756 q5=0.0842 (-0.010, REJECTED) TTA Hungarian min_passes=1: mean=0.3853 q5=0.0848 (-0.000, neutral) TTA Hungarian min_passes=2: mean=0.3888 q5=0.0907 q50=0.4032 (+0.003 mean, +0.029 q5) The strict variant wins primarily on hard scenes - q5 jumps 47% (0.062 -> 0.091), q25 +0.006, q50 +0.009. Strict filter throws out hallucinatio…b6bc99a -
Vertex view-projection refinement: snap 3D corners to 2D gestalt evidence
xsponenta +1: Claude Opus 4.7For each predicted 3D vertex V: 1. Project V into every registered COLMAP view via its P matrix. 2. Find the nearest gestalt corner-class pixel (apex / eave_end_point / flashing_end_point) within 15 px in each view. 3. If at least 2 views have a match, DLT-triangulate a new 3D position from the matched 2D corner pixels. 4. Sanity-check: refined position must lie within 0.5 m of V and reproject with mean error <= 10 px. 5. If both checks pass, replace V with the refined position. This is precision refinement of vertex *positions* — topology (edges) is unchanged, no new geometry is introduced. Directly targets corner_f1 (currently 0.517 vs leader ~0.65+) by snapping model approximations to exact gestalt corner detections that already drove training. Reuses validated machinery: mvs_utils.collect_views + project_world_to_image + triangulate_dlt + mean_reprojection_error. Falls back to the input on any error so the pipeline cannot regress structurally. Local 100-…2df06c6 -
Orphan-vertex cleanup + apex snap + local eval harness
xsponenta +1: Claude Opus 4.7Two production changes (validated by 100-sample local A/B on M4): - snap_to_point_cloud: target_classes [1,2] -> [0,1,2] (add apex). NB: reverted commit 6cf3fbd tried [1,2,3], but class 3 = rake (an EDGE class, not a point class). [0,1,2] = apex + eave_end_point + flashing_end_point is the actually-correct extension. - Replace the 2D edge-content filter with pure orphan-vertex cleanup. The 2D filter (50e27b8) regressed hss_q5 by 28% locally; the orphan cleanup recovers most of that while keeping the corner_f1 win. Local 100-sample A/B (this commit vs no-filter baseline, same seed): hss_mean: 0.3747 -> 0.3800 (+0.0053) hss_q5: 0.0792 -> 0.0776 (-0.0016) hss_q25: 0.2012 -> 0.2190 (+0.0178) hss_q50: 0.3658 -> 0.3590 (-0.0068) hss_q95: 0.7015 -> 0.7100 (+0.0085) Paired test: 54 improved / 44 worsened / 2 unchanged; t = 1.28 (small but consistent positive direction). Local eval infrastructure (BIG: solves the no-local-testing blocker): test_on…b1c3ec5
-
2D gestalt-edge consistency filter: drop edges with no view support
xsponenta +1: Claude Opus 4.7For each predicted 3D edge, project both endpoints into every COLMAP view and walk the 2D segment. Count how many sampled pixels fall on a gestalt edge-class pixel (eave, ridge, rake, valley, hip, flashing, step_flashing) after a 4px dilation of the mask. If at least 2 views show >=25% of the projected segment overlapping the edge mask, keep the edge; otherwise drop it as a hallucination with no 2D evidence. Precision-only operation: can drop bad edges but cannot add new geometry, so it can't repeat the plane_wireframe failure mode of polluting predictions. Uses the same COLMAP cameras + gestalt masks that triangulation tracks already rely on (validated machinery). Conservative thresholds chosen for first-evaluation safety: - min_views_support=2 (needs 2-view agreement to KEEP, not 1) - min_pixel_frac=0.25 (a truly hallucinated edge projects to random pixels, ~5-10% mask overlap; a real edge after dilation should be >=80%, so 0.25 is a wide margin from both extremes) - dilate_px=…50e27b8 -
Add per-sample diagnostic prints (no behavior change)
xsponenta +1: Claude Opus 4.7Logs per sample: colmap point count, fused point count, triangulation track output sizes, final predicted vertex/edge count, pipeline status (ok / fuse_failed / track_failed / predict_failed). submission.json output is byte-identical to the prior commit — only stdout changes. Score should reproduce the 0.4584 baseline; if not, the rollback wasn't clean. Once we have HF Space logs we can correlate input signal strength with output size and identify which scenes are systematically failing, targeting the next experiment with evidence instead of guesses. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>dec2057 -
Revert plane_wireframe ensemble: massive regression to 0.2412
xsponenta +1: Claude Opus 4.7Commit 3a43227 added plane_wireframe.predict_wireframe_planes to the ensemble and the leaderboard score collapsed from 0.4584 to 0.2412 (corner_f1 halved, edge_iou halved, even hss_q95 dropped from 0.724 to 0.367 — meaning every sample got worse, not just a subset). The uniform percentile-wise drop rules out a crash on a subset; plane_wireframe was systematically polluting every prediction. Most likely cause: its plane-intersection segments are produced in the same world frame but in regions far from real geometry, then appended as new vertices/edges by hybrid_merge(radius=0.8) on every sample. Restoring script.py to the proven 0.4584 state (commit 56f1ec6 contents). plane_wireframe.py is left in the tree but unused, consistent with the prior state. Lesson: code that is fully implemented but never wired in by the original developer should be treated as suspect. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>2d9a7cb -
Rollback to proven 0.4584 baseline, add plane_wireframe to ensemble
xsponenta +1: Claude Opus 4.7Two changes in one commit: 1. ROLLBACK: revert script.py and postprocess_v2.py to commit 56f1ec6 contents (the highest-scoring submission at hss_mean=0.4584). Removes snap_vertical + snap_manhattan (regressed edge_iou -0.009 in 72962c4) and the filter_by_colmap_support step (added in 6ecd5f8 but never independently evaluated, so its effect is unknown). 2. NEW: wire plane_wireframe.predict_wireframe_planes into the ensemble as a third recall source after triangulation tracks. RANSAC-segments roof planes from the COLMAP cloud and intersects them to recover ridge/eave edges the learned model misses. The module was fully implemented but never wired in. Uses the same append-only hybrid_merge(radius=0.8) pattern as triangulation, so it only adds genuinely new vertices/edges; cannot corrupt existing topology. Wrapped in try/except so any failure falls back silently to the pre-plane prediction. Runtime deps open3d and scikit-spatial added via install_if_miss…3a43227
-
Geometric regularization pass: vertical + Manhattan-direction snap
xsponenta +1: Claude Opus 4.7Two new post-process passes added after snap_horizontal: - snap_vertical: mirror of snap_horizontal across the up-axis. Near-vertical edges (small horizontal spread vs vertical spread) get their X and Z forced equal so the edge is exactly vertical. - snap_manhattan: detects the dominant XZ-plane building direction of all near-horizontal edges via a 4x-angle circular mean (90 deg symmetry). Edges within 3 deg of the dominant direction or its perpendicular are snapped to align exactly, via 3 iterations of Gauss-Seidel vertex averaging so shared endpoints converge consistently without drift. Non-Manhattan wireframes (hexagonal roofs, complex geometry) leave untouched because no edges fall within tolerance. Both passes are no-ops on edges that don't qualify; order is safe. Mathematically distinct from the reverted 6cf3fbd's snap changes (which touched target_classes and snap_horizontal incident-edge logic). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>72962c4
-
Revert TTA + add COLMAP-support vertex filter
xsponentaThe TTA experiment (commit 857514e) regressed -0.011 vs baseline (0.4475 vs 0.4584). The K=3 union added more candidate vertices than the post-merge could consolidate, producing duplicate / shifted vertices and dropping corner_f1 by 0.022. Restore script.py to the 56f1ec6 baseline state, then add ONE principled precision-only step: filter_by_colmap_support: after hybrid_merge, drop predicted vertices that have no COLMAP point within support_radius=0.6m. These are model hallucinations in regions without geometric evidence. Why this is principled: real roof vertices are always near reconstructed COLMAP geometry (the COLMAP cloud covers the entire visible building). Predicted vertices in empty 3D space are by construction wrong. Safety guarantees: - Falls back to unfiltered output on any exception (try/except wraps pycolmap access and KD-tree query). - Refuses to leave fewer than 2 vertices / 1 edge — never produces an empty submission. - Conservative 0.6m radius: comfortably cove…6ecd5f8 -
TTA optimization: cache point fusion, vary only priority sampling
xsponentaThe previous TTA commit (8e33a89) timed out because it called build_compact_scene 3x per sample (the expensive multi-view label voting step). Refactor: - compute_scene(sample, cfg, rng): does build_compact_scene + group/class/ center/scale computation. Called ONCE per sample. - sample_from_scene(scene): does priority sampling + result-dict assembly. Cheap, called K=3 times per sample. - fuse_and_sample is preserved as a backward-compat wrapper. Why this still gives TTA variation: _priority_sample uses the *global* numpy random state (np.random.shuffle), not an explicit rng arg. Each consecutive call advances the global state and produces a different 4096-point subset of the same fused scene. The model sees different inputs across passes despite the scene being identical. Cost: ~10% extra wall time vs single pass (3x cheap priority sampling + 3x cheap model forward), instead of ~200% from the previous commit. Should fit comfortably in the 2h budget.857514e -
TTA: 3-pass test-time augmentation with priority-sample seed variation
xsponentaReplace the single learned-pipeline pass + losing classical sklearn ensemble (commit 3118106 regressed -0.018) with K=3 learned passes that share the same model checkpoint but use different priority-sample RNG seeds. Each pass produces a different mix of depth-unprojected points, so the model sees a slightly different input — model averaging on a fixed checkpoint is the standard inference-time technique for 1-3% F1 gain. Aggregation: union the 3 (vertices, edges) outputs via ensemble_merge with a tight 0.3m merge radius (same vertex predicted by multiple passes consolidates; pass-specific noise stays separate). The classical predict_wireframe_tracks step (DLT triangulation) is kept on top of the unioned learned output via hybrid_merge — this part worked in the 0.4584 baseline and is unchanged. Removed: the sklearn-classical ensemble (USE_TRACK_ENSEMBLE-disabled predict_wireframe_sklearn). It added noise from 2D semantic vertex detection that the learned pipeline had not produced. R…8e33a89 -
Ensemble: disable redundant heavy features in classical pipeline
xsponentaThe previous ensemble commit (9cbefb9) timed out because the classical sklearn pipeline calls predict_wireframe_tracks via USE_TRACK_ENSEMBLE and USE_TRACKS_AS_VERTICES — which is the same heavy DLT triangulation already called by script.py's hybrid_merge. Doubling that step blows the time budget. Before calling predict_wireframe_sklearn, monkey-patch its module-level flags to disable: - USE_TRACK_ENSEMBLE (duplicate of hybrid_merge) - USE_TRACKS_AS_VERTICES (duplicate of hybrid_merge) - USE_WINNER_CANDIDATES (expensive iterative dilation) - USE_LINE_EDGES (3D line clustering) What we keep: per-view 2D semantic vertex detection, RANSAC affine depth fit, 3D unprojection, multi-view merge, sklearn edge classifier. This is the cheap-but-distinct signal — independent from anything the learned pipeline produces. Flags are restored after the call.3118106 -
Add learned + classical pipeline ensemble (LOCAL only, push tomorrow)
xsponentaAfter hybrid_merge, also run predict_wireframe_sklearn (the full classical pipeline with line cloud, winner candidates, sklearn edge classifier, track ensemble) and union its output with the learned-pipeline output via ensemble_merge. ensemble_merge: - Vertex union with close-pair merging (0.4m radius via cKDTree). - Edge union after re-mapping classical edge endpoints onto merged vertex indices, deduplicating undirected edge pairs. - Robust to NaN/Inf vertices from the classical side. Wrapped in try/except so a sklearn-pipeline failure on any sample falls back to the existing learned + hybrid_merge output. Independent error modes between the two pipelines should complement each other (semantic 2D detection + line cloud + sklearn classifier vs learned 3D segment regression). DO NOT PUSH today — daily submission slot already used (commit 56f1ec6 scored 0.4584). Push tomorrow when budget refreshes.9cbefb9
-
Lower CONF_THRESH 0.5 -> 0.4 to recover missing edges
xsponentaSingle-line tuning experiment. Targets the recall bottleneck (corner_f1 0.5104 vs leader 0.6472). With confidence threshold at 0.5, real edges with mid-confidence model output were being filtered out. Lowering to 0.4 trades a small amount of precision for higher recall on segment retention, before the downstream merge / snap / hybrid_merge post-processing further consolidates noise. Easy revert if it regresses: change back to 0.5.56f1ec6 -
Revert: roll back COLMAP refine + junction + snap changes
xsponentaThe previous commit's changes regressed the leaderboard score: - hss_mean: 0.4583 -> 0.4443 (-0.014) - corner_f1: 0.5104 -> 0.5003 (-0.010) - edge_iou: 0.4268 -> 0.4101 (-0.017) Most likely culprits without local validation: - COLMAP multi-view plane refinement: snapped some vertices onto wall or ground planes instead of roof planes (corner_f1 hit). - Junction constraints: the leaf_min_len=0.4m and collinear_cos=0.97 thresholds removed valid short edges and corner vertices (edge_iou hit). - Loosened hybrid_merge admitted incorrect track edges between existing predicted vertices. Restore script.py and s23dr_2026_example/postprocess_v2.py to the state from commit 9deb9e1 (the previous best, hss_mean=0.4583). Tomorrow we can attempt smaller, targeted experiments one at a time.61a6827 -
Boost: COLMAP plane refinement + junction constraints + snap fixes
xsponentaInference-only improvements (no retraining required) targeting both corner_f1 and edge_iou: - Integrate refine_vertices_multiview_plane in main loop. Built but never called; snaps each vertex onto the roof plane visible at its 2D projection across views, weighted by per-view PCA quality. Directly targets corner_f1 (currently the largest gap vs leaders). - Integrate apply_junction_constraints after hybrid_merge: drops collinear duplicate vertices, antiparallel duplicate edges, and short leaf edges. Improves edge_iou by removing structurally invalid topology. Falls back to pre-junction graph if it would produce zero edges. - snap_to_point_cloud now includes flashing_end_point (class 3) as a snap target. Previously only classes 1+2 were used. - snap_horizontal now only moves a vertex when ALL of its incident edges are near-horizontal — prevents corruption of sloped edges that share a vertex with an eave. - hybrid_merge: accept track edges between two existing predicte…6cf3fbd -
Optimize hybrid geometric ensemble for massive HSS boost
9deb9e1 -
Re-enable hybrid geometric tracking ensemble
7bd967e -
Add dummy app.py to fix NO_APP_FILE Space error
d601542 -
Upload checkpoint.pt with huggingface_hub
Verified signature2a53a25 -
Merge remote
5e51a27 -
Keep remote README.md
c92ef5c -
initial commit
Verified signaturecee8389 -
Add runtime dependency installation for scipy and pandas
4bde5b4 -
Temporarily disable hybrid logic for debugging
2276c14 -
Fix OpenMP SIGABRT crash caused by pycolmap import
1c251a9 -
Fix dataset script loading and add parquet fallback
6899728 -
Fix submission.json output path and filter NaNs in hybrid_merge
648e32c
-
Deploy learned baseline + hybrid multi-view tracking ensemble
7df6a88 -
Disable bundle adjust (timeout) and set TRACK_MIN_VIEWS=2 for recall
ff4370f -
Lower sklearn edge threshold to 0.45 to boost edge recall
084d259 -
Enable Bundle Adjustment and Track Vertices
04b55f0 -
Add missing core Python files
d40cee6 -
Bypass validation for track edges and fix SVD crashes
9506584 -
Switch to alternative vertex generation strategies since DGCNN cannot run
f699165 -
Fix sys.path and networkx dependency for Hugging Face
db2ae8e -
Fix relative paths for PyTorch models
6d0029c -
Optimize DGCNN edge hyper-parameters to beat baseline
6cc08ce
-
Update tuned hyperparameters
8f748c3
-
Enhance wireframe prediction filtering and clustering
29e5ee8 -
Fix competition config and script crash
ffa2c1d -
Update team name and submission repo
677e5b4 -
submit handcrafted baseline
8fd8b7c
-
Update script.py
Verified signature8e16bfb -
Update script.py
Verified signature25af80e