core.distributed.fsdp.src.megatron_fsdp.experimental.owner_planning#
Owner assignment and P2P packing for MFSDP v2’s all-RowAtomic layout.
Tensor shapes and shard ranges come from the group’s existing GlobalLayout.
Owner assignments and peer dictionaries use global process ranks.
Module Contents#
Classes#
A tensor’s compute cost and eligible owner ranks in buffer order. |
|
A group’s shared buffer layout and owner assignments. |
|
Metadata and send buffers for the owner-gather P2P step of a set of parameters. |
|
Metadata and send buffers for the owner-scatter P2P step of a set of parameters. |
Functions#
Whether the given tensor has dimensionality ≥2. |
|
Estimate Newton-Schulz work from a tensor’s full shape. |
|
Assign each participating tensor to a global rank holding part of it. |
API#
- core.distributed.fsdp.src.megatron_fsdp.experimental.owner_planning.select_ge_2d_params(param: torch.Tensor) bool#
Whether the given tensor has dimensionality ≥2.
- core.distributed.fsdp.src.megatron_fsdp.experimental.owner_planning.ns_cost_fn(
- num_ns_steps: int,
Estimate Newton-Schulz work from a tensor’s full shape.
View the tensor as
(rows, cols) = (shape[0], shape[1:].numel()). After normalization and transposing so that rows <= cols, a quintic Newton-Schulz step with scalar coefficients(a, b, c)is:A = X @ X.T X = a * X + (b * A + c * (A @ A)) @ X
The matrix products cost O(numel * min(rows, cols)) per step. We use
numel * (min(rows, cols) * num_ns_steps + 1)as a relative work estimate, omitting constant factors and adding a linear term for normalization and elementwise work.
- class core.distributed.fsdp.src.megatron_fsdp.experimental.owner_planning._OwnerWork#
A tensor’s compute cost and eligible owner ranks in buffer order.
- tensor_index: int#
None
- cost: float#
None
- candidates: list[int]#
None
- core.distributed.fsdp.src.megatron_fsdp.experimental.owner_planning.assign_owner_work(
- layout: core.distributed.fsdp.src.megatron_fsdp.experimental.layout.GlobalLayout,
- mesh: torch.distributed.device_mesh.DeviceMesh,
- tensor_indices: collections.abc.Iterable[int],
- cost_fn: collections.abc.Callable[[torch.Size], float] | None = None,
Assign each participating tensor to a global rank holding part of it.
Tensors with a single candidate are assigned first, followed by tensors with multiple candidates in descending cost order. Each tensor is assigned to its least-loaded holder. Ties follow buffer order.
- Parameters:
layout – The group’s DBuffer layout, including padding and ineligible tensors.
mesh – The device mesh across which the buffer is all-RowAtomic sharded.
tensor_indices – Indices of participating tensors in
layout.cost_fn – Positive cost estimate from a tensor’s full shape. Defaults to Newton-Schulz with five iterations.
- class core.distributed.fsdp.src.megatron_fsdp.experimental.owner_planning.GroupOwnerLayout#
A group’s shared buffer layout and owner assignments.
.. attribute:: mesh
The device mesh over which the buffer is all-RowAtomic sharded.
.. attribute:: layout
The existing
DBuffer.layout, including all tensors in the group... attribute:: tensor_to_owner
Participating tensor index to owner global process rank. These keys identify the participating tensors; no filtered layout copy is stored.
- mesh: torch.distributed.device_mesh.DeviceMesh#
None
- tensor_to_owner: dict[int, int]#
None
- classmethod from_group(
- group: core.distributed.fsdp.src.megatron_fsdp.experimental.parameter_group.FsdpParameterGroup,
- *,
- cost_fn: collections.abc.Callable[[torch.Size], float] | None = None,
- eligible_fn: collections.abc.Callable[[torch.Tensor], bool] | None = None,
Select participating parameters and balance their owner assignments.
eligible_fndefaults to selecting ≥2D parameters.cost_fnreceives full tensor shapes; seeassign_owner_workfor the default estimate.
- class core.distributed.fsdp.src.megatron_fsdp.experimental.owner_planning.OwnerGatherPlan#
Metadata and send buffers for the owner-gather P2P step of a set of parameters.
The owner keeps its own shard locally (no self-send), so it only receives from the other shard-holding ranks.
reconstruct_fullreconstructs each owned tensor by concatenating the per-rank shards in buffer order.Example:
# We are also using some pseudocode here for brevity. # Assume: torch.distributed.get_world_size() == 2 torch.distributed.get_rank() == 0 # We're observing from rank 0. mesh.mesh.tolist() == [0, 1] # Global process ranks. param_0: torch.Tensor param_1: torch.Tensor # Params are in this order as observed by MFSDP. model.param_groups == [{"params": [param_0, param_1]}] param_0.shape == (6, 4) # Global shape. param_1.shape == (4, 4) # Global shape. layout.tensor_to_offset == (0, 24) layout.size == 40 # The buffer, rather than each parameter separately, is split evenly: # rank 0 holds [0, 20); rank 1 holds [20, 40). # Choose rank 1 as both owners for this example. It holds part of param_0 # and all of param_1; these are explicit assignments, not the default balancer's output. owner_layout = GroupOwnerLayout(mesh=mesh, layout=layout, tensor_to_owner={0: 1, 1: 1}) param_0.local_shard.shape == (5, 4) # Rank 0 holds param_0[0:5, ...]. param_1.local_shard.shape == (0, 4) # Rank 0 holds none of param_1. param_0.local_shard.numel() == 20 param_1.local_shard.numel() == 0 owner_gather_plan.send_buffers == {1: tensor(20)} # 20 elements from param_0. # `owner_gather_plan.send_buffers[1]` represents the following flat buffer: # +--------------------+ # | param_0 (20 elems) | # +--------------------+ # element order: --> # Rank 0 owns nothing. owner_gather_plan.recv_sizes == {} owner_gather_plan.own_shards == {} owner_gather_plan.recv_offsets == {} # --- # Same settings as above, now observing from rank 1 (the owner): torch.distributed.get_rank() == 1 param_0.local_shard.shape == (1, 4) # Rank 1 holds param_0[5:6, ...]. param_1.local_shard.shape == (4, 4) # Rank 1 holds all of param_1. send_buffers = {} # Rank 1 owns everything. recv_sizes = {0: 20} # 20 elements from rank 0. # Rank 1's own shards, flattened (views): own_shards = {0: param_0.local_shard.view(-1), 1: param_1.local_shard.view(-1)} recv_offsets = { (0, 0): 0, # `param_0` (tensor index 0) from rank 0: offset 0. # No entry for param_1: it is fully local to rank 1. } # Reconstruct param_0 from the received 20 elements followed by its own 4. # Reconstruct param_1 directly from its own 16 elements, without communication.
.. attribute:: send_buffers
Per-destination-owner flat send buffer (this rank’s shards for that owner’s params, in tensor-index order). Only owners with non-zero send size appear.
.. attribute:: recv_sizes
Per-source-rank element count this rank (as an owner) receives. Only sources with non-zero total size appear.
.. attribute:: own_shards
This rank’s flat local shard per owned parameter, keyed by tensor index (used directly in reconstruction, not communicated).
.. attribute:: recv_offsets
Per
(tensor_index, src_rank), the flat offset of this param’s shard inside the recv buffer received fromsrc_rank. Only contains tuples for whichsrc_rankholds elements.- rank_ranges: dict[int, core.distributed.fsdp.src.megatron_fsdp.experimental.range.Range]#
None
- this_rank: int#
None
- send_buffers: dict[int, torch.Tensor]#
None
- recv_sizes: dict[int, int]#
None
- own_shards: dict[int, torch.Tensor]#
None
- recv_offsets: dict[tuple[int, int], int]#
None
- classmethod pack(
- owner_layout: core.distributed.fsdp.src.megatron_fsdp.experimental.owner_planning.GroupOwnerLayout,
- local_shards: dict[int, torch.Tensor],
Pack this rank’s local shards into per-owner P2P send buffers.
- Parameters:
owner_layout – The group’s owner layout.
local_shards – This rank’s local shard per parameter, only required for every parameter it holds elements of. Shards may be passed in any shape.
- reconstruct_full(
- param_index: int,
- recv_buffers: dict[int, torch.Tensor],
Reconstruct the full flat tensor for one owned parameter from its per-rank shards.
Concatenates the per-rank shards in buffer order. Results can be
viewed into the desired shape. For a parameter only this rank holds elements of, the own flat shard is returned directly.- Parameters:
param_index – Tensor index of an owned parameter in the group layout.
recv_buffers – Per-source-rank received buffer (only sources that sent).
- class core.distributed.fsdp.src.megatron_fsdp.experimental.owner_planning.OwnerScatterPlan#
Metadata and send buffers for the owner-scatter P2P step of a set of parameters.
The owner keeps its own result shard (applied directly), so it only sends to the other shard-holding ranks.
.. attribute:: send_buffers
Per-destination-rank flat send buffer (this owner’s result shards for the params it owns, in tensor-index order). Only destinations with non-zero send size appear.
.. attribute:: recv_sizes
Per-owner-rank element count this rank (as a destination) receives. Only owners with non-zero total size appear.
.. attribute:: recv_offsets
Per
(tensor_index, owner_rank), the flat offset of this param’s result shard inside the recv buffer received fromowner_rank. Only contains tuples for which this rank holds elements.- local_range: core.distributed.fsdp.src.megatron_fsdp.experimental.range.Range#
None
- send_buffers: dict[int, torch.Tensor]#
None
- recv_sizes: dict[int, int]#
None
- recv_offsets: dict[tuple[int, int], int]#
None
- classmethod pack(
- owner_layout: core.distributed.fsdp.src.megatron_fsdp.experimental.owner_planning.GroupOwnerLayout,
- full_results: dict[int, torch.Tensor],
Pack this owner rank’s full results into per-destination P2P send buffers.
- Parameters:
owner_layout – The group’s owner layout.
full_results – Full result tensor per parameter this rank owns. Tensors may be passed in any shape.
- unpack(
- recv_buffers: dict[int, torch.Tensor],
Extract this rank’s local flat result shards from the per-owner recv buffers.
- Parameters:
recv_buffers – Per-owner-rank received buffer (only owners that sent).
- Returns:
Mapping from tensor index to this rank’s local flat result shard, for parameters this rank holds elements of but does NOT own.