Conversation
The reflection engine rewrites the resolved config to disk on read. Two round-trip bugs are fixed: - dict[str, primitive] defaults are persisted (previously dropped) - keys containing '.' are escaped on write / unescaped on read so their values survive the round-trip
Metric, network and model correctness: - metric: Dice/SSIM/Variance edge cases and dict-payload metric logging - perceptual/feature losses compare against the intended targets - loss-weight scheduling honours the configured schedule - accepts_init dispatch routes init() to modules that declare it - BatchNorm gamma is initialised around 1.0, not 0.0 - named_forward resets the inner-match set per module (no sibling leak) - mixed-precision training creates and steps the GradScaler correctly - resume applies the --lr override when loading a checkpoint - UNet attention gated skip is routed to a free branch - DDPM and 3-D VoxelMorph fail fast with an actionable NotImplementedError
Lazy patch-based pipeline correctness: - dataset split / padding / HDF5 read paths - label maps use nearest-neighbour interpolation under augmentation - Crop.transform_shape predicts the exact output spatial shape - overlap blending keeps unit weight at patch borders (no seams) - DDP training shards are equalised to avoid an uneven-input hang - get_infos reverses SITK size to numpy order on every rank - HDF5 datasets are opened read-only for inference
Checkpoint, resume and IO safety: - BEST-checkpoint scan loads through safe_torch_load - https checkpoints never fall back to the unsafe pickle loader - resume restores EMA / optimizer state with the documented convention - interactive-session guard tolerates a non-tty stdout - evaluator statistics aggregate per-case and overall correctly - ITK transform IO and DDP-aware progress reporting
App server hardening, security and packaging: - server auth honours --token-env and --auth off - /repo_apps endpoints are restricted to the configured allowlist - uploads that share a basename are disambiguated - stop bundling konfai-apps into the konfai wheel - per-app setup.py / pyproject metadata and the publish workflow - remove the local AUDIT.md from the repository
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
First wave of the correctness/security audit: behaviour-fixing changes across the config reflection engine, the lazy patch pipeline, metrics/losses, the network/model graph, the training/resume path, the evaluator, and the
konfai-appsserver and client, plus packaging hygiene. Several of these are silent-corruption or hang-inducing bugs — config write-back droppingdictdefaults, overlap-blending seams on volume edges, unequal-length DDP shards hanging NCCL, an unsafe pickle loader on remote checkpoints, andkonfai-appsleaking into thekonfaiwheel. Each fix ships with a focused regression test.Stacked PR — this is the bottom of the stack (#16 →
main); #17–#19 build on it. Review/merge order matters.What changed
Config reflection round-trip (
konfai/utils/config.py)dict[str, primitive]defaults on write-back instead of collapsing them toNone/{}(which silently dropped them on the next run)..and%in dict-key path components (_escape_key_component/_unescape_key_component) so keys containing dots survive the dotted-path split used to recurse into nested configs.Lazy patch pipeline (
konfai/data/patching.py,transform.py,augmentation.py,data_manager.py,konfai/utils/dataset.py)Accumulator, andPathCombine.set_patch_configshort-circuitsoverlap <= 0to unit weights — fixes darkened patch borders/corners on volume edges without whole-image padding.Crop.transform_shapetreatsshapeas the already channel-stripped spatial shape, so the predicted output shape matches__call__exactly (patch planning depends on this).mode="nearest"underEulerTransform/Elastix(integer dtype → nearest) instead of blending class ids;Translateparams are normalized to grid coordinates (value * 2 / (size - 1)) andRotatequarter-turns are randomized per case/axis; augmentation state is drawn once per case and shared across destination groups (reset_stategating inreset_augmentation).get_infosand the per-rank reader indataset.pyreverseSimpleITK.GetSize()for every dimensionality, not only 3-D (2-D/4-D were transposed).threading.RLock(_get_h5_file_lock) serialises the open/use/close sequence so cache workers cannot race/truncate;is_dataset_exist-path reads open read-only (Dataset.File(..., True, ...)).TensorCastsource dtype) back onto the case attribute (_stream_attributes_persisted), matching the non-streamed path.Paddinginverse-origin correction indexes the correct axis (origin[dim]);ResampleToResolution/ResampleToShapenowraise TransformError(were constructed and discarded); unsupported ITK transform typesraise DatasetManagerErrorinstead of falling through (elifchains).Subsetselection is deterministic (sorted); shuffling moved toDataunder an explicitsubset.shuffleguard.DDP training shards (
konfai/data/data_manager.py)min_len(DistributedSamplerdrop_lastsemantics) so every rank runs the same number of backward all-reduces per epoch — prevents the NCCL hang understatic_graph=True.world_size == 1keeps every sample.Metrics & losses (
konfai/metric/measure.py,schedulers.py)Diceexcludes background (label 0) from auto-labels and normalizes by the count of present labels;SSIMcomputes over channels viachannel_axis, returns a tensor, and tolerates a missing mask;Varianceguards single-channel input;PerceptualLosspasses targets with*targetsunpacking (was comparing against a list).Measure.Loss.get_lossaligns the current losses with their trailing weights so a scheduler drives the gradient; dict-payload metrics (per-label Dice/TRE) are nan-mean-summarized for logging inMeasure.Loss.add.accepts_initdispatch reads the flag off the criterion module, not theCriterionsAttrvalue (was alwaysFalse, silently skipping graph-rewiring criteria likeKLDivergence).PolyLRScheduler.steprespectslast_epochwhen set.Network & models (
konfai/network/network.py,models/)1.0(pix2pix convention), not0.0(which stalled early training).named_forwardresets its per-module inner-match set (tmp = []) so a sibling's output is not silently dropped.Measureholds theGradScalerand scales the backward pass; the scaler is wired fromNetworkwhen built.UNetBlockattention routes the gated skip to a free branch (out_branch=[2],skip_branch) so it captures theMultiplyoutput, not an internal half-resolution projection.NotImplementedError:DDPM(broken time-embedding wiring) and 3-DVoxelMorph(2-D-hardcoded warping); deadCycleGanDiscriminator.initializedremoved.Training / resume / checkpoints / EMA (
konfai/trainer.py,network.py,konfai/main.py)_loadgo throughsafe_torch_load;https://model URLs are kept as raw strings (noPath()//collapse) and never fall back to the unsafe unpickler._broadcast_stopviasynchronize_data) so the loop is left together; the LR-decayed-to-zero clean stop is preserved.loss=Noneis stored asinf; EMAn_averagedis saved/restored (Model_EMA_n_averaged); the EMA blend uses the standard convention (decay * avg + (1 - decay) * model).--lroverride forRESUME: threadedbuild_train(lr=...)→Trainer.set_lr→Network.load(override_lr=...), resetting optimizerlr/initial_lrand schedulerbase_lrs/last_epoch/_last_lr.Noneresumes the checkpoint LR and continues the schedule.Evaluator (
konfai/evaluator.py)_to_serializable→nullfor non-finite,allow_nan=False);countno longer becomes NaN; per-case metric mean guardsc == 0;Statistics.readkeys by the full metric path and drops component sub-entries by aggregate-prefix instead of the hardcodedDicespecial-case.IO safety & runtime (
konfai/utils/runtime.py,ITK.py)safe_torch_load(prefersweights_only=True; local checkpoints may fall back,https://never does), reused acrosstrainer.py,bundle.py, andapp.py.is_interactive_sessionguardsstdout.isatty(tolerates a non-ttyLog/MinimalLogproxy);synchronize_dataworks without CUDA whendist.is_initialized(); workflow seeding (np/random/torch.manual_seed) is applied frommanual_seed;_invert_via_displacement_fieldrejects a missing reference image.App server hardening & security (
konfai-apps/konfai_apps/app_server.py,cli.py)hmac.compare_digest;_require_configured_apprestricts/repo_apps_*endpoints and job submission to the configured allowlist (SSRF/exfiltration guard);_configure_server_auth_envhonours--token-envand clearsKONFAI_API_TOKENunder--auth off.save_uploads); grouped uploads (save_upload_groups) and zip-slip-protected dataset extraction (extract_zip_safely); SSE switched from a hard TTL to a: keepaliveheartbeat that terminates on real job state; log lines push thread-safely viaemit_log(call_soon_threadsafe);q_put_drop_oldestcatchesQueueEmpty; GPU selection validates requested ids or auto-selects.App client & CLI (
konfai-apps/konfai_apps/app.py,cli.py,app_repository.py)chdir;fine_tunetakes a single zippeddatasetand forwards--lr; remote__ERROR__markers raiseRuntimeError;_supported_suffixpicks the longest registered extension forVolume_icopies; supported-file listing issortedso cases pair across groups; newkonfai-apps downloadcommand +LocalAppRepositoryFromHF.download_files.Packaging (
pyproject.toml, per-appsetup.py,.github/workflows/publish.yml)packages.findinclude changed to["konfai", "konfai.*"]withkonfai-apps*excluded, so the hyphenated sibling no longer ships in thekonfaiwheel while PEP 420 namespace subpackages (konfai.models.*) still do.konfai-appssetup.pypininstall_requiresto the matching release (dynamic = [..., "dependencies"]);publish.ymlgains atestjob that gatesbuild;pixigainstest-apps(folded intocheck); the localAUDIT.mdis removed from the repo.Testing
31 new regression tests under
tests/unit/(one per fix area):test_config_dict_roundtrip,test_config_dotted_dict_keys,test_patch_overlap_border,test_crop_transform_shape,test_augmentation_fixes,test_augmentation_label_interpolation,test_data_pipeline_audit,test_dataset_audit,test_ddp_shard_balance,test_get_infos_shape_order,test_hdf5_read_only,test_measure,test_dict_metric_logging,test_loss_weight_scheduling,test_perceptual_loss_targets,test_accepts_init_dispatch,test_batchnorm_init,test_named_forward_sibling,test_network_ddp_fixes,test_unet_attention,test_experimental_models,test_trainer_checkpoints,test_ema_convention,test_resume_https_checkpoint,test_safe_torch_load,test_evaluator_statistics,test_itk_transforms,test_interactive_session_guard,test_runtime_progress_ddp,test_transform_fixes, andtest_wheel_packaging; plus updates totest_audit_fixes,test_early_stopping, andtest_runtime_guards.New
konfai-apps/tests/unit/suites:test_app_server_helpers,test_finetune_lr_override,test_repo_apps_allowlist,test_server_auth_env,test_upload_basename_collision, plus substantial additions totest_app_runtime.CI:
publish.ymlrunspytest testsandpytest konfai-apps/testsas atestjob thatbuilddepends on. Thekonfai-appssuite is a separate package and is not covered bypixi run test— run it via the newtest-appstask (folded intocheck).Review notes
_avg_fn, BatchNorm gamma init0.0 → 1.0, thePaddinginverse-origin axis fix,Translategrid-coordinate normalization, and theget_infossize reversal for 2-D/4-D. These correct real bugs but will change numeric output for pipelines/checkpoints that depended on the old behaviour.DDPMor 3-DVoxelMorphnow raisesNotImplementedError(previously crashed opaquely);https://remote checkpoints loadweights_only=Trueonly and will fail if they need the unsafe unpickler (by design); thekonfaiwheel no longer containskonfai_apps.fine_tunenow expects a single zippeddatasetupload rather thaninputs, grouped uploads add*_groupssize fields, and endpoints enforce the app allowlist. Clients on the old format need updating.konfai-apps/konfai_apps/app_server.py,konfai/utils/dataset.py,konfai/trainer.py,konfai/network/network.py, andkonfai/data/patching.py.