spikingjelly.timing_based.neuron 源代码

import math

import torch
import torch.nn as nn
import torch.nn.functional as F

__all__ = ["Tempotron"]


[文档] class Tempotron(nn.Module): def __init__( self, in_features: int, out_features: int, T: int, tau: float = 15.0, tau_s: float = 15.0 / 4, v_threshold: float = 1.0, ) -> None: r""" **API Language** - :ref:`中文 <Tempotron.__init__-cn>` | :ref:`English <Tempotron.__init__-en>` ---- .. _Tempotron.__init__-cn: * **中文** 实现 Tempotron 脉冲时序分类神经元。输入中的每个值表示对应输入神经元 的脉冲时刻,负值表示未发放。 :param in_features: 输入神经元数量 :type in_features: int :param out_features: 输出神经元数量 :type out_features: int :param T: 仿真时间窗口 :type T: int :param tau: 膜电位时间常数 :type tau: float :param tau_s: 突触电流时间常数 :type tau_s: float :param v_threshold: 发放阈值 :type v_threshold: float :raises ValueError: 数量、时间常数或阈值非正,或两个时间常数相等 ---- .. _Tempotron.__init__-en: * **English** Implement a Tempotron neuron for spike-timing classification. Each input value is the spike time of one input neuron; a negative value means that neuron did not spike. :param in_features: Number of input neurons :type in_features: int :param out_features: Number of output neurons :type out_features: int :param T: Simulation time window :type T: int :param tau: Membrane-potential time constant :type tau: float :param tau_s: Synaptic-current time constant :type tau_s: float :param v_threshold: Firing threshold :type v_threshold: float :raises ValueError: If a size, time constant, or threshold is not positive, or if the two time constants are equal """ super().__init__() if in_features <= 0 or out_features <= 0 or T <= 0: raise ValueError("in_features, out_features, and T must be positive.") if tau <= 0 or tau_s <= 0 or v_threshold <= 0 or tau == tau_s: raise ValueError( "tau and tau_s must be positive and different; v_threshold must be positive." ) self.in_features = in_features self.out_features = out_features self.T = T self.tau = tau self.tau_s = tau_s self.v_threshold = v_threshold # Preserve the public checkpoint key ``model.summation_layer.weight``. self.model = nn.Module() self.model.summation_layer = nn.Linear(in_features, out_features, bias=False) t_max = tau * tau_s * math.log(tau / tau_s) / (tau - tau_s) self.v0 = v_threshold / (math.exp(-t_max / tau) - math.exp(-t_max / tau_s)) @staticmethod def _psp_kernel(t: torch.Tensor, tau: float, tau_s: float) -> torch.Tensor: t = t.clamp_min(0) return torch.exp(-t / tau) - torch.exp(-t / tau_s)
[文档] def mse_loss(self, v_max: torch.Tensor, label: torch.Tensor) -> torch.Tensor: r""" **API Language** - :ref:`中文 <Tempotron.mse_loss-cn>` | :ref:`English <Tempotron.mse_loss-en>` ---- .. _Tempotron.mse_loss-cn: * **中文** :param v_max: 各输出神经元在时间窗口内的最大电压,形状为 ``[batch_size, out_features]`` :type v_max: torch.Tensor :param label: 分类标签,形状为 ``[batch_size]`` :type label: torch.Tensor :return: 仅计算错误发放神经元的均方误差 :rtype: torch.Tensor ---- .. _Tempotron.mse_loss-en: * **English** :param v_max: Maximum voltage of each output neuron with shape ``[batch_size, out_features]`` :type v_max: torch.Tensor :param label: Class labels with shape ``[batch_size]`` :type label: torch.Tensor :return: Mean squared error over incorrectly firing neurons :rtype: torch.Tensor """ wrong = ( (v_max >= self.v_threshold).to(v_max.dtype) != F.one_hot(label, self.out_features) ).to(v_max.dtype) return ((v_max - self.v_threshold) * wrong).square().sum() / label.shape[0]
[文档] def forward(self, in_spikes: torch.Tensor, ret_type: str) -> torch.Tensor: r""" **API Language** - :ref:`中文 <Tempotron.forward-cn>` | :ref:`English <Tempotron.forward-en>` ---- .. _Tempotron.forward-cn: * **中文** :param in_spikes: 输入脉冲时刻,形状为 ``[batch_size, in_features]`` :type in_spikes: torch.Tensor :param ret_type: ``"v"``、``"v_max"`` 或 ``"spikes"`` :type ret_type: str :return: 完整电压轨迹、最大电压或输出脉冲时刻 :rtype: torch.Tensor :raises ValueError: ``ret_type`` 不受支持 ---- .. _Tempotron.forward-en: * **English** :param in_spikes: Input spike times with shape ``[batch_size, in_features]`` :type in_spikes: torch.Tensor :param ret_type: ``"v"``, ``"v_max"``, or ``"spikes"`` :type ret_type: str :return: Full voltage trace, maximum voltage, or output spike times :rtype: torch.Tensor :raises ValueError: If ``ret_type`` is unsupported """ times = torch.arange(self.T, device=in_spikes.device).view(1, 1, self.T) spike_times = in_spikes.unsqueeze(-1) voltage = ( self.v0 * self._psp_kernel(times - spike_times, self.tau, self.tau_s) * (spike_times >= 0).float() ) voltage = self.model.summation_layer(voltage.permute(0, 2, 1)).permute(0, 2, 1) if ret_type == "v": return voltage if ret_type == "v_max": return voltage.max(dim=2).values if ret_type == "spikes": max_index = voltage.argmax(dim=2) times = times.expand(in_spikes.shape[0], self.out_features, -1) soft_index = (F.softmax(voltage * self.T, dim=2) * times).sum(dim=2) fired = (voltage.max(dim=2).values >= self.v_threshold).to(voltage.dtype) sign = fired * 2 - 1 max_index = max_index * sign soft_index = soft_index * sign return soft_index + (max_index - soft_index).detach() raise ValueError( f"Invalid out_voltage_type: {ret_type}. Must be 'v', 'v_max', or 'spikes'" )