CMS 3D CMS Logo

ProcMLP.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //
00003 // Package:     MVAComputer
00004 // Class  :     ProcMLP
00005 // 
00006 
00007 // Implementation:
00008 //     An evaluator for a feed-forward neural net (multi-layer perceptron).
00009 //     Each layer has (n + 1) x m weights for n input neurons, 1 bias
00010 //     and m neurons. Also each layer can select between linear and logistic
00011 //     activation function. The output from the last layer is returned.
00012 //
00013 // Author:      Christophe Saout
00014 // Created:     Sat Apr 24 15:18 CEST 2007
00015 // $Id: ProcMLP.cc,v 1.3 2007/07/15 22:31:46 saout Exp $
00016 //
00017 
00018 #include <stdlib.h>
00019 #include <algorithm>
00020 #include <iterator>
00021 #include <vector>
00022 #include <cmath>
00023 
00024 #include "FWCore/Utilities/interface/Exception.h"
00025 
00026 #include "PhysicsTools/MVAComputer/interface/VarProcessor.h"
00027 #include "PhysicsTools/MVAComputer/interface/Calibration.h"
00028 
00029 using namespace PhysicsTools;
00030 
00031 namespace { // anonymous
00032 
00033 class ProcMLP : public VarProcessor {
00034     public:
00035         typedef VarProcessor::Registry::Registry<ProcMLP,
00036                                         Calibration::ProcMLP> Registry;
00037 
00038         ProcMLP(const char *name,
00039                  const Calibration::ProcMLP *calib,
00040                  const MVAComputer *computer);
00041         virtual ~ProcMLP() {}
00042 
00043         virtual void configure(ConfIterator iter, unsigned int n);
00044         virtual void eval(ValueIterator iter, unsigned int n) const;
00045 
00046     private:
00047         struct Layer {
00048                 Layer(const Calibration::ProcMLP::Layer &calib);
00049                 Layer(const Layer &orig) :
00050                         inputs(orig.inputs), neurons(orig.neurons),
00051                         coeffs(orig.coeffs), sigmoid(orig.sigmoid) {}
00052 
00053                 unsigned int            inputs;
00054                 unsigned int            neurons;
00055                 std::vector<double>     coeffs;
00056                 bool                    sigmoid;
00057         };
00058 
00059         std::vector<Layer>      layers;
00060         unsigned int            maxTmp;
00061 };
00062 
00063 static ProcMLP::Registry registry("ProcMLP");
00064 
00065 ProcMLP::Layer::Layer(const Calibration::ProcMLP::Layer &calib) :
00066         inputs(calib.first.front().second.size()),
00067         neurons(calib.first.size()),
00068         sigmoid(calib.second)
00069 {
00070         typedef Calibration::ProcMLP::Neuron Neuron;
00071 
00072         coeffs.resize(neurons * (inputs + 1));
00073         std::vector<double>::iterator inserter = coeffs.begin();
00074 
00075         for(std::vector<Neuron>::const_iterator iter = calib.first.begin();
00076             iter != calib.first.end(); iter++) {
00077                 *inserter++ = iter->first;
00078 
00079                 if (iter->second.size() != inputs)
00080                         throw cms::Exception("ProcMLPInput")
00081                                 << "ProcMLP neuron layer inconsistent."
00082                                 << std::endl;
00083 
00084                 inserter = std::copy(iter->second.begin(), iter->second.end(),
00085                                      inserter);
00086         }
00087 }
00088 
00089 ProcMLP::ProcMLP(const char *name,
00090                    const Calibration::ProcMLP *calib,
00091                    const MVAComputer *computer) :
00092         VarProcessor(name, calib, computer),
00093         maxTmp(0)
00094 {
00095         std::copy(calib->layers.begin(), calib->layers.end(),
00096                   std::back_inserter(layers));
00097 
00098         for(unsigned int i = 0; i < layers.size(); i++) {
00099                 maxTmp = std::max<unsigned int>(maxTmp, layers[i].neurons);
00100                 if (i > 0 && layers[i - 1].neurons != layers[i].inputs)
00101                         throw cms::Exception("ProcMLPInput")
00102                                 << "ProcMLP neuron layers do not connect "
00103                                 "properly." << std::endl;
00104         }
00105 }
00106 
00107 void ProcMLP::configure(ConfIterator iter, unsigned int n)
00108 {
00109         if (n != layers.front().inputs)
00110                 return;
00111 
00112         for(unsigned int i = 0; i < n; i++)
00113                 iter++(Variable::FLAG_NONE);
00114 
00115         for(unsigned int i = 0; i < layers.back().neurons; i++)
00116                 iter << Variable::FLAG_NONE;
00117 }
00118 
00119 void ProcMLP::eval(ValueIterator iter, unsigned int n) const
00120 {
00121         double *tmp = (double*)alloca(2 * maxTmp * sizeof(double));
00122         bool flip = false;
00123 
00124         for(double *pos = tmp; iter; iter++, pos++)
00125                 *pos = *iter;
00126 
00127         double *output = 0;
00128         for(std::vector<Layer>::const_iterator layer = layers.begin();
00129             layer != layers.end(); layer++, flip = !flip) {
00130                 const double *input = &tmp[flip ? maxTmp : 0];
00131                 output = &tmp[flip ? 0 : maxTmp];
00132                 std::vector<double>::const_iterator coeff =
00133                                                         layer->coeffs.begin();
00134                 for(unsigned int i = 0; i < layer->neurons; i++) {
00135                         double sum = *coeff++;
00136                         for(unsigned int j = 0; j < layer->inputs; j++)
00137                                 sum += input[j] * *coeff++;
00138                         if (layer->sigmoid)
00139                                 sum = 1.0 / (std::exp(-sum) + 1.0);
00140                         *output++ = sum;
00141                 }
00142         }
00143 
00144         for(const double *pos = &tmp[flip ? maxTmp : 0]; pos < output; pos++)
00145                 iter(*pos);
00146 }
00147 
00148 } // anonymous namespace

Generated on Tue Jun 9 17:41:28 2009 for CMSSW by  doxygen 1.5.4