clewen / adapter_runtime.py
salyamq's picture
Upload Clewen inference release
cda44d2 verified
Raw History Blame Contribute Delete
5.33 kB
"""switchable recovered deltas; inactive mode leaves base weights untouched"""
from pathlib import Path
def install_adapters(model, artifact_dir, manifest, packed_tensors=None):
import torch
import torch.nn.functional as F
from safetensors.torch import load_file
class DeltaLinear(torch.nn.Module):
def __init__(self, base, tensors, kind):
super().__init__()
self.base = base
self.enabled = False
self.kind = kind
for name, tensor in tensors.items():
self.register_buffer(name, tensor.to(device=base.weight.device, dtype=base.weight.dtype))
@property
def weight(self):
return self.base.weight
@property
def bias(self):
return self.base.bias
def forward(self, x):
result = self.base(x)
if not self.enabled:
return result
if self.kind == "low_rank":
update = F.linear(F.linear(x, self.A), self.B)
else:
update = F.linear(x, self.delta)
return result + update
# validate every target before replacing any modules
kinds = {"low_rank": ("A", "B"), "dense_delta": ("delta",), "parameter_override": ("target",)}
entries = manifest["entries"]
if len({entry["tensor"] for entry in entries}) != len(entries):
raise ValueError("Duplicate adapter targets")
if packed_tensors is not None:
expected = {entry["file"] + "/" + key for entry in entries for key in kinds[entry["kind"]]}
if set(packed_tensors) != expected:
raise ValueError("Packed adapter keys do not match the manifest")
for entry in entries:
kind, name = entry["kind"], entry["tensor"]
if kind not in kinds:
raise ValueError(f"Unknown adapter kind: {kind}")
parameter = model.get_parameter(name)
if list(parameter.shape) != entry["shape"]:
raise ValueError(f"Adapter shape mismatch at {name}")
tensors = (
load_file(str(Path(artifact_dir) / entry["file"]))
if packed_tensors is None
else {key: packed_tensors[entry["file"] + "/" + key] for key in kinds[kind]}
)
if kind == "low_rank":
A, B = tensors["A"], tensors["B"]
if (
A.ndim != 2
or B.ndim != 2
or A.shape[0] != B.shape[1]
or (B.shape[0], A.shape[1]) != tuple(parameter.shape)
):
raise ValueError(f"Invalid low-rank factors at {name}")
elif tensors[kinds[kind][0]].shape != parameter.shape:
raise ValueError(f"Invalid adapter tensor at {name}")
if kind in {"low_rank", "dense_delta"} and not isinstance(
model.get_submodule(name.removesuffix(".weight")), torch.nn.Linear
):
raise TypeError(f"Expected Linear at {name}")
wrappers, replacements = [], []
for entry in manifest["entries"]:
name = entry["tensor"]
if packed_tensors is None:
tensors = load_file(str(Path(artifact_dir) / entry["file"]), device="cpu")
else:
keys = {"low_rank": ("A", "B"), "dense_delta": ("delta",), "parameter_override": ("target",)}[entry["kind"]]
tensors = {key: packed_tensors[entry["file"] + "/" + key] for key in keys}
if entry["kind"] in {"low_rank", "dense_delta"}:
module_name = name.removesuffix(".weight")
base = model.get_submodule(module_name)
if not isinstance(base, torch.nn.Linear):
raise TypeError(f"Expected Linear at {module_name}, got {type(base).__name__}")
parent_name, _, child = module_name.rpartition(".")
parent = model.get_submodule(parent_name) if parent_name else model
wrapper = DeltaLinear(base, tensors, entry["kind"])
setattr(parent, child, wrapper)
wrappers.append(wrapper)
else:
module_name, _, parameter_name = name.rpartition(".")
owner = model.get_submodule(module_name) if module_name else model
original = owner._parameters[parameter_name]
target = torch.nn.Parameter(tensors["target"].to(original.device, original.dtype), requires_grad=False)
replacements.append((owner, parameter_name, original, target))
class Controller(torch.nn.Module):
def __init__(self):
super().__init__()
self.enabled = False
self.originals = torch.nn.ParameterList([item[2] for item in replacements])
self.targets = torch.nn.ParameterList([item[3] for item in replacements])
def set_enabled(self, enabled):
for wrapper in wrappers:
wrapper.enabled = bool(enabled)
for index, (owner, name, _, _) in enumerate(replacements):
owner._parameters[name] = self.targets[index] if enabled else self.originals[index]
self.enabled = bool(enabled)
def parameter_bytes(self):
return sum(t.numel() * t.element_size() for wrapper in wrappers for t in wrapper.buffers()) + sum(
target.numel() * target.element_size() for target in self.targets
)
return Controller()