You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Same result with dtype="float32", with or without device_map, and with dtype=torch.float64. The concrete class honors the same argument, so the bug is specific to the Auto path:
_BaseAutoModelClass.from_pretrained pops dtype from kwargs only when it is the string "auto" (src/transformers/models/auto/auto_factory.py:330-333). A concrete torch.dtype or dtype string stays in kwargs.
AutoConfig.from_pretrained(..., return_unused_kwargs=True, **kwargs) (auto_factory.py:338) then absorbs dtype into the loaded composite config's top level via standard config-kwarg handling, and it is no longer in the returned unused kwargs:
Because the resolved model class is text-only, model_class.config_class matches the composite's text_config, so the config is swapped: config = config.get_text_config() (auto_factory.py:394-398, same pattern in from_config around lines 240-244). The top-level dtype, which now holds the user's value, is dropped here. Note this block already propagates quantization_config from the parent config for exactly this reason (Fix: propagate quantization_config to text sub-config for composite models in AutoModelForCausalLM #45494), but not dtype.
model_class.from_pretrained(...) is then called with no dtype in kwargs, so it falls back to its default "auto", and _get_dtype (src/transformers/modeling_utils.py:837-838) resolves it from the extracted sub-config (text_config.dtype: bfloat16 in all Qwen3.5 checkpoints) or, when that is unset, from the checkpoint weights. The user's request is silently gone.
Impact
All Qwen/Qwen3.5-* repos ship architectures: ["Qwen3_5ForConditionalGeneration"] (MoE: Qwen3_5MoeForConditionalGeneration) with text_config.dtype: bfloat16 (verified on 0.8B/2B/4B/9B/122B-A10B), so every AutoModelForCausalLM.from_pretrained("Qwen/Qwen3.5-*", dtype=...) ignores the requested dtype.
The failure is silent: no warning, and users believe they are running fp32/fp16. As the offline repro shows, it does not even require dtype in the sub-config json (it then falls back to the weights dtype), so it affects any composite checkpoint loaded through an Auto class whose resolved class's config_class equals sub_configs["text_config"].
Alternatively, pop a user-provided dtype before the AutoConfig.from_pretrained call (extending the existing "auto" special case at auto_factory.py:330-333) and pass it explicitly to model_class.from_pretrained, so the user value never round-trips through the config object.
I am happy to open a PR with either approach plus an offline regression test based on the snippet above, lmk.
System Info
transformersversion: 5.10.0.dev0 (main @ effde20); also reproduced on the v5.9.0 releaseWho can help?
@Cyrilvallez @zucchini-nlp
Information
Reproduction
Same result with
dtype="float32", with or withoutdevice_map, and withdtype=torch.float64. The concrete class honors the same argument, so the bug is specific to the Auto path:Fully offline reproduction (no Hub access, also a regression-test candidate):
Root cause (line numbers as of effde20)
_BaseAutoModelClass.from_pretrainedpopsdtypefrom kwargs only when it is the string"auto"(src/transformers/models/auto/auto_factory.py:330-333). A concretetorch.dtypeor dtype string stays in kwargs.AutoConfig.from_pretrained(..., return_unused_kwargs=True, **kwargs)(auto_factory.py:338) then absorbsdtypeinto the loaded composite config's top level via standard config-kwarg handling, and it is no longer in the returned unused kwargs:Because the resolved model class is text-only,
model_class.config_classmatches the composite'stext_config, so the config is swapped:config = config.get_text_config()(auto_factory.py:394-398, same pattern infrom_configaround lines 240-244). The top-leveldtype, which now holds the user's value, is dropped here. Note this block already propagatesquantization_configfrom the parent config for exactly this reason (Fix: propagate quantization_config to text sub-config for composite models in AutoModelForCausalLM #45494), but notdtype.model_class.from_pretrained(...)is then called with nodtypein kwargs, so it falls back to its default"auto", and_get_dtype(src/transformers/modeling_utils.py:837-838) resolves it from the extracted sub-config (text_config.dtype: bfloat16in all Qwen3.5 checkpoints) or, when that is unset, from the checkpoint weights. The user's request is silently gone.Impact
Qwen/Qwen3.5-*repos shiparchitectures: ["Qwen3_5ForConditionalGeneration"](MoE:Qwen3_5MoeForConditionalGeneration) withtext_config.dtype: bfloat16(verified on 0.8B/2B/4B/9B/122B-A10B), so everyAutoModelForCausalLM.from_pretrained("Qwen/Qwen3.5-*", dtype=...)ignores the requested dtype.dtypein the sub-config json (it then falls back to the weights dtype), so it affects any composite checkpoint loaded through an Auto class whose resolved class'sconfig_classequalssub_configs["text_config"].Expected behavior
dtype=torch.float32through the Auto classes should produce fp32 parameters, identical to loading through the concrete class.Possible fixes
get_text_config()extraction sites, carry the parent config'sdtypeover to the extracted text config when it is not None.dtypebefore theAutoConfig.from_pretrainedcall (extending the existing"auto"special case atauto_factory.py:330-333) and pass it explicitly tomodel_class.from_pretrained, so the user value never round-trips through the config object.I am happy to open a PR with either approach plus an offline regression test based on the snippet above, lmk.