-
Notifications
You must be signed in to change notification settings - Fork 713
Fix grouped expert quantizer checkpoint replicas #2500
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
636b474
89c1c9d
dbfa1cd
6a5a123
87cb850
c2be0f2
4041950
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1145,6 +1145,16 @@ def _assert_te_grouped_weight_quantizer_state(model, expected_amax, expect_globa | |
| assert checked > 0, "no TEGrouped per-expert weight quantizer amax was checked" | ||
|
|
||
|
|
||
| def _override_te_grouped_modelopt_tp_group(model, tp_group): | ||
| grouped_linears = [ | ||
| module for module in model.modules() if isinstance(module, _QuantMegatronTEGroupedLinear) | ||
| ] | ||
| assert grouped_linears, "no quantized TEGroupedLinear found" | ||
| for linear in grouped_linears: | ||
| assert getattr(linear, "_pg_collection", None) is not None | ||
| linear.parallel_state.tensor_parallel_group.group = tp_group | ||
|
|
||
|
|
||
| def test_initialize_grouped_weight_quantizer_state_for_restore(): | ||
| """Missing grouped state inherits the shape and dtype of a populated sibling.""" | ||
| source = mtq.nn.StaticBlockScaleQuantizer.from_tensor_quantizer( | ||
|
|
@@ -1184,19 +1194,24 @@ def _test_te_grouped_sharded_state_dict_reshard_helper( | |
| checkpoint_path, | ||
| rank, | ||
| size, | ||
| save_etp_size=None, | ||
| load_etp_size=None, | ||
| override_modelopt_tp_group=False, | ||
| ): | ||
| """Round-trip TEGroupedMLP amax through a topology change.""" | ||
| num_experts = 4 | ||
| save_num_local_experts = num_experts // save_ep_size | ||
| initialize_for_megatron( | ||
| tensor_model_parallel_size=save_tp_size, | ||
| expert_model_parallel_size=save_ep_size, | ||
| expert_tensor_parallel_size=save_etp_size, | ||
| seed=SEED, | ||
| ) | ||
|
|
||
| source = _gpt_model_provider( | ||
| tp_size=save_tp_size, | ||
| ep_size=save_ep_size, | ||
| etp_size=save_etp_size, | ||
| hidden_size=32, | ||
| moe_grouped_gemm=True, | ||
| transformer_impl="transformer_engine", | ||
|
|
@@ -1207,6 +1222,8 @@ def _test_te_grouped_sharded_state_dict_reshard_helper( | |
| if isinstance(module, TopKRouter): | ||
| module.topk = module.num_experts | ||
| mtq.quantize(source, copy.deepcopy(quant_cfg), forward) | ||
| if override_modelopt_tp_group: | ||
| _override_te_grouped_modelopt_tp_group(source, get_tensor_model_parallel_group()) | ||
| _set_te_grouped_weight_quantizer_state( | ||
| source, get_expert_model_parallel_rank(), save_num_local_experts | ||
| ) | ||
|
|
@@ -1219,11 +1236,13 @@ def _test_te_grouped_sharded_state_dict_reshard_helper( | |
| initialize_for_megatron( | ||
| tensor_model_parallel_size=load_tp_size, | ||
| expert_model_parallel_size=load_ep_size, | ||
| expert_tensor_parallel_size=load_etp_size, | ||
| seed=SEED, | ||
| ) | ||
| target = _gpt_model_provider( | ||
| tp_size=load_tp_size, | ||
| ep_size=load_ep_size, | ||
| etp_size=load_etp_size, | ||
| hidden_size=32, | ||
| moe_grouped_gemm=True, | ||
| transformer_impl="transformer_engine", | ||
|
|
@@ -1232,6 +1251,8 @@ def _test_te_grouped_sharded_state_dict_reshard_helper( | |
| target_models = [target] | ||
| restore_sharded_modelopt_state(target_models, checkpoint_path) | ||
| target = target_models[0] | ||
| if override_modelopt_tp_group: | ||
| _override_te_grouped_modelopt_tp_group(target, get_tensor_model_parallel_group()) | ||
| load_distributed_checkpoint(checkpoint_path, target) | ||
| load_num_local_experts = num_experts // load_ep_size | ||
| expected_amax = tuple( | ||
|
|
@@ -1305,6 +1326,30 @@ def test_te_grouped_sharded_state_dict_reshard( | |
| ) | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("override_modelopt_tp_group", [False, True]) | ||
| def test_te_grouped_sharded_state_dict_combined_tp_ep( | ||
| dist_workers_size_4, tmp_path, override_modelopt_tp_group | ||
| ): | ||
| """Round-trip grouped expert quantizer state with TP and EP both greater than one.""" | ||
| dist_workers_size_4.run( | ||
| partial( | ||
| _test_te_grouped_sharded_state_dict_reshard_helper, | ||
| 2, | ||
| 2, | ||
| 2, | ||
| 2, | ||
| mtq.NVFP4_DEFAULT_CFG, | ||
| False, | ||
| tmp_path, | ||
| save_etp_size=1, | ||
| load_etp_size=1, | ||
| # The True case simulates child conversion without the parent MLP setup: checkpoint | ||
| # groups must still come from the grouped linear's MCore process-group collection. | ||
| override_modelopt_tp_group=override_modelopt_tp_group, | ||
| ) | ||
| ) | ||
|
|
||
|
Comment on lines
+1343
to
+1351
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: sed -n '1130,1360p' tests/gpu_megatron/torch/quantization/plugins/test_megatron.py
git diff 051d6adb204f10cd3e78d0f824f31a5a01d54831 dbfa1cdb5059d4fa156f0509bc850feb28cefcb0 -- tests/gpu_megatron/torch/quantization/plugins/test_megatron.pyRepository: NVIDIA/Model-Optimizer Length of output: 12822 🏁 Script executed: #!/bin/bash
set -e
printf '%s\n' '--- relevant symbols ---'
rg -n "_gpt_model_provider|_QuantMegatronTEGroupedLinear|parallel_state|tensor_parallel_group|expert_tensor_parallel|_set_te_grouped_weight_quantizer_state|_assert_te_grouped_weight_quantizer_state|combined_tp_ep|sharded_state_dict" tests/gpu_megatron/torch/quantization/plugins/test_megatron.py tests -g '*.py' | head -240
printf '%s\n' '--- provider and fixture definitions ---'
rg -n "def _gpt_model_provider|def initialize_for_megatron|def _set_te_grouped_weight_quantizer_state|def _assert_te_grouped_weight_quantizer_state" tests/gpu_megatron/torch/quantization/plugins/test_megatron.py
printf '%s\n' '--- nearby source around provider and helpers ---'
sed -n '850,1165p' tests/gpu_megatron/torch/quantization/plugins/test_megatron.py
printf '%s\n' '--- all relevant test names ---'
rg -n "^def test_.*(grouped|reshard|checkpoint|restore)|^class .*Grouped|expert_tensor_parallel_size|etp_size=" tests/gpu_megatron tests/unit -g '*.py' | head -240Repository: NVIDIA/Model-Optimizer Length of output: 41672 🏁 Script executed: set -e
rg -n "_gpt_model_provider|_QuantMegatronTEGroupedLinear|parallel_state|tensor_parallel_group|expert_tensor_parallel|_set_te_grouped_weight_quantizer_state|_assert_te_grouped_weight_quantizer_state|combined_tp_ep" tests/gpu_megatron/torch/quantization/plugins/test_megatron.py
sed -n '700,1165p' tests/gpu_megatron/torch/quantization/plugins/test_megatron.py
sed -n '1165,1365p' tests/gpu_megatron/torch/quantization/plugins/test_megatron.py
rg -n "expert_tensor_parallel_size|etp_size=|TEGrouped|grouped_sharded" tests/gpu_megatron tests/unit -g '*.py' | head -260Repository: NVIDIA/Model-Optimizer Length of output: 38825 🏁 Script executed: printf '%s\n' '--- declarations ---'
rg -n -C 8 "def _gpt_model_provider|def _set_te_grouped_weight_quantizer_state|def _assert_te_grouped_weight_quantizer_state|class _QuantMegatronTEGroupedLinear" tests/gpu_megatron/torch/quantization/plugins/test_megatron.py tests
printf '%s\n' '--- relevant group references ---'
rg -n -C 5 "tensor_parallel_group|expert_tensor_parallel_size|get_tensor_model_parallel_group|expert_tensor_parallel" tests/gpu_megatron/torch/quantization/plugins/test_megatron.py tests -g '*.py'
printf '%s\n' '--- test/helper call sites ---'
rg -n -C 4 "_test_te_grouped_sharded_state_dict_reshard_helper|test_te_grouped_sharded_state_dict" tests -g '*.py'Repository: NVIDIA/Model-Optimizer Length of output: 41686 Exercise the unmodified ETP=1 process group. The combined test configures ETP=1, but overrides every grouped linear to use Add an unmodified ETP=1 case while retaining the child-conversion override case. Suggested fix+@pytest.mark.parametrize("override_modelopt_tp_group", [False, True])
def test_te_grouped_sharded_state_dict_combined_tp_ep(dist_workers_size_4, tmp_path):
@@
- # Simulate child conversion without the parent MLP setup: checkpoint groups must still
- # come from the grouped linear's MCore process-group collection.
- override_modelopt_tp_group=True,
+ override_modelopt_tp_group=override_modelopt_tp_group,🤖 Prompt for AI Agents🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: sed -n '995,1065p' modelopt/torch/quantization/plugins/megatron.py
sed -n '1180,1270p' tests/gpu_megatron/torch/quantization/plugins/test_megatron.py
rg -n 'singleton_local_shards|sharded_state_dict\(' modelopt/torch/quantization/plugins/megatron.py tests/gpu_megatron/torch/quantization/plugins/test_megatron.pyRepository: NVIDIA/Model-Optimizer Length of output: 11115 🏁 Script executed: sed -n '790,995p' modelopt/torch/quantization/plugins/megatron.py
printf '\n--- helper and test call sites ---\n'
rg -n -A35 -B15 '_override_te_grouped_modelopt_tp_group|_test_te_grouped_sharded_state_dict_reshard_helper|save_tp_size.*2|override_modelopt_tp_group' tests/gpu_megatron/torch/quantization/plugins/test_megatron.py
printf '\n--- relevant checkpoint consumers ---\n'
rg -n -A18 -B8 'def save_distributed_checkpoint|def load_distributed_checkpoint|save_distributed_checkpoint\(|load_distributed_checkpoint\(' tests/gpu_megatron/torch/quantization/plugins/test_megatron.py modelopt/torch/quantization/plugins/megatron.pyRepository: NVIDIA/Model-Optimizer Length of output: 26018 🏁 Script executed: printf '%s\n' '--- checkpoint imports and bindings ---'
rg -n -A8 -B8 'save_distributed_checkpoint|load_distributed_checkpoint' tests/gpu_megatron/torch/quantization/plugins/test_megatron.py modelopt
printf '%s\n' '--- grouped MLP registration and inheritance ---'
sed -n '995,1045p' modelopt/torch/quantization/plugins/megatron.pyRepository: NVIDIA/Model-Optimizer Length of output: 8454 🏁 Script executed: rg -n -A45 -B8 '^def (save_distributed_checkpoint|load_distributed_checkpoint)\b' _test_utils/torch/megatron/utils.pyRepository: NVIDIA/Model-Optimizer Length of output: 303 🏁 Script executed: git ls-files | rg '(^|/)(utils|megatron)[^/]*\.py$|_test_utils'
printf '%s\n' '--- exact definitions ---'
rg -n -g '*.py' -A45 -B8 '^def (save_distributed_checkpoint|load_distributed_checkpoint)\b' .Repository: NVIDIA/Model-Optimizer Length of output: 9276 Gate
Set the flag only when EP=1 or TP=ETP=1. This lets the grouped-linear implementation use its existing EP-offset path for the new topology. Suggested fix- metadata["singleton_local_shards"] = True
+ ep_size = get_pg_size(mcore_parallel.get_expert_model_parallel_group())
+ tp_size = get_pg_size(mcore_parallel.get_tensor_model_parallel_group())
+ etp_size = get_pg_size(mcore_parallel.get_expert_tensor_parallel_group())
+ metadata["singleton_local_shards"] = ep_size <= 1 or (
+ tp_size == 1 and etp_size == 1
+ )🤖 Prompt for AI Agents |
||
|
|
||
| def _test_te_grouped_vs_sequential_default_loss_helper(tp_size, ep_size, quant_cfg, rank, size): | ||
| """TEGrouped quantized output should diverge from BF16 more than SequentialMLP under default sync=False.""" | ||
| initialize_for_megatron( | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the first place in the repo that passes
tp_group=/dp_cp_group=tomake_sharded_tensors_for_checkpoint(the sparsity plugin and the calls above still use the 4-positional-arg form). Please confirm the oldest megatron-core this plugin supports accepts those kwargs — and likewise thatpg_collection.expt_tpis always populated on aTEGroupedLinear's_pg_collection, otherwise_expert_parallel_groupswill raiseAttributeErroron save.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Confirmed against this repository's pinned Megatron-LM gitlink
4a279f3552b1b48aa8892d4c5f5d73a8ab68f6de:megatron/core/transformer/utils.py::make_sharded_tensors_for_checkpointdeclares bothtp_groupanddp_cp_group,ProcessGroupCollectiondeclaresexpt_tp, andTEGroupedLinear.__init__stores_pg_collectionand selectspg_collection.expt_tp. The NeMo 26.08 runtime used for the regression also exposes these APIs. This PR therefore stays within the repository's pinned/supported Megatron baseline.