PLearn 0.1
|
00001 // -*- C++ -*- 00002 00003 // plearn_learners/meta/MultiClassAdaBoost.cc 00004 // 00005 // Copyright (C) 2007 Frederic Bastien 00006 // 00007 // Redistribution and use in source and binary forms, with or without 00008 // modification, are permitted provided that the following conditions are met: 00009 // 00010 // 1. Redistributions of source code must retain the above copyright 00011 // notice, this list of conditions and the following disclaimer. 00012 // 00013 // 2. Redistributions in binary form must reproduce the above copyright 00014 // notice, this list of conditions and the following disclaimer in the 00015 // documentation and/or other materials provided with the distribution. 00016 // 00017 // 3. The name of the authors may not be used to endorse or promote 00018 // products derived from this software without specific prior written 00019 // permission. 00020 // 00021 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 00022 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00023 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 00024 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00025 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 00026 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00027 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00028 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00029 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00030 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00031 // 00032 // This file is part of the PLearn library. For more information on the PLearn 00033 // library, go to the PLearn Web site at www.plearn.org 00034 00035 // Authors: Frederic Bastien 00036 00040 #include "MultiClassAdaBoost.h" 00041 #include <plearn/vmat/OneVsAllVMatrix.h> 00042 #include <plearn/vmat/SubVMatrix.h> 00043 #include <plearn/vmat/MemoryVMatrix.h> 00044 #include <plearn_learners/regressors/RegressionTreeRegisters.h> 00045 #define PL_LOG_MODULE_NAME "MultiClassAdaBoost" 00046 #include <plearn/io/pl_log.h> 00047 #ifdef _OPENMP 00048 #include <omp.h> 00049 #endif 00050 00051 namespace PLearn { 00052 using namespace std; 00053 00054 PLEARN_IMPLEMENT_OBJECT( 00055 MultiClassAdaBoost, 00056 "Implementation of a 3 class AdaBoost learning algorithm.", 00057 "It divide the work in 2 sub learner AdaBoost, class 0 vs other" 00058 " and 2 vs other."); 00059 00060 MultiClassAdaBoost::MultiClassAdaBoost(): 00061 train_time(0), 00062 total_train_time(0), 00063 test_time(0), 00064 total_test_time(0), 00065 time_costs(true), 00066 warn_once_target_gt_2(false), 00067 done_warn_once_target_gt_2(false), 00068 timer(new PTimer(true)), 00069 time_sum(0), 00070 time_sum_ft(0), 00071 time_last_stage(0), 00072 time_last_stage_ft(0), 00073 last_stage(0), 00074 nb_sequential_ft(0), 00075 forward_sub_learner_test_costs(false), 00076 forward_test(0) 00077 /* ### Initialize all fields to their default value here */ 00078 { 00079 // ... 00080 00081 // ### You may (or not) want to call build_() to finish building the object 00082 // ### (doing so assumes the parent classes' build_() have been called too 00083 // ### in the parent classes' constructors, something that you must ensure) 00084 00085 // ### If this learner needs to generate random numbers, uncomment the 00086 // ### line below to enable the use of the inherited PRandom object. 00087 // random_gen = new PRandom(); 00088 } 00089 00090 void MultiClassAdaBoost::declareOptions(OptionList& ol) 00091 { 00092 // ### Declare all of this object's options here. 00093 // ### For the "flags" of each option, you should typically specify 00094 // ### one of OptionBase::buildoption, OptionBase::learntoption or 00095 // ### OptionBase::tuningoption. If you don't provide one of these three, 00096 // ### this option will be ignored when loading values from a script. 00097 // ### You can also combine flags, for example with OptionBase::nosave: 00098 // ### (OptionBase::buildoption | OptionBase::nosave) 00099 00100 // ### ex: 00101 // declareOption(ol, "myoption", &MultiClassAdaBoost::myoption, 00102 // OptionBase::buildoption, 00103 // "Help text describing this option"); 00104 // ... 00105 00106 // Now call the parent class' declareOptions 00107 inherited::declareOptions(ol); 00108 declareOption(ol, "learner1", &MultiClassAdaBoost::learner1, 00109 OptionBase::learntoption, 00110 "The sub learner to use."); 00111 declareOption(ol, "learner2", &MultiClassAdaBoost::learner2, 00112 OptionBase::learntoption, 00113 "The sub learner to use."); 00114 declareOption(ol, "forward_sub_learner_test_costs", 00115 &MultiClassAdaBoost::forward_sub_learner_test_costs, 00116 OptionBase::buildoption, 00117 "Did we add the learner1 and learner2 costs to our costs.\n"); 00118 declareOption(ol, "learner_template", 00119 &MultiClassAdaBoost::learner_template, 00120 OptionBase::buildoption, 00121 "The template to use for learner1 and learner2.\n"); 00122 declareOption(ol, "forward_test", 00123 &MultiClassAdaBoost::forward_test, 00124 OptionBase::buildoption, 00125 "if 0, default test. If 1 forward the test fct to the sub" 00126 " learner. If 2, determine at each stage what is the faster" 00127 " based on past test time.\n"); 00128 00129 declareOption(ol, "train_time", 00130 &MultiClassAdaBoost::train_time, 00131 OptionBase::learntoption|OptionBase::nosave, 00132 "The time spent in the last call to train() in second."); 00133 00134 declareOption(ol, "total_train_time", 00135 &MultiClassAdaBoost::total_train_time, 00136 OptionBase::learntoption|OptionBase::nosave, 00137 "The total time spent in the train() function in second."); 00138 00139 declareOption(ol, "test_time", 00140 &MultiClassAdaBoost::test_time, 00141 OptionBase::learntoption|OptionBase::nosave, 00142 "The time spent in the last call to test() in second."); 00143 00144 declareOption(ol, "total_test_time", 00145 &MultiClassAdaBoost::total_test_time, 00146 OptionBase::learntoption|OptionBase::nosave, 00147 "The total time spent in the test() function in second."); 00148 00149 declareOption(ol, "time_costs", 00150 &MultiClassAdaBoost::time_costs, OptionBase::buildoption, 00151 "If true, generate the time costs. Else they are nan."); 00152 00153 declareOption(ol, "warn_once_target_gt_2", 00154 &MultiClassAdaBoost::warn_once_target_gt_2, 00155 OptionBase::buildoption, 00156 "If true, generate only one warning if we find target > 2."); 00157 00158 declareOption(ol, "done_warn_once_target_gt_2", 00159 &MultiClassAdaBoost::done_warn_once_target_gt_2, 00160 OptionBase::learntoption|OptionBase::nosave, 00161 "Used to keep track if we have done the warning or not."); 00162 00163 declareOption(ol, "time_sum", 00164 &MultiClassAdaBoost::time_sum, 00165 OptionBase::learntoption|OptionBase::nosave, 00166 "The time spend in test() during the last stage if" 00167 " forward_test==2 and we use the inhereted::test fct." 00168 " If test() is called multiple time for the same stage" 00169 " this is the sum of the time."); 00170 declareOption(ol, "time_sum_ft", 00171 &MultiClassAdaBoost::time_sum_ft, 00172 OptionBase::learntoption|OptionBase::nosave, 00173 "The time spend in test() during the last stage if" 00174 " forward_test is 1 or 2 and we forward the test to the" 00175 " subleaner. If test() is called multiple time for the same" 00176 " stage this is the sum of the time."); 00177 declareOption(ol, "time_last_stage", 00178 &MultiClassAdaBoost::time_last_stage, 00179 OptionBase::learntoption|OptionBase::nosave, 00180 "This is the last value of time_sum in the last stage."); 00181 declareOption(ol, "time_last_stage_ft", 00182 &MultiClassAdaBoost::time_last_stage_ft, 00183 OptionBase::learntoption|OptionBase::nosave, 00184 "This is the last value of time_sum_ft in the last stage."); 00185 declareOption(ol, "last_stage", 00186 &MultiClassAdaBoost::last_stage, 00187 OptionBase::learntoption |OptionBase::nosave, 00188 "The stage at witch time_sum or time_sum_ft was used"); 00189 declareOption(ol, "last_stage", 00190 &MultiClassAdaBoost::last_stage, 00191 OptionBase::learntoption |OptionBase::nosave, 00192 "The stage at witch time_sum or time_sum_ft was used"); 00193 declareOption(ol, "nb_sequential_ft", 00194 &MultiClassAdaBoost::nb_sequential_ft, 00195 OptionBase::learntoption |OptionBase::nosave, 00196 "The number of sequential time that we forward the test()" 00197 " fct. We must do that as the first time we forward it, the" 00198 " time is higher then the following ones."); 00199 } 00200 00201 void MultiClassAdaBoost::build_() 00202 { 00203 sub_target_tmp.resize(2); 00204 for(int i=0;i<sub_target_tmp.size();i++) 00205 sub_target_tmp[i].resize(1); 00206 00207 if(learner_template){ 00208 if(!learner1) 00209 learner1 = ::PLearn::deepCopy(learner_template); 00210 if(!learner2) 00211 learner2 = ::PLearn::deepCopy(learner_template); 00212 } 00213 tmp_target.resize(1); 00214 tmp_output.resize(outputsize()); 00215 if(learner1) 00216 output1.resize(learner1->outputsize()); 00217 if(learner2) 00218 output2.resize(learner2->outputsize()); 00219 if(!train_stats) 00220 train_stats=new VecStatsCollector(); 00221 00222 if(train_set){ 00223 if(learner1 && learner2) 00224 if(! learner1->getTrainingSet() 00225 || ! learner2->getTrainingSet() 00226 || targetname.empty() 00227 ) 00228 setTrainingSet(train_set); 00229 } 00230 00231 timer->newTimer("MultiClassAdaBoost::test()", true); 00232 timer->newTimer("MultiClassAdaBoost::test() current",true); 00233 00234 } 00235 00236 // ### Nothing to add here, simply calls build_ 00237 void MultiClassAdaBoost::build() 00238 { 00239 inherited::build(); 00240 build_(); 00241 } 00242 00243 00244 void MultiClassAdaBoost::makeDeepCopyFromShallowCopy(CopiesMap& copies) 00245 { 00246 inherited::makeDeepCopyFromShallowCopy(copies); 00247 00248 deepCopyField(tmp_input, copies); 00249 deepCopyField(tmp_target, copies); 00250 deepCopyField(tmp_output, copies); 00251 deepCopyField(tmp_costs, copies); 00252 deepCopyField(output1, copies); 00253 deepCopyField(output2, copies); 00254 deepCopyField(subcosts1, copies); 00255 deepCopyField(subcosts2, copies); 00256 deepCopyField(timer, copies); 00257 deepCopyField(learner1, copies); 00258 deepCopyField(learner2, copies); 00259 00260 //not needed as we only read it. 00261 //deepCopyField(learner_template, copies); 00262 } 00263 00264 00265 int MultiClassAdaBoost::outputsize() const 00266 { 00267 // Compute and return the size of this learner's output (which typically 00268 // may depend on its inputsize(), targetsize() and set options). 00269 00270 return 3; 00271 } 00272 00273 void MultiClassAdaBoost::finalize() 00274 { 00275 inherited::finalize(); 00276 learner1->finalize(); 00277 learner2->finalize(); 00278 } 00279 00280 void MultiClassAdaBoost::forget() 00281 { 00282 inherited::forget(); 00283 00284 stage = 0; 00285 train_stats->forget(); 00286 learner1->forget(); 00287 learner2->forget(); 00288 } 00289 00290 void MultiClassAdaBoost::train() 00291 { 00292 EXTREME_MODULE_LOG<<"train() start"<<endl; 00293 timer->startTimer("MultiClassAdaBoost::train"); 00294 Profiler::pl_profile_start("MultiClassAdaBoost::train"); 00295 Profiler::pl_profile_start("MultiClassAdaBoost::train+test"); 00296 learner1->nstages = nstages; 00297 learner2->nstages = nstages; 00298 00299 //if you use the parallel version, you must disable all verbose, verbosity and report progress int he learner1 and learner2. 00300 //Otherwise this will cause crash due to the parallel printing to stdout stderr. 00301 #ifdef _OPENMP 00302 //the AdaBoost and the weak learner should not print anything as this will cause race condition on the printing 00303 //TODO find a way to have thread safe output? 00304 if(omp_get_max_threads()>1){ 00305 learner1->verbosity=0; 00306 learner2->verbosity=0; 00307 learner1->weak_learner_template->verbosity=0; 00308 learner2->weak_learner_template->verbosity=0; 00309 } 00310 00311 EXTREME_MODULE_LOG<<"train() // start"<<endl; 00312 #pragma omp parallel sections default(none) 00313 { 00314 #pragma omp section 00315 learner1->train(); 00316 #pragma omp section 00317 learner2->train(); 00318 } 00319 EXTREME_MODULE_LOG<<"train() // end"<<endl; 00320 #else 00321 learner1->train(); 00322 learner2->train(); 00323 #endif 00324 stage=max(learner1->stage,learner2->stage); 00325 00326 train_stats->stats.resize(0); 00327 PP<VecStatsCollector> v; 00328 00329 //we do it this way in case the learner don't have train_stats 00330 if(v=learner1->getTrainStatsCollector()) 00331 train_stats->append(*(v),"sublearner1."); 00332 if(v=learner2->getTrainStatsCollector()) 00333 train_stats->append(*(v),"sublearner2."); 00334 timer->stopTimer("MultiClassAdaBoost::train"); 00335 Profiler::pl_profile_end("MultiClassAdaBoost::train"); 00336 Profiler::pl_profile_end("MultiClassAdaBoost::train+test"); 00337 00338 real tmp = timer->getTimer("MultiClassAdaBoost::train"); 00339 train_time=tmp - total_train_time; 00340 total_train_time=tmp; 00341 00342 //we get the test_time here as we want the test time for all dataset. 00343 //if we put it in the test function, we would have it for one dataset. 00344 tmp = timer->getTimer("MultiClassAdaBoost::test()"); 00345 test_time=tmp-total_test_time; 00346 total_test_time=tmp; 00347 EXTREME_MODULE_LOG<<"train() end"<<endl; 00348 } 00349 00350 void MultiClassAdaBoost::computeOutput(const Vec& input, Vec& output) const 00351 { 00352 PLASSERT(output.size()==outputsize()); 00353 PLASSERT(output1.size()==learner1->outputsize()); 00354 PLASSERT(output2.size()==learner2->outputsize()); 00355 #ifdef _OPENMP 00356 #pragma omp parallel sections default(none) 00357 { 00358 #pragma omp section 00359 learner1->computeOutput(input, output1); 00360 #pragma omp section 00361 learner2->computeOutput(input, output2); 00362 } 00363 00364 #else 00365 learner1->computeOutput(input, output1); 00366 learner2->computeOutput(input, output2); 00367 #endif 00368 int ind1=int(round(output1[0])); 00369 int ind2=int(round(output2[0])); 00370 00371 int ind=-1; 00372 if(ind1==0 && ind2==0) 00373 ind=0; 00374 else if(ind1==1 && ind2==0) 00375 ind=1; 00376 else if(ind1==1 && ind2==1) 00377 ind=2; 00378 else 00379 ind=1;//TODOself.confusion_target; 00380 output[0]=ind; 00381 output[1]=output1[0]; 00382 output[2]=output2[0]; 00383 } 00384 00385 void MultiClassAdaBoost::computeOutputAndCosts(const Vec& input, 00386 const Vec& target, 00387 Vec& output, Vec& costs) const 00388 { 00389 PLASSERT(costs.size()==nTestCosts()); 00390 PLASSERT_MSG(output.length()==outputsize(), 00391 "In MultiClassAdaBoost::computeOutputAndCosts -" 00392 " output don't have the good length!"); 00393 00394 getSubLearnerTarget(target, sub_target_tmp); 00395 #ifdef _OPENMP 00396 #pragma omp parallel sections default(none) 00397 { 00398 #pragma omp section 00399 learner1->computeOutputAndCosts(input, sub_target_tmp[0], 00400 output1, subcosts1); 00401 #pragma omp section 00402 learner2->computeOutputAndCosts(input, sub_target_tmp[1], 00403 output2, subcosts2); 00404 } 00405 00406 #else 00407 learner1->computeOutputAndCosts(input, sub_target_tmp[0], 00408 output1, subcosts1); 00409 learner2->computeOutputAndCosts(input, sub_target_tmp[1], 00410 output2, subcosts2); 00411 #endif 00412 00413 int ind1=int(round(output1[0])); 00414 int ind2=int(round(output2[0])); 00415 int ind=-1; 00416 if(ind1==0 && ind2==0) 00417 ind=0; 00418 else if(ind1==1 && ind2==0) 00419 ind=1; 00420 else if(ind1==1 && ind2==1) 00421 ind=2; 00422 else 00423 ind=1;//TODOself.confusion_target; 00424 output[0]=ind; 00425 output[1]=output1[0]; 00426 output[2]=output2[0]; 00427 00428 int out = ind; 00429 int pred = int(round(target[0])); 00430 costs[0]=int(out != pred);//class_error 00431 costs[1]=abs(out-pred);//linear_class_error 00432 costs[2]=pow(real(abs(out-pred)),2);//square_class_error 00433 00434 //append conflict cost 00435 if(fast_is_equal(round(output[1]),0) 00436 && fast_is_equal(round(output[2]),1)) 00437 costs[3]=1; 00438 else 00439 costs[3]=0; 00440 00441 costs[4]=costs[5]=costs[6]=0; 00442 costs[out+4]=1; 00443 if(time_costs){ 00444 costs[7]=train_time; 00445 costs[8]=total_train_time; 00446 costs[9]=test_time; 00447 costs[10]=total_test_time; 00448 costs[11]=time_sum; 00449 costs[12]=time_sum_ft; 00450 costs[13]=time_last_stage; 00451 costs[14]=time_last_stage_ft; 00452 costs[15]=last_stage; 00453 }else{ 00454 costs[7]=costs[8]=costs[9]=costs[10]=MISSING_VALUE; 00455 costs[11]=costs[12]=costs[13]=costs[14]=costs[15]=MISSING_VALUE; 00456 } 00457 if(forward_sub_learner_test_costs){ 00458 costs.resize(7+4+5); 00459 subcosts1+=subcosts2; 00460 costs.append(subcosts1); 00461 } 00462 00463 PLASSERT(costs.size()==nTestCosts()); 00464 00465 } 00466 00467 void MultiClassAdaBoost::computeCostsFromOutputs(const Vec& input, const Vec& output, 00468 const Vec& target, Vec& costs) const 00469 { 00470 subcosts1.resize(0); 00471 subcosts2.resize(0); 00472 computeCostsFromOutputs_(input, output, target, subcosts1, subcosts2, costs); 00473 } 00474 00475 void MultiClassAdaBoost::computeCostsFromOutputs_(const Vec& input, const Vec& output, 00476 const Vec& target, Vec& sub_costs1, 00477 Vec& sub_costs2, Vec& costs) const 00478 { 00479 PLASSERT(costs.size()==nTestCosts()); 00480 00481 int out = int(round(output[0])); 00482 int pred = int(round(target[0])); 00483 costs[0]=int(out != pred);//class_error 00484 costs[1]=abs(out-pred);//linear_class_error 00485 costs[2]=pow(real(abs(out-pred)),2);//square_class_error 00486 00487 //append conflict cost 00488 if(fast_is_equal(round(output[1]),0) 00489 && fast_is_equal(round(output[2]),1)) 00490 costs[3]=1; 00491 else 00492 costs[3]=0; 00493 00494 costs[4]=costs[5]=costs[6]=0; 00495 costs[out+4]=1; 00496 costs[7]=train_time; 00497 costs[8]=total_train_time; 00498 costs[9]=test_time; 00499 costs[10]=total_test_time; 00500 costs[11]=time_sum; 00501 costs[12]=time_sum_ft; 00502 costs[13]=time_last_stage; 00503 costs[14]=time_last_stage_ft; 00504 costs[15]=last_stage; 00505 00506 if(forward_sub_learner_test_costs){ 00507 costs.resize(7+4+5); 00508 PLASSERT(sub_costs1.size()==learner1->nTestCosts() || sub_costs1.size()==0); 00509 PLASSERT(sub_costs2.size()==learner2->nTestCosts() || sub_costs2.size()==0); 00510 00511 getSubLearnerTarget(target, sub_target_tmp); 00512 if(sub_costs1.size()==0){ 00513 PLASSERT(input.size()>0); 00514 sub_costs1.resize(learner1->nTestCosts()); 00515 learner1->computeCostsOnly(input,sub_target_tmp[0],sub_costs1); 00516 } 00517 if(sub_costs2.size()==0){ 00518 PLASSERT(input.size()>0); 00519 sub_costs2.resize(learner2->nTestCosts()); 00520 learner2->computeCostsOnly(input,sub_target_tmp[1],sub_costs2); 00521 } 00522 sub_costs1+=sub_costs2; 00523 costs.append(sub_costs1); 00524 } 00525 00526 PLASSERT(costs.size()==nTestCosts()); 00527 } 00528 00529 TVec<string> MultiClassAdaBoost::getOutputNames() const 00530 { 00531 TVec<string> names(3); 00532 names[0]="prediction"; 00533 names[1]="prediction_learner_1"; 00534 names[2]="prediction_learner_2"; 00535 return names; 00536 } 00537 00538 TVec<string> MultiClassAdaBoost::getTestCostNames() const 00539 { 00540 // Return the names of the costs computed by computeCostsFromOutputs 00541 // (these may or may not be exactly the same as what's returned by 00542 // getTrainCostNames). 00543 // ... 00544 TVec<string> names; 00545 names.append("class_error"); 00546 names.append("linear_class_error"); 00547 names.append("square_class_error"); 00548 names.append("conflict"); 00549 names.append("class0"); 00550 names.append("class1"); 00551 names.append("class2"); 00552 names.append("train_time"); 00553 names.append("total_train_time"); 00554 names.append("test_time"); 00555 names.append("total_test_time"); 00556 names.append("time_sum"); 00557 names.append("time_sum_ft"); 00558 names.append("time_last_stage"); 00559 names.append("time_last_stage_ft"); 00560 names.append("last_stage"); 00561 00562 if(forward_sub_learner_test_costs){ 00563 TVec<string> subcosts=learner1->getTestCostNames(); 00564 for(int i=0;i<subcosts.length();i++){ 00565 subcosts[i]="sum_sublearner."+subcosts[i]; 00566 } 00567 names.append(subcosts); 00568 } 00569 return names; 00570 } 00571 00572 TVec<string> MultiClassAdaBoost::getTrainCostNames() const 00573 { 00574 // Return the names of the objective costs that the train method computes 00575 // and for which it updates the VecStatsCollector train_stats 00576 // (these may or may not be exactly the same as what's returned by 00577 // getTestCostNames). 00578 // ... 00579 00580 TVec<string> names; 00581 return names; 00582 } 00583 00584 void MultiClassAdaBoost::getSubLearnerTarget(const Vec target, 00585 TVec<Vec> sub_target) const 00586 { 00587 if(fast_is_equal(target[0],0.)){ 00588 sub_target[0][0]=0; 00589 sub_target[1][0]=0; 00590 }else if(fast_is_equal(target[0],1.)){ 00591 sub_target[0][0]=1; 00592 sub_target[1][0]=0; 00593 }else if(fast_is_equal(target[0],2.)){ 00594 sub_target[0][0]=1; 00595 sub_target[1][0]=1; 00596 }else if(target[0]>2){ 00597 if(!warn_once_target_gt_2 || ! done_warn_once_target_gt_2){ 00598 PLWARNING("In MultiClassAdaBoost::getSubLearnerTarget - " 00599 "We only support target 0/1/2. We got %f. We transform " 00600 "it to a target of 2.", target[0]); 00601 done_warn_once_target_gt_2=true; 00602 if(warn_once_target_gt_2) 00603 PLWARNING("We will show this warning only once."); 00604 } 00605 sub_target[0][0]=1; 00606 sub_target[1][0]=1; 00607 }else{ 00608 PLERROR("In MultiClassAdaBoost::getSubLearnerTarget - " 00609 "We only support target 0/1/2. We got %f.", target[0]); 00610 sub_target[0][0]=0; 00611 sub_target[1][0]=0; 00612 } 00613 } 00614 00615 void MultiClassAdaBoost::setTrainingSet(VMat training_set, bool call_forget) 00616 { 00617 PLCHECK(learner1 && learner2); 00618 00619 bool training_set_has_changed = !train_set || !(train_set->looksTheSameAs(training_set)); 00620 00621 targetname = training_set->fieldName(training_set->inputsize()); 00622 00623 //We don't give it if the script give them one explicitly. 00624 //This can be usefull for optimization 00625 if(training_set_has_changed || !learner1->getTrainingSet()){ 00626 VMat vmat1 = new OneVsAllVMatrix(training_set,0,true); 00627 if(training_set->hasMetaDataDir()) 00628 vmat1->setMetaDataDir(training_set->getMetaDataDir()/"0vsOther"); 00629 learner1->setTrainingSet(vmat1, call_forget); 00630 } 00631 if(training_set_has_changed || !learner2->getTrainingSet()){ 00632 VMat vmat2 = new OneVsAllVMatrix(training_set,2); 00633 PP<RegressionTreeRegisters> t1 = 00634 (PP<RegressionTreeRegisters>)learner1->getTrainingSet(); 00635 if(t1->classname()=="RegressionTreeRegisters"){ 00636 vmat2 = new RegressionTreeRegisters(vmat2, 00637 t1->getTSortedRow(), 00638 t1->getTSource(), 00639 learner1->report_progress, 00640 learner1->verbosity,false,false); 00641 } 00642 learner2->setTrainingSet(vmat2, call_forget); 00643 } 00644 00645 //we do it here as RegressionTree need a trainingSet to know 00646 // the number of test. 00647 subcosts2.resize(learner2->nTestCosts()); 00648 subcosts1.resize(learner1->nTestCosts()); 00649 00650 inherited::setTrainingSet(training_set, call_forget); 00651 } 00652 00653 void MultiClassAdaBoost::test(VMat testset, PP<VecStatsCollector> test_stats, 00654 VMat testoutputs, VMat testcosts) const 00655 { 00656 Profiler::pl_profile_start("MultiClassAdaBoost::test()"); 00657 Profiler::pl_profile_start("MultiClassAdaBoost::train+test"); 00658 00659 timer->startTimer("MultiClassAdaBoost::test()"); 00660 if(!forward_test){ 00661 inherited::test(testset,test_stats,testoutputs,testcosts); 00662 Profiler::pl_profile_end("MultiClassAdaBoost::test()"); 00663 Profiler::pl_profile_end("MultiClassAdaBoost::train+test"); 00664 00665 timer->stopTimer("MultiClassAdaBoost::test()"); 00666 return; 00667 } 00668 00669 if(last_stage<stage && time_sum>0){ 00670 time_last_stage=time_sum; 00671 time_sum=0; 00672 } 00673 if(last_stage<stage && time_sum_ft>0){ 00674 if(nb_sequential_ft>0) 00675 time_last_stage_ft=time_sum_ft; 00676 nb_sequential_ft++; 00677 time_sum_ft=0; 00678 } 00679 00680 if(forward_test==2 && time_last_stage<time_last_stage_ft){ 00681 EXTREME_MODULE_LOG<<"inherited start time_sum="<<time_sum<<" time_sum_ft="<<time_sum_ft<<" last_stage="<<last_stage <<" stage=" <<stage <<" time_last_stage=" <<time_last_stage<<" time_last_stage_ft=" <<time_last_stage_ft<<endl; 00682 timer->resetTimer("MultiClassAdaBoost::test() current"); 00683 timer->startTimer("MultiClassAdaBoost::test() current"); 00684 PLCHECK(last_stage<=stage); 00685 inherited::test(testset,test_stats,testoutputs,testcosts); 00686 timer->stopTimer("MultiClassAdaBoost::test() current"); 00687 timer->stopTimer("MultiClassAdaBoost::test()"); 00688 Profiler::pl_profile_end("MultiClassAdaBoost::test()"); 00689 Profiler::pl_profile_end("MultiClassAdaBoost::train+test"); 00690 00691 time_sum += timer->getTimer("MultiClassAdaBoost::test() current"); 00692 last_stage=stage; 00693 nb_sequential_ft = 0; 00694 EXTREME_MODULE_LOG<<"inherited end time_sum="<<time_sum<<" time_sum_ft="<<time_sum_ft<<" last_stage="<<last_stage <<" stage=" <<stage <<" time_last_stage=" <<time_last_stage<<" time_last_stage_ft=" <<time_last_stage_ft<<endl; 00695 return; 00696 } 00697 EXTREME_MODULE_LOG<<"start time_sum="<<time_sum<<" time_sum_ft="<<time_sum_ft<<" last_stage="<<last_stage <<" stage=" <<stage <<" time_last_stage=" <<time_last_stage<<" time_last_stage_ft=" <<time_last_stage_ft<<endl; 00698 timer->resetTimer("MultiClassAdaBoost::test() current"); 00699 timer->startTimer("MultiClassAdaBoost::test() current"); 00700 //Profiler::pl_profile_start("MultiClassAdaBoost::test() part1");//cheap 00701 int index=-1; 00702 for(int i=0;i<saved_testset.length();i++){ 00703 if(saved_testset[i]==testset){ 00704 index=i;break; 00705 } 00706 } 00707 PP<VecStatsCollector> test_stats1 = 0; 00708 PP<VecStatsCollector> test_stats2 = 0; 00709 VMat testoutputs1 = VMat(new MemoryVMatrix(testset->length(), 00710 learner1->outputsize())); 00711 VMat testoutputs2 = VMat(new MemoryVMatrix(testset->length(), 00712 learner2->outputsize())); 00713 VMat testcosts1 = 0; 00714 VMat testcosts2 = 0; 00715 VMat testset1 = 0; 00716 VMat testset2 = 0; 00717 if ((testcosts || test_stats )&& forward_sub_learner_test_costs){ 00718 //comment 00719 testcosts1 = VMat(new MemoryVMatrix(testset->length(), 00720 learner1->nTestCosts())); 00721 testcosts2 = VMat(new MemoryVMatrix(testset->length(), 00722 learner2->nTestCosts())); 00723 } 00724 if(index<0){ 00725 testset1 = new OneVsAllVMatrix(testset,0,true); 00726 testset2 = new OneVsAllVMatrix(testset,2); 00727 00728 saved_testset.append(testset); 00729 saved_testset1.append(testset1); 00730 saved_testset2.append(testset2); 00731 }else{ 00732 //we need to do that as AdaBoost need 00733 //the same dataset to reuse their test results 00734 testset1=saved_testset1[index]; 00735 testset2=saved_testset2[index]; 00736 PLCHECK(((PP<OneVsAllVMatrix>)testset1)->source==testset); 00737 PLCHECK(((PP<OneVsAllVMatrix>)testset2)->source==testset); 00738 } 00739 00740 //Profiler::pl_profile_end("MultiClassAdaBoost::test() part1");//cheap 00741 Profiler::pl_profile_start("MultiClassAdaBoost::test() subtest"); 00742 #ifdef _OPENMP 00743 #pragma omp parallel sections if(false)//false as this is not thread safe right now. 00744 { 00745 #pragma omp section 00746 learner1->test(testset1,test_stats1,testoutputs1,testcosts1); 00747 #pragma omp section 00748 learner2->test(testset2,test_stats2,testoutputs2,testcosts2); 00749 } 00750 #else 00751 learner1->test(testset1,test_stats1,testoutputs1,testcosts1); 00752 learner2->test(testset2,test_stats2,testoutputs2,testcosts2); 00753 #endif 00754 Profiler::pl_profile_end("MultiClassAdaBoost::test() subtest"); 00755 00756 VMat my_outputs = 0; 00757 VMat my_costs = 0; 00758 if(testoutputs){ 00759 my_outputs=testoutputs; 00760 }else if(bool(testcosts) | bool(test_stats)){ 00761 my_outputs=VMat(new MemoryVMatrix(testset->length(), 00762 outputsize())); 00763 } 00764 if(testcosts){ 00765 my_costs=testcosts; 00766 }else if(test_stats){ 00767 my_costs=VMat(new MemoryVMatrix(testset->length(), 00768 nTestCosts())); 00769 } 00770 // Profiler::pl_profile_start("MultiClassAdaBoost::test() my_outputs");//cheap 00771 if(my_outputs){ 00772 for(int row=0;row<testset.length();row++){ 00773 real out1=testoutputs1->get(row,0); 00774 real out2=testoutputs2->get(row,0); 00775 int ind1=int(round(out1)); 00776 int ind2=int(round(out2)); 00777 int ind=-1; 00778 if(ind1==0 && ind2==0) 00779 ind=0; 00780 else if(ind1==1 && ind2==0) 00781 ind=1; 00782 else if(ind1==1 && ind2==1) 00783 ind=2; 00784 else 00785 ind=1;//TODOself.confusion_target; 00786 tmp_output[0]=ind; 00787 tmp_output[1]=out1; 00788 tmp_output[2]=out2; 00789 my_outputs->putOrAppendRow(row,tmp_output); 00790 } 00791 } 00792 // Profiler::pl_profile_end("MultiClassAdaBoost::test() my_outputs"); 00793 // Profiler::pl_profile_start("MultiClassAdaBoost::test() my_costs");//cheap 00794 00795 if (my_costs){ 00796 tmp_costs.resize(nTestCosts()); 00797 // if (forward_sub_learner_test_costs) 00798 //TODO optimize by reusing testoutputs1 and testoutputs2 00799 // PLWARNING("will be long"); 00800 int target_index = testset->inputsize(); 00801 PLASSERT(testset->targetsize()==1); 00802 Vec costs1,costs2; 00803 if(forward_sub_learner_test_costs){ 00804 costs1.resize(learner1->nTestCosts()); 00805 costs2.resize(learner2->nTestCosts()); 00806 } 00807 for(int row=0;row<testset.length();row++){ 00808 //default version 00809 //testset.getExample(row, input, target, weight); 00810 //computeCostsFromOutputs(input,my_outputs(row),target,costs); 00811 00812 //the input is not needed for the cost of this class if the subcost are know. 00813 testset->getSubRow(row,target_index,tmp_target); 00814 // Vec costs1=testcosts1(row); 00815 // Vec costs2=testcosts2(row); 00816 if(forward_sub_learner_test_costs){ 00817 testcosts1->getRow(row,costs1); 00818 testcosts2->getRow(row,costs2); 00819 } 00820 //TODO??? tmp_input is empty!!! 00821 computeCostsFromOutputs_(tmp_input, my_outputs(row), tmp_target, costs1, 00822 costs2, tmp_costs); 00823 my_costs->putOrAppendRow(row,tmp_costs); 00824 } 00825 } 00826 // Profiler::pl_profile_end("MultiClassAdaBoost::test() my_costs"); 00827 // Profiler::pl_profile_start("MultiClassAdaBoost::test() test_stats");//cheap 00828 if (test_stats){ 00829 if(testset->weightsize()==0){ 00830 for(int row=0;row<testset.length();row++){ 00831 Vec costs = my_costs(row); 00832 test_stats->update(costs, 1); 00833 } 00834 }else{ 00835 int weight_index=inputsize()+targetsize(); 00836 Vec costs(my_costs.width()); 00837 for(int row=0;row<testset.length();row++){ 00838 // Vec costs = my_costs(row); 00839 my_costs->getRow(row, costs); 00840 test_stats->update(costs, testset->get(row, weight_index)); 00841 } 00842 } 00843 } 00844 // Profiler::pl_profile_end("MultiClassAdaBoost::test() test_stats"); 00845 timer->stopTimer("MultiClassAdaBoost::test() current"); 00846 timer->stopTimer("MultiClassAdaBoost::test()"); 00847 Profiler::pl_profile_end("MultiClassAdaBoost::test()"); 00848 Profiler::pl_profile_end("MultiClassAdaBoost::train+test"); 00849 00850 time_sum_ft +=timer->getTimer("MultiClassAdaBoost::test() current"); 00851 00852 00853 last_stage=stage; 00854 EXTREME_MODULE_LOG<<"end time_sum="<<time_sum<<" time_sum_ft="<<time_sum_ft<<" last_stage="<<last_stage <<" stage=" <<stage <<" time_last_stage=" <<time_last_stage<<" time_last_stage_ft=" <<time_last_stage_ft<<endl; 00855 00856 } 00857 00858 } // end of namespace PLearn 00859 00860 00861 /* 00862 Local Variables: 00863 mode:c++ 00864 c-basic-offset:4 00865 c-file-style:"stroustrup" 00866 c-file-offsets:((innamespace . 0)(inline-open . 0)) 00867 indent-tabs-mode:nil 00868 fill-column:79 00869 End: 00870 */ 00871 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :