(Brette, et, al., 2007) COBA-HH

Colab Open in Kaggle

Implementation of the paper:

  • Brette, R., Rudolph, M., Carnevale, T., Hines, M., Beeman, D., Bower, J. M., et al. (2007), Simulation of networks of spiking neurons: a review of tools and strategies., J. Comput. Neurosci., 23, 3, 349–98

which is based on the balanced network proposed by:

  • Vogels, T. P. and Abbott, L. F. (2005), Signal propagation and logic gating in networks of integrate-and-fire neurons., J. Neurosci., 25, 46, 10786–95

Authors:

[1]:
import brainpy as bp
import brainpy.math as bm
import numpy as np

bp.math.set_platform('cpu')
[2]:
bp.__version__
[2]:
'2.4.4.post1'

Parameters

[3]:
num_exc = 3200
num_inh = 800
Cm = 200  # Membrane Capacitance [pF]

gl = 10.  # Leak Conductance   [nS]
g_Na = 20. * 1000
g_Kd = 6. * 1000  # K Conductance      [nS]
El = -60.  # Resting Potential [mV]
ENa = 50.  # reversal potential (Sodium) [mV]
EK = -90.  # reversal potential (Potassium) [mV]
VT = -63.
V_th = -20.

# Time constants
taue = 5.  # Excitatory synaptic time constant [ms]
taui = 10.  # Inhibitory synaptic time constant [ms]

# Reversal potentials
Ee = 0.  # Excitatory reversal potential (mV)
Ei = -80.  # Inhibitory reversal potential (Potassium) [mV]

# excitatory synaptic weight
we = 6.  # excitatory synaptic conductance [nS]

# inhibitory synaptic weight
wi = 67.  # inhibitory synaptic conductance [nS]

Implementation 1

[4]:
class HH(bp.dyn.NeuDyn):
  def __init__(self, size, method='exp_auto'):
    super(HH, self).__init__(size)

    # variables
    self.V = bm.Variable(El + (bm.random.randn(self.num) * 5 - 5))
    self.m = bm.Variable(bm.zeros(self.num))
    self.n = bm.Variable(bm.zeros(self.num))
    self.h = bm.Variable(bm.zeros(self.num))
    self.spike = bm.Variable(bm.zeros(self.num, dtype=bool))
    self.input = bm.Variable(bm.zeros(size))

    def dV(V, t, m, h, n, Isyn):
      gna = g_Na * (m * m * m) * h
      gkd = g_Kd * (n * n * n * n)
      dVdt = (-gl * (V - El) - gna * (V - ENa) - gkd * (V - EK) + Isyn) / Cm
      return dVdt

    def dm(m, t, V, ):
      m_alpha = 0.32 * (13 - V + VT) / (bm.exp((13 - V + VT) / 4) - 1.)
      m_beta = 0.28 * (V - VT - 40) / (bm.exp((V - VT - 40) / 5) - 1)
      dmdt = (m_alpha * (1 - m) - m_beta * m)
      return dmdt

    def dh(h, t, V):
      h_alpha = 0.128 * bm.exp((17 - V + VT) / 18)
      h_beta = 4. / (1 + bm.exp(-(V - VT - 40) / 5))
      dhdt = (h_alpha * (1 - h) - h_beta * h)
      return dhdt

    def dn(n, t, V):
      c = 15 - V + VT
      n_alpha = 0.032 * c / (bm.exp(c / 5) - 1.)
      n_beta = .5 * bm.exp((10 - V + VT) / 40)
      dndt = (n_alpha * (1 - n) - n_beta * n)
      return dndt

    # functions
    self.integral = bp.odeint(bp.JointEq([dV, dm, dh, dn]), method=method)

  def update(self):
    tdi = bp.share.get_shargs()
    V, m, h, n = self.integral(self.V, self.m, self.h, self.n, tdi.t, Isyn=self.input, dt=tdi.dt)
    self.spike.value = bm.logical_and(self.V < V_th, V >= V_th)
    self.m.value = m
    self.h.value = h
    self.n.value = n
    self.V.value = V
    self.input[:] = 0.
[5]:
class ExpCOBA(bp.synapses.TwoEndConn):
  def __init__(self, pre, post, conn, g_max=1., delay=0., tau=8.0, E=0.,
               method='exp_auto'):
    super(ExpCOBA, self).__init__(pre=pre, post=post, conn=conn)
    self.check_pre_attrs('spike')
    self.check_post_attrs('input', 'V')

    # parameters
    self.E = E
    self.tau = tau
    self.delay = delay
    self.g_max = g_max
    self.pre2post = self.conn.require('pre2post')

    # variables
    self.g = bm.Variable(bm.zeros(self.post.num))

    # function
    self.integral = bp.odeint(lambda g, t: -g / self.tau, method=method)

  def update(self):
    self.g.value = self.integral(self.g, bp.share['t'], dt=bp.share['dt'])
    post_sps = bm.pre2post_event_sum(self.pre.spike, self.pre2post, self.post.num, self.g_max)
    self.g.value += post_sps
    self.post.input += self.g * (self.E - self.post.V)
d:\codes\projects\brainpy\brainpy\_src\deprecations.py:86: DeprecationWarning: brainpy.TwoEndConn is deprecated. Use brainpy.synapses.TwoEndConn instead.
  _deprecate(message)
[6]:
class COBAHH(bp.Network):
  def __init__(self, scale=1., method='exp_auto'):
    num_exc = int(3200 * scale)
    num_inh = int(800 * scale)
    E = HH(num_exc, method=method)
    I = HH(num_inh, method=method)
    E2E = ExpCOBA(pre=E, post=E, conn=bp.conn.FixedProb(prob=0.02),
                  E=Ee, g_max=we / scale, tau=taue, method=method)
    E2I = ExpCOBA(pre=E, post=I, conn=bp.conn.FixedProb(prob=0.02),
                  E=Ee, g_max=we / scale, tau=taue, method=method)
    I2E = ExpCOBA(pre=I, post=E, conn=bp.conn.FixedProb(prob=0.02),
                  E=Ei, g_max=wi / scale, tau=taui, method=method)
    I2I = ExpCOBA(pre=I, post=I, conn=bp.conn.FixedProb(prob=0.02),
                  E=Ei, g_max=wi / scale, tau=taui, method=method)

    super(COBAHH, self).__init__(E2E, E2I, I2I, I2E, E=E, I=I)
[7]:
net = COBAHH()
[8]:
runner = bp.DSRunner(net, monitors=['E.spike'])
t = runner.run(100.)
[9]:
bp.visualize.raster_plot(runner.mon.ts, runner.mon['E.spike'], show=True)
../_images/ei_nets_Brette_2007_COBAHH_12_0.png

Implementation 2

[10]:
class HH2(bp.dyn.CondNeuGroupLTC):
  def __init__(self, size):
    super(HH2, self).__init__(size)
    self.INa = bp.channels.INa_TM1991(size, g_max=100., V_sh=-63.)
    self.IK = bp.channels.IK_TM1991(size, g_max=30., V_sh=-63.)
    self.IL = bp.channels.IL(size, E=-60., g_max=0.05)
[11]:
class EINet_v2(bp.DynSysGroup):
  def __init__(self, scale=1.):
    super(EINet_v2, self).__init__()

    prob = 0.02
    self.num_exc = int(3200 * scale)
    self.num_inh = int(800 * scale)

    self.N = HH2(self.num_exc + self.num_inh)
    self.Esyn = bp.synapses.Exponential(self.N[:self.num_exc],
                                        self.N,
                                        bp.conn.FixedProb(prob),
                                        g_max=0.03 / scale, tau=5,
                                        output=bp.synouts.COBA(E=0.))
    self.Isyn = bp.synapses.Exponential(self.N[self.num_exc:],
                                        self.N,
                                        bp.conn.FixedProb(prob),
                                        g_max=0.335 / scale, tau=10.,
                                        output=bp.synouts.COBA(E=-80))
[12]:
net = EINet_v2(scale=1)
runner = bp.DSRunner(net, monitors={'spikes': net.N.spike})
runner.run(100.)
bp.visualize.raster_plot(runner.mon.ts, runner.mon['spikes'], show=True)
../_images/ei_nets_Brette_2007_COBAHH_16_1.png

New version (brainpy>=2.4.0)

[13]:
class ExponCOBA(bp.Projection):
  def __init__(self, num_pre, post, prob, g_max, tau, E):
    super().__init__()

    self.proj = bp.dyn.ProjAlignPostMg1(
      comm=bp.dnn.EventCSRLinear(bp.conn.FixedProb(prob, pre=num_pre, post=post.num), g_max),
      syn=bp.dyn.Expon.desc(size=post.num, tau=tau),
      out=bp.dyn.COBA.desc(E=E),
      post=post
    )

  def update(self, sps):
    return self.proj(sps)
[14]:
class EINet_v3(bp.DynSysGroup):
  def __init__(self, scale=1.):
    super().__init__()

    self.num_exc = int(3200 * scale)
    self.num_inh = int(800 * scale)

    self.N = HH2(self.num_exc + self.num_inh)
    self.Esyn = ExponCOBA(self.num_exc, self.N, 0.02, g_max=0.03 / scale, tau=5, E=0.)
    self.Isyn = ExponCOBA(self.num_inh, self.N, 0.02,  g_max=0.335 / scale, tau=10., E=-80)

  def update(self):
    # update E inputs
    e_sps = self.N.spike[:self.num_exc]
    self.Esyn(e_sps)

    # update I inputs
    i_sps = self.N.spike[self.num_exc:]
    self.Isyn(i_sps)

    # update neurons
    self.N()

    # monitor
    return self.N.spike
[15]:
net = EINet_v3(scale=1)
indices = np.arange(1000) # 100 ms
sps = bm.for_loop(net.step_run, indices, progress_bar=True)
bp.visualize.raster_plot(indices * bm.get_dt(), sps, show=True)
../_images/ei_nets_Brette_2007_COBAHH_20_1.png
[35]: