Skip to content

Commit 65a5bb5

Browse files
authored
Merge branch 'brainpy:master' into master
2 parents b9f818f + c89bffa commit 65a5bb5

26 files changed

+2940
-467
lines changed

.github/workflows/docker.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ jobs:
3535

3636
- name: Login to DockerHub
3737
if: github.event_name != 'pull_request'
38-
uses: docker/login-action@v2
38+
uses: docker/login-action@v3
3939
with:
4040
username: ${{ secrets.DOCKERHUB_USERNAME }}
4141
password: ${{ secrets.DOCKERHUB_TOKEN }}
4242

4343
- name: Docker Build & Push (version tag)
44-
uses: docker/build-push-action@v4
44+
uses: docker/build-push-action@v5
4545
with:
4646
context: ${{ matrix.context }}
4747
tags: ${{ matrix.base }}:${{ env.DOCKER_TAG_NAME }}
@@ -51,7 +51,7 @@ jobs:
5151
- name: Docker Build & Push (latest tag)
5252
if: |
5353
(github.event_name == 'release' && ! github.event.release.prerelease)
54-
uses: docker/build-push-action@v4
54+
uses: docker/build-push-action@v5
5555
with:
5656
context: ${{ matrix.context }}
5757
tags: ${{ matrix.base }}:latest

README.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,25 @@ BrainPy is a flexible, efficient, and extensible framework for computational neu
2828
BrainPy is based on Python (>=3.8) and can be installed on Linux (Ubuntu 16.04 or later), macOS (10.12 or later), and Windows platforms. Install the latest version of BrainPy:
2929

3030
```bash
31-
$ pip install brainpy brainpylib -U
31+
$ pip install brainpy -U
32+
```
33+
34+
In addition, many customized operators in BrainPy are implemented in ``brainpylib``.
35+
Install the latest version of `brainpylib` by:
36+
37+
```bash
38+
# CPU installation for Linux, macOS and Windows
39+
$ pip install --upgrade brainpylib
40+
```
41+
42+
```bash
43+
# CUDA 12 installation for Linux only
44+
$ pip install --upgrade brainpylib-cu12x
45+
```
46+
47+
```bash
48+
# CUDA 11 installation for Linux only
49+
$ pip install --upgrade brainpylib-cu11x
3250
```
3351

3452
For detailed installation instructions, please refer to the documentation: [Quickstart/Installation](https://brainpy.readthedocs.io/en/latest/quickstart/installation.html)

brainpy/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# -*- coding: utf-8 -*-
22

33
__version__ = "2.4.4.post4"
4+
_minimal_brainpylib_version = '0.1.10'
45

56
# fundamental supporting modules
67
from brainpy import errors, check, tools
@@ -11,6 +12,15 @@
1112
except ModuleNotFoundError:
1213
raise ModuleNotFoundError(tools.jaxlib_install_info) from None
1314

15+
16+
try:
17+
import brainpylib
18+
if brainpylib.__version__ < _minimal_brainpylib_version:
19+
raise SystemError(f'This version of brainpy ({__version__}) needs brainpylib >= {_minimal_brainpylib_version}.')
20+
del brainpylib
21+
except ModuleNotFoundError:
22+
pass
23+
1424
# Part: Math Foundation #
1525
# ----------------------- #
1626

brainpy/_src/analysis/utils/model.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,11 @@ def update(self):
135135
self.implicit_vars[key].update(intg(*all_vars, *self.pars, dt=share['dt']))
136136

137137
def __getattr__(self, item):
138-
child_vars = super(TrajectModel, self).__getattribute__('implicit_vars')
138+
child_vars = super().__getattribute__('implicit_vars')
139139
if item in child_vars:
140140
return child_vars[item]
141141
else:
142-
return super(TrajectModel, self).__getattribute__(item)
142+
return super().__getattribute__(item)
143143

144144
def run(self, duration):
145145
self.runner.run(duration)

brainpy/_src/delay.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -375,10 +375,6 @@ def reset_state(self, batch_size: int = None):
375375
# initialize delay data
376376
if self.data is not None:
377377
self._init_data(self.max_length, batch_size)
378-
for cls in self.before_updates.values():
379-
cls.reset_state(batch_size)
380-
for cls in self.after_updates.values():
381-
cls.reset_state(batch_size)
382378

383379
def _init_data(self, length: int, batch_size: int = None):
384380
if batch_size is not None:
@@ -468,13 +464,16 @@ def __init__(
468464
*indices
469465
):
470466
super().__init__(mode=delay.mode)
471-
self.delay = delay
467+
self.refs = {'delay': delay}
472468
assert isinstance(delay, Delay)
473469
delay.register_entry(self.name, time)
474470
self.indices = indices
475471

476472
def update(self):
477-
return self.delay.at(self.name, *self.indices)
473+
return self.refs['delay'].at(self.name, *self.indices)
474+
475+
def reset_state(self, *args, **kwargs):
476+
pass
478477

479478

480479
def init_delay_by_return(info: Union[bm.Variable, ReturnInfo]) -> Delay:

brainpy/_src/dnn/linear.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class Dense(Layer, SupportOnline, SupportOffline, SupportSTDP):
4444
The number of the input feature. A positive integer.
4545
num_out: int
4646
The number of the output features. A positive integer.
47-
weight_initializer: optional, Initializer
47+
W_initializer: optional, Initializer
4848
The weight initialization.
4949
b_initializer: optional, Initializer
5050
The bias initialization.

brainpy/_src/dyn/projections/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
from .aligns import *
33
from .conn import *
44
from .others import *
5+
from .inputs import *
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
from typing import Optional, Any
2+
3+
from brainpy import math as bm
4+
from brainpy._src.dynsys import Dynamic
5+
from brainpy._src.mixin import SupportAutoDelay
6+
from brainpy.types import Shape
7+
8+
__all__ = [
9+
'InputVar',
10+
]
11+
12+
13+
class InputVar(Dynamic, SupportAutoDelay):
14+
"""Define an input variable.
15+
16+
Example::
17+
18+
import brainpy as bp
19+
20+
21+
class Exponential(bp.Projection):
22+
def __init__(self, pre, post, prob, g_max, tau, E=0.):
23+
super().__init__()
24+
self.proj = bp.dyn.ProjAlignPostMg2(
25+
pre=pre,
26+
delay=None,
27+
comm=bp.dnn.EventCSRLinear(bp.conn.FixedProb(prob, pre=pre.num, post=post.num), g_max),
28+
syn=bp.dyn.Expon.desc(post.num, tau=tau),
29+
out=bp.dyn.COBA.desc(E=E),
30+
post=post,
31+
)
32+
33+
34+
class EINet(bp.DynSysGroup):
35+
def __init__(self, num_exc, num_inh, method='exp_auto'):
36+
super(EINet, self).__init__()
37+
38+
# neurons
39+
pars = dict(V_rest=-60., V_th=-50., V_reset=-60., tau=20., tau_ref=5.,
40+
V_initializer=bp.init.Normal(-55., 2.), method=method)
41+
self.E = bp.dyn.LifRef(num_exc, **pars)
42+
self.I = bp.dyn.LifRef(num_inh, **pars)
43+
44+
# synapses
45+
w_e = 0.6 # excitatory synaptic weight
46+
w_i = 6.7 # inhibitory synaptic weight
47+
48+
# Neurons connect to each other randomly with a connection probability of 2%
49+
self.E2E = Exponential(self.E, self.E, 0.02, g_max=w_e, tau=5., E=0.)
50+
self.E2I = Exponential(self.E, self.I, 0.02, g_max=w_e, tau=5., E=0.)
51+
self.I2E = Exponential(self.I, self.E, 0.02, g_max=w_i, tau=10., E=-80.)
52+
self.I2I = Exponential(self.I, self.I, 0.02, g_max=w_i, tau=10., E=-80.)
53+
54+
# define input variables given to E/I populations
55+
self.Ein = bp.dyn.InputVar(self.E.varshape)
56+
self.Iin = bp.dyn.InputVar(self.I.varshape)
57+
self.E.add_inp_fun('', self.Ein)
58+
self.I.add_inp_fun('', self.Iin)
59+
60+
61+
net = EINet(3200, 800, method='exp_auto') # "method": the numerical integrator method
62+
runner = bp.DSRunner(net, monitors=['E.spike', 'I.spike'], inputs=[('Ein.input', 20.), ('Iin.input', 20.)])
63+
runner.run(100.)
64+
65+
# visualization
66+
bp.visualize.raster_plot(runner.mon.ts, runner.mon['E.spike'],
67+
title='Spikes of Excitatory Neurons', show=True)
68+
bp.visualize.raster_plot(runner.mon.ts, runner.mon['I.spike'],
69+
title='Spikes of Inhibitory Neurons', show=True)
70+
71+
72+
"""
73+
def __init__(
74+
self,
75+
size: Shape,
76+
keep_size: bool = False,
77+
sharding: Optional[Any] = None,
78+
name: Optional[str] = None,
79+
mode: Optional[bm.Mode] = None,
80+
method: str = 'exp_auto'
81+
):
82+
super().__init__(size=size, keep_size=keep_size, sharding=sharding, name=name, mode=mode, method=method)
83+
84+
self.reset_state(self.mode)
85+
86+
def reset_state(self, batch_or_mode=None):
87+
self.input = self.init_variable(bm.zeros, batch_or_mode)
88+
89+
def update(self, *args, **kwargs):
90+
return self.input.value
91+
92+
def return_info(self):
93+
return self.input
94+
95+
def clear_input(self, *args, **kwargs):
96+
self.reset_state(self.mode)

brainpy/_src/dyn/projections/plasticity.py

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ class STDP_Song2000(Projection):
4040
where :math:`t_{sp}` denotes the spike time and :math:`A_1` is the increment
4141
of :math:`A_{pre}`, :math:`A_2` is the increment of :math:`A_{post}` produced by a spike.
4242
43-
Example::
43+
Here is an example of the usage of this class::
44+
4445
import brainpy as bp
4546
import brainpy.math as bm
4647
@@ -138,10 +139,7 @@ def __init__(
138139
if not post.has_bef_update(self._post_repr):
139140
syn_cls = syn()
140141
out_cls = out()
141-
if out_label is None:
142-
out_name = self.name
143-
else:
144-
out_name = f'{out_label} // {self.name}'
142+
out_name = self.name if out_label is None else f'{out_label} // {self.name}'
145143
post.add_inp_fun(out_name, out_cls)
146144
post.add_bef_update(self._post_repr, _AlignPost(syn_cls, out_cls))
147145
# references
@@ -154,35 +152,29 @@ def __init__(
154152
# synapse initialization
155153
self._syn_id = f'Delay({str(delay)}) // {syn.identifier}'
156154
if not delay_cls.has_bef_update(self._syn_id):
157-
# delay
158155
delay_access = DelayAccess(delay_cls, delay)
159-
# synapse
160156
syn_cls = syn()
161-
# add to "after_updates"
162157
delay_cls.add_bef_update(self._syn_id, _AlignPreMg(delay_access, syn_cls))
163-
164158
# output initialization
165-
if out_label is None:
166-
out_name = self.name
167-
else:
168-
out_name = f'{out_label} // {self.name}'
159+
out_name = self.name if out_label is None else f'{out_label} // {self.name}'
169160
post.add_inp_fun(out_name, out)
170-
171161
# references
172162
self.refs = dict(pre=pre, post=post) # invisible to `self.nodes()`
173163
self.refs['delay'] = delay_cls.get_bef_update(self._syn_id)
174164
self.refs['syn'] = delay_cls.get_bef_update(self._syn_id).syn
175165
self.refs['out'] = out
176166

177-
self.refs['pre_trace'] = self.calculate_trace(pre, delay, Expon.desc(pre.num, tau=tau_s))
178-
self.refs['post_trace'] = self.calculate_trace(post, None, Expon.desc(post.num, tau=tau_t))
179-
# parameters
167+
# trace initialization
168+
self.refs['pre_trace'] = self._init_trace(pre, delay, Expon.desc(pre.num, tau=tau_s))
169+
self.refs['post_trace'] = self._init_trace(post, None, Expon.desc(post.num, tau=tau_t))
170+
171+
# synapse parameters
180172
self.tau_s = parameter(tau_s, sizes=self.pre_num)
181173
self.tau_t = parameter(tau_t, sizes=self.post_num)
182174
self.A1 = parameter(A1, sizes=self.pre_num)
183175
self.A2 = parameter(A2, sizes=self.post_num)
184176

185-
def calculate_trace(
177+
def _init_trace(
186178
self,
187179
target: DynamicalSystem,
188180
delay: Union[None, int, float],
@@ -234,5 +226,5 @@ def update(self):
234226
if issubclass(self.syn.cls, AlignPost):
235227
self.refs['syn'].add_current(current) # synapse post current
236228
else:
237-
self.refs['out'].bind_cond(current)
229+
self.refs['out'].bind_cond(current) # align pre
238230
return current

brainpy/_src/dyn/projections/tests/test_STDP.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,4 @@ def run(i, I_pre, I_post):
5151

5252
indices = bm.arange(0, duration, bm.dt)
5353
bm.for_loop(run, [indices, I_pre, I_post], jit=True)
54+
bm.clear_buffer_memory()

0 commit comments

Comments
 (0)