Agnes-AI's picture
Add inference code
fc3971e verified
Raw History Blame Contribute Delete
4.02 kB
"""Original Wanda/SparseGPT importance adapted to SwiGLU mid-neuron groups.
The algorithms remain unstructured at the score level, but the selected
coordinates are removed as complete SwiGLU neurons so checkpoint shapes shrink.
"""
from __future__ import annotations
import torch
def wanda_mid_scores(energy: torch.Tensor, down_weight: torch.Tensor) -> torch.Tensor:
"""Return classic Wanda scores for V/A/T and each SwiGLU mid coordinate."""
if energy.ndim != 2 or energy.shape[0] != 3:
raise ValueError(f"energy must be [3, d_int], got {tuple(energy.shape)}")
if down_weight.ndim != 2 or down_weight.shape[1] != energy.shape[1]:
raise ValueError(
f"down_weight must be [hidden, {energy.shape[1]}], got {tuple(down_weight.shape)}"
)
col_norm = down_weight.detach().float().norm(dim=0)
return col_norm.unsqueeze(0) * energy.detach().float().clamp_min(0).sqrt()
def _damped_hinv(gram: torch.Tensor, percdamp: float) -> torch.Tensor:
"""Upper-triangular Cholesky factor of damped H^{-1} (miniSeedance SparseGPT)."""
if gram.ndim != 2 or gram.shape[0] != gram.shape[1]:
raise ValueError(f"gram must be square, got {tuple(gram.shape)}")
h = gram.detach().float().clone()
h = (h + h.T) * 0.5
diag = torch.diag(h)
dead = diag == 0
if bool(dead.any()):
ids = torch.arange(h.shape[0], device=h.device)
h[ids[dead], ids[dead]] = 1.0
diag = torch.diag(h)
damping = float(percdamp) * diag.clamp_min(1e-8).mean()
ids = torch.arange(h.shape[0], device=h.device)
inv = None
for _ in range(8):
trial = h.clone()
trial[ids, ids] += damping
chol, info = torch.linalg.cholesky_ex(trial)
if int(info.max()) == 0:
inv = torch.cholesky_inverse(chol)
break
damping *= 10.0
if inv is None:
raise torch.linalg.LinAlgError("unable to stabilize Gram matrix for SparseGPT")
return torch.linalg.cholesky(inv, upper=True)
def sparsegpt_mid_scores(
gram: torch.Tensor,
energy: torch.Tensor,
down_weight: torch.Tensor,
percdamp: float = 0.01,
) -> torch.Tensor:
"""Return OBS/SparseGPT salience for grouped SwiGLU mid coordinates."""
if energy.ndim != 2 or energy.shape[0] != 3:
raise ValueError(f"energy must be [3, d_int], got {tuple(energy.shape)}")
if down_weight.ndim != 2 or down_weight.shape[1] != energy.shape[1]:
raise ValueError(
f"down_weight must be [hidden, {energy.shape[1]}], got {tuple(down_weight.shape)}"
)
hinv = _damped_hinv(gram, percdamp)
d = torch.diag(hinv).clamp_min(1e-8)
base = down_weight.detach().float().pow(2).sum(dim=0) / d.pow(2)
return energy.detach().float().clamp_min(0) * base.unsqueeze(0)
def sparsegpt_compensate_down(
down_weight: torch.Tensor,
gram: torch.Tensor,
keep_idx: torch.Tensor,
percdamp: float = 0.01,
eps: float = 1e-8,
) -> torch.Tensor:
"""OBS-style compensation on down_proj before physical slice (miniSeedance SparseGPT)."""
keep_idx = keep_idx.long()
w = down_weight.detach().clone().float()
d_int = w.shape[1]
keep_set = set(keep_idx.tolist())
drop = [i for i in range(d_int) if i not in keep_set]
if not drop:
return w.to(down_weight.dtype)
work = gram.device
if work.type == "cpu" and torch.cuda.is_available():
work = torch.device("cuda")
w = w.to(work)
gram = gram.to(work)
hinv = _damped_hinv(gram, percdamp)
d_diag = torch.diag(hinv).clamp_min(eps)
importance = w.pow(2).sum(dim=0) / d_diag.pow(2)
drop_t = torch.tensor(drop, device=w.device, dtype=torch.long)
drop_sorted = drop_t[torch.argsort(importance[drop_t])]
for i in drop_sorted.tolist():
col = w[:, i]
d = hinv[i, i]
err = col / d
w[:, i:] -= err.unsqueeze(1).matmul(hinv[i, i:].unsqueeze(0))
w[:, i] = 0
return w.to(device=down_weight.device, dtype=down_weight.dtype)