feat(core): registration primitives + app patch/batch & asset plumbing - #17
Merged
Conversation
Optional per-dimension patch and batch overrides that take precedence over the VRAM plan and the bundled config; expose get_patch_size() and stage evaluation/uncertainty assets alongside inference.
Norm transform, Flip with vector-field handling, Attribute passthrough in the network, and predictor guard used by the registration apps, with unit tests.
Forward --patch-size/--batch-size through the impact_synth, mrsegmentator and totalsegmentator CLIs.
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
Adds the core building blocks the registration apps need and hardens the KonfAI Apps inference path.
Core: a vector-field-aware
Flipaugmentation, aNormmagnitude transform, an optional geometry (Attribute) channel threaded through the network forward, and a fail-fast guard when no checkpoint is supplied.Apps: the per-app CLIs are refactored onto a single
build_app_clifactory,--patch-size/--batch-sizeinference overrides are plumbed end-to-end, all non-checkpoint bundle assets are staged into the workspace (not just.py), and app-requirement installation becomes opt-in and hardened.These are the primitives the stacked seg/reg apps (
#18/#19) build on.What changed
Core — registration primitives (
konfai/)data/augmentation.py:Flipgains avector_field: boolflag. A new_flip()helper (shared by_computeand_inverse) negates the component channel matching each flipped spatial axis (channel = tensor.dim() - 1 - dim) only when the tensor is a genuine displacement/vector field (tensor.shape[0] == tensor.dim() - 1). The default (vector_field=False) path and scalars/masks are unchanged; an inline comment flags the multi-contrast edge case the channel-count guard cannot distinguish.data/transform.py: newNormtransform. Reduces a stacked vector field over its trailing component axis viatorch.linalg.norm(dim=-1)(e.g. a displacement-field ensemble[N,(D),H,W,C]→ per-sample magnitudes[N,(D),H,W]), drops that axis fromOrigin/Spacing/Direction, and reports the reduced shape intransform_shape()(shape[:-1]) so patch planning stays correct. Intended to precedeVariance/StandardDeviation.network/network.py: optionalattributeschannel through the forward.ModuleArgsDict.named_forward,Network.named_forward, andNetwork.get_layersnow acceptattributes: list[list[Attribute]] | None, thread a parallelattribute_branchsregister alongside the tensor branches, recurse into nestedModuleArgsDict, and passattributes=to leaf modules that declareaccepts_attributes = True(all others keep the old call signature). The measure path sources them from each inputbatch_data_item.attribute, letting geometry-aware registration modules readOrigin/Spacing/Directionduring forward.predictor.py: safer load + fail-fast on missing weights.ModelCompositeloads local checkpoints viasafe_torch_load(...)instead of rawtorch.load(..., weights_only=False), andPredictornow raisesPredictorErrorwhenpath_to_modelsis empty instead of silently running no model and producing no output.Apps — CLI factory (
konfai-apps/konfai_apps/cli.py+apps/*)build_app_cli(...)factory produces a subcommandmain()exposing a uniform operation set (<infer_command>/eval/uncertainty/pipeline) while keeping arguments domain-specific through hooks (resolve_app,add_selection,add_infer_knobs,resolve_infer).infer_commandrenames the inference verb per domain andwith_uncertainty=Falsedrops the uncertainty command. Shared arg builders:_add_app_io,_add_gt,_add_mask,_add_patch_overrides.impact_synth(synthesize; ensemble/tta/mc knobs),mrsegmentator(segment;--folds),totalsegmentator(segment;--models,with_uncertainty=False).Apps — inference overrides & metadata
--patch-size/--batch-sizeoverrides plumbed end-to-end: CLI (_add_patch_overrides, also wired intomain_appsinfer/pipeline) →KonfAIApp.infer/pipeline→install_inference(forced_patch_size=, forced_batch_size=)→_set_patch_size_and_batch_size. Precedence is explicit override → VRAM plan → config default; a single--patch-sizevalue is broadcast to the config's spatial dimensionality (isotropic cube), and_set_patch_size_and_batch_sizewrites only the values supplied (no-op when both areNone).patch_sizesurfaced as app metadata: parsed fromapp.json, exposed viaAppRepositoryInfo.get_patch_size(), and returned inapp_server.get_app_infofor UI patch controls.--lrflag added to thefine-tunesubparser, forwarded throughfine_tune(...)to the existingNetwork.load(override_lr=...)resume-override path.Apps — asset staging & requirement safety (
app_repository.py)download_inference/download_evaluation/download_uncertaintynow copy every bundle file except.pt(custom.py, elastix parameter maps, lookup tables, …) into the workspace, and the config file is written last so its patch/batch tweaks are never clobbered by a raw copy. New_all_repo_filenames()refreshes the file list from the HF tree (metadata-only, cache-backed) so lazily-populated snapshots don't miss assets, falling back to the local snapshot when offline._install_requirements(..., install_requirements=False)defaults to a no-op, skips protected core packages (torch,torchvision,torchaudio,konfai,konfai-apps), and skips non-PEP 508 lines (-r,--extra-index-url,git+https, …) via anInvalidRequirementguard..locksdirectory (and itsHF_HUB_CACHE/repo_folder_nameimports) inLocalAppRepositoryFromHF, relying onsnapshot_download.Docs & misc
README.mdinstall hint uses.[imaging];examples/README.mdcorrects the custom-module filename (UNetpp.py→Model.py)..gitignorestops ignoringapps/impact_reg/apps/impact_segand addsbuild/.Testing
New regression tests:
tests/unit/test_augmentation_flip.py— vector-field round-trip identity, component-channel negation on flip, scalar data stays layout-only, and the default (vector_field=False) stays layout-only on vector data.tests/unit/test_transform_norm.py— trailing-axis reduction with geometry update, andtransform_shape()dropping the trailing axis.tests/unit/test_resume_lr_override.py— resume without override keeps the decayed LR and restores the scheduler; with override the LR/scheduler restart from the requested value (incl.PolyLRScheduler).konfai-apps/tests/unit/test_app_repository.py—install_evaluation/install_uncertaintystage non-Python assets;_install_requirementsis a no-op by default and skips protected / non-PEP 508 lines.Review notes
pr/audit(#16); review only thepr/audit..pr/modif-corerange.Flip.vector_fielddefaults toFalse,Normis new, and the networkattributesargument is optional with leaf modules opted in viaaccepts_attributes— existing configs and models behave exactly as before..ptasset rather than only.pyfiles (intentional, so registration bundles reach the workspace); and an empty checkpoint set is now a hardPredictorErrorinstead of a silent no-op.Flipcomponent-negation guard keys on channel-count == spatial-rank, sovector_field=Trueshould only be set on configs whose augmented tensors are scalars/masks or true vector fields (see the inline comment on the multi-contrast case).