Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TMultiLayerPerceptron.cxx
Go to the documentation of this file.
1// @(#)root/mlp:$Id$
2// Author: Christophe.Delaere@cern.ch 20/07/03
3
4/*************************************************************************
5 * Copyright (C) 1995-2003, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12/** \class TMultiLayerPerceptron
13
14
15This class describes a neural network.
16There are facilities to train the network and use the output.
17
18The input layer is made of inactive neurons (returning the
19optionally normalized input) and output neurons are linear.
20The type of hidden neurons is free, the default being sigmoids.
21(One should still try to pass normalized inputs, e.g. between [0.,1])
22
23The basic input is a TTree and two (training and test) TEventLists.
24Input and output neurons are assigned a value computed for each event
25with the same possibilities as for TTree::Draw().
26Events may be weighted individually or via TTree::SetWeight().
276 learning methods are available: kStochastic, kBatch,
28kSteepestDescent, kRibierePolak, kFletcherReeves and kBFGS.
29
30This implementation, written by C. Delaere, is *inspired* from
31the mlpfit package from J.Schwindling et al. with some extensions:
32
33 - the algorithms are globally the same
34 - in TMultilayerPerceptron, there is no limitation on the number of
35 layers/neurons, while MLPFIT was limited to 2 hidden layers
36 - TMultilayerPerceptron allows you to save the network in a root file, and
37 provides more export functionalities
38 - TMultilayerPerceptron gives more flexibility regarding the normalization of
39 inputs/outputs
40 - TMultilayerPerceptron provides, thanks to Andrea Bocci, the possibility to
41 use cross-entropy errors, which allows to train a network for pattern
42 classification based on Bayesian posterior probability.
43
44### Introduction
45
46Neural Networks are more and more used in various fields for data
47analysis and classification, both for research and commercial
48institutions. Some randomly chosen examples are:
49
50 - image analysis
51 - financial movements predictions and analysis
52 - sales forecast and product shipping optimisation
53 - in particles physics: mainly for classification tasks (signal
54 over background discrimination)
55
56More than 50% of neural networks are multilayer perceptrons. This
57implementation of multilayer perceptrons is inspired from the
58<A HREF="http://schwind.home.cern.ch/schwind/MLPfit.html">MLPfit
59package</A> originally written by Jerome Schwindling. MLPfit remains
60one of the fastest tool for neural networks studies, and this ROOT
61add-on will not try to compete on that. A clear and flexible Object
62Oriented implementation has been chosen over a faster but more
63difficult to maintain code. Nevertheless, the time penalty does not
64exceed a factor 2.
65
66### The MLP
67
68The multilayer perceptron is a simple feed-forward network with
69the following structure:
70
71\image html mlp.png
72
73It is made of neurons characterized by a bias and weighted links
74between them (let's call those links synapses). The input neurons
75receive the inputs, normalize them and forward them to the first
76hidden layer.
77
78Each neuron in any subsequent layer first computes a linear
79combination of the outputs of the previous layer. The output of the
80neuron is then function of that combination with <I>f</I> being
81linear for output neurons or a sigmoid for hidden layers. This is
82useful because of two theorems:
83
84 1. A linear combination of sigmoids can approximate any
85 continuous function.
86 2. Trained with output = 1 for the signal and 0 for the
87 background, the approximated function of inputs X is the probability
88 of signal, knowing X.
89
90### Learning methods
91
92The aim of all learning methods is to minimize the total error on
93a set of weighted examples. The error is defined as the sum in
94quadrature, divided by two, of the error on each individual output
95neuron.
96In all methods implemented, one needs to compute
97the first derivative of that error with respect to the weights.
98Exploiting the well-known properties of the derivative, especially the
99derivative of compound functions, one can write:
100
101 - for a neuron: product of the local derivative with the
102 weighted sum on the outputs of the derivatives.
103 - for a synapse: product of the input with the local derivative
104 of the output neuron.
105
106This computation is called back-propagation of the errors. A
107loop over all examples is called an epoch.
108Six learning methods are implemented.
109
110#### Stochastic minimization:
111
112is the most trivial learning method. This is the Robbins-Monro
113stochastic approximation applied to multilayer perceptrons. The
114weights are updated after each example according to the formula:
115\f$w_{ij}(t+1) = w_{ij}(t) + \Delta w_{ij}(t)\f$
116
117with
118
119\f$\Delta w_{ij}(t) = - \eta(d e_p / d w_{ij} + \delta) + \epsilon \Delta w_{ij}(t-1)\f$
120
121The parameters for this method are Eta, EtaDecay, Delta and
122Epsilon.
123
124#### Steepest descent with fixed step size (batch learning):
125
126It is the same as the stochastic
127minimization, but the weights are updated after considering all the
128examples, with the total derivative dEdw. The parameters for this
129method are Eta, EtaDecay, Delta and Epsilon.
130
131#### Steepest descent algorithm:
132
133Weights are set to the minimum along the line defined by the gradient. The
134only parameter for this method is Tau. Lower tau = higher precision =
135slower search. A value Tau = 3 seems reasonable.
136
137#### Conjugate gradients with the Polak-Ribiere updating formula:
138
139Weights are set to the minimum along the line defined by the conjugate gradient.
140Parameters are Tau and Reset, which defines the epochs where the direction is
141reset to the steepest descent.
142
143#### Conjugate gradients with the Fletcher-Reeves updating formula:
144
145Weights are set to the minimum along the line defined by the conjugate gradient. Parameters
146are Tau and Reset, which defines the epochs where the direction is
147reset to the steepest descent.
148
149#### Broyden, Fletcher, Goldfarb, Shanno (BFGS) method:
150
151 Implies the computation of a NxN matrix
152computation, but seems more powerful at least for less than 300
153weights. Parameters are Tau and Reset, which defines the epochs where
154the direction is reset to the steepest descent.
155
156### How to use it...
157
158TMLP is build from 3 classes: TNeuron, TSynapse and
159TMultiLayerPerceptron. Only TMultiLayerPerceptron should be used
160explicitly by the user.
161
162TMultiLayerPerceptron will take examples from a TTree
163given in the constructor. The network is described by a simple
164string: The input/output layers are defined by giving the expression for
165each neuron, separated by comas. Hidden layers are just described
166by the number of neurons. The layers are separated by colons.
167In addition, input/output layer formulas can be preceded by '@' (e.g "@out")
168if one wants to also normalize the data from the TTree.
169Input and outputs are taken from the TTree given as second argument.
170Expressions are evaluated as for TTree::Draw(), arrays are expended in
171distinct neurons, one for each index.
172This can only be done for fixed-size arrays.
173If the formula ends with "!", softmax functions are used for the output layer.
174One defines the training and test datasets by TEventLists.
175
176Example:
177~~~ {.cpp}
178TMultiLayerPerceptron("x,y:10:5:f",inputTree);
179~~~
180
181Both the TTree and the TEventLists can be defined in
182the constructor, or later with the suited setter method. The lists
183used for training and test can be defined either explicitly, or via
184a string containing the formula to be used to define them, exactly as
185for a TCut.
186
187The learning method is defined using the TMultiLayerPerceptron::SetLearningMethod() .
188Learning methods are :
189
190 - TMultiLayerPerceptron::kStochastic,
191 - TMultiLayerPerceptron::kBatch,
192 - TMultiLayerPerceptron::kSteepestDescent,
193 - TMultiLayerPerceptron::kRibierePolak,
194 - TMultiLayerPerceptron::kFletcherReeves,
195 - TMultiLayerPerceptron::kBFGS
196
197A weight can be assigned to events, either in the constructor, either
198with TMultiLayerPerceptron::SetEventWeight(). In addition, the TTree weight
199is taken into account.
200
201Finally, one starts the training with
202TMultiLayerPerceptron::Train(Int_t nepoch, Option_t* options). The
203first argument is the number of epochs while option is a string that
204can contain: "text" (simple text output) , "graph"
205(evoluting graphical training curves), "update=X" (step for
206the text/graph output update) or "+" (will skip the
207randomisation and start from the previous values). All combinations
208are available.
209
210Example:
211~~~ {.cpp}
212net.Train(100,"text, graph, update=10");
213~~~
214
215When the neural net is trained, it can be used
216directly ( TMultiLayerPerceptron::Evaluate() ) or exported to a
217standalone C++ code ( TMultiLayerPerceptron::Export() ).
218
219Finally, note that even if this implementation is inspired from the mlpfit code,
220the feature lists are not exactly matching:
221
222 - mlpfit hybrid learning method is not implemented
223 - output neurons can be normalized, this is not the case for mlpfit
224 - the neural net is exported in C++, FORTRAN or PYTHON
225 - the drawResult() method allows a fast check of the learning procedure
226
227In addition, the paw version of mlpfit had additional limitations on the number of
228neurons, hidden layers and inputs/outputs that does not apply to TMultiLayerPerceptron.
229*/
230
231
233#include "TSynapse.h"
234#include "TNeuron.h"
235#include "TClass.h"
236#include "TTree.h"
237#include "TEventList.h"
238#include "TRandom3.h"
239#include "TTimeStamp.h"
240#include "TRegexp.h"
241#include "TCanvas.h"
242#include "TH2.h"
243#include "TGraph.h"
244#include "TLegend.h"
245#include "TMatrixD.h"
246#include "TMultiGraph.h"
247#include "TDirectory.h"
248#include "TSystem.h"
249#include <iostream>
250#include <fstream>
251#include "TMath.h"
252#include "TTreeFormula.h"
253#include "TTreeFormulaManager.h"
254#include "TMarker.h"
255#include "TLine.h"
256#include "TText.h"
257#include "TObjString.h"
258#include <cstdlib>
259
260
261////////////////////////////////////////////////////////////////////////////////
262/// Default constructor
263
265{
266 if(!TClass::GetClass("TTreePlayer")) gSystem->Load("libTreePlayer");
267 fNetwork.SetOwner(true);
268 fFirstLayer.SetOwner(false);
269 fLastLayer.SetOwner(false);
270 fSynapses.SetOwner(true);
271 fData = nullptr;
272 fCurrentTree = -1;
274 fStructure = "";
275 fWeight = "1";
276 fTraining = nullptr;
277 fTrainingOwner = false;
278 fTest = nullptr;
279 fTestOwner = false;
280 fEventWeight = nullptr;
281 fManager = nullptr;
283 fEta = .1;
284 fEtaDecay = 1;
285 fDelta = 0;
286 fEpsilon = 0;
287 fTau = 3;
288 fLastAlpha = 0;
289 fReset = 50;
292 fextF = "";
293 fextD = "";
294}
295
296////////////////////////////////////////////////////////////////////////////////
297/// The network is described by a simple string:
298/// The input/output layers are defined by giving
299/// the branch names separated by comas.
300/// Hidden layers are just described by the number of neurons.
301/// The layers are separated by colons.
302///
303/// Ex: "x,y:10:5:f"
304///
305/// The output can be prepended by '@' if the variable has to be
306/// normalized.
307/// The output can be followed by '!' to use Softmax neurons for the
308/// output layer only.
309///
310/// Ex: "x,y:10:5:c1,c2,c3!"
311///
312/// Input and outputs are taken from the TTree given as second argument.
313/// training and test are the two TEventLists defining events
314/// to be used during the neural net training.
315/// Both the TTree and the TEventLists can be defined in the constructor,
316/// or later with the suited setter method.
317
322 const char* extF, const char* extD)
323{
324 if(!TClass::GetClass("TTreePlayer")) gSystem->Load("libTreePlayer");
325 fNetwork.SetOwner(true);
326 fFirstLayer.SetOwner(false);
327 fLastLayer.SetOwner(false);
328 fSynapses.SetOwner(true);
330 fData = data;
331 fCurrentTree = -1;
334 fTrainingOwner = false;
335 fTest = test;
336 fTestOwner = false;
337 fWeight = "1";
338 fType = type;
340 fextF = extF;
341 fextD = extD;
342 fEventWeight = nullptr;
343 fManager = nullptr;
344 if (data) {
345 BuildNetwork();
346 AttachData();
347 }
349 fEta = .1;
350 fEpsilon = 0;
351 fDelta = 0;
352 fEtaDecay = 1;
353 fTau = 3;
354 fLastAlpha = 0;
355 fReset = 50;
356}
357
358////////////////////////////////////////////////////////////////////////////////
359/// The network is described by a simple string:
360/// The input/output layers are defined by giving
361/// the branch names separated by comas.
362/// Hidden layers are just described by the number of neurons.
363/// The layers are separated by colons.
364///
365/// Ex: "x,y:10:5:f"
366///
367/// The output can be prepended by '@' if the variable has to be
368/// normalized.
369/// The output can be followed by '!' to use Softmax neurons for the
370/// output layer only.
371///
372/// Ex: "x,y:10:5:c1,c2,c3!"
373///
374/// Input and outputs are taken from the TTree given as second argument.
375/// training and test are the two TEventLists defining events
376/// to be used during the neural net training.
377/// Both the TTree and the TEventLists can be defined in the constructor,
378/// or later with the suited setter method.
379
381 const char * weight, TTree * data,
385 const char* extF, const char* extD)
386{
387 if(!TClass::GetClass("TTreePlayer")) gSystem->Load("libTreePlayer");
388 fNetwork.SetOwner(true);
389 fFirstLayer.SetOwner(false);
390 fLastLayer.SetOwner(false);
391 fSynapses.SetOwner(true);
393 fData = data;
394 fCurrentTree = -1;
397 fTrainingOwner = false;
398 fTest = test;
399 fTestOwner = false;
400 fWeight = weight;
401 fType = type;
403 fextF = extF;
404 fextD = extD;
405 fEventWeight = nullptr;
406 fManager = nullptr;
407 if (data) {
408 BuildNetwork();
409 AttachData();
410 }
412 fEta = .1;
413 fEtaDecay = 1;
414 fDelta = 0;
415 fEpsilon = 0;
416 fTau = 3;
417 fLastAlpha = 0;
418 fReset = 50;
419}
420
421////////////////////////////////////////////////////////////////////////////////
422/// The network is described by a simple string:
423/// The input/output layers are defined by giving
424/// the branch names separated by comas.
425/// Hidden layers are just described by the number of neurons.
426/// The layers are separated by colons.
427///
428/// Ex: "x,y:10:5:f"
429///
430/// The output can be prepended by '@' if the variable has to be
431/// normalized.
432/// The output can be followed by '!' to use Softmax neurons for the
433/// output layer only.
434///
435/// Ex: "x,y:10:5:c1,c2,c3!"
436///
437/// Input and outputs are taken from the TTree given as second argument.
438/// training and test are two cuts (see TTreeFormula) defining events
439/// to be used during the neural net training and testing.
440///
441/// Example: "Entry$%2", "(Entry$+1)%2".
442///
443/// Both the TTree and the cut can be defined in the constructor,
444/// or later with the suited setter method.
445
447 const char * training,
448 const char * test,
450 const char* extF, const char* extD)
451{
452 if(!TClass::GetClass("TTreePlayer")) gSystem->Load("libTreePlayer");
453 fNetwork.SetOwner(true);
454 fFirstLayer.SetOwner(false);
455 fLastLayer.SetOwner(false);
456 fSynapses.SetOwner(true);
458 fData = data;
459 fCurrentTree = -1;
461 {
462 TDirectory::TContext ctxt{nullptr};
463 fTraining = new TEventList(Form("fTrainingList_%zu",(size_t)this));
464 }
465 fTrainingOwner = true;
466 {
467 TDirectory::TContext ctxt{nullptr};
468 fTest = new TEventList(Form("fTestList_%zu",(size_t)this));
469 }
470 fTestOwner = true;
471 fWeight = "1";
473 if(testcut=="") testcut = Form("!(%s)",training);
474 fType = type;
476 fextF = extF;
477 fextD = extD;
478 fEventWeight = nullptr;
479 fManager = nullptr;
480 if (data) {
481 BuildNetwork();
484 data->Draw(Form(">>fTrainingList_%zu",(size_t)this),training,"goff");
485 data->Draw(Form(">>fTestList_%zu",(size_t)this),(const char *)testcut,"goff");
486 fTraining->SetDirectory(nullptr);
487 fTest->SetDirectory(nullptr);
488 AttachData();
489 }
490 else {
491 Warning("TMultiLayerPerceptron::TMultiLayerPerceptron","Data not set. Cannot define datasets");
492 }
494 fEta = .1;
495 fEtaDecay = 1;
496 fDelta = 0;
497 fEpsilon = 0;
498 fTau = 3;
499 fLastAlpha = 0;
500 fReset = 50;
501}
502
503////////////////////////////////////////////////////////////////////////////////
504/// The network is described by a simple string:
505/// The input/output layers are defined by giving
506/// the branch names separated by comas.
507/// Hidden layers are just described by the number of neurons.
508/// The layers are separated by colons.
509///
510/// Ex: "x,y:10:5:f"
511///
512/// The output can be prepended by '@' if the variable has to be
513/// normalized.
514/// The output can be followed by '!' to use Softmax neurons for the
515/// output layer only.
516///
517/// Ex: "x,y:10:5:c1,c2,c3!"
518///
519/// Input and outputs are taken from the TTree given as second argument.
520/// training and test are two cuts (see TTreeFormula) defining events
521/// to be used during the neural net training and testing.
522///
523/// Example: "Entry$%2", "(Entry$+1)%2".
524///
525/// Both the TTree and the cut can be defined in the constructor,
526/// or later with the suited setter method.
527
529 const char * weight, TTree * data,
530 const char * training,
531 const char * test,
533 const char* extF, const char* extD)
534{
535 if(!TClass::GetClass("TTreePlayer")) gSystem->Load("libTreePlayer");
536 fNetwork.SetOwner(true);
537 fFirstLayer.SetOwner(false);
538 fLastLayer.SetOwner(false);
539 fSynapses.SetOwner(true);
541 fData = data;
542 fCurrentTree = -1;
544 {
545 TDirectory::TContext ctxt{nullptr};
546 fTraining = new TEventList(Form("fTrainingList_%zu",(size_t)this));
547 }
548 fTrainingOwner = true;
549 {
550 TDirectory::TContext ctxt{nullptr};
551 fTest = new TEventList(Form("fTestList_%zu",(size_t)this));
552 }
553 fTestOwner = true;
554 fWeight = weight;
556 if(testcut=="") testcut = Form("!(%s)",training);
557 fType = type;
559 fextF = extF;
560 fextD = extD;
561 fEventWeight = nullptr;
562 fManager = nullptr;
563 if (data) {
564 BuildNetwork();
567 data->Draw(Form(">>fTrainingList_%zu",(size_t)this),training,"goff");
568 data->Draw(Form(">>fTestList_%zu",(size_t)this),(const char *)testcut,"goff");
569 fTraining->SetDirectory(nullptr);
570 fTest->SetDirectory(nullptr);
571 AttachData();
572 }
573 else {
574 Warning("TMultiLayerPerceptron::TMultiLayerPerceptron","Data not set. Cannot define datasets");
575 }
577 fEta = .1;
578 fEtaDecay = 1;
579 fDelta = 0;
580 fEpsilon = 0;
581 fTau = 3;
582 fLastAlpha = 0;
583 fReset = 50;
584}
585
586////////////////////////////////////////////////////////////////////////////////
587/// Destructor
588
594
595////////////////////////////////////////////////////////////////////////////////
596/// Set the data source
597
599{
600 if (fData) {
601 std::cerr << "Error: data already defined." << std::endl;
602 return;
603 }
604 fData = data;
605 if (data) {
606 BuildNetwork();
607 AttachData();
608 }
609}
610
611////////////////////////////////////////////////////////////////////////////////
612/// Set the event weight
613
615{
617 if (fData) {
618 if (fEventWeight) {
620 delete fEventWeight;
621 }
622 fManager->Add((fEventWeight = new TTreeFormula("NNweight",fWeight.Data(),fData)));
623 }
624}
625
626////////////////////////////////////////////////////////////////////////////////
627/// Sets the Training dataset.
628/// Those events will be used for the minimization
629
631{
632 if(fTraining && fTrainingOwner) delete fTraining;
633 fTraining = train;
634 fTrainingOwner = false;
635}
636
637////////////////////////////////////////////////////////////////////////////////
638/// Sets the Test dataset.
639/// Those events will not be used for the minimization but for control
640
642{
643 if(fTest && fTestOwner) delete fTest;
644 fTest = test;
645 fTestOwner = false;
646}
647
648////////////////////////////////////////////////////////////////////////////////
649/// Sets the Training dataset.
650/// Those events will be used for the minimization.
651/// Note that the tree must be already defined.
652
654{
655 if(fTraining && fTrainingOwner) delete fTraining;
656 {
657 TDirectory::TContext ctxt{nullptr};
658 fTraining = new TEventList(Form("fTrainingList_%zu",(size_t)this));
659 }
660 fTrainingOwner = true;
661 if (fData) {
663 fData->Draw(Form(">>fTrainingList_%zu",(size_t)this),train,"goff");
664 fTraining->SetDirectory(nullptr);
665 }
666 else {
667 Warning("TMultiLayerPerceptron::TMultiLayerPerceptron","Data not set. Cannot define datasets");
668 }
669}
670
671////////////////////////////////////////////////////////////////////////////////
672/// Sets the Test dataset.
673/// Those events will not be used for the minimization but for control.
674/// Note that the tree must be already defined.
675
677{
678 if(fTest && fTestOwner) {delete fTest; fTest=nullptr;}
679 if(fTest) if(strncmp(fTest->GetName(),Form("fTestList_%zu",(size_t)this),10)) delete fTest;
680 {
682 fTest = new TEventList(Form("fTestList_%zu",(size_t)this));
683 }
684 fTestOwner = true;
685 if (fData) {
687 fData->Draw(Form(">>fTestList_%zu",(size_t)this),test,"goff");
688 fTraining->SetDirectory(nullptr);
689 }
690 else {
691 Warning("TMultiLayerPerceptron::TMultiLayerPerceptron","Data not set. Cannot define datasets");
692 }
693}
694
695////////////////////////////////////////////////////////////////////////////////
696/// Sets the learning method.
697/// Available methods are: kStochastic, kBatch,
698/// kSteepestDescent, kRibierePolak, kFletcherReeves and kBFGS.
699/// (look at the constructor for the complete description
700/// of learning methods and parameters)
701
706
707////////////////////////////////////////////////////////////////////////////////
708/// Sets Eta - used in stochastic minimisation
709/// (look at the constructor for the complete description
710/// of learning methods and parameters)
711
713{
714 fEta = eta;
715}
716
717////////////////////////////////////////////////////////////////////////////////
718/// Sets Epsilon - used in stochastic minimisation
719/// (look at the constructor for the complete description
720/// of learning methods and parameters)
721
726
727////////////////////////////////////////////////////////////////////////////////
728/// Sets Delta - used in stochastic minimisation
729/// (look at the constructor for the complete description
730/// of learning methods and parameters)
731
733{
734 fDelta = delta;
735}
736
737////////////////////////////////////////////////////////////////////////////////
738/// Sets EtaDecay - Eta *= EtaDecay at each epoch
739/// (look at the constructor for the complete description
740/// of learning methods and parameters)
741
746
747////////////////////////////////////////////////////////////////////////////////
748/// Sets Tau - used in line search
749/// (look at the constructor for the complete description
750/// of learning methods and parameters)
751
753{
754 fTau = tau;
755}
756
757////////////////////////////////////////////////////////////////////////////////
758/// Sets number of epochs between two resets of the
759/// search direction to the steepest descent.
760/// (look at the constructor for the complete description
761/// of learning methods and parameters)
762
764{
765 fReset = reset;
766}
767
768////////////////////////////////////////////////////////////////////////////////
769/// Load an entry into the network
770
772{
773 if (!fData) return;
775 if (fData->GetTreeNumber() != fCurrentTree) {
776 ((TMultiLayerPerceptron*)this)->fCurrentTree = fData->GetTreeNumber();
777 fManager->Notify();
778 ((TMultiLayerPerceptron*)this)->fCurrentTreeWeight = fData->GetWeight();
779 }
781 for (Int_t i=0;i<nentries;i++) {
782 TNeuron *neuron = (TNeuron *)fNetwork.UncheckedAt(i);
783 neuron->SetNewEvent();
784 }
785}
786
787////////////////////////////////////////////////////////////////////////////////
788/// Train the network.
789/// nEpoch is the number of iterations.
790/// option can contain:
791/// - "text" (simple text output)
792/// - "graph" (evoluting graphical training curves)
793/// - "update=X" (step for the text/graph output update)
794/// - "+" will skip the randomisation and start from the previous values.
795/// - "current" (draw in the current canvas)
796/// - "minErrorTrain" (stop when NN error on the training sample gets below minE
797/// - "minErrorTest" (stop when NN error on the test sample gets below minE
798/// All combinations are available.
799
801{
802 Int_t i;
803 TString opt = option;
804 opt.ToLower();
805 // Decode options and prepare training.
806 Int_t verbosity = 0;
807 Bool_t newCanvas = true;
808 Bool_t minE_Train = false;
809 Bool_t minE_Test = false;
810 if (opt.Contains("text"))
811 verbosity += 1;
812 if (opt.Contains("graph"))
813 verbosity += 2;
815 if (opt.Contains("update=")) {
816 TRegexp reg("update=[0-9]*");
817 TString out = opt(reg);
818 displayStepping = atoi(out.Data() + 7);
819 }
820 if (opt.Contains("current"))
821 newCanvas = false;
822 if (opt.Contains("minerrortrain"))
823 minE_Train = true;
824 if (opt.Contains("minerrortest"))
825 minE_Test = true;
826 TVirtualPad *canvas = nullptr;
827 TMultiGraph *residual_plot = nullptr;
828 TGraph *train_residual_plot = nullptr;
829 TGraph *test_residual_plot = nullptr;
830 if ((!fData) || (!fTraining) || (!fTest)) {
831 Error("Train","Training/Test samples still not defined. Cannot train the neural network");
832 return;
833 }
834 Info("Train","Using %d train and %d test entries.",
835 fTraining->GetN(), fTest->GetN());
836 // Text and Graph outputs
837 if (verbosity % 2)
838 std::cout << "Training the Neural Network" << std::endl;
839 if (verbosity / 2) {
841 if(newCanvas)
842 canvas = new TCanvas("NNtraining", "Neural Net training");
843 else {
844 canvas = gPad;
845 if(!canvas) canvas = new TCanvas("NNtraining", "Neural Net training");
846 }
849 canvas->SetLeftMargin(0.14);
850 train_residual_plot->SetLineColor(4);
851 test_residual_plot->SetLineColor(2);
854 residual_plot->Draw("LA");
855 if (residual_plot->GetXaxis()) residual_plot->GetXaxis()->SetTitle("Epoch");
856 if (residual_plot->GetYaxis()) residual_plot->GetYaxis()->SetTitle("Error");
857 }
858 // If the option "+" is not set, one has to randomize the weights first
859 if (!opt.Contains("+"))
860 Randomize();
861 // Initialisation
862 fLastAlpha = 0;
864 Double_t *buffer = new Double_t[els];
865 Double_t *dir = new Double_t[els];
866 for (i = 0; i < els; i++)
867 buffer[i] = 0;
870 TMatrixD gamma(matrix_size, 1);
871 TMatrixD delta(matrix_size, 1);
872 // Epoch loop. Here is the training itself.
875 for (Int_t iepoch = 0; (iepoch < nEpoch) && (!minE_Train || training_E>minE) && (!minE_Test || test_E>minE) ; iepoch++) {
876 switch (fLearningMethod) {
878 {
879 MLP_Stochastic(buffer);
880 break;
881 }
883 {
884 ComputeDEDw();
885 MLP_Batch(buffer);
886 break;
887 }
889 {
890 ComputeDEDw();
891 SteepestDir(dir);
892 if (LineSearch(dir, buffer))
893 MLP_Batch(buffer);
894 break;
895 }
897 {
898 ComputeDEDw();
899 if (!(iepoch % fReset)) {
900 SteepestDir(dir);
901 } else {
902 Double_t norm = 0;
903 Double_t onorm = 0;
904 for (i = 0; i < els; i++)
905 onorm += dir[i] * dir[i];
906 Double_t prod = 0;
907 Int_t idx = 0;
908 TNeuron *neuron = nullptr;
909 TSynapse *synapse = nullptr;
911 for (i=0;i<nentries;i++) {
912 neuron = (TNeuron *) fNetwork.UncheckedAt(i);
913 prod -= dir[idx++] * neuron->GetDEDw();
914 norm += neuron->GetDEDw() * neuron->GetDEDw();
915 }
917 for (i=0;i<nentries;i++) {
919 prod -= dir[idx++] * synapse->GetDEDw();
920 norm += synapse->GetDEDw() * synapse->GetDEDw();
921 }
922 ConjugateGradientsDir(dir, (norm - prod) / onorm);
923 }
924 if (LineSearch(dir, buffer))
925 MLP_Batch(buffer);
926 break;
927 }
929 {
930 ComputeDEDw();
931 if (!(iepoch % fReset)) {
932 SteepestDir(dir);
933 } else {
934 Double_t norm = 0;
935 Double_t onorm = 0;
936 for (i = 0; i < els; i++)
937 onorm += dir[i] * dir[i];
938 TNeuron *neuron = nullptr;
939 TSynapse *synapse = nullptr;
941 for (i=0;i<nentries;i++) {
942 neuron = (TNeuron *) fNetwork.UncheckedAt(i);
943 norm += neuron->GetDEDw() * neuron->GetDEDw();
944 }
946 for (i=0;i<nentries;i++) {
948 norm += synapse->GetDEDw() * synapse->GetDEDw();
949 }
951 }
952 if (LineSearch(dir, buffer))
953 MLP_Batch(buffer);
954 break;
955 }
957 {
958 SetGammaDelta(gamma, delta, buffer);
959 if (!(iepoch % fReset)) {
960 SteepestDir(dir);
961 bfgsh.UnitMatrix();
962 } else {
963 if (GetBFGSH(bfgsh, gamma, delta)) {
964 SteepestDir(dir);
965 bfgsh.UnitMatrix();
966 } else {
967 BFGSDir(bfgsh, dir);
968 }
969 }
970 if (DerivDir(dir) > 0) {
971 SteepestDir(dir);
972 bfgsh.UnitMatrix();
973 }
974 if (LineSearch(dir, buffer)) {
975 bfgsh.UnitMatrix();
976 SteepestDir(dir);
977 if (LineSearch(dir, buffer)) {
978 Error("TMultiLayerPerceptron::Train()","Line search fail");
979 iepoch = nEpoch;
980 }
981 }
982 break;
983 }
984 }
985 // Security: would the learning lead to non real numbers,
986 // the learning should stop now.
988 Error("TMultiLayerPerceptron::Train()","Stop.");
989 iepoch = nEpoch;
990 }
991 // Process other ROOT events. Time penalty is less than
992 // 1/1000 sec/evt on a mobile AMD Athlon(tm) XP 1500+
996 // Intermediate graph and text output
997 if ((verbosity % 2) && ((!(iepoch % displayStepping)) || (iepoch == nEpoch - 1))) {
998 std::cout << "Epoch: " << iepoch
999 << " learn=" << training_E
1000 << " test=" << test_E
1001 << std::endl;
1002 }
1003 if (verbosity / 2) {
1006 if (!iepoch) {
1009 for (i = 1; i < nEpoch; i++) {
1010 train_residual_plot->SetPoint(i, i, trp);
1011 test_residual_plot->SetPoint(i, i, tep);
1012 }
1013 }
1014 if ((!(iepoch % displayStepping)) || (iepoch == nEpoch - 1)) {
1015 if (residual_plot->GetYaxis()) {
1016 residual_plot->GetYaxis()->UnZoom();
1017 residual_plot->GetYaxis()->SetTitleOffset(1.4);
1018 residual_plot->GetYaxis()->SetDecimals();
1019 }
1020 canvas->Modified();
1021 canvas->Update();
1022 }
1023 }
1024 }
1025 // Cleaning
1026 delete [] buffer;
1027 delete [] dir;
1028 // Final Text and Graph outputs
1029 if (verbosity % 2)
1030 std::cout << "Training done." << std::endl;
1031 if (verbosity / 2) {
1032 TLegend *legend = new TLegend(.75, .80, .95, .95);
1033 legend->AddEntry(residual_plot->GetListOfGraphs()->At(0),
1034 "Training sample", "L");
1035 legend->AddEntry(residual_plot->GetListOfGraphs()->At(1),
1036 "Test sample", "L");
1037 legend->Draw();
1038 }
1039}
1040
1041////////////////////////////////////////////////////////////////////////////////
1042/// Computes the output for a given event.
1043/// Look at the output neuron designed by index.
1044
1046{
1047 GetEntry(event);
1048 TNeuron *out = (TNeuron *) (fLastLayer.At(index));
1049 if (out)
1050 return out->GetValue();
1051 else
1052 return 0;
1053}
1054
1055////////////////////////////////////////////////////////////////////////////////
1056/// Error on the output for a given event
1057
1059{
1060 GetEntry(event);
1061 Double_t error = 0;
1062 // look at 1st output neuron to determine type and error function
1064 if (nEntries == 0) return 0.0;
1065 switch (fOutType) {
1066 case (TNeuron::kSigmoid):
1067 error = GetCrossEntropyBinary();
1068 break;
1069 case (TNeuron::kSoftmax):
1070 error = GetCrossEntropy();
1071 break;
1072 case (TNeuron::kLinear):
1073 error = GetSumSquareError();
1074 break;
1075 default:
1076 // default to sum-of-squares error
1077 error = GetSumSquareError();
1078 }
1079 error *= fEventWeight->EvalInstance();
1080 error *= fCurrentTreeWeight;
1081 return error;
1082}
1083
1084////////////////////////////////////////////////////////////////////////////////
1085/// Error on the whole dataset
1086
1088{
1089 TEventList *list =
1091 Double_t error = 0;
1092 Int_t i;
1093 if (list) {
1094 Int_t nEvents = list->GetN();
1095 for (i = 0; i < nEvents; i++) {
1096 error += GetError(list->GetEntry(i));
1097 }
1098 } else if (fData) {
1099 Int_t nEvents = (Int_t) fData->GetEntries();
1100 for (i = 0; i < nEvents; i++) {
1101 error += GetError(i);
1102 }
1103 }
1104 return error;
1105}
1106
1107////////////////////////////////////////////////////////////////////////////////
1108/// Error on the output for a given event
1109
1111{
1112 Double_t error = 0;
1113 for (Int_t i = 0; i < fLastLayer.GetEntriesFast(); i++) {
1114 TNeuron *neuron = (TNeuron *) fLastLayer[i];
1115 error += neuron->GetError() * neuron->GetError();
1116 }
1117 return (error / 2.);
1118}
1119
1120////////////////////////////////////////////////////////////////////////////////
1121/// Cross entropy error for sigmoid output neurons, for a given event
1122
1124{
1125 Double_t error = 0;
1126 for (Int_t i = 0; i < fLastLayer.GetEntriesFast(); i++) {
1127 TNeuron *neuron = (TNeuron *) fLastLayer[i];
1128 Double_t output = neuron->GetValue(); // sigmoid output and target
1129 Double_t target = neuron->GetTarget(); // values lie in [0,1]
1130 if (target < DBL_EPSILON) {
1131 if (output == 1.0)
1132 error = DBL_MAX;
1133 else
1134 error -= TMath::Log(1 - output);
1135 } else
1136 if ((1 - target) < DBL_EPSILON) {
1137 if (output == 0.0)
1138 error = DBL_MAX;
1139 else
1140 error -= TMath::Log(output);
1141 } else {
1142 if (output == 0.0 || output == 1.0)
1143 error = DBL_MAX;
1144 else
1145 error -= target * TMath::Log(output / target) + (1-target) * TMath::Log((1 - output)/(1 - target));
1146 }
1147 }
1148 return error;
1149}
1150
1151////////////////////////////////////////////////////////////////////////////////
1152/// Cross entropy error for a softmax output neuron, for a given event
1153
1155{
1156 Double_t error = 0;
1157 for (Int_t i = 0; i < fLastLayer.GetEntriesFast(); i++) {
1158 TNeuron *neuron = (TNeuron *) fLastLayer[i];
1159 Double_t output = neuron->GetValue(); // softmax output and target
1160 Double_t target = neuron->GetTarget(); // values lie in [0,1]
1161 if (target > DBL_EPSILON) { // (target == 0) => dE = 0
1162 if (output == 0.0)
1163 error = DBL_MAX;
1164 else
1165 error -= target * TMath::Log(output / target);
1166 }
1167 }
1168 return error;
1169}
1170
1171////////////////////////////////////////////////////////////////////////////////
1172/// Compute the DEDw = sum on all training events of dedw for each weight
1173/// normalized by the number of events.
1174
1176{
1177 Int_t i,j;
1180 for (i=0;i<nentries;i++) {
1182 synapse->SetDEDw(0.);
1183 }
1184 TNeuron *neuron;
1186 for (i=0;i<nentries;i++) {
1187 neuron = (TNeuron *) fNetwork.UncheckedAt(i);
1188 neuron->SetDEDw(0.);
1189 }
1190 Double_t eventWeight = 1.;
1191 if (fTraining) {
1192 Int_t nEvents = fTraining->GetN();
1193 for (i = 0; i < nEvents; i++) {
1195 eventWeight = fEventWeight->EvalInstance();
1196 eventWeight *= fCurrentTreeWeight;
1198 for (j=0;j<nentries;j++) {
1200 synapse->SetDEDw(synapse->GetDEDw() + (synapse->GetDeDw()*eventWeight));
1201 }
1203 for (j=0;j<nentries;j++) {
1204 neuron = (TNeuron *) fNetwork.UncheckedAt(j);
1205 neuron->SetDEDw(neuron->GetDEDw() + (neuron->GetDeDw()*eventWeight));
1206 }
1207 }
1209 for (j=0;j<nentries;j++) {
1211 synapse->SetDEDw(synapse->GetDEDw() / (Double_t) nEvents);
1212 }
1214 for (j=0;j<nentries;j++) {
1215 neuron = (TNeuron *) fNetwork.UncheckedAt(j);
1216 neuron->SetDEDw(neuron->GetDEDw() / (Double_t) nEvents);
1217 }
1218 } else if (fData) {
1219 Int_t nEvents = (Int_t) fData->GetEntries();
1220 for (i = 0; i < nEvents; i++) {
1221 GetEntry(i);
1222 eventWeight = fEventWeight->EvalInstance();
1223 eventWeight *= fCurrentTreeWeight;
1225 for (j=0;j<nentries;j++) {
1227 synapse->SetDEDw(synapse->GetDEDw() + (synapse->GetDeDw()*eventWeight));
1228 }
1230 for (j=0;j<nentries;j++) {
1231 neuron = (TNeuron *) fNetwork.UncheckedAt(j);
1232 neuron->SetDEDw(neuron->GetDEDw() + (neuron->GetDeDw()*eventWeight));
1233 }
1234 }
1236 for (j=0;j<nentries;j++) {
1238 synapse->SetDEDw(synapse->GetDEDw() / (Double_t) nEvents);
1239 }
1241 for (j=0;j<nentries;j++) {
1242 neuron = (TNeuron *) fNetwork.UncheckedAt(j);
1243 neuron->SetDEDw(neuron->GetDEDw() / (Double_t) nEvents);
1244 }
1245 }
1246}
1247
1248////////////////////////////////////////////////////////////////////////////////
1249/// Randomize the weights
1250
1252{
1254 Int_t j;
1256 TNeuron *neuron;
1257 TTimeStamp ts;
1258 TRandom3 gen(ts.GetSec());
1259 for (j=0;j<nentries;j++) {
1261 synapse->SetWeight(gen.Rndm() - 0.5);
1262 }
1264 for (j=0;j<nentries;j++) {
1265 neuron = (TNeuron *) fNetwork.UncheckedAt(j);
1266 neuron->SetWeight(gen.Rndm() - 0.5);
1267 }
1268}
1269
1270////////////////////////////////////////////////////////////////////////////////
1271/// Connects the TTree to Neurons in input and output
1272/// layers. The formulas associated to each neuron are created
1273/// and reported to the network formula manager.
1274/// By default, the branch is not normalised since this would degrade
1275/// performance for classification jobs.
1276/// Normalisation can be requested by putting '@' in front of the formula.
1277
1279{
1280 Int_t j = 0;
1281 TNeuron *neuron = nullptr;
1282 Bool_t normalize = false;
1284
1285 // Set the size of the internal array of parameters of the formula
1289
1290 //first layer
1291 const TString input = TString(fStructure(0, fStructure.First(':')));
1292 const TObjArray *inpL = input.Tokenize(", ");
1294 // make sure nentries == entries in inpL
1295 R__ASSERT(nentries == inpL->GetLast()+1);
1296 for (j=0;j<nentries;j++) {
1297 normalize = false;
1298 const TString brName = ((TObjString *)inpL->At(j))->GetString();
1299 neuron = (TNeuron *) fFirstLayer.UncheckedAt(j);
1300 if (brName[0]=='@')
1301 normalize = true;
1302 fManager->Add(neuron->UseBranch(fData,brName.Data() + (normalize?1:0)));
1303 if(!normalize) neuron->SetNormalisation(0., 1.);
1304 }
1305 delete inpL;
1306
1307 // last layer
1308 TString output = TString(
1309 fStructure(fStructure.Last(':') + 1,
1310 fStructure.Length() - fStructure.Last(':')));
1311 const TObjArray *outL = output.Tokenize(", ");
1313 // make sure nentries == entries in outL
1314 R__ASSERT(nentries == outL->GetLast()+1);
1315 for (j=0;j<nentries;j++) {
1316 normalize = false;
1317 const TString brName = ((TObjString *)outL->At(j))->GetString();
1318 neuron = (TNeuron *) fLastLayer.UncheckedAt(j);
1319 if (brName[0]=='@')
1320 normalize = true;
1321 fManager->Add(neuron->UseBranch(fData,brName.Data() + (normalize?1:0)));
1322 if(!normalize) neuron->SetNormalisation(0., 1.);
1323 }
1324 delete outL;
1325
1326 fManager->Add((fEventWeight = new TTreeFormula("NNweight",fWeight.Data(),fData)));
1327 //fManager->Sync();
1328
1329 // Set the old values
1331}
1332
1333////////////////////////////////////////////////////////////////////////////////
1334/// Expand the structure of the first layer
1335
1337{
1339 const TObjArray *inpL = input.Tokenize(", ");
1340 Int_t nneurons = inpL->GetLast()+1;
1341
1343 fStructure(fStructure.First(':') + 1,
1344 fStructure.Length() - fStructure.First(':')));
1346 Int_t i = 0;
1347 // loop on input neurons
1348 for (i = 0; i<nneurons; i++) {
1349 const TString name = ((TObjString *)inpL->At(i))->GetString();
1350 TTreeFormula f("sizeTestFormula",name,fData);
1351 // Variable size arrays are unreliable
1352 if(f.GetMultiplicity()==1 && f.GetNdata()>1) {
1353 Warning("TMultiLayerPerceptron::ExpandStructure()","Variable size arrays cannot be used to build implicitly an input layer. The index 0 will be assumed.");
1354 }
1355 // Check if we are coping with an array... then expand
1356 // The array operator used is {}. It is detected in TNeuron, and
1357 // passed directly as instance index of the TTreeFormula,
1358 // so that complex compounds made of arrays can be used without
1359 // parsing the details.
1360 else if(f.GetNdata()>1) {
1361 for(Int_t j=0; j<f.GetNdata(); j++) {
1362 if(i||j) newInput += ",";
1363 newInput += name;
1364 newInput += "{";
1365 newInput += j;
1366 newInput += "}";
1367 }
1368 continue;
1369 }
1370 if(i) newInput += ",";
1371 newInput += name;
1372 }
1373 delete inpL;
1374
1375 // Save the result
1377}
1378
1379////////////////////////////////////////////////////////////////////////////////
1380/// Instantiates the network from the description
1381
1383{
1386 TString hidden = TString(
1387 fStructure(fStructure.First(':') + 1,
1388 fStructure.Last(':') - fStructure.First(':') - 1));
1389 TString output = TString(
1390 fStructure(fStructure.Last(':') + 1,
1391 fStructure.Length() - fStructure.Last(':')));
1392 Int_t bll = atoi(TString(
1393 hidden(hidden.Last(':') + 1,
1394 hidden.Length() - (hidden.Last(':') + 1))).Data());
1395 if (input.Length() == 0) {
1396 Error("BuildNetwork()","malformed structure. No input layer.");
1397 return;
1398 }
1399 if (output.Length() == 0) {
1400 Error("BuildNetwork()","malformed structure. No output layer.");
1401 return;
1402 }
1404 BuildHiddenLayers(hidden);
1405 BuildLastLayer(output, bll);
1406}
1407
1408////////////////////////////////////////////////////////////////////////////////
1409/// Instantiates the neurons in input
1410/// Inputs are normalised and the type is set to kOff
1411/// (simple forward of the formula value)
1412
1414{
1415 const TObjArray *inpL = input.Tokenize(", ");
1416 const Int_t nneurons =inpL->GetLast()+1;
1417 TNeuron *neuron = nullptr;
1418 Int_t i = 0;
1419 for (i = 0; i<nneurons; i++) {
1420 const TString name = ((TObjString *)inpL->At(i))->GetString();
1421 neuron = new TNeuron(TNeuron::kOff, name);
1422 fFirstLayer.AddLast(neuron);
1423 fNetwork.AddLast(neuron);
1424 }
1425 delete inpL;
1426}
1427
1428////////////////////////////////////////////////////////////////////////////////
1429/// Builds hidden layers.
1430
1432{
1433 Int_t beg = 0;
1434 Int_t end = hidden.Index(":", beg + 1);
1435 Int_t prevStart = 0;
1437 Int_t layer = 1;
1438 while (end != -1) {
1439 BuildOneHiddenLayer(hidden(beg, end - beg), layer, prevStart, prevStop, false);
1440 beg = end + 1;
1441 end = hidden.Index(":", beg + 1);
1442 }
1443
1444 BuildOneHiddenLayer(hidden(beg, hidden.Length() - beg), layer, prevStart, prevStop, true);
1445}
1446
1447////////////////////////////////////////////////////////////////////////////////
1448/// Builds a hidden layer, updates the number of layers.
1449
1453{
1454 TNeuron *neuron = nullptr;
1455 TSynapse *synapse = nullptr;
1456 TString name;
1457 if (!sNumNodes.IsAlnum() || sNumNodes.IsAlpha()) {
1458 Error("BuildOneHiddenLayer",
1459 "The specification '%s' for hidden layer %d must contain only numbers!",
1460 sNumNodes.Data(), layer - 1);
1461 } else {
1462 Int_t num = atoi(sNumNodes.Data());
1463 for (Int_t i = 0; i < num; i++) {
1464 name.Form("HiddenL%d:N%d",layer,i);
1465 neuron = new TNeuron(fType, name, "", (const char*)fextF, (const char*)fextD);
1466 fNetwork.AddLast(neuron);
1467 for (Int_t j = prevStart; j < prevStop; j++) {
1468 synapse = new TSynapse((TNeuron *) fNetwork[j], neuron);
1470 }
1471 }
1472
1473 if (!lastLayer) {
1474 // tell each neuron which ones are in its own layer (for Softmax)
1476 for (Int_t i = prevStop; i < nEntries; i++) {
1477 neuron = (TNeuron *) fNetwork[i];
1478 for (Int_t j = prevStop; j < nEntries; j++)
1479 neuron->AddInLayer((TNeuron *) fNetwork[j]);
1480 }
1481 }
1482
1485 layer++;
1486 }
1487}
1488
1489////////////////////////////////////////////////////////////////////////////////
1490/// Builds the output layer
1491/// Neurons are linear combinations of input, by default.
1492/// If the structure ends with "!", neurons are set up for classification,
1493/// ie. with a sigmoid (1 neuron) or softmax (more neurons) activation function.
1494
1496{
1497 Int_t nneurons = output.CountChar(',')+1;
1498 if (fStructure.EndsWith("!")) {
1499 fStructure = TString(fStructure(0, fStructure.Length() - 1)); // remove "!"
1500 if (nneurons == 1)
1502 else
1504 }
1506 Int_t prevStart = prevStop - prev;
1507 Ssiz_t pos = 0;
1508 TNeuron *neuron;
1510 TString name;
1511 Int_t i,j;
1512 for (i = 0; i<nneurons; i++) {
1513 Ssiz_t nextpos=output.Index(",",pos);
1514 if (nextpos!=kNPOS)
1515 name=output(pos,nextpos-pos);
1516 else name=output(pos,output.Length());
1517 pos+=nextpos+1;
1518 neuron = new TNeuron(fOutType, name);
1519 for (j = prevStart; j < prevStop; j++) {
1520 synapse = new TSynapse((TNeuron *) fNetwork[j], neuron);
1522 }
1523 fLastLayer.AddLast(neuron);
1524 fNetwork.AddLast(neuron);
1525 }
1526 // tell each neuron which ones are in its own layer (for Softmax)
1528 for (i = prevStop; i < nEntries; i++) {
1529 neuron = (TNeuron *) fNetwork[i];
1530 for (j = prevStop; j < nEntries; j++)
1531 neuron->AddInLayer((TNeuron *) fNetwork[j]);
1532 }
1533
1534}
1535
1536////////////////////////////////////////////////////////////////////////////////
1537/// Draws the neural net output
1538/// It produces an histogram with the output for the two datasets.
1539/// Index is the number of the desired output neuron.
1540/// "option" can contain:
1541/// - test or train to select a dataset
1542/// - comp to produce a X-Y comparison plot
1543/// - nocanv to not create a new TCanvas for the plot
1544
1546{
1547 TString opt = option;
1548 opt.ToLower();
1549 TNeuron *out = (TNeuron *) (fLastLayer.At(index));
1550 if (!out) {
1551 Error("DrawResult()","no such output.");
1552 return;
1553 }
1554 //TCanvas *canvas = new TCanvas("NNresult", "Neural Net output");
1555 if (!opt.Contains("nocanv"))
1556 new TCanvas("NNresult", "Neural Net output");
1557 const Double_t *norm = out->GetNormalisation();
1558 TEventList *events = nullptr;
1560 Int_t i;
1561 if (opt.Contains("train")) {
1562 events = fTraining;
1563 setname = Form("train%d",index);
1564 } else if (opt.Contains("test")) {
1565 events = fTest;
1566 setname = Form("test%d",index);
1567 }
1568 if ((!fData) || (!events)) {
1569 Error("DrawResult()","no dataset.");
1570 return;
1571 }
1572 if (opt.Contains("comp")) {
1573 //comparison plot
1574 TString title = "Neural Net Output control. ";
1575 title += setname;
1576 setname = "MLP_" + setname + "_comp";
1577 TH2D *hist = ((TH2D *) gDirectory->Get(setname.Data()));
1578 if (!hist)
1579 hist = new TH2D(setname.Data(), title.Data(), 50, -1, 1, 50, -1, 1);
1580 hist->Reset();
1581 Int_t nEvents = events->GetN();
1582 for (i = 0; i < nEvents; i++) {
1583 GetEntry(events->GetEntry(i));
1584 hist->Fill(out->GetValue(), (out->GetBranch() - norm[1]) / norm[0]);
1585 }
1586 hist->Draw();
1587 } else {
1588 //output plot
1589 TString title = "Neural Net Output. ";
1590 title += setname;
1591 setname = "MLP_" + setname;
1592 TH1D *hist = ((TH1D *) gDirectory->Get(setname.Data()));
1593 if (!hist)
1594 hist = new TH1D(setname, title, 50, 1, -1);
1595 hist->Reset();
1596 Int_t nEvents = events->GetN();
1597 for (i = 0; i < nEvents; i++)
1598 hist->Fill(Result(events->GetEntry(i), index));
1599 hist->Draw();
1600 if (opt.Contains("train") && opt.Contains("test")) {
1601 events = fTraining;
1602 setname = "train";
1603 hist = ((TH1D *) gDirectory->Get("MLP_test"));
1604 if (!hist)
1605 hist = new TH1D(setname, title, 50, 1, -1);
1606 hist->Reset();
1607 nEvents = events->GetN();
1608 for (i = 0; i < nEvents; i++)
1609 hist->Fill(Result(events->GetEntry(i), index));
1610 hist->Draw("same");
1611 }
1612 }
1613}
1614
1615////////////////////////////////////////////////////////////////////////////////
1616/// Dumps the weights to a text file.
1617/// Set filename to "-" (default) to dump to the standard output
1618
1620{
1622 std::ostream * output;
1623 if (filen == "") {
1624 Error("TMultiLayerPerceptron::DumpWeights()","Invalid file name");
1625 return kFALSE;
1626 }
1627 if (filen == "-")
1628 output = &std::cout;
1629 else
1630 output = new std::ofstream(filen.Data());
1631 TNeuron *neuron = nullptr;
1632 *output << "#input normalization" << std::endl;
1634 Int_t j=0;
1635 for (j=0;j<nentries;j++) {
1636 neuron = (TNeuron *) fFirstLayer.UncheckedAt(j);
1637 *output << neuron->GetNormalisation()[0] << " "
1638 << neuron->GetNormalisation()[1] << std::endl;
1639 }
1640 *output << "#output normalization" << std::endl;
1642 for (j=0;j<nentries;j++) {
1643 neuron = (TNeuron *) fLastLayer.UncheckedAt(j);
1644 *output << neuron->GetNormalisation()[0] << " "
1645 << neuron->GetNormalisation()[1] << std::endl;
1646 }
1647 *output << "#neurons weights" << std::endl;
1649 while ((neuron = (TNeuron *) it->Next()))
1650 *output << neuron->GetWeight() << std::endl;
1651 delete it;
1653 TSynapse *synapse = nullptr;
1654 *output << "#synapses weights" << std::endl;
1655 while ((synapse = (TSynapse *) it->Next()))
1656 *output << synapse->GetWeight() << std::endl;
1657 delete it;
1658 if (filen != "-") {
1659 ((std::ofstream *) output)->close();
1660 delete output;
1661 }
1662 return kTRUE;
1663}
1664
1665////////////////////////////////////////////////////////////////////////////////
1666/// Loads the weights from a text file conforming to the format
1667/// defined by DumpWeights.
1668
1670{
1672 Double_t w;
1673 if (filen == "") {
1674 Error("TMultiLayerPerceptron::LoadWeights()","Invalid file name");
1675 return kFALSE;
1676 }
1677 char *buff = new char[100];
1678 std::ifstream input(filen.Data());
1679 // input normalzation
1680 input.getline(buff, 100);
1682 Float_t n1,n2;
1683 TNeuron *neuron = nullptr;
1684 while ((neuron = (TNeuron *) it->Next())) {
1685 input >> n1 >> n2;
1686 neuron->SetNormalisation(n2,n1);
1687 }
1688 input.getline(buff, 100);
1689 // output normalization
1690 input.getline(buff, 100);
1691 delete it;
1693 while ((neuron = (TNeuron *) it->Next())) {
1694 input >> n1 >> n2;
1695 neuron->SetNormalisation(n2,n1);
1696 }
1697 input.getline(buff, 100);
1698 // neuron weights
1699 input.getline(buff, 100);
1700 delete it;
1702 while ((neuron = (TNeuron *) it->Next())) {
1703 input >> w;
1704 neuron->SetWeight(w);
1705 }
1706 delete it;
1707 input.getline(buff, 100);
1708 // synapse weights
1709 input.getline(buff, 100);
1711 TSynapse *synapse = nullptr;
1712 while ((synapse = (TSynapse *) it->Next())) {
1713 input >> w;
1714 synapse->SetWeight(w);
1715 }
1716 delete it;
1717 delete[] buff;
1718 return kTRUE;
1719}
1720
1721////////////////////////////////////////////////////////////////////////////////
1722/// Returns the Neural Net for a given set of input parameters
1723/// #%parameters must equal #%input neurons
1724
1726{
1728 TNeuron *neuron;
1729 while ((neuron = (TNeuron *) it->Next()))
1730 neuron->SetNewEvent();
1731 delete it;
1733 Int_t i=0;
1734 while ((neuron = (TNeuron *) it->Next()))
1735 neuron->ForceExternalValue(params[i++]);
1736 delete it;
1737 TNeuron *out = (TNeuron *) (fLastLayer.At(index));
1738 if (out)
1739 return out->GetValue();
1740 else
1741 return 0;
1742}
1743
1744////////////////////////////////////////////////////////////////////////////////
1745/// Exports the NN as a function for any non-ROOT-dependant code
1746/// Supported languages are: only C++ , FORTRAN and Python (yet)
1747/// This feature is also useful if you want to plot the NN as
1748/// a function (TF1 or TF2).
1749
1751{
1753 lg.ToUpper();
1754 Int_t i;
1756 Warning("TMultiLayerPerceptron::Export","Request to export a network using an external function");
1757 }
1758 if (lg == "C++") {
1760 Int_t slash = basefilename.Last('/')+1;
1762
1763 TString classname = basefilename;
1764 TString header = filename;
1765 header += ".h";
1767 source += ".cxx";
1768 std::ofstream headerfile(header);
1769 std::ofstream sourcefile(source);
1770 headerfile << "#ifndef " << basefilename << "_h" << std::endl;
1771 headerfile << "#define " << basefilename << "_h" << std::endl << std::endl;
1772 headerfile << "class " << classname << " { " << std::endl;
1773 headerfile << "public:" << std::endl;
1774 headerfile << " " << classname << "() {}" << std::endl;
1775 headerfile << " ~" << classname << "() {}" << std::endl;
1776 sourcefile << "#include \"" << header << "\"" << std::endl;
1777 sourcefile << "#include <cmath>" << std::endl << std::endl;
1778 headerfile << " double Value(int index";
1779 sourcefile << "double " << classname << "::Value(int index";
1780 for (i = 0; i < fFirstLayer.GetEntriesFast(); i++) {
1781 headerfile << ",double in" << i;
1782 sourcefile << ",double in" << i;
1783 }
1784 headerfile << ");" << std::endl;
1785 sourcefile << ") {" << std::endl;
1786 for (i = 0; i < fFirstLayer.GetEntriesFast(); i++)
1787 sourcefile << " input" << i << " = (in" << i << " - "
1788 << ((TNeuron *) fFirstLayer[i])->GetNormalisation()[1] << ")/"
1789 << ((TNeuron *) fFirstLayer[i])->GetNormalisation()[0] << ";"
1790 << std::endl;
1791 sourcefile << " switch(index) {" << std::endl;
1792 TNeuron *neuron;
1794 Int_t idx = 0;
1795 while ((neuron = (TNeuron *) it->Next()))
1796 sourcefile << " case " << idx++ << ":" << std::endl
1797 << " return neuron" << neuron << "();" << std::endl;
1798 sourcefile << " default:" << std::endl
1799 << " return 0.;" << std::endl << " }"
1800 << std::endl;
1801 sourcefile << "}" << std::endl << std::endl;
1802 headerfile << " double Value(int index, double* input);" << std::endl;
1803 sourcefile << "double " << classname << "::Value(int index, double* input) {" << std::endl;
1804 for (i = 0; i < fFirstLayer.GetEntriesFast(); i++)
1805 sourcefile << " input" << i << " = (input[" << i << "] - "
1806 << ((TNeuron *) fFirstLayer[i])->GetNormalisation()[1] << ")/"
1807 << ((TNeuron *) fFirstLayer[i])->GetNormalisation()[0] << ";"
1808 << std::endl;
1809 sourcefile << " switch(index) {" << std::endl;
1810 delete it;
1812 idx = 0;
1813 while ((neuron = (TNeuron *) it->Next()))
1814 sourcefile << " case " << idx++ << ":" << std::endl
1815 << " return neuron" << neuron << "();" << std::endl;
1816 sourcefile << " default:" << std::endl
1817 << " return 0.;" << std::endl << " }"
1818 << std::endl;
1819 sourcefile << "}" << std::endl << std::endl;
1820 headerfile << "private:" << std::endl;
1821 for (i = 0; i < fFirstLayer.GetEntriesFast(); i++)
1822 headerfile << " double input" << i << ";" << std::endl;
1823 delete it;
1825 idx = 0;
1826 while ((neuron = (TNeuron *) it->Next())) {
1827 if (!neuron->GetPre(0)) {
1828 headerfile << " double neuron" << neuron << "();" << std::endl;
1829 sourcefile << "double " << classname << "::neuron" << neuron
1830 << "() {" << std::endl;
1831 sourcefile << " return input" << idx++ << ";" << std::endl;
1832 sourcefile << "}" << std::endl << std::endl;
1833 } else {
1834 headerfile << " double input" << neuron << "();" << std::endl;
1835 sourcefile << "double " << classname << "::input" << neuron
1836 << "() {" << std::endl;
1837 sourcefile << " double input = " << neuron->GetWeight()
1838 << ";" << std::endl;
1839 TSynapse *syn = nullptr;
1840 Int_t n = 0;
1841 while ((syn = neuron->GetPre(n++))) {
1842 sourcefile << " input += synapse" << syn << "();" << std::endl;
1843 }
1844 sourcefile << " return input;" << std::endl;
1845 sourcefile << "}" << std::endl << std::endl;
1846
1847 headerfile << " double neuron" << neuron << "();" << std::endl;
1848 sourcefile << "double " << classname << "::neuron" << neuron << "() {" << std::endl;
1849 sourcefile << " double input = input" << neuron << "();" << std::endl;
1850 switch(neuron->GetType()) {
1851 case (TNeuron::kSigmoid):
1852 {
1853 sourcefile << " return ((input < -709. ? 0. : (1/(1+exp(-input)))) * ";
1854 break;
1855 }
1856 case (TNeuron::kLinear):
1857 {
1858 sourcefile << " return (input * ";
1859 break;
1860 }
1861 case (TNeuron::kTanh):
1862 {
1863 sourcefile << " return (tanh(input) * ";
1864 break;
1865 }
1866 case (TNeuron::kGauss):
1867 {
1868 sourcefile << " return (exp(-input*input) * ";
1869 break;
1870 }
1871 case (TNeuron::kSoftmax):
1872 {
1873 sourcefile << " return (exp(input) / (";
1874 Int_t nn = 0;
1875 TNeuron* side = neuron->GetInLayer(nn++);
1876 sourcefile << "exp(input" << side << "())";
1877 while ((side = neuron->GetInLayer(nn++)))
1878 sourcefile << " + exp(input" << side << "())";
1879 sourcefile << ") * ";
1880 break;
1881 }
1882 default:
1883 {
1884 sourcefile << " return (0.0 * ";
1885 }
1886 }
1887 sourcefile << neuron->GetNormalisation()[0] << ")+" ;
1888 sourcefile << neuron->GetNormalisation()[1] << ";" << std::endl;
1889 sourcefile << "}" << std::endl << std::endl;
1890 }
1891 }
1892 delete it;
1893 TSynapse *synapse = nullptr;
1895 while ((synapse = (TSynapse *) it->Next())) {
1896 headerfile << " double synapse" << synapse << "();" << std::endl;
1897 sourcefile << "double " << classname << "::synapse"
1898 << synapse << "() {" << std::endl;
1899 sourcefile << " return (neuron" << synapse->GetPre()
1900 << "()*" << synapse->GetWeight() << ");" << std::endl;
1901 sourcefile << "}" << std::endl << std::endl;
1902 }
1903 delete it;
1904 headerfile << "};" << std::endl << std::endl;
1905 headerfile << "#endif // " << basefilename << "_h" << std::endl << std::endl;
1906 headerfile.close();
1907 sourcefile.close();
1908 std::cout << header << " and " << source << " created." << std::endl;
1909 }
1910 else if(lg == "FORTRAN") {
1911 TString implicit = " implicit double precision (a-h,n-z)\n";
1912 std::ofstream sigmoid("sigmoid.f");
1913 sigmoid << " double precision FUNCTION SIGMOID(X)" << std::endl
1914 << implicit
1915 << " IF(X.GT.37.) THEN" << std::endl
1916 << " SIGMOID = 1." << std::endl
1917 << " ELSE IF(X.LT.-709.) THEN" << std::endl
1918 << " SIGMOID = 0." << std::endl
1919 << " ELSE" << std::endl
1920 << " SIGMOID = 1./(1.+EXP(-X))" << std::endl
1921 << " ENDIF" << std::endl
1922 << " END" << std::endl;
1923 sigmoid.close();
1925 source += ".f";
1926 std::ofstream sourcefile(source);
1927
1928 // Header
1929 sourcefile << " double precision function " << filename
1930 << "(x, index)" << std::endl;
1932 sourcefile << " double precision x(" <<
1933 fFirstLayer.GetEntriesFast() << ")" << std::endl << std::endl;
1934
1935 // Last layer
1936 sourcefile << "C --- Last Layer" << std::endl;
1937 TNeuron *neuron;
1939 Int_t idx = 0;
1940 TString ifelseif = " if (index.eq.";
1941 while ((neuron = (TNeuron *) it->Next())) {
1942 sourcefile << ifelseif.Data() << idx++ << ") then" << std::endl
1943 << " " << filename
1944 << "=neuron" << neuron << "(x);" << std::endl;
1945 ifelseif = " else if (index.eq.";
1946 }
1947 sourcefile << " else" << std::endl
1948 << " " << filename << "=0.d0" << std::endl
1949 << " endif" << std::endl;
1950 sourcefile << " end" << std::endl;
1951
1952 // Network
1953 sourcefile << "C --- First and Hidden layers" << std::endl;
1954 delete it;
1956 idx = 0;
1957 while ((neuron = (TNeuron *) it->Next())) {
1958 sourcefile << " double precision function neuron"
1959 << neuron << "(x)" << std::endl
1960 << implicit;
1961 sourcefile << " double precision x("
1962 << fFirstLayer.GetEntriesFast() << ")" << std::endl << std::endl;
1963 if (!neuron->GetPre(0)) {
1964 sourcefile << " neuron" << neuron
1965 << " = (x(" << idx+1 << ") - "
1966 << ((TNeuron *) fFirstLayer[idx])->GetNormalisation()[1]
1967 << "d0)/"
1968 << ((TNeuron *) fFirstLayer[idx])->GetNormalisation()[0]
1969 << "d0" << std::endl;
1970 idx++;
1971 } else {
1972 sourcefile << " neuron" << neuron
1973 << " = " << neuron->GetWeight() << "d0" << std::endl;
1974 TSynapse *syn;
1975 Int_t n = 0;
1976 while ((syn = neuron->GetPre(n++)))
1977 sourcefile << " neuron" << neuron
1978 << " = neuron" << neuron
1979 << " + synapse" << syn << "(x)" << std::endl;
1980 switch(neuron->GetType()) {
1981 case (TNeuron::kSigmoid):
1982 {
1983 sourcefile << " neuron" << neuron
1984 << "= (sigmoid(neuron" << neuron << ")*";
1985 break;
1986 }
1987 case (TNeuron::kLinear):
1988 {
1989 break;
1990 }
1991 case (TNeuron::kTanh):
1992 {
1993 sourcefile << " neuron" << neuron
1994 << "= (tanh(neuron" << neuron << ")*";
1995 break;
1996 }
1997 case (TNeuron::kGauss):
1998 {
1999 sourcefile << " neuron" << neuron
2000 << "= (exp(-neuron" << neuron << "*neuron"
2001 << neuron << "))*";
2002 break;
2003 }
2004 case (TNeuron::kSoftmax):
2005 {
2006 Int_t nn = 0;
2007 TNeuron* side = neuron->GetInLayer(nn++);
2008 sourcefile << " div = exp(neuron" << side << "())" << std::endl;
2009 while ((side = neuron->GetInLayer(nn++)))
2010 sourcefile << " div = div + exp(neuron" << side << "())" << std::endl;
2011 sourcefile << " neuron" << neuron ;
2012 sourcefile << "= (exp(neuron" << neuron << ") / div * ";
2013 break;
2014 }
2015 default:
2016 {
2017 sourcefile << " neuron " << neuron << "= 0.";
2018 }
2019 }
2020 sourcefile << neuron->GetNormalisation()[0] << "d0)+" ;
2021 sourcefile << neuron->GetNormalisation()[1] << "d0" << std::endl;
2022 }
2023 sourcefile << " end" << std::endl;
2024 }
2025 delete it;
2026
2027 // Synapses
2028 sourcefile << "C --- Synapses" << std::endl;
2029 TSynapse *synapse = nullptr;
2031 while ((synapse = (TSynapse *) it->Next())) {
2032 sourcefile << " double precision function " << "synapse"
2033 << synapse << "(x)\n" << implicit;
2034 sourcefile << " double precision x("
2035 << fFirstLayer.GetEntriesFast() << ")" << std::endl << std::endl;
2036 sourcefile << " synapse" << synapse
2037 << "=neuron" << synapse->GetPre()
2038 << "(x)*" << synapse->GetWeight() << "d0" << std::endl;
2039 sourcefile << " end" << std::endl << std::endl;
2040 }
2041 delete it;
2042 sourcefile.close();
2043 std::cout << source << " created." << std::endl;
2044 }
2045 else if(lg == "PYTHON") {
2046 TString classname = filename;
2048 pyfile += ".py";
2049 std::ofstream pythonfile(pyfile);
2050 pythonfile << "from math import exp" << std::endl << std::endl;
2051 pythonfile << "from math import tanh" << std::endl << std::endl;
2052 pythonfile << "class " << classname << ":" << std::endl;
2053 pythonfile << "\tdef value(self,index";
2054 for (i = 0; i < fFirstLayer.GetEntriesFast(); i++) {
2055 pythonfile << ",in" << i;
2056 }
2057 pythonfile << "):" << std::endl;
2058 for (i = 0; i < fFirstLayer.GetEntriesFast(); i++)
2059 pythonfile << "\t\tself.input" << i << " = (in" << i << " - "
2060 << ((TNeuron *) fFirstLayer[i])->GetNormalisation()[1] << ")/"
2061 << ((TNeuron *) fFirstLayer[i])->GetNormalisation()[0] << std::endl;
2062 TNeuron *neuron;
2064 Int_t idx = 0;
2065 while ((neuron = (TNeuron *) it->Next()))
2066 pythonfile << "\t\tif index==" << idx++
2067 << ": return self.neuron" << neuron << "();" << std::endl;
2068 pythonfile << "\t\treturn 0." << std::endl;
2069 delete it;
2071 idx = 0;
2072 while ((neuron = (TNeuron *) it->Next())) {
2073 pythonfile << "\tdef neuron" << neuron << "(self):" << std::endl;
2074 if (!neuron->GetPre(0))
2075 pythonfile << "\t\treturn self.input" << idx++ << std::endl;
2076 else {
2077 pythonfile << "\t\tinput = " << neuron->GetWeight() << std::endl;
2078 TSynapse *syn;
2079 Int_t n = 0;
2080 while ((syn = neuron->GetPre(n++)))
2081 pythonfile << "\t\tinput = input + self.synapse"
2082 << syn << "()" << std::endl;
2083 switch(neuron->GetType()) {
2084 case (TNeuron::kSigmoid):
2085 {
2086 pythonfile << "\t\tif input<-709. : return " << neuron->GetNormalisation()[1] << std::endl;
2087 pythonfile << "\t\treturn ((1/(1+exp(-input)))*";
2088 break;
2089 }
2090 case (TNeuron::kLinear):
2091 {
2092 pythonfile << "\t\treturn (input*";
2093 break;
2094 }
2095 case (TNeuron::kTanh):
2096 {
2097 pythonfile << "\t\treturn (tanh(input)*";
2098 break;
2099 }
2100 case (TNeuron::kGauss):
2101 {
2102 pythonfile << "\t\treturn (exp(-input*input)*";
2103 break;
2104 }
2105 case (TNeuron::kSoftmax):
2106 {
2107 pythonfile << "\t\treturn (exp(input) / (";
2108 Int_t nn = 0;
2109 TNeuron* side = neuron->GetInLayer(nn++);
2110 pythonfile << "exp(self.neuron" << side << "())";
2111 while ((side = neuron->GetInLayer(nn++)))
2112 pythonfile << " + exp(self.neuron" << side << "())";
2113 pythonfile << ") * ";
2114 break;
2115 }
2116 default:
2117 {
2118 pythonfile << "\t\treturn 0.";
2119 }
2120 }
2121 pythonfile << neuron->GetNormalisation()[0] << ")+" ;
2122 pythonfile << neuron->GetNormalisation()[1] << std::endl;
2123 }
2124 }
2125 delete it;
2126 TSynapse *synapse = nullptr;
2128 while ((synapse = (TSynapse *) it->Next())) {
2129 pythonfile << "\tdef synapse" << synapse << "(self):" << std::endl;
2130 pythonfile << "\t\treturn (self.neuron" << synapse->GetPre()
2131 << "()*" << synapse->GetWeight() << ")" << std::endl;
2132 }
2133 delete it;
2134 pythonfile.close();
2135 std::cout << pyfile << " created." << std::endl;
2136 }
2137}
2138
2139////////////////////////////////////////////////////////////////////////////////
2140/// Shuffle the Int_t index[n] in input.
2141///
2142/// Input:
2143/// - index: the array to shuffle
2144/// - n: the size of the array
2145///
2146/// Output:
2147/// - index: the shuffled indexes
2148///
2149/// This method is used for stochastic training
2150
2152{
2153 TTimeStamp ts;
2154 TRandom3 rnd(ts.GetSec());
2155 Int_t j, k;
2156 Int_t a = n - 1;
2157 for (Int_t i = 0; i < n; i++) {
2158 j = (Int_t) (rnd.Rndm() * a);
2159 k = index[j];
2160 index[j] = index[i];
2161 index[i] = k;
2162 }
2163 return;
2164}
2165
2166////////////////////////////////////////////////////////////////////////////////
2167/// One step for the stochastic method
2168/// buffer should contain the previous dw vector and will be updated
2169
2171{
2172 Int_t nEvents = fTraining->GetN();
2173 Int_t *index = new Int_t[nEvents];
2174 Int_t i,j,nentries;
2175 for (i = 0; i < nEvents; i++)
2176 index[i] = i;
2177 fEta *= fEtaDecay;
2178 Shuffle(index, nEvents);
2179 TNeuron *neuron;
2181 for (i = 0; i < nEvents; i++) {
2183 // First compute DeDw for all neurons: force calculation before
2184 // modifying the weights.
2186 for (j=0;j<nentries;j++) {
2187 neuron = (TNeuron *) fFirstLayer.UncheckedAt(j);
2188 neuron->GetDeDw();
2189 }
2190 Int_t cnt = 0;
2191 // Step for all neurons
2193 for (j=0;j<nentries;j++) {
2194 neuron = (TNeuron *) fNetwork.UncheckedAt(j);
2195 buffer[cnt] = (-fEta) * (neuron->GetDeDw() + fDelta)
2196 + fEpsilon * buffer[cnt];
2197 neuron->SetWeight(neuron->GetWeight() + buffer[cnt++]);
2198 }
2199 // Step for all synapses
2201 for (j=0;j<nentries;j++) {
2203 buffer[cnt] = (-fEta) * (synapse->GetDeDw() + fDelta)
2204 + fEpsilon * buffer[cnt];
2205 synapse->SetWeight(synapse->GetWeight() + buffer[cnt++]);
2206 }
2207 }
2208 delete[]index;
2209}
2210
2211////////////////////////////////////////////////////////////////////////////////
2212/// One step for the batch (stochastic) method.
2213/// DEDw should have been updated before calling this.
2214
2216{
2217 fEta *= fEtaDecay;
2218 Int_t cnt = 0;
2220 TNeuron *neuron = nullptr;
2221 // Step for all neurons
2222 while ((neuron = (TNeuron *) it->Next())) {
2223 buffer[cnt] = (-fEta) * (neuron->GetDEDw() + fDelta)
2224 + fEpsilon * buffer[cnt];
2225 neuron->SetWeight(neuron->GetWeight() + buffer[cnt++]);
2226 }
2227 delete it;
2229 TSynapse *synapse = nullptr;
2230 // Step for all synapses
2231 while ((synapse = (TSynapse *) it->Next())) {
2232 buffer[cnt] = (-fEta) * (synapse->GetDEDw() + fDelta)
2233 + fEpsilon * buffer[cnt];
2234 synapse->SetWeight(synapse->GetWeight() + buffer[cnt++]);
2235 }
2236 delete it;
2237}
2238
2239////////////////////////////////////////////////////////////////////////////////
2240/// Sets the weights to a point along a line
2241/// Weights are set to [origin + (dist * dir)].
2242
2244{
2245 Int_t idx = 0;
2246 TNeuron *neuron = nullptr;
2247 TSynapse *synapse = nullptr;
2249 while ((neuron = (TNeuron *) it->Next())) {
2250 neuron->SetWeight(origin[idx] + (dir[idx] * dist));
2251 idx++;
2252 }
2253 delete it;
2255 while ((synapse = (TSynapse *) it->Next())) {
2256 synapse->SetWeight(origin[idx] + (dir[idx] * dist));
2257 idx++;
2258 }
2259 delete it;
2260}
2261
2262////////////////////////////////////////////////////////////////////////////////
2263/// Sets the search direction to steepest descent.
2264
2266{
2267 Int_t idx = 0;
2268 TNeuron *neuron = nullptr;
2269 TSynapse *synapse = nullptr;
2271 while ((neuron = (TNeuron *) it->Next()))
2272 dir[idx++] = -neuron->GetDEDw();
2273 delete it;
2275 while ((synapse = (TSynapse *) it->Next()))
2276 dir[idx++] = -synapse->GetDEDw();
2277 delete it;
2278}
2279
2280////////////////////////////////////////////////////////////////////////////////
2281/// Search along the line defined by direction.
2282/// buffer is not used but is updated with the new dw
2283/// so that it can be used by a later stochastic step.
2284/// It returns true if the line search fails.
2285
2287{
2288 Int_t idx = 0;
2290 TNeuron *neuron = nullptr;
2291 TSynapse *synapse = nullptr;
2292 // store weights before line search
2296 for (j=0;j<nentries;j++) {
2297 neuron = (TNeuron *) fNetwork.UncheckedAt(j);
2298 origin[idx++] = neuron->GetWeight();
2299 }
2301 for (j=0;j<nentries;j++) {
2303 origin[idx++] = synapse->GetWeight();
2304 }
2305 // try to find a triplet (alpha1, alpha2, alpha3) such that
2306 // Error(alpha1)>Error(alpha2)<Error(alpha3)
2308 Double_t alpha1 = 0.;
2310 if (alpha2 < 0.01)
2311 alpha2 = 0.01;
2312 if (alpha2 > 2.0)
2313 alpha2 = 2.0;
2317 Double_t err3 = err2;
2318 Bool_t bingo = false;
2319 Int_t icount;
2320 if (err1 > err2) {
2321 for (icount = 0; icount < 100; icount++) {
2322 alpha3 *= fTau;
2325 if (err3 > err2) {
2326 bingo = true;
2327 break;
2328 }
2329 alpha1 = alpha2;
2330 err1 = err2;
2331 alpha2 = alpha3;
2332 err2 = err3;
2333 }
2334 if (!bingo) {
2336 delete[]origin;
2337 return true;
2338 }
2339 } else {
2340 for (icount = 0; icount < 100; icount++) {
2341 alpha2 /= fTau;
2344 if (err1 > err2) {
2345 bingo = true;
2346 break;
2347 }
2348 alpha3 = alpha2;
2349 err3 = err2;
2350 }
2351 if (!bingo) {
2353 delete[]origin;
2354 fLastAlpha = 0.05;
2355 return true;
2356 }
2357 }
2358 // Sets the weights to the bottom of parabola
2359 fLastAlpha = 0.5 * (alpha1 + alpha3 -
2360 (err3 - err1) / ((err3 - err2) / (alpha3 - alpha2)
2361 - (err2 - err1) / (alpha2 - alpha1)));
2362 fLastAlpha = fLastAlpha < 10000 ? fLastAlpha : 10000;
2365 // Stores weight changes (can be used by a later stochastic step)
2366 idx = 0;
2368 for (j=0;j<nentries;j++) {
2369 neuron = (TNeuron *) fNetwork.UncheckedAt(j);
2370 buffer[idx] = neuron->GetWeight() - origin[idx];
2371 idx++;
2372 }
2374 for (j=0;j<nentries;j++) {
2376 buffer[idx] = synapse->GetWeight() - origin[idx];
2377 idx++;
2378 }
2379 delete[]origin;
2380 return false;
2381}
2382
2383////////////////////////////////////////////////////////////////////////////////
2384/// Sets the search direction to conjugate gradient direction
2385/// beta should be:
2386///
2387/// \f$||g_{(t+1)}||^2 / ||g_{(t)}||^2\f$ (Fletcher-Reeves)
2388///
2389/// \f$g_{(t+1)} (g_{(t+1)}-g_{(t)}) / ||g_{(t)}||^2\f$ (Ribiere-Polak)
2390
2392{
2393 Int_t idx = 0;
2395 TNeuron *neuron = nullptr;
2396 TSynapse *synapse = nullptr;
2398 for (j=0;j<nentries;j++) {
2399 neuron = (TNeuron *) fNetwork.UncheckedAt(j);
2400 dir[idx] = -neuron->GetDEDw() + beta * dir[idx];
2401 idx++;
2402 }
2404 for (j=0;j<nentries;j++) {
2406 dir[idx] = -synapse->GetDEDw() + beta * dir[idx];
2407 idx++;
2408 }
2409}
2410
2411////////////////////////////////////////////////////////////////////////////////
2412/// Computes the hessian matrix using the BFGS update algorithm.
2413/// from gamma (g_{(t+1)}-g_{(t)}) and delta (w_{(t+1)}-w_{(t)}).
2414/// It returns true if such a direction could not be found
2415/// (if gamma and delta are orthogonal).
2416
2418{
2419 TMatrixD gd(gamma, TMatrixD::kTransposeMult, delta);
2420 if ((Double_t) gd[0][0] == 0.)
2421 return true;
2425 Double_t a = 1 / (Double_t) gd[0][0];
2426 Double_t f = 1 + ((Double_t) gHg[0][0] * a);
2427 TMatrixD res( TMatrixD(delta, TMatrixD::kMult,
2429 res *= f;
2430 res -= (TMatrixD(delta, TMatrixD::kMult, tmp) +
2433 res *= a;
2434 bfgsh += res;
2435 return false;
2436}
2437
2438////////////////////////////////////////////////////////////////////////////////
2439/// Sets the gamma \f$(g_{(t+1)}-g_{(t)})\f$ and delta \f$(w_{(t+1)}-w_{(t)})\f$ vectors
2440/// Gamma is computed here, so ComputeDEDw cannot have been called before,
2441/// and delta is a direct translation of buffer into a TMatrixD.
2442
2444 Double_t * buffer)
2445{
2447 Int_t idx = 0;
2449 TNeuron *neuron = nullptr;
2450 TSynapse *synapse = nullptr;
2452 for (j=0;j<nentries;j++) {
2453 neuron = (TNeuron *) fNetwork.UncheckedAt(j);
2454 gamma[idx++][0] = -neuron->GetDEDw();
2455 }
2457 for (j=0;j<nentries;j++) {
2459 gamma[idx++][0] = -synapse->GetDEDw();
2460 }
2461 for (Int_t i = 0; i < els; i++)
2462 delta[i].Assign(buffer[i]);
2463 //delta.SetElements(buffer,"F");
2464 ComputeDEDw();
2465 idx = 0;
2467 for (j=0;j<nentries;j++) {
2468 neuron = (TNeuron *) fNetwork.UncheckedAt(j);
2469 gamma[idx++][0] += neuron->GetDEDw();
2470 }
2472 for (j=0;j<nentries;j++) {
2474 gamma[idx++][0] += synapse->GetDEDw();
2475 }
2476}
2477
2478////////////////////////////////////////////////////////////////////////////////
2479/// scalar product between gradient and direction
2480/// = derivative along direction
2481
2483{
2484 Int_t idx = 0;
2486 Double_t output = 0;
2487 TNeuron *neuron = nullptr;
2488 TSynapse *synapse = nullptr;
2490 for (j=0;j<nentries;j++) {
2491 neuron = (TNeuron *) fNetwork.UncheckedAt(j);
2492 output += neuron->GetDEDw() * dir[idx++];
2493 }
2495 for (j=0;j<nentries;j++) {
2497 output += synapse->GetDEDw() * dir[idx++];
2498 }
2499 return output;
2500}
2501
2502////////////////////////////////////////////////////////////////////////////////
2503/// Computes the direction for the BFGS algorithm as the product
2504/// between the Hessian estimate (bfgsh) and the dir.
2505
2507{
2509 TMatrixD dedw(els, 1);
2510 Int_t idx = 0;
2512 TNeuron *neuron = nullptr;
2513 TSynapse *synapse = nullptr;
2515 for (j=0;j<nentries;j++) {
2516 neuron = (TNeuron *) fNetwork.UncheckedAt(j);
2517 dedw[idx++][0] = neuron->GetDEDw();
2518 }
2520 for (j=0;j<nentries;j++) {
2522 dedw[idx++][0] = synapse->GetDEDw();
2523 }
2525 for (Int_t i = 0; i < els; i++)
2526 dir[i] = -direction[i][0];
2527 //direction.GetElements(dir,"F");
2528}
2529
2530////////////////////////////////////////////////////////////////////////////////
2531/// Draws the network structure.
2532/// Neurons are depicted by a blue disk, and synapses by
2533/// lines connecting neurons.
2534/// The line width is proportional to the weight.
2535
2537{
2538#define NeuronSize 2.5
2539
2541 Float_t xStep = 1./(nLayers+1.);
2542 Int_t layer;
2543 for(layer=0; layer< nLayers-1; layer++) {
2545 if(layer==0) {
2547 nNeurons_this = input.CountChar(',')+1;
2548 }
2549 else {
2550 Int_t cnt=0;
2551 TString hidden = TString(fStructure(fStructure.First(':') + 1,fStructure.Last(':') - fStructure.First(':') - 1));
2552 Int_t beg = 0;
2553 Int_t end = hidden.Index(":", beg + 1);
2554 while (end != -1) {
2555 Int_t num = atoi(TString(hidden(beg, end - beg)).Data());
2556 cnt++;
2557 beg = end + 1;
2558 end = hidden.Index(":", beg + 1);
2559 if(layer==cnt) nNeurons_this = num;
2560 }
2561 Int_t num = atoi(TString(hidden(beg, hidden.Length() - beg)).Data());
2562 cnt++;
2563 if(layer==cnt) nNeurons_this = num;
2564 }
2566 if(layer==nLayers-2) {
2568 nNeurons_next = output.CountChar(',')+1;
2569 }
2570 else {
2571 Int_t cnt=0;
2572 TString hidden = TString(fStructure(fStructure.First(':') + 1,fStructure.Last(':') - fStructure.First(':') - 1));
2573 Int_t beg = 0;
2574 Int_t end = hidden.Index(":", beg + 1);
2575 while (end != -1) {
2576 Int_t num = atoi(TString(hidden(beg, end - beg)).Data());
2577 cnt++;
2578 beg = end + 1;
2579 end = hidden.Index(":", beg + 1);
2580 if(layer+1==cnt) nNeurons_next = num;
2581 }
2582 Int_t num = atoi(TString(hidden(beg, hidden.Length() - beg)).Data());
2583 cnt++;
2584 if(layer+1==cnt) nNeurons_next = num;
2585 }
2589 TSynapse *theSynapse = nullptr;
2590 Float_t maxWeight = 0;
2591 while ((theSynapse = (TSynapse *) it->Next()))
2592 maxWeight = maxWeight < theSynapse->GetWeight() ? theSynapse->GetWeight() : maxWeight;
2593 delete it;
2598 synapse->Draw();
2599 theSynapse = (TSynapse *) it->Next();
2600 if (!theSynapse) continue;
2601 synapse->SetLineWidth(Int_t((theSynapse->GetWeight()/maxWeight)*10.));
2602 synapse->SetLineStyle(1);
2603 if(((TMath::Abs(theSynapse->GetWeight())/maxWeight)*10.)<0.5) synapse->SetLineStyle(2);
2604 if(((TMath::Abs(theSynapse->GetWeight())/maxWeight)*10.)<0.25) synapse->SetLineStyle(3);
2605 }
2606 }
2607 delete it;
2608 }
2609 for(layer=0; layer< nLayers; layer++) {
2610 Float_t nNeurons = 0;
2611 if(layer==0) {
2613 nNeurons = input.CountChar(',')+1;
2614 }
2615 else if(layer==nLayers-1) {
2617 nNeurons = output.CountChar(',')+1;
2618 }
2619 else {
2620 Int_t cnt=0;
2621 TString hidden = TString(fStructure(fStructure.First(':') + 1,fStructure.Last(':') - fStructure.First(':') - 1));
2622 Int_t beg = 0;
2623 Int_t end = hidden.Index(":", beg + 1);
2624 while (end != -1) {
2625 Int_t num = atoi(TString(hidden(beg, end - beg)).Data());
2626 cnt++;
2627 beg = end + 1;
2628 end = hidden.Index(":", beg + 1);
2629 if(layer==cnt) nNeurons = num;
2630 }
2631 Int_t num = atoi(TString(hidden(beg, hidden.Length() - beg)).Data());
2632 cnt++;
2633 if(layer==cnt) nNeurons = num;
2634 }
2635 Float_t yStep = 1./(nNeurons+1.);
2636 for(Int_t neuron=0; neuron<nNeurons; neuron++) {
2637 TMarker* m = new TMarker(xStep*(layer+1),yStep*(neuron+1),20);
2638 m->SetMarkerColor(4);
2640 m->Draw();
2641 }
2642 }
2643 const TString input = TString(fStructure(0, fStructure.First(':')));
2644 const TObjArray *inpL = input.Tokenize(" ,");
2645 const Int_t nrItems = inpL->GetLast()+1;
2646 Float_t yStep = 1./(nrItems+1);
2647 for (Int_t item = 0; item < nrItems; item++) {
2648 const TString brName = ((TObjString *)inpL->At(item))->GetString();
2649 TText* label = new TText(0.5*xStep,yStep*(item+1),brName.Data());
2650 label->Draw();
2651 }
2652 delete inpL;
2653
2655 yStep=1./(numOutNodes+1);
2657 TNeuron* neuron=(TNeuron*)fLastLayer[outnode];
2658 if (neuron && neuron->GetName()) {
2659 TText* label = new TText(xStep*nLayers,
2660 yStep*(outnode+1),
2661 neuron->GetName());
2662 label->Draw();
2663 }
2664 }
2665}
#define f(i)
Definition RSha256.hxx:104
#define a(i)
Definition RSha256.hxx:99
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:60
float Float_t
Float 4 bytes (float)
Definition RtypesCore.h:72
constexpr Bool_t kFALSE
Definition RtypesCore.h:109
double Double_t
Double 8 bytes.
Definition RtypesCore.h:74
constexpr Ssiz_t kNPOS
The equivalent of std::string::npos for the ROOT class TString.
Definition RtypesCore.h:132
constexpr Bool_t kTRUE
Definition RtypesCore.h:108
const char Option_t
Option string (const char)
Definition RtypesCore.h:81
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define gDirectory
Definition TDirectory.h:385
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
Option_t Option_t option
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void input
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t target
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void reg
char name[80]
Definition TGX11.cxx:148
int nentries
TMatrixT< Double_t > TMatrixD
Definition TMatrixDfwd.h:23
#define NeuronSize
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2570
R__EXTERN TSystem * gSystem
Definition TSystem.h:582
#define gPad
static void SetMaxima(Int_t maxop=1000, Int_t maxpar=1000, Int_t maxconst=1000)
static function to set the maximum value of 3 parameters
static void GetMaxima(Int_t &maxop, Int_t &maxpar, Int_t &maxconst)
static function to get the maximum value of 3 parameters -maxop : maximum number of operations -maxpa...
virtual void SetMarkerColor(Color_t mcolor=1)
Set the marker color.
Definition TAttMarker.h:41
virtual void SetMarkerSize(Size_t msize=1)
Set the marker size.
Definition TAttMarker.h:48
virtual void SetLeftMargin(Float_t leftmargin)
Set Pad left margin in fraction of the pad width.
Definition TAttPad.cxx:108
The Canvas class.
Definition TCanvas.h:23
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:2994
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
TDirectory::TContext keeps track and restore the current directory.
Definition TDirectory.h:89
<div class="legacybox"><h2>Legacy Code</h2> TEventList is a legacy interface: there will be no bug fi...
Definition TEventList.h:31
virtual Long64_t GetEntry(Int_t index) const
Return value of entry at index in the list.
virtual Int_t GetN() const
Definition TEventList.h:56
virtual void SetDirectory(TDirectory *dir)
Remove reference to this EventList from current directory and add reference to new directory dir.
A TGraph is an object made of two arrays X and Y with npoints each.
Definition TGraph.h:41
1-D histogram with a double per channel (see TH1 documentation)
Definition TH1.h:926
void Reset(Option_t *option="") override
Reset.
Definition TH1.cxx:10696
virtual Int_t Fill(Double_t x)
Increment bin with abscissa X by 1.
Definition TH1.cxx:3489
void Draw(Option_t *option="") override
Draw this histogram with options.
Definition TH1.cxx:3193
2-D histogram with a double per channel (see TH1 documentation)
Definition TH2.h:400
void Reset(Option_t *option="") override
Reset this histogram: contents, errors, etc.
Definition TH2.cxx:4228
Int_t Fill(Double_t) override
Invalid Fill method.
Definition TH2.cxx:364
This class displays a legend box (TPaveText) containing several legend entries.
Definition TLegend.h:23
Use the TLine constructor to create a simple line.
Definition TLine.h:22
Manages Markers.
Definition TMarker.h:22
void Draw(Option_t *option="") override
Draw this marker with its current attributes.
Definition TMarker.cxx:198
A TMultiGraph is a collection of TGraph (or derived) objects.
Definition TMultiGraph.h:34
This class describes a neural network.
TTreeFormula * fEventWeight
! formula representing the event weight
void BuildOneHiddenLayer(const TString &sNumNodes, Int_t &layer, Int_t &prevStart, Int_t &prevStop, Bool_t lastLayer)
Builds a hidden layer, updates the number of layers.
void SteepestDir(Double_t *)
Sets the search direction to steepest descent.
void BuildNetwork()
Instantiates the network from the description.
TObjArray fNetwork
Collection of all the neurons in the network.
Double_t Evaluate(Int_t index, Double_t *params) const
Returns the Neural Net for a given set of input parameters #parameters must equal #input neurons.
TEventList * fTest
! EventList defining the events in the test dataset
bool GetBFGSH(TMatrixD &, TMatrixD &, TMatrixD &)
Computes the hessian matrix using the BFGS update algorithm.
void BuildHiddenLayers(TString &)
Builds hidden layers.
void BuildFirstLayer(TString &)
Instantiates the neurons in input Inputs are normalised and the type is set to kOff (simple forward o...
void SetTau(Double_t tau)
Sets Tau - used in line search (look at the constructor for the complete description of learning meth...
TMultiLayerPerceptron()
Default constructor.
Double_t GetSumSquareError() const
Error on the output for a given event.
void ConjugateGradientsDir(Double_t *, Double_t)
Sets the search direction to conjugate gradient direction beta should be:
Double_t fTau
! Tau - used in line search - Default=3.
TTree * fData
! pointer to the tree used as datasource
Double_t Result(Int_t event, Int_t index=0) const
Computes the output for a given event.
void SetGammaDelta(TMatrixD &, TMatrixD &, Double_t *)
Sets the gamma and delta vectors Gamma is computed here, so ComputeDEDw cannot have been called bef...
TEventList * fTraining
! EventList defining the events in the training dataset
TString fStructure
String containing the network structure.
Int_t fReset
! number of epochs between two resets of the search direction to the steepest descent - Default=50
Bool_t LoadWeights(Option_t *filename="")
Loads the weights from a text file conforming to the format defined by DumpWeights.
void MLP_Batch(Double_t *)
One step for the batch (stochastic) method.
TNeuron::ENeuronType fOutType
Type of output neurons.
Double_t fCurrentTreeWeight
! weight of the current tree in a chain
ELearningMethod fLearningMethod
! The Learning Method
Double_t fLastAlpha
! internal parameter used in line search
Int_t fCurrentTree
! index of the current tree in a chain
void Export(Option_t *filename="NNfunction", Option_t *language="C++") const
Exports the NN as a function for any non-ROOT-dependant code Supported languages are: only C++ ,...
Double_t fEpsilon
! Epsilon - used in stochastic minimisation - Default=0.
void Train(Int_t nEpoch, Option_t *option="text", Double_t minE=0)
Train the network.
TNeuron::ENeuronType GetType() const
void BFGSDir(TMatrixD &, Double_t *)
Computes the direction for the BFGS algorithm as the product between the Hessian estimate (bfgsh) and...
void SetTestDataSet(TEventList *test)
Sets the Test dataset.
Bool_t fTrainingOwner
! internal flag whether one has to delete fTraining or not
void SetLearningMethod(TMultiLayerPerceptron::ELearningMethod method)
Sets the learning method.
void SetTrainingDataSet(TEventList *train)
Sets the Training dataset.
void BuildLastLayer(TString &, Int_t)
Builds the output layer Neurons are linear combinations of input, by default.
Double_t fDelta
! Delta - used in stochastic minimisation - Default=0.
TTreeFormulaManager * fManager
! TTreeFormulaManager for the weight and neurons
void Randomize() const
Randomize the weights.
Bool_t LineSearch(Double_t *, Double_t *)
Search along the line defined by direction.
void ExpandStructure()
Expand the structure of the first layer.
Double_t fEta
! Eta - used in stochastic minimisation - Default=0.1
Double_t GetError(Int_t event) const
Error on the output for a given event.
Double_t fEtaDecay
! EtaDecay - Eta *= EtaDecay at each epoch - Default=1.
void SetEtaDecay(Double_t ed)
Sets EtaDecay - Eta *= EtaDecay at each epoch (look at the constructor for the complete description o...
void AttachData()
Connects the TTree to Neurons in input and output layers.
void SetData(TTree *)
Set the data source.
void SetEventWeight(const char *)
Set the event weight.
Bool_t DumpWeights(Option_t *filename="-") const
Dumps the weights to a text file.
TString fWeight
String containing the event weight.
void SetDelta(Double_t delta)
Sets Delta - used in stochastic minimisation (look at the constructor for the complete description of...
~TMultiLayerPerceptron() override
Destructor.
Double_t GetCrossEntropy() const
Cross entropy error for a softmax output neuron, for a given event.
void SetReset(Int_t reset)
Sets number of epochs between two resets of the search direction to the steepest descent.
Bool_t fTestOwner
! internal flag whether one has to delete fTest or not
void Shuffle(Int_t *, Int_t) const
Shuffle the Int_t index[n] in input.
Double_t DerivDir(Double_t *)
scalar product between gradient and direction = derivative along direction
void MLP_Stochastic(Double_t *)
One step for the stochastic method buffer should contain the previous dw vector and will be updated.
void Draw(Option_t *option="") override
Draws the network structure.
TObjArray fSynapses
Collection of all the synapses in the network.
void MLP_Line(Double_t *, Double_t *, Double_t)
Sets the weights to a point along a line Weights are set to [origin + (dist * dir)].
TNeuron::ENeuronType fType
Type of hidden neurons.
TObjArray fLastLayer
Collection of the output neurons; subset of fNetwork.
TString fextD
String containing the derivative name.
void ComputeDEDw() const
Compute the DEDw = sum on all training events of dedw for each weight normalized by the number of eve...
Double_t GetCrossEntropyBinary() const
Cross entropy error for sigmoid output neurons, for a given event.
void DrawResult(Int_t index=0, Option_t *option="test") const
Draws the neural net output It produces an histogram with the output for the two datasets.
void SetEta(Double_t eta)
Sets Eta - used in stochastic minimisation (look at the constructor for the complete description of l...
TObjArray fFirstLayer
Collection of the input neurons; subset of fNetwork.
void GetEntry(Int_t) const
Load an entry into the network.
void SetEpsilon(Double_t eps)
Sets Epsilon - used in stochastic minimisation (look at the constructor for the complete description ...
TString fextF
String containing the function name.
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
This class describes an elementary neuron, which is the basic element for a Neural Network.
Definition TNeuron.h:25
Double_t GetWeight() const
Definition TNeuron.h:48
void SetWeight(Double_t w)
Sets the neuron weight to w.
Definition TNeuron.cxx:1144
Double_t GetDEDw() const
Definition TNeuron.h:53
Double_t GetValue() const
Computes the output using the appropriate function and all the weighted inputs, or uses the branch as...
Definition TNeuron.cxx:944
void SetDEDw(Double_t in)
Sets the derivative of the total error wrt the neuron weight.
Definition TNeuron.cxx:1164
Double_t GetDeDw() const
Computes the derivative of the error wrt the neuron weight.
Definition TNeuron.cxx:1080
Double_t GetBranch() const
Returns the formula value.
Definition TNeuron.cxx:910
TNeuron * GetInLayer(Int_t n) const
Definition TNeuron.h:37
Double_t GetError() const
Computes the error for output neurons.
Definition TNeuron.cxx:1059
TTreeFormula * UseBranch(TTree *, const char *)
Sets a formula that can be used to make the neuron an input.
Definition TNeuron.cxx:873
TSynapse * GetPre(Int_t n) const
Definition TNeuron.h:35
void ForceExternalValue(Double_t value)
Uses the branch type to force an external value.
Definition TNeuron.cxx:1121
Double_t GetTarget() const
Computes the normalized target pattern for output neurons.
Definition TNeuron.cxx:1070
const Double_t * GetNormalisation() const
Definition TNeuron.h:50
ENeuronType GetType() const
Returns the neuron type.
Definition TNeuron.cxx:862
void SetNewEvent() const
Inform the neuron that inputs of the network have changed, so that the buffered values have to be rec...
Definition TNeuron.cxx:1153
void SetNormalisation(Double_t mean, Double_t RMS)
Sets the normalization variables.
Definition TNeuron.cxx:1133
void AddInLayer(TNeuron *)
Tells a neuron which neurons form its layer (including itself).
Definition TNeuron.cxx:852
ENeuronType
Definition TNeuron.h:29
@ kLinear
Definition TNeuron.h:29
@ kSigmoid
Definition TNeuron.h:29
@ kExternal
Definition TNeuron.h:29
@ kSoftmax
Definition TNeuron.h:29
@ kGauss
Definition TNeuron.h:29
@ kOff
Definition TNeuron.h:29
@ kTanh
Definition TNeuron.h:29
Iterator of object array.
Definition TObjArray.h:123
TObject * Next() override
Return next object in array. Returns 0 when no more objects in array.
An array of TObjects.
Definition TObjArray.h:31
Int_t GetEntriesFast() const
Definition TObjArray.h:58
TIterator * MakeIterator(Bool_t dir=kIterForward) const override
Returns an array iterator.
TObject * At(Int_t idx) const override
Definition TObjArray.h:170
void AddLast(TObject *obj) override
Add object in the next empty slot in the array.
TObject * UncheckedAt(Int_t i) const
Definition TObjArray.h:90
Collectable string class.
Definition TObjString.h:28
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1082
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1096
virtual void Draw(Option_t *option="")
Default Draw method for all objects.
Definition TObject.cxx:292
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:1070
Random number generator class based on M.
Definition TRandom3.h:27
Regular expression class.
Definition TRegexp.h:31
Basic string class.
Definition TString.h:138
Ssiz_t Length() const
Definition TString.h:427
void ToLower()
Change string to lower-case.
Definition TString.cxx:1189
Bool_t EndsWith(const char *pat, ECaseCompare cmp=kExact) const
Return true if string ends with the specified string.
Definition TString.cxx:2324
Ssiz_t First(char c) const
Find first occurrence of a character c.
Definition TString.cxx:545
const char * Data() const
Definition TString.h:386
Ssiz_t Last(char c) const
Find last occurrence of a character c.
Definition TString.cxx:938
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition TString.cxx:2344
Int_t CountChar(Int_t c) const
Return number of times character c occurs in the string.
Definition TString.cxx:522
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:643
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:662
This is a simple weighted bidirectional connection between two neurons.
Definition TSynapse.h:20
virtual int Load(const char *module, const char *entry="", Bool_t system=kFALSE)
Load a shared library.
Definition TSystem.cxx:1872
virtual Bool_t ProcessEvents()
Process pending events (GUI, timers, sockets).
Definition TSystem.cxx:418
Base class for several text objects.
Definition TText.h:22
The TTimeStamp encapsulates seconds and ns since EPOCH.
Definition TTimeStamp.h:45
Used to coordinate one or more TTreeFormula objects.
bool Notify() override
This method must be overridden to handle object notification (the base implementation is no-op).
virtual void Add(TTreeFormula *)
Add a new formula to the list of formulas managed The manager of the formula will be changed and the ...
virtual void Remove(TTreeFormula *)
Remove a formula from this manager.
Used to pass a selection expression to the Tree drawing routine.
T EvalInstance(Int_t i=0, const char *stringStack[]=nullptr)
Evaluate this treeformula.
A TTree represents a columnar dataset.
Definition TTree.h:89
virtual Int_t GetEntry(Long64_t entry, Int_t getall=0)
Read all branches of entry and return total number of bytes read.
Definition TTree.cxx:5718
virtual Double_t GetWeight() const
Definition TTree.h:631
void Draw(Option_t *opt) override
Default Draw method for all objects.
Definition TTree.h:478
virtual Long64_t GetEntries() const
Definition TTree.h:510
virtual Int_t GetTreeNumber() const
Definition TTree.h:606
TVirtualPad is an abstract base class for the Pad and Canvas classes.
Definition TVirtualPad.h:51
virtual void Modified(Bool_t flag=1)=0
virtual void Update()=0
const Int_t n
Definition legend1.C:16
Bool_t IsNaN(Double_t x)
Definition TMath.h:905
Double_t Log(Double_t x)
Returns the natural logarithm of x.
Definition TMath.h:769
Double_t Sqrt(Double_t x)
Returns the square root of x.
Definition TMath.h:675
Short_t Abs(Short_t d)
Returns the absolute value of parameter Short_t d.
Definition TMathBase.h:122
TCanvas * slash()
Definition slash.C:1
TMarker m
Definition textangle.C:8