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

[![StapleBridge framework: feasible stapling plans, exact finite-support control target, and plan execution](figure/framework.png)](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. -->