00001 /************************************************************************ 00002 * Verve * 00003 * Copyright (C) 2004-2006 * 00004 * Tyler Streeter tylerstreeter@gmail.com * 00005 * All rights reserved. * 00006 * Web: http://verve-agents.sourceforge.net * 00007 * * 00008 * This library is free software; you can redistribute it and/or * 00009 * modify it under the terms of EITHER: * 00010 * (1) The GNU Lesser General Public License as published by the Free * 00011 * Software Foundation; either version 2.1 of the License, or (at * 00012 * your option) any later version. The text of the GNU Lesser * 00013 * General Public License is included with this library in the * 00014 * file license-LGPL.txt. * 00015 * (2) The BSD-style license that is included with this library in * 00016 * the file license-BSD.txt. * 00017 * * 00018 * This library is distributed in the hope that it will be useful, * 00019 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * 00021 * license-LGPL.txt and license-BSD.txt for more details. * 00022 ************************************************************************/ 00023 00024 #include "WinnerTakeAllPopulation.h" 00025 #include "Neuron.h" 00026 00027 namespace verve 00028 { 00029 WinnerTakeAllPopulation::WinnerTakeAllPopulation() 00030 : UltraSparseCodePopulation() 00031 { 00032 } 00033 00034 WinnerTakeAllPopulation::~WinnerTakeAllPopulation() 00035 { 00036 } 00037 00038 void WinnerTakeAllPopulation::updateFiringRatesWTA() 00039 { 00040 // IDEA: This could be a little more efficient if we could avoid 00041 // updating all of the Neurons' targets (post-synaptic Neurons) 00042 // until the end. Right now, we are updating all firing rates 00043 // twice. 00044 00045 // Compute new firing rates from the synaptic input sums. Use 00046 // a sigmoidal activation. 00047 unsigned int size = (unsigned int)mNeurons.size(); 00048 for (unsigned int i = 0; i < size; ++i) 00049 { 00050 mNeurons[i]->updateFiringRateSigmoid(); 00051 } 00052 00053 // Now pick the "winner" Neuron; set its firing rate to 1 and the 00054 // rest to 0. Save the index of the winner. 00055 mActiveIndex = computeWinnerIndex(); 00056 00057 // Set the winner's firing rate to 1 and the rest to 0. 00058 for (unsigned int i = 0; i < size; ++i) 00059 { 00060 if (i == mActiveIndex) 00061 { 00062 mNeurons[i]->setFiringRate(1); 00063 } 00064 else 00065 { 00066 mNeurons[i]->setFiringRate(0); 00067 } 00068 } 00069 } 00070 00071 unsigned int WinnerTakeAllPopulation::computeWinnerIndex() 00072 { 00073 unsigned int winnerIndex = 0; 00074 unsigned int size = (unsigned int)mNeurons.size(); 00075 00076 // We will use a roulette selection method to choose the winner. 00077 // First we find the total firing rate and count the number of 00078 // inactive Neurons. 00079 real totalFiringRate = 0; 00080 unsigned int numInactiveNeurons = 0; 00081 for (unsigned int i = 0; i < size; ++i) 00082 { 00083 real firingRate = mNeurons[i]->getFiringRate(); 00084 if (0 == firingRate) 00085 { 00086 ++numInactiveNeurons; 00087 } 00088 else 00089 { 00090 totalFiringRate += firingRate; 00091 } 00092 } 00093 00094 // We need to add a little to the total for each inactive Neuron. 00095 // This ensures that the 'defaults::minActionSelectionProb' exactly 00096 // specifies the minimum action selection probability. 00097 real extra = 0; 00098 if (defaults::minActionSelectionProb > 0) 00099 { 00100 // The purpose of using this extra variable is to avoid 00101 // compiler (e.g. gcc 3.4.4) warnings about division by 00102 // zero. For example, when defaults::minActionSelectionProb 00103 // is zero, the calculation below looks like a divide by 00104 // zero problem, but this will never happen because of 00105 // the 'if' check above. 00106 real minProb = defaults::minActionSelectionProb; 00107 00108 // The restriction on 'defaults::minActionSelectionProb' ensure 00109 // that the following quantity is a valid positive number. 00110 extra = totalFiringRate / (1 / minProb - numInactiveNeurons); 00111 } 00112 totalFiringRate += numInactiveNeurons * extra; 00113 00114 // Generate a random number uniformly between 0 and 00115 // 'totalFiringRate.' 00116 real randomValue = globals::randomRealUniform(0, 00117 totalFiringRate); 00118 00119 // Pick a "winner" probabilistically. A higher firing 00120 // rate means a higher chance of being chosen as the 00121 // winner. 00122 real currentTotal = 0; 00123 for (unsigned int i = 0; i < size; ++i) 00124 { 00125 // We need to add some activation to the inactive Neurons to 00126 // make the 'defaults::minActionSelectionProb' valid. 00127 real firingRate = mNeurons[i]->getFiringRate(); 00128 if (0 == firingRate) 00129 { 00130 firingRate = extra; 00131 } 00132 00133 if (randomValue <= firingRate + currentTotal) 00134 { 00135 winnerIndex = i; 00136 break; 00137 } 00138 else 00139 { 00140 currentTotal += firingRate; 00141 } 00142 } 00143 00144 return winnerIndex; 00145 } 00146 }