File size: 13,888 Bytes
bb6d2aa 65b3f9d bb6d2aa | 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 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 | # StapleBridge
Official training code for **StapleBridge**, a chemistry-aware framework for optimizing existing peptide leads through hydrocarbon stapling.
StapleBridge constructs a finite set of chemically and geometrically feasible stapling interventions for each peptide, learns to rank these interventions, and executes the selected plan with minimal sequence edits.
This repository contains the **main StapleBridge training pipeline** and **one representative pretrained checkpoint**.
## Framework
[](figure/framework.pdf)
---
## 1. What is included
The code required to **train the main StapleBridge model**, and one
representative pretrained checkpoint.
```
release/staplebridge_training/
βββ README.md
βββ THIRD_PARTY_NOTICES.md
βββ requirements.txt
βββ .gitignore
βββ configs/
β βββ staplebridge_main.yaml # configuration used for the checkpoint
βββ scripts/
β βββtrain.py # canonical training entry point
βββ staplebridge/
β βββ chemistry/ # design state, actions, edit distance
β βββ data/ # split loading, schemas, catalog, vocab
β βββ hydrocarbon/ # plans, catalog, q_ref, q*, q_theta, geometry
β βββ models/ # policy / value nets, controlled kernel
β βββ oracles/ # ESM2 + anchor/block reference priors
β βββ reference/ # reference energy and kernel
β βββ training/ # stack construction, main loop, losses
β βββ integrations/ # PeptiVerse wrapper
β βββ utils/ # paths, profiling
βββ data/
β βββ README.md # expected input schema and file layout
βββ checkpoints/
βββ staplebridge_seed42_best.pt # representative seed=42 model
```
The training code in `staplebridge/training/` is numerically identical to the
run that produced the shipped checkpoint.
<!-- ## 2. What is intentionally not included
This release covers **training only**. Not included:
- Baseline and ablation implementations, and their checkpoints.
- Alternative stapling chemistries.
- Downstream and post-hoc evaluation pipelines, including the test-set
evaluator, structural and docking analyses, and permeability benchmarking.
- Analysis, figure-generation and manuscript material.
- Training outputs: logs, cached predictions, intermediate checkpoints.
- **Processed training and validation data** β see Β§5; these will be handled
separately.
One checkpoint is shipped: the representative seed=42 model.
Reproducing the paper's *evaluation* numbers requires the evaluation pipelines,
which are outside this release. What is here reproduces *training*. -->
## 2. Environment setup
The released checkpoint was trained under:
| | Version |
| --- | --- |
| Python | 3.10.20 |
| PyTorch | 2.12.1+cu130 (CUDA 13.0) |
| NumPy | 2.0.2 |
| PyYAML | 6.0.3 |
| RDKit | 2026.03.5 |
| transformers | 4.46.0 |
```bash
python -m venv .venv && source .venv/bin/activate
# Install torch first, matched to your CUDA build: https://pytorch.org
pip install -r requirements.txt
```
<!-- StapleBridge's own model is small (~142k parameters total) and runs on CPU. A
GPU is needed in practice because the frozen ESM2-650M prior and the PeptiVerse
oracles are invoked per candidate. Set the device in one place β the config
requires `training.device`, `property_predictor.device` and
`reference_priors.peptide.device` to agree, and `check_config.py` enforces it. -->
## 3. External model dependencies
**No third-party model weights are bundled.** Four external resources must be
provided and referenced from the config: the ESM2-650M snapshot, the PeptiVerse
distribution, and the two SMILES encoders PeptiVerse depends on. Paths may be
absolute, or relative to the package root.
### ESM2-650M (frozen sequence context)
`facebook/esm2_t33_650M_UR50D`, used frozen β never fine-tuned. It supplies the
reference-process peptide prior and the V2 plan head's anchor/local-context
features. It is also the feature source for the plan head, which refuses to
build without it.
```bash
huggingface-cli download facebook/esm2_t33_650M_UR50D \
--local-dir models/esm2_t33_650M_UR50D
```
Then set, in `configs/staplebridge_main.yaml`:
```yaml
reference_priors:
peptide:
model_name_or_path: models/esm2_t33_650M_UR50D
property_predictor:
esm_model_name_or_path: models/esm2_t33_650M_UR50D
```
The config runs the prior with `offline: true` and `strict_runtime: true`, so the
snapshot must already be on disk; training fails fast rather than downloading or
silently substituting a fallback. Licensed by Meta under the ESM2 terms.
### PeptiVerse (property oracles)
The main training objective optimises the PeptiVerse
permeability-penetrance E/Z product mean. Obtain the PeptiVerse checkout and its
classifier weights separately, then set:
```yaml
property_predictor:
peptiverse_root: external/PeptiVerse
classifier_weight_root: external/PeptiVerse
manifest_path: external/PeptiVerse/basic_models.txt
```
Scoring is **strict**: `strict: true`, `enable_fallback: false`,
`allow_wt_token_fallback: false`. If the oracle stack cannot load, training
aborts β it never degrades to a heuristic.
Toxicity, hemolysis and half-life are monitored only. Solubility and binding
affinity are excluded from the objective.
### PeptideCLM-23M and ChemBERTa-77M (required)
The `basic_models.txt` manifest selects predictors embedded with PeptideCLM and
ChemBERTa, so **both are required** β not optional. The permeability-penetrance
predictor that defines the objective is itself ChemBERTa-embedded. Loading fails
fast without them.
```bash
huggingface-cli download aaronfeller/PeptideCLM-23M-all \
--local-dir models/PeptideCLM-23M-all
huggingface-cli download DeepChem/ChemBERTa-77M-MLM \
--local-dir models/ChemBERTa-77M-MLM
```
```yaml
property_predictor:
peptideclm_model_name_or_path: models/PeptideCLM-23M-all
chemberta_model_name_or_path: models/ChemBERTa-77M-MLM
```
`scripts/check_config.py` verifies all four before training starts.
## 4. Data
**The processed training and validation data are not included in this release**
and will be handled separately. No preprocessing, download or reconstruction
utilities are provided.
Training reads two JSON Lines files, resolved from the config:
```
data/real/ # data.root
βββ train.jsonl # data.train_file
βββ valid.jsonl # data.valid_file
```
See [`data/README.md`](data/README.md) for the expected input schema β in
particular the required per-residue CΞ± coordinates, which staple-geometry
feasibility depends on.
The reference protocol uses 4020 training and 111 validation leads;
`scripts/check_config.py` asserts those counts, so substituting a differently
sized dataset requires relaxing the check.
## 5. Training command
```bash
python scripts/train.py \
--config configs/staplebridge_main.yaml \
--out-dir outputs/main_seed42
```
<!-- `check_config.py` is read-only: it verifies the configuration and the presence of
the external assets without loading a model or training. Run it first β it turns
a misconfiguration into an immediate error rather than a failure hours in.
The CLI is intentionally small β **seed (42) and device come from the config**,
not from flags, so a run cannot silently diverge from the recorded protocol.
`--resume <checkpoint>` restores model, optimizer and RNG state so the remaining
epochs match an uninterrupted run. `train.py` refuses to start in a non-empty
`--out-dir`.
Written to `--out-dir`: `resolved_config.yaml`, `metrics.jsonl` (per-epoch),
`run_summary.json`, per-epoch validation summaries, and
`checkpoints/{best_kl,best_pv,latest,epoch_NNN}.pt`. **`best_kl.pt` is the
selected model** β see Β§7. -->
<!-- ## 7. Main reproducibility settings
Read from `configs/staplebridge_main.yaml` and asserted by
`scripts/check_config.py`:
| Setting | Value |
| --- | --- |
| Splits | `train.jsonl` (4020) / `valid.jsonl` (111), full validation every epoch |
| Seed | 42 |
| Epochs | 10, no early stopping (all 10 always run) |
| Horizon | 8 (training and validation must match) |
| Max neighboring actions | 128 |
| Chunk size | 32 |
| Committed plans per lead | 4 |
| `beta` (Exact-SB) | 1.0 |
| Plan-loss weight | 1.0 |
| Plan head | hidden dim 128, frozen ESM2-650M features |
| Objective | `permeability_penetrance`, E/Z product mean, neutral-canonical SMILES |
| Monitored only | toxicity, hemolysis, half-life |
| Excluded | solubility, binding affinity |
| PeptiVerse | strict SMILES mode, all fallbacks disabled |
| Catalog | hydrocarbon only (`include_optional: false`): S5-S5/i,i+4 and R8-S5/i,i+7 |
| Hard constraints | chemistry + geometry + edit budget 6.0, min sequence identity 0.6, protected edits forbidden, exact committed-plan completion |
| Decoding | strict hierarchical plan-first (`hierarchical_plan_ranking: true`) |
| **Checkpoint selection** | **minimum validation `q_star_vs_q_theta_kl`**, guarded by `require_both_topologies` |
Optimizer: Adam, lr 1e-3, grad-norm clip 1.0.
### Checkpoint selection
The rule is: the epoch minimising `KL(q* β q_theta)` on the full 111-lead
validation split, among epochs where both staple topologies appear in the
selected candidates. Validation permeability and the test split play no part in
selecting it.
For the shipped checkpoint that rule chose **epoch 9**, validation
`q_star_vs_q_theta_kl = 0.081568` β the minimum over all 10 epochs (epoch 10 rose
to 0.082585). `train.py` also maintains `best_pv.pt` by validation
delta-penetrance for monitoring; it is **not** the selected model and is not
shipped.
## 8. Checkpoint loading
`checkpoints/staplebridge_seed42_best.pt` is the `best_kl.pt` of the seed=42
training run, copied byte-for-byte with weights unmodified
(sha256 `22d273164a3132d43617c51649947028f11859f90ca0bee28540edc9ad62a298`).
Verify it loads against this package's model definitions: -->
<!-- ```bash
python scripts/smoke_test.py
```
This checks imports, config, model construction and a strict checkpoint load
(zero missing / unexpected keys). It is not an evaluation suite.
Minimal manual load:
```python
import torch, yaml
from staplebridge.hydrocarbon.plan_control import build_hydrocarbon_plan_head
from staplebridge.models.policy_net import PolicyNet
from staplebridge.models.value_net import ValueNet
config = yaml.safe_load(open("configs/staplebridge_main.yaml"))
emb_dim = int(config["model"]["emb_dim"])
ckpt = torch.load("checkpoints/staplebridge_seed42_best.pt",
map_location="cpu", weights_only=False)
policy = PolicyNet(emb_dim=emb_dim)
value = ValueNet(emb_dim=emb_dim)
policy.load_state_dict(ckpt["policy_state_dict"]) # strict, exact match
value.load_state_dict(ckpt["value_state_dict"])
print("epoch:", ckpt["epoch"]) # -> 9
```
The plan head is the one component that cannot be built without the frozen
ESM2-650M prior β it refuses a stand-in by design, so training can never
silently substitute a different context model:
```python
from staplebridge.training.stack import build_stack
stack = build_stack(config, seed=42) # requires ESM2 on disk
head = build_hydrocarbon_plan_head(config, emb_dim, "cpu",
esm2_prior=stack["reference_priors"].peptide)
head.load_state_dict(ckpt["plan_head_state_dict"])
```
Checkpoint payload: `policy_state_dict` (20 tensors), `value_state_dict` (20),
`plan_head_state_dict` (6), plus non-model metadata β `epoch`, the full resolved
`config`, `plan_control_enabled`, `optimizer_state_dict`, and RNG state
(`plan_rng_state`, `python_random_state`, `numpy_random_state`,
`torch_rng_state`, `cuda_rng_state_all`). The optimizer and RNG entries exist so
`--resume` can continue a run bit-identically; they are not model weights.
## 9. Reproducibility note
- **Seed.** Fixed at 42 in the config and applied to Python, NumPy and Torch
(including all CUDA devices). Plan sampling uses its own seeded
`random.Random(42)`, checkpointed so `--resume` continues the same stream.
- **Determinism.** `torch.use_deterministic_algorithms(False)`, matching the
reference run. Results are therefore **device- and version-dependent**: a
different GPU model, CUDA version, or PyTorch build can shift metrics
slightly. Exact bit-level reproduction requires the environment in Β§3.
- **External models.** The frozen ESM2-650M snapshot and the PeptiVerse
classifier stack are part of the training objective. Different versions of
either change the optimisation target and will not reproduce these numbers.
- **Caches.** Training maintains a persistent ESM2 prior cache and an exact-SB
target cache (SQLite, under `outputs/cache/`). These are pure speedups β
deterministic values keyed by content β and do not change results.
- **Cost.** 10 epochs over 4020 leads with full 111-lead validation each epoch.
The reference run totalled about 3.9 h of epoch time on one GPU (~16 GiB peak).
Cache warming dominates the first epoch β 4964 s, against 760-890 s for later
epochs once the ESM2 and exact-SB caches are populated.
- **Scale guard.** `train.py` hard-asserts `train_n == 4020` and `epochs == 10`,
so the protocol cannot be shrunk by editing the config alone.
## License
See [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md) for third-party
components. A license for the StapleBridge code itself has not yet been
selected; add a `LICENSE` file before publishing. -->
|