Skip to content

Add paper-ready benchmark evals + plots as mhcflurry subcommands (clean-room, no Keras/TF) #314

Description

@iskandr

Summary

The published-paper analysis layer — the multi-tool accuracy benchmark, the significance testing, the headline figures, and the supplemental tables (Tables S1/S2/S6/S7, Data S1–S6) — currently exists only as a stack of one-off Jupyter notebooks (the 2023-retraining set) that never landed in the repo. Those notebooks are TF1/Keras-era, depend on hardcoded cluster paths (/home/odonnt02/..., /data/mhcflurry-evaluation/), pull inputs from Springer/Dropbox URLs, use unseeded RNG, and reference three different download versions. They will not run against the current PyTorch 2.3 tree and are not something we should port line-for-line.

Meanwhile the in-repo reproducible pipeline stops at scored prediction tables (downloads-generation/data_evaluation) and a 2-way new-vs-public release-regression evaluator (mhcflurry compare-models / plot-model-comparison). There is no reproducible in-tree path that answers the paper's actual question — "does MHCflurry beat the field (netMHCpan, MixMHCpred), and is the difference significant?" — nor one that regenerates the figures/tables.

This issue proposes rebuilding that whole layer clean-room as first-class mhcflurry subcommands plus one orchestration script, reusing the existing metric core and CLI conventions, and carrying none of the historical Keras/TF baggage.

Design principles (the "no baggage" contract)

  1. Clean-room, current-era inputs only. Consume only current artifacts: the data_evaluation scored benchmark, data_predictions (external-tool scores via mhctools, already produced upstream — never re-invoke netMHCpan/MixMHCpred inline the way the notebooks do), analysis_predictor_info, data_mass_spec_annotated, data_curated, data_references (FM-index for peptide→protein mapping instead of pyensembl), and current PyTorch model bundles. No keras/tensorflow imports anywhere.
  2. No hidden state, no hardcoded paths. Every input is a CLI flag with a mhcflurry-downloads-resolvable default. Datasets the notebooks hardcoded as sibling files (expression_groups.xlsx, the immunogenicity screening set, Wolf-Levy S2) become explicit --dataset/--input args or documented download items.
  3. Deterministic. All decoy resampling and bootstrap steps take --seed; default seeded. Golden-CSV tests become possible.
  4. Follow the established metric/plot split. Metric subcommands write CSV/JSON only (torch/pandas/sklearn, no matplotlib) exactly like compare-models; plot subcommands read those artifacts and render, with matplotlib/logomaker lazy-imported, exactly like plot-model-comparison.
  5. One metric implementation. Refactor the shared scoring core (ROC-AUC / PR-AUC / PPV@N, per-allele/per-sample/per-length aggregation) out of mhcflurry/cli/compare_models.py into a library (mhcflurry/benchmarks/) and have both compare-models and the new paper commands call it, so the release-regression numbers and the paper numbers can never silently diverge.
  6. Register through the existing lazy dispatcher. Add each new subcommand to _SUBCOMMANDS + _HELP_GROUPS in mhcflurry/cli/main.py (new group: "Paper benchmarks"), each exposing run_argv(argv); add matching mhcflurry-* console-script shims in setup.py for parity. Builds directly on Unify mhcflurry CLI under a single mhcflurry parent command #291.

Proposed shared library: mhcflurry/benchmarks/

Pure-python, matplotlib-free, importable by both the regression and paper commands:

  • metrics.pyroc_auc, pr_auc, ppv_at_n, per-{allele,sample,length} aggregation. (Lifted from compare_models.py; compare-models switches to importing it.)
  • stats.py — seeded bootstrap CIs, paired ttest_rel, binomial win-counts, percent-change-vs-baseline normalization.
  • assembly.py — benchmark table assembly: predictor-column merge, train-leak assertion, seeded per-sample decoy resampling, sample-group tagging, external-tool masking.
  • predictor_registry.py + predictor_info.csvreplaces notebook 0 aesthetics: a versioned data file mapping predictor id → display name, plot color, sort order, primary flag. Single source of truth for every plot command (kills the runtime color-hacking in the old aesthetics cell).

Proposed subcommands

Metric / eval (matplotlib-free → CSV/JSON)

