Note: The current implementation supports Boltz-2 only.
This document describes how to run distributed training using
src/boltz/distributed/train.py, which implements DTensor-based context
parallelism (CP) combined with data parallelism (DP).
The distributed training entrypoint is:
src/boltz/distributed/train.py <config.yaml> [override1=value1] [override2=value2] ...
It accepts a YAML config file as the first positional argument, followed by
zero or more OmegaConf-style dotlist overrides. The config is loaded via
Hydra (respecting defaults: chains), struct mode is disabled to allow
adding new keys, and CLI overrides are merged on top.
The script is designed to be launched with either torchrun (for
single-node or multi-node runs outside SLURM) or srun (for SLURM
clusters). The DistributedManager (src/boltz/distributed/manager.py)
auto-detects the launch method:
torchrun— detected viaRANK,WORLD_SIZE,LOCAL_RANK,MASTER_ADDR,MASTER_PORTenvironment variables.srun(SLURM) — detected viaSLURM_PROCID,SLURM_NPROCS,SLURM_LOCALID,SLURM_LAUNCH_NODE_IPADDRenvironment variables.
The detection order can be forced by setting
BOLTZ_DISTRIBUTED_INIT_METHOD=ENV or BOLTZ_DISTRIBUTED_INIT_METHOD=SLURM.
Example with torchrun (single node, 8 GPUs):
torchrun \
--nnodes 1 \
--nproc_per_node 8 \
src/boltz/distributed/train.py \
scripts/train/configs/structurev2_small_cp.yaml \
parallel_size.size_dp=2 \
parallel_size.size_cp=4 \
output=<output_dir> \
...Example with srun (multi-node SLURM):
srun --ntasks-per-node=8 --nodes=2 \
python src/boltz/distributed/train.py \
scripts/train/configs/structurev2_cp.yaml \
parallel_size.size_dp=4 \
parallel_size.size_cp=4 \
output=<output_dir> \
...The constraint size_dp * size_cp == world_size must hold, and size_cp
must be a perfect square (the CP mesh is 2D).
scripts/train/configs/structurev2.yaml is the base configuration for
Boltz serial training (used by scripts/train/train.py). It defines the
full model architecture, data pipeline, training hyperparameters, and
defaults to single-device training:
trainer:
accelerator: cuda
devices: 1
num_nodes: 1
precision: bf16-mixedscripts/train/configs/structurev2_cp.yaml extends structurev2.yaml with
settings required for DTensor context-parallel training:
defaults:
- structurev2
- _self_
trainer:
accelerator: gpu # must be gpu (not cuda) — CP code manages devices
devices: 1 # must be 1 — each Lightning Trainer manages one device
num_nodes: 1 # must be 1 — multi-node is handled by torchrun/SLURM
precision: null # superseded by top-level precision setting
parallel_size:
size_cp: 1 # context-parallel group size (must be a perfect square)
size_dp: 1 # data-parallel group size
timeout_nccl: 30 # NCCL timeout in minutes
timeout_gloo: 30 # Gloo timeout in minutes
precision: BF16_MIXED # top-level precision enum (FP32, TF32, BF16, BF16_MIXED, FP16, FP64)
triattn_backend: cueq
sdpa_with_bias_backend: torch_flex_attn
sdpa_with_bias_shardwise_backend: torch_flex_attn
data:
num_workers: 0 # must be 0 — DTensor CP requires main-process collation
pin_memory: falseKey differences from the serial config:
| Setting | Serial (structurev2.yaml) |
CP (structurev2_cp.yaml) |
|---|---|---|
trainer.accelerator |
cuda |
gpu |
trainer.devices |
configurable (e.g. 8) | must be 1 |
trainer.num_nodes |
configurable (e.g. 4) | must be 1 |
trainer.precision |
bf16-mixed |
null (use top-level precision) |
parallel_size |
not present | size_dp, size_cp, timeouts |
precision (top-level) |
not present | BF16_MIXED enum |
triattn_backend |
not present | triangular attention kernel backend |
sdpa_with_bias_backend |
not present | ring-attention SDPA backend |
sdpa_with_bias_shardwise_backend |
not present | window-batched SDPA backend |
data.num_workers |
2 |
0 (required) |
data.pin_memory |
false |
false |
CUDAMemoryProfile |
not present | optional memory profiling |
-
structurev2_small.yamlextendsstructurev2.yamlwith reduced model depth (12 pairformer blocks, 3 MSA blocks), smaller sequence limits (max_tokens: 256,max_atoms: 2048), and no activation checkpointing. It also setstrainer.devices: 8andtrainer.num_nodes: 4for multi-GPU serial DDP training. -
structurev2_small_cp.yamlextendsstructurev2_cp.yaml(not the serial small variant) with the same reduced model depth and sequence limits. It does not settrainer.devicesortrainer.num_nodesbecause the CP config already fixes those to1. The parallel topology is controlled entirely viaparallel_size.size_dpandparallel_size.size_cpCLI overrides.
The following settings exist in DistributedTrainConfig but have no
counterpart in the serial TrainConfig:
Controls the distributed topology.
| Key | Type | Description |
|---|---|---|
size_dp |
int | Data-parallel group size |
size_cp |
int | Context-parallel group size (must be a perfect square: 1, 4, 9, 16, ...) |
timeout_nccl |
int | NCCL timeout in minutes (for CUDA) |
timeout_gloo |
int | Gloo timeout in minutes (for CPU) |
The product size_dp * size_cp must equal the total world size
(nproc_per_node * nnodes).
An enum (FP32, TF32, BF16, BF16_MIXED, FP16, FP64) that
replaces trainer.precision. Setting trainer.precision directly raises an
error in the CP entrypoint.
| Key | Values | Description |
|---|---|---|
triattn_backend |
reference, cueq, trifast, cueq_fwd_trifast_bwd |
Triangular attention kernel. cueq does not support FP32. |
sdpa_with_bias_backend |
reference, torch_sdpa_efficient_attention, torch_flex_attn |
SDPA backend for ring-attention layers |
sdpa_with_bias_shardwise_backend |
reference, torch_sdpa_efficient_attention, torch_flex_attn |
SDPA backend for window-batched (shardwise) attention layers |
Enables CPU offloading of activation-checkpoint boundary tensors for selected distributed module types. When activation checkpointing is active, intermediate activations saved for backward are moved to CPU during the forward pass and restored on backward, trading extra CPU-GPU transfers for reduced GPU memory.
# Disabled by default.
OffloadActvCkptToCPU: null
# Enable for all three supported module types:
OffloadActvCkptToCPU:
- DiffusionTransformer
- MSAModule
- PairformerModuleCLI override:
OffloadActvCkptToCPU='[DiffusionTransformer,MSAModule,PairformerModule]'Valid module type names: DiffusionTransformer, MSAModule,
PairformerModule. Any subset may be specified.
Prerequisite: activation checkpointing must be enabled on every targeted
module. The setter raises ValueError if a targeted module has
activation_checkpointing=False. The standard activation-checkpointing
overrides cover four config sections:
model.msa_args.activation_checkpointing=true
model.template_args.activation_checkpointing=true
model.pairformer_args.activation_checkpointing=true
model.score_model_args.activation_checkpointing=trueHowever, there is a fifth DiffusionTransformer instance nested inside the
InputEmbedder (via AtomAttentionEncoder -> AtomTransformer ->
DiffusionTransformer). This instance is controlled by embedder_args, not
score_model_args. If DiffusionTransformer is included in
OffloadActvCkptToCPU, you must also enable:
model.embedder_args.activation_checkpointing=trueOtherwise the setter will raise because the InputEmbedder's
DiffusionTransformer still has activation_checkpointing=False.
Optional CUDA memory profiling. Each rank writes a pickle file.
CUDAMemoryProfile:
output_path_prefix: null # set a path prefix to enable, e.g. "profiling/mem"
max_entries: 300000Overrides for Lightning's ModelCheckpoint. The CP entrypoint applies
Boltz defaults (monitor="val/lddt", save_last=True,
save_on_train_epoch_end=True, mode="max", every_n_epochs=1) but any
key can be overridden via CLI:
checkpoint.monitor=val/disto_lddt_protein_protein \
checkpoint.save_top_k=3When set, seeds are offset by rank + epoch + global_step on resume to
avoid replaying identical data samples across ranks and restarts.
When true, runs trainer.validate() instead of trainer.fit(). Useful
for evaluating a checkpoint without training.
All config keys can be overridden from the command line using OmegaConf dotlist syntax. The config's struct mode is disabled, so new keys can also be introduced.
A recently added utility (convert_datasets_dict_to_list_config from
src/boltz/workflow/utils.py) enables partial overrides of individual
dataset entries within the data.datasets list directly from the CLI.
This was not possible before because OmegaConf does not natively support
partial updates to ListConfig entries.
The utility converts dict-style index keys (e.g. data.datasets.0.key)
into proper list merges against the base config. The overridable dataset
keys are:
_target_, target_dir, msa_dir, prob, sampler, cropper,
template_dir, filters, split, symmetry_correction, val_group,
use_train_subset, moldir, override_bfactor, override_method
Examples:
# Override dataset 0's data directory and disable filters
data.datasets.0.target_dir=/path/to/data \
data.datasets.0.msa_dir=/path/to/msa \
'data.datasets.0.filters=[]' \
# Remove dataset 1 entirely (null removes the entry)
data.datasets.1=null \When filters needs to be set to an empty list, it must be quoted to
prevent shell interpretation: 'data.datasets.0.filters=[]'.
# Parallelism topology
parallel_size.size_dp=<int>
parallel_size.size_cp=<int>
# Output and checkpointing
output=<output_dir>
resume=<checkpoint_path>
pretrained=<pretrained_path>
checkpoint.monitor=<metric_name>
# Training schedule
trainer.max_epochs=<int>
trainer.accumulate_grad_batches=<int>
# Logging frequency
trainer.log_every_n_steps=<int> # Lightning: how often to flush to logger (default: 50)
model.log_loss_every_steps=<int> # Model: how often to compute and log losses/norms (default: 50)
# Data
data.samples_per_epoch=<int>
data.overfit=<int> # Activate overfit mode: use first N samples, validate on train data
data.datasets.0.target_dir=<path>
data.datasets.0.split=<path_or_null>
# Precision
precision=BF16_MIXED
# WandB (all keys required when wandb section is present)
wandb.name=<run_name>
wandb.project=<project>
wandb.id=<run_id>
wandb.entity=<entity_or_null>
# Validation only
validation_only=trueThere are two independent gates that control when training metrics appear in the logger:
-
model.log_loss_every_steps(default: 50) — The Boltz model only callsself.log()(and computes parameter/gradient norms) every N global steps. Steps where this condition is not met skip all logging computation entirely. -
trainer.log_every_n_steps(default: 50) — PyTorch Lightning only flushesself.log()calls to the configured logger (e.g. WandB) every N steps. Calls on other steps are buffered but not written.
Both conditions must be satisfied for metrics to appear. For small
datasets with few steps per epoch, set both to 1.
Setting data.overfit=N activates overfit mode:
- Training samples are truncated to the first N per dataset.
- Validation uses the training datasets instead of the validation split.
- Sample weights are normalized for uniform sampling.
When using overfit mode, set data.datasets.0.split=null to prevent the
train/val split from reducing the training set. Set
data.samples_per_epoch to control the epoch length (divided by size_dp
for per-rank step count).
| Aspect | Serial (scripts/train/train.py) |
CP (src/boltz/distributed/train.py) |
|---|---|---|
| Multi-GPU strategy | Lightning DDP (DDPStrategy) |
BoltzContextParallelStrategy (DTensor) |
| Device management | Lightning (trainer.devices, trainer.num_nodes) |
DistributedManager via parallel_size |
| Launch method | python scripts/train/train.py |
torchrun or srun |
num_workers |
Configurable (default: 2) | Must be 0 |
| Precision | trainer.precision (Lightning string) |
Top-level precision enum |
| Attention backends | Not configurable | triattn_backend, sdpa_with_bias_backend, sdpa_with_bias_shardwise_backend |
| CUDA memory profiling | Not available | CUDAMemoryProfile section |
| Confidence prediction | Supported | Not yet supported (auto-disabled with warning) |
| Steering potentials | Supported | Not yet supported (auto-disabled with warning) |
| Checkpoint strategy | Lightning default | BoltzContextParallelStrategy (DTensor-aware save/load) |