00001 /*!@file Neuro/WinnerTakeAll.C 2D winner-take-all network */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00005 // University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Laurent Itti <itti@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Neuro/WinnerTakeAll.C $ 00035 // $Id: WinnerTakeAll.C 13065 2010-03-28 00:01:00Z itti $ 00036 // 00037 00038 #include "Neuro/WinnerTakeAll.H" 00039 00040 #include "Channels/ChannelOpts.H" // for OPT_LevelSpec 00041 #include "Component/GlobalOpts.H" 00042 #include "Component/OptionManager.H" 00043 #include "Image/Image.H" 00044 #include "Image/MathOps.H" 00045 #include "Image/Transforms.H" // for chamfer34() 00046 #include "Neuro/NeuroOpts.H" 00047 #include "Neuro/WTAwinner.H" 00048 #include "Neuro/NeuroSimEvents.H" 00049 #include "Simulation/SimEventQueue.H" 00050 #include "Simulation/SimEvents.H" 00051 #include "Transport/FrameInfo.H" 00052 #include "Transport/FrameOstream.H" 00053 #include "Util/TextLog.H" 00054 #include "Util/log.H" 00055 #include "Util/sformat.H" 00056 #include "rutz/trace.h" 00057 00058 // ###################################################################### 00059 // ###################################################################### 00060 // ########## WinnerTakeAll implementation 00061 // ###################################################################### 00062 // ###################################################################### 00063 00064 WinnerTakeAll::WinnerTakeAll(OptionManager& mgr, 00065 const std::string& descrName, 00066 const std::string& tagName) : 00067 SimModule(mgr, descrName, tagName) 00068 { 00069 GVX_TRACE(__PRETTY_FUNCTION__); 00070 } 00071 00072 // ###################################################################### 00073 WinnerTakeAll::~WinnerTakeAll() 00074 { 00075 GVX_TRACE(__PRETTY_FUNCTION__); 00076 } 00077 00078 // ###################################################################### 00079 // ###################################################################### 00080 // ########## WinnerTakeAllStub implementation 00081 // ###################################################################### 00082 // ###################################################################### 00083 00084 WinnerTakeAllStub::WinnerTakeAllStub(OptionManager& mgr, 00085 const std::string& descrName, 00086 const std::string& tagName) : 00087 WinnerTakeAll(mgr, descrName, tagName) 00088 { 00089 GVX_TRACE(__PRETTY_FUNCTION__); 00090 } 00091 00092 // ###################################################################### 00093 WinnerTakeAllStub::~WinnerTakeAllStub() 00094 { 00095 GVX_TRACE(__PRETTY_FUNCTION__); 00096 } 00097 00098 // ###################################################################### 00099 // ###################################################################### 00100 // ########## WinnerTakeAllAdapter implementation 00101 // ###################################################################### 00102 // ###################################################################### 00103 00104 WinnerTakeAllAdapter::WinnerTakeAllAdapter(OptionManager& mgr, 00105 const std::string& descrName, 00106 const std::string& tagName) : 00107 WinnerTakeAll(mgr, descrName, tagName), 00108 SIMCALLBACK_INIT(SimEventAttentionGuidanceMapOutput), 00109 SIMCALLBACK_INIT(SimEventSaccadeStatusEye), 00110 SIMCALLBACK_INIT(SimEventInputFrame), 00111 SIMCALLBACK_INIT(SimEventSaveOutput), 00112 itsLogFile(&OPT_TextLogFile, this), 00113 itsSaveResults(&OPT_WTAsaveResults, this), // see Neuro/NeuroOpts.{H,C} 00114 itsUseSaccadicSuppression(&OPT_WTAuseSacSuppress, this), 00115 itsUseBlinkSuppression(&OPT_WTAuseBlinkSuppress, this), 00116 itsLevelSpec(&OPT_LevelSpec, this), 00117 itsUseRandom(&OPT_UseRandom, this), // see Component/ModelManager.{H,C} 00118 itsTooManyShifts(&OPT_BrainTooManyShifts, this), // Neuro/NeuroOpts.{H,C} 00119 itsTooManyShiftsPerFrame(&OPT_BrainTooManyShiftsPerFrame, this), // Neuro/NeuroOpts.{H,C} 00120 itsBoringDelay(&OPT_BrainBoringDelay, this), 00121 itsBoringSMmv(&OPT_BrainBoringSMmv, this), 00122 itsNumShifts(0), 00123 itsInputCopy(), 00124 itsEyePos(-1, -1), 00125 itsLastWinner(WTAwinner::NONE()) 00126 { 00127 GVX_TRACE(__PRETTY_FUNCTION__); 00128 } 00129 00130 // ###################################################################### 00131 WinnerTakeAllAdapter::~WinnerTakeAllAdapter() 00132 { 00133 GVX_TRACE(__PRETTY_FUNCTION__); 00134 } 00135 00136 // ###################################################################### 00137 void WinnerTakeAllAdapter::reset1() 00138 { 00139 GVX_TRACE(__PRETTY_FUNCTION__); 00140 itsNumShifts = 0; 00141 itsInputCopy.freeMem(); 00142 itsEyePos = Point2D<int>(-1, -1); 00143 WinnerTakeAll::reset1(); 00144 } 00145 00146 // ###################################################################### 00147 void WinnerTakeAllAdapter:: 00148 onSimEventInputFrame(SimEventQueue& q, rutz::shared_ptr<SimEventInputFrame>& e) 00149 { 00150 itsNumShifts = 0; // Reset at each new frame 00151 } 00152 00153 // ###################################################################### 00154 void WinnerTakeAllAdapter:: 00155 onSimEventAttentionGuidanceMapOutput(SimEventQueue& q, rutz::shared_ptr<SimEventAttentionGuidanceMapOutput>& e) 00156 { 00157 // process the input: 00158 itsInputCopy = e->agm(); 00159 this->input(itsInputCopy); 00160 00161 // evolve our internals: 00162 Point2D<int> winner(-1,-1); 00163 this->integrate(q.now(), winner); 00164 00165 // stop here if we have already too many shifts per frame: 00166 if (itsTooManyShiftsPerFrame.getVal() > 0 && itsNumShifts >= itsTooManyShiftsPerFrame.getVal()) return; 00167 00168 // did we just get a winner? 00169 if (winner.isValid()) 00170 { 00171 WTAwinner newwin = WTAwinner::buildFromSMcoords(winner, itsLevelSpec.getVal().mapLevel(), 00172 itsUseRandom.getVal(), q.now(), 00173 itsInputCopy.getVal(winner), false); 00174 00175 // if the last covert attention shift was slow or the SM voltage 00176 // was low, mark the covert attention shift as boring: 00177 if ( (itsLastWinner.t > SimTime::ZERO() && newwin.t - itsLastWinner.t > itsBoringDelay.getVal() ) || 00178 newwin.sv < itsBoringSMmv.getVal() * 0.001) 00179 newwin.boring = true; 00180 00181 LINFO("##### WinnerTakeAll winner (%d,%d) at %fms %s#####", 00182 newwin.p.i, newwin.p.j, newwin.t.msecs(), newwin.boring ? "[boring] ":""); 00183 00184 // log what happened: 00185 textLog(itsLogFile.getVal(), "CovertShift", 00186 sformat("(%d,%d) %.3fmV", newwin.p.i, newwin.p.j, newwin.sv * 1000.0F), newwin.t); 00187 itsLastWinner = newwin; 00188 00189 // post an event so that anyone interested in the winner can grab it: 00190 q.post(rutz::make_shared(new SimEventWTAwinner(this, newwin, itsNumShifts))); 00191 00192 // also notify that if we have a SimOutputFrameSeries that is 00193 // operating in event-driven mode (no framerate was specified on 00194 // the command-line), this covert shift is a good reason to save 00195 // outputs now: 00196 q.post(rutz::make_shared(new SimEventRequestSaveOutput(this))); 00197 00198 // that's one more shift of attention: 00199 ++itsNumShifts; 00200 00201 // too many shifts of attention? 00202 if (itsTooManyShifts.getVal() > 0 && itsNumShifts >= itsTooManyShifts.getVal()) 00203 q.post(rutz::make_shared(new SimEventBreak(this, "Too many attention shifts"))); 00204 } 00205 } 00206 00207 // ###################################################################### 00208 void WinnerTakeAllAdapter:: 00209 onSimEventSaccadeStatusEye(SimEventQueue& q, rutz::shared_ptr<SimEventSaccadeStatusEye>& e) 00210 { 00211 this->eyeMovement(e->position()); 00212 00213 // should we also turn saccadic suppression on/off? 00214 TransientStatus evs = e->saccadeStatus(); 00215 if (evs == TSTATUS_BEGIN) this->saccadicSuppression(true); 00216 else if (evs == TSTATUS_END) this->saccadicSuppression(false); 00217 00218 // how about blink suppression? 00219 TransientStatus evb = e->blinkStatus(); 00220 if (evb == TSTATUS_BEGIN) this->blinkSuppression(true); 00221 else if (evb == TSTATUS_END) this->blinkSuppression(false); 00222 } 00223 00224 // ###################################################################### 00225 void WinnerTakeAllAdapter::eyeMovement(const Point2D<int>& curreye) 00226 { 00227 GVX_TRACE(__PRETTY_FUNCTION__); 00228 itsEyePos = curreye; 00229 } 00230 00231 // ###################################################################### 00232 void WinnerTakeAllAdapter:: 00233 onSimEventSaveOutput(SimEventQueue& q, rutz::shared_ptr<SimEventSaveOutput>& e) 00234 { 00235 if (itsSaveResults.getVal()) 00236 { 00237 // get the OFS to save to, assuming sinfo is of type 00238 // SimModuleSaveInfo (will throw a fatal exception otherwise): 00239 nub::ref<FrameOstream> ofs = 00240 dynamic_cast<const SimModuleSaveInfo&>(e->sinfo()).ofs; 00241 ofs->writeFloat(this->getV(), FLOAT_NORM_PRESERVE, "WTA", 00242 FrameInfo("winner-take-all map", SRC_POS)); 00243 } 00244 } 00245 00246 // ###################################################################### 00247 // ###################################################################### 00248 // ########## WinnerTakeAllStd implementation 00249 // ###################################################################### 00250 // ###################################################################### 00251 00252 WinnerTakeAllStd::WinnerTakeAllStd(OptionManager& mgr, 00253 const std::string& descrName, 00254 const std::string& tagName) : 00255 WinnerTakeAllAdapter(mgr, descrName, tagName), 00256 itsNeurons(), 00257 itsGIN(), itsT(), itsGleak(1.0e-8F), itsGinh(1.0e-2F), itsGinput(5.0e-8F) 00258 { 00259 GVX_TRACE(__PRETTY_FUNCTION__); 00260 itsGIN.setGleak(itsGleak); 00261 } 00262 00263 // ###################################################################### 00264 WinnerTakeAllStd::~WinnerTakeAllStd() 00265 { 00266 GVX_TRACE(__PRETTY_FUNCTION__); 00267 } 00268 00269 // ###################################################################### 00270 void WinnerTakeAllStd::reset1() 00271 { 00272 GVX_TRACE(__PRETTY_FUNCTION__); 00273 itsNeurons.freeMem(); 00274 itsGleak = 1.0e-8F; 00275 itsGinh = 1.0e-2F; 00276 itsGinput = 5.0e-8F; 00277 itsT = SimTime::ZERO(); 00278 00279 WinnerTakeAllAdapter::reset1(); 00280 } 00281 00282 // ###################################################################### 00283 void WinnerTakeAllStd::input(const Image<float>& in) 00284 { 00285 GVX_TRACE(__PRETTY_FUNCTION__); 00286 if (itsNeurons.initialized() == false) { 00287 // first input, let's initialize our array 00288 itsNeurons.resize(in.getDims(), ZEROS); 00289 00290 Image<LeakyIntFire>::iterator 00291 nptr = itsNeurons.beginw(), stop = itsNeurons.endw(); 00292 while (nptr != stop) 00293 { 00294 nptr->setGleak(itsGleak); 00295 nptr->setG(0.0F, itsGinh); 00296 ++nptr; 00297 } 00298 } 00299 } 00300 00301 // ###################################################################### 00302 void WinnerTakeAllStd::integrate(const SimTime& t, Point2D<int>& winner) 00303 { 00304 GVX_TRACE(__PRETTY_FUNCTION__); 00305 winner.i = -1; 00306 const int w = itsNeurons.getWidth(); 00307 const int h = itsNeurons.getHeight(); 00308 00309 // the array of neurons receive excitatory inputs from outside. 00310 // here we update the inputs and let the neurons evolve; here we 00311 // need to run this loop time step by time step, since this is a 00312 // feedback network, so we have code similar to that in 00313 // LeakyIntFire::evolve() to figure out how many time steps to run: 00314 const SimTime dt = 00315 SimTime::computeDeltaT((t - itsT), itsGIN.getTimeStep()); 00316 00317 for (SimTime tt = itsT; tt < t; tt += dt) 00318 { 00319 Image<LeakyIntFire>::iterator nptr = itsNeurons.beginw(); 00320 Image<float>::const_iterator inptr = itsInputCopy.begin(); 00321 for (int j = 0 ; j < h; j ++) 00322 for (int i = 0; i < w; i ++) 00323 { 00324 nptr->input(itsGinput * (*inptr++)); 00325 if (nptr->integrate(tt)) { winner.i = i; winner.j = j; } 00326 nptr->setG(0.0F, 0.0F); // only leak conductance 00327 ++nptr; 00328 } 00329 00330 // if there is a winner, the winner triggers the global inhibition: 00331 if (winner.i > -1) itsGIN.setG(itsGleak * 10.0F, 0.0F); 00332 00333 // when the global inhibition fires, it triggers inhibitory 00334 // conductances for one time step in the array of excited 00335 // neurons, shuts off excitatory conductances, and turns itself 00336 // off: 00337 if (itsGIN.integrate(tt)) inhibit(); 00338 } 00339 itsT = t; 00340 } 00341 00342 // ###################################################################### 00343 Image<float> WinnerTakeAllStd::getV() const 00344 { 00345 GVX_TRACE(__PRETTY_FUNCTION__); 00346 Image<float> result(itsNeurons.getDims(), NO_INIT); 00347 00348 Image<float>::iterator dptr = result.beginw(), stop = result.endw(); 00349 Image<LeakyIntFire>::const_iterator nptr = itsNeurons.begin(); 00350 while(dptr != stop) *dptr++ = (nptr++)->getV(); 00351 00352 return result; 00353 } 00354 00355 // ###################################################################### 00356 void WinnerTakeAllStd::inhibit() 00357 { 00358 GVX_TRACE(__PRETTY_FUNCTION__); 00359 Image<LeakyIntFire>::iterator 00360 nptr = itsNeurons.beginw(), stop = itsNeurons.endw(); 00361 while(nptr != stop) (nptr++)->setG(0.0F, itsGinh); 00362 itsGIN.setG(0.0F, 0.0F); 00363 LDEBUG("WTA inhibition firing..."); 00364 } 00365 00366 // ###################################################################### 00367 void WinnerTakeAllStd::saccadicSuppression(const bool on) 00368 { 00369 GVX_TRACE(__PRETTY_FUNCTION__); 00370 if (itsUseSaccadicSuppression.getVal() == false) return; 00371 if (on) inhibit(); 00372 LINFO("------- WTA saccadic suppression %s -------", on ? "on":"off"); 00373 } 00374 00375 // ###################################################################### 00376 void WinnerTakeAllStd::blinkSuppression(const bool on) 00377 { 00378 GVX_TRACE(__PRETTY_FUNCTION__); 00379 if (itsUseBlinkSuppression.getVal() == false) return; 00380 if (on) inhibit(); 00381 LINFO("------- WTA blink suppression %s -------", on ? "on":"off"); 00382 } 00383 00384 // ###################################################################### 00385 // ###################################################################### 00386 // ########## WinnerTakeAllFast implementation 00387 // ###################################################################### 00388 // ###################################################################### 00389 00390 WinnerTakeAllFast::WinnerTakeAllFast(OptionManager& mgr, 00391 const std::string& descrName, 00392 const std::string& tagName) : 00393 WinnerTakeAllAdapter(mgr, descrName, tagName) 00394 { 00395 GVX_TRACE(__PRETTY_FUNCTION__); 00396 } 00397 00398 // ###################################################################### 00399 WinnerTakeAllFast::~WinnerTakeAllFast() 00400 { 00401 GVX_TRACE(__PRETTY_FUNCTION__); 00402 } 00403 00404 // ###################################################################### 00405 void WinnerTakeAllFast::input(const Image<float>& in) 00406 { 00407 GVX_TRACE(__PRETTY_FUNCTION__); 00408 } 00409 00410 // ###################################################################### 00411 void WinnerTakeAllFast::integrate(const SimTime& t, Point2D<int>& winner) 00412 { 00413 GVX_TRACE(__PRETTY_FUNCTION__); 00414 float maxval; 00415 findMax(itsInputCopy, winner, maxval); 00416 if (maxval <= 1.0e-20F) { winner.i = -1; winner.j = -1; } 00417 00418 } 00419 00420 // ###################################################################### 00421 Image<float> WinnerTakeAllFast::getV() const 00422 { 00423 GVX_TRACE(__PRETTY_FUNCTION__); 00424 return itsInputCopy; 00425 } 00426 00427 // ###################################################################### 00428 void WinnerTakeAllFast::saccadicSuppression(const bool on) 00429 { 00430 GVX_TRACE(__PRETTY_FUNCTION__); 00431 if (itsUseSaccadicSuppression.getVal() == false) return; 00432 if (on) itsInputCopy.clear(); 00433 LINFO("------- WTA saccadic suppression %s -------", on ? "on":"off"); 00434 } 00435 00436 // ###################################################################### 00437 void WinnerTakeAllFast::blinkSuppression(const bool on) 00438 { 00439 GVX_TRACE(__PRETTY_FUNCTION__); 00440 if (itsUseBlinkSuppression.getVal() == false) return; 00441 if (on) itsInputCopy.clear(); 00442 LINFO("------- WTA blink suppression %s -------", on ? "on":"off"); 00443 } 00444 00445 // ###################################################################### 00446 // ###################################################################### 00447 // ########## WinnerTakeAllGreedy implementation 00448 // ###################################################################### 00449 // ###################################################################### 00450 00451 WinnerTakeAllGreedy::WinnerTakeAllGreedy(OptionManager& mgr, 00452 const std::string& descrName, 00453 const std::string& tagName) : 00454 WinnerTakeAllStd(mgr, descrName, tagName), 00455 itsThresholdFac(&OPT_WinnerTakeAllGreedyThreshFac, this) 00456 { 00457 GVX_TRACE(__PRETTY_FUNCTION__); 00458 } 00459 00460 // ###################################################################### 00461 WinnerTakeAllGreedy::~WinnerTakeAllGreedy() 00462 { 00463 GVX_TRACE(__PRETTY_FUNCTION__); 00464 } 00465 00466 // ###################################################################### 00467 void WinnerTakeAllGreedy::integrate(const SimTime& t, Point2D<int>& winner) 00468 { 00469 GVX_TRACE(__PRETTY_FUNCTION__); 00470 if (itsEyePos.isValid() == false) CLFATAL("I need a valid eyepos"); 00471 00472 winner.i = -1; 00473 const int w = itsNeurons.getWidth(); 00474 const int h = itsNeurons.getHeight(); 00475 00476 // the array of neurons receive excitatory inputs from outside. 00477 // here we update the inputs and let the neurons evolve; here we 00478 // need to run this loop time step by time step, since this is a 00479 // feedback network, so we have code similar to that in 00480 // LeakyIntFire::evolve() to figure out how many time steps to run: 00481 const SimTime dt = 00482 SimTime::computeDeltaT((t - itsT), itsGIN.getTimeStep()); 00483 00484 for (SimTime tt = itsT; tt < t; tt += dt) 00485 { 00486 Image<LeakyIntFire>::iterator nptr = itsNeurons.beginw(); 00487 Image<float>::const_iterator inptr = itsInputCopy.begin(); 00488 for (int j = 0 ; j < h; j ++) 00489 for (int i = 0; i < w; i ++) 00490 { 00491 nptr->input(itsGinput * (*inptr++)); 00492 if (nptr->integrate(tt)) { winner.i = i; winner.j = j; } 00493 nptr->setG(0.0F, 0.0F); // only leak conductance 00494 ++nptr; 00495 } 00496 00497 // if there is a winner, the winner triggers the global 00498 // inhibition; but before that let's replace our true WTA winner 00499 // by whoever is above threshold and closest to current eye 00500 // position: 00501 if (winner.i > -1) 00502 { 00503 // get our current voltages: 00504 Image<float> v = getV(); 00505 00506 // do not consider values below threshold: 00507 float thresh = v.getVal(winner) * itsThresholdFac.getVal(); 00508 00509 // scale the current eye position down to salmap level coords: 00510 Point2D<int> eye = itsEyePos; 00511 const int smlevel = itsLevelSpec.getVal().mapLevel(); 00512 eye.i = int(eye.i / double(1 << smlevel) + 0.49); 00513 eye.j = int(eye.j / double(1 << smlevel) + 0.49); 00514 00515 // if eye out of image (or unknown), we will not do our 00516 // special greedy processing here and instead will just act 00517 // like a normal WTA: 00518 if (v.coordsOk(eye) && (eye.i != 0 || eye.j != 0)) 00519 { 00520 // create distance map from a single pixel at our eye position: 00521 Image<float> dmap(v.getDims(), ZEROS); 00522 dmap.setVal(eye, 100.0f); 00523 dmap = chamfer34(dmap, 1000.0f); 00524 00525 // let's scan the dmap and find the closest location 00526 // that is a local max and is above threshold: 00527 const int w = v.getWidth(), h = v.getHeight(); 00528 float bestd = 1000.0f; Point2D<int> p; 00529 00530 for (p.j = 0; p.j < h; p.j ++) 00531 for (p.i = 0; p.i < w; p.i ++) 00532 if (v.getVal(p) >= thresh && // we are above threshold 00533 dmap.getVal(p) < bestd && // we are closer to eye 00534 isLocalMax(v, p) == true) // we are a local max 00535 { 00536 winner.i = p.i; 00537 winner.j = p.j; 00538 bestd = dmap.getVal(p); 00539 } 00540 } 00541 00542 // trigger global inhibition: 00543 itsGIN.setG(itsGleak * 10.0F, 0.0F); 00544 } 00545 00546 // when the global inhibition fires, it triggers inhibitory 00547 // conductances for one time step in the array of excited 00548 // neurons, shuts off excitatory conductances, and turns itself 00549 // off: 00550 if (itsGIN.integrate(tt)) inhibit(); 00551 } 00552 itsT = t; 00553 } 00554 00555 // ###################################################################### 00556 // ###################################################################### 00557 // ########## WinnerTakeAll Temporal Noticing implementation 00558 // ###################################################################### 00559 // ###################################################################### 00560 00561 WinnerTakeAllTempNote::WinnerTakeAllTempNote(OptionManager& mgr, 00562 const std::string& descrName, 00563 const std::string& tagName) : 00564 WinnerTakeAllStd(mgr, descrName, tagName), 00565 itsNeurons(), 00566 itsGIN(), itsT(), itsGleak(1.0e-8F), itsGinh(1.0e-2F), itsGinput(5.0e-8F) 00567 { 00568 GVX_TRACE(__PRETTY_FUNCTION__); 00569 itsGIN.setGleak(itsGleak); 00570 itsHighMaskBound.resize(1,256.0F); 00571 itsLowMaskBound.resize(1,0.0002F); 00572 } 00573 00574 // ###################################################################### 00575 WinnerTakeAllTempNote::~WinnerTakeAllTempNote() 00576 { 00577 GVX_TRACE(__PRETTY_FUNCTION__); 00578 } 00579 00580 // ###################################################################### 00581 void WinnerTakeAllTempNote::reset1() 00582 { 00583 GVX_TRACE(__PRETTY_FUNCTION__); 00584 itsNeurons.freeMem(); 00585 itsGleak = 1.0e-8F; 00586 itsGinh = 1.0e-2F; 00587 itsGinput = 5.0e-8F; 00588 itsT = SimTime::ZERO(); 00589 00590 WinnerTakeAllStd::reset1(); 00591 } 00592 00593 // ###################################################################### 00594 void WinnerTakeAllTempNote::input(const Image<float>& in) 00595 { 00596 GVX_TRACE(__PRETTY_FUNCTION__); 00597 if (itsNeurons.initialized() == false) { 00598 // first input, let's initialize our array 00599 itsNeurons.resize(in.getDims(), ZEROS); 00600 00601 Image<LeakyIntFireAdp>::iterator 00602 nptr = itsNeurons.beginw(), stop = itsNeurons.endw(); 00603 while (nptr != stop) 00604 { 00605 nptr->setGleak(itsGleak); 00606 nptr->setG(0.0F, itsGinh); 00607 ++nptr; 00608 } 00609 00610 int width = in.getWidth(); 00611 int height = in.getHeight(); 00612 00613 itsInitMask.resize(width,height); 00614 00615 // set up mask segmenting 00616 itsMaskSegment.SIsetFrame(&width,&height); 00617 itsMaskSegment.SIsetValThresh(itsHighMaskBound,itsLowMaskBound); 00618 itsMaskSegment.SIsetAvg(1); 00619 itsMaskSegment.SItoggleCandidateBandPass(false); 00620 } 00621 } 00622 00623 // ###################################################################### 00624 void WinnerTakeAllTempNote::integrate(const SimTime& t, Point2D<int>& winner) 00625 { 00626 GVX_TRACE(__PRETTY_FUNCTION__); 00627 winner.i = -1; 00628 const int w = itsNeurons.getWidth(); 00629 const int h = itsNeurons.getHeight(); 00630 00631 // the array of neurons receive excitatory inputs from outside. 00632 // here we update the inputs and let the neurons evolve; here we 00633 // need to run this loop time step by time step, since this is a 00634 // feedback network, so we have code similar to that in 00635 // LeakyIntFire::evolve() to figure out how many time steps to run: 00636 const SimTime dt = 00637 SimTime::computeDeltaT((t - itsT), itsGIN.getTimeStep()); 00638 00639 for (SimTime tt = itsT; tt < t; tt += dt) 00640 { 00641 Image<LeakyIntFireAdp>::iterator nptr = itsNeurons.beginw(); 00642 Image<float>::const_iterator inptr = itsInputCopy.begin(); 00643 for (int j = 0 ; j < h; j ++) 00644 { 00645 for (int i = 0; i < w; i ++) 00646 { 00647 nptr->input(itsGinput * (*inptr++)); 00648 if (nptr->integrate(tt)) { winner.i = i; winner.j = j; } 00649 nptr->setG(0.0F, 0.0F); // only leak conductance 00650 ++nptr; 00651 } 00652 } 00653 00654 // if there is a winner, the winner triggers the global inhibition: 00655 if (winner.i > -1) 00656 { 00657 itsGIN.setG(itsGleak * 10.0F, 0.0F); 00658 } 00659 00660 if (winner.i > -1) 00661 { 00662 const float Vfire = itsNeurons.getVal(winner.i,winner.j).getVfire(); 00663 const float V = itsNeurons.getVal(winner.i,winner.j).getV(); 00664 LINFO("VFIRE IS %f",Vfire); 00665 LINFO("V is %f",V); 00666 std::vector<Image<float> > sal_input(1, itsInputCopy); 00667 00668 // find out which neurons around the winner are salient based 00669 // on their salmap values 00670 itsMaskSegment.SIsegment(&sal_input,true); 00671 Image<long> maskCandidates = itsMaskSegment.SIreturnBlobs(); 00672 const long winnerID = maskCandidates.getVal(winner.i, winner.j); 00673 00674 itsInitMask = itsMaskSegment.SIreturnNormalizedCandidates(); 00675 00676 // for each salient pixel/neuron that is grouped with the winner 00677 // update its threshold fire value 00678 Image<long>::iterator imask = maskCandidates.beginw(); 00679 Image<float>::iterator isal = itsInputCopy.beginw(); 00680 Image<LeakyIntFireAdp>::iterator nptr = itsNeurons.beginw(); 00681 for (int j = 0 ; j < h; j ++) 00682 { 00683 for (int i = 0; i < w; i ++) 00684 { 00685 if(*imask == winnerID) 00686 { 00687 LINFO("WINNER %d, %d - SLAVE %d, %d - ID %d",winner.i,winner.j,i,j 00688 ,(int)winnerID); 00689 const float dist = sqrt(pow(winner.i - i,2) + pow(winner.j - j,2)); 00690 nptr->setNewVth(*isal,Vfire,dist); 00691 } 00692 ++imask; ++isal; ++nptr; 00693 } 00694 } 00695 } 00696 00697 // when the global inhibition fires, it triggers inhibitory 00698 // conductances for one time step in the array of excited 00699 // neurons, shuts off excitatory conductances, and turns itself 00700 // off: 00701 if (itsGIN.integrate(tt)) 00702 { 00703 inhibit(); 00704 } 00705 } 00706 itsT = t; 00707 } 00708 00709 // ###################################################################### 00710 Image<float> WinnerTakeAllTempNote::getV() const 00711 { 00712 GVX_TRACE(__PRETTY_FUNCTION__); 00713 Image<float> result(itsNeurons.getDims(), NO_INIT); 00714 00715 Image<float>::iterator dptr = result.beginw(), stop = result.endw(); 00716 Image<LeakyIntFireAdp>::const_iterator nptr = itsNeurons.begin(); 00717 while(dptr != stop) *dptr++ = (nptr++)->getV(); 00718 00719 return result; 00720 } 00721 00722 // ###################################################################### 00723 Image<float> WinnerTakeAllTempNote::getVth(const bool normalize) const 00724 { 00725 GVX_TRACE(__PRETTY_FUNCTION__); 00726 Image<float> result(itsNeurons.getDims(),NO_INIT); 00727 00728 Image<float>::iterator dptr = result.beginw(), stop = result.endw(); 00729 Image<LeakyIntFireAdp>::const_iterator nptr = itsNeurons.begin(); 00730 while(dptr != stop) 00731 { 00732 *dptr = (nptr)->getVth(); 00733 ++dptr; ++nptr; 00734 } 00735 00736 if (normalize) 00737 inplaceNormalize(result, 0.0F, 255.0F); 00738 00739 result = result * 1000.0F; 00740 00741 return result; 00742 } 00743 00744 // ###################################################################### 00745 void WinnerTakeAllTempNote::inhibit() 00746 { 00747 GVX_TRACE(__PRETTY_FUNCTION__); 00748 Image<LeakyIntFireAdp>::iterator 00749 nptr = itsNeurons.beginw(), stop = itsNeurons.endw(); 00750 while(nptr != stop) (nptr++)->setG(0.0F, itsGinh); 00751 itsGIN.setG(0.0F, 0.0F); 00752 LDEBUG("WTA inhibition firing..."); 00753 } 00754 00755 // ###################################################################### 00756 void WinnerTakeAllTempNote::saccadicSuppression(const bool on) 00757 { 00758 GVX_TRACE(__PRETTY_FUNCTION__); 00759 if (itsUseSaccadicSuppression.getVal() == false) return; 00760 if (on) inhibit(); 00761 LINFO("------- WTA saccadic suppression %s -------", on ? "on":"off"); 00762 } 00763 00764 // ###################################################################### 00765 void WinnerTakeAllTempNote::blinkSuppression(const bool on) 00766 { 00767 GVX_TRACE(__PRETTY_FUNCTION__); 00768 if (itsUseBlinkSuppression.getVal() == false) return; 00769 if (on) inhibit(); 00770 LINFO("------- WTA blink suppression %s -------", on ? "on":"off"); 00771 } 00772 00773 // ###################################################################### 00774 void WinnerTakeAllTempNote::save1(const ModelComponentSaveInfo& sinfo) 00775 { 00776 GVX_TRACE(__PRETTY_FUNCTION__); 00777 00778 // get the OFS to save to, assuming sinfo is of type 00779 // SimModuleSaveInfo (will throw a fatal exception otherwise): 00780 nub::ref<FrameOstream> ofs = 00781 dynamic_cast<const SimModuleSaveInfo&>(sinfo).ofs; 00782 00783 ofs->writeFloat(this->getV(), FLOAT_NORM_PRESERVE, "WTA", 00784 FrameInfo("winner-take-all map", SRC_POS)); 00785 00786 ofs->writeFloat(getVth(false), FLOAT_NORM_0_255, "WTA-Vth", 00787 FrameInfo("winner-take-all threshold", SRC_POS)); 00788 00789 ofs->writeFloat(itsInitMask,FLOAT_NORM_0_255, "WTA-MASK", 00790 FrameInfo("winner-take-all mask", SRC_POS)); 00791 00792 } 00793 00794 // ###################################################################### 00795 /* So things look consistent in everyone's emacs... */ 00796 /* Local Variables: */ 00797 /* indent-tabs-mode: nil */ 00798 /* End: */