Enzyme classification: DIAMOND homology + learned EC re-ranker (v6)
Submission for the Leak CURBER enzyme classification task (leak-curber-enzyme-classification). Only the provided train.parquet is used. No external labelled data.
Pipeline
- Homology search. Every unique input is searched against all 186,488 unique training sequences with DIAMOND v2.1.10 (
blastp --very-sensitive, 50 hits). - Second pass. Inputs with no hit, or a best hit of 30% identity or less, are searched again with
--ultra-sensitive. This pass runs only when the time budget clearly allows it. - Candidate features. The candidate ECs come from the hits. Each candidate gets 33 features:
- vote weights (bitscore^1/4/8)
- identity, coverage and e-value of the best supporting hit
- support among the top 10 and top 50 hits
- agreement at the L3, L2 and L1 levels of the EC hierarchy
- EC frequency
- query-level difficulty
- out-of-fold EC reliability: how often this EC was correct when proposed
- Re-ranker. A gradient-boosted tree ensemble (scikit-learn HistGradientBoosting, exported to pure numpy in
weights/ranker.npz) scores each candidate, and the best one comes first.
Training the re-ranker without leakage
Training sequences were clustered at 50% identity (diamond cluster). The clusters were split into 15 folds, and each fold was searched against the other 14. This mimics the official validation set, where the median top-hit identity to train is 44%. The result is 434k candidate rows from 181k queries, and the EC reliability features are computed out-of-fold.
Local results (cluster-held-out, queries with a top hit below 58% identity)
| L4 | |
|---|---|
| Nearest-neighbour vote (v1) | 0.787 |
| + learned re-ranker (v2) | 0.806 |
These numbers cover queries that have at least one hit. About 5% of held-out queries have an EC that never occurs in training, which caps the achievable score.
Robustness
- The evaluator caps every written file at 16 MiB (RLIMIT_FSIZE) and allows only 256 open files (RLIMIT_NOFILE).
- v3 failed on the size cap: DIAMOND's temporary seed-hit file was too big (SIGXFSZ).
- v4 failed on the file cap:
--bin 256meant too many open files. - v5 uses
--bin 128, derived from RLIMIT_NOFILE, and batches of at most 8,000 queries. It halves the bin count and retries on "Too many open files", and splits a batch and retries on SIGXFSZ. - Tested under
ulimit -f 16384 -n 256 -u 128 -s 10240: the output is identical to an unrestricted run, in about 3 minutes.
predict.pylogs environment diagnostics: CPU flags, memory and process limits, and mounts.- Each DIAMOND binary is smoke-tested before use: first the official release binary, then a generic, fully static build of DIAMOND v2.1.10 (
bin/diamond-generic, compiled with-march=x86-64). A crash is logged with its signal. - A watchdog stops DIAMOND at 420 s. In v6 the ultra-sensitive second pass runs when the first pass finishes within 215 s. Under the sandbox limits the whole run takes about 300 s.
- If DIAMOND cannot run, a pure numpy/scipy 3-mer TF-IDF nearest-neighbour fallback (
kmer_knn.py) predicts every input. It scores about 0.39 L4 locally.
Runtime
About 4.5 minutes for the 11,367 validation inputs on 2 vCPU. Faster search modes switch in automatically for much larger inputs. bin/diamond-linux64.tar.gz is the official DIAMOND release. The Dockerfile extracts it at build time, and predict.py extracts it to /tmp if it is missing.