Skip to content

Add train_controlnet_image-from-mask skill - #40

Merged
Can-Zhao merged 15 commits into
NVIDIA-Medtech:mainfrom
Can-Zhao:skill/train-controlnet-image-from-mask
Jul 16, 2026
Merged

Add train_controlnet_image-from-mask skill#40
Can-Zhao merged 15 commits into
NVIDIA-Medtech:mainfrom
Can-Zhao:skill/train-controlnet-image-from-mask

Conversation

@Can-Zhao

Copy link
Copy Markdown
Contributor

Skill for training the 3D image-from-mask ControlNet (scripts.train_controlnet), covering the training-data format (paired VAE latent embedding + combined integer label mask, JSON data list schema, folds, modality), the label↔latent 4x spatial relationship with nearest-neighbor resampling, configs, single/multi-GPU launch, key knobs, and outputs.

Skill for training the 3D image-from-mask ControlNet (scripts.train_controlnet),
covering the training-data format (paired VAE latent embedding + combined integer
label mask, JSON data list schema, folds, modality), the label↔latent 4x spatial
relationship with nearest-neighbor resampling, configs, single/multi-GPU launch,
key knobs, and outputs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds the train_controlnet_image-from-mask skill (new file) and extends the data-prep skill with the missing Step 4 (resample combined label to 4× the latent grid), along with a bug fix in scripts/utils.py that adds "image" to the Orientationd transform so both the latent embedding and the label are reoriented to RAS — previously only the label was reoriented, which could produce axis-misaligned pairs for non-RAS NIfTI inputs.

  • scripts/utils.py: One-line fix adds "image" to Orientationd(keys=["image", "label"]), ensuring the 4-channel latent NIfTI and its paired label are always in the same canonical axis order before training.
  • skills/train_controlnet_image-from-mask.md (new): Documents the full training loop — data format, JSON schema, configs, single/multi-GPU launch, version selection table, and a gotchas checklist with real shipped config defaults.
  • skills/finetune_image-from-mask_data-prep.md: Adds Step 4 (nearest-neighbor resampling of the combined label to the encoded-image grid), updates step references, and cross-links to the new train skill.

Confidence Score: 5/5

Safe to merge — the utils.py fix is a correct hardening of the dataloader orientation step, and the new skill documentation accurately reflects the code.

The only executable code change adds image to an existing Orientationd transform, which is correct: MONAI handles multi-channel 4D volumes by reordering spatial axes while leaving the channel axis intact. All other changes are documentation with two minor inconsistencies that do not affect training correctness.

skills/finetune_image-from-mask_data-prep.md — Step 4 is missing an explicit save-to-disk instruction matching the pattern from Step 3.

Important Files Changed

Filename Overview
scripts/utils.py Bug fix: adds image to Orientationd so the 4-channel latent embedding is reoriented to RAS alongside the label.
skills/finetune_image-from-mask_data-prep.md Adds Step 4 for resampling the combined label; missing save instruction and stale Step 3 comment in JSON schema.
skills/train_controlnet_image-from-mask.md New skill file documenting ControlNet training loop, data format, JSON schema, configs, launch commands, and gotchas checklist.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Raw image + mask] --> B[Step 1: VAE encode]
    A --> C[Step 2: NV-Segment]
    C --> D[Step 3: Remap + combine]
    D --> E[Step 4: NN-resample to 4x latent]
    B --> F[JSON data list]
    E --> F
    F --> G[scripts.train_controlnet]
    G --> H[Checkpoints best + current]
    H --> I[infer_image-from-mask]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[Raw image + mask] --> B[Step 1: VAE encode]
    A --> C[Step 2: NV-Segment]
    C --> D[Step 3: Remap + combine]
    D --> E[Step 4: NN-resample to 4x latent]
    B --> F[JSON data list]
    E --> F
    F --> G[scripts.train_controlnet]
    G --> H[Checkpoints best + current]
    H --> I[infer_image-from-mask]
