有一说一,使用VScode写c++是真的难受,以后估计再也不会用了,还是Visual studio好用,方便调试和修改错误,长记性了。我建了如下的一个网络
现在我们来看看代码首先时main函数如下
#include <iostream>
#include <vector>
#include <random>
#include "Neuron.h"
#include "Synapse.h"
#include "Params.h"
#include "Manager.h"
int main()
{
//设置网络 定义邻接表
std::vector<std::vector<int>> adjList = { {1,2},{} };
//实例化神经元
// 创建随机数生成器
std::random_device rd;
std::mt19937 gen(rd());
// 生成随机浮点数
std::uniform_real_distribution<double> realDist(-65.0, -50.0); // 生成范围为-65.0到-55.0的浮点数
// 实例化神经元
std::vector<Neuron> localNeuron;
double v_init = realDist(gen);
Neuron neuron1 = Neuron(v_init, 0);
neuron1.set_I_offset(1.0);
localNeuron.push_back(neuron1);
Neuron neuron2 = Neuron(-65.0, 1);
neuron2.set_I_offset(0.0);
localNeuron.push_back(neuron2);
Neuron neuron3 = Neuron(-65.0, 2);
neuron3.set_I_offset(0.0);
localNeuron.push_back(neuron3);
//实例化突触
int max_delay = 10;
int min_delay = 15;
std::vector<int> delays(2);
delays[0] = min_delay;
delays[1] = max_delay;
std::vector<std::vector<Synapse>> localSynapse(adjList.size());
for (int i = 0; i < adjList.size(); i++)
{
for (int j = 0; j < adjList[i].size(); j++)
{
localSynapse[i].push_back(Synapse(delays[j], 0.2, &localNeuron[adjList[i][j]]));
}
}
//初始化 环形缓冲区
Manager::kernel()->init_moduli(min_delay, max_delay);
//设置仿真的参数
double dt = 0.1; //时间戳
double sim_time = 300; //仿真时间
int slice = static_cast<int>(sim_time / min_delay);//总共要执行循环数
int timespan = min_delay / dt;
double current_time = 0;
std::vector<SpikeEvent> spike_event;
//开始仿真
for (int timestep = 0; timestep < slice; timestep++)
{
Manager::kernel()->Print();
//更新神经元
for (auto node = localNeuron.begin(); node != localNeuron.end(); node++)
{
(*node).update(0, 10, spike_event);
}
// 传递脉冲
for (int i = 0; i < spike_event.size(); i++)
{
int pre_gid = spike_event[i].source; // 前神经元脉冲的gid
for (int j = 0; j < localSynapse[i].size(); j++)
{
localSynapse[i][j].send(spike_event[i]);//找到对应的突触将脉冲发送给后神经元
}
}
spike_event.clear(); //清楚本回合的脉冲
Manager::kernel()->update_moduli(min_delay, max_delay);
}
Manager::kernel()->delete_manager();
}
我重新设计了神经元
#ifndef NEURON_H
#define NEURON_H
#include<iostream>
#include "Params.h"
#include "Ringbuffer.h"
class Neuron
{
private:
double v; //膜电压
double last_fired; //上次发放脉冲的的时间
int gid; //神经元全局id
double i_e; //累加电流
double dt; //时间精度
int ref_counter; //不应期计时
int RefractoryCounts; //不应期的相对时常
RingBuffer buffer;
struct NeuronParams
{
// LIF神经元的参数
float v_rest; // 静息电位
float v_reset; // 重置电位
float tau_m; // 膜时间常数
float refractory; //不应期时间
float c_m; //膜电容
float r_m; //膜电阻
float v_thresh; // 脉冲发放阈值
float i_offset; // 注入电流
float dt;
/// @brief 初始化参数
NeuronParams();
};
NeuronParams params;
/// @brief 神经元的初始化操作
/// @param v_init 初始电压
void init(double v_init, int gid_);
public:
/// @brief 有参构造函数
/// @param gid_ 神经元的全局id
Neuron(double v_init, int gid_);
~Neuron() = default;
/// @brief 神经元更新的主要函数
/// @param current_t 当前的时间
/// @param spike_evnet 用来收集脉冲时间的,主要是发射脉冲的神经元和发射的时间
void update(int from, int to, std::vector<SpikeEvent>& spike_evnet);
/// @brief 处理脉冲事件
/// @param se 脉冲事件
void handle(SpikeEvent se);
/// @brief 设置输入电流
/// @param i_offset_
void set_I_offset(double i_offset_);
double getVoltage();
};
Neuron::NeuronParams::NeuronParams()
:tau_m(10.0f),
refractory(2.0f),
v_rest(-45.0f),
v_thresh(-50.0f),
v_reset(-65.0f),
i_offset(0.95f),
c_m(0.250f),
r_m(40.0f),
dt(0.1)
{
}
Neuron::Neuron(double v_init, int gid_)
{
init(v_init, gid_);
}
void Neuron::init(double v_init, int gid_)
{
v = v_init;
i_e = params.i_offset;
last_fired = -params.refractory;
gid = gid_;
dt = params.dt;
buffer.resize(15);
RefractoryCounts = params.refractory / dt;
ref_counter = 0;
}
void Neuron::update(int from, int to, std::vector<SpikeEvent>& spike_evnet)
{
for (int lag = 0; lag < to; ++lag)
{
if (ref_counter == 0)
{
//神经元不在不应期
//v += dt * ((params.v_rest - v + i_e * params.r_m)/params.tau_m);
double v_inf = params.v_rest + i_e * params.r_m;
v = v_inf + (v - v_inf) * expf(-dt / params.tau_m);
}
else
{
ref_counter--;
}
//计算突触的电流
double i_syn = buffer.get_value(0);
i_e = i_syn + params.i_offset;
if (v > params.v_thresh)
{
SpikeEvent se;
se.source = gid;
se.stamp = lag;
spike_evnet.push_back(se);
printf("%d spike happenned in %d\n", gid, lag);
ref_counter = RefractoryCounts;
v = params.v_reset;
}
}
}
void Neuron::handle(SpikeEvent se)
{
buffer.add_value(se.index, se.weight);
}
void Neuron::set_I_offset(double i_offset_)
{
params.i_offset = i_offset_;
}
double Neuron::getVoltage()
{
return v;
}
#endif
运行结果如下
如今实现之前双缓冲机制了,但是缺乏相关工作的验证,我是这样计划的。我需要设计一个全局的时间类,以用来验证脉冲是否在指定的延迟传送到了后神经元。还有就是我对,整体的有些参数感觉不太好,比如最大和最小延迟啊,他其实需要在全局能够访问的。还有就是设计的这个单例模式是线程不安全的,因为暂时没有设计到多进程,所以暂时不需要更改。理一下思路就是需要做一个时间的类。要做的东西好多啊,但是一步一步来吧,加油。