|
18 | 18 |
|
19 | 19 | import pytest |
20 | 20 | import torch |
| 21 | +from transformers import PretrainedConfig |
21 | 22 |
|
22 | 23 |
|
23 | 24 | mtq = pytest.importorskip("modelopt.torch.quantization") |
24 | 25 | weight_export = pytest.importorskip("modelopt.torch.export.quantized_weight_export") |
25 | 26 |
|
26 | 27 | from megatron.bridge.models.conversion import modelopt_utils |
27 | 28 | from megatron.bridge.models.conversion.auto_bridge import AutoBridge |
| 29 | +from megatron.bridge.models.conversion.mapping_registry import MegatronMappingRegistry |
28 | 30 | from megatron.bridge.models.conversion.model_bridge import HFWeightTuple, MegatronModelBridge, WeightConversionTask |
29 | 31 | from megatron.bridge.models.conversion.param_mapping import ( |
30 | 32 | AutoMapping, |
@@ -119,6 +121,95 @@ def test_build_plan_delegates_fp8_packing_and_config_to_modelopt(): |
119 | 121 | assert plan.quantization_config["config_groups"]["group_0"]["targets"] == ["Linear"] |
120 | 122 |
|
121 | 123 |
|
| 124 | +@pytest.mark.parametrize("cached_names", [False, True]) |
| 125 | +@pytest.mark.parametrize("quantization", ["fp8", "static_nvfp4"]) |
| 126 | +def test_public_modelopt_plan_excludes_quantizer_state_before_mapping_validation( |
| 127 | + monkeypatch, cached_names, quantization |
| 128 | +): |
| 129 | + monkeypatch.setenv("ENABLE_BRIDGE_QUANT_MAPPING", "1") |
| 130 | + |
| 131 | + class ProjectionBridge(MegatronModelBridge): |
| 132 | + def provider_bridge(self, hf_pretrained): |
| 133 | + raise NotImplementedError |
| 134 | + |
| 135 | + def mapping_registry(self): |
| 136 | + return MegatronMappingRegistry(ColumnParallelMapping("projection.weight", "model.projection.weight")) |
| 137 | + |
| 138 | + implementation = ProjectionBridge() |
| 139 | + monkeypatch.setattr(implementation, "_megatron_global_adapters_info_all_pp_ranks", lambda _models: []) |
| 140 | + |
| 141 | + class ProjectionAutoBridge(AutoBridge): |
| 142 | + @property |
| 143 | + def _model_bridge(self): |
| 144 | + return implementation |
| 145 | + |
| 146 | + model = torch.nn.Module() |
| 147 | + model.config = SimpleNamespace(share_embeddings_and_output_weights=False) |
| 148 | + if quantization == "static_nvfp4": |
| 149 | + model.projection = mtq.quantize( |
| 150 | + torch.nn.Linear(16, 4, bias=False), |
| 151 | + { |
| 152 | + "quant_cfg": [ |
| 153 | + {"quantizer_name": "*", "enable": False}, |
| 154 | + { |
| 155 | + "quantizer_name": "*weight_quantizer", |
| 156 | + "enable": True, |
| 157 | + "cfg": { |
| 158 | + "num_bits": (2, 1), |
| 159 | + "block_sizes": {-1: 16, "type": "static", "scale_bits": (4, 3)}, |
| 160 | + }, |
| 161 | + }, |
| 162 | + ], |
| 163 | + "algorithm": "max", |
| 164 | + }, |
| 165 | + lambda candidate: candidate(torch.ones(2, 16)), |
| 166 | + ) |
| 167 | + assert isinstance(model.projection.weight_quantizer, mtq.nn.NVFP4StaticQuantizer) |
| 168 | + assert model.projection.weight_quantizer.global_amax is not None |
| 169 | + else: |
| 170 | + model.projection = _fp8_linear() |
| 171 | + original_state = dict(model.named_buffers()) |
| 172 | + model_bridge = modelopt_utils.model_bridge_utils |
| 173 | + monkeypatch.setattr(model_bridge, "_get_pg_collection_from_model", lambda _model: None) |
| 174 | + monkeypatch.setattr(model_bridge, "_get_pp_group", lambda _model: SimpleNamespace(size=lambda: 1)) |
| 175 | + monkeypatch.setattr(model_bridge, "_get_pp_rank", lambda _model: 0) |
| 176 | + monkeypatch.setattr(model_bridge, "unwrap_model", lambda candidate: candidate) |
| 177 | + monkeypatch.setattr(model_bridge, "_megatron_local_name_to_global", lambda _models, _config, name, _vp: name) |
| 178 | + monkeypatch.setattr( |
| 179 | + torch.distributed, "all_gather_object", lambda output, value, group: output.__setitem__(0, value) |
| 180 | + ) |
| 181 | + monkeypatch.setattr(model_bridge.parallel_state, "get_tensor_model_parallel_group", lambda: None) |
| 182 | + monkeypatch.setattr(model_bridge.parallel_state, "get_expert_tensor_parallel_group", lambda: None) |
| 183 | + monkeypatch.setattr(model_bridge.parallel_state, "get_expert_model_parallel_group", lambda: None) |
| 184 | + bridge = ProjectionAutoBridge(PretrainedConfig()) |
| 185 | + if cached_names: |
| 186 | + implementation._megatron_global_param_names_all_pp_ranks([model]) |
| 187 | + |
| 188 | + plan = bridge.build_hf_modelopt_export_plan(model) |
| 189 | + |
| 190 | + assert [task.global_param_name for task in plan.conversion_tasks] == ["projection.weight"] |
| 191 | + assert hasattr(implementation, "_cached_param_names") == cached_names |
| 192 | + exported = dict(bridge.export_hf_weights_modelopt(model, cpu=True, show_progress=False, export_plan=plan)) |
| 193 | + if quantization == "static_nvfp4": |
| 194 | + assert exported["model.projection.weight"].dtype == torch.uint8 |
| 195 | + expected_scale = model.projection.weight_quantizer.global_amax / (6 * 448) |
| 196 | + torch.testing.assert_close(exported["model.projection.weight_scale_2"], expected_scale) |
| 197 | + assert "model.projection.weight_scale" in exported |
| 198 | + else: |
| 199 | + assert exported["model.projection.weight"].dtype == torch.float8_e4m3fn |
| 200 | + assert dict(model.named_buffers()).keys() == original_state.keys() |
| 201 | + assert all(dict(model.named_buffers())[name] is value for name, value in original_state.items()) |
| 202 | + if quantization == "static_nvfp4": |
| 203 | + with pytest.raises(ValueError, match="_global_amax"): |
| 204 | + implementation.build_conversion_tasks(bridge.hf_pretrained, [model]) |
| 205 | + else: |
| 206 | + ordinary_tasks = implementation.build_conversion_tasks(bridge.hf_pretrained, [model]) |
| 207 | + assert any(isinstance(task.mapping, AmaxMapping) for task in ordinary_tasks) |
| 208 | + model.register_buffer("unmapped_buffer", torch.tensor(1.0)) |
| 209 | + with pytest.raises(ValueError, match="unmapped_buffer"): |
| 210 | + bridge.build_hf_modelopt_export_plan(model) |
| 211 | + |
| 212 | + |
122 | 213 | def test_numbered_grouped_weight_uses_exact_modelopt_quantizer(): |
123 | 214 | module = _GroupedWeights() |
124 | 215 | hf_name = "model.layers.0.mlp.experts.0.down_proj.weight" |
|
0 commit comments