CMS 3D CMS Logo

ProcMLP.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: MVAComputer
4 // Class : ProcMLP
5 //
6 
7 // Implementation:
8 // An evaluator for a feed-forward neural net (multi-layer perceptron).
9 // Each layer has (n + 1) x m weights for n input neurons, 1 bias
10 // and m neurons. Also each layer can select between linear and logistic
11 // activation function. The output from the last layer is returned.
12 //
13 // Author: Christophe Saout
14 // Created: Sat Apr 24 15:18 CEST 2007
15 //
16 
17 #include <cstdlib>
18 #include <algorithm>
19 #include <iterator>
20 #include <vector>
21 #include <cmath>
22 
24 
27 
28 using namespace PhysicsTools;
29 
30 namespace { // anonymous
31 
32 class ProcMLP : public VarProcessor {
33  public:
34  typedef VarProcessor::Registry::Registry<ProcMLP,
35  Calibration::ProcMLP> Registry;
36 
37  ProcMLP(const char *name,
39  const MVAComputer *computer);
40  ~ProcMLP() override {}
41 
42  void configure(ConfIterator iter, unsigned int n) override;
43  void eval(ValueIterator iter, unsigned int n) const override;
44  std::vector<double> deriv(
45  ValueIterator iter, unsigned int n) const override;
46 
47  private:
48  struct Layer {
50  Layer(const Layer &orig) :
51  inputs(orig.inputs), neurons(orig.neurons),
52  coeffs(orig.coeffs), sigmoid(orig.sigmoid) {}
53 
54  unsigned int inputs;
55  unsigned int neurons;
56  std::vector<double> coeffs;
57  bool sigmoid;
58  };
59 
60  std::vector<Layer> layers;
61  unsigned int maxTmp;
62 };
63 
64 ProcMLP::Registry registry("ProcMLP");
65 
67  inputs(calib.first.front().second.size()),
68  neurons(calib.first.size()),
69  sigmoid(calib.second)
70 {
71  typedef Calibration::ProcMLP::Neuron Neuron;
72 
73  coeffs.resize(neurons * (inputs + 1));
74  std::vector<double>::iterator inserter = coeffs.begin();
75 
76  for(std::vector<Neuron>::const_iterator iter = calib.first.begin();
77  iter != calib.first.end(); iter++) {
78  *inserter++ = iter->first;
79 
80  if (iter->second.size() != inputs)
81  throw cms::Exception("ProcMLPInput")
82  << "ProcMLP neuron layer inconsistent."
83  << std::endl;
84 
85  inserter = std::copy(iter->second.begin(), iter->second.end(),
86  inserter);
87  }
88 }
89 
90 ProcMLP::ProcMLP(const char *name,
91  const Calibration::ProcMLP *calib,
92  const MVAComputer *computer) :
93  VarProcessor(name, calib, computer),
94  maxTmp(0)
95 {
96  std::copy(calib->layers.begin(), calib->layers.end(),
97  std::back_inserter(layers));
98 
99  for(unsigned int i = 0; i < layers.size(); i++) {
100  maxTmp = std::max<unsigned int>(maxTmp, layers[i].neurons);
101  if (i > 0 && layers[i - 1].neurons != layers[i].inputs)
102  throw cms::Exception("ProcMLPInput")
103  << "ProcMLP neuron layers do not connect "
104  "properly." << std::endl;
105  }
106 }
107 
108 void ProcMLP::configure(ConfIterator iter, unsigned int n)
109 {
110  if (n != layers.front().inputs)
111  return;
112 
113  for(unsigned int i = 0; i < n; i++)
114  iter++(Variable::FLAG_NONE);
115 
116  for(unsigned int i = 0; i < layers.back().neurons; i++)
117  iter << Variable::FLAG_NONE;
118 }
119 
120 void ProcMLP::eval(ValueIterator iter, unsigned int n) const
121 {
122  double *tmp = (double*)alloca(2 * maxTmp * sizeof(double));
123  bool flip = false;
124 
125  for(double *pos = tmp; iter; iter++, pos++)
126  *pos = *iter;
127 
128  double *output = nullptr;
129  for(std::vector<Layer>::const_iterator layer = layers.begin();
130  layer != layers.end(); layer++, flip = !flip) {
131  const double *input = &tmp[flip ? maxTmp : 0];
132  output = &tmp[flip ? 0 : maxTmp];
133  std::vector<double>::const_iterator coeff =
134  layer->coeffs.begin();
135  for(unsigned int i = 0; i < layer->neurons; i++) {
136  double sum = *coeff++;
137  for(unsigned int j = 0; j < layer->inputs; j++)
138  sum += input[j] * *coeff++;
139  if (layer->sigmoid)
140  sum = 1.0 / (std::exp(-sum) + 1.0);
141  *output++ = sum;
142  }
143  }
144 
145  for(const double *pos = &tmp[flip ? maxTmp : 0]; pos < output; pos++)
146  iter(*pos);
147 }
148 
149 std::vector<double> ProcMLP::deriv(ValueIterator iter, unsigned int n) const
150 {
151  std::vector<double> prevValues, nextValues;
152  std::vector<double> prevMatrix, nextMatrix;
153 
154  while(iter)
155  nextValues.push_back(*iter++);
156 
157  unsigned int size = nextValues.size();
158  nextMatrix.resize(size * size);
159  for(unsigned int i = 0; i < size; i++)
160  nextMatrix[i * size + i] = 1.;
161 
162  for(std::vector<Layer>::const_iterator layer = layers.begin();
163  layer != layers.end(); layer++) {
164  prevValues.clear();
165  std::swap(prevValues, nextValues);
166  prevMatrix.clear();
167  std::swap(prevMatrix, nextMatrix);
168 
169  std::vector<double>::const_iterator coeff =
170  layer->coeffs.begin();
171  for(unsigned int i = 0; i < layer->neurons; i++) {
172  double sum = *coeff++;
173  for(unsigned int j = 0; j < layer->inputs; j++)
174  sum += prevValues[j] * *coeff++;
175 
176  double deriv;
177  if (layer->sigmoid) {
178  double e = std::exp(-sum);
179  sum = 1.0 / (e + 1.0);
180  deriv = 1.0 / (e + 1.0/e + 2.0);
181  } else
182  deriv = 1.0;
183 
184  nextValues.push_back(sum);
185 
186  for(unsigned int k = 0; k < size; k++) {
187  sum = 0.0;
188  coeff -= layer->inputs;
189  for(unsigned int j = 0; j < layer->inputs; j++)
190  sum += prevMatrix[j * size + k] *
191  *coeff++;
192  nextMatrix.push_back(sum * deriv);
193  }
194  }
195  }
196 
197  return nextMatrix;
198 }
199 
200 } // anonymous namespace
size
Write out results.
std::vector< LayerSetAndLayers > layers(const SeedingLayerSetsHits &sets)
Definition: LayerTriplets.cc:4
def copy(args, dbName)
template to generate a registry singleton for a type.
std::pair< std::vector< Neuron >, bool > Layer
Definition: MVAComputer.h:209
static std::string const input
Definition: EdmProvDump.cc:44
SeedingLayerSetsHits::SeedingLayer Layer
Definition: LayerTriplets.h:14
U second(std::pair< T, U > const &p)
std::pair< double, std::vector< double > > Neuron
Definition: MVAComputer.h:208
Main interface class to the generic discriminator computer framework.
Definition: MVAComputer.h:39
void swap(edm::DataFrameContainer &lhs, edm::DataFrameContainer &rhs)
int k[5][pyjets_maxn]
std::vector< std::vector< double > > tmp
Definition: MVATrainer.cc:100
static Interceptor::Registry registry("Interceptor")
Common base class for variable processors.
Definition: VarProcessor.h:36