Skip to content

feat(apps): compile a multi-model bundle to a program.json for a Python-free runtime - #66

Merged
vboussot merged 4 commits into
mainfrom
feat/onnx-export
Jul 21, 2026
Merged

feat(apps): compile a multi-model bundle to a program.json for a Python-free runtime#66
vboussot merged 4 commits into
mainfrom
feat/onnx-export

Conversation

@vboussot

@vboussot vboussot commented Jul 21, 2026

Copy link
Copy Markdown
Member

What

Follow-up to #64 (single-model onnx + manifest). Adds multi-model export so a whole
bundle — an ensemble's folds or a nested pipeline — compiles to one program.json a
Python-free runtime can execute.

  • assemble_program(models, *, reduce, classes) emits an ordered dataflow program
    ({steps, output}) over named buffers: one Model step per checkpoint, then a
    reduction step.
  • Reductions: mean, median (new), and merge_labels (disjoint-label ensembles
    like TotalSegmentator's 5 tasks — cumulative per-model offset, last-model-wins).
  • A masked / TTA synthesis bundle compiles to a program (mask + flip TTA steps around the
    model), matching what the KonfAI predictor does at runtime.
  • The reduction is derived from the bundle's output transforms (InferenceStack
    mode → mean/median), so the emitted program mirrors the app's own config.

Why

