Files
wehub-resource-sync caf324b09d
tests / check_code_quality (push) Waiting to run
tests / tests (ubuntu-latest, 3.10) (push) Blocked by required conditions
tests / tests (ubuntu-latest, 3.11) (push) Blocked by required conditions
Deploy "method_comparison" Gradio to Spaces / deploy (push) Waiting to run
Deploy "PEFT shop" Gradio app to Spaces / deploy (push) Waiting to run
tests on transformers main / tests (push) Waiting to run
tests / tests (ubuntu-latest, 3.12) (push) Blocked by required conditions
tests / tests (ubuntu-latest, 3.13) (push) Blocked by required conditions
tests / tests (windows-latest, 3.10) (push) Blocked by required conditions
tests / tests (windows-latest, 3.11) (push) Blocked by required conditions
tests / tests (windows-latest, 3.12) (push) Blocked by required conditions
tests / tests (windows-latest, 3.13) (push) Blocked by required conditions
Secret Leaks / trufflehog (push) Waiting to run
CI security linting / zizmor latest via Cargo (push) Waiting to run
Build documentation / build (push) Failing after 0s
chore: import upstream snapshot with attribution
2026-07-13 13:24:42 +08:00

73 lines
2.3 KiB
Python

import pytest
import torch
from torch.testing import assert_close
from peft import OSFConfig, get_peft_model
from peft.tuners.osf.layer import OSFLayer
from peft.tuners.osf.utils import (
decompose_weight_matrix,
reconstruct_weight_matrix,
)
def test_osf_roundtrip():
w = torch.randn(10, 8)
svd = decompose_weight_matrix(w, top_k=4)
w_rec = reconstruct_weight_matrix(svd)
assert_close(w_rec, w, atol=1e-5, rtol=1e-5)
class DummyConfig(dict):
pass
class DummyModel(torch.nn.Module):
def __init__(self, config=None):
super().__init__()
self.config = config
self.linear = torch.nn.Linear(8, 4)
def forward(self, x):
return self.linear(x)
def test_osf_gradient_projection_hook():
torch.manual_seed(0)
model = DummyModel(DummyConfig())
# Specify target module explicitly for DummyModel
cfg = OSFConfig(target_modules=["linear"], effective_rank=2)
wrapped = get_peft_model(model, cfg)
x = torch.randn(3, 8)
wrapped(x).sum().backward()
# Access the injected OSF layer
osf_linear = wrapped.base_model.model.linear
adapter = wrapped.base_model.active_adapters[0]
U_high = osf_linear._osf_U_high[adapter]
V_high = osf_linear._osf_V_high[adapter]
svd_params = osf_linear.osf_svd_params[adapter]
# Check orthogonality of gradients after projection
proj_u = U_high.T @ svd_params["U_low"].grad
proj_v = svd_params["V_low"].grad @ V_high.T
assert_close(proj_u, torch.zeros_like(proj_u), atol=1e-6, rtol=1e-6)
assert_close(proj_v, torch.zeros_like(proj_v), atol=1e-6, rtol=1e-6)
def test_osf_merge_and_unload_and_unmerge_behavior():
model = DummyModel(DummyConfig())
cfg = OSFConfig(target_modules=["linear"], effective_rank=2)
wrapped = get_peft_model(model, cfg)
# merge_adapter should work via BaseTuner and OSFLayer.merge
osf_linear = wrapped.base_model.model.linear
assert isinstance(osf_linear, OSFLayer)
wrapped.merge_adapter()
assert osf_linear.merged, "OSF layer should be marked as merged after merge_adapter()"
# unmerge_adapter is not supported for OSF
with pytest.raises(NotImplementedError):
wrapped.unmerge_adapter()
# merge_and_unload should return the base model (no OSF wrappers)
merged_model = wrapped.merge_and_unload()
assert isinstance(merged_model.linear, torch.nn.Linear)