Το έργο υλοποιεί pipeline δύο φάσεων για εντοπισμό πιθανών remote homologs (“Twilight Zone”, <30% sequence identity) συνδυάζοντας:
- ESM-2 embeddings: μετατροπή πρωτεϊνικών ακολουθιών (FASTA) σε διανύσματα σταθερού μεγέθους (mean pooling).
- ANN αναζήτηση (Approximate Nearest Neighbors) και πειραματική σύγκριση απέναντι σε BLAST: Euclidean LSH, Hypercube, IVF-Flat, IVF-PQ, Neural LSH, και (προαιρετικά) brute force baseline.
Παραδοτέα “εκτελέσιμα” (όπως ζητάει η εκφώνηση):
- Generating Embeddings:
Generating_Embeddings/protein_embed.py - Search Benchmark:
Search_Benchmark/protein_search.py
Το project root έχει την παρακάτω δομή:
<project-root>/
├── bio_data/
├── black_box/
├── blast_out/
├── Common/
├── data/
├── embed_data/
├── Generating_Embeddings/
├── Nearest-Neighbors/
├── Neural-LSH/
├── scripts/
├── Search_Benchmark/
├── test_results/
├── test_summary/
├── requirements.txt
├── results_average.txt
├── results.txt
├── run_bench_grid.py
└── search_preparation.sh
Περιέχει UniProt/SwissProt/InterPro metadata (TSV) που χρησιμοποιούνται για bio comments (Pfam, GO, EC number, InterPro). Χρησιμεύει στη “βιολογική αξιολόγηση” των υποψηφίων remote homologs: όταν το BLAST identity είναι χαμηλό, το πρόγραμμα μπορεί να σχολιάσει αν υπάρχουν κοινά Pfam/GO/EC/InterPro στοιχεία.
Περιλαμβάνει και βοηθητικά scripts προετοιμασίας:
THE_MERGER.py(merge GO+InterPro σε annot TSV). Κάνει merge όλα τα "UniPro"/"Bio-annot" με “Gene Ontology IDs” και “InterPro” από ένα GO/InterPro TSV σε ένα annotation TSV, ώστε τοbio_comment.pyνα έχει όλα τα πεδία ενιαία.filter_tsv.py(φιλτράρισμα μεγάλων TSV ώστε να κρατάμε μόνο accessions που υπάρχουν στο dataset/queries)
“Σημείο ολοκλήρωσης” με εξωτερικά binaries/indices:
- Το compiled εκτελέσιμο
search(απόNearest-Neighbors/) αντιγράφεται εδώ και καλείται από τοprotein_search.pyγια LSH/Hypercube/IVF-Flat/IVF-PQ. - Τα Neural-LSH indices αποθηκεύονται επίσης εδώ (π.χ.
black_box/nlsh_model/).
Αποθηκεύει BLAST artifacts:
- BLAST database prefix (π.χ.
blast_out/swissprot_db.*) - Χρειάζεται γιατί το
protein_search.pyτρέχει BLAST ως reference baseline (Top-N hits) και υπολογίζει Recall@N.
Κοινά modules που χρησιμοποιούνται από embed & search:
Διαβάζει FASTA και επιστρέφει λίστα από (header/id, sequence), με “καθαρισμό” γραμμών/κενών και σωστό χειρισμό πολλαπλών records.
Φορτώνει το μοντέλο ESM-2 και επιστρέφει έτοιμα αντικείμενα για inference: (model, batch_converter)
Υλοποιεί το “embedding pipeline”: batching → forward pass → εξαγωγή representations (π.χ. layer 6) → mean pooling στα residue tokens (χωρίς CLS/EOS/PAD) → αποθήκευση σε SIFT/fvecs binary format.
Loader για dataset σε SIFT/fvecs format (binary: [int32 d] + d float32 ανά vector) και το επιστρέφει ως numpy.ndarray τύπου (N, D).
Brute force kNN baseline (L2/Euclidean) πάνω σε embeddings: για κάθε query βρίσκει τους top-k γείτονες με πλήρη σάρωση του dataset και επιστρέφει/γράφει αποτελέσματα σε format συμβατό με το report. Το χρησιμοποιειούμε στο Search Benchmark ως baseline/για έλεγχο ορθότητας.
Είσοδοι (inputs):
- dataset FASTA (π.χ.
swissprot_50k.fastaή αντίστοιχο) - query FASTA (π.χ.
targets.fasta)
Outputs από τη φάση embeddings:
- embedded vectors file σε SIFT/fvecs format (π.χ.
dataset.dat) - ids mapping file (γραμμή i → protein accession/id)
Σημείωση: το protein_embed.py γράφει σε embed_data/dataset_ids.txt
Το σενάριο παραγωγής embeddings:
protein_embed.py(main) — Υλοποιεί το πρώτο στάδιο του pipeline, όπου μετατρέπουμε το σωστό dataset FASTA (δηλαδή το σύνολο αναφοράς πάνω στο οποίο θα γίνει αργότερα η αναζήτηση) σε ESM-2 embeddings και τα αποθηκεύουμε σε αρχείο vector-format (π.χ. embed_data/dataset.dat) μαζί με το αντίστοιχο mapping IDs, ώστε το Search Benchmark να μπορεί να εκτελέσει ANN/BLAST συγκρίσεις πάνω σε ακριβώς αυτό το σταθερό embedded dataset.embed_args.py(CLI args)
Κώδικας/εργαλεία από 1η εργασία (C++/Make) που παράγουν το executable search για Euclidean LSH / Hypercube / IVF-Flat / IVF-PQ σε “SIFT-like” μορφή. Η προετοιμασία γίνεται μέσω του search_preparation.sh, το οποίο τρέχει make στον φάκελο Nearest-Neighbors/ και στη συνέχεια μεταφέρει/αντιγράφει το παραγόμενο εκτελέσιμο search στο σωστό runtime directory black_box/ (δηλ. black_box/search) ώστε να μπορεί να κληθεί απευθείας από το Search_Benchmark/protein_search.py.
Επιπλέον, έγιναν στοχευμένες αλλαγές στον κώδικα των IVF υλοποιήσεων και στο output interface:
-
Optimizations σε IVFFlat και IVFPQ (speed-up): Όπως στη μετάβαση του IVFFlat από την Εργασία 1 → Εργασία 2, βελτιστοποιήσαμε τον υπολογισμό αποστάσεων και εδώ ώστε να είναι ταχύτερος. Συγκεκριμένα, στον IVFFlat (και κατ’ αναλογία στον IVFPQ) αντικαταστήσαμε την κλασική
lp_distμεfast_dist, αποφεύγοντας περιττέςsqrtπράξεις (δηλαδή δουλεύουμε με squared distances όπου είναι δυνατό), μειώνοντας αισθητά το κόστος ανά query. -
Αλλαγή output format (stdout αντί για κάποιο results.txt): Το
searchκαλείται από το κύριο πρόγραμμαprotein_search.pyμέσωsubprocess(). Για μεγαλύτερη αμεσότητα και ευκολία στο integration, αλλάξαμε το output τουsearchώστε να γράφεται στο stdout. Έτσι τοprotein_search.pyμπορεί να διαβάζει άμεσα το output stream και να κάνει το αντίστοιχο parsing. Παράλληλα, αφαιρέσαμε περιττές πληροφορίες από την έξοδο (π.χ. το όνομα του αλγορίθμου στην αρχή) ώστε το format να είναι πιο “καθαρό” και σταθερό για parsing.
Κώδικας από τη 2η εργασία (Neural LSH pipeline), ο οποίος χρησιμοποιείται για την ANN μέθοδο neural. Για να είναι λειτουργικό το υποσύστημα, απαιτείται build του βοηθητικού component στο Neural-LSH/IVFFlat_build_knn/ (δημιουργία του approx kNN graph που αξιοποιείται στο Neural-LSH), και αυτό το αναλαμβάνει επίσης το search_preparation.sh, το οποίο μπαίνει στον συγκεκριμένο φάκελο και εκτελεί make.
Επιπλέον, για λόγους ενοποίησης με το benchmark pipeline, κάναμε και εδώ τις ίδιες αλλαγές στο output format που εφαρμόσαμε στο Nearest-Neighbors: το output παράγεται στο stdout (όχι σε ενδιάμεσο αρχείο τύπου results.txt) και έχει “καθαρό”/σταθερό format χωρίς περιττά headers (π.χ. αφαίρεση ονόματος αλγορίθμου στην αρχή), ώστε το Search_Benchmark/protein_search.py να μπορεί να το διαβάζει άμεσα μέσω subprocess() και να κάνει το parsing με τον ίδιο ακριβώς τρόπο.
protein_search.py(main pipeline) — Κάνει embed τα queries on-the-fly, καλεί τις ANN μεθόδους (μέσωsubprocess()προςblack_box/searchή Neural-LSH scripts), τρέχει BLAST ως reference και στο τέλος παράγει ενιαίο report (χρόνοι/QPS, Recall@N, top-N hits, bio comments).search_args.py(CLI args + defaults + hyperparameters) — Κεντρικός ορισμός όλων των CLI ορισμάτων και defaults· περιλαμβάνει και method-specific υπερπαραμέτρους (LSH/Hypercube/IVF/Neural) ώστε να μπορούμε να κάνουμε εύκολα benchmarking και grid runs.blast.py(run + parse BLAST) — Αναλαμβάνει την εκτέλεση BLAST (καιmakeblastdbόπου χρειάζεται) και κάνει parsing των hits σε δομή που χρησιμοποιείται για Recall@N και για identity-based σύγκριση ανά query.
Σημείωση: Τα αρχεία που χειρίζεται πρέπει να είναι μέσα στο directory blast_out/
search_report.py(parsing ANN stdout outputs + Recall@N + report formatting) — Κάνει parsing του stdout από τα ANN runs (σταθερό format), υπολογίζει Recall@N έναντι BLAST Top-N και γράφει το τελικό report σε αναγνώσιμη/συγκρίσιμη μορφή.bio_comment.py(UniProt maps + “Remote homolog?” comments) — Φορτώνει BIO-data maps (Pfam/GO/EC/InterPro όπου υπάρχουν) και προσθέτει ερμηνευτικά σχόλια ειδικά όταν το BLAST identity είναι χαμηλό ή απουσιάζει (υποψία remote homolog).
Φάκελοι για μαζικά πειράματα/αναζητήσεις (grid runs):
test_results/: αποθήκευση των “results reports” ανά runtest_summary/: αποθήκευση stdout/stderr/metadata ανά run
(Το run_bench_grid.py έχει τα παραπάνω directories ως default προορισμούς των αποτελεσμάτων του.)
-
summarize_grid.py: Διαβάζει όλα τα*_summary.txtαπό τοtest_summary/, εξάγει για κάθε run τα metrics (avg recall@N, QPS), τα params και τον χρόνο, και φτιάχνει συγκεντρωτικό CSVtest_summary/grid_results_summary.csv. Επιπλέον παράγει βασικά plots στοtest_summary/plots/(QPS vs Recall). -
pick_best_configs.py: Παίρνει ως είσοδο το παραπάνω CSV και τυπώνει “καλύτερες” ρυθμίσεις ανά μέθοδο και συνολικά: (1) μέγιστο Recall, (2) μέγιστο QPS, (3) μέγιστο QPS υπό κατώφλι Recall, (4) “all-around best” με ένα dominance score. -
csv_to_latex.py: Μετατρέπει τοgrid_results_summary.csvσε έτοιμους \LaTeX{} πίνακες (ένας ανά μέθοδο) και γράφει το αρχείοtest_summary/grid_results_tables.tex.
-
search_preparation.sh
Script προετοιμασίας/build που αυτοματοποιεί το setup των εξωτερικών εκτελέσιμων -
run_bench_grid.pyGrid/benchmark runner που εκτελεί μαζικά τοSearch_Benchmark/protein_search.pyγια πολλές μεθόδους και συνδυασμούς υπερπαραμέτρων (σύμφωνα με προ-ορισμένα grids), δημιουργώντας ξεχωριστά αρχεία αποτελεσμάτων (test_results/) και αναλυτικά summaries με stdout/stderr/χρόνους/return codes (test_summary/) για εύκολη σύγκριση runs. -
results.txtΤα αποτελέσματα των καλύτερων εκτελέσεων -
results_average.txtΟ μέσος όρος των τιμών αυτών των καλύτερων αποτελεσμάτων
- Linux, Python 3.10+
- build tools:
make, C/C++ compiler - NCBI BLAST+ (απαραίτητο για το reference BLAST κομμάτι)
Εγκατάσταση BLAST+ (Ubuntu/Debian):
sudo apt update
sudo apt install ncbi-blast+Από <project-root>:
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pipΕγκαταστήστε τις απαραίτητες βιβλιοθήκες:
pip install numpy
pip install torch --index-url https://download.pytorch.org/whl/cu121
pip install fair-esm
pip install scikit-learn
pip install kahipή
pip install -r requirements.txtΠριν την εκτέλεση του search benchmark για LSH/Hypercube/IVF-Flat/IVF-PQ, πρέπει να υπάρχει το executable black_box/search.
Από <project-root>:
bash search_preparation.shΤο script:
- κάνει
makeστοNearest-Neighbors/ - αντιγράφει το
Nearest-Neighbors/searchσεblack_box/search - κάνει
makeκαι στοNeural-LSH/IVFFlat_build_knn(χρήσιμο για Neural-LSH pipeline)
Σημείωση: τα scripts απαιτούν έξτρα βιβλιοθήκες:
pip install pandas matplotlibΔιαβάζει dataset FASTA και παράγει embeddings με ESM-2, αποθηκεύοντάς τα σε SIFT/fvecs αρχείο (ανά διάνυσμα γράφει πρώτα int32 d και μετά d float32).
Από <project-root>:
python Generating_Embeddings/protein_embed.py -i data/swissprot_50k.fasta -o embed_data/dataset.dat-i / --input_file: dataset FASTA (π.χ.data/swissprot_50k.fasta)-o / --output_file: output vectors file (π.χ.embed_data/dataset.dat)
embed_data/dataset.dat(ή ό,τι ορίστηκε στο-o) SIFT/fvecs embeddings, διαστάσεωνN x D.embed_data/dataset_ids.txtΈνα ID ανά γραμμή. Η γραμμήiαντιστοιχεί στοi-οστό διάνυσμα του dataset file.
Για κάθε query πρωτεΐνη:
-
Κάνει embed τις query ακολουθίες σε προσωρινό fvecs (δεν χρειάζεται να τις κάνεις pre-embed χειροκίνητα).
-
Τρέχει μία ή περισσότερες ANN μεθόδους:
lsh,hypercube,ivfflat,ivfpqμέσωblack_box/searchneuralμέσωNeural-LSHscripts (κάνει build index αν δεν υπάρχει)- (προαιρετικά)
bruteforcebaseline (ενεργοποιείται αυτόματα όταν ζητήσεις-method all)
-
Τρέχει BLAST reference σε ίδιο dataset FASTA (φτιάχνει DB στην πρώτη εκτέλεση).
-
Παράγει report με:
- QPS / time per query
- Recall@N vs BLAST Top-N
- αναλυτικούς Top-
print_nγείτονες με L2 distance, BLAST identity, “In BLAST Top-N?”, και bio comment (αν δεν έχεις--no_bio).
Από <project-root>:
python3 Search_Benchmark/protein_search.py \
-d embed_data/dataset.dat \
-q data/targets.fasta \
-o out/results.txt \
-method all \
--recall_n 50 \
--print_n 10 \
--ids_file embed_data/ids.txt \
--dataset data/swissprot_50k.fasta \
--annot_tsv bio_data/annot.tsv \
--pfam_tsv bio_data/pfam.filtered.tsv-d / --dataset_file: embedded dataset vectors file (π.χ.embed_data/dataset.dat)-q / --query_file: query FASTA (π.χ.data/targets.fasta)-o / --output_file: report file (π.χ.out/results.txt)-method / --method:all|lsh|hypercube|ivfflat|ivfpq|neural
--recall_n: N για Recall@N vs BLAST Top-N (default 50)--print_n: πόσους γείτονες να εκτυπώσει αναλυτικά (default 10)--ids_file: mapping file για dataset IDs--dataset: dataset FASTA για BLAST (defaultdata/swissprot_50k.fasta)--annot_tsv,--pfam_tsv: TSV paths για bio comments--no_bio: απενεργοποιεί bio comments
Μπορείς να τα ορίσεις από command line μέσω search_args.py:
Euclidean LSH
--lsh_k(default 6)--lsh_L(default 8)--lsh_w(default 2000.0)
Hypercube
--cube_kproj(default 12)--cube_w(default 1.5)--cube_M(default 5000)--cube_probes(default 2)
IVF (shared for ivfflat/ivfpq)
--ivf_kclusters(default 1000)--ivf_nprobe(default 50)
IVF-PQ
--ivfpq_M(default 16)--ivfpq_nbits(default 8)
Neural LSH
--neural_T(default 10) (search-time)--neural_m(default 256)--neural_layers(default 2)--neural_nodes(default 128)--neural_knn_mode(approxήbrute, defaultapprox)--neural_kahip_mode(default 1)--neural_index(defaultnlsh_model) → directory name μέσα στοblack_box/
-
Report: το αρχείο που ήταν στο
-o(π.χ.out/results.txt) -
blast_out/:- BLAST DB prefix files (π.χ.
swissprot_db.*)
- BLAST DB prefix files (π.χ.
-
black_box/:- Neural indices (π.χ.
black_box/nlsh_model/) όταν τρέχει για-method neuralήall
- Neural indices (π.χ.
Το run_bench_grid.py τρέχει πολλά runs του protein_search.py αλλάζοντας παραμέτρους ανά μέθοδο.
Παράδειγμα (τρέξε όλες τις μεθόδους με Recall@50 και print 10):
python3 run_bench_grid.py \
-d embed_data/dataset.dat \
-q data/targets.fasta \
--recall_n 50 \
--print_n 10 \
--ids_file embed_data/ids.txt \
--dataset data/swissprot_50k.fasta \
--annot_tsv bio_data/annot.tsv \
--pfam_tsv bio_data/pfam.filtered.tsv \
--results_dir test_results \
--summary_dir test_summaryΣημειώσεις:
- Ο runner γράφει ένα report ανά run (στο
results_dir) και ένα summary (stdout/stderr/params) ανά run (στοsummary_dir). - Για Neural LSH φτιάχνει unique
--neural_indexname ανά set υπερπαραμέτρων ώστε να μην “πατάει” indices.
python bio_data/filter_tsv.py \
--pfam <uniprot_pfam.tsv.gz> \
--annot <uniprot_annot.tsv.gz> \
--ids embed_data/ids.txt data/targets.fasta \
--out_dir bio_data/filtered_uniprot \
--pfam_out pfam.filtered.tsv \
--annot_out annot.filtered.tsv \
--acc_col EntryΑν υπάρχει ξεχωριστό TSV με GO/InterPro και θέλουμε να τα ενσωματώσουμε στο annot:
python3 bio_data/THE_MERGER.py annot.tsv dataset.interpro_go.tsv annot_with_go_ipr.tsv-
Πρώτη εκτέλεση BLAST είναι αργή Γιατί γίνεται
makeblastdbκαι γράφονται αρχεία στοblast_out/. Οι επόμενες εκτελέσεις είναι ταχύτερες. -
Bio comments εμφανίζονται μόνο σε “Twilight Zone” περιπτώσεις Το
bio_comment.pyεπιστρέφει σχόλιο κυρίως όταν το BLAST identity είναι< 30%ή δεν υπάρχει BLAST hit, και υπάρχουν ενδείξεις (κοινά Pfam/GO/EC/InterPro).
# 1) env + deps + BLAST
python -m venv .venv
source .venv/bin/activate
pip install numpy scikit-learn fair-esm kahip
# (torch ανάλογα με CPU/CUDA)
sudo apt install -y ncbi-blast+
# 2) build binaries
bash search_preparation.sh
# 3) embeddings
python Generating_Embeddings/protein_embed.py -i data/swissprot_50k.fasta -o embed_data/dataset.dat
# 4) benchmark
python Search_Benchmark/protein_search.py \
-d embed_data/dataset.dat \
-q data/targets.fasta \
-o results.txt \
-method all \
--recall_n 50 \
--print_n 10 \
--ids_file embed_data/ids.txt \
--dataset data/swissprot_50k.fasta \
--annot_tsv bio_data/annot.tsv \
--pfam_tsv bio_data/pfam.filtered.tsv