NeuralNetwork.cpp

Go to the documentation of this file.
00001 #include "NeuralNetwork.h"
00002 #include "UniformRNG.h"
00003 #include "Adaptors.h"
00004 #include "FatalException.h"
00005 #include <algorithm>
00006 #include <iostream>
00007 #include <fstream>
00008 
00009 using namespace std;
00010 
00011 namespace gplib
00012   {
00013     NeuralNetwork::NeuralNetwork(const int inputsize, const int outputsize) :
00014       AdaptiveFilter(inputsize, outputsize), alpha(0.0), mu(0.0), LocInput(
00015           inputsize, 0.0), LocOutput(outputsize, 0.0), LocDesired(outputsize,
00016           0.0)
00017       {
00018       }
00019 
00020     NeuralNetwork::NeuralNetwork(const int inputsize, const int outputsize,
00021         const double mu_, const ttypeArray &Layersetup, const double maxinit,
00022         bool cachedoutput) :
00023       AdaptiveFilter(inputsize, outputsize), alpha(0.0), mu(mu_), LocInput(
00024           inputsize, 0.0), LocOutput(outputsize, 0.0), LocDesired(outputsize,
00025           0.0)
00026       {
00027         SetLayers(Layersetup, cachedoutput);
00028         InitWeights(maxinit, maxinit);
00029       }
00030 
00031     NeuralNetwork::~NeuralNetwork()
00032       {
00033       }
00034 
00035     void NeuralNetwork::AdaptFilter(const gplib::rvec &Input,
00036         const gplib::rvec &Desired)
00037       {
00038         if (Desired.size() != LocDesired.size())
00039           throw FatalException("Input does not match network geometry !");
00040         copy(Desired.begin(), Desired.end(), LocDesired.begin());
00041         AdaptWeights();
00042         SetEpsilon(Desired - GetFilterOutput());
00043       }
00044 
00045     void NeuralNetwork::CalcOutput(const gplib::rvec &Input,
00046         gplib::rvec &Output)
00047       {
00048         if (Input.size() != LocInput.size())
00049           throw FatalException("Input does not match network geometry !");
00050         copy(Input.begin(), Input.end(), LocInput.begin());
00051         CalcOutput();
00052         if (Output.size() != LocOutput.size())
00053           throw FatalException("Output does not match network geometry !");
00054         copy(LocOutput.begin(), LocOutput.end(), Output.begin());
00055         SetOutput(Output);
00056       }
00057 
00058     const gplib::rvec &NeuralNetwork::GetWeightsAsVector()
00059       {
00060         size_t size = 0;
00061         for (size_t i = 1; i < Layers.size(); ++i)
00062           {
00063             for (size_t j = 0; j < Layers.at(i).size(); ++j)
00064               size += Layers.at(i).at(j)->GetWeights().size();
00065           }
00066         gplib::rvec temp(size);
00067         size_t currstart = 0;
00068         for (size_t i = 1; i < Layers.size(); ++i)
00069           {
00070             for (size_t j = 0; j < Layers.at(i).size(); ++j)
00071               {
00072                 for (size_t k = 0; k < Layers.at(i).at(j)->GetWeights().size(); ++k)
00073                   temp(currstart + k) = Layers.at(i).at(j)->GetWeights().at(k);
00074                 currstart += Layers.at(i).at(j)->GetWeights().size();
00075               }
00076           }
00077         WeightsAsVector = temp;
00078         return WeightsAsVector;
00079       }
00080 
00081     void NeuralNetwork::SetLayers(ttypeArray typeArray, bool cachedoutput)
00082       {
00083         tNeuralLayer CurrentLayer;
00084         GeneralLinearCombiner::tinvector inputvector;
00085 
00086         const size_t nlayers = typeArray.size();
00087         LocOutput.assign(typeArray.back().size(), 0);
00088         LocDesired.assign(typeArray.back().size(), 0);
00089         for (size_t i = 0; i < LocInput.size(); ++i)
00090           CurrentLayer.push_back(boost::shared_ptr<GeneralNeuron>(
00091               new InputNeuron(LocInput.at(i))));
00092         Layers.push_back(CurrentLayer);
00093         CurrentLayer.clear();
00094         cout << "Nlayers: " << nlayers << endl;
00095         for (size_t i = 0; i < nlayers; ++i)
00096           {
00097             for (size_t j = 0; j < typeArray.at(i).size(); ++j)
00098               {
00099                 CurrentLayer.push_back(boost::shared_ptr<GeneralNeuron>(
00100                     new SigmoidalNeuron(typeArray.at(i).at(j), cachedoutput)));
00101               }
00102             Layers.push_back(CurrentLayer);
00103             CurrentLayer.clear();
00104           }
00105         for (size_t i = 1; i < nlayers + 1; ++i)
00106           {
00107             inputvector.clear();
00108             const size_t prevsize = Layers.at(i - 1).size();
00109             cout << "Previous layer size: " << prevsize << endl;
00110             for (size_t j = 0; j < prevsize; ++j)
00111               {
00112                 inputvector.push_back(Layers.at(i - 1).at(j));
00113               }
00114             for (size_t j = 0; j < Layers.at(i).size(); ++j)
00115               {
00116                 Layers.at(i).at(j)->SetInput(inputvector);
00117                 Layers.at(i).at(j)->SetOldDelta().assign(prevsize, 0.0);
00118               }
00119           }
00120       }
00121 
00122     void NeuralNetwork::InitWeights(const double MaxWeight,
00123         const double MaxBias)
00124       {
00125         UniformRNG Random;
00126         for (size_t i = 1; i < Layers.size(); ++i)
00127           for (size_t j = 0; j < Layers.at(i).size(); ++j)
00128             {
00129               for (size_t k = 0; k < Layers.at(i).at(j)->GetWeights().size(); ++k)
00130                 {
00131                   Layers.at(i).at(j)->SetWeights().at(k) = Random.GetNumber(
00132                       -MaxWeight, MaxWeight);
00133                   Layers.at(i).at(j)->SetOldDelta().at(k) = 0.0;
00134                 }
00135               Layers.at(i).at(j)->SetBias(Random.GetNumber(-MaxBias, MaxBias));
00136             }
00137       }
00138 
00139     std::vector<double> &NeuralNetwork::CalcOutput()
00140       {
00141         gplib::rvec temp(LocOutput.size());
00142         for (size_t i = 0; i < Layers.back().size(); ++i)
00143           {
00144             LocOutput.at(i) = Layers.back().at(i)->GetOutput();
00145           }
00146         return LocOutput;
00147       }
00148 
00149     void NeuralNetwork::AdaptWeights()
00150       {
00151         tNeuralArray::iterator previouslayer = (Layers.end() - 2);
00152         tNeuralArray::iterator currlayer = (Layers.end() - 1);
00153         double correction = 0.0;
00154         for (size_t i = 0; i < previouslayer->size(); ++i)
00155           previouslayer->at(i)->SetDelta(0.0);
00156         for (size_t j = 0; j < currlayer->size(); ++j)
00157           {
00158             // Delta for the last layer depends on the difference between output and reference
00159             currlayer->at(j)->SetDelta(Layers.back().at(j)->CalcDeriv(
00160                 Layers.back().at(j)->GetNet()) * (LocDesired.at(j)
00161                 - LocOutput.at(j)));
00162             //follow all the weights to update delta for the previous layer
00163             for (size_t i = 0; i < currlayer->at(j)->GetWeights().size(); ++i)
00164               {
00165                 currlayer->at(j)->GetInput().at(i)->SetDelta(
00166                     currlayer->at(j)->GetInput().at(i)->GetDelta()
00167                         + currlayer->at(j)->GetWeights().at(i) * currlayer->at(
00168                             j)->GetDelta());
00169                 //calculate the correction for the last layer
00170                 correction = alpha * currlayer->at(j)->GetOldDelta().at(i) + mu
00171                     * (previouslayer->at(i)->GetLastOutput())
00172                     * Layers.back().at(j)->GetDelta();
00173                 currlayer->at(j)->SetWeights().at(i) += correction;
00174                 currlayer->at(j)->SetOldDelta().at(i) = correction;
00175               }
00176             currlayer->at(j)->SetBias(Layers.back().at(j)->GetBias() + mu
00177                 * Layers.back().at(j)->GetDelta());
00178           }
00179         //for all layers but the last and the first one
00180         for (size_t i = Layers.size() - 2; i >= 1; --i)
00181           {
00182             //initialize delta for previous layer
00183             for (size_t j = 0; j < Layers.at(i - 1).size(); ++j)
00184               Layers.at(i - 1).at(j)->SetDelta(0.0);
00185             //for all neurons in the current layer
00186             for (tNeuralLayer::iterator currneuron = Layers.at(i).begin(); currneuron
00187                 < Layers.at(i).end(); ++currneuron)
00188               {
00189                 //multiply delta of current neuron by derivative of activation function
00190                 currneuron->get()->SetDelta(currneuron->get()->GetDelta()
00191                     * currneuron->get()->CalcDeriv(currneuron->get()->GetNet()));
00192                 //for all weights of the current neuron
00193                 for (size_t k = 0; k < currneuron->get()->GetWeights().size(); ++k)
00194                   {
00195                     //propagate delta along the weight to the previous layer
00196                     currneuron->get()->GetInput().at(k)->SetDelta(
00197                         currneuron->get()->GetInput().at(k)->GetDelta()
00198                             + currneuron->get()->GetWeights().at(k)
00199                                 * currneuron->get()->GetDelta());
00200                     //calculate the correction for the current layer
00201                     correction
00202                         = alpha * currneuron->get()->GetOldDelta().at(k)
00203                             + mu
00204                                 * currneuron->get()->GetInput().at(k)->GetLastOutput()
00205                                 * currneuron->get()->GetDelta();
00206                     //apply weight correction
00207                     currneuron->get()->SetWeights().at(k) += correction;
00208                     //store weight correction for feedback loop
00209                     currneuron->get()->SetOldDelta().at(k) = correction;
00210                   }
00211 
00212                 currneuron->get()->SetBias(currneuron->get()->GetBias() + mu
00213                     * currneuron->get()->GetDelta());
00214               }
00215           }
00216         //we do not have to consider the first layer, it only gets the input
00217       }
00218 
00219     void NeuralNetwork::PrintWeights(ostream &output)
00220       {
00221         for (size_t i = 1; i < Layers.size(); ++i)
00222           {
00223             for (size_t j = 0; j < Layers.at(i).size(); ++j)
00224               {
00225                 copy(Layers.at(i).at(j)->GetWeights().begin(), Layers.at(i).at(
00226                     j)->GetWeights().end(), ostream_iterator<double> (output,
00227                     " "));
00228               }
00229           }
00230         output << endl;
00231       }
00232 
00233     void NeuralNetwork::PrintTopology(std::string filename)
00234       {
00235         gplib::rvec WeightVector = GetWeightsAsVector();
00236         const double maxpower = std::abs(*max_element(WeightVector.begin(),
00237             WeightVector.end(), gplib::absLess<double, double>()));
00238         std::ofstream output(filename.c_str());
00239         output << "digraph network {" << endl;
00240         for (size_t i = 0; i < Layers.front().size(); ++i)
00241           {
00242             output << "node [shape=point];" << std::endl;
00243             output << "i" << i << " -> input" << i << ";" << std::endl;
00244             output << "input" << i << " [shape=circle];" << std::endl;
00245             for (size_t j = 0; j < Layers.at(1).size(); ++j)
00246               {
00247                 output << "input" << i << " -> n1" << j;
00248                 //output <<  "[label =\" " << Layers.at(1).at(j)->GetWeights().at(i) << " \"]";
00249                 output << "[color =\" 0.7 1.0 " << 0.1 + std::abs(
00250                     Layers.at(1).at(j)->GetWeights().at(i)) / maxpower
00251                     << " \"]";
00252                 output << ";" << std::endl;
00253               }
00254           }
00255         for (size_t i = 1; i < Layers.size() - 1; ++i)
00256           {
00257             output << "{ rank=same;" << std::endl;
00258             for (size_t j = 0; j < Layers.at(i).size(); ++j)
00259               {
00260                 output << "n" << i << j << " [shape=circle];" << std::endl;
00261                 //output << "b" << i << j << " [shape=point];"<<std::endl;
00262                 //output << "b" << i << j << " -> n" << i << j;
00263                 //output << "[label =\" " << Layers.at(i).at(j)->GetBias() << " \"] ";
00264                 //output <<  "[color =\" " << Layers.at(1).at(j)->GetBias()/maxpower << " 1.0 1.0\"]";
00265                 //output << ";" << std::endl;
00266               }
00267             output << "};" << std::endl;
00268             for (size_t j = 0; j < Layers.at(i).size(); ++j)
00269               for (size_t k = 0; k < Layers.at(i + 1).size(); ++k)
00270                 {
00271                   output << "n" << i << j << " -> n" << i + 1 << k;
00272                   //output <<  "[label =\" " << Layers.at(i+1).at(k)->GetWeights().at(j) << " \"]";
00273                   output << "[color =\" 0.7 1.0 " << 0.1 + std::abs(
00274                       Layers.at(i + 1).at(k)->GetWeights().at(j)) / maxpower
00275                       << " \"]";
00276                   output << ";" << std::endl;
00277                 }
00278           }
00279         output << "{ rank=same;" << std::endl;
00280         for (size_t i = 0; i < Layers.back().size(); ++i)
00281           {
00282             output << "n" << Layers.size() - 1 << i << " [shape=circle];"
00283                 << std::endl;
00284             //output << "b" << Layers.size()-1 << i << " -> n" << Layers.size()-1 << i;
00285             //output <<  "[color =\" " << Layers.at(Layers.size()-1).at(i)->GetBias()/maxpower << " 1.0 1.0\"]";
00286             //output <<  "[label =\" " << Layers.at(Layers.size()-1).at(i)->GetBias() << " \"]";
00287             //output << ";" << std::endl;
00288           }
00289         output << "};" << std::endl;
00290         for (size_t i = 0; i < Layers.back().size(); ++i)
00291           {
00292             output << "output" << i << " [shape=point];" << std::endl;
00293             for (size_t j = 0; j < Layers.at(Layers.size() - 1).size(); ++j)
00294               {
00295                 output << "n" << Layers.size() - 1 << j << " -> output" << i
00296                     << ";" << std::endl;
00297               }
00298           }
00299         output << "}";
00300       }
00301   }

Generated on Tue May 4 16:52:14 2010 for GPLIB++ by  doxygen 1.5.8