Project assignment for the Bioinformatics Master Course, 2026 edition (AnacletoLAB, Università degli Studi di Milano).
The task is to predict ncRNA-ncRNA interactions from sequence only, using an RNA language model. Each RNA is turned into a vector by RNA-FM, the two vectors of a pair are concatenated and an MLP says if the two RNAs interact or not. Last year everybody worked on miRNA-miRNA; this year there are five groups and each group gets one interaction type from RNAInter v4. Positives are known interactions, negatives are sampled pairs (see below and the dataset README for the rules).
Last year's notebooks (miRNA-miRNA, RNA-KG data) are in the folder 2025/.
| group | type | pairs | pos | neg | interactions | unique seqs |
|---|---|---|---|---|---|---|
| A | miRNA-pseudo | 5360 | 2685 | 2675 | 2268 | 653 |
| B | snoRNA-snoRNA | 9378 | 4689 | 4689 | 4243 | 506 |
| C | lncRNA-snoRNA | 3032 | 1516 | 1516 | 935 | 781 |
| D | miRNA-snoRNA | 4002 | 2001 | 2001 | 1672 | 849 |
| E | lncRNA-lncRNA | 4542 | 2271 | 2271 | 794 | 1802 |
Split is 70/10/20 (train/val/test) by interaction. All sequences are at most 1022 nt.
Negatives: one per positive, inside each split, sampled stratified by interaction type. One RNA of a positive pair is kept, the other is replaced by an RNA of the same category and species, drawn from the RNAs of the positive pairs of the same split (an RNA with more partners is drawn more often). The new pair is never a known interaction in RNAInter, and its gene pair is never used by a negative of another split (so isoforms of the same gene pair are not negatives in both train and test).
So positives and negatives have a similar degree: a predictor that only counts how many train positives the two RNAs have gets test AUROC 0.54-0.61 on our negatives, and 0.59-0.64 if the replacement is drawn uniformly over the unique RNAs. The test pairs are mostly known RNAs in new combinations, except for group E. Numbers for the test set:
| group | type | both RNAs seen in train | one seen | none seen | degree-only AUROC, ours | uniform draw |
|---|---|---|---|---|---|---|
| A | miRNA-pseudo | 0.864 | 0.135 | 0.002 | 0.572 | 0.631 |
| B | snoRNA-snoRNA | 0.962 | 0.027 | 0.011 | 0.547 | 0.641 |
| C | lncRNA-snoRNA | 0.615 | 0.345 | 0.040 | 0.540 | 0.616 |
| D | miRNA-snoRNA | 0.778 | 0.213 | 0.009 | 0.561 | 0.595 |
| E | lncRNA-lncRNA | 0.077 | 0.639 | 0.284 | 0.610 | 0.619 |
For group E the two are close: most of its test RNAs are not in train, so their train degree says little anyway.
Your data is one zip, <type>.zip (e.g. miRNA-snoRNA.zip), given with the course material together
with the dataset README. It contains <type>/pairs.csv, <type>/pairs_1to10.csv (optional, see bonus c), <type>/sequences.fasta
and <type>/metadata/.
Read the dataset README before starting: it explains every column and how the negatives were built.
Everything runs on Google Colab with a T4 GPU (Runtime -> Change runtime type -> T4 GPU). Open each notebook in Colab with its button (or File -> Open notebook -> GitHub):
| notebook | |
|---|---|
| part1_data_exploration.ipynb | |
| part2_embeddings.ipynb | |
| part3_training.ipynb | |
| part4_bonus_multimodal.ipynb |
Before running,
File -> Save a copy in Drive, so your outputs are kept. At the end, File -> Download -> .ipynb for the hand-in.
Run the notebooks in this order. In the first cell of each notebook set GROUP_TYPE to your type;
the data cell asks you to upload the zip if it is not already in DATA_ROOT.
part1_data_exploration.ipynb: look at the data, the negatives, the overlap between splits and the augmentation. Writes<type>_sequences_with_flipped.fasta.part2_embeddings.ipynb: RNA-FM embeddings (mean + max pooling, 1280 per sequence). Writes<type>_rnafm_pooled.pkl. Needs the GPU: about 5 min on a T4 for lncRNA-lncRNA and under 2 min for the other types. The other notebooks take a few minutes each.part3_training.ipynb: MLP on the pair embeddings, metrics, plots, k-mer baseline. The classification threshold is picked on validation with Youden's J (TPR - FPR). Writes<type>_rnafm_mlp.pt,<type>_rnafm_scaler.pkl,<type>_rnafm_test_predictions.csv,<type>_rnafm_metrics.jsonandplots/.part4_bonus_multimodal.ipynb: bonus, see below.
All outputs go to WORK_DIR (default /content/work). Always remember: Colab is not saving any
data. When the runtime is gone, /content is gone, and a free runtime disconnects after a while
if you leave it idle. Each notebook opens its own Colab machine, so files written by one notebook
are not visible in the next one unless WORK_DIR is on Drive (or you upload them).
Either point WORK_DIR to your Drive (/content/drive/MyDrive/..., the data cell mounts it)
or download the files at the end of each notebook.
Part 2 needs the FASTA from part 1 (it can rebuild the list from pairs.csv if missing),
part 3 needs the pickle from part 2, part 4 can use both.
Imbalanced data (1:10): set NEG_RATIO = 10 in parts 1, 3 and 4 to use pairs_1to10.csv (same
positives and splits, 10 negatives per positive, same embeddings). Outputs get a _1to10 suffix.
In part 3, BALANCED_BATCHES = True puts half positives and half negatives in every training
batch (negatives without replacement, positives with replacement); outputs get a _bal suffix.
Look at AUPRC, and compare with the degree-only baseline: at 1:10 the hubs run out of negative
partners, so counting partners alone already gives AUROC 0.63-0.88 (dataset README).
a. Second backbone: biRNA-BERT. Set RUN_BIRNA = True in part 2 (writes <type>_birna_pooled.pkl),
then run part 3 again with BACKBONE = "birna". Compare the two models on the same test set.
b. Multimodal model: part 4 builds features from metadata/sequences.tsv (species, Rfam, GO,
gene type, genomic position) and a metadata-only baseline. Combine them with the embeddings
and see if it helps. Read the warning about metadata/interactions.tsv first.
See the assignment (exam rules, project steps, report), given in class with the slides of the project: code and report in a private GitHub repository shared with NicoRota-0, at least 7 days before the exam.