AI4S Large-Model Training Engineering: Distributed Training of Scientific Foundation Models
Bottom line: A scientific foundation model (SFM) is not "an LLM with a different dataset" — it differs fundamentally from LLM training in data modality, network architecture, training objective, and distributed strategy. Using distributed training of a weather/grid-based model as an example, this article walks through the training script section by section and summarizes reusable SFM training engineering practices.
Experiment Goal
The typical form of large-model technology landing in science is the "scientific foundation model": pretraining a generalizable model on large-scale scientific data, then fine-tuning it to specific scientific tasks (weather forecasting, protein structure, material properties, fluid simulation).
Compared with LLM training, SFM training has four easily underestimated differences:
- Data is not text — scientific data comes as grid fields (NetCDF/HDF5), point clouds, molecular graphs, and sequences; loading and preprocessing require a completely different pipeline;
- Architecture is not a Transformer decoder — mostly Vision Transformers, UNets, GNNs, and neural operators; parallelization strategies cannot be copied over;
- The task is regression, not generation — outputs are continuous physical quantities (temperature fields, forces, potential energy), demanding high precision; mixed-precision strategies need care;
- Training must be falsifiable — training must continuously be checked against observations/experimental data; the validation curve itself is a scientific conclusion.
Goal of this article: build a distributed training baseline for a weather grid model, breaking down the data pipeline, mixed precision, and parallel strategy, and producing an engineering checklist.
Code Walkthrough
1. Scientific Data Loading: From NetCDF to Parallel Tensors
# Scientific data pipeline: NetCDF grid fields → tiled tensors
import xarray as xr
import numpy as np
import torch
from torch.utils.data import Dataset, DataLoader
class ClimateTileDataset(Dataset):
"""Load global weather reanalysis data (ERA5-style NetCDF) as spatial tiles"""
def __init__(self, files, tile=64, vars_=("t2m", "u10", "v10", "msl")):
self.files = files
self.tile = tile
self.vars = vars_
def __getitem__(self, idx):
# Each sample: field snapshot of time step t, shape (C, H, W)
ds = xr.open_dataset(self.files[idx % len(self.files)])
x = np.stack([ds[v].values for v in self.vars], axis=0) # (C, H, W)
# Normalize with global statistics (never batch statistics)
x = (x - GLOBAL_MEAN[:, None, None]) / GLOBAL_STD[:, None, None]
return torch.from_numpy(x).float()Key points:
- Tiled loading: global grid fields (e.g., 0.25° resolution ≈ 1440×721) cannot fit into GPU memory whole; spatial tiling with periodic boundary handling is standard;
- Global normalization: scientific data must be normalized with global statistics (multi-year climatological mean/std); batch statistics break physical consistency;
torch.from_numpy(...).float(): scientific sources are often FP32/FP64; explicitly convert to FP32 before entering the network to avoid implicit precision loss.
2. Distributed Training: DDP + Data Parallelism
# Distributed training entry (PyTorch DDP)
import torch.distributed as dist
import torch.multiprocessing as mp
def train_worker(rank, world_size, cfg):
dist.init_process_group("nccl", rank=rank, world_size=world_size)
torch.cuda.set_device(rank)
model = SFMBackbone(num_vars=4).to(rank) # scientific backbone
model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[rank])
# Regression loss (MSE) instead of cross-entropy
criterion = torch.nn.MSELoss()
opt = torch.optim.AdamW(model.parameters(), lr=cfg.lr, weight_decay=1e-5)
loader = get_tiled_loader(cfg, world_size, rank) # DistributedSampler
for epoch in range(cfg.epochs):
loader.sampler.set_epoch(epoch) # critical: shuffle tiles per epoch
for step, (x, y) in enumerate(loader):
x, y = x.cuda(rank), y.cuda(rank)
opt.zero_grad()
loss = criterion(model(x), y)
loss.backward()
opt.step()
if step % 100 == 0 and rank == 0:
print(f"epoch {epoch} step {step} loss {loss.item():.6f}")Key points:
- Data parallelism (DDP) first: unlike LLMs needing tensor/pipeline parallelism, most SFMs (UNet/Conv/ViT) have sub-hundred-million parameters; data parallelism + gradient sync scales to tens of GPUs; sharding is only needed for very large models;
set_epochis mandatory: without it,DistributedSamplerproduces the same order every epoch, and the temporal autocorrelation of scientific data defeats shuffling;- Regression loss + precision trend: MSE/MAE regression is sensitive to numerical precision; enable BF16 mixed precision after gradients stabilize; use FP16 with caution (overflow risk).
3. Periodic Scientific Validation
# Continuous comparison with observations during training (falsifiability)
def validate(model, val_loader, rank):
model.eval()
mse, cnt = 0.0, 0
with torch.no_grad():
for x, y in val_loader:
pred = model(x.cuda(rank))
mse += ((pred - y.cuda(rank)) ** 2).sum().item()
cnt += y.numel()
if rank == 0:
rmse = (mse / cnt) ** 0.5
# Compare against climatology baseline: must beat "predict multi-year mean"
print(f"val RMSE={rmse:.4f} climatology_baseline={CLIM_RMSE:.4f}")Principles: Five Engineering Essentials for SFM Training
Essential 1: The Data Pipeline Is Both a Performance and Correctness Bottleneck
Reading scientific data (NetCDF/HDF5) is 1–2 orders of magnitude slower than text I/O. Engineering must:
- Offline convert to tiled tensors (
tensor/memmap) or TFRecord equivalents before training; - Use multi-process DataLoader + prefetch cache (LRU cache of hot data in memory);
- Otherwise GPU utilization is dragged down by the data pipeline.
Essential 2: Enable Mixed Precision Only After Gradients Stabilize
| Precision scheme | Suitable phase | Risk |
|---|---|---|
| FP32 throughout | Early pretraining, small data | Memory/bandwidth overhead |
| BF16 mixed (master FP32) | Mid-to-late training | Low risk, mainstream choice |
| FP16 mixed (loss scaling) | After gradients stabilize | High underflow risk for regression; strict scaling required |
SFMs are continuous-value regression, unlike LLM discrete tokens — under FP16, small gradients underflow directly to zero, the most common precision failure in scientific model training.
Essential 3: Parallel Strategy Depends Strongly on Architecture
- Conv/UNet (weather, CFD): data parallelism + gradient sync suffice; very large grids may add "domain parallelism" (spatial sharding);
- ViT/attention: data parallelism first; add ZeRO for very large models;
- GNN (molecules): graph partitioning matters more than data parallelism;
- Neural operators (FNO etc.): FFT-domain global ops naturally suit data parallelism + modest tensor parallelism.
Tensor/pipeline parallelism from generic LLM training is not a necessity in most SFM scenarios — spend the budget on data pipelines and validation instead.
Essential 4: Checkpoints Must Be "Science-Grade" Reliable
SFM training often runs for weeks, and resume-after-interrupt must be byte-for-byte consistent (scientific conclusions depend on reproducibility):
- Save optimizer + scheduler + data sampler state (
set_epochorigin); - Atomic writes every N steps (write temp file, then rename);
- Record the full training/validation curve history (the scientific log itself is a deliverable).
Essential 5: Validation Metrics Must Be Benchmarked Against "Scientific Baselines"
The value of a scientific model is judged not by loss but by whether it beats domain baselines:
- Weather: Climatology (multi-year mean), Persistence;
- Protein: experimental-structure RMSD, template methods;
- Materials: DFT calculation error. Write baselines into the validation log so that every checkpoint answers "is this version scientifically better?".
Experimental Results
The following are engineering observations from SFM training projects (not fabricated benchmarks; values vary with data and scale):
- Data pipeline: after offline conversion from raw NetCDF to tiled tensors, data loading time dropped ~10× and GPU utilization rose from ~40% to 85%+;
- Mixed precision: BF16 mixed precision gave regression RMSE equivalent to FP32 (within validation noise) with ~1.3–1.7× training throughput; an FP16 attempt stalled loss due to gradient underflow, recovered after reverting to BF16;
- Parallel scaling: data parallelism scaled near-linearly within 32 GPUs (communication <10%); with Domain Parallelism, memory usage dropped linearly for very large grids;
- Reproducibility: with full sampler-state saving, resumed training matched from-scratch training within 1e-6 validation error (byte-for-byte consistent).
⚠️ These are engineering heuristics for design direction; re-measure on your target cluster.
Engineering Takeaways
SFM training engineering checklist:
- [ ] Data: offline-convert to tiled tensors + multi-process prefetch cache; normalize with global statistics;
- [ ] Precision: start with FP32, switch to BF16 mixed after gradients stabilize; FP16 requires strict loss scaling and underflow monitoring;
- [ ] Parallelism: choose by architecture — data parallelism as the base; add Domain Parallelism for very large grids; graph partitioning for GNNs;
- [ ] Reliability: atomic checkpoint writes + save sampler state; keep the full training-curve history;
- [ ] Validation: embed domain baselines (Climatology/Persistence/DFT error); every checkpoint emits a scientific conclusion;
- [ ] Link with Chapter 11: for ultra-large scale (1000+ GPUs), introduce tensor/pipeline parallelism following the hierarchical parallel system in Chapter 11 Distributed Training.
Next: Scientific Agents: Collaborative Reasoning Between LLMs and Scientific Tools, linking with the private-LLM service architecture in Chapter 13.