Add NetTCR-2.2 pMHC:TCR binding predictor (#215) - #216
Merged
Conversation
Adds TCR specificity as a new modality: predicts whether a paired αβ TCR recognises a class-I peptide. This is the first predictor whose input is a receptor rather than an MHC allele, and the first pMHC:TCR output. New public API: - `Kind.pMHC_TCR_binding` output kind - `TCR` input type (six CDR loops + optional name) - `NetTCR` predictor: runs NetTCR-2.2's pan CV ensemble (20 TFLite models) in-process, returning the ensemble-mean recognition probability - `Prediction.tcr` field + `tcr` dataframe column; `PeptideResult.tcr_binding` and `.tcrs` accessors NetTCR ships its weights in-repo as small TFLite models, so the wrapper loads them directly (via ai-edge-litert / tflite-runtime / tensorflow) and does not need NetTCR's conda env — only a cloned repo (NETTCR_DIR) and a TFLite runtime (`pip install mhctools[nettcr]`). Nothing is vendored. The BLOSUM50 encoding, per-feature padding lengths, and name-based input tensor assignment reproduce NetTCR-2.2 `src/predict.py` exactly — verified to ~1e-7 against its own output on held-out pairs. Version bump 3.14.1 -> 3.15.0. Claude-Session: https://claude.ai/code/session_01LZahFhBSCiehXTESCYQ7wG
Fixes from PR #216 self-review: - _find_nettcr_dir now validates an explicit nettcr_path / NETTCR_DIR up front, failing with a clear message instead of a late "no models found" - Clear ValueError (not a bare KeyError) if a model exposes an unexpected input tensor whose parsed feature name isn't one of the 7 expected - Cache tensor allocation by batch size, so repeated same-size predict() calls skip re-resize/re-allocate - Move the n==0 early return ahead of model loading; import pandas at module top; document that a NetTCR instance is not thread-safe Tests: - Scope the skip marker to model-dependent tests only, so the encoding and constructor-error tests now run in CI without a NetTCR install (previously a module-level pytestmark skipped the whole file) - Add model-free constructor error-path tests (missing path, no models) - Add test_reproduces_published_ensemble: asserts the wrapper matches NetTCR-2.2's own 20-pan-model ensemble (generated by running upstream src/predict.py over all 20 checkpoints and averaging) to <1e-3 on six real TCRs from NetTCR's own dataset; plus a labeled-binder-ranks-top check and a batch-vs-single consistency check for the allocation-caching path Claude-Session: https://claude.ai/code/session_01LZahFhBSCiehXTESCYQ7wG
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #215.
Adds TCR specificity as a new modality to mhctools — predicting whether a paired αβ T-cell receptor recognises a class-I peptide. This is the first predictor whose input is a receptor (six CDR loops) rather than an MHC allele, and the first
pMHC:TCRoutput.What's new
Ontology / data model
Kind.pMHC_TCR_binding— new output kind.TCR— new input type: a paired αβ receptor given by its six CDR loops (cdr1a…cdr3b) + optionalname. NetTCR-stylea1…b3aliases and a stable.identifier.Prediction.tcrfield +tcrdataframe column (empty for non-TCR predictions, same convention asalleleon processing predictors).PeptideResult.tcr_bindingand.tcrsaccessors.Predictor
NetTCR— runs NetTCR-2.2's pan cross-validation ensemble (20 TFLite models, ~0.4 MB each) in-process; the reported score is the ensemble mean recognition probability.Distribution — no gated download, no conda env
NetTCR ships its weights directly in its git repo (not git-LFS), so the wrapper loads the TFLite models directly and does not need NetTCR's conda/Keras environment. Requirements:
NetTCR-2.2(weights) — resolved fromnettcr_path=,NETTCR_DIR, or~/NetTCR-2.2/~/code/NetTCR-2.2;pip install mhctools[nettcr](uses the lightweightai-edge-litert;tflite-runtimeandtensorflowalso work via a runtime fallback).Nothing from NetTCR (which is under an academic software license) is vendored — same "user provides the install" model as the DTU
netMHC*tools and BigMHC.Faithfulness — verified against upstream
The BLOSUM50 encoding (residues → BLOSUM50/5, padding → −1), per-feature padding lengths (
pep=12,a1..b3=7/8/22/6/7/23), and name-based input-tensor assignment (serving_default_<feature>:0) reproduce NetTCR-2.2src/predict.pyexactly. Ran NetTCR's ownpredict.pyfor a model and matched this wrapper's per-model output to ~1e-7; the ensemble recovers sensible binding signal (cognateLLWNGPMAVpair 0.77 vs mismatchRAKFKQLL0.001).Scope
Tests
tests/test_tcr.py—TCRdataclass (model-free, always runs).tests/test_nettcr.py— encoding unit tests that pin the exact BLOSUM50/pad/normalize behaviour (model-free, always run) + integration tests gated on a NetTCR install (skip when absent, mirroringtest_bigmhc.py).Full suite: 462 passed, 9 skipped, 2 xfailed (with
NETTCR_DIRset so the model tests execute). Ruff clean. Version bump 3.14.1 → 3.15.0.https://claude.ai/code/session_01LZahFhBSCiehXTESCYQ7wG