Brian2_脉冲神经网络_神经元学习记录

2023-10-11 14:40

本文主要是介绍Brian2_脉冲神经网络_神经元学习记录,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

脉冲神经网络被称作是第三代神经网络,生物可信度更高,在近年来兴起的类脑科学研究中,SNN也一直占据着核心地位。并且在性能相近的情况下,基于脉冲神经网络制成的芯片相较于人工神经网络功耗更低,稳定性、鲁棒性等也更为优异。
通过pip方式安装了Brian2,并运行了一些官网上提供的程序,也附了一些自己的学习心得。

from brian2 import *
start_scope()
#start_scope()函数确保在调用该函数之前创建的任何 
#Brian对象都不会包含在下一次模拟运行中。
tau = 10*ms
eqs ='dv/dt = (1-v)/tau : 1'
G = NeuronGroup(1, eqs,method='exact')
print('Before v = %s' % G.v[0])
run(100*ms)
print('After v = %s' % G.v[0])
start_scope()
G = NeuronGroup(1, eqs, method='exact')
M = StateMonitor(G, 'v', record=0)
run(30*ms)
plot(M.t/ms, M.v[0], 'C0', label='Brian')
plot(M.t/ms, 1-exp(-M.t/tau), 'C1--',label='Analytic')
xlabel('Time (ms)')
ylabel('v')
legend()
show()

请添加图片描述

程序中要注意量纲,如将不同单位的量进行相加、等式左右量纲不一致程序都会报错。如在eqs ='dv/dt = (1-v)/tau : 1'中去掉/tau就会出现量纲不一致而报错。

该程序中,创建神经元组函数NeuronGroup()创建了一个以微分方程dv/dt = (1-v)/tau : 1定义好模型的神经元,我们使用了 StateMonitor函数来监测神经元状态。前两个参数是要记录的组和要记录的变量。我们还指定record=0. 这意味着我们记录神经元 0 的所有值。我们必须指定我们想要记录哪些神经元,因为在具有许多神经元的大型模拟中,它通常会占用太多 RAM 来记录所有神经元的值。

蓝色实线即为该神经元v的变化,橙色虚线为微分方程dv/dt = (1-v)/tau : 1的解析解1-exp(-t/tau)的函数曲线,二者是重合的。

start_scope()
tau = 10*ms
eqs = '''
dv/dt = (1-v)/tau : 1
'''
G = NeuronGroup(1, eqs, threshold='v>0.8', reset='v = 0', method='exact')
M = StateMonitor(G, 'v', record=0)
run(50*ms)
plot(M.t/ms, M.v[0])
xlabel('Time (ms)')
ylabel('v')
show()

请添加图片描述

我们在NeuronGroup声明中添加了两个新关键字: threshold='v>0.8'reset='v = 0'。这意味着当我们发射尖峰时,并在尖峰后立即重置。

from brian2 import *
start_scope()
tau = 10*ms
eqs ='dv/dt = (1-v)/tau : 1'
G = NeuronGroup(1, eqs, threshold='v>0.8', reset='v = 0', method='exact')
statemon = StateMonitor(G, 'v', record=0)
spikemon = SpikeMonitor(G)
run(50*ms)
print('Spike times: %s' % spikemon.t[:])
plot(statemon.t/ms, statemon.v[0])
for t in spikemon.t:axvline(t/ms, ls='--', c='C1', lw=3)
xlabel('Time (ms)')
ylabel('v')
show()

请添加图片描述

脉冲时间:Spike times: [16. 32.1 48.2] ms

神经元模型的一个共同特征是不应期。这意味着在神经元发射一个尖峰之后,它会在一段时间内变得顽固,并且在这段时间结束之前不能再发射另一个尖峰。以下是我们在 Brian 中的做法。

from brian2 import *
start_scope()
tau = 10*ms
eqs ='dv/dt = (1-v)/tau : 1'
start_scope()
tau = 10*ms
eqs = '''
dv/dt = (1-v)/tau : 1 (unless refractory)
'''
G = NeuronGroup(1, eqs, threshold='v>0.8', reset='v = 0', refractory=5*ms, method='exact')
statemon = StateMonitor(G, 'v', record=0)
spikemon = SpikeMonitor(G)
run(50*ms)
plot(statemon.t/ms, statemon.v[0])
for t in spikemon.t:axvline(t/ms, ls='--', c='C1', lw=3)
xlabel('Time (ms)')
ylabel('v')
show()

请添加图片描述

虽然我们在NeuronGroup函数中添加了参数refractory=5*ms,但是在微分方程中还是要添加(unless refractory),否则神经元的行为不会产生不应期。

from brian2 import *
start_scope()
tau = 5*ms
eqs = '''
dv/dt = (1-v)/tau : 1
'''
G = NeuronGroup(1, eqs, threshold='v>0.8', reset='v = 0', refractory=15*ms, method='exact')
statemon = StateMonitor(G, 'v', record=0)
spikemon = SpikeMonitor(G)
run(50*ms)
plot(statemon.t/ms, statemon.v[0])
for t in spikemon.t:axvline(t/ms, ls='--', c='C1', lw=3)
axhline(0.8, ls=':', c='C2', lw=3)
xlabel('Time (ms)')
ylabel('v')
print("Spike times: %s" % spikemon.t[:])
show()

请添加图片描述

那么这里发生了什么?第一个尖峰的行为是相同的: v上升到 0.8,然后神经元在0到8 毫秒的时间内触发尖峰,然后立即重置为 0。由于不应期现在是 15 毫秒,这意味着神经元将无法尖峰再次直到时间 8 + 15 = 23 毫秒。在第一个尖峰之后,v的值立即开始上升,因为我们没有在NeuronGroup的定义中指定(unless refractory),此时虽然它可以在大约 8 毫秒的时间达到值 0.8(绿色虚线),但因为神经元现在正处于不应期,故到达阈值后不会重置反而继续上升,直到不应期结束电位才会被复位。

下面演示多个神经元。

from brian2 import *
start_scope()
N = 100
tau = 10*ms
eqs = '''
dv/dt = (2-v)/tau : 1
'''
G = NeuronGroup(N, eqs, threshold='v>1', reset='v=0', method='exact')
G.v = 'rand()'
spikemon = SpikeMonitor(G)
run(50*ms)
plot(spikemon.t/ms, spikemon.i, '.k')
xlabel('Time (ms)')
ylabel('Neuron index')
show()

请添加图片描述

变量N 来确定神经元的数量,G.v = 'rand()'是用 0 到 1 之间不同的随机值初始化每个神经元,这样做只是为了让每个神经元做一些不同的事情。spikemon.t表示神经元尖峰时间,spikemon.i为每个尖峰提供相应的神经元索引值。这是神经科学中使用的标准“光栅图”。

from brian2 import *
start_scope()
N = 100
tau = 10*ms
v0_max = 3.
duration = 1000*ms
eqs = '''
dv/dt = (v0-v)/tau : 1 (unless refractory)
v0 : 1
'''
G = NeuronGroup(N, eqs, threshold='v>1', reset='v=0', refractory=5*ms, method='exact')
M = SpikeMonitor(G)
G.v0 = 'i*v0_max/(N-1)'
run(duration)
figure(figsize=(12,4))
subplot(121)
plot(M.t/ms, M.i, '.k')
xlabel('Time (ms)')
ylabel('Neuron index')
subplot(122)
plot(G.v0, M.count/duration)
xlabel('v0')
ylabel('Firing rate (sp/s)')
show()

请添加图片描述

在这个例子中,我们将神经元以v0 指数方式驱动到该值,但是当v>1时,它会触发一个尖峰并重置。结果是它发射尖峰的速率将与v0的值相关。因为v0<1它永远不会发射尖峰,而且随着v0变大它会以更高的速率发射尖峰。右图显示了v0的函数的点火率 。这是这个神经元模型的 If 曲线。

请注意,在图中我们使用了SpikeMonitor中的变量count: 这是组中每个神经元被激发的尖峰数量的数组。将其除以运行的持续时间得出点火率。

from brian2 import *
start_scope()
N = 100
tau = 10*ms
v0_max = 3.
duration = 1000*ms
sigma = 0.2
eqs = '''
dv/dt = (v0-v)/tau+sigma*xi*tau**-0.5 : 1 (unless refractory)
v0 : 1
'''
G = NeuronGroup(N, eqs, threshold='v>1', reset='v=0', refractory=5*ms, method='euler')
M = SpikeMonitor(G)
G.v0 = 'i*v0_max/(N-1)'
run(duration)
figure(figsize=(12,4))
subplot(121)
plot(M.t/ms, M.i, '.k')
xlabel('Time (ms)')
ylabel('Neuron index')
subplot(122)
plot(G.v0, M.count/duration)
xlabel('v0')
ylabel('Firing rate (sp/s)')
show()

Often when making models of neurons, we include a random element to model the effect of various forms of neural noise. In Brian, we can do this by using the symbol xi in differential equations. Strictly speaking, this symbol is a “stochastic differential(随机微分)” but you can sort of thinking of it as just a Gaussian random variable with mean 0 and standard deviation 1. We do have to take into account the way stochastic differentials scale with time, which is why we multiply it by tau**-0.5 in the equations below (see a textbook on stochastic differential equations for more details). Note that we also changed the method keyword argument to use 'euler' (which stands for the Euler-Maruyama method); the 'exact' method that we used earlier is not applicable to stochastic differential equations(随机微分方程).

这一段程序我没有看懂,故把原文也附了上来,看些文献后研究,相比于上一块代码,神经网络中增加了一些噪音,使得点火率以S形方式上升,以下为运行结果。

请添加图片描述

这篇关于Brian2_脉冲神经网络_神经元学习记录的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/188767

相关文章

在Spring Boot中集成RabbitMQ的实战记录

《在SpringBoot中集成RabbitMQ的实战记录》本文介绍SpringBoot集成RabbitMQ的步骤,涵盖配置连接、消息发送与接收,并对比两种定义Exchange与队列的方式:手动声明(... 目录前言准备工作1. 安装 RabbitMQ2. 消息发送者(Producer)配置1. 创建 Spr

k8s上运行的mysql、mariadb数据库的备份记录(支持x86和arm两种架构)

《k8s上运行的mysql、mariadb数据库的备份记录(支持x86和arm两种架构)》本文记录在K8s上运行的MySQL/MariaDB备份方案,通过工具容器执行mysqldump,结合定时任务实... 目录前言一、获取需要备份的数据库的信息二、备份步骤1.准备工作(X86)1.准备工作(arm)2.手

SpringBoot3应用中集成和使用Spring Retry的实践记录

《SpringBoot3应用中集成和使用SpringRetry的实践记录》SpringRetry为SpringBoot3提供重试机制,支持注解和编程式两种方式,可配置重试策略与监听器,适用于临时性故... 目录1. 简介2. 环境准备3. 使用方式3.1 注解方式 基础使用自定义重试策略失败恢复机制注意事项

Python UV安装、升级、卸载详细步骤记录

《PythonUV安装、升级、卸载详细步骤记录》:本文主要介绍PythonUV安装、升级、卸载的详细步骤,uv是Astral推出的下一代Python包与项目管理器,主打单一可执行文件、极致性能... 目录安装检查升级设置自动补全卸载UV 命令总结 官方文档详见:https://docs.astral.sh/

统一返回JsonResult踩坑的记录

《统一返回JsonResult踩坑的记录》:本文主要介绍统一返回JsonResult踩坑的记录,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录统一返回jsonResult踩坑定义了一个统一返回类在使用时,JsonResult没有get/set方法时响应总结统一返回

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

java对接海康摄像头的完整步骤记录

《java对接海康摄像头的完整步骤记录》在Java中调用海康威视摄像头通常需要使用海康威视提供的SDK,下面这篇文章主要给大家介绍了关于java对接海康摄像头的完整步骤,文中通过代码介绍的非常详细,需... 目录一、开发环境准备二、实现Java调用设备接口(一)加载动态链接库(二)结构体、接口重定义1.类型

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

apache的commons-pool2原理与使用实践记录

《apache的commons-pool2原理与使用实践记录》ApacheCommonsPool2是一个高效的对象池化框架,通过复用昂贵资源(如数据库连接、线程、网络连接)优化系统性能,这篇文章主... 目录一、核心原理与组件二、使用步骤详解(以数据库连接池为例)三、高级配置与优化四、典型应用场景五、注意事

SpringBoot实现文件记录日志及日志文件自动归档和压缩

《SpringBoot实现文件记录日志及日志文件自动归档和压缩》Logback是Java日志框架,通过Logger收集日志并经Appender输出至控制台、文件等,SpringBoot配置logbac... 目录1、什么是Logback2、SpringBoot实现文件记录日志,日志文件自动归档和压缩2.1、