Upload svd_llm/heal/llama2-13b-base/lowrank_linear.py with huggingface_hub
Browse files
svd_llm/heal/llama2-13b-base/lowrank_linear.py
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Minimal standalone loader for the SVD-baseline compressed LLaMA-2-7B checkpoints.
|
| 2 |
+
|
| 3 |
+
No dependency beyond torch + transformers. The state_dict stores every compressed
|
| 4 |
+
projection as two factors of a LowRankLinear (A: out x k, B: k x in); ranks.json
|
| 5 |
+
holds the per-layer integer rank of each projection. Untouched parameters
|
| 6 |
+
(embeddings, norms) keep their stock transformers names.
|
| 7 |
+
|
| 8 |
+
Usage:
|
| 9 |
+
import json, torch
|
| 10 |
+
from lowrank_linear import build
|
| 11 |
+
model = build(
|
| 12 |
+
base_id="NousResearch/Llama-2-7b-chat-hf",
|
| 13 |
+
ranks=json.load(open("ranks.json")),
|
| 14 |
+
state_dict_path="state_dict_fp16.pt",
|
| 15 |
+
device="cuda", dtype=torch.float16,
|
| 16 |
+
)
|
| 17 |
+
tokenizer = AutoTokenizer.from_pretrained("NousResearch/Llama-2-7b-chat-hf")
|
| 18 |
+
out = model.generate(tokenizer("2+2=", return_tensors="pt").to("cuda").input_ids,
|
| 19 |
+
max_new_tokens=16, do_sample=False)
|
| 20 |
+
print(tokenizer.decode(out[0]))
|
| 21 |
+
"""
|
| 22 |
+
|
| 23 |
+
from __future__ import annotations
|
| 24 |
+
|
| 25 |
+
import torch
|
| 26 |
+
import torch.nn as nn
|
| 27 |
+
import torch.nn.functional as F
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
class LowRankLinear(nn.Module):
|
| 31 |
+
"""y = A (B x). A: out x r, B: r x in. (LLaMA projections carry no bias.)"""
|
| 32 |
+
|
| 33 |
+
def __init__(self, A: torch.Tensor, B: torch.Tensor):
|
| 34 |
+
super().__init__()
|
| 35 |
+
self.A = nn.Parameter(A)
|
| 36 |
+
self.B = nn.Parameter(B)
|
| 37 |
+
|
| 38 |
+
def forward(self, x):
|
| 39 |
+
return F.linear(F.linear(x, self.B), self.A)
|
| 40 |
+
|
| 41 |
+
@torch.no_grad()
|
| 42 |
+
def materialize_(self) -> nn.Linear:
|
| 43 |
+
"""Replace this module with the dense W = A @ B (inference only; never call
|
| 44 |
+
while training -- it cuts the gradient path)."""
|
| 45 |
+
W = (self.A @ self.B).to(self.A.dtype)
|
| 46 |
+
dense = nn.Linear(self.B.shape[1], self.A.shape[0], bias=False,
|
| 47 |
+
device=W.device, dtype=W.dtype)
|
| 48 |
+
dense.weight.data = W
|
| 49 |
+
return dense
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def build(base_id: str, ranks: dict, state_dict_path: str,
|
| 53 |
+
device: str = "cuda", dtype=torch.float16):
|
| 54 |
+
from transformers import AutoModelForCausalLM
|
| 55 |
+
|
| 56 |
+
model = AutoModelForCausalLM.from_pretrained(base_id, torch_dtype=dtype)
|
| 57 |
+
search = {}
|
| 58 |
+
for name, mod in model.named_modules():
|
| 59 |
+
if isinstance(mod, nn.Linear):
|
| 60 |
+
search[name] = mod
|
| 61 |
+
for path, k in ranks.items():
|
| 62 |
+
out_f, in_f = search[path].weight.shape
|
| 63 |
+
model_mod = model
|
| 64 |
+
for p in path.split(".")[:-1]:
|
| 65 |
+
model_mod = getattr(model_mod, p)
|
| 66 |
+
setattr(model_mod, path.split(".")[-1],
|
| 67 |
+
LowRankLinear(torch.zeros(out_f, int(k), dtype=dtype),
|
| 68 |
+
torch.zeros(int(k), in_f, dtype=dtype)))
|
| 69 |
+
sd = torch.load(state_dict_path, map_location="cpu", weights_only=True)
|
| 70 |
+
model.load_state_dict(sd, strict=True)
|
| 71 |
+
del sd
|
| 72 |
+
return model.to(device)
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def materialize_all(model):
|
| 76 |
+
"""Fuse every LowRankLinear back into a dense nn.Linear in place."""
|
| 77 |
+
for name, mod in list(model.named_modules()):
|
| 78 |
+
if isinstance(mod, LowRankLinear):
|
| 79 |
+
parent = model
|
| 80 |
+
for p in name.split(".")[:-1]:
|
| 81 |
+
parent = getattr(parent, p)
|
| 82 |
+
setattr(parent, name.split(".")[-1], mod.materialize_())
|
| 83 |
+
return model
|