// @(#)root/tmva $Id$ // Author: Matt Jachowski /********************************************************************************** * Project: TMVA - a Root-integrated toolkit for multivariate data analysis * * Package: TMVA * * Class : TNeuron * * Web : http://tmva.sourceforge.net * * * * Description: * * Implementation (see header for description) * * * * Authors (alphabetical): * * Matt Jachowski - Stanford University, USA * * * * Copyright (c) 2005: * * CERN, Switzerland * * * * Redistribution and use in source and binary forms, with or without * * modification, are permitted according to the terms listed in LICENSE * * (http://tmva.sourceforge.net/LICENSE) * **********************************************************************************/ //_______________________________________________________________________ // // Neuron class used by TMVA artificial neural network methods // //_______________________________________________________________________ #include "TH1D.h" #ifndef ROOT_TMVA_MsgLogger #include "TMVA/MsgLogger.h" #endif #ifndef ROOT_TMVA_TNeuron #include "TMVA/TNeuron.h" #endif #ifndef ROOT_TMVA_TActivation #include "TMVA/TActivation.h" #endif #ifndef ROOT_TMVA_Tools #include "TMVA/Tools.h" #endif #ifndef ROOT_TMVA_TNeuronInput #include "TMVA/TNeuronInput.h" #endif static const Int_t UNINITIALIZED = -1; using std::vector; ClassImp(TMVA::TNeuron) TMVA::MsgLogger* TMVA::TNeuron::fgLogger = 0; //______________________________________________________________________________ TMVA::TNeuron::TNeuron() { // standard constructor if (!fgLogger) fgLogger = new MsgLogger("TNeuron",kDEBUG); InitNeuron(); } TMVA::TNeuron::~TNeuron() { // destructor if (fLinksIn != NULL) delete fLinksIn; if (fLinksOut != NULL) delete fLinksOut; } void TMVA::TNeuron::InitNeuron() { // initialize the neuron, most variables still need to be set via setters fLinksIn = new TObjArray(); fLinksOut = new TObjArray(); fValue = UNINITIALIZED; fActivationValue = UNINITIALIZED; fDelta = UNINITIALIZED; fDEDw = UNINITIALIZED; fError = UNINITIALIZED; fActivation = NULL; fForcedValue = kFALSE; fInputCalculator = NULL; } //______________________________________________________________________________ void TMVA::TNeuron::ForceValue(Double_t value) { // force the value, typically for input and bias neurons fValue = value; fForcedValue = kTRUE; } //______________________________________________________________________________ void TMVA::TNeuron::CalculateValue() { // calculate neuron input if (fForcedValue) return; fValue = fInputCalculator->GetInput(this); } //______________________________________________________________________________ void TMVA::TNeuron::CalculateActivationValue() { // calculate neuron activation/output if (fActivation == NULL) { PrintMessage( kWARNING ,"No activation equation specified." ); fActivationValue = UNINITIALIZED; return; } fActivationValue = fActivation->Eval(fValue); } //______________________________________________________________________________ void TMVA::TNeuron::CalculateDelta() { // calculate error field // no need to adjust input neurons if (IsInputNeuron()) { fDelta = 0.0; return; } Double_t error; // output neuron should have error set all ready if (IsOutputNeuron()) error = fError; // need to calculate error for any other neuron else { error = 0.0; TSynapse* synapse = NULL; // Replaced TObjArrayIter pointer by object, as creating it on the stack // is much faster (5-10% improvement seen) than re-allocating the new // memory for the pointer each time. Thansk to Peter Elmer who pointed this out // TObjArrayIter* iter = (TObjArrayIter*)fLinksOut->MakeIterator(); TObjArrayIter iter(fLinksOut); while (true) { synapse = (TSynapse*) iter.Next(); if (synapse == NULL) break; error += synapse->GetWeightedDelta(); } } fDelta = error * fActivation->EvalDerivative(GetValue()); } //______________________________________________________________________________ void TMVA::TNeuron::SetInputCalculator(TNeuronInput* calculator) { // set input calculator if (fInputCalculator != NULL) delete fInputCalculator; fInputCalculator = calculator; } //______________________________________________________________________________ void TMVA::TNeuron::SetActivationEqn(TActivation* activation) { // set activation equation if (fActivation != NULL) delete fActivation; fActivation = activation; } //______________________________________________________________________________ void TMVA::TNeuron::AddPreLink(TSynapse* pre) { // add synapse as a pre-link to this neuron if (IsInputNeuron()) return; fLinksIn->Add(pre); } //______________________________________________________________________________ void TMVA::TNeuron::AddPostLink(TSynapse* post) { // add synapse as a post-link to this neuron if (IsOutputNeuron()) return; fLinksOut->Add(post); } //______________________________________________________________________________ void TMVA::TNeuron::DeletePreLinks() { // delete all pre-links DeleteLinksArray(fLinksIn); } //______________________________________________________________________________ void TMVA::TNeuron::DeleteLinksArray(TObjArray*& links) { // delete an array of TSynapses if (links == NULL) return; TSynapse* synapse = NULL; Int_t numLinks = links->GetEntriesFast(); for (Int_t i=0; iAt(i); if (synapse != NULL) delete synapse; } delete links; links = NULL; } //______________________________________________________________________________ void TMVA::TNeuron::SetError(Double_t error) { // set error, this should only be done for an output neuron if (!IsOutputNeuron()) PrintMessage( kWARNING, "Warning! Setting an error on a non-output neuron is probably not what you want to do." ); fError = error; } //______________________________________________________________________________ void TMVA::TNeuron::UpdateSynapsesBatch() { // update and adjust the pre-synapses for each neuron (input neuron has no pre-synapse) // this method should only be called in batch mode if (IsInputNeuron()) return; TSynapse* synapse = NULL; TObjArrayIter iter(fLinksIn); while (true) { synapse = (TSynapse*) iter.Next(); if (synapse == NULL) break; synapse->CalculateDelta(); } } //______________________________________________________________________________ void TMVA::TNeuron::UpdateSynapsesSequential() { // update the pre-synapses for each neuron (input neuron has no pre-synapse) // this method should only be called in sequential mode if (IsInputNeuron()) return; TSynapse* synapse = NULL; TObjArrayIter iter(fLinksIn); while (true) { synapse = (TSynapse*) iter.Next(); if (synapse == NULL) break; synapse->InitDelta(); synapse->CalculateDelta(); synapse->AdjustWeight(); } } //______________________________________________________________________________ void TMVA::TNeuron::AdjustSynapseWeights() { // adjust the pre-synapses' weights for each neuron (input neuron has no pre-synapse) // this method should only be called in batch mode if (IsInputNeuron()) return; TSynapse* synapse = NULL; TObjArrayIter iter(fLinksIn); while (true) { synapse = (TSynapse*) iter.Next(); if (synapse == NULL) break; synapse->AdjustWeight(); } } //______________________________________________________________________________ void TMVA::TNeuron::InitSynapseDeltas() { // initialize the error fields of all pre-neurons // this method should only be called in batch mode // an input neuron has no pre-weights to adjust if (IsInputNeuron()) return; TSynapse* synapse = NULL; TObjArrayIter iter(fLinksIn); while (true) { synapse = (TSynapse*) iter.Next(); if (synapse == NULL) break; synapse->InitDelta(); } } //______________________________________________________________________________ void TMVA::TNeuron::PrintLinks(TObjArray* links) const { // print an array of TSynapses, for debugging if (links == NULL) { Log() << kDEBUG << "\t\t\t" << Endl; return; } TSynapse* synapse; Int_t numLinks = links->GetEntriesFast(); for (Int_t i = 0; i < numLinks; i++) { synapse = (TSynapse*)links->At(i); Log() << kDEBUG << "\t\t\tweighta: " << synapse->GetWeight() << "\t\tw-value: " << synapse->GetWeightedValue() << "\t\tw-delta: " << synapse->GetWeightedDelta() << "\t\tl-rate: " << synapse->GetLearningRate() << Endl; } } //______________________________________________________________________________ void TMVA::TNeuron::PrintActivationEqn() { // print activation equation, for debugging if (fActivation != NULL) Log() << kDEBUG << fActivation->GetExpression() << Endl; else Log() << kDEBUG << "" << Endl; } //______________________________________________________________________________ void TMVA::TNeuron::PrintMessage( EMsgType type, TString message) { // print message, for debugging Log() << type << message << Endl; }