前言
最近一直在看相关的内容,在官网的链接 :
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
。
现在尝试更改上面的单元格中的字符串threshold
和reset
,看看会发生什么。
耐火性(不应期)
神经元模型的一个共同特点是耐火性。这意味着,在神经元发射尖峰后,它会在一定持续时间内变得耐火,在此期间结束之前不能再发射一个尖峰。以下是我们在布莱恩的做事。
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
'''</