PLearn 0.1
MultiClassAdaBoost.cc
Go to the documentation of this file.
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 :
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines