@@ -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
0 commit comments