Runs a single simulation step. :param x: Inputs to the layer.
(self, x: torch.Tensor)
| 912 | self.lbound = lbound # Lower bound of voltage. |
| 913 | |
| 914 | def forward(self, x: torch.Tensor) -> None: |
| 915 | # language=rst |
| 916 | """ |
| 917 | Runs a single simulation step. |
| 918 | |
| 919 | :param x: Inputs to the layer. |
| 920 | """ |
| 921 | # Decay voltages and adaptive thresholds. |
| 922 | self.v = self.decay * (self.v - self.rest) + self.rest |
| 923 | if self.learning: |
| 924 | self.theta *= self.theta_decay |
| 925 | |
| 926 | # Integrate inputs. |
| 927 | self.v += (self.refrac_count <= 0).float() * x |
| 928 | |
| 929 | # Decrement refractory counters. |
| 930 | self.refrac_count -= self.dt |
| 931 | |
| 932 | # Check for spiking neurons. |
| 933 | self.s = self.v >= self.thresh + self.theta |
| 934 | |
| 935 | # Refractoriness, voltage reset, and adaptive thresholds. |
| 936 | self.refrac_count.masked_fill_(self.s, self.refrac) |
| 937 | self.v.masked_fill_(self.s, self.reset) |
| 938 | if self.learning: |
| 939 | self.theta += self.theta_plus * self.s.float().sum(0) |
| 940 | |
| 941 | # voltage clipping to lowerbound |
| 942 | if self.lbound is not None: |
| 943 | self.v.masked_fill_(self.v < self.lbound, self.lbound) |
| 944 | |
| 945 | super().forward(x) |
| 946 | |
| 947 | def reset_state_variables(self) -> None: |
| 948 | # language=rst |