PLearn 0.1
|
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 :