elmTutorial.cpp
Go to the documentation of this file.
1 //headers needed for ELM
4 #include <shark/Models/FFNet.h>
7 
8 //header needed for the problem
10 
11 //just for evaluation of the ELM
13 #include <iostream>
14 using namespace std;
15 using namespace shark;
16 
17 //In this example an extreme learning machine is constructed and
18 //trained. An ELM is a neural net with one single hidden layer. The
19 //weight of the hidden neurons are random and only the outputs are
20 //trained. This makes the learning problem much easier since the
21 //remaining linear weights form a convex problem. in principle, the
22 //ELM can be constructed using a simple FFNet. But this would mean
23 //that we had to calculate the weight vector for the FFNet - which is
24 //not trivial. Instead we will construct the ELM out of one FFNet and
25 //two linear networks. That's a bit slower but usually not a problem
26 
27 ///Our problem:
28 ///z = sin(x)/x+y+noise
29 /// @cond EXAMPLE_SYMBOLS
30 class Problem:public LabeledDataDistribution<RealVector,RealVector>{
31 public:
32  void draw(RealVector& input, RealVector& label)const
33  {
34  input.resize(2);
35  label.resize(1);
36  input(0) = random::uni(random::globalRng, -5, 5);
37  input(1) = random::uni(random::globalRng, -5, 5);
38  if(input(0) != 0)
39  label(0) = sin(input(0)) / input(0) + input(1) + random::gauss(random::globalRng, 0.0, 0.1);
40  else
41  label(0) = 1 + input(1) + random::gauss(random::globalRng, 0.0, 0.1);
42  }
43 };
44 /// @endcond
45 
46 int main(){
47  //change these constants for your own problem
48  size_t hiddenNeurons = 17;
49  size_t numSamples = 1000;
50  unsigned int randomSeed = 42;
51 
52  //configure random number generator
53  random::globalRng.seed(randomSeed);
54 
55  //create the regression problem
56  Problem problem;
57  RegressionDataset data = problem.generateDataset(numSamples);
58  size_t inputDim = inputDimension(data);
59 
60  //usually an elm uses zero mean unit variance inputs. so we should
61  //normalize the data first
62  Normalizer<> normalizer;
63  NormalizeComponentsUnitVariance<> normalizingTrainer(true);
64  normalizingTrainer.train(normalizer,data.inputs());
65 
66  // now we construct the hidden layer of the elm
67  // we create a two layer network and initialize it randomly. By keeping the random
68  // hidden weights and only learning the visible later, we will create the elm
69  FFNet<LogisticNeuron,LinearNeuron> elmNetwork;
70  elmNetwork.setStructure(inputDim,hiddenNeurons,labelDimension(data));
71  initRandomNormal(elmNetwork,1);
72 
73  //We need to train the linear part. in this simple example we use the elm standard
74  //technique: linear regression. For this we need to propagate the data first
75  // through the normalization and the hidden layer of the elm
76  RegressionDataset transformedData = transformInputs(data,normalizer);
77  transformedData.inputs() = elmNetwork.evalLayer(0,transformedData.inputs());
78  LinearModel<> elmOutput;
79  LinearRegression trainer;
80  trainer.train(elmOutput,transformedData);
81 
82  //we need to set the learned weights of the hidden layer of the elm
83  elmNetwork.setLayer(1,elmOutput.matrix(),elmOutput.offset());
84 
85 
86  ConcatenatedModel<RealVector,RealVector> elm = normalizer >> elmNetwork;
87  //to test whether everything works, we will evaluate the elm and the elmOutput layer separately
88  //both results should be identical
89  SquaredLoss<> loss;
90  double outputResult = loss(transformedData.labels(),elmOutput(transformedData.inputs()));
91  double elmResult = loss(transformedData.labels(),elm(data.inputs()));
92 
93  cout<<"Results"<<std::endl;
94  cout<<"============"<<std::endl;
95  cout<<"output Layer: "<< outputResult<<std::endl;
96  cout<<"ELM: "<< elmResult<<std::endl;
97 }