Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion megatron/core/dist_checkpointing/state_dict_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
StateDict,
apply_factories,
)
from .utils import extract_nonpersistent, extract_sharded_base
from .utils import _clean_metadata_for_serialization, extract_nonpersistent, extract_sharded_base
from .validation import determine_global_metadata, validate_sharding_integrity


Expand Down Expand Up @@ -43,6 +43,11 @@ def save_preprocess(
sharded_part = filter_out_empty_flatten_tensor(sharded_part)
if validate_access_integrity:
preprocessed_common_state_dict = common_state_dict
if "content_metadata" in preprocessed_common_state_dict:
preprocessed_common_state_dict["content_metadata"] = _clean_metadata_for_serialization(
preprocessed_common_state_dict["content_metadata"]
)

if preprocess_common_before_consistancy_check:
preprocessed_common_state_dict = preprocess_common_before_consistancy_check(
common_state_dict
Expand Down
17 changes: 17 additions & 0 deletions megatron/core/dist_checkpointing/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,3 +330,20 @@ def debug_msg(msg: str):
"""
with logger_stack(None, None) as (stacked_name, last_logger):
last_logger.debug(f"{stacked_name} {msg}")


def _clean_metadata_for_serialization(metadata: dict) -> dict:
"""Create a clean copy of metadata for serialization by removing non-serializable objects.

Args:
metadata: Original metadata dict

Returns:
Clean metadata dict suitable for serialization
"""
if metadata is None:
return None
clean_metadata = metadata.copy()
# Remove dp_cp_group as it's not serializable
clean_metadata.pop('dp_cp_group', None)
return clean_metadata
54 changes: 48 additions & 6 deletions megatron/core/extensions/transformer_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
from megatron.core.transformer.mlp import MLP
from megatron.core.transformer.transformer_config import TransformerConfig
from megatron.core.transformer.utils import (
ensure_metadata_has_dp_cp_group,
is_layer_window_attention,
make_sharded_tensors_for_checkpoint,
)
Expand Down Expand Up @@ -420,6 +421,9 @@ def __init__(
# duplicated across TP ranks
setattr(param, "sequence_parallel", self.config.sequence_parallel)

tp_group = get_tensor_model_parallel_group_if_none(tp_group, is_expert=is_expert)
self._tp_group = tp_group

def forward(self, x):
"""Forward."""
_is_first_microbatch = (
Expand All @@ -444,7 +448,14 @@ def sharded_state_dict(self, prefix="", sharded_offsets=(), metadata=None):
self.parallel_mode is None
), "TELinear sharded_state_dict can only be used with duplicated parallel mode"
state_dict = self.state_dict(prefix="", keep_vars=True)
return make_sharded_tensors_for_checkpoint(state_dict, prefix, None, sharded_offsets)
return make_sharded_tensors_for_checkpoint(
state_dict,
prefix,
None,
sharded_offsets,
tp_group=self._tp_group,
dp_cp_group=metadata["dp_cp_group"],
)

def backward_dw(self):
"""Compute weight gradients during the backward pass if delay_wgrad_compute is enabled."""
Expand Down Expand Up @@ -492,6 +503,7 @@ def __init__(

# TODO: For backward compatibility, remove in v0.15.
tp_group = get_tensor_model_parallel_group_if_none(tp_group, is_expert=is_expert)
self._tp_group = tp_group

# TE returns a zero length Tensor when bias=False and
# return_bias=True, but we prefer None. So in that case we
Expand Down Expand Up @@ -625,9 +637,15 @@ def forward(self, x):

def sharded_state_dict(self, prefix="", sharded_offsets=(), metadata=None):
"""Sharding along axis 0, bias sharded"""
metadata = ensure_metadata_has_dp_cp_group(metadata)
state_dict = self.state_dict(prefix="", keep_vars=True)
return make_sharded_tensors_for_checkpoint(
state_dict, prefix, {"weight": 0, "bias": 0}, sharded_offsets
state_dict,
prefix,
{"weight": 0, "bias": 0},
sharded_offsets,
tp_group=self._tp_group,
dp_cp_group=metadata["dp_cp_group"],
)

def __repr__(self):
Expand Down Expand Up @@ -670,6 +688,7 @@ def __init__(
if gather_output:
raise ValueError("Transformer Engine linear layers do not support gather_output = True")
tp_group = get_tensor_model_parallel_group_if_none(tp_group, is_expert=is_expert)
self._tp_group = tp_group
world_size = get_pg_size(tp_group)
rank = get_pg_rank(tp_group)

Expand Down Expand Up @@ -720,7 +739,12 @@ def sharded_state_dict(self, prefix="", sharded_offsets=(), metadata=None):
"""Sharding along axis 0, bias sharded"""
state_dict = self.state_dict(prefix="", keep_vars=True)
return make_sharded_tensors_for_checkpoint(
state_dict, prefix, {"weight": 0, "bias": 0}, sharded_offsets
state_dict,
prefix,
{"weight": 0, "bias": 0},
sharded_offsets,
tp_group=self._tp_group,
dp_cp_group=metadata["dp_cp_group"],
)

def __repr__(self):
Expand Down Expand Up @@ -764,6 +788,7 @@ def __init__(
"Transformer Engine linear layers do not support input_is_parallel = False"
)
tp_group = get_tensor_model_parallel_group_if_none(tp_group, is_expert=is_expert)
self._tp_group = tp_group

super().__init__(
input_size=input_size,
Expand Down Expand Up @@ -814,7 +839,12 @@ def sharded_state_dict(self, prefix="", sharded_offsets=(), metadata=None):
"""Sharding along axis 1, bias not sharded"""
state_dict = self.state_dict(prefix="", keep_vars=True)
return make_sharded_tensors_for_checkpoint(
state_dict, prefix, {"weight": 1}, sharded_offsets
state_dict,
prefix,
{"weight": 1},
sharded_offsets,
tp_group=self._tp_group,
dp_cp_group=metadata["dp_cp_group"],
)

def __repr__(self):
Expand Down Expand Up @@ -901,6 +931,7 @@ def __init__(
assert hasattr(
pg_collection, "hcp"
), "TEDotProductAttention pg_collection must have hierarchical cp pg"
self._tp_group = pg_collection.tp

if is_te_min_version("0.10.0"):
extra_kwargs["attention_type"] = attention_type
Expand Down Expand Up @@ -1078,7 +1109,12 @@ def sharded_state_dict(
else:
state_dict = {}
return make_sharded_tensors_for_checkpoint(
state_dict, prefix, {'softmax_offset': 0}, sharded_offsets
state_dict,
prefix,
{'softmax_offset': 0},
sharded_offsets,
tp_group=self._tp_group,
dp_cp_group=metadata["dp_cp_group"],
)


Expand Down Expand Up @@ -1138,6 +1174,7 @@ def __init__(
# The comms between TP and EP group is explicitly handled by MoE token dispatcher.
# So we disable comms by making TE agnostic of model parallel.
tp_group = get_tensor_model_parallel_group_if_none(tp_group, is_expert=is_expert)
self._tp_group = tp_group
tp_size = get_pg_size(tp_group)

self.explicit_expert_comm = is_expert and (tp_size > 1 or self.expert_parallel)
Expand Down Expand Up @@ -1372,7 +1409,12 @@ def _sharded_state_dict_grouped(
(ep_axis, global_expert_idx, num_global_experts),
)
sub_sd = make_sharded_tensors_for_checkpoint(
state_dict, '', tp_axis_map, new_sharded_offsets
state_dict,
'',
tp_axis_map,
new_sharded_offsets,
tp_group=self._tp_group,
dp_cp_group=metadata["dp_cp_group"],
)
# Remove expert layers indexing from sharded keys
replace_prefix_for_sharding(sub_sd, f"{gemm_idx}.", expert_prefix)
Expand Down
4 changes: 3 additions & 1 deletion megatron/core/models/bert/bert_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from megatron.core.models.common.embeddings.language_model_embedding import LanguageModelEmbedding
from megatron.core.models.common.embeddings.rotary_pos_embedding import RotaryEmbedding
from megatron.core.models.common.language_module.language_module import LanguageModule
from megatron.core.process_groups_config import ProcessGroupCollection
from megatron.core.transformer.dot_product_attention import (
DotProductAttention as MCoreDotProductAttention,
)
Expand Down Expand Up @@ -73,9 +74,10 @@ def __init__(
seq_len_interpolation_factor: Optional[float] = None,
add_binary_head=True,
return_embeddings=False,
pg_collection: Optional[ProcessGroupCollection] = None,
vp_stage: Optional[int] = None,
):
super(BertModel, self).__init__(config=config)
super(BertModel, self).__init__(config=config, pg_collection=pg_collection)

if has_config_logger_enabled(config):
log_config_to_disk(config, locals(), prefix=type(self).__name__)
Expand Down
19 changes: 17 additions & 2 deletions megatron/core/models/common/language_module/language_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@
from megatron.core.transformer.enums import AttnBackend
from megatron.core.transformer.module import MegatronModule
from megatron.core.transformer.transformer_config import TransformerConfig
from megatron.core.utils import is_te_min_version, make_tp_sharded_tensor_for_checkpoint
from megatron.core.transformer.utils import ensure_metadata_has_dp_cp_group
from megatron.core.utils import (
get_tensor_model_parallel_group_if_none,
is_te_min_version,
make_tp_sharded_tensor_for_checkpoint,
)


class LanguageModule(MegatronModule):
Expand All @@ -44,6 +49,7 @@ def __init__(
pg_collection = ProcessGroupCollection.use_mpu_process_groups()
self.pg_collection = pg_collection
self.cp_group = pg_collection.cp
self.tp_group = get_tensor_model_parallel_group_if_none(pg_collection.tp)
self.pp_group = pg_collection.pp
assert hasattr(self.pg_collection, 'embd'), (
"pg_collection must have a embd. In previous version, it used default "
Expand Down Expand Up @@ -278,6 +284,10 @@ def sharded_state_dict(
ShardedStateDict: sharded state dict for the LanguageModel
"""
assert not sharded_offsets, "Unexpected sharded offsets"

# Guard for cases metadata is not provided
metadata = ensure_metadata_has_dp_cp_group(metadata)

sharded_state_dict = super().sharded_state_dict(prefix, sharded_offsets, metadata)

first_stage_word_emb_key = f'{prefix}embedding.word_embeddings.weight'
Expand All @@ -286,7 +296,7 @@ def sharded_state_dict(

if self.share_embeddings_and_output_weights:
self.tie_embeddings_and_output_weights_state_dict(
sharded_state_dict, output_layer_weight_key, first_stage_word_emb_key
sharded_state_dict, output_layer_weight_key, first_stage_word_emb_key, metadata
)
elif self.post_process:
# Make sure the output layer follows the embeddings padding logic
Expand All @@ -303,6 +313,7 @@ def tie_embeddings_and_output_weights_state_dict(
sharded_state_dict: ShardedStateDict,
output_layer_weight_key: str,
first_stage_word_emb_key: str,
metadata: Optional[dict] = None,
) -> None:
"""Ties the embedding and output weights in a given sharded state dict.

Expand All @@ -312,9 +323,11 @@ def tie_embeddings_and_output_weights_state_dict(
This entry will be replaced with a tied version
first_stage_word_emb_key (str): this must be the same as the
ShardedTensor.key of the first stage word embeddings.
metadata (Optional[Dict]): metadata controlling sharded state dict creation.

Returns: None, acts in-place
"""
metadata = ensure_metadata_has_dp_cp_group(metadata)
if not self.post_process:
# No output layer
assert output_layer_weight_key not in sharded_state_dict, sharded_state_dict.keys()
Expand Down Expand Up @@ -347,4 +360,6 @@ def tie_embeddings_and_output_weights_state_dict(
key=first_stage_word_emb_key,
replica_id=last_stage_word_emb_replica_id,
allow_shape_mismatch=True,
tp_group=self.tp_group,
dp_cp_group=metadata['dp_cp_group'],
)
8 changes: 7 additions & 1 deletion megatron/core/models/gpt/gpt_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,12 @@ def sharded_state_dict(
if self.mtp_process and not self.pre_process:
emb_weight_key = f'{prefix}embedding.word_embeddings.weight'
emb_weight = self.embedding.word_embeddings.weight
tie_word_embeddings_state_dict(sharded_state_dict, emb_weight, emb_weight_key)
tie_word_embeddings_state_dict(
sharded_state_dict,
emb_weight,
emb_weight_key,
tp_group=self.tp_group,
dp_cp_group=metadata['dp_cp_group'],
)

return sharded_state_dict
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def __init__(
pin_cpu_grads: bool = True,
pin_cpu_params: bool = True,
overlap_cpu_optimizer_d2h_h2d: bool = True,
**kwargs
**kwargs,
):
super(HybridDeviceOptimizer, self).__init__(
params,
Expand Down
12 changes: 10 additions & 2 deletions megatron/core/post_training/modelopt/layers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.

import logging
from typing import Callable, List, Optional

import torch
Expand All @@ -10,6 +11,8 @@
from megatron.core.transformer.transformer_layer import TransformerLayer
from megatron.core.transformer.utils import make_sharded_tensors_for_checkpoint

logger = logging.getLogger(__name__)

try:
import transformer_engine as te

Expand Down Expand Up @@ -116,6 +119,7 @@ def __init__(
tp_group: Optional[torch.distributed.ProcessGroup] = None,
):
self.config = config
self.tp_group = tp_group

self._return_bias = skip_bias_add and bias

Expand Down Expand Up @@ -153,7 +157,11 @@ def sharded_state_dict(self, prefix="", sharded_offsets=(), metadata=None):
if v.ndim == 0:
state_dict[k] = v.view(1)
sharded_state_dict = make_sharded_tensors_for_checkpoint(
state_dict, prefix, sharded_offsets=sharded_offsets
state_dict,
prefix,
sharded_offsets=sharded_offsets,
tp_group=self.tp_group,
dp_cp_group=metadata['dp_cp_group'],
)
return sharded_state_dict

Expand Down Expand Up @@ -229,7 +237,7 @@ def _report_quantize_tensor_info(self):
if not isinstance(v, torch.Tensor):
continue
original_dtype, original_shape = self._original_tensor_info.get(k, ("-", "-"))
print(
logger.info(
"{:<64} {:<16} {:<32} {:<16} {:<32}".format(
k, original_dtype, original_shape, str(v.dtype), str(v.shape)
)
Expand Down
18 changes: 15 additions & 3 deletions megatron/core/ssm/gated_delta_net.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from megatron.core.transformer.module import MegatronModule
from megatron.core.transformer.spec_utils import ModuleSpec, build_module
from megatron.core.transformer.utils import (
ensure_metadata_has_dp_cp_group,
make_sharded_tensors_for_checkpoint,
sharded_state_dict_default,
)
Expand Down Expand Up @@ -412,8 +413,11 @@ def _apply_gated_norm(self, x, gate):
y = y.to(x_dtype)
return y

def sharded_state_dict(self, prefix="", sharded_offsets=(), metadata=None):
def sharded_state_dict(self, prefix="", sharded_offsets=(), metadata=None, tp_group=None):
"""Provide a sharded state dictionary for distributed checkpointing."""
# Guard for cases metadata is not provided
metadata = ensure_metadata_has_dp_cp_group(metadata)

sharded_state_dict = {}
# Parameters
self._save_to_state_dict(sharded_state_dict, "", keep_vars=True)
Expand All @@ -425,8 +429,11 @@ def sharded_state_dict(self, prefix="", sharded_offsets=(), metadata=None):
"dt_bias": 0,
}, # parameters sharded across TP
sharded_offsets=sharded_offsets,
tp_group=(tp_group if tp_group is not None else self.pg_collection.tp),
dp_cp_group=metadata['dp_cp_group'],
)
# Submodules
tp_group = tp_group if tp_group is not None else self.pg_collection.tp
for name, module in self.named_children():
if name == "conv1d":
# Add TP sharding for Conv1d
Expand All @@ -435,11 +442,16 @@ def sharded_state_dict(self, prefix="", sharded_offsets=(), metadata=None):
if self.conv_bias:
tp_sharding_map[f"bias"] = 0
module_sharded_sd = make_sharded_tensors_for_checkpoint(
module_sd, f"{prefix}{name}.", tp_sharding_map, sharded_offsets
module_sd,
f"{prefix}{name}.",
tp_sharding_map,
sharded_offsets,
tp_group=tp_group,
dp_cp_group=metadata['dp_cp_group'],
)
else:
module_sharded_sd = sharded_state_dict_default(
module, f"{prefix}{name}.", sharded_offsets, metadata
module, f"{prefix}{name}.", sharded_offsets, metadata, tp_group=tp_group
)

sharded_state_dict.update(module_sharded_sd)
Expand Down
Loading
Loading