microproteins / README.md
EmmaScharfmann's picture
Report the sites the cutoff rejected, instead of nothing
c357a0a
|
Raw History Blame Contribute Delete
11.9 kB
metadata
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) 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).

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

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

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.