Skip to content

Commit b8898d5

Browse files
author
Alexander Ororbia
committed
minor cleanup/edits to srm predictor co-routines
1 parent 873d2c6 commit b8898d5

2 files changed

Lines changed: 48 additions & 10 deletions

File tree

ngclearn/components/neurons/spiking/LIFSRM.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ def __init__(
7070

7171
## analytical SRM state compartments/variables (NOTE: designed to avoid maintaining explicit spike history tensors)
7272
self.t_last_spike = Compartment(jnp.full((self.batch_size, self.n_units), -1.0))
73+
self.next_spike_t = Compartment(jnp.full((self.batch_size, self.n_units), -1.0))
7374
self.j_lowpass = Compartment(jnp.zeros((self.batch_size, self.n_units))) ## integrated input trace
7475
self.last_t_eval = Compartment(jnp.zeros((self.batch_size, self.n_units))) ## tracks clock index (when evaluated)
7576

@@ -98,9 +99,23 @@ def reset(self):
9899
self.v.set(jnp.full((self.batch_size, self.n_units), self.v_rest))
99100
self.s.set(jnp.zeros((self.batch_size, self.n_units)))
100101
self.t_last_spike.set(jnp.full((self.batch_size, self.n_units), -1.0))
102+
self.next_spike_t.set(jnp.full((self.batch_size, self.n_units), -1.0))
101103
self.j_lowpass.set(jnp.zeros((self.batch_size, self.n_units)))
102104
self.last_t_eval.set(jnp.zeros((self.batch_size, self.n_units)))
103105

106+
@compilable
107+
def predict_next_spike(self, t_start):
108+
next_spike_t = LIFSRM._predict_next_spike( ## call next-spike-time predictor
109+
t_start,
110+
self.t_last_spike.get(),
111+
self.j_lowpass.get(),
112+
self.tau_m,
113+
self.v_rest,
114+
self.v_reset,
115+
self.thr
116+
)
117+
self.next_spike_t.set(next_spike_t) ## store predicted next spike time(s)
118+
104119
@staticmethod
105120
def _evaluate_SRM_filter( ## kernel co-routine
106121
t,
@@ -129,11 +144,11 @@ def _evaluate_SRM_filter( ## kernel co-routine
129144
return v_total, new_j_trace
130145

131146
@staticmethod
132-
def predict_next_spike( ## next-spike-time prediction co-routine
147+
def _predict_next_spike( ## next-spike-time prediction co-routine
133148
t_start, t_last_spike, j_lowpass, tau_m, v_rest, v_reset, thr
134149
):
135-
## co-routine to predict future next spike, takes advantage of an LIF-SRM's
136-
## closed-form setup; specificaly, this function calculates a future (global)
150+
## co-routine predicts future next spike, taking particular advantage of an LIF-SRM's
151+
## closed-form setup; specifically, this function calculates a future (global)
137152
## clock time-stamp as to when this LIF model's decaying voltage would
138153
## cross a firing threshold (note, this does not require step-wise numerical integration)
139154

@@ -160,4 +175,3 @@ def predict_next_spike( ## next-spike-time prediction co-routine
160175
## safety check: if total driving force is insufficient to cross,
161176
## then flag output as "un-triggered" (i.e.,-1.0)
162177
return jnp.where(can_reach_thr, predicted_t, -1.0) # predicted spike time(s)
163-

ngclearn/components/neurons/spiking/RAFSRM.py

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from ngclearn.components.jaxComponent import JaxComponent
2-
from jax import numpy as jnp, jit
2+
from jax import numpy as jnp, jit, lax
33
from ngclearn import compilable, Compartment
44

55

@@ -82,6 +82,7 @@ def __init__(
8282
self.s = Compartment(jnp.zeros((self.batch_size, self.n_units)))
8383
## set up analytical state filters (to match RAFCell construction)
8484
self.t_last_spike = Compartment(jnp.full((self.batch_size, self.n_units), -1.0))
85+
self.next_spike_t = Compartment(jnp.full((self.batch_size, self.n_units), -1.0))
8586
self.j_v = Compartment(jnp.zeros((self.batch_size, self.n_units)))
8687
self.j_w = Compartment(jnp.zeros((self.batch_size, self.n_units)))
8788
self.last_t_eval = Compartment(jnp.zeros((self.batch_size, self.n_units)))
@@ -111,10 +112,26 @@ def reset(self): #
111112
self.v.set(jnp.zeros((self.batch_size, self.n_units)))
112113
self.s.set(jnp.zeros((self.batch_size, self.n_units)))
113114
self.t_last_spike.set(jnp.full((self.batch_size, self.n_units), -1.0))
115+
self.next_spike_t.set(jnp.full((self.batch_size, self.n_units), -1.0))
114116
self.j_v.set(jnp.zeros((self.batch_size, self.n_units)))
115117
self.j_w.set(jnp.zeros((self.batch_size, self.n_units)))
116118
self.last_t_eval.set(jnp.zeros((self.batch_size, self.n_units)))
117119

120+
@compilable
121+
def predict_next_spike(self, t_start):
122+
next_spike_t = RAFSRM._predict_next_spike( ## next-spike-time predictor
123+
t_start,
124+
self.j_v.get(),
125+
self.j_w.get(),
126+
self.tau_v,
127+
self.tau_w,
128+
self.omega,
129+
self.dampen_factor,
130+
self.thr,
131+
max_iters=10
132+
)
133+
self.next_spike_t.set(next_spike_t) ## store predicted next spike time(s)
134+
118135
@staticmethod
119136
def _evaluate_SRM_filter( ## kernel co-routine
120137
t,
@@ -176,11 +193,18 @@ def _evaluate_SRM_filter( ## kernel co-routine
176193
return v_total, new_v, new_w
177194

178195
@staticmethod
179-
def predict_next_spike(
180-
t_start, j_v, j_w, tau_v, tau_w, omega, dampen_factor, thr, max_iters=10
196+
def _predict_next_spike( ## co-routine used to compute when a future spike will occur
197+
t_start,
198+
j_v,
199+
j_w,
200+
tau_v,
201+
tau_w,
202+
omega,
203+
dampen_factor,
204+
thr,
205+
max_iters=10
181206
):
182-
## co-routine used to compute when a future spike will occur
183-
## based on a Newton-Raphson root finding process to predict when exactly
207+
## NOTE: this co-routine is based on a Newton-Raphson root finding process to predict when exactly
184208
## continuous sub-threshold wave equation will cross threshold line
185209

186210
## standardize SRM system parameters
@@ -220,7 +244,7 @@ def scan_body(carry, _): ## set up scanner for this search process
220244
return s_next, None
221245

222246
## execute unrolled iteration passes completely w/in JAX/JIT compiler context
223-
final_s, _ = jax.lax.scan(scan_body, s_guess, None, length=max_iters)
247+
final_s, _ = lax.scan(scan_body, s_guess, None, length=max_iters)
224248
predicted_t = t_start + final_s ## compute absolute (executed) global clock projection coordinate
225249
## employ a safety check:
226250
### if initial slope is negative (or diverging), flag it as un-triggered (i.e., -1.0)

0 commit comments

Comments
 (0)