突触连接 SpikingFlow.connection

本教程作者: fangwei123456

本节教程主要关注 SpikingFlow.connection,包括如何使用已有突触连接、如何定义新的突触连接。

脉冲电流转换器

SpikingFlow中,神经元的输出都是 torch.bool 类型的脉冲,而输入则为 torch.float 类型的电流。将脉冲转换为电流的转换器,功能上类似于突触连接,但又有所不同,因此被视为突触连接包的子模块,定义在 SpikingFlow.connection.transform 中。

最简单的将脉冲转换为电流的方式,自然是不做任何处理,直接转换。SpikingFlow.connection.transform.SpikeCurrent 正是这样做的:

def forward(self, in_spike):
    '''
    :param in_spike: 输入脉冲
    :return: 输出电流

    简单地将输入脉冲转换为0/1的浮点数,然后乘以amplitude
    '''
    return in_spike.float() * self.amplitude

其中 self.amplitude 是初始化时给定的放大系数。

更复杂的转换器,例如 SpikingFlow.connection.transform.ExpDecayCurrent,具有指数衰减的特性。若当前时刻到达一个脉冲,则电流变为 amplitude,否则电流按时间常数为 tau 进行指数衰减:

def forward(self, in_spike):
    '''
    :param in_spike: 输入脉冲
    :return: 输出电流
    '''
    in_spike_float = in_spike.float()
    i_decay = -self.i / self.tau
    self.i += i_decay * (1 - in_spike_float) + self.amplitude * in_spike_float
    return self.i

ExpDecayCurrent 可以看作是一个能够瞬间充满电的电容器,有脉冲作为输入时,则直接充满电;无输入时则自行放电。这种特性,使得ExpDecayCurrentSpikeCurrent 相比,具有了“记忆”,因而它需要额外定义一个重置状态的函数:

def reset(self):
    '''
    :return: None
    重置所有状态变量为初始值,对于ExpDecayCurrent而言,直接将电流设置为0即可
    '''
    self.i = 0

定义新的脉冲电流转换器

从之前的例子也可以看出,脉冲电流转换器的定义比较简单,接受 torch.bool 类型的脉冲作为输入,输出 torch.float 类型的电流。只需要继承 SpikingFlow.connection.transform.BaseTransformer,实现 __init__()forward() 函数,对于有记忆(状态)的转换器,则额外实现一个 reset() 函数。

突触连接

SpikingFlow里的突触连接,与传统ANN中的连接非常类似,都可以看作是一个简单的矩阵,而信息在突触上的传递,则可以看作是矩阵运算。

例如 SpikingFlow.connection.Linear,与PyTorch中的 nn.Linear 的行为基本相同:

def forward(self, x):
    '''
    :param x: 输入电流,shape=[batch_size, *, in_num]
    :return: 输出电流,shape=[batch_size, *, out_num]
    '''
    return torch.matmul(x, self.w.t())

定义新的突触连接

定义新的突触连接,与定义新的脉冲电流转换器非常类似,只需要继承 SpikingFlow.connection.BaseConnection,实现 __init__()forward() 函数。对于有记忆(状态)的突触,也需要额外实现 reset() 函数。