Round-1 report — Azure retrain on 260624_confirmed_good

2026-07-11 · AI3D-338 · linebitmapsegmentation · program plan

Summary

Both round-1 anchors reproduce their Phase-D scores almost exactly on the 2× bigger dataset — the ~0.87 pixel-F1 ceiling did not move. dice_focal 0.8750 (was 0.8712), focal_tversky+r34 0.8678 (was 0.8683), now measured on a 97-tile test set vs the old 50. Doubling clean data neither lifted nor dented headline F1, while calibration and topology stayed excellent (clDice 0.97–0.98, dice_focal area ratios 1.03/1.00). This is strong evidence for Phase D's #1 suspect: the fixed 4 px label stroke, not data volume and not the model, is what caps pixel-F1. Round 2 attacks exactly that (per-class stroke at physical paint width — the rasterizer only paints odd widths, so the realizable correction is solid 5 / dashed 3 px), plus a longer schedule for the r34 run that hit its 60-epoch cap without early-stopping.

Results (held-out 97-tile test)

runloss / encoderF1 fgF1 S/DclDicecov S/Darea S/Dbest ep
dice_focal_260624dice_focal / r18 0.87500.863 / 0.8870.971 0.875 / 0.8891.03 / 1.0035 / 46 early stop
ft_r34_260624focal_tversky / r34 0.86780.853 / 0.8820.975 0.916 / 0.9381.15 / 1.1354 / 60 hit cap
Phase-D refs (old 50-tile test)same configs 0.8712 / 0.8683~0.96 / 0.975 — / 0.93·0.940.98·1.03 / 1.19·1.12

Overlay review (best-F1 checkpoints, 6-tile sheets)

What it means

Round 2 — design

#runchange vs round 1question it answers
1dice_focal_260624_s5d3per-class label stroke: solid 5 / dashed 3 px Is the 4 px label the F1 ceiling? If F1 jumps on either anchor → yes, keep per-class stroke and re-tune. If flat on both → label geometry beyond stroke width (gores, faint paint) is the bottleneck → data verdict, program exit criterion approaches.
2ft_r34_260624_s5d3per-class stroke + max_epochs 90
3ft_r34_260624_e90max_epochs 90 only (4 px stroke) Was the 60-epoch cap costing the r34 run real F1? Also isolates schedule from stroke in run 2.

The per-class stroke needs a small harness change (label_stroke_px accepting {solid: 5, dashed: 3} through config → tiles → rasterize → evaluate) — implementation delegated to Grok 4.5 in Cursor per Miro's instruction, reviewed here before submission. Training labels change, so metrics of stroke runs are compared on trend and coverage/tightness, and additionally re-scored against the 4 px test labels for a fixed yardstick.

held for round 3 seed repeats (noise floor on new data), Tversky α dial, r50/unet++ capacity probe — only if round 2 leaves headline F1 ambiguous.

Implementation note — stroke quantization

While wiring the per-class stroke, Grok 4.5's verification surfaced a fact that reframes the stroke hypothesis: _cv_thickness quantizes every requested width to an odd painted width (cv2 cannot center an even stroke), and 4 rounds up — so the round-1 "4 px" labels already painted 5 px. Solid labels have therefore matched the measured physical paint (~5 px) all along; it is the dashed labels that are fat (painted 5 px vs measured ~3.5 px). The realizable correction is {solid: 5, dashed: 3} — solid unchanged, dashed thinned — which is what round 2 runs. This weakens the "label too thin for solids" reading of the sweep2 report and sharpens the alternative: if F1 stays flat in round 2, the residual gap is label geometry beyond stroke width (gores, faint paint, ambiguous edges) — the program's data-bottleneck exit.

Artifacts