ProCap is a comprehensive benchmark for evaluating Protein Language Models (PLMs) across cognitive ability levels based on Bloom's Taxonomy.
# Clone the repository
git clone https://github.com/msparsa/procap.git
cd procap-v2
# Install dependencies (recommended)
pip install -r requirements.txt
# Or install as package
pip install -e .
Most benchmark datasets are included in the repository. However, the ProteinGym variant effect dataset (~2GB) must be downloaded separately:
# Download large data files (ProteinGym ~2GB)
python scripts/download_data.py
# List available downloads without downloading
python scripts/download_data.py --list
Included datasets:
*_small.csv test datasets (<2MB each)External datasets (download required):
See configs/data_sources.yaml for dataset sources and citations.
# Run SS3 benchmark on a single model
python run_ss3_benchmark.py
# Run GO term benchmark
python run_go_benchmark.py
# Run PPI benchmark
python run_ppi_benchmark.py
# Run other benchmarks
python run_family_benchmark.py
python run_homology_benchmark.py
python run_variant_benchmark.py
# Run all models on each task
python run_ss3_all_models.py
python run_go_all_models.py
python run_ppi_all_models.py
python run_family_all_models.py
python run_homology_all_models.py
python run_variant_all_models.py
Results are saved to benchmark_results/ as JSON files.
# Run a quick model test
python -m procap.cli test --model esm2_t6_8M
# List all available models
python -m procap.cli list-models
# List all benchmark tasks
python -m procap.cli list-tasks
# Get task info
python -m procap.cli info --task secondary_structure_ss3
# Run evaluation
python -m procap.cli evaluate --model esm2_t33_650M --task secondary_structure_ss3 --max-samples 100
ProCap supports 37 model variants across 11 model families:
| Model Family | Variants | Parameters | Description |
|---|---|---|---|
| ESM-2 | 6 variants | 8M - 15B | Meta AI's state-of-the-art PLM |
| ESM-1b/1v | 6 variants | 650M | Earlier ESM versions, ESM-1v optimized for variants |
| ProtBERT | 2 variants | ~420M | BERT-based PLM from Rostlab |
| OntoProtein | 1 variant | ~420M | GO knowledge-enhanced PLM |
| ProtT5 | 3 variants | ~3B | T5-based PLM from Rostlab |
| Ankh | 2 variants | 450M - 1.5B | Efficient PLM from ElnaggarLab |
| ProtAlbert | 1 variant | 12M | Lightweight ALBERT-based PLM |
| SaProt | 2 variants | 650M | Structure-aware PLM (ICLR 2024) |
| Model Family | Variants | Parameters | Description |
|---|---|---|---|
| ProGen2 | 4 variants | 151M - 2.7B | Protein sequence generation |
| ZymCTRL | 1 variant | ~350M | Enzyme-specialized generation |
| ProtGPT2 | 1 variant | 738M | GPT-2 based protein generation |
| Tranception | 3 variants | Various | Mutation effect prediction specialist |
The following 11 models have been extensively tested across all benchmark tasks:
| Model | Parameters | Status |
|---|---|---|
| ESM2-8M | 8M | Working |
| ESM2-35M | 35M | Working |
| ESM2-150M | 150M | Working |
| ESM2-650M | 650M | Working |
| ESM1b-650M | 650M | Working |
| ProtBERT | 420M | Working |
| ProtBERT-BFD | 420M | Working |
| OntoProtein | 420M | Working |
| ProtT5-XL-BFD | 3B | Working |
| Ankh-Base | 450M | Working |
| ProtAlbert | 12M | Working |
Note: ProGen2 and ProtGPT2 have known compatibility issues with linear probe evaluation.
from procap.models import get_model
# Load ESM-2
model = get_model("esm2_t33_650M")
model.load()
embeddings = model.get_embeddings(["MLKFV", "ACDEFG"], pooling="mean")
# Load SaProt (structure-aware)
model = get_model("saprot_650m_af2")
model.load()
# With structure tokens
embeddings = model.get_embeddings(["MaLbKcFdVe"])
# Or sequence-only (auto-adds default structure tokens)
embeddings = model.get_embeddings(["MLKFV"])
# Load ProtGPT2 for generation
model = get_model("protgpt2")
model.load()
generated = model.generate(["MKTV"], max_new_tokens=50)
# Load Tranception for mutation scoring
model = get_model("tranception_medium")
model.load()
scores = model.score_mutations("MLKFVAAAA", ["M1A", "L2V"])
ProCap includes 11 tasks organized by Bloom's Taxonomy levels:
| Task | Type | Bloom Level | Dataset Size |
|---|---|---|---|
go_term_identification | multilabel_classification | Remembering | 30,184 |
family_classification | multiclass_classification | Remembering | 6,372 |
function_explanation | text_generation | Understanding | 4* |
secondary_structure_ss3 | token_classification | Understanding | 10,000 |
go_term_prediction | multilabel_classification | Applying | 5,000 |
variant_effect_prediction | regression | Analysis | 2,465,767 |
remote_homology | multiclass_classification | Analysis | 19,983 |
ppi_prediction | ppi_classification | Analysis | 50,000 |
annotation_validation | multilabel_classification | Evaluation | 2,000 |
novel_function_generation | text_generation | Creating | 1,000 |
enzyme_sequence_generation | sequence_generation | Creating | 1,000 |
*function_explanation has placeholder data
# Test model loading and basic inference
python -m procap.cli test [--model MODEL_NAME]
# List available models
python -m procap.cli list-models
# List available tasks (optionally filter by Bloom level)
python -m procap.cli list-tasks [--bloom LEVEL]
# Get detailed info about a model or task
python -m procap.cli info --model MODEL_NAME
python -m procap.cli info --task TASK_NAME
# Run evaluation
python -m procap.cli evaluate \
--model MODEL_NAME \
--task TASK_NAME \
[--max-samples N] \
[--batch-size B] \
[--output results.json] \
[--device cuda|cpu]
# Evaluate ESM-2 on secondary structure prediction
python -m procap.cli evaluate \
--model esm2_t33_650M \
--task secondary_structure_ss3 \
--max-samples 1000 \
--batch-size 8
# Evaluate on GO term prediction
python -m procap.cli evaluate \
--model protbert \
--task go_term_prediction \
--max-samples 500
# Evaluate on protein-protein interaction
python -m procap.cli evaluate \
--model esm2_t33_650M \
--task ppi_prediction \
--max-samples 1000
from procap.models import get_model
from procap.tasks import get_task
from procap.data import load_dataset
from procap.runners import MultiLabelClassificationRunner
# Load model
model = get_model("esm2_t33_650M")
model.load()
# Load task configuration
task = get_task("go_term_identification")
# Load dataset
df = load_dataset(task.dataset_path, nrows=1000)
# Run evaluation
runner = MultiLabelClassificationRunner(task, model, batch_size=16)
results = runner.run(df)
print(results)
from procap.models import get_model
# Get embeddings for downstream tasks
model = get_model("esm2_t33_650M")
model.load()
sequences = ["MLKFVAAAA", "ACDEFGHIK", "MKTVRQERLK"]
embeddings = model.get_embeddings(sequences, pooling="mean")
# embeddings shape: [3, hidden_size]
print(f"Embedding shape: {embeddings.shape}")
data/
├── functional/
│ ├── gobench_remember.csv # GO term identification
│ ├── gobench_understand.csv # Function explanation
│ ├── gobench_apply.csv # GO term prediction
│ ├── gobench_create.csv # Novel function generation
│ ├── family_classification.csv # Protein family
│ └── peer_eval.csv # Annotation validation
├── variant_effect/
│ └── proteingym_substitutions.csv # Variant effect prediction
├── structure/
│ ├── secondary_structure_ss3.csv # SS3 prediction (10K)
│ └── secondary_structure_ss3_small.csv # SS3 small (1K)
├── homology/
│ └── remote_homology.csv # Remote homology detection
└── interaction/
└── ppi_prediction.csv # Protein-protein interaction
accuracy, f1_micro, f1_macro, f1_maxprecision_micro, recall_microauprc_micro, auprc_macroauroc_micro, auroc_macrospearman, pearson, kendall_taurmse, mae, r2rougeL, bertscorenovelty_50, diversityseq_identitysecondary_structure_ss3:
name: secondary_structure_ss3
bloom_level: Understanding
domain: Structure
description: Predict 3-state secondary structure for each residue
task_type: token_classification
dataset_path: data/structure/secondary_structure_ss3.csv
input_fields: [sequence]
target_field: ss3_labels
metrics: [accuracy, f1_macro]
num_labels: 3
models:
my_custom_esm:
type: esm
variant: esm2_t33_650M
max_batch_size: 8
procap/models/:from procap.core.base_model import BaseProteinModel, ModelOutput
class MyModelAdapter(BaseProteinModel):
def load(self) -> None:
# Load model weights
pass
def tokenize(self, sequences):
# Tokenize sequences
pass
def get_embeddings(self, sequences, pooling="mean"):
# Extract embeddings
pass
procap/models/registry.py:from procap.models.my_model import MyModelAdapter
DEFAULT_MODELS["my_model"] = {
"class": MyModelAdapter,
"params": {"variant": "my_variant", "max_batch_size": 8},
}
ProCap is a comprehensive benchmark for evaluating Protein Language Models (PLMs) across cognitive ability levels based on Bloom's Taxonomy.
# Clone the repository
git clone https://github.com/msparsa/procap.git
cd procap-v2
# Install dependencies (recommended)
pip install -r requirements.txt
# Or install as package
pip install -e .
Most benchmark datasets are included in the repository. However, the ProteinGym variant effect dataset (~2GB) must be downloaded separately:
# Download large data files (ProteinGym ~2GB)
python scripts/download_data.py
# List available downloads without downloading
python scripts/download_data.py --list
Included datasets:
*_small.csv test datasets (<2MB each)External datasets (download required):
See configs/data_sources.yaml for dataset sources and citations.
# Run SS3 benchmark on a single model
python run_ss3_benchmark.py
# Run GO term benchmark
python run_go_benchmark.py
# Run PPI benchmark
python run_ppi_benchmark.py
# Run other benchmarks
python run_family_benchmark.py
python run_homology_benchmark.py
python run_variant_benchmark.py
# Run all models on each task
python run_ss3_all_models.py
python run_go_all_models.py
python run_ppi_all_models.py
python run_family_all_models.py
python run_homology_all_models.py
python run_variant_all_models.py
Results are saved to benchmark_results/ as JSON files.
# Run a quick model test
python -m procap.cli test --model esm2_t6_8M
# List all available models
python -m procap.cli list-models
# List all benchmark tasks
python -m procap.cli list-tasks
# Get task info
python -m procap.cli info --task secondary_structure_ss3
# Run evaluation
python -m procap.cli evaluate --model esm2_t33_650M --task secondary_structure_ss3 --max-samples 100
ProCap supports 37 model variants across 11 model families:
| Model Family | Variants | Parameters | Description |
|---|---|---|---|
| ESM-2 | 6 variants | 8M - 15B | Meta AI's state-of-the-art PLM |
| ESM-1b/1v | 6 variants | 650M | Earlier ESM versions, ESM-1v optimized for variants |
| ProtBERT | 2 variants | ~420M | BERT-based PLM from Rostlab |
| OntoProtein | 1 variant | ~420M | GO knowledge-enhanced PLM |
| ProtT5 | 3 variants | ~3B | T5-based PLM from Rostlab |
| Ankh | 2 variants | 450M - 1.5B | Efficient PLM from ElnaggarLab |
| ProtAlbert | 1 variant | 12M | Lightweight ALBERT-based PLM |
| SaProt | 2 variants | 650M | Structure-aware PLM (ICLR 2024) |
| Model Family | Variants | Parameters | Description |
|---|---|---|---|
| ProGen2 | 4 variants | 151M - 2.7B | Protein sequence generation |
| ZymCTRL | 1 variant | ~350M | Enzyme-specialized generation |
| ProtGPT2 | 1 variant | 738M | GPT-2 based protein generation |
| Tranception | 3 variants | Various | Mutation effect prediction specialist |
The following 11 models have been extensively tested across all benchmark tasks:
| Model | Parameters | Status |
|---|---|---|
| ESM2-8M | 8M | Working |
| ESM2-35M | 35M | Working |
| ESM2-150M | 150M | Working |
| ESM2-650M | 650M | Working |
| ESM1b-650M | 650M | Working |
| ProtBERT | 420M | Working |
| ProtBERT-BFD | 420M | Working |
| OntoProtein | 420M | Working |
| ProtT5-XL-BFD | 3B | Working |
| Ankh-Base | 450M | Working |
| ProtAlbert | 12M | Working |
Note: ProGen2 and ProtGPT2 have known compatibility issues with linear probe evaluation.
from procap.models import get_model
# Load ESM-2
model = get_model("esm2_t33_650M")
model.load()
embeddings = model.get_embeddings(["MLKFV", "ACDEFG"], pooling="mean")
# Load SaProt (structure-aware)
model = get_model("saprot_650m_af2")
model.load()
# With structure tokens
embeddings = model.get_embeddings(["MaLbKcFdVe"])
# Or sequence-only (auto-adds default structure tokens)
embeddings = model.get_embeddings(["MLKFV"])
# Load ProtGPT2 for generation
model = get_model("protgpt2")
model.load()
generated = model.generate(["MKTV"], max_new_tokens=50)
# Load Tranception for mutation scoring
model = get_model("tranception_medium")
model.load()
scores = model.score_mutations("MLKFVAAAA", ["M1A", "L2V"])
ProCap includes 11 tasks organized by Bloom's Taxonomy levels:
| Task | Type | Bloom Level | Dataset Size |
|---|---|---|---|
go_term_identification | multilabel_classification | Remembering | 30,184 |
family_classification | multiclass_classification | Remembering | 6,372 |
function_explanation | text_generation | Understanding | 4* |
secondary_structure_ss3 | token_classification | Understanding | 10,000 |
go_term_prediction | multilabel_classification | Applying | 5,000 |
variant_effect_prediction | regression | Analysis | 2,465,767 |
remote_homology | multiclass_classification | Analysis | 19,983 |
ppi_prediction | ppi_classification | Analysis | 50,000 |
annotation_validation | multilabel_classification | Evaluation | 2,000 |
novel_function_generation | text_generation | Creating | 1,000 |
enzyme_sequence_generation | sequence_generation | Creating | 1,000 |
*function_explanation has placeholder data
# Test model loading and basic inference
python -m procap.cli test [--model MODEL_NAME]
# List available models
python -m procap.cli list-models
# List available tasks (optionally filter by Bloom level)
python -m procap.cli list-tasks [--bloom LEVEL]
# Get detailed info about a model or task
python -m procap.cli info --model MODEL_NAME
python -m procap.cli info --task TASK_NAME
# Run evaluation
python -m procap.cli evaluate \
--model MODEL_NAME \
--task TASK_NAME \
[--max-samples N] \
[--batch-size B] \
[--output results.json] \
[--device cuda|cpu]
# Evaluate ESM-2 on secondary structure prediction
python -m procap.cli evaluate \
--model esm2_t33_650M \
--task secondary_structure_ss3 \
--max-samples 1000 \
--batch-size 8
# Evaluate on GO term prediction
python -m procap.cli evaluate \
--model protbert \
--task go_term_prediction \
--max-samples 500
# Evaluate on protein-protein interaction
python -m procap.cli evaluate \
--model esm2_t33_650M \
--task ppi_prediction \
--max-samples 1000
from procap.models import get_model
from procap.tasks import get_task
from procap.data import load_dataset
from procap.runners import MultiLabelClassificationRunner
# Load model
model = get_model("esm2_t33_650M")
model.load()
# Load task configuration
task = get_task("go_term_identification")
# Load dataset
df = load_dataset(task.dataset_path, nrows=1000)
# Run evaluation
runner = MultiLabelClassificationRunner(task, model, batch_size=16)
results = runner.run(df)
print(results)
from procap.models import get_model
# Get embeddings for downstream tasks
model = get_model("esm2_t33_650M")
model.load()
sequences = ["MLKFVAAAA", "ACDEFGHIK", "MKTVRQERLK"]
embeddings = model.get_embeddings(sequences, pooling="mean")
# embeddings shape: [3, hidden_size]
print(f"Embedding shape: {embeddings.shape}")
data/
├── functional/
│ ├── gobench_remember.csv # GO term identification
│ ├── gobench_understand.csv # Function explanation
│ ├── gobench_apply.csv # GO term prediction
│ ├── gobench_create.csv # Novel function generation
│ ├── family_classification.csv # Protein family
│ └── peer_eval.csv # Annotation validation
├── variant_effect/
│ └── proteingym_substitutions.csv # Variant effect prediction
├── structure/
│ ├── secondary_structure_ss3.csv # SS3 prediction (10K)
│ └── secondary_structure_ss3_small.csv # SS3 small (1K)
├── homology/
│ └── remote_homology.csv # Remote homology detection
└── interaction/
└── ppi_prediction.csv # Protein-protein interaction
accuracy, f1_micro, f1_macro, f1_maxprecision_micro, recall_microauprc_micro, auprc_macroauroc_micro, auroc_macrospearman, pearson, kendall_taurmse, mae, r2rougeL, bertscorenovelty_50, diversityseq_identitysecondary_structure_ss3:
name: secondary_structure_ss3
bloom_level: Understanding
domain: Structure
description: Predict 3-state secondary structure for each residue
task_type: token_classification
dataset_path: data/structure/secondary_structure_ss3.csv
input_fields: [sequence]
target_field: ss3_labels
metrics: [accuracy, f1_macro]
num_labels: 3
models:
my_custom_esm:
type: esm
variant: esm2_t33_650M
max_batch_size: 8
procap/models/:from procap.core.base_model import BaseProteinModel, ModelOutput
class MyModelAdapter(BaseProteinModel):
def load(self) -> None:
# Load model weights
pass
def tokenize(self, sequences):
# Tokenize sequences
pass
def get_embeddings(self, sequences, pooling="mean"):
# Extract embeddings
pass
procap/models/registry.py:from procap.models.my_model import MyModelAdapter
DEFAULT_MODELS["my_model"] = {
"class": MyModelAdapter,
"params": {"variant": "my_variant", "max_batch_size": 8},
}