摘要:
这项工作介绍了sPyNNaker 4.0.0,这是用于在SpiNNaker神经形态平台上模拟PyNN定义的尖刺神经网络(SNN)的软件包的最新版本。
1. INTRODUCTION
一个能够有效模拟脉冲神经元大规模网络(不同于深度学习社区中使用的人工神经网络)的平台,能够在多个研究领域中取得进步。其中包括:在计算神经科学领域内探索规模;了解类脑信息处理以及如何在传统计算问题中利用它;以及将类似大脑的系统嵌入物理应用程序的能力,例如,促进可控假肢和无人驾驶机器人等机器人的高效实时处理。使用定制硬件解决此类问题的好处是众所周知的,并导致了神经形态工程领域的发展(Indiveri和Horiuchi,2011)。
现在存在多个平台,它们能够对大量神经元和突触进行高性能仿真,其速度通常大大超过生物实时性。示例系统包括海德堡大学的StanfordNeuroGrid(Benjamin等人,2014),IBMTrueNorth(Akopyan等人,2015)和BrainScaleS平台(Schemmel等人,2010)。同时还开发了许多定制的芯片级系统(Qiao等,2015)。
这些系统具有一个共同的特征,即它们通过模拟硬件或具有固定软件的数字硬件中建模的神经元提供预定义的仿真功能。然而,许多神经形态系统专注于提供一个灵活的平台,为研究人员提供重新配置仿真功能以满足其问题要求的机会。 例子包括英特尔Loihi(Davies等人,2018)系统,该系统具有可配置的功能,例如用于学习的突触可塑性引擎; SpiNNaker系统由完全可编程的ARM内核组成(Furber,2016年)。尽管就绝对能量消耗或处理速度而言,这种灵活的特性相对于其他神经形态系统损害了这些平台,但它使它们成为有价值的研究工具,可用于探索计算神经科学及其他方面的新兴概念。
例如,这种灵活性已导致SpiNNaker平台执行大规模的神经元网络(Sen-Bhattacharya等人,2017; van Albada等人,2018),并进行认知任务分析,例如动作选择(Sen- Bhattacharya et al,2018)。还研究了学习在SNN中的应用,例如Knight等人(2016)中基于贝叶斯推理的学习研究,以及Mikaitis等人(2018)中的强化学习。 在计算神经科学领域之外,SpiNNaker还已应用于约束满足问题,例如,在Fonseca Guerra和Furber(2017)中解决了计算困难的数独或地图颜色问题。除了这些处理应用程序外,还展示了SpiNNaker系统在多个物理自主机器人中的实施方式,也许最令人印象深刻的应用是肌肉骨骼机器人硬件与在SpiNNaker上实现的神经控制系统的结合(Christoph等,2016)。然而,尽管取得了这些进步,但上述所有领域仍面临着巨大的挑战。为了进一步了解大脑和受大脑启发的系统,发展对记忆,动作选择和注意力的理解至关重要。 SpiNNaker方法使用可编程ARMcore来模拟神经元和突触,从而随着理论神经科学,并行计算和机器人技术领域的发展,可以同时升级和扩展系统功能。这不仅促进了这些领域的研究,而且为高性能,更“刚性”的基于硬件的神经形态解决方案的设计提供了宝贵的见识。但是,此类软件的创建与大多数其他计算机器不同(Furber等2013; Brown等2015; Lin等2018);虽然SpiNNaker硬件的开发已经有充分的文献记载(Furber等2013,2014; Painkras等2013),但迄今为止,该软件的关注点有所减少。
本文全面概述了SpiNNaker软件中与尖峰神经网络建模有关的最新技术。 因此,它将重点描述sPyNNaker存储库1中的软件,包括用于模拟神经元网络的内部操作,硬件资源的使用和用户交互。该描述 https://github.com/SpiNNakerManchester/sPyNNaker假定存在SpiNNTools,这是基于低级图的软件,用于管理SpiNNaker机器上通用并行软件的执行,如Rowley等人(2018)所述。 虽然SpiNNaker软件的版本先前已部分发布(Jin等人,2010; Sharp等人,2011,2012; Davies等人,2012),但这项工作为基础操作和相关的硬件交互提供了全面的概述 其中有指导性的API设计。希望这将为系统用户提供洞察力,从而在扩展软件框架以用于未来的神经应用程序时提高性能。 作为本文其余部分的背景,在此介绍之后,将对SpiNNaker硬件和用于定义尖峰神经元网络的PyNN接口进行高层概述。 接下来是方法和实现部分,深入探讨了由英国曼彻斯特大学的SpiNNaker软件团队开发的sPyNNaker API。 然后提供表现出性能分析的结果。 最后,讨论部分将对本文进行完善,并提供有关API未来方向的建议。
2. Background
2.1 the spinnaker platform---hardware to simulate 1 billion neurons
Spinnaker用来仿真real time SNN, 并在软件中对神经元和突触进行建模。该机器针对的是包含大约10^9个神经元和10^12个突触的大规模网络,每个神经元的平均扇出数为10^3(Furber等人,2013),适用于处理10Hz的平均触发频率(峰值频率为100Hz) )。根据模拟突触所需的计算能力来确定机器的大小,因为这些突触通常主导神经网络处理。假设处理单个突触事件需要20条指令(其中,突触事件定义为接收单个脉冲的单个神经元),则机器的大小可提供2×10^8 MIPS,每秒可处理10^13个突触事件。
出于简化和成本的原因,使用了现成的组件,特别是用于处理的ARM9内核。在200MHz时钟速度下,需要10^6个ARM9内核进行突触处理,因此每个ARM内核应同时对10^9个神经元中的10^3个建模。本节的其余部分概述了后续的SpiNNaker芯片,包括有关芯片布局的详细信息以及与神经仿真有关的功能。
SpiNNaker芯片具有18个内核,以及片上网络(NoC)和外部RAM控制器-如图1所示。每个内核包含:ARM968(ARM,2004年),直接存储器访问(DMA)控制器,通信控制器,网络接口控制器以及其他外设,包括计时器。 每个内核都以200MHz的时钟速度运行,并且通常运行一个模拟一组神经元的应用程序。 每个内核具有96 kB的紧密耦合内存(TCM),可避免争用被分割:32 kB用于指令(ITCM),64 kB用于数据(DTCM)。应用程序代码被编译成ARM968可执行文件并加载到ITCM,而DTCM包含应用程序数据,包括堆,堆栈和其他读/写以及零初始化数据。 每个芯片都有一个额外的128MB共享内存(SDRAM),可由芯片上的所有内核直接访问。 对这些不同的存储器的访问时间相差很大,因此在设计SpiNNaker软件应用程序时要重点考虑。
单个DMA请求最多可以传输64 kB,但可以分解成较小的数据突发以方便传输。该突发大小通常设置为16 double words,每个突发建立期间会产生少量时间损失。DMA请求在SDRAM控制器上受到竞争,但是每个DMA控制器一次只能提交一个突发请求,从而在内核之间引入了公平的排队策略。还要注意,请求本身很容易发生争用,这可能导致DMA操作启动时出现等待时间。尽管在DMA请求之间存在这种争用,但SDRAM控制器带宽仍具有同时向多个内核传输DMA的能力,既可以向SDRAM读取数据,也可以从SDRAM写入数据。但是,当读取三个或更多核心,而写入两个或更多核心时,性能将受到带宽限制,最大带宽据报道为900MBs-1(Painkras等,2013; Sharp和Furber,2013)。
Individual SpiNNaker chips 以二维网格的形式组装到板上,常见的板尺寸包含4和48个芯片。 然后可以连接多个板以创建SpiNNaker“机器”。 内核以全局异步本地同步(GALS)方式运行,并通过通过NoC和SpiNNaker路由器发送的小消息或数据包进行通信(Navaridas等,2015)。路由器允许将数据包传输到芯片上内核的任何子集以及6个片外链路的子集(启用芯片到芯片传输,从而将数据包路由到计算机上的任何内核)。本文介绍的神经应用程序使用多播数据包,该数据包设计为同时从源传输到多个目标。multicast packet包含系统使用的8-bit control byte和用于路由数据包的32-bit key。在table of entries中查找该key,每个entries指示应将匹配的cores and/or链接数据包发送至哪个。这种multicast behavior使core可以发送针对多个目的地的单个消息,而不必向每个目的地发送单独的消息。它还允许一劳永逸地发送数据包,而无需在源和目标之间进行网络级互锁。 与传统的网络体系结构相比,最终的以源为导向的路由体系结构可以实现高效的消息分发。
SpiNNaker软件应用程序通常用C编写,并编译成ARM可执行代码以实现最大执行速度。 在设计解决方程组的应用程序时,必须考虑精度对结果及其数值稳定性的影响。SpiNNaker ARM968不支持硬件浮点,而软件实现的浮点操作在ITCM和执行时间方面都非常昂贵。 因此,在求解控制神经动力学的方程组时,定点算法是首选的数据表示形式。尽管可以创建自定义的定点数据类型,并有可能实现最佳性能(Jin等,2008),但除非另有说明,否则建议使用ISO / IEC TR 18037:20082标准。 这提供了与定义标准浮点运算的类型和运算符相似的类型和运算符,从而为非专业的ARM968程序员提高了读取和代码开发的便利性。 该标准已在针对ARM目标的GCC工具链中实现,其中5.4版是sPyNNaker 4.0.0的推荐编译器。 除非另有说明,否则本文中的变量将根据ISO标准累加类型进行定义:带符号的16整数和15分数位固定点数,如Hopkins和Furber(2015)所述。键入为accum的变量的绝对下限为0.000030517578125(发生下溢且低于此值将返回0),并且绝对上限为65535.999969482421875(在其之上将上溢并包装)。由于缺乏硬件支持,所以划分是昂贵的,并且在开发对性能有严格要求的应用程序时,应该用相乘来代替。 定点标准的扩展实现了指数和对数函数,但是它们的评估成本很高,因此在用作常量以优化性能时应在主机上预先计算。
2.2. PyNN
PyNN是一个Python界面,用于为一系列模拟器后端定义SNN模拟(Davison等,2008)。 它允许用户一次通过Python脚本指定SNN仿真,并使其在任何或所有受支持的后端上执行,包括NEST(Gewaltig和Diesmann,2007),NEURON(Carnevale和Hines,2006)和Brian( Goodman和Brette,2009年)。这鼓励了模拟器的标准化,结果的可重复性,并通过代码共享和重用以及为与模拟器无关的后处理,可视化和数据管理工具提供了基础,从而提高了神经网络建模器的生产率。
PyNN作为欧洲旗舰人类脑计划的一部分(Amunts等人,2016)而继续发展,因此被包括SpiNNaker在内的许多合作伙伴采用作为建模语言。 它提供了用于定义神经元,突触和输入源的结构化界面,使用户可以灵活地构建各种网络拓扑。
模型通常由single-compartment point 神经元组成,并按“population”分组。然后将这些population与“projection”联系起来,“projection”代表source population中神经元轴突与目标population中神经元树突之间的突触连接。 一旦定义,许多仿真控件将用于在给定的时间段内执行模型,并具有在运行之间更新参数和初始化状态变量的选项。在仿真中,可以提取完成数据以供后处理和将来参考。 神经元变量如:脉冲序列,总突触电导和神经元膜电位可从population对象获得; 而突触的权重和延迟是从projection中提取的。 随后可以使用内置绘图功能保存或可视化此数据。
CODE 1中详细说明了用于生成总体和投影的示例PyNN命令。
此处,模拟器的sPyNNaker版本作为sim导入,随后用于构建和执行仿真。
创建带有标签“ poisson_source”的250个泊松源神经元,并在5 s内向网络提供50Hz输入。
然后创建第二个500个整合并激发神经元的population,并将其标记为“ excitatory_pop”。
在“ poisson_source”和“ excitatory_pop”之间建立兴奋connection,连接概率为20%,每个连接的权重为0.06 nA,并通过概率分布指定延迟。
然后启用“ excitatory_pop”的数据记录,并执行5 s的模拟。
最后,从模拟器中提取“ excitatory_pop”脉冲历史数据。
因此,PyNN仿真器的工作是提供PyNN语言的特定于后端的实现,从而能够执行在模型脚本(CODE S1)中定义的仿真。
SpiNNaker硬件(s-PyNN-aker)的PyNN实现在第3节中进行了详细介绍,这是这项工作的主要贡献。 它涵盖了将PyNN脚本转换为适合在SpiNNaker机器上执行的形式的过程,以及在机器本身上的低级执行的过程。
1 import pyNN.spiNNaker as sim
7 # Spike input
8 poisson_spike_source = sim.Population(
9 250,
10 sim.SpikeSourcePoisson(rate=50, duration=5000),
11 label=’poisson_source’)
30 pop_exc = sim.Population(
31 500,
32 sim.IF_curr_exp(**cell_params_exc),
33 label=’excitatory_pop’)
58 poisson_projection_exc = sim.Projection(
poisson_spike_source, pop_exc,
59 sim.FixedProbabilityConnector(p_connect=0.2),
60 synapse_type=sim.StaticSynapse(weight=0.06,
delay=delay_distribution),
61 receptor_type=’excitatory’)
62 poisson_projection_inh = sim.Projection(
poisson_spike_source, pop_inh,
93 pop_exc.record(’all’)
94 pop_inh.record(’spikes’)
98 sim.run(simtime=5000)
102 exc_data = pop_exc.get_data(’spikes’)
103 inh_data = pop_inh.get_data(’spikes’)
3. SPYNNAKER: METHODS AND IMPLEMENTATION
sPyNNaker API由两个软件栈组成,如图2所示:一个在主要用Python编写的主机上运行,另一个在用C编写的SpiNNaker机器上运行。
用户通过PyNN接口创建SNN模型,然后通过将Python sPyNNaker软件转换为适用于SpiNNaker机器的形式。 通过事件驱动的操作系统在SpiNNaker机器上执行仿真,并在仿真完成结果上将数据提取回主机,以通过PyNN API进行后处理和可视化。
本节从预处理的SNN特定方面的摘要开始,详细说明了这些阶段的软件实现(有关基于Python的预处理阶段的进一步说明,读者请参阅Rowley等人,2018)。 然后详细介绍了SpiNNaker计算机上的仿真执行,包括事件驱动的操作系统SpiN1API的概述。 然后介绍了用于定义神经元和突触模型的软件框架,然后概述了现有的实现。 最后,讨论了辅助应用程序,包括生成输入峰值以驱动网络行为。
3.1. Preprocessing
用户在图2左侧堆栈的顶部创建一个定义SNN的PyNN脚本。 指定了SpiNNaker后端,它将SNN转换为适合在SpiNNaker机器上执行的形式。 该过程包括:将SNN映射到应用程序图,划分成机器图,生成所需的路由信息以及将数据和应用程序加载到SpiNNaker机器。加载完成后,将指示所有核心应用程序开始执行,并运行预定的时间。 仿真完成后,将从机器中提取请求的输出数据,并通过PyNN API进行访问。完整的仿真工作流程的文档超出了本文的范围,但是Rowley等人介绍了此处未详述的方面(2018)用于基于图的通用仿真(将SpiNNaker扩展到神经应用之外)。 但是,由于SNN的某些方面对仿真工作流具有直接影响,因此下面将介绍在神经仿真的背景下此过程中的关键点。
样本SNN被开发为描述预处理阶段的工具。 根据代码S1(补充材料)中详细介绍的PyNN脚本定义了随机平衡网络,结果网络拓扑如图3A所示。
该网络由500个兴奋性神经元和125个抑制性神经元组成,它们分别相互产生兴奋性和抑制性预测。 另外,每个population都以相同的效果反复连接到自己。 包含兴奋的泊松分布输入以表示背景活动,同时通过尖峰源阵列注入预定义的尖峰模式。
神经元population由基于电流的泄漏积分和发射(LIF)神经元组成,兴奋性population中每个神经元的膜电位通过阈值和静息电位的均一分布进行初始化。
sPyNNaker API首先解释PyNN定义的网络以构建应用图:神经网络的顶点和边缘视图,其中每个边缘对应于带有突触的projection,每个顶点对应于一组神经元。然后,通过根据可用硬件资源和需求约束细分应用程序顶点和边缘,将该应用程序图划分为机器图,最终确保每个生成的机器顶点都可以在单个SpiNNaker内核上执行。从此以后,术语“顶点”将指代机器顶点,与术语“sub population”同义,表示可以在单个核上模拟的一组神经元。 图3中显示了该分区的示例,其中,由于其大小, “Excitatory Population” 被分为两个子分区(A和B)。图3还显示了如何创建其他机器边缘以保留分区A,B和其他总体之间的网络拓扑,以及在此过程中如何不同地对待不同的PyNN连接器。例如,PyNN OneToOneConnector将population中的每个神经元连接到自身。 这导致分区A和B都具有代表其自身连接的机器边缘,但是不需要边缘来将连接器从一个sub population 映射到另一个sub population。 相反,PyNN FixedProbabilityConnector根据连接概率将源population和目标population中的神经元链接起来,因此需要机器边缘携带所有可能的突触连接(例如,在顶点A和B之间以及它们自身之间)。
分区后,机器图将放置在SpiNNaker机器的虚拟表示上,以方便分配基于芯片的资源(例如核心和内存)。 从该虚拟表示中删除了会损害SpiNNaker机器性能的已知故障内核,芯片和电路板链接,并相应放置了机器图。 然后生成特定于芯片的路由表,以利于根据代表PyNN定义的投影的机器边缘传输尖峰信号。 这些表随后被压缩并加载到路由器内存中(如第2.1节所述)。然后,图2中的Python软件堆栈生成核心特定的神经元和突触数据结构,并使用SpiNNTools软件将它们加载到SpiNNaker机器上。 核心特定的神经元数据被加载到适当的DTCM,而相关的突触数据被加载到同一芯片上SDRAM的核心特定区域,准备根据3.2节使用。 最后,将在应用程序内核上执行的程序加载到ITCM,每个内核执行初始化功能以加载适当的数据结构(来自SDRAM)并在切换到就绪状态之前准备内核。 一旦所有仿真核心就绪,主机将向所有核心发出开始仿真的信号,并且SNN将根据3.2节中定义的过程执行。
3.2. SpiNNaker Runtime Execution
sPyNNaker应用程序使用时间驱动的神经元更新和事件驱动的突触更新,通过混合仿真方法执行SNN,与Morrison等人(2005)中讨论的类似。 这种神经元更新方案提供了一个灵活的框架,可以在其中嵌入一系列神经元模型,并且在考虑生物学上具有代表性的脉冲频率时,其效率与基于事件的方法相当。突触事件得到有效处理,不需要更新突触前神经元脉冲之间突触状态的中间信息,在生物网络中,突触状态在1Hz的数量级上相对很少见。 执行sPyNNaker应用程序的内核将神经元状态变量保存在本地DTCM中,从而可以高效地访问所需的数据结构,以进行周期性的时间驱动的神经元更新。 core之间的脉冲传输是通过地址事件表示(AER)模型(Mead,1989年)进行的,神经元动作电位以多播数据包的形式进行通信,其键仅包含源神经元ID(在本工作的其余部分中称为:动作电位) ,秒杀和数据包是同义词)。每个数据包都可以通过SpiNNaker路由结构同时传递到多个位置,从而复制了轴突的一对多连接。 数据包的处理由内核模拟突触后神经元执行,该内核包含仅使用数据包密钥评估基于尖峰的突触贡献的功能。 由于可能会大量扇入神经元,因此内存限制会阻止将突触数据存储在DTCM中。 因此,源神经元ID用于定位存储在相对较大但速度较慢的SDRAM内存中的关联突触数据,并在尖峰到达时将其本地复制,以方便评估对突触状态的贡献。
本节着重于在模拟神经元亚群的单个核心中部署此模拟方法,例如图3B中的“兴奋性A”。 它包括:基本的基于事件的操作系统和底层软件库的概述; 关于执行框架和关键软件功能(也称为回调)的讨论; 最后是运行时操作的讨论,使读者可以深入了解处理层次结构。 在3.3节中将对这种模拟方法对神经元和突触模型动力学的影响进行后续讨论。
3.2.1. Operating System and Low-Level Libraries
为了消除底层编程的复杂性并专注于神经建模任务,针对sPyNNaker应用程序针对SpiNNaker Application Runtime Kernel(SARK)(Temple,2016)和事件驱动库SpiN1API(Sharp等人, 2011; SpiNNaker,2011a)。
SARK提供了底层硬件管理,简化了与DMA,网络接口和通信控制器的交互。SpiN1API提供了一个基于事件的操作系统,如图4所示,每个内核具有三个处理线程:一个用于任务调度,一个用于任务调度,一个用于服务快速中断请求(FIQ)。
SpiN1API还提供了将软件回调链接到硬件事件的机制,并能够触发动作,例如将数据包发送到另一个内核和启动DMA。 根据所需的功能,以-1至2的不同优先级注册回调,优先安排较低的编号。可以将优先级为1和2的回调任务排队(在最大长度为15的队列中),并将新事件添加到队列的后面。 优先级为-1和0的回调不排队,而是为优先任务分配了更高的优先级编号。 该系统的操作遵循图4A中详述的流程。 调度程序线程将回调放入优先级为1和更高级别的队列中,调度程序选择这些回调并根据优先级执行它们。 当调度程序正在执行优先级为1或更高的回调并且调度了优先级为0的回调时,此任务将抢占当前正在执行的任务,从而使其挂起,直到更高优先级的回调已完成。优先级-1的回调使用FIQ线程与调度程序和调度程序进行交互,从而可以快速响应和抢占优先级0及以上的任务。 指针被存储以允许快速访问回调代码,处理器切换到FIQ存储区寄存器以避免堆栈需求(Sloss等人,2004),优化了优先级-1回调的响应时间。 但是,这种优化的性能将应用程序限制为仅注册单个-1优先级事件和回调。
在sPyNNaker应用程序的神经元和突触建模系统中,针对硬件事件注册了回调:计时器,接收到的数据包和DMA完成; 表1中显示了软件触发的用户事件。相关的回调有助于定期更新神经元状态,并在代表峰值的数据包到达核心时对突触进行基于事件的处理。这些事件(正方形)及其回调(圆圈)如图4B所示。 函数timer_callback会随着时间改变神经元的状态,并在整个仿真过程中定期针对定时器事件进行调用。 数据包接收事件触发_multicast_packet_received_callback,该回调读取数据包以提取源神经元ID并将其传输到尖峰队列。 如果当前未执行任何尖峰处理,则发出软件触发的用户事件,然后执行user_callback,该事件从尖峰队列中读取下一个ID,找到存储在SDRAM中的关联突触信息,并启动DMA进行复制 进入DTCM进行后续处理。最后,_dma_complete_callback在DMA完成事件上执行,并启动对突触后神经元的突触贡献的处理。 如果完成此处理后,输入尖峰队列中仍有剩余项目,则此回调将启动下一个尖峰的处理:这意味着此回调集合可被视为尖峰处理管道。
3.2.2. Time-Driven Neuron Update
sPyNNaker模拟通常包含多个核,每个核模拟一个不同的神经元population(见图3B)。 每个核心通过具有固定仿真时间步长(△t)的显式更新方案,及时推进其神经元的状态。 当一个神经元被触发时,数据包被传递到神经元投射到的所有核心,并由突触后核心实时处理以评估所产生的突触贡献。 因此,尽管所有核异步运行,但是希望在所有核上近似并行地推进神经元,以便连贯地进行仿真。 因此,仿真中的所有内核都开始同步,并以通用频率注册定时器事件,事件之间的时间间隔由固定数量的时钟周期定义,如图5所示。
When a neuron is deemed to have fired, packets are delivered to all cores that neuron projects to, and processed in realtime by the postsynaptic core to evaluate the resulting synaptic contribution. Therefore, while all cores operate asynchronously, it is desirable to advance neurons on all cores approximately in parallel in order to march forward a simulation coherently. All cores in a simulation therefore start synchronized, and register timer events with common frequency, with the period between events defined by a fixed number of clock cycles, as shown in Figure 5.
因此,尽管系统是异步的,因为没有用于同步内核的硬件或软件机制,所以所有内核将发起一个计时器事件并执行timer_callback以大致并行地推进其神经元的状态。个别更新时间可能会因进行任何额外的尖峰处理而有所不同(请参阅第3.2.6节),但是,在一对较低的定时器事件之间具有额外脉冲要处理的内核可能会在随后的较低活动周期中赶上。电路板之间的相对漂移可能是由于时钟速度的微小变化(由于时钟晶体制造的可变性)引起的,但是相对于仿真时间而言,这种影响很小(SpiNNaker,2011b)。由于“启动”信号的传递方式(尤其是在大型机器上),也会发生使内核更新略有异相的小变化。但是,这种影响可以忽略不计。
这种更新方案的结果是将生成的峰值限制在时间网格(模拟时间步长△t的倍数)上。由于不能保证在更新神经元之前的当前时间步中输入无法到达,因此它还强制在△t神经元之间进行有限的最小仿真脉冲过渡时间。从硬件的角度来看,百万核心计算机的最大数据包传输时间为_25μs(假设每个路由器200 ns(SpiNNaker,2011b),最大路径长度为128)。
SpiNNaker平台的设计目标是实现SNN的实时仿真,其中“实时”定义为模拟网络所需的时间与网络建模的时间相匹配。因此,模拟timestep为△t = 1ms的SNN,需要将the period of timer events设置为200,000个clock cycles(其中在200MHz时,每个时钟周期的周期为5 ns,请参见第2.1节)。这将导致1ms的仿真过程在1ms内执行,这意味着该解决方案将紧跟wall-clock time,从而实现出色的性能,并与在 same clock上运行的系统(例如机器人,人类和动物)进行交互。实际上,实时执行并非总是可行的,因此在特殊情况下用户可以自由地减小△t的值,还可以调整定时器事件之间的时钟周期数。例如,如果神经元模型需要△t = 0.1ms的精度,通常的做法是让计时器事件之间的时间间隔保持为200、000个时钟周期,以确保有足够的处理时间来更新神经元并处理传入的峰值(Sen-Bhattacharya等人,2018)。相对于实时,这会强制将减速因子设置为10。
从单个核心的角度来看,每个神经元在时间t0处使用用户定义的参数进行初始化(通过PyNN脚本提供)。然后,一次一次更新所有状态变量,直到模拟结束时间趋于正常。根据趋势和用户定义的仿真时间步长△t(在仿真过程中是固定的)计算所需的更新次数以及因此发生的计时器事件。根据算法S1,每次调用timer_callback都会使核心上的所有神经元前进△t,如图6左侧所示。首先,根据模型的形状更新核心上所有神经元的突触状态。规则,并且此时间步长的所有新输入都将从突触输入缓冲区添加(如下所述)。在此更新过程中禁用了中断,以防止脉冲处理操作同时访问缓冲区。然后依次更新核心上所有神经元的状态。在内存中访问当前时间Nit的单个神经元状态,如果神经元not refractory,则根据表征其sub-threshold dynamics 的模型来更新其状态(请参见第3.3节中的示例)。如果判断为发出脉冲信号,则启动 refractory dynamics ,并指示路由器将 multicast packet 发送到网络。最后,所有请求的神经元变量都被记录为属于该新时间步(t +△t),并存储在核心存储器中,以便随后由SpiNNTools软件提取—在此过程中禁止中断,以防止同时访问记录数据结构。
突触输入缓冲区(图6中部)用于累积给定受体类型上的所有突触输入,从而消除了管理各个突触状态变量的计算成本(如Morrison等人,2005年开发)。每个缓冲区都由多个“插槽”构成,其中每个插槽代表未来仿真时间步长上的输入。所有指定要在特定时间到达的输入都被累积在适当的时隙中,从而将突触模型约束到其贡献可以线性求和的模型。指针保持与进行中的时间步长(t + 1t)相关的输入。每次神经元更新都会消耗此指针寻址的输入,然后将其前进一个时隙(有效地旋转缓冲区)。当指针到达最后一个时隙时,它会循环回到第一个时隙,这意味着这些时隙连续表示接下来的d个时间步长内的输入,其中d是时隙数。默认情况下,d的值是通过4位无符号整数设置的,从而可以表示最多16个时间步长的延迟(但是3.4.2节包含有关扩展此延迟的信息)。在默认的sPyNNaker实现中,为每个神经元,每个受体类型创建一个突触输入缓冲区,并且是16个槽的集合,每个槽由无符号的16位整数构成。 相对于使用标准的32位定点累加类型,使用整数表示可以减少DTCM中的缓冲区大小,也可以减少SDRAM中突触权重的大小。 但是,它需要转换为累加类型,以用于神经元模型计算(如图6所示)。此转换是通过并集和左移来执行的,其大小代表了余量和精度之间的权衡。所示的示例移位为6,在突触状态的累加类型中,使突触输入缓冲区的最小位表示2-9 = 1.953125×10-3,最大27 = 128。 在极端条件下,缓冲区插槽将因并发的尖峰活动而饱和,这意味着应增大移位大小。 但是,移位也是权重表示的内在因素,并且会影响精度,因为在将所有权重作为整数写入第3.2.5节中讨论的突触矩阵之前,所有权重必须按2(15-shift)进行缩放。 例如,在图6中,将1.15 nA的权重在生成突触数据时转换为主机上的589,但在仿真过程中使用时(移位6)则返回1.150390625 nA。 偏移值目前是由sPyNNaker工具链计算得出的,以在处理大重量,高扇入和/或突触前射击频率以及保持精度之间取得平衡。有关更多详细信息,请参见van Albada等人(2018)。
3.2.3. Receiving a Spike(接收脉冲)
_multicast_packet_received_callback由数据包接收事件触发,该事件在多播数据包到达核心时触发。 该回调被分配了最高优先级(-1),因此利用了FIQ线程并抢占了所有其他核心处理(参见图4A)。 此回调无法排队,因此,为防止流量在网络上备份,此回调旨在快速执行,并且只需提取源神经元ID(从32bit key)并将其存储在输入峰值缓冲区中以进行后续处理。 请注意,默认情况下,该缓冲区的长度为256个条目,从而可以同时对256个脉冲进行排队。 然后,该回调检查尖峰处理管道中是否有活动,如果不活动,则注册一个用户事件。 算法S2中提供了此回调的伪代码。
3.2.4. Activation of the Spike Processing Pipeline 激活脉冲处理pipeline
user_callback回调由在3.2.3节中注册的用户事件触发,并启动脉冲处理管道。 回调在SDRAM中定位与脉冲ID相关联的突触数据,并启动将其DMA传输到DTCM进行后续处理。
在此过程中使用了三种特定于核心的数据结构,即:master population table, address list, and synaptic matrix。
当从Excitatory A population中获得脉冲时,从模拟图3B中的Excitatory A population的core的角度来看,这些数据结构的使用如图7所示。The master population table是一个lightweight list,它以被屏蔽的源神经元ID作为关键字,从而可以标识源顶点。 每行属于一个源顶点(source vertex),由以下各项组成:32-bit key; 32-bit mask; 16-bit start location of the first row in the address list pertaining to this source vertex; and a 16-bit value defining the number of rows, where each row in the address list represents a PyNN projection。
搜索此table时,在与entry key进行比较之前,将使用每个entry-specific mask来屏蔽来自传入数据包的key。这掩盖了单个神经元ID位,并使源顶点能够模拟不同数量的神经元。 The entry keys在加载之前在主机上被屏蔽以提高效率,并且其结构可以防止屏蔽后出现重叠并便于二进制搜索。 The structure of an address list row consists of:a single header bit detailing whether the synaptic matrix associated with this projection is located in DTCM or SDRAM; 32-bit memory address indicating the first row of the synaptic matrix; and an 8-bit value detailing the synaptic matrix row length (i.e., the maximum number of postsynaptic neurons connected to by a presynaptic neuron in a particular projection)。
Note that synaptic matrix rows are indexed by source neuron ID, and that all rows are padded to the maximum row length to facilitate retrieval, including empty rows for presynaptic neurons not connected to neurons on this core. The row data structure is covered in detail in section 3.2.5.
因此,This callback从input spike buffer中获取下一个spike ID进行处理,并在master population table的二进制搜索中使用它来定位地址列表区域,以捕获携带spike到该顶点的projection。 然后,SDRAM location and size specified by each row are then used
in sequential processing of the projections。 对于图7所示的情况,搜索master population table会在address list中产生两行,这些行又定义了SDRAM中相应突触矩阵的位置。 根据突触前神经元ID对每个突触矩阵进行索引,从而使适当行的位置能够复制到核心DTCM,以处理每个spike。 然后,该行的详细信息将传递到DMA控制器以开始数据传输,标志着回调的结束。 这允许内核返回到处理其他回调,从而隐藏DMA传输,如图9中的“Spike 1”所示。
3.2.5. Synapse Processing
在3.2.4节中完成DMA后,DMA完成事件会触发_dma_complete_callback,从而启动对突触行的处理。
As described previously, each row pertains to synapses made, within a single PyNN projection, between a single presynaptic neuron and multiple postsynaptic neurons. At the highest level, a synaptic row is an array of synaptic words, where each word is defined as a 32-bit unsigned integer. The row is split into three designated regions to enable identification of static and plastic synapses (connections capable of changing their weight at runtime). The row regions contain: dynamic plastic data; constant fixed plastic data; and static data. Three header fields are also included, detailing the size of each region and enabling easy navigation of the row. A schematic breakdown of the synaptic row structure is detailed in Figure 8. Note that because a PyNN projection cannot be both static and plastic simultaneously, a single row contains only either static or plastic data. Plastic data is intentionally segregated into dynamic and fixed regions to facilitate processing. While all plastic data must be copied locally to evaluate synaptic contributions to a neuron, only the dynamic region—i.e., that changing at runtime—requires updating for use when processing subsequent spikes. Keeping this dynamic data in a separate block facilitates writing back to the synaptic matrix with a single DMA, and writing back less data helps compensate for reduced DMA write bandwidth (relative to read—see section 2.1).
The static region占据突触行的下部,并且本身就是一组synaptic words,其中每个单词对应于该行的突触前神经元和单个突触后神经元之间的突触连接。
如图8所示,each 32-bit data structure is split such that the top 16 bits represent the weight, while the lower 16 bits typically
split: bottom 8 bits specifying the postsynaptic neuron ID; 1 bit to specify the synapse type (excitatory 0, or inhibitory 1); 4
bits to specify synaptic delay; leaving 3 bits of padding (useful for model customization, e.g., adding additional receptor types).
Data defining plastic synapses is divided across the dynamic and fixed regions. Fixed plastic data is defined by a 16-bit
unsigned integer, and matches the structure of the lower half of a static synapse (see lower half of Figure 8). These 16-bit synaptic half-words enable double-packing inside the 32-bit array of the synaptic row, meaning an empty half-slot will be apparent if the row targets an odd number of postsynaptic neurons. The dynamic plastic region contains a header defining the Presynaptic Event History, followed by a series of Synapse Structures capturing the weight of each synapse. Note that for typical plasticitymodels this defaults to the same 16-bit weight describing static synapses, however Synapse Structure can be extended to include additional parameters (in multiples of 16 bits) if required by a given plasticity rule.
A task of the _dma_complete_callback is therefore to convert the synaptic row into individual postsynaptic neuron input. The callback processes the row headers to ascertain whether it contains static or plastic data, adjusts synapses according to a given plasticity rule, and then loops over each synaptic word and extracts its neuronal contribution—pseudo code for this callback is detailed in Algorithm S4. An example of this process for a single static synaptic word is shown in the lower-right of Figure 6, where a synaptic word of [0000001001001101 0001010100001100] leads to a contribution of 589 to slot 10 of the inhibitory synaptic input buffer for neuron N12.
3.2.6. Callback Interaction
The callbacks described above define how a sPyNNaker application responds to hardware events and updates an SNN simulation. The interaction of these events is a complex process, with the potential to impact the ability of a SpiNNaker machine to perform realtime execution. Figure 9 covers the time between two timer events, and shows interaction of spike processing and neuron update callbacks for four scenarios detailed by the arrival of spikes 1–4. The first timer event initiates processing of the neuron update, however after completion of approximately one third of the update, the core receives Spike 1, interrupting the timer_callback and triggering execution of a _multicast_packet_received_callback, which in turn raises a user event, initiating DMA transfer of the appropriate synaptic information. On completion of the callback, the core returns to the timer_callback, with the DMA transfer occurring in parallel. On completion of the DMA, a _dma_complete_callback is initiated, which processes the transferred synaptic information into neuronal input. The core then returns to the timer_callback, which continues to completion. The core is idle when it receives Spike 2, therefore processing of the spike begins immediately, and the subsequent user event and hence DMA request is initiated. While waiting for the data to transfer, Spike 3 is received, and the associated _multicast_packet_received_callback processed. This time, due to the active spike processing pipeline, no user event is raised, and instead the DMA for Spike 3 is initiated at the beginning of the _dma_complete_callback triggered by Spike 2. Whilst processing this callback, Spike 4 is received, and the associated _multicast_packet_received_callback interrupts the core to place the packet key in the input spike buffer. This buffer entry is eventually processed at the beginning of the _dma_complete_callback for Spike 3, demonstrating the spike processing pipeline in action. This also shows the benefit of having two hardware “threads” working in parallel, as the core is utilized completely, and the DMA transfer hidden behind the _dma_complete_callback, when the pipeline is active. Finally, after an idle period (where the processor is put to sleep in a low energy state) the next timer event is issued at time t + △t.
From Figure 9 it is seen that core processing is dependent on SNN activity. When targeting realtime execution (section 3.2.2), it is important to consider extreme circumstances and how they will affect both the core and global simulation. For example, it is clear from Figure 9 that when a core receives spikes, it can delay completion of the timer_callback due to the assigned callback priorities (as shown in Figure 5). This is a design choice, as it helps maximize core utilization by hiding DMA transfers behind the timer_callback when the spike processing pipeline is inactive. However, in the extreme case spike processing will delay completion of the callback beyond the issuing of the next timer event. While the core can potentially catch up this lost time, this scenario has the potential to delay the neuron update beyond a single timer event, and ultimately cause any spike packets emitted from this core to be received and processed at the wrong time by the rest of the network. To guard against this, sPyNNaker applications report any occurrences of an overrun, where a timer_callback is not complete before the next timer event is raised; and also the maximum number of timer events that a single timer_callback overruns. Similar metrics are also reported when the input spike buffer overflows (exceeds 256 entries), and when the synaptic input buffers saturate. Together these metrics provide a window into the ability of a core to handle the required processing within a simulation.
Another important performance consideration when responding to spike packets using prioritized events is the time taken to switch between the associated callbacks. Events are displayed in Figure 9 by solid black lines, the width of which represents the time taken to switch context and begin execution of the callback. The timer_callback takes longest to respond due to queuing of events with priority > 0; while the _multicast_packet_received_callback is quickest due to its priority of −1 and use of the FIQ thread. Other chip-level factors can also influence execution, such as SDRAM contention with applications running on adjacent cores. As DMAs are processed in serial bursts, if multiple simultaneous requests are received by the SDRAM controller, there may be latency in beginning the DMA for some cores, and a reduced rate of transfer (see section S1.2 in Supplementary Material for further information).