Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ee72023
enable deepseekv4 with hybrid models on dev branch
guihong-nv May 28, 2026
0fbaa46
Merge branch 'dev' of https://github.com/NVIDIA/Megatron-LM into dev_…
guihong-nv May 28, 2026
234f316
fix linting issues
guihong-nv May 28, 2026
8890789
fix linting issues
guihong-nv May 28, 2026
d37d8fd
fix the e2e training issues
Jun 1, 2026
7e4344a
update the unit test
Jun 1, 2026
91033fe
fix the reviews for claude
guihong-nv Jun 1, 2026
1fab8ba
fix the linting issues
guihong-nv Jun 1, 2026
3b5e6d9
Merge branch 'dev' into dev_hybrid_dsv4
guihong-nv Jun 1, 2026
00a5cb0
address the comments
guihong-nv Jun 2, 2026
546ae6c
add the support for sliding window attention only
guihong-nv Jun 3, 2026
ca3ddb0
Merge branch 'dev' into dev_hybrid_dsv4
guihong-nv Jun 3, 2026
d17fcc2
remove csa_block_sizes
guihong-nv Jun 3, 2026
03d2540
fix linting issues
guihong-nv Jun 3, 2026
6742859
fix linting issues
guihong-nv Jun 3, 2026
b702138
fix linting issues
guihong-nv Jun 3, 2026
0a570d3
fix(mHC): make HybridStack mHC wrapper CUDA-graph capturable
Connor-XY Jun 4, 2026
15209ed
Merge branch 'dev' into dev_hybrid_dsv4
guihong-nv Jun 9, 2026
5aa1255
Merge branch 'dev' into dev_hybrid_dsv4
guihong-nv Jun 9, 2026
0e641e7
remvoe dynamic compile flag
guihong-nv Jun 9, 2026
eda900e
fix linting issues
guihong-nv Jun 9, 2026
6386220
Merge branch 'dev' into dev_hybrid_dsv4
guihong-nv Jun 10, 2026
bcd9a4f
Merge branch 'dev' into dev_hybrid_dsv4
hxbai Jun 12, 2026
b099b89
remove duplicated args
guihong-nv Jun 12, 2026
7ff5ac0
add the moe hash support
guihong-nv Jun 14, 2026
8090aa2
fix linting issue
guihong-nv Jun 14, 2026
b923459
Merge branch 'dev' into dev_hybrid_dsv4
guihong-nv Jun 15, 2026
cdecf57
feat(mHC): CUDA-graph the MoE-wrapped hybrid layers (router/preprocess)
Connor-XY Jun 15, 2026
54556ea
fix(mHC): rebase fixups for MoE-wrapped CUDA-graph capture
Connor-XY Jun 15, 2026
f360b25
Merge branch 'dev' into dev_hybrid_dsv4
guihong-nv Jun 15, 2026
69abeed
fix the mtp unit test issues
guihong-nv Jun 15, 2026
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
55 changes: 53 additions & 2 deletions hybrid_builders.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

