antigen-model 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- antigen_model-0.1.0/LICENSE +21 -0
- antigen_model-0.1.0/PKG-INFO +264 -0
- antigen_model-0.1.0/README.md +232 -0
- antigen_model-0.1.0/antiGen/__init__.py +1 -0
- antigen_model-0.1.0/antiGen/baselines/__init__.py +0 -0
- antigen_model-0.1.0/antiGen/baselines/covfit.py +259 -0
- antigen_model-0.1.0/antiGen/baselines/msa_transformer.py +428 -0
- antigen_model-0.1.0/antiGen/config.py +607 -0
- antigen_model-0.1.0/antiGen/configs/esm2_default.yaml +21 -0
- antigen_model-0.1.0/antiGen/configs/esm2_mutation_fitness.yaml +22 -0
- antigen_model-0.1.0/antiGen/configs/transformer_default.yaml +24 -0
- antigen_model-0.1.0/antiGen/datasets.py +86 -0
- antigen_model-0.1.0/antiGen/eval.py +760 -0
- antigen_model-0.1.0/antiGen/eval_utils.py +404 -0
- antigen_model-0.1.0/antiGen/infer.py +168 -0
- antigen_model-0.1.0/antiGen/load.py +175 -0
- antigen_model-0.1.0/antiGen/models/__init__.py +12 -0
- antigen_model-0.1.0/antiGen/models/base.py +84 -0
- antigen_model-0.1.0/antiGen/models/blosum62_fitness_predictor.py +78 -0
- antigen_model-0.1.0/antiGen/models/esm2_fitness_predictor.py +223 -0
- antigen_model-0.1.0/antiGen/models/evcouplings_fitness_predictor.py +310 -0
- antigen_model-0.1.0/antiGen/models/eve_fitness_predictor.py +439 -0
- antigen_model-0.1.0/antiGen/models/factory.py +230 -0
- antigen_model-0.1.0/antiGen/models/fitness_predictor.py +89 -0
- antigen_model-0.1.0/antiGen/models/gated_fitness_predictor.py +166 -0
- antigen_model-0.1.0/antiGen/models/pssm_fitness_predictor.py +69 -0
- antigen_model-0.1.0/antiGen/models/tranception_fitness_predictor.py +553 -0
- antigen_model-0.1.0/antiGen/train.py +561 -0
- antigen_model-0.1.0/antiGen/validate_examples.py +67 -0
- antigen_model-0.1.0/antigen_model.egg-info/PKG-INFO +264 -0
- antigen_model-0.1.0/antigen_model.egg-info/SOURCES.txt +35 -0
- antigen_model-0.1.0/antigen_model.egg-info/dependency_links.txt +1 -0
- antigen_model-0.1.0/antigen_model.egg-info/entry_points.txt +5 -0
- antigen_model-0.1.0/antigen_model.egg-info/requires.txt +17 -0
- antigen_model-0.1.0/antigen_model.egg-info/top_level.txt +1 -0
- antigen_model-0.1.0/pyproject.toml +63 -0
- antigen_model-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ivan Specht
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: antigen-model
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Train sequence models of viral fitness and score amino-acid substitutions for any query sequence.
|
|
5
|
+
Author: Ivan Specht
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Repository, https://github.com/evo-design/antiGen
|
|
8
|
+
Project-URL: Issues, https://github.com/evo-design/antiGen/issues
|
|
9
|
+
Keywords: protein,fitness,viral evolution,transformer
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: torch>=2.7
|
|
19
|
+
Requires-Dist: numpy
|
|
20
|
+
Requires-Dist: pandas
|
|
21
|
+
Requires-Dist: biopython
|
|
22
|
+
Requires-Dist: pyyaml
|
|
23
|
+
Provides-Extra: esm
|
|
24
|
+
Requires-Dist: transformers; extra == "esm"
|
|
25
|
+
Provides-Extra: dca
|
|
26
|
+
Requires-Dist: evcouplings; extra == "dca"
|
|
27
|
+
Provides-Extra: plot
|
|
28
|
+
Requires-Dist: matplotlib; extra == "plot"
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest; extra == "dev"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# antiGen
|
|
34
|
+
|
|
35
|
+
Welcome to antiGen, a model that predicts future mutations to viral proteins based on inferred phylogenetic trees. This repository is intended for (1) generating training data from phylogenetic trees, (2) training antiGen on said data, (3) querying substitution probabilities predicted by antiGen, (4) running the evaluations reported in the antiGen manuscript, and (5) reproducing the manuscript figures.
|
|
36
|
+
|
|
37
|
+
## Install
|
|
38
|
+
|
|
39
|
+
Install the modeling package and its command-line tools from PyPI (Python ≥ 3.10):
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install antigen-model # core: from-scratch transformer + BLOSUM62 / PSSM / gated (no model downloads)
|
|
43
|
+
pip install "antigen-model[esm]" # + ESM-2 pretrained language model
|
|
44
|
+
pip install "antigen-model[dca]" # + EVcouplings (needs external `plmc`)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The distribution is named `antigen-model`, but the import name and CLIs keep the
|
|
48
|
+
`antiGen` spelling (`import antiGen`; `antiGen-train`/`-infer`/`-eval`). This is
|
|
49
|
+
all you need to train antiGen and score substitutions (Parts 2–3). The
|
|
50
|
+
training-data generator (Part 1, C++/CUDA) and the figure-reproduction code
|
|
51
|
+
(Part 5, R) are not part of the wheel — clone the repo for those and, if you want
|
|
52
|
+
a source install of the package, `pip install` it from the clone:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
git clone git@github.com:evo-design/antiGen.git
|
|
56
|
+
cd antiGen
|
|
57
|
+
pip install ".[esm]" # editable/source install of the same package
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Quickstart (generate → train → infer, runs on CPU)
|
|
61
|
+
|
|
62
|
+
Runs the whole pipeline on a toy example: **generate** training data from a tiny
|
|
63
|
+
Nextstrain-format mutation-annotated tree and MSA using the included `antiGen-data` tool, then **train** a model and **score** substitutions.
|
|
64
|
+
No GPU is required for this example.
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# 1. build the data-generation tool (make auto-selects nvcc if present, else g++)
|
|
68
|
+
cd antiGen-data && make && cd ..
|
|
69
|
+
|
|
70
|
+
# 2. generate training data from the toy Nextstrain JSON + MSA (~ms; GPU if present, else CPU)
|
|
71
|
+
antiGen-data/antiGen-data antiGen-data/example/out 0.6 toy \
|
|
72
|
+
antiGen-data/example/ref.json antiGen-data/example/tree.json \
|
|
73
|
+
antiGen-data/example/metadata.tsv antiGen-data/example/seqs.fasta
|
|
74
|
+
|
|
75
|
+
# 3. (optional) sanity-check the generated examples file
|
|
76
|
+
antiGen-validate-examples antiGen-data/example/out/examples_cutoff_0.6.txt
|
|
77
|
+
|
|
78
|
+
# 4. train a small from-scratch transformer on it
|
|
79
|
+
antiGen-train --model-type transformer \
|
|
80
|
+
--examples antiGen-data/example/out/examples_cutoff_0.6.txt \
|
|
81
|
+
--d-model 32 --num-layers 1 --epochs 3 --batch-size 4 --output-dir ./checkpoints
|
|
82
|
+
|
|
83
|
+
# 5. score substitutions for the toy query sequences
|
|
84
|
+
antiGen-infer ./checkpoints/fitness_*.pt antiGen-data/example/seqs.fasta -o scores.csv
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
# 1. Generating training data
|
|
90
|
+
|
|
91
|
+
antiGen training data is produced by the included **[`antiGen-data/`](antiGen-data/)** tool, a
|
|
92
|
+
C++/CUDA application that grows a mutation-annotated phylogeny by parsimonious attachment and returns training/testing examples, as well as position-specific scoring matrices
|
|
93
|
+
(PSSMs) for the training window and at various cutoff times in the testing window. To build it, cd into the antiGen-data sub-directory and run `make` (needs a C++17 compiler; `nvcc` is optional, for GPU support).
|
|
94
|
+
|
|
95
|
+
Run it as:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
antiGen-data <output_dir> <cutoff> <dataset_type> <ref_json> <tree_json> <metadata_tsv> <alignment_files...> [max_seqs] [--cpu]
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
- `output_dir` — where outputs are written (created if absent).
|
|
102
|
+
- `cutoff` — train/test split, in **years after the tree's root date**: examples dated before `root + cutoff` are labeled `TRAINING`, later ones `TESTING`.
|
|
103
|
+
- `dataset_type` — one of `sc2`, `h3n2`, `rsv_a`, `rsv_b`, `denv2`, or `toy`; selects the alphabet, segment layout, and evaluation region.
|
|
104
|
+
- `ref_json`, `tree_json`, `metadata_tsv` — the reference sequence, guide phylogeny, and per-strain dates (formats under **Input files** below).
|
|
105
|
+
- `alignment_files` — one or more MSA FASTAs of the sequences to attach, one per segment (1 for most datasets; 3 for H3N2 HA).
|
|
106
|
+
- `max_seqs` *(optional)* — cap on how many sequences to attach.
|
|
107
|
+
- `--cpu` *(optional)* — force the CPU path; a GPU is used automatically when present.
|
|
108
|
+
|
|
109
|
+
**Input files.** The three inputs follow the Nextstrain convention; see
|
|
110
|
+
[`antiGen-data/example/`](antiGen-data/example/) for a complete, runnable set.
|
|
111
|
+
|
|
112
|
+
- `ref_json` — root sequence per segment, e.g. `{"S": "MFVF…"}`.
|
|
113
|
+
- `tree_json` — a Nextstrain tree whose nodes carry `node_attrs.num_date.value` (decimal year) and `branch_attrs.mutations`, one list per segment of `<ref><pos><alt>` strings, 1-indexed (e.g. `"S": ["A222V", "D614G"]`).
|
|
114
|
+
- `metadata_tsv` — `strain`⇥`date` (ISO `YYYY-MM-DD`) for each sequence in the alignment(s).
|
|
115
|
+
|
|
116
|
+
Each run writes to `<output_dir>/`, formated as follows:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
output_<dataset>/
|
|
120
|
+
examples_cutoff_<value>.txt # training/testing examples (one entry per inferred ancestral genotype; see below)
|
|
121
|
+
pssms/root.csv # PSSM of all sequences in the training window
|
|
122
|
+
pssms/<variant>/time_*.csv # PSSM of all sequences in the testing window up through the cutoff time specified in the file name
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Each example within `examples_cutoff_*.txt` holds a sequence, its `TRAINING`/`TESTING` designation, whether it is the root example of or is descended from a supplied variant of interest, and the substitutions observed in that sequence's children (the training target).
|
|
126
|
+
`antiGen-validate-examples <file> [--variant V]` checks a file is well-formed (single consistent
|
|
127
|
+
sequence length, alphabet `ACDEFGHIKLMNPQRSTVWY*-`, in-range positions, ≥1 training example). The
|
|
128
|
+
Quickstart above generates a miniature example of this format from the toy inputs in
|
|
129
|
+
[`antiGen-data/example/`](antiGen-data/example/).
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
# 2. Training antiGen
|
|
134
|
+
|
|
135
|
+
**Pointing antiGen at data.** Give an explicit file with `--examples <path>` (works for any
|
|
136
|
+
dataset with no code edits), or use a built-in dataset shortcut which resolves
|
|
137
|
+
`examples_cutoff_<cutoff>.txt` under `$FITNESS_DATA_ROOT` (or an explicit `--data-dir`). These
|
|
138
|
+
shortcuts only build a local path — the data is never downloaded, so you must have generated it
|
|
139
|
+
first (Part 1) and placed it under `$FITNESS_DATA_ROOT`:
|
|
140
|
+
|
|
141
|
+
| Flag | Dataset | Variant | `--cutoff` | Eval region |
|
|
142
|
+
|------|---------|---------|------------|-------------|
|
|
143
|
+
| *(default)* | SARS-CoV-2 spike | BA.2 (or `--variant`) | 1, 4, or 5 | RBD (330–530) |
|
|
144
|
+
| `--flu` | Influenza HA | J or K | 12 | full sequence |
|
|
145
|
+
| `--rsv-a` | RSV-A F | A.D.1.6 | 74 | full sequence |
|
|
146
|
+
| `--denv2` | Dengue 2 envelope | 2II_F.1.1.2_annotated | 191 | full sequence |
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# built-in dataset: resolve the file from $FITNESS_DATA_ROOT via a shortcut
|
|
150
|
+
export FITNESS_DATA_ROOT=/path/to/antiGen-data # holds output1/, output_flu_full_cutoff12/, ...
|
|
151
|
+
antiGen-train --flu --cutoff 12 --model-type transformer --output-dir ./checkpoints
|
|
152
|
+
|
|
153
|
+
# your own data: point --examples straight at a file you generated in Part 1
|
|
154
|
+
# (no $FITNESS_DATA_ROOT, no shortcut — works for any protein/pathogen). seq_len is read from
|
|
155
|
+
# the file (alphabet is the standard 22 AAs); add --variant <label> if it has a variant of interest.
|
|
156
|
+
antiGen-train --examples ./mydata/examples_cutoff_5.txt \
|
|
157
|
+
--model-type transformer --d-model 128 --num-layers 2 \
|
|
158
|
+
--epochs 64 --batch-size 64 --lr 1e-4 --output-dir ./checkpoints
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Model architectures (`--model-type`)
|
|
162
|
+
|
|
163
|
+
| Model | `--model-type` | Extra install | Description |
|
|
164
|
+
|-------|----------------|---------------|-------------|
|
|
165
|
+
| Transformer | `transformer` | — (core) | Small transformer trained from scratch. **Default; no downloads.** |
|
|
166
|
+
| ESM-2 | `esm2` | `.[esm]` | ESM-2 protein LM (default `esm2_t12_35M_UR50D`), frozen/partial/full finetune |
|
|
167
|
+
| BLOSUM62 | `blosum62` | — (core) | Static BLOSUM62 substitution matrix (no training, eval only) |
|
|
168
|
+
| PSSM | `pssm` | — (core) | Per-position `log(count+1)` from the root PSSM (no training, eval only) |
|
|
169
|
+
| Gated | `gated` | — (core) | Learnable per-position blend of two predictors (`--gate-partner-a/-b`, `--gate-variant`) |
|
|
170
|
+
| EVcouplings | `evcouplings` | `.[dca]` + `plmc` | Mean-field DCA Potts model fitted from a pandemic MSA (eval only) |
|
|
171
|
+
| EVE | `eve` | — (core) | EVE VAE (frozen or finetuned) trained on a pandemic MSA |
|
|
172
|
+
| Tranception | `tranception` | — (core) | Tranception autoregressive scorer (frozen or finetuned) |
|
|
173
|
+
|
|
174
|
+
For the pretrained ESM-2 backbone, three finetuning strategies: **frozen**
|
|
175
|
+
(`--freeze-backbone`, head only), **partial** (`--freeze-backbone --finetune-layers N`), and
|
|
176
|
+
**full** (no freeze flags). MSA models (`evcouplings`/`eve`/`tranception`) additionally need
|
|
177
|
+
`--msa` / `--metadata`; their date cutoff is derived from the dataset MRCA + `--cutoff` (or
|
|
178
|
+
`--date-cutoff`).
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
# from-scratch transformer (the default)
|
|
182
|
+
antiGen-train --model-type transformer --d-model 128 --num-layers 2 \
|
|
183
|
+
--epochs 64 --batch-size 64 --lr 1e-4 --flu --output-dir ./checkpoints
|
|
184
|
+
|
|
185
|
+
# ESM-2, partial finetune of the last 4 layers
|
|
186
|
+
antiGen-train --model-type esm2 --freeze-backbone --finetune-layers 4 --lr 1e-4 --flu
|
|
187
|
+
|
|
188
|
+
# gated blend of a from-scratch transformer and the root PSSM
|
|
189
|
+
antiGen-train --model-type gated --gate-partner-a fitness_predictor --gate-partner-b pssm \
|
|
190
|
+
--gate-variant static --flu
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Checkpoints are written to `--output-dir` as `fitness_<run_prefix>.pt`, alongside a
|
|
194
|
+
`manifest.json` recording the full recipe. They are self-describing (they store the complete
|
|
195
|
+
`ModelConfig`), so `antiGen-infer` / `antiGen-eval` reload them standalone.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
# 3. Querying substitution probabilities
|
|
200
|
+
|
|
201
|
+
`antiGen-infer <checkpoint> <queries.fasta>` runs a forward pass on one or more query sequences
|
|
202
|
+
and writes the model's probability distribution over substitutions relative to each query.
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
antiGen-infer ./checkpoints/fitness_*.pt my_queries.fasta -o scores.csv
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Default **long** output reports one row per candidate substitution:
|
|
209
|
+
|
|
210
|
+
```
|
|
211
|
+
query_id,position,ref_aa,alt_aa,prob
|
|
212
|
+
toy_root,0,M,A,0.00148030
|
|
213
|
+
toy_root,0,M,C,0.00164760
|
|
214
|
+
...
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
`prob` is the inferred probability of each possible amino acid substitution relative to the
|
|
218
|
+
query (including premature stop codons `*` and gaps `-`, i.e. point indels). Use `--format wide`
|
|
219
|
+
for a position × amino-acid matrix, and `--drop-gap-stop` to exclude the `-`/`*` columns.
|
|
220
|
+
|
|
221
|
+
**Length / alignment.** antiGen operates on a **fixed, aligned coordinate frame**: provide
|
|
222
|
+
query sequences aligned to the training reference (same length and alignment).
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
# 4. Running the manuscript evaluations
|
|
227
|
+
|
|
228
|
+
`antiGen-eval` scans a directory of checkpoints, groups them by model, and writes unified
|
|
229
|
+
per-variant comparison CSVs against a set of fixed baselines.
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
antiGen-eval --dataset sc2 --data-dir $FITNESS_DATA_ROOT/output1 \
|
|
233
|
+
--checkpoint-dir ./checkpoints --output-dir ./evals_sc2
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
It produces two metric families per variant: **quantile hit-rate** (how often observed mutations
|
|
237
|
+
fall in the model's top-q% predictions) and **variant-emergence** (across top-q quantiles
|
|
238
|
+
q = 0.1 … 1.0). These are termed next-mutation recall and PSSM precision in the paper, respectively. Baselines come from `data/baselines*/` plus two built from the root PSSM
|
|
239
|
+
(`pssm_root` and the position-only `pssm_root_position`). Ties at a top-q boundary are broken
|
|
240
|
+
**fractionally** (the expected value under random tie-breaking).
|
|
241
|
+
|
|
242
|
+
The SLURM scripts used for the manuscript runs are in [`examples/slurm/`](examples/slurm/); they
|
|
243
|
+
embed lab-specific paths/partitions and are meant to be copied and edited for your environment.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
# 5. Reproducing the paper figures
|
|
248
|
+
|
|
249
|
+
[`antiGen-figures/`](antiGen-figures/) is R code that plots the evaluation outputs into the
|
|
250
|
+
manuscript figures (it trains and evaluates nothing). From that directory, `Rscript run_all.R`
|
|
251
|
+
regenerates everything into `figs/` (PNG) and `figs_vector/` (PDF), or `Rscript figures/<script>.R`
|
|
252
|
+
runs a single figure; the inputs it reads live in `antiGen-figures/data/` and sibling directories.
|
|
253
|
+
Requires R with ggplot2, cowplot, reshape2, dplyr, tidyr, tibble, forcats, magick, ggtext,
|
|
254
|
+
jsonlite, and scales.
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## Citing
|
|
259
|
+
|
|
260
|
+
See [CITATION.cff](CITATION.cff).
|
|
261
|
+
|
|
262
|
+
## License
|
|
263
|
+
|
|
264
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# antiGen
|
|
2
|
+
|
|
3
|
+
Welcome to antiGen, a model that predicts future mutations to viral proteins based on inferred phylogenetic trees. This repository is intended for (1) generating training data from phylogenetic trees, (2) training antiGen on said data, (3) querying substitution probabilities predicted by antiGen, (4) running the evaluations reported in the antiGen manuscript, and (5) reproducing the manuscript figures.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
Install the modeling package and its command-line tools from PyPI (Python ≥ 3.10):
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install antigen-model # core: from-scratch transformer + BLOSUM62 / PSSM / gated (no model downloads)
|
|
11
|
+
pip install "antigen-model[esm]" # + ESM-2 pretrained language model
|
|
12
|
+
pip install "antigen-model[dca]" # + EVcouplings (needs external `plmc`)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The distribution is named `antigen-model`, but the import name and CLIs keep the
|
|
16
|
+
`antiGen` spelling (`import antiGen`; `antiGen-train`/`-infer`/`-eval`). This is
|
|
17
|
+
all you need to train antiGen and score substitutions (Parts 2–3). The
|
|
18
|
+
training-data generator (Part 1, C++/CUDA) and the figure-reproduction code
|
|
19
|
+
(Part 5, R) are not part of the wheel — clone the repo for those and, if you want
|
|
20
|
+
a source install of the package, `pip install` it from the clone:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
git clone git@github.com:evo-design/antiGen.git
|
|
24
|
+
cd antiGen
|
|
25
|
+
pip install ".[esm]" # editable/source install of the same package
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quickstart (generate → train → infer, runs on CPU)
|
|
29
|
+
|
|
30
|
+
Runs the whole pipeline on a toy example: **generate** training data from a tiny
|
|
31
|
+
Nextstrain-format mutation-annotated tree and MSA using the included `antiGen-data` tool, then **train** a model and **score** substitutions.
|
|
32
|
+
No GPU is required for this example.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# 1. build the data-generation tool (make auto-selects nvcc if present, else g++)
|
|
36
|
+
cd antiGen-data && make && cd ..
|
|
37
|
+
|
|
38
|
+
# 2. generate training data from the toy Nextstrain JSON + MSA (~ms; GPU if present, else CPU)
|
|
39
|
+
antiGen-data/antiGen-data antiGen-data/example/out 0.6 toy \
|
|
40
|
+
antiGen-data/example/ref.json antiGen-data/example/tree.json \
|
|
41
|
+
antiGen-data/example/metadata.tsv antiGen-data/example/seqs.fasta
|
|
42
|
+
|
|
43
|
+
# 3. (optional) sanity-check the generated examples file
|
|
44
|
+
antiGen-validate-examples antiGen-data/example/out/examples_cutoff_0.6.txt
|
|
45
|
+
|
|
46
|
+
# 4. train a small from-scratch transformer on it
|
|
47
|
+
antiGen-train --model-type transformer \
|
|
48
|
+
--examples antiGen-data/example/out/examples_cutoff_0.6.txt \
|
|
49
|
+
--d-model 32 --num-layers 1 --epochs 3 --batch-size 4 --output-dir ./checkpoints
|
|
50
|
+
|
|
51
|
+
# 5. score substitutions for the toy query sequences
|
|
52
|
+
antiGen-infer ./checkpoints/fitness_*.pt antiGen-data/example/seqs.fasta -o scores.csv
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
# 1. Generating training data
|
|
58
|
+
|
|
59
|
+
antiGen training data is produced by the included **[`antiGen-data/`](antiGen-data/)** tool, a
|
|
60
|
+
C++/CUDA application that grows a mutation-annotated phylogeny by parsimonious attachment and returns training/testing examples, as well as position-specific scoring matrices
|
|
61
|
+
(PSSMs) for the training window and at various cutoff times in the testing window. To build it, cd into the antiGen-data sub-directory and run `make` (needs a C++17 compiler; `nvcc` is optional, for GPU support).
|
|
62
|
+
|
|
63
|
+
Run it as:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
antiGen-data <output_dir> <cutoff> <dataset_type> <ref_json> <tree_json> <metadata_tsv> <alignment_files...> [max_seqs] [--cpu]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
- `output_dir` — where outputs are written (created if absent).
|
|
70
|
+
- `cutoff` — train/test split, in **years after the tree's root date**: examples dated before `root + cutoff` are labeled `TRAINING`, later ones `TESTING`.
|
|
71
|
+
- `dataset_type` — one of `sc2`, `h3n2`, `rsv_a`, `rsv_b`, `denv2`, or `toy`; selects the alphabet, segment layout, and evaluation region.
|
|
72
|
+
- `ref_json`, `tree_json`, `metadata_tsv` — the reference sequence, guide phylogeny, and per-strain dates (formats under **Input files** below).
|
|
73
|
+
- `alignment_files` — one or more MSA FASTAs of the sequences to attach, one per segment (1 for most datasets; 3 for H3N2 HA).
|
|
74
|
+
- `max_seqs` *(optional)* — cap on how many sequences to attach.
|
|
75
|
+
- `--cpu` *(optional)* — force the CPU path; a GPU is used automatically when present.
|
|
76
|
+
|
|
77
|
+
**Input files.** The three inputs follow the Nextstrain convention; see
|
|
78
|
+
[`antiGen-data/example/`](antiGen-data/example/) for a complete, runnable set.
|
|
79
|
+
|
|
80
|
+
- `ref_json` — root sequence per segment, e.g. `{"S": "MFVF…"}`.
|
|
81
|
+
- `tree_json` — a Nextstrain tree whose nodes carry `node_attrs.num_date.value` (decimal year) and `branch_attrs.mutations`, one list per segment of `<ref><pos><alt>` strings, 1-indexed (e.g. `"S": ["A222V", "D614G"]`).
|
|
82
|
+
- `metadata_tsv` — `strain`⇥`date` (ISO `YYYY-MM-DD`) for each sequence in the alignment(s).
|
|
83
|
+
|
|
84
|
+
Each run writes to `<output_dir>/`, formated as follows:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
output_<dataset>/
|
|
88
|
+
examples_cutoff_<value>.txt # training/testing examples (one entry per inferred ancestral genotype; see below)
|
|
89
|
+
pssms/root.csv # PSSM of all sequences in the training window
|
|
90
|
+
pssms/<variant>/time_*.csv # PSSM of all sequences in the testing window up through the cutoff time specified in the file name
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Each example within `examples_cutoff_*.txt` holds a sequence, its `TRAINING`/`TESTING` designation, whether it is the root example of or is descended from a supplied variant of interest, and the substitutions observed in that sequence's children (the training target).
|
|
94
|
+
`antiGen-validate-examples <file> [--variant V]` checks a file is well-formed (single consistent
|
|
95
|
+
sequence length, alphabet `ACDEFGHIKLMNPQRSTVWY*-`, in-range positions, ≥1 training example). The
|
|
96
|
+
Quickstart above generates a miniature example of this format from the toy inputs in
|
|
97
|
+
[`antiGen-data/example/`](antiGen-data/example/).
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
# 2. Training antiGen
|
|
102
|
+
|
|
103
|
+
**Pointing antiGen at data.** Give an explicit file with `--examples <path>` (works for any
|
|
104
|
+
dataset with no code edits), or use a built-in dataset shortcut which resolves
|
|
105
|
+
`examples_cutoff_<cutoff>.txt` under `$FITNESS_DATA_ROOT` (or an explicit `--data-dir`). These
|
|
106
|
+
shortcuts only build a local path — the data is never downloaded, so you must have generated it
|
|
107
|
+
first (Part 1) and placed it under `$FITNESS_DATA_ROOT`:
|
|
108
|
+
|
|
109
|
+
| Flag | Dataset | Variant | `--cutoff` | Eval region |
|
|
110
|
+
|------|---------|---------|------------|-------------|
|
|
111
|
+
| *(default)* | SARS-CoV-2 spike | BA.2 (or `--variant`) | 1, 4, or 5 | RBD (330–530) |
|
|
112
|
+
| `--flu` | Influenza HA | J or K | 12 | full sequence |
|
|
113
|
+
| `--rsv-a` | RSV-A F | A.D.1.6 | 74 | full sequence |
|
|
114
|
+
| `--denv2` | Dengue 2 envelope | 2II_F.1.1.2_annotated | 191 | full sequence |
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# built-in dataset: resolve the file from $FITNESS_DATA_ROOT via a shortcut
|
|
118
|
+
export FITNESS_DATA_ROOT=/path/to/antiGen-data # holds output1/, output_flu_full_cutoff12/, ...
|
|
119
|
+
antiGen-train --flu --cutoff 12 --model-type transformer --output-dir ./checkpoints
|
|
120
|
+
|
|
121
|
+
# your own data: point --examples straight at a file you generated in Part 1
|
|
122
|
+
# (no $FITNESS_DATA_ROOT, no shortcut — works for any protein/pathogen). seq_len is read from
|
|
123
|
+
# the file (alphabet is the standard 22 AAs); add --variant <label> if it has a variant of interest.
|
|
124
|
+
antiGen-train --examples ./mydata/examples_cutoff_5.txt \
|
|
125
|
+
--model-type transformer --d-model 128 --num-layers 2 \
|
|
126
|
+
--epochs 64 --batch-size 64 --lr 1e-4 --output-dir ./checkpoints
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Model architectures (`--model-type`)
|
|
130
|
+
|
|
131
|
+
| Model | `--model-type` | Extra install | Description |
|
|
132
|
+
|-------|----------------|---------------|-------------|
|
|
133
|
+
| Transformer | `transformer` | — (core) | Small transformer trained from scratch. **Default; no downloads.** |
|
|
134
|
+
| ESM-2 | `esm2` | `.[esm]` | ESM-2 protein LM (default `esm2_t12_35M_UR50D`), frozen/partial/full finetune |
|
|
135
|
+
| BLOSUM62 | `blosum62` | — (core) | Static BLOSUM62 substitution matrix (no training, eval only) |
|
|
136
|
+
| PSSM | `pssm` | — (core) | Per-position `log(count+1)` from the root PSSM (no training, eval only) |
|
|
137
|
+
| Gated | `gated` | — (core) | Learnable per-position blend of two predictors (`--gate-partner-a/-b`, `--gate-variant`) |
|
|
138
|
+
| EVcouplings | `evcouplings` | `.[dca]` + `plmc` | Mean-field DCA Potts model fitted from a pandemic MSA (eval only) |
|
|
139
|
+
| EVE | `eve` | — (core) | EVE VAE (frozen or finetuned) trained on a pandemic MSA |
|
|
140
|
+
| Tranception | `tranception` | — (core) | Tranception autoregressive scorer (frozen or finetuned) |
|
|
141
|
+
|
|
142
|
+
For the pretrained ESM-2 backbone, three finetuning strategies: **frozen**
|
|
143
|
+
(`--freeze-backbone`, head only), **partial** (`--freeze-backbone --finetune-layers N`), and
|
|
144
|
+
**full** (no freeze flags). MSA models (`evcouplings`/`eve`/`tranception`) additionally need
|
|
145
|
+
`--msa` / `--metadata`; their date cutoff is derived from the dataset MRCA + `--cutoff` (or
|
|
146
|
+
`--date-cutoff`).
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# from-scratch transformer (the default)
|
|
150
|
+
antiGen-train --model-type transformer --d-model 128 --num-layers 2 \
|
|
151
|
+
--epochs 64 --batch-size 64 --lr 1e-4 --flu --output-dir ./checkpoints
|
|
152
|
+
|
|
153
|
+
# ESM-2, partial finetune of the last 4 layers
|
|
154
|
+
antiGen-train --model-type esm2 --freeze-backbone --finetune-layers 4 --lr 1e-4 --flu
|
|
155
|
+
|
|
156
|
+
# gated blend of a from-scratch transformer and the root PSSM
|
|
157
|
+
antiGen-train --model-type gated --gate-partner-a fitness_predictor --gate-partner-b pssm \
|
|
158
|
+
--gate-variant static --flu
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Checkpoints are written to `--output-dir` as `fitness_<run_prefix>.pt`, alongside a
|
|
162
|
+
`manifest.json` recording the full recipe. They are self-describing (they store the complete
|
|
163
|
+
`ModelConfig`), so `antiGen-infer` / `antiGen-eval` reload them standalone.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
# 3. Querying substitution probabilities
|
|
168
|
+
|
|
169
|
+
`antiGen-infer <checkpoint> <queries.fasta>` runs a forward pass on one or more query sequences
|
|
170
|
+
and writes the model's probability distribution over substitutions relative to each query.
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
antiGen-infer ./checkpoints/fitness_*.pt my_queries.fasta -o scores.csv
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Default **long** output reports one row per candidate substitution:
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
query_id,position,ref_aa,alt_aa,prob
|
|
180
|
+
toy_root,0,M,A,0.00148030
|
|
181
|
+
toy_root,0,M,C,0.00164760
|
|
182
|
+
...
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
`prob` is the inferred probability of each possible amino acid substitution relative to the
|
|
186
|
+
query (including premature stop codons `*` and gaps `-`, i.e. point indels). Use `--format wide`
|
|
187
|
+
for a position × amino-acid matrix, and `--drop-gap-stop` to exclude the `-`/`*` columns.
|
|
188
|
+
|
|
189
|
+
**Length / alignment.** antiGen operates on a **fixed, aligned coordinate frame**: provide
|
|
190
|
+
query sequences aligned to the training reference (same length and alignment).
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
# 4. Running the manuscript evaluations
|
|
195
|
+
|
|
196
|
+
`antiGen-eval` scans a directory of checkpoints, groups them by model, and writes unified
|
|
197
|
+
per-variant comparison CSVs against a set of fixed baselines.
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
antiGen-eval --dataset sc2 --data-dir $FITNESS_DATA_ROOT/output1 \
|
|
201
|
+
--checkpoint-dir ./checkpoints --output-dir ./evals_sc2
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
It produces two metric families per variant: **quantile hit-rate** (how often observed mutations
|
|
205
|
+
fall in the model's top-q% predictions) and **variant-emergence** (across top-q quantiles
|
|
206
|
+
q = 0.1 … 1.0). These are termed next-mutation recall and PSSM precision in the paper, respectively. Baselines come from `data/baselines*/` plus two built from the root PSSM
|
|
207
|
+
(`pssm_root` and the position-only `pssm_root_position`). Ties at a top-q boundary are broken
|
|
208
|
+
**fractionally** (the expected value under random tie-breaking).
|
|
209
|
+
|
|
210
|
+
The SLURM scripts used for the manuscript runs are in [`examples/slurm/`](examples/slurm/); they
|
|
211
|
+
embed lab-specific paths/partitions and are meant to be copied and edited for your environment.
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
# 5. Reproducing the paper figures
|
|
216
|
+
|
|
217
|
+
[`antiGen-figures/`](antiGen-figures/) is R code that plots the evaluation outputs into the
|
|
218
|
+
manuscript figures (it trains and evaluates nothing). From that directory, `Rscript run_all.R`
|
|
219
|
+
regenerates everything into `figs/` (PNG) and `figs_vector/` (PDF), or `Rscript figures/<script>.R`
|
|
220
|
+
runs a single figure; the inputs it reads live in `antiGen-figures/data/` and sibling directories.
|
|
221
|
+
Requires R with ggplot2, cowplot, reshape2, dplyr, tidyr, tibble, forcats, magick, ggtext,
|
|
222
|
+
jsonlite, and scales.
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Citing
|
|
227
|
+
|
|
228
|
+
See [CITATION.cff](CITATION.cff).
|
|
229
|
+
|
|
230
|
+
## License
|
|
231
|
+
|
|
232
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""antiGen: viral fitness prediction — train models and score substitutions."""
|
|
File without changes
|