📄 network.cpp
字号:
/*************************************************************************** network.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. * * * ***************************************************************************/// Uncomment for debugging messages//#define DEBUG_NETWORKusing namespace std;#include "types.h"#include <math.h>#include <stdio.h>#include <iostream>#include <string>#include <iterator>#include <algorithm>#include <vector>#include <list>#if GCC_VERSION >= 30000 #include <ext/hash_map>#else #include <hash_map>#endif#include "neuron.h"#include "basicneuron.h"#include "layer.h"#include "network.h"#include "simplespikeinput.h"#include "functionlookup.h"#include "utilities.h"#ifdef DEBUG_NETWORK#include <sys/time.h>#endifclass SimpleSpikeInput;Network::Network(){ // initialize the lookup tables SetDefaults(); pspLRes = 100; // unit = microseconds => 0.1 ms pspLSize = 1000; functionRef = new FunctionLookup(); spikeInput = new SimpleSpikeInput(this); // default input object netSize = 0; eventRequestCount = 0; isLayered = false; runCount++; trainingMode = true; maxSpikeDelay = 0; maxSpikeDelaySyn = 0; currSpikeDelayOffset = 0; maxOffset = 0; spikeDelaysOn = false; spikeBatchCount = 0;}void Network::SetDefaults(){ nextNeuronId = 1; nextLayerId = 1; streamingInput = false;}Network::~Network(){ // We don't know if the keys are contiguous // in net, so use an iterator to delete // Neurons instead of subscripting hash_map<AmIdInt, Neuron*>::iterator netItr; netItr = net.begin(); while (netItr != net.end()) { delete netItr->second; netItr->second = 0; netItr++; } net.clear(); runCount--; delete functionRef; delete spikeInput; for(layer_iterator layer = layers.begin(); layer != layers.end(); layer++){ delete layer->second; }}// Initialize staticsAmTimeInt Network::simTime = 0;unsigned int Network::runCount = 0;AmTimeInt Network::simStepSize = 100; // Default must match Neuron::simStepSize default!void Network::ResetSimTime(){ // FIXME: Some checks need to be developed to make // sure that it is safe to reset simTime right now. // For example, simTime should not be reset if // any Networks are in the run loop. This should // maybe be done as part of a more general reset routine // that clears out old data, etc. A flag would have to be // set to indicate to other instances that they need to reset, also. simTime = 0;}void Network::SetTimeStepSize(AmTimeInt stepSize){ // FIXME: Need a static flag to keep this from running after // neurons have been added to a net. simStepSize = stepSize; Neuron::simStepSize = stepSize;}Neuron* Network::AddNeuron(LayerType lType, AmIdInt nId){ if (nId >= nextNeuronId) { nextNeuronId = nId + 1; } //cout << "Adding neuron " << nId << endl; BasicNeuron* nrn = new BasicNeuron(nId); net[nId] = nrn; nrn->SetTableDimensions(pspLSize, pspLRes); nrn->SetLookupTables(functionRef); nrn->SetLayerType(lType); nrn->SetParentNet(this); nrn->TrainingOn(trainingMode); return nrn;}Neuron* Network::AddNeuron(LayerType lType, Neuron* nrn){ AmIdInt nId = 0; nId = nrn->GetID(); if (nId >= nextNeuronId) { nextNeuronId = nId + 1; } //cout << "Adding neuron " << nId << endl; net[nId] = nrn; nrn->SetTableDimensions(pspLSize, pspLRes); nrn->SetLookupTables(functionRef); nrn->SetLayerType(lType); nrn->SetParentNet(this); nrn->TrainingOn(trainingMode); return nrn;}bool Network::ConnectNeurons(Neuron* preSynapticNeuron, Neuron* postSynapticNeuron, float weight, AmTimeInt delay=0){// FIXME: Sign enforcement is not working. There is confusion// as to when a neuron should be designated as inhibitory.// This code should maybe run in the neuron instead, and// a static function can set the enforceSign flag.// NOTE: EnforceSign() has been made a static member of Neuron,// but this section of code has still not been tested. Remove// the fixme once this is confirmed to work correctly. if ( Neuron::EnforceSign() ) { // Make sure weight has correct sign if ( preSynapticNeuron->Inhibitory() ) { if (weight > 0.0) { cerr << "Inhibitory neuron " << preSynapticNeuron->GetID() << " has a positive weight!\n"; return false; } } else if (weight < 0.0) { cerr << "Excitatory neuron " << preSynapticNeuron->GetID() << " has a negative weight!\n"; return false; } } try { Synapse* syn = new Synapse(postSynapticNeuron, weight, delay); preSynapticNeuron->AddSynapse(syn); if (delay > maxSpikeDelay) { maxSpikeDelay = delay; maxSpikeDelaySyn = syn; } } catch(string& e) { cerr << e << endl; return false; } catch(...) { cerr << "An error occured while connecting the neurons.\n"; return false; } return true;}bool Network::ConnectNeurons(AmIdInt preSynapticNeuron, AmIdInt postSynapticNeuron, float weight, AmTimeInt delay=0){ return ConnectNeurons(net[preSynapticNeuron], net[postSynapticNeuron], weight, delay);}void Network::AddLayer(Layer* newLayer){ unsigned int lId = newLayer->LayerId(); if (!lId) { lId = nextLayerId; newLayer->SetLayerId(lId); } if (lId >= nextLayerId) { nextLayerId = lId + 1; } // we don't want duplicate Layer IDs for(layer_iterator layer = layers.begin(); layer != layers.end(); layer++){ Layer *l = layer->second; if(l->LayerId() == lId) throw string("Layer ID: " + Utilities::itostr(lId) + " already in use"); } layers[newLayer->LayerId()] = newLayer; newLayer->SetLayerParent(this); isLayered = true;}void Network::ScheduleNEvent(NEvent eventType, AmTimeInt eventTime, Neuron* reqNrn){ SpikeRequest newSpike; if (eventType > RMSPIKE) { // initialize a new event request newSpike.requestTime = simTime; newSpike.requestor = reqNrn; newSpike.spikeTime = eventTime; newSpike.requestOrder = eventRequestCount++; // insert into the queue if (eventType == SPIKE || eventType == RESPIKE) { eventQ.push(newSpike); } else if (eventType == INPUTSPIKE) { inputQ.push(newSpike); } }}void Network::ScheduleNEvent(NEvent eventType, AmTimeInt eventTime, AmIdInt reqNrnId){ Neuron* nrn = net.find(reqNrnId)->second; if (nrn) { ScheduleNEvent(eventType, eventTime, nrn); } else { string errMsg = "Neuron ID could not be found."; throw errMsg; }}void Network::Run(AmTimeInt maxRunTime){ // This is the main loop // If streaming input is being used, keep on going until simTime >= maxRunTime. // Otherwise, run until the event queue is empty or // until simTime >= maxRunTime -- whichever happens first. bool stopRun = false; const unsigned int stopTime = maxRunTime + simTime; AmTimeInt nextInputTime = 0; #ifdef DEBUG_NETWORK timeval time1; timeval time2; int totalTime; #endif if (simTime == 0) simTime = simStepSize; // Initialize the delayed spike queue if it has not been done. if (!delayedSpikeQ.size()) { InitializeDelayedSpikeQ(); } if (eventQ.empty() && inputQ.empty()) { if(!streamingInput) { stopRun = true; } else { stopRun = false; } } else { if (!inputQ.empty()) { nextInputTime = inputQ.top().spikeTime; } else { nextInputTime = 0; } stopRun = false; } while (!stopRun) { while (!eventQ.empty()) { const SpikeRequest& topSpike = eventQ.top(); if (topSpike.spikeTime != simTime) break; #ifdef DEBUG_NETWORK cout << "\nSending spike from Neuron: " << topSpike.requestor->GetID() << endl; gettimeofday(&time1, NULL); #endif topSpike.requestor->SendSpike(simTime); eventQ.pop(); #ifdef DEBUG_NETWORK gettimeofday(&time2, NULL); totalTime = time2.tv_usec - time1.tv_usec; cout << "\nTotal time for sending spike: " << totalTime << "us" << endl; #endif } if (streamingInput) { spikeInput->ReadInputBuffer(); if (!inputQ.empty()) { nextInputTime = inputQ.top().spikeTime; } else { nextInputTime = 0; } } while (nextInputTime <= simTime) { if (nextInputTime == 0) break; inputQ.top().requestor->SendSpike(simTime); inputQ.pop(); if (!inputQ.empty()) { nextInputTime = inputQ.top().spikeTime; } else { nextInputTime = 0; } } // send the delayed spikes // this must be called after Neuron::SendSpike() // has been called for the last time during this // time step if (spikeDelaysOn) { SendDelayedSpikes(); } // increment simTime if (runCount > 1) { // A call to IncrementSimTime() is made if more than one // instance of Network is running in a process. This is done // to keep all of the Networks synchronized and to handle any // threading issues that may arise due to simTime being static. IncrementSimTime(); } else { simTime += simStepSize; } if (simTime >= stopTime) { stopRun = true; } else if (!streamingInput) { if (eventQ.empty() && inputQ.empty() && !spikeBatchCount) { stopRun = true; } } }}void Network::SetSpikeInput(SpikeInput* sIn){ delete spikeInput; spikeInput = sIn;}void Network::IncrementSimTime(){ simTime += simStepSize;}void Network::SetTrainingMode(bool tMode){ if (tMode == trainingMode) { return; } trainingMode = tMode; hash_map<AmIdInt, Neuron*>::iterator itr; itr = net.begin(); while (itr != net.end()) { itr->second->TrainingOn(tMode); itr++; }}void Network::ScheduleSpikeDelay(vector<Synapse*>& axon){ unsigned int maxOffset = delayedSpikeQ.size() - 1; for (vector<Synapse*>::iterator it=axon.begin(); it!=axon.end(); ++it) { AmTimeInt offset = (*it)->GetOffset(); offset += currSpikeDelayOffset; // If the offset goes past the end of the queue, then // start back at the beginning if (offset > maxOffset) { offset -= (maxOffset + 1); } delayedSpikeQ[offset].push_back((*it)); } spikeBatchCount += axon.size();}void Network::SendDelayedSpikes(){ vector<Synapse*>& spikeBatch = delayedSpikeQ[currSpikeDelayOffset]; if (!spikeBatch.size()) { IncrementDelayOffset(); return; } // sort the elements in the current offset batch // according to neuronId and get a pointer to // the first element vector<Synapse*>::iterator beginItr = spikeBatch.begin(); vector<Synapse*>::iterator endItr = spikeBatch.end(); static CompareSynapse comp; sort(beginItr, endItr, comp); //Synapse* firstSyn = spikeBatch[0]; SynapseItr firstSyn = spikeBatch.begin(); unsigned int numSyn = 0; // parse the spikeBatch vector and send one group of spikes // to each neuron in the vector. for (unsigned int i=0; i<spikeBatch.size(); ++i) { if (spikeBatch[i]->GetPostNeuron() != (*firstSyn)->GetPostNeuron()) { (*firstSyn)->GetPostNeuron()->InputSpike(firstSyn, simTime, numSyn); //firstSyn = spikeBatch[i]; firstSyn += numSyn; numSyn = 1; } else { ++numSyn; } } // send the last batch of delayed spikes (*firstSyn)->GetPostNeuron()->InputSpike(firstSyn, simTime, numSyn); // clean up spikeBatchCount -= spikeBatch.size(); spikeBatch.clear(); IncrementDelayOffset();}void Network::InitializeDelayedSpikeQ(){ if (maxSpikeDelay) { spikeDelaysOn = true; Neuron::EnableSpikeBatching(); } maxOffset = maxSpikeDelay/simStepSize; delayedSpikeQ.reserve(maxOffset+1); delayedSpikeQ.resize(maxOffset+1); for (unsigned int i=0; i<delayedSpikeQ.size(); ++i) { // TODO: Assuming 100 delayed spikes per offset for now. // A more intelligent algorithm to determine proper // sizing should be developed later on. delayedSpikeQ[i].reserve(100); }}inline void Network::IncrementDelayOffset(){ if (currSpikeDelayOffset >= maxOffset) { currSpikeDelayOffset = 0; } else { ++currSpikeDelayOffset; }}Layer * Network::GetLayer(AmIdInt layerId){ return layers[layerId];}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -