📄 neuron.cpp
字号:
/*************************************************************************** neuron.cpp - description ------------------- copyright : (C) 2001, 2002 by Matt Grover email : mgrover@amygdala.org ***************************************************************************//*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/using namespace std;#include <iostream.h>#include <cmath>#include "neuron.h"#include "network.h"#include "spikeoutput.h"#include "simplespikeoutput.h"#include "types.h"#include "node.h"#include "mpnetwork.h"#include "instance.h"// Uncomment for debugging messages//#define DEBUG_NEURONNeuron::Neuron(AmIdInt neuronId): nId(neuronId){ SetDefaults();}Neuron::~Neuron(){ //cout << "Deleting a neuron\n"; // delete the synapses for (unsigned int i=0; i<axon.size(); ++i) { delete axon[i]; } axon.clear(); inputHist.clear(); smpAxon.clear();}// Initialize static variablesAmTimeInt Neuron::simStepSize = 100;bool Neuron::recordOutput = false;OutputMode Neuron::outputMode = OUTPUT_LAYERS;SpikeOutput* Neuron::spikeOutput = new SimpleSpikeOutput;bool Neuron::defaultOutputObj = true;bool Neuron::enforceSign = false;bool Neuron::mpMode = false;bool Neuron::spikeDelaysOn = false;void Neuron::SetDefaults(){ // Default values for constants (made up for now) memTimeConst = 10.0; synTimeConst = 2.0; // unused except in learning //restPtnl = -0.07; restPtnl = 0.0; membranePtnl = restPtnl; refPeriod = 2000; inputTime = 0; currTime = 0; spikeTime = 0; axonSize = 0; thresholdPtnl = 5.0; // abs val of difference between thresh and rest ptnl maxScaledWeight = 0.0; maxThreshCrs = 0.0; convergeRes = 0.0; usePspLookup = false; trainingMode = true; // training off by default inhibitory = false; // Set defaults for learning synPotConst = 0.5; // A+ in Pulsed Neural Networks synDepConst = 0.2; // A- in Pulsed Neural Networks learningMax = -0.05; // ms units posLearnTimeConst = 1.0; // ms negLearnTimeConst = 20.0; // ms learningConst = 1e-2; //dendriteSize = 10; initAxonSize = 100; //default number of outputs for now if (nId == 0) { nId = int(this); // default id } axon.reserve(initAxonSize); //allocate some memory for the axon// inWeightHist.reserve(16);// inTimeHist.reserve(16); inputHist.reserve(500); histBeginIdx = 0;}void Neuron::SetMaxScaledWeight(){ maxScaledWeight = 1;}void Neuron::SetSpikeOutput(SpikeOutput* output){ if (defaultOutputObj) { delete spikeOutput; defaultOutputObj = false; } spikeOutput = output;}void Neuron::SetTimeConstants(float synapticConst, float membraneConst){ // Don't do anything if the lookup table has already been set. // This will have to be changed when dynamic constant alterations // are implemented. if ( !usePspLookup ) { synTimeConst = synapticConst; memTimeConst = membraneConst; }}void Neuron::CaptureOutput(OutputMode mode){ if (mode == OFF) { recordOutput = false; } else { recordOutput = true; } outputMode = mode;}void Neuron::SendSpike(AmTimeInt& now){ int i; if ( (schedSpikeTime == now) || (layerType == INPUTLAYER) || (layerType == IOLAYER) ) { #ifdef DEBUG_NEURON cout << "\nNeuron " << nId << " spiking!" << endl; #endif // Do a check to make sure the refractory period has passed. This // check will normally be done before the spike is scheduled, but // some spikes can get thru anyway (input spikes, for example). // Any spikes scheduled within the refractory period are ignored. if ( (now - spikeTime) <= refPeriod ) { // Don't do anything if spikeTime == 0 because this neuron // has not yet fired and the simulation time could be less // than the refractory period. if (spikeTime) { return; } } membranePtnl = restPtnl; currTime = now; if (spikeDelaysOn) { SNet->ScheduleSpikeDelay(axon); } else { SynapseItr syn = axon.begin(); for (i=0; i<axonSize; ++i) { //Synapse* syn = axon[i]; (*syn)->GetPostNeuron()->InputSpike(syn, currTime); ++syn; } } // Send the remote spikes if in multi-processing mode if (mpMode) SendSMPSpike(now); // do training and reset the history table if (trainingMode) { Train(currTime); } inputHist.clear(); synapseHist.clear(); spikeTime = schedSpikeTime; schedSpikeTime = 0; histBeginIdx = 0; // If this is an output neuron and output mode // is turned on, record the event according to // the outputMode. if (recordOutput) { if (outputMode == ALL) { spikeOutput->OutputEvent(nId, currTime); } else if (layerType >= OUTPUTLAYER) { spikeOutput->OutputEvent(nId, currTime); } } }}void Neuron::SendSMPSpike(AmTimeInt& ){ for(unsigned int i=0; i<smpAxon.size(); i++){ SMPSynapse *syn = smpAxon[i]; syn->SpikeEvent(); }}void Neuron::Train(AmTimeInt& spikeTime){ /************************************************************************** * Implement a Hebbian learning rule as described in Chapter 14 of _Pulsed * Neural Networks_. The learning window is defined by a pair of equations. * For s <= smax (where s = input time and smax = time of maximum learning), * W = (Apos - Aneg) * exp( -(smax - s)/synTimeConst ). * For s > smax, * W = ( Apos * exp( -(s - smax)/posLearnTimeConst )) - * ( Aneg * exp( -(s - smax)/negLearnTimeConst )). **************************************************************************/ AmTimeInt usTimeDiff; int numInputs; float timeDiff; float weightDiff; float newWeight; float window; SynapseHist tmpInput; int i; // Declare the inverses of the learning time constants as statics static float tauPosInv = 1 / posLearnTimeConst; static float tauNegInv = 1 / negLearnTimeConst; static float synTimeConstInv = 1 / synTimeConst; #ifdef DEBUG_NEURON cout << "Training...\n"; #endif // iterate thru inputHist and adjust weights for each // entry. numInputs = synapseHist.size(); for (i=0; i<numInputs; i++) { tmpInput = synapseHist[i]; // The time delta will be negative if the input spike // arrived before the post synaptic spike time, and // positive otherwise. if (tmpInput.time > spikeTime) { usTimeDiff = tmpInput.time - spikeTime; timeDiff = float(usTimeDiff) * 0.001; // divide by 1000 to get ms units } else { usTimeDiff = spikeTime - tmpInput.time; timeDiff = float(usTimeDiff) * -0.001; } #ifdef DEBUG_NEURON cout << "inputTime: " << tmpInput.time << endl; cout << "spikeTime: " << spikeTime << endl; cout << "timeDiff: " << usTimeDiff << endl; #endif // s < s* if (timeDiff < learningMax) { float expTerm = exp( -(learningMax - timeDiff) * synTimeConstInv ); window = (synPotConst - synDepConst) * expTerm; weightDiff = ( learningConst * window ) * maxScaledWeight; } else { // s > s* float expTerm1 = exp( -(timeDiff - learningMax) * tauPosInv ); float expTerm2 = exp( -(timeDiff - learningMax) * tauNegInv ); window = ( synPotConst * expTerm1 ) - ( synDepConst * expTerm2 ); weightDiff = ( learningConst * window ) * maxScaledWeight; } newWeight = tmpInput.syn->GetWeight(); if (newWeight < 0.0) { newWeight = newWeight - weightDiff; } else { newWeight = newWeight + weightDiff; } if (abs(newWeight) < maxScaledWeight) { tmpInput.syn->SetWeight(newWeight); } }}void Neuron::AddSynapse(Synapse* synapse){ // normalize weight float maxWeight = synapse->GetPostNeuron()->GetMaxScaledWeight(); if (!maxWeight) { throw "maxScaledWeight has not been set."; } float synWeight = synapse->GetWeight(); synapse->SetWeight(synWeight*maxWeight); //synWeight *= maxWeight; axon.push_back(synapse); ++axonSize;}void Neuron::AddSMPSynapse(SMPSynapse* synapse){ // normalize weight float maxWeight = synapse->GetPostNeuron()->GetMaxScaledWeight(); if (!maxWeight) { throw "maxScaledWeight has not been set."; } float synWeight = synapse->GetWeight(); synapse->SetWeight(synWeight*maxWeight); //synWeight *= maxWeight; smpAxon.push_back(synapse);}void Neuron::SetAxonSize(int size){ if (size > axonSize) { axon.reserve(size); }}void Neuron::SetTableDimensions(int tblSize, int tblRes){ pspLSize = tblSize; pspStepSize = tblRes;}/** return a pointer to the physical properties of this neuron */PhysicalProperties * Neuron::GetPhysicalProperties(){ return &physicalProperties;}void Neuron::EnableSpikeBatching(){ spikeDelaysOn = true;}//--------------- Methods of class PhysicalProperties --------------------//PhysicalProperties::PhysicalProperties() { location[0] = 0.; location[1] = 0.; location[2] = 0.;}PhysicalProperties::~PhysicalProperties() {}float *PhysicalProperties::GetLocation(float loc[]){ for(int i=0; i<3; i++) loc[i] = location[i]; return loc;}void PhysicalProperties::SetLocation(float _newVal[]){ location[0] = _newVal[0]; location[1] = _newVal[1]; location[2] = _newVal[2];}//-------------- Methods of class Synapse ---------------------------------//Synapse::Synapse(Neuron* _postNrn, float _weight, AmTimeInt _delay = 0): weight(_weight), postNrn(_postNrn){ offset = _delay/Network::TimeStepSize();}AmTimeInt Synapse::GetDelay() const{ return offset*Network::TimeStepSize();}//bool CompareSyn(const Synapse* lsyn, const Synapse* rsyn) {// return lsyn->GetPostNeuron() < rsyn->GetPostNeuron(); }//-------------- Methods of class SMPSynapse ---------------------------------//SMPSynapse::SMPSynapse(MpSpikeInput *_connector, Neuron* _postNrn, float _weight, AmTimeInt _delay = 0): Synapse(_postNrn, _weight, _delay){ connector = _connector;}void SMPSynapse::SpikeEvent(){ connector->queueSpike(this);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -