daylight-00 commited on
Commit
2e831b9
·
verified ·
1 Parent(s): 2819c14

Add README.md

Browse files
Files changed (1) hide show
  1. README.md +257 -0
README.md ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ library_name: pytorch
4
+ tags:
5
+ - biology
6
+ - protein
7
+ - immunology
8
+ - mhc-class-ii
9
+ - epitope
10
+ - binding-prediction
11
+ - esm
12
+ pipeline_tag: tabular-classification
13
+ ---
14
+
15
+ # PREpiBind — research checkpoints (float32)
16
+
17
+ Four MHC class II peptide-binding models, one per measurement type, in the precision they were
18
+ trained in. Weights only: the optimizer state and the epoch counter are dropped, nothing else is
19
+ changed.
20
+
21
+ - Code and everything needed to run these: <https://github.com/daylight-00/PREpiBind>
22
+ - float16 copies of the same four models, for the notebooks and Colab:
23
+ [`daylight-00/prepibind-demo`](https://huggingface.co/daylight-00/prepibind-demo)
24
+ - The backbone they call: [`daylight-00/esmc-300m-2024-12`](https://huggingface.co/daylight-00/esmc-300m-2024-12)
25
+ - The full-length HLA embedding store they read:
26
+ [`daylight-00/prepibind-embeddings`](https://huggingface.co/datasets/daylight-00/prepibind-embeddings)
27
+
28
+ ## The four files
29
+
30
+ | file | arm | seed | fold | val_loss | predict config |
31
+ |---|---|---|---|---:|---|
32
+ | `prepibind_qualitative_s100_f0.pt` | qualitative binding assays | 100 | 0 | 0.35582 | `configs/predict/config_demo.py` |
33
+ | `prepibind_ms_s128_f3.pt` | mass-spectrometry eluted ligands | 128 | 3 | 0.12274 | `configs/predict/config_ms.py` |
34
+ | `prepibind_ic50_500_s128_f2.pt` | IC50, binder threshold < 500 nM | 128 | 2 | 0.46631 | `configs/predict/config_ic50_500.py` |
35
+ | `prepibind_ic50_1000_s42_f1.pt` | IC50, binder threshold < 1000 nM | 42 | 1 | 0.49456 | `configs/predict/config_ic50_1000.py` |
36
+
37
+ Each is 213.0 MiB, a one-key `{"model_state_dict": ...}` dict of 64 float32 tensors, 55,820,161
38
+ parameters. The seed and the fold are in the filename because they are part of what the file is.
39
+
40
+ All four rows are the val_loss argmin of their arm. **Not yet published:** the files exist locally
41
+ and nothing has been uploaded to HuggingFace; that is a human step, and the sequence is
42
+ `tools/release/upload_plan.md`.
43
+
44
+ ## How these four were chosen, and why they are not the paper's numbers
45
+
46
+ Each arm was trained as **15 runs**: three seeds (42, 100, 128) by five cross-validation folds.
47
+ **Every number reported in the paper is a mean over those 15 runs.**
48
+
49
+ A released checkpoint is one single run out of the fifteen — the one with the **lowest validation
50
+ loss** in its arm, the value in the table above. **Validation loss is the selection criterion; the
51
+ `Val ROC-AUC` in the training logs is invalid — `train.py` defines `roc_auc_score(outputs, labels)`
52
+ and calls it with the arguments swapped, so 21.7 % of the logged values fall outside [0, 1] — and
53
+ it was never used for anything.** No test-set quantity took part in the choice either.
54
+
55
+ **The ms row changed on 2026-09-10, and only the ms row.** It was seed 100, fold 1 from
56
+ `250527/1_ms_re`, whose true val_loss is 0.13128. The corrected parse puts the arm's argmin at seed
57
+ 128, fold 3 from `260829/ms`, 0.12274. That run was already one of the fifteen this arm averages:
58
+ `analysis/scoring/2_ms/per_run_results.csv` draws 9 of them from `250527/1_ms_re` and 6 from
59
+ `260829/ms` (seed 100 fold 4, and seed 128 folds 0-4). The two directories carry byte-identical
60
+ `config_global.json` and `config_esmc_small.py`, both log `Total samples: 77954` from the one
61
+ `data/dataset/ms_ql/train.csv`, and `260829`'s replicate of three seed-42 folds reproduces the
62
+ earlier root's validation losses exactly (0.14181, 0.14277, 0.14074). So this is a re-selection
63
+ inside the arm, on a criterion that did not change — not a new model, and not a new comparison.
64
+
65
+ The val_loss values above were re-derived on 2026-09-10 from `analysis/val_metrics.csv`, after a
66
+ regex in `analysis/tools/parse_train_logs.py` was fixed: it required an unsigned number for
67
+ `Val ROC-AUC`, so every epoch line carrying one of those negative values was dropped and the
68
+ recorded minimum was a minimum over a filtered subset. It could only ever come out too high, and on
69
+ 46.7 % of runs it did. The training itself was never affected — `train.py` checkpoints on the true
70
+ minimum — which is why the epoch stored inside each of these four files (20, 27, 28, 28) matches the
71
+ corrected argmin and not the old one.
72
+
73
+ So a released checkpoint does not reproduce a paper number and is not meant to. It scores a little
74
+ above the mean on most metrics, because it was picked for a quantity correlated with test
75
+ performance — though not on all of them: F1 comes out slightly below the mean in the qualitative and
76
+ ic50_1000 arms. Both are below:
77
+
78
+ | arm | metric | paper (mean ± sd over 15 runs) | this checkpoint alone |
79
+ |---|---|---|---|
80
+ | qualitative | ROC AUC | 0.9193 ± 0.0028 | 0.9211 |
81
+ | | PR AUC | 0.9448 ± 0.0019 | 0.9460 |
82
+ | | F1 | 0.8586 ± 0.0037 | 0.8582 |
83
+ | | accuracy | 0.8375 ± 0.0038 | 0.8391 |
84
+ | | MCC | 0.6683 ± 0.0084 | 0.6736 |
85
+ | ms | ROC AUC | 0.9897 ± 0.0009 | 0.9911 |
86
+ | | PR AUC | 0.9865 ± 0.0012 | 0.9884 |
87
+ | | F1 | 0.9439 ± 0.0042 | 0.9502 |
88
+ | | accuracy | 0.9563 ± 0.0030 | 0.9612 |
89
+ | | MCC | 0.9083 ± 0.0063 | 0.9186 |
90
+ | ic50_500 | ROC AUC | 0.8375 ± 0.0039 | 0.8436 |
91
+ | | PR AUC | 0.7429 ± 0.0055 | 0.7520 |
92
+ | | F1 | 0.6764 ± 0.0146 | 0.6805 |
93
+ | | accuracy | 0.7685 ± 0.0035 | 0.7739 |
94
+ | | MCC | 0.4979 ± 0.0107 | 0.5067 |
95
+ | ic50_1000 | ROC AUC | 0.8347 ± 0.0044 | 0.8401 |
96
+ | | PR AUC | 0.8024 ± 0.0057 | 0.8093 |
97
+ | | F1 | 0.7399 ± 0.0083 | 0.7322 |
98
+ | | accuracy | 0.7554 ± 0.0039 | 0.7575 |
99
+ | | MCC | 0.5101 ± 0.0092 | 0.5110 |
100
+
101
+ Held-out test sets, never used for selection: 48,352 rows (qualitative), 33,490 (ms), 14,150 (both
102
+ IC50 arms). The per-run table these come from is `analysis/scoring/*/per_run_results.csv` in the
103
+ repository. Ignore its `val_auc` column, and the `Val ROC-AUC` in the training logs it comes from:
104
+ the `roc_auc_score` arguments are swapped and the values are meaningless. **Ignore its `val_loss`
105
+ column too** — it was written before the parser fix and is still the filtered minimum, 0.36951 for
106
+ the qualitative checkpoint and 0.14216 for the ms one. The validation losses in this card come from
107
+ `analysis/val_metrics.csv`, which was regenerated on 2026-09-10, and that is the only file to quote
108
+ them from.
109
+
110
+ ## Training data
111
+
112
+ From the IEDB Export v3, split into arms by measurement type. The rebuild is
113
+ `pipeline/preprocess/` in the repository; the resulting CSVs are `data/dataset/` there.
114
+
115
+ | arm | directory | train rows | test rows | target column | positives (train) |
116
+ |---|---|---:|---:|---|---:|
117
+ | qualitative | `data/dataset/full/` | 112,871 | 48,352 | `Target` | 58.1 % |
118
+ | ms | `data/dataset/ms_ql/` | 77,954 | 33,490 | `Target` | 39.4 % |
119
+ | ic50_500 | `data/dataset/ic50/` | 33,004 | 14,150 | `Target_500` | 36.7 % |
120
+ | ic50_1000 | `data/dataset/ic50/` | 33,004 | 14,150 | `Target_1000` | 46.0 % |
121
+
122
+ The qualitative arm's training config names `dataset/full_bal/`, a directory since renamed to
123
+ `full`. Same CSVs.
124
+
125
+ Training: AdamW, lr 1e-5, betas (0.9, 0.999), eps 1e-8, weight decay 0.01, five-fold CV, best epoch
126
+ by validation loss (20, 27, 28, 28 for the four files above — the epoch each file stores, and the
127
+ corrected argmin of its run). Both sides were fed from precomputed
128
+ ESM C 300M embeddings, `emb_hla_esmc_small_0430.h5` for the HLA chains and the matching epitope
129
+ store.
130
+
131
+ ## Architecture
132
+
133
+ `prepibind.model.plm_cat_mean_inf(hla_dim=960, epi_dim=960, head_div=64)`, 55,820,161 parameters:
134
+
135
+ - 2 self-attention blocks over the HLA chain-pair embeddings, 2 over the epitope embeddings,
136
+ 15 heads each (`960 // 64`)
137
+ - 1 joint self-attention block over the two concatenated token sequences
138
+ - masked mean pool, then `Linear(960, 480) -> GELU -> Dropout -> Linear(480, 1)`, one logit
139
+
140
+ Inputs are per-residue ESM C 300M embeddings, 960-dimensional. The head is not a language model and
141
+ never sees a raw sequence: the epitope is encoded at run time by ESM C 300M, the HLA alpha and beta
142
+ chains are read from a precomputed store.
143
+
144
+ ## Input format
145
+
146
+ Two columns. The MHC field is the two chain names joined by an underscore. Both names must be keys
147
+ in the HLA mapping table the config points at, spelled exactly as that table spells them. The
148
+ datasets and the demo write **beta first, then alpha**; the order does not change the score, because
149
+ the head carries no positional encoding and pools over tokens, but following the convention keeps
150
+ inputs comparable with the published ones.
151
+
152
+ ```csv
153
+ MHC,Epitope
154
+ HLA-DRB1*01:01_HLA-DRA*01:01,PKYVKQNTLKLATA
155
+ HLA-DPB1*03:01_HLA-DPA1*01:03,AAAARYPNVTIAAAA
156
+ H2-IAbB_H2-IAbA,AAAAPAAAATTAAPA
157
+ ```
158
+
159
+ Output is the input with `Logits` and `Score` (sigmoid of the logit) appended.
160
+
161
+ Two limits worth knowing before feeding it anything:
162
+
163
+ - **Every training and test epitope is a 15-mer.** The arms were normalised to 15 residues. Other
164
+ lengths run, since the encoder pads and masks, but they are outside the training distribution.
165
+ - **Coverage is 116 chains**: 98 human HLA class II chains and 18 mouse H2 chains, the ones the four
166
+ arms actually use. The research embedding store carries 154 keys; the other 38 (20 BoLA, Mamu and
167
+ SLA chains, plus 18 further human alleles) were curated alongside them, and no released model was
168
+ trained to score them.
169
+
170
+ ## Usage
171
+
172
+ ```bash
173
+ git clone https://github.com/daylight-00/PREpiBind && cd PREpiBind
174
+ pip install --extra-index-url https://download.pytorch.org/whl/cu126 -e .
175
+
176
+ hf download daylight-00/prepibind prepibind_qualitative_s100_f0.pt --local-dir models
177
+ hf download daylight-00/esmc-300m-2024-12 esmc_300m_2024_12_v0_fp16.pth --local-dir models
178
+ hf download daylight-00/prepibind-embeddings emb_hla_esmc_small_0430.h5 --repo-type dataset --local-dir emb
179
+ ```
180
+
181
+ The ESM C encoder is vendored into the package (`prepibind/esmc/`), so `torch` and
182
+ `huggingface_hub` are the only runtime dependencies for inference — no `pip install esm`.
183
+
184
+ ```python
185
+ from prepibind.inference import load_config, main
186
+
187
+ cfg = load_config(
188
+ "configs/predict/config_demo.py", # the qualitative model's config
189
+ chkp_path="models/prepibind_qualitative_s100_f0.pt", # this float32 checkpoint
190
+ hla_emb_path="emb/emb_hla_esmc_small_0430.h5", # full-length store
191
+ hla_path="data/mhc_mapping/HLA2_IMGT_MSA_idx_edit.csv", # mapping WITH the windows
192
+ test_path="my_input.csv",
193
+ out_path="outputs",
194
+ )
195
+ cfg["Test"]["precision"] = "as-trained" # bfloat16 ESM C, float32 head. The default in that
196
+ # config is "fp16", which is the demo's setting.
197
+ df = main(cfg) # writes outputs/prediction.csv, returns the DataFrame
198
+ ```
199
+
200
+ Three things have to agree, and the code will tell you if they do not: a **full-length** store needs
201
+ the mapping table that carries the window as `sequence|start|end`
202
+ (`data/mhc_mapping/HLA2_IMGT_MSA_idx_edit.csv`), while the bundled demo store is already cut to the
203
+ window and needs `demo/data/mhc_mapping_demo.csv`, which has none. Applying a window twice raises.
204
+
205
+ The CLI does the same thing for the configs' own settings:
206
+
207
+ ```bash
208
+ python -m prepibind.inference configs/predict/config_ms.py --chkp_path models/prepibind_ms_s128_f3.pt --plot
209
+ ```
210
+
211
+ No GPU is required. Without CUDA, or on a pre-Ampere card, the runtime turns off flash-attn, falls
212
+ back to float32 and says so.
213
+
214
+ ## Limitations and known caveats
215
+
216
+ - **One run, not the reported mean.** See above. For a benchmark comparison, use the 15-run means in
217
+ the paper, not one checkpoint.
218
+ - **Class II only.** No class I allele is in the training data or in the embedding store.
219
+ - **The embedding store moved after training.** `emb_hla_esmc_small_0430.h5` as published in
220
+ [`daylight-00/prepibind-embeddings`](https://huggingface.co/datasets/daylight-00/prepibind-embeddings)
221
+ received the 2026-09-08 H2 chain-swap correction and differs from what these checkpoints were
222
+ trained on in 3 of its 154 keys: `H2-IAdA` and `H2-IAdB`, which held each other's arrays, and
223
+ `H2-IAg7A`, same shape and different values. The correction is disclosed, not retro-applied. All
224
+ three are mouse H2 chains and all three are in the training data — 0.48 % to 0.66 % of the rows
225
+ of each arm — so **predictions for H2-IAd and H2-IAg7 come from a model fit on the pre-fix
226
+ arrays**. Every human HLA embedding is unchanged. The dataset card has the per-arm counts.
227
+ - **Training is not bit-reproducible** across GPU models, so a retrained checkpoint will differ in
228
+ the last decimals. Inference on fixed inputs is deterministic.
229
+ - The models score binding, not immunogenicity. A high score is not a prediction that a peptide is
230
+ presented in vivo, still less that it elicits a response.
231
+
232
+ ## Licence
233
+
234
+ **MIT** for these weights and for the PREpiBind code, same as the repository.
235
+
236
+ The backbone is not ours, but it is also MIT. ESM C 300M moved to Chan Zuckerberg Biohub:
237
+ [`biohub/esmc-300m-2024-12`](https://huggingface.co/biohub/esmc-300m-2024-12) is ungated and its card
238
+ is tagged `mit` + `other`, and `esm` 3.4.0 — the release the vendored `prepibind/esmc/` source is
239
+ copied from — ships a plain MIT licence, "Copyright 2026 Chan Zuckerberg Biohub, Inc.". These
240
+ checkpoints were produced by training on ESM C 300M embeddings. Checked 2026-09-10; the repository's
241
+ `THIRD_PARTY_NOTICES.md` records the evidence and every other dependency.
242
+
243
+ Training data derives from the IEDB Export v3 (free to use, asks to be cited) and allele sequences
244
+ from IPD-IMGT/HLA and UniProt.
245
+
246
+ ## Citation
247
+
248
+ ```bibtex
249
+ @article{jang2026prepibind,
250
+ title = {PREpiBind: Protein Representation-integrated Epitope-MHC Class II Binding Prediction},
251
+ author = {Jang, David Hyunyoo and Kim, Dongwoo and Park, Byungho and Hwang, Untaek and Choi, Yoonjoo and Lee, Juyong},
252
+ journal = {bioRxiv},
253
+ year = {2026}
254
+ }
255
+ ```
256
+
257
+ The preprint is not posted yet; the DOI goes here when it is.