| 19 | return spikes_int, vth |
| 20 | |
| 21 | class QuantLinear(nn.Linear): |
| 22 | def __init__(self, in_features: int, out_features: int, bias: bool = True, device=None, dtype=None, w_group_size=128, dynamic_sfr=3.0): |
| 23 | super().__init__(in_features, out_features, bias, device=device, dtype=dtype) |
| 24 | |
| 25 | self.k = dynamic_sfr |
| 26 | self.w_group_size = w_group_size |
| 27 | self.weight_quantizer = Quantizer(in_features, out_features, w_group_size) |
| 28 | |
| 29 | def forward(self, x): |
| 30 | # BLD |
| 31 | assert not self.training |
| 32 | # # NOTICE: can use spike_matmul func to substitute the matmul between spikes_int & weight. |
| 33 | # if self.w_group_size is not None: |
| 34 | # spikes_int, vth = dynamic_spikes(x, self.k) |
| 35 | # weight = self.weight_quantizer(self.weight).reshape(self.out_features, -1, self.w_group_size) |
| 36 | # spikes_int = spikes_int.reshape(*spikes_int.shape[:-1], 1, -1, self.w_group_size) |
| 37 | # o = (spikes_int.float() * weight).sum(-1) # BLOG # group wise matmul. |
| 38 | # o = (o * vth.float()).sum(-1).to(self.weight) # BLO |
| 39 | # else: |
| 40 | # spikes_int, vth = dynamic_spikes(x, self.k) |
| 41 | # weight = self.weight_quantizer(self.weight) |
| 42 | # o = spikes_int.float() @ weight # BLO |
| 43 | # o = (o * vth.float()).to(self.weight) |
| 44 | # return o |
| 45 | |
| 46 | spikes_int, vth = dynamic_spikes(x, self.k) |
| 47 | x = (spikes_int * vth).to(x.dtype) |
| 48 | weight = self.weight_quantizer(self.weight) |
| 49 | out = torch.nn.functional.linear(x, weight, self.bias) |
| 50 | return out |
| 51 | |
| 52 | class Quantizer(nn.Module): |
| 53 | def __init__(self, in_features: int, out_features: int, w_group_size=None): |