YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
TD3B: Transition-Directed Discrete Diffusion for Allosteric Binder Generation
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). For the clean code-only release seeChatterjeeLab/TD3B.
Installation
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 (configured for a Colab T4 GPU).
To run it: download the notebook from this repository, open Google Colab, 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 (~3.4 GB)
Unzip it at the repository root to restore the full layout:
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:
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_lengthif 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_lengthand a validity-boosting sampler (see below), e.g.: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 4On 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.
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):
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}(defaultboth) β which binders to generate. Finetuning always searches both directions.--validity_reward {on,off}(defaulton) β validity gate applied to both halves.onkeeps theis_peptidefilter (invalid MCTS children are zero-rewarded during finetuning; only valid peptides are eligible for resampling during generation).offdrops the gate on both halves (invalid samples are retained, each row keepsis_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),--seedas 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.
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(defaultnucleus_remask) β one ofbaseline,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_remaskis 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
- Edit
launch_multi_target.shonly if needed βBASE_PATHauto-detects the repo root (this script's own directory), and the checkpoint, data, and oracle paths derive from it:
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.
- Launch training:
bash launch_multi_target.sh
Key hyperparameters (in launch_multi_target.sh):
CONTRASTIVE_WEIGHT=0.1β Ξ» for L_ctrKL_BETA=0.1β Ξ² for L_KLSIGMOID_TEMPERATURE=0.1β Ο for gated rewardNUM_ITER=20β MCTS iterations per roundNUM_CHILDREN=16β Children per MCTS expansion
Baselines
Run baseline methods (CG, SMC, TDS, PepTune, Unguided):
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
@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}
}
