PLearn 0.1
EarlyStoppingOracle.cc
Go to the documentation of this file.
00001 
00002 // -*- C++ -*-
00003 
00004 // EarlyStoppingOracle.cc
00005 //
00006 // Copyright (C) 2003-2004 ApSTAT Technologies Inc.
00007 //
00008 // Redistribution and use in source and binary forms, with or without
00009 // modification, are permitted provided that the following conditions are met:
00010 //
00011 //  1. Redistributions of source code must retain the above copyright
00012 //     notice, this list of conditions and the following disclaimer.
00013 //
00014 //  2. Redistributions in binary form must reproduce the above copyright
00015 //     notice, this list of conditions and the following disclaimer in the
00016 //     documentation and/or other materials provided with the distribution.
00017 //
00018 //  3. The name of the authors may not be used to endorse or promote
00019 //     products derived from this software without specific prior written
00020 //     permission.
00021 //
00022 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
00023 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00024 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
00025 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00026 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00027 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00028 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00029 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00030 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00031 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00032 //
00033 // This file is part of the PLearn library. For more information on the PLearn
00034 // library, go to the PLearn Web site at www.plearn.org
00035 
00036 // Author: Pascal Vincent
00037 
00038 /* *******************************************************
00039  * $Id: EarlyStoppingOracle.cc 9830 2009-01-14 19:00:27Z nouiz $
00040  ******************************************************* */
00041 
00043 #include "EarlyStoppingOracle.h"
00044 #include <plearn/base/stringutils.h>
00045 #define PL_LOG_MODULE_NAME "EarlyStoppingOracle"
00046 #include <plearn/io/pl_log.h>
00047 #
00048 namespace PLearn {
00049 using namespace std;
00050 
00051 EarlyStoppingOracle::EarlyStoppingOracle()
00052     : nreturned(0),
00053       previous_objective(REAL_MAX),
00054       best_objective(REAL_MAX),
00055       best_step(-1),
00056       met_early_stopping(false),
00057       min_value(-REAL_MAX),
00058       max_value(REAL_MAX),
00059       max_degradation(REAL_MAX),
00060       relative_max_degradation(-1),
00061       min_improvement(-REAL_MAX),
00062       relative_min_improvement(-1),
00063       max_degraded_steps(100),
00064       min_n_steps(0)
00065 {
00066     //    build_();
00067 }
00068 
00069 PLEARN_IMPLEMENT_OBJECT(EarlyStoppingOracle, "ONE LINE DESCR", "NO HELP");
00070 
00071 void EarlyStoppingOracle::declareOptions(OptionList& ol)
00072 {
00073     declareOption(ol, "option", &EarlyStoppingOracle::option, OptionBase::buildoption,
00074                   "the name of the option to change");
00075     declareOption(ol, "values", &EarlyStoppingOracle::values, OptionBase::buildoption,
00076                   "a list of values to try in sequence ");
00077     declareOption(ol, "range", &EarlyStoppingOracle::range, OptionBase::buildoption,
00078                   "a numerical range of the form [ start, end ] or [ start, end, step ]\n"
00079                   "WARNING: end is not included!");
00080 
00081     declareOption(ol, "min_value", &EarlyStoppingOracle::min_value, OptionBase::buildoption,
00082                   "minimum allowed error beyond which we stop\n");
00083 
00084     declareOption(ol, "max_value", &EarlyStoppingOracle::max_value, OptionBase::buildoption,
00085                   "maximum allowed error beyond which we stop\n");
00086 
00087     declareOption(ol, "max_degradation", &EarlyStoppingOracle::max_degradation, OptionBase::buildoption,
00088                   "maximum allowed degradation from last best objective value\n");
00089 
00090     declareOption(ol, "relative_max_degradation", &EarlyStoppingOracle::relative_max_degradation, OptionBase::buildoption,
00091                   "maximum allowed degradation from last best objective, relative to abs(best_objective)\n"
00092                   "ex: 0.10 will allow a degradation of 10% the magnitude of best_objective\n"
00093                   "Will be ignored if negative}n");
00094 
00095     declareOption(ol, "min_improvement", &EarlyStoppingOracle::min_improvement, OptionBase::buildoption,
00096                   "minimum required improvement from previous objective value\n");
00097 
00098     declareOption(ol, "relative_min_improvement", &EarlyStoppingOracle::relative_min_improvement, OptionBase::buildoption,
00099                   "minimum required improvement from previous objective value, relative to it.\n"
00100                   "ex: 0.01 means we need an improvement of 0.01*abs(previous_objective)  i.e. 1%\n"
00101                   "Will be ignored if negative\n");
00102 
00103     declareOption(ol, "max_degraded_steps", &EarlyStoppingOracle::max_degraded_steps, OptionBase::buildoption,
00104                   "    ax. nb of steps beyond best found\n");
00105 
00106     declareOption(ol, "min_n_steps", &EarlyStoppingOracle::min_n_steps, OptionBase::buildoption,
00107                   "minimum required number of steps before allowing early stopping\n");
00108 
00109     //learnt option
00110     declareOption(ol, "nreturned", &EarlyStoppingOracle::nreturned,
00111                   OptionBase::learntoption,
00112                   "The number of returned option\n");
00113 
00114     declareOption(ol, "best_objective", &EarlyStoppingOracle::best_objective,
00115                   OptionBase::learntoption,
00116                   "The best objective see up to date\n");
00117 
00118     declareOption(ol, "best_step", &EarlyStoppingOracle::best_step,
00119                   OptionBase::learntoption,
00120                   "The step where we have see the best objective\n");
00121 
00122     declareOption(ol, "met_early_stopping", &EarlyStoppingOracle::met_early_stopping,
00123                   OptionBase::learntoption,
00124                   "True if we met the early stopping criterion\n");
00125 
00126     // Now call the parent class' declareOptions
00127     inherited::declareOptions(ol);
00128 }
00129 
00130 void EarlyStoppingOracle::build_()
00131 {
00132     if(values.length()>0)
00133         option_values = values;
00134     else if(range.length()>=2)
00135     {
00136         option_values.resize(0);
00137         real step = 1;
00138         if(range.length()==3){
00139             step = range[2];
00140             if(step<0 || is_equal(step,0))
00141                 PLERROR("IN EarlyStoppingOracle::build_() - the"
00142                         " step(=%f) should be greater the 0!",step);
00143         }
00144         for(real x = range[0]; x<range[1]; x+=step)
00145             option_values.append(tostring(x));
00146         if(fast_exact_is_equal(range[0], range[1]))
00147             PLWARNING("In EarlyStoppingOracle::build_ - no range selected. "
00148                     "Maybe you forgot that the end part of the range is not "
00149                     "included!");
00150     }
00151     if(option_values.length()==0)
00152         PLWARNING("In EarlyStoppingOracle::build_ - no range selected.");
00153   
00154 }
00155 
00156 // ### Nothing to add here, simply calls build_
00157 void EarlyStoppingOracle::build()
00158 {
00159     inherited::build();
00160     build_();
00161 }
00162 
00163 TVec<string>  EarlyStoppingOracle::getOptionNames() const
00164 { return TVec<string>(1,option); }
00165 
00166 TVec<string> EarlyStoppingOracle::generateNextTrial(const TVec<string>& older_trial, real obtained_objective)
00167 {
00168     if(met_early_stopping)
00169         return TVec<string>();
00170 
00171     if(older_trial.length()>0)
00172     {
00173         real current_objective = obtained_objective;
00174         int current_step = nreturned;
00175 
00176         if(current_objective<best_objective && current_step >= min_n_steps)
00177         {
00178             best_objective = current_objective;
00179             best_step = current_step;
00180         }
00181 
00182         real improvement = previous_objective-current_objective;
00183         real degradation = current_objective-best_objective;
00184 
00185         int n_degraded_steps = current_step-best_step;
00186 
00187         // Check if early-stopping condition was met
00188         if (( (current_objective < min_value) ||
00189               (current_objective > max_value) ||
00190               (n_degraded_steps >= max_degraded_steps) ||
00191               (degradation > max_degradation) ||
00192               (relative_max_degradation>=0 && degradation > relative_max_degradation * abs(best_objective)) ||
00193               (improvement < min_improvement) ||
00194               (relative_min_improvement>=0 && improvement < relative_min_improvement * abs(previous_objective))
00195                 ) && current_step >= min_n_steps){
00196             met_early_stopping = true;
00197 
00198             //print debug info
00199             if(current_objective < min_value){
00200                 DBG_MODULE_LOG 
00201                     <<"stopping the learner as: current_objective "
00202                     <<current_objective
00203                     <<" < min_value "<<min_value
00204                     <<endl;
00205             }
00206             if(current_objective > max_value){
00207                 DBG_MODULE_LOG
00208                     <<"stopping the learner as: current_objective ("<<current_objective
00209                     <<") < max_value ("<<max_value<<")"<<endl;
00210             }
00211             if(n_degraded_steps >= max_degraded_steps){
00212                 DBG_MODULE_LOG
00213                     <<"stopping the learner as:n_degraded_steps("<<
00214                     n_degraded_steps<<") >= max_degraded_steps("<<
00215                     max_degraded_steps<<") "
00216                     <<endl;
00217             }
00218             if(degradation > max_degradation){
00219                 DBG_MODULE_LOG
00220                     <<"stopping the learner as: degradation("<<degradation
00221                     <<") > max_degradation("<<max_degradation<<")"
00222                     <<endl;
00223             }
00224             if(relative_max_degradation>=0 
00225                && degradation > relative_max_degradation * abs(best_objective)){
00226                 DBG_MODULE_LOG
00227                     <<"stopping the learner as: relative_max_degradation>=0 "
00228                     <<"&& degradation("<<degradation
00229                     <<") > relative_max_degradation("<<relative_max_degradation
00230                     <<") * abs(best_objective)("<<best_objective<<")"
00231                     <<endl;
00232             }
00233             if(improvement < min_improvement){
00234                 DBG_MODULE_LOG
00235                     <<"stopping the learner as: improvement("<<improvement<<") < min_improvement("
00236                     <<min_improvement<<")"
00237                     <<endl;
00238             }
00239             if(relative_min_improvement>=0 
00240                && improvement < relative_min_improvement * abs(previous_objective)){
00241                 DBG_MODULE_LOG
00242                     <<"stopping the learner as: relative_min_improvement("<<relative_min_improvement<<")>=0 "
00243                     <<endl
00244                     <<"&& improvement("<<improvement<<") < relative_min_improvement("<<relative_min_improvement<<") * abs(previous_objective"<<previous_objective<<")"
00245                     <<endl;
00246             }
00247         }
00248 
00249         previous_objective = current_objective;
00250     }
00251 
00252     if(met_early_stopping || nreturned >= option_values.length())
00253         return TVec<string>();
00254     else
00255         return TVec<string>(1, option_values[nreturned++]);
00256 }
00257 
00258 void EarlyStoppingOracle::forget()
00259 {
00260     nreturned = 0;
00261     previous_objective = FLT_MAX;
00262     best_objective = FLT_MAX;
00263     best_step = -1;
00264     met_early_stopping = false;
00265 }
00266 
00267 
00268 void EarlyStoppingOracle::makeDeepCopyFromShallowCopy(CopiesMap& copies)
00269 {
00270     inherited::makeDeepCopyFromShallowCopy(copies);
00271 
00272     deepCopyField(option_values, copies);
00273     deepCopyField(values, copies);
00274     deepCopyField(range, copies);
00275 }
00276 
00277 } // end of namespace PLearn
00278 
00279 
00280 /*
00281   Local Variables:
00282   mode:c++
00283   c-basic-offset:4
00284   c-file-style:"stroustrup"
00285   c-file-offsets:((innamespace . 0)(inline-open . 0))
00286   indent-tabs-mode:nil
00287   fill-column:79
00288   End:
00289 */
00290 // 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