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