fix: store miss_fn per-adapter in MiSS layer - #3379
peft-jambot wants to merge 8 commits into
Conversation
The miss_fn attribute (derived from init_weights) was stored as a single value on the MissLinear instance instead of per-adapter. This meant adding a second adapter with a different init_weights value would override the first adapter's setting, leading to incorrect behavior in merge, unmerge, forward, and LoRA conversion operations. Convert miss_fn to a dict keyed by adapter_name, following the same pattern used by miss_r, miss_mini_r, and other per-adapter attributes. Add miss_fn to other_param_names so it is included in adapter lifecycle operations (delete_adapter, _all_available_adapter_names, etc). Fixes #6
BenjaminBossan
left a comment
There was a problem hiding this comment.
Thanks for this fix but I'm not convinced about how the forward pass is handled. Please check my comment.
| if self.miss_fn == "bat": | ||
| # Determine the MiSS variant from the active adapters. When multiple adapters are active, they must | ||
| # all use the same variant; otherwise, the forward pass is ambiguous. | ||
| active_fns = {self.miss_fn[adapter] for adapter in self.active_adapters if adapter in self.miss_block} |
There was a problem hiding this comment.
This looks incorrect. If I have a mix of bat and non-bat MiSS adapters, I would treat all of them as non-bat. Shouldn't it be possible to mix bat and non-bat in the same forward pass? If it's not possible, I would rather raise an error when incompatible MiSS adapters are being added.
There was a problem hiding this comment.
Good point, thanks. Fixed in commit 136910c.
The forward pass now separates active adapters into bat and non-bat lists. bat adapters modify the base weight first (via get_delta_weight), then non-bat adapters (balance/mini) add their delta to the output. Both contributions are applied when mixed.
Two tests added (test_miss_mix_bat_and_non_bat_forward, test_miss_mix_bat_and_mini_forward) verifying that mixed forward passes produce outputs distinct from either adapter alone.
Please re-review when you have a chance.
Address review feedback on PR huggingface#3379. Instead of treating all adapters as non-bat when a mix of bat and non-bat adapters is active, the forward pass now separates them: bat adapters modify the base weight first, then non-bat adapters add their delta to the output. This allows bat and non-bat MiSS adapters to coexist in the same forward pass. Added two tests verifying that mixed bat+non-bat and bat+mini forward passes produce outputs that differ from either adapter used alone.
Addressing review feedbackThanks for the review! I've addressed the inline comment on the forward pass in commit 136910c. The problemThe previous code checked The fixInstead of choosing one branch based on a set comparison, the forward pass now separates active adapters into bat and non-bat lists and applies both:
This means bat and non-bat MiSS adapters can now coexist in the same forward pass — bat modifies the weight, non-bat adds to the output, and both contributions are present. TestsAdded two tests in
All existing tests pass:
|
BenjaminBossan
left a comment
There was a problem hiding this comment.
Thanks for the update to forward, I just have a small comment concerning the testing.
| assert layer.miss_fn["adapter1"] == "bat" | ||
| assert layer.miss_fn["adapter2"] == "mini" | ||
|
|
||
| def test_miss_mix_bat_and_non_bat_forward(self, data): |
There was a problem hiding this comment.
This test and test_miss_mix_bat_and_mini_forward don't really check if the different inits are correctly applied and as such don't add too much, except for guarding against the incorrect implementation that you initially submitted. Let's remove these tests.
There was a problem hiding this comment.
Removed both tests in commit ba1f073. Thanks for the feedback.
Remove test_miss_mix_bat_and_non_bat_forward and test_miss_mix_bat_and_mini_forward per reviewer feedback. These tests only guarded against the incorrect initial implementation and don't verify that different inits are correctly applied.
Review feedback addressedThanks for the feedback! I've removed both The remaining MiSS initialization tests still pass:
|
|
The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update. |
BenjaminBossan
left a comment
There was a problem hiding this comment.
LGTM, failing CI is unrelated. @githubnemo please review.
|
This issue has been automatically marked as stale because it has not had recent activity. If you think this still needs to be addressed please comment on this thread. |
…ialization.py - layer.py: keep per-adapter miss_fn dict logic, add quantization_backend supports_merge check from upstream for bat init_weights - test_initialization.py: keep both TestTinyLoraInitialization (upstream) and TestMissInitialization (this PR) classes
|
not stale |
githubnemo
left a comment
There was a problem hiding this comment.
One comment, otherwise LGTM
| layer = model.base_model.model.lin0 | ||
| assert layer.miss_fn["default"] is True | ||
| assert layer.miss_fn["adapter1"] == "bat" | ||
| assert layer.miss_fn["adapter2"] == "mini" |
There was a problem hiding this comment.
It would be good to also have a test that reproduces the overriding behavior this PR fixes.
Idea: have two adapters (one bat, one with a different init fn), gather per-adapter outputs, add both adapters into one model, trigger init fn override bug, observe that output != (adapter1_output + adpater2_output).
|
Addressed the review feedback. Summary of changes:
Note: the sanity-check assertion in the suggested diff referenced an undefined Tests run:
Ready for review again. |
|
@githubnemo Please review again. Note that the latest changes are code that I wrote and then passed as a patch to the bot, who made small adjustments. |
|
Synced and merged the latest What changed:
Tests run:
Ready for review again. |
githubnemo
left a comment
There was a problem hiding this comment.
Thanks for addressing :) LGTM
Description
Fixes #6 (peft-jambot#6)
The
miss_fnattribute (derived frominit_weights) was stored as a single value on theMissLinearinstance instead of per-adapter. This meant adding a second MiSS adapter with a differentinit_weightsvalue (e.g.Truevs"bat") would override the first adapter's setting, leading to incorrect behavior in merge, unmerge, forward, and LoRA conversion operations.Changes
self.miss_fnfrom a single attribute to a dict keyed byadapter_name, following the same pattern used bymiss_r,miss_mini_r, and other per-adapter attributes.self.miss_fn[adapter_name]inupdate_layer(which is called for each adapter) instead of inMissLinear.__init__(called only once).miss_fntoother_param_namesso it is included in adapter lifecycle operations (delete_adapter,_all_available_adapter_names, etc).self.miss_fninmerge,unmerge,get_delta_weight_miss,forward, and the LoRA conversion code to use per-adapter lookup.Tests
Added
TestMissInitializationclass totests/test_initialization.pywith three tests:test_miss_fn_per_adapter: verifiesmiss_fnis stored per-adapter when adding two adapters with differentinit_weightsvalues.test_miss_fn_per_adapter_forward: ensures forward pass works correctly with differentinit_weightsper adapter.test_miss_fn_per_adapter_three_variants: tests all threeinit_weightsvariants (True,"bat","mini") coexisting on the same layer.Test results
AI assistance
This PR was created with AI assistance. The task was assigned via the peft-jambot issue tracker (issue #6). The changes were reviewed and tested locally.