mcore-bridge 1.6.4__tar.gz → 1.8.0.dev0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/PKG-INFO +5 -5
  2. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/README.md +2 -2
  3. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/setup.py +3 -0
  4. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/__init__.py +6 -6
  5. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/bridge/gpt_bridge.py +170 -12
  6. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/config/__init__.py +1 -1
  7. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/config/model_config.py +108 -55
  8. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/config/parser.py +146 -3
  9. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/__init__.py +1 -0
  10. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/constant.py +5 -0
  11. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/gpt_model.py +92 -99
  12. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/gpts/deepseek_v4.py +81 -20
  13. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/gpts/glm4.py +4 -4
  14. mcore_bridge-1.8.0.dev0/src/mcore_bridge/model/gpts/glm_moe_dsa.py +41 -0
  15. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/gpts/llm.py +1 -0
  16. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/gpts/minimax_m2.py +4 -5
  17. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/gpts/nemotron_h.py +33 -33
  18. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/gpts/olmoe.py +4 -5
  19. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/gpts/qwen3_next.py +14 -29
  20. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/gpts/qwen3_next_gdn.py +26 -4
  21. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/gpts/qwen4_exp.py +294 -23
  22. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/hybrid_model.py +30 -5
  23. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/mm_gpt_model.py +29 -4
  24. mcore_bridge-1.8.0.dev0/src/mcore_bridge/model/mm_gpts/__init__.py +3 -0
  25. mcore_bridge-1.8.0.dev0/src/mcore_bridge/model/mm_gpts/deepseek_v41.py +1852 -0
  26. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/mm_gpts/gemma4.py +82 -19
  27. mcore_bridge-1.8.0.dev0/src/mcore_bridge/model/mm_gpts/glm5_next.py +726 -0
  28. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/mm_gpts/llama4.py +4 -11
  29. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/mm_gpts/muse_glimmer.py +1 -0
  30. mcore_bridge-1.8.0.dev0/src/mcore_bridge/model/mm_gpts/nemo_speechlm.py +328 -0
  31. mcore_bridge-1.8.0.dev0/src/mcore_bridge/model/mm_gpts/nemotron_h_omni.py +379 -0
  32. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/mm_gpts/qwen3_5.py +2 -0
  33. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/mm_gpts/qwen3_5_gdn.py +2 -0
  34. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/mm_gpts/qwen4_exp.py +2 -0
  35. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/mm_gpts/utils.py +28 -2
  36. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/modules/__init__.py +4 -2
  37. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/modules/absorbed_mla.py +2 -6
  38. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/modules/dsa_indexer.py +2 -9
  39. mcore_bridge-1.8.0.dev0/src/mcore_bridge/model/modules/dspark.py +447 -0
  40. mcore_bridge-1.8.0.dev0/src/mcore_bridge/model/modules/engram.py +431 -0
  41. mcore_bridge-1.8.0.dev0/src/mcore_bridge/model/modules/engram_fp8.py +239 -0
  42. mcore_bridge-1.8.0.dev0/src/mcore_bridge/model/modules/gated_delta_net.py +493 -0
  43. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/modules/gated_self_attention.py +1 -5
  44. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/modules/kernels/__init__.py +3 -1
  45. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/modules/kernels/ple_kernels.py +17 -14
  46. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/modules/kernels/qsa_block_sparse_attn.py +71 -107
  47. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/modules/kernels/qsa_kernels.py +155 -39
  48. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/modules/ple.py +116 -42
  49. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/modules/qsa_indexer.py +68 -21
  50. mcore_bridge-1.8.0.dev0/src/mcore_bridge/model/modules/topk_router.py +77 -0
  51. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/modules/transformer_block.py +8 -9
  52. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/modules/transformer_layer.py +70 -17
  53. mcore_bridge-1.8.0.dev0/src/mcore_bridge/model/mtp.py +711 -0
  54. mcore_bridge-1.8.0.dev0/src/mcore_bridge/model/mtp_detect.py +188 -0
  55. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/register.py +112 -64
  56. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/patcher.py +0 -65
  57. mcore_bridge-1.8.0.dev0/src/mcore_bridge/patches/megatron_glm53_dev.patch +592 -0
  58. mcore_bridge-1.8.0.dev0/src/mcore_bridge/tools/__init__.py +1 -0
  59. mcore_bridge-1.8.0.dev0/src/mcore_bridge/tools/apply_megatron_patch.py +210 -0
  60. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/tuners/lora.py +78 -98
  61. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/tuners/npu_lora.py +27 -20
  62. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/tuners/patcher.py +10 -1
  63. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/utils/__init__.py +2 -1
  64. mcore_bridge-1.8.0.dev0/src/mcore_bridge/utils/constants.py +6 -0
  65. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/utils/megatron_utils.py +38 -141
  66. mcore_bridge-1.8.0.dev0/src/mcore_bridge/utils/quantizer.py +95 -0
  67. mcore_bridge-1.8.0.dev0/src/mcore_bridge/utils/qwen4_exp_checkpoint.py +395 -0
  68. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/utils/safetensors.py +19 -2
  69. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/version.py +2 -2
  70. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge.egg-info/PKG-INFO +5 -5
  71. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge.egg-info/SOURCES.txt +54 -2
  72. mcore_bridge-1.8.0.dev0/src/mcore_bridge.egg-info/requires.txt +6 -0
  73. mcore_bridge-1.8.0.dev0/tests/test_apply_megatron_patch.py +280 -0
  74. mcore_bridge-1.8.0.dev0/tests/test_deepseek_v41_block32_loading.py +144 -0
  75. mcore_bridge-1.8.0.dev0/tests/test_deepseek_v41_engram.py +988 -0
  76. mcore_bridge-1.8.0.dev0/tests/test_deepseek_v41_hybrid.py +598 -0
  77. mcore_bridge-1.8.0.dev0/tests/test_deepseek_v41_language_only_preprocess.py +114 -0
  78. mcore_bridge-1.8.0.dev0/tests/test_deepseek_v41_packing_cp.py +194 -0
  79. mcore_bridge-1.8.0.dev0/tests/test_dsv4_layer_spec_builders.py +102 -0
  80. mcore_bridge-1.8.0.dev0/tests/test_dsv4_mla_rope.py +46 -0
  81. mcore_bridge-1.8.0.dev0/tests/test_engram_fp8_tables.py +262 -0
  82. mcore_bridge-1.8.0.dev0/tests/test_engram_fp8_upstream.py +219 -0
  83. mcore_bridge-1.8.0.dev0/tests/test_gdn_sp_projection_params.py +173 -0
  84. mcore_bridge-1.8.0.dev0/tests/test_gemma4_ffpa_attn.py +263 -0
  85. mcore_bridge-1.8.0.dev0/tests/test_gemma4_per_layer_config.py +96 -0
  86. mcore_bridge-1.8.0.dev0/tests/test_glm5_hybrid.py +401 -0
  87. mcore_bridge-1.8.0.dev0/tests/test_glm5_next.py +1448 -0
  88. mcore_bridge-1.8.0.dev0/tests/test_hybrid_compat.py +144 -0
  89. mcore_bridge-1.8.0.dev0/tests/test_lora_replicated_base.py +158 -0
  90. mcore_bridge-1.8.0.dev0/tests/test_lora_row_parallel.py +94 -0
  91. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/tests/test_mllm.py +5 -1
  92. mcore_bridge-1.8.0.dev0/tests/test_mtp_capabilities.py +134 -0
  93. mcore_bridge-1.8.0.dev0/tests/test_mtp_checkpoint.py +235 -0
  94. mcore_bridge-1.8.0.dev0/tests/test_mtp_detection.py +190 -0
  95. mcore_bridge-1.8.0.dev0/tests/test_mtp_layout_spec.py +267 -0
  96. mcore_bridge-1.8.0.dev0/tests/test_mtp_runtime.py +557 -0
  97. mcore_bridge-1.8.0.dev0/tests/test_nemo_speechlm.py +646 -0
  98. mcore_bridge-1.8.0.dev0/tests/test_nemotron_omni.py +582 -0
  99. mcore_bridge-1.8.0.dev0/tests/test_npu_grouped_lora_expert_params.py +39 -0
  100. mcore_bridge-1.8.0.dev0/tests/test_ple_checkpoint.py +147 -0
  101. mcore_bridge-1.8.0.dev0/tests/test_ple_cp_grad.py +170 -0
  102. mcore_bridge-1.8.0.dev0/tests/test_ple_kernels.py +131 -0
  103. mcore_bridge-1.8.0.dev0/tests/test_ple_sp_tp_grad.py +281 -0
  104. mcore_bridge-1.8.0.dev0/tests/test_qsa_indexer.py +168 -0
  105. mcore_bridge-1.8.0.dev0/tests/test_qsa_packed_documents.py +58 -0
  106. mcore_bridge-1.8.0.dev0/tests/test_qsa_sparse_kernels.py +203 -0
  107. mcore_bridge-1.8.0.dev0/tests/test_qsa_tile_index.py +141 -0
  108. mcore_bridge-1.8.0.dev0/tests/test_qwen4_exp_checkpoint.py +635 -0
  109. mcore_bridge-1.8.0.dev0/tests/test_qwen4_exp_mtp.py +382 -0
  110. mcore_bridge-1.8.0.dev0/tests/test_qwen4_exp_peft_export.py +147 -0
  111. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/tests/test_qwen4_exp_units.py +13 -3
  112. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/tests/test_save_missing_weights_dsv4.py +54 -33
  113. mcore_bridge-1.8.0.dev0/tests/test_split_cp_inputs.py +83 -0
  114. mcore_bridge-1.8.0.dev0/tests/test_vision_token_provenance.py +68 -0
  115. mcore_bridge-1.6.4/src/mcore_bridge/model/gpts/glm_moe_dsa.py +0 -50
  116. mcore_bridge-1.6.4/src/mcore_bridge/model/mm_gpts/__init__.py +0 -3
  117. mcore_bridge-1.6.4/src/mcore_bridge/model/modules/gated_delta_net.py +0 -502
  118. mcore_bridge-1.6.4/src/mcore_bridge/model/modules/mtp_layer.py +0 -453
  119. mcore_bridge-1.6.4/src/mcore_bridge/model/modules/topk_router.py +0 -21
  120. mcore_bridge-1.6.4/src/mcore_bridge.egg-info/requires.txt +0 -6
  121. mcore_bridge-1.6.4/tests/test_qsa_indexer.py +0 -67
  122. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/LICENSE +0 -0
  123. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/setup.cfg +0 -0
  124. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/bridge/__init__.py +0 -0
  125. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/gpts/__init__.py +0 -0
  126. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/gpts/bailing_hybrid.py +0 -0
  127. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/gpts/bailing_moe.py +0 -0
  128. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/gpts/hunyuan.py +0 -0
  129. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/gpts/qwen3_emb.py +0 -0
  130. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/mm_gpts/glm.py +0 -0
  131. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/mm_gpts/internvl.py +0 -0
  132. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/mm_gpts/kimi_vl.py +0 -0
  133. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/mm_gpts/llava.py +0 -0
  134. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/mm_gpts/minicpmv4_6.py +0 -0
  135. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/mm_gpts/qwen.py +0 -0
  136. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/mm_gpts/qwen3_asr.py +0 -0
  137. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/mm_gpts/qwen3_omni.py +0 -0
  138. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/mm_gpts/qwen3_vl.py +0 -0
  139. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/modules/compressor.py +0 -0
  140. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/modules/hyper_connection_gated.py +0 -0
  141. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/modules/multi_latent_attention.py +0 -0
  142. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/model/rope.py +0 -0
  143. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/tuners/__init__.py +0 -0
  144. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/tuners/utils.py +0 -0
  145. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/utils/dequantizer.py +0 -0
  146. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/utils/env.py +0 -0
  147. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/utils/import_utils.py +0 -0
  148. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/utils/logger.py +0 -0
  149. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/utils/torch_utils.py +0 -0
  150. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge/utils/utils.py +0 -0
  151. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge.egg-info/dependency_links.txt +0 -0
  152. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge.egg-info/not-zip-safe +0 -0
  153. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/src/mcore_bridge.egg-info/top_level.txt +0 -0
  154. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/tests/test_llm.py +0 -0
  155. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/tests/test_ple_fp8_scale.py +0 -0
  156. {mcore_bridge-1.6.4 → mcore_bridge-1.8.0.dev0}/tests/test_save_missing_weights.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mcore_bridge
3
- Version: 1.6.4
3
+ Version: 1.8.0.dev0
4
4
  Summary: MCore-Bridge: Making Megatron training as simple as Transformers
5
5
  Home-page: https://github.com/modelscope/mcore-bridge
6
6
  Author: ModelScope teams
@@ -19,12 +19,12 @@ Classifier: Programming Language :: Python :: 3.12
19
19
  Requires-Python: >=3.8.0
20
20
  Description-Content-Type: text/markdown
21
21
  License-File: LICENSE
22
- Requires-Dist: megatron-core<0.20,>=0.16
22
+ Requires-Dist: megatron-core<0.21,>=0.18
23
23
  Requires-Dist: modelscope
24
24
  Requires-Dist: peft<0.21,>=0.11
25
25
  Requires-Dist: safetensors
26
26
  Requires-Dist: tqdm
27
- Requires-Dist: transformers<5.17.0,>=4.33
27
+ Requires-Dist: transformers>=4.33
28
28
 
29
29
  # MCore-Bridge: Making Megatron training as simple as Transformers
30
30
 
@@ -48,7 +48,7 @@ Requires-Dist: transformers<5.17.0,>=4.33
48
48
  <p align="center">
49
49
  <img src="https://img.shields.io/badge/python-3.12-5be.svg">
