Shark Machine Learning Library
  • About Shark
  • Sourceforge
    • Project Summary
    • Downloads
    • Subversion Repository
  • Getting Started
  • Tutorials
  • FAQ
  • Main Modules
    • ReClaM
    • EALib
    • MOO-EALib
    • Fuzzy
  • Tools
    • Mixture
    • Array
    • Rng
    • LinAlg
    • FileUtil
  • Main Page
  • Related Pages
  • Classes

MSERNNet.cpp

Go to the documentation of this file.
00001 
00034 #include <SharkDefs.h>
00035 #include <ReClaM/MSERNNet.h>
00036 #include <sstream>
00037 
00038 
00039 using namespace std;
00040 
00041 
00042 MSERNNet::MSERNNet()
00043 {
00044     init0();
00045 }
00046 
00047 MSERNNet::MSERNNet(Array<int> con)
00048 {
00049     init0();
00050     setStructure(con);
00051 }
00052 
00053 MSERNNet::MSERNNet(Array<int> con, Array<double> wei)
00054 {
00055     init0();
00056     setStructure(con, wei);
00057 }
00058 
00059 MSERNNet::MSERNNet(std::string filename)
00060 {
00061     init0();
00062     setStructure(filename);
00063 }
00064 
00065 
00066 void MSERNNet::includeWarmUp(unsigned WUP)
00067 {
00068     warmUpLength = WUP;
00069 }
00070 
00071 void MSERNNet::model(const Array<double> &input)
00072 {
00073     if (input.ndim() != 2)
00074     {
00075         throw SHARKEXCEPTION("STOP: MSERNNet::model requires a 2-dim input array");
00076     }
00077     if (warmUpLength > 0) Y = 0.;
00078     processTimeSeries(input);
00079 }
00080 
00081 void MSERNNet::model(const Array<double>& input, Array<double>& output)
00082 {
00083     if (output.ndim() != 2)
00084     {
00085         throw SHARKEXCEPTION("STOP: MSERNNet::model requires a 2-dim output array");
00086     }
00087     unsigned t, i, T = output.dim(0), M = output.dim(1);
00088     model(input);
00089     for (t = 0;t < T;t++)
00090         for (i = 0;i < M;i++)
00091             output(t, i) = Y(numberOfNeurons - 1 - i, T - 1 - t);
00092 }
00093 
00094 double MSERNNet::error(Model& model, const Array<double> &input, const Array<double> &target)
00095 {
00096     if (target.ndim() != 2)
00097     {
00098         throw SHARKEXCEPTION("STOP: MSERNNet::error requires a 2-dim target array");
00099     }
00100 
00101     unsigned i, t, T, M;
00102     T = target.dim(0);
00103     M = target.dim(1);
00104 
00105     if (T <= warmUpLength) throw SHARKEXCEPTION("[MSERNNet::error] number of patterns not larger than warmup length");
00106     this->model(input);
00107 
00108     err = 0;
00109     double totalError = 0;
00110     double z;
00111     for (t = 0;t < warmUpLength;t++)
00112     {
00113         for (i = 0;i < M;i++)
00114         {
00115             err(numberOfNeurons - 1 - i, T - 1 - t) = 0.0;
00116         }
00117     }
00118     for (t = warmUpLength;t < T;t++)
00119     {
00120         for (i = 0;i < M;i++)
00121         {
00122             z = err(numberOfNeurons - 1 - i, T - 1 - t) = Y(numberOfNeurons - 1 - i, T - 1 - t) - target(t, i);
00123             totalError += z * z;
00124         }
00125     }
00126     totalError /= (T - warmUpLength) * M;
00127     return totalError;
00128 }
00129 
00130 double MSERNNet::errorPercentage(const Array<double> &input, const Array<double> &target)
00131 {
00132     unsigned t;
00133     double outmax = -MAXDOUBLE;
00134     double outmin = MAXDOUBLE;
00135 
00136     if (target.ndim() != 2)
00137     {
00138         throw SHARKEXCEPTION("STOP: MSERNNet::error requires a 2-dim target array");
00139     }
00140 
00141     unsigned T, M;
00142     T = target.dim(0);
00143     M = target.dim(1);
00144 
00145     if (T <= warmUpLength)
00146     {
00147         throw SHARKEXCEPTION("number of patterns not larger than warmup length");
00148     }
00149 
00150     this->model(input);
00151 
00152     err      = 0;
00153     double totalError = 0;
00154     double z;
00155     for (t = 0; t < warmUpLength; t++)
00156         for (unsigned i = 0; i < M; i++)
00157         {
00158             err(numberOfNeurons - 1 - i, T - 1 - t) = 0.0;
00159         }
00160     for (t = warmUpLength; t < T; t++)
00161         for (unsigned i = 0; i < M; i++)
00162         {
00163             if (target(t, i) > outmax) outmax = target(t, i);
00164             if (target(t, i) < outmin) outmin = target(t, i);
00165             z = err(numberOfNeurons - 1 - i, T - 1 - t) = Y(numberOfNeurons - 1 - i, T - 1 - t) - target(t, i);
00166             totalError += z * z;
00167         }
00168     totalError /= (T - warmUpLength) * M;
00169     totalError *= 100 / ((outmax - outmin) * (outmax - outmin));
00170     return totalError;
00171 }
00172 
00173 double MSERNNet::meanSquaredError(const Array<double> &input,
00174                                   const Array<double> &target)
00175 {
00176     return error(*this, input, target);
00177 }
00178 
00179 double MSERNNet::errorDerivative(Model& model, const Array<double> &input, const Array<double> &target, Array<double>& derivative)
00180 {
00181     double e;
00182     e = error(model, input, target);
00183     calcGradBPTT();
00184 
00185     writeGradient(derivative);
00186     derivative /= (double)(target.dim(0) - warmUpLength) * target.dim(1);
00187     return e;
00188 }
00189 
00190 Array<int> & MSERNNet::getConnections()
00191 {
00192     return connectionMatrix.A;
00193 }
00194 
00195 Array<double> & MSERNNet::getWeights()
00196 {
00197     return weightMatrix.A;
00198 }
00199 
00200 void MSERNNet::initWeights(long seed, double min, double max)
00201 {
00202     Rng::seed(seed);
00203     initWeights(min, max);
00204 }
00205 
00206 void MSERNNet::initWeights(double low, double up)
00207 {
00208     unsigned i, j, t;
00209     for (t = 0;t < delay;t++) for (i = 0;i < numberOfNeurons;i++) for (j = 0;j < numberOfNeurons;j++)
00210             {
00211                 if (connectionMatrix(t, i, j)) weightMatrix(t, i, j) = Rng::uni(low, up);
00212                 else weightMatrix(t, i, j) = 0;
00213             }
00214     writeParameters();
00215 }
00216 
00217 void MSERNNet::setStructure(Array<int> &mat)
00218 {
00219     unsigned i, j, t;
00220 
00221     delay = mat.dim(0);
00222     numberOfNeurons = mat.dim(1);
00223     weightMatrix.resize(delay, numberOfNeurons, numberOfNeurons, false);
00224     dEw.resize(delay, numberOfNeurons, numberOfNeurons, false);
00225     stimulus.resize(numberOfNeurons, false);
00226     connectionMatrix.resize(delay, numberOfNeurons, numberOfNeurons, false);
00227     delMask.resize(delay, false);
00228 
00229     Y.resize(numberOfNeurons, delay, false);
00230     Y = 0;
00231     delta.resize(numberOfNeurons, delay, false);
00232     delta = 0;
00233 
00234     connectionMatrix.A = mat;
00235     numberOfParameters = 0;
00236     for (t = 0;t < delay;t++)
00237     {
00238         delMask(t) = 0;
00239         for (i = 0;i < numberOfNeurons;i++) for (j = 0;j < numberOfNeurons;j++) if (connectionMatrix(t, i, j))
00240                 {
00241                     numberOfParameters++;
00242                     delMask(t) = 1;
00243                 }
00244     }
00245     parameter.resize(numberOfParameters, false);
00246 }
00247 
00248 void MSERNNet::setStructure(Array<int> &con, Array<double> &wei)
00249 {
00250     setStructure(con);
00251     setStructure(wei);
00252 }
00253 
00254 void MSERNNet::setStructure(Array<double> &wei)
00255 {
00256     weightMatrix.A = wei;
00257     writeParameters();
00258 }
00259 
00260 void MSERNNet::setStructure(std::string filename)
00261 {
00262     std::ifstream is;
00263     is.open(filename.c_str());
00264     unsigned nDelay;
00265     is >> nDelay;
00266 
00267     std::vector<int> l;
00268     const unsigned Len = 256;
00269     char buffer[Len];
00270     unsigned n = 0;
00271     is >> std::setw(Len) >> buffer;
00272 
00273     while (is)
00274     {
00275         n++;
00276         l.push_back(atoi(buffer));
00277         if (is.peek() == '\n')
00278         {
00279             break;
00280         }
00281 
00282         is >> std::setw(Len) >> buffer;
00283     }
00284 
00285     if (n == 0)
00286     {
00287         throw SHARKEXCEPTION("[MSERNNet::setStructure] no matrices given in net file");
00288     }
00289 
00290     Array<int> con(nDelay, n, n);
00291     Array<double> wei(nDelay, n, n);
00292     unsigned i, j, k;
00293 
00294     for (i = 0; i < con.dim(0); i++)
00295         for (j = 0; j < con.dim(1); j++)
00296             if ((i == 0) && (j == 0))
00297             {
00298                 for (k = 0; k < n; k++) con(i, j, k) = l[k];
00299             }
00300             else
00301                 for (k = 0; k < con.dim(2); k++)
00302                 {
00303                     is >> con(i, j, k);
00304                     if (!is)
00305                     {
00306                         throw SHARKEXCEPTION("[MSERNNet::setStructure] not enough entries to build connection matrix");
00307                     }
00308                 }
00309 
00310     for (i = 0; i < wei.dim(0); i++)
00311         for (j = 0; j < wei.dim(1); j++)
00312             for (k = 0; k < wei.dim(2); k++)
00313             {
00314                 is >> wei(i, j, k);
00315                 if (!is)
00316                 {
00317                     throw SHARKEXCEPTION("[MSERNNet::setStructure] not enough entries to build weight matrix");
00318                 }
00319             }
00320 
00321     setStructure(con, wei);
00322 }
00323 
00324 void MSERNNet::write(std::string filename)
00325 {
00326     unsigned i, j, k;
00327     FILE *fp = fopen(filename.c_str(), "wt");
00328 
00329     Array<int> con = getConnections();
00330     unsigned nDelay = con.dim(0);
00331     fprintf(fp, "%u\n", nDelay);
00332 
00333     for (k = 0; k < nDelay; k++)
00334     {
00335         for (i = 0; i < con.dim(1); i++)
00336         {
00337             for (j = 0; j < con.dim(2); j++)
00338             {
00339                 fprintf(fp, "%1d", con(k, i, j));
00340                 if (j < con.dim(2) - 1) fprintf(fp, " ");
00341             }
00342             fprintf(fp, "\n");
00343         }
00344         fprintf(fp, "\n");
00345     }
00346 
00347     Array<double> wei = getWeights();
00348     for (k = 0; k < nDelay; k++)
00349     {
00350         for (i = 0; i < wei.dim(1); i++)
00351         {
00352             for (j = 0; j < wei.dim(2); j++)
00353             {
00354                 fprintf(fp, "%10.8e", wei(k, i, j));
00355                 if (j < wei.dim(2) - 1) fprintf(fp, " ");
00356             }
00357             fprintf(fp, "\n");
00358         }
00359         fprintf(fp, "\n");
00360     }
00361     fclose(fp);
00362 }
00363 
00364 void MSERNNet::setHistory(const Array<double> &Ystate)
00365 {
00366     if (Ystate.dim(0) != numberOfNeurons || Ystate.dim(1) != delay)
00367     {
00368         throw SHARKEXCEPTION("STOP: MSERNNet::setHistory: wrong dimensions");
00369     }
00370     unsigned i, j;
00371     for (i = 0;i < numberOfNeurons;i++)
00372         for (j = 0;j < delay;j++)
00373             Y(i, j) = Ystate(i, j);
00374 }
00375 
00376 Array<double> MSERNNet::getHistory()
00377 {
00378     unsigned i, j;
00379     Array<double> Ystate(numberOfNeurons, delay);
00380     for (i = 0;i < numberOfNeurons;i++)
00381         for (j = 0;j < delay;j++)
00382             Ystate(i, j) = Y(i, j);
00383     return Ystate;
00384 }
00385 
00386 
00387 //###########################################################################
00388 //
00389 // Protected Methods:
00390 //
00391 //###########################################################################
00392 
00393 
00394 // Activation function of all neurons.
00395 double MSERNNet::g(double a)
00396 {
00397     return 1 / (1 + exp(-a));
00398 }
00399 
00400 
00401 // Computes the derivative of g(a) for all neurons.
00402 double MSERNNet::dg(double ga)
00403 {
00404     return ga*(1 - ga);
00405 }
00406 
00407 
00408 // Initializes some internal variables.
00409 void MSERNNet::init0()
00410 {
00411     time = numberOfNeurons = delay = episode = numberOfParameters = 0;
00412     warmUpLength = 0;
00413     Y.resize(0, 0, false);
00414     err.resize(0, 0, false);
00415     delta.resize(0, 0, false);
00416 }
00417 
00418 
00419 // Writes the values of the weights stored in the weight matrix to
00420 // the parameter vector of the model.
00421 void MSERNNet::writeParameters()
00422 {
00423     unsigned i, j, t, n = 0;
00424     for (t = 0;t < delay;t++) for (i = 0;i < numberOfNeurons;i++) for (j = 0;j < numberOfNeurons;j++)
00425                 if (connectionMatrix(t, i, j))  parameter(n++) = weightMatrix(t, i, j);
00426 }
00427 
00428 
00429 // Reads the values of the parameter vector parameter of Model
00430 // and stores these values in the weight matrix.
00431 void MSERNNet::readParameters()
00432 {
00433     unsigned i, j, t, n = 0;
00434     for (t = 0;t < delay;t++) for (i = 0;i < numberOfNeurons;i++) for (j = 0;j < numberOfNeurons;j++)
00435                             if (connectionMatrix(t, i, j)) weightMatrix(t, i, j) = parameter(n++); else weightMatrix(t, i, j) = 0;
00436 }
00437 
00438 
00439 // Writes the values of the gradient of the error with respect to the
00440 // different weights from the variable dEw to the parameter derivative
00441 void MSERNNet::writeGradient(Array<double>& derivative)
00442 {
00443     unsigned i, j, t, n = 0;
00444     derivative.resize(numberOfParameters, false);
00445     for (t = 0;t < delay;t++) for (i = 0;i < numberOfNeurons;i++) for (j = 0;j < numberOfNeurons;j++)
00446                 if (connectionMatrix(t, i, j)) derivative(n++) = dEw(t, i, j);
00447 }
00448 
00449 
00450 // Performs some initializations that are necessary to process the
00451 // time series.
00452 void MSERNNet::prepareTime(unsigned t)
00453 {
00454     unsigned i, j;
00455     ArrayTable<double> Ystate, Dstate;
00456     Ystate.resize(numberOfNeurons, delay, false);
00457     Dstate.resize(numberOfNeurons, delay, false);
00458     for (i = 0;i < numberOfNeurons;i++) for (j = 0;j < delay;j++)
00459         {
00460             Ystate(i, j) = Y(i, j);
00461             Dstate(i, j) = delta(i, j);
00462         }
00463     if (t != episode)
00464     {
00465         episode = t;
00466         Y.resize(numberOfNeurons, episode + delay, false);
00467         Y = 0;
00468         delta.resize(numberOfNeurons, episode + delay, false);
00469         delta = 0;
00470         err.resize(numberOfNeurons, episode + delay, false);
00471         err = 0;
00472     }
00473     for (i = 0;i < numberOfNeurons;i++) for (j = 0;j < delay;j++)
00474         {
00475             Y(i, t + j) = Ystate(i, j);
00476             delta(i, t + j) = Dstate(i, j);
00477         }
00478     time = t;
00479 }
00480 
00481 
00482 // Processes a whole time series. After processing the output can be
00483 // found in the variable Y.
00484 void MSERNNet::processTimeSeries(const Array<double>& input)
00485 {
00486     unsigned t, i;
00487     if (input.dim(1) >= numberOfNeurons)
00488     {
00489         throw SHARKEXCEPTION("[MSERNNet::processTimeSeries] structure has not enough neurons to handle input - use setStructure(...)");
00490     }
00491 
00492     readParameters();
00493     prepareTime(input.dim(0));
00494     stimulus = 0;
00495     for (t = 0;t < input.dim(0);t++)
00496     {
00497         for (i = 0;i < input.dim(1);i++) stimulus(i) = input(t, i);
00498         processTimeStep();
00499     }
00500 }
00501 
00502 
00503 // Processes one input pattern.
00504 void MSERNNet::processTimeStep()
00505 {
00506     unsigned i, j, t;
00507     double z;
00508     if (!time)
00509     {
00510         throw SHARKEXCEPTION("[MSERNNet::process] no time prepared!");
00511     }
00512     time--;
00513     for (i = 0;i < numberOfNeurons;i++)
00514     {
00515         z = stimulus(i);
00516         z += weightMatrix(0, i, i);
00517         if (delMask(0))
00518             for (j = 0;j < i;j++)
00519                 z += weightMatrix(0, i, j) * Y(j, time);
00520         for (t = 1;t < delay;t++)
00521             if (delMask(t))
00522                 for (j = 0;j < numberOfNeurons;j++)
00523                     z += weightMatrix(t, i, j) * Y(j, time + t);
00524         Y(i, time) = g(z);
00525     }
00526 }
00527 
00528 
00529 // Performs backpropagation through time to calculate the derivative
00530 // of the error with respect to the weights. The results are stored to
00531 // dEw.
00532 void MSERNNet::calcGradBPTT()
00533 {
00534     int i, j, t, s, n;
00535     double z;
00536 
00537     for (t = 0;t < (int)episode;t++) for (i = numberOfNeurons - 1;i >= 0;i--)
00538         {
00539             z = err(i, t);
00540             if (delMask(0)) for (j = numberOfNeurons - 1;j > i;j--)
00541                     z += delta(j, t) * weightMatrix(0, j, i);
00542             for (s = 1;s < (int)delay && s <= t;s++) if (delMask(s)) for (j = numberOfNeurons - 1;j >= 0;j--)
00543                         z += delta(j, t - s) * weightMatrix(s, j, i);
00544             delta(i, t) = dg(Y(i, t)) * z;
00545         }
00546 
00547     for (t = 0;t < (int)delay;t++) if (delMask(t)) for (i = 0;i < (int)numberOfNeurons;i++)
00548             {
00549                 if (t > 0) n = numberOfNeurons; else n = i;
00550                 for (j = 0;j < n;j++) if (connectionMatrix(t, i, j))
00551                     {
00552                         dEw(t, i, j) = 0;
00553                         for (s = 0;s + t < (int)episode;s++) dEw(t, i, j) += delta(i, s) * Y(j, t + s);
00554                         dEw(t, i, j) *= 2.0;
00555                     }
00556             }
00557 
00558     for (i = 0;i < (int)numberOfNeurons;i++) if (connectionMatrix(0, i, i))
00559         {
00560             dEw(0, i, i) = 0;
00561             for (s = 0;s < (int)episode;s++) dEw(0, i, i) += delta(i, s);
00562             dEw(0, i, i) *= 2.0;
00563         }
00564 }
00565 
00566 //===========================================================================
00577 void MSERNNet::setStructure(unsigned in, unsigned hidden, unsigned out,
00578                                unsigned memory, bool layered,
00579                                bool recurrentInputs, bool bias, bool elman, bool previousInputs)
00580 {
00581     unsigned N;  // total number of neurons:
00582     unsigned k, i, j;
00583     Array<int> con;
00584 
00585     //
00586     // Calculate total number of neurons from the
00587     // number of neurons per layer:
00588     //
00589     N = in + hidden + out;
00590     con.resize(1 + memory, N, N);
00591     con[0] = 0;
00592 
00593     if (!layered)
00594     {
00595         for (i = in; i < N; i++)
00596         {
00597             for (j = 0; j < i; j++)
00598                 con(0, i, j) = 1;
00599             if (bias) con(0, i, i) = 1;
00600         }
00601     }
00602     else
00603     {
00604         for (i = in; i < N - out; i++)
00605         {
00606             for (j = 0; j < in; j++)
00607                 con(0, i, j) = 1;
00608             if (bias) con(0, i, i) = 1;
00609         }
00610         if (elman)
00611             for (i = N - out; i < N; i++)
00612             {
00613                 for (j = 0; j < N - out; j++)
00614                     con(0, i, j) = 1;
00615                 if (bias) con(0, i, i) = 1;
00616             }
00617         else
00618             for (i = N - out; i < N; i++)
00619             {
00620                 for (j = 0; j < in; j++)
00621                     con(0, i, j) = 1;
00622                 if (bias) con(0, i, i) = 1;
00623             }
00624     }
00625     if (recurrentInputs)
00626         for (i = 1; i <= memory; i++) con[i] = 1;
00627     else
00628     {
00629         for (i = 1; i <= memory; i++)
00630         {
00631             con[i] = 1;
00632             for (j = 0; j < in; j++)
00633             {
00634                 (con[i])[j] = 0;
00635                 if (!previousInputs) for (k = in; k < N; k++) con(i, k, j) = 0;
00636             }
00637         }
00638     }
00639     setStructure(con);
00640 }