0
stars
29
commits
Python
primary language
Sep 6, 2026
updated
A generalized framework for fair, reproducible evaluation of
whole-slide pathology vision-language models.
PGVL-Gym is a registry-based benchmark that runs recent few-shot and zero-shot whole-slide-image (WSI) vision-language methods through one explicit experiment contract. It preserves each paper's model-specific architecture while standardizing protocols, feature provenance, folds, shots, seeds, and reporting.
Systematic protocols cover TCGA NSCLC, BRCA and RCC plus UBC-OCEAN and CAMELYON16. A separate combined CAMELYON16+17 matrix registers the native FOCUS/MUSE cohort without mixing it into CAMELYON16-only results.
Each cohort owns one benchmark directory under benchmarks/, holding its
protocol.yaml and everything generated from it (manifests, splits, configs,
run_matrix.csv, readiness reports). Cohorts are kept separate so one whose
data is not ready cannot hold back the ones that are:
| Benchmark | Task |
|---|---|
benchmarks/tcga_nsclc | LUAD vs LUSC |
benchmarks/tcga_brca | IDC vs ILC |
benchmarks/tcga_rcc | RCC subtyping |
benchmarks/ubc_ocean | five-class ovarian carcinoma subtyping |
benchmarks/camelyon16 | lymph-node metastasis detection |
benchmarks/camelyon_combined | combined CAMELYON16+17 metastasis detection for FOCUS/MUSE |
The documentation site combines curated guides with API reference generated directly from the stable Python docstrings:
python -m pip install -r requirements-docs.txt
python scripts/check_docstrings.py
python -m mkdocs build --strict
PGVL-Gym is a reproducible benchmark for few-shot and zero-shot whole-slide pathology vision-language methods. It standardizes datasets, feature provenance, patient-disjoint folds, training, and reporting while explicitly recording whether each adapter is vendored, mixed, or a partial local reimplementation.
The normal workflow is:
configure local paths → generate run YAMLs → preflight → train → aggregate → explain
The supported Python range is 3.10–3.11. Create the base environment with Conda:
conda env create -f environment.yml
conda activate pgvl-gym
pip install -e .
Install only the optional dependencies needed by your method:
pip install -e '.[cod-mil]'
pip install -e '.[pathpt-musk]'
pip install -e '.[convlm]'
pip install -e '.[hive-mil]'
Available extras are listed in pyproject.toml. Foundation-model checkpoints
are not downloaded automatically; benchmark runs are designed for local or
offline model caches.
Copy the environment template and edit the ignored local file:
cp .env.example .env
PGVL_REPO_ROOT=/path/to/PGVL-Gym
PGVL_USER_ROOT=/path/to/user-root
PGVL_STORAGE_ROOT=/path/to/storage-root
PGVL_CONDA_ENV=/path/to/project/envs/pgvl-gym
Committed protocols, manifests, splits, and configs use references such as
${PGVL_REPO_ROOT} and ${PGVL_STORAGE_ROOT}. Python commands load .env
automatically. The launch shell scripts source it as well. Existing process
environment variables take precedence, which is useful on a cluster.
Do not commit .env; it is intentionally ignored.
Each cohort has one source-of-truth protocol:
benchmarks/<cohort>/protocol.yaml
Edit its cohort metadata, feature registry, checkpoints, methods, folds, and shot counts, then generate manifests, splits, method configs, and the run matrix:
python scripts/tcga_benchmark.py all \
--protocol benchmarks/tcga_brca/protocol.yaml
Useful stages are inventory, prepare, configs, validate, aggregate,
and all. Generated configs appear under
benchmarks/<cohort>/configs/<experiment>/; runnable rows are indexed in
benchmarks/<cohort>/run_matrix.csv.
Shot schedules are cohort-capacity-aware while retaining identical nested, patient-disjoint splits across methods: CAMELYON16, combined CAMELYON16+17, TCGA-BRCA, and TCGA-NSCLC provide 4/8/16/32/64-shot configs; TCGA-RCC provides 4/8/16/32; UBC-OCEAN provides 4/8/16. The combined cohort's 32/64-shot rows are explicit benchmark extensions beyond the upstream 4/8/16 comparison. Higher RCC and UBC-OCEAN levels are deliberately absent because the rarest classes cannot supply equal-sized training and validation sets without leakage or patient reuse.
Feature extraction may finish after those artifacts are generated. Campaign
planning refreshes feature_coverage.csv, missing_feature_files, and the
feature-derived ready state directly from the existing manifests before every
plan. It does not rebuild prompts, manifests, splits, or configs. Thus a pending
feature set remains a clean skip, then becomes runnable automatically once all
of its referenced files arrive. Use --no-refresh-readiness only when you
deliberately need to inspect the frozen matrix cells.
Check one generated run before allocating a GPU:
python scripts/preflight.py \
benchmarks/tcga_brca/configs/focus/brca_4shot.yaml
python scripts/preflight.py run.yaml --features
python scripts/preflight.py run.yaml --features --deep
python scripts/preflight.py run.yaml --prompts --encoders
python scripts/preflight.py run.yaml --quick
python scripts/preflight.py --system
python scripts/preflight.py run.yaml --strict --json
The preflight command is a read-only doctor. Failures include suggested fixes. Normal mode does not construct a model or load a feature tensor.
Key Checks:
--deep): Verifies keys, shapes, widths, and finite values.Useful doctor modes are:
| Option | Purpose |
|---|---|
--system | Check Python 3.10–3.11, all core packages (including the supported and mutually compatible Torch/torchvision releases), .env, and all PGVL root directories; a run YAML is optional. |
--quick | Check feature roots without statting every manifest row; equivalent to --no-feature-scan. |
--deep | Open every available referenced feature and validate its payload; incompatible with --quick. |
--min-feature-coverage N | Temporarily override the configured coverage threshold with a fraction from 0 through 1. |
--strict | Turn warnings, including explicitly allowed partial coverage, into a failing readiness gate. |
--json | Emit schema-versioned JSON with summaries, timings, host diagnostics, and per-config results. |
--verbose | Include successful resolved paths, asset types, and file sizes. |
--quiet | Print only findings and the final diagnosis. |
--no-color | Disable ANSI color explicitly; redirected output disables it automatically. |
Selectors --assets, --features, --prompts, --encoders, and --splits
can be combined; --all or omitting selectors runs every check. Multiple YAMLs
or shell globs are accepted. A healthy diagnosis exits zero, diagnosed failures
exit one, and invalid command arguments exit two. See
Commands and run lifecycle
for the full interface and JSON contract.
Prompt provenance is tracked by method and by role in text_prompts/PROVENANCE.json.
Every method summary records an exact disclosed generator, an explicit
not_disclosed_by_upstream/legacy_local_generator_not_recorded marker, or a
precise not_applicable_* reason. scripts/audit_prompt_provenance.py --check
fails when a generated asset or method summary omits that identity.
* slots are trainable (all_ctx_trainable: false); external CLIP-RN50 patch rows are unit-normalized before the paper's cosine-similarity operations. CAMELYON also preserves the upstream space before instance prompt slots and its 500-epoch launcher recipe. Unwired alternatives are explicitly labeled. The doctor validates prompt structure, ordered labels, hashes, and the frozen-description boundary.1e-4, 80 epochs); the local runtime restores cached 768-wide PLIP vision features with PLIP's frozen native projection and corrects a released reshape mismatch.att_splits.mat and a usable attribute builder. NSCLC deliberately enables a partial local reconstruction using complete QuiltNet-B-16 20x bags, the pinned B16 text checkpoint, and an audited generated bank; the other banks remain unwired. It must not be reported as an upstream reproduction.derived. Runs pair CONCH v1 5x/20x bags and build each [N,16,D] child hierarchy from audited Trident coordinates. Parent spans are derived per slide and strictly checked against the shared coordinate frame, supporting mixed 20x/40x/60x/80x source scans without a scanner-specific constant; this local feature-preparation boundary is disclosed as partial.derived. Two explicit rows resolve a paper/code conflict: mi_visionshot preserves the released executable's unnormalized projected patch rows, while mi_visionshot_paper_l2 applies the per-patch L2 normalization required by paper Eq. 2.2 before support top-200 selection and inference BGAP. Both restore cached 768D PLIP features through PLIP's frozen native visual projection and keep labels support-only. The current 939-slide, patient-level, 224px protocol remains partial relative to the paper's 923-slide, random-repeat, 256px experiment.9e-6, 200 epochs), correcting the conflicting release command example (5x/20x, 9e-4, 50 epochs). It remains partial because cached tiles are 224px rather than 256px, augmented bags are unavailable, and it is not the primary PLIP-G/Prov-GigaPath condition. Upstream does not disclose a generator LLM.Paired-VLM encoder ports are available as opt-in extensions for FOCUS,
ViLa-MIL, TOP, MGPATH, Libra-MIL, DyKo, and HIPSS. Native rows are unchanged.
Each extension requires one exact CONCH, KEEP, MUSK, PLIP, or QuiltNet-B-16
image/text checkpoint,
encoder_extension: true, and a method-specific strategy recorded in the
resolved config and result provenance. Most ports replace inaccessible
token-level prompting with zero-initialized final-feature context; Libra-MIL
only re-encodes its prompt roles, DyKo also learns a bridge from its fixed
TITAN concept bank, and HIPSS replaces CONCH-block SSF with final-feature
affine SSF. PLIP's cached 768-wide vision-preprojection rows are restored with
the matching frozen native 768-to-512 visual projection; QuiltNet-B-16 caches
are already in its 512-wide shared image/text space. These rows are partial
architecture extensions, not upstream reproductions. Inspect the legal
combinations with:
The generated matrices now enumerate every exact on-disk encoder condition for each already registered method/cohort pair. PathPT uses its method-owned CONCH/KEEP/MUSK implementations; its PLIP path remains unregistered because the available bags are 768-wide vision-preprojection rather than the required 512-wide shared features. MUSE separately identifies native CONCH, cross-space CONCH-text, and paired-tower conditions; SLDPC's CLIP-RN50 text tower uses an explicit learned slide projection. Dual-scale methods are emitted only when both required scales exist for one checkpoint, so a missing 5x or 10x store is never replaced with a different magnification.
python scripts/list_encoder_swaps.py
python scripts/list_encoder_swaps.py --method hipss --json
python train.py \
--method focus \
--config benchmarks/tcga_brca/configs/focus/brca_4shot.yaml \
--device cuda:0
Generate an audited patch-evidence artifact set (lossless CSV, rendered PNG, and provenance manifest) for an eligible method:
python scripts/generate_heatmap.py \
--method pathpt --config run.yaml --ckpt-dir /path/to/results \
--fold 0 --split test --slide-id SLIDE_ID
The command validates the run/checkpoint identity, uses exact HDF5 level-0
coordinates, and defaults to the predicted class on a coordinate-only canvas.
Pass --target-class LABEL for another class or
--wsi /path/to/slide.svs for an overlay whose dimensions are checked against
the feature geometry. FOCUS, ViLa-MIL, CoD-MIL, native PathPT, TOP, SLIP,
MUSE, Libra-MIL, DyKo, MGPATH, and HIPSS expose audited providers.
Their quantities are intentionally not conflated: outputs retain names such as class-query attention, prompt evidence, patch-class probability, transport attention, and hierarchical contribution. Methods without an audited patch-aligned quantity refuse generation. See the full interpretability workflow and compact method support matrix.
Completed prediction files can be analyzed without retraining:
python scripts/statistical_report.py \
--matrix benchmarks/tcga_nsclc/run_matrix.csv \
--output-dir "${PGVL_STORAGE_ROOT}/PGVL-Gym-results/analysis/statistics/nsclc"
python scripts/efficiency_report.py \
--output-dir "${PGVL_STORAGE_ROOT}/PGVL-Gym-results/analysis/efficiency/current"
The statistical report adds patient-stratified bootstrap confidence intervals,
strict paired differences, AUPRC/Brier/calibration outputs, and collapse
diagnostics. It also writes patient-level reliability curves and confidence
histograms as PNG/PDF figures with hashed run provenance (--no-plots keeps
tables only). This assesses calibration without changing predictions.
The efficiency report joins current run fingerprints with Slurm
GPU hours and memory, trainer parameter records, checkpoint sizes, and optional
profiled throughput, then emits broad and encoder-controlled Pareto fronts.
Unavailable measurements stay blank. See
statistical analysis and
efficiency reporting for the exact contracts.
For a campaign:
./launch_pgvl.sh --dry-run
./launch_pgvl.sh --cohort brca --shots 4 --limit 3
./launch_pgvl.sh
For a convergence and launch-blocker audit, run one full-recipe fold without touching the five-fold outputs:
./launch_pgvl.sh --one-fold --shots 4 --dry-run \
--report benchmarks/launch_report_one_fold_4shot_dry_run.csv
./launch_pgvl.sh --one-fold --shots 4 \
--report benchmarks/launch_report_one_fold_4shot.csv
--one-fold preserves every method's configured epochs and staged-training
recipe, writes to results/one_fold/, and resumes by skipping valid completed
rows. It is not the same as the one-epoch --smoke mode and is not a final
five-fold paper result. Check the quota of the filesystem containing results/
before a large matrix launch because model checkpoints can dominate storage.
Dry-run planning inspects the campaign directly from a bootstrap Python without importing heavy libraries. Real submissions require PGVL_CONDA_ENV.
Launcher & Trainer Features:
Use --rerun for a clean slate run (archives existing state) and --best-effort for explicit automation override.
Generated results also carry implementation_provenance and
upstream_fidelity. These are independent of encoder_provenance: a backbone
can be natively supported while the local objective remains partial. Set
require_upstream_fidelity: true to make the doctor reject partial adapters.
mscpt_raw_rgb row restores the trainable deep visual-prompt branch from 50 ordered selector-ranked RGB crops per slide, deterministically compiled from transferred PNG slides and aligned 5x CONCH coordinates; this local cache boundary remains disclosed.upstream_patch_ssl subtyping recipe, the released zero-start two-epoch warm-up, exact prompt-ranking behavior, and the family-specific pseudo-loss policy (CONCH/KEEP on; PLIP/MUSK off). CAMELYON16 is explicitly a local WSI-detection adaptation—the paper evaluates region segmentation there—and uses validation-only top-1% tumour-evidence calibration rather than majority patch voting. Report balanced accuracy first on imbalanced cohorts.[2C:-1] omission, and matches the release's inert scheduler behavior. These disclosed corrections make implementation fidelity partial. The extension name quiltnet is locked to wisdomik/QuiltNet-B-16; the upstream B-32 tensor remains audit-only and is never relabelled as B-16.few_shot_class_anchor_weight; set it to 0 for the pure-objective ablation). CAMELYON16 runs the released DSMIL/classname transfer condition: exact normal/tumor text, the restored 50%-then-22,528 interval sampler, upstream question dropout, layer-1/layer-2/last soft-prompt pooling, and the SHA-256-pinned TCGA image-report pretrained FiVE checkpoint required by the paper's downstream protocol. Its two unused 16,384-position MIT parameters are reinitialized at the CAMELYON length; the released forward path ignores them and computes position encodings from patch indices. The authors' lung-specific questions in fix_pth_cam.yaml are preserved and disclosed. CAMELYON also has separately named CONCH, CLIP-RN50, and KEEP patch-feature swaps that retain BioClinicalBERT and the released transfer initialization; paired CAMELYON towers are excluded because that checkpoint is BioClinicalBERT-specific. Separate NSCLC VLM-feature rows remain partial BioClinicalBERT extensions; six additional paired-space ablations freeze the exact CONCH v1, QuiltNet-B-16, CLIP-RN50, PLIP, KEEP, or MUSK tower while training native soft prompts and WSI-FiVE fusion. The paired CLIP-RN50 row alone applies CLIP's native EOT-preserving truncation at its immutable 77-token boundary (clip_eot_truncate_77_v1); BioClinicalBERT and the other paired towers are unchanged.The TCGA-NSCLC protocol also maintains a complete 23-source feature inventory
for the requested encoder families and magnifications. See
benchmarks/tcga_nsclc/README.md for exact
coverage. WSI-FiVE's downloaded DSMIL CSV release is imported into audited
HDF5 bags by scripts/import_wsi_five_dsmil_features.py;
the same importer handles CAMELYON16. Inventory registration is intentionally
separate from method/runtime encoder support.
Generated YAMLs are preferred, but this shows the core contract:
method: focus
backbone: conch
backbone_weights: ${PGVL_STORAGE_ROOT}/models/conch.bin
feature_space_id: hf:MahmoodLab/conch
feature_dim: 512
implementation_provenance: vendored
upstream_fidelity: upstream
dataset_csv: ${PGVL_REPO_ROOT}/benchmarks/tcga_brca/data/brca/manifest.csv
split_dir: ${PGVL_REPO_ROOT}/benchmarks/tcga_brca/splits/brca/4shot
feature_path_column: feature__conch_v1_20x
feature_path_column_l: feature__conch_v1_20x
feature_key: features
min_feature_coverage: 1.0
n_classes: 2
classnames:
- invasive ductal carcinoma
- invasive lobular carcinoma
label_dict:
IDC: 0
ILC: 1
text_prompt_path: ${PGVL_REPO_ROOT}/text_prompts/focus/TCGA_BRCA_two_scale_text_prompt.csv
shots: 4
k: 5
k_start: 0
k_end: 5
seed: 1
epochs: 200
batch_size: 1
lr: 0.0001
weight_decay: 0.00001
early_stopping: true
results_dir: ${PGVL_REPO_ROOT}/results/focus/brca/4shot
Feature provenance and dimensions are part of the experiment identity. Do not change a generated YAML in place and reuse its results directory.
A backbone registration declares its real capabilities and returns an
EncoderBundle. Registration does not automatically make every method
compatible; each method's MethodBackboneContract still decides whether the
combination is native, adaptable, or blocked.
import torch
from common.backbones import (
BackboneCapability,
BackboneSpec,
EncoderBundle,
register_backbone,
)
SPEC = BackboneSpec(
name="my-backbone",
family="my-family",
feature_space_id="org/my-backbone@revision",
capabilities=frozenset({BackboneCapability.TILE_ENCODE}),
tile_dim=768,
revision="commit-or-checksum",
)
def build_my_backbone(*, weights_path=None, device="cpu", **kwargs):
model = load_my_model(weights_path).to(device) # your implementation
tile_encoder = MyTileEncoder(model) # implements encode_tiles
return EncoderBundle(
raw_model=model,
spec=SPEC,
tile=tile_encoder,
metadata={"weights_path": weights_path},
)
register_backbone(SPEC, build_my_backbone)
For a permanent built-in registration, place the spec and loader in
common/backbones/factory.py, export any wrapper from common/backbones/, and
add interface tests. Inspect compatibility without loading weights:
python scripts/list_backbone_compatibility.py
python scripts/list_backbone_compatibility.py --method pathpt --json
python scripts/list_encoder_swaps.py
python scripts/list_encoder_swaps.py --method muse --json
See docs/BACKBONE_INTERFACES.md for capability definitions and method swap
boundaries.
train.py unified training and reporting
common/ datasets, backbone contracts, shared model blocks
common/interpretability.py validated patch-evidence and rendering contract
common/statistical_analysis.py patient-bootstrap and calibration contracts
common/efficiency_analysis.py Slurm parsing and Pareto contracts
methods/<name>/ paper-specific model plus BaseMethod adapter
benchmarks/<cohort>/ protocol and generated experiment artifacts
scripts/tcga_benchmark.py protocol compiler
scripts/preflight.py filesystem and feature health check
scripts/generate_heatmap.py checkpoint-bound heatmap artifact generator
scripts/statistical_report.py current-run uncertainty and diagnostic reports
scripts/efficiency_report.py resource, artifact-size, and Pareto reports
configs/ small hand-authored examples
docs/ detailed design and method documentation
Run tests with pytest -q. Contribution and extension guidance lives in
CONTRIBUTING.md and docs/extending.md.
This codebase consolidates code from the following repositories. All copyright remains with the original authors.
| Repository | Method/Role | License |
|---|---|---|
| dddavid4real/FOCUS | FOCUS | 🔒 Apache-2.0 |
| Jiangbo-Shi/ViLa-MIL | ViLa-MIL | 🔒 CC-BY-NC-ND-4.0 * |
| Jiangbo-Shi/CoD-MIL | CoD-MIL | 🔒 CC-BY-NC-ND-4.0 * |
| JJ-ZHOU-Code/MAPLE | MAPLE | 🔒 CC-BY-NC-ND-4.0 * |
| Hanminghao/MSCPT | MSCPT | 🔒 CC-BY-NC-ND-4.0 * |
| MAGIC-AI4Med/PathPT | PathPT | 🔒 MIT |
| miccaiif/TOP | TOP | 🔒 CC-BY-NC-ND-4.0 * |
| LTS5/SLIP | SLIP | 🔒 CC-BY-NC-ND-4.0 * |
| ls1rius/WSI_FiVE | WSI-FiVE | 🔒 CC-BY-NC-ND-4.0 * |
| JiahaoXu-god/CVPR2026_MUSE | MUSE | 🔒 CC-BY-NC-ND-4.0 * |
| BasitAlawode/ConVLM | ConVLM | 🔒 MIT |
| linlu2022/SLDPC | SLDPC | 🔒 Apache-2.0 |
| bryanwong17/HiVE-MIL | HiVE-MIL | 🔒 MIT |
| cvblab/MIVisionShot | MI-VisionShot | ⚠️ No license declared; equations cleanly reimplemented, no source vendored |
| zfy07/Libra-MIL | Libra-MIL | ⚠️ No license declared; equations cleanly reimplemented, no source vendored |
| junjianli106/DyKo | DyKo | ⚠️ No license declared; equations cleanly reimplemented, no source vendored |
| HauschildLab/MGPATH | MGPATH | ⚠️ No license declared; equations cleanly reimplemented, no source vendored |
| Jayanie/HIPSS | HIPSS | ⚠️ No license declared; equations cleanly reimplemented, no source vendored |
| Repository | Method/Role | License |
|---|---|---|
| mahmoodlab/CLAM | CLAM Scaffold | 🔒 GPL-3.0 |
| KaiyangZhou/CoOp | CoOp Blocks | 🔒 MIT |
21 commits
8 commits
Python
97.1%
0
stars
29
commits
Python
primary language
Sep 6, 2026
updated
A generalized framework for fair, reproducible evaluation of
whole-slide pathology vision-language models.
PGVL-Gym is a registry-based benchmark that runs recent few-shot and zero-shot whole-slide-image (WSI) vision-language methods through one explicit experiment contract. It preserves each paper's model-specific architecture while standardizing protocols, feature provenance, folds, shots, seeds, and reporting.
Systematic protocols cover TCGA NSCLC, BRCA and RCC plus UBC-OCEAN and CAMELYON16. A separate combined CAMELYON16+17 matrix registers the native FOCUS/MUSE cohort without mixing it into CAMELYON16-only results.
Each cohort owns one benchmark directory under benchmarks/, holding its
protocol.yaml and everything generated from it (manifests, splits, configs,
run_matrix.csv, readiness reports). Cohorts are kept separate so one whose
data is not ready cannot hold back the ones that are:
| Benchmark | Task |
|---|---|
benchmarks/tcga_nsclc | LUAD vs LUSC |
benchmarks/tcga_brca | IDC vs ILC |
benchmarks/tcga_rcc | RCC subtyping |
benchmarks/ubc_ocean | five-class ovarian carcinoma subtyping |
benchmarks/camelyon16 | lymph-node metastasis detection |
benchmarks/camelyon_combined | combined CAMELYON16+17 metastasis detection for FOCUS/MUSE |
The documentation site combines curated guides with API reference generated directly from the stable Python docstrings:
python -m pip install -r requirements-docs.txt
python scripts/check_docstrings.py
python -m mkdocs build --strict
PGVL-Gym is a reproducible benchmark for few-shot and zero-shot whole-slide pathology vision-language methods. It standardizes datasets, feature provenance, patient-disjoint folds, training, and reporting while explicitly recording whether each adapter is vendored, mixed, or a partial local reimplementation.
The normal workflow is:
configure local paths → generate run YAMLs → preflight → train → aggregate → explain
The supported Python range is 3.10–3.11. Create the base environment with Conda:
conda env create -f environment.yml
conda activate pgvl-gym
pip install -e .
Install only the optional dependencies needed by your method:
pip install -e '.[cod-mil]'
pip install -e '.[pathpt-musk]'
pip install -e '.[convlm]'
pip install -e '.[hive-mil]'
Available extras are listed in pyproject.toml. Foundation-model checkpoints
are not downloaded automatically; benchmark runs are designed for local or
offline model caches.
Copy the environment template and edit the ignored local file:
cp .env.example .env
PGVL_REPO_ROOT=/path/to/PGVL-Gym
PGVL_USER_ROOT=/path/to/user-root
PGVL_STORAGE_ROOT=/path/to/storage-root
PGVL_CONDA_ENV=/path/to/project/envs/pgvl-gym
Committed protocols, manifests, splits, and configs use references such as
${PGVL_REPO_ROOT} and ${PGVL_STORAGE_ROOT}. Python commands load .env
automatically. The launch shell scripts source it as well. Existing process
environment variables take precedence, which is useful on a cluster.
Do not commit .env; it is intentionally ignored.
Each cohort has one source-of-truth protocol:
benchmarks/<cohort>/protocol.yaml
Edit its cohort metadata, feature registry, checkpoints, methods, folds, and shot counts, then generate manifests, splits, method configs, and the run matrix:
python scripts/tcga_benchmark.py all \
--protocol benchmarks/tcga_brca/protocol.yaml
Useful stages are inventory, prepare, configs, validate, aggregate,
and all. Generated configs appear under
benchmarks/<cohort>/configs/<experiment>/; runnable rows are indexed in
benchmarks/<cohort>/run_matrix.csv.
Shot schedules are cohort-capacity-aware while retaining identical nested, patient-disjoint splits across methods: CAMELYON16, combined CAMELYON16+17, TCGA-BRCA, and TCGA-NSCLC provide 4/8/16/32/64-shot configs; TCGA-RCC provides 4/8/16/32; UBC-OCEAN provides 4/8/16. The combined cohort's 32/64-shot rows are explicit benchmark extensions beyond the upstream 4/8/16 comparison. Higher RCC and UBC-OCEAN levels are deliberately absent because the rarest classes cannot supply equal-sized training and validation sets without leakage or patient reuse.
Feature extraction may finish after those artifacts are generated. Campaign
planning refreshes feature_coverage.csv, missing_feature_files, and the
feature-derived ready state directly from the existing manifests before every
plan. It does not rebuild prompts, manifests, splits, or configs. Thus a pending
feature set remains a clean skip, then becomes runnable automatically once all
of its referenced files arrive. Use --no-refresh-readiness only when you
deliberately need to inspect the frozen matrix cells.
Check one generated run before allocating a GPU:
python scripts/preflight.py \
benchmarks/tcga_brca/configs/focus/brca_4shot.yaml
python scripts/preflight.py run.yaml --features
python scripts/preflight.py run.yaml --features --deep
python scripts/preflight.py run.yaml --prompts --encoders
python scripts/preflight.py run.yaml --quick
python scripts/preflight.py --system
python scripts/preflight.py run.yaml --strict --json
The preflight command is a read-only doctor. Failures include suggested fixes. Normal mode does not construct a model or load a feature tensor.
Key Checks:
--deep): Verifies keys, shapes, widths, and finite values.Useful doctor modes are:
| Option | Purpose |
|---|---|
--system | Check Python 3.10–3.11, all core packages (including the supported and mutually compatible Torch/torchvision releases), .env, and all PGVL root directories; a run YAML is optional. |
--quick | Check feature roots without statting every manifest row; equivalent to --no-feature-scan. |
--deep | Open every available referenced feature and validate its payload; incompatible with --quick. |
--min-feature-coverage N | Temporarily override the configured coverage threshold with a fraction from 0 through 1. |
--strict | Turn warnings, including explicitly allowed partial coverage, into a failing readiness gate. |
--json | Emit schema-versioned JSON with summaries, timings, host diagnostics, and per-config results. |
--verbose | Include successful resolved paths, asset types, and file sizes. |
--quiet | Print only findings and the final diagnosis. |
--no-color | Disable ANSI color explicitly; redirected output disables it automatically. |
Selectors --assets, --features, --prompts, --encoders, and --splits
can be combined; --all or omitting selectors runs every check. Multiple YAMLs
or shell globs are accepted. A healthy diagnosis exits zero, diagnosed failures
exit one, and invalid command arguments exit two. See
Commands and run lifecycle
for the full interface and JSON contract.
Prompt provenance is tracked by method and by role in text_prompts/PROVENANCE.json.
Every method summary records an exact disclosed generator, an explicit
not_disclosed_by_upstream/legacy_local_generator_not_recorded marker, or a
precise not_applicable_* reason. scripts/audit_prompt_provenance.py --check
fails when a generated asset or method summary omits that identity.
* slots are trainable (all_ctx_trainable: false); external CLIP-RN50 patch rows are unit-normalized before the paper's cosine-similarity operations. CAMELYON also preserves the upstream space before instance prompt slots and its 500-epoch launcher recipe. Unwired alternatives are explicitly labeled. The doctor validates prompt structure, ordered labels, hashes, and the frozen-description boundary.1e-4, 80 epochs); the local runtime restores cached 768-wide PLIP vision features with PLIP's frozen native projection and corrects a released reshape mismatch.att_splits.mat and a usable attribute builder. NSCLC deliberately enables a partial local reconstruction using complete QuiltNet-B-16 20x bags, the pinned B16 text checkpoint, and an audited generated bank; the other banks remain unwired. It must not be reported as an upstream reproduction.derived. Runs pair CONCH v1 5x/20x bags and build each [N,16,D] child hierarchy from audited Trident coordinates. Parent spans are derived per slide and strictly checked against the shared coordinate frame, supporting mixed 20x/40x/60x/80x source scans without a scanner-specific constant; this local feature-preparation boundary is disclosed as partial.derived. Two explicit rows resolve a paper/code conflict: mi_visionshot preserves the released executable's unnormalized projected patch rows, while mi_visionshot_paper_l2 applies the per-patch L2 normalization required by paper Eq. 2.2 before support top-200 selection and inference BGAP. Both restore cached 768D PLIP features through PLIP's frozen native visual projection and keep labels support-only. The current 939-slide, patient-level, 224px protocol remains partial relative to the paper's 923-slide, random-repeat, 256px experiment.9e-6, 200 epochs), correcting the conflicting release command example (5x/20x, 9e-4, 50 epochs). It remains partial because cached tiles are 224px rather than 256px, augmented bags are unavailable, and it is not the primary PLIP-G/Prov-GigaPath condition. Upstream does not disclose a generator LLM.Paired-VLM encoder ports are available as opt-in extensions for FOCUS,
ViLa-MIL, TOP, MGPATH, Libra-MIL, DyKo, and HIPSS. Native rows are unchanged.
Each extension requires one exact CONCH, KEEP, MUSK, PLIP, or QuiltNet-B-16
image/text checkpoint,
encoder_extension: true, and a method-specific strategy recorded in the
resolved config and result provenance. Most ports replace inaccessible
token-level prompting with zero-initialized final-feature context; Libra-MIL
only re-encodes its prompt roles, DyKo also learns a bridge from its fixed
TITAN concept bank, and HIPSS replaces CONCH-block SSF with final-feature
affine SSF. PLIP's cached 768-wide vision-preprojection rows are restored with
the matching frozen native 768-to-512 visual projection; QuiltNet-B-16 caches
are already in its 512-wide shared image/text space. These rows are partial
architecture extensions, not upstream reproductions. Inspect the legal
combinations with:
The generated matrices now enumerate every exact on-disk encoder condition for each already registered method/cohort pair. PathPT uses its method-owned CONCH/KEEP/MUSK implementations; its PLIP path remains unregistered because the available bags are 768-wide vision-preprojection rather than the required 512-wide shared features. MUSE separately identifies native CONCH, cross-space CONCH-text, and paired-tower conditions; SLDPC's CLIP-RN50 text tower uses an explicit learned slide projection. Dual-scale methods are emitted only when both required scales exist for one checkpoint, so a missing 5x or 10x store is never replaced with a different magnification.
python scripts/list_encoder_swaps.py
python scripts/list_encoder_swaps.py --method hipss --json
python train.py \
--method focus \
--config benchmarks/tcga_brca/configs/focus/brca_4shot.yaml \
--device cuda:0
Generate an audited patch-evidence artifact set (lossless CSV, rendered PNG, and provenance manifest) for an eligible method:
python scripts/generate_heatmap.py \
--method pathpt --config run.yaml --ckpt-dir /path/to/results \
--fold 0 --split test --slide-id SLIDE_ID
The command validates the run/checkpoint identity, uses exact HDF5 level-0
coordinates, and defaults to the predicted class on a coordinate-only canvas.
Pass --target-class LABEL for another class or
--wsi /path/to/slide.svs for an overlay whose dimensions are checked against
the feature geometry. FOCUS, ViLa-MIL, CoD-MIL, native PathPT, TOP, SLIP,
MUSE, Libra-MIL, DyKo, MGPATH, and HIPSS expose audited providers.
Their quantities are intentionally not conflated: outputs retain names such as class-query attention, prompt evidence, patch-class probability, transport attention, and hierarchical contribution. Methods without an audited patch-aligned quantity refuse generation. See the full interpretability workflow and compact method support matrix.
Completed prediction files can be analyzed without retraining:
python scripts/statistical_report.py \
--matrix benchmarks/tcga_nsclc/run_matrix.csv \
--output-dir "${PGVL_STORAGE_ROOT}/PGVL-Gym-results/analysis/statistics/nsclc"
python scripts/efficiency_report.py \
--output-dir "${PGVL_STORAGE_ROOT}/PGVL-Gym-results/analysis/efficiency/current"
The statistical report adds patient-stratified bootstrap confidence intervals,
strict paired differences, AUPRC/Brier/calibration outputs, and collapse
diagnostics. It also writes patient-level reliability curves and confidence
histograms as PNG/PDF figures with hashed run provenance (--no-plots keeps
tables only). This assesses calibration without changing predictions.
The efficiency report joins current run fingerprints with Slurm
GPU hours and memory, trainer parameter records, checkpoint sizes, and optional
profiled throughput, then emits broad and encoder-controlled Pareto fronts.
Unavailable measurements stay blank. See
statistical analysis and
efficiency reporting for the exact contracts.
For a campaign:
./launch_pgvl.sh --dry-run
./launch_pgvl.sh --cohort brca --shots 4 --limit 3
./launch_pgvl.sh
For a convergence and launch-blocker audit, run one full-recipe fold without touching the five-fold outputs:
./launch_pgvl.sh --one-fold --shots 4 --dry-run \
--report benchmarks/launch_report_one_fold_4shot_dry_run.csv
./launch_pgvl.sh --one-fold --shots 4 \
--report benchmarks/launch_report_one_fold_4shot.csv
--one-fold preserves every method's configured epochs and staged-training
recipe, writes to results/one_fold/, and resumes by skipping valid completed
rows. It is not the same as the one-epoch --smoke mode and is not a final
five-fold paper result. Check the quota of the filesystem containing results/
before a large matrix launch because model checkpoints can dominate storage.
Dry-run planning inspects the campaign directly from a bootstrap Python without importing heavy libraries. Real submissions require PGVL_CONDA_ENV.
Launcher & Trainer Features:
Use --rerun for a clean slate run (archives existing state) and --best-effort for explicit automation override.
Generated results also carry implementation_provenance and
upstream_fidelity. These are independent of encoder_provenance: a backbone
can be natively supported while the local objective remains partial. Set
require_upstream_fidelity: true to make the doctor reject partial adapters.
mscpt_raw_rgb row restores the trainable deep visual-prompt branch from 50 ordered selector-ranked RGB crops per slide, deterministically compiled from transferred PNG slides and aligned 5x CONCH coordinates; this local cache boundary remains disclosed.upstream_patch_ssl subtyping recipe, the released zero-start two-epoch warm-up, exact prompt-ranking behavior, and the family-specific pseudo-loss policy (CONCH/KEEP on; PLIP/MUSK off). CAMELYON16 is explicitly a local WSI-detection adaptation—the paper evaluates region segmentation there—and uses validation-only top-1% tumour-evidence calibration rather than majority patch voting. Report balanced accuracy first on imbalanced cohorts.[2C:-1] omission, and matches the release's inert scheduler behavior. These disclosed corrections make implementation fidelity partial. The extension name quiltnet is locked to wisdomik/QuiltNet-B-16; the upstream B-32 tensor remains audit-only and is never relabelled as B-16.few_shot_class_anchor_weight; set it to 0 for the pure-objective ablation). CAMELYON16 runs the released DSMIL/classname transfer condition: exact normal/tumor text, the restored 50%-then-22,528 interval sampler, upstream question dropout, layer-1/layer-2/last soft-prompt pooling, and the SHA-256-pinned TCGA image-report pretrained FiVE checkpoint required by the paper's downstream protocol. Its two unused 16,384-position MIT parameters are reinitialized at the CAMELYON length; the released forward path ignores them and computes position encodings from patch indices. The authors' lung-specific questions in fix_pth_cam.yaml are preserved and disclosed. CAMELYON also has separately named CONCH, CLIP-RN50, and KEEP patch-feature swaps that retain BioClinicalBERT and the released transfer initialization; paired CAMELYON towers are excluded because that checkpoint is BioClinicalBERT-specific. Separate NSCLC VLM-feature rows remain partial BioClinicalBERT extensions; six additional paired-space ablations freeze the exact CONCH v1, QuiltNet-B-16, CLIP-RN50, PLIP, KEEP, or MUSK tower while training native soft prompts and WSI-FiVE fusion. The paired CLIP-RN50 row alone applies CLIP's native EOT-preserving truncation at its immutable 77-token boundary (clip_eot_truncate_77_v1); BioClinicalBERT and the other paired towers are unchanged.The TCGA-NSCLC protocol also maintains a complete 23-source feature inventory
for the requested encoder families and magnifications. See
benchmarks/tcga_nsclc/README.md for exact
coverage. WSI-FiVE's downloaded DSMIL CSV release is imported into audited
HDF5 bags by scripts/import_wsi_five_dsmil_features.py;
the same importer handles CAMELYON16. Inventory registration is intentionally
separate from method/runtime encoder support.
Generated YAMLs are preferred, but this shows the core contract:
method: focus
backbone: conch
backbone_weights: ${PGVL_STORAGE_ROOT}/models/conch.bin
feature_space_id: hf:MahmoodLab/conch
feature_dim: 512
implementation_provenance: vendored
upstream_fidelity: upstream
dataset_csv: ${PGVL_REPO_ROOT}/benchmarks/tcga_brca/data/brca/manifest.csv
split_dir: ${PGVL_REPO_ROOT}/benchmarks/tcga_brca/splits/brca/4shot
feature_path_column: feature__conch_v1_20x
feature_path_column_l: feature__conch_v1_20x
feature_key: features
min_feature_coverage: 1.0
n_classes: 2
classnames:
- invasive ductal carcinoma
- invasive lobular carcinoma
label_dict:
IDC: 0
ILC: 1
text_prompt_path: ${PGVL_REPO_ROOT}/text_prompts/focus/TCGA_BRCA_two_scale_text_prompt.csv
shots: 4
k: 5
k_start: 0
k_end: 5
seed: 1
epochs: 200
batch_size: 1
lr: 0.0001
weight_decay: 0.00001
early_stopping: true
results_dir: ${PGVL_REPO_ROOT}/results/focus/brca/4shot
Feature provenance and dimensions are part of the experiment identity. Do not change a generated YAML in place and reuse its results directory.
A backbone registration declares its real capabilities and returns an
EncoderBundle. Registration does not automatically make every method
compatible; each method's MethodBackboneContract still decides whether the
combination is native, adaptable, or blocked.
import torch
from common.backbones import (
BackboneCapability,
BackboneSpec,
EncoderBundle,
register_backbone,
)
SPEC = BackboneSpec(
name="my-backbone",
family="my-family",
feature_space_id="org/my-backbone@revision",
capabilities=frozenset({BackboneCapability.TILE_ENCODE}),
tile_dim=768,
revision="commit-or-checksum",
)
def build_my_backbone(*, weights_path=None, device="cpu", **kwargs):
model = load_my_model(weights_path).to(device) # your implementation
tile_encoder = MyTileEncoder(model) # implements encode_tiles
return EncoderBundle(
raw_model=model,
spec=SPEC,
tile=tile_encoder,
metadata={"weights_path": weights_path},
)
register_backbone(SPEC, build_my_backbone)
For a permanent built-in registration, place the spec and loader in
common/backbones/factory.py, export any wrapper from common/backbones/, and
add interface tests. Inspect compatibility without loading weights:
python scripts/list_backbone_compatibility.py
python scripts/list_backbone_compatibility.py --method pathpt --json
python scripts/list_encoder_swaps.py
python scripts/list_encoder_swaps.py --method muse --json
See docs/BACKBONE_INTERFACES.md for capability definitions and method swap
boundaries.
train.py unified training and reporting
common/ datasets, backbone contracts, shared model blocks
common/interpretability.py validated patch-evidence and rendering contract
common/statistical_analysis.py patient-bootstrap and calibration contracts
common/efficiency_analysis.py Slurm parsing and Pareto contracts
methods/<name>/ paper-specific model plus BaseMethod adapter
benchmarks/<cohort>/ protocol and generated experiment artifacts
scripts/tcga_benchmark.py protocol compiler
scripts/preflight.py filesystem and feature health check
scripts/generate_heatmap.py checkpoint-bound heatmap artifact generator
scripts/statistical_report.py current-run uncertainty and diagnostic reports
scripts/efficiency_report.py resource, artifact-size, and Pareto reports
configs/ small hand-authored examples
docs/ detailed design and method documentation
Run tests with pytest -q. Contribution and extension guidance lives in
CONTRIBUTING.md and docs/extending.md.
This codebase consolidates code from the following repositories. All copyright remains with the original authors.
| Repository | Method/Role | License |
|---|---|---|
| dddavid4real/FOCUS | FOCUS | 🔒 Apache-2.0 |
| Jiangbo-Shi/ViLa-MIL | ViLa-MIL | 🔒 CC-BY-NC-ND-4.0 * |
| Jiangbo-Shi/CoD-MIL | CoD-MIL | 🔒 CC-BY-NC-ND-4.0 * |
| JJ-ZHOU-Code/MAPLE | MAPLE | 🔒 CC-BY-NC-ND-4.0 * |
| Hanminghao/MSCPT | MSCPT | 🔒 CC-BY-NC-ND-4.0 * |
| MAGIC-AI4Med/PathPT | PathPT | 🔒 MIT |
| miccaiif/TOP | TOP | 🔒 CC-BY-NC-ND-4.0 * |
| LTS5/SLIP | SLIP | 🔒 CC-BY-NC-ND-4.0 * |
| ls1rius/WSI_FiVE | WSI-FiVE | 🔒 CC-BY-NC-ND-4.0 * |
| JiahaoXu-god/CVPR2026_MUSE | MUSE | 🔒 CC-BY-NC-ND-4.0 * |
| BasitAlawode/ConVLM | ConVLM | 🔒 MIT |
| linlu2022/SLDPC | SLDPC | 🔒 Apache-2.0 |
| bryanwong17/HiVE-MIL | HiVE-MIL | 🔒 MIT |
| cvblab/MIVisionShot | MI-VisionShot | ⚠️ No license declared; equations cleanly reimplemented, no source vendored |
| zfy07/Libra-MIL | Libra-MIL | ⚠️ No license declared; equations cleanly reimplemented, no source vendored |
| junjianli106/DyKo | DyKo | ⚠️ No license declared; equations cleanly reimplemented, no source vendored |
| HauschildLab/MGPATH | MGPATH | ⚠️ No license declared; equations cleanly reimplemented, no source vendored |
| Jayanie/HIPSS | HIPSS | ⚠️ No license declared; equations cleanly reimplemented, no source vendored |
| Repository | Method/Role | License |
|---|---|---|
| mahmoodlab/CLAM | CLAM Scaffold | 🔒 GPL-3.0 |
| KaiyangZhou/CoOp | CoOp Blocks | 🔒 MIT |
21 commits
8 commits
Python
97.1%