Skip to content

Commit 4719ba0

Browse files
committed
fix(conversion): preserve legacy model construction paths
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
1 parent fff3669 commit 4719ba0

17 files changed

Lines changed: 131 additions & 22 deletions

File tree

examples/conversion/compare_hf_and_megatron/compare.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,7 @@ def _load_megatron_model(args):
716716
),
717717
**_hf_revision_kwargs(args.hf_revision),
718718
)
719-
if getattr(bridge._model_bridge, "MODEL_CONFIG_CLASS", None) is not None:
719+
if getattr(bridge._model_bridge, "USE_MODEL_CONFIG_FOR_CONVERSION", False):
720720
model_config = bridge.get_model_config()
721721
transformer = model_config.transformer
722722
transformer.tensor_model_parallel_size = tp
@@ -756,7 +756,7 @@ def _load_megatron_model(args):
756756
),
757757
**_hf_revision_kwargs(args.hf_revision),
758758
)
759-
if getattr(bridge._model_bridge, "MODEL_CONFIG_CLASS", None) is not None:
759+
if getattr(bridge._model_bridge, "USE_MODEL_CONFIG_FOR_CONVERSION", False):
760760
model_config = bridge.get_model_config()
761761
transformer = model_config.transformer
762762
transformer.tensor_model_parallel_size = tp

scripts/conversion/gpu_backend.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ def _configure_model_provider(
178178

179179
def _uses_model_builder(bridge: AutoBridge) -> bool:
180180
"""Return whether the selected bridge supports native builder construction."""
181-
return getattr(bridge._model_bridge, "MODEL_CONFIG_CLASS", None) is not None
181+
return getattr(bridge._model_bridge, "USE_MODEL_CONFIG_FOR_CONVERSION", False)
182182

183183

184184
def _configure_model_config(

scripts/inference/vlm_generation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ def _hf_revision_kwargs(revision: str | None) -> dict[str, str]:
151151

152152
def _uses_model_builder(bridge: AutoBridge) -> bool:
153153
"""Return whether the selected bridge supports native builder construction."""
154-
return getattr(bridge._model_bridge, "MODEL_CONFIG_CLASS", None) is not None
154+
return getattr(bridge._model_bridge, "USE_MODEL_CONFIG_FOR_CONVERSION", False)
155155

156156

157157
def _enable_deterministic_execution() -> None:

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1484,7 +1484,7 @@ def import_ckpt(
14841484
with model_context:
14851485
# Prefer the native ModelConfig/ModelBuilder path for migrated model
14861486
# families while preserving the provider path for legacy bridges.
1487-
if bridge._model_bridge.MODEL_CONFIG_CLASS is not None:
1487+
if bridge._model_bridge.USE_MODEL_CONFIG_FOR_CONVERSION:
14881488
model_config = bridge.get_model_config()
14891489
model_config.transformer.use_cpu_initialization = True
14901490
megatron_model = bridge.get_model(

src/megatron/bridge/models/conversion/model_bridge.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,12 @@ def mapping_registry(self) -> MegatronMappingRegistry:
441441
# transformer config class.
442442
MODEL_CONFIG_CLASS: ClassVar[type[ModelConfig] | None] = BridgeGPTModelConfig
443443

444+
# Conversion still uses the provider-backed construction path unless a model family has
445+
# explicitly migrated its conversion lifecycle to ModelBuilder. Keeping this separate
446+
# from MODEL_CONFIG_CLASS preserves get_model_config() for legacy families without
447+
# silently changing how their checkpoints are constructed.
448+
USE_MODEL_CONFIG_FOR_CONVERSION: ClassVar[bool] = False
449+
444450
# Leave unset unless HF export must copy nonstandard files in addition to the usual artifacts,
445451
# for example ``["*reasoning_parser.py"]``.
446452
ADDITIONAL_FILE_PATTERNS = None

src/megatron/bridge/models/conversion/utils.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -256,9 +256,10 @@ def remove_non_pickleables(obj, max_depth: int = 3, current_depth: int = 0):
256256
# Create a copy to avoid modifying the original
257257
cleaned_obj = copy.copy(obj)
258258

259-
for attr_name in list(vars(cleaned_obj).keys()):
260-
attr_value = getattr(cleaned_obj, attr_name)
261-
259+
# Read stored attributes from ``__dict__`` directly. Configuration classes may
260+
# deliberately reject dynamic attribute access for values whose meaning is
261+
# layer-dependent, even though the raw value still needs to be copied for IPC.
262+
for attr_name, attr_value in list(vars(cleaned_obj).items()):
262263
# Recursively clean attribute
263264
cleaned_value = remove_non_pickleables(attr_value, max_depth, current_depth + 1)
264265

src/megatron/bridge/models/muse_glimmer/muse_glimmer_bridge.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ class MuseGlimmerBridge(MegatronModelBridge):
139139
"""Builder-backed bridge for the complete Muse Glimmer multimodal model."""
140140

141141
MODEL_CONFIG_CLASS = MuseGlimmerModelConfig
142+
USE_MODEL_CONFIG_FOR_CONVERSION = True
142143

143144
@staticmethod
144145
def _validate_architecture(hf_config: PretrainedConfig) -> tuple[Any, Any]:

src/megatron/bridge/training/checkpointing.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,12 @@ class _CpuTorchDistSaveShardedStrategy(TorchDistSaveShardedStrategy):
177177
"""Run MCore's synchronous torch-dist writer without a CUDA staging barrier."""
178178

179179
@staticmethod
180-
def _run_cpu_finalize(finalize_fn: Callable[[], None]) -> None:
181-
"""Make MCore's failure-status tensor use the CPU for a Gloo save."""
180+
def _run_finalize(finalize_fn: Callable[[], None]) -> None:
181+
"""Use a backend-compatible device for MCore's failure-status tensor."""
182+
if torch.distributed.is_initialized() and torch.distributed.get_backend() == "nccl":
183+
finalize_fn()
184+
return
185+
182186
current_device = torch.cuda.current_device
183187
try:
184188
torch.cuda.current_device = lambda: torch.device("cpu")
@@ -204,7 +208,7 @@ def save(self, sharded_state_dict: ShardedStateDict, checkpoint_dir: Path) -> No
204208
preload_fn=partial(preload_fn.func, *bound.args, **bound.kwargs),
205209
)
206210
async_request = async_request._replace(
207-
finalize_fns=[partial(self._run_cpu_finalize, finalize_fn) for finalize_fn in async_request.finalize_fns],
211+
finalize_fns=[partial(self._run_finalize, finalize_fn) for finalize_fn in async_request.finalize_fns],
208212
)
209213
async_request.execute_sync()
210214

tests/functional_tests/test_groups/models/nemotron_omni/test_nemotron_omni_conversion.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@
4040
# 52-layer pattern, which keeps a representative mamba (M), MoE-MLP (E) and
4141
# attention (*) layer mix.
4242
_LLM_LAYER_TYPES = ["mamba", "moe", "mamba", "moe", "mamba", "attention"]
43+
# Transformers 5.15 serializes the same hybrid blocks under their canonical names.
44+
_SERIALIZED_LLM_LAYER_TYPES = [
45+
"linear_attention",
46+
"moe",
47+
"linear_attention",
48+
"moe",
49+
"linear_attention",
50+
"full_attention",
51+
]
4352
_LLM_OVERRIDES = {
4453
"hybrid_override_pattern": "MEMEM*",
4554
"layer_types": _LLM_LAYER_TYPES,
@@ -220,5 +229,5 @@ def test_nemotron_omni_conversion_roundtrip(self, nemotron_omni_toy_model_path,
220229
assert "vision_config" in saved_config
221230
assert "sound_config" in saved_config
222231
assert saved_config["llm_config"]["num_hidden_layers"] == 6
223-
assert saved_config["llm_config"]["layer_types"] == _LLM_LAYER_TYPES
224-
assert saved_config["llm_config"]["layers_block_type"] == _LLM_LAYER_TYPES
232+
assert saved_config["llm_config"]["layer_types"] == _SERIALIZED_LLM_LAYER_TYPES
233+
assert saved_config["llm_config"]["layers_block_type"] == _SERIALIZED_LLM_LAYER_TYPES

tests/unit_tests/conversion/launcher/test_gpu_backend.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ def provide_distributed_model(self, *args, **kwargs):
115115

116116
class _FakeModelBridge:
117117
MODEL_CONFIG_CLASS = None
118+
USE_MODEL_CONFIG_FOR_CONVERSION = False
118119

119120
def get_hf_tokenizer_kwargs(self):
120121
return {"padding_side": "left"}
@@ -191,6 +192,7 @@ def test_import_uses_builder_for_migrated_model(self, cli, monkeypatch):
191192

192193
class BuilderModelBridge(_FakeModelBridge):
193194
MODEL_CONFIG_CLASS = object
195+
USE_MODEL_CONFIG_FOR_CONVERSION = True
194196

195197
class FakeBridge:
196198
_model_bridge = BuilderModelBridge()

0 commit comments

Comments
 (0)