{{ message }}
Repository navigation
perf(checkpointing): describe prepended-axis shards with the checkpointable path - #7287
Merged
dimapihtar merged 3 commits intoOct 7, 2026
Merged
Conversation
…ntable path `mcore_to_pyt_state_dict` routes ShardedTensors with a non-zero `prepend_axis_num` through the legacy PyTorch ShardedTensor conversion, which enumerates the entire global shard grid (including remote shards) for every converted key. Homogeneous transformer stacks prepend a layer axis to every parameter and MoE routed experts add a global-expert axis on top of it, so the conversion cost grows with the number of fragments across all logical axes instead of with the number of locally held shards. The conversion runs synchronously before the async write request is returned, so it cannot be hidden by asynchronous checkpointing. A prepended axis has extent one within a local chunk, which the checkpointable path can describe directly: expose prepended axes as singleton dimensions of the local chunk metadata and of the local data view (a view, no payload copy). The resulting DCP metadata is identical to the legacy one, so checkpoints stay readable in both directions. Measured on 8xH200 for a local MoE model (48 layers, 128 experts, EP=8, SequentialMLP experts, 4.7M grid entries per rank): `mcore_to_pyt_state_dict` drops from 11.71 s to 0.07 s, and the synchronous prefix of an async save from 17.75 s to 5.22 s. Signed-off-by: Gawr Gura 0721 <LiRunGuo@users.noreply.github.com>
Adds regression coverage for routing prepended-axis shards (homogeneous layer axis, MoE expert axis) through the checkpointable path: - DCP write-item metadata parity against the legacy conversion, including the singleton prepended dimensions of the local chunk; - save/load round trip of a standalone prepended-axis shard, checking the stored chunk metadata and the loaded values; - loading a checkpoint written by the legacy conversion (old-format checkpoints must keep loading); - a MoE model end-to-end test (local, non-TransformerEngine experts) covering EP=1/2/4 round trips and EP=4 -> EP=2 resharding, which asserts the expert weights carry the prepended layer/expert axes. Signed-off-by: Gawr Gura 0721 <LiRunGuo@users.noreply.github.com>
LiRunGuo
marked this pull request as ready for review
September 13, 2026 20:09
dimapihtar
approved these changes
Sep 17, 2026
Contributor
|
@NVIDIA/core-adlr @NVIDIA/core-nemo The checkpointing expert review is approved on the current head ( |
Connor-XY
approved these changes
Sep 21, 2026
Contributor
|
/ok to test f4af454 |
Phlip79
approved these changes
Oct 5, 2026
jaredcasper
approved these changes
Oct 6, 2026
cspades
pushed a commit
to cspades/Megatron-LM
that referenced
this pull request
Oct 7, 2026
…ntable path (NVIDIA#7287) Signed-off-by: Gawr Gura 0721 <LiRunGuo@users.noreply.github.com> Co-authored-by: Gawr Gura 0721 <LiRunGuo@users.noreply.github.com> Co-authored-by: Dmytro Pykhtar <37850217+dimapihtar@users.noreply.github.com>
This branch was previously deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Motivation
mcore_to_pyt_state_dictroutes everyShardedTensorwith a non-zeroprepend_axis_numthrough the legacy PyTorch
ShardedTensorconversion(
sharded_tensor_to_torch_sharded_tensor). That conversion enumerates the entire globalshard grid — remote shards included — for each converted key:
so its cost grows with the number of fragments across all logical axes, not with the number of
locally held shards.
Prepended axes are not an exotic corner case (closes #7275):
TransformerBlock.sharded_state_dictpasses(0, global_layer_offset, num_layers)as thesharded_offsetsof every layer whenever the stack is homogeneous, andsharded_state_dict_defaultturns those offsets into a prepended layer axis of everyparameter of the block.
SequentialMLP.sharded_state_dictadds a prepended global-expert axis on top of it foreach routed expert.
For a 48-layer MoE model with 128 experts and EP=8 the per-rank local shards for one weight key
therefore describe a 48 x 128 grid — 4.7M grid entries per rank in total — and all of that work
happens synchronously before the async write request is returned, so asynchronous
checkpointing cannot hide it from the training loop.
What changed
A prepended axis has extent one within a local chunk (that is what
prepend_axis_nummeans:the local data covers a single index along the prepended axes). The DCP checkpointable path can
describe that directly, so prepended-axis shards no longer need the legacy conversion:
CheckpointableShardedTensornow reports prepended axes as singleton dimensions of the localchunk (
sizes = (1,) * prepend_axis_num + local_shape) and exposes the local data through amatching view (
data.view((1,) * prepend_axis_num + local_shape)) — a view, no payload copy.mcore_to_pyt_state_dictroutes prepended-axis shards to the checkpointable path, keeping theexisting restrictions (PyTorch >= 2.6, regular grid, no flattened shards).
The resulting DCP metadata is identical to the metadata produced by the legacy conversion
(same chunk offsets, chunk sizes, global size and dtype — asserted by the new tests), so:
Measurements (8xH200, PyTorch 2.10,
torch_dist)Local (non-TransformerEngine) MoE model, 48 layers, 128 experts, EP=8, 1,109 local shards per
rank, 1,646 unique keys, 4,734,725 grid entries per rank:
mcore_to_pyt_state_dictasync_save()save_preprocess(unchanged)A synthetic prepended-axis workload with 3,072 keys/rank x 128 grid entries (393,216 entries)
lands in the same place: 3.69 s -> 0.027 s.
Testing
tests/unit_tests/dist_checkpointing/test_checkpointable.py::TestPrependedAxisCheckpointable— write-item metadata parity with the legacy conversion, save/load round trip, and loading a
checkpoint written by the legacy conversion.
tests/unit_tests/dist_checkpointing/models/test_moe_expert_sharding.py— MoE modelround trips for EP=1/2/4 and EP=4 -> EP=2 resharding (asserts the prepended layer/expert axes
are present). Runs without TransformerEngine.
pytest tests/unit_tests/dist_checkpointing/{test_checkpointable,test_torch_dist, test_serialization,test_validation,test_local,test_fully_parallel,test_replication}.pyon 8 GPUs: 65 passed, 2 skipped.
black,isort,ruff,pylintclean on the changed files.Follow-ups (not in this PR)
The legacy branch of
mcore_to_pyt_state_dict(andsharded_tensor_to_torch_sharded_tensor)is now reachable only for
torch < 2.6; removing it once the minimum PyTorch version allowswould be a separate cleanup.