Pipeline Architecture
This document describes the decomposed pipeline architecture of kreview, how commands share code through the nbdev notebook-first workflow, and how to add a new pipeline stage.
Pipeline Overview
The kreview pipeline is decomposed into independent stages that can run either sequentially (kreview run) or in parallel (Nextflow / HPC):
graph LR
classDef step fill:#8b5cf6,stroke:#5b21b6,color:#fff;
classDef opt fill:#f59e0b,stroke:#b45309,color:#fff;
A["Label"]:::step --> B["Extract ×N"]:::step
B --> C[Select]:::step
C --> ABL_CPU["Ablate CPU ×N"]:::opt
C --> ABL_GPU["Ablate GPU ×N"]:::opt
ABL_CPU --> ABL_MERGE["Merge Ablation ×N"]:::opt
ABL_GPU --> ABL_MERGE
ABL_MERGE --> D["Eval CPU"]:::step
ABL_MERGE --> E["Eval GPU"]:::step
C --> D
C --> E
C --> F[Fuse]:::step
D --> S[Scoreboard]:::step
E --> S
D --> MM_PREP["Multimodal Prep"]:::step
E --> MM_PREP
F --> MM_PREP
MM_PREP --> MM_SINGLE["Multimodal Single ×M"]:::step
MM_SINGLE --> MM_ABLATION["Multimodal Ablation"]:::step
MM_ABLATION --> MM_MERGE["Multimodal Merge"]:::step
S --> H[Report]:::step
D --> H
E --> H
MM_MERGE --> I["Report Multimodal"]:::step
Parallel execution
After feature selection, eval cpu, eval gpu, and fuse run in parallel.
After eval, scoreboard and report run in parallel.
The multimodal pipeline is decomposed: prep builds the stacking matrix, single trains per-model stacking classifiers (parallelized across models), ablation runs feature ablation, and merge aggregates final results.
The legacy monolithic kreview eval multimodal run can also execute the full pipeline as a single step.
Feature Group Ablation (v0.0.20+, optional)
When params.run_ablation = true, the ABLATE stages (shown in amber) run between SELECT and EVAL. They use nested inner CV to identify the best feature group subset per model, producing a best_subset.json that EVAL consumes via --best-subset. When run_ablation = false (default), EVAL runs directly after SELECT with all selected features.
Command → Module → Notebook Mapping
Every module in kreview is auto-generated from an nbdev notebook in nbs/. Never manually edit the .py files (see nbdev Workflow).
| CLI Command | Module | Source Notebook | Purpose |
|---|---|---|---|
kreview label |
cli.py:label() |
nbs/90_cli.ipynb |
Generate ctDNA labels |
kreview extract |
cli.py:extract() |
nbs/90_cli.ipynb |
Label + extract feature matrices |
kreview select |
cli_select.py:select() |
nbs/92_cli_select.ipynb |
Score features + mRMR/hybrid-union selection |
kreview eval ablate cpu |
cli_eval.py:eval_ablate_cpu() |
nbs/91_cli_eval.ipynb |
Nested CV feature group ablation (CPU) |
kreview eval ablate gpu |
cli_eval.py:eval_ablate_gpu() |
nbs/91_cli_eval.ipynb |
Nested CV feature group ablation (GPU) |
kreview eval ablate merge |
cli_eval.py:eval_ablate_merge() |
nbs/91_cli_eval.ipynb |
Merge CPU + GPU ablation → best_subset.json |
kreview eval cpu |
cli_eval.py:eval_cpu() |
nbs/91_cli_eval.ipynb |
CPU model evaluation (LR, RF, XGB) |
kreview eval gpu |
cli_eval.py:eval_gpu() |
nbs/91_cli_eval.ipynb |
GPU model evaluation (TabPFN, TabPFN-FT, TabICL, TabICL-FT) |
kreview fuse |
cli.py:fuse() |
nbs/90_cli.ipynb |
Fuse per-evaluator matrices → super-matrix |
kreview eval multimodal run |
cli_eval.py:multimodal_run() |
nbs/91_cli_eval.ipynb |
Monolithic cross-evaluator stacking + ablation |
kreview eval multimodal prep |
cli_eval.py:multimodal_prep() |
nbs/91_cli_eval.ipynb |
Build stacking matrix + feature selection |
kreview eval multimodal single |
cli_eval.py:multimodal_single() |
nbs/91_cli_eval.ipynb |
Train single stacking model (parallelizable) |
kreview eval multimodal ablation |
cli_eval.py:multimodal_ablation() |
nbs/91_cli_eval.ipynb |
Feature ablation analysis |
kreview eval multimodal merge |
cli_eval.py:multimodal_merge() |
nbs/91_cli_eval.ipynb |
Aggregate stacking + ablation results |
kreview report |
cli.py:report() |
nbs/90_cli.ipynb |
Re-generate HTML dashboards |
kreview run |
cli.py:run() |
nbs/90_cli.ipynb |
Full pipeline orchestrator |
kreview features-list |
cli.py:features_list() |
nbs/90_cli.ipynb |
List registered evaluators |
Shared Libraries
| Module | Source Notebook | Functions | Used By |
|---|---|---|---|
selection.py |
nbs/04_selection.ipynb |
score_features(), select_features(), build_binary_target(), MODEL_LABELS, POSITIVE_LABELS |
kreview run, kreview select, report templates |
eval_engine.py |
nbs/02_eval_engine.ipynb |
cpu_models(), gpu_models(), univariate_auc(), mutual_info_score(), load_model_results(), load_all_model_results(), identify_feature_groups(), generate_subsets(), ablate_feature_groups(), merge_ablation(), _compute_oof_metrics(), multimodal_prep(), multimodal_single(), multimodal_ablation(), multimodal_merge() |
kreview run, kreview eval cpu/gpu, kreview eval ablate *, kreview eval multimodal *, selection.py, scoreboard.py, report templates |
scoreboard.py |
Standalone | build_scoreboard() |
kreview report, KREVIEW_SCOREBOARD |
core.py |
nbs/00_core.ipynb |
LABEL_META_COLS, Paths, LabelConfig |
All commands |
registry.py |
nbs/03_registry.ipynb |
get_all_evaluators() |
kreview run, kreview extract, kreview features-list |
Shared Code Principle
kreview run is an orchestrator — it calls the same shared functions as the standalone commands. This guarantees that local runs and HPC runs produce identical results given the same inputs.
# selection.py — used by BOTH kreview run AND kreview select
from kreview.selection import score_features, select_features
# eval_engine.py — used by BOTH kreview run AND kreview eval cpu/gpu
from kreview.eval_engine import cpu_models, gpu_models
When editing these shared functions, always edit the source notebook (nbs/*.ipynb) and run nbdev_export to regenerate the .py modules.
Data Flow
Each stage communicates through parquet files on disk:
Label: → labels.parquet (5-tier ctDNA labels + train/test split column)
Extract: → {evaluator}_matrix.parquet (full features)
Select: → {evaluator}_matrix.parquet (selected features, overwrites)
→ {evaluator}_eval_stats.parquet (per-feature scores for ALL features)
→ {evaluator}_selection_qc.json (selection audit trail)
Ablate CPU: → {evaluator}_ablation_cpu_results.json (per-fold best subsets for LR/RF/XGB)
Ablate GPU: → {evaluator}_ablation_gpu_results.json (per-fold best subsets for TabPFN/TabICL)
Merge Ablation: → {evaluator}_best_subset.json (merged per-model-per-fold winning features + fold_assignment)
Eval CPU: → {evaluator}_model_results.json (AUCs, OOF probs)
→ {evaluator}_{model}_model.joblib (trained models)
Eval GPU: → {evaluator}_gpu_model_results.json (all GPU model AUCs + OOF probs in one JSON)
Fuse: → super_matrix.parquet (wide join on SAMPLE_ID)
Scoreboard: → scoreboard_combined__all.parquet (cross-evaluator rankings)
Multimodal Prep: → stacking_matrix.parquet (OOF probs from all evaluators)
→ prep_metadata.json (feature names, selection QC)
Multimodal Single: → stacking_{model}_results.json (per-model stacking CV)
Multimodal Ablation: → ablation_results.json (feature ablation analysis)
Multimodal Merge: → multimodal_model_results.json (final aggregated results)
Report: → reports/{evaluator}.html (interactive dashboards)
Nextflow Parallelism
See Nextflow Integration for full HPC execution docs.
In Nextflow multistage mode (params.pipeline_mode = 'multistage'), the DAG executes as:
LABEL (1 job) → EXTRACT ×N → SELECT ×N ──┬── [ABLATE_CPU ×N] ──┬── EVAL_CPU ────┬── MULTIMODAL_PREP
├── [ABLATE_GPU ×N] ──┤ (optional) ├── EVAL_GPU ────┤
│ [MERGE_ABLATION] ──┘ └── FUSE ────────┘
│ ↓
│ MULTIMODAL_SINGLE ×M
│ ↓
│ MULTIMODAL_ABLATION
│ ↓
│ MULTIMODAL_MERGE
│ ↓
│ REPORT_MULTIMODAL
└── SCOREBOARD ───────── REPORT (parallel)
Optional Ablation Stages (v0.0.20+)
The [ABLATE_CPU], [ABLATE_GPU], and [MERGE_ABLATION] stages are optional and controlled by params.run_ablation (default: false). When disabled, EVAL runs directly after SELECT with all selected features. When enabled, MERGE produces a best_subset.json consumed by EVAL via --best-subset.
Legacy Monolithic Module
The original KREVIEW_EVAL_MULTIMODAL module (eval_multimodal.nf) is kept for standalone testing. It uses kreview eval multimodal run to execute the full pipeline in a single process.
Each stage is a separate Nextflow process in nextflow/modules/local/kreview/:
| Process | Module | Input | Output | publishDir |
|---|---|---|---|---|
KREVIEW_LABEL |
label.nf |
Samplesheets + cBioPortal | labels.parquet |
outdir/labels/ |
KREVIEW_EXTRACT |
extract.nf |
Samplesheets + labels.parquet | *_matrix.parquet |
outdir/matrices/raw/ |
KREVIEW_SELECT_SINGLE |
select_single.nf |
Raw matrix | Selected matrix + stats + QC | outdir/matrices/selected/ |
KREVIEW_ABLATE_CPU_SINGLE |
ablate_cpu_single.nf |
Selected matrix + labels | *_ablation_cpu_results.json |
outdir/models/ablation/ |
KREVIEW_ABLATE_GPU_SINGLE |
ablate_gpu_single.nf |
Selected matrix + labels + eval_stats | *_ablation_gpu_results.json |
outdir/models/ablation/ |
KREVIEW_MERGE_ABLATION |
merge_ablation.nf |
CPU + GPU ablation JSONs | *_best_subset.json |
outdir/models/ablation/ |
KREVIEW_EVAL_CPU_SINGLE |
eval_cpu_single.nf |
Selected matrix + best_subset | *_model_results.json + *.joblib |
outdir/models/cpu/ |
KREVIEW_EVAL_GPU_SINGLE |
eval_gpu_single.nf |
Selected matrix + eval_stats + best_subset | *_gpu_model_results.json + *.joblib |
outdir/models/gpu/ |
KREVIEW_FUSE |
fuse.nf |
All selected matrices | super_matrix.parquet |
outdir/matrices/fused/ |
KREVIEW_SCOREBOARD |
scoreboard.nf |
Collected CPU + GPU JSONs | scoreboard_combined__all.parquet |
outdir/ |
KREVIEW_MULTIMODAL_PREP |
multimodal_prep.nf |
Eval results + super_matrix | stacking_matrix.parquet + prep_metadata.json |
outdir/models/multimodal/ |
KREVIEW_MULTIMODAL_SINGLE_CPU |
multimodal_single.nf |
Stacking matrix + model name | stacking_{model}_results.json |
outdir/models/multimodal/ |
KREVIEW_MULTIMODAL_SINGLE_GPU |
multimodal_single.nf |
Stacking matrix + GPU model name | stacking_{model}_results.json |
outdir/models/multimodal/ |
KREVIEW_MULTIMODAL_ABLATION |
multimodal_ablation.nf |
Stacking matrix + stacking results | ablation_results.json |
outdir/models/multimodal/ |
KREVIEW_MULTIMODAL_MERGE |
multimodal_merge.nf |
All stacking + ablation results | multimodal_model_results.json |
outdir/models/multimodal/ |
KREVIEW_REPORT |
report.nf |
Matrices + JSONs + stats + QC + joblib + scoreboard | HTML dashboards | outdir/reports/ |
KREVIEW_REPORT_MULTIMODAL |
report_multimodal.nf |
Multimodal JSON + super_matrix | Multimodal dashboard | outdir/reports/ |
KREVIEW_EVAL_MULTIMODAL |
eval_multimodal.nf |
Fuse + eval results | Multimodal results | outdir/models/multimodal/ |
Adding a New Pipeline Stage
- Create the source notebook (e.g.,
nbs/04_new_stage.ipynb) with the shared logic functions - Run
nbdev_exportto generatekreview/new_stage.py - Create a CLI notebook (e.g.,
nbs/93_cli_new_stage.ipynb) with the thin CLI wrapper - Run
nbdev_exportto generatekreview/cli_new_stage.py - Register in
nbs/90_cli.ipynbviaapp.command()orapp.add_typer() - Update
kreview runin the same notebook to call the shared functions - Create a Nextflow process in
nextflow/modules/local/kreview/new_stage.nf - Wire into
nextflow/workflows/kreview_eval.nf - Add tests in
tests/test_new_stage.py - Update this document and Pipeline CLI
Remember the Golden Rule
Always edit the notebook first, then nbdev_export. See nbdev Workflow for details.