File size: 6,166 Bytes
e11bc48 39e808f e11bc48 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | ---
license: mit
tags:
- protein
- biology
- sequence-encoder
- contrastive-learning
- lemon
---
# LEMON: Layered Extraction of Molecular Ordering from Nature
LEMON is a protein sequence encoder trained with hierarchical contrastive
learning for family and fold similarity search, using the ZEST tokenizer
(Zoned Encoding of Sequence Traits). Submitted anonymously for double-blind
peer review.
## Architecture
| Component | Details |
|---|---|
| **Encoder** | 24-layer transformer, 768-d, 12 heads, SwiGLU FFN (ff_mult=4), RoPE with linear scaling |
| **Pooling** | Learned-query multi-head attention aggregator β 768-d sequence vector |
| **Projector** | Bottleneck MLP (768 β 768 β 384-d), L2-normalised output |
| **Tokenizer** | ZEST 32K (Zoned Encoding of Sequence Traits) β greedy max-match trie over biochemically-substitutable amino-acid n-gram clusters |
| **Context** | 1,024 tokens (linear RoPE scaling for longer sequences) |
| **Dropout** | 0.04 |
**Parameter breakdown (203.72M total):**
| Module | Params |
|---|---|
| Core transformer | 194.52M |
| Attention aggregator | 2.95M |
| Profile expansion head | 2.41M |
| Global position embedding | 2.36M |
| Projector | 1.48M |
| **Total** | **203.72M** |
## Quickstart
```python
import torch
from huggingface_hub import snapshot_download
import sys, os
path = snapshot_download("Team-LEMON/lemon")
sys.path.insert(0, path)
from modeling_lemon import LemonEncoder
from tokenization_zest import ZESTTokenizer
tok = ZESTTokenizer.from_pretrained(path)
model = LemonEncoder.from_pretrained(
os.path.join(path, "model.safetensors"),
os.path.join(path, "config.json"),
)
model.eval()
seqs = ["MKTAYIAKQRQISFVKSHFSRQ", "ACDEFGHIKLMNPQRSTVWY"]
enc = tok.batch_encode_plus(seqs, max_length=512, padding=True)
with torch.no_grad():
emb = model.embed(enc["input_ids"], enc["attention_mask"]) # [2, 384]
print(emb.shape) # torch.Size([2, 384])
sim = model.similarity(emb[:1], emb[1:])
print("cosine-like similarity:", sim.item())
```
## Reproducing Table 1
The `eval_retrieval.py` script and all three benchmark datasets are bundled in this
repo. No external downloads required.
**Run all three datasets in one command:**
```python
from huggingface_hub import snapshot_download
path = snapshot_download("Team-LEMON/lemon")
```
```bash
cd /path/to/snapshot
python eval_retrieval.py # runs SCOPe + SCOP + CATH-S20
python eval_retrieval.py --scope # SCOPe only
python eval_retrieval.py --cath # CATH-S20 only
python eval_retrieval.py --scop # SCOP only
```
**Test-Time Augmentation (TTA) with Trie-Dropout:**
TTA improves retrieval by averaging embeddings from multiple stochastic tokenizations.
```bash
python eval_retrieval.py --dropout 0.45 --tta 5 # 5 stochastic passes, averaged
```
**TTA Gain (SCOPe, seed=42):**
| Level | Metric | Baseline | TTA (d=0.45, k=5) | Gain |
|-------|--------|----------|-------------------|------|
| fold | AUROC | 0.9025 | 0.9080 | +0.0055 |
| fold | mAP | 0.3067 | 0.3197 | +0.0130 |
| superfamily | AUROC | 0.9443 | 0.9519 | +0.0076 |
| superfamily | mAP | 0.4700 | 0.4803 | +0.0103 |
To reproduce:
```bash
# Baseline
python eval_retrieval.py --scope --seed 42
# With TTA
python eval_retrieval.py --scope --seed 42 --dropout 0.45 --tta 5
```
**Or from a Jupyter notebook:**
```python
import sys
from huggingface_hub import snapshot_download
path = snapshot_download("Team-LEMON/lemon")
sys.path.insert(0, path)
from eval_retrieval import run_benchmark, display_results
results = run_benchmark(repo=path, seed=42) # deterministic with seed=42
display_results(results)
# With TTA:
# results = run_benchmark(repo=path, seed=42, dropout=0.1, tta_passes=8)
```
**Expected output (seed=42, deterministic):**
| Dataset | Level | AUROC | mAP |
|----------|--------------|--------|--------|
| SCOPe | fold | 0.9025 | 0.3066 |
| SCOPe | superfamily | 0.9443 | 0.4700 |
| CATH-S20 | architecture | 0.8871 | 0.3128 |
| CATH-S20 | topology | 0.9580 | 0.5381 |
| SCOP | fold | 0.9062 | 0.2919 |
> Results are deterministic with `--seed 42` (default).
> CATH uses Architecture/Topology levels; SCOP/SCOPe uses Fold/Superfamily.
**Bundled dataset provenance:**
| File | Sequences | Original source |
|------|-----------|----------------|
| `data/scope_10_2.08.fa` | 7 117 | SCOPe 2.08, 10% seq-id β [scop.berkeley.edu](https://scop.berkeley.edu/downloads/scopeseq-2.08/) |
| `data/cath_s20.fa` | 15 043 | CATH v4.4.0 S20 β [cathdb.info](https://www.cathdb.info/wiki/doku/?id=data:index) |
| `data/cath_s20_labels.tsv` | 15 043 | CATH domain list v4.4.0 (S20 subset) β [cathdb.info](https://www.cathdb.info/wiki/doku/?id=data:index) |
| `data/scop175.fa` | 31 073 | SCOP 1.75 β [plm-zero-shot-remote-homology-evaluation](https://github.com/amoldwin/plm-zero-shot-remote-homology-evaluation) |
## Circular Permutation Detection (CIRPIN SCOPe40)
Zero-shot detection of circularly permuted protein pairs using cosine similarity of LEMON embeddings.
Benchmark: CIRPIN SCOPe40 β 18,127 pairs (1,967 positive CP pairs) from ASTRAL SCOPe 2.08 at 40% identity.
**Results (seed=42):**
| Configuration | AUROC | AUPRC | Accuracy |
|---------------|-------|-------|----------|
| Baseline | 0.7413 | 0.3035 | 0.8990 |
| TTA (d=0.45, k=5) | **0.7576** | **0.3066** | 0.8987 |
| Gain | +0.0163 | +0.0031 | - |
TTA improves CP detection by averaging embeddings over multiple stochastic tokenizations.
To reproduce:
```bash
# Baseline
python eval_circular_permutation.py --fasta data/cirpin/scope40.fa --pairs data/cirpin/pairs.tsv --seed 42
# With TTA
python eval_circular_permutation.py --fasta data/cirpin/scope40.fa --pairs data/cirpin/pairs.tsv --seed 42 --dropout 0.45 --tta 5
```
## Requirements
```
torch>=2.0
safetensors
huggingface_hub
```
## Notes
- Input sequences should be standard single-letter amino-acid strings.
- The tokenizer handles unknown characters via `<MASK>` token fallback.
- `model.embed()` returns L2-normalised embeddings; use dot product for
cosine similarity.
- `model.similarity()` applies a learned temperature scalar.
|