SOFM.C

Go to the documentation of this file.
00001 /*!@file Learn/SOFM.C Self-Organizing Map network */
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: Lior Elazary <elazary@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Learn/SOFM.C $
00035 // $Id: SOFM.C 14390 2011-01-13 20:17:22Z pez $
00036 //
00037 
00038 #ifndef LEARN_SOFM_C_DEFINED
00039 #define LEARN_SOFM_C_DEFINED
00040 
00041 #include "Learn/SOFM.H"
00042 #include "Image/CutPaste.H"
00043 #include "GUI/DebugWin.H"
00044 #include <fcntl.h>
00045 #include <stdio.h>
00046 
00047 SOFM::SOFM(const char *net_name, int InputSize, int x, int y){
00048 
00049 
00050   name = net_name;
00051   MapSizeX = x;
00052   MapSizeY = y;
00053 
00054   InputLayer = new Layer;
00055   KohonenLayer = new Layer;
00056 
00057   //alocate input
00058   InputLayer->Units = InputSize;
00059   InputLayer->Output = new double[InputSize];
00060 
00061   //alocate map
00062   KohonenLayer->Units = x*y;
00063   KohonenLayer->Output = new double[x*y];
00064   KohonenLayer->Weight = new float*[x*y];
00065   KohonenLayer->StepSizeX = new double[x*y];
00066   KohonenLayer->StepSizeY = new double[x*y];
00067   KohonenLayer->dScoreMean = new double[x*y];
00068   KohonenLayer->score = new double[x*y];
00069   KohonenLayer->BadDim = new int[x*y];
00070   KohonenLayer->Lambda = new double[x*y];
00071 
00072   for (int i=0; i<KohonenLayer->Units; i++){
00073     KohonenLayer->Weight[i] = new float[InputLayer->Units];
00074   }
00075 
00076 
00077   itsWinner = -1; //no winner
00078   itsLooser = -1; //no winner
00079   KohonenAlpha = 0;
00080   OutAlpha = 0 ;
00081   StepAlpha = 0;
00082   Gamma = 0;
00083   Sigma = 0.1;
00084 
00085   itsLearningTime = 0;
00086 }
00087 
00088 void SOFM::InitSofm(){
00089 
00090   for(int i=0; i<KohonenLayer->Units; i++){
00091     KohonenLayer->StepSizeX[i] = -20;
00092     KohonenLayer->StepSizeY[i] = -20;
00093     KohonenLayer->dScoreMean[i] = 0;
00094     KohonenLayer->score[i] = 0;
00095     KohonenLayer->BadDim[i] = 0;
00096     KohonenLayer->Lambda[i] = 0;
00097   }
00098 }
00099 
00100 double SOFM::RandomRange(double Low, double High){
00101   return ( (double) rand() / RAND_MAX) * (High - Low) + Low;
00102 }
00103 
00104 double SOFM::RandomBinaryRange(double Low, double High){
00105   int i;
00106   i = (int)(1.0*rand()/(RAND_MAX+1.0));
00107   if (i)
00108     return High;
00109   else
00110     return Low;
00111 }
00112 
00113 
00114 void SOFM::RandomWeights(int min, int max){
00115   initRandomNumbers();
00116   for (int i=0; i<KohonenLayer->Units; i++){
00117     for (int j=0; j<InputLayer->Units; j++){
00118       KohonenLayer->Weight[i][j] = (float)RandomRange(min, max);
00119     }
00120   }
00121 }
00122 
00123 void SOFM::ZeroWeights(){
00124 
00125   for (int i=0; i<KohonenLayer->Units; i++){
00126     for (int j=0; j<InputLayer->Units; j++){
00127       KohonenLayer->Weight[i][j] = 0;
00128     }
00129   }
00130 }
00131 
00132 
00133 SOFM::~SOFM(){
00134   delete InputLayer;
00135   delete KohonenLayer;
00136 }
00137 
00138 
00139 void SOFM::SetInput(float *in){
00140   for (int i=0; i<InputLayer->Units; i++){
00141     InputLayer->Output[i] = in[i];
00142   }
00143 }
00144 
00145 void SOFM::setInput(const std::vector<double> &in){
00146   for (int i=0; i<InputLayer->Units; i++){
00147     InputLayer->Output[i] = in[i];
00148   }
00149 }
00150 
00151 void SOFM::setInput(const Image<float> &in){
00152   for (int i=0; i<InputLayer->Units; i++){
00153     InputLayer->Output[i] = in[i];
00154   }
00155 }
00156 
00157 Image<float> SOFM::getMap(){
00158 
00159   Image<float> sofmOut(MapSizeX,MapSizeY,NO_INIT);
00160 
00161   //convert the SOFM to image
00162   Image<float>::iterator dest_itr = sofmOut.beginw();
00163 
00164   int i=0;
00165   for (Image<float>::iterator itr = sofmOut.beginw(), stop = sofmOut.endw();
00166       itr != stop; itr++, dest_itr++, i++) {
00167     *dest_itr = (float)KohonenLayer->Output[i];
00168   }
00169 
00170   return sofmOut;
00171 
00172 }
00173 
00174 Image<float> SOFM::getActMap(){
00175 
00176   Image<float> sofmOut(MapSizeX,MapSizeY,NO_INIT);
00177 
00178   //convert the SOFM to image
00179   Image<float>::iterator dest_itr = sofmOut.beginw();
00180 
00181   int i=0;
00182   for (Image<float>::iterator itr = sofmOut.beginw(), stop = sofmOut.endw();
00183       itr != stop; itr++, dest_itr++, i++) {
00184     *dest_itr = (float)KohonenLayer->Output[i];
00185   }
00186 
00187   return sofmOut;
00188 
00189 }
00190 
00191 Image<PixRGB<byte> > SOFM::getWeightsImage(){
00192 
00193 
00194   int i=0;
00195   Image<PixRGB<byte> > sofmOut;
00196 
00197   if (InputLayer->Units == 3)
00198   {
00199     sofmOut = Image<PixRGB<byte> >(MapSizeX,MapSizeY,NO_INIT);
00200 
00201     //convert the SOFM to image
00202     Image<PixRGB<byte> >::iterator dest_itr = sofmOut.beginw();
00203 
00204     for (Image<PixRGB<byte> >::iterator itr = sofmOut.beginw(), stop = sofmOut.endw();
00205         itr != stop; itr++, dest_itr++, i++) {
00206       *dest_itr = PixRGB<byte>(KohonenLayer->Weight[i][0], KohonenLayer->Weight[i][1], KohonenLayer->Weight[i][2]);
00207     }
00208   } else {
00209     int patchSize = (int)sqrt(InputLayer->Units);
00210     int w = MapSizeX*patchSize;
00211     int h = MapSizeY*patchSize;
00212     Image<float> tmp(w,h,NO_INIT);
00213 
00214     for(int j=0; j<MapSizeY; j++)
00215       for(int i=0; i<MapSizeX; i++)
00216       {
00217         int weightIdx = j*MapSizeY + i;
00218         Image<float> patch(patchSize, patchSize, NO_INIT);
00219         for(uint pix=0; pix<patch.size(); pix++)
00220           patch[pix] = KohonenLayer->Weight[weightIdx][pix];
00221         inplaceNormalize(patch, 0.0F, 255.0F);
00222         inplacePaste(tmp, patch, Point2D<int>(i*patchSize,j*patchSize));
00223       }
00224 
00225     sofmOut = toRGB(tmp);
00226 
00227   }
00228 
00229 
00230   return sofmOut;
00231 
00232 }
00233 
00234 std::vector<float> SOFM::getWeights(const Point2D<int> loc)
00235 {
00236   std::vector<float> weights;
00237 
00238   int weightIdx = loc.j*MapSizeY + loc.i;
00239   for(int i=0; i<InputLayer->Units; i++)
00240     weights.push_back(KohonenLayer->Weight[weightIdx][i]);
00241 
00242   return weights;
00243 
00244 }
00245 
00246 
00247 void SOFM::Propagate(DISTANCE_MEASURE dm){
00248 
00249   double minOut = +HUGE_VAL, maxOut = -HUGE_VAL;
00250   int winner = -1, looser = -1;
00251   //Caculate Output of all units
00252 
00253   for (int i=0; i<KohonenLayer->Units; i++){
00254 
00255     switch (dm)
00256     {
00257       case EUCLIDEAN:
00258         {
00259           //find the sum of the input*wight^2
00260           double sum = 0;
00261           for(int j=0; j<InputLayer->Units; j++)
00262           {
00263             double out = InputLayer->Output[j];
00264             double weight = KohonenLayer->Weight[i][j];
00265             sum += (out - weight)*(out - weight);
00266           }
00267           KohonenLayer->Output[i] = sqrt(sum);
00268         }
00269         break;
00270       case KL:
00271         {
00272           //use the kl Distance
00273           double sum = 0;
00274           for(int j=0; j<InputLayer->Units; j++){
00275             double out = InputLayer->Output[j];
00276             double weight = KohonenLayer->Weight[i][j];
00277             sum += weight*log(weight/out);
00278           }
00279           KohonenLayer->Output[i] = fabs(sum);
00280         }
00281         break;
00282       case L2GMM:
00283         {
00284 
00285 
00286 
00287         }
00288     }
00289 
00290     //find the winner
00291     if (KohonenLayer->Output[i] < minOut){
00292       minOut = KohonenLayer->Output[i];
00293       winner = i;
00294     }
00295     if (KohonenLayer->Output[i] > maxOut){
00296       maxOut = KohonenLayer->Output[i];
00297       looser = i;
00298     }
00299 
00300   }
00301 
00302   itsWinner = winner;
00303   itsWinnerValue = minOut;
00304   itsLooser = looser;
00305   itsLooserValue = maxOut;
00306 
00307 }
00308 
00309 double SOFM::Neighborhood(int i){
00310 
00311   double Distance;
00312   int iRow, iCol, jRow, jCol;
00313 
00314   iRow = i / MapSizeX; jRow = itsWinner / MapSizeX;
00315   iCol = i % MapSizeX; jCol = itsWinner % MapSizeX;
00316 
00317   Distance = sqrt(((iRow-jRow)*(iRow-jRow)) + ((iCol-jCol)*(iCol-jCol)));
00318 
00319   return exp(-(Distance*Distance) / (2*(Sigma*Sigma)));
00320 }
00321 
00322 Point2D<int> SOFM::getWinner(double& val)
00323 {
00324   int y = itsWinner/MapSizeX;
00325   int x = itsWinner - (y*MapSizeX);
00326 
00327   val = itsWinnerValue;
00328 
00329   return Point2D<int>(x,y);
00330 }
00331 
00332 
00333 void SOFM::Train(float *Input, float *Target, double score){
00334 
00335   double Out, Weight, Lambda=0;
00336 
00337   //set the map to the input
00338   for(int i=0; i<KohonenLayer->Units; i++){
00339     Lambda = Neighborhood(i);
00340     if (Lambda > 0.000001){
00341       for(int j=0; j<InputLayer->Units; j++){
00342         Out = Input[j];
00343         Weight = KohonenLayer->Weight[i][j];
00344         KohonenLayer->Weight[i][j] += KohonenAlpha * Lambda * (Out - Weight);
00345       }
00346     }
00347     KohonenLayer->Lambda[i] = Lambda;         //set the Lambda for display
00348     //StepSize = KohonenLayer->StepSize[i];
00349     //KohonenLayer->StepSize[i] += StepAlpha * Lambda * -StepSize;
00350   }
00351 
00352 
00353   /*
00354   //set the score
00355 
00356   KohonenLayer->score[Winner] = score;
00357   for(int i=0; i<KohonenLayer->Units; i++){
00358   Lambda = Neighborhood(i);
00359   if (Lambda > 0.1)        //only update if not set from before
00360   if (KohonenLayer->score[i] == 0){
00361   KohonenLayer->score[i] = score;
00362   }
00363   if (i != Winner){
00364 //KohonenLayer->score[i] += 0.01 * (double)((int)(score/Lambda)%900);        //score increses
00365 }
00366 if (Lambda > 0.1){
00367 KohonenLayer->StepSizeX[i] = KohonenLayer->StepSizeX[Winner];
00368 KohonenLayer->StepSizeY[i] = KohonenLayer->StepSizeY[Winner];
00369 }
00370 if (Lambda > 0.5){
00371 KohonenLayer->BadDim[i] = KohonenLayer->BadDim[Winner];
00372 }
00373 
00374 } */
00375 
00376 }
00377 
00378 void SOFM::organize(std::vector<double> &input){
00379 
00380   double Out, Weight, Lambda=0;
00381 
00382   //set the map to the input
00383   for(int i=0; i<KohonenLayer->Units; i++){
00384     Lambda = Neighborhood(i);
00385     if (Lambda > 0.000001){
00386       for(int j=0; j<InputLayer->Units; j++){
00387         Out = input[j];
00388         Weight = KohonenLayer->Weight[i][j];
00389         KohonenLayer->Weight[i][j] += KohonenAlpha * Lambda * (Out - Weight);
00390       }
00391     }
00392     KohonenLayer->Lambda[i] = Lambda;         //set the Lambda for display
00393     //StepSize = KohonenLayer->StepSize[i];
00394     //KohonenLayer->StepSize[i] += StepAlpha * Lambda * -StepSize;
00395   }
00396 
00397 }
00398 
00399 void SOFM::organize(const Image<float>& input){
00400 
00401   double Out, Weight, Lambda=0;
00402 
00403   //increment the learning time
00404   SetLearningRate(itsLearningTime++);
00405 
00406   //set the map to the input
00407   for(int i=0; i<KohonenLayer->Units; i++){
00408     Lambda = Neighborhood(i);
00409     if (Lambda > 0.000001){
00410       for(int j=0; j<InputLayer->Units; j++){
00411         Out = input[j];
00412         Weight = KohonenLayer->Weight[i][j];
00413         //KohonenLayer->Weight[i][j] += KohonenAlpha * Lambda * (Out - Weight);
00414         KohonenLayer->Weight[i][j] += 1 * Lambda * (Out - Weight);
00415       }
00416     }
00417     KohonenLayer->Lambda[i] = Lambda;         //set the Lambda for display
00418     //StepSize = KohonenLayer->StepSize[i];
00419     //KohonenLayer->StepSize[i] += StepAlpha * Lambda * -StepSize;
00420   }
00421 
00422 }
00423 
00424 void SOFM::SetLearningRate(unsigned long long learning_time){
00425 
00426   //set the net param
00427   KohonenAlpha         = 0.1 * pow(0.001, (double) learning_time / 1000);
00428   OutAlpha             = 1; //0.5 * pow(0.01, (double) learning_time / 1000);
00429   StepAlpha           = 0.05;
00430   Gamma                     = 0.05;
00431   // after the leraning time, always update about 0.5 around the winner
00432   // this is why the 1.5 +
00433   Sigma                    =  0.5 + ( MapSizeX * pow(0.2, (double) learning_time / 1000));
00434 
00435   //LINFO("%llu: Sigma %f, Alpha %f",
00436   //    learning_time, Sigma, KohonenAlpha);
00437 
00438 }
00439 
00440 void SOFM::ReadNet(const char *filename){
00441   int fd;
00442   int in, sizeX, sizeY;
00443 
00444   if ((fd = open(filename, 0, 0644)) == -1) return;
00445 
00446   printf("Reading from %s\n", filename);
00447   //read the # of input, size of sofm, and output
00448   if(read(fd, (char *) &in, sizeof(int)) != sizeof(int)) LFATAL("fread error");
00449   if(read(fd, (char *) &sizeX, sizeof(int)) != sizeof(int)) LFATAL("fread error");
00450   if(read(fd, (char *) &sizeY, sizeof(int)) != sizeof(int)) LFATAL("fread error");
00451   if(read(fd, (char *) &itsLearningTime, sizeof(itsLearningTime)) != sizeof(itsLearningTime)) LFATAL("fread error");
00452 
00453   printf("%i %i %i %llu\n", in, sizeX, sizeY, itsLearningTime);
00454 
00455   //read the weights
00456 
00457   for (int i=0; i<KohonenLayer->Units; i++){
00458     int sz = sizeof(float)*InputLayer->Units;
00459     if(read(fd, KohonenLayer->Weight[i], sz) != sz) LFATAL("fread failed");
00460   }
00461 
00462   close(fd);
00463 
00464 }
00465 
00466 void SOFM::WriteNet(const char *filename){
00467   int fd;
00468 
00469   if ((fd = creat(filename, 0644)) == -1) {
00470     printf("Can not open %s for saving\n", filename);
00471     return;
00472   }
00473 
00474   //write the # of input, size of sofm, and output
00475   if(write(fd, (char *) &InputLayer->Units, sizeof(int)) != sizeof(int)) LFATAL("write failed");
00476   if(write(fd, (char *) &MapSizeX, sizeof(int)) != sizeof(int)) LFATAL("write failed");
00477   if(write(fd, (char *) &MapSizeY, sizeof(int)) != sizeof(int)) LFATAL("write failed");
00478   if(write(fd, (char *) &itsLearningTime, sizeof(itsLearningTime)) != sizeof(itsLearningTime)) LFATAL("write failed");
00479 
00480   //write the weights
00481 
00482   for (int i=0; i<KohonenLayer->Units; i++){
00483     int sz = sizeof(float)*InputLayer->Units;
00484     if(write(fd, KohonenLayer->Weight[i], sz) != sz) LFATAL("write failed");
00485   }
00486 
00487   close(fd);
00488 }
00489 
00490 
00491 
00492 // ######################################################################
00493 /* So things look consistent in everyone's emacs... */
00494 /* Local Variables: */
00495 /* indent-tabs-mode: nil */
00496 /* End: */
00497 
00498 #endif // LEARN_SOFM_C_DEFINED
Generated on Sun May 8 08:40:58 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3