
Domain parallelism for high-resolution science
Proteins Structure prediction competitive with experiment AlphaFold · Nature 2021
Weather Global medium-range forecasts that beat operational numerical systems GraphCast · Science 2023; Pangu-Weather · Nature 2023
Fusion Magnetic control of tokamak plasmas by deep reinforcement learning Nature 2022
Materials Deep learning at scale for materials discovery, and autonomous synthesis labs Nature 2023 (×2)
Fluids Machine-learning-accelerated computational fluid dynamics PNAS 2021
Medicine Dermatologist-level classification of skin cancer Nature 2017
Resolution is where discoveries are made:
one scientific sample is often far larger than one language-model sample.

torch.cuda.OutOfMemoryError: CUDA out of memory.
| Method | What it splits | Built for |
|---|---|---|
| Data parallel (Horovod, DDP) | the batch: one or more samples per GPU | more data per step |
| Fully sharded (FSDP, ZeRO) | weights, gradients, optimizer state | models too big for one GPU |
| Tensor parallel | each weight matrix | layers too big for one GPU |
| Pipeline parallel | groups of layers | very deep models |
| Context / sequence parallel | tokens, inside attention | long text; transformers only |
Every tool assumes either that one sample fits on a GPU, or that the model is a transformer.
| Where | What it splits | The catch |
|---|---|---|
| Classical HPC: CFD, climate, molecular dynamics | the simulation domain, for decades | solvers, not ML models |
| Ring Attention, DeepSpeed Ulysses | the token sequence | attention and transformers only |
| Makani (weather), Transolver++ (CFD) | the spatial domain | written into one model |
| DistDL | layers, over MPI | rebuild the model; fixed partitions |
PyTorch DTensor |
any tensor | built for weights: even, static shapes |
JAX shard_map |
anything | you compose every operation by hand |
Missing: a general tool where your model runs unchanged.
forward()DTensor for scientific datatorch.chunk)DTensor fallbackdistribute_modulenn.Modulephysicsnemo.domain_parallel.from torch.distributed.device_mesh import init_device_mesh
from torch.nn.parallel import DistributedDataParallel as DDP
from torch.distributed.tensor import Shard
from physicsnemo.domain_parallel import scatter_tensor, sync_module_over_mesh
mesh = init_device_mesh("cuda", (16, 2), mesh_dim_names=("data", "domain"))
model = MyModel().cuda() # your model, unchanged
model = DDP(model, process_group=mesh["data"].get_group())
loss_fn(model(x), y).backward()MyModel is not rewritten. The ShardTensor input triggers domain-parallel dispatch inside every layer, forward and backward.
from torch.distributed.device_mesh import init_device_mesh
from torch.nn.parallel import DistributedDataParallel as DDP
from torch.distributed.tensor import Shard
from physicsnemo.domain_parallel import scatter_tensor, sync_module_over_mesh
mesh = init_device_mesh("cuda", (16, 2), mesh_dim_names=("data", "domain"))
model = MyModel().cuda() # your model, unchanged
# 1. Make the weights agree across GPUs that share a sample
sync_module_over_mesh(model, mesh["domain"])
model = DDP(model, process_group=mesh["data"].get_group())
# 2. Split each input sample along its height axis
x = scatter_tensor(x, src, mesh["domain"], (Shard(2),))
loss_fn(model(x), y).backward()MyModel is not rewritten. The ShardTensor input triggers domain-parallel dispatch inside every layer, forward and backward.
H. Liu, M. Zaharia, P. Abbeel, “Ring Attention with Blockwise Transformers for Near-Infinite Context,” arXiv:2310.01889 (2023)
H. Liu, M. Zaharia, P. Abbeel, “Ring Attention with Blockwise Transformers for Near-Infinite Context,” arXiv:2310.01889 (2023)
H. Liu, M. Zaharia, P. Abbeel, “Ring Attention with Blockwise Transformers for Near-Infinite Context,” arXiv:2310.01889 (2023)
H. Liu, M. Zaharia, P. Abbeel, “Ring Attention with Blockwise Transformers for Near-Infinite Context,” arXiv:2310.01889 (2023)
H. Liu, M. Zaharia, P. Abbeel, “Ring Attention with Blockwise Transformers for Near-Infinite Context,” arXiv:2310.01889 (2023)
H. Liu, M. Zaharia, P. Abbeel, “Ring Attention with Blockwise Transformers for Near-Infinite Context,” arXiv:2310.01889 (2023)
H. Liu, M. Zaharia, P. Abbeel, “Ring Attention with Blockwise Transformers for Near-Infinite Context,” arXiv:2310.01889 (2023)
| Layers | Communication | What moves |
|---|---|---|
| Linear, MLP, activations | none | nothing |
| Convolution, neighborhood attention, graph message passing | halo exchange | a thin edge from each neighbor |
| Normalization, pooling, loss | all-reduce | a few statistics per GPU |
| Full attention | ring | keys and values, overlapped with compute |
Each gives the same answer as one GPU.
import torch, torch.distributed as dist
from torch.distributed.tensor import Replicate
from physicsnemo.domain_parallel import ShardTensor
def sharded_dot(func, types, args, kwargs):
x, y = args
out = torch.dot(x.to_local(), y.to_local()) # each GPU: its own piece
dist.all_reduce(out, group=x._spec.mesh.get_group()) # sum over GPUs
return ShardTensor.from_local(out, x._spec.mesh, (Replicate(),))
ShardTensor.register_function_handler(torch.dot, sharded_dot)Register handlers for Python functions, torch.library.custom_op kernels, or low-level aten ops — intercept and parallelize user code at whatever level fits your model.
init_device_mesh("cuda", (16, 2))
One GPU stops at 384³. 16 GPUs train 1024³ = 1.07 billion points, and run 384³ 10.5× faster.

Ring attention training latency. At 2¹⁹ tokens, 16 GPUs are 97% efficient (96% for inference).

ViT inference on 2D data: 16 GPUs are 14.9× faster than one at 4096².
torch.compile cuts it
At scientific resolutions, ~60 µs of eager dispatch is small next to GPU kernel time. torch.compile cuts it 134×, to 0.45 µs.

Left: forecast. Right: what happened. Without domain parallelism: a coarser grid or a smaller region.

MACE on quartz (SiO₂) via NVIDIA ALCHEMI: 52 k atoms on 1 GPU → 716 k on 16 (vs. 323 k when copying the full multi-hop receptive field).

Domain-parallel training is as stable as single-GPU training, and combines with data parallelism.
torch.compile cuts it to ~0.45 µs.DTensor or a handler you write. Tested to 16 GPUs per sample.1. Install NVIDIA PhysicsNeMo
Coming soon: PhysicsNeMo is splitting key functionality into standalone libraries — pip install physicsnemo-domain-parallel will soon be available.
2. Install the coding-agent skill
Clone the repo and link skills/physicsnemo-shard-tensor into your agent’s skills directory (Claude Code, Codex, Cursor, OpenCode):
DeviceMesh + scatter_tensor into your script without touching your nn.Moduletorchrun gradient testsResolution should be a scientific choice, not a GPU-memory limit.
Docs & tutorials: docs.nvidia.com/physicsnemo/latest · Source & examples: github.com/NVIDIA/physicsnemo (physicsnemo/domain_parallel)
Questions?
Slides: coreyadams.net/talks/sc26-shardtensor (PDF) · Code: github.com/NVIDIA/physicsnemo
ShardTensor · AI4S @ SC26 · github.com/NVIDIA/physicsnemo · Slides: coreyadams.net/talks/sc26-shardtensor (PDF)