PLearn 0.1
VPLPreprocessedLearner.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 // VPLPreprocessedLearner.cc
00004 //
00005 // Copyright (C) 2005 Pascal Vincent 
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 /* *******************************************************      
00036  * $Id: VPLPreprocessedLearner.cc 7042 2007-05-09 23:44:20Z saintmlx $ 
00037  ******************************************************* */
00038 
00039 // Authors: Pascal Vincent
00040 
00044 #include "VPLPreprocessedLearner.h"
00045 #include <plearn/vmat/ProcessingVMatrix.h>
00046 #include <plearn/base/tostring.h>
00047 
00048 namespace PLearn {
00049 using namespace std;
00050 
00051 VPLPreprocessedLearner::VPLPreprocessedLearner() 
00052     : newtargetsize(-1),
00053       newweightsize(-1),
00054       newextrasize(0)
00055 {
00056 }
00057 
00058 PLEARN_IMPLEMENT_OBJECT(
00059     VPLPreprocessedLearner,
00060     "DEPRECATED. Consider using VPLPreprocessedLearner2 instead.",
00061     "Learner whose training-set, inputs and outputs can be pre/post-processed by VPL code. See VMatLanguage for the definition of the allowed VPL syntax."
00062     );
00063 
00064 void VPLPreprocessedLearner::declareOptions(OptionList& ol)
00065 {
00066     // ### Declare all of this object's options here
00067     // ### For the "flags" of each option, you should typically specify  
00068     // ### one of OptionBase::buildoption, OptionBase::learntoption or 
00069     // ### OptionBase::tuningoption. Another possible flag to be combined with
00070     // ### is OptionBase::nosave
00071 
00072     // ### ex:
00073     // declareOption(ol, "myoption", &VPLPreprocessedLearner::myoption, OptionBase::buildoption,
00074     //               "Help text describing this option");
00075     // ...
00076 
00077     declareOption(ol, "learner", &VPLPreprocessedLearner::learner_,
00078                   OptionBase::buildoption,
00079                   "The embedded learner");
00080 
00081     declareOption(ol, "trainset_preproc", &VPLPreprocessedLearner::trainset_preproc, OptionBase::buildoption,
00082                   "Program string in VPL language to be applied to each row of the initial\n"
00083                   "training set to generate the new preprocessed training set.\n"
00084                   "This should generate preprocessed input and target (and weight if any).\n"
00085                   "Note that names must be given to the generated values with :fieldname VPL syntax.\n"
00086                   "An empty string means NO PREPROCESSING. (initial training set is used as is)");
00087     declareOption(ol, "newtargetsize", &VPLPreprocessedLearner::newtargetsize, OptionBase::buildoption,
00088                   "Size of target produced by trainset_preproc (target must follow preprocessed input).");
00089     declareOption(ol, "newweightsize", &VPLPreprocessedLearner::newweightsize, OptionBase::buildoption,
00090                   "0 or 1, depending on whether trainset_preproc generates a weight or not after the target.");
00091     declareOption(ol, "newextrasize", &VPLPreprocessedLearner::newextrasize, OptionBase::buildoption,
00092                   "size of extra fields generated by trainset_preproc after target and wright.");
00093 
00094     declareOption(ol, "input_preproc", &VPLPreprocessedLearner::input_preproc, OptionBase::buildoption,
00095                   "Program string in VPL language to be applied to a new input.\n"
00096                   "This must produce exactly the same thing as the preprocessed.\n"
00097                   "input part produced by trainset_preproc\n"
00098                   "Note that names must be given to the generated values with :fieldname VPL syntax.\n");
00099   
00100     declareOption(ol, "output_postproc", &VPLPreprocessedLearner::output_postproc, OptionBase::buildoption,
00101                   "Program string in VPL language to optain postprocessed output\n"
00102                   "from the underlying learner's output.\n"
00103                   "Note that names must be given to the generated values with :fieldname VPL syntax.\n"
00104                   "An empty string means NO OUTPUT POSTPROCESSING.\n\n"
00105                   "Additional Note: when this snippet of VPL starts executing, the\n"
00106                   "ORIGINAL (not preprocessed) input row is stored in VPL memory, starting\n"
00107                   "from memory location 0 until inputsize-1 (inclusive).  You can access these\n"
00108                   "memory locations using VPL instructions of the form:\n"
00109                   "\n"
00110                   "    <memory_location> memget\n"
00111                   "\n"
00112                   "This lets the output postprocessor use some information from the input\n"
00113                   "vector to construct the output (e.g. put back some data that was hidden\n"
00114                   "from the embedded learner.)");
00115     declareOption(ol, "costs_postproc", &VPLPreprocessedLearner::costs_postproc, OptionBase::buildoption,
00116                   "Program string in VPL language to optain postprocessed test costs\n"
00117                   "from the underlying learner's test costs.\n"
00118                   "Note that names must be given to the generated values with :fieldname VPL syntax.\n"
00119                   "An empty string means NO COSTS POSTPROCESSING.\n"
00120                   "Note that the *train* costs are those of the underlying learner. No postproc is applied to those.");
00121 
00122     declareOption(ol, "row_prg", &VPLPreprocessedLearner::row_prg, OptionBase::learntoption,
00123                   "Compiled trainset_preproc program");
00124     declareOption(ol, "input_prg", &VPLPreprocessedLearner::input_prg, OptionBase::learntoption,
00125                   "Compiled input_preproc program");
00126     declareOption(ol, "output_prg", &VPLPreprocessedLearner::output_prg, OptionBase::learntoption,
00127                   "Compiled output_postproc program");
00128     declareOption(ol, "costs_prg", &VPLPreprocessedLearner::costs_prg, OptionBase::learntoption,
00129                   "Compiled costs_postproc program");
00130 
00131     declareOption(ol, "row_prg_fieldnames", &VPLPreprocessedLearner::row_prg_fieldnames, OptionBase::learntoption,
00132                   "names of fields produced by row_prg");
00133     declareOption(ol, "input_prg_fieldnames", &VPLPreprocessedLearner::input_prg_fieldnames, OptionBase::learntoption,
00134                   "names of fields produced by input_prg");
00135     declareOption(ol, "output_prg_fieldnames", &VPLPreprocessedLearner::output_prg_fieldnames, OptionBase::learntoption,
00136                   "names of fields produced by output_prg");
00137     declareOption(ol, "costs_prg_fieldnames", &VPLPreprocessedLearner::costs_prg_fieldnames, OptionBase::learntoption,
00138                   "names of fields produced by costs_prg");
00139 
00140     // Now call the parent class' declareOptions
00141     inherited::declareOptions(ol);
00142 }
00143 
00144 void VPLPreprocessedLearner::build_()
00145 {
00146 }
00147 
00148 // ### Nothing to add here, simply calls build_
00149 void VPLPreprocessedLearner::build()
00150 {
00151     inherited::build();
00152     build_();
00153 }
00154 
00155 
00156 void VPLPreprocessedLearner::makeDeepCopyFromShallowCopy(CopiesMap& copies)
00157 {
00158     inherited::makeDeepCopyFromShallowCopy(copies);
00159 
00160     // ### Call deepCopyField on all "pointer-like" fields 
00161     // ### that you wish to be deepCopied rather than 
00162     // ### shallow-copied.
00163 
00164     deepCopyField(learner_, copies);    
00165 
00166     deepCopyField(row_prg, copies);
00167     deepCopyField(input_prg, copies);
00168     deepCopyField(output_prg, copies);
00169     deepCopyField(costs_prg, copies);
00170 /*
00171     row_prg.makeDeepCopyFromShallowCopy(copies);
00172     input_prg.makeDeepCopyFromShallowCopy(copies);
00173     output_prg.makeDeepCopyFromShallowCopy(copies);
00174     costs_prg.makeDeepCopyFromShallowCopy(copies);
00175 */
00176  
00177     deepCopyField(row_prg_fieldnames, copies); 
00178     deepCopyField(input_prg_fieldnames, copies);
00179     deepCopyField(output_prg_fieldnames, copies);
00180     deepCopyField(costs_prg_fieldnames, copies);
00181     deepCopyField(row, copies);
00182     deepCopyField(processed_row, copies);
00183     deepCopyField(processed_input, copies);
00184     deepCopyField(pre_output, copies);
00185     deepCopyField(pre_costs, copies);
00186 }
00187 
00188 void VPLPreprocessedLearner::setValidationSet(VMat validset)
00189 {
00190     PLASSERT( learner_ );
00191     inherited::setValidationSet(validset);
00192     learner_->setValidationSet(validset);
00193 }
00194 
00195 void VPLPreprocessedLearner::setTrainStatsCollector(PP<VecStatsCollector> statscol)
00196 {
00197     PLASSERT( learner_ );
00198     inherited::setTrainStatsCollector(statscol);
00199     learner_->setTrainStatsCollector(statscol);
00200 }
00201 
00202 int VPLPreprocessedLearner::outputsize() const
00203 {
00204     if(output_prg && *output_prg)
00205         return output_prg_fieldnames.length();
00206     else
00207     {
00208         PLASSERT( learner_ );
00209         return learner_->outputsize();
00210     }
00211 }
00212 
00213 void VPLPreprocessedLearner::setExperimentDirectory(const PPath& the_expdir)
00214 {
00215     PLASSERT( learner_ );
00216     inherited::setExperimentDirectory(the_expdir);
00217     learner_->setExperimentDirectory(the_expdir);
00218 }
00219 
00220 void VPLPreprocessedLearner::forget()
00221 {
00222     PLASSERT( learner_);
00223     learner_->forget();
00224     stage = 0;
00225 }
00226     
00227 void VPLPreprocessedLearner::train()
00228 {
00229     PLASSERT( learner_ );
00230     learner_->train();
00231     stage = learner_->stage;
00232 }
00233 
00234 void VPLPreprocessedLearner::setTrainingSet(VMat training_set, bool call_forget)
00235 {
00236     PLASSERT( learner_ );
00237 
00238     if(!row_prg) 
00239         row_prg= new VMatLanguage();
00240     if(trainset_preproc!="")
00241     {
00242         row_prg->setSource(training_set);
00243         row_prg->compileString(trainset_preproc, row_prg_fieldnames);
00244         int newinputsize = row_prg_fieldnames.length()-(newtargetsize+newweightsize+newextrasize);
00245         VMat processed_trainset = new ProcessingVMatrix(training_set, trainset_preproc);
00246         processed_trainset->defineSizes(newinputsize,newtargetsize,newweightsize,newextrasize);
00247         learner_->setTrainingSet(processed_trainset, false);
00248     }
00249     else
00250     {
00251         row_prg->clear();
00252         row_prg_fieldnames.resize(0);
00253         learner_->setTrainingSet(training_set, false);
00254     }
00255     bool training_set_has_changed = !train_set || !(train_set->looksTheSameAs(training_set));
00256     if (call_forget && !training_set_has_changed)
00257         // In this case, learner_->build() will not have been called, which may
00258         // cause trouble if it updates data from the training set.
00259         learner_->build();
00260     inherited::setTrainingSet(training_set, call_forget); // will call forget if needed
00261 
00262     if(!input_prg) 
00263         input_prg= new VMatLanguage();
00264     if(input_preproc!="")
00265     {
00266         int insize = training_set->inputsize();
00267         TVec<string> infieldnames = training_set->fieldNames().subVec(0,insize);
00268         input_prg->setSourceFieldNames(infieldnames);
00269         input_prg->compileString(input_preproc, input_prg_fieldnames);
00270     }
00271     else
00272     {
00273         input_prg->clear();
00274         input_prg_fieldnames.resize(0);
00275     }
00276 
00277     if(!output_prg) 
00278         output_prg= new VMatLanguage();
00279     if(output_postproc!="")
00280     {
00281         int outsize = learner_->outputsize();
00282         TVec<string> outfieldnames(outsize);
00283         for(int k=0; k<outsize; k++)
00284             outfieldnames[k] = "output"+tostring(k);
00285         output_prg->setSourceFieldNames(outfieldnames);
00286         output_prg->compileString(output_postproc, output_prg_fieldnames);
00287     }
00288     else
00289     {
00290         output_prg->clear();
00291         output_prg_fieldnames.resize(0);
00292     }
00293 
00294     if(!costs_prg) 
00295         costs_prg= new VMatLanguage();
00296     if(costs_postproc!="")
00297     {
00298         costs_prg->setSourceFieldNames(learner_->getTestCostNames());
00299         costs_prg->compileString(costs_postproc, costs_prg_fieldnames);
00300     }
00301     else
00302     {
00303         costs_prg->clear();
00304         costs_prg_fieldnames.resize(0);
00305     }
00306 }
00307 
00308 
00309 void VPLPreprocessedLearner::computeOutput(const Vec& input, Vec& output) const
00310 {
00311     PLASSERT( learner_ );
00312     output.resize(outputsize());
00313     Vec newinput = input;
00314     if(input_prg && *input_prg)
00315     {
00316         processed_input.resize(input_prg_fieldnames.length());
00317         input_prg->run(input, processed_input);
00318         newinput = processed_input;
00319     }
00320 
00321     if(output_prg && *output_prg)
00322     {
00323         learner_->computeOutput(newinput, pre_output);
00324         output_prg->setMemory(input);           // Put original input vector
00325         // as context for output postproc
00326         output_prg->run(pre_output, output);
00327     }
00328     else
00329         learner_->computeOutput(newinput, output);
00330     
00331 }
00332 
00333 void VPLPreprocessedLearner::computeOutputAndCosts(const Vec& input, const Vec& target, 
00334                                                    Vec& output, Vec& costs) const
00335 { 
00336     output.resize(outputsize());
00337     costs.resize(nTestCosts());
00338 
00339     PLASSERT( learner_ );
00340     int ilen = input.length();
00341     int tlen = target.length();
00342     PLASSERT(ilen==inputsize());
00343     PLASSERT(tlen==targetsize());
00344 
00345     if(row_prg && *row_prg)
00346     {
00347         row.resize(ilen+tlen);
00348         row.subVec(0,ilen) << input;
00349         row.subVec(ilen,tlen) << target;
00350         if(weightsize()==1)
00351             row.append(1.0);
00352 
00353         int newrowsize = row_prg_fieldnames.length();
00354         processed_row.resize(newrowsize);
00355         row_prg->run(row, processed_row);
00356         int newinputsize = newrowsize-(newtargetsize+newweightsize+newextrasize);
00357         Vec processed_input = processed_row.subVec(0,newinputsize);
00358         Vec processed_target = processed_row.subVec(newinputsize,newtargetsize);
00359         learner_->computeOutputAndCosts(processed_input, processed_target, pre_output, pre_costs);
00360     }
00361     else
00362         learner_->computeOutputAndCosts(input, target, pre_output, pre_costs);
00363 
00364     if(output_prg && *output_prg) {
00365         output_prg->setMemory(input);           // Put original input vector
00366         // as context for output postproc
00367         output_prg->run(pre_output, output);
00368     }
00369     else
00370         output << pre_output;
00371 
00372     if(costs_prg && *costs_prg)
00373         costs_prg->run(pre_costs, costs);
00374     else
00375         costs << pre_costs;
00376 }
00377 
00378 void VPLPreprocessedLearner::computeCostsFromOutputs(const Vec& input, const Vec& output, 
00379                                                      const Vec& target, Vec& costs) const
00380 { 
00381     Vec nonconst_output = output; // to make the constipated compiler happy
00382     computeOutputAndCosts(input, target, nonconst_output, costs); 
00383 }
00384 
00385 bool VPLPreprocessedLearner::computeConfidenceFromOutput(
00386     const Vec& input, const Vec& output,
00387     real probability, TVec< pair<real,real> >& intervals) const
00388 {
00389     int d = outputsize();
00390     if(d!=output.length())
00391         PLERROR("In VPLPreprocessedLearner::computeConfidenceFromOutput, length of passed output (%d)"
00392                 "differes from outputsize (%d)!",output.length(),d);
00393 
00394     PLASSERT( learner_ );
00395     Vec newinput = input;
00396     if(input_prg && *input_prg)
00397     {
00398         processed_input.resize(input_prg_fieldnames.length());
00399         input_prg->run(input, processed_input);
00400         newinput = processed_input;
00401     }
00402 
00403     bool status = false;
00404     if(!output_prg || !(*output_prg)) // output is already the output of the underlying learner
00405         status = learner_->computeConfidenceFromOutput(newinput, output, probability, intervals);
00406     else // must recompute the output of underlying learner, and post-process returned intervals
00407     {
00408         learner_->computeOutput(newinput, pre_output);
00409         TVec< pair<real,real> > pre_intervals;
00410         status = learner_->computeConfidenceFromOutput(newinput, pre_output, probability, pre_intervals);
00411         if(!status) // no confidence computation available
00412         {
00413             intervals.resize(d);
00414             for(int k=0; k<d; k++)
00415                 intervals[k] = pair<real,real>(MISSING_VALUE,MISSING_VALUE);
00416         }
00417         else // postprocess low and high vectors
00418         {
00419             int ud = learner_->outputsize(); // dimension of underlying learner's output
00420             // first build low and high vectors
00421             Vec low(ud);
00422             Vec high(ud);
00423             for(int k=0; k<ud; k++)
00424             {
00425                 pair<real,real> p = pre_intervals[k];
00426                 low[k] = p.first;
00427                 high[k] = p.second;
00428             }
00429             Vec post_low(d); // postprocesed low
00430             Vec post_high(d); // postprocessed high
00431 
00432             // Put original input vector as context for output postproc
00433             output_prg->setMemory(input);
00434             output_prg->run(low, post_low);
00435 
00436             // Put original input vector as context for output postproc
00437             output_prg->setMemory(input);
00438             output_prg->run(high, post_high);
00439 
00440             // Now copy post_low and post_high to intervals
00441             intervals.resize(d);
00442             for(int k=0; k<d; k++)
00443                 intervals[k] = pair<real,real>(post_low[k],post_high[k]);
00444         }
00445     }
00446     return status;
00447 }
00448 
00449 TVec<string> VPLPreprocessedLearner::getOutputNames() const
00450 {
00451     if(output_prg && *output_prg)
00452         return output_prg_fieldnames;
00453     else
00454         return learner_->getOutputNames();
00455 }
00456 
00457 
00458 TVec<string> VPLPreprocessedLearner::getTestCostNames() const
00459 {
00460     if(costs_prg && *costs_prg)
00461         return costs_prg_fieldnames;
00462     else
00463         return learner_->getTestCostNames();
00464 }
00465 
00466 TVec<string> VPLPreprocessedLearner::getTrainCostNames() const
00467 {
00468     PLASSERT( learner_ );
00469     return learner_->getTrainCostNames();
00470 }
00471 
00472 void VPLPreprocessedLearner::resetInternalState()
00473 {
00474     PLASSERT( learner_ );
00475     learner_->resetInternalState();
00476 }
00477 
00478 bool VPLPreprocessedLearner::isStatefulLearner() const
00479 {
00480     PLASSERT( learner_ );
00481     return learner_->isStatefulLearner();
00482 }
00483 
00484 
00485 } // end of namespace PLearn
00486 
00487 
00488 /*
00489   Local Variables:
00490   mode:c++
00491   c-basic-offset:4
00492   c-file-style:"stroustrup"
00493   c-file-offsets:((innamespace . 0)(inline-open . 0))
00494   indent-tabs-mode:nil
00495   fill-column:79
00496   End:
00497 */
00498 // 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