Subcommand Replaces notebook(s) Reads Writes
benchmark-assemble 1 prepare benchmark dataset - {mono,multi}allelic data_evaluation, data_mass_spec_annotated benchmark.{mono,multi}allelic.parquet, manifest.json
benchmark-score 2 multiallelic accuracy, 2 monoallelic accuracy plots assembled benchmark accuracy_scores.{mono,multi}.csv, significance.csv, summary.json
benchmark-novel-alleles 2 monoallelic analysis of novel alleles assembled benchmark, models_class1_pan_variants novel_alleles.csv
benchmark-immunogenicity immunogenicity experiments --dataset (screening set), data_predictions immunogenicity_scores.csv
benchmark-processing 1 proteasome mass spec, 2 processing predictor motifs --dataset (Wolf-Levy S2), data_references FM-index, presentation predictor processing_proteasome.csv, processing_correlation.parquet, processing_motifs.parquet
model-selection-accuracy 1 model selection predictor accuracy (retires the …UNUSED, NOW WE PRECOMPUTE THIS notebook) analysis_predictor_info model_selection_accuracy.csv
sample-table 2 sample table, 4 supplemental sample table with accuracies data_mass_spec_annotated, assembled benchmark, --expression-groups sample_table.csv, sample_table_with_accuracies.csv

benchmark-score detail (the scientific core): per-sample × per-length × per-predictor ROC-AUC / PR-AUC / PPV@N over all predictors including external tools; percent-change vs configurable baseline predictors; seeded bootstrap CIs; paired significance (ttest_rel + binomial win-count) for each predictor against each baseline; optional cysteine-removed variant (--exclude-residues C). This is the N-way, statistics-bearing generalization of what compare-models' affinity/presentation components do 2-way — hence the shared metrics.py.

Plot (matplotlib/logomaker isolated → figures)

Subcommand Replaces Renders
plot-benchmark 3 scores plots - {mono,multi}allelic multi-tool AUC/PPV scatter grids, per-length bars, presentation-score panels, mean-PPV summary; --panels selects subsets
plot-processing 4 processing predictor plots (+ its "redo post resubmission" dupe) AP sequence logos, processing-vs-affinity correlation panels w/ significance annotations

(Novel-allele and immunogenicity panels fold into plot-benchmark --panels rather than getting their own commands.)

Bespoke release packaging → sub-scripts (not core subcommands)

Supplemental assembly is release-specific and file-shuffling-heavy, so it stays a script rather than a general tool:

  • scripts/release/make_supplemental.shreplaces 1 training datasets copy, 3 make additional files, 5 make supplemental data: assembles Tables S1/S2/S6/S7 + Data S1–S6 with publication column renaming from the eval outputs + training-data copies. No ln -s symlink deliverables (the notebooks' approach); real file copies.

Tie-it-together orchestration

scripts/release/paper_eval.sh, mirroring the existing scripts/release/retrain_evaluate_deploy.sh conventions (set -euo pipefail, run_cmd command-echo, --dry-run, phase --skip-* flags):

scripts/release/paper_eval.sh \
    --run-dir /path/to/release-run \
    --out /path/to/paper-eval \
    [--data-dir <data_evaluation path>] \
    [--skip-assemble] [--skip-score] [--skip-specialized] \
    [--skip-plots] [--skip-supplemental] [--dry-run]

Flow: mhcflurry-downloads fetch …benchmark-assemblebenchmark-score → (novel-alleles, immunogenicity, processing, model-selection-accuracy, sample-table) → plot-benchmark + plot-processingmake_supplemental.sh.

Then wire a --paper-eval phase into retrain_evaluate_deploy.sh that simply invokes this script after the existing compare-models/plot-model-comparison step, so a release run can optionally produce the full paper bundle from the same entry point.

Explicitly out of scope (the baggage we are not carrying)

  • No line-for-line port of the Keras/TF notebooks; the notebooks are reference only.
  • No inline re-invocation of external predictor binaries — external scores come from data_predictions.
  • No hardcoded machine paths, sibling-dir inputs, or Dropbox/Springer URL fetches.
  • pyensembl + Ensembl-release dependency dropped in favor of the data_references FM-index already in the pipeline. logomaker/statannot become optional plotting extras, not hard deps of the metric path.

Suggested phasing

  1. Extract mhcflurry/benchmarks/ (metrics/stats/assembly/registry); refactor compare-models onto it (no behavior change; golden-CSV regression test).
  2. benchmark-assemble + benchmark-score + plot-benchmark — the headline mono/multi benchmark. This alone reproduces the main figures.
  3. sample-table + model-selection-accuracy (Table S1/S2 substrate).
  4. benchmark-processing + plot-processing; then benchmark-novel-alleles, benchmark-immunogenicity.
  5. make_supplemental.sh + paper_eval.sh; wire --paper-eval into retrain_evaluate_deploy.sh.

Testing

Tiny fixtures under test/data/, golden CSVs for each metric command, and a --limit-samples/--limit-files fast path (as compare-models already has --limit-files) so the whole chain runs in CI on a handful of samples.

Related


Source for the notebook→subcommand mapping: audit of the untracked notebooks/2023-retraining/ set against downloads-generation/, scripts/, and mhcflurry/cli/.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions