Skip to content

Commit 7aed8d2

Browse files
authored
[ckpt] fix: support multi-layer MTP export filtering (#5495)
Signed-off-by: Yu Yao <yaoyu.094@gmail.com>
1 parent a1a6996 commit 7aed8d2

2 files changed

Lines changed: 27 additions & 6 deletions

File tree

‎src/megatron/bridge/models/conversion/auto_bridge.py‎

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,10 @@ def _mtp_source_key_prefixes(source: Any, *configs: Any) -> tuple[str, ...]:
174174
differently:
175175
176176
* DeepSeek-style: a dedicated ``mtp.*`` prefix.
177-
* GLM-4.x ``glm4_moe_lite``: the nextn layer is stored as a regular decoder
178-
layer at index ``num_hidden_layers`` (i.e. one past the last real layer),
179-
so its tensors live under ``model.layers.{num_hidden_layers}.*``.
177+
* GLM-4.x ``glm4_moe_lite`` and Step3.7: nextn layers are stored as regular
178+
decoder layers starting at index ``num_hidden_layers`` (i.e. one past the
179+
last real layer), so their tensors live under consecutive
180+
``model.layers.{layer_index}.*`` prefixes.
180181
181182
When the megatron model is built without an MTP head the generator never
182183
yields these tensors. If they remain in the source sharding map, the shards
@@ -212,9 +213,20 @@ def _mtp_source_key_prefixes(source: Any, *configs: Any) -> tuple[str, ...]:
212213
break
213214

214215
if num_hidden_layers is not _MISSING:
215-
nextn_prefix = f"model.layers.{num_hidden_layers}."
216-
if source.has_glob(f"{nextn_prefix}*"):
217-
prefixes.append(nextn_prefix)
216+
num_nextn_layers = 1
217+
for config in configs:
218+
text_config = _get_config_field(config, "text_config")
219+
config_candidates = (config,) if text_config is _MISSING else (config, text_config)
220+
for config_candidate in config_candidates:
221+
for field in MTP_CONFIG_FIELDS:
222+
value = _get_config_field(config_candidate, field)
223+
if value is not _MISSING and value is not None:
224+
num_nextn_layers = max(num_nextn_layers, int(value))
225+
226+
for layer_index in range(num_hidden_layers, num_hidden_layers + num_nextn_layers):
227+
nextn_prefix = f"model.layers.{layer_index}."
228+
if source.has_glob(f"{nextn_prefix}*"):
229+
prefixes.append(nextn_prefix)
218230

219231
return tuple(prefixes)
220232

‎tests/unit_tests/models/test_auto_bridge.py‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,15 @@ def src(*present_globs):
311311
# Nested text_config carries num_hidden_layers.
312312
assert _mtp_source_key_prefixes(glm_src, {"text_config": {"num_hidden_layers": 47}}) == ("model.layers.47.",)
313313

314+
# Step3.7 stores multiple MTP layers after the regular decoder layers.
315+
step37_src = src("model.layers.45.*", "model.layers.46.*", "model.layers.47.*")
316+
step37_config = {"text_config": {"num_hidden_layers": 45, "num_nextn_predict_layers": 3}}
317+
assert _mtp_source_key_prefixes(step37_src, step37_config) == (
318+
"model.layers.45.",
319+
"model.layers.46.",
320+
"model.layers.47.",
321+
)
322+
314323
# No matching source keys -> nothing to strip.
315324
assert _mtp_source_key_prefixes(src(), {"num_hidden_layers": 47}) == ()
316325

0 commit comments

Comments
 (0)