--- 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.