00001
00025 #include <magic/mmath.h>
00026 #include <magic/mgdev-eps.h>
00027 #include <magic/mclass.h>
00028
00029 #include "inanna/annetwork.h"
00030 #include "inanna/patternset.h"
00031 #include "inanna/initializer.h"
00032 #include "inanna/equalization.h"
00033
00034 impl_dynamic (NeuronContainer, {});
00035 impl_dynamic (ANNetwork, {NeuronContainer});
00036
00037
00039
00040
00041
00042
00043
00045
00046 NeuronContainer::~NeuronContainer () {
00047
00048 for (int i=0; i<size(); i++)
00049 for (int j=0; j<(*this)[i].incomings(); j++) {
00050 (*this)[i].incoming(j).cut();
00051 delete & ((*this)[i].incoming(j));
00052 }
00053
00054
00055
00056 for (int i=0; i<size(); i++)
00057 (*this)[i].shallowDisconnectAll ();
00058 }
00059
00060 void NeuronContainer::add (Neuron* neuron) {
00061 Array<Neuron>::add (neuron);
00062 neuron->setId (size()-1);
00063 }
00064
00065 void NeuronContainer::removeUnit (int unitID) {
00066
00067 mUnits[unitID].disconnectAll ();
00068
00069
00070 mUnits.removeFill (unitID);
00071
00072
00073 for (int i=unitID; i<mUnits.size(); i++)
00074 mUnits[i].setId (i);
00075 }
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00088
00089
00090
00091
00092
00093
00094
00096
00103 ANNetwork::ANNetwork (const char* desc)
00104 {
00105 mUnitTemplate = NULL;
00106 mInitializer = NULL;
00107 mTopology = NULL;
00108 mpEqualizer = NULL;
00109 if (desc)
00110 failtrace (makeUnits (desc));
00111 }
00112
00113 ANNetwork::~ANNetwork ()
00114 {
00115 delete mUnitTemplate;
00116 delete mInitializer;
00117 delete mTopology;
00118 delete mpEqualizer;
00119 }
00120
00121 void ANNetwork::copy (const ANNetwork& fnet, bool onlyWeights)
00122 {
00123 Learner::copy (fnet, onlyWeights);
00124 copyFreeNet (fnet, onlyWeights);
00125 }
00126
00127 void ANNetwork::makeUnits (const char* desc)
00128 {
00129 mTopology = new LayeredTopology (desc);
00130 mTopology->build (*this);
00131 }
00132
00133 void ANNetwork::empty ()
00134 {
00135 mTopology->empty ();
00136 NeuronContainer::empty ();
00137 }
00138
00139 void ANNetwork::connectFfw (const PackTable<int>& connmat)
00140 {
00141 ASSERT (connmat.rows == connmat.cols);
00142 ASSERT (connmat.rows == size());
00143 ANNLayering& mLayering = dynamic_cast<ANNLayering&>(*mTopology);
00144
00145
00146 int outlindex = mLayering.layerIndex(-1);
00147 for (int i=0; i<outlindex; i++)
00148 mUnits[i].enable (connmat.get(i,i));
00149
00150
00151 for (int i=0; i<mUnits.size(); i++)
00152 for (int j=0; j<mUnits.size(); j++) {
00153 int ilayer, jlayer, dummy;
00154 mLayering.getPos (i, ilayer, dummy);
00155 mLayering.getPos (j, jlayer, dummy);
00156 if (mUnits[i].isEnabled() && mUnits[j].isEnabled() &&
00157 ilayer==jlayer-1 && connmat.get(i,j))
00158 connect (i,j);
00159 }
00160 }
00161
00162 void ANNetwork::connectFullFfw (bool shortcuts)
00163 {
00164 ASSERT (mTopology);
00165 ANNLayering* mpLayering = dynamic_cast<ANNLayering*>(mTopology);
00166 if (!mpLayering)
00167 throw runtime_error (i18n("Neural network didn't have a topology when doing connectFullFfw()"));
00168
00169
00170 for (int l=1; l<mpLayering->layers(); l++) {
00171
00172
00173 int loffset = mpLayering->layerIndex (l);
00174
00175
00176 for (int j=0; j<(*mpLayering)[l]; j++)
00177 for (int pl=shortcuts?0:l-1; pl<=l-1; pl++) {
00178 int ploffset = mpLayering->layerIndex (pl);
00179 for (int i=0; i<(*mpLayering)[pl]; i++)
00180 connect (ploffset+i, loffset+j);
00181 }
00182 }
00183 }
00184
00185 void ANNetwork::connectFull ()
00186 {
00187
00188 for (int i=0; i<mUnits.size(); i++)
00189 for (int j=0; j<mUnits.size(); j++)
00190 connect (i,j);
00191 }
00192
00193 void ANNetwork::copyFreeNet (const ANNetwork& other, bool onlyWeights)
00194 {
00195 ANNLayering& mLayering = dynamic_cast<ANNLayering&>(*mTopology);
00196 if (onlyWeights) {
00197 ASSERTWITH (false, "onlyWeights-copy not implemented for ANNetwork");
00198 } else {
00199
00200 mLayering = dynamic_cast<ANNLayering&>(*other.mTopology);
00201 failtrace (copyClone (mUnits, other.mUnits));
00202 mUnitTemplate = other.mUnitTemplate? other.mUnitTemplate->clone () : (Neuron*)NULL;
00203 }
00204 }
00205
00206 void ANNetwork::init (double r)
00207 {
00208 for (int i=0; i<mUnits.size(); i++) {
00209 if (mInitializer)
00210 mInitializer->initialize (mUnits[i]);
00211 else
00212 mUnits[i].init (r);
00213 }
00214 }
00215
00216 void ANNetwork::setInitializer (NeuronInitializer* initer)
00217 {
00218 delete mInitializer;
00219 mInitializer = initer;
00220 }
00221
00222 void ANNetwork::setEqualizer (Equalizer* eq)
00223 {
00224 delete mpEqualizer;
00225 mpEqualizer = eq;
00226 }
00227
00228 Connection* ANNetwork::connect (int i, int j) {
00229 ASSERTWITH (i>=0 && i<mUnits.size(),
00230 format ("Invalid source index from(i)=%d, to(j)=%d", i, j));
00231
00232
00233 Connection* conn = new Connection (&mUnits[i], &mUnits[j]);
00234 failtrace (mUnits[j].addIncoming (conn));
00235 failtrace (mUnits[i].addOutgoing (conn));
00236 return conn;
00237 }
00238
00239 void ANNetwork::reset () {
00240 for (int i=0; i<mUnits.size(); i++)
00241 mUnits[i].reset ();
00242 }
00243
00244 void ANNetwork::update () {
00245 for (int i=0; i<mUnits.size(); i++)
00246 if (mUnits[i].incomings()>0)
00247 mUnits[i].transfer (*this);
00248 }
00249
00250 Vector ANNetwork::testPattern (const PatternSource& set, int pattern) const {
00251 Vector result;
00252
00253
00254 for (int inp=0; inp<set.inputs; inp++)
00255 (*const_cast<ANNetwork*>(this))[inp].setActivation (set.input (pattern, inp));
00256
00257 const_cast<ANNetwork*>(this)->update ();
00258
00259
00260 result.make (set.outputs);
00261 for (int outp=0; outp<set.outputs; outp++)
00262 result[outp] = (*this)[size() - set.outputs + outp].activation();
00263
00264 return result;
00265 }
00266
00270 OStream& ANNetwork::operator>> (OStream& out) const
00271 {
00272 for (int i=0; i<mUnits.size(); i++) {
00273 char ttype = "SLE"[mUnits[i].transferFunc()];
00274 out.printf ("%3d: A=%2.2f b=%+2.2f %c (%d): ",
00275 mUnits[i].id(), mUnits[i].activation(), mUnits[i].bias(), ttype, mUnits[i].incomings());
00276 for (int j=0; j<mUnits[i].incomings(); j++)
00277 out.printf ("%2d:%+2.2f ",
00278 mUnits[i].incoming(j).source().id(),
00279 mUnits[i].incoming(j).weight());
00280 out << " \n";
00281 }
00282 return out;
00283 }
00284
00285 double quadatan (double x, double y) {
00286 if (y==0)
00287 return (x>=0)? 0 : M_PI;
00288
00289 double at=atan (y/x);
00290
00291
00292 if (y>0 && x<0) at+=M_PI;
00293 if (y<0 && x<0) at+=M_PI;
00294 if (y<0 && x>0) at+=2*M_PI;
00295
00296 return at;
00297 }
00298
00299 String ANNetwork::drawEPS (double xsize, double ysize) const {
00300 ANNLayering& mLayering = dynamic_cast<ANNLayering&>(*mTopology);
00301 if (xsize<0 || ysize<0)
00302 xsize=175, ysize=175;
00303
00304
00305 int maxSize=0;
00306 for (int i=0; i<mLayering.layers(); i++)
00307 if (mLayering[i]>maxSize)
00308 maxSize = mLayering[i];
00309 double size = (mLayering.layers()>maxSize)? mLayering.layers():maxSize;
00310
00311 Coord2D picSize (175, 175);
00312 EPSDevice dc (picSize);
00313 dc.framedStyle (size, size);
00314
00315
00316 for (int i=0; i<mUnits.size(); i++) {
00317 const Neuron& unit = mUnits[i];
00318 const Coord2D& pos = Coord2D (unit.getPlace ());
00319
00320 bool inOrOutUnit = (i<mLayering[0]) || (i>=mUnits.size()-mLayering[-1])
00321 || unit.transferFunc()==Neuron::LINEAR_TF;
00322
00323
00324 double unitRadius = inOrOutUnit? 0.15 : 0.25;
00325 dc.saveState ();
00326 dc.lineWidth (0);
00327 dc.circle (pos, unitRadius, unit.isEnabled());
00328 dc.restoreState ();
00329
00330
00331 dc.lineStyle ("->", 0.2);
00332 if (unit.isEnabled())
00333 for (int c=0; c<unit.incomings(); c++) {
00334 const Neuron& source = unit.incoming(c).source();
00335 const Coord2D& tpos = Coord2D(source.getPlace ());
00336
00337
00338 double angle = quadatan (tpos.x-pos.x, tpos.y-pos.y);
00339 double trgRadius = (unit.incoming(c).source().id() >= mUnits.size() - mLayering[-1]
00340 || source.transferFunc()==Neuron::LINEAR_TF)? 0.15:0.25;
00341 Coord2D tmpos (tpos.x-trgRadius*cos(angle), tpos.y-trgRadius*sin(angle));
00342 dc.lineWidth (0.5);
00343 dc.saveState ();
00344 if (unit.transferFunc()==Neuron::LINEAR_TF)
00345 dc.lineStyle ("dashed", 0.02);
00346 dc.line (pos, tmpos);
00347 dc.restoreState ();
00348 }
00349
00350
00351 if (i >= mUnits.size() - mLayering[-1]) {
00352 dc.lineWidth (0.5);
00353 dc.saveState ();
00354 if (unit.transferFunc()==Neuron::LINEAR_TF)
00355 dc.lineStyle ("dashed", 0.02);
00356 dc.line (pos, pos+Coord2D(0.5,0));
00357 dc.restoreState ();
00358 }
00359 }
00360
00361 dc.printFooter ();
00362 return dc.getBuffer ();
00363 }
00364
00365 void ANNetwork::cleanup (bool removeDisableds, bool removePassthroughs) {
00366 ANNLayering& mLayering = dynamic_cast<ANNLayering&>(*mTopology);
00367 int inputIndex = mLayering[0];
00368 int outputIndex = mUnits.size() - mLayering[-1];
00369
00370 int disconnects;
00371 do {
00372 disconnects=0;
00373 for (int i=inputIndex; i<outputIndex; i++) {
00374
00375 int ins=0;
00376 for (int j=0; j < mUnits.size(); j++)
00377 if (mUnits[j].connectedFrom (mUnits[i]))
00378 ins++;
00379
00380
00381 if ((ins>0 && mUnits[i].incomings()==0) || (ins==0 && mUnits[i].incomings()>0)) {
00382
00383 for (int j=0; j < mUnits.size(); j++)
00384 if (mUnits[j].connectedFrom (mUnits[i]))
00385 mUnits[j].disconnectFrom (mUnits[i]);
00386
00387
00388 mUnits[i].disconnectAll ();
00389
00390
00391 mUnits[i].enable (false);
00392
00393 disconnects++;
00394 continue;
00395 }
00396
00397
00398 if (removePassthroughs && (ins==1 && mUnits[i].incomings()>=1)) {
00399
00400 for (int j=0; j<mUnits.size(); j++)
00401 if (mUnits[j].connectedFrom (mUnits[i])) {
00402
00403 mUnits[j].disconnectFrom (mUnits[i]);
00404 for (int trg=0; trg<mUnits[i].incomings(); trg++)
00405 mUnits[j].connectFrom (mUnits[i].incoming(trg).source());
00406 break;
00407 }
00408 mUnits[i].disconnectAll ();
00409 mUnits[i].enable (false);
00410 disconnects++;
00411 continue;
00412 }
00413
00414
00415 if (removePassthroughs && (ins>=1 && mUnits[i].incomings()==1)) {
00416
00417 for (int j=0; j<mUnits.size(); j++)
00418 if (mUnits[j].connectedFrom (mUnits[i])) {
00419
00420 mUnits[j].disconnectFrom (mUnits[i]);
00421 mUnits[j].connectFrom (mUnits[i].incoming(0).source());
00422 }
00423 mUnits[i].disconnectAll ();
00424 mUnits[i].enable (false);
00425 disconnects++;
00426 continue;
00427 }
00428 }
00429 } while (disconnects>0);
00430
00431
00432 for (int i=0; i<outputIndex; i++)
00433 mUnits[i].enable (mUnits[i].incomings()>0);
00434
00435
00436 if (removeDisableds)
00437 for (int i=inputIndex; i<mUnits.size()-mLayering[-1]; i++)
00438 if (!mUnits[i].isEnabled()) {
00439 removeUnit (i);
00440
00441
00442 int layer, pos;
00443 mLayering.getPos (i, layer, pos);
00444 if (mLayering[layer]>1)
00445 mLayering[layer]--;
00446 else {
00447
00448
00449 mLayering.removeLayer (layer);
00450 }
00451
00452
00453 i--;
00454 }
00455 }
00456
00457 struct ValueIndex : public Comparable {
00458 double value;
00459 int index;
00460
00461 int operator== (const Comparable& other) const {return 0;}
00462 int compare (const Comparable& other) const {
00463 const ValueIndex& o = dynamic_cast<const ValueIndex&> (other);
00464 return (value<o.value)? -1 : (value>o.value)? 1 : (index<o.index)? -1 : 1;
00465 }
00466 };
00467
00468 void ANNetwork::drawFeedForward () {
00469 ANNLayering& mLayering = dynamic_cast<ANNLayering&>(*mTopology);
00470 int inputs = mLayering[0];
00471 int outputs = mLayering[-1];
00472 int hiddens = mUnits.size()-inputs-outputs;
00473
00474
00475 String layeringDesc = String(inputs);
00476
00477
00478 if (hiddens) {
00479 int column = 0;
00480 int firstOnColumn = inputs;
00481 for (int i=inputs; i<mUnits.size(); i++) {
00482 if (i==inputs+hiddens) {
00483
00484 layeringDesc += String("-") + String(i-firstOnColumn);
00485 column++;
00486 firstOnColumn = i;
00487 } else
00488 for (int j=firstOnColumn; j<i; j++) {
00489 if (mUnits[j].isEnabled() && mUnits[j].connectedFrom(mUnits[i]) &&
00490 i<inputs+hiddens) {
00491
00492 layeringDesc += String("-") + String(i-firstOnColumn);
00493
00494
00495 column++;
00496 firstOnColumn = i;
00497 break;
00498 }
00499 }
00500 mUnits[i].mCoord.x = 3*(column+1);
00501 }
00502 }
00503
00504
00505 layeringDesc += String("-") + String(outputs);
00506
00507
00508
00509
00510 mLayering.make (layeringDesc);
00511
00512
00513 int maxSize=0;
00514 for (int i=0; i<mLayering.layers(); i++)
00515 if (mLayering[i]>maxSize)
00516 maxSize = mLayering[i];
00517
00518
00519 double gridSize = (mLayering.layers()>maxSize)? mLayering.layers():maxSize;
00520 double layerStep = gridSize/double(mLayering.layers()+0.5);
00521
00522 for (int l=0; l<mLayering.layers(); l++) {
00523
00524 Array<ValueIndex> idealY (mLayering[l]);
00525 int layerBase = mLayering.layerIndex(l);
00526 for (int i=0; i<mLayering[l]; i++) {
00527
00528 double sum=0;
00529 int conns=0;
00530 for (int j=0; j<layerBase+i; j++)
00531 if (mUnits[j].connectedFrom(mUnits[layerBase+i])) {
00532 sum += mUnits[j].mCoord.y;
00533 conns++;
00534 }
00535 if (conns)
00536 idealY[i].value = sum/conns;
00537 else
00538 idealY[i].value = double(i)/mLayering[l];
00539 idealY[i].index = i+layerBase;
00540 }
00541
00542
00543 if (l<mLayering.layers()-1)
00544 idealY.quicksort ();
00545
00546
00547 double unitStep = gridSize/double(mLayering[l]+1);
00548 for (int i=0; i<mLayering[l]; i++) {
00549 mUnits[idealY[i].index].moveTo (double(l)*layerStep+0.5,
00550 double(i+1)*unitStep);
00551 }
00552 }
00553 }
00554
00555 inline int sgn (double x) {return (x==0)?0 : ((x<0)? -1:1);}
00556
00557 void ANNetwork::check () const {
00558 ANNLayering& mLayering = dynamic_cast<ANNLayering&>(*mTopology);
00559 mLayering.check ();
00560 for (int i=0; i<mUnits.size(); i++)
00561 mUnits[i].check (mUnits.size());
00562 if (mUnitTemplate)
00563 mUnitTemplate->check (1);
00564 }
00565
00566