-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathq_sparse.py
More file actions
60 lines (44 loc) · 1.62 KB
/
Copy pathq_sparse.py
File metadata and controls
60 lines (44 loc) · 1.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import torch
import torch.nn as nn
import torch.nn.functional as F
class QSparse(torch.autograd.Function):
@staticmethod
def forward(ctx, tensor, K):
topk_values, topk_indices = torch.topk(tensor, K, dim=-1)
masked_tensor = torch.zeros_like(tensor)
masked_tensor.scatter_(-1, topk_indices, topk_values)
output = masked_tensor
return output
@staticmethod
def backward(ctx, grad_output):
return grad_output, None
def q_sparse(tensor, K):
return QSparse.apply(tensor, K)
class QSparseLinear(nn.Linear):
def __init__(self, pct, *args, **kwargs):
super().__init__(*args, **kwargs)
self.K = int(pct * self.weight.shape[1])
print(self.in_features, self.out_features, self.K)
def forward(self, x: torch.Tensor):
x = QSparse.apply(x, self.K)
x = x / torch.norm(x, dim=-1, keepdim=True)
return F.linear(x, self.weight, self.bias)
def monkey_patch_model(model: nn.Module, target_layers: list[str], pct: float = 0.7):
for name, module in model.named_children():
if isinstance(module, nn.Linear) and name in target_layers:
setattr(
model,
name,
QSparseLinear(
pct, module.in_features, module.out_features, bias=module.bias is not None
),
)
else:
monkey_patch_model(module, target_layers, pct)
if __name__ == "__main__":
# Example usage
tensor = torch.randn(4, 10, requires_grad=True)
K = 3
output = QSparse.apply(tensor, K)
output.sum().backward()
print(tensor.grad)