Skip to content

Fix bias='lora_only' state-dict collection in train_lora#3859

Open
Chessing234 wants to merge 1 commit intolm-sys:mainfrom
Chessing234:fix/train-lora-bias-only-state-dict
Open

Fix bias='lora_only' state-dict collection in train_lora#3859
Chessing234 wants to merge 1 commit intolm-sys:mainfrom
Chessing234:fix/train-lora-bias-only-state-dict

Conversation

@Chessing234
Copy link
Copy Markdown

Bug

In fastchat/train/train_lora.py, get_peft_state_maybe_zero_3 crashes
or silently stores bias params under the wrong key whenever bias == \"lora_only\" is used and the model has any bias parameter.

Root cause

elif bias == \"lora_only\":
    to_return = {}
    maybe_lora_bias = {}
    lora_bias_names = set()
    for k, t in named_params:
        if \"lora_\" in k:
            to_return[k] = t
            bias_name = k.split(\"lora_\")[0] + \"bias\"
            lora_bias_names.add(bias_name)
        elif \"bias\" in k:
            maybe_lora_bias[k] = t
    for k, t in maybe_lora_bias:                 # (1)
        if bias_name in lora_bias_names:         # (2)
            to_return[bias_name] = t             # (3)
  1. for k, t in maybe_lora_bias: iterates dict keys, not items.
    Unpacking a string key into k, t raises
    ValueError: too many values to unpack the first time the dict is
    non-empty.
  2. bias_name leaks from the previous loop – it's always the last
    lora-derived bias name – so the membership check is independent of
    the current bias key k.
  3. to_return[bias_name] = t writes the tensor t under that leaked
    name, not k, so the saved bias param has the wrong key (or
    overwrites whatever was saved there).

Why the fix is correct

peft's reference implementation (the comment says this helper was
"borrowed from peft.utils.get_peft_model_state_dict") matches bias
keys directly against the current loop variable, not a leaked one.
Using maybe_lora_bias.items() and k makes the three lines self
consistent and produces the same behaviour as peft's lora_only branch.

Change

fastchat/train/train_lora.py:

-        for k, t in maybe_lora_bias:
-            if bias_name in lora_bias_names:
-                to_return[bias_name] = t
+        for k, t in maybe_lora_bias.items():
+            if k in lora_bias_names:
+                to_return[k] = t

…ro_3

The lora_only branch of get_peft_state_maybe_zero_3 has three related
bugs in the same loop:

1. `for k, t in maybe_lora_bias:` iterates dictionary keys (strings),
   not (key, value) pairs. Unpacking a string into `k, t` raises
   ValueError as soon as the dict is non-empty.
2. `if bias_name in lora_bias_names` reuses `bias_name` leaked from the
   previous loop — always the last lora-derived bias name — so the
   condition has nothing to do with the current key `k`.
3. `to_return[bias_name] = t` writes to that same leaked name instead
   of `k`, which means the bias param keyed by `k` is stored under the
   wrong name (or overwritten).

Mirror the peft reference (peft/utils/save_and_load.py get_peft_model_state_dict):
iterate `maybe_lora_bias.items()` and match against `k` directly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant