fix(tuners/lora): re-apply lora_dtype after peft _cast_adapter_dtype (#9694) - #9699
fix(tuners/lora): re-apply lora_dtype after peft _cast_adapter_dtype (#9694)#9699Anai-Guo wants to merge 1 commit into
Conversation
…odelscope#9694) peft's PeftModel.__init__ calls LoraModel._cast_adapter_dtype(autocast_adapter_dtype=True) after swift's __new_init__ has already converted the adapter to lora_dtype. That call upcasts float16/bfloat16 adapter weights back to float32, so --lora_dtype bfloat16/float16 silently has no effect and checkpoints are saved as float32. Re-run swift's dtype conversion after peft's cast so the requested lora_dtype takes effect.
There was a problem hiding this comment.
Code Review
This pull request modifies swift/tuners/peft.py to re-apply lora_dtype after PEFT's _cast_adapter_dtype is called, which prevents float16/bfloat16 adapters from being silently upcast back to float32. The review feedback suggests optimizing this change by checking if autocast_adapter_dtype is False and returning early to avoid redundant iterations over modules.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| def _cast_adapter_dtype(self, adapter_name: str, autocast_adapter_dtype: bool = True): | ||
| self._cast_adapter_dtype_origin( | ||
| adapter_name=adapter_name, autocast_adapter_dtype=autocast_adapter_dtype) | ||
| active_config = self.peft_config.get(adapter_name) |
There was a problem hiding this comment.
If autocast_adapter_dtype is False, the original _cast_adapter_dtype method returns early without performing any upcasting. In this case, the lora_dtype applied during initialization remains intact, and re-running the conversion is redundant. We should check autocast_adapter_dtype and return early to avoid unnecessary iteration over all modules.
def _cast_adapter_dtype(self, adapter_name: str, autocast_adapter_dtype: bool = True):
self._cast_adapter_dtype_origin(
adapter_name=adapter_name, autocast_adapter_dtype=autocast_adapter_dtype)
if not autocast_adapter_dtype:
return
active_config = self.peft_config.get(adapter_name)
What this fixes
Fixes #9694.
--lora_dtype bfloat16(orfloat16) has no effect when using the peft backend: LoRA adapter weights are always saved asfloat32.Root cause
swift/tuners/peft.pymonkey-patchesLoraModel.__init__(__new_init__), which converts the adapter tolora_dtyperight after peft builds it. But peft'sPeftModel.__init__then callsLoraModel._cast_adapter_dtype(autocast_adapter_dtype=True)afterLoraModel.__init__returns, and that helper upcastsfloat16/bfloat16adapter params back tofloat32:So swift's conversion runs too early and is silently discarded.
Fix
Patch
LoraModel._cast_adapter_dtypeso that, after peft's cast, swift re-applieslora_dtype. This runs at the correct point (after peft's upcast) and is a no-op for the defaultlora_dtype=None, so existing fp32-adapter behavior is unchanged.Verification (CPU, no training, from the issue repro)
🤖 Generated with Claude Code