Spaces:
Sleeping
Accuracy improvement pack (resumed 2026-07-21 after PC crash)
Pull from Priyanka
Merged github-dev/New/Priyanka β uday (5462489).
Task 1 β GT for Grid_54 vs H43X2E1 β DONE (curated)
Hand-reviewed fullres detection regions; kept structural changes only (new blue/grey roofs, compound rebuild, solar). Dropped shadows, pool water color, wetland/vegetation.
- Label:
docs/delhi_eval/labels/dda_grid54_h43x2e1.png(changeβ0.23%, 10 components) - Pack:
docs/delhi_eval/dda_labeling/dda_grid54_h43x2e1/gt_mask.png - Review notes/overview:
.../_review/gt_labeling_notes.json,gt_overview.png
Re-paint and re-ingest anytime:
python scripts/ingest_dda_gt_label.py
Task 2 β Threshold / config recalibration β DONE
v3_frozen: keep thr=0.2 (runs/calibration/v3_recalibration_recommendation.json)
App grid (dl_only): sens 0.4 slightly best; DL floors irrelevant under dl_only
(runs/calibration/grid_search_v3_dl_only/summary.json).
Hard-neg thr sweep: still best at 0.2 (val F1 0.688, test F1 0.563)
β runs/v3_hardneg_analysis/recommended_threshold.json
Task 3 β Hard negatives + fine-tune β DONE
- Mined 7 veg/seasonal FP tiles β
data/delhi_cd/hard_negatives/ - Fixed
keep-emptyso empty GT tiles actually train - Run:
runs/finetune_hardneg/20260721_112416- Best val F1=0.6751 @ thr=0.2 (epoch 4)
- Test F1=0.548β0.563 (vs v3_frozen test β0.595)
- Hard-neg pairs still 100% FP in analysis β do not promote yet
- Exported:
models/adaptformer_delhi/v3_hardneg/ - Production default stays
v3_frozen
Task 4 β Fullres DDA detection (cap 5120) β DONE
runs/native_dda/20260721_121410/cap5120/
- 4706Γ5120, ~19.6 min, change%β1.21, 23 regions
- Artifacts:
change_mask.png,overlay.png,summary.json - 899 tiles, fusion=
dl_only, thr=0.2, model=adaptformer-delhi-v3
# true native overnight if needed:
python scripts/run_native_dda_detection.py --native
Missed-detection accuracy pass (2026-07-21 evening) β APPLIED
Root causes of under-detection on Grid_54 vs H43X2E1:
strip_transient_from_maskover-deleted mid-size roofs (weak-perm usedmax_car*2).- Blue-roof recovery rejected novel roofs merged with existing blue courts.
- Dark roofs / solar (brightβblack tarp) had no recovery; shadow strip could erase them.
- AdaptFormer often fires only on fragments β mild score hysteresis + open on low mask.
Applied in app/detection_engine.py:
- Protect blue/dark-roof + structural large footprints in transient strip
- Chromatic recovery keeps novel (non-blue-before) pixels; lower min area
recover_dark_roof_construction(local grow + strict standalone)- Protect dark-new pixels in shadow strip
- DL-only mild hysteresis (
low β 0.65Γthr, low-mask opened) - Strip helper for large seasonal veg (when NDVI evidence is clear)
Re-applied to run #47 (working 4706Γ5120 PNGs):
python scripts/reapply_run47_accuracy.py
- change% β 4.23, 60 regions (was ~1.21 / 10)
- GT recall vs overlay β 0.96 (was ~0.69); 0 missed GT components
- Artifacts:
runs/accuracy_improve_20260721/
Note: curated GT #7 is basketball-court activity (people/paint), not structural β still detected under the denser mask; structural policy may want to drop it from GT later.
Tuesday 2026-07-28 β day plan integration
Uday P0 β Real weights + held-out baseline
models/adaptformer_delhi/v3_frozen/model.safetensorspresent (~50 MB)/healthβloadedFrom=.../v3_frozen,available=true, device=cuda- Held-out test split (
data/delhi_cd/test, 4 pairs) @ thr=0.2,dl_only, TTA off:- mean F1=0.5867 Β· P=0.6028 Β· R=0.614 Β· IoU=0.4171
- Artifact:
runs/tuesday_baseline_20260728/metrics.json - Re-run:
python scripts/record_tuesday_baseline.py
Integrated from Priyanka (same day)
pair_alignguard wired indetect_service(identical β message, low NCC β warning)- Shadow classification: shadow-only blobs kept as
Shadow; structural vs all % - Verify:
python scripts/verify_tuesday.pyβ ALL CHECKS PASSED
Wednesday 2026-07-29 β retrain + hard-negatives
Training fixes (--preset wed)
- Drop empty real GT; keep mined
hn_*hard-neg tiles - Loss: CE + pos_weight
- Oversample change tiles Γ4; full-image 256 resize; change-centered crops
- Val-calibrate + freeze threshold
- Warm-start:
v3_frozen
Hard-negative mining
- Refreshed
scripts/mine_hard_negatives.py(parking / seasonal veg / shadow tags) - Saved 5 tiles (
hn_delhi_0002/0006/0013/...), all tagged vegetation_seasonal+shadow - Appended to
data/delhi_cd/train/manifest.json
Result (target test F1 > 0.60) β HIT
- Run:
runs/finetune_wed/20260729_134453 - best val F1=0.630 Β· frozen thr=0.446
- test F1=0.6051 Β· P=0.526 Β· R=0.772 Β· IoU=0.436
- Export:
models/adaptformer_delhi/wed_retrain/(does not replace productionv3_frozen) - Summary:
data/delhi_cd/wednesday_retrain/metrics.json
python scripts/build_delhi_cd_splits.py --min-change-frac 0.001 --stratify
python scripts/mine_hard_negatives.py --include-all-labeled --min-fp-frac 0.03
python scripts/finetune_adaptformer.py --delhi-cd data/delhi_cd --preset wed --out runs/finetune_wed
Thursday 2026-07-30 β DSIFN spike + wed_retrain OP freeze
Priyanka
Fast-forward merged github-dev/New/Priyanka β uday (ROI crop / training packs).
DSIFN vs AdaptFormer (boundary completeness)
- Cloned official DSIFN + Change-Detection-Review index under
third_party/ - Official Drive package = dataset only (no
.pth/.h5); trained proxy on DSIFN val β test F1β0.485 - Delhi 5 pairs (4 test + 1 val): AdaptFormer fills interiors; DSIFN does not
| Model | F1 | Fill | Hole |
|---|---|---|---|
AdaptFormer (wed_retrain) |
0.624 | 0.832 | 0.148 |
| DSIFN proxy | 0.090 | 0.356 | 0.644 |
Decision: KEEP_ADAPTFORMER β do not switch backbones.
Artifacts: data/delhi_cd/thursday_dsifn_compare/DECISION.md
wed_retrain operating point
Sweep F_Ξ² thr + DETECTION_TTA + DETECTION_MULTISCALE on held-out test:
| Config | Test F1 | Notes |
|---|---|---|
| thr=0.446, TTA=off, MS=off | 0.606 | Wed sidecar baseline |
| thr=0.354 (F_Ξ²), TTA/MS variants | β€0.601 | Drop (hurt F1) |
| thr=0.446, TTA=full, MS=off | 0.626 | KEEP (+0.020 F1, ~3Γ flips) |
| thr=0.446, MS=0.75,1 | 0.587 | Drop |
Frozen OP (models/adaptformer_delhi/wed_retrain/):
threshold=0.446DETECTION_TTA=fullDETECTION_MULTISCALE=off- Production remains
v3_frozenuntil an explicit promote.
python scripts/sweep_wed_operating_point.py
python scripts/dsifn_proxy_train.py --epochs 6 --batch 2
python scripts/compare_dsifn_vs_adaptformer.py
Friday 2026-07-31 β integrate + regression (Priyanka, Task 1)
Labeling round (drone pairs, before splits)
Hand/assisted-labeled 9 drone before/after pairs (georeferenced but
un-orthorectified, NCC 0.07β0.61 β well below the ~0.9 needed for clean
pixel correspondence). Registration attempts (SIFT homography, ECC
affine/euclidean/homography on the static region) could not raise NCC further
β confirmed local parallax, not a fixable global misalignment; orthomosaic
reprocessing from raw photos is the only real fix. See each pack's meta.json
(orthomosaics_needed: true) for the caveat.
By explicit user directive (2026-07-31), these 9 are now flagged
training_use: true (training_use_override recorded in each meta.json)
and registered in docs/delhi_eval/manifest.json with pack-local
before.png/after.png (not the original Downloads TIFFs, so the split is
portable to Uday's machine):
| pair_id | change_frac | split |
|---|---|---|
dda_1_2_scene |
0.0079 | train |
dda_after_testing |
0.1604 | train |
dda_before1_after |
0.2124 | train |
dda_before1_after2_testing |
0.2342 | test |
dda_before2_after2 |
0.3396 | val |
dda_before3_after3 |
0.0332 | val |
dda_before4_after4 |
0.1932 | train |
dda_before5_after5 |
0.2232 | train |
dda_before6_after6 |
0.0471 | train |
An earlier aligned-source labeling attempt (2019β2026 satellite pair, 1
positive + 3 seasonal hard-negatives, dda_before2019_r0..r3) was created,
then removed by user request before ingest β not present in the splits.
Splits rebuilt
python scripts/build_delhi_cd_splits.py --min-change-frac 0.001 --stratify
33 labeled pairs β train=23 Β· val=5 Β· test=5 (was 24/16Β·4Β·4 before today).
Regression check
python scripts/validate_detection.py(unit checks) β all pass, no change from HEAD.python scripts/validate_detection.py --benchmark --method "AI-Based Deep Learning"β synthetic-scene F1 is very low (0.00β0.06) vs the oldruns/calibration/best_params.jsonnumbers (0.86β1.0). Not a regression from this week's commits β confirmed viagit diffthatfeature_based_method/fusion logic are byte-identical to before Tuesday. Root cause: those old numbers were measured undersmart_unionfusion (classical+DL) on a different model; current default isdl_only(app/detection_config.py:200docstring:smart_union"collapsed mean F1 from ~0.58 to ~0.04" on the v3 Delhi model β a deliberate, documented tradeoff). The synthetic suite's expected baseline is stale fordl_onlyand should be recalibrated separately; it is not something TueβFri changes broke.- End-to-end wiring smoke (ROI crop β detect β export training pack β ingest) β all 4 steps pass, artifacts cleaned up.
Shadow classification β removed (user decision)
Reverted Tuesday's Shadow DDA type / region classifier
(change_type_map.py, detection_engine.py, detect_service.py).
Shadow-only pixels are still suppressed (strip_shadow_only_from_mask,
unchanged) β just no longer surfaced as a labeled class or split stat.
ROI β training-pack export β shipped
POST /api/dda/training/pack (app/dda/training_pack.py,
app/dda/training_routes.py) + scripts/ingest_dda_gt_label.py --pair-id
generalization + "Export training pack" button in the result view
(static/js/dda/result.js). Verified end-to-end (see regression check above).
π© Found + fixed: test-set drift risk (before handing off to Uday)
Rebuilding the splits (needed to fold in Friday's labels) reshuffled which
pairs land in test even at the same seed β Wednesday/Thursday's frozen
wed_retrain operating point (thr=0.446, TTA=full, test F1=0.6263) and
Tuesday's v3_frozen baseline (F1=0.5867) were both measured on
{delhi_0024, delhi_0001, delhi_0005, delhi_0016}. The first Friday rebuild
produced a different test set ({delhi_0024, delhi_0011, delhi_0017, delhi_0022, dda_before1_after2_testing}, only 1 pair overlapping) β any F1
number from that set would not be comparable to Tue/Wed/Thu's, and a drop
could look like "the model got worse" when it's really "the benchmark
changed."
Fix implemented: scripts/build_delhi_cd_splits.py now supports
--freeze-test-ids (default: data/delhi_cd/frozen_test_ids.json), which
pins specific pair_ids to test on every run regardless of what's
added/removed from the labeled pool. Created
data/delhi_cd/frozen_test_ids.json = the original Tue/Wed/Thu set. Rebuilt
splits β test is now exactly {delhi_0024, delhi_0001, delhi_0005, delhi_0016} again, so today's held-out eval is directly comparable to the
whole week's numbers. All 9 drone pairs land in train (8) / val (1) β
none in test β so the benchmark stays 100% clean satellite imagery
regardless of the drone-data alignment-quality question (see below).
Residual minor risk: dda_before2019 removal + drone-pair addition also
shifted val composition (dda_1_2_scene, a low-NCC pair, is now in val).
Val doesn't affect the headline test-F1 comparison but does feed the
val-threshold sweep (Thursday's sweep_wed_operating_point.py pattern) β if
Uday re-runs that sweep, note val is not fully frozen, only test.
Handoff to Uday (Friday P0)
- Fine-tune on the rebuilt 24/5/4 split (train includes 8 of the 9 new drone pairs β low-NCC caveat applies; test is unchanged/frozen, clean satellite only).
- Held-out eval on the frozen test set β before/after F1/P/R vs Tuesday's
v3_frozenbaseline (now a valid, apples-to-apples comparison) β promotion decision (v3_frozenvswed_retrainvs new fine-tune). - Recommended extra check: since low-NCC drone pairs are now in training, additionally report F1 on the frozen test set split by training-data recipe (with vs without the 9 drone pairs, if time allows an ablation) to isolate whether they helped or hurt real (clean satellite) performance β directly answers "did the drone data degrade F1."
Result: fri2_retrain (delhi + drone) β confirmed regression, root cause found
| Checkpoint | Frozen test F1 | thr | Val F1 | Val P | Val R |
|---|---|---|---|---|---|
v3_frozen |
0.587 | 0.2 | 0.677 | 0.686 | 0.700 |
wed_retrain |
0.605 (0.626 TTA) | 0.446 | 0.630 | - | - |
fri2_retrain |
0.487 | 0.5 | 0.436 | 0.345 | 0.641 |
fri2_retrain's threshold.json follows the same schema as v3/wed (real
per-epoch val calibration, not a default) - so the drop is not a
threshold-calibration bug. Precision collapsed 0.69->0.35 while recall
stayed reasonable (0.64): the model became far less selective, consistent
with training on the 9 un-orthorectified drone pairs (dda_before*,
dda_after*, dda_1_2_scene - NCC 0.07-0.61) - large misaligned regions
labeled "change" taught the model "big pixel differences = change" too
broadly. Confirmed visually on DDA_Report_55_before1_tif_vs_after_tif.pdf:
16.63% flagged, mostly cars/vegetation/ground, buildings still not covered.
Fix in progress: ablation split prepared and pushed -
data/delhi_cd_ablation_no_drone/ (same 24-pair pool that produced
wed_retrain's 0.605/0.626, drone pairs excluded via the new
--exclude-prefix flag on build_delhi_cd_splits.py, frozen test set
intact). Requested from Uday:
python scripts/finetune_adaptformer.py --delhi-cd data/delhi_cd_ablation_no_drone --preset wed --out runs/finetune_fri3_no_drone
If F1 recovers to ~0.60+, confirms drone data as the cause -> exclude drone
pairs from training going forward (keep eval-only, per the original plan);
promote whichever of wed_retrain / fri3_no_drone scores higher on the
frozen test set. Status: awaiting Uday's run (sent EOD Friday).