Repository navigation
feat(dynacell): score interior-only foreground metrics by default - #527
Merged
alxndrkalinin merged 9 commits intoOct 14, 2026
Merged
Conversation
Spotlight v2 judged models on foreground-limited pixel metrics, because whole-image pixel metrics are dominated by background voxels. Turn the FG_* columns on in eval.yaml with a hard GT interior mask (feather_sigma_um: 0.0); feather_sigma_um: null keeps the per-target feathered recipe from metrics.FOREGROUND_SIGMAS_UM. The weight map is built from the GT alone and only weights the scoring; neither image is zeroed, so whole-image columns are untouched. FOREGROUND_METRICS_VERSION is not bumped: no FG_* value moves for a given recipe, and the recipe is already stamped in metrics_provenance.json, so an existing save dir recomputes its final metrics once on its next run. Hand-built test configs omit the block, so a compose test of the real eval.yaml pins the new default. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gwn9hwgT8uJSoWaCxCAm8J
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The new default raises for supported nucleoli and lysosome evaluations because their smoothing defaults are undefined.
1 open finding
What changed in this PR
Enables hard-mask foreground metrics by default in DynaCell evaluations.
Changes:
- Enables unfeathered foreground scoring in
eval.yaml. - Updates documentation and reporting comments.
- Adds a composed-default regression test.
| File | Description |
|---|---|
test_evaluate_compose.py |
Tests the resolved ER foreground defaults. |
reporting/tables.py |
Updates the foreground-default comment. |
evaluation/README.md |
Documents the new defaults. |
_configs/eval.yaml |
Enables hard-mask foreground metrics. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
With FG metrics on by default, an eval whose target has no FOREGROUND_SIGMAS_UM entry raises before scoring, and nucleoli and lysosomes are accepted targets without one. They take mitochondria's sigmas (a region mask around compact or punctate bodies), marked untuned because DynaCell has no GT for them. A composition test now resolves the default FG settings for every accepted target; the null-sigma error test moves to a target outside the table. New entries move no existing FG value, so FOREGROUND_METRICS_VERSION stays. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gwn9hwgT8uJSoWaCxCAm8J
Contributor
There was a problem hiding this comment.
🔵 Needs a closer look
Its stated merge conditions remain unresolved, including the pending #526 integration and Spotlight-v2 evaluations.
0 open findings
1 resolved since last review
🧠 Review effort: Balanced
…val-fg-interior-default
test_otsu_source_resolves_no_smoothing_sigma switched to lysosomes to prove the otsu source needs no smooth_sigma_um default. This PR gives lysosomes a default, so the check passed whether or not otsu looks one up. Use golgi, as the sibling resolution test already does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gwn9hwgT8uJSoWaCxCAm8J
…r's list Merge the two new FG-default tests into one parametrized test that checks the exact resolved settings per target. The expected smoothing sigma comes from FOREGROUND_SIGMAS_UM, and the target list from the new segmentation.EVAL_TARGETS, which prepare_segmentation_model now uses too, so a target added to the evaluator is covered automatically. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gwn9hwgT8uJSoWaCxCAm8J
…mito They take mitochondria's sigmas by design; copying the literal would let them drift silently if mitochondria is retuned. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gwn9hwgT8uJSoWaCxCAm8J
eval.yaml named FOREGROUND_SIGMAS_UM twice in one comment, and the tables.py comment copied the default, which is how its old "off by default" went stale. The default now lives in eval.yaml and the README defaults table only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gwn9hwgT8uJSoWaCxCAm8J
The previous derivation bound both entries to mitochondria's dict, so an in-place edit of one (a test monkeypatch or a sensitivity sweep) changed all three. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gwn9hwgT8uJSoWaCxCAm8J
eval.yaml and the README metrics table still called the weight a soft map; under the new default (feather_sigma_um 0) it is binary, feathered only when feather_sigma_um is positive or null. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gwn9hwgT8uJSoWaCxCAm8J
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

What changes
eval.yamlpixel_metrics.foreground:enabled: true,feather_sigma_um: 0.0(hard GT interior mask).source: smooth_otsuandsmooth_sigma_um: null(per-target smoothing default) are unchanged. Setfeather_sigma_um: nullfor the per-target feathered recipe (metrics.FOREGROUND_SIGMAS_UM).reporting/tables.pycomment no longer say "off by default".test_default_eval_scores_interior_only_foregroundcomposes the realeval.yamlthe way the CLI does (_compose_eval_cfg) and checksenabled is True,feather_sigma_um == 0.0, and that_foreground_settingsresolves to{source: smooth_otsu, smooth_sigma_um: 1.0, feather_sigma_um: 0.0}forer. The existing FG tests build configs withOmegaConf.createand cannot see the packaged default, so this test is the only guard on it.Why
Spotlight v2 judged models on interior-only FG metrics. Whole-image pixel metrics are dominated by background voxels, so the FG columns should be in every eval by default.
What I verified in
metrics.pyforeground_weightbuilds the weight from the GT alone (smooth, then Otsu, then an optional feather). Withfeather_sigma_um=0the Gaussian feather is skipped, so the weight is the binary Otsu mask (1 inside, 0 outside). Constant z-planes (padding) are 0.foreground_pixel_metricsnever zeroes the images. The weighted means, std, gain, PCC and MSE are allsum(weight * x) / sum(weight), so background voxels get weight 0 and drop out._weighted_ssimuses normalized convolution: the local statistics come from weight-weighted windows, and the SSIM map is averaged with the weight, so only interior voxels count.target_namein the tracked configs (er,membrane,mitochondria,nucleus) has an entry inFOREGROUND_SIGMAS_UM. Thesmooth_sigma_um: nulldefault therefore resolves and does not raise.No
FOREGROUND_METRICS_VERSIONbumpIts rule is to bump only when an
FG_*value moves for a given recipe, and none does. The recipe (source, sigmas, version, spacing) is already stamped aspixel_foregroundinmetrics_provenance.json, so the cache gate catches the new default without a bump. A bump would also invalidate every existing FG cache, including the Spotlight-v2 FG buckets.One-time cost
On its next non-forced run, any existing save dir without a matching
pixel_foregroundstamp recomputes its final-metrics pass once. That is about 48 single-condition canonical leaves. Grouped leaves already setforce_recompute.final_metrics. The Spotlight-v2 FG buckets fromgenerate_fg_buckets.pyalways writefeather_sigma_umexplicitly, so the new default does not change their recipe.Note: the experiment-local
trackh/make_eval_leaf.py(untracked, underexperiments/2026-09-24_spotlight-v2/) writes onlyforeground.enabled: true. Leaves it generates after this merges will use the hard mask instead of the per-target feather. Pinfeather_sigma_umthere if those runs need the feathered recipe.Merge conditions — met (2026-10-13)
dynacell-modelswas merged into this branch in 5867793, with no rebase and no force-push, and the tests were rerun (below).FG_*columns in their canonical dirs. Whole-image and seg metrics are unchanged. The FG re-score buckets keep their explicitfeather_sigma_um.Review
segmentation.EVAL_TARGETS, which is also used byprepare_segmentation_model).enabledfallback for hand-built configs, and the nucleoli/lysosomes defaults Copilot asked for.Tests (head 26a38cd)
feather_sigma_um: nullin eval.yaml fails 6/6 targets, and dropping the nucleoli/lysosomes defaults fails 2/6.applications/dynacell(tests+src): 4802 tests, 4603 passed, 2 failed, 0 errors, 197 skipped (junitxml).dynacell-models: they fail identically at a23b75c without this PR.test_every_grouped_leaf_is_generated_or_registered_hand_writtenfails because guard 3ae322e rejects feat(dynacell): 2D benchmark on one focus slab — slab3-only predict + focus2d eval #526's 16__2d_focus2dbuckets.test_registered_hand_written_buckets_all_exist_and_are_unstampedfails because the 26 registered hand-written buckets are untracked and exist only in the main checkout.🤖 Generated with Claude Code
https://claude.ai/code/session_01Gwn9hwgT8uJSoWaCxCAm8J