Repository navigation
DynaCell v1.1 application - #534
Merged
Merged
Conversation
Port the Spotlight-motivated losses from dynacell-models so they live in the shared package before any application consumes them: SegAuxDice (seg_aux.py) with the SAUNA-map and soft-clDice weight maps (seg_aux_maps.py), the segmenter-consistency loss (seg_consistency.py), the Track H background low-pass target (background_lowpass.py), and SpotlightLoss(return_components=True). Defaults keep SpotlightLoss's existing behavior; no package imports an application. Source on dynacell-models: 40de793 (#498), 6c28a31 (#521), 0cbeda1 (#524), 050f553 (#530). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port the Spotlight fg-mask recipe from dynacell-models. generate_fg_masks now binarizes a CLAHE-equalized, 5^3-median-filtered volume at an Otsu threshold picked on that volume after a sigma=5 Gaussian; compute_otsu uses the same full-resolution smoothing, so the otsu_grid_spacing parameter is gone from generate_normalization_metadata and VisCyTrainer.preprocess. The median and Gaussian run through cubic on the GPU when cubic and a device are present, else SciPy; cubic stays an optional import. torch is imported lazily so that light callers of write_meta_field do not pay for it. Behavior change: Spotlight masks and Otsu thresholds written by `viscy preprocess` differ from main's. Source on dynacell-models: 40de793 (#498), d087d96 (#510). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rite-once Port the HCSPredictionWriter and prediction_metadata work from dynacell-models: - z_reduction="center" and z_planes (slab-only predicts write only the planes they predicted, and record them); - per-FOV completion markers and the checkpoint/settings identity that predict resume and the eval caches key on (prediction_metadata.py); - refuse writes into an existing store when a FOV outside the run has unmarked prediction channels, or when the array would grow; - assemble each volume in memory and write it once on a background thread (bytes unchanged); - raise NotImplementedError when trainer.world_size > 1, instead of letting ranks race on one store. Source on dynacell-models: 2b848a6, 1be4466, 74fa18a (#497), 8e41498 (#511), 996adb4 (#526), 6c83fff (#531), 8e74a7e (#532). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port the training guardrails from dynacell-models. VisCyCLI now injects, on every `fit`: - a latest-weights ModelCheckpoint that owns last.ckpt (the monitored checkpoint gets save_last=False), so last.ckpt always means the latest epoch, inheriting the leaf's write cadence; - MonitorHealthCheck, which raises when the monitored metric is non-finite or bit-identical for 10 validation epochs; - OptimizerHealthCheck, which raises after 5 consecutive non-finite losses or on GradScaler collapse. Also adds the opt-in LinearLRCooldown callback and raises the CLI subprocess test timeout to 120 s (it timed out on main). Behavior change: this applies to cytoland, dynaclr and dynacell fits. Source on dynacell-models: 20e54db, daa7477, bc0f444, 74fa18a (#497), 92693ae, 2f9ef31 (#528). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port two viscy-utils changes from dynacell-models: - ssim_25d / ms_ssim_25d: clamp the variances, bound the covariance by Cauchy-Schwarz through a safe sqrt, floor the stability constants symmetrically, and run MS-SSIM outside autocast, so 16-mixed training cannot NaN the gradient. SSIM/MS-SSIM loss values change slightly for MixedLoss users. - viscy_utils/__init__ resolves its exports lazily (PEP 562), keeping torch and lightning off light import paths. Source on dynacell-models: a556bc9 (#484), 130e034, cee4e41, 272051c, 59343ad, 8b2413f (#509). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…asks Port the viscy-data side of the dynacell-models predict and Spotlight work: - HCSDataModule.predict_z_planes and SlidingWindowDataset z_planes / read_z_planes, so a 2D model predicts only its focus slab; - cache_volume: with num_workers == 0 predict reads each (position, t) volume once and, when every transform is pointwise, normalizes it once; - foreground masks are read in their stored dtype (uint8) and cast to float on the device in on_after_batch_transfer. Behavior change: every app's predict at num_workers=0 takes the read-once path. Source on dynacell-models: 40de793 (#498), 996adb4 (#526), 6c83fff (#531), 8e74a7e (#532). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hannels Port from dynacell-models: - patch_size may be a per-axis (z, y, x) tuple through the patch embedding, transformer unpatchify and ViT bottleneck, which lets CELLDiffNet run Z-preserving at Z=1 for the 2D track (an int is still accepted); - CELLDiffNet(cond_channels=1) adds extra conditioning input channels (default keeps the old single-channel net). Source on dynacell-models: 0126fe6, 0617ed7, 40de793 (#498). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port the time_schedule option of the CellDiff ODE integrators from dynacell-models: uniform (default, unchanged), cosine, or a Beta(p, q) grid packed toward the data end, which is what lets the DynaCell-lite recipe sample in 14 velocity evaluations. scipy joins the celldiff extra for betaincinv. Source on dynacell-models: 19765e7 (#520). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port MorphEmModel from dynacell-models, the fifth deep-feature extractor of the DynaCell evaluation. transformers is imported lazily and the trust_remote_code model is pinned to a Hub commit. Source on dynacell-models: d3f6422 (#479), 4918d2e, 13cb336, c9c6914. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port preserve_z from dynacell-models, so the 3D PatchGAN runs on Z=1 inputs for pix2pix2d (default off, unchanged). Source on dynacell-models: c2d0481. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port from dynacell-models: - UNet3D(downsample_z=True): False keeps Z through the encoder, which is how FNet2D runs on single planes (default unchanged); - UNet3DBase.forward raises on non-5D input, and a comment flags the ConvTranspose checkerboard artifact. Source on dynacell-models: a556bc9 (#484), 83a1d69, 16b1d31. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port 9640537 from dynacell-models: a size-1 spatial axis (Z=1 for 2D models) gets an identity row in the affine, instead of being resampled off the volume and zeroed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port dfcf9a5 (#512) from dynacell-models: pytest-xdist joins the test group, and a root conftest.py pins OMP/MKL/OpenBLAS to one thread under each xdist worker. Without the pin every worker's torch sizes its pool to all cores, which made `-n 11` 10x slower than it should be and timed out subprocess tests. CLAUDE.md documents the usage. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port the marker half of c50300f (#489) from dynacell-models. strict_markers = true turns an unregistered marker into a collection error, so a typo'd marker can no longer silently decorate nothing. hpc_integration moves from the cytoland and dynaclr conftests to the root: an addinivalue_line registration only holds when that conftest is in the invocation's ancestry. dynaclr drops its own testpaths so the root ini applies. requires_data is registered too: main's applications/dynacell/tools/generate_grouped_eval_configs_test.py uses it, and strict markers would otherwise drop that module at collection. (dynacell-models no longer uses the marker; the dynacell PR that follows removes the registration with it.) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port d1ea492 from dynacell-models. The orchestrated linear-classifier fixture joined on the first fov_name component, which failed 7 tests on main once pytest collects dynaclr's colocated *_test.py. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port the cytoland recipe comment fixes from 40de793 (#498): the preprocess flags take explicit values (`--compute_otsu true --compute_fg_masks true`), fg_threshold and nonzero_threshold are inert while fg_mask_key is set, and the Otsu-centred target is what makes 0 the FG/BG boundary. Comments only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port 93ac234 from dynacell-models: drop the repo-layout tree, setup and common-command blocks, lint/docstring rules (pyproject.toml is the source) and the generic coding-philosophy sections. The DynaCell job runbook from the same file arrives with the dynacell PR, since it documents tools that only exist there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
viscy-utils had no CI job on main or on dynacell-models: four of its test files ran inside the dynacell job and the rest (losses, metrics, meta_utils, optimizer health, CLI, lazy imports) ran nowhere. Mirror the viscy-data job on ubuntu-latest for Python 3.12 and 3.13, and make the gate job wait for it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port the test-dynacell-configs job from dynacell-models, minus the eight test files that only arrive with the dynacell PR: sync viscy-utils' test group with dynacell, and add test_submit_benchmark_batch, test_engine, test_pipeline_cache, feature_metrics_test and the viscy-utils prediction-writer, prediction-metadata, monitor-health and LR-cooldown tests. The dynacell-models PR target is not carried over. Source on dynacell-models: 33d2fee, 74fa18a (#497), 2d1ed32 (#506), 4450efd (#518), 2798dee (#519), 2f9ef31 (#528). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Start from dynacell-models' uv.lock and re-resolve with `uv lock` against this tree, whose applications/dynacell/pyproject.toml is still main's. Against dynacell-models' lock this drops the ten dynacell-only packages (dinov3, etils, ftfy, jsonpath-rw, mlcroissant, pandas-stubs, ply, rdflib, submitit, termcolor) and resolves cubic back to 0.7.0; the dynacell PR restores them. Against main's lock it adds pytest-xdist and moves boto3/botocore 1.43.0 -> 1.43.20, cellpose 4.1.1 -> 4.2.1.1, pyarrow 19.0.1 -> 24.0.0, s3transfer and tracksdata; torch and lightning are unchanged. `uv lock --check` exits 0 (main's own lock does not). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port every DynaCell config path of dynacell-models verbatim: the model leaves (baselines, A549/joint/HEK/brightfield, the 2D track with its seed replicates and warmup-matched refit, the temporal and patch-vs-augmentation ablations, CELL-Diff-R2 and the DynaCell-lite leaves), the grouped and instance-AP eval buckets of the paper models, the shared overlays, train/predict sets and launcher profiles, and the deletion of 155 stale config files. The leaves are generated; review the generators and guard tests in the code commits, not each leaf. Spotlight v2 arm leaves, their four fit overlays and their 231 spotlight_v2_* eval buckets are left out; they follow in their own PR. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port every DynaCell code path of dynacell-models verbatim (226 non-merge commits since 2026-06-16; PRs #479-#530): the evaluation pipeline (cpdino/MorphEm/focus-aware 2D, focus2d slab metrics, foreground-limited metrics, MicroMS3IM, scale-invariant pixel metrics, CP shared space, provenance and cache invalidation), the paths registry, preprocessing/registry/croissant/distribution, the launcher and stall watchdog, the lite benchmark and CELL-Diff fast inference, the 2D track, the HF demo, docs, and the engine, celldiff_wrapper and mask_conditioning modules exactly as on dynacell-models. The three LightningModules keep their Spotlight training hooks (seg_aux, seg_consistency, mask_mode, target_bg_lowpass). Every hook defaults off, the bit-identity tests guard that, and only Spotlight leaves turn them on; two DynaCell-paper 2D checkpoints store seg_aux_weight in their hparams, so a hook-free engine could not resume them. mask_conditioning.py comes along because engine.py and celldiff_wrapper.py import it. The files that import the Spotlight leaf generator are trimmed in the commits that follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Take dynacell-models' uv.lock verbatim, which this tree's pyprojects now match (`uv lock --check` exits 0). Against the shared-packages lock it moves cubic 0.7.0 -> 0.9.0a4 and adds dinov3 (pinned commit), etils, ftfy, jsonpath-rw, mlcroissant, pandas-stubs, ply, rdflib, submitit and termcolor. A fresh `uv lock` would instead float dinov3 to its current HEAD and bump mlcroissant/pandas-stubs, so the verbatim lock keeps the versions the paper evaluations ran with. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Its only user was main's generate_grouped_eval_configs_test.py, which the DynaCell port replaced: the live-data tests there are now marked slow. With strict markers, nothing needs the registration. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Restore the eight dynacell test files the shared-packages PR left out of the test-dynacell-configs job, now that they exist: test_evaluation_microssim_calibration, segmentation_test, test_distribution, test_croissant, test_main_cli_routing, test_evaluation_fid_provenance, provenance_test and watch_stalled_jobs_test. The job now matches dynacell-models'. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port the DynaCell job runbook of the root CLAUDE.md from dynacell-models (6193b9c, bcbfbe6, c4c5ed0, 74fa18a #497, e1d75cf): how to tell a finished-but-hung job from healthy compute by the CPU-time derivative, the stall watchdog (tools/watch_stalled_jobs.py), per-family predict and fit wall limits, and the forensics to capture before cancelling. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…walk
The live tree holds second-checkpoint predictions of registered models
beside their canonical stores, under train-set dirs paths.py does not
know: fnet3d_paper/ipsc_step{8400,11k}, fnet2d_voxelmatched/ipsc_step200k,
fcmae_vscyto{2d_scratch_samplematched,3d_scratch}/ipsc_final and
fcmae_vscyto3d_scratch/ipsc_repredict (34 stores). key_from_prediction_store
raises on them ("unknown train_set token 'ipsc_final'"), which stopped
walk_predictions and filled the instance-AP audit. They come from the
voxel-matched FNet-2D and sample-matched UNeXt2-2D ablations, are
scored only by hand-written experiment buckets, and no committed config
references them, so they are not canonical inputs. Each
(model dir, train-set dir) pair is now listed in _CHECKPOINT_REPREDICTS
with its campaign; the walk skips and counts them and the audit skips
them. A train-set dir that is neither canonical nor listed still raises.
Fixes part of FOLLOWUPS #1 (live-tree walk crash).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
nucleus/pix2pix2d_unetvit_segcons_{s1,ctrl_s1,x10} (12 stores, Spotlight
P1 follow-ups of 2026-10-19) sit in the canonical tree but are in
neither this generator's registry nor paths.PAPER_KEY, so the
PAPER_KEY-based foreign test cannot see them and they raised "unknown
model code-name". They are now listed by name in _FOREIGN_MODEL_DIRS
and skipped like the PAPER_KEY arms; the skip message no longer says
"PAPER_KEY". Any other unknown dir still raises. The new audit test
holds one store of each kind on the live tree (registered, checkpoint
re-predict, named foreign, wmatch, unknown train set) and expects only
the unknown one to be flagged.
Fixes the rest of FOLLOWUPS #1 (live-tree walk crash).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
_CHECKPOINT_REPREDICTS matched (model dir, train-set dir) in every organelle, so a future mito/fnet3d_paper/ipsc_step8400 store would have been skipped as a known re-predict instead of raising, though only the ER one exists. Entries are now (organelle, model, train set) triples for exactly the stores on the live tree; a listed token in another organelle raises "unknown train_set token" again (new test, fails before this change). The audit test now uses the nucleus step-11k store, since the step-8400 one is ER-only. Found by /code-review on the FOLLOWUPS #1 fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
walk_predictions and audit_prediction_coverage each called is_foreign_model_dir and is_checkpoint_repredict inline, so a third skip category added to one could silently miss the other and split them again. Both now call skip_reason(zarr_path), which names the category; the walk counts per category. No behavior change. Found by /code-review on the FOLLOWUPS #1 fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lass Two guards on the hand-kept registries behind the live-tree crash: - every _CODE_TO_PAPER model must parse. At a04b3eb this lists pix2pix2d_unetvit_wmatch{,_seed1}, the omission that stopped walk_predictions; - the name-based skip lists stay disjoint from what the campaign registers: no _FOREIGN_MODEL_DIRS entry in _CODE_TO_PAPER or the parse tuples (it would be dropped silently, since the foreign check runs first), and no re-predict token among the canonical train sets. Found by /code-review on the FOLLOWUPS #1 fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The organelle-scoping edit left a broken line wrap in the _CHECKPOINT_REPREDICTS comment. Comment only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
alxndrkalinin
added a commit
that referenced
this pull request
Oct 27, 2026
Brings in #534's fix for the walk/audit crash on the live prediction tree (FOLLOWUPS #1): wmatch registered for parsing, the listed checkpoint re-predicts and the named P1 segcons replicate dirs skipped with counts, one skip rule for walk and audit, registry guard tests. Resolution in generate_grouped_eval_configs.py: dynacell-models' Spotlight registrations and _SPOTLIGHT_ARM_MODELS stay, with the wmatch entries and _FOREIGN_MODEL_DIRS added beside them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… leaves
Registering pix2pix2d_unetvit_wmatch{,_seed1} for parsing (97c30a1)
fixed the live-tree walk, but a default regeneration would then also
fold their 56 stores into the canonical {organelle}_{train_set}
buckets and the instance-AP leaves, against DON'T-FOLD: the committed
*__2d_focus2d_pix2pix2d_wmatch buckets are where they are scored.
They are now listed in _SIBLING_ONLY_MODELS: walk_predictions still
returns them, so sibling buckets can be built from it, but main()
buckets canonical_predictions() (the walk minus that list) and the
instance-AP in_scope() drops them. New tests: canonical_predictions
leaves them out, in_scope rejects them.
MEASURED on the live tree, both generators run the default way (no
--out-root) emit 0 wmatch blocks, and the canonical pool (628 stores)
is identical, store by store, to what the pre-fix rules parse, so a
default regeneration writes exactly what a04b3eb would have written
had its walk not crashed.
Found by /code-review on the FOLLOWUPS #1 fix (finding 2).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
alxndrkalinin
added a commit
that referenced
this pull request
Oct 27, 2026
Brings in #534's fix that keeps pix2pix2d_unetvit_wmatch{,_seed1} out of the canonical grouped buckets and the instance-AP leaves on a default regeneration. No conflicts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r framework The camera-ready title is now "Evaluating Dynamic 3D Virtual Staining of Live Cells with DynaCell": DynaCell names a broader framework for image-based profiling of cell-state dynamics, and this paper's evaluation framework is part of it. Update the title in CITATION.cff (software and preferred citation), the README and both HF card BibTeX entries, and the Croissant citeAs string; rewrite the CITATION.cff abstract and the README tagline to describe the evaluation framework as part of DynaCell. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015kuht3npKtb2o5E6h19xbA
Mirror paper 1c85e84: "This evaluation framework is part of DynaCell, a broader framework" repeated the noun. The paper's contribution is now the DynaCell evaluation suite, and DynaCell stays the broader framework. The CITATION.cff abstract also says "a set of baseline models", so "suite" means one thing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015kuht3npKtb2o5E6h19xbA
The paper's title is now "The DynaCell Evaluation Suite for Dynamic 3D Virtual Staining of Live Cells" (Overleaf b73f25f). Updates CITATION.cff, the README and HF card BibTeX, and the Croissant citeAs. test_croissant.py: 17 passed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015kuht3npKtb2o5E6h19xbA
edyoshikun
approved these changes
Nov 2, 2026
edyoshikun
left a comment
Collaborator
There was a problem hiding this comment.
this is a pretty solid and huge PR with most of the changes being the addition of the all the config files + tests.
Not sure how much you plan to reuse things but the /tools/*.py has a bunch of stuff.
Otherwise LGTM!
#533 was squash-merged as 4a4ac9f while this branch carried its commits only up to 0b1cb97, so the merge base is pre-#533 main and four files conflicted: - .github/workflows/test.yml, pyproject.toml, uv.lock: main's copy equals #533 at 0b1cb97 and this branch only adds to it, so this branch's side is kept (uv lock --check passes); - applications/dynaclr/tests/conftest.py: unchanged here since 0b1cb97, so main's side is taken (the pandas infer_string fix). No file changed on both sides after 0b1cb97, and every merged file equals this branch's copy where it changed the file, else main's. Full suite (pytest -n 11): 5269 passed, 0 failed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MzpgExfYMKCgogfnhcSgDc
Each did a one-time job that is done, and nothing else imports them: - build_migration_manifest, run_migration, restandardize_config_paths (+ tests): the canonical-path migration was applied 2026-07-13; a rebuilt manifest on 07-24 had nothing left to move; - retokenize_deconv_predictions (+ test): the 24 a549__deconv / joint__legacy_deconvgt renames were applied 2026-07-22; paths.py still reads both tokens for the dirs kept on purpose; - scan_nan_microssim_caches (+ test): one audit for the cubic 0.9.0a1 NaN MicroMS3IM caches that #506 fixed; - add_instance_ap_to_ablation_leaves: one codemod, already applied; - smoke_joint_leaf: an April CPU smoke the config-composition tests now cover. The provenance builders (cpdino seg masks, HEK stores, A549 dual fuse, random-init checkpoints) stay. README entries and one bake_best_ckpt docstring line follow. Full suite: 5251 passed, 0 failed (the 18 fewer are the two deleted tests/ files; the 14 colocated tool tests were never collected by the root run). Raised in review by edyoshikun. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MzpgExfYMKCgogfnhcSgDc
Collaborator
Author
|
@edyoshikun thanks for pointing out the leftovers in |
alxndrkalinin
added a commit
that referenced
this pull request
Nov 4, 2026
#534 was squash-merged into main as 7286fb2. This branch stacked on #534 but stopped six commits short of its final head (d7986fd): the paper retitle, the #533 squash merge, and the deletion of the finished one-shot tools. Merging that head first keeps the real ancestry, so the following merge of main resolves against #533's squash commit instead of the pre-split base. None of these six commits touches a file this branch changes, and no file here references a deleted tool. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01APoGhoKfkCho9Z1VMS5jsG
alxndrkalinin
added a commit
that referenced
this pull request
Nov 4, 2026
main's tree equals #534's final head (d7986fd) byte for byte, and the previous commit merged that head here, so every one of the 47 conflicts (the 40 generated 2D seed1 leaves, evaluation/paths.py and README, the grouped generator and its test, test_paths, test_evaluate_compose, test_benchmark_config_composition) resolves to this branch's side. They are the trims #534 made that this PR reverts. The merge leaves the tree unchanged: the PR's diff against main is byte-identical to its previous diff against its #534 base (772 files). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01APoGhoKfkCho9Z1VMS5jsG
3 tasks done
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.
Summary
Second of three stacked PRs that replace #494. This one ports
applications/dynacellfromdynacell-models(8e74a7e) without the Spotlight v2 experiments. #533 (shared packages) is merged (squash4a4ac9ff); this PR now targetsmain, withmainmerged in atd074562f.After all three merge,
mainis the DynaCell dev line anddynacell-modelsstays frozen as the paper-cited snapshot.Review guide
Most of the size is generated YAML.
configs/is 1,522 files (+73k). The leaves come from the generators (tools/generate_*), and guard tests pin them:test_benchmark_config_composition,test_evaluate_compose,test_paths, and the generators' own*_test.py. Review the generators and the guard tests, not each leaf.Code (
src/,tools/,tests/) is 274 files, +53k/−4k, of whichsrc/is +28k. It is a verbatim copy ofdynacell-modelsexcept the trim commits listed below.Commit layout:
81a74c92configs, verbatim;cdbfcfc6code, verbatim;e0be4c68,d4277d86,898e2e14,9cee1166) and the /code-review fixes (6cb538e6,d86c682f,76e307f8,769cb04c,eb9dc300,f21ed1e8,b96ae3f7). These are the only hand edits to DynaCell files;50f9fe1f,ec725171,d3dc0ce8,0b07f26c,a04b3eb5);97c30a1e..8ebca438, see below).d7986fdedeletes seven finished one-shot tools and their tests (path-migration trio, deconv re-tokenizer, NaN-MicroMS3IM scan, instance-AP codemod, joint-leaf smoke), raised in review by edyoshikun. Full suite after it: 5251 passed, 0 failed.Review them as a diff against
dynacell-models:git diff origin/dynacell-models HEAD -- <file>.Engine hooks (default off)
engine.py,celldiff_wrapper.pyandmask_conditioning.pyare exactly as ondynacell-models. The three LightningModules keep the Spotlight training hooks (seg_aux,seg_consistency,mask_mode,target_bg_lowpass):test_training_integration.pyguard that (e.g.test_unet_seg_aux_none_is_bit_identical_to_the_base_path,test_flow_matching_bg_lowpass_off_is_bit_identical_with_fg_mask_in_the_batch);pix2pix2d_unetvit_wmatch,fcmae_vscyto2d_scratch_samplematched) storeseg_aux_weightin their hparams, so they could not resume against a hook-free class.Behavior change for Spotlight v1 users:
fg_maskis re-binarized> 0.5before it reachesSpotlightLoss.Trim edits (the only differences from
dynacell-modelsbesides the missing Spotlight files)git diff --stat origin/dynacell-models HEADlists 794 files (the live-tree fix changed lines inside the generator files listed below; no new file):lint.yml,test.yml,uv.lock, the 11packages/viscy-utilsfiles of Port shared VisCy package changes from DynaCell v1.1 #533's review fixes, and the 6 VCP tutorial files.tools/generate_grouped_eval_configs.py(e0be4c68, refined in6cb538e6,769cb04c,eb9dc300,f21ed1e8):ARMSimport from the Spotlight leaf generator and the Spotlight names from_CODE_TO_PAPER/_DETERMINISTIC_MODELS/_CELLDIFF_MODELS. It keeps the four 2D*_seed1replicates the 2D appendix scores.is_foreign_model_dir, picks out a dir whose modelpaths.PAPER_KEYknows while this generator neither parses it nor lists it in_CODE_TO_PAPER.walk_predictionsand the instance-AP coverage audit both skip those dirs before parsing, and the walk prints the count. Without this,parse_zarr_nameraises on the first arm (unknown CellDiff variant 'segaux_iterative').dynacell-models: an unknown dir, or a_CODE_TO_PAPERmodel that does not parse (thewmatchdirs).dynacell-models'(102 entries, compared path by path)._match_model_variantis now the single model-dir acceptance rule;_split_model_variantwraps it with the same errors.tests/test_benchmark_config_composition.py,tests/test_paths.py(d4277d86): drop the v1*_spotlightleaf entries, the Spotlight members of the wide-GPU and long-wall sets, and the twotest_pathstests that import the Spotlight generator or need the grouped generator to register the arms.{nucleus,membrane}/{fnet2d,celldiff_2d,fcmae_vscyto2d_scratch,pix2pix2d_unetvit}_seed1leaves (898e2e14): the header pointed atgenerate_spotlight_v2_leaves.py, which is not in this PR. It now says what the leaves are for. The change is comments only. PR-C restores the generated header, because that generator's test pins each leaf byte for byte.evaluation/README.md,tests/test_evaluate_compose.py(9cee1166): no longer list the Spotlight eval generator.tools/generate_instance_ap_eval_configs{,_test}.py(eb9dc300): the audit applies the sameis_foreign_model_dirskip, with a test that has one registered, one foreign and one unknown store.evaluation/paths.py,tests/test_paths.py(b96ae3f7): comments only. They no longer citetools/generate_spotlight_v2_leaves.py, which this branch lacks, and the Spotlight model names stay. PR-C restores the original text.Moved from PR-C to here (
76e307f8, verbatim):tests/test_seg_consistency_{training,focus}.py. They test this PR's engine hook and focus rule with a stand-in segmenter.src/dynacell/mask_conditioning.py, whichengine.pyandcelldiff_wrapper.pyimport.Kept on purpose: the Spotlight model names in
evaluation/paths.py(PAPER_KEYetc.) and thetest_pathstests of those names.canonical_model_nameresolves by longest prefix, so without these names an arm's run dir (fnet2d_segaux) would silently resolve onto its baseline (fnet2d).Root changes on top of PR-A
uv.lock:dynacell-models' lock verbatim, which this tree's pyprojects match (uv lock --checkexit 0). Against PR-A it moves cubic 0.7.0 → 0.9.0a4 and adds dinov3 (pinned commit), mlcroissant, rdflib, etils, submitit and others. A freshuv lockwould float dinov3 to its current HEAD.pyproject.toml: drops therequires_datamarker PR-A registered, since its only user (main's grouped-generator test) is replaced.pyproject.toml: re-adds theapplications/dynacell/examples/hf_demopytest path, forbuild_demo_data_test.py.test.yml: the dynacell job gets backtest_submit_benchmark_batchand the eight test files PR-A left out. Like PR-A, it no longer repeats the four viscy-utils test files that the newtest-utilsjob runs.CLAUDE.mdgets the hung-job / stall-watchdog / wall-limit runbook.Live-tree fix for the grouped eval walk (FOLLOWUPS #1)
On
dynacell-models,walk_predictions()and the instance-AP coverage audit fail on the live prediction tree.Before the fix (MEASURED):
unknown train_set token 'ipsc_final';This PR now handles every known non-canonical dir explicitly. Anything else still raises.
pix2pix2d_unetvit_wmatch{,_seed1}(56 stores)._CODE_TO_PAPERalready declared them a parse-only registration, but_DETERMINISTIC_MODELSlacked them. The committed*__2d_focus2d_pix2pix2d_wmatchbuckets score them._SIBLING_ONLY_MODELSkeeps them out of the canonical grouped buckets and the instance-AP leaves; the walk still returns them, so sibling buckets can be built from it._CHECKPOINT_REPREDICTS: 12 (organelle, model, train set) triples, 34 stores. These are checkpoint variants from the voxel-matched FNet-2D and sample-matched UNeXt2-2D ablations (ipsc_step8400,ipsc_step11k,ipsc_step200k,ipsc_final,ipsc_repredict). Hand-written experiment buckets score them, and no committed config references them._FOREIGN_MODEL_DIRS: the three P1 segcons replicate dirs (12 stores). Neither registry norPAPER_KEYknows them.skip_reason). Guard tests check that every_CODE_TO_PAPERmodel parses and that the skip lists stay disjoint from the registries.After the fix (MEASURED on the live tree, 1,148 stores):
Regression proof (MEASURED, both generators run the default way, without
--out-rootor a filter):{org}_{train_set}bucket orinstance_apleaf.main()buckets (628 stores) is identical, store by store, to what the pre-fix rules parse. Bucketing and emission code is unchanged, so a default regeneration writes exactly what the pre-fix generator would have written if its walk had not crashed.Known limits
SegConsistencyLossdocstring namesdynacell.cellpose_dense, which arrives with PR-C.Tests
Local runs:
pytest -n 8on an A40 node, in this branch's own venv (uv sync --all-packages --all-extras --frozen: cubic 0.9.0a4). The rootaddoptsdeselectslow.applications/dynacell -k 'not test_combined_ddp'8ebca438; one earlier run at that head failedtest_ssim_real_cubic_2d_and_3d_identical_scores_one, which depends on test order; it is pre-existing and unchanged fromdynacell-models)packages/Composition guard runs 0 Spotlight leaves.
test_benchmark_config_composition.pycollects 1,773 tests here, and 0 of their ids match a Spotlight arm token. The same regex matches 705 of 2,478 ids on PR-C, so the check can tell the two apart. The onlyfnet3d_vscyto3daugids arenucleus/fnet3d_vscyto3daug, the DynaCell patch-vs-augmentation ablation.Lint: the pre-commit hooks pass on every commit.
CI: green on
d074562fafter the retarget (29 checks pass, 1 skipped).Merging
main(d074562f). #533 landed as a squash while this branch carried its commits only up to0b1cb979, so four files conflicted against the pre-#533 merge base.test.yml, rootpyproject.tomlanduv.lockkeep this branch's side (main's copy equals #533 at0b1cb979, which this branch only adds to;uv lock --checkpasses);applications/dynaclr/tests/conftest.pytakes main's side (#533's pandasinfer_stringfix; this branch never touched it). Every merged file equals this branch's copy where it changed the file and main's otherwise. Full repopytest -n 11atd074562f: 5269 passed, 0 failed, 138 skipped, 1 xfailed.Review triage and follow-ups are recorded with the split (/code-review triage per finding, and a FOLLOWUPS list of the issues that are pre-existing on
dynacell-models).🤖 Generated with Claude Code