【SRM神经元模型】利用代码解析SRM神经元

2 篇文章 0 订阅
1 篇文章 0 订阅

在解析代码之前,我们现在看一下SRM模型。
在这里插入图片描述
第一个函数表示一个spike应该具有的形状。其中tf是上一个发放脉冲的时间。
第二个函数中Iext描述的是所有突触前脉冲时间对膜电位产生的影响。
第三个函数应该很好理解,就是一个静息电位的电压。
早期的文章里SRM模型被描述成:
在这里插入图片描述
第二项就是前任神经元对本神经元对影响。
第三项比较特殊
一般的SNN模型里强行规定在本神经元射了之后的任何输入刺激均直接舍弃,但是这样的话显得太暴力了,不符合生物运行的规律,于是G大爷给这个贤者时间的消退也安排了函数。简单来说,在贤者时间中,收到的刺激会反应在膜电位上,但是对于膜电位的影响非常小,可能不及射前的百分之一。并且,贤者时间导致神经元的敏感度降低会指数降低,也就是说,神经元的敏感度会指数回升!
总的来说,第一项贴上了标准的发射过程 电位,第二项表示在射之前收到的所有刺激对电位的影响,第三项表示射之后(贤者时间)收到的所有刺激对电位的影响。

至于简化版SRM0神经元。
在这里插入图片描述
可以看出就是早期的SRM模型把最后一项,在不应期也会对刺激产生反应的部分去掉了。
形式是这样的。
其中,
在这里插入图片描述
eta函数图像。
在这里插入图片描述

在这里插入图片描述
eps函数图像:
在这里插入图片描述

上代码吧,代码看的更清楚一些。

import numpy as np
import functools


class SRM:
    """ SRM_0 (Spike Response Model) """
    #def __init__(self, neurons, threshold, t_current, t_membrane, eta_reset, simulation_window_size=100, verbose=False):
    def __init__(self, neurons, threshold=1, t_current=0.3, t_membrane=20, eta_reset=5, simulation_window_size=100, verbose=True):
        """
        Neurons can have different threshold, t_current, t_membrane and eta_resets: Set those variables to 1D np.arrays of all the same size.


        :param neurons: Number of neurons
        :param threshold: Spiking threshold
        :param t_current: Current-time-constant (:math:`t_s`)       #电流时间常数
        :type t_current: Float or Numpy Float Array
        :param t_membrane: Membrane-time-constant (t_m)     #细胞膜时间常数
        :param eta_reset: Reset constant
        :param simulation_window_size: Only look at the n last spikes       #滑动窗口
        :param verbose: Print verbose output to the console
        :return: ``None``
        """


        # Check user input
        try: neurons = int(neurons)
        except: raise ValueError("Variable neurons should be int or convertible to int")


        # threshold, t_current, t_membrane, and eta_reset are all vector
        threshold = np.array(threshold)
        t_current = np.array(t_current)
        t_membrane = np.array(t_membrane)
        eta_reset = np.array(eta_reset)


        if not(threshold.shape == t_current.shape == t_membrane.shape == eta_reset.shape):      #阈值 输入电流时序 细胞膜时序 重置时间常数+
            raise ValueError("Vector of threshhold, t_current, t_membrane, and eta_reset must be same size")


        try: simulation_window_size = int(simulation_window_size)
        except: raise ValueError("Variable simulation_window_size should be int or convertible to int")


        self.neurons = neurons
        self.threshold = threshold
        self.t_current = t_current
        self.t_membrane = t_membrane
        self.eta_reset = eta_reset
        self.simulation_window_size = simulation_window_size
        self.verbose = verbose
        self.cache = {}
        self.cache['last_t'] = -1   #上一个时序
        self.cache['last_spike'] = np.ones(self.neurons, dtype=float) * -1000000  #上一个脉冲
        self.cache['last_potential'] = np.zeros(self.neurons, dtype=float)  #上一时刻电势


    def eta(self, s):
        r"""
        Evaluate the Eta function:


        .. math:: \eta (s) = - \eta_{reset} * \exp(\frac{- s}{\tau_m})
            :label: eta


        :param s: Time s
        :return: Function eta(s) at time s
        :return type: Float or Vector of Floats
        """


        return - self.eta_reset*np.exp(-s/self.t_membrane)


    @functools.lru_cache()
    def eps(self, s):
        r"""
        Evaluate the Epsilon function:


        .. math:: \epsilon (s) =  \frac{1}{1 - \frac{\tau_c}{\tau_m}} (\exp(\frac{-s}{\tau_m}) - \exp(\frac{-s}{\tau_c}))
            :label: epsilon


        Returns a single Float Value if the time constants (current, membrane) are the same for each neuron.
        Returns a Float Vector with eps(s) for each neuron, if the time constants are different for each neuron.


        :param s: Time s
        :return: Function eps(s) at time s
        :rtype: Float or Vector of Floats
        """
        return (1/(1-self.t_current/self.t_membrane))*(np.exp(-s/self.t_membrane) - np.exp(-s/self.t_current))


    @functools.lru_cache()
    def eps_matrix(self, k, size):
        """


        Returns the epsilon helpermatrix.


        :Example:


        #>>> eps_matrix(3,5)


        [[eps_0(3), eps_0(2), eps_0(1), eps_0(0), eps_0(0)],
         [eps_1(3), eps_1(2), eps_1(1), eps_1(0), eps_1(0)]]


        Where `eps_0(3)` means the epsilon function of neuron 0 at time 3.


        :param k: Leftmost epsilon time
        :param size: Width of the return matrix
        :return: Epsilon helper matrix
        :return type: Numpy Float Array, dimensions: (neurons x size)
        """


        matrix = np.zeros((self.neurons, size), dtype=float)


        for i in range(k):
            matrix[:, i] = self.eps(k-i)


        return matrix


    def check_spikes(self, spiketrain, weights, t, additional_term=None):
        """
        Simulate one time step at time t. Changes the spiketrain in place at time t!
        Return the total membrane potential of all neurons.


        :param spiketrain: Spiketrain (Time indexing begins with 0)
        :param weights: Weights
        :param t: Evaluation time
        :param additional_term: Additional potential that gets added before we check for spikes (For example for extern voltage)
        :return: total membrane potential of all neurons at time step t (vector), spikes at time t
        """


        # Check correct user input


        if type(spiketrain) != np.ndarray:
            raise ValueError("Spiketrain should be a numpy array")


        if type(weights) != np.ndarray:
            raise ValueError("Weights should be a numpy matrix")


        if additional_term != None and type(additional_term) != np.ndarray:
            raise ValueError("Additional_term should be a numpy array")


        try: t = int(t)
        except: raise ValueError("Variable t should be int or convertible to int")


        if t < 0:
            raise ValueError("Time to be simulated is too small")


        if t >= spiketrain.shape[1]:         #spiketrain.shape[1] 'return no of column in each row '
            raise ValueError("Spiketrain too short (0ms -- %dms) for simulating time %d" % (spiketrain.shape[1]-1, t))


        if weights.shape[0] != self.neurons or self.neurons != weights.shape[1]:
            raise ValueError("Weigths should be a quadratic matrix, with one row and one column for each neuron")


        if spiketrain.shape[0] != self.neurons:
            raise ValueError("Spikes should be a matrix, with one row for each neuron")


        if additional_term != None and additional_term.shape[0] != self.neurons:
            raise ValueError("Additional_term should be a vector with one element for each neuron")


        if additional_term != None and len(additional_term) == 2 and additional_term.shape[1] != 1:
            raise ValueError("Additional_term should be a vector with one element for each neuron")


        # Work on a windowed view 工作区间
        spiketrain_window = spiketrain[:, max(0, t+1-self.simulation_window_size):t+1]


        # Retrieve necessary simulation data from cache if possible
        if self.cache['last_t'] == -1 or self.cache['last_t'] == t - 1:
            last_spike = self.cache['last_spike']
            last_potential = self.cache['last_potential']
        else:
            last_spike = t - np.argmax(spiketrain_window[:, ::-1], axis=1)
            # TODO find a way to calculate last_potential (recursive call to check_spikes is not a good option)
            last_potential = np.zeros(self.neurons)


        neurons, timesteps = spiketrain_window.shape


        epsilon_matrix = self.eps_matrix(min(self.simulation_window_size, t), timesteps)


        # Calculate current
        incoming_spikes = np.dot(weights.T, spiketrain_window)      #矩阵乘法
        incoming_potential = np.sum(incoming_spikes * epsilon_matrix, axis=1)
        total_potential = self.eta(np.ones(neurons)*t - last_spike) + incoming_potential
        # Calculate current end


        # Add additional term (user-defined)
        if additional_term != None:
            total_potential += additional_term


        # Any new spikes? Only spike if potential hits the threshold from below.
        neurons_high_current = np.where((total_potential > self.threshold) & (last_potential < self.threshold))
        spiketrain[neurons_high_current, t] = True


        # Update cache (last_spike, last_potential and last_t)
        spiking_neurons = np.where(spiketrain[:, t])
        self.cache['last_spike'][spiking_neurons] = t
        self.cache['last_potential'] = total_potential
        self.cache['last_t'] = t


        if self.verbose:
            print("SRM Time step", t)
            print("Incoming current", incoming_potential)
            print("Total potential", total_potential)
            print("Last spike", last_spike)
            print("")


        return total_potential


if __name__ == "__main__":


    srm_model = SRM(neurons=3, threshold=1, t_current=0.3, t_membrane=20, eta_reset=5, verbose=True)        #定义一个SRM神经元


    models = [srm_model]


    for model in models:
        print("-"*10)
        if isinstance(model, SRM):
            print('Demonstration of the SRM Model')


        s = np.array([[0, 0, 1, 0, 0, 0, 1, 1, 0, 0],
                      [1, 0, 0, 0, 0, 0, 1, 1, 0, 0],
                      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])


        #w = np.array([[0, 0, 3.8], [0, 0, 1.78], [0, 0, 0]])
        w = np.array([[0, 0, 1], [0, 0, 1], [0, 0, 0]]) #权重
        #w = np.random.random((3,3))
        neurons, timesteps = s.shape


        for t in range(timesteps):
            total_current = model.check_spikes(s, w, t)
            print("Spiketrain:\n", s)
  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值