KernelMachine.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) 1999-2009 Soeren Sonnenburg
00008  * Copyright (C) 1999-2009 Fraunhofer Institute FIRST and Max-Planck-Society
00009  */
00010 
00011 
00012 
00013 #include "classifier/KernelMachine.h"
00014 #include "lib/Signal.h"
00015 #include "base/Parameter.h"
00016 
00017 using namespace shogun;
00018 
00019 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00020 struct S_THREAD_PARAM
00021 {
00022     CKernelMachine* kernel_machine;
00023     CLabels* result;
00024     int32_t start;
00025     int32_t end;
00026     bool verbose;
00027 };
00028 #endif // DOXYGEN_SHOULD_SKIP_THIS
00029 
00030 CKernelMachine::CKernelMachine()
00031 : CClassifier(), kernel(NULL), use_batch_computation(true), use_linadd(true), use_bias(true)
00032 {
00033     m_parameters->add((CSGObject**) &kernel, "kernel");
00034     m_parameters->add(&use_batch_computation, "use_batch_computation",
00035                       "Batch computation is enabled.");
00036     m_parameters->add(&use_linadd, "use_linadd",
00037                       "Linadd is enabled.");
00038     m_parameters->add(&use_bias, "use_bias",
00039                       "Bias shall be used.");
00040     m_parameters->add(&m_bias, "m_bias",
00041                       "Bias term.");
00042     m_parameters->add_vector(&m_alpha, &num_svs, "m_alpha",
00043                              "Array of coefficients alpha.");
00044     m_parameters->add_vector(&m_svs, &num_svs, "m_svs",
00045                              "Number of ``support vectors''.");
00046 
00047     m_bias=0.0;
00048     m_alpha=NULL;
00049     m_svs=NULL;
00050     num_svs=0;
00051 }
00052 
00053 CKernelMachine::~CKernelMachine()
00054 {
00055     SG_UNREF(kernel);
00056 
00057     delete[] m_alpha;
00058     delete[] m_svs;
00059 }
00060 
00061 bool CKernelMachine::init_kernel_optimization()
00062 {
00063     int32_t num_sv=get_num_support_vectors();
00064 
00065     if (kernel && kernel->has_property(KP_LINADD) && num_sv>0)
00066     {
00067         int32_t * sv_idx    = new int32_t[num_sv] ;
00068         float64_t* sv_weight = new float64_t[num_sv] ;
00069 
00070         for(int32_t i=0; i<num_sv; i++)
00071         {
00072             sv_idx[i]    = get_support_vector(i) ;
00073             sv_weight[i] = get_alpha(i) ;
00074         }
00075 
00076         bool ret = kernel->init_optimization(num_sv, sv_idx, sv_weight) ;
00077 
00078         delete[] sv_idx ;
00079         delete[] sv_weight ;
00080 
00081         if (!ret)
00082             SG_ERROR( "initialization of kernel optimization failed\n");
00083 
00084         return ret;
00085     }
00086     else
00087         SG_ERROR( "initialization of kernel optimization failed\n");
00088 
00089     return false;
00090 }
00091 
00092 CLabels* CKernelMachine::classify()
00093 {
00094     CLabels* lab=NULL;
00095 
00096     if (!kernel)
00097         SG_ERROR( "Kernelmachine can not proceed without kernel!\n");
00098 
00099     if ( kernel && kernel->get_num_vec_rhs()>0 )
00100     {
00101         int32_t num_vectors=kernel->get_num_vec_rhs();
00102 
00103         lab=new CLabels(num_vectors);
00104         SG_DEBUG( "computing output on %d test examples\n", num_vectors);
00105 
00106         CSignal::clear_cancel();
00107 
00108         if (io->get_show_progress())
00109             io->enable_progress();
00110         else
00111             io->disable_progress();
00112 
00113         if (kernel->has_property(KP_BATCHEVALUATION) &&
00114                 get_batch_computation_enabled())
00115         {
00116             float64_t* output=new float64_t[num_vectors];
00117             memset(output, 0, sizeof(float64_t)*num_vectors);
00118 
00119             if (get_num_support_vectors()>0)
00120             {
00121                 int32_t* sv_idx=new int32_t[get_num_support_vectors()];
00122                 float64_t* sv_weight=new float64_t[get_num_support_vectors()];
00123                 int32_t* idx=new int32_t[num_vectors];
00124 
00125                 //compute output for all vectors v[0]...v[num_vectors-1]
00126                 for (int32_t i=0; i<num_vectors; i++)
00127                     idx[i]=i;
00128 
00129                 for (int32_t i=0; i<get_num_support_vectors(); i++)
00130                 {
00131                     sv_idx[i]    = get_support_vector(i) ;
00132                     sv_weight[i] = get_alpha(i) ;
00133                 }
00134 
00135                 kernel->compute_batch(num_vectors, idx,
00136                         output, get_num_support_vectors(), sv_idx, sv_weight);
00137                 delete[] sv_idx ;
00138                 delete[] sv_weight ;
00139                 delete[] idx;
00140             }
00141 
00142             for (int32_t i=0; i<num_vectors; i++)
00143                 lab->set_label(i, get_bias()+output[i]);
00144 
00145             delete[] output;
00146         }
00147         else
00148         {
00149             int32_t num_threads=parallel->get_num_threads();
00150             ASSERT(num_threads>0);
00151 
00152             if (num_threads < 2)
00153             {
00154                 S_THREAD_PARAM params;
00155                 params.kernel_machine=this;
00156                 params.result=lab;
00157                 params.start=0;
00158                 params.end=num_vectors;
00159                 params.verbose=true;
00160                 classify_example_helper((void*) &params);
00161             }
00162 #ifndef WIN32
00163             else
00164             {
00165                 pthread_t* threads = new pthread_t[num_threads-1];
00166                 S_THREAD_PARAM* params = new S_THREAD_PARAM[num_threads];
00167                 int32_t step= num_vectors/num_threads;
00168 
00169                 int32_t t;
00170 
00171                 for (t=0; t<num_threads-1; t++)
00172                 {
00173                     params[t].kernel_machine = this;
00174                     params[t].result = lab;
00175                     params[t].start = t*step;
00176                     params[t].end = (t+1)*step;
00177                     params[t].verbose = false;
00178                     pthread_create(&threads[t], NULL,
00179                             CKernelMachine::classify_example_helper, (void*)&params[t]);
00180                 }
00181 
00182                 params[t].kernel_machine = this;
00183                 params[t].result = lab;
00184                 params[t].start = t*step;
00185                 params[t].end = num_vectors;
00186                 params[t].verbose = true;
00187                 classify_example_helper((void*) &params[t]);
00188 
00189                 for (t=0; t<num_threads-1; t++)
00190                     pthread_join(threads[t], NULL);
00191 
00192                 delete[] params;
00193                 delete[] threads;
00194             }
00195 #endif
00196         }
00197 
00198 #ifndef WIN32
00199         if ( CSignal::cancel_computations() )
00200             SG_INFO( "prematurely stopped.           \n");
00201         else
00202 #endif
00203             SG_DONE();
00204     }
00205     else
00206         return NULL;
00207 
00208     return lab;
00209 }
00210 
00211 float64_t CKernelMachine::classify_example(int32_t num)
00212 {
00213     ASSERT(kernel);
00214 
00215     if (kernel->has_property(KP_LINADD) && (kernel->get_is_initialized()))
00216     {
00217         float64_t score = kernel->compute_optimized(num);
00218         return score+get_bias();
00219     }
00220     else
00221     {
00222         float64_t score=0;
00223         for(int32_t i=0; i<get_num_support_vectors(); i++)
00224             score+=kernel->kernel(get_support_vector(i), num)*get_alpha(i);
00225 
00226         return score+get_bias();
00227     }
00228 }
00229 
00230 
00231 CLabels* CKernelMachine::classify(CFeatures* data)
00232 {
00233     if (!kernel)
00234         SG_ERROR("No kernel assigned!\n");
00235 
00236     CFeatures* lhs=kernel->get_lhs();
00237     if (!lhs || !lhs->get_num_vectors())
00238     {
00239         SG_UNREF(lhs);
00240         SG_ERROR("No vectors on left hand side\n");
00241     }
00242     kernel->init(lhs, data);
00243     SG_UNREF(lhs);
00244 
00245     return classify();
00246 }
00247 
00248 void* CKernelMachine::classify_example_helper(void* p)
00249 {
00250     S_THREAD_PARAM* params= (S_THREAD_PARAM*) p;
00251     CLabels* result=params->result;
00252     CKernelMachine* kernel_machine=params->kernel_machine;
00253 
00254 #ifdef WIN32
00255     for (int32_t vec=params->start; vec<params->end; vec++)
00256 #else
00257     for (int32_t vec=params->start; vec<params->end &&
00258             !CSignal::cancel_computations(); vec++)
00259 #endif
00260     {
00261         if (params->verbose)
00262         {
00263             int32_t num_vectors=params->end - params->start;
00264             int32_t v=vec-params->start;
00265             if ( (v% (num_vectors/100+1))== 0)
00266                 SG_SPROGRESS(v, 0.0, num_vectors-1);
00267         }
00268 
00269         result->set_label(vec, kernel_machine->classify_example(vec));
00270     }
00271 
00272     return NULL;
00273 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

SHOGUN Machine Learning Toolbox - Documentation