--- license: mit tags: - protein - small-molecule - affinity-prediction - hit-to-lead - qsar - boltz - structure-based - capo metrics: - pearsonr - spearmanr model-index: - name: capo-hit-to-lead-ft-binding-boltz-20260706-1111-cd08-best results: - task: type: regression name: Hit-to-lead affinity ranking (FEP benchmark, held-out batch) metrics: - type: pearsonr value: 0.7396 name: All-targets mean log-Pearson r (15 valid targets) - type: spearmanr value: 0.7000 name: All-targets mean Spearman r (15 valid targets) --- # CAPO · Hit-to-lead affinity head on frozen Boltz-2 A **per-target-calibrated QSAR affinity head** that turns [Boltz-2](https://github.com/jwohlwend/boltz) co-folding outputs into a **calibrated potency ranking** for hit-to-lead. Boltz-2 weights are **frozen** — this is "fine-tuning to the assay" by calibration on measured `batch_1` potencies, not gradient training. That is precisely why 549 cached co-folds from a prior run could be reused at 0 GPU-hours. Produced by **CAPO** (Compute-Aware Automated Protein-Model Optimization), run `binding-boltz-20260706-1111-cd08`. This repo contains the **best** checkpoint only. ## What this is (and is not) - **Is:** a light regression head (`affinity_head.pkl`) + per-target calibration that predicts log₁₀-potency from features derived from a Boltz-2 co-fold of a protein–ligand complex. - **Is not:** a standalone folding/affinity model. It **requires Boltz-2** to generate structural features for any new ligand, and no Boltz-2 weights are included or modified. ## Features consumed by the head Per protein–ligand complex (`affinity_head_manifest.json`): - **Ligand:** ECFP4 fingerprint (radius 2, 1024 bits) + RDKit descriptors (MolWt, MolLogP, TPSA, NumHDonors, NumHAcceptors, NumRotatableBonds, NumAromaticRings, FractionCSP3). - **Boltz-2 signals:** affinity_pred_value, affinity_probability_binary, ptm, iptm, complex_plddt, complex_pde. - **Contacts:** contacts_4A, contacts_5A, contact_residues, buried_frac. ## Task & data Hit-to-lead affinity ranking on a FEP-style benchmark spanning **29 drug targets** (bace, cdk2, tyk2, shp2, mcl1, eg5, p38, …). Given `batch_1` measured potencies per target, rank a held-out `batch_2`. **644 complexes** were co-folded (549 reused + 96 new). The intended headline was to show `classical-ML < raw Boltz-2 << CAPO` on the regime that is hard for **both** baselines. ## Evaluation All-target mean over the **15 targets** that yielded valid ranking metrics (`results/analysis/summary.json`): | Metric (log₁₀ µM) | This model (CAPO) | Raw Boltz-2 | Classical ML | |---|---:|---:|---:| | log-Pearson r | **0.7396** | 0.6227 | 0.6416 | | Spearman r | **0.7000** | 0.5936 | 0.6162 | | RMSE | **0.5588** | 1.0611 | — | Calibration improves ordering and **nearly halves RMSE vs raw Boltz-2** — its main win is fixing magnitude. The `classical < Boltz < CAPO` ordering holds on the all-target log-Pearson average. ## ⚠️ Important caveats - **Pre-registered headline is unresolved.** The "hard-for-both" filter (raw-Boltz Spearman < 0.30 **and** classical LOO < 0.20, `loo_min_n = 8`) selected **zero targets** (`headline_hard_for_both_targets: []`). The primary claim was never testable on this benchmark — thresholds were too strict. - **14 / 29 targets returned NaN** ranking metrics from sparse `batch_2` / too-few ligands; only 15 targets contribute to the average above. - Sparse ligand counts can drive negative per-target correlations (e.g. hsp90 Spearman −0.80). Trust the pooled average over any single sparse target. ## Files - `affinity_head.pkl` — the calibrated QSAR affinity head (~23 MB). - `affinity_head_manifest.json` — feature spec, seed, per-target detail, versions (Python 3.10.12). - `config.json` — `{strategy: "custom_frozen_boltz2_calibrate_qsar", model_id: "custom", n_targets: 29}`. - `metrics.json` — full pre-registration table + thresholds + per-target results. ## How to use ```python import pickle from huggingface_hub import hf_hub_download REPO = "theoschiff-biie/capo-hit-to-lead-ft-binding-boltz-20260706-1111-cd08-best" head = pickle.load(open(hf_hub_download(REPO, "affinity_head.pkl"), "rb")) # 1. Co-fold each protein–ligand pair with Boltz-2 (frozen). # 2. Build the feature vector per the ECFP4 + RDKit + Boltz-2 + contact spec in # affinity_head_manifest.json (feature order must match training). # 3. head.predict(X) -> calibrated log10-potency; rank within a target to lead-rank. ``` Reproduce feature extraction with the CAPO run's `src/` pipeline; the manifest is the authoritative feature contract. ## Provenance - **CAPO run:** `binding-boltz-20260706-1111-cd08` (`RUN_REPORT.md` in the run dir). - **Model selection:** bypassed — user-specified custom frozen-Boltz-2 pipeline. - **Cost gate:** projected $10.61 vs $75 cap on 1× A100-SXM4 @ $1.99/h. - **Cost:** infra $3.35 (1h 57m); total run $22.09. Reuse of 549 co-folds at 0 GPU-h. - **Push:** `checkpoints/best/` only (private). `checkpoints/last/` retained locally, not pushed. *License follows the Boltz-2 base model (MIT).*