spikingjelly.activation_based.op_counter.spikesim.config 源代码
from __future__ import annotations
import math
from dataclasses import dataclass, replace
__all__ = ["SpikeSimEnergyConfig"]
_SPIKESIM_XBAR_ROW_DIVISOR = 8.0
[文档]
@dataclass
class SpikeSimEnergyConfig:
r"""
**API Language:**
:ref:`中文 <SpikeSimEnergyConfig-cn>` | :ref:`English <SpikeSimEnergyConfig-en>`
----
.. _SpikeSimEnergyConfig-cn:
* **中文**
SpikeSim 事件驱动能耗估计器的运行时能耗配置。
默认系数有意与已发布的 ``ela_spikesim.py`` 能耗路径保持一致,
但计数逻辑已替换为基于运行时事件的分析。
----
.. _SpikeSimEnergyConfig-en:
* **English**
Runtime energy configuration for the event-driven SpikeSim estimator.
The default coefficients intentionally match the released ``ela_spikesim.py``
energy path, while the counting logic is replaced by runtime event analysis.
"""
xbar_size: int = 64
device: str = "rram"
activity_mode: str = "dense"
require_if_lif_neurons: bool = True
tile_buffer_pj: float = 397.0
temp_buffer_pj: float = 0.2
sub_pj: float = 1.15e-6
adc_pj: float = 2.03084
htree_pj: float = 19.64 * 8.0
mux_pj: float = 0.094245
mem_fetch_pj: float = 4.64
neuron_pj: float = 1.274 * 4.0
rram_xbar_pj: float = 1.76423
sram_xbar_pj: float = 671.089
[文档]
def copy(self) -> "SpikeSimEnergyConfig":
r"""
**API Language:**
:ref:`中文 <SpikeSimEnergyConfig.copy-cn>` |
:ref:`English <SpikeSimEnergyConfig.copy-en>`
----
.. _SpikeSimEnergyConfig.copy-cn:
* **中文**
复制当前配置并返回新对象。
:return: 当前配置的副本
:rtype: :class:`SpikeSimEnergyConfig`
----
.. _SpikeSimEnergyConfig.copy-en:
* **English**
Return a copied config object.
:return: a copy of the current config
:rtype: :class:`SpikeSimEnergyConfig`
"""
return replace(self)
[文档]
def validate(self) -> None:
r"""
**API Language:**
:ref:`中文 <SpikeSimEnergyConfig.validate-cn>` |
:ref:`English <SpikeSimEnergyConfig.validate-en>`
----
.. _SpikeSimEnergyConfig.validate-cn:
* **中文**
校验配置是否合法; 不合法时抛出 ``ValueError``。
----
.. _SpikeSimEnergyConfig.validate-en:
* **English**
Validate the config and raise ``ValueError`` on invalid values.
"""
if self.xbar_size <= 0:
raise ValueError(f"xbar_size must be positive, got {self.xbar_size}.")
if self.device not in ("rram", "sram"):
raise ValueError(f"device must be 'rram' or 'sram', got {self.device}.")
if self.activity_mode not in ("dense", "event"):
raise ValueError(
f"activity_mode must be 'dense' or 'event', got {self.activity_mode}."
)
@property
def xbar_array_energy_pj(self) -> float:
if self.device == "rram":
return self.rram_xbar_pj
if self.device == "sram":
return self.sram_xbar_pj
raise ValueError(f"device must be 'rram' or 'sram', got {self.device}.")
@property
def patch_control_energy_pj(self) -> float:
b = float(self.xbar_size)
return (
self.htree_pj
+ self.mem_fetch_pj
+ self.tile_buffer_pj
+ (b / _SPIKESIM_XBAR_ROW_DIVISOR) * 16.0 * self.sub_pj
+ (b / _SPIKESIM_XBAR_ROW_DIVISOR) * self.temp_buffer_pj
+ (b / _SPIKESIM_XBAR_ROW_DIVISOR)
* (b / _SPIKESIM_XBAR_ROW_DIVISOR)
* (self.adc_pj + self.mux_pj)
)
[文档]
def pe_cycle_energy_for_kernel_pj(self, kernel_size: tuple[int, int]) -> float:
if len(kernel_size) != 2:
raise ValueError(
f"kernel_size must be a tuple of length 2, got {kernel_size}."
)
k_h, k_w = kernel_size
if k_h <= 0 or k_w <= 0:
raise ValueError(
f"kernel_size dimensions must be positive, got ({k_h}, {k_w})."
)
return (
self.patch_control_energy_pj
+ self.neuron_pj
+ (self.xbar_size / _SPIKESIM_XBAR_ROW_DIVISOR)
* float(k_h)
* float(k_w)
* self.xbar_array_energy_pj
)
[文档]
def xbar_row_energy_pj(self, tile_channels: int) -> float:
if tile_channels <= 0:
raise ValueError(f"tile_channels must be positive, got {tile_channels}.")
if self.xbar_size <= 0:
raise ValueError(f"xbar_size must be positive, got {self.xbar_size}.")
padded_ratio = math.ceil(tile_channels / self.xbar_size)
padded_ratio = padded_ratio * self.xbar_size / float(tile_channels)
# Keep the row-level basis aligned with the released SpikeSim dense
# energy path, whose xbar contribution scales as (xbar_size / 8) * k^2.
return (self.xbar_array_energy_pj / _SPIKESIM_XBAR_ROW_DIVISOR) * padded_ratio