nest / nest-simulator

The NEST simulator
http://www.nest-simulator.org
GNU General Public License v2.0
532 stars 361 forks source link

Problems with stdp_synapse weight update #1604

Open golosio opened 4 years ago

golosio commented 4 years ago

The synaptic weight should decrease when presynaptic spike time > postsynaptic spike time However, in simple pynest scripts it seems that things go in the opposite way with stdp_synapse. Furthermore, it seems that the first pre-post couple is always lost, i.e. the update always starts from the second pre-post couple. Comparison with theoretical calculation shows that the weight increases as if post-pre is inverted, and the update starts from the second pre-post couple, missing the first one. stdp.py.zip

clinssen commented 4 years ago

Some confusion might arise because the word "delay" is used ambiguously in NEST Simulator. Intuitively we expect this to be an axonal delay (time from presynaptic neuron firing until time of spike arrival at the synapse), but actually it typically refers to the dendritic delay (time from spike arrival at the synapse to time at which the spike has an effect on the membrane potential).

With this interpretation, from the perspective of the STDP synapse in your example, the spike arrival actually occurs as pre-before-post, so the synapse is potentiated, as observed. No spikes should be "lost" regardless of the timing.

Please let us know if you continue to observe any behaviour that is not explained by the interpretation of delays as purely dendritic.

golosio commented 4 years ago

Thank you for your email and for your interest in this issue. However unfortunately I'm afraid that the interpretation of delays as dendritic does not solve the issue. I really hope I made some mistake or I misinterpreted the results. In my example, the presynaptic neuron spike has a negligible effect on the postsynaptic potential, since the weight is intentionally very small. For sure it does not induce or contribute to a subsequent spike. The spikes are due to the constant input currents. Indeed, It can be verified that the presynaptic and postsynaptic neurons fire EXACTLY at the same times, with intervals of 250 ms, much greater than the synaptic delay. This is an expected behavior, since the two neurons have the same parameters and the same input current, and the time discretization compensates for the very small change of postsynaptic potential due to the input spike. Most importantly, the script that I uploaded is not simply a qualitative check on whether the presynaptic spike arrival occurs before or after the post synaptic spike. It is a quantitative comparison with the theoretical computation of STDP weight update. This comparison shows that the updated weight is compatible, within 7 digits, with the theoretical calculation made using a difference time_post-time_pre equal to the synaptic delay, with POSITIVE sign. To be more specific, say that I choose a delay of 10 ms. The updated weight is consistent with the STDP update formula for a presynaptic spike time smaller than the postsynaptic spike time by 10 ms, leading to a synaptic weight increase. The dendritic delay interpretation does not explain this result: the two neurons fire at the same time, so for sure the presynaptic spike cannot reach the synapse BEFORE the postsynaptic spike by 10 ms.

golosio commented 4 years ago

I get consistent results if I change the sign of dendritic_delay in models/stdp_connection.h ,

243c243
<   target->get_history( t_lastspike_ - dendritic_delay, t_spike - dendritic_delay, &start, &finish );
>   target->get_history( t_lastspike_ + dendritic_delay, t_spike + dendritic_delay, &start, &finish );
248c248
<     minus_dt = t_lastspike_ - ( start->t_ + dendritic_delay );
>     minus_dt = t_lastspike_ + dendritic_delay - start->t_; 
256c256
<   const double _K_value = target->get_K_value( t_spike - dendritic_delay );
>   const double _K_value = target->get_K_value( t_spike + dendritic_delay );

or alternatively if I assume that the "delay "parameter in stdp_synapse refers to the time the postsynaptic action potential takes to travel "backward" through the dendrites until it reaches the input synapse. Please let me know if the latter is the intended behavior. If this is the case, I must say yes, it is really confusing, also because I would expect in most cases the axonal delay to be larger. Furthermore, I have to say that while the fix to the dendritic_delay sign completely solves the issue, the interpretation of the delay as "backward propagation time of the postsynaptic action potential through the dendrites" does not solve the problem that the first couple of pre-post spikes is always lost.

clinssen commented 4 years ago

This interpretation of the delays is indeed correct. I agree that we should make this more clear in the documentation.

As for the first pair being "lost": might this be due to another implementation quirk? In NEST, for performance reasons, the weight is only updated when a presynaptic spike is received by the synapse. Postsynaptic spikes are buffered (from the perspective of the synapse), and only result in a weight update at the time that the next presynaptic spike arrives. This is entirely consistent on a network dynamics level, but if you start inspecting weight values at arbitrary times during the simulation, you might hit a not-yet-updated value, making it seem wrong.

golosio commented 4 years ago

Thank you Charl. I made a drawing that in my opinion clarifies the intended behavior. synaptic_post_pre_diff.pdf In NEST, the value of the stdp_synapse "delay" parameter is assigned to the variable dendritic_delay, which corresponds to what is called Dt_post in the drawing. Most users will assume "delay" to represent the axonal delay. In my opinion it would not be sufficient to make this more clear in the documentation, a modification of the code would be appropriate. I suggest two possible modifications: 1) If the increase in memory requirements for having one more parameter is not an issue, use two delay parameters, e.g. "axonal_delay" (or simply "delay", because this is what most users expect to be the meaning of the delay parameter) and "pspd_delay" (postsynaptic potential dendritic delay). 2) If the increase in memory requirement is an issue, considering that what really matters is the difference Dt_pre - Dt_post , let the parameter "delay" represent this difference, i.e. the difference between the axonal delay and the time it takes for the postsynaptic action potential to propagate bacward through the dendrite. The current NEST behavior, which neglects axonal delay, could be obtained by setting "delay" to a negative value, equal to -Dt_post. The behavior that most users expects could be obtained by setting "delay" equal to Dt_pre, i.e. the axonal delay. EDIT: from the following comment it seems that solution 2) would not be appropriate, because while for STDP weight update only the difference Dt_pre - Dt_post is relevant, for evaluating the time when the dg_exc variable of synaptic conductance should be modified by a spike the relevant delay is Dt_pre (the axonal delay), so the only appropriate solution seems to be solution 1)

golosio commented 4 years ago

I must add that when the target neuron of the stdp synapse is a conductance-based model, the time when the synaptic conductance is modified (i.e. when dg_exc is increased) due to an incoming spike is evaluated as the time of the presynaptic spike plus the "delay" parameter. This use of the delay parameter is not consistent with the dendritic delay interpretation.

github-actions[bot] commented 3 years ago

Issue automatically marked stale!

heplesser commented 1 year ago

@JanVogelsang Could you take a look at this?

JanVogelsang commented 1 year ago

What Charl said is correct and as Bruno said, we will need an implementation with both dendritic and axonal delays. And I can promise, we will soon have one, in combination with a nice thesis explaining all the details of delays in neural simulators, with a special focus on synaptic plasticity.