Run dynamic cross-cell-type prediction of RBP–RNA interactions#

This notebook documents main.py --dynamic_predict.

Dynamic prediction differs from validation only by which checkpoint name is loaded:

  • resolve_dynamic_model_name(DATA_FILE) returns a name

  • main.py loads: {model_save_path}/{resolved_name}.pth

0. Setup & parameters#

import os, sys
from pathlib import Path

project_root = Path.cwd()
os.chdir(project_root.parent.parent.parent)
project_root = Path.cwd()
print("project_root:", project_root)
assert (project_root / "utils").exists(), "Open this notebook from repo root."
sys.path.insert(0, str(project_root))

DATA_FILE = "AUH_HepG2"
DATA_PATH = "./dataset"
TRANSFORMER_PATH = "./RBPformer"
MODEL_SAVE_PATH = "./results/model"

SEED = 42
DEVICE_NUM = 0
USE_CPU = False
MAX_LENGTH = 101

print("DATA_FILE:", DATA_FILE)
project_root: /fs1/private/user/wangyubo/code/BRIDGE
DATA_FILE: AUH_HepG2

1. Resolve the dynamic checkpoint name#

from pathlib import Path
from utils.utils import resolve_dynamic_model_name

resolved = resolve_dynamic_model_name(DATA_FILE)
ckpt = Path(MODEL_SAVE_PATH) / f"{resolved}.pth"

print("Resolved dynamic model name:", resolved)
print("Expected checkpoint path:", ckpt)
print("Exists:", ckpt.exists())

if not ckpt.exists():
    print("\nNo checkpoint found under the expected name.")
    print("Copy or symlink a trained checkpoint to this filename (no code change needed).")
    print("Example:")
    print(f"  cp /path/to/your_checkpoint.pth {ckpt}")
Resolved dynamic model name: AUH_K562
Expected checkpoint path: results/model/AUH_K562.pth
Exists: True

2. Rebuild test split and evaluate (print modality shapes)#

import random, torch
import numpy as np

def fix_seed(seed: int):
    torch.set_num_threads(1)
    random.seed(seed)
    os.environ["PYTHONHASHSEED"] = str(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)

fix_seed(SEED)

device = torch.device("cpu") if USE_CPU else torch.device(f"cuda:{DEVICE_NUM}" if torch.cuda.is_available() else "cpu")
if device.type == "cuda":
    torch.cuda.set_device(DEVICE_NUM)
print("Device:", device)
Device: cuda:0
from utils.dataloaders import read_fasta
from utils.gen_transformer_embedding import build_Transformer_embeddings
from utils.structureFeatures import build_structure_tensor
from utils.FeatureEncoding import dealwithdata
from utils.motif_prior.motif_prior import get_motif_prior_matrix
from utils.utils import split_dataset, myDataset
from torch.utils.data import DataLoader
from pathlib import Path
import numpy as np

data_path = Path(DATA_PATH)
neg_fa = data_path / f"{DATA_FILE}_neg.fa"
pos_fa = data_path / f"{DATA_FILE}_pos.fa"
assert neg_fa.exists() and pos_fa.exists(), "Missing FASTA files."

sequences, structs, labels = read_fasta(str(neg_fa), str(pos_fa))
sequences, structs = list(sequences), list(structs)
labels = np.asarray(labels)

Transformer_emb, attention_weight = build_Transformer_embeddings(
    sequences=sequences,
    transformer_path=TRANSFORMER_PATH,
    device=device,
    k=1,
    transpose_to_ch_first=True,
)

structure = build_structure_tensor(structs, MAX_LENGTH)
biochem = dealwithdata(DATA_FILE).transpose([0, 2, 1])
motif = get_motif_prior_matrix(DATA_FILE)

print("Transformer_emb:", getattr(Transformer_emb, "shape", None))
print("attention_weight:", getattr(attention_weight, "shape", None))
print("structure:", getattr(structure, "shape", None))
print("biochem:", getattr(biochem, "shape", None))
print("motif:", getattr(motif, "shape", None))
print("labels:", labels.shape)

(_, _, _, _, _, _), \
(test_emb, test_attn, test_struc, test_motif, test_biochem, test_label) = split_dataset(
    Transformer_emb,
    attention_weight,
    structure,
    motif,
    biochem,
    labels,
)

test_set = myDataset(test_emb, test_attn, test_struc, test_motif, test_biochem, test_label)
test_loader = DataLoader(test_set, batch_size=32*8, shuffle=False)

print("Test size:", len(test_set))
[INFO] Encoded 15002 sequences for AUH_HepG2, shape: (15002, 101, 99)
Valid motif file detected, skipping motif_prior: utils/motif_prior/output/AUH_HepG2/output/STRME_training_set.tab
Transformer_emb: (15002, 512, 101)
attention_weight: (15002, 101, 103)
structure: (15002, 1, 101)
biochem: (15002, 99, 101)
motif: (15002, 1, 24)
labels: (15002, 1)
Test size: 3000

3. Load dynamic checkpoint and report metrics#

import torch
import torch.nn as nn
from utils.BRIDGE import BRIDGE
from utils.train_loop import validate

if not ckpt.exists():
    raise FileNotFoundError(f"Dynamic checkpoint not found: {ckpt}")

model = BRIDGE().to(device)
model.load_state_dict(torch.load(ckpt, map_location=device))
model.eval()

criterion = nn.BCEWithLogitsLoss(pos_weight=torch.tensor(2).to(device))
met, y_all, p_all = validate(model, device, test_loader, criterion)

print("Dynamic prediction metrics")
print("AUC  :", met.auc)
print("ACC  :", met.acc)
print("AUPRC:", met.prc)
print("MCC  :", met.mcc)
Dynamic prediction metrics
AUC  : 0.8140310000000001
ACC  : 0.7746666666666666
AUPRC: 0.7315971195404499
MCC  : 0.46596121150192704

4. Alternative: run main.py --dynamic_predict (CLI)#

import subprocess, shlex

cmd = (
    f"python main.py "
    f"--dynamic_predict "
    f"--data_file {DATA_FILE} "
    f"--data_path {DATA_PATH} "
    f"--Transformer_path {TRANSFORMER_PATH} "
    f"--model_save_path {MODEL_SAVE_PATH} "
    f"--seed {SEED} "
    f"--device_num {DEVICE_NUM}"
)

print("Command:\n", cmd)

# Uncomment to run:
# subprocess.run(shlex.split(cmd), check=True)