PLearn 0.1
|
00001 // -*- C++ -*- 00002 00003 // ModuleStackModule.cc 00004 // 00005 // Copyright (C) 2007 Pascal Lamblin 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 // Authors: Pascal Lamblin 00036 00041 #include "ModuleStackModule.h" 00042 00043 namespace PLearn { 00044 using namespace std; 00045 00046 PLEARN_IMPLEMENT_OBJECT( 00047 ModuleStackModule, 00048 "Wraps a stack of layered OnlineLearningModule into a single one", 00049 "The OnlineLearningModule's are disposed like superposed layers:\n" 00050 "outputs of module i are the inputs of module (i+1), the last layer is\n" 00051 "the output layer.\n" 00052 ); 00053 00054 ModuleStackModule::ModuleStackModule() : 00055 n_modules(0) 00056 { 00057 } 00058 00060 // declareOptions // 00062 void ModuleStackModule::declareOptions(OptionList& ol) 00063 { 00064 declareOption(ol, "modules", &ModuleStackModule::modules, 00065 OptionBase::buildoption, 00066 "The underlying modules"); 00067 00068 declareOption(ol, "n_modules", &ModuleStackModule::n_modules, 00069 OptionBase::learntoption, 00070 "The number of modules"); 00071 00072 // Now call the parent class' declareOptions 00073 inherited::declareOptions(ol); 00074 00075 // Hide unused options. 00076 00077 redeclareOption(ol, "input_size", &ModuleStackModule::input_size, 00078 OptionBase::nosave, 00079 "Set at build time."); 00080 00081 redeclareOption(ol, "output_size", &ModuleStackModule::output_size, 00082 OptionBase::nosave, 00083 "Set at build time."); 00084 00085 } 00086 00088 // build_ // 00090 void ModuleStackModule::build_() 00091 { 00092 n_modules = modules.length(); 00093 00094 if( n_modules > 0 ) 00095 { 00096 values.resize( n_modules-1 ); 00097 gradients.resize( n_modules-1 ); 00098 diag_hessians.resize( n_modules-1 ); 00099 values_m.resize(n_modules - 1); 00100 gradients_m.resize(n_modules - 1); 00101 00102 input_size = modules[0]->input_size; 00103 output_size = modules[n_modules-1]->output_size; 00104 } 00105 else 00106 { 00107 input_size = -1; 00108 output_size = -1; 00109 } 00110 00111 // If we have a random_gen and some modules do not, share it with them 00112 if( random_gen ) 00113 for( int i=0; i<n_modules; i++ ) 00114 if( !(modules[i]->random_gen) ) 00115 { 00116 modules[i]->random_gen = random_gen; 00117 modules[i]->forget(); 00118 } 00119 } 00120 00122 // build // 00124 void ModuleStackModule::build() 00125 { 00126 inherited::build(); 00127 build_(); 00128 } 00129 00130 00132 // makeDeepCopyFromShallowCopy // 00134 void ModuleStackModule::makeDeepCopyFromShallowCopy(CopiesMap& copies) 00135 { 00136 inherited::makeDeepCopyFromShallowCopy(copies); 00137 00138 deepCopyField(modules, copies); 00139 deepCopyField(values, copies); 00140 deepCopyField(gradients, copies); 00141 deepCopyField(diag_hessians, copies); 00142 deepCopyField(values_m, copies); 00143 deepCopyField(gradients_m, copies); 00144 } 00145 00147 // fprop // 00149 void ModuleStackModule::fprop(const Vec& input, Vec& output) const 00150 { 00151 PLASSERT( n_modules >= 2 ); 00152 PLASSERT( input.size() == input_size ); 00153 00154 modules[0]->fprop( input, values[0] ); 00155 for( int i=1 ; i<n_modules-1 ; i++ ) 00156 modules[i]->fprop( values[i-1], values[i] ); 00157 modules[n_modules-1]->fprop( values[n_modules-2], output ); 00158 } 00159 00160 void ModuleStackModule::fprop(const Mat& inputs, Mat& outputs) 00161 { 00162 PLASSERT( n_modules >= 2 ); 00163 PLASSERT( inputs.width() == input_size ); 00164 00165 modules[0]->fprop( inputs, values_m[0] ); 00166 for( int i=1 ; i<n_modules-1 ; i++ ) 00167 modules[i]->fprop( values_m[i-1], values_m[i] ); 00168 modules[n_modules-1]->fprop( values_m[n_modules-2], outputs ); 00169 } 00170 00172 // bpropUpdate // 00174 void ModuleStackModule::bpropUpdate(const Vec& input, const Vec& output, 00175 Vec& input_gradient, 00176 const Vec& output_gradient, 00177 bool accumulate) 00178 { 00179 PLASSERT( n_modules >= 2 ); 00180 PLASSERT( input.size() == input_size ); 00181 PLASSERT( output.size() == output_size ); 00182 PLASSERT( output_gradient.size() == output_size ); 00183 00184 if( accumulate ) 00185 { 00186 PLASSERT_MSG( input_gradient.size() == input_size, 00187 "Cannot resize input_gradient AND accumulate into it" ); 00188 } 00189 00190 // bpropUpdate should be called just after the corresponding fprop, 00191 // so values should be up-to-date. 00192 modules[n_modules-1]->bpropUpdate( values[n_modules-2], output, 00193 gradients[n_modules-2], 00194 output_gradient ); 00195 00196 for( int i=n_modules-2 ; i>0 ; i-- ) 00197 modules[i]->bpropUpdate( values[i-1], values[i], 00198 gradients[i-1], gradients[i] ); 00199 00200 modules[0]->bpropUpdate( input, values[0], input_gradient, gradients[0], 00201 accumulate ); 00202 } 00203 00204 void ModuleStackModule::bpropUpdate(const Mat& inputs, const Mat& outputs, 00205 Mat& input_gradients, 00206 const Mat& output_gradients, 00207 bool accumulate) 00208 { 00209 PLASSERT( n_modules >= 2 ); 00210 PLASSERT( inputs.width() == input_size ); 00211 PLASSERT( outputs.width() == output_size ); 00212 PLASSERT( output_gradients.width() == output_size ); 00213 00214 if( accumulate ) 00215 { 00216 PLASSERT_MSG( input_gradients.width() == input_size && 00217 input_gradients.length() == inputs.length(), 00218 "Cannot resize input_gradients and accumulate into it" ); 00219 } else 00220 input_gradients.resize(inputs.length(), input_size); 00221 00222 // bpropUpdate should be called just after the corresponding fprop, 00223 // so 'values_m' should be up-to-date. 00224 modules[n_modules-1]->bpropUpdate( values_m[n_modules-2], outputs, 00225 gradients_m[n_modules-2], 00226 output_gradients ); 00227 00228 for( int i=n_modules-2 ; i>0 ; i-- ) 00229 modules[i]->bpropUpdate( values_m[i-1], values_m[i], 00230 gradients_m[i-1], gradients_m[i] ); 00231 00232 modules[0]->bpropUpdate( inputs, values_m[0], input_gradients, gradients_m[0], 00233 accumulate ); 00234 } 00235 00236 void ModuleStackModule::bpropUpdate(const Vec& input, const Vec& output, 00237 const Vec& output_gradient) 00238 { 00239 PLASSERT( n_modules > 0 ); 00240 PLASSERT( input.size() == input_size ); 00241 PLASSERT( output.size() == output_size ); 00242 PLASSERT( output_gradient.size() == output_size ); 00243 00244 // bpropUpdate should be called just after the corresponding fprop, 00245 // so values should be up-to-date. 00246 modules[n_modules-1]->bpropUpdate( values[n_modules-2], output, 00247 gradients[n_modules-2], 00248 output_gradient ); 00249 00250 for( int i=n_modules-2 ; i>0 ; i-- ) 00251 modules[i]->bpropUpdate( values[i-1], values[i], 00252 gradients[i-1], gradients[i] ); 00253 00254 modules[0]->bpropUpdate( input, values[0], gradients[0] ); 00255 } 00256 00258 // bbpropUpdate // 00260 void ModuleStackModule::bbpropUpdate(const Vec& input, const Vec& output, 00261 Vec& input_gradient, 00262 const Vec& output_gradient, 00263 Vec& input_diag_hessian, 00264 const Vec& output_diag_hessian, 00265 bool accumulate) 00266 { 00267 PLASSERT( n_modules > 0 ); 00268 PLASSERT( input.size() == input_size ); 00269 PLASSERT( output.size() == output_size ); 00270 PLASSERT( output_gradient.size() == output_size ); 00271 PLASSERT( output_diag_hessian.size() == output_size ); 00272 00273 if( accumulate ) 00274 { 00275 PLASSERT_MSG( input_gradient.size() == input_size, 00276 "Cannot resize input_gradient AND accumulate into it" ); 00277 PLASSERT_MSG( input_diag_hessian.size() == input_size, 00278 "Cannot resize input_diag_hessian AND accumulate into it" 00279 ); 00280 } 00281 00282 // bbpropUpdate should be called just after the corresponding fprop, 00283 // so values should be up-to-date. 00284 modules[n_modules-1]->bbpropUpdate( values[n_modules-2], output, 00285 gradients[n_modules-2], output_gradient, 00286 diag_hessians[n_modules-2], 00287 output_diag_hessian ); 00288 00289 for( int i=n_modules-2 ; i>0 ; i-- ) 00290 modules[i]->bbpropUpdate( values[i-1], values[i], 00291 gradients[i-1], gradients[i], 00292 diag_hessians[i-1], diag_hessians[i] ); 00293 00294 modules[0]->bbpropUpdate( input, values[0], input_gradient, gradients[0], 00295 input_diag_hessian, diag_hessians[0], 00296 accumulate ); 00297 } 00298 00299 void ModuleStackModule::bbpropUpdate(const Vec& input, const Vec& output, 00300 const Vec& output_gradient, 00301 const Vec& output_diag_hessian) 00302 { 00303 PLASSERT( n_modules > 0 ); 00304 PLASSERT( input.size() == input_size ); 00305 PLASSERT( output.size() == output_size ); 00306 PLASSERT( output_gradient.size() == output_size ); 00307 PLASSERT( output_diag_hessian.size() == output_size ); 00308 00309 // bbpropUpdate should be called just after the corresponding fprop, 00310 // so values should be up-to-date. 00311 modules[n_modules-1]->bbpropUpdate( values[n_modules-2], output, 00312 gradients[n_modules-2], output_gradient, 00313 diag_hessians[n_modules-2], 00314 output_diag_hessian ); 00315 00316 for( int i=n_modules-2 ; i>0 ; i-- ) 00317 modules[i]->bbpropUpdate( values[i-1], values[i], 00318 gradients[i-1], gradients[i], 00319 diag_hessians[i-1], diag_hessians[i] ); 00320 00321 modules[0]->bbpropUpdate( input, values[0], 00322 gradients[0], diag_hessians[0] ); 00323 } 00324 00326 // forget // 00328 void ModuleStackModule::forget() 00329 { 00330 values.clear(); 00331 gradients.clear(); 00332 diag_hessians.clear(); 00333 00334 if( !random_gen ) 00335 { 00336 PLWARNING("ModuleStackModule: cannot forget() without random_gen"); 00337 return; 00338 } 00339 for( int i=0 ; i<n_modules ; i++ ) 00340 { 00341 // Ensure modules[i] can forget 00342 if( !(modules[i]->random_gen) ) 00343 modules[i]->random_gen = random_gen; 00344 modules[i]->forget(); 00345 } 00346 } 00347 00349 // finalize // 00351 void ModuleStackModule::finalize() 00352 { 00353 for( int i=0 ; i<n_modules ; i++ ) 00354 modules[i]->finalize(); 00355 } 00356 00358 // bpropDoesNothing // 00360 bool ModuleStackModule::bpropDoesNothing() 00361 { 00362 for( int i=0 ; i<n_modules ; i++ ) 00363 if( !(modules[i]->bpropDoesNothing()) ) 00364 return false; 00365 return true; 00366 } 00367 00369 // setLearningRate // 00371 void ModuleStackModule::setLearningRate(real dynamic_learning_rate) 00372 { 00373 for( int i=0 ; i<n_modules ; i++ ) 00374 modules[i]->setLearningRate( dynamic_learning_rate ); 00375 } 00376 00377 } // end of namespace PLearn 00378 00379 00380 /* 00381 Local Variables: 00382 mode:c++ 00383 c-basic-offset:4 00384 c-file-style:"stroustrup" 00385 c-file-offsets:((innamespace . 0)(inline-open . 0)) 00386 indent-tabs-mode:nil 00387 fill-column:79 00388 End: 00389 */ 00390 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :