神经元的实现细节问题

今天主要时实现三种神经元的c++代码,并且展示他的膜电位随着时间的变化而变化,如果时间充足我会记录一下电位,并且画出其膜电位随着时间的变化。

首先时父类Neuron神经元,考虑lif和izhikevich神经元共有的属性为膜电压和上次方法脉冲的时间,因此我将父类设计成如下

#ifndef NEURON_H
#define NEURON_H

class Neuron
{
protected:
    double v; //膜电压
    double last_fired;      //上次发放脉冲的的时间
    
    
public:
    Neuron() = default;
    ~Neuron() = default;

    virtual bool update(float dt, float current_t) = 0;

    double getVoltage() {
        return v;
    }

    void setVoltag(double membraneVoltage){
        v = membraneVoltage;
    }
};
#endif

而lif神经元较为简单,易于实现,代码如下所示

#ifndef LIFNEURON_H
#define LIFNEURON_H

#include "Neuron.h"
#include "NeuronParams.h"

class LIFNeuron : public Neuron
{
private:
    double i_e;             //输入电流

    NeuronParams* params;   //参数
public:

    LIFNeuron(NeuronParams *params_)
    {
        init(params_,-65.0);
    }

    void init(NeuronParams *params_,double v_init)
    {
        params = params_;
        v = v_init;
        i_e = 0;
        last_fired = -params->refractory;
    }

    bool update(float dt, float current_t)
    {
        bool fired = false;
        
        if(current_t >= params->refractory + last_fired) //判断是否在不应期
        {
			//累加电流
			i_e += params->i_offset;
			
            // 更新方程
            v += dt * ((params->v_rest - v + i_e * params->r_m)/params->tau_m);
            
            
			// 判断是否达到阈值
			if(v > params->v_thresh) {
				v = params->v_reset;
				last_fired = current_t;
				fired = true;
			}
		}
		// 注入电流设置为0
		i_e = 0;
		return fired;
    }

};

#endif

还有izhikevich神经元代码

#ifndef IZHIKEVICH_H
#define IZHIKEVICH_H

#include "Neuron.h"
#include "NeuronParams.h"

class Izhikevich : public Neuron
{
private:
    double a, b, c, d;       // 模型参数
    double u;
    double i_e;             //输入电流
    double last_fired;      //上次发放脉冲的的时间

    NeuronParams* params;
public:
    Izhikevich(NeuronParams *params_)
    {
        init(params_,-65.0,-30.0);
    }
    void init(NeuronParams *params_,double v_init,double u_init)
    {
        params = params_;
        v = v_init;
        u = u_init;
        i_e = 0;
        last_fired = -params->refractory;
    }

    bool update(float dt, float current_t)
    {
        bool fired = false;
        double v_old = v;
        double u_old = u;

        i_e += params->i_offset;
        v += dt * ( 0.04 * v_old * v_old + 5.0 * v_old + 140.0 - u_old + i_e );
        u += dt * params->a * ( params->b * v_old - u_old );

        if(v >= params->v_thresh)
        {
            v = params->c;
            v += params->d;
            last_fired = current_t;
			fired = true;
        }
        i_e = 0;
        return false;
    }

    ~Izhikevich() = default;
};


#endif

主函数验证代码:

#include<iostream>
#include <fstream>

#include "LIFNeuron.h"
#include "NeuronParams.h"
#include "Izhikevich.h"
int main(int argc, char const *argv[])
{

    std::string filename = "izh.txt"; // 文件名
    std::ofstream file(filename); // 创建文件流对象
    if (!file.is_open())
    {
        std::cout<<"打开文件失败!"<<std::endl;
        exit(-1);
    }
    NeuronParams *c_params = (NeuronParams *)malloc(sizeof(NeuronParams));
    
	c_params->tau_m = 10.0f;		 
	c_params->refractory = 2.0f;		 
	c_params->v_rest = -65.0f;		 
	c_params->v_thresh = -50.0f;		 
	c_params->v_reset = -65.0f;		
	c_params->i_offset = 2.0f;	
    c_params->c_m = 0.250f;
    c_params->r_m = 40.0f;

    LIFNeuron lifNeuron(c_params);


    // for (int i = 0; i < 100; i++)
    // {
    //     lifNeuron.update(0.1,i*0.1);
        
    //     //file<<lifNeuron.getVoltage()<<std::endl;
    // }
    
    


    c_params->a = 0.02;
    c_params->b = 0.2;
    c_params->c = -65.0;
    c_params->d = 8.0;
    c_params->v_thresh = 30.0;

    Izhikevich izh(c_params);
    for (int i = 0; i < 100; i++)
    {
        izh.update(0.1,i*0.1);
        printf("%lf\n",izh.getVoltage());
        file<<izh.getVoltage()<<std::endl;
    }

    file.close(); // 关闭文件流
    return 0;
}

以上代码中的实现细节很简单,但是涉及的参数量众多,我暂时还有想好如何去管理这些参数量。全部写成一个数据结构如下:

#ifndef NEURONPARAMS_H
#define NEURONPARAMS_H

struct NeuronParams
{
    // LIF神经元的参数
    float v_rest;			// 静息电位
    float v_reset;			// 重置电位
    float tau_m;			// 膜时间常数
    float refractory;       //不应期时间
    float c_m;				//膜电容
    float r_m;              //膜电阻

    // Izhikevich参数
    double a;
    double b;
    double c;
    double d;

    //lif神经元和突触公共有的参数
    float v_thresh;		   // 脉冲发放阈值
    float i_offset;	    // 注入电流

};


#endif

无论是lif和izh都采用了欧拉法,很简单且易于实现。如果感兴趣,我可以把龙格库卡的四阶求微分的代码给出来。但是我的主要任务是分布式的实现,因此,暂时不给出。

神经元只是模拟很简单的一部分,接下来我会思考如何使用突触来连接这些神经元,并且能够实现脉冲的交互,这可能要花几天时间,突触也同样有很多的类型,比如静态突触,STDP等,我计划先实现静态突触,然后再去实现更有难度的突触,目前计划和神经元一样,给突触做一个父类,其他突触类型都继承于它。

明天计划做一个简单的静态突触,并且实现两个神经元之间的脉冲交互。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值