Closed yilun-wu closed 10 months ago
Thanks again for your question. Conventionally, I do the double filtering for synaptic traces differently when the inputs are spikes so that the jump for spike arrival in the first filter is always one regardless of the time step. However, the alpha trace does not receive spikes as inputs, so this is unnecessary here. I can only assume that I did it out of habit, but frankly, I do not remember off the top of my head. In any case, the only thing it changes is the amplitude of the filter kernel, which can be absorbed in the learning rate. Concerning your second question, why is one filtering done first? This choice was probably unintentional, and the two are approximately the same for small time steps (or long enough time constants). Strictly speaking, all updates should be done simultaneously anyway. However, in Auryn, we deliberately do in-place operations for performance reasons. I will keep your two tickets open until I have time to look into the code again in more detail. But as I already mentioned, it will take me some time. If we confirm discrepancies between the code and our methods, we will issue an erratum.
Thanks heaps again for your careful reading of the code, and let me know if you have any further questions.
Understood. Thank you!
Dear authors, In the implementation for $\alpha * \big(\epsilon * S_j(t)f^{\prime}U_i(t)\big)$ (eq. 18):
https://github.com/fmi-basel/latent-predictive-learning/blob/dd486d092b8cea9bfa1f27f42209f9174b82e61c/spiking_simulations/LPLConnection.cpp#L303-L316
It seems the two exponential filterings of $\alpha$ are done differently:
el_val_flt
using time constanttau_el_decay
throughAurynVectorFloat::follow
: https://github.com/fzenke/auryn/blob/6174a67a56074e8b72a94a763277131f62778713/src/auryn/AurynVector.h#L372-L377el_val
is updated throughadd_to_syntrace( didx, syn_trace_input )
andel_val->scale(scale_const)
.My questions are:
AurynVectorFloat::follow
for both of them?add_to_syntrace
only updates the trace by adding the $\epsilon * S_j(t)f^{\prime}U_i(t)$ before scaling it. This results in the following discrete update I think: $\bar{c}[t+1]=\exp(-dt/\tau)(\bar{c}[t]+c[t])\approx (1-dt/\tau)(\bar{c}[t]+c[t])=(1-dt/\tau)\bar{c}[t]+(1-dt/\tau)c[t]$ According to eq. 21, the discrete update should be: $\bar{c}[t+1]=(1-dt/\tau)\bar{c}[t]+(dt/\tau)c[t]$, which is implemented correctly inAurynVectorFloat::follow
, which renders the inner and outer update scheme different. I am wondering if I am missing something here.