src/IO/OutputInfo.cpp

00001 /*
00002 * This file is part of MultiBoost, a multi-class 
00003 * AdaBoost learner/classifier
00004 *
00005 * Copyright (C) 2005 Norman Casagrande
00006 * For informations write to nova77@gmail.com
00007 *
00008 * This library is free software; you can redistribute it and/or
00009 * modify it under the terms of the GNU Lesser General Public
00010 * License as published by the Free Software Foundation; either
00011 * version 2.1 of the License, or (at your option) any later version.
00012 *
00013 * This library is distributed in the hope that it will be useful,
00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016 * Lesser General Public License for more details.
00017 *
00018 * You should have received a copy of the GNU Lesser General Public
00019 * License along with this library; if not, write to the Free Software
00020 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00021 *
00022 */
00023 
00024 #include <limits>
00025 #include "IO/OutputInfo.h"
00026 
00027 namespace MultiBoost {
00028 
00029 // -------------------------------------------------------------------------
00030 
00031 OutputInfo::OutputInfo(const string& outputInfoFile)
00032 {
00033    // open the stream
00034    _outStream.open(outputInfoFile.c_str());
00035 
00036    // is it really open?
00037    if ( !_outStream.is_open() )
00038    {
00039       cerr << "ERROR: cannot open the output steam (<" 
00040            << outputInfoFile << ">) for the step-by-step info!" << endl;
00041       exit(1);
00042    }
00043 }
00044 
00045 // -------------------------------------------------------------------------
00046 
00047 void OutputInfo::outputIteration(const int t)
00048 { 
00049    _outStream << t; // just output t
00050 }
00051 
00052 // -------------------------------------------------------------------------
00053 
00054 void OutputInfo::outputError(InputData* pData, BaseLearner* pWeakHypothesis)
00055 {
00056    const int numClasses = ClassMappings::getNumClasses();
00057    const int numExamples = pData->getNumExamples();
00058 
00059    if ( _gTableMap.find(pData) == _gTableMap.end() )
00060    {
00061       // if it's the first time it sees this data
00062       // it creates and initializes a new table
00063 
00064       table& g = _gTableMap[pData];
00065       g.resize(numExamples);
00066 
00067       for ( int i = 0; i < numExamples; ++i )
00068          g[i].resize(numClasses, 0);
00069    }
00070    
00071    table& g = _gTableMap[pData];
00072    
00073    int numWrongs = 0;
00074 
00075    // Compute the training error
00076    for (int i = 0; i < numExamples; ++i)
00077    {
00078       // the class with the highest vote
00079       int maxClassIdx = -1;
00080 
00081       // the vote of the winning class
00082       double maxClass = -numeric_limits<double>::max();
00083 
00084       for (int l = 0; l < numClasses; ++l)
00085       {     
00086          // building the strong learner
00087          g[i][l] += pWeakHypothesis->getAlpha() * // alpha
00088                     pWeakHypothesis->classify( pData, i, l ); // h_l(x)
00089 
00090          // get the winner class
00091          if (g[i][l] > maxClass)
00092          {
00093             maxClass = g[i][l];
00094             maxClassIdx = l;
00095          }
00096 
00097       }
00098 
00099       // if the winner class is not the real class, then it is
00100       // an error
00101       if (maxClassIdx != pData->getClass(i))
00102          ++numWrongs;
00103    }
00104 
00105    // The error must be bounded between 0 and 1
00106    _outStream << '\t' << (double)(numWrongs)/(double)(numExamples);
00107 }
00108 
00109 // -------------------------------------------------------------------------
00110 
00111 void OutputInfo::outputMargins(InputData* pData, BaseLearner* pWeakHypothesis)
00112 {
00113    const int numClasses = ClassMappings::getNumClasses();
00114    const int numExamples = pData->getNumExamples();
00115 
00116    if ( _margins.find(pData) == _margins.end() )
00117    {
00118       // if it's the first time it sees this data
00119       // it creates and initializes a new table
00120 
00121       table& margins = _margins[pData];
00122       margins.resize(numExamples);
00123 
00124       for ( int i = 0; i < numExamples; ++i )
00125          margins[i].resize(numClasses, 0);
00126    }
00127 
00128    // Same for the sums of alpha. If it is the first time it
00129    // sees this data, it initialize the sums of the alpha for it
00130    if ( _alphaSums.find(pData) == _alphaSums.end() )
00131       _alphaSums[pData] = 0;
00132 
00133    table& margins = _margins[pData];
00134 
00135    double minMargin = numeric_limits<double>::max();
00136    double belowZeroMargin = 0;                        
00137 
00138    for (int i = 0; i < numExamples; ++i)
00139    {
00140       for (int l = 0; l < numClasses; ++l)
00141       {
00142          // hy = +1 if the classification it is correct, -1 otherwise
00143          double hy = pWeakHypothesis->classify(pData, i, l) * // h_l(x_i)
00144                      pData->getBinaryClass(i, l); // y_i
00145 
00146          double w = pData->getWeight(i, l);
00147 
00148          // compute the margin
00149          margins[i][l] += pWeakHypothesis->getAlpha() * hy;
00150 
00151          // gets the margin below zero
00152          if ( margins[i][l] < 0 )
00153          {
00154             if (l == pData->getClass(i))
00155                belowZeroMargin += ( 1.0 / (double)(2*numExamples) );
00156             else
00157                belowZeroMargin += ( 1.0 / (double)(2*numExamples * (numClasses - 1)) );
00158 
00159          }        
00160 
00161          // get the minimum margin among classes and examples
00162          if (margins[i][l] < minMargin)
00163             minMargin = margins[i][l];
00164       }
00165    }
00166 
00167    // compute the sums of the alphas for normalization
00168    _alphaSums[pData] += pWeakHypothesis->getAlpha();
00169 
00170    _outStream << '\t' << minMargin/_alphaSums[pData] << "\t" // minimum margin
00171               << belowZeroMargin; // margins that are below zero
00172 }
00173 
00174 // -------------------------------------------------------------------------
00175 
00176 void OutputInfo::outputEdge(InputData* pData, BaseLearner* pWeakHypothesis)
00177 {
00178    const int numClasses = ClassMappings::getNumClasses();
00179    const int numExamples = pData->getNumExamples();
00180 
00181    double gamma = 0; // the edge
00182 
00183    for (int i = 0; i < numExamples; ++i)
00184    {
00185       for (int l = 0; l < numClasses; ++l)
00186       {      
00187          // hy = +1 if the classification it is correct, -1 otherwise
00188          double hy = pWeakHypothesis->classify(pData, i, l) * // h_l(x_i)
00189                      pData->getBinaryClass(i, l); // y_i
00190 
00191          double w = pData->getWeight(i, l);
00192 
00193          gamma += w * hy;
00194       }
00195    }
00196 
00197    _outStream << '\t' << gamma; // edge
00198 
00199 }
00200 
00201 // -------------------------------------------------------------------------
00202 
00203 } // end of namespace MultiBoost

Generated on Mon Nov 28 21:43:46 2005 for MultiBoost by  doxygen 1.4.5