00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
#include "SequentialModelSelector.h"
00039 
00040 
00041 
00042 
namespace PLearn {
00043 
using namespace std;
00044 
00045 
00046 
PLEARN_IMPLEMENT_OBJECT(SequentialModelSelector, 
"ONE LINE DESCR", 
"NO HELP");
00047 
00048 SequentialModelSelector::SequentialModelSelector(): 
00049   report_paired_T_tests(false),
00050   stepwise_save(true),
00051   comparison_type(1),
00052   comparison_window(-1)
00053 {}
00054 
00055 void SequentialModelSelector::setExperimentDirectory(
const string& _expdir)
00056 {
00057   
int nb_models = 
models.
length();
00058   
checkModelNames();
00059 
00060   PLearner::setExperimentDirectory(_expdir);
00061   
string model_m;
00062   
for(
int m=0; m < nb_models; m++)
00063   {
00064     model_m = 
models[m]->getExperimentDirectory();
00065     
if(model_m == 
"")
00066       model_m = 
model_names[m];
00067     models[m]->setExperimentDirectory(
append_slash(_expdir)+ model_m);
00068   }
00069 }
00070 
00071 void SequentialModelSelector::build_()
00072 {
00073   
00074   
if(init_train_size < horizon)
00075   {
00076     
PLWARNING(
"The init_train_size provided by the user was %d. However since the horizon is %d\n"
00077               
"the init_train_size will be modified to be %d, the horizon value. This modification is\n"
00078               
"necessary because, within a model selection context, a first internal test is needed to\n"
00079               
"determine the first best model (see the SequentialModelSelector::train method\n"
00080               
"implementation). If you want to avoid getting this warning, you should set init_train_size\n"
00081               
"to horizon (%d) directly.", 
00082               init_train_size, horizon, horizon, horizon);
00083     init_train_size = horizon;
00084   }
00085   
00086   
int nb_models = 
models.
length();
00087   
if(nb_models < 1)
00088     
PLERROR(
"The 'models' option is mandatory in a SequentialModelSelector.");
00089       
00090   
int nb_common_costs = 
common_costs.
length();
00091   
if(nb_common_costs < 1)
00092     
PLERROR(
"The 'common_costs' requires at least 1 cost from which models will\n"
00093             
"be compared to choose the best model.");  
00094 
00095   
common_cost_indices.
resize(nb_models, nb_common_costs); 
00096   
for(
int m=0; m < nb_models; m++)
00097     
for(
int c=0; c < nb_common_costs; c++) 
00098       
common_cost_indices(m, c) = 
models[m]->getTestCostIndex( 
common_costs[c] );
00099   
00100   
best_model.
resize(max_seq_len);
00101   
sequence_costs.
resize(nb_models);
00102 
00103   
forget();
00104 }
00105 
00106 void SequentialModelSelector::build()
00107 {
00108   inherited::build();
00109   
build_();
00110 }
00111 
00112 void SequentialModelSelector::declareOptions(
OptionList& ol)
00113 {    
00114   
declareOption(ol, 
"stepwise_save", &SequentialModelSelector::stepwise_save, OptionBase::buildoption,
00115                 
"Does the model selector hass to save errors at each step.\n"
00116                 
"Default: true.");
00117 
00118   
declareOption(ol, 
"models", &SequentialModelSelector::models,
00119                 OptionBase::buildoption, 
"List of all the models.\n");
00120 
00121   
declareOption(ol, 
"model_names", &SequentialModelSelector::model_names, OptionBase::buildoption,
00122                 
"If the user desires to provide a name for each model instead of model_i.");
00123 
00124   
declareOption(ol, 
"common_costs", &SequentialModelSelector::common_costs, OptionBase::buildoption,
00125                 
"The names of costs that are common to all models and that the user wishes the model\n"
00126                 
"selector to keep track of. The first one is considered to be the main cost, the one\n"
00127                 
"from which models will be compared to choose the best model.");
00128 
00129   
declareOption(ol, 
"report_paired_T_tests", &SequentialModelSelector::report_paired_T_tests, OptionBase::buildoption,
00130                 
"If true, the model selector will report as costs the paired T tests on common_cost_indices[0] for\n"
00131                 
"models[0] against each other model. The model selector will only report T tests once,\n"
00132                 
"at t=(max_seq_len-1)\n"
00133                 
"\n"
00134                 
"Default: false.");
00135 
00136   
declareOption(ol, 
"comparison_type", &SequentialModelSelector::comparison_type,
00137                 OptionBase::buildoption, 
00138                 
"From the common_costs list, the first cost is the one from which models will be compared\n"
00139                 
"to choose the best model. But should the best model be chosen according to the\n"
00140                 
"\n"
00141                 
"max/min\n"
00142                 
"  +/-   1: Mean\n"
00143                 
"  +/-   2: Mean / Variance\n"
00144                 
"  +/-   3: more to come.\n"
00145                 
"\n"
00146                 
"of the cost realizations. \n"
00147                 
"Default: 1.\n");
00148 
00149   
declareOption(ol, 
"comparison_window", &SequentialModelSelector::comparison_window, OptionBase::buildoption,
00150                 
"If positive, the comparison performed on the basis of common_cost[0] will be applyed only\n"
00151                 
"the comparison_window last elements of the cost sequence.\n"
00152                 
"Default: -1. (No window)");
00153 
00154   inherited::declareOptions(ol);
00155 }
00156 
00157 real SequentialModelSelector::sequenceCost(
const Vec& sequence_errors)
00158 {
00159   
int seq_len = sequence_errors.
length();
00160   
if(seq_len == 0)
00161     
return MISSING_VALUE;
00162   
00163   
int window_start = seq_len - 
comparison_window;
00164   
Vec windowed;
00165   
if(comparison_window < 1 || window_start < 0)     
00166     windowed = sequence_errors; 
00167   
else
00168     windowed = sequence_errors.
subVec(window_start, comparison_window);
00169   
00170   
int type = 
abs(
comparison_type);
00171   
real mean_ = 
mean(windowed);
00172   
if (type == 1)
00173     
return mean_;
00174   
00175   
if (type == 2)
00176     
return mean_ / 
variance(windowed, mean_);
00177   
00178   
PLERROR(
"Invalid comparison type %d!", 
comparison_type);
00179   
return MISSING_VALUE;
00180 }
00181 
00182 real SequentialModelSelector::paired_t_test(
const int& m1, 
const int& m2, 
int cc )
 const
00183 
{
00184   
Vec u = 
remove_missing(
models[m1]->errors.
column( 
common_cost_indices(m1, cc) ).toVecCopy());
00185   
Vec v = 
remove_missing(
models[m2]->errors.
column( 
common_cost_indices(m2, cc) ).toVecCopy());
00186 
00187   
int n = u.
length();
00188   
if( v.
length() != n )
00189     
PLERROR(
"SequentialModelSelector::paired_t_test -- Can't make a paired t-test on to unequally lengthed vectors (%d != %d).",
00190             n, v.
length());
00191   
00192   
real ubar = 
mean(u);
00193   
real vbar = 
mean(v);
00194   
Vec u2 = u - ubar;
00195   
Vec v2 = v - vbar;
00196 
00197   
return (ubar - vbar) * 
sqrt( n*(n-1) / 
sumsquare(u2-v2));
00198 }
00199 
00200 void SequentialModelSelector::forget()
00201 {
00202   
best_model.
resize(max_seq_len);
00203   
best_model.
fill(-1);  
00204   
for (
int i=0; i<
models.
size(); i++)
00205     
models[i]->forget();
00206 
00207   inherited::forget();
00208 }
00209 
00210 void SequentialModelSelector::train()
00211 {  
00221   
if(last_call_train_t == -1) 
00222     
for (
int i=0; i<
models.
size(); i++)
00223     {
00224       
models[i]->horizon = horizon;
00225       
models[i]->init_train_size = init_train_size-horizon;
00226     }
00227 
00228   last_call_train_t = train_set.
length()-1;
00229 
00230   
00231   
00232   
00233   
int init_train_t = init_train_size-1;
00234   
int start_t = 
MAX(init_train_t, last_train_t+train_step);
00235   
if( start_t < last_test_t )
00236     
PLERROR(
"SequentialModelSelector::train -- start_t = %d < %d = last_test_t", start_t, last_test_t);
00237 
00238   
if( last_call_train_t < start_t )
00239     
return;
00240   
00241   
ProgressBar* pb = NULL;
00242   
if (report_progress)
00243     pb = 
new ProgressBar(
"Training SequentialModelSelector learner",train_set.
length());
00244 
00245   
TVec< PP<VecStatsCollector> > dummy_stats(
models.
length());
00246   
for (
int t=start_t; t < train_set.
length(); t++)
00247   {
00248     
00249     
int set_length = t+1;
00250 
00251 
#ifdef DEBUG
00252 
    cout << 
"SequentialModelSelector::train() -- sub_train.length = " << set_length-horizon << 
" et sub_test.length = " << set_length << 
endl;
00253 
#endif
00254 
        
00255     
VMat sub_train = train_set.
subMatRows(0,set_length-horizon); 
00256     sub_train->defineSizes(train_set->inputsize(), train_set->targetsize(), train_set->weightsize());
00257 
00258     
VMat sub_test  = train_set.
subMatRows(0,set_length); 
00259     sub_test->defineSizes(train_set->inputsize(), train_set->targetsize(), train_set->weightsize());
00260 
00261     
for (
int i=0; i < 
models.
size(); i++)
00262     {
00263       
if(t == start_t)
00264         dummy_stats[i] = 
new VecStatsCollector();
00265 
00266       
models[i]->setTrainingSet(sub_train, 
false);
00267       
models[i]->train();
00268       
models[i]->test(sub_test, dummy_stats[i]); 
00269       
00270       
Vec sequence_errors = 
remove_missing(
models[i]->errors.
column( 
common_cost_indices(i, 0) ).toVecCopy());
00271       
00272 
#ifdef DEBUG
00273 
      cout << 
"models["<<i<<
"]->getTestCostNames()[common_cost_indices(i, 0)]: " 
00274            << 
models[i]->getTestCostNames()[
common_cost_indices(i, 0)] << 
endl;
00275       
PLWARNING(
"models[%d]->errors.subMat(0,%d,%d,1)", i, 
common_cost_indices(i, 0), t);
00276       cout << 
remove_missing( models[i]->errors.
subMat(0,
common_cost_indices(i,0),set_length,1).toVecCopy() ) << 
endl;
00277       cout << 
"---\nOR\n---\n" << sequence_errors << 
endl; 
00278 
#endif
00279 
      
00280       
sequence_costs[i] = 
sequenceCost(sequence_errors);
00281     }
00282     
00283     
00284     
if(
comparison_type > 0)
00285       
best_model[t] = 
argmax(
sequence_costs, 
true);
00286     
else
00287       
best_model[t] = 
argmin(
sequence_costs, 
true);
00288 
00289     
if(
best_model[t] == -1)
00290       
best_model[t] = 0;   
00291 
00292 
#ifdef DEBUG
00293 
    cout << 
"sequence_costs: " << 
sequence_costs << 
endl;
00294     cout << 
"SequentialModelSelector::train() -- t = " << t << 
" et best_model = " << 
best_model[t] << 
endl;
00295 
#endif
00296 
00297     
if(predictions(t-horizon).
hasMissing())
00298       predictions(t-horizon) << 
models[best_model[t]]->predictions(t-horizon);
00299     
00300 
#ifdef DEBUG
00301 
    cout << 
"SequentialModelSelector::train() -- train_set.length = " << set_length << 
endl;
00302 
#endif
00303 
    if (pb)
00304       pb->
update(t);
00305   }
00306   
00307   
00308   
Vec best_model_costs; 
00309   
for (
int i=0; i<
models.
size(); i++)
00310   {
00311     
models[i]->setTrainingSet(train_set, 
false);
00312     
models[i]->train();
00313     
00314     
if(i == 
best_model[last_call_train_t])
00315       best_model_costs = 
models[i]->errors(last_call_train_t);
00316   }
00317 
00318   
if(train_stats)
00319   {
00320     
Vec update = best_model_costs( 
common_cost_indices(
best_model[last_call_train_t]) );
00321     train_stats->update( 
update );
00322   }
00323 
00324   predictions(last_call_train_t) << 
models[ 
best_model[last_call_train_t] ]->predictions(last_call_train_t);
00325   
00326   
if(pb)
00327     pb->
close();
00328 
00329 
00330   last_train_t = last_call_train_t;
00331 
#ifdef DEBUG
00332 
  cout << 
"SequentialModelSelector.last_train_t = " << last_train_t << 
endl;
00333 
#endif
00334 
  
00335 
00336   
if(
stepwise_save)
00337   {
00338     
string s1 = 
append_slash(expdir) + 
"predictions_train_t=" + 
tostring(last_train_t); 
00339     
saveAsciiWithoutSize(s1, predictions);
00340 
00341     
string s2 = 
append_slash(expdir) + 
"errors_train_t=" + 
tostring(last_train_t);
00342     
saveAsciiWithoutSize(s2, errors);
00343   }
00344 }
00345 
00346 void SequentialModelSelector::test(
VMat test_set, 
PP<VecStatsCollector> test_stats,
00347     
VMat testoutputs, 
VMat testcosts)
 const
00348 
{
00349   
00350   
00351   
00352   
if(last_train_t == -1)
00353   {
00354     
PLWARNING(
"SequentialModelSelector::test -- Skipped because there were no prior train.");
00355     
return;
00356   }
00357 
00358   
int start_t = 
MAX(last_train_t+1,last_test_t+1);
00359   
if( test_set.
length()-1 < start_t )
00360     
return;
00361 
00362   
ProgressBar* pb = NULL;
00363   
if (report_progress)
00364     pb = 
new ProgressBar(
"Testing SequentialModelSelector learner",test_set.
length());
00365 
00366   
TVec< PP<VecStatsCollector> > dummy_stats(
models.
length());  
00367   
for (
int t=start_t; t < test_set.
length(); t++)
00368   { 
00369     
Vec best_model_costs;      
00370     
Vec models_update;
00371     
00372     
for (
int i=0; i<
models.
size(); i++)
00373     {    
00374       
if(t == start_t)
00375         dummy_stats[i] = 
new VecStatsCollector();
00376 
00377       
models[i]->test(test_set, dummy_stats[i]);
00378       
00379       
if(i == 
best_model[last_train_t])
00380       {
00381         best_model_costs = 
models[i]->errors(t);
00382         models_update.
append( best_model_costs );
00383       }
00384       
else
00385         models_update.
append( 
models[i]->errors(t) );
00386     }
00387     
00388     
00389     
Vec update = best_model_costs( 
common_cost_indices(
best_model[last_train_t]) );
00390     
update.append(models_update);
00391     
00392     
00393     
if( 
report_paired_T_tests )
00394       
for(
int m=1; m < 
models.
length(); m++)
00395       {
00396         
if( test_set.
length() == max_seq_len )
00397           
update.append( 
paired_t_test(0, m) );      
00398         
else
00399           
update.append( 
MISSING_VALUE );
00400       }
00401     
00402     test_stats->update( 
update );
00403   
00404     predictions(t) << 
models[
best_model[last_train_t]]->predictions(t); 
00405     errors(t) << 
update;
00406     
if (testoutputs) testoutputs->appendRow( predictions(t) );
00407     
if (testcosts) testcosts->appendRow(
update);
00408 
00409 
#ifdef DEBUG
00410 
    cout << 
"predictions(" << t << 
"): " << predictions(t) << 
endl
00411          << 
"errors(" << t << 
"): " << errors(t) << 
endl;
00412 
#endif
00413 
00414     
if(pb)
00415       pb->
update(t);
00416   }
00417   
if(pb)
00418     pb->
close();
00419 
00420   
00421   last_test_t = test_set.
length()-1;
00422 
#ifdef DEBUG
00423 
  cout << 
"SequentialModelSelector.last_test_t = " << last_test_t << 
endl;
00424 
#endif
00425 
  
00426 
00427   
if(
stepwise_save)
00428   {
00429     
string s1 = 
append_slash(expdir) + 
"predictions_test_t=" + 
tostring(last_test_t);
00430     
saveAsciiWithoutSize(s1, predictions);
00431     
00432     
string s2 = 
append_slash(expdir) + 
"errors_test_t=" + 
tostring(last_test_t);
00433     
saveAsciiWithoutSize(s2, errors);
00434   }
00435 }
00436 
00437 void SequentialModelSelector::computeOutput(
const Vec& input, 
Vec& output)
 const
00438 
{
00439   
models[
best_model[last_train_t]]->computeOutput(input, output);
00440 }
00441 
00442 void SequentialModelSelector::computeCostsFromOutputs(
const Vec& input,
00443     
const Vec& output, 
const Vec& target, 
Vec& costs)
 const
00444 
{
00445   
models[
best_model[last_train_t]]->computeCostsFromOutputs(input, output, target, costs);
00446 }
00447 
00448 void SequentialModelSelector::computeOutputAndCosts(
const Vec& input,
00449     
const Vec& target, 
Vec& output, 
Vec& costs)
 const
00450 
{
00451   
models[
best_model[last_train_t]]->computeOutputAndCosts(input, target, output, costs);
00452 }
00453  
00454 void SequentialModelSelector::computeCostsOnly(
const Vec& input,
00455     
const Vec& target, 
Vec& costs)
 const
00456 
{
00457   
models[
best_model[last_train_t]]->computeCostsOnly(input, target, costs);
00458 }
00459 
00460 void SequentialModelSelector::checkModelNames()
 const
00461 
{
00462   
int nb_models = 
models.
length();
00463   
int nb_names = 
model_names.
length();
00464   
if(nb_names == 0)
00465   {
00466     
model_names.
resize(nb_models);
00467     
for(
int m=0; m < nb_models; m++)
00468       
model_names[m] = 
"Model_"+
tostring(m);
00469   }
00470   
else if(nb_names != nb_models)
00471     
PLERROR(
"Names must be provided for all models (%d = nb_names != nb_models = %d).", nb_names, nb_models);
00472 }
00473 
00474 TVec<string> SequentialModelSelector::getTestCostNames()
 const
00475 
{ 
00476   
TVec<string> tcnames = 
common_costs;
00477   
00478   
int nb_models = 
models.
length();
00479   
checkModelNames();
00480 
00481   
for(
int m=0; m < nb_models; m++)
00482   {
00483     
TVec<string> tcm = 
models[m]->getTestCostNames();
00484     
for(
int c=0; c < tcm.
length(); c++)
00485       tcnames.
append(
model_names[m] + 
"::" + tcm[c]);
00486   }
00487   
00488   
if( 
report_paired_T_tests )
00489     
for(
int m=1; m < nb_models; m++)
00490       tcnames.
append(
"T-test_" + 
model_names[0] + 
"_vs_" + 
model_names[m]);
00491   
00492   
return tcnames;
00493 }
00494 
00495 TVec<string> SequentialModelSelector::getTrainCostNames()
 const
00496 
{ 
return common_costs; }
00497 
00498 void SequentialModelSelector::makeDeepCopyFromShallowCopy(
CopiesMap& copies)
00499 {
00500   inherited::makeDeepCopyFromShallowCopy(copies);
00501   
deepCopyField(
models, copies);
00502   
00503 } 
00504 
00505 void SequentialModelSelector::matlabSave(
const string& matlab_subdir)
00506 {
00507   
string save_dir = 
append_slash(
getExperimentDirectory()) + matlab_subdir;
00508   
Vec dummy, 
add(1); 
add[0] = 0;
00509   
00510   
TVec<string> legend(1, 
"ModelSelector");
00511   legend.
append(
model_names);
00512   
00513   
int nb_models = 
models.
length();
00514   
int nb_common_costs = 
common_costs.
length();
00515   
for(
int g=0; g < nb_common_costs; g++)
00516   {
00517     
Vec cs;
00518 
00519     
Array<Mat> columns(nb_models+1);
00520     cs = getCostSequence(g);
00521 
00522     
00523     
00524     
int msel_cs_len = cs.
length(); 
00525 
00526     columns[0] = 
Mat(cs.
length(), 1, cs);
00527     
for(
int m=0; m < nb_models; m++)
00528     {
00529       cs = 
models[m]->getCostSequence( 
common_cost_indices(m, g) );
00530       cs = cs.
subVec(cs.
length() - msel_cs_len, msel_cs_len); 
00531       columns[m+1] = 
Mat(cs.
length(), 1, cs);
00532     }
00533     
00534     
Mat concat = 
hconcat(columns);
00535     
PLearn::matlabSave( save_dir, 
common_costs[g], 
00536                         
concat,
00537                         
add, dummy, legend);
00538   }
00539   
00540   
for(
int m=0; m < nb_models; m++)
00541     
models[m]->matlabSave(matlab_subdir);
00542 }
00543 
00544 } 
00545