00001 /*!@file Learn/FuzzyART.C */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00005 // by the 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: John Shen <shenjohn@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Learn/FuzzyART.C $ 00035 // $Id: FuzzyART.C 13373 2010-05-09 04:28:40Z jshen $ 00036 // 00037 00038 #include "Component/ModelOptionDef.H" 00039 #include "Component/OptionManager.H" 00040 #include "Component/ModelComponent.H" 00041 #include "Component/ModelParam.H" 00042 #include "Learn/FuzzyART.H" 00043 #include "Util/Assert.H" 00044 #include "Util/log.H" 00045 #include <vector> 00046 00047 const ModelOptionCateg MOC_Learn_ART = { 00048 MOC_SORTPRI_3, "ART Model-related Options" }; 00049 00050 const ModelOptionDef OPT_FuzzyART_InputSize = 00051 { MODOPT_ARG(uint), "FuzzyART_InputSize", &MOC_Learn_ART, OPTEXP_CORE, 00052 "The size of the input vectors to ART", 00053 "fuzzy-art-inputsize", '\0', "<uint>", "2"}; 00054 00055 const ModelOptionDef OPT_FuzzyART_NumCategories = 00056 { MODOPT_ARG(uint), "FuzzyART_MaxNumCategories", &MOC_Learn_ART, OPTEXP_CORE, 00057 "The maximum number of categories fuzzy ART can learn", 00058 "fuzzy-art-max-categories", '\0', "<uint>", "10"}; 00059 00060 const ModelOptionDef OPT_FuzzyART_ComplementCode = 00061 { MODOPT_FLAG, "FuzzyART_ComplementCoding", &MOC_Learn_ART, OPTEXP_CORE, 00062 "Use complement coding for the fuzzy ART input layer", 00063 "fuzzy-art-complement-code", '\0', "", "true"}; 00064 00065 const ModelOptionDef OPT_FuzzyART_Alpha = 00066 { MODOPT_ARG(double), "FuzzyART_Alpha", &MOC_Learn_ART, OPTEXP_CORE, 00067 "Set the choice parameter alpha for fuzzy ART dynamics", 00068 "fuzzy-art-alpha", '\0', "<0..1>", "0.01"}; 00069 00070 const ModelOptionDef OPT_FuzzyART_Beta = 00071 { MODOPT_ARG(double), "FuzzyART_Beta", &MOC_Learn_ART, OPTEXP_CORE, 00072 "Set the learning rate parameter beta for fuzzy ART dynamics", 00073 "fuzzy-art-beta", '\0', "<0..1>", "0.1"}; 00074 00075 const ModelOptionDef OPT_FuzzyART_Rho = 00076 { MODOPT_ARG(double), "FuzzyART_Rho", &MOC_Learn_ART, OPTEXP_CORE, 00077 "Set the vigilance parameter rho for fuzzy ART dynamics", 00078 "fuzzy-art-rho", '\0', "<0..1>", "0.9"}; 00079 00080 // ###################################################################### 00081 FuzzyART::FuzzyART(OptionManager& mgr, const std::string& descrName, const std::string& tagName) : 00082 ModelComponent(mgr, descrName, tagName), 00083 itsInputSize(&OPT_FuzzyART_InputSize, this), 00084 itsNumCategories(&OPT_FuzzyART_NumCategories, this), 00085 itsComplementCoded(&OPT_FuzzyART_ComplementCode, this), 00086 itsAlpha(&OPT_FuzzyART_Alpha, this), 00087 itsBeta(&OPT_FuzzyART_Beta, this), 00088 itsRho(&OPT_FuzzyART_Rho, this) 00089 { 00090 } 00091 00092 void FuzzyART::start2() 00093 { 00094 for(uint i = 0; i < itsNumCategories.getVal(); i++) { 00095 00096 Unit L; 00097 if(itsComplementCoded.getVal()) 00098 L.weights.assign(2*itsInputSize.getVal(),1.0); 00099 else 00100 L.weights.assign(itsInputSize.getVal(),1.0); 00101 L.committed = false; 00102 itsF1.push_back(L); 00103 } 00104 } 00105 00106 // ###################################################################### 00107 uint FuzzyART::learnInput(std::vector<double> input) 00108 { 00109 ASSERT(input.size() == itsInputSize.getVal()); 00110 00111 if(itsComplementCoded.getVal()) 00112 itsCurrInput = complementCode(input); 00113 else 00114 itsCurrInput = input; 00115 00116 // set activations for all units 00117 for(uint i = 0; i < numUnitsCommitted(); i++) { 00118 itsF1[i].activity = choiceFunction(i); 00119 } 00120 bool resonant = false; 00121 uint max_active = 0; 00122 while(!resonant) { 00123 // find pattern of maximum activity 00124 for(uint i = 0; i < numUnitsCommitted(); i++) 00125 if(itsF1[i].activity > itsF1[max_active].activity) 00126 max_active = i; 00127 00128 if(itsF1[max_active].activity == -1 || numUnitsCommitted() == 0) { 00129 // all units are made inactive 00130 max_active = numUnitsCommitted(); // create new node 00131 break; 00132 } 00133 resonant = vigilanceCrit(max_active); 00134 if(!resonant) itsF1[max_active].activity = -1; //inactivate this node 00135 } 00136 updateWeights(max_active); 00137 00138 if(max_active == itsNumCategories.getVal()) return -1; 00139 return max_active; 00140 } 00141 00142 // ###################################################################### 00143 std::vector<double> FuzzyART::complementCode(const std::vector<double> c) const 00144 { 00145 std::vector<double> d = c; 00146 const uint N = c.size(); 00147 for(uint i = 0; i < N; i++) 00148 d.push_back(1-d[i]); 00149 00150 return d; 00151 } 00152 00153 // ###################################################################### 00154 double FuzzyART::choiceFunction(const uint cat) const 00155 { 00156 std::vector<double> ha = itsF1[cat].weights; 00157 double nom = norm(fuzzyAnd(itsCurrInput,itsF1[cat].weights)); 00158 double denom = itsAlpha.getVal() + norm(itsF1[cat].weights); 00159 return nom/denom; 00160 // return norm(fuzzyAnd(itsCurrInput,itsF1[cat].weights))/ 00161 // (itsAlpha.getVal() + norm(itsF1[cat].weights)); 00162 } 00163 00164 // ###################################################################### 00165 bool FuzzyART::vigilanceCrit(const uint cat) const 00166 { 00167 return norm(fuzzyAnd(itsCurrInput,itsF1[cat].weights))/norm(itsCurrInput) >= 00168 itsRho.getVal(); 00169 // if true, resonance 00170 // if false, mismatch reset 00171 } 00172 00173 // ###################################################################### 00174 void FuzzyART::updateWeights(const uint cat) 00175 { 00176 if(cat >= itsNumCategories.getVal()) { 00177 LINFO("Max number of categories #%d hit: input unlearned", itsNumCategories.getVal()); 00178 return; 00179 } 00180 00181 if(!itsF1[cat].committed) { //fast learning mode 00182 itsF1[cat].weights = itsCurrInput; 00183 itsF1[cat].committed = true; 00184 LINFO("activating new node #%d", cat); 00185 } 00186 else { 00187 std::vector<double> fuz = fuzzyAnd(itsCurrInput,itsF1[cat].weights); 00188 for(uint i = 0; i < itsInputSize.getVal(); i++) 00189 itsF1[cat].weights[i] = itsBeta.getVal()*fuz[i] + (1 - itsBeta.getVal()) * itsF1[cat].weights[i]; 00190 } 00191 } 00192 00193 // ###################################################################### 00194 uint FuzzyART::numUnitsCommitted() const 00195 { 00196 uint i; 00197 for(i = 0; i < itsNumCategories.getVal(); i++) if (!itsF1[i].committed) break; 00198 return i; 00199 } 00200 00201 // ###################################################################### 00202 std::vector<double> FuzzyART::fuzzyAnd(const std::vector<double> A, const std::vector<double> B) const 00203 { 00204 std::vector<double> ret(itsInputSize.getVal()); 00205 for(uint i = 0; i < itsInputSize.getVal(); i++) ret[i] = (A[i] < B[i] ? A[i] : B[i]); 00206 return ret; 00207 } 00208 00209 // ###################################################################### 00210 double FuzzyART::norm(const std::vector<double> A) const 00211 { 00212 double sum = 0; 00213 for(uint i = 0; i < itsInputSize.getVal(); i++) sum += A[i]; 00214 return sum; 00215 } 00216 00217 // ###################################################################### 00218 /* So things look consistent in everyone's emacs... */ 00219 /* Local Variables: */ 00220 /* indent-tabs-mode: nil */ 00221 /* End: */ 00222