|
32 | 32 | Reference: https://huggingface.co/mistralai/Ministral-3-3B-Base-2512 |
33 | 33 | """ |
34 | 34 |
|
| 35 | +from typing import Mapping, Union |
| 36 | + |
| 37 | +import torch |
| 38 | + |
35 | 39 | from megatron.bridge.models.conversion.mapping_registry import MegatronMappingRegistry |
36 | 40 | from megatron.bridge.models.conversion.model_bridge import MegatronModelBridge |
37 | 41 | from megatron.bridge.models.conversion.param_mapping import ( |
@@ -170,6 +174,51 @@ def mapping_registry(self) -> MegatronMappingRegistry: |
170 | 174 |
|
171 | 175 | return MegatronMappingRegistry(*mapping_list) |
172 | 176 |
|
| 177 | + def maybe_modify_loaded_hf_weight( |
| 178 | + self, |
| 179 | + hf_param: Union[str, dict[str, str]], |
| 180 | + hf_state_dict: Mapping[str, torch.Tensor], |
| 181 | + ) -> Union[torch.Tensor, dict[str, torch.Tensor]]: |
| 182 | + """Load HF weights and dequantize FP8 tensors on the fly. |
| 183 | +
|
| 184 | + Ministral-3-*-Instruct-2512 stores LM weights in FP8 (float8_e4m3fn) with |
| 185 | + separate ``weight_scale_inv`` scalar tensors. The true bfloat16 weight is:: |
| 186 | +
|
| 187 | + w_bf16 = fp8_weight.to(bfloat16) * weight_scale_inv |
| 188 | +
|
| 189 | + This override applies dequantization transparently so that the bridge produces |
| 190 | + correct Megatron checkpoints without a separate preprocessing step. |
| 191 | + """ |
| 192 | + hf_weights = super().maybe_modify_loaded_hf_weight(hf_param, hf_state_dict) |
| 193 | + |
| 194 | + if isinstance(hf_weights, dict): |
| 195 | + # Compound params (QKV / GatedMLP): dequantize each component individually |
| 196 | + return { |
| 197 | + key: self._maybe_dequantize_fp8(tensor, hf_param[key], hf_state_dict) |
| 198 | + for key, tensor in hf_weights.items() |
| 199 | + } |
| 200 | + return self._maybe_dequantize_fp8(hf_weights, hf_param, hf_state_dict) |
| 201 | + |
| 202 | + @staticmethod |
| 203 | + def _maybe_dequantize_fp8( |
| 204 | + weight: torch.Tensor, |
| 205 | + param_name: str, |
| 206 | + hf_state_dict: Mapping[str, torch.Tensor], |
| 207 | + ) -> torch.Tensor: |
| 208 | + """Dequantize *weight* if it is stored as FP8. |
| 209 | +
|
| 210 | + Looks up ``param_name + "_scale_inv"`` in *hf_state_dict* and applies:: |
| 211 | +
|
| 212 | + w_bf16 = weight.to(bfloat16) * scale_inv |
| 213 | + """ |
| 214 | + if weight.dtype != torch.float8_e4m3fn: |
| 215 | + return weight |
| 216 | + scale_key = param_name + "_scale_inv" |
| 217 | + if scale_key not in hf_state_dict: |
| 218 | + return weight.to(torch.bfloat16) |
| 219 | + scale_inv = hf_state_dict[scale_key].to(torch.bfloat16) |
| 220 | + return weight.to(torch.bfloat16) * scale_inv |
| 221 | + |
173 | 222 |
|
174 | 223 | # Register the bridge if Mistral3ForConditionalGeneration is available |
175 | 224 | if HAS_MISTRAL3 and Mistral3ForConditionalGeneration is not None: |
|
0 commit comments