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
00390
00391
00392
00393
00394
00395 double MSERNNet::g(double a)
00396 {
00397 return 1 / (1 + exp(-a));
00398 }
00399
00400
00401
00402 double MSERNNet::dg(double ga)
00403 {
00404 return ga*(1 - ga);
00405 }
00406
00407
00408
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
00420
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
00430
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
00440
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
00451
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
00483
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
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
00530
00531
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;
00582 unsigned k, i, j;
00583 Array<int> con;
00584
00585
00586
00587
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 }