File size: 12,818 Bytes
ff4cd76 ee6da62 7c8f828 4bb2309 ee6da62 7d3c9bf ee6da62 5e88b4f ee6da62 7d3c9bf ee6da62 7d3c9bf ee6da62 7d3c9bf ee6da62 7d3c9bf ee6da62 7d3c9bf ee6da62 8d43f08 ee6da62 7d3c9bf ee6da62 7d3c9bf ee6da62 7d3c9bf ee6da62 7d3c9bf ee6da62 bcc72b5 7d3c9bf ee6da62 | 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 | <h1 align="center">
TD3B: Transition-Directed Discrete Diffusion for Allosteric Binder Generation
</h1>
<div align="center">
<a href="https://arxiv.org/abs/2605.09810"><img src="https://img.shields.io/badge/Arxiv-2605.09810-red?style=for-the-badge&logo=Arxiv" alt="arXiv"/></a>
</div>

TD3B is a sequence-based generative framework that designs peptide binders with specified agonist or antagonist behavior. It combines a Direction Oracle, a soft binding-affinity gate, and amortized fine-tuning of a pre-trained discrete diffusion model (MDLM).
> **Development release.** This repository (`ChatterjeeLab/TD3B-dev`) carries the full code. The heavy artifacts β trained checkpoints, training/test data, and generated binders β are distributed as a single archive on Google Drive (see [Data and Checkpoints](#data-and-checkpoints)). For the clean code-only release see [`ChatterjeeLab/TD3B`](https://huggingface.co/ChatterjeeLab/TD3B).
## Installation
```bash
conda env create -f env.yml
conda activate td3b
pip install -e .
```
## Demo
An interactive inference demo is provided in [`notebooks/TD3B_Inference_Demo.ipynb`](notebooks/TD3B_Inference_Demo.ipynb) (configured for a Colab T4 GPU).
[](https://colab.research.google.com/)
To run it: download the notebook from this repository, open [Google Colab](https://colab.research.google.com/), upload it via **File β Upload notebook**, and select a GPU runtime (**Runtime β Change runtime type β T4 GPU**).
## Data and Checkpoints
The checkpoints, datasets, and generated binders are bundled in a single archive on Google Drive:
**Download:** [`td3b_dev_artifacts.zip`](https://drive.google.com/file/d/1EU0-pcF-UoEb0OEMuO4qhodZ5RjMU4n9/view?usp=sharing) (~3.4 GB)
Unzip it at the repository root to restore the full layout:
```bash
unzip td3b_dev_artifacts.zip -d .
```
```
TD3B-dev/
βββ checkpoints/
β βββ pretrained.ckpt # Pre-trained MDLM weights (1.4 GB)
β βββ td3b.ckpt # Fine-tuned TD3B model (231 MB)
β βββ direction_oracle.pt # Direction Oracle weights (2.85 GB)
βββ scoring/functions/classifiers/
β βββ binding-affinity.pt # (from archive)
β βββ permeability-xgboost.json # (from archive)
β βββ hemolysis-xgboost.json # (in repo)
β βββ nonfouling-xgboost.json # (in repo)
β βββ solubility-xgboost.json # (in repo)
βββ data/
β βββ train.csv # Training set (target-binder pairs)
β βββ test.csv # Test set
β βββ td3b_data_new.csv # Full labeled target/ligand pairs (agonist/antagonist)
βββ generated_binders/
βββ agonist/ # 1106 generated agonist binders (.pdb + .trb), 249 targets
βββ antagonist.tar.gz # Generated antagonist binders
```
## Code Structure
```
TD3B/
βββ inference.py # Generate binders (main inference entry point)
βββ finetune_on_target.py # Finetune on your own target(s) + generate (Function A)
βββ generate_valid.py # Validity-boosting sampling CLI (Function B)
βββ sampling_strategies.py # Validity-boosting sampler library (Function B)
βββ finetune_multi_target.py # Multi-target TD3B training
βββ launch_multi_target.sh # Training launcher script
βββ models/
β βββ diffusion.py # MDLM backbone (TR2-D2)
β βββ roformer.py # RoFormer wrapper
β βββ noise_schedule.py # Noise schedules
βββ training/
β βββ finetune_utils.py # Training utilities
β βββ distributed_utils.py # Distributed training helpers
βββ mcts/
β βββ peptide_mcts.py # MCTS tree search
βββ td3b/
β βββ direction_oracle.py # Direction Oracle (f_Ο)
β βββ td3b_scoring.py # Gated reward R = g_Ο Β· Ο(d*Β·(f_Οβ0.5)/Ο)
β βββ td3b_losses.py # L_WDCE + λ·L_ctr + Ξ²Β·L_KL
β βββ td3b_mcts.py # TD3B-extended MCTS
β βββ td3b_finetune.py # Training loop
β βββ data_utils.py # Data loading utilities
βββ scoring/ # Affinity predictor (g_Ο) and property classifiers
βββ baselines/ # CG, SMC, TDS, PepTune, Unguided baselines
βββ tokenizer/ # SMILES tokenizer (vocab + splits)
βββ configs/ # Model and training configs
βββ utils/ # Misc utilities
```
## Inference
Generate agonist/antagonist binders for target proteins:
```bash
python inference.py \
--ckpt_path checkpoints/td3b.ckpt \
--val_csv data/test.csv \
--save_path results/ \
--seed 42 \
--num_pool 32 \
--val_samples_per_target 8 \
--resample_alpha 0.1
```
This generates 32 candidates per (target, direction), scores them with the Direction Oracle and affinity predictor, applies Algorithm 2 weighted resampling, and saves only valid peptide samples.
> **Generation length matters.** The length (in SMILES tokens) comes from `--seq_length` if given, else it is
> derived from each row's reference binder (correctly tokenized). This released checkpoint reliably produces
> **valid** SMILES only at **short lengths (β²100 tokens)**; long binders (e.g. 25β30-residue peptides β 150β210
> tokens) yield few or no valid samples regardless of step count. For non-empty output on such targets, pass a
> shorter `--seq_length` and a validity-boosting sampler (see below), e.g.:
> ```bash
> python inference.py --ckpt_path checkpoints/td3b.ckpt --val_csv data/test.csv \
> --seq_length 50 --sampler best_of_n --best_of_n 6 --num_pool 32 --val_samples_per_target 4
> ```
> On a real run this yields valid, oracle-scored binders in both directions (antagonist direction accuracy β 1.0).
Output: `results/td3b_results_seed42.csv` with columns: target, target_uid, sequence, direction_name, target_direction, is_valid, affinity, gated_reward, direction_oracle, direction_accuracy.
## Finetune on your own target(s)
`finetune_on_target.py` takes protein target(s) you supply, finetunes the pretrained TD3B policy on **only those target(s)**, then generates directional (agonist/antagonist) binders for them. It reuses the existing machinery: the finetune half subprocess-invokes `finetune_multi_target.py` (with `K` set to the number of targets), and the generation half runs in-process with the same reward, oracle, and Algorithm 2 resampling as `inference.py`.
```bash
python finetune_on_target.py \
--target_seq MKTAYIAKQRQISFVKSHFSRQLEERLGLIEVQ \
--target_seq GSHMKELVLALYDYQEKSPREVTMKKGDILTLL \
--direction both \
--validity_reward on \
--num_epochs 20 \
--num_pool 32 \
--gen_samples_per_target 8 \
--device cuda:0 --seed 42
```
Provide targets by repeating `--target_seq` and/or via `--targets_csv` (a CSV with a `Target_Sequence` column; optional `Ligand_Sequence`/`label` rows seed the per-direction length prior):
```bash
python finetune_on_target.py --targets_csv my_targets.csv --direction agonist --binder_length 20
```
Key flags:
- `--target_seq SEQ` (repeatable) and/or `--targets_csv` β provide at least one target.
- `--direction {agonist,antagonist,both}` (default `both`) β which binders to **generate**. Finetuning always searches both directions.
- `--validity_reward {on,off}` (default `on`) β validity gate applied to **both** halves. `on` keeps the `is_peptide` filter (invalid MCTS children are zero-rewarded during finetuning; only valid peptides are eligible for resampling during generation). `off` drops the gate on both halves (invalid samples are retained, each row keeps `is_valid`); the reward itself is always affinity Γ direction β validity is only ever a filter, never part of the reward formula. `--finetune_validity_hook {on,off}` overrides just the finetune-side gate.
- `--binder_length` (default 20) β placeholder binder length (residues) used to seed the generation-length prior for any target with no known binder.
- `--skip_finetune` (generate directly from `--td3b_checkpoint`) / `--skip_generate` (finetune only).
- Training knobs: `--num_epochs` (20), `--num_iter` (10) / `--num_children` (16) (MCTS), `--learning_rate` (3e-4), `--seq_length` (200). Generation knobs: `--num_pool` (32), `--gen_samples_per_target` (8), `--resample_alpha` (0.1), `--total_num_steps` (128).
- Paths default to the repo root; override `--pretrained_checkpoint`, `--direction_oracle_ckpt`, `--output_dir`, `--device` (`auto`/`cpu`/`cuda:N`), `--seed` as needed.
Output: `results/finetune_on_target/binders_<direction>_validity-<on|off>_seed<seed>.csv` with columns target, sequence, direction_name, target_direction, is_valid, affinity, gated_reward, direction_oracle, direction_accuracy, gen_length. The finetuned checkpoint is written under `results/<run_name>_<timestamp>/` (used automatically for the generation half).
## Higher-validity sampling for long binders
As the target length grows, the fraction of decoded SMILES that pass the RDKit peptide check drops. `generate_valid.py` (backed by `sampling_strategies.py`) applies **sampling-time** strategies β no retraining β to raise the valid-peptide yield, especially at large length, and reports the valid fraction. The strategies only change token selection (temperature / top-k / top-p) and add a remask self-correction loop and best-of-N rejection on top of the model's existing diffusion primitives.
```bash
python generate_valid.py \
--ckpt_path checkpoints/td3b.ckpt \
--length 400 --num_samples 64 \
--strategy nucleus_remask \
--device cuda:0 --seed 42 \
--save_path results/valid_len400.csv
```
Key flags:
- `--strategy` (default `nucleus_remask`) β one of `baseline`, `more_steps`, `top_p` (a.k.a. `nucleus`), `top_k`, `low_temp`, `remask`, `best_of_n`, `nucleus_remask`. On random-init benchmarks the self-correcting strategies (`remask`, `best_of_n`, `nucleus_remask`) give the largest relative validity gains at length β₯ 200; `nucleus_remask` is the recommended default.
- `--length` (default 200, in tokens) and `--num_samples` (default 64).
- `--ckpt_path` β TD3B checkpoint. If omitted or missing, a **random-init** model is used (exercises the sampling machinery only; yields are meaningless β pass a real checkpoint for real numbers).
- Per-strategy overrides (else the preset default is used): `--top_p`, `--top_k`, `--temperature`, `--steps_per_token`, `--remask_rounds`, `--remask_frac`, `--remask_steps`, `--best_of_n`, `--num_steps`.
Output: prints the valid yield (valid / `num_samples`) with per-round counts, and writes the valid sequences to `--save_path` (default `results/valid_<strategy>_len<L>.csv`) with columns idx, sequence, n_chars.
## Training
### Multi-target TD3B
1. Edit `launch_multi_target.sh` only if needed β `BASE_PATH` auto-detects the repo root (this script's own directory), and the checkpoint, data, and oracle paths derive from it:
```bash
BASE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # auto-detects the repo root
PRETRAINED_CHECKPOINT="${BASE_PATH}/checkpoints/pretrained.ckpt"
TRAIN_CSV="${BASE_PATH}/data/train.csv"
ORACLE_CKPT="${BASE_PATH}/checkpoints/direction_oracle.pt"
```
`finetune_multi_target.py --base_path` also defaults to the repo root, so you only need to override these when your checkpoints or data live elsewhere.
2. Launch training:
```bash
bash launch_multi_target.sh
```
Key hyperparameters (in `launch_multi_target.sh`):
- `CONTRASTIVE_WEIGHT=0.1` β Ξ» for L_ctr
- `KL_BETA=0.1` β Ξ² for L_KL
- `SIGMOID_TEMPERATURE=0.1` β Ο for gated reward
- `NUM_ITER=20` β MCTS iterations per round
- `NUM_CHILDREN=16` β Children per MCTS expansion
### Baselines
Run baseline methods (CG, SMC, TDS, PepTune, Unguided):
```bash
cd baselines/
bash run.sh --baseline cg --device cuda:0
bash run.sh --baseline smc --device cuda:0
bash run.sh --baseline tds --device cuda:0
```
## Citation
```bibtex
@inproceedings{
cao2026tdb,
title={{TD}3B: Transition-Directed Discrete Diffusion for Allosteric Binder Generation},
author={Hanqun Cao and Aastha Pal and Sophia Tang and Yinuo Zhang and Jingjie Zhang and Pheng-Ann Heng and Pranam Chatterjee},
booktitle={Learning Meaningful Representations of Life (LMRL) Workshop at ICLR 2026},
year={2026},
url={https://openreview.net/forum?id=uMUicLylVp}
}
```
|