huggingface / huggingface/peft
Bug: Hotswapping error with rank pattern
- Dominant language
- Python
- Stars
- 21.7k
- Forks
- 2.5k
- Avg merge
- 4d 12h
- Merged PRs (30d)
- 59
Description
### System Info
I found an issue with hotswapping in combination with `rank_pattern`. I only did a quick investigation so far and could not determine the issue yet. What's clear is that after hotswapping, the scaling for `lin1` in the example below is incorrectly set to 3.0, even though the rank is correctly set to `4` and the `lora_alpha` to `9`, which should lead to a scaling of `9 / 4 == 2.25`.
### Who can help?
Contributions are welcome. If you figure out the cause, please report it here and how you plan to fix it. I will assign the issue on a first come first serve basis. If there are no takers, I'll tackle this myself once I have time (probably not this week).
### Reproduction
```python
from copy import deepcopy
import torch
from torch import nn
from peft import LoraConfig, PeftModel, get_peft_model
from peft.utils.hotswap import hotswap_adapter
def test_foobar(tmp_path):
class MLP(nn.Module):
def __init__(self):
super().__init__()
self.lin0 = nn.Linear(10, 20)
self.relu = nn.ReLU()
self.lin1 = nn.Linear(20, 2)
def forward(self, X):
X = self.lin0(X)
X = self.relu(X)
X = self.lin1(X)
return X
base_model = MLP()
inputs = torch.randn(2, 10)
configs = [
# FIXME test passes with rank_pattern={"lin1": 3} but fails with anything != the base rank
LoraConfig(r=3, lora_alpha=9, target_modules=["lin0", "lin1"], rank_pattern={"lin1": 4}),
LoraConfig(r=2, lora_alpha=4, target_modules=["lin0"]),
LoraConfig(r=1, lora_alpha=3, target_modules=["lin1"]),
]
expected = []
with torch.inference_mode():
base_output = base_model(inputs)
for index, config in enumerate(configs):
config.init_lora_weights = False
adapter = get_peft_model(deepcopy(base_model), deepcopy(config)).eval()
adapter.save_pretrained(tmp_path / str(index))
with torch.inference_mode():
output = adapter(inputs)
# sanity check
assert not torch.allclose(output, base_output)
expected.append(output)
# note: the first loaded adapter must be the one that targets all layers
model = PeftModel.from_pretrained(deepcopy(base_model), tmp_path / "0")
with torch.inference_mode():
for index in [0]:
hotswap_adapter(model, tmp_path / str(index), adapter_name="default")
torch.testing.assert_close(model(inputs), expected[index])
```
### Expected behavior
The test should pass even if the rank in `rank_pattern` differs from the global LoRA rank.
Contributor guide
Research direction
Start by running the issue's test_foobar reproduction and tracing peft.utils.hotswap.hotswap_adapter, especially how rank_pattern and lora_alpha are applied during hotswapping. Done means the test passes when lin1 uses rank 4 and lora_alpha 9, producing scaling 2.25 and matching the expected output.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, pytorch
- Domain
- machine-learning
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100