Brian2学习——经典STDP模型简介及代码实现

STDP是一种模拟神经元间突触权重变化的模型,基于神经元放电时间的相对差异。通过动态变量a_pre和a_post,可以更高效地模拟STDP过程,这在生理上更合理且计算效率更高。这种方法与原始STDP规则等价,并在Brian2库中得以实现。
该文章已生成可运行项目,

经典STDP模型

STDP(Spike-Timing-Dependent Plasticity,脉冲时间依赖可塑性)可认为是对Hebb学习规则的一种拓展。在实际的生物体中,神经细胞是一个复杂的动力学系统,具有静息、兴奋、发放脉冲,接收脉冲、膜电位累积、不应期等多种状态和行为。研究发现,两个神经元之间突触连接强度的变化与神经元发放脉冲的精确时间紧密相关。具体地,突触前和突触后神经元发放脉冲的相对时间差对神经元之间突触连接权值改变的方向和大小具有关键作用。

STDP被如下等式定义[1]:
Δw=∑tpre∑tpostW(tpost−tpre)W(Δt)={Apree−Δt/τpre,Δt>0AposteΔt/τpost,Δt<0 \Delta w = \sum_{t_{pre}}\sum_{t_{post}}W(t_{post} - t_{pre}) \\ W(\Delta t) = \begin{cases} A_{pre} e^{-\Delta t/\tau_{pre}},\quad \Delta t > 0\\ A_{post} e^{\Delta t/\tau_{post}}, \quad \Delta t < 0 \end{cases} Δw=tpretpostW(tposttpre)W(Δt)={ApreeΔt/τpre,Δt>0AposteΔt/τpost,Δt<0
用brian2实现:

from brian2 import *
import numpy as np
import matplotlib.pyplot as plt

# 参数见Competitive Hebbian learning through spike-timing-dependent synaptic plasticity论文
tau_pre = tau_post = 20*ms
A_pre = 0.01
A_post = -A_pre * 1.05
delta_t = np.linspace(-50, 50, 100)*ms
W = where(delta_t > 0, A_pre * exp(-delta_t / tau_pre), A_post * exp(delta_t / tau_post))

plot(delta_t/ms, W)
xlabel(r'$\Delta t$ (ms)')
ylabel('W')
axhline(0, ls='-', c='k')

plt.savefig(r'C:\Users\wzc\Documents\自学技术笔记\img\demo_stdp.png')
plt.show()

得到如下的结果:
在这里插入图片描述

然而,直接使用这个方程模拟它将是非常低效的,因为我们必须对所有的尖峰对求和。这在生理上也是不现实的,因为神经元无法记住之前的所有尖峰时间。事实证明,有一种更有效、生理上更合理的方法可以获得同样的效果。我们定义两个新变量apre、aposta_{pre}、a_{post}apreapost,分别是前突触活动和后突触活动的‘trace’,并有如下的微分方程:
τpredapredt=−apreτpostdapostdt=−apost \tau_{pre} \frac{da_{pre}}{dt} = -a_{pre} \\ \tau_{post} \frac{da_{post}}{dt} = -a_{post} τpredtdapre=apreτpostdtdapost=apost
当前突触神经元产生脉冲尖峰时,更新前突触trace和突触权重:
apre=apre+Aprew=w+apost a_{pre} = a_{pre} + A_{pre} \\ w = w + a_{post} apre=apre+Aprew=w+apost
类似地,当后突触神经元产生脉冲尖峰时:
apost=apost+Apostw=w+apre a_{post} = a_{post} + A_{post} \\w = w + a_{pre} apost=apost+Apostw=w+apre采用python中的Brian2公式格式实现如下,其中taupre和taupost是时间常数τpre、τpost\tau_{pre}、\tau_{post}τpreτpost,event-driven代表是脉冲事件驱动的,当有脉冲到来时,采用此STDP规则进行更新。

    'eqs_stdp': '''
       w : volt
       dapre/dt = -apre/taupre : volt (event-driven)
       dapost/dt = -apost/taupost : volt (event-driven)
       ''',
    'eqs_on_pre': '''
       v_post += w
       apre += Apre
       w = clip(w+nu_pre*apost, wmin, wmax)
       ''',
    'eqs_on_post': '''
       apost += Apost
       w = clip(w+nu_post*apre, wmin, wmax)
       '''

可以证明的,这种方式跟原始经典的STDP规则是完全一样的。

参考文献

[1] Song S, Miller K D, Abbott L F. Competitive Hebbian learning through spike-timing-dependent synaptic plasticity[J]. Nature neuroscience, 2000, 3(9): 919-926.

本文章已经生成可运行项目
### 使用Brian2实现SNN的STDP算法在MNIST数据集上的代码示例 以下是使用Brian2实现脉冲神经网络(SNN)中的STDP算法在MNIST数据集上的代码示例。此代码展示了如何构建一个简单的SNN模型,使用STDP学习规则,并在MNIST数据集上进行训练和测试。 ```python from brian2 import * import numpy as np import matplotlib.pyplot as plt from sklearn.datasets import fetch_openml from sklearn.preprocessing import MinMaxScaler # 加载MNIST数据集 mnist = fetch_openml('mnist_784', version=1) data = mnist.data.astype(float) / 255.0 # 归一化到[0,1] labels = mnist.target.astype(int) # 超参数设置 num_input = 784 # 输入神经元数量 num_output = 10 # 输出神经元数量 sim_time = 1 * second # 模拟时间 tau_m = 10 * ms # 膜电位时间常数 v_rest = -65 * mV # 静息电位 v_thresh = -50 * mV # 阈值电位 v_reset = -65 * mV # 复位电位 E_l = -65 * mV # 漏电流电位 g_L = 10 * nS # 漏电导 tau_pre = 20 * ms # STDP前突触时间常数 tau_post = 20 * ms # STDP后突触时间常数 A_pre = 0.01 # STDP前突触权重更新系数 A_post = -A_pre * tau_pre / tau_post * 1.05 # STDP后突触权重更新系数 w_max = 0.1 # 权重最大值 # 定义神经元模型 eqs_neurons = ''' dv/dt = (g_L*(E_l - v) + I_syn) / tau_m : volt (unless refractory) I_syn = g_syn * (E_syn - v) : amp dg_syn/dt = -g_syn / tau_syn : siemens ''' # 创建输入层神经元 input_layer = NeuronGroup(num_input, eqs_neurons, threshold='v > v_thresh', reset='v = v_reset', refractory=5 * ms, method='euler') input_layer.v = v_rest input_layer.g_syn = 0 # 创建输出层神经元 output_layer = NeuronGroup(num_output, eqs_neurons, threshold='v > v_thresh', reset='v = v_reset', refractory=5 * ms, method='euler') output_layer.v = v_rest output_layer.g_syn = 0 # 定义突触连接 synapses = Synapses(input_layer, output_layer, model='''w : 1 dApre/dt = -Apre / tau_pre : 1 (event-driven) dApost/dt = -Apost / tau_post : 1 (event-driven)''', on_pre=''' g_syn_post += w Apre += A_pre w = clip(w + Apost, 0, w_max) ''', on_post=''' Apost += A_post w = clip(w + Apre, 0, w_max) ''') synapses.connect() synapses.w = 'rand() * w_max' # 监控器 spike_monitor_input = SpikeMonitor(input_layer) spike_monitor_output = SpikeMonitor(output_layer) # 运行模拟 def run_simulation(image): input_layer.I_syn = TimedArray(image.reshape((num_input, 1)) * amp, dt=1*ms)(t) run(sim_time) return spike_monitor_output.count # 示例:选择一张MNIST图像并运行模拟 image_index = 0 image = data[image_index].reshape((num_input, 1)) label = labels[image_index] output_spike_counts = run_simulation(image) print(f"Input image label: {label}") print(f"Output neuron spike counts: {output_spike_counts}") plt.figure(figsize=(10, 5)) plt.subplot(1, 2, 1) plt.imshow(image.reshape((28, 28)), cmap='gray') plt.title("Input Image") plt.subplot(1, 2, 2) plt.bar(range(num_output), output_spike_counts) plt.title("Output Spike Counts") plt.show() ``` 上述代码实现了一个简单的SNN模型[^3],其中包含以下关键点: - 使用`NeuronGroup`定义了输入层和输出层神经元。 - 使用`Synapses`定义了突触连接,并实现STDP学习规则。 - 使用`TimedArray`将MNIST图像转换为输入电流。 - 监控器记录了神经元的发放情况,并绘制了结果。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值