Loading

Reviews (4): Last reviewed commit: "data-prep: hand off to the train_control..." | Re-trigger Greptile

Comment thread skills/train_controlnet_image-from-mask.md Outdated
Comment thread skills/train_controlnet_image-from-mask.md Outdated
Comment thread skills/train_controlnet_image-from-mask.md
@Can-Zhao Can-Zhao self-assigned this Jul 15, 2026
Can-Zhao and others added 14 commits July 15, 2026 15:05
- Align controlnet_train snippet with the shipped config_maisi_controlnet_train_rflow-ct.json
  (real defaults incl. weighted_loss=100, label [23], region-contrastive keys) instead of a
  disabled template; note per-version differences and how to disable emphasis.
- Replace invalid [None] with valid [null].
- Clarify the ambiguous "encoded-image grid" table cell.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Fix the key error: the autoencoder is NOT loaded by train_controlnet.py; it is a
  data-prep dependency. Reword "How training is wired", the env-config comment, the
  version table (split AE/DM columns), and the gotcha accordingly.
- modality note: give the real "mri_t2"->10 value and attribute the requirement to
  diffusion_unet_def.num_class_embeds (gates include_modality).
- Clarify image_size in the resample snippet is the pre-encoding image shape (4x latent).
- Add caveat: loader orients label to RAS but uses the image embedding as-is.
- Align the frontmatter wording with the reworded "same grid as the encoded image".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The combined label must be resampled (nearest-neighbor) to the same
nearest-multiple-of-128 grid Step 1 uses for the image, so its spatial size is
exactly 4x the latent; otherwise ControlNet training errors out on a shape
mismatch (no auto-resampling in the loop). Replaces the misleading "same
affine/spacing as the pseudo label" note, adds a Step-3b callout + snippet,
cross-references from the JSON dim comment, and adds a gotcha.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the encoded-image-grid requirement out of a Step-3b blockquote into its own
Step 4 (kept short), update the file-map + cross-references accordingly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
State explicitly that the 512x512x167 case resamples the label to 512x512x128.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…xis)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ata-prep Step 4

State the 4x invariant + why, drop the redundant resample snippet (now owned by
data-prep Step 4), keep the RAS-orientation caveat.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…bsection

Was a blockquote footnote under Spatial relationship; now a clear "Orientation"
subsection explaining Orientationd(label→RAS) vs image-as-is and the silent-misalign
failure mode.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…dy RAS)

diff_model_create_training_data.py orients images to RAS before encoding, so
standard embeddings are already RAS; label->RAS just matches that frame. Adding
"image" to the loader transform would be a no-op. Clarify the real misalign
risk (non-standard embeddings) and the correct fix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reframe: it's a no-op for standard RAS embeddings and losslessly realigns a
non-standard one (given a faithful affine), rather than implying it's pointless
or risky.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add "image" to the Orientationd transform in prepare_maisi_controlnet_json_dataloader
so the latent and label are always in the same frame (no-op for standard RAS
embeddings, hardens against non-RAS ones). Removes the need for the orientation
caveat, so drop that subsection from the train skill and simplify the field note.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Point "Next: train the ControlNet" at the dedicated training skill (the fuller
sibling reference) instead of only docs/training.md; keep the quick command.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Can-Zhao

Copy link
Copy Markdown
Contributor Author

@addsouza-nvidia May I ask if you can help review it? Thank you!

@addsouza-nvidia

Copy link
Copy Markdown

Addresses missing info about training data size by adding a new train_controlnet_image-from-mask skill, and extends the data-prep skill with Step 4 (resampling the combined label to the encoded-image grid).

@Can-Zhao
Can-Zhao merged commit 006ac3c into NVIDIA-Medtech:main Jul 16, 2026
2 checks passed
@Can-Zhao
Can-Zhao deleted the skill/train-controlnet-image-from-mask branch July 16, 2026 00:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants