Repository: huggingface/transformers
Pull request: Fix loading of Qwen3 FP8

The Qwen3 MoE config was missing the mapping attribute for the num_expert_local config variable which made it impossible to load FP8 quantized models, due to the following exception:

```
Traceback (most recent call last):
  File ".../exps/train-qwen3-lora.py", line 4, in <module>
    base_model = AutoModelForCausalLM.from_pretrained('Qwen/Qwen3-30B-A3B-Thinking-2507-FP8')
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../transformers/src/transformers/models/auto/auto_factory.py", line 372, in from_pretrained
    return model_class.from_pretrained(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../transformers/src/transformers/modeling_utils.py", line 4075, in from_pretrained
    hf_quantizer.preprocess_model(
  File ".../transformers/src/transformers/quantizers/base.py", line 167, in preprocess_model
    self._process_model_before_weight_loading(model, **kwargs)
  File ".../transformers/src/transformers/quantizers/quantizer_finegrained_fp8.py", line 106, in _process_model_before_weight_loading
    model = replace_with_fp8_linear(
            ^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../transformers/src/transformers/integrations/finegrained_fp8.py", line 617, in replace_with_fp8_linear
    new_module = FP8Expert(
                 ^^^^^^^^^^
  File ".../transformers/src/transformers/integrations/finegrained_fp8.py", line 496, in __init__
    self.num_experts = config.num_local_experts
                       ^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../transformers/src/transformers/configuration_utils.py", line 164, in __getattribute__
    return super().__getattribute__(key)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Qwen3MoeConfig' object has no attribute 'num_local_experts'
```

A small reproducer is added in the form of a unit test.

Changed files:
filename: src/transformers/models/qwen3_moe/configuration_qwen3_moe.py
patch: @@ -118,6 +118,10 @@ class Qwen3MoeConfig(PreTrainedConfig):
     model_type = "qwen3_moe"
     keys_to_ignore_at_inference = ["past_key_values"]
 
+    attribute_map = {
+        "num_experts": "num_local_experts",
+    }
+
     # Default tensor parallel plan for base model `Qwen3Moe`
     base_model_tp_plan = {
         "layers.*.self_attn.q_proj": "colwise",

filename: src/transformers/models/qwen3_omni_moe/configuration_qwen3_omni_moe.py
patch: @@ -720,6 +720,10 @@ class Qwen3OmniMoeTalkerTextConfig(PreTrainedConfig):
     model_type = "qwen3_omni_moe_talker_text"
     keys_to_ignore_at_inference = ["past_key_values"]
 
+    attribute_map = {
+        "num_experts": "num_local_experts",
+    }
+
     # Default tensor parallel plan for base model `Qwen3OmniMoeTalkerText`
     base_model_tp_plan = {
         "layers.*.self_attn.q_proj": "colwise",

filename: tests/quantization/finegrained_fp8/test_fp8.py
patch: @@ -18,6 +18,8 @@
 from contextlib import ExitStack, contextmanager
 from unittest.mock import patch
 
+from parameterized import parameterized
+
 from transformers import AutoConfig, AutoModelForCausalLM, AutoTokenizer, FineGrainedFP8Config, OPTForCausalLM
 from transformers.quantizers.quantizer_finegrained_fp8 import FineGrainedFP8HfQuantizer
 from transformers.testing_utils import (
@@ -137,6 +139,16 @@ def tearDown(self):
         backend_empty_cache(torch_device)
         gc.collect()
 
+    @parameterized.expand(
+        [
+            "hf-internal-testing/tiny-random-Qwen3MoeForCausalLM",
+            "hf-internal-testing/tiny-random-MixtralForCausalLM",
+        ]
+    )
+    def test_moe_conversion_doesnt_raise(self, model_id):
+        quantization_config = FineGrainedFP8Config(weight_block_size=(32, 32))
+        AutoModelForCausalLM.from_pretrained(model_id, quantization_config=quantization_config)
+
     def test_quantized_model_conversion(self):
         """
         Simple test that checks if the quantized model has been converted properly