Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

355 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

proteinFM

A protein foundation model framework integrating and extending UniMoMo for protein-ligand design with Mixture-of-Transformers (MoT) architecture.

Quick Links


Table of Contents

  1. Training
  2. Inference
  3. Evaluation
  4. Configuration Reference
  5. Extended JSONL Format
  6. Environment Setup

Training

Quick Start Training

Single GPU:

python src/lmms_engine/models/bagel_protein/train/train_bagel_protein.py \
    --config src/lmms_engine/models/bagel_protein/config/train_bagel_protein_antibody_dual_leakage.yaml

Multi-GPU (8 GPUs):

torchrun --nproc_per_node=8 --nnodes=1 --node_rank=0 \
    --master_addr=127.0.0.1 --master_port=12355 \
    src/lmms_engine/models/bagel_protein/train/train_bagel_protein.py \
    --config src/lmms_engine/models/bagel_protein/config/train_bagel_protein_antibody_dual_leakage.yaml

Hyperparameter Sweep Script

The recommended way to train is using the hyperparameter sweep script, which automatically generates output directories and saves modified configs:

./src/lmms_engine/models/bagel_protein/train/train_hyperparameter_sweep.sh [OPTIONS]

Common Examples:

# Basic training with default parameters (8 GPUs)
./src/lmms_engine/models/bagel_protein/train/train_hyperparameter_sweep.sh

# Custom learning rates
./src/lmms_engine/models/bagel_protein/train/train_hyperparameter_sweep.sh \
    --diffusion_lr 5.0e-5 \
    --understanding_lr 1.0e-5

# Train from antibody-scratch checkpoint
./src/lmms_engine/models/bagel_protein/train/train_hyperparameter_sweep.sh --abscratch

# Freeze understanding model (only train diffusion)
./src/lmms_engine/models/bagel_protein/train/train_hyperparameter_sweep.sh --no-train-understanding

# Resume from checkpoint
./src/lmms_engine/models/bagel_protein/train/train_hyperparameter_sweep.sh \
    --resume ./output/bagel_protein_dual_leakage_diff4_bs8_ga8_dlr1e-4_ulr1e-4_ep300_pretrained

# Enable Weights & Biases logging
./src/lmms_engine/models/bagel_protein/train/train_hyperparameter_sweep.sh \
    --wandb_project bagel_protein \
    --wandb_run_name experiment_1

Full Options:

Option Description Default
--num_iter_per_und INT Diffusion iterations per understanding step 4
--diffusion_lr FLOAT Diffusion model learning rate 1.0e-4
--understanding_lr FLOAT Understanding model learning rate 1.0e-4
--gradient_accumulation INT Gradient accumulation steps 8
--batch_size INT Per-device train batch size 8
--num_train_epochs INT Number of training epochs 300
--abscratch Use antibody-scratch checkpoint false
--no-train-understanding Freeze understanding model false
--training_mode MODE joint, generation_only, understanding_only from config
--answer_only_qkv DEBUG: Use answer-only for QKV (no thinking) false
--num_gpus INT Number of GPUs 8
--master_port INT Port for distributed training 12355
--wandb_project NAME Wandb project (enables logging) disabled
--wandb_run_name NAME Wandb run name auto-generated
--resume PATH Resume from output directory -

Output Directory Naming:

bagel_protein_dual_leakage_diff{N}_bs{B}_ga{G}_dlr{DLR}_ulr{ULR}_ep{E}[_frozenund][_answeronly]_{ckpt}

Example: bagel_protein_dual_leakage_diff4_bs8_ga8_dlr1e-4_ulr1e-4_ep300_frozenund_pretrained

Training Modes

Mode Description Use Case
joint Train both understanding + diffusion Default, best performance
generation_only Only train diffusion model Debug diffusion without SFT
understanding_only Only train understanding model Debug Qwen fine-tuning

Understanding Model Control

Control whether the understanding model (Qwen3) is trainable:

Flag Effect
--train-understanding Qwen3 parameters receive gradients (trainable)
--no-train-understanding Qwen3 frozen, only diffusion trains
Neither Uses default (frozen)

