Runs a single simulation step. :param x: Inputs to the layer.
(self, x: torch.Tensor)
| 1425 | ) # Vector of refractory kernel values over a window of time |
| 1426 | |
| 1427 | def forward(self, x: torch.Tensor) -> None: |
| 1428 | # language=rst |
| 1429 | """ |
| 1430 | Runs a single simulation step. |
| 1431 | |
| 1432 | :param x: Inputs to the layer. |
| 1433 | """ |
| 1434 | # Decay voltages. |
| 1435 | self.v *= self.decay |
| 1436 | |
| 1437 | if self.learning: |
| 1438 | self.theta *= self.theta_decay |
| 1439 | |
| 1440 | # Integrate inputs. |
| 1441 | v = torch.einsum( |
| 1442 | "i,kij->kj", self.resKernel, x |
| 1443 | ) # Response due to incoming current |
| 1444 | v += torch.einsum( |
| 1445 | "i,kij->kj", self.refKernel, self.last_spikes |
| 1446 | ) # Refractoriness due to previous spikes |
| 1447 | self.v += v.view(x.size(0), *self.shape) |
| 1448 | |
| 1449 | # Check for spiking neurons. |
| 1450 | self.s = self.v >= self.thresh + self.theta |
| 1451 | |
| 1452 | if self.learning: |
| 1453 | self.theta += self.theta_plus * self.s.float().sum(0) |
| 1454 | |
| 1455 | # Add the spike vector into the first in first out matrix of windowed (ref) spike trains |
| 1456 | self.last_spikes = torch.cat( |
| 1457 | (self.last_spikes[:, 1:, :], self.s[:, None, :]), 1 |
| 1458 | ) |
| 1459 | |
| 1460 | # Voltage clipping to lower bound. |
| 1461 | if self.lbound is not None: |
| 1462 | self.v.masked_fill_(self.v < self.lbound, self.lbound) |
| 1463 | |
| 1464 | super().forward(x) |
| 1465 | |
| 1466 | def reset_state_variables(self) -> None: |
| 1467 | # language=rst |