feat: add adaptive sampling, motion registration, MEDL, and e2e ADS configs - #316
feat: add adaptive sampling, motion registration, MEDL, and e2e ADS configs#316georgeyiasemis wants to merge 127 commits into
Conversation
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…onfig LPD/VarSplit/ViT engines were refining coil sensitivities twice via _do_iteration and forward_function. ConjGrad Calgary configs need unet_conv_out_bias so Hub weights with conv_out.bias load correctly. Co-authored-by: Cursor <cursoragent@cursor.com>
Zoo validation metrics used crop_outer_slices (slice 50:-50). Released Hub YAMLs omitted it, so full-volume eval scored outer slices. Mirror configs under projects/calgary_campinas/configs/inference and keep the flag in minimize_inference_yaml. Co-authored-by: Cursor <cursoragent@cursor.com>
Add an inference block with crop_outer_slices and commented 5x/10x accelerations to each base_*.yaml instead of separate Hub-style YAMLs. Co-authored-by: Cursor <cursoragent@cursor.com>
Fill missing Unet/RIM/VarNet/LPD/RecurrentVarNet fields from the trained configs and add 4x inference with commented 8x masking for Hub-style predict. Co-authored-by: Cursor <cursoragent@cursor.com>
Rename AXT1 ablation to t6_h128_nl2, drop fastmri metrics, set inference batch_size to 10, and sync Calgary VarNet comparison params. Co-authored-by: Cursor <cursoragent@cursor.com>
jonasteuwen
left a comment
There was a problem hiding this comment.
Please look at my comments
|
|
||
| for i in range(batch_size): | ||
| x = inputs[i : i + 1] | ||
| count = 0 |
There was a problem hiding this comment.
Can you do @jit.compile? Or doesn't that work here
There was a problem hiding this comment.
No because of the rejection sampling
| super().__init__() | ||
| self.slope = slope | ||
| self.clamp = clamp | ||
|
|
||
| self.fun = ThresholdSigmoidMaskFunction.apply | ||
|
|
There was a problem hiding this comment.
I prefer self._variable for class private variables
| data["sensitivity_map"] = self.compute_sensitivity_map(data["sensitivity_map"]) | ||
|
|
There was a problem hiding this comment.
This was a bug. Sens estimation is already happening in main engine
| self.image_initialization = ( | ||
| image_initialization.lower() if isinstance(image_initialization, str) else image_initialization | ||
| ) |
There was a problem hiding this comment.
Hmm, feels like you should override the __eq__ in the object and make sure str doesn't end up here.
| data["sensitivity_map"] = self.compute_sensitivity_map(data["sensitivity_map"]) | ||
|
|
There was a problem hiding this comment.
This was a bug. Sens estimation is already happening in main engine
| def _deform_random_grid(*args, **kwargs) -> list[np.ndarray]: | ||
| """Lazy import wrapper for :func:`elasticdeform.deform_random_grid`. | ||
|
|
||
| ``elasticdeform`` wheels may be incompatible with NumPy 2.x. | ||
|
|
||
| Returns | ||
| ------- | ||
| list[np.ndarray] | ||
| Deformed images returned by ``elasticdeform``. | ||
| """ | ||
| try: | ||
| from elasticdeform import deform_random_grid | ||
| except ImportError as exc: |
There was a problem hiding this comment.
Isn't this a function that can be forked/vendored?
| curr_model_cfg.update(operator_kwargs) | ||
| # Drop keys unknown to the constructor (e.g. ModConv defaults on legacy modules). | ||
| additional_models[k] = curr_model(**filter_arguments_by_signature(curr_model, curr_model_cfg)) |
There was a problem hiding this comment.
Can this cause silent bugs?
| ARG PYTHON="3.12" | ||
|
|
||
| # TODO: conda installs its own version of cuda | ||
| FROM nvidia/cuda:${CUDA}-devel-ubuntu18.04 |
There was a problem hiding this comment.
Probably need to boost this too
| "pytest>=9", | ||
| "ruff>=0.16.1", | ||
| "ruff>=0.14", | ||
| "ty>=0.0.38", |
There was a problem hiding this comment.
I would keep it to 0.16.1 or you run into issues.
Prefer InitType for RIM init, private binarizer attrs, warn on dropped model kwargs, vendor SciPy elastic deform (drop elasticdeform), pin ruff 0.16.1, and boost the Docker CUDA/PyTorch stack. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Remove `from __future__ import annotations` from Python files touched in this PR and delete the obsolete `projects/scripts/minimize_inference_yaml.py` helper from the repository. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Predict without targets when inference.metrics is empty, only write metrics_inference.json when metrics are computed, and fix DirectEnum from_str typing after dropping future annotations. Co-authored-by: Cursor <cursoragent@cursor.com>
Align the annotation with the (volumes, metrics) tuple returned by inference, and silence BaseConfig/subclass attribute checks. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Keep ADS as an example rather than baking acquisition-specific wording into the H5 writer API docs. Co-authored-by: Cursor <cursoragent@cursor.com>
Drop branch-only batch_size bumps and redundant regularizer_dropout defaults that did not change behavior. Co-authored-by: Cursor <cursoragent@cursor.com>
Restore validation metrics and main inference batch sizes, remove redundant model defaults (dropouts, unused RIM initializer fields), and keep only real diffs: inference blocks and SENSE enum casing. Co-authored-by: Cursor <cursoragent@cursor.com>
Inference lives on the training YAMLs (4x active, 8x commented); the rate-specific copies were duplicates. Update the project README accordingly. Co-authored-by: Cursor <cursoragent@cursor.com>
Description
This PR brings end-to-end adaptive dynamic sampling (ADS) and optional motion registration into DIRECT, together with the paper experiment layouts for the MIDL 2026 e2e ADS works.
It wires learned sampling policies and registration models through the MRI training/inference stack, ships validated train + inference YAML pairs under
projects/e2e_ads_reconandprojects/e2e_ads_recon_reg, and hardens config/checkpoint loading so those projects (and Hub-style inference YAMLs) run cleanly on currentmain(including ruff 0.16).What's new
direct/nn/adaptive/): policies for 1D/2D and static/dynamic masks, rejection-sampling as a typed training path (RejectionSamplingError), and budgeting that works with static ACS on dynamic volumes.direct/registration/,direct/nn/registration/): VoxelMorph-style learned registration plus classical utilities (demons, optical flow, elastic deformation); joint or decoupled recon↔registration training.source_key/target_key) and displacement-field visualization for registration runs.projects/e2e_ads_recon— adaptive sampling + reconstruction (vSHARP / MEDL variants, frame/init2 configs).projects/e2e_ads_recon_reg— same family with registration (vSHARP / VarNet / LOUPE / fixed-mask variants, phase/frame and disjoint options).*_inference.yaml): one inference file per model with active val-4× masking and commented 6×/8× alternatives (no per-rate file explosion).What's changed
MRIModelEngine) call into adaptive sampling / registration when configured; writers can persist registration volumes and displacement fields.training/validationare optional so inference-only YAMLs are valid;logging.log_intervalcontrols TensorBoard/scalar flush cadence.RuntimeErroron missing keys; ModConvconv_out_bias/ AdaIN kwargs wiring aligned so paper weights load under current UNet construction.filter_arguments_by_signaturekeeps**kwargs-based model builders working when configs carry extraimage_*fields.mainruff cleanup without dropping the above behavior.User impact
training/validationblocks; use*_inference.yaml(or the minimizer) instead of maintaining many rate-specific files.registration_simulate_referencein transforms); without that, predict fails with a missingreference_imagekey.