PLearn 0.1
|
00001 // -*- C++ -*- 00002 00003 // StackedModulesModule.cc 00004 // 00005 // Copyright (C) 2006 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 "StackedModulesModule.h" 00042 00043 namespace PLearn { 00044 using namespace std; 00045 00046 PLEARN_IMPLEMENT_OBJECT( 00047 StackedModulesModule, 00048 "Wraps a stack of OnlineLearningModule, which are layers", 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 StackedModulesModule::StackedModulesModule() : 00054 last_layer_is_cost( false ), 00055 target_size( 0 ), 00056 nmodules( 0 ) 00057 { 00058 } 00059 00060 void StackedModulesModule::declareOptions(OptionList& ol) 00061 { 00062 /* 00063 declareOption(ol, "", &StackedModulesModule::, 00064 OptionBase::buildoption, 00065 ""); 00066 */ 00067 declareOption(ol, "modules", &StackedModulesModule::modules, 00068 OptionBase::buildoption, 00069 "Underlying layers of the Module"); 00070 00071 declareOption(ol, "last_layer_is_cost", 00072 &StackedModulesModule::last_layer_is_cost, 00073 OptionBase::buildoption, 00074 "Indicates if the last layer is a cost layer (taking input" 00075 " and target\n" 00076 "as input, and outputing the cost we will minimize)," 00077 " allowing this\n" 00078 "module to behave the same way.\n"); 00079 00080 declareOption(ol, "target_size", &StackedModulesModule::target_size, 00081 OptionBase::buildoption, 00082 "If last_layer_is_cost, the size of the target"); 00083 00084 declareOption(ol, "nmodules", &StackedModulesModule::nmodules, 00085 OptionBase::learntoption, 00086 "Number of module layers"); 00087 00088 // Now call the parent class' declareOptions 00089 inherited::declareOptions(ol); 00090 } 00091 00092 void StackedModulesModule::build_() 00093 { 00094 // initialize random generator from seed 00095 if( !random_gen ) 00096 random_gen = new PRandom(); 00097 else 00098 random_gen->manual_seed( random_gen->seed_ ); 00099 00100 // get some options 00101 nmodules = modules.length(); 00102 if( nmodules == 0 ) 00103 return; 00104 00105 if( last_layer_is_cost && target_size <= 0 ) 00106 PLERROR("StackedModulesModule::build_() - Please provide a target_size" 00107 " > 0\n" 00108 "(is '%d').\n", target_size ); 00109 if( !last_layer_is_cost ) 00110 target_size = 0; 00111 00112 PLASSERT( modules[0]->input_size >= 0 ); 00113 input_size = modules[0]->input_size + target_size; 00114 00115 // int last_module_output_size = modules[nmodules-1]->output_size; 00116 // if( last_layer_is_cost ) 00117 // last_module_output_size = 1; 00118 00119 output_size = modules[nmodules-1]->output_size; 00120 00121 // build the modules 00122 buildLayers(); 00123 00124 } 00125 00126 void StackedModulesModule::buildLayers() 00127 { 00128 // first values will be "input" values 00129 int size = input_size - target_size; 00130 values.resize( nmodules+1 ); 00131 values[0].resize( size ); 00132 gradients.resize( nmodules+1 ); 00133 gradients[0].resize( size ); 00134 // TODO: use it only if we actually use bbprop? 00135 diag_hessians.resize( nmodules+1 ); 00136 diag_hessians[0].resize( size ); 00137 00138 for( int i=0 ; i<nmodules ; i++ ) 00139 { 00140 modules[i]->estimate_simpler_diag_hessian = 00141 estimate_simpler_diag_hessian; 00142 modules[i]->random_gen = random_gen; 00143 modules[i]->build(); 00144 00145 size = modules[i]->output_size; 00146 values[i+1].resize( size ); 00147 gradients[i+1].resize( size ); 00148 diag_hessians[i+1].resize( size ); 00149 } 00150 00151 // stores the input of the last module, and the target if there is one 00152 cost_layer_input = values[nmodules-1]; 00153 if( last_layer_is_cost ) 00154 cost_layer_input.resize( cost_layer_input.size() + target_size ); 00155 } 00156 00157 void StackedModulesModule::build() 00158 { 00159 inherited::build(); 00160 build_(); 00161 } 00162 00163 00164 void StackedModulesModule::makeDeepCopyFromShallowCopy(CopiesMap& copies) 00165 { 00166 inherited::makeDeepCopyFromShallowCopy(copies); 00167 00168 deepCopyField(modules, copies); 00169 deepCopyField(values, copies); 00170 deepCopyField(cost_layer_input, copies); 00171 deepCopyField(gradients, copies); 00172 deepCopyField(diag_hessians, copies); 00173 } 00174 00176 void StackedModulesModule::fprop(const Vec& input, Vec& output) const 00177 { 00178 PLASSERT( input.size() == input_size ); 00179 PLASSERT( modules[0]->input_size + target_size == input_size ); 00180 int last_input_size = values[nmodules-1].size(); 00181 00182 values[0] << input.subVec(0, input_size - target_size ); 00183 00184 for( int i=0 ; i<nmodules-1 ; i++ ) 00185 modules[i]->fprop( values[i], values[i+1] ); 00186 00187 if( last_layer_is_cost ) 00188 { 00189 cost_layer_input.subVec( last_input_size, target_size ) 00190 << input.subVec( input_size - target_size, target_size ); 00191 } 00192 00193 modules[nmodules-1]->fprop( cost_layer_input, values[nmodules] ); 00194 output.resize( output_size ); 00195 output << values[ nmodules ]; 00196 } 00197 00200 void StackedModulesModule::bpropUpdate(const Vec& input, const Vec& output, 00201 Vec& input_gradient, 00202 const Vec& output_gradient) 00203 { 00204 // If last_layer_is_cost, the gradient wrt it is 1 00205 if( last_layer_is_cost ) 00206 gradients[nmodules][0] = 1; 00207 else 00208 gradients[nmodules] << output_gradient; 00209 00210 // values should have the values given by fprop(), so 00211 // values[nmodules] should already be equal to output 00212 modules[nmodules-1]->bpropUpdate( cost_layer_input, values[nmodules], 00213 gradients[nmodules-1], 00214 gradients[nmodules] ); 00215 00216 for( int i=nmodules-2 ; i>=0 ; i-- ) 00217 modules[i]->bpropUpdate( values[i], values[i+1], 00218 gradients[i], gradients[i+1] ); 00219 00220 input_gradient = gradients[0].copy(); 00221 } 00222 00225 void StackedModulesModule::forget() 00226 { 00227 random_gen->manual_seed( random_gen->seed_ ); 00228 00229 // reset inputs 00230 values[0].clear(); 00231 gradients[0].clear(); 00232 diag_hessians[0].clear(); 00233 00234 // reset modules and outputs 00235 for( int i=0 ; i<nmodules ; i++ ) 00236 { 00237 modules[i]->forget(); 00238 values[i+1].clear(); 00239 gradients[i+1].clear(); 00240 diag_hessians[i+1].clear(); 00241 } 00242 } 00243 00244 /* THIS METHOD IS OPTIONAL 00249 void StackedModulesModule::finalize() 00250 { 00251 } 00252 */ 00253 00260 void StackedModulesModule::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 { 00266 // If last_layer_is_cost, the gradient wrt it is 1 and hessian is 0 00267 if( last_layer_is_cost ) 00268 { 00269 gradients[nmodules][0] = 1; 00270 diag_hessians[nmodules][0] = 1; 00271 } 00272 else 00273 { 00274 gradients[nmodules] << output_gradient; 00275 diag_hessians[nmodules] << output_diag_hessian; 00276 } 00277 00278 // values should have the values given by fprop(), so 00279 // values[nmodules] should already be equal to output 00280 for( int i=nmodules-1 ; i>=0 ; i-- ) 00281 modules[i]->bbpropUpdate( values[i], values[i+1], 00282 gradients[i], gradients[i+1], 00283 diag_hessians[i], diag_hessians[i+1] ); 00284 00285 input_gradient = gradients[0].copy(); 00286 input_diag_hessian = diag_hessians[0].copy(); 00287 } 00288 00289 00290 } // end of namespace PLearn 00291 00292 00293 /* 00294 Local Variables: 00295 mode:c++ 00296 c-basic-offset:4 00297 c-file-style:"stroustrup" 00298 c-file-offsets:((innamespace . 0)(inline-open . 0)) 00299 indent-tabs-mode:nil 00300 fill-column:79 00301 End: 00302 */ 00303 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :