Runs a single simulation step. :param x: Inputs to the layer.
(self, x: torch.Tensor)
| 1637 | self.lbound = lbound # Lower bound of voltage. |
| 1638 | |
| 1639 | def forward(self, x: torch.Tensor) -> None: |
| 1640 | # language=rst |
| 1641 | """ |
| 1642 | Runs a single simulation step. |
| 1643 | |
| 1644 | :param x: Inputs to the layer. |
| 1645 | """ |
| 1646 | # Decay voltages. |
| 1647 | self.v = self.decay * (self.v - self.rest) + self.rest |
| 1648 | |
| 1649 | # Integrate inputs. |
| 1650 | self.v += (self.refrac_count <= 0).float() * self.eps_0 * x |
| 1651 | |
| 1652 | # Compute (instantaneous) probabilities of spiking, clamp between 0 and 1 using exponentials. |
| 1653 | # Also known as 'escape noise', this simulates nearby neurons. |
| 1654 | self.rho = self.rho_0 * torch.exp((self.v - self.thresh) / self.d_thresh) |
| 1655 | self.s_prob = 1.0 - torch.exp(-self.rho * self.dt) |
| 1656 | |
| 1657 | # Decrement refractory counters. |
| 1658 | self.refrac_count -= self.dt |
| 1659 | |
| 1660 | # Check for spiking neurons (spike when probability > some random number). |
| 1661 | self.s = torch.rand_like(self.s_prob) < self.s_prob |
| 1662 | |
| 1663 | # Refractoriness and voltage reset. |
| 1664 | self.refrac_count.masked_fill_(self.s, self.refrac) |
| 1665 | self.v.masked_fill_(self.s, self.reset) |
| 1666 | |
| 1667 | # Voltage clipping to lower bound. |
| 1668 | if self.lbound is not None: |
| 1669 | self.v.masked_fill_(self.v < self.lbound, self.lbound) |
| 1670 | |
| 1671 | super().forward(x) |
| 1672 | |
| 1673 | def reset_state_variables(self) -> None: |
| 1674 | # language=rst |