Skip to content

Horizontal Parallelism

About

The d9d.module.parallelism package provides functions that distribute modules across device meshes. These strategies are "horizontal": they split work within one pipeline stage. Pipeline parallelism is "vertical": it splits the model into stages of layers.

Design

DTensor-First

d9d requires every trainable parameter in a distributed run to be a torch.distributed.tensor.DTensor. This keeps the rest of the system simple:

  • Checkpointing: The checkpointing engine does not need to know the parallel strategy. It reads DTensor.placements to decide how to gather, deduplicate and save each tensor.
  • Gradient synchronization: Gradient Synchronization reads the placements to find the mesh dimensions along which a parameter is replicated.

Composition over Monoliths

d9d does not use monolithic wrappers like torch.nn.parallel.DistributedDataParallel (DDP). DDP takes ownership of the whole model execution. Instead, d9d builds on PyTorch's parallelize_module API, which lets you choose a strategy for each submodule:

  • Layer A can use tensor parallelism (row-wise or column-wise).
  • Layer B, such as a router, can use replicate parallelism.
  • Layer C, such as an MoE layer, can use expert parallelism.

Data parallelism is one more placement ("Replicate") in this system, so all strategies share one interface.

Strategies

Replicate Parallelism

parallelize_replicate replicates parameters across the mesh. Use it for data parallelism or context parallelism.

During the forward pass, the module sees its parameters as plain local torch.Tensor objects. Standard PyTorch operations and custom kernels therefore run without changes. Outside the forward pass, the parameters and the state dict hold DTensor objects.

Expert Parallelism (MoE)

parallelize_expert_parallel applies expert parallelism to an MoELayer:

  1. It shards the experts (the GroupedLinear weights) along the ep_shard mesh dimension, so each GPU holds a subset of experts. Along ep_replicate, the experts are replicated.
  2. It replicates the router and the shared expert, if any, across the whole mesh.
  3. It switches the token dispatcher of the layer to DeepEP. This requires the d9d[backend-expert-parallel-deepep] extra.

Fully Sharded Data Parallel (FSDP)

parallelize_fsdp is a thin wrapper around PyTorch's fully_shard. It differs from plain FSDP in two ways:

  • Plain FSDP averages gradients across the mesh. parallelize_fsdp sums them instead, because d9d normalizes gradients itself.
  • parallelize_fsdp requires a 1D mesh. For a multi-dimensional mesh, use parallelize_hsdp, or first apply parallelize_replicate to the other dimensions.

Hybrid Sharded Data Parallel (HSDP)

parallelize_hsdp combines full sharding with replicate parallelism. It takes a multi-dimensional mesh and a shard_dim. It applies parallelize_fsdp along shard_dim and parallelize_replicate along all other dimensions. It skips dimensions of size 1.

Usage

The examples below use the mesh domains of Distributed Context. MyCustomLayer stands for your own module.

Replicate Parallelism

from d9d.core.dist_context import DENSE_DOMAIN, DistributedContext
from d9d.module.parallelism.api import parallelize_replicate

ctx: DistributedContext = ...

# Dimensions: pp, dp_replicate, dp_cp_shard, cp_replicate, tp.
dense_mesh = ctx.mesh_for(DENSE_DOMAIN)

model = MyCustomLayer(...)

parallelize_replicate(model, dense_mesh["dp_replicate", "cp_replicate"])

Expert Parallelism

from d9d.core.dist_context import EXPERT_DOMAIN, DistributedContext
from d9d.module.block.moe import MoELayer
from d9d.module.parallelism.api import parallelize_expert_parallel

ctx: DistributedContext = ...

# Dimensions: pp, ep_replicate, ep_shard.
expert_mesh = ctx.mesh_for(EXPERT_DOMAIN)

model = MoELayer(...)

parallelize_expert_parallel(
    model,
    mesh_experts=expert_mesh["ep_replicate", "ep_shard"],
    expert_shard_dim="ep_shard",
)

FSDP

from d9d.core.dist_context import DENSE_DOMAIN, DistributedContext
from d9d.module.parallelism.api import parallelize_fsdp

ctx: DistributedContext = ...

dense_mesh = ctx.mesh_for(DENSE_DOMAIN)

model = MyCustomLayer(...)

parallelize_fsdp(model, mesh=dense_mesh["dp_cp_shard"])

HSDP

from d9d.core.dist_context import DENSE_DOMAIN, DistributedContext
from d9d.module.parallelism.api import parallelize_hsdp

ctx: DistributedContext = ...

# Dimensions: pp, dp_replicate, dp_cp_shard, cp_replicate, tp.
dense_mesh = ctx.mesh_for(DENSE_DOMAIN)

model = MyCustomLayer(...)

parallelize_hsdp(
    model,
    mesh=dense_mesh["dp_replicate", "dp_cp_shard", "cp_replicate"],
    shard_dim="dp_cp_shard",
)

API Reference

d9d.module.parallelism.api

Functions that apply horizontal parallelism strategies to modules.

parallelize_expert_parallel(module, mesh_experts, expert_shard_dim='ep_shard')

Applies expert parallelism to an MoE layer.

The sparse experts are sharded along expert_shard_dim and replicated along the other mesh dimensions. The router and the shared expert (if any) are replicated across the whole mesh.

Parameters:

Name Type Description Default
module MoELayer

The MoE layer to parallelize.

required
mesh_experts DeviceMesh

The device mesh to distribute the layer over.

required
expert_shard_dim str

The name of the mesh dimension to shard the experts along.

'ep_shard'

parallelize_fsdp(module, mesh, *args, **kwargs)

Applies Fully Sharded Data Parallel (FSDP) with gradient summation.

The module is sharded with PyTorch's fully_shard over mesh. Unlike default FSDP, gradients are summed across the mesh instead of averaged, and FSDP does not all-reduce them across replicas. d9d normalizes and reduces gradients across replicas itself.

Parameters:

Name Type Description Default
module Module

The module to shard.

required
mesh DeviceMesh

The device mesh over which to shard the module.

required
*args Any

Additional positional arguments passed to fully_shard.

()
**kwargs Any

Additional keyword arguments passed to fully_shard.

{}

Raises:

Type Description
ValueError

If the mesh does not have exactly one dimension.

RuntimeError

If fully_shard did not convert the module to an FSDPModule.

parallelize_hsdp(module, mesh, shard_dim='dp_cp_shard', *fsdp_args, **fsdp_kwargs)

Applies Hybrid Sharded Data Parallel (HSDP) to a module.

The module is sharded with FSDP along shard_dim and replicated along every other mesh dimension. Dimensions of size 1 are skipped.

Parameters:

Name Type Description Default
module Module

The module to parallelize.

required
mesh DeviceMesh

The device mesh to distribute the module over.

required
shard_dim str

The name of the mesh dimension to shard along. All other dimensions are replication dimensions.

'dp_cp_shard'
*fsdp_args Any

Positional arguments passed to the underlying FSDP parallelizer.

()
**fsdp_kwargs Any

Keyword arguments passed to the underlying FSDP parallelizer.

{}

Raises:

Type Description
ValueError

If the device mesh has no dimension names.

parallelize_replicate(module, mesh)

Applies Replicate Parallelism to a module.

Parameters become DTensor objects with Replicate placements on every mesh dimension. During the forward pass, the module computes with plain local tensors (see ToLocalParallel). This is data parallelism expressed with DTensor.

Parameters:

Name Type Description Default
module Module

The module to parallelize.

required
mesh DeviceMesh

The device mesh to replicate the module over.

required

d9d.module.parallelism.style

Custom ParallelStyle implementations for d9d modules.

ShardMoESparseExpertsParallel

Bases: ParallelStyle

Parallel style that shards the experts of an MoELayer along one mesh dimension.

Every GroupedLinear weight in the layer is sharded along the expert dimension on the shard mesh dimension and replicated on the other mesh dimensions. If the shard dimension has more than one rank, the style also enables the layer's distributed token dispatch over that dimension.

__init__(shard_dim_name)

Constructs the ShardMoESparseExpertsParallel object.

Parameters:

Name Type Description Default
shard_dim_name str

The name of the mesh dimension to shard the experts along.

required

ToLocalParallel

Bases: ParallelStyle

Parallel style that stores parameters as DTensor but computes with local tensors.

Parameters become DTensor objects with the given placements. During the forward pass, the module sees them as local torch.Tensor objects. Use it for strategies such as Replicate, where the module code is not DTensor-aware but gradient sync and checkpointing need DTensor.

__init__(param_placement, grad_placement)

Constructs the ToLocalParallel object.

Parameters:

Name Type Description Default
param_placement tuple[Placement, ...]

The placements of the parameters, one per mesh dimension.

required
grad_placement tuple[Placement, ...]

The placements of the gradients, one per mesh dimension. They are passed to DTensor.to_local as grad_placements.

required