ouroboros / source /scripts /benchmark_metrics.py
REXWind's picture
Publish the Ouroboros scientific showcase to CladeTeam
03677d0 verified
Raw History Blame Contribute Delete
3.16 kB
"""Aggregate additional archived text-to-protein benchmark metrics."""
import csv
import hashlib
import json
from collections import defaultdict
from pathlib import Path
from statistics import mean
MODEL_FILES = {
'Ouroboros': ('large_newds_v5_esmif.json', 'ours_hard1_esmif.json'),
'Pinal-1.2B': ('pinal1p2b_esmif.json', 'pinal1p2b_hard1_esmif.json'),
'Pinal-15B': ('pinal15b_esmif.json', 'pinal15b_hard1_esmif.json'),
'ESM-3': ('esm3_esmif.json', 'esm3_hard1_esmif.json'),
'ProteinDT': ('proteindt_esmif.json', 'proteindt_hard1_esmif.json'),
'Chroma': ('chroma_newds_esmif.json', 'chroma_hard1_esmif.json'),
'ProtDAT': ('protdat_esmif.json', 'protdat_hard1_esmif.json'),
}
DATASET = {'id': 'swissprot_time_cutoff', 'name': 'Swiss-Prot time-cutoff',
'pairs': 500, 'keywordScoredPairs': 476,
'sourceSplits': ['hard1', 'hard']}
def time_cutoff_metrics(metrics):
"""Publish only the 500-pair temporal cohort; retain measured means and n."""
return [dict(row, split=DATASET['id']) for row in metrics
if row['split'] in {'hard', 'hard1', DATASET['id']}]
def augment(metrics, paper, project, provenance):
def source(path):
raw = path.read_bytes()
provenance.append({'file': str(path.relative_to(project)), 'sha256': hashlib.sha256(raw).hexdigest()}
if path.is_relative_to(project) else
{'file': str(path.relative_to(paper)), 'sha256': hashlib.sha256(raw).hexdigest()})
return raw
metrics = [r for r in metrics if r['metric'] not in {'PAE', 'ProTrek score', 'Keyword recovery', 'Inverse folding recovery', 'Inverse folding SW'}]
for filename in ('protrek_score.csv', 'keyword_recovery.csv'):
path = paper / 'figures/text2prot/source_data' / filename
grouped = defaultdict(list)
for row in csv.DictReader(source(path).decode('utf-8-sig').splitlines()):
if row['split'] in {'hard', 'hard1'} and row['model'] not in {'Ground Truth', 'Random'}:
grouped[(row['metric'], row['split'], row['model'].replace('Ours (large)', 'Ouroboros'))].append(float(row['value']))
for (metric, split, model), scores in grouped.items():
metrics.append({'task': 't2p', 'metric': metric, 'split': split, 'model': model,
'n': len(scores), 'mean': mean(scores)})
folders = {
'hard1': project / 'prot_downstream/text2prot/results/inverse_folding',
}
for split, folder in folders.items():
for model, filenames in MODEL_FILES.items():
rows = json.loads(source(folder / filenames[split == 'hard1']))
assert len(rows) == (500 if split == 'hard1' else 100)
for label, key in [('Inverse folding recovery', 'recovery'), ('Inverse folding SW', 'sw_similarity')]:
scores = [float(r[key]) for r in rows]
assert len(scores) == len(rows)
metrics.append({'task': 't2p', 'metric': label, 'split': split, 'model': model,
'n': len(scores), 'mean': mean(scores)})
return time_cutoff_metrics(metrics)