Example: Frozen understanding + abscratch:

./src/lmms_engine/models/bagel_protein/train/train_hyperparameter_sweep.sh \
    --no-train-understanding \
    --abscratch

Debug Options

Answer-Only QKV (--answer_only_qkv)

Test if the diffusion model can learn to use ground truth text representations:

# DEBUG: Train diffusion using only answer text for QKV conditioning
# (excludes thinking and foldability sections)
./src/lmms_engine/models/bagel_protein/train/train_hyperparameter_sweep.sh \
    --answer_only_qkv \
    --abscratch

This option:

  • QKV conditioning: Uses only the answer field from JSONL
  • SFT loss: Still uses full question + thinking + answer
  • Purpose: Verify if diffusion can learn from GT answer text representation

Inference

MoT Generation (Chain-of-Thought + Diffusion)

Generate protein structures using the BAGEL Protein MoT model:

  1. Generate Chain-of-Thought (CoT) from understanding expert (Qwen3)
  2. Extract QKV from thinking portion only (before </think>)
  3. Run diffusion conditioned on thinking tokens

Single GPU:

python src/lmms_engine/models/bagel_protein/inference/mot_generate.py \
    --config src/lmms_engine/models/bagel_protein/config/test_ab_mot.yaml \
    --checkpoint /path/to/checkpoint.pt \
    --gpu 0 \
    --save_dir ./results/experiment_name

Multi-GPU (8 GPUs):

torchrun --nproc_per_node=8 src/lmms_engine/models/bagel_protein/inference/mot_generate.py \
    --config src/lmms_engine/models/bagel_protein/config/test_ab_mot.yaml \
    --checkpoint /path/to/checkpoint.pt \
    --save_dir ./results/experiment_name

Example (HCDR3 antibody generation):

torchrun --nproc_per_node=8 src/lmms_engine/models/bagel_protein/inference/mot_generate.py \
    --config src/lmms_engine/models/bagel_protein/config/test_ab_mot.yaml \
    --checkpoint ./output/bagel_protein_dual_leakage_diff4_bs8_ga8_dlr1e-4_ulr1e-4_ep300_pretrained/best_model.pt \
    --save_dir ./results/ab_mot_epoch13

Configuration (test_ab_mot.yaml):

Parameter Description Default
n_cot_samples Number of CoT generations per sample 10
n_diff_samples Number of diffusion samples per CoT 10
dataloader.batch_size Batch size for inference 8
cdr_type CDR types to generate (e.g., [HCDR3]) [HCDR3]

Total samples per protein = n_cot_samples × n_diff_samples (default: 100)

Command-Line Options:

Option Description Default
--max_new_tokens Maximum tokens to generate for CoT 4096
--temperature Temperature for CoT generation 0.7
--seed Random seed 42
--use_gt_answer DEBUG: Use GT answer text for QKV false

Debug Mode (--use_gt_answer):

Tests if diffusion can correctly use ground truth answer text representations:

torchrun --nproc_per_node=8 src/lmms_engine/models/bagel_protein/inference/mot_generate.py \
    --config src/lmms_engine/models/bagel_protein/config/test_ab_mot.yaml \
    --checkpoint /path/to/checkpoint.pt \
    --save_dir ./results/ab_mot_gt_answer \
    --use_gt_answer

When --use_gt_answer is enabled:

  • Extracts QKV from ground truth answer field instead of generating CoT
  • Tests if diffusion can correctly map GT answer text → structure
  • Useful for debugging whether the diffusion model can use text representations

Output Structure:

results/experiment_name/
├── results_mot.jsonl       # Main results for metric evaluation
├── cot_texts.jsonl         # Generated CoT texts for analysis
├── references/             # Ground truth structures (PDB)
│   └── {pdb_id}_ref.pdb
└── candidates/             # Generated structures
    └── {pdb_id}/
        └── {CDR}/
            ├── 0.pdb       # Sample 0
            ├── 1.pdb       # Sample 1
            └── ...         # Up to 99.pdb

CoT Quality Evaluation

Evaluate Chain-of-Thought generation quality across checkpoints:

python src/lmms_engine/models/bagel_protein/inference/evaluate_cot_checkpoints.py \
    --config src/lmms_engine/models/bagel_protein/config/test_ab_mot.yaml \
    --checkpoints /path/to/checkpoint1.pt /path/to/checkpoint2.pt \
    --output_dir ./cot_eval_results \
    --num_samples 50

Evaluation

Structural Metrics

Evaluate generated structures using UniMoMo's metrics pipeline:

PYTHONPATH=./external/UniMoMo:$PYTHONPATH python -m scripts.metrics.peptide \
    --results ./results/experiment_name/results_mot.jsonl \
    --antibody \
    --log_suffix HCDR3 \
    --num_workers 96

Example:

PYTHONPATH=./external/UniMoMo:$PYTHONPATH python -m scripts.metrics.peptide \
    --results ./results/ab_mot_epoch13/results_mot.jsonl \
    --antibody \
    --log_suffix HCDR3 \
    --num_workers 96

Metrics Computed:

Metric Description Better
RMSD Root Mean Square Deviation (Å) Lower
TMscore Template Modeling score (0-1) Higher
DockQ Docking quality score Higher
AAR Amino Acid Recovery (%) Higher
Energy PyRosetta energy score Lower

Output:

  • Results written to stdout with summary statistics
  • Detailed per-sample metrics in the results JSONL

Requirements:

  • NumPy < 2.0 (for DockQ compatibility)
  • PyRosetta (for energy calculations)
  • Ray (for parallel processing)
# Install if needed
uv pip install numpy==1.26.4
uv pip install pyrosetta-installer
python -c "import pyrosetta_installer; pyrosetta_installer.install_pyrosetta()"

Configuration Reference

Training Configuration (train_bagel_protein_antibody_dual_leakage.yaml)

Model Config:

model_config:
  training_mode: joint                    # joint, generation_only, understanding_only
  understanding_model_id: thinking-bio-lab/qwen3_4b_it_full_sft_v35_n3416
  extract_layer: 6                        # Qwen layer for QKV extraction
  num_diffusion_timesteps: 100
  generation_latent_dim: 32
  num_iter_per_und: 4                     # Diffusion iters per understanding step
  use_gradient_checkpointing: true        # Save memory (~30% slower)
  understanding_dtype: "bfloat16"         # Qwen dtype (bfloat16 saves memory)
  use_chat_template: true                 # Use Qwen chat template

Dataset Config (Dual Leakage Mode):

dataset_config:
  datasets:
    - class: AntibodyDataset
      mmap_dir: ./datasets/antibody/SAbDab_new/processed
      prompt_jsonl: ./datasets/prompt/train.jsonl
      use_extended_format: true
      prevent_leakage_qkv_only: true      # QKV: no answer, SFT: with answer
      leakage_marker: "**Foldability:**"  # Truncate at this marker for QKV
      use_answer_only_qkv: false          # DEBUG: true = answer-only QKV
      strict_prompt: true

Trainer Args:

trainer_args:
  per_device_train_batch_size: 8
  gradient_accumulation_steps: 8
  learning_rate: 1.0e-4                   # Diffusion LR
  understanding_learning_rate: 1.0e-4     # Qwen LR
  num_train_epochs: 300
  lr_scheduler_type: reduce_on_plateau

Inference Configuration (test_ab_mot.yaml)

# Sampling parameters
n_cot_samples: 10      # CoT generations per sample
n_diff_samples: 10     # Diffusion samples per CoT

# Dataset
eval_dataset_config:
  datasets:
    - class: AntibodyDataset
      specify_index: ./datasets/antibody/SAbDab_new/processed/test_index.txt
      cdr_type:
        - HCDR3

Extended JSONL Format for SFT Training

The system supports two JSONL formats for training data:

Format Comparison

Legacy Format (Simple):

{"id": "7abc", "prompt": "Design a protein that binds to DNA"}

Extended Format (SFT-Ready):