manifest.json (from #64) covers one model; real apps are ensembles or nested pipelines.
program.json is the portable counterpart that lets a non-Python runtime run the whole
bundle.

Validation

  • pixi run check green (lint + format-check + core tests + apps tests).
  • New/updated tests: test_program.py, test_bundle.py, test_onnx_fold.py,
    test_onnx_export.py (45 pass on the export/program surface).
  • Exercised end-to-end on the real TotalSegmentator 5-fold bundle (25/27/19/24/27-class
    disjoint heads → 118 labels via merge_labels): 98.78% foreground voxel agreement
    vs the KonfAI-native app output on a real CT.

Scope

konfai-apps + konfai export only. No Rust runtime in this PR.

Summary by CodeRabbit

  • New Features
    • Added portable runtime bundle exports, including multi-checkpoint ensembles and masked test-time augmentation workflows.
    • Added nested auxiliary model export support within bundles.
    • Enhanced ONNX exporting with configurable output filenames and optional manifest generation.
    • Expanded ensemble reduction to support mean, median, and label-merge behaviors.
  • Bug Fixes
    • Improved export pipelines to properly treat program-level transforms and correctly source the portable “pre” chain.
  • Tests
    • Added/updated unit tests covering ensemble reduction derivation, masked TTA wiring, and multi-checkpoint nested-model refusal.

vboussot added 3 commits July 21, 2026 23:40
A bundle with several checkpoints exports one <fold>.onnx per checkpoint
plus a program.json -- the multi-model dataflow the konfai-rs runtime runs.
The ensemble reduction is read from the config (MergeLabels -> merge_labels,
InferenceStack -> mean), never a per-app flag; in_channels falls back to the
loaded model. export_to_onnx returns the manifest so folds embed it in the
program; export_onnx_into_bundle stays a single-checkpoint wrapper.
A prediction config with an auxiliary mask group (a nested KonfAIInference
model plus a Mask on the output) compiles to the full dataflow program the
konfai-rs runtime runs: the nested model is resolved and exported, its buffer
is resampled onto the primary grid and dilated, the primary folds run over
flip test-time-augmentation passes, the copies are averaged, masked, inverse
resampled, and cast. Everything is read from the config -- the is_input group,
the program-level transforms (Mask / KonfAIInference / Dilate / Save), the
ensemble reduction, and the TTA. The flip passes are drawn (identity + nb
draws, reproducible from manual_seed): randomness is embraced, so the result
is close, not byte-identical, to a torch-seeded run; a non-Flip augmentation
is skipped rather than blocking the export.
InferenceStack's reduction mode is read from the config (mean vs median)
instead of always assuming mean, and both are runtime buffer ops -- so a
median ensemble is reproduced rather than silently averaged. The masked/TTA
program takes the derived reduction for its copy reduction too.
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6cd496cc-373b-4948-92cf-bc2960d27f22

📥 Commits

Reviewing files that changed from the base of the PR and between 86a4776 and cdf6033.

📒 Files selected for processing (2)
  • konfai-apps/konfai_apps/bundle.py
  • konfai-apps/tests/unit/test_program.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • konfai-apps/konfai_apps/bundle.py

📝 Walkthrough

Walkthrough

Portable bundle export now supports single and multi-checkpoint artifacts, ensemble reduction, masked TTA synthesis, nested models, and configurable ONNX output contracts. Transform compilation and CLI wiring share the portable export path.

Changes

Portable runtime bundle export

Layer / File(s) Summary
Pipeline and reduction contracts
konfai-apps/konfai_apps/bundle.py, konfai-apps/tests/unit/test_bundle.py, konfai-apps/tests/unit/test_onnx_fold.py
Input transforms use is_input groups, program-level transforms are excluded from fold pipelines, reductions support mean, median, and merge_labels, and non-foldable transforms remain rejected.
Masked TTA and nested model programs
konfai-apps/konfai_apps/bundle.py, konfai-apps/tests/unit/test_bundle.py, konfai-apps/tests/unit/test_program.py
TTA passes, auxiliary mask operations, nested inference models, and masked synthesis programs are compiled from configuration; multi-checkpoint nested models are refused.
Portable export orchestration
konfai-apps/konfai_apps/bundle.py
The portable exporter handles checkpoint lists, validation, per-checkpoint artifacts, ensemble programs, masked programs, the legacy wrapper, and CLI integration.
Configurable ONNX export contract
konfai/export.py, tests/unit/test_onnx_export.py
ONNX exports accept custom filenames, optionally write manifests, and return both the ONNX path and manifest dictionary.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant PortableExporter
  participant ONNXExporter
  participant BundleProgram
  CLI->>PortableExporter: provide checkpoints and prediction configuration
  PortableExporter->>ONNXExporter: export checkpoint ONNX and manifest
  ONNXExporter-->>PortableExporter: return artifact path and manifest
  PortableExporter->>BundleProgram: assemble ensemble or masked-TTA program
  BundleProgram-->>CLI: return portable bundle artifact
Loading

Possibly related PRs

Poem

I’m a bunny with bundles, hopping in flight,
Folding checkpoints to programs just right.
Masks bloom softly, flips dance in a row,
ONNX paths and manifests now flow.
Median or mean, the runtimes agree—
Portable exports bring carrots to me!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers the change, rationale, and validation, but it omits required template sections like Type of change and Checklist. Add the missing template sections (Type of change, Checklist, and any breaking-change notes) and align headings with the repository template.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: exporting multi-model bundles to program.json for a Python-free runtime.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/onnx-export

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
konfai/export.py (1)

134-169: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Constrain model_filename to a bare .onnx filename.

out_dir / model_filename accepts absolute and ../ paths, so export_to_onnx() can write outside output_dir. Reject manifest.json too; with write_manifest=True, the manifest write will overwrite the exported ONNX file.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@konfai/export.py` around lines 134 - 169, Validate model_filename in
export_to_onnx before constructing onnx_path: require a bare filename with an
.onnx suffix, reject absolute paths, path components such as directories or ..,
and manifest.json, and raise an appropriate error for invalid values. Keep
writing the validated filename beneath output_dir.
🧹 Nitpick comments (1)
konfai/export.py (1)

134-136: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the new export options.

The changed tests exercise only the defaults. Add a focused case covering a custom .onnx filename, the returned manifest, and write_manifest=False ensuring no manifest.json is written.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@konfai/export.py` around lines 134 - 136, Add a focused test for the export
function covering a custom .onnx filename, validation of the returned manifest,
and write_manifest=False. Assert the custom model file is created, the manifest
is returned as expected, and manifest.json is not written.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@konfai-apps/konfai_apps/bundle.py`:
- Around line 484-486: Update the docstring describing non-Flip TTA handling to
state that such augmentations are skipped rather than refused or rejected. Keep
the existing behavior and the inline comment near the draw loop unchanged, and
ensure the documentation accurately reflects the `f_prob`/`range(0)` path.
- Around line 637-639: Update _export_nested_model around
export_portable_into_bundle so nested mask models with multiple checkpoints do
not unconditionally read manifest.json or copy model.onnx. Validate that nested
exports use exactly one checkpoint, or explicitly handle the program.json
multi-checkpoint output before copying the model and loading metadata.

---

Outside diff comments:
In `@konfai/export.py`:
- Around line 134-169: Validate model_filename in export_to_onnx before
constructing onnx_path: require a bare filename with an .onnx suffix, reject
absolute paths, path components such as directories or .., and manifest.json,
and raise an appropriate error for invalid values. Keep writing the validated
filename beneath output_dir.

---

Nitpick comments:
In `@konfai/export.py`:
- Around line 134-136: Add a focused test for the export function covering a
custom .onnx filename, validation of the returned manifest, and
write_manifest=False. Assert the custom model file is created, the manifest is
returned as expected, and manifest.json is not written.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2083cc40-78d5-4753-8828-517f9cadbce3

📥 Commits

Reviewing files that changed from the base of the PR and between a0b42a3 and 86a4776.

📒 Files selected for processing (5)
  • konfai-apps/konfai_apps/bundle.py
  • konfai-apps/tests/unit/test_bundle.py
  • konfai-apps/tests/unit/test_onnx_fold.py
  • konfai/export.py
  • tests/unit/test_onnx_export.py

Comment thread konfai-apps/konfai_apps/bundle.py Outdated
Comment thread konfai-apps/konfai_apps/bundle.py
mypy failed on three call sites in the program export: the TTA draw read an
optional f_prob, the checkpoint list mixed None with str, and the ensemble
reduction stayed optional at assemble_program.

Narrow each at its source: skip a non-Flip augmentation explicitly instead of
looping zero times, name the resolved checkpoint list, and resolve the ensemble
reduction once (the earlier guard already rejects a missing one).

A nested mask model with several checkpoints exported a program.json while the
caller copied model.onnx, failing on a missing file; refuse it with an
actionable error. Align the _tta_passes docstring with the skip behaviour.
@vboussot
vboussot merged commit 788f2e6 into main Jul 21, 2026
34 checks passed
@vboussot
vboussot deleted the feat/onnx-export branch July 21, 2026 23:10
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.

1 participant