Skip to content

Commit 05a3ef3

Browse files
Merge pull request BindsNET#446 from BindsNET/hananel
Neuron ref and monitor optimization
2 parents c1412e8 + 1d882c9 commit 05a3ef3

6 files changed

Lines changed: 40 additions & 22 deletions

File tree

bindsnet/network/monitors.py

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,36 +28,47 @@ def __init__(
2828
state_vars: Iterable[str],
2929
time: Optional[int] = None,
3030
batch_size: int = 1,
31+
device: str = "cpu",
3132
):
3233
# language=rst
3334
"""
3435
Constructs a ``Monitor`` object.
3536
3637
:param obj: An object to record state variables from during network simulation.
37-
:param state_vars: Iterable of strings indicating names of state variables to
38-
record.
38+
:param state_vars: Iterable of strings indicating names of state variables to record.
3939
:param time: If not ``None``, pre-allocate memory for state variable recording.
40+
:param device: Allow the monitor to be on different device separate from Network device
4041
"""
4142
super().__init__()
4243

4344
self.obj = obj
4445
self.state_vars = state_vars
4546
self.time = time
4647
self.batch_size = batch_size
48+
self.device = device
49+
50+
# if time is not specified the monitor variable accumulate the logs
51+
if self.time is None:
52+
self.device = "cpu"
4753

48-
# Deal with time later, the same underlying list is used
49-
self.recording = {v: [] for v in self.state_vars}
54+
self.recording = []
55+
self.reset_state_variables()
5056

5157
def get(self, var: str) -> torch.Tensor:
5258
# language=rst
5359
"""
5460
Return recording to user.
5561
5662
:param var: State variable recording to return.
57-
:return: Tensor of shape ``[time, n_1, ..., n_k]``, where ``[n_1, ..., n_k]`` is
58-
the shape of the recorded state variable.
63+
:return: Tensor of shape ``[time, n_1, ..., n_k]``, where ``[n_1, ..., n_k]`` is the shape of the recorded state
64+
variable.
65+
Note, if time == `None`, get return the logs and empty the monitor variable
66+
5967
"""
60-
return torch.cat(self.recording[var], 0)
68+
return_logs = torch.cat(self.recording[var], 0)
69+
if self.time is None:
70+
self.recording[var] = []
71+
return return_logs
6172

6273
def record(self) -> None:
6374
# language=rst
@@ -66,20 +77,27 @@ def record(self) -> None:
6677
"""
6778
for v in self.state_vars:
6879
data = getattr(self.obj, v).unsqueeze(0)
69-
self.recording[v].append(data.detach().clone())
70-
71-
# remove the oldest element (first in the list)
72-
if self.time is not None:
73-
for v in self.state_vars:
74-
if len(self.recording[v]) > self.time:
75-
self.recording[v].pop(0)
80+
# self.recording[v].append(data.detach().clone().to(self.device))
81+
self.recording[v].append(
82+
torch.empty_like(data, device=self.device, requires_grad=False).copy_(
83+
data, non_blocking=True
84+
)
85+
)
86+
# remove the oldest element (first in the list)
87+
if self.time is not None:
88+
self.recording[v].pop(0)
7689

7790
def reset_state_variables(self) -> None:
7891
# language=rst
7992
"""
80-
Resets recordings to empty ``torch.Tensor``s.
93+
Resets recordings to empty ``List``s.
8194
"""
82-
self.recording = {v: [] for v in self.state_vars}
95+
if self.time is None:
96+
self.recording = {v: [] for v in self.state_vars}
97+
else:
98+
self.recording = {
99+
v: [[] for i in range(self.time)] for v in self.state_vars
100+
}
83101

84102

85103
class NetworkMonitor(AbstractMonitor):

bindsnet/network/nodes.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ class LIFNodes(Nodes):
420420
# language=rst
421421
"""
422422
Layer of `leaky integrate-and-fire (LIF) neurons
423-
<http://icwww.epfl.ch/~gerstner/SPNM/node26.html#SECTION02311000000000000000>`_.
423+
<http://web.archive.org/web/20190318204706/http://icwww.epfl.ch/~gerstner/SPNM/node26.html#SECTION02311000000000000000>`_.
424424
"""
425425

426426
def __init__(
@@ -683,7 +683,7 @@ class CurrentLIFNodes(Nodes):
683683
# language=rst
684684
"""
685685
Layer of `current-based leaky integrate-and-fire (LIF) neurons
686-
<http://icwww.epfl.ch/~gerstner/SPNM/node26.html#SECTION02313000000000000000>`_.
686+
<http://web.archive.org/web/20190318204706/http://icwww.epfl.ch/~gerstner/SPNM/node26.html#SECTION02313000000000000000>`_.
687687
Total synaptic input current is modeled as a decaying memory of input spikes multiplied by synaptic strengths.
688688
"""
689689

@@ -1148,7 +1148,7 @@ def set_batch_size(self, batch_size) -> None:
11481148
class IzhikevichNodes(Nodes):
11491149
# language=rst
11501150
"""
1151-
Layer of Izhikevich neurons.
1151+
Layer of `Izhikevich neurons<https://www.izhikevich.org/publications/spikes.htm>`_.
11521152
"""
11531153

11541154
def __init__(

bindsnet/network/topology.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ def __init__(
160160
w = self.wmin + torch.rand(source.n, target.n) * (self.wmax - self.wmin)
161161
else:
162162
if self.wmin != -np.inf or self.wmax != np.inf:
163-
w = torch.clamp(w, self.wmin, self.wmax)
163+
w = torch.clamp(torch.as_tensor(w), self.wmin, self.wmax)
164164

165165
self.w = Parameter(w, requires_grad=False)
166166

@@ -381,10 +381,10 @@ def normalize(self) -> None:
381381
if self.norm is not None:
382382
# get a view and modify in place
383383
w = self.w.view(
384-
self.w.size(0) * self.w.size(1), self.w.size(2) * self.w.size(3)
384+
self.w.shape[0] * self.w.shape[1], self.w.shape[2] * self.w.shape[3]
385385
)
386386

387-
for fltr in range(w.size(0)):
387+
for fltr in range(w.shape[0]):
388388
w[fltr] *= self.norm / w[fltr].sum(0)
389389

390390
def reset_state_variables(self) -> None:
9.71 KB
Loading
17.5 KB
Loading
325 KB
Loading

0 commit comments

Comments
 (0)