{"complex_id": "7abc", "question": "Design...", "thinking": "We need helices... **Foldability:** ANSWER", "answer": "ANSWER"}

Dual Leakage Prevention Mode

The recommended configuration prevents data leakage while enabling proper SFT:

prevent_leakage_qkv_only: true  # QKV: truncated thinking, SFT: full response
leakage_marker: "**Foldability:**"

What happens:

  • QKV extraction: Uses question + thinking (truncated at marker) - NO answer leakage
  • SFT loss: Uses question + thinking + answer - FULL supervision

Data Flow

JSONL: {"question": "Design...", "thinking": "Analysis... **Foldability:** SEQ", "answer": "SEQ"}
                    ↓
┌──────────────────────────────────────────────────────────┐
│  QKV Version (for diffusion conditioning):               │
│  "Design..." + "Analysis..."                             │
│  (truncated at marker, no answer leakage)                │
├──────────────────────────────────────────────────────────┤
│  SFT Version (for language model loss):                  │
│  "Design..." + "Analysis... **Foldability:** SEQ" + SEQ  │
│  (full response for supervision)                         │
└──────────────────────────────────────────────────────────┘

Environment Setup

Quick Install (uv)

# Clone with submodules
git clone --recursive https://github.com/ThinkProteo/proteinFM.git
cd proteinFM

# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh
source "$HOME/.cargo/env"

# Create venv and install
uv venv && source .venv/bin/activate
uv pip install -e .

Key Dependencies

# PyTorch (CUDA 12.1)
uv pip install torch --find-links https://download.pytorch.org/whl/cu121

# PyTorch Geometric
uv pip install torch_scatter torch_sparse torch_cluster \
    -f https://data.pyg.org/whl/torch-2.4.0+cu121.html --no-build-isolation

# Flash Attention (optional, for speed)
uv pip install flash-attn --no-build-isolation

# For metrics evaluation
uv pip install numpy==1.26.4  # DockQ requires NumPy < 2
uv pip install pyrosetta-installer
python -c "import pyrosetta_installer; pyrosetta_installer.install_pyrosetta()"

Environment Variables

export UNIMOMO_CODE_ROOT=/path/to/UniMoMo
export UNIMOMO_DATA_ROOT=/path/to/data
export UNIMOMO_CKPT=/path/to/checkpoint.ckpt

Architecture Overview

proteinFM/
├── external/UniMoMo/           # Git submodule (unmodified)
├── src/lmms_engine/models/
│   ├── bagel_protein/          # Main BAGEL Protein implementation
│   │   ├── config/             # YAML configurations
│   │   ├── model/              # Model implementations
│   │   ├── train/              # Training scripts
│   │   └── inference/          # Inference scripts
│   └── unimomo/                # UniMoMo adapters & MoT
├── datasets/                   # Data directory
└── output/                     # Training outputs

Key Components

Component Description
BagelProteinSimpleModel Main model combining Qwen3 + LDM
EPTMoT Mixture-of-Transformers encoder
train_hyperparameter_sweep.sh Training launcher with hyperparameter control
mot_generate.py MoT inference (CoT + diffusion)
BagelChatCollate Collate function with Qwen chat template

Troubleshooting

Q: NCCL timeout during evaluation

  • Set eval_generation_mode: false in config for multi-GPU training

Q: NumPy/DockQ incompatibility

  • Install numpy<2: uv pip install numpy==1.26.4
  • Reinstall DockQ: uv pip install --force-reinstall DockQ

Q: PyRosetta import error

  • Use pyrosetta-installer: python -c "import pyrosetta_installer; pyrosetta_installer.install_pyrosetta()"

Q: OOM during training

  • Enable gradient checkpointing: use_gradient_checkpointing: true
  • Use bfloat16 for understanding model: understanding_dtype: "bfloat16"
  • Reduce batch size or increase gradient accumulation

Q: SFT loss is always zero

  • Ensure training_mode: joint (not generation_only)
  • Verify use_extended_format: true in dataset config

License

This project builds upon UniMoMo. Please see the respective licenses.

About

No description, website, or topics provided.

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages