Training configurations¶
This tutorial trains models using the configurations from the FlashCart paper and shows how to generate configurations for the five SPICE models, each with three random seeds. For the configuration format and available settings, see Configuration files.
The examples use files from the cloned FlashCart repository. Follow Installation and Data preparation before starting, then run the commands from the repository root.
Select the GPU before training. The following settings also disable TF32 to match the numerical settings used in the FlashCart paper:
export CUDA_VISIBLE_DEVICES=0
export NVIDIA_TF32_OVERRIDE=0
export TORCH_ALLOW_TF32_CUBLAS_OVERRIDE=0
Replace 0 with the GPU index for your run. These settings apply to later
commands in the same shell.
Train a SPICE model¶
examples/configs/spice.yaml defines a model with approximately 1.1 million
parameters, three interactions, correlation order three, and 64 feature channels.
Train and evaluate it with:
bash examples/configs/train_and_test.sh examples/configs/spice.yaml data/spice/test_subsets
The script trains one model, evaluates its best checkpoint on the configured
test set, and then evaluates each supplied test subset. This configuration
writes the run to models/i3c3f64l2_s0. The evaluation produces test.log
and a separate log for each subset under test_subsets in that run directory.
# SPICE (MACE-OFF23): 1.1M-parameter model (i3c3f64l2) on the split with seed 0.
# Only keys that differ from flashcart/configs/default.yaml are listed.
# make_configs.py generates the five SPICE models with three seeds each.
# data (see examples/datasets/prepare_spice.py)
train_path: data/spice/train_0.extxyz
valid_path: data/spice/val_0.extxyz
test_path: data/spice/test.extxyz
elements: [H, C, N, O, F, P, S, Cl, Br, I]
train_batch_size: 128
eval_batch_size: 128
data_seed: 0
n_workers: 2
# output
output_path: models/i3c3f64l2_s0
# model
model_seed: 0
r_max: 6.0
n_hidden_feats: 64
l_max_hidden_feats: 2
n_interactions: 3
correlation: 3
path_reduced_product: false
gate_activation: silu
# isolated-atom energies (eV) of the SPICE reference, in `elements` order
atomic_shifts: [-13.571964772646918, -1030.5671648271828, -1486.3750255780376,
-2043.933693071156, -2715.318528602957, -9287.407133426237,
-10834.4844708122, -12522.649269035726, -70045.28385080204,
-8102.524593409054]
# optimizer and schedule: 400 epochs (default), 20 linear warmup, then 380 cosine decay
weight_decay: 3.0e-4
end_factor: 1.0e-2
warmup_epochs: 20
decay_epochs: 380
decay_shape: cosine
# training
save_every: 5
ema_decay: 0.999
devices: 1
predict_compile: true
# energy MAE per atom + mean force-vector norm, equally weighted
train_loss:
weighted_sum:
- property: energy
reduce: mae
normalization: per_atom
weight: 1.0
- property: forces
reduce: norm_mean
normalization: none
weight: 1.0
Training and evaluation script
#!/usr/bin/env bash
# Train one model, then evaluate it on its test set and on every test subset.
#
# bash train_and_test.sh configs/i3c3f64l2_s0.yaml data/spice/test_subsets
#
# Writes <output_path>/test.log and <output_path>/test_subsets/<subset>.log.
set -euo pipefail
CONFIG=$1
SUBSET_DIR=${2:-}
# Disable TF32 for the float32 training protocol.
export NVIDIA_TF32_OVERRIDE=0
export TORCH_ALLOW_TF32_CUBLAS_OVERRIDE=0
OUT=$(python -c "import sys; from flashcart.utils.config import load_config; print(load_config(sys.argv[1])['output_path'])" "$CONFIG")
flashcart-train "$CONFIG"
flashcart-test "$CONFIG"
if [ -n "$SUBSET_DIR" ]; then
mkdir -p "$OUT/test_subsets"
for subset in "$SUBSET_DIR"/*.extxyz; do
name=$(basename "$subset" .extxyz)
flashcart-test "$CONFIG" valid_path=null test_path="$subset" 2>&1 | tee "$OUT/test_subsets/$name.log"
done
fi
Generate model configurations¶
make_configs.py generates the five SPICE model configurations reported in the
FlashCart paper, each with seeds 0, 1, and 2:
Model |
Configuration name before the seed suffix |
GPUs |
|---|---|---|
FlashCart-69k |
|
1 |
FlashCart-0.5M |
|
1 |
FlashCart-1.1M |
|
1 |
FlashCart-3.0M |
|
1 |
FlashCart-5.6M |
|
2 |
The script updates the architecture, seeds, data paths, output directory, and GPU count for each run. Generate the files with:
python examples/configs/make_configs.py --out configs
This writes 15 configuration files without launching training. To train a model, pass one generated file to the training script. For example, this command selects the same architecture as above with seed 1:
bash examples/configs/train_and_test.sh configs/i3c3f64l2_s1.yaml data/spice/test_subsets
Each generated configuration has a distinct output directory. Repeat the command with the other configurations you want to evaluate.
FlashCart-5.6M requests two GPUs. Make two devices available with a setting
such as CUDA_VISIBLE_DEVICES=0,1 before running the command.
The global batch target is unchanged, but actual batches can differ under
dynamic batching. See Batch sizes and data distribution for how batches are
distributed across GPUs.
Configuration generation script
"""Generate configurations for the five SPICE models reported in the FlashCart paper.
python examples/configs/make_configs.py --out configs
Generate the five SPICE models reported in the FlashCart paper, each with seeds
0, 1, and 2. This writes 15 files named <arch>_s<seed>.yaml. Train each with
``flashcart-train configs/<name>.yaml`` (or train_and_test.sh). Architecture
names read i<interactions>c<correlation>f<features>l<l_max_hidden>, with a
trailing r for the path-reduced product.
"""
import argparse
from pathlib import Path
from flashcart.utils.config import load_yaml, save_yaml
# (n_interactions, correlation, n_hidden_feats, l_max_hidden_feats, path_reduced_product, devices)
MODELS = [
(2, 3, 20, 2, True, 1), # FlashCart-69k
(3, 5, 32, 2, False, 1), # FlashCart-0.5M
(3, 3, 64, 2, False, 1), # FlashCart-1.1M
(3, 5, 88, 2, False, 1), # FlashCart-3.0M
(4, 5, 104, 2, False, 2), # FlashCart-5.6M
]
SEEDS = [0, 1, 2]
def main():
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
parser.add_argument("--base", type=Path, default=Path(__file__).with_name("spice.yaml"))
parser.add_argument("--out", type=Path, default=Path("configs"))
parser.add_argument("--data", default="data/spice", help="directory written by prepare_spice.py")
args = parser.parse_args()
base = load_yaml(args.base)
for i, c, f, l, reduced, devices in MODELS:
arch = f"i{i}c{c}f{f}l{l}" + ("r" if reduced else "")
for seed in SEEDS:
name = f"{arch}_s{seed}"
cfg = dict(base)
cfg.update(
train_path=f"{args.data}/train_{seed}.extxyz",
valid_path=f"{args.data}/val_{seed}.extxyz",
test_path=f"{args.data}/test.extxyz",
output_path=f"models/{name}",
data_seed=seed,
model_seed=seed,
n_interactions=i,
correlation=c,
n_hidden_feats=f,
l_max_hidden_feats=l,
path_reduced_product=reduced,
devices=devices,
)
save_yaml(args.out / f"{name}.yaml", cfg)
print(f"wrote {len(MODELS) * len(SEEDS)} configs to {args.out}")
if __name__ == "__main__":
main()
Train a MAD model¶
examples/configs/mad.yaml uses a smaller cutoff and gives force errors a lower
weight in the training loss function than the SPICE configuration. MAD already
subtracts an isolated-atom baseline from its reference energies. The supplied
configuration keeps atomic_shifts: ~, so FlashCart starts from zero prior
offsets and fits the remaining per-element energy shifts.
Train and evaluate the three seeds, each with a separate output directory:
for seed in 0 1 2
do
flashcart-train examples/configs/mad.yaml model_seed="$seed" data_seed="$seed" \
output_path="models/mad_i3c3f96l2_s${seed}"
flashcart-test examples/configs/mad.yaml model_seed="$seed" data_seed="$seed" \
output_path="models/mad_i3c3f96l2_s${seed}"
done
MAD uses fixed dataset splits. Here, data_seed changes the training shuffle.
The configuration uses one GPU, selected from the visible devices.
# MAD: model i3c3f96l2, seed 0.
# Only keys that differ from flashcart/configs/default.yaml are listed.
# data (see examples/datasets/prepare_mad.py)
train_path: data/mad/mad-train.extxyz
valid_path: data/mad/mad-val.extxyz
test_path: data/mad/mad-test.extxyz
elements:
[H, He, Li, Be, B, C, N, O, F, Ne, Na, Mg, Al, Si, P, S, Cl, Ar, K, Ca,
Sc, Ti, V, Cr, Mn, Fe, Co, Ni, Cu, Zn, Ga, Ge, As, Se, Br, Kr, Rb, Sr, Y,
Zr, Nb, Mo, Tc, Ru, Rh, Pd, Ag, Cd, In, Sn, Sb, Te, I, Xe, Cs, Ba, La, Ce,
Pr, Nd, Pm, Sm, Eu, Gd, Tb, Dy, Ho, Er, Tm, Yb, Lu, Hf, Ta, W, Re, Os, Ir,
Pt, Au, Hg, Tl, Pb, Bi, Po, Rn]
data_seed: 0
# output
output_path: models/mad_i3c3f96l2_s0
# model (atomic_shifts stays ~: MAD energies already have the isolated atoms subtracted)
model_seed: 0
r_max: 5.0
n_hidden_feats: 96
n_interactions: 3
gate_activation: silu
# optimizer and schedule: 400 epochs (default), 20 linear warmup, then 380 cosine decay
lr: 2.5e-3
weight_decay: 1.2e-2
end_factor: 1.0e-2
warmup_epochs: 20
decay_epochs: 380
decay_shape: cosine
# training
save_every: 5
ema_decay: 0.999
devices: 1
predict_compile: true
# energy MAE per atom + mean force-vector norm, forces down-weighted
train_loss:
weighted_sum:
- property: energy
reduce: mae
normalization: per_atom
weight: 1.0
- property: forces
reduce: norm_mean
normalization: none
weight: 0.1
Evaluate and compare models¶
To evaluate the seed-zero MAD model on the complete PET-MAD benchmark, run:
flashcart-test examples/configs/mad.yaml valid_path=null \
test_path=data/mad/mad-bench.extxyz output_path=models/mad_i3c3f96l2_s0
This reports errors over the complete benchmark. To obtain results for
individual benchmark datasets, evaluate the corresponding mad-bench-*.extxyz
files in data/mad/subsets, passing one filename as test_path for each run.
Use the matching output_path when evaluating another model seed.
The FlashCart paper reports SPICE errors averaged equally over the seven test subsets, followed by the mean and standard deviation across three training seeds.