突触模型#

作者: MamieZhu

突触是神经系统中的关键构成单位,是神经元之间的连接,负责在神经元之间传递信息,从而实现大脑的各种计算功能。突触分为静态突触和动态突触,静态突触通常指固定连接,而动态突触则可以根据活动和经验进行调整和改变。

本章将重点探讨突触的静态和动态性质,详细讨论突触模型的构建和行为特性,以便更好地理解神经元之间的信息传递过程。

突触模型介绍#

首先定义一个 neurai.nn.synapse.synapse.Synapse 基类,所有的突触都继承这个基类。如果是自定义突触,需要用户继承这个类进行突触模型的扩展。下面是参数说明。

Synapse 总共有7个参数,必须要传入的有 prepost,这两个参数分别表示前神经元簇和后神经元簇对象。注意的是,如果是 Generator,则必须作为前神经元簇对象传入。

其它参数如下:

  • conn 表示突触的连接规则,默认 All2All ,会根据连接规则创建相应的连接,具体的连接规则后面有详细介绍。

  • conn_repr 表示创建的连接数据结构,默认 ConnectRepr.COO ,可根据连接数量稀疏度选择数据结构表示,有利于提高后续突触算子的计算性能。

  • weight 表示连接权重,可以是单个浮点数值,一个大小与连接数量相对应的浮点数数组,或者是一个分布,比如具有给定均值和标准差的正态分布。

  • delay_step 表示延迟步长,可以是单个整数值,一个大小与连接数量相对应的整数数组,或者是一个分布,比如具有给定均值和标准差的正态分布。

  • receptor_type 表示受体类型,可以是单个整数值,一个大小与连接数量相对应的整数数组,或者是一个分布,比如具有给定均值和标准差的正态分布,默认为None。

具体地,在 ConnectRepr 中定义了三种数据结构供选择, COO, CSRMAT

  • COO 表示坐标数据格式,表示为(前神经元ID,后神经元ID),前神经元ID的数量与后神经元ID的数量一致,分别一对一对应神经元簇中的局部ID;

  • CSR 表示压缩稀疏行数据格式,表示为(后神经元ID,前神经元指针),可根据前神经元指针,确定和索引后神经元的ID;

  • MAT 表示矩阵数据格式,表示为前神经元数量*后神经元数量的数组,其中有连接的值为 True ,没有连接为 False

静态突触#

静态突触是指在突触传递过程中,突触的连接强度和传递效率在短时间内基本保持不变的突触类型,通常被用来模拟生物神经网络中的化学突触传递过程。 静态突触在神经网络模型中具有重要作用,它们可以用来描述神经元之间的稳定连接关系,从而实现网络的长期稳定性和记忆功能。 在模拟大脑功能或构建神经网络模型时,静态突触的特性使得模型能够更准确地反映生物神经系统的特点和行为。

在NeurAI中,静态突触用类 StaticSynapse 表示,用来实现前神经元的脉冲或者电流的信号处理,然后传递到后神经元上。 无论是两个生物神经元簇或者是生成器作为前神经元簇,都可以用 StaticSynapse 来建立连接。

StaticSynapse 继承 Synapse ,其参数与 Synapse 完全一致。

使用示例如下:

from neurai import nn
from neurai import initializer

weight_mean, weight_std = 100., 5.
delay_mean, delay_std = 20, 5

lif0 = nn.LIF(size=10)
lif1 = nn.LIF(size=20)
dc = nn.DCGenerator(size=10, amplitude=100, start=0.5, stop=1.5)
synapse0 = nn.StaticSynapse(pre=dc, post=lif0, conn=nn.One2One())
synapse1 = nn.StaticSynapse(pre=lif0, post=lif1, conn=nn.FixedIndegree(degree=0.2, multi_conn=False), conn_repr=nn.ConnectRepr.CSR, weight=100., delay_step=2)
synapse2 = nn.StaticSynapse(pre=lif1, post=lif0, conn=nn.FixedProb(prob=0.2), weight=initializer.NormalIniter(weight_mean, weight_std), delay_step=initializer.NormalIniter(delay_mean, delay_std))

在使用 Generator 作为前神经元簇进行突触连接时,推荐使用 neurai.nn.conn.connrule.One2One 或者 neurai.nn.conn.connrule.All2All 的连接方式。 使用 One2One 的连接方式时,要求 Generator 的神经元数量和与之相连的后神经元簇的神经元数量一致;使用 All2All 连接方式时, Generatorsize 为1。

动态突触#

动态突触是指具有可塑性的突触,其连接强度和传递延迟可以根据神经元之间的活动模式而变化。其中,STDP(Spike-Timing-Dependent Plasticity,时序相关塑性)是动态突触中的一种常见形式。 STDP规则规定了神经元之间突触连接权重如何根据其产生的脉冲的时间差异而改变。具体而言,如果一个神经元在另一个神经元激活之前释放脉冲,则该连接的权重可能增强;相反,如果一个神经元在另一个神经元激活之后释放脉冲,则该连接的权重可能减弱。 这种规则促使神经元之间的连接能够根据它们的活动模式进行调整,从而实现信息的动态调节和学习。 STDP通常被认为是大脑中长期记忆形成和学习的基础之一,因为它允许神经元之间的连接权重随着时间的推移而调整,以适应不断变化的输入模式和环境条件。

在NeurAI中,定义了三种不同的STDP突触, STDPNearest, STDPAll2AllSTDPTriplet。需要注意的是,如果使用STDP突触时,神经元需要有与树突相关的参数,比如 dendritic_delay, tau_triplet 等。

  • STDPAll2All

STDPAll2All 表示权重增强时,发生在突触后神经元发放脉冲到达树突的时刻,会和当前时刻突触前神经元已经发放的所有脉冲存在关联;权重抑制时,发生在突触前神经元发放脉冲的时刻,同样会和当前时刻突触后神经元已经发放的所有脉冲有关联。

STDPAll2All 除了继承 Synapse 基类的属性参数 ( pre, post, conn, conn_repr, weight, delay_stepreceptor_type)外,还有其自己的特有参数。

  • tau_plus,float类型,表示增强的STDP窗口的时间常数,默认值为20.0。

  • tau_minus,float类型,表示抑制的STDP窗口的时间常数,默认值为20.0。

  • lambda_p,float类型,表示步长,默认值为0.01。

  • alpha,float类型,表示不对称参数,默认值为1.00。

  • mu_plus,float类型,表示增强的权重依赖指数,默认值为1.0。

  • mu_minus,float类型,表示抑制的权重依赖指数,默认值为1.0。

  • Wmax,float类型,表示允许的最大权重值,权重将在范围 [0, Wmax] 内更新,默认值为100.0。

使用示例如下:

from neurai import nn
lif0 = nn.ExpLIF(size=1, tau_ref=1.0, dendritic_delay=1)
lif1 = nn.ExpLIF(size=1, tau_ref=1.0, dendritic_delay=1)
syn = nn.STDPAll2All(pre=lif0, post=lif1, conn=nn.One2One(), delay_step=2, weight=10)
  • STDPNearest

STDPNearest 表示此突触权重增强时,仅仅和当前时刻突触前神经元最近邻的脉冲时刻有关;权重抑制时,同样只和当前时刻突触后神经元最近邻的脉冲时刻有关。

STDPNearest 的参数与 STDPAll2All 一致。

使用示例如下:

from neurai import nn
lif0 = nn.ExpLIF(size=1, tau_ref=1.0, dendritic_delay=1)
lif1 = nn.ExpLIF(size=1, tau_ref=1.0, dendritic_delay=1)
syn = nn.STDPNearest(pre=lif0, post=lif1, delay_step=10, weight=0.5, tau_plus=16.8, alpha=0.85, Wmax=15.0)
  • STDPTriplet

STDPTriplet 表示权重增强时,发生在突触后神经元发放脉冲到达树突的时刻,不仅会和当前时刻突触前神经元已经发放的所有脉冲存在关联,而且会和突触后神经元已经发放的所有脉冲存在关联;权重抑制时,发生在突触前神经元发放脉冲的时刻,同样不仅会和当前时刻突触后神经元已经发放的所有脉冲有关联,而且会和突触前神经元已经发放的所有脉冲存在关联。

STDPTriplet 的除了继承 Synapse 基类的属性参数 (pre, post, conn, conn_repr, weight , delay_stepreceptor_type)外,还有其自己的特有参数。

  • tau_plus,float类型,表示增强的STDP窗口的时间常数,默认值为20.0;

  • tau_plus_triplet,float类型,表示增强的三重态STDP窗口时间常数,默认值为101.0;

  • tau_minus,float类型,表示抑制的STDP窗口时间常数,默认20.0;

  • aplus_,float类型,表示对增强规则的权重,默认5e-10;

  • aminus_,float类型,表示对压低规则的权重,默认7e-3;

  • aplus_triplet,float类型,表示三重态增强规则的权重,默认6.2e-3;

  • aminus_triplet,float类型,表示三重态抑郁规则的权重,默认2.3e-4;

  • Wmax,float类型,表示最大允许权重,权重会在[0,Wmax]范围内更新,默认100.0。

使用示例如下:

from neurai import nn
lif0 = nn.ExpLIF(size=1, tau_ref=1.0, tau_triplet=33.7, dendritic_delay=1)
lif1 = nn.ExpLIF(size=1, tau_ref=1.0, tau_triplet=33.7, dendritic_delay=1)
syn = nn.STDPTriplet(pre=lif0, post=lif1, conn=nn.One2One(), delay_step=2, weight=10)

突触连接规则#

突触连接方法是实现神经元簇之间以及神经元与生成器之间的连接的关键操作,是指以特定的模式或规则建立突触前后神经元簇之间的连接。这一操作通过突触创建过程中的 conn 参数完成。 在最简单的情况下, conn 可不传参数,使用默认连接规则,即实现全对全的连接方式。用户可以通过指定连接规则来定义所需的连接模式,具体的连接规则如下:

连接规则

介绍

One2One (一对一连接)

逐个连接两个神经元簇中的神经元

All2All (全对全连接)

将前一神经元簇中的每个神经元连接到后神经元簇中的所有神经元

FixedProb (固定概率连接)

以固定概率连接前神经元簇与后神经元簇的神经元

FixedTotalNum (固定数量连接)

以固定数量连接前神经元簇与后神经元簇的神经元

FixedIndegree (固定入度连接)

固定数量的前神经元簇神经元连接每个后神经元簇神经元

FixedOutdegree (固定出度连接)

每个前神经元簇神经元连接固定数量的后神经元簇神经元

CustomConn (用户自定义连接)

从用户自定义数据中连接前神经元簇与后神经元簇的神经元

1. One2One#

One2One 表示将两个神经元簇中的神经元一对一连接,这两个簇中必须包含相同数量的神经元。

使用示例如下:

from neurai import nn
lif0 = nn.LIF(size=10)
lif1 = nn.LIF(size=10)
syn = nn.StaticSynapse(pre=lif0, post=lif1, conn=nn.One2One())

2. All2All#

All2All 表示将前神经元簇的每个神经元连接到后神经元簇的所有神经元。 All2All 是默认规则,实际上可不指定。

使用示例如下:

from neurai import nn
lif0 = nn.LIF(size=10)
lif1 = nn.LIF(size=20)
syn = nn.StaticSynapse(pre=lif0, post=lif1, conn=nn.All2All())
syn = nn.StaticSynapse(pre=lif0, post=lif1)

3. FixedProb#

FixedProb 表示前后神经元簇之间以概率 p 创建神经元之间连接。对于 FixedProb,用户需要提供参数 prob 代表概率,其大小必须在0-1之间。 实际固定概率的连接遵循伯努利分布,因此给定的概率表示了在连接过程中每次尝试连接时,连接成功的概率。

使用示例如下:

from neurai import nn
lif0 = nn.LIF(size=10)
lif1 = nn.LIF(size=20)
syn = nn.StaticSynapse(pre=lif0, post=lif1, conn=nn.FixedProb(prob=0.5))

4. FixedTotalNum#

FixedTotalNum 表示以固定数量连接前神经元簇与后神经元簇的神经元。 在 FixedTotalNum 的情况下,用户需要提供参数 num,它表示了前后神经元簇之间的连接数量。 其他参数有默认值,比如 multi_conn=True,需要注意的是,在 conn_reprMAT 的情况下, multi_conn 必须设置为 False

使用示例如下:

from neurai import nn
from neurai.const import ConnectRepr

# example 1
lif0 = nn.LIF(size=10)
lif1 = nn.LIF(size=20)
syn = nn.StaticSynapse(pre=lif0, post=lif1, conn=nn.FixedTotalNum(num=100))

# example 2
lif0 = nn.LIF(size=10)
lif1 = nn.LIF(size=20)
syn = nn.StaticSynapse(pre=lif0, post=lif1, conn=nn.FixedTotalNum(num=100, multi_conn=False), conn_repr=ConnectRepr.MAT)

5. FixedIndegree#

FixedIndegree 表示为每个后神经元簇神经元连接固定数量的前神经元簇神经元。 在 FixedIndegree 的情况下,用户需要提供参数 degree,它表示了固定概率(如果 degree 是浮点数)或者固定数量的前神经元数量(如果 degree 是整数)。 其他参数有默认值,比如 multi_conn=True,需要注意的是,在 conn_reprMAT 的情况下, multi_conn 必须设置为 False

使用示例如下:

from neurai import nn
from neurai.const import ConnectRepr

# example 1
lif0 = nn.LIF(size=10)
lif1 = nn.LIF(size=20)
syn = nn.StaticSynapse(pre=lif0, post=lif1, conn=nn.FixedIndegree(degree=0.2))
syn = nn.StaticSynapse(pre=lif0, post=lif1, conn=nn.FixedIndegree(degree=2))   # equivalent

# example 2
lif0 = nn.LIF(size=10)
lif1 = nn.LIF(size=20)
syn = nn.StaticSynapse(pre=lif0, post=lif1, conn=nn.FixedIndegree(degree=0.2, multi_conn=False), conn_repr=ConnectRepr.MAT)

6. FixedOutdegree#

FixedOutdegree 表示每个前神经元簇神经元连接固定数量的后神经元簇神经元。 在 FixedOutdegree 的情况下,用户需要提供参数 degree,它表示了固定概率(如果 degree 是浮点数)或者固定数量的后神经元数量(如果 degree 是整数)。 其他参数有默认值,比如 multi_conn=True,需要注意的是,在 conn_reprMAT 的情况下, multi_conn 必须设置为 False

使用示例如下:

from neurai import nn
from neurai.const import ConnectRepr

# example 1
lif0 = nn.LIF(size=10)
lif1 = nn.LIF(size=20)
syn = nn.StaticSynapse(pre=lif0, post=lif1, conn=nn.FixedOutdegree(degree=0.2))
syn = nn.StaticSynapse(pre=lif0, post=lif1, conn=nn.FixedOutdegree(degree=4))   # equivalent

# example 2
lif0 = nn.LIF(size=10)
lif1 = nn.LIF(size=20)
syn = nn.StaticSynapse(pre=lif0, post=lif1, conn=nn.FixedOutdegree(degree=0.2, multi_conn=False), conn_repr=ConnectRepr.MAT)

7. CustomConn#

CustomConn 表示根据用户自定义数据连接前后神经元簇。 在 CustomConn 连接规则中,用户可以输入自定义连接数据,共有五种类型的数据可用作输入值。 pre_ids 表示前神经元簇神经元的索引到后一群体神经元的索引; post_ids 表示后神经元簇神经元的索引到前一群体神经元的索引; pre_indptr 表示索引数组中每行的起始索引指针数组; post_indptr 表示索引数组中每列的起始索引指针数组; mat 表示连接矩阵。

用户可以根据连接的数据结构表示有选择性地输入所需的参数值。 如果 conn_reprConnectRepr.COO,用户必须提供 pre_ids, post_idsmat; 如果 conn_reprConnectRepr.CSR,用户必须提供 post_ids, pre_indptrpre_ids, post_idsmat; 如果 conn_reprConnectRepr.MAT,用户必须提供 mat

下面这段代码示例展示了使用不同的输入参数和数据结构表示的 CustomConn 连接规则的用法,实际的连接性保持不变,只是数据表示不同。

使用示例如下:

import jax.numpy as jnp
from neurai import nn
from neurai.const import ConnectRepr

lif0 = nn.LIF(size=4)
lif1 = nn.LIF(size=4)

syn = nn.StaticSynapse(pre=lif0, post=lif1, conn=nn.CustomConn(pre_ids=[0, 1, 3, 1], post_ids=[2, 1, 0, 0]),conn_repr=ConnectRepr.COO)
syn = nn.StaticSynapse(pre=lif0, post=lif1, conn=nn.CustomConn(pre_ids=[0, 1, 3, 1], post_ids=[2, 1, 0, 0]),conn_repr=ConnectRepr.CSR)   # equivalent
syn = nn.StaticSynapse(pre=lif0, post=lif1, conn=nn.CustomConn(post_ids=[2, 1, 0, 0], pre_indptr=[0, 1, 3, 3, 4]),conn_repr=ConnectRepr.CSR)   # equivalent
syn = nn.StaticSynapse(pre=lif0, post=lif1, conn=nn.CustomConn(mat=jnp.asarray([[False,False,True,False],[True,True,False,False],[False,False,False,False],[True,False,False,False]])),conn_repr=ConnectRepr.COO)   # equivalent
syn = nn.StaticSynapse(pre=lif0, post=lif1, conn=nn.CustomConn(mat=jnp.asarray([[False,False,True,False],[True,True,False,False],[False,False,False,False],[True,False,False,False]])),conn_repr=ConnectRepr.CSR)   # equivalent
syn = nn.StaticSynapse(pre=lif0, post=lif1, conn=nn.CustomConn(mat=jnp.asarray([[False,False,True,False],[True,True,False,False],[False,False,False,False],[True,False,False,False]])),conn_repr=ConnectRepr.MAT)   # equivalent