SHOGUN v0.9.0
|
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*) ¶ms); 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*)¶ms[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*) ¶ms[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 }