精华内容
下载资源
问答
  • 官网指南的翻译版本,包括我翻译好的ipynb文件,源文件,pdf文件,markdown文件,整理好导出的Word文件。 源网址https://brian2.readthedocs.io/en/stable/resources/tutorials/1-intro-to-brian-neurons.html ...
  • snn脉冲神经网络.py

    2019-09-26 17:21:57
    snn脉冲神经网络,大家可以看看,转载(侵权联系必删)五十字
  • 今天给对脉冲神经网络(Spiking Neural Network, SNN)的同学介绍一个从相关领域论文中发现的关于模型和使用都相当成熟的一个工具,如果去年我刚开始还尝试使用matlab自己搭建SNN时能够看到相关资料,就会少走很多弯路...

    今天给对脉冲神经网络(Spiking Neural Network, SNN)的同学介绍一个从相关领域论文中发现的关于模型和使用都相当成熟的一个工具,如果去年我刚开始还尝试使用matlab自己搭建SNN时能够看到相关资料,就会少走很多弯路了。而且相较于nest,这个也不限制平台,只要有python环境即可,可以说是相当方便了。

    下面的内容基本都是brain官网以及相关项目网页信息的翻译,如果需要更进一步的了解直接点击相关链接即可,希望对脉冲神经网络研究相关的同学一点帮助。

    The Brian Simulator | The Brian spiking neural network simulator

    介绍

    Brian 是一个免费的开源模拟器,用于刺激神经网络。它以 Python 编程语言编写,几乎在所有平台上都有售。我们认为,模拟器不仅应该节省处理器的时间,而且应该节省科学家的时间。因此,Brian 的设计易于学习和使用,非常灵活且易于扩展。

    使用详细教程: Brian 2 Tutorials

    详细介绍文档:Brian 2 documentation

    github项目地址:brian-team/brian2

    优势

    易于使用

    Brian 具有强大且易于理解的语法,只需几行代码即可定义、运行和绘制神经模型。

    我们有简单的指南,让你开始安装和学习Python和brain,和详细的文件,以帮助您掌握一切barin所提供的。

    在这里插入图片描述

    灵活

    详细的生物物理霍奇金-赫克斯利模型?减少两个可变泄漏集成和火神经元?尚未添加到其他模拟器的新突触模型?

    没问题,只需在标准数学符号中写下方程并运行它。
    在这里插入图片描述

    性能

    1952年,霍奇金和赫克斯利模拟了他们的鱿鱼巨型轴心模型。他们花了三个星期使用手工操作的布伦斯维加机械计算器。幸运的是,你不必等那么久。brain可以实时模拟成千上万的神经元。

    Brian 使用运行时代码生成来表示最先进的性能,自动将方程转换为低级别的C++代码,在不需要任何用户输入的情况下编译和运行它们。
    在这里插入图片描述

    可靠

    Brian 已经十多岁了,所以你可以依靠它给出准确的结果。我们有一个广泛的测试套件,可以捕获任何错误,并确保它在所有平台上运行。我们继续研究brain,大约每六个月发布一个新版本。

    并且,我们帮助您确保您的代码没有错误。如果您尝试编写一个维度不一致的方程,我们会告诉你。如果您为差分方程指定的解算器不稳定,我们会通知您。
    在这里插入图片描述

    使用广泛

    Brian 已成功用于数百项建模研究,其中许多研究都使他们的代码可以免费在线下载。它用于流行的计算神经科学教科书神经元动力学(Gerstner等)中的编码练习。

    Brian 还拥有一个充满活力的软件包生态系统,这些软件包都建在它上面。
    在这里插入图片描述

    在线程序示例

    示例网址

    %matplotlib inline
    from brian2 import *
    from brian2tools import *
    import ipywidgets as ipw
    prefs.codegen.target = 'numpy'
    
    def model(N=20, R_max=150, f=10, w=0.1, p=0.5, tau=5, tau_t=50, delta_t=0.1):
        # Get parameters
        R_max = R_max*Hz
        f = f*Hz
        tau = tau*ms
        tau_t = tau_t*ms
        duration = 200*ms
        
        # Simulation code
        G = PoissonGroup(N, rates='R_max*0.5*(1+sin(2*pi*f*t))')
        eqs = '''
        dV/dt = -V/tau : 1
        dVt/dt = (1-Vt)/tau_t : 1
        '''
        H = NeuronGroup(1, eqs, threshold='V>Vt', reset='V=0; Vt += delta_t', method='linear')
        H.Vt = 1
        S = Synapses(G, H, on_pre='V += w')
        S.connect(p=p)
        # Run it
        MG = SpikeMonitor(G)
        MH = StateMonitor(H, ('V', 'Vt'), record=True)
        run(duration)
        
        # Plotting code
        figure(figsize=(15, 4))
        subplot(131)
        brian_plot(MG)
        title('Source neurons (Poisson)')
        subplot(132)
        plot(zeros(N), arange(N), 'ob')
        plot([0, 1], [S.i, ones(len(S.i))*N/2.], '-k')
        plot([1], [N/2.], 'og')
        xlim(-0.1, 1.1)
        ylim(-1, N)
        axis('off')
        title('Synapses')
        subplot(133)
        plot(MH.t, MH.V[0], label='V')
        plot(MH.t, MH.Vt[0], label='Vt')
        legend(loc='upper left')
        title('Target neuron')
        
    layout = ipw.Layout(width='100%')
    style = {'description_width': 'initial'}
    ipw.interact(model,
                 N=ipw.IntSlider(value=20, min=5, max=100, step=5, continuous_update=False,
                                 description="Number of source neurons", style=style, layout=layout),
                 R_max=ipw.FloatSlider(value=300, min=0, max=500, step=10, continuous_update=False,
                                       description=r"Source neuron max firing rate (Hz)", style=style, layout=layout),
                 f=ipw.FloatSlider(value=10, min=1, max=50, step=1, continuous_update=False,
                                   description=r"Source neuron frequency (Hz)", style=style, layout=layout),
                 p=ipw.FloatSlider(value=0.5, min=0, max=1, step=0.01, continuous_update=False,
                                   description=r"Synapse probability", style=style, layout=layout),
                 w=ipw.FloatSlider(value=0.3, min=0, max=1, step=0.01, continuous_update=False,
                                   description=r"Synapse weight", style=style, layout=layout),
                 tau=ipw.FloatSlider(value=5, min=1, max=50, step=1, continuous_update=False,
                                     description=r"Target neuron membrane time constant (ms)", style=style, layout=layout),
                 tau_t=ipw.FloatSlider(value=30, min=5, max=500, step=5, continuous_update=False,
                                       description=r"Target neuron adaptation constant (ms)", style=style, layout=layout),
                 delta_t=ipw.FloatSlider(value=1.0, min=0, max=20, step=0.1, continuous_update=False,
                                         description=r"Target neuron adaptation strength", style=style, layout=layout),
                );
    

    预期结果:
    在这里插入图片描述

    安装指南

    我们介绍了我们简单的六步计划,学习如何与 Brian 模拟尖刺神经网络。

    1. 学习计算神经科学

    如果您还不熟悉计算神经科学,我们建议您开始使用其中一些免费在线资源:

    2. 尝试barin在浏览器

    在开始之前,您可以在浏览器中尝试 Brian 的演示,而无需安装任何内容。请注意,此页面使用mybinder.org服务,可能需要一些时间来加载。

    3. 下载并学习 Python

    如果您以前没有使用过 Python,我们建议您使用蟒蛇派发

    和一些学习 Python 的选项:

    • Python 初学者是安装和学习 Python 的一般介绍。
    • 西皮讲座笔记是面向 Python 科学的介绍。它比一般介绍技术性稍高一些,但可能更相关,包括讨论有用的工具和环境。

    4. 下载并安装brain

    如果您已在上面安装了 Anaconda 分布,则安装 Brian 非常简单:

     conda install -c conda-forge brian2
    

    在其他 Python 分布中,您可以尝试:

     pip install brian2
    

    有关详细信息,请参阅我们的详细安装文档

    最后,查看各种运行 Brian 脚本的方式,包括交互式记事本、集成开发环境和命令行。

    5. 按照教程

    我们的教程专为学习brain的基本知识而设计。最简单的使用方法是单击按钮并在浏览器中交互式运行它们。

    6. 后续步骤

    一旦你了解了基本知识,下面是一些如何掌握brain更高级的功能的想法:

    • 查看一些可以使用的功能想法示例
    • 通读我们关于brain的一些文章。
    • 看看一些已发布的代码(这里这里)。请注意,其中一些示例是针对较旧版本的 Brian。
    • 阅读用户指南。Brian 的每一个功能都被覆盖,但尝试从头到尾阅读可能有点让人难以承受。
    • 一旦你掌握了这一切,尝试阅读高级指南

    项目例程

    Examples

    advanced

    compartmental

    frompapers

    frompapers/Brette_2012

    frompapers/Stimberg_et_al_2018

    standalone

    synapses

    部分被引文献

    ** Models**
    1.A full-scale cortical microcircuit spiking network model (Shimoura et al 2018)
    2.A model of neuronal bursting using three coupled first order diff. eqs. (Hindmarsh & Rose 1984)
    3.CN bushy, stellate neurons (Rothman, Manis 2003) (Brian 2)
    4.Excitation Properties of Computational Models of Unmyelinated Peripheral Axons (Pelot et al., 2020)
    5.Inhibitory microcircuits for top-down plasticity of sensory representations (Wilmes & Clopath 2019)
    6.Low Threshold Calcium Currents in TC cells (Destexhe et al 1998) (Brian)
    7.Mesoscopic dynamics from AdEx recurrent networks (Zerlaut et al JCNS 2018)
    8.Model of the hippocampus over the sleep-wake cycle using Hodgkin-Huxley neurons (Aussel et al 2018)
    9.Modeling dendritic spikes and plasticity (Bono and Clopath 2017)
    10.Modelling the effects of short and random proto-neural elongations (de Wiljes et al 2017)
    11.Neuromuscular network model of gut motility (Barth et al 2017)
    12.PLS-framework (Tikidji-Hamburyan and Colonnese 2021)
    13.PyRhO: A multiscale optogenetics simulation platform (Evans et al 2016)
    14.Response to correlated synaptic input for HH/IF point neuron vs with dendrite (Górski et al 2018)
    15.Robust modulation of integrate-and-fire models (Van Pottelbergh et al 2018)
    16.Sharpness of spike initiation in neurons explained by compartmentalization (Brette 2013)
    17.Vibration-sensitive Honeybee interneurons (Ai et al 2017)

    关于引用

    Stimberg M, Brette R, Goodman DFM (2019) Brian 2, an intuitive and efficient neural simulator eLife 8:e47314. doi: 10.7554/eLife.47314

    BibTeX (click to expand)
    @article{Stimberg2019,
        title = {Brian 2, an intuitive and efficient neural simulator},
        volume = {8},
        issn = {2050-084X},
        doi = {10.7554/eLife.47314},
        journal = {eLife},
        author = {Stimberg, Marcel and Brette, Romain and Goodman, Dan FM},
        editor = {Skinner, Frances K},
        month = aug,
        year = {2019},
        pages = {e47314}
    }
    

    总结

    另外要注意的是,如果是python2版本的话,就会需要安装barin而不是brain2了

    最新版本所使用的brain2.4的相关特性及资料可以参照官网或者下面这篇文献:

    [1] Stimberg Marcel, Brette Romain, Goodman Dan F. M. Brian 2, an intuitive and efficient neural simulator [J]. eLife, 2019, 8(e47314.

    以上就是所有内容了,欢迎友善讨论,共同进步。

    展开全文
  • SNN 脉冲神经网络

    2020-05-20 17:08:21
    关于SNN的简介,可以参考机器之心写的——简述脉冲神经网络SNN:下一代神经网络(原文链接https://blog.csdn.net/Uwr44UOuQcNsUQb60zk2/article/details/79060595) Brian1的手册网址: brian.readthedocs.io/en/...

    关于SNN的简介,可以参考:

    机器之心写的——简述脉冲神经网络SNN:下一代神经网络(原文链接https://blog.csdn.net/Uwr44UOuQcNsUQb60zk2/article/details/79060595

    脉冲神经网络(Spiking Neural Network,SNN)概述

    https://blog.csdn.net/h__ang/article/details/90513919

    系列文章:SNN系列|编码篇(1)频率编码

    https://blog.csdn.net/ly18846826264/article/details/105420944/

    感谢作者的分享与整理。


    Brian1的手册网址:
    brian.readthedocs.io/en/latest/installation.html
    Brian2的手册网址:
    brian2.readthedocs.io/en/2.0b4/resources/tutorials/1-intro-to-brian-neurons.html
    将CNN转换成SNN(2017年)
    https://www.frontiersin.org/articles/10.3389/fnins.2017.00682/abstract
    利用基于STDP的SNN的无监督手写字符识别(2015年)
    https://github.com/peter-u-diehl/stdp-mnist
    利用基于STDP的SNN的无监督手写字符识别(2017年)
    https://github.com/djsaunde/stdp-mnist
    基于GPU加速的库设计(自2015年持续更新中)
    https://github.com/UCI-CARL/CARLsim4
    https://github.com/UCI-CARL/CARLsim3
    用3D卷积SNN来分类视频,神经元模型是用的LIF模型(2015年)
    https://github.com/MarcoSaku/Spiking-C3D
    基于SNN的音符识别(2015-2016年)
    https://github.com/mrahtz/musical-pattern-recognition-in-spiking-neural-networks
    模拟器auryn(自2016年持续更新中)
    https://github.com/fzenke/auryn
    基于SNN的强化学习(2015年)
    https://github.com/tartavull/snn-rl
    基于SNN的模式识别(2016年)
    https://github.com/Shikhargupta/Spiking-Neural-Network
    基于速率的神经网络转换到SNN的工具(2017年)
    https://github.com/NeuromorphicProcessorProject/snn_toolbox
    SNN模拟器和通用尖峰神经脉冲模拟器(2012年)
    https://github.com/paulking/ei_net
    基于GPU的模拟器(2015年)
    https://github.com/brainstudio-team/NeMo


    声明:
    原文链接:https://blog.csdn.net/xiaoqu001/article/details/78713527

    展开全文
  • `timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: // // Create Date: 2020/07/13 05:46:04 // Design Name: ...

    `timescale 1ns / 1ps
    //
    // Company: 
    // Engineer: 
    // 
    // Create Date: 2020/07/13 05:46:04
    // Design Name: 
    // Module Name: LIF_Vt
    // Project Name: 
    // Target Devices: 
    // Tool Versions: 
    // Description: 
    // 
    // Dependencies: 
    // 
    // Revision:
    // Revision 0.01 - File Created
    // Additional Comments:
    // 
    //


    module LIF_Vt(
                 input i_clk,
                 input i_rst,
                 input signed[15:0]i_Vtn,
                 input signed[15:0]i_deltat,
                 input signed[15:0]i_tao,
                 input signed[15:0]i_stn1,i_stn2,i_stn3,
                 input signed[15:0]i_W1j,i_W2j,i_W3j,
                 output signed[15:0]o_Vtn1,
                 //test
                 output signed[15:0]o_exp,
                 output signed[15:0]o_dat1,
                 output signed[15:0]o_dat2,
                 

    展开全文
  • 基于脉冲神经网络的语音识别,大规模脉冲神经网络建模
  • 看网上也没有相关的内容,主要做了一些翻译和汉化的工作,时间也比较仓促,如果之后有时间的话再校正,如果不太通顺的地方敬请谅解,大体意思就是那样,有些专业名词可能我不是搞脑神经的,也不知道如何翻译合适,...

    前言

    最近一直在看相关的内容,在官网的链接 :
    Introduction to Brian part 1: Neurons
    Introduction to Brian part 2: Synapses
    Introduction to Brian part 3: Simulations
    看网上也没有相关的内容,主要做了一些翻译和汉化的工作,时间也比较仓促,如果之后有时间的话再校正,如果不太通顺的地方敬请谅解,大体意思就是那样,有些专业名词可能我不是搞脑神经的,也不知道如何翻译合适,下面是具体内容。

    第1部分介绍:神经元

    所有 Brian 脚本都从以下开头。如果正在Jupyter笔记本中试用此笔记本,则应从运行此单元格开始。

    from brian2 import *
    

    稍后,我们将在Jupyter笔记本中进行一些绘图,通过执行此操作激活笔记本中的内联绘图:

    %matplotlib inline
    

    如果您没有使用 Jupyter 笔记本来运行此示例(例如,您使用的是标准 Python 终端,或者您将这些示例复制并粘贴到编辑器中并作为脚本运行),则不会自动显示绘图。在这种情况下,在绘图命令之后明确调用命令show()

    单位系统

    Brian 有一个用于使用物理尺寸数量的系统:

    20*volt
    

    20.0   V 20.0\,\mathrm{V} 20.0V

    所有基本的 SI 单元都可以使用(伏特、放大器等)以及所有标准前缀(m=milli、pé pico 等),以及一些特殊缩写,如、等。mV 毫伏特, pF皮法等。

    1000*amp
    

    1.0   k   A 1.0\,\mathrm{k}\,\mathrm{A} 1.0kA

    1e6*volt
    

    1.0   M   V 1.0\,\mathrm{M}\,\mathrm{V} 1.0MV

    1000*namp
    

    1.0000000000000002   μ   A 1.0000000000000002\,\mathrm{\mu}\,\mathrm{A} 1.0000000000000002μA

    另请注意,单位与的组合:

    10*nA*5*Mohm
    

    49.99999999999999   m   V 49.99999999999999\,\mathrm{m}\,\mathrm{V} 49.99999999999999mV

    如果你试图相加电流和电压, 则会报错:

    5*amp+10*volt
    
    ---------------------------------------------------------------------------
    
    DimensionMismatchError                    Traceback (most recent call last)
    
    <ipython-input-8-245c0c0332d1> in <module>
    ----> 1 5*amp+10*volt
    
    
    ~/programming/brian2/brian2/units/fundamentalunits.py in __add__(self, other)
       1429 
       1430     def __add__(self, other):
    -> 1431         return self._binary_operation(other, operator.add,
       1432                                       fail_for_mismatch=True,
       1433                                       operator_str='+')
    
    
    ~/programming/brian2/brian2/units/fundamentalunits.py in _binary_operation(self, other, operation, dim_operation, fail_for_mismatch, operator_str, inplace)
       1369                 message = ('Cannot calculate {value1} %s {value2}, units do not '
       1370                            'match') % operator_str
    -> 1371                 _, other_dim = fail_for_dimension_mismatch(self, other, message,
       1372                                                            value1=self,
       1373                                                            value2=other)
    
    
    ~/programming/brian2/brian2/units/fundamentalunits.py in fail_for_dimension_mismatch(obj1, obj2, error_message, **error_quantities)
        184             raise DimensionMismatchError(error_message, dim1)
        185         else:
    --> 186             raise DimensionMismatchError(error_message, dim1, dim2)
        187     else:
        188         return dim1, dim2
    
    
    DimensionMismatchError: Cannot calculate 5. A + 10. V, units do not match (units are A and V).
    

    应该从底部开始,向上工作。最后一行给出错误类型以及更具体的消息DimensionMismatchError (在这种情况下,您尝试将两个数量与不同的 SI 单位加起来,这是不可能的)。

    简单的模型

    让我们从定义一个简单的神经元模型开始。在 Brian 中,所有模型都由微分方程系统定义。下面是一个简单的例子,它看起来像什么:

    tau = 10*ms
    eqs = '''
    dv/dt = (1-v)/tau : 1
    '''
    

    在 Python 中,符号'''用于开始和结束多行字符串。因此,方程只是一个字符串,每个方程有一行。方程格式采用标准数学符号,并添加一个。在行的末尾,您写: unit到该变量的SI单位unit在哪里。请注意,这不是方程的两侧单位(这将是 1/second),而是方程所定义的变量的单位,即在这种情况下 v v v
    现在,让我们使用这个定义来创建神经元。

    G = NeuronGroup(1, eqs)
    

    在Brian,你只创建神经元组,使用类NeuronGroup。创建这些对象中的一个时,前两个参数是神经元的数量(在此例中为 1)和定义的微分方程。NeuronGroup

    让我们看看如果我们没有将变量 tau 放在等式中会发生什么:

    eqs = '''
    dv/dt = 1-v : 1
    '''
    G = NeuronGroup(1, eqs)
    run(100*ms)
    
    ---------------------------------------------------------------------------
    
    DimensionMismatchError                    Traceback (most recent call last)
    
    ~/programming/brian2/brian2/equations/equations.py in check_units(self, group, run_namespace)
        955                 try:
    --> 956                     check_dimensions(str(eq.expr), self.dimensions[var] / second.dim,
        957                                      all_variables)
    
    
    ~/programming/brian2/brian2/equations/unitcheck.py in check_dimensions(expression, dimensions, variables)
         44                                                   expected=repr(get_unit(dimensions)))
    ---> 45     fail_for_dimension_mismatch(expr_dims, dimensions, err_msg)
         46 
    
    
    ~/programming/brian2/brian2/units/fundamentalunits.py in fail_for_dimension_mismatch(obj1, obj2, error_message, **error_quantities)
        183         if obj2 is None or isinstance(obj2, (Dimension, Unit)):
    --> 184             raise DimensionMismatchError(error_message, dim1)
        185         else:
    
    
    DimensionMismatchError: Expression 1-v does not have the expected unit hertz (unit is 1).
    


    During handling of the above exception, another exception occurred:

    DimensionMismatchError                    Traceback (most recent call last)
    
    ~/programming/brian2/brian2/core/network.py in before_run(self, run_namespace)
        897                 try:
    --> 898                     obj.before_run(run_namespace)
        899                 except Exception as ex:
    
    
    ~/programming/brian2/brian2/groups/neurongroup.py in before_run(self, run_namespace)
        883         # Check units
    --> 884         self.equations.check_units(self, run_namespace=run_namespace)
        885         # Check that subexpressions that refer to stateful functions are labeled
    
    
    ~/programming/brian2/brian2/equations/equations.py in check_units(self, group, run_namespace)
        958                 except DimensionMismatchError as ex:
    --> 959                     raise DimensionMismatchError(('Inconsistent units in '
        960                                                   'differential equation '
    
    
    DimensionMismatchError: Inconsistent units in differential equation defining variable v:
    Expression 1-v does not have the expected unit hertz (unit is 1).
    


    During handling of the above exception, another exception occurred:

    BrianObjectException                      Traceback (most recent call last)
    
    <ipython-input-11-97ed109f5888> in <module>
          3 '''
          4 G = NeuronGroup(1, eqs)
    ----> 5 run(100*ms)
    
    
    ~/programming/brian2/brian2/units/fundamentalunits.py in new_f(*args, **kwds)
       2383                                                      get_dimensions(newkeyset[k]))
       2384 
    -> 2385             result = f(*args, **kwds)
       2386             if 'result' in au:
       2387                 if au['result'] == bool:
    
    
    ~/programming/brian2/brian2/core/magic.py in run(duration, report, report_period, namespace, profile, level)
        371         intended use. See `MagicNetwork` for more details.
        372     '''
    --> 373     return magic_network.run(duration, report=report, report_period=report_period,
        374                              namespace=namespace, profile=profile, level=2+level)
        375 run.__module__ = __name__
    
    
    ~/programming/brian2/brian2/core/magic.py in run(self, duration, report, report_period, namespace, profile, level)
        229             namespace=None, profile=False, level=0):
        230         self._update_magic_objects(level=level+1)
    --> 231         Network.run(self, duration, report=report, report_period=report_period,
        232                     namespace=namespace, profile=profile, level=level+1)
        233 
    
    
    ~/programming/brian2/brian2/core/base.py in device_override_decorated_function(*args, **kwds)
        274                 return getattr(curdev, name)(*args, **kwds)
        275             else:
    --> 276                 return func(*args, **kwds)
        277 
        278         device_override_decorated_function.__doc__ = func.__doc__
    
    
    ~/programming/brian2/brian2/units/fundamentalunits.py in new_f(*args, **kwds)
       2383                                                      get_dimensions(newkeyset[k]))
       2384 
    -> 2385             result = f(*args, **kwds)
       2386             if 'result' in au:
       2387                 if au['result'] == bool:
    
    
    ~/programming/brian2/brian2/core/network.py in run(self, duration, report, report_period, namespace, profile, level)
       1007             namespace = get_local_namespace(level=level+3)
       1008 
    -> 1009         self.before_run(namespace)
       1010 
       1011         if len(all_objects) == 0:
    
    
    ~/programming/brian2/brian2/core/base.py in device_override_decorated_function(*args, **kwds)
        274                 return getattr(curdev, name)(*args, **kwds)
        275             else:
    --> 276                 return func(*args, **kwds)
        277 
        278         device_override_decorated_function.__doc__ = func.__doc__
    
    
    ~/programming/brian2/brian2/core/network.py in before_run(self, run_namespace)
        898                     obj.before_run(run_namespace)
        899                 except Exception as ex:
    --> 900                     raise brian_object_exception("An error occurred when preparing an object.", obj, ex)
        901 
        902         # Check that no object has been run as part of another network before
    
    
    BrianObjectException: Original error and traceback:
    Traceback (most recent call last):
      File "/home/marcel/programming/brian2/brian2/equations/equations.py", line 956, in check_units
        check_dimensions(str(eq.expr), self.dimensions[var] / second.dim,
      File "/home/marcel/programming/brian2/brian2/equations/unitcheck.py", line 45, in check_dimensions
        fail_for_dimension_mismatch(expr_dims, dimensions, err_msg)
      File "/home/marcel/programming/brian2/brian2/units/fundamentalunits.py", line 184, in fail_for_dimension_mismatch
        raise DimensionMismatchError(error_message, dim1)
    brian2.units.fundamentalunits.DimensionMismatchError: Expression 1-v does not have the expected unit hertz (unit is 1).
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "/home/marcel/programming/brian2/brian2/core/network.py", line 898, in before_run
        obj.before_run(run_namespace)
      File "/home/marcel/programming/brian2/brian2/groups/neurongroup.py", line 884, in before_run
        self.equations.check_units(self, run_namespace=run_namespace)
      File "/home/marcel/programming/brian2/brian2/equations/equations.py", line 959, in check_units
        raise DimensionMismatchError(('Inconsistent units in '
    brian2.units.fundamentalunits.DimensionMismatchError: Inconsistent units in differential equation defining variable v:
    Expression 1-v does not have the expected unit hertz (unit is 1).
    
    Error encountered with object named "neurongroup_1".
    Object was created here (most recent call only, full details in debug log):
      File "<ipython-input-11-97ed109f5888>", line 4, in <module>
        G = NeuronGroup(1, eqs)
    
    An error occurred when preparing an object. brian2.units.fundamentalunits.DimensionMismatchError: Inconsistent units in differential equation defining variable v:
    Expression 1-v does not have the expected unit hertz (unit is 1).
    (See above for original error message and traceback.)
    

    提出了错误,但为什么?原因是微分方程现在在维度上不一致。左侧有单位 dv/dt,但右侧1-v是无维度的。人们经常觉得布赖恩的这种行为令人困惑,因为这种等式在数学中很常见。但是,对于具有物理尺寸的数量,这是不正确的,因为结果会根据您测量的单位而改变。对于时间,如果您在几秒钟内测量它,则相同的方程行为与以毫秒计量时间的方式不同。为了避免这种情况,我们坚持要求您始终指定维度一致的方程。

    现在,让我们回到良好的方程,并实际运行模拟。

    start_scope()
    
    tau = 10*ms
    eqs = '''
    dv/dt = (1-v)/tau : 1
    '''
    
    G = NeuronGroup(1, eqs)
    run(100*ms)
    
    INFO       No numerical integration method specified for group 'neurongroup', using method 'exact' (took 0.02s). [brian2.stateupdaters.base.method_choice]
    

    首先,忽略在细胞的顶部的start_scope() 。在这个教程中的每个单元格中,都会看到我们运行模拟。它所做的只是确保在功能被调用之前创建的任何 Brian 对象不包括在模拟的下一个运行中。

    其次,您会看到有一个关于不指定数字集成方法的"INFO"消息。这是无害的,只是为了让你知道我们选择了什么方法,但我们会通过明确指定方法来修复它在下一个单元格。

    那么,这里发生了什么?那么,命令运行模拟100毫秒run(100*ms) 。我们可以看到,这通过在模拟前后打印变量值v而起作用。

    start_scope()
    
    G = NeuronGroup(1, eqs, method='exact')
    print('Before v = %s' % G.v[0])
    run(100*ms)
    print('After v = %s' % G.v[0])
    
    Before v = 0.0
    After v = 0.9999546000702376
    

    默认情况下,所有变量都以值 0 开头。由于微分方程是dv/dt=(1-v)/tau,我们预计一段时间后, v 将倾向于价值1,这正是我们所看到的。具体来说,我们期望v有这个价值1-exp(-t/tau)。让我们看看是否正确。

    print('Expected value of v = %s' % (1-exp(-100*ms/tau)))
    
    Expected value of v = 0.9999546000702375
    

    好消息是,模拟提供了我们所期望的价值!

    现在,让我们来看看变量v如何随时间演变的图表。v

    start_scope()
    
    G = NeuronGroup(1, eqs, method='exact')
    M = StateMonitor(G, 'v', record=True)
    
    run(30*ms)
    
    plot(M.t/ms, M.v[0])
    xlabel('Time (ms)')
    ylabel('v');
    


    在这里插入图片描述

    这一次,我们只运行了30毫秒的模拟,以便我们可以看到更好的行为。看起来它的行为似乎如预期的那样, 但让我们通过在上面绘制预期的行为来分析性地检查一下。

    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();
    


    在这里插入图片描述

    如您所见,蓝色(Brain)和破折号橙色(分析解决方案)线重合。

    在此示例中,我们使用了 StateMonitor 对象。这用于在模拟运行时记录神经元变量的值。前两个参数是要记录的组,以及要记录的变量。我们还指定record=0。这意味着我们记录神经元 0 的所有值。我们必须指定哪些神经元,我们希望记录,因为在大型模拟与许多神经元,它通常用了太多的RAM来记录所有神经元的值。StateMonitorrecord=0

    现在尝试修改方程和参数,看看下面的单元格中会发生什么。

    start_scope()
    
    tau = 10*ms
    eqs = '''
    dv/dt = (sin(2*pi*100*Hz*t)-v)/tau : 1
    '''
    
    # Change to Euler method because exact integrator doesn't work here
    G = NeuronGroup(1, eqs, method='euler')
    M = StateMonitor(G, 'v', record=0)
    
    G.v = 5 # initial value
    
    run(60*ms)
    
    plot(M.t/ms, M.v[0])
    xlabel('Time (ms)')
    ylabel('v');
    


    在这里插入图片描述

    添加脉冲

    到目前为止,我们还没有做任何神经元,只是玩弄了微分方程。现在,让我们开始添加尖刺。

    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');
    


    在这里插入图片描述

    我们在NeuronGroup 中增加了两个新关键词:threshold='v>0.8'reset='v = 0'这意味着,当我们发射一个尖峰,并在峰值v>0.8后立即重置v = 0。我们可以把任何表达和一系列的语句作为这些字符串。

    正如你所看到的,在开始时,行为与以前相同,直到v 越过阈值v>0.8,此时您看到它重置为0。你不能在这个图中看到它, 但内部布赖恩已经注册了这个事件作为一个高峰。让我们来看看。

    start_scope()
    
    G = NeuronGroup(1, eqs, threshold='v>0.8', reset='v = 0', method='exact')
    
    spikemon = SpikeMonitor(G)
    
    run(50*ms)
    
    print('Spike times: %s' % spikemon.t[:])
    
    Spike times: [16.  32.1 48.2] ms
    

    对象SpikeMonitor以您想要记录的峰值组作为参数,并将峰值时间存储在变量t中。让我们在另一个图形上绘制这些尖峰, 看看它是正确的。

    start_scope()
    
    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)
    
    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');
    


    在这里插入图片描述

    在这里,我们已经使用matplotlib 命令axvline绘制一个橙色的,虚线的垂直线时,每个尖峰记录的SpikeMonitor

    现在尝试更改上面的单元格中的字符串thresholdreset ,看看会发生什么。

    耐火性(不应期)

    神经元模型的一个共同特点是耐火性。这意味着,在神经元发射尖峰后,它会在一定持续时间内变得耐火,在此期间结束之前不能再发射一个尖峰。以下是我们在布莱恩的做事。

    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');
    


    在这里插入图片描述

    正如你可以看到在这个数字,在第一个峰值后,v 保持在0约5毫秒之前,它恢复正常的行为。为此,我们做了两件事。首先,我们在声明NeuronGroup中添加了关键字refractory=5*ms。就其本身,这仅意味着神经元不能在这一时期激增(见下文),但不会改变v 行为方式。为了使耐火期保持不变,我们必须在微分方程中添加(unless refractory) 在定义v的末尾。这意味着微分方程决定了除非其耐火性,否则v被关闭的行为。

    下面是会发生什么,如果我们不包括 (unless refractory)。请注意,我们还降低了耐火期的值tau 并延长了耐火期的长度,使行为更加清晰。

    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[:])
    
    Spike times: [ 8. 23. 38.] ms
    

    在这里插入图片描述

    发生什么事了?第一个峰值的行为是相同的:v 上升到0.8,然后神经元在8毫秒时发射一个峰值,然后立即重置为0。由于耐火期现在是15毫秒,这意味着神经元将无法再次尖峰,直到时间8+15=23毫秒。紧接着第一个峰值v,现在的价值立即开始上升,因为我们没有在定义dv/dt中指定(unless refractory) 。然而,一旦它达到值0.8(虚线绿线)的时间大约8毫秒,它不会发射尖峰,即使阈值是v>0.8。这是因为神经元仍然耐火,直到时间23毫秒,在这一点上,它发射了一个尖峰。

    请注意,您可以做更复杂和有趣的事情与耐火材料。有关其工作原理的更多详细信息,请参阅完整文档。

    多个神经元

    到目前为止,我们只与一个神经元工作。让我们用多个神经元做一些有趣的事情。

    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');
    


    在这里插入图片描述

    这显示了一些变化。首先,我们有一个新的变量N 来确定神经元的数量。其次,我们在运行前添加了该声明G.v = 'rand()'。这样做是初始化每个神经元与0和1之间的不同均匀随机值。我们这样做只是为了让每个神经元都会做一些不同的事情。另一个大的变化是我们最终如何绘制数据。NG.v = ‘rand()’

    除了与所有峰值的时间变量,我们还使用了变量spikemon.t,该变量为每个尖峰提供了相应的神经元指数spikemon.i,并在 y 值上的 x 轴和神经元索引上绘制了一个带时间的单个黑点。这是神经科学中使用的标准" raster plot "。

    参数

    为了让这些多个神经元做一些更有趣的事情,让我们介绍每个神经元参数,没有附加到它们的微分方程。

    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)');
    


    在这里插入图片描述

    线 v0 : 1 声明一个新的每个神经元参数 v0与单位1(即无维度)。

    线G.v0 = 'i*v0_max/(N-1)'初始化每个神经元从0到v0_max。符号 i 在这样的字符串中出现时,是指神经元索引。

    因此,在这个示例中,我们正以指数级的倍率驱动神经元v0,但当vv>1交叉时,它会发射尖峰并重置。其效果是,它发射尖峰的速度将与值v0有关。因为v0<1它永远不会发射尖峰,随着v0变大,它会以更高的速度发射尖峰。右手图显示发射速率作值v0的函数。这是这个神经元模型的 I-f 曲线。

    请注意,在绘图中,我们使用了 SpikeMonitor 变量count:这是组中每个神经元发射的峰值数的数组。除以运行持续时间,可以给出发射速率。

    随机神经元

    通常,在制作神经元模型时,我们包括一个随机元素来模拟各种形式的神经噪音的影响。在 Brian 中,我们可以使用微分方程中的符号xi来做到这一点。严格地说,这个符号是一个"随机差分",但你可以把它看作是一个高斯随机变量,平均0和标准偏差1。我们必须考虑随机差分随时间进行缩放的方式,这就是为什么我们在下面的方程中将其乘以tau**-0.5(有关更多详细信息,请参阅有关随机差分方程的教科书)。
    请注意,我们也更改了method关键字参数使用'euler'(代表Euler-Maruyama method):我们之前使用的方法'exact'不适用于随机微分方程。

    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)');
    

    在这里插入图片描述

    这与上一节的数字相同,但增加了一些噪音。请注意曲线是如何改变形状的:它现在不是从以 0 的速度发射到以正速发射的急剧跳跃,而是以sigmoidal fashion的方式增加。这是因为无论驱动力多么小,随机性都可能导致它引发峰值。

    教程结束

    这是教程这一部分的结尾。下面的细胞有另一个例子。看看你能否弄清楚它在做什么,为什么。尝试添加一个StateMonitor 来记录其中一个神经元的变量值,以帮助您理解它。

    你也可以尝试你在这个细胞中学到的东西。

    完成后,您可以转到 Synapss 的下一个教程。

    start_scope()
    
    N = 1000
    tau = 10*ms
    vr = -70*mV
    vt0 = -50*mV
    delta_vt0 = 5*mV
    tau_t = 100*ms
    sigma = 0.5*(vt0-vr)
    v_drive = 2*(vt0-vr)
    duration = 100*ms
    
    eqs = '''
    dv/dt = (v_drive+vr-v)/tau + sigma*xi*tau**-0.5 : volt
    dvt/dt = (vt0-vt)/tau_t : volt
    '''
    
    reset = '''
    v = vr
    vt += delta_vt0
    '''
    
    G = NeuronGroup(N, eqs, threshold='v>vt', reset=reset, refractory=5*ms, method='euler')
    spikemon = SpikeMonitor(G)
    
    G.v = 'rand()*(vt0-vr)+vr'
    G.vt = vt0
    
    run(duration)
    
    _ = hist(spikemon.t/ms, 100, histtype='stepfilled', facecolor='k', weights=list(ones(len(spikemon))/(N*defaultclock.dt)))
    xlabel('Time (ms)')
    ylabel('Instantaneous firing rate (sp/s)');
    


    在这里插入图片描述

    第 2 部分: 突触

    如果你还没有读过第1部分:神经元,现在就去读吧。

    和以前一样,我们开始引入brian2包,并为IPython设置matplotlib:

    from brian2 import *
    %matplotlib inline
    

    最简单的突触

    一旦你有一些神经元,下一步是通过突触连接它们。我们将首先做最简单的突触类型,导致峰值后变量的瞬时变化。

    start_scope()
    
    eqs = '''
    dv/dt = (I-v)/tau : 1
    I : 1
    tau : second
    '''
    G = NeuronGroup(2, eqs, threshold='v>1', reset='v = 0', method='exact')
    G.I = [2, 0]
    G.tau = [10, 100]*ms
    
    # Comment these two lines out to see what happens without Synapses
    S = Synapses(G, G, on_pre='v_post += 0.2')
    S.connect(i=0, j=1)
    
    M = StateMonitor(G, 'v', record=True)
    
    run(100*ms)
    
    plot(M.t/ms, M.v[0], label='Neuron 0')
    plot(M.t/ms, M.v[1], label='Neuron 1')
    xlabel('Time (ms)')
    ylabel('v')
    legend();
    


    在这里插入图片描述

    这里发生了一些事情。首先,让我们回顾一下NeuronGroup发生了什么事情。我们创建了两个神经元,每个神经元都有相同的微分方程,但参数 I 和 tau 的值不同。神经元 0 有I=2tau=10*ms, 这意味着被驱动以相当高的速度反复尖峰。神经元 1 有I=0tau=100*ms, 这意味着它自己 - 没有突触 - 它不会尖峰在所有 (驱动电流我是 0) 。您可以通过评论定义突触的两行来证明这一点。

    接下来,我们定义突触:Synapses(source, target, ...) 意味着我们正在定义一个突触模型,从sourcetarget。在这种情况下,来源和目标都是相同的,组G语法on_pre='v_post += 0.2'意味着,当尖峰发生在前突触神经元(因此on_pre),它会导致瞬间的变化发生v_post += 0.2。所述_post是指突触后v值,并且增加了 0.2。因此,总的说来,这个模型说的是,每当G中的两个神经元通过突触连接时,当源神经元发射尖峰时,目标神经元的v值将增加

    然而,在这一点上,我们只定义了突触模型,我们实际上还没有创建任何突触。下一行S.connect(i=0, j=1)创建从神经元 0 到神经元 1 的突触。

    增加重量

    在前一节中,我们硬编码突触的重量为值 0.2,但我们通常会允许这对于不同的突触有所不同。我们通过引入突触方程来做到这一点。

    start_scope()
    
    eqs = '''
    dv/dt = (I-v)/tau : 1
    I : 1
    tau : second
    '''
    G = NeuronGroup(3, eqs, threshold='v>1', reset='v = 0', method='exact')
    G.I = [2, 0, 0]
    G.tau = [10, 100, 100]*ms
    
    # Comment these two lines out to see what happens without Synapses
    S = Synapses(G, G, 'w : 1', on_pre='v_post += w')
    S.connect(i=0, j=[1, 2])
    S.w = 'j*0.2'
    
    M = StateMonitor(G, 'v', record=True)
    
    run(50*ms)
    
    plot(M.t/ms, M.v[0], label='Neuron 0')
    plot(M.t/ms, M.v[1], label='Neuron 1')
    plot(M.t/ms, M.v[2], label='Neuron 2')
    xlabel('Time (ms)')
    ylabel('v')
    legend();
    


    在这里插入图片描述

    此示例的行为与上一个示例非常相似,但现在有突触重量变量w。字符串'w : 1'是一个方程字符串,与神经元完全相同,定义单个无维参数 w。我们改变了尖峰上的行为到on_pre='v_post += w',使每个突触可以根据w值的行为不同。为了说明这一点,我们制造了第三个神经元,其行为与第二个神经元完全相同,并将神经元0连接到神经元1和2。我们还通过S.w = 'j*0.2'设置权重。突触中ij发生的时候,i 是指源神经元指数和目标神经元j 指数。因此,这将给予一个突触连接从0到1的重量0.2=0.2*1和从0到2的重量0.4=0.2*2

    引入延迟

    到目前为止,突触是瞬时的,但我们也可以让他们采取行动有一定的延迟。

    start_scope()
    
    eqs = '''
    dv/dt = (I-v)/tau : 1
    I : 1
    tau : second
    '''
    G = NeuronGroup(3, eqs, threshold='v>1', reset='v = 0', method='exact')
    G.I = [2, 0, 0]
    G.tau = [10, 100, 100]*ms
    
    S = Synapses(G, G, 'w : 1', on_pre='v_post += w')
    S.connect(i=0, j=[1, 2])
    S.w = 'j*0.2'
    S.delay = 'j*2*ms'
    
    M = StateMonitor(G, 'v', record=True)
    
    run(50*ms)
    
    plot(M.t/ms, M.v[0], label='Neuron 0')
    plot(M.t/ms, M.v[1], label='Neuron 1')
    plot(M.t/ms, M.v[2], label='Neuron 2')
    xlabel('Time (ms)')
    ylabel('v')
    legend();
    

    在这里插入图片描述

    正如你所看到的,这就像添加一条线一样简单,S.delay = 'j*2*ms' 这样从0到1的突触延迟为2毫秒,从0到2的延迟为4毫秒。

    更复杂的连接

    到目前为止,我们明确指定了突触连接,但对于较大的网络,这通常是不可能的。为此,我们通常要指定一些条件。

    start_scope()
    
    N = 10
    G = NeuronGroup(N, 'v:1')
    S = Synapses(G, G)
    S.connect(condition='i!=j', p=0.2)
    

    在这里,我们创建了一个由 N 神经元组成的虚拟神经元组和一个虚拟突触模型,它实际上不做任何事情只是为了演示连接性。只要条件成立,S.connect(condition='i!=j', p=0.2)将连接所有神经元ij,概率为 0.2。那么,我们如何才能看到这种连接呢?这里有一个小功能,让我们可视化它。

    def visualise_connectivity(S):
        Ns = len(S.source)
        Nt = len(S.target)
        figure(figsize=(10, 4))
        subplot(121)
        plot(zeros(Ns), arange(Ns), 'ok', ms=10)
        plot(ones(Nt), arange(Nt), 'ok', ms=10)
        for i, j in zip(S.i, S.j):
            plot([0, 1], [i, j], '-k')
        xticks([0, 1], ['Source', 'Target'])
        ylabel('Neuron index')
        xlim(-0.1, 1.1)
        ylim(-1, max(Ns, Nt))
        subplot(122)
        plot(S.i, S.j, 'ok')
        xlim(-1, Ns)
        ylim(-1, Nt)
        xlabel('Source neuron index')
        ylabel('Target neuron index')
        
    visualise_connectivity(S)
    


    在这里插入图片描述

    这里有两个情节。在左手边,您会看到一条垂直的圆线,指示左侧的源神经元,以及指示右侧目标神经元的垂直线,以及两个具有突触的神经元之间的线。右手边是另一种可视化相同事物的方式。在这里,每个黑点都是突触,x 值源神经元指数,y 值目标神经元指数。

    让我们看看这些数字如何变化,因为我们改变了连接的概率:

    start_scope()
    
    N = 10
    G = NeuronGroup(N, 'v:1')
    
    for p in [0.1, 0.5, 1.0]:
        S = Synapses(G, G)
        S.connect(condition='i!=j', p=p)
        visualise_connectivity(S)
        suptitle('p = '+str(p))
    

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    让我们看看其他连接条件是什么样子的。这一个只会连接邻近的神经元。

    start_scope()
    
    N = 10
    G = NeuronGroup(N, 'v:1')
    
    S = Synapses(G, G)
    S.connect(condition='abs(i-j)<4 and i!=j')
    visualise_connectivity(S)
    

    在这里插入图片描述

    尝试使用该单元格查看其他连接条件的外观。

    您还可以使用生成器语法更高效地创建这样的连接。在这样的小例子中,这并不重要,但是对于大量的神经元来说,直接指定哪些神经元应该连接比仅仅指定一个条件要有效得多。请注意,以下示例用skip_if_invalid 避免边界上的错误(例如,不要尝试将神经元与指数 1 连接到带有指数 -2 的神经元)。

    start_scope()
    
    N = 10
    G = NeuronGroup(N, 'v:1')
    
    S = Synapses(G, G)
    S.connect(j='k for k in range(i-3, i+4) if i!=k', skip_if_invalid=True)
    visualise_connectivity(S)
    


    在这里插入图片描述

    如果每个源神经元都与一个目标神经元连接(通常与两个大小相同的单独组一起使用,而不是与本示例中相同的源和目标组一起使用),则有一种非常有效的特殊语法。例如,1 到 1 连接看起来是这样的:

    start_scope()
    
    N = 10
    G = NeuronGroup(N, 'v:1')
    
    S = Synapses(G, G)
    S.connect(j='i')
    visualise_connectivity(S)
    


    在这里插入图片描述

    您还可以使用字符串指定重量值。让我们来看看一个例子,我们为每个神经元分配一个空间位置,并具有距离依赖的连接功能。我们通过标记的大小来可视化突触的重量。

    start_scope()
    
    N = 30
    neuron_spacing = 50*umetre
    width = N/4.0*neuron_spacing
    
    # Neuron has one variable x, its position
    G = NeuronGroup(N, 'x : metre')
    G.x = 'i*neuron_spacing'
    
    # All synapses are connected (excluding self-connections)
    S = Synapses(G, G, 'w : 1')
    S.connect(condition='i!=j')
    # Weight varies with distance
    S.w = 'exp(-(x_pre-x_post)**2/(2*width**2))'
    
    scatter(S.x_pre/um, S.x_post/um, S.w*20)
    xlabel('Source neuron position (um)')
    ylabel('Target neuron position (um)');
    


    在这里插入图片描述

    现在尝试更改该功能,看看情节如何变化。

    更复杂的突触模型:STDP

    Brian 的突触框架非常一般,可以做短期可塑性 (STP) 或峰值计时依赖可塑性 (STDP) 之类的事情。让我们看看它是如何工作的STDP。

    STDP 通常由类似这样的方程定义:

    Δ w = ∑ t p r e ∑ t p o s t W ( t p o s t − t p r e ) \Delta w = \sum_{t_{pre}} \sum_{t_{post}} W(t_{post}-t_{pre}) Δw=tpretpostW(tposttpre)

    即突触重量 w 的变化是所有先天性峰值时间 t p r e t_{pre} tpre 和后突触峰值时间 t p o s t t_{post} tpost的总和,这些尖峰时间的某些 W W W函数的差异。常用的功能 W W W是:

    W ( Δ t ) = { A p r e e − Δ t / τ p r e Δ t > 0 A p o s t e Δ t / τ p o s t Δ t < 0 W(\Delta t) = \begin{cases} A_{pre} e^{-\Delta t/\tau_{pre}} & \Delta t>0 \\ A_{post} e^{\Delta t/\tau_{post}} & \Delta t<0 \end{cases} W(Δt)={ApreeΔt/τpreAposteΔt/τpostΔt>0Δt<0

    此功能看起来像这样:

    tau_pre = tau_post = 20*ms
    A_pre = 0.01
    A_post = -A_pre*1.05
    delta_t = 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');
    


    在这里插入图片描述

    直接使用这个方程进行模拟是非常低效的,因为我们将不得不总结所有对尖峰。这也是生理上不现实的,因为神经元不记得它以前的所有峰值时间。事实证明,有一个更有效和生理上更合理的方法来获得同样的效果。
    我们定义了两个新的变量,它们是*“traces” of pre-* a p r e a_{pre} aprepost-synaptic activity a p o s t a_{post} apost,由微分方程管理:

    τ p r e d d t a p r e = − a p r e τ p o s t d d t a p o s t = − a p o s t \begin{aligned} \tau_{pre}\frac{\mathrm{d}}{\mathrm{d}t} a_{pre} &= -a_{pre}\\ \tau_{post}\frac{\mathrm{d}}{\mathrm{d}t} a_{post} &= -a_{post} \end{aligned} τpredtdapreτpostdtdapost=apre=apost

    当发生先天性尖峰时,会更新前突起痕迹,并根据规则修改重量:

    a p r e → a p r e + A p r e w → w + a p o s t \begin{aligned} a_{pre} &\rightarrow a_{pre}+A_{pre}\\ w &\rightarrow w+a_{post} \end{aligned} aprewapre+Aprew+apost

    当发生后突起时:

    a p o s t → a p o s t + A p o s t w → w + a p r e \begin{aligned} a_{post} &\rightarrow a_{post}+A_{post}\\ w &\rightarrow w+a_{pre} \end{aligned} apostwapost+Apostw+apre

    要看到此配方是等价的,您只需要检查方程是否线性相等,并考虑两种情况:如果先发制人峰值发生在后突刺之前会发生什么,反之亦然。试着画一张它的图片。

    现在,我们有一个仅依赖于微分方程和尖峰事件的公式,我们可以将其转换为 Brian 代码。

    start_scope()
    
    taupre = taupost = 20*ms
    wmax = 0.01
    Apre = 0.01
    Apost = -Apre*taupre/taupost*1.05
    
    G = NeuronGroup(1, 'v:1', threshold='v>1')
    
    S = Synapses(G, G,
                 '''
                 w : 1
                 dapre/dt = -apre/taupre : 1 (event-driven)
                 dapost/dt = -apost/taupost : 1 (event-driven)
                 ''',
                 on_pre='''
                 v_post += w
                 apre += Apre
                 w = clip(w+apost, 0, wmax)
                 ''',
                 on_post='''
                 apost += Apost
                 w = clip(w+apre, 0, wmax)
                 ''')
    

    有几件事情要看。首先,在定义突触时,我们给出了一个更复杂的多线字符串,定义了三个突触变量((w, apreapost))。我们也有一个新的语法位(event-driven),在定义apreapost,这意味着,虽然这两个变量会随着时间而不断演变,但 Brian 仅应在事件(峰值)时更新它们。这是因为我们不需要apreapost的值,除了在高峰时间,它是更有效的,只有在需要时更新它们。

    接下来我们有一个 on_pre=...。第一行是v_post += w:这是实际上将突触重量应用于目标神经元的线。第二行apre += Apre 是编码上述规则。在第三行中,我们还编码了上述规则,但我们增加了一个额外的功能:我们夹住了至少 0 到最大wmax之间的突触重量,以便重量不会变得太大或为负。函数 clip(x, low, high) 可以这样做。

    最后,我们有一个 on_post=...。这为当突触后神经元发生火灾时提供要计算的语句。请注意,在这种情况下,我们不会修改v,只修改突触变量。

    现在,让我们看看当先天性峰值在后突峰之前的某个时间到达时,所有变量的行为如何。

    start_scope()
    
    taupre = taupost = 20*ms
    wmax = 0.01
    Apre = 0.01
    Apost = -Apre*taupre/taupost*1.05
    
    G = NeuronGroup(2, 'v:1', threshold='t>(1+i)*10*ms', refractory=100*ms)
    
    S = Synapses(G, G,
                 '''
                 w : 1
                 dapre/dt = -apre/taupre : 1 (clock-driven)
                 dapost/dt = -apost/taupost : 1 (clock-driven)
                 ''',
                 on_pre='''
                 v_post += w
                 apre += Apre
                 w = clip(w+apost, 0, wmax)
                 ''',
                 on_post='''
                 apost += Apost
                 w = clip(w+apre, 0, wmax)
                 ''', method='linear')
    S.connect(i=0, j=1)
    M = StateMonitor(S, ['w', 'apre', 'apost'], record=True)
    
    run(30*ms)
    
    figure(figsize=(4, 8))
    subplot(211)
    plot(M.t/ms, M.apre[0], label='apre')
    plot(M.t/ms, M.apost[0], label='apost')
    legend()
    subplot(212)
    plot(M.t/ms, M.w[0], label='w')
    legend(loc='best')
    xlabel('Time (ms)');
    


    在这里插入图片描述

    这里有几件事情要注意。首先,我们用一个技巧,使神经元0火在10毫秒的时间尖峰,神经元1在时间20毫秒。你能看看它是如何工作的吗?

    其次,我们用(clock-driven)取代(event-driven),这样你就可以看到apreapost如何随着时间的推移演变。尝试恢复此更改,看看会发生什么。

    尝试更改峰值的时间,看看会发生什么。

    最后,让我们验证此配方是否与原始配方相当。

    start_scope()
    
    taupre = taupost = 20*ms
    Apre = 0.01
    Apost = -Apre*taupre/taupost*1.05
    tmax = 50*ms
    N = 100
    
    # Presynaptic neurons G spike at times from 0 to tmax
    # Postsynaptic neurons G spike at times from tmax to 0
    # So difference in spike times will vary from -tmax to +tmax
    G = NeuronGroup(N, 'tspike:second', threshold='t>tspike', refractory=100*ms)
    H = NeuronGroup(N, 'tspike:second', threshold='t>tspike', refractory=100*ms)
    G.tspike = 'i*tmax/(N-1)'
    H.tspike = '(N-1-i)*tmax/(N-1)'
    
    S = Synapses(G, H,
                 '''
                 w : 1
                 dapre/dt = -apre/taupre : 1 (event-driven)
                 dapost/dt = -apost/taupost : 1 (event-driven)
                 ''',
                 on_pre='''
                 apre += Apre
                 w = w+apost
                 ''',
                 on_post='''
                 apost += Apost
                 w = w+apre
                 ''')
    S.connect(j='i')
    
    run(tmax+1*ms)
    
    plot((H.tspike-G.tspike)/ms, S.w)
    xlabel(r'$\Delta t$ (ms)')
    ylabel(r'$\Delta w$')
    axhline(0, ls='-', c='k');
    

    在这里插入图片描述

    你能看看这是怎么工作的吗?

    教程结束

    第3部分:模拟

    如果您尚未阅读关于神经元和突触的第1部分和第2部分,请先阅读它们。

    本教程是关于管理在研究问题中出现的稍微复杂一点的任务,而不是我们迄今为止一直在研究的玩具示例。因此,我们涵盖了输入感官数据、模拟实验条件等内容。

    和以前一样,我们开始引入brian2包,并为IPython设置matplotlib:

    from brian2 import *
    %matplotlib inline
    

    多次运行

    让我们从查看一个非常常见的任务开始:使用某些参数进行多次模拟,以更改这些参数。让我们从一些非常简单的事情开始,由泊松尖刺神经元驱动的漏水集成和火神经元的发射速率如何根据其膜时间不变而变化?让我们设置它。

    # remember, this is here for running separate simulations in the same notebook
    start_scope() 
    # Parameters
    num_inputs = 100
    input_rate = 10*Hz
    weight = 0.1
    # Range of time constants
    tau_range = linspace(1, 10, 30)*ms
    # Use this list to store output rates
    output_rates = []
    # Iterate over range of time constants
    for tau in tau_range:
        # Construct the network each time
        P = PoissonGroup(num_inputs, rates=input_rate)
        eqs = '''
        dv/dt = -v/tau : 1
        '''
        G = NeuronGroup(1, eqs, threshold='v>1', reset='v=0', method='exact')
        S = Synapses(P, G, on_pre='v += weight')
        S.connect()
        M = SpikeMonitor(G)
        # Run it and store the output firing rate in the list
        run(1*second)
        output_rates.append(M.num_spikes/second)
    # And plot it
    plot(tau_range/ms, output_rates)
    xlabel(r'$\tau$ (ms)')
    ylabel('Firing rate (sp/s)');
    


    在这里插入图片描述

    现在,如果你正在运行笔记本,你会发现这是一个有点慢运行。原因是,对于每个循环,您正在从头开始重新创建对象。我们可以通过只建立一次网络来改进这一点。我们在循环之前存储网络状态的副本,并在每次迭代的开始时还原它。

    start_scope() 
    num_inputs = 100
    input_rate = 10*Hz
    weight = 0.1
    tau_range = linspace(1, 10, 30)*ms
    output_rates = []
    # Construct the network just once
    P = PoissonGroup(num_inputs, rates=input_rate)
    eqs = '''
    dv/dt = -v/tau : 1
    '''
    G = NeuronGroup(1, eqs, threshold='v>1', reset='v=0', method='exact')
    S = Synapses(P, G, on_pre='v += weight')
    S.connect()
    M = SpikeMonitor(G)
    # Store the current state of the network
    store()
    for tau in tau_range:
        # Restore the original state of the network
        restore()
        # Run it with the new value of tau
        run(1*second)
        output_rates.append(M.num_spikes/second)
    plot(tau_range/ms, output_rates)
    xlabel(r'$\tau$ (ms)')
    ylabel('Firing rate (sp/s)');
    


    在这里插入图片描述

    这是一个非常简单的例子,使用存储和恢复,但你可以在更复杂的情况下使用它。例如,您可能需要运行长期训练运行,然后运行多个测试运行之后。只需在长时间的训练后放置一个存储,并在每次测试运行之前进行恢复。

    您还可以看到输出曲线非常嘈杂,不会像我们预期的那样单调地增加。噪音来自我们每次都重新运行泊松小组的事实。如果我们只想看到时间恒定的效果,我们可以确保每次峰值是相同的(虽然请注意,真的,你应该做多个运行,并采取平均)。我们通过运行一次泊松组,记录其峰值,然后创建一个新的SpikeGeneratorGroup ,将输出这些记录的峰值每次。

    start_scope() 
    num_inputs = 100
    input_rate = 10*Hz
    weight = 0.1
    tau_range = linspace(1, 10, 30)*ms
    output_rates = []
    # Construct the Poisson spikes just once
    P = PoissonGroup(num_inputs, rates=input_rate)
    MP = SpikeMonitor(P)
    # We use a Network object because later on we don't
    # want to include these objects
    net = Network(P, MP)
    net.run(1*second)
    # And keep a copy of those spikes
    spikes_i = MP.i
    spikes_t = MP.t
    # Now construct the network that we run each time
    # SpikeGeneratorGroup gets the spikes that we created before
    SGG = SpikeGeneratorGroup(num_inputs, spikes_i, spikes_t)
    eqs = '''
    dv/dt = -v/tau : 1
    '''
    G = NeuronGroup(1, eqs, threshold='v>1', reset='v=0', method='exact')
    S = Synapses(SGG, G, on_pre='v += weight')
    S.connect()
    M = SpikeMonitor(G)
    # Store the current state of the network
    net = Network(SGG, G, S, M)
    net.store()
    for tau in tau_range:
        # Restore the original state of the network
        net.restore()
        # Run it with the new value of tau
        net.run(1*second)
        output_rates.append(M.num_spikes/second)
    plot(tau_range/ms, output_rates)
    xlabel(r'$\tau$ (ms)')
    ylabel('Firing rate (sp/s)');
    


    在这里插入图片描述

    你可以看到,现在噪音要小得多,而且单调地增加噪音,因为每次输入尖峰都是一样的,这意味着我们看到的是时间恒定的影响,而不是随机的尖峰。

    请注意,在上面的代码中,我们创建了对象Network。原因是,在循环中,如果我们只是调用run它会尝试模拟所有的对象,包括泊松神经元P,我们只想运行一次。我们用Network明确指定要包含哪些对象。

    到目前为止,我们研究的技术是概念上最简单的多运行方式,但并不总是最有效的。由于上面的模型中只有一个输出神经元,我们可以简单地复制输出神经元,使时间恒定成为该组的参数。

    start_scope() 
    num_inputs = 100
    input_rate = 10*Hz
    weight = 0.1
    tau_range = linspace(1, 10, 30)*ms
    num_tau = len(tau_range)
    P = PoissonGroup(num_inputs, rates=input_rate)
    # We make tau a parameter of the group
    eqs = '''
    dv/dt = -v/tau : 1
    tau : second
    '''
    # And we have num_tau output neurons, each with a different tau
    G = NeuronGroup(num_tau, eqs, threshold='v>1', reset='v=0', method='exact')
    G.tau = tau_range
    S = Synapses(P, G, on_pre='v += weight')
    S.connect()
    M = SpikeMonitor(G)
    # Now we can just run once with no loop
    run(1*second)
    output_rates = M.count/second # firing rate is count/duration
    plot(tau_range/ms, output_rates)
    xlabel(r'$\tau$ (ms)')
    ylabel('Firing rate (sp/s)');
    
    WARNING    "tau" is an internal variable of group "neurongroup", but also exists in the run namespace with the value 10. * msecond. The internal variable will be used. [brian2.groups.group.Group.resolve.resolution_conflict]
    

    在这里插入图片描述

    你可以看到,这是更快了!这在概念上有点复杂,而且并不总是可以做到这一点,但如果有可能的话,它可以更有效率。

    让我们通过快速了解间窥点间隔的平均值和标准偏差如何取决于时间的恒定来结束此示例。

    trains = M.spike_trains()
    isi_mu = full(num_tau, nan)*second
    isi_std = full(num_tau, nan)*second
    for idx in range(num_tau):
        train = diff(trains[idx])
        if len(train)>1:
            isi_mu[idx] = mean(train)
            isi_std[idx] = std(train)
    errorbar(tau_range/ms, isi_mu/ms, yerr=isi_std/ms)
    xlabel(r'$\tau$ (ms)')
    ylabel('Interspike interval (ms)');
    


    在这里插入图片描述

    请注意,我们使用了SpikeMonitorspike_trains()这是一本字典,其中键是神经元的指数,值是该神经元的峰值时间阵列。

    运行时更改内容

    想象一下,一个实验,你注入电流到神经元,并随机改变振幅每10毫秒。让我们看看我们是否可以使用霍奇金-赫克斯利Hodgkin-Huxley型神经元进行建模。

    start_scope()
    # Parameters
    area = 20000*umetre**2
    Cm = 1*ufarad*cm**-2 * area
    gl = 5e-5*siemens*cm**-2 * area
    El = -65*mV
    EK = -90*mV
    ENa = 50*mV
    g_na = 100*msiemens*cm**-2 * area
    g_kd = 30*msiemens*cm**-2 * area
    VT = -63*mV
    # The model
    eqs_HH = '''
    dv/dt = (gl*(El-v) - g_na*(m*m*m)*h*(v-ENa) - g_kd*(n*n*n*n)*(v-EK) + I)/Cm : volt
    dm/dt = 0.32*(mV**-1)*(13.*mV-v+VT)/
        (exp((13.*mV-v+VT)/(4.*mV))-1.)/ms*(1-m)-0.28*(mV**-1)*(v-VT-40.*mV)/
        (exp((v-VT-40.*mV)/(5.*mV))-1.)/ms*m : 1
    dn/dt = 0.032*(mV**-1)*(15.*mV-v+VT)/
        (exp((15.*mV-v+VT)/(5.*mV))-1.)/ms*(1.-n)-.5*exp((10.*mV-v+VT)/(40.*mV))/ms*n : 1
    dh/dt = 0.128*exp((17.*mV-v+VT)/(18.*mV))/ms*(1.-h)-4./(1+exp((40.*mV-v+VT)/(5.*mV)))/ms*h : 1
    I : amp
    '''
    group = NeuronGroup(1, eqs_HH,
                        threshold='v > -40*mV',
                        refractory='v > -40*mV',
                        method='exponential_euler')
    group.v = El
    statemon = StateMonitor(group, 'v', record=True)
    spikemon = SpikeMonitor(group, variables='v')
    figure(figsize=(9, 4))
    for l in range(5):
        group.I = rand()*50*nA
        run(10*ms)
        axvline(l*10, ls='--', c='k')
    axhline(El/mV, ls='-', c='lightgray', lw=3)
    plot(statemon.t/ms, statemon.v[0]/mV, '-b')
    plot(spikemon.t/ms, spikemon.v/mV, 'ob')
    xlabel('Time (ms)')
    ylabel('v (mV)');
    


    在这里插入图片描述

    在上面的代码中,我们使用多个运行的循环来实现此目标。这很好,但这不是最有效的方法,因为每次run,我们必须做大量的初始化工作,减慢一切。它也不会与布赖恩更有效的独立模式工作。这是另一种方式。

    start_scope()
    group = NeuronGroup(1, eqs_HH,
                        threshold='v > -40*mV',
                        refractory='v > -40*mV',
                        method='exponential_euler')
    group.v = El
    statemon = StateMonitor(group, 'v', record=True)
    spikemon = SpikeMonitor(group, variables='v')
    # we replace the loop with a run_regularly
    group.run_regularly('I = rand()*50*nA', dt=10*ms)
    run(50*ms)
    figure(figsize=(9, 4))
    # we keep the loop just to draw the vertical lines
    for l in range(5):
        axvline(l*10, ls='--', c='k')
    axhline(El/mV, ls='-', c='lightgray', lw=3)
    plot(statemon.t/ms, statemon.v[0]/mV, '-b')
    plot(spikemon.t/ms, spikemon.v/mV, 'ob')
    xlabel('Time (ms)')
    ylabel('v (mV)');
    


    在这里插入图片描述

    我们已经用 run_regularly 替换了多次run 的循环。这使得指定的代码块运行每一个dt=10*msrun_regularly允许您运行特定于单个NeuronGroup的代码,但有时您可能需要更大的灵活性。为此,您可以使用它允许您运行任意的 Python 代码(但不会与独立模式配合使用)。

    start_scope()
    group = NeuronGroup(1, eqs_HH,
                        threshold='v > -40*mV',
                        refractory='v > -40*mV',
                        method='exponential_euler')
    group.v = El
    statemon = StateMonitor(group, 'v', record=True)
    spikemon = SpikeMonitor(group, variables='v')
    # we replace the loop with a network_operation
    @network_operation(dt=10*ms)
    def change_I():
        group.I = rand()*50*nA
    run(50*ms)
    figure(figsize=(9, 4))
    for l in range(5):
        axvline(l*10, ls='--', c='k')
    axhline(El/mV, ls='-', c='lightgray', lw=3)
    plot(statemon.t/ms, statemon.v[0]/mV, '-b')
    plot(spikemon.t/ms, spikemon.v/mV, 'ob')
    xlabel('Time (ms)')
    ylabel('v (mV)');
    


    在这里插入图片描述

    现在,让我们扩展此示例,以运行多个神经元,每个神经元都具有不同的电容,以了解这如何影响细胞的行为。

    start_scope()
    N = 3
    eqs_HH_2 = '''
    dv/dt = (gl*(El-v) - g_na*(m*m*m)*h*(v-ENa) - g_kd*(n*n*n*n)*(v-EK) + I)/C : volt
    dm/dt = 0.32*(mV**-1)*(13.*mV-v+VT)/
        (exp((13.*mV-v+VT)/(4.*mV))-1.)/ms*(1-m)-0.28*(mV**-1)*(v-VT-40.*mV)/
        (exp((v-VT-40.*mV)/(5.*mV))-1.)/ms*m : 1
    dn/dt = 0.032*(mV**-1)*(15.*mV-v+VT)/
        (exp((15.*mV-v+VT)/(5.*mV))-1.)/ms*(1.-n)-.5*exp((10.*mV-v+VT)/(40.*mV))/ms*n : 1
    dh/dt = 0.128*exp((17.*mV-v+VT)/(18.*mV))/ms*(1.-h)-4./(1+exp((40.*mV-v+VT)/(5.*mV)))/ms*h : 1
    I : amp
    C : farad
    '''
    group = NeuronGroup(N, eqs_HH_2,
                        threshold='v > -40*mV',
                        refractory='v > -40*mV',
                        method='exponential_euler')
    group.v = El
    # initialise with some different capacitances
    group.C = array([0.8, 1, 1.2])*ufarad*cm**-2*area
    statemon = StateMonitor(group, variables=True, record=True)
    # we go back to run_regularly
    group.run_regularly('I = rand()*50*nA', dt=10*ms)
    run(50*ms)
    figure(figsize=(9, 4))
    for l in range(5):
        axvline(l*10, ls='--', c='k')
    axhline(El/mV, ls='-', c='lightgray', lw=3)
    plot(statemon.t/ms, statemon.v.T/mV, '-')
    xlabel('Time (ms)')
    ylabel('v (mV)');
    


    在这里插入图片描述

    所以,运行,但看起来有问题!注射的电流看起来是不同的所有不同的神经元!让我们检查一下:

    plot(statemon.t/ms, statemon.I.T/nA, '-')
    xlabel('Time (ms)')
    ylabel('I (nA)');
    


    在这里插入图片描述

    果然每次都不一样了。但是为什么?我们写的group.run_regularly('I = rand()*50*nA', dt=10*ms)似乎应该给每个神经元相同的价值。但是,与阈值和重置语句一样,代码run_regularly被解释为每个神经元单独运行,并且因为我是一个参数,因此每个神经元可能不同。我们可以通过将我变成一个共享变量来解决这个问题,这意味着它对每个神经元具有相同的值。

    start_scope()
    N = 3
    eqs_HH_3 = '''
    dv/dt = (gl*(El-v) - g_na*(m*m*m)*h*(v-ENa) - g_kd*(n*n*n*n)*(v-EK) + I)/C : volt
    dm/dt = 0.32*(mV**-1)*(13.*mV-v+VT)/
        (exp((13.*mV-v+VT)/(4.*mV))-1.)/ms*(1-m)-0.28*(mV**-1)*(v-VT-40.*mV)/
        (exp((v-VT-40.*mV)/(5.*mV))-1.)/ms*m : 1
    dn/dt = 0.032*(mV**-1)*(15.*mV-v+VT)/
        (exp((15.*mV-v+VT)/(5.*mV))-1.)/ms*(1.-n)-.5*exp((10.*mV-v+VT)/(40.*mV))/ms*n : 1
    dh/dt = 0.128*exp((17.*mV-v+VT)/(18.*mV))/ms*(1.-h)-4./(1+exp((40.*mV-v+VT)/(5.*mV)))/ms*h : 1
    I : amp (shared) # everything is the same except we've added this shared
    C : farad
    '''
    group = NeuronGroup(N, eqs_HH_3,
                        threshold='v > -40*mV',
                        refractory='v > -40*mV',
                        method='exponential_euler')
    group.v = El
    group.C = array([0.8, 1, 1.2])*ufarad*cm**-2*area
    statemon = StateMonitor(group, 'v', record=True)
    group.run_regularly('I = rand()*50*nA', dt=10*ms)
    run(50*ms)
    figure(figsize=(9, 4))
    for l in range(5):
        axvline(l*10, ls='--', c='k')
    axhline(El/mV, ls='-', c='lightgray', lw=3)
    plot(statemon.t/ms, statemon.v.T/mV, '-')
    xlabel('Time (ms)')
    ylabel('v (mV)');
    


    在这里插入图片描述

    Ahh, ,那看起来更像它!

    添加输入

    现在让我们想想神经元是由sinusoidal输入驱动的。让我们回到一个leaky integrate-and-fire模型,以简化方程。

    start_scope()
    A = 2.5
    f = 10*Hz
    tau = 5*ms
    eqs = '''
    dv/dt = (I-v)/tau : 1
    I = A*sin(2*pi*f*t) : 1
    '''
    G = NeuronGroup(1, eqs, threshold='v>1', reset='v=0', method='euler')
    M = StateMonitor(G, variables=True, record=True)
    run(200*ms)
    plot(M.t/ms, M.v[0], label='v')
    plot(M.t/ms, M.I[0], label='I')
    xlabel('Time (ms)')
    ylabel('v')
    legend(loc='best');
    


    在这里插入图片描述

    到目前为止,我们在第一个教程中看到的那种东西。现在,如果输入电流是我们记录并保存在文件中的内容,该怎么办?在这种情况下,我们可以使用 TimedArray。让我们从复制上图开始,但使用TimedArray

    start_scope()
    A = 2.5
    f = 10*Hz
    tau = 5*ms
    # Create a TimedArray and set the equations to use it
    t_recorded = arange(int(200*ms/defaultclock.dt))*defaultclock.dt
    I_recorded = TimedArray(A*sin(2*pi*f*t_recorded), dt=defaultclock.dt)
    eqs = '''
    dv/dt = (I-v)/tau : 1
    I = I_recorded(t) : 1
    '''
    G = NeuronGroup(1, eqs, threshold='v>1', reset='v=0', method='exact')
    M = StateMonitor(G, variables=True, record=True)
    run(200*ms)
    plot(M.t/ms, M.v[0], label='v')
    plot(M.t/ms, M.I[0], label='I')
    xlabel('Time (ms)')
    ylabel('v')
    legend(loc='best');
    


    在这里插入图片描述

    请注意,例如,当我们将sin 函数直接放在方程中时,我们必须使用参数method='euler',因为确切的集成商不会在这里工作(试试看!)但是,在时间步骤中TimedArray被认为是恒定的,因此可以使用线性集成器。这意味着你不会从这两种方法得到相同的行为,原因有二。首先,数字集成方法exacteuler给出的结果略有不同。其次,sin不是一个时间步数不变,而是TimedArray

    现在只是为了显示TimedArray ,适用于任意电流,让我们做一个奇怪的"记录"电流,并运行它。

    start_scope()
    A = 2.5
    f = 10*Hz
    tau = 5*ms
    # Let's create an array that couldn't be
    # reproduced with a formula
    num_samples = int(200*ms/defaultclock.dt)
    I_arr = zeros(num_samples)
    for _ in range(100):
        a = randint(num_samples)
        I_arr[a:a+100] = rand()
    I_recorded = TimedArray(A*I_arr, dt=defaultclock.dt)
    eqs = '''
    dv/dt = (I-v)/tau : 1
    I = I_recorded(t) : 1
    '''
    G = NeuronGroup(1, eqs, threshold='v>1', reset='v=0', method='exact')
    M = StateMonitor(G, variables=True, record=True)
    run(200*ms)
    plot(M.t/ms, M.v[0], label='v')
    plot(M.t/ms, M.I[0], label='I')
    xlabel('Time (ms)')
    ylabel('v')
    legend(loc='best');
    


    在这里插入图片描述

    最后,让我们完成一个实际从文件中读取某些数据的示例。看看您是否能找出这个例子的工作原理。

    start_scope()
    from matplotlib.image import imread
    img = (1-imread('brian.png'))[::-1, :, 0].T
    num_samples, N = img.shape
    ta = TimedArray(img, dt=1*ms) # 228
    A = 1.5
    tau = 2*ms
    eqs = '''
    dv/dt = (A*ta(t, i)-v)/tau+0.8*xi*tau**-0.5 : 1
    '''
    G = NeuronGroup(N, eqs, threshold='v>1', reset='v=0', method='euler')
    M = SpikeMonitor(G)
    run(num_samples*ms)
    plot(M.t/ms, M.i, '.k', ms=3)
    xlim(0, num_samples)
    ylim(0, N)
    xlabel('Time (ms)')
    ylabel('Neuron index');
    

    在这里插入图片描述

    总结

    以上就是本指南的内容和学习过程了,怎样把这个工具用好,用到希望仿真的地方还有很长的路要走。

    欢迎讨论,共同进步。

    展开全文
  • 基于SNN脉冲神经网络的FPGA实现介绍

    千次阅读 2021-12-09 00:35:22
    SNN神经网络系统的开发主要是通过专用芯片、FPGA芯片或者ARM芯片等可编程芯片来实现。但是专用的芯片成本往往较大,ARM芯片的数据处理方式为顺序执行方式,其处理速度较慢,每个时钟周期内完成一个处理任务,而FPGA...
  • 脉冲神经网络(Spiking Neural Network,SNN)概述

    万次阅读 多人点赞 2019-05-24 16:15:48
    主要讨论脉冲神经网络的拓扑结构、信息的脉冲序列编码方法、脉冲神经网络的学习算法和进化方法等。 一. 脉冲神经网络的拓扑结构 同传统的人工神经网络一样,脉冲神经网络同样分为三种拓扑结构。它们分别是前馈型脉冲...
  • 脉冲神经网络SNN)概述

    万次阅读 多人点赞 2019-06-18 08:37:15
    主要讨论脉冲神经网络的拓扑结构、信息的脉冲序列编码方法、脉冲神经网络的学习算法和进化方法等。 一、脉冲神经网络的拓扑结构 同传统的人工神经网络一样,脉冲神经网络同样分为三种拓扑结构。它们分别是前馈型...
  • `timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: ...// Module Name: SNN_IM // Project Name: // Target Devices: // Tool...
  • 简述脉冲神经网络SNN:下一代神经网络

    万次阅读 多人点赞 2018-01-15 06:49:42
    脉冲神经网络SNN)属于第三代神经网络模型,实现了更高级的生物神经模拟水平。除了神经元和突触状态之外,SNN 还将时间概念纳入了其操作之中。本文将简要介绍这种神秘的神经网络形式。 所有对目前机器学习...
  • 脉冲神经网络SNN)属于第三代神经网络模型,实现了更高级的生物神经模拟水平。除了神经元和突触状态之外,SNN 还将时间概念纳入了其操作之中。本文将简要介绍这种神秘的神经网络形式。 所有对目前机器学习有所...
  • 脉冲神经网络的一个训练方法,基于PYTHON3写的,可以直接运行,神经元模型采用简化的脉冲响应模型。采用ASA训练算法

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 439
精华内容 175
关键字:

snn脉冲神经网络