from megatron.core.models.hybrid.hybrid_layer_specs import hybrid_inference_stack_spec
from megatron.core.models.hybrid.hybrid_model import HybridModel
from megatron.core.transformer import TransformerConfig
from megatron.core.transformer.spec_utils import import_module
from megatron.core.transformer import MLATransformerConfig, TransformerConfig
from megatron.core.transformer.spec_utils import ModuleSpec, import_module
from megatron.training import print_rank_0
from megatron.training.arguments import core_transformer_config_from_args
from model_provider import count_parameters_in_layer
Expand All @@ -13,6 +13,52 @@ def hybrid_builder(args, pre_process, post_process, vp_stage=None, config=None,
print_rank_0('building Hybrid model ...')
if config is None:
config = core_transformer_config_from_args(args, TransformerConfig)
# MLA (and DSv4 hybrid) require MLATransformerConfig so that its __post_init__ runs
# the dsv4_hybrid derivation. The hybrid pretrain path can hand us a plain
# TransformerConfig, which silently skips that derivation; rebuild as MLA to match GPT.
if args.multi_latent_attention and not isinstance(config, MLATransformerConfig):
config = core_transformer_config_from_args(args)
# DSv4-hybrid head-dim contract: qk_head_dim and kv_lora_rank are derived from
# v_head_dim and qk_pos_emb_head_dim (MLATransformerConfig.__post_init__ does this for the
# GPT path). The hybrid config can reach here without that derivation applied, which breaks
# the MLA up-proj / fused-rope contract (q head dim must equal qk_head_dim + qk_pos_emb_head
# _dim == v_head_dim). Apply it for any DSv4 MLA attention: experimental_attention_variant
# == dsv4_hybrid, OR the layer pattern uses a DSv4 attention symbol (D/C/H/W). Idempotent.
_pattern = getattr(args, "hybrid_layer_pattern", None) or ""
_uses_dsv4_attn = (
getattr(args, "experimental_attention_variant", None) == "dsv4_hybrid"
or any(sym in _pattern for sym in ("C", "H", "W"))
)
Comment thread
hxbai marked this conversation as resolved.
if _uses_dsv4_attn:
derived = config.v_head_dim - config.qk_pos_emb_head_dim
if config.qk_head_dim != derived or config.kv_lora_rank != derived:
print_rank_0(
f"[hybrid dsv4] deriving qk_head_dim/kv_lora_rank = {config.v_head_dim} - "
f"{config.qk_pos_emb_head_dim} = {derived} (was qk_head_dim={config.qk_head_dim}, "
f"kv_lora_rank={config.kv_lora_rank})"
)
config.qk_head_dim = derived
config.kv_lora_rank = derived
# 'C'/'H'/'W' layers carry their compress ratio via the spec, but array-driven 'D' layers
# AND the indexer-loss logger (which counts ratio==4 layers) read
# config.csa_compress_ratios. When not given explicitly, derive it from the pattern
# symbols (C->4, H->128, W/D/other->0) so the array is consistent with the symbols and
# the indexer loss is normalized correctly; pad MTP depths with 0. An explicit
# --csa-compress-ratios is always respected.
if config.csa_compress_ratios is None:
ratio_map = {"C": 4, "H": 128}
# One entry per ACTUAL layer: main layers, then every MTP layer of every MTP depth
# (a depth can hold multiple hybrid layers, e.g. "/MD-E"), mirroring the arguments.py
# derivation. Padding by mtp_num_layers (depth count) would be too short and an MTP
# attention that isn't first would IndexError at num_layers + layer_number - 1.
sections = _pattern.split("/")
ratios = [ratio_map.get(c, 0) for c in sections[0].replace("|", "")]
for mtp_sec in sections[1:]:
ratios += [ratio_map.get(c, 0) for c in mtp_sec.replace("|", "")]
config.csa_compress_ratios = ratios
print_rank_0(
f"[hybrid dsv4] derived csa_compress_ratios from pattern symbols: {ratios}"
)

if config.transformer_impl == "inference_optimized":
hybrid_stack_spec = hybrid_inference_stack_spec
Expand All @@ -21,6 +67,11 @@ def hybrid_builder(args, pre_process, post_process, vp_stage=None, config=None,
), "inference_fuse_tp_communication is not supported for HybridModel"
elif args.spec is not None:
hybrid_stack_spec = import_module(args.spec)
# Allow config-aware specs: if --spec resolves to a callable (not a ModuleSpec),
# call it with config to build the stack spec (e.g. hybrid_dsv4_stack_spec, which
# wires the DSv4 CompressedSparseAttention into the 'D' layer per config).
if not isinstance(hybrid_stack_spec, ModuleSpec) and callable(hybrid_stack_spec):
hybrid_stack_spec = hybrid_stack_spec(config)
else:
raise ValueError("You must provide a valid hybrid layer spec via --spec")

Expand Down
28 changes: 22 additions & 6 deletions megatron/core/extensions/transformer_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -2011,12 +2011,28 @@ def __init__(
tp_group_for_te = None

if is_te_min_version("2.14.0"):
extra_kwargs["single_grouped_weight"] = getattr(
config, "moe_single_grouped_weight", False
)
extra_kwargs["single_grouped_bias"] = getattr(
config, "moe_single_grouped_bias", False
)
# nemo_26.04 ships TE 2.14.0+71bbefbf whose GroupedLinear.__init__ does NOT
# yet accept single_grouped_{weight,bias}, even though the version string
# passes is_te_min_version("2.14.0"). Introspect the signature instead of
# version-gating, mirroring the patch in dsv4_fused_attn / main_megatron.
# The GroupedLinear.__init__ signature is constant for a given TE install, so
# introspect once and cache at module scope rather than on every TEGroupedLinear
# instantiation (matters for large MoE models with many expert groups).
global _TE_GROUPED_LINEAR_INIT_PARAMS
try:
_gl_params = _TE_GROUPED_LINEAR_INIT_PARAMS
except NameError:
_gl_params = _TE_GROUPED_LINEAR_INIT_PARAMS = set(
inspect.signature(te.pytorch.GroupedLinear.__init__).parameters
)
if "single_grouped_weight" in _gl_params:
extra_kwargs["single_grouped_weight"] = getattr(
config, "moe_single_grouped_weight", False
)
if "single_grouped_bias" in _gl_params:
extra_kwargs["single_grouped_bias"] = getattr(
config, "moe_single_grouped_bias", False
)
Comment thread
guihong-nv marked this conversation as resolved.

self.te_quant_params: Optional[TEQuantizationParams] = None
quant_config = get_quant_config_or_none(name, config.quant_recipe)
Expand Down
Loading
Loading