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:
35 
36  ProcMLP(const char *name, const Calibration::ProcMLP *calib, const MVAComputer *computer);
37  ~ProcMLP() override {}
38 
39  void configure(ConfIterator iter, unsigned int n) override;
40  void eval(ValueIterator iter, unsigned int n) const override;
41  std::vector<double> deriv(ValueIterator iter, unsigned int n) const override;
42 
43  private:
44  struct Layer {
46  Layer(const Layer &orig)
47  : inputs(orig.inputs), neurons(orig.neurons), coeffs(orig.coeffs), sigmoid(orig.sigmoid) {}
48 
49  unsigned int inputs;
50  unsigned int neurons;
51  std::vector<double> coeffs;
52  bool sigmoid;
53  };
54 
55  std::vector<Layer> layers;
56  unsigned int maxTmp;
57  };
58 
59  ProcMLP::Registry registry("ProcMLP");
60 
62  : inputs(calib.first.front().second.size()), neurons(calib.first.size()), sigmoid(calib.second) {
63  typedef Calibration::ProcMLP::Neuron Neuron;
64 
65  coeffs.resize(neurons * (inputs + 1));
66  std::vector<double>::iterator inserter = coeffs.begin();
67 
68  for (std::vector<Neuron>::const_iterator iter = calib.first.begin(); iter != calib.first.end(); iter++) {
69  *inserter++ = iter->first;
70 
71  if (iter->second.size() != inputs)
72  throw cms::Exception("ProcMLPInput") << "ProcMLP neuron layer inconsistent." << std::endl;
73 
74  inserter = std::copy(iter->second.begin(), iter->second.end(), inserter);
75  }
76  }
77 
78  ProcMLP::ProcMLP(const char *name, const Calibration::ProcMLP *calib, const MVAComputer *computer)
79  : VarProcessor(name, calib, computer), maxTmp(0) {
80  std::copy(calib->layers.begin(), calib->layers.end(), std::back_inserter(layers));
81 
82  for (unsigned int i = 0; i < layers.size(); i++) {
83  maxTmp = std::max<unsigned int>(maxTmp, layers[i].neurons);
84  if (i > 0 && layers[i - 1].neurons != layers[i].inputs)
85  throw cms::Exception("ProcMLPInput") << "ProcMLP neuron layers do not connect "
86  "properly."
87  << std::endl;
88  }
89  }
90 
91  void ProcMLP::configure(ConfIterator iter, unsigned int n) {
92  if (n != layers.front().inputs)
93  return;
94 
95  for (unsigned int i = 0; i < n; i++)
96  iter++(Variable::FLAG_NONE);
97 
98  for (unsigned int i = 0; i < layers.back().neurons; i++)
99  iter << Variable::FLAG_NONE;
100  }
101 
102  void ProcMLP::eval(ValueIterator iter, unsigned int n) const {
103  double *tmp = (double *)alloca(2 * maxTmp * sizeof(double));
104  bool flip = false;
105 
106  for (double *pos = tmp; iter; iter++, pos++)
107  *pos = *iter;
108 
109  double *output = nullptr;
110  for (std::vector<Layer>::const_iterator layer = layers.begin(); layer != layers.end(); layer++, flip = !flip) {
111  const double *input = &tmp[flip ? maxTmp : 0];
112  output = &tmp[flip ? 0 : maxTmp];
113  std::vector<double>::const_iterator coeff = layer->coeffs.begin();
114  for (unsigned int i = 0; i < layer->neurons; i++) {
115  double sum = *coeff++;
116  for (unsigned int j = 0; j < layer->inputs; j++)
117  sum += input[j] * *coeff++;
118  if (layer->sigmoid)
119  sum = 1.0 / (std::exp(-sum) + 1.0);
120  *output++ = sum;
121  }
122  }
123 
124  for (const double *pos = &tmp[flip ? maxTmp : 0]; pos < output; pos++)
125  iter(*pos);
126  }
127 
128  std::vector<double> ProcMLP::deriv(ValueIterator iter, unsigned int n) const {
129  std::vector<double> prevValues, nextValues;
130  std::vector<double> prevMatrix, nextMatrix;
131 
132  while (iter)
133  nextValues.push_back(*iter++);
134 
135  unsigned int size = nextValues.size();
136  nextMatrix.resize(size * size);
137  for (unsigned int i = 0; i < size; i++)
138  nextMatrix[i * size + i] = 1.;
139 
140  for (std::vector<Layer>::const_iterator layer = layers.begin(); layer != layers.end(); layer++) {
141  prevValues.clear();
142  std::swap(prevValues, nextValues);
143  prevMatrix.clear();
144  std::swap(prevMatrix, nextMatrix);
145 
146  std::vector<double>::const_iterator coeff = layer->coeffs.begin();
147  for (unsigned int i = 0; i < layer->neurons; i++) {
148  double sum = *coeff++;
149  for (unsigned int j = 0; j < layer->inputs; j++)
150  sum += prevValues[j] * *coeff++;
151 
152  double deriv;
153  if (layer->sigmoid) {
154  double e = std::exp(-sum);
155  sum = 1.0 / (e + 1.0);
156  deriv = 1.0 / (e + 1.0 / e + 2.0);
157  } else
158  deriv = 1.0;
159 
160  nextValues.push_back(sum);
161 
162  for (unsigned int k = 0; k < size; k++) {
163  sum = 0.0;
164  coeff -= layer->inputs;
165  for (unsigned int j = 0; j < layer->inputs; j++)
166  sum += prevMatrix[j * size + k] * *coeff++;
167  nextMatrix.push_back(sum * deriv);
168  }
169  }
170  }
171 
172  return nextMatrix;
173  }
174 
175 } // anonymous namespace
size
Write out results.
template to generate a registry singleton for a type.
std::pair< std::vector< Neuron >, bool > Layer
Definition: MVAComputer.h:212
static std::string const input
Definition: EdmProvDump.cc:50
SeedingLayerSetsHits::SeedingLayer Layer
Definition: LayerTriplets.h:14
constexpr std::array< uint8_t, layerIndexSize< TrackerTraits > > layer
U second(std::pair< T, U > const &p)
std::pair< double, std::vector< double > > Neuron
Definition: MVAComputer.h:211
Main interface class to the generic discriminator computer framework.
Definition: MVAComputer.h:39
void swap(edm::DataFrameContainer &lhs, edm::DataFrameContainer &rhs)
Definition: output.py:1
void sigmoid(data_T data[CONFIG_T::n_in], res_T res[CONFIG_T::n_in])
tmp
align.sh
Definition: createJobs.py:716
Common base class for variable processors.
Definition: VarProcessor.h:36