MKLMultiClass.cpp

Go to the documentation of this file.
00001 /*
00002  * This program is free software; you can redistribute it and/or modify
00003  * it under the terms of the GNU General Public License as published by
00004  * the Free Software Foundation; either version 3 of the License, or
00005  * (at your option) any later version.
00006  *
00007  * Written (W) 2009 Alexander Binder
00008  * Copyright (C) 2009 Fraunhofer Institute FIRST and Max-Planck-Society
00009  */
00010 
00011 #include "classifier/mkl/MKLMultiClass.h"
00012 #include "lib/io.h"
00013 
00014 using namespace shogun;
00015 
00016 
00017 CMKLMultiClass::CMKLMultiClass()
00018 : CMultiClassSVM(ONE_VS_REST)
00019 {
00020     svm=NULL;
00021     lpw=NULL;
00022 
00023     mkl_eps=0.01;
00024     max_num_mkl_iters=999;
00025 }
00026 
00027 CMKLMultiClass::CMKLMultiClass(float64_t C, CKernel* k, CLabels* lab)
00028 : CMultiClassSVM(ONE_VS_REST, C, k, lab)
00029 {
00030     svm=NULL;
00031     lpw=NULL;
00032     
00033     mkl_eps=0.01;
00034     max_num_mkl_iters=999;
00035 
00036 }
00037 
00038 
00039 CMKLMultiClass::~CMKLMultiClass()
00040 {
00041     SG_UNREF(svm);
00042     svm=NULL;
00043     delete lpw;
00044     lpw=NULL;
00045 }
00046 
00047 CMKLMultiClass::CMKLMultiClass( const CMKLMultiClass & cm)
00048 : CMultiClassSVM(ONE_VS_REST)
00049 {
00050     svm=NULL;
00051     lpw=NULL;
00052     SG_ERROR(
00053             " CMKLMultiClass::CMKLMultiClass(const CMKLMultiClass & cm): must "
00054             "not be called, glpk structure is currently not copyable");
00055 }
00056 
00057 CMKLMultiClass CMKLMultiClass::operator=( const CMKLMultiClass & cm)
00058 {
00059         SG_ERROR(
00060             " CMKLMultiClass CMKLMultiClass::operator=(...): must "
00061             "not be called, glpk structure is currently not copyable");
00062     return (*this);
00063 }
00064 
00065 
00066 void CMKLMultiClass::initsvm()
00067 {
00068     if (!labels)    
00069     {
00070         SG_ERROR("CMKLMultiClass::initsvm(): the set labels is NULL\n");
00071     }
00072 
00073     SG_UNREF(svm);
00074     svm=new CGMNPSVM;
00075     SG_REF(svm);
00076 
00077     svm->set_C(get_C1(),get_C2());
00078     svm->set_epsilon(epsilon);
00079 
00080     int32_t numlabels;
00081     float64_t * lb=labels->get_labels ( numlabels);
00082 
00083     if (numlabels<=0)   
00084     {
00085         SG_ERROR("CMKLMultiClass::initsvm(): the number of labels is "
00086                 "nonpositive, do not know how to handle this!\n");
00087     }
00088 
00089     CLabels* newlab=new CLabels(lb, labels->get_num_labels() );
00090     delete[] lb;
00091     lb=NULL;
00092 
00093     svm->set_labels(newlab);
00094 
00095     newlab=NULL;
00096 }
00097 
00098 void CMKLMultiClass::initlpsolver()
00099 {
00100     if (!kernel)    
00101     {
00102         SG_ERROR("CMKLMultiClass::initlpsolver(): the set kernel is NULL\n");
00103     }
00104 
00105     if (kernel->get_kernel_type()!=K_COMBINED)
00106     {
00107         SG_ERROR("CMKLMultiClass::initlpsolver(): given kernel is not of type"
00108                 " K_COMBINED %d required by Multiclass Mkl \n",
00109                 kernel->get_kernel_type());
00110     }
00111 
00112     int numker=dynamic_cast<CCombinedKernel *>(kernel)->get_num_subkernels();
00113 
00114     ASSERT(numker>0);
00115     /*
00116     if (lpw)
00117     {
00118         delete lpw;
00119     }
00120     */
00121     lpw=new MKLMultiClassGLPK;
00122     lpw->setup(numker);
00123 }
00124 
00125 
00126 bool CMKLMultiClass::evaluatefinishcriterion(const int32_t
00127         numberofsilpiterations)
00128 {
00129     if ( (max_num_mkl_iters>0) && (numberofsilpiterations>=max_num_mkl_iters) )
00130     {
00131         return(true);
00132     }
00133 
00134     if (weightshistory.size()>1)
00135     {
00136         std::vector<float64_t> wold,wnew;
00137 
00138         wold=weightshistory[ weightshistory.size()-2 ];
00139         wnew=weightshistory.back();
00140         float64_t delta=0;
00141 
00142         ASSERT (wold.size()==wnew.size());
00143 
00144         for (size_t i=0;i< wnew.size();++i)
00145         {
00146             delta+=(wold[i]-wnew[i])*(wold[i]-wnew[i]);
00147         }
00148         delta=sqrt(delta);
00149 
00150         if( (delta < mkl_eps) && (numberofsilpiterations>=1) )
00151         {
00152             return(true);
00153         }
00154     }
00155 
00156     return(false);
00157 }
00158 
00159 void CMKLMultiClass::addingweightsstep( const std::vector<float64_t> &
00160         curweights)
00161 {
00162 
00163     if (weightshistory.size()>2)
00164     {
00165         weightshistory.erase(weightshistory.begin());
00166     }
00167 
00168     float64_t* weights(NULL);
00169     weights=new float64_t[curweights.size()];
00170     std::copy(curweights.begin(),curweights.end(),weights);
00171 
00172     kernel->set_subkernel_weights(  weights, curweights.size());
00173     delete[] weights;
00174     weights=NULL;
00175 
00176     initsvm();
00177 
00178     svm->set_kernel(kernel);
00179     svm->train();
00180 
00181     float64_t sumofsignfreealphas=getsumofsignfreealphas();
00182     int32_t numkernels=
00183             dynamic_cast<CCombinedKernel *>(kernel)->get_num_subkernels();
00184 
00185 
00186     std::vector<float64_t> normw2(numkernels);
00187     for (int32_t ind=0; ind < numkernels; ++ind )
00188     {
00189         normw2[ind]=getsquarenormofprimalcoefficients( ind );
00190     }
00191 
00192     lpw->addconstraint(normw2,sumofsignfreealphas);
00193 }
00194 
00195 float64_t CMKLMultiClass::getsumofsignfreealphas()
00196 {
00197 
00198     std::vector<int> trainlabels2(labels->get_num_labels());
00199     int32_t tmpint;
00200     int32_t * lab=labels->get_int_labels ( tmpint);
00201     std::copy(lab,lab+labels->get_num_labels(), trainlabels2.begin());
00202     delete[] lab;
00203     lab=NULL;
00204 
00205 
00206     ASSERT (trainlabels2.size()>0);
00207     float64_t sum=0;
00208 
00209     for (int32_t nc=0; nc< labels->get_num_classes();++nc)
00210     {
00211         CSVM * sm=svm->get_svm(nc);
00212 
00213         float64_t bia=sm->get_bias();
00214         sum+= bia*bia;
00215 
00216         SG_UNREF(sm);
00217     }
00218 
00219     ::std::vector< ::std::vector<float64_t> > basealphas;
00220     svm->getbasealphas( basealphas);
00221 
00222     for (size_t lb=0; lb< trainlabels2.size();++lb)
00223     {
00224         for (int32_t nc=0; nc< labels->get_num_classes();++nc)
00225         {
00226             CSVM * sm=svm->get_svm(nc);
00227 
00228             if ((int)nc!=trainlabels2[lb])
00229             {
00230                 CSVM * sm2=svm->get_svm(trainlabels2[lb]);
00231 
00232                 float64_t bia1=sm2->get_bias();
00233                 float64_t bia2=sm->get_bias();
00234                 SG_UNREF(sm2);
00235 
00236                 sum+= -basealphas[nc][lb]*(bia1-bia2-1);
00237             }
00238             SG_UNREF(sm);
00239         }
00240     }
00241 
00242     return(sum);
00243 }
00244 
00245 float64_t CMKLMultiClass::getsquarenormofprimalcoefficients(
00246         const int32_t ind)
00247 {
00248     CKernel * ker=dynamic_cast<CCombinedKernel *>(kernel)->get_kernel(ind);
00249 
00250     float64_t tmp=0;
00251 
00252     for (int32_t classindex=0; classindex< labels->get_num_classes();
00253             ++classindex)
00254     {
00255         CSVM * sm=svm->get_svm(classindex);
00256 
00257         for (int32_t i=0; i < sm->get_num_support_vectors(); ++i)
00258         {
00259             float64_t alphai=sm->get_alpha(i);
00260             int32_t svindi= sm->get_support_vector(i); 
00261 
00262             for (int32_t k=0; k < sm->get_num_support_vectors(); ++k)
00263             {
00264                 float64_t alphak=sm->get_alpha(k);
00265                 int32_t svindk=sm->get_support_vector(k);
00266 
00267                 tmp+=alphai*ker->kernel(svindi,svindk)
00268                 *alphak;
00269 
00270             }
00271         }
00272         SG_UNREF(sm);
00273     }
00274     SG_UNREF(ker);
00275     ker=NULL;
00276 
00277     return(tmp);
00278 }
00279 
00280 
00281 bool CMKLMultiClass::train(CFeatures* data)
00282 {
00283     int numcl=labels->get_num_classes();
00284     ASSERT(kernel);
00285     ASSERT(labels && labels->get_num_labels());
00286 
00287     if (data)
00288     {
00289         if (labels->get_num_labels() != data->get_num_vectors())
00290             SG_ERROR("Number of training vectors does not match number of "
00291                     "labels\n");
00292         kernel->init(data, data);
00293     }
00294 
00295     initlpsolver();
00296 
00297     weightshistory.clear();
00298 
00299     int32_t numkernels=
00300             dynamic_cast<CCombinedKernel *>(kernel)->get_num_subkernels();
00301 
00302     ::std::vector<float64_t> curweights(numkernels,1.0/numkernels);
00303     weightshistory.push_back(curweights);
00304 
00305     addingweightsstep(curweights);
00306 
00307     int32_t numberofsilpiterations=0;
00308     bool final=false;
00309     while (!final)
00310     {
00311 
00312         curweights.clear();
00313         lpw->computeweights(curweights);
00314         weightshistory.push_back(curweights);
00315 
00316 
00317         final=evaluatefinishcriterion(numberofsilpiterations);
00318         ++numberofsilpiterations;
00319 
00320         addingweightsstep(curweights);
00321 
00322     } // while(false==final)
00323 
00324 
00325     //set alphas, bias, support vecs
00326     ASSERT(numcl>=1);
00327     create_multiclass_svm(numcl);
00328 
00329     for (int32_t i=0; i<numcl; i++)
00330     {
00331         CSVM* osvm=svm->get_svm(i);
00332         CSVM* nsvm=new CSVM(osvm->get_num_support_vectors());
00333 
00334         for (int32_t k=0; k<osvm->get_num_support_vectors() ; k++)
00335         {
00336             nsvm->set_alpha(k, osvm->get_alpha(k) );
00337             nsvm->set_support_vector(k,osvm->get_support_vector(k) );
00338         }
00339         nsvm->set_bias(osvm->get_bias() );
00340         set_svm(i, nsvm);
00341 
00342         SG_UNREF(osvm);
00343         osvm=NULL;
00344     }
00345 
00346     SG_UNREF(svm);
00347     svm=NULL;
00348     if (lpw)
00349     {
00350         delete lpw;
00351     }
00352     lpw=NULL;
00353     return(true);
00354 }
00355 
00356 
00357 
00358 
00359 float64_t* CMKLMultiClass::getsubkernelweights(int32_t & numweights)
00360 {
00361     if ( weightshistory.empty() )
00362     {
00363         numweights=0;
00364         return NULL;
00365     }
00366 
00367     std::vector<float64_t> subkerw=weightshistory.back();
00368     numweights=weightshistory.back().size();
00369 
00370     float64_t* res=new float64_t[numweights];
00371     std::copy(weightshistory.back().begin(), weightshistory.back().end(),res);
00372     return res;
00373 }
00374 
00375 void CMKLMultiClass::set_mkl_epsilon(float64_t eps )
00376 {
00377     mkl_eps=eps;
00378 }
00379 
00380 void CMKLMultiClass::set_max_num_mkliters(int32_t maxnum)
00381 {
00382     max_num_mkl_iters=maxnum;
00383 }

SHOGUN Machine Learning Toolbox - Documentation