NEST main@caf0ae8
 
Loading...
Searching...
No Matches
eprop_synapse.h
Go to the documentation of this file.
1/*
2 * eprop_synapse.h
3 *
4 * This file is part of NEST.
5 *
6 * Copyright (C) 2004 The NEST Initiative
7 *
8 * NEST is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * NEST is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with NEST. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#ifndef EPROP_SYNAPSE_H
24#define EPROP_SYNAPSE_H
25
26// nestkernel
27#include "connection.h"
28#include "connector_base.h"
30#include "target_identifier.h"
31#include "weight_optimizer.h"
32
33namespace nest
34{
35
36/* BeginUserDocs: synapse, abstract, learning, Bellec, e-prop plasticity, 3-factor
37
38Short description
39+++++++++++++++++
40
41Synapse type for e-prop plasticity
42
43Description
44+++++++++++
45
46``eprop_synapse`` is an implementation of a connector model to create synapses between postsynaptic
47neurons :math:`j` and presynaptic neurons and :math:`i` for eligibility propagation (e-prop) plasticity.
48
49E-prop plasticity was originally introduced and implemented in TensorFlow in :footcite:p:`Bellec2020`.
50
51The e-prop synapse triggers the calculation of the gradient at each spike
52over an interval that begins at the previous spike and ends at a cutoff specified by the user or the
53current spike, depending on which of the two time points is earlier.
54The gradient calculation is specific to the post-synaptic neuron and thus defined there.
55
56Eventually, it optimizes the weight with the specified optimizer.
57
58E-prop synapses require archiving of continuous quantities. Therefore e-prop
59synapses can only be connected to neuron models that are capable of
60archiving. So far, compatible models are ``eprop_iaf``, ``eprop_iaf_psc_delta``, ``eprop_iaf_psc_delta_adapt``,
61``eprop_iaf_adapt``, and ``eprop_readout``.
62
63For more information, see the following topics:
64
65* other e-prop plasticity models:
66
67 * :doc:`eprop_iaf<../models/eprop_iaf/>`
68 * :doc:`eprop_iaf_adapt<../models/eprop_iaf_adapt/>`
69 * :doc:`eprop_readout<../models/eprop_readout/>`
70 * :doc:`eprop_learning_signal_connection<../models/eprop_learning_signal_connection/>`
71
72* :doc:`weight optimizer<../models/weight_optimizer/>`
73* triggering synaptic plasticity computations to reduce memory usage via the
74 :ref:`flush event mechanism<flush_event_mechanism>`
75
76Details on the event-based NEST implementation of e-prop can be found in :footcite:p:`KorcsakGorzo2025`.
77
78.. warning::
79
80 This synaptic plasticity rule does not take
81 :ref:`precise spike timing <sim_precise_spike_times>` into
82 account. When calculating the weight update, the precise spike time part
83 of the timestamp is ignored.
84
85Parameters
86++++++++++
87
88The following parameters can be set in the status dictionary.
89
90================ ==== =============== ======= ======================================================
91**Common e-prop synapse parameters**
92----------------------------------------------------------------------------------------------------
93Parameter Unit Math equivalent Default Description
94================ ==== =============== ======= ======================================================
95``optimizer`` {} Dictionary of optimizer parameters
96================ ==== =============== ======= ======================================================
97
98============= ==== ========================= ======= =========================================================
99**Individual synapse parameters**
100--------------------------------------------------------------------------------------------------------------
101Parameter Unit Math equivalent Default Description
102============= ==== ========================= ======= =========================================================
103``delay`` ms :math:`d_{ji}` 1.0 Dendritic delay
104``weight`` pA :math:`W_{ji}` 1.0 Initial value of synaptic weight
105============= ==== ========================= ======= =========================================================
106
107Recordables
108+++++++++++
109
110The following variables can be recorded.
111
112================== ==== =============== ============= ==========================================================
113**Synapse recordables**
114----------------------------------------------------------------------------------------------------------------
115State variable Unit Math equivalent Initial value Description
116================== ==== =============== ============= ==========================================================
117``weight`` pA :math:`B_{jk}` 1.0 Synaptic weight
118================== ==== =============== ============= ==========================================================
119
120Usage
121+++++
122
123This model can only be used in combination with the other e-prop models
124and the network architecture requires specific wiring, input, and output.
125The usage is demonstrated in several
126:doc:`supervised regression and classification tasks <../auto_examples/eprop_plasticity/index>`
127reproducing among others the original proof-of-concept tasks in :footcite:p:`Bellec2020`.
128
129Transmits
130+++++++++
131
132SpikeEvent, DSSpikeEvent
133
134References
135++++++++++
136
137.. footbibliography::
138
139See also
140++++++++
141
142Examples using this model
143+++++++++++++++++++++++++
144
145.. listexamples:: eprop_synapse
146
147EndUserDocs */
148
192
194void register_eprop_synapse( const std::string& name );
195
220template < typename targetidentifierT >
221class eprop_synapse : public Connection< targetidentifierT >
222{
223
224public:
227
230
239
241 static constexpr bool supports_flush_event = true;
242
245
248
251
254
257
260
265
267 void get_status( Dictionary& d ) const;
268
270 void set_status( const Dictionary& d, ConnectorModel& cm );
271
273 bool send( Event& e, size_t thread, const EpropSynapseCommonProperties& cp );
274
277 {
278 public:
280
281 size_t
283 {
284 return invalid_port;
285 }
286
287 size_t
289 {
290 return invalid_port;
291 }
292 };
293
299 void check_connection( Node& s, Node& t, size_t receptor_type, const CommonPropertiesType& cp );
300
302 void
303 set_weight( const double w )
304 {
305 weight_ = w;
306 }
307
309 void delete_optimizer();
310
311private:
313 double weight_;
314
317
320
323
325 double z_bar_ = 0.0;
326
328 double e_bar_ = 0.0;
329
331 double e_bar_reg_ = 0.0;
332
334 double epsilon_ = 0.0;
335
337 double z_previous_buffer_ = 0.0;
338
340 double gradient_ = 0.0;
341
344
346 long decay_steps_ = 0;
347
354};
355
356template < typename targetidentifierT >
358
359// Explicitly declare specializations of Connector methods that need to do special things for eprop_synapse
360template <>
361void Connector< eprop_synapse< TargetIdentifierPtrRport > >::disable_connection( const size_t lcid );
362
363template <>
364void Connector< eprop_synapse< TargetIdentifierIndex > >::disable_connection( const size_t lcid );
365
366template <>
368
369template <>
371
372template < typename targetidentifierT >
375 , weight_( 1.0 )
376 , t_spike_previous_( 0 )
377 , previous_was_flush_event_( false )
378 , t_previous_trigger_spike_( 0 )
379 , optimizer_( nullptr )
380{
381}
382
383template < typename targetidentifierT >
387
388// This copy constructor is used to create instances from prototypes.
389// Therefore, only parameter values are copied.
390template < typename targetidentifierT >
392 : ConnectionBase( es )
393 , weight_( es.weight_ )
394 , optimizer_( es.optimizer_ )
395{
396}
397
398// This assignment operator is used to write a connection into the connection array.
399template < typename targetidentifierT >
402{
403 if ( this == &es )
404 {
405 return *this;
406 }
407
408 ConnectionBase::operator=( es );
409
410 weight_ = es.weight_;
411 t_spike_previous_ = es.t_spike_previous_;
412 previous_was_flush_event_ = es.previous_was_flush_event_;
413 t_previous_trigger_spike_ = es.t_previous_trigger_spike_;
414 z_bar_ = es.z_bar_;
415 e_bar_ = es.e_bar_;
416 e_bar_reg_ = es.e_bar_reg_;
417 epsilon_ = es.epsilon_;
418 z_previous_buffer_ = es.z_previous_buffer_;
419 gradient_ = es.gradient_;
420 remaining_steps_until_cutoff_ = es.remaining_steps_until_cutoff_;
421 decay_steps_ = es.decay_steps_;
422 optimizer_ = es.optimizer_;
423
424 return *this;
425}
426
427template < typename targetidentifierT >
429 : ConnectionBase( es )
430 , weight_( es.weight_ )
431 , t_spike_previous_( es.t_spike_previous_ )
432 , previous_was_flush_event_( es.previous_was_flush_event_ )
433 , t_previous_trigger_spike_( es.t_previous_trigger_spike_ )
434 , z_bar_( es.z_bar_ )
435 , e_bar_( es.e_bar_ )
436 , e_bar_reg_( es.e_bar_reg_ )
437 , epsilon_( es.epsilon_ )
438 , z_previous_buffer_( es.z_previous_buffer_ )
439 , gradient_( es.gradient_ )
440 , remaining_steps_until_cutoff_( es.remaining_steps_until_cutoff_ )
441 , decay_steps_( es.decay_steps_ )
442 , optimizer_( es.optimizer_ )
443{
444 // Move operator, therefore we must null the optimizer pointer in the source of the move.
445 es.optimizer_ = nullptr;
446}
447
448// This is the move assignment operator.
449template < typename targetidentifierT >
452{
453 if ( this == &es )
454 {
455 return *this;
456 }
457
458 ConnectionBase::operator=( es );
459
460 weight_ = es.weight_;
461 t_spike_previous_ = es.t_spike_previous_;
462 previous_was_flush_event_ = es.previous_was_flush_event_;
463 t_previous_trigger_spike_ = es.t_previous_trigger_spike_;
464 z_bar_ = es.z_bar_;
465 e_bar_ = es.e_bar_;
466 e_bar_reg_ = es.e_bar_reg_;
467 epsilon_ = es.epsilon_;
468 z_previous_buffer_ = es.z_previous_buffer_;
469 gradient_ = es.gradient_;
470 remaining_steps_until_cutoff_ = es.remaining_steps_until_cutoff_;
471 decay_steps_ = es.decay_steps_;
472 optimizer_ = es.optimizer_;
473
474 // Move assignment, therefore we must null the optimizer pointer in the source of the move.
475 es.optimizer_ = nullptr;
476
477 return *this;
478}
479
480template < typename targetidentifierT >
481inline void
483 Node& t,
484 size_t receptor_type,
485 const CommonPropertiesType& cp )
486{
487 // When we get here, delay has been set so we can check it.
488 if ( get_delay_steps() != 1 )
489 {
490 throw IllegalConnection( "eprop synapses currently require a delay of one simulation step" );
491 }
492
493 ConnTestDummyNode dummy_target;
494 ConnectionBase::check_connection_( dummy_target, s, t, receptor_type );
495
497
498 optimizer_ = cp.optimizer_cp_->get_optimizer();
499}
500
501template < typename targetidentifierT >
502inline void
504{
505 delete optimizer_;
506 // do not set to nullptr to allow detection of double deletion
507}
508
509template < typename targetidentifierT >
510bool
512{
513 Node* target = get_target( thread );
514 assert( target );
515
516 const long t_spike = e.get_stamp().get_steps();
517 const bool is_flush_event = e.is_flush_event();
518
519 if ( t_spike_previous_ != 0 )
520 {
521 target->compute_gradient( t_spike,
522 t_spike_previous_,
523 z_previous_buffer_,
524 z_bar_,
525 e_bar_,
526 e_bar_reg_,
527 epsilon_,
528 weight_,
529 cp,
530 optimizer_,
531 is_flush_event,
532 previous_was_flush_event_,
533 gradient_,
534 remaining_steps_until_cutoff_,
535 decay_steps_ );
536 }
537
538 target->erase_used_eprop_history( t_spike, t_spike_previous_ );
539
540 t_spike_previous_ = t_spike;
541 previous_was_flush_event_ = is_flush_event;
542
543 if ( not is_flush_event )
544 {
545 e.set_receiver( *target );
546 e.set_weight( weight_ );
547 e.set_delay_steps( get_delay_steps() );
548 e.set_rport( get_rport() );
549 e();
550 }
551 return true;
552}
553
554template < typename targetidentifierT >
555void
557{
558 ConnectionBase::get_status( d );
559 d[ names::weight ] = weight_;
560 d[ names::size_of ] = static_cast< long >( sizeof( *this ) );
561
562 Dictionary optimizer_dict;
563
564 // The default_connection_ has no optimizer, therefore we need to protect it
565 if ( optimizer_ )
566 {
567 optimizer_->get_status( optimizer_dict );
568 d[ names::optimizer ] = optimizer_dict;
569 }
570}
571
572template < typename targetidentifierT >
573void
575{
576 ConnectionBase::set_status( d, cm );
577 if ( d.known( names::optimizer ) )
578 {
579 // We must pass here if called by SetDefaults. In that case, the user will get and error
580 // message because the parameters for the synapse-specific optimizer have not been accessed.
581 if ( optimizer_ )
582 {
583 optimizer_->set_status( d.get< Dictionary >( names::optimizer ) );
584 }
585 }
586
587 d.update_value( names::weight, weight_ );
588
589 const auto& gcm = dynamic_cast< const GenericConnectorModel< eprop_synapse< targetidentifierT > >& >( cm );
590 const CommonPropertiesType& epcp = gcm.get_common_properties();
591 if ( weight_ < epcp.optimizer_cp_->get_Wmin() )
592 {
593 throw BadProperty( "Minimal weight Wmin ≤ weight required." );
594 }
595
596 if ( weight_ > epcp.optimizer_cp_->get_Wmax() )
597 {
598 throw BadProperty( "weight ≤ maximal weight Wmax required." );
599 }
600}
601
602} // namespace nest
603
604#endif // EPROP_SYNAPSE_H
Dictionary class for interface to Python and C++ API.
Definition dictionary.h:213
Exception to be thrown if a status parameter is incomplete or inconsistent.
Definition exceptions.h:680
Class containing the common properties for all connections of a certain type.
Definition common_synapse_properties.h:50
Base class for dummy nodes used in connection testing.
Definition connection.h:67
Base class for representing connections.
Definition connection.h:110
long get_delay_steps() const
Return the delay of the connection in steps.
Definition connection.h:181
Node * get_target(const size_t tid) const
Definition connection.h:239
size_t get_rport() const
Definition connection.h:244
double get_delay() const
Return the delay of the connection in ms.
Definition connection.h:172
Definition connector_model.h:69
Homogeneous connector, contains synapses of one particular type (syn_id_).
Definition connector_base.h:221
"Callback request event" for use in Device.
Definition event.h:521
Base class implementing common properties for e-prop synapses with additional biological features.
Definition eprop_synapse.h:165
WeightOptimizerCommonProperties * optimizer_cp_
Pointer to common properties object for weight optimizer.
Definition eprop_synapse.h:190
~EpropSynapseCommonProperties()
Destructor.
Definition eprop_synapse.cpp:49
EpropSynapseCommonProperties & operator=(const EpropSynapseCommonProperties &)=delete
Assignment operator.
EpropSynapseCommonProperties()
Definition eprop_synapse.cpp:37
void get_status(Dictionary &d) const
Get parameter dictionary.
Definition eprop_synapse.cpp:55
void set_status(const Dictionary &d, ConnectorModel &cm)
Update values in parameter dictionary.
Definition eprop_synapse.cpp:65
Encapsulate information sent between nodes.
Definition event.h:103
Definition connector_model.h:152
To be thrown if a connection is not possible.
Definition exceptions.h:490
Base class for all NEST network objects.
Definition node.h:99
virtual void register_eprop_connection()
Registers an eprop connection.
Definition node.cpp:217
Event for spike information.
Definition event.h:418
Base class implementing common properties of a weight optimizer model.
Definition weight_optimizer.h:154
virtual WeightOptimizer * get_optimizer() const =0
Get optimizer.
Base class implementing a weight optimizer model.
Definition weight_optimizer.h:238
Dummy node for testing the connection.
Definition eprop_synapse.h:277
size_t handles_test_event(SpikeEvent &, size_t)
Check if the node can handle a particular event and receptor type.
Definition eprop_synapse.h:282
size_t handles_test_event(DSSpikeEvent &, size_t)
Definition eprop_synapse.h:288
Class implementing a synapse model for e-prop plasticity with additional biological features.
Definition eprop_synapse.h:222
Connection< targetidentifierT > ConnectionBase
Type of the connection base.
Definition eprop_synapse.h:229
double z_bar_
Low-pass filtered spiking variable.
Definition eprop_synapse.h:325
double weight_
Synaptic weight.
Definition eprop_synapse.h:313
static constexpr bool supports_flush_event
Whether this connection type supports flush events.
Definition eprop_synapse.h:241
EpropSynapseCommonProperties CommonPropertiesType
Type of the common synapse properties.
Definition eprop_synapse.h:226
double epsilon_
Adaptive threshold component of the eligibility vector.
Definition eprop_synapse.h:334
double gradient_
Sum of gradients.
Definition eprop_synapse.h:340
eprop_synapse & operator=(const eprop_synapse &)
Assignment operator.
Definition eprop_synapse.h:401
long remaining_steps_until_cutoff_
Remaining computation steps.
Definition eprop_synapse.h:343
long t_previous_trigger_spike_
The time step when the spike arrived that triggered the previous e-prop update.
Definition eprop_synapse.h:322
void set_status(const Dictionary &d, ConnectorModel &cm)
Update values in parameter dictionary.
Definition eprop_synapse.h:574
void set_weight(const double w)
Set the synaptic weight to the provided value.
Definition eprop_synapse.h:303
~eprop_synapse()
Destructor.
Definition eprop_synapse.h:384
bool previous_was_flush_event_
Previous event was a flush event.
Definition eprop_synapse.h:319
double z_previous_buffer_
Value of spiking variable one time step before t_previous_spike_.
Definition eprop_synapse.h:337
eprop_synapse()
Default constructor.
Definition eprop_synapse.h:373
WeightOptimizer * optimizer_
Optimizer.
Definition eprop_synapse.h:353
void get_status(Dictionary &d) const
Get parameter dictionary.
Definition eprop_synapse.h:556
double e_bar_reg_
Low-pass filtered eligibility trace for firing rate regularization.
Definition eprop_synapse.h:331
void delete_optimizer()
Delete optimizer.
Definition eprop_synapse.h:503
static constexpr ConnectionModelProperties properties
Properties of the connection model.
Definition eprop_synapse.h:236
long decay_steps_
Decay steps for the eligibility trace.
Definition eprop_synapse.h:346
long t_spike_previous_
The time step when the previous spike arrived.
Definition eprop_synapse.h:316
double e_bar_
Low-pass filtered eligibility trace.
Definition eprop_synapse.h:328
bool send(Event &e, size_t thread, const EpropSynapseCommonProperties &cp)
Send the spike event.
Definition eprop_synapse.h:511
void check_connection(Node &s, Node &t, size_t receptor_type, const CommonPropertiesType &cp)
Check if the target accepts the event and receptor type requested by the sender.
Definition eprop_synapse.h:482
virtual size_t handles_test_event(SpikeEvent &, size_t receptor_type)
Check if the node can handle a particular event and receptor type.
Definition node.cpp:271
const std::string optimizer("optimizer")
const std::string weight("weight")
const std::string size_of("sizeof")
Namespace for the NEST simulation kernel.
Definition beta_normalization_factor.h:33
void register_eprop_synapse(const std::string &name)
Register the eprop synapse model.
Definition eprop_synapse.cpp:32
ConnectionModelProperties
Definition connector_model.h:49
constexpr size_t invalid_port
Value for invalid connection port number.
Definition nest_types.h:141