microproteins / README.md
EmmaScharfmann's picture
Claude Opus 5
Report the sites the cutoff rejected, instead of nothing
c357a0a
|
Raw History Blame Contribute Delete
11.9 kB
---
title: Translatome to Epitope
emoji: 🧬
colorFrom: indigo
colorTo: green
sdk: gradio
sdk_version: 6.31.0
python_version: '3.12'
app_file: app.py
pinned: false
license: apache-2.0
short_description: Predicted initiation sites to candidate HLA epitopes
---
# Translatome β†’ microprotein β†’ candidate epitope
An end-to-end demo of what can be assembled **today** from existing, openly
licensed tools:
```
transcript sequence
β†’ TIS Transformer P(translation initiation) per nucleotide [MIT]
β†’ ORF typing uORF / intORF / N-ext / CDS ... [this repo]
β†’ MHCflurry HLA class I presentation [Apache-2.0]
β†’ candidate peptides
```
No new models. The contribution is the join, and what the join reveals about
where sequence-only prediction stops being useful.
## The result that matters
Sequence-only initiation prediction is **not** blind to non-canonical
translation. It finds some hidden ORFs confidently. What it misses is the
short ones, and microproteins are short by definition.
Scored against validated ORFs, each on the model fold that excluded its
chromosome from training:
| ORF | length | score | found? |
| --- | ---: | ---: | :---: |
| MIEF1 upstream ORF | 70 aa | **0.674** | yes |
| ATF4 uORF2 | 59 aa | **0.303** | yes |
| HOXB-AS3 peptide | 53 aa | 0.000892 | no |
| TYK2 uORF | 8 aa | 0.000038 | no |
| ATF4 uORF1 | 3 aa | 0.000044 | no |
The MIEF1 ORF scores **above** the canonical start in its own transcript
(0.674 vs 0.349). ATF4 is the cleanest case because both uORFs sit in the
same 282 nt leader, 99 nt apart, differing mainly in length: the 59 aa one is
ranked second in the transcript, the 3 aa one is invisible despite a textbook
Kozak context (`GCCACC[ATG]G`).
So the useful claim is not "sequence models cannot find non-canonical starts".
It is narrower and more actionable: **sensitivity falls away in the short-ORF
regime, which is exactly where microproteins live.** Ribosome profiling is the
evidence that does not degrade with length.
HOXB-AS3 is the informative exception β€” 53 aa but still missed, and the only
case with no annotated CDS anywhere in the transcript. The model may also
lean on surrounding protein-coding context that a lncRNA does not provide.
One data point is not enough to claim this.
### Caveat on these matches
ORFs are matched to published ones by **position and length only**. That is
inference, not a cited coordinate, and no paper here publishes transcript
coordinates. The ATF4 assignments are strong: uORF1 is 3 codons and uORF2 is
59 codons overlapping the CDS out of frame, both exactly as described, and
the 87 nt inter-uORF spacing falls out of the human sequence independently
and matches the published figure. The MIEF1 match rests on length (70 aa)
and position alone. Confirm before quoting.
## The examples, and what each shows
The Space ships four example sets, each preselecting the fold that held out
its chromosome. The order is deliberate: the tool gets credit before any
limitation is shown.
**1. MIEF1 + ATF4 (chr22, fold 0)** β€” the model finds a hidden microprotein
and misses a shorter one, in the same run.
```
MIEF1 @176 0.674 70 aa uORF found, outranks the canonical start
MIEF1 @487 0.349 463 aa CDS
ATF4 @185 0.303 59 aa uoORF uORF2, found
ATF4 @282 0.565 351 aa CDS
ATF4 @86 0.000044 3 aa uORF1, missed
```
At the default cutoff this yields 2 non-canonical ORFs and **12 novel
candidate peptides** β€” peptides absent from any canonical protein in the
input.
**2. TYK2 (chr19, fold 3)** β€” a type 1 diabetes risk gene carrying a
validated primate-specific uORF that the model scores at essentially zero.
```
TYK2 per-nucleotide initiation probability (chr19 held out)
@186 published uORF (validated) 0.000038
@214 unvalidated 36 aa ORF 0.007686
@378 canonical CDS 0.984922 ~26,000x higher
All six upstream ATGs in the 378 nt leader:
{154: 0.000387, 186: 0.000038, 205: 0.003272,
214: 0.007686, 251: 0.000004, 283: 0.000272}
```
Walters et al. ([doi:10.2337/db24-0527](https://doi.org/10.2337/db24-0527))
characterise an 8 aa primate-specific uORF, `MPGSVLNV`, spanning the first
two exons of the TYK2 5β€² leader, and validate it by mutating its start codon.
It maps to position 186. The ORF the model does surface at 214 is a
different, longer, unvalidated one, out of frame with both the TYK2 CDS and
theirs.
We have not read their supplementary nuORF tables, so whether the ORF at 214
appears there as a separate entry is open.
**3. INS (chr11, fold 4)** β€” insulin, the reference point. Canonical start
only, 0.912, nothing else above threshold.
**4. IAPP (chr12, fold 3)** β€” islet amyloid polypeptide, the other gene a
Ξ²-cell lab reaches for first. Same shape as insulin, lower confidence in the
annotated start.
```
INS @59 0.912 110 aa CDS
INS @71 0.003660 106 aa N-trunc below cutoff
IAPP @118 0.180 89 aa CDS
IAPP @737 0.000812 59 aa dORF below cutoff
```
Scored right down to 0.0005, those four sites are *everything* the model
finds in the two transcripts. Nothing in an alternative frame registers on
either gene β€” including the alternative-frame insulin product described by
Kracht et al. ([doi:10.1038/nm.4289](https://doi.org/10.1038/nm.4289)).
That absence is a property of the model, not of the missing ribosome-profiling
track. The sequence was scored and came back near zero. Ribo-seq conditioning
is a reason to expect a *different* answer; it is not the reason this one is
empty.
## Reporting what the cutoff rejected
Every run scores down to `NEAR_MISS_FLOOR` (0.0005) whatever cutoff is
selected, and the sites below the cutoff are listed in their own tab rather
than dropped. This costs nothing β€” the model scores every nucleotide either
way β€” and it changes what an empty result means. "No non-canonical ORFs" and
"the best non-canonical candidate scored 0.0008, three orders of magnitude
under the annotated start" are the same table with and without the near
misses, and only the second one says whether the gene is worth a Ribo-seq
experiment.
## Choosing a fold
The model ships as five versions, each trained with certain chromosomes held
out. Running a sequence on a fold that was trained on its chromosome inflates
the score. The tool prints a warning when this happens, and it is easy to
miss in the log noise.
| gene | chromosome | fold |
| --- | --- | --- |
| MIEF1, ATF4 | 22 | 0 |
| TYK2 | 19 | 3 |
| IAPP | 12 | 3 |
| INS | 11 | 4 |
Fold 0 has an empty test set, meaning any contig not in its train or
validation split lands there. Chromosome 22 is absent from both, so fold 0 is
genuinely correct for ATF4 and MIEF1 β€” but it will also happily score a
chromosome it trained on, so it is the wrong default for anything else.
Leakage is worth roughly Β±0.06 here: canonical starts score 0.889–0.985 on
held-out folds versus 0.944–0.965 on fold 0. The headline findings are
unaffected.
The bundled examples set their own fold. Anything pasted in does not, so
pick one.
## Verified facts about TIS Transformer
Checked by running it, not inferred from docs:
- CLI is `tis_transformer` (not `transcript_transformer`, which is deprecated).
`--fasta --model {human,mouse} --fold {0..4} --accelerator --out_prefix
--prob_cutoff --start_codons --min_ORF_len` are all valid on the FASTA path.
- **The FASTA-path CSV schema differs from the documented one.** It is
`transcript_id, transcript_length, TIS_pos, output, start_codon, TTS_pos,
stop_codon, TTS_on_transcript, protein_length, protein_sequence`. The ~40
column table in the docs belongs to the h5/GTF pipeline.
- **The score column is `output`**, not `tis_transformer_score`. It is a real
probability, a 2-class softmax per nucleotide. Positions are scored
independently, so they do not compete for probability mass.
- **`TIS_pos` is 1-based.** Everything in `orf.py` is 0-based; the conversion
lives in one named function so an off-by-one cannot hide.
- **Weights ship inside the wheel** (~128 MB, 5 folds Γ— 2 species). No runtime
download. MHCflurry's weights are *not* bundled; see `MHCFLURRY_BOOTSTRAP`.
- `--start_codons` defaults to `.*TG$` β€” near-cognate (ATG, CTG, GTG, TTG).
- `--prob_cutoff` effectively defaults to 0.03 via `configs/defaults.tt.yml`.
- pyfaidx writes a `.fai` beside the input, so that directory must be writable.
- Licence: MIT.
## Known limitations
Also listed in the app's "What this does not show" tab:
- **Sensitivity tracks ORF length**, as above. This is the finding, not a
footnote.
- **Sequence alone cannot be cell-type specific.** The same answer comes back
for a Ξ²-cell, a hepatocyte and a neuron.
- **One start per transcript is a learned prior.** Training labels come from
annotation, which records exactly one CDS start per transcript, so the model
reproduces that shape.
- **Novelty here is local** β€” a peptide is compared only against the canonical
CDSs of the submitted sequences, not the human proteome.
- **Class I only.** The strongest genetic risk in T1D is class II (DQ8/DQ2),
which MHCflurry does not model.
- **Binding β‰  immunogenicity.**
- **No proteomic evidence is used.**
### A trap worth knowing
lncRNAs famous for encoding a validated microprotein tend to get reclassified
as protein-coding, precisely because of that discovery. LINC00961 is now
SPAAR, LINC00948 is MRLN, LINC01420 is NBDY β€” all `protein_coding` in current
Ensembl. Any benchmark that defines its classes by biotype is built on a
moving target, and the best-characterised examples migrate out of the
"non-coding" class first. Pin an annotation release, or define classes by
evidence rather than label.
## Deliberately out of scope
RiboTIE, the ribosome-profiling model from the same package. It takes mapped
BAM files that can need >100 GB of RAM. That is not a Space β€” it is the part
that would need real infrastructure, and it is the natural next step.
## Running locally
```bash
pip install -r requirements.txt
mhcflurry-downloads fetch models_class1_presentation
TRISTAN_ACCELERATOR=cpu MHCFLURRY_BOOTSTRAP=0 python app.py
pytest -q
```
## ZeroGPU notes
- TIS Transformer runs **in-process** on the GPU path, because a subprocess
may not inherit the ZeroGPU allocation. Any failure falls back to the CPU
subprocess route, which is the tested one.
- **MHCflurry is pinned to CPU** via `configure_pytorch(backend="cpu")`. It is
a PyTorch model whose device defaults to `auto`, so on a GPU box it calls
`network.to('cuda')` during prediction β€” in the Gradio worker thread,
outside any `@spaces.GPU` function, which ZeroGPU rejects. Its sibling
option `gpu_device_nums=[]` must be avoided: it sets `CUDA_VISIBLE_DEVICES`
process-wide and breaks the TIS stage.
## Citing
- TIS Transformer: Clauwaert et al., *NAR Genomics and Bioinformatics* (2023),
[doi:10.1093/nargab/lqad021](https://doi.org/10.1093/nargab/lqad021)
- MHCflurry 2.0: O'Donnell et al., *Cell Systems* (2020),
[doi:10.1016/j.cels.2020.06.010](https://doi.org/10.1016/j.cels.2020.06.010)
- TYK2 uORF: Walters et al., *Diabetes* (2025),
[doi:10.2337/db24-0527](https://doi.org/10.2337/db24-0527)
- ATF4 uORFs: Lu, Harding & Ron, *J Cell Biol* (2004),
[doi:10.1083/jcb.200408003](https://doi.org/10.1083/jcb.200408003); Vattem &
Wek, *PNAS* (2004),
[doi:10.1073/pnas.0400541101](https://doi.org/10.1073/pnas.0400541101)
- Transcript sequences: Ensembl GRCh38, MANE Select
## Before making this public
Email the TRISTAN authors. Their repo invites contributions, so an issue
offering to mirror weights to the Hub and host a demo is the right opening.
The MIEF1 result is a good thing to lead with: their model finds a validated
microprotein and ranks it above the canonical start.