spikingjelly.activation_based.ann2snn.factories 源代码

import math
from typing import Optional, Type, Union

import torch.nn as nn

from spikingjelly.activation_based import neuron
from spikingjelly.activation_based.ann2snn.modules import VoltageHook


[文档] class NeuronFactory: def __init__( self, neuron_type: Type[nn.Module] = neuron.IFNode, v_threshold: float = 1.0, v_reset: Optional[float] = None, **kwargs, ): """ **API Language** - :ref:`中文 <NeuronFactory.__init__-cn>` | :ref:`English <NeuronFactory.__init__-en>` ---- .. _NeuronFactory.__init__-cn: * **中文** 用于创建替换激活函数的脉冲神经元模块。默认创建 :class:`spikingjelly.activation_based.neuron.IFNode`,并使用 ``v_threshold=1.0`` 与 ``v_reset=None`` 保持原有 ANN2SNN 行为。默认转换会通过 :class:`VoltageScaler` 处理激活尺度,因此默认工厂不会把 ``scale`` 直接写入 神经元阈值;自定义工厂可读取 ``scale`` 派生阈值或其他参数。 :param neuron_type: 神经元类,必须接受 ``v_threshold`` 与 ``v_reset`` 关键字参数。 默认为 :class:`spikingjelly.activation_based.neuron.IFNode`。 :type neuron_type: Type[nn.Module] :param v_threshold: 神经元发放阈值,传递给神经元构造函数。 :type v_threshold: float :param v_reset: 膜电位复位值。``None`` 表示软复位(减法复位),默认为 ``None``。 :type v_reset: Optional[float] :param kwargs: 透传给神经元构造函数的其他关键字参数。 ---- .. _NeuronFactory.__init__-en: * **English** Factory that creates spiking-neuron modules used to replace ANN activation functions. By default it instantiates :class:`spikingjelly.activation_based.neuron.IFNode` with ``v_threshold=1.0`` and ``v_reset=None`` to preserve the original ANN2SNN behaviour. The default conversion handles the activation scale with :class:`VoltageScaler`, so the default factory does not copy ``scale`` into the neuron threshold. Custom factories may derive thresholds or other neuron parameters from ``scale``. :param neuron_type: Neuron class to instantiate. Must accept ``v_threshold`` and ``v_reset`` keyword arguments. Defaults to :class:`spikingjelly.activation_based.neuron.IFNode`. :type neuron_type: Type[nn.Module] :param v_threshold: Firing threshold passed to the neuron constructor. :type v_threshold: float :param v_reset: Membrane reset value. ``None`` means soft reset (subtractive reset). Defaults to ``None``. :type v_reset: Optional[float] :param kwargs: Additional keyword arguments forwarded to the neuron constructor. """ if not isinstance(neuron_type, type) or not issubclass(neuron_type, nn.Module): raise TypeError( f"neuron_type must be an nn.Module subclass, but got {neuron_type!r}." ) if not isinstance(v_threshold, (int, float)) or isinstance(v_threshold, bool): raise TypeError( f"v_threshold must be a real number, got {type(v_threshold).__name__}." ) if not math.isfinite(float(v_threshold)) or not (v_threshold > 0): raise ValueError( f"v_threshold must be finite and positive, got {v_threshold}." ) if v_reset is not None and ( not isinstance(v_reset, (int, float)) or isinstance(v_reset, bool) ): raise TypeError(f"v_reset must be None or a real number, got {v_reset!r}.") if v_reset is not None and not math.isfinite(float(v_reset)): raise ValueError(f"v_reset must be finite, got {v_reset}.") reserved = self.neuron_kwargs_reserved_keys() & kwargs.keys() if reserved: names = ", ".join(sorted(reserved)) raise TypeError( f"neuron kwargs contain reserved key(s): {names}. " "Use NeuronFactory parameters instead." ) self.neuron_type = neuron_type self.v_threshold = v_threshold self.v_reset = v_reset self.neuron_kwargs = kwargs
[文档] @staticmethod def neuron_kwargs_reserved_keys() -> set[str]: return {"v_threshold", "v_reset"}
[文档] def create(self, scale: float) -> nn.Module: r""" **API Language** - :ref:`中文 <NeuronFactory.create-cn>` | :ref:`English <NeuronFactory.create-en>` ---- .. _NeuronFactory.create-cn: * **中文** 根据工厂配置创建一个脉冲神经元模块实例。``scale`` 为当前层校准得到的激活 尺度,默认实现不直接使用该值,但子类可据此派生阈值或其他参数。 :param scale: 当前层的校准尺度。 :type scale: float :return: 配置完成的脉冲神经元模块。 :rtype: nn.Module ---- .. _NeuronFactory.create-en: * **English** Instantiate a spiking-neuron module with the configured parameters. ``scale`` is the calibrated activation scale of the current layer; the default implementation does not use it directly, but subclasses can derive thresholds or other neuron parameters from it. :param scale: Calibration scale for the layer. :type scale: float :return: A spiking-neuron module. :rtype: nn.Module """ return self.neuron_type( v_threshold=self.v_threshold, v_reset=self.v_reset, **self.neuron_kwargs, )
[文档] class HookFactory: def __init__(self, mode: Union[str, float] = "Max", momentum: float = 0.1): """ **API Language** - :ref:`中文 <HookFactory.__init__-cn>` | :ref:`English <HookFactory.__init__-en>` ---- .. _HookFactory.__init__-cn: * **中文** 用于创建校准阶段使用的 :class:`VoltageHook` 实例。每个匹配到的激活节点会获得 独立的 hook 实例。 :param mode: 校准模式,传递给 :class:`VoltageHook`。``"Max"`` 记录激活最大值; ``"99.9%"`` 记录 99.9 分位点;``(0, 1]`` 区间的 float 表示 ``max * mode``。 :type mode: str, float :param momentum: :class:`VoltageHook` 的 EMA 动量。 :type momentum: float ---- .. _HookFactory.__init__-en: * **English** Factory that creates :class:`VoltageHook` instances used during calibration. Each matched activation node receives an independent hook instance. :param mode: Calibration mode forwarded to :class:`VoltageHook`. ``"Max"`` records the maximum activation; ``"99.9%"`` records the 99.9-th percentile; a float in ``(0, 1]`` records ``max * mode``. :type mode: str, float :param momentum: EMA momentum for :class:`VoltageHook`. :type momentum: float """ if isinstance(mode, str): if not mode: raise ValueError("mode must be 'Max', a percentile string, or a float.") if mode[-1] == "%": try: percentile = float(mode[:-1]) except ValueError as exc: raise ValueError( "mode percentile string must contain a numeric value." ) from exc if not (0.0 <= percentile <= 100.0): raise ValueError( f"mode percentile must lie in [0, 100], got {mode!r}." ) elif mode.lower() != "max": raise ValueError( f"mode string must be 'Max' or a percentile string, got {mode!r}." ) elif isinstance(mode, (int, float)) and not isinstance(mode, bool): if not math.isfinite(float(mode)) or not (0.0 < float(mode) <= 1.0): raise ValueError(f"mode float must lie in (0, 1], got {mode!r}.") else: raise TypeError( "mode must be a string or a float in (0, 1], " f"got {type(mode).__name__}." ) if not isinstance(momentum, (int, float)) or isinstance(momentum, bool): raise TypeError( f"momentum must be a real number, got {type(momentum).__name__}." ) if not math.isfinite(float(momentum)) or not (0.0 <= float(momentum) <= 1.0): raise ValueError(f"momentum must lie in [0, 1], got {momentum!r}.") self.mode = mode self.momentum = momentum
[文档] def create(self) -> VoltageHook: r""" **API Language** - :ref:`中文 <HookFactory.create-cn>` | :ref:`English <HookFactory.create-en>` ---- .. _HookFactory.create-cn: * **中文** 创建一个新的 :class:`VoltageHook` 实例。 :return: 配置完成的 :class:`VoltageHook`。 :rtype: VoltageHook ---- .. _HookFactory.create-en: * **English** Create a new :class:`VoltageHook` instance. :return: A configured :class:`VoltageHook`. :rtype: VoltageHook """ return VoltageHook(momentum=self.momentum, mode=self.mode)