50
50
  <img src="https://img.shields.io/badge/pytorch-%E2%89%A52.0-orange.svg">
51
- <a href="https://github.com/NVIDIA/Megatron-LM/"><img src="https://img.shields.io/badge/megatron--core-%E2%89%A50.16-76B900.svg"></a>
51
+ <a href="https://github.com/NVIDIA/Megatron-LM/"><img src="https://img.shields.io/badge/megatron--core-%E2%89%A50.18-76B900.svg"></a>
52
52
  <!-- <a href="https://mcore-bridge.readthedocs.io/en/latest/"><img src="https://img.shields.io/badge/docs-latest-blue.svg"></a> -->
53
53
  <a href="https://pypi.org/project/mcore-bridge/"><img src="https://badge.fury.io/py/mcore-bridge.svg"></a>
54
54
  <a href="https://github.com/modelscope/mcore-bridge/blob/main/LICENSE"><img src="https://img.shields.io/github/license/modelscope/mcore-bridge"></a>
@@ -138,7 +138,7 @@ Recommended Runtime Environment:
138
138
  | torch | >=2.0 | 2.8.0/2.11.0 | |
139
139
  | transformer-engine | >=2.3 | 2.14.1 | |
140
140
  | apex | | 0.1 | Optional |
141
- | megatron-core | >=0.16,<0.20 | 0.17.1 | |
141
+ | megatron-core | >=0.18,<0.21 | 0.19.2 | |
142
142
  | flash-attn | | 2.8.3/3.0.0b1 | Optional |
143
143
  | transformers | >=4.33 | 4.57.6/5.8.1 | |
144
144
  | modelscope | >=1.23 | | |
@@ -20,7 +20,7 @@
20
20
  <p align="center">
21
21
  <img src="https://img.shields.io/badge/python-3.12-5be.svg">
22
22
  <img src="https://img.shields.io/badge/pytorch-%E2%89%A52.0-orange.svg">
23
- <a href="https://github.com/NVIDIA/Megatron-LM/"><img src="https://img.shields.io/badge/megatron--core-%E2%89%A50.16-76B900.svg"></a>
23
+ <a href="https://github.com/NVIDIA/Megatron-LM/"><img src="https://img.shields.io/badge/megatron--core-%E2%89%A50.18-76B900.svg"></a>
24
24
  <!-- <a href="https://mcore-bridge.readthedocs.io/en/latest/"><img src="https://img.shields.io/badge/docs-latest-blue.svg"></a> -->
25
25
  <a href="https://pypi.org/project/mcore-bridge/"><img src="https://badge.fury.io/py/mcore-bridge.svg"></a>
26
26
  <a href="https://github.com/modelscope/mcore-bridge/blob/main/LICENSE"><img src="https://img.shields.io/github/license/modelscope/mcore-bridge"></a>
@@ -110,7 +110,7 @@ Recommended Runtime Environment:
110
110
  | torch | >=2.0 | 2.8.0/2.11.0 | |
111
111
  | transformer-engine | >=2.3 | 2.14.1 | |
112
112
  | apex | | 0.1 | Optional |
113
- | megatron-core | >=0.16,<0.20 | 0.17.1 | |
113
+ | megatron-core | >=0.18,<0.21 | 0.19.2 | |
114
114
  | flash-attn | | 2.8.3/3.0.0b1 | Optional |
115
115
  | transformers | >=4.33 | 4.57.6/5.8.1 | |
116
116
  | modelscope | >=1.23 | | |
@@ -45,6 +45,9 @@ if __name__ == '__main__':
45
45
  url='https://github.com/modelscope/mcore-bridge',
46
46
  package_dir={'': 'src'},
47
47
  packages=find_packages('src'),
48
+ # The Megatron patch for GLM-5.3 ships inside the package so an installed mcore-bridge can
49
+ # apply it (see mcore_bridge/tools/apply_megatron_patch.py).
50
+ package_data={'mcore_bridge': ['patches/*.patch']},
48
51
  python_requires='>=3.8.0',
49
52
  classifiers=[
50
53
  'Development Status :: 4 - Beta',
@@ -9,18 +9,18 @@ apply_patch()
9
9
 
10
10
  if TYPE_CHECKING:
11
11
  from .bridge import GPTBridge
12
- from .config import ModelConfig, hf_to_mcore_config
13
- from .model import get_mcore_model
12
+ from .config import MLAModelConfig, ModelConfig, hf_to_mcore_config
13
+ from .model import get_mcore_model, resolve_mtp_config, resolve_mtp_num_layers
14
14
  from .tuners import LoraParallelLinear
15
- from .utils import get_logger, set_random_seed, split_cp_inputs, unwrap_model
15
+ from .utils import get_logger, set_random_seed, split_cp_inputs
16
16
  from .version import __release_datetime__, __version__
17
17
  else:
18
18
  _import_structure = {
19
19
  'bridge': ['GPTBridge'],
20
- 'config': ['ModelConfig', 'hf_to_mcore_config'],
21
- 'model': ['get_mcore_model'],
20
+ 'config': ['MLAModelConfig', 'ModelConfig', 'hf_to_mcore_config'],
21
+ 'model': ['get_mcore_model', 'resolve_mtp_config', 'resolve_mtp_num_layers'],
22
22
  'tuners': ['LoraParallelLinear'],
23
- 'utils': ['get_logger', 'set_random_seed', 'split_cp_inputs', 'unwrap_model'],
23
+ 'utils': ['get_logger', 'set_random_seed', 'split_cp_inputs'],
24
24
  'version': ['__release_datetime__', '__version__'],
25
25
  }
26
26
 
@@ -7,6 +7,7 @@ import torch.distributed as dist
7
7
  import torch.nn.functional as F
8
8
  from contextlib import contextmanager
9
9
  from megatron.core import mpu
10
+ from megatron.core.utils import unwrap_model
10
11
  from peft import PeftModel
11
12
  from peft.utils import ModulesToSaveWrapper
12
13
  from tqdm import tqdm
@@ -17,7 +18,8 @@ from typing import Callable, List, Optional, Union
17
18
  from mcore_bridge.config import ModelConfig
18
19
  from mcore_bridge.tuners import LoraParallelLinear
19
20
  from mcore_bridge.utils import (MxFp4Dequantizer, PackedDequantizer, SafetensorLazyLoader, StreamingSafetensorSaver,
20
- deep_getattr, gc_collect, get_logger, is_master, unwrap_model)
21
+ deep_getattr, gc_collect, get_logger, is_master)
22
+ from mcore_bridge.utils.constants import EXPORT_CHUNK_BYTES
21
23
 
22
24
  logger = get_logger()
23
25
 
@@ -28,6 +30,9 @@ EP_PP_RANK = None
28
30
 
29
31
  class GPTBridge:
30
32
  fp8_block_size = 128
33
+ # Bound the per-collective GPU buffer when a full gathered tensor is
34
+ # streamed to CPU (checkpoint save / CPU-offloaded weight sync).
35
+ export_chunk_bytes = EXPORT_CHUNK_BYTES
31
36
  hf_layers_prefix = 'model.layers'
32
37
  hf_mtp_prefix = 'model.layers'
33
38
  hf_embed_key = 'model.embed_tokens.weight'
@@ -51,6 +56,11 @@ class GPTBridge:
51
56
  additional_dim1_keys = set()
52
57
  _support_hf_grouped_lora = True
53
58
 
59
+ def __deepcopy__(self, memo):
60
+ # Bridges hold process groups; per-layer config copies must share, not copy, them.
61
+ memo[id(self)] = self
62
+ return self
63
+
54
64
  def __init__(self, config: ModelConfig):
55
65
  self.config = config
56
66
  self._disable_tqdm = False
@@ -336,11 +346,57 @@ class GPTBridge:
336
346
  hf_state_dict[k] = v.to(self._target_device)
337
347
  return self._add_prefix(hf_state_dict, hf_prefix)
338
348
 
349
+ def _stream_to_cpu(self) -> bool:
350
+ """Whether large gathers/broadcasts should be chunked straight into host
351
+ memory. Enabled when the exported tensor is requested on CPU (checkpoint
352
+ save / CPU-offloaded weight sync): materializing the full gathered tensor
353
+ on GPU can OOM while the training state is still resident. The decision
354
+ only depends on properties identical across the group, so the collective
355
+ sequence stays in sync on every rank. Every participating rank still
356
+ assembles the full CPU result (matching the pre-chunking semantics); only
357
+ the GPU-resident full-size buffer is avoided."""
358
+ return self._target_device == 'cpu'
359
+
360
+ def _chunk_rows(self, shape, elem_size: int) -> int:
361
+ """Rows (along dim0) per broadcast/gather chunk, ~export_chunk_bytes."""
362
+ inner = 1
363
+ for s in shape[1:]:
364
+ inner *= s
365
+ rows = max(1, self.export_chunk_bytes // max(1, inner * elem_size))
366
+ return max(1, min(rows, shape[0]))
367
+
368
+ def _chunked_all_gather_tp(self, tensor, tp_dim: int, tp_group, tp_size: int):
369
+ """All-gather `tensor` along tp_dim and assemble the result in host memory
370
+ chunk by chunk, so the full gathered tensor never exists on GPU at once.
371
+ The chunk count derives from the local shape, which is identical on every
372
+ rank of the group, so the collective sequence stays in sync."""
373
+ dim_size = tensor.shape[tp_dim]
374
+ chunk_bytes = max(1, self.export_chunk_bytes // tp_size)
375
+ inner_rows = max(1, chunk_bytes // max(1, tensor.numel() // dim_size * tensor.element_size()))
376
+ out_shape = list(tensor.shape)
377
+ out_shape[tp_dim] = dim_size * tp_size
378
+ output = torch.empty(out_shape, dtype=tensor.dtype, device='cpu')
379
+ for start in range(0, dim_size, inner_rows):
380
+ end = min(dim_size, start + inner_rows)
381
+ local = tensor.narrow(tp_dim, start, end - start).contiguous()
382
+ gathered = [torch.empty_like(local) for _ in range(tp_size)]
383
+ dist.all_gather(gathered, local, group=tp_group)
384
+ del local
385
+ for j in range(tp_size):
386
+ dst = tuple(
387
+ slice(j * dim_size + start, j * dim_size + end) if ax == tp_dim else slice(None)
388
+ for ax in range(tensor.ndim))
389
+ output[dst] = gathered[j].cpu()
390
+ del gathered
391
+ return output
392
+
339
393
  def _all_gather_tp(self, tensor, tp_dim, is_expert):
340
394
  tensor = None if tensor is None else tensor.to('cuda')
341
395
  tp_size = self.etp_size if is_expert else self.tp_size
342
396
  tp_group = self.etp_group if is_expert else self.tp_group
343
397
  if tensor is not None and tp_dim is not None and tp_size > 1:
398
+ if self._stream_to_cpu() and tensor.numel() * tensor.element_size() > self.export_chunk_bytes:
399
+ return self._chunked_all_gather_tp(tensor, tp_dim, tp_group, tp_size)
344
400
  if tp_dim == 0:
345
401
  # save memory
346
402
  tensor_shape = list(tensor.shape)
@@ -363,6 +419,33 @@ class GPTBridge:
363
419
  del output
364
420
  return tensor
365
421
 
422
+ def _chunked_broadcast_pp(self, tensor, shape, dtype, src_rank: int, pp_group):
423
+ """Chunked pp/ep-pp broadcast (the pp counterpart of _chunked_all_gather_tp):
424
+ stream the tensor chunk by chunk instead of materializing the full buffer
425
+ on GPU. On the holder rank `tensor` carries the data and is returned
426
+ as-is; receivers pass `shape`/`dtype` from the already-broadcast meta and
427
+ assemble the result in host memory (ranks that do not keep the export
428
+ still join every collective but skip the host assembly). Both sides
429
+ derive the same chunk count from the meta shape."""
430
+ rows = self._chunk_rows(shape, torch.tensor([], dtype=dtype).element_size())
431
+ if tensor is not None:
432
+ for start in range(0, shape[0], rows):
433
+ end = min(shape[0], start + rows)
434
+ send = tensor[start:end]
435
+ if not send.is_cuda or send.dtype != dtype or not send.is_contiguous():
436
+ send = send.to(device='cuda', dtype=dtype).contiguous()
437
+ dist.broadcast(send, src=src_rank, group=pp_group)
438
+ return tensor
439
+ output = torch.empty(shape, dtype=dtype, device='cpu')
440
+ buf = None
441
+ for start in range(0, shape[0], rows):
442
+ end = min(shape[0], start + rows)
443
+ if buf is None or buf.shape[0] != end - start:
444
+ buf = torch.empty([end - start] + list(shape[1:]), device='cuda', dtype=dtype)
445
+ dist.broadcast(buf, src=src_rank, group=pp_group)
446
+ output[start:end] = buf.cpu()
447
+ return output
448
+
366
449
  def _broadcast_ep_pp(self, tensor, is_expert):
367
450
  pp_group = self.ep_pp_group if is_expert else self.pp_group
368
451
  pp_size = self.ep_pp_size if is_expert else self.pp_size
@@ -373,12 +456,20 @@ class GPTBridge:
373
456
  dist.all_reduce(src_rank, group=pp_group)
374
457
  src_rank = dist.get_global_rank(pp_group, src_rank.item())
375
458
  meta_data = torch.zeros(10, dtype=torch.int64, device='cuda')
376
- dtype_mapping = [torch.float64, torch.float32, torch.float16, torch.bfloat16, torch.uint8, torch.int32]
459
+ # Append NCCL-supported buffer dtypes without renumbering existing metadata.
460
+ dtype_mapping = [
461
+ torch.float64, torch.float32, torch.float16, torch.bfloat16, torch.uint8, torch.int32, torch.int64,
462
+ torch.bool, torch.int8
463
+ ]
377
464
  dtype_mapping_r = {v: k for k, v in enumerate(dtype_mapping)}
378
465
  if tensor is None:
379
466
  dist.broadcast(meta_data, src=src_rank, group=pp_group)
380
467
  shape = meta_data[1:1 + meta_data[0]].tolist()
381
468
  dtype = dtype_mapping[meta_data[-1].item()]
469
+ numel = math.prod(shape) if shape else 1
470
+ elem_size = torch.empty((), dtype=dtype).element_size()
471
+ if self._stream_to_cpu() and numel * elem_size > self.export_chunk_bytes and len(shape) > 0:
472
+ return self._chunked_broadcast_pp(None, shape, dtype, src_rank, pp_group)
382
473
  tensor = torch.empty(shape, device='cuda', dtype=dtype)
383
474
  dist.broadcast(tensor, src=src_rank, group=pp_group)
384
475
  else:
@@ -386,6 +477,9 @@ class GPTBridge:
386
477
  meta_data[1:1 + tensor.ndim] = torch.tensor(tensor.shape, dtype=torch.int64, device='cuda')
387
478
  meta_data[-1] = dtype_mapping_r[tensor.dtype]
388
479
  dist.broadcast(meta_data, src=src_rank, group=pp_group)
480
+ if self._stream_to_cpu() and tensor.numel() * tensor.element_size() > (
481
+ self.export_chunk_bytes) and tensor.ndim > 0:
482
+ return self._chunked_broadcast_pp(tensor, list(tensor.shape), tensor.dtype, src_rank, pp_group)
389
483
  dist.broadcast(tensor, src=src_rank, group=pp_group)
390
484
  return tensor
391
485
 
@@ -405,7 +499,7 @@ class GPTBridge:
405
499
  tensor = [tensor]
406
500
  if self._is_fp8_param(tensor[0]):
407
501
  mg_scale_inv = [
408
- t._rowwise_scale_inv[..., :math.ceil(t._rowwise_data.shape[-1] / self.fp8_block_size)]
502
+ t._rowwise_scale_inv[..., :math.ceil(t._rowwise_data.shape[-1] / self.fp8_block_size)].contiguous()
409
503
  for t in tensor
410
504
  ]
411
505
  tensor = [t._rowwise_data for t in tensor]
@@ -428,14 +522,16 @@ class GPTBridge:
428
522
  if tensor.dtype == torch.uint8:
429
523
  mg_scale_inv = self._all_gather_tp(mg_scale_inv, tp_dim, is_expert)
430
524
  mg_scale_inv = self._broadcast_ep_pp(mg_scale_inv, is_expert)
525
+ if mg_scale_inv is not None and mg_scale_inv.device != tensor.device:
526
+ mg_scale_inv = mg_scale_inv.to(tensor.device)
431
527
  tensor = tensor.view(torch.float8_e4m3fn)
432
528
  assert tensor is not None, f'mg_key: {mg_key}'
433
529
  if offset:
434
530
  assert mg_scale_inv is None, f'mg_key: {mg_key}'
435
531
  tensor = tensor + offset
436
532
  is_embedding = mg_key in {'embedding.word_embeddings.weight', 'output_layer.weight'}
437
- if is_embedding and self.config.padded_vocab_size < tensor.shape[0]:
438
- tensor = tensor[:self.config.padded_vocab_size]
533
+ if is_embedding and self.config.actual_vocab_size < tensor.shape[0]:
534
+ tensor = tensor[:self.config.actual_vocab_size]
439
535
  if self._target_device is not None:
440
536
  tensor = tensor.to(device=self._target_device)
441
537
  if mg_scale_inv is not None:
@@ -1670,7 +1766,11 @@ class GPTBridge:
1670
1766
  self._set_state_dict(hyper_connection, 'bias', hf_state_dict, f'hc_{hf_key}_base', to_mcore)
1671
1767
  has_hyper_connection = hyper_connection is not None
1672
1768
  has_hyper_connection = self._reduce_tensor_pp_group(has_hyper_connection, to_mcore)
1673
- if has_hyper_connection:
1769
+ # ``alpha_*`` are frozen base parameters written outside ``_set_state_dict``, so they
1770
+ # need the peft guard the mapping_proj/bias calls above get for free -- otherwise a
1771
+ # LoRA export writes base weights into ``adapter_model.safetensors`` and a LoRA load
1772
+ # demands a key the adapter does not carry. Same shape as the Engram export guard.
1773
+ if has_hyper_connection and not self._peft_format:
1674
1774
  if to_mcore:
1675
1775
  alpha = hf_state_dict[f'hc_{hf_key}_scale'].load()
1676
1776
  for i, alpha_suffix in enumerate(['pre', 'post', 'res']):
@@ -1758,6 +1858,10 @@ class GPTBridge:
1758
1858
  self._set_state_dict(lm_model, 'decoder.final_layernorm.weight', hf_state_dict, self.hf_final_layernorm_key,
1759
1859
  to_mcore)
1760
1860
 
1861
+ def _convert_additional_layers(self, mg_model, hf_state_dict, hf_prefix, to_mcore, is_pp_last_stage):
1862
+ """Extension point for model-specific auxiliary stacks outside standard MTP."""
1863
+ return ()
1864
+
1761
1865
  def _convert_hf_state_dict(self, hf_state_dict, to_mcore):
1762
1866
  res = {}
1763
1867
  for k, v in hf_state_dict.items():
@@ -1771,6 +1875,7 @@ class GPTBridge:
1771
1875
  return res
1772
1876
 
1773
1877
  def _convert(self, mg_models, hf_state_dict, hf_prefix: str, to_mcore: bool, tqdm_desc: str = 'Converting: '):
1878
+ self._pending_export_iter = None
1774
1879
  if to_mcore:
1775
1880
  hf_state_dict = self._remove_prefix(hf_state_dict, hf_prefix)
1776
1881
  hf_state_dict = self._convert_hf_state_dict(hf_state_dict, to_mcore)
@@ -1820,7 +1925,11 @@ class GPTBridge:
1820
1925
  yield
1821
1926
  else:
1822
1927
  res = self._convert_hf_state_dict(res, to_mcore)
1823
- yield from list(self._add_prefix(res, hf_prefix).items())
1928
+ # Drain any staged PLE table shards first: they are produced one
1929
+ # at a time (see _iter_ple_table_export) so the 100GB-scale table
1930
+ # never accumulates in host memory.
1931
+ yield from self._drain_pending_export(hf_prefix)
1932
+ yield from self._add_prefix(res, hf_prefix).items()
1824
1933
  hf_state_dict = {}
1825
1934
 
1826
1935
  if (not to_mcore or is_pp_last_stage) and self.config.mtp_num_layers:
@@ -1828,8 +1937,14 @@ class GPTBridge:
1828
1937
  if to_mcore and self.pp_rank > 0:
1829
1938
  self._set_state_dict(lm_model, 'embedding.word_embeddings.weight', hf_state_dict, self.hf_embed_key,
1830
1939
  to_mcore)
1940
+ from mcore_bridge.model.mtp import get_physical_mtp_count
1941
+ if not to_mcore:
1942
+ phys_count = self._reduce_mtp_physical_count(lm_model)
1943
+ else:
1944
+ # Import: only the owning (last) stage reaches here.
1945
+ phys_count = get_physical_mtp_count(lm_model)
1831
1946
  layer_idx = 0
1832
- while layer_idx < self.config.mtp_num_layers:
1947
+ while layer_idx < phys_count:
1833
1948
  res = self._convert_mtp_layer(lm_model, hf_state_dict, f'{self.hf_mtp_prefix}.', layer_idx, to_mcore)
1834
1949
  layer_idx += 1
1835
1950
  if to_mcore:
@@ -1838,6 +1953,7 @@ class GPTBridge:
1838
1953
  res = self._convert_hf_state_dict(res, to_mcore)
1839
1954
  yield from list(self._add_prefix(res, hf_prefix).items())
1840
1955
  hf_state_dict = {}
1956
+ yield from self._convert_additional_layers(mg_model, hf_state_dict, hf_prefix, to_mcore, is_pp_last_stage)
1841
1957
  if not to_mcore or is_pp_last_stage:
1842
1958
  hf_state_dict.update(self._convert_post_process(mg_model, hf_state_dict, '', to_mcore))
1843
1959
  if to_mcore:
@@ -1847,6 +1963,16 @@ class GPTBridge:
1847
1963
  yield from list(self._add_prefix(hf_state_dict, hf_prefix).items())
1848
1964
  prog_bar.close()
1849
1965
 
1966
+ def _drain_pending_export(self, hf_prefix: str):
1967
+ """Yield (and release) the PLE table shards staged by _set_layer_ple."""
1968
+ it, self._pending_export_iter = self._pending_export_iter, None
1969
+ if it is None:
1970
+ return
1971
+ for k, v in it:
1972
+ if v is None:
1973
+ continue
1974
+ yield from self._add_prefix(self._convert_hf_state_dict({k: v}, False), hf_prefix).items()
1975
+
1850
1976
  def _convert_mtp_extra(self, mtp_layer, hf_state_dict, to_mcore, origin_hf_state_dict):
1851
1977
  for key in ['enorm.weight', 'hnorm.weight', 'eh_proj.weight']:
1852
1978
  self._set_state_dict(mtp_layer, key, hf_state_dict, key, to_mcore)
@@ -1854,6 +1980,17 @@ class GPTBridge:
1854
1980
  self._set_state_dict(mtp_layer, 'final_layernorm.weight', hf_state_dict, self.hf_mtp_final_layernorm_key,
1855
1981
  to_mcore)
1856
1982
 
1983
+ def _reduce_mtp_physical_count(self, lm_model) -> int:
1984
+ """PP export: obtain the physical MTP layer count from the owning stage
1985
+ so every rank iterates the same number of times (collective safety)."""
1986
+ from mcore_bridge.model.mtp import get_physical_mtp_count
1987
+ local = get_physical_mtp_count(lm_model)
1988
+ if self.pp_size <= 1:
1989
+ return local
1990
+ t = torch.tensor([local], dtype=torch.long, device='cuda')
1991
+ dist.all_reduce(t, op=dist.ReduceOp.MAX, group=self.pp_group)
1992
+ return int(t.item())
1993
+
1857
1994
  def _convert_mtp_layer(self, lm_model, hf_state_dict, hf_prefix: str, layer_idx: int, to_mcore: bool):
1858
1995
  mtp_layer = lm_model.mtp.layers[layer_idx] if hasattr(lm_model, 'mtp') else None
1859
1996
  if self.hf_mtp_prefix == self.hf_layers_prefix:
@@ -1865,8 +2002,16 @@ class GPTBridge:
1865
2002
  origin_hf_state_dict = hf_state_dict
1866
2003
  hf_state_dict = self._remove_prefix(hf_state_dict, hf_prefix)
1867
2004
  if len(hf_state_dict) == 0:
1868
- logger.info(f'MTP Layer {mtp_layer.layer_number} safetensors weights not found, '
1869
- 'this part will be randomly initialized.')
2005
+ if self._peft_format:
2006
+ return {}
2007
+ expected = f'{hf_prefix}*'
2008
+ if not self.config.mtp_allow_random_init:
2009
+ raise ValueError(f'MTP weights not found under {expected} (expected '
2010
+ f'{self.config.mtp_num_layers} physical set(s) after the {self.config.num_layers} '
2011
+ 'decoder layers). Set mtp_shared_weights=True to reuse one set across depths, or '
2012
+ 'mtp_allow_random_init=True to train MTP from random init.')
2013
+ logger.warning(f'MTP Layer {mtp_layer.layer_number} weights not found under {expected}; '
2014
+ 'randomly initializing (mtp_allow_random_init=True).')
1870
2015
  for param in mtp_layer.parameters():
1871
2016
  if param.ndim == 2:
1872
2017
  mtp_layer.config.init_method(param.data)
@@ -1875,7 +2020,7 @@ class GPTBridge:
1875
2020
  origin_hf_state_dict = {}
1876
2021
  hf_state_dict = {}
1877
2022
  self._convert_mtp_extra(mtp_layer, hf_state_dict, to_mcore, origin_hf_state_dict)
1878
- transformer_layer = None if mtp_layer is None else mtp_layer.transformer_layer
2023
+ transformer_layer = None if mtp_layer is None else mtp_layer.mtp_model_layer
1879
2024
  self._convert_mtp_embeds(lm_model, hf_state_dict, to_mcore)
1880
2025
  hf_state_dict.update(self._set_layer_attn(transformer_layer, hf_state_dict, -1, to_mcore))
1881
2026
  hf_state_dict.update(self._set_layer_mlp(transformer_layer, hf_state_dict, -1, to_mcore, is_mtp=True))
@@ -1948,6 +2093,7 @@ class GPTBridge:
1948
2093
  tqdm_desc: str = 'Exporting: ',
1949
2094
  disable_tqdm: bool = True,
1950
2095
  _is_saving: bool = False,
2096
+ skip_unsupported_export: bool = False,
1951
2097
  ):
1952
2098
  """Export Megatron model weights to safetensors (HuggingFace) format as a generator.
1953
2099
 
@@ -1965,6 +2111,11 @@ class GPTBridge:
1965
2111
  converter: Used to perform key-value conversion on the newly exported state_dict.
1966
2112
  tqdm_desc: Description text for the progress bar. Defaults to 'Exporting: '.
1967
2113
  disable_tqdm: Whether to disable the tqdm progress bar. Defaults to True.
2114
+ skip_unsupported_export: When True, weights whose Megatron->HF export is not implemented
2115
+ (e.g. DeepSeek-V4.1 Engram tables, which are frozen during on-policy RL and already
2116
+ loaded in the rollout engine) are silently skipped instead of raising. Used by the RL
2117
+ weight-sync path; the checkpoint-save path keeps the default (False) so a saved HF
2118
+ checkpoint stays complete.
1968
2119
 
1969
2120
  Yields:
1970
2121
  Tuple[str, torch.Tensor]: Key-value pairs of parameter names and tensors.
@@ -1975,6 +2126,7 @@ class GPTBridge:
1975
2126
  self._adapter_name = adapter_name
1976
2127
  self._disable_tqdm = disable_tqdm
1977
2128
  self._is_saving = _is_saving
2129
+ self._skip_unsupported_export = skip_unsupported_export
1978
2130
  self._peft_target_modules = set()
1979
2131
  self._peft_modules_to_save = set()
1980
2132
  self._fp8_skip_modules = set()
@@ -2045,6 +2197,10 @@ class GPTBridge:
2045
2197
  saver.finalize()
2046
2198
  dist.barrier() # Ensure all weights are saved completely
2047
2199
 
2200
+ def _normalize_missing_weight_key(self, key: str) -> str:
2201
+ """Return the identity used to detect aliases while restoring source-only weights."""
2202
+ return key
2203
+
2048
2204
  def _save_missing_weights(self, saver, saved_keys, source_model_dir=None) -> None:
2049
2205
  """Copy tensors present in the source checkpoint but absent from the exported ones.
2050
2206
 
@@ -2061,7 +2217,9 @@ class GPTBridge:
2061
2217
  return
2062
2218
  with SafetensorLazyLoader(source_model_dir) as loader:
2063
2219
  state_dict = loader.get_state_dict()
2064
- missing_keys = sorted(set(state_dict.keys()) - saved_keys)
2220
+ saved_identities = {self._normalize_missing_weight_key(key) for key in saved_keys}
2221
+ missing_keys = sorted(
2222
+ key for key in state_dict if self._normalize_missing_weight_key(key) not in saved_identities)
2065
2223
  if not missing_keys:
2066
2224
  return
2067
2225
  logger.info(f'Restoring {len(missing_keys)} weights from the source checkpoint '
@@ -1,3 +1,3 @@
1
1
  # Copyright (c) ModelScope Contributors. All rights reserved.
2
- from .model_config import ModelConfig
2
+ from .model_config import MLAModelConfig, ModelConfig
3
3
  from .parser import hf_to_mcore_config