PLearn 0.1
|
00001 // -*- C++ -*- 00002 00003 // Subsampling2DModule.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 00040 #define PL_LOG_MODULE_NAME "Subsampling2DModule" 00041 00042 #include "Subsampling2DModule.h" 00043 #include <plearn/math/convolutions.h> 00044 #include <plearn/math/TMat_maths.h> 00045 #include <plearn/io/pl_log.h> 00046 00047 namespace PLearn { 00048 using namespace std; 00049 00050 PLEARN_IMPLEMENT_OBJECT( 00051 Subsampling2DModule, 00052 "Apply convolution filters on (possibly multiple) 2D inputs (images)", 00053 ""); 00054 00055 Subsampling2DModule::Subsampling2DModule() : 00056 n_input_images(1), 00057 input_images_length(-1), 00058 input_images_width(-1), 00059 kernel_length(-1), 00060 kernel_width(-1), 00061 start_learning_rate(0.), 00062 decrease_constant(0.), 00063 output_images_length(-1), 00064 output_images_width(-1), 00065 input_images_size(-1), 00066 output_images_size(-1), 00067 kernel_size(-1), 00068 learning_rate(0.), 00069 step_number(0) 00070 { 00071 } 00072 00073 void Subsampling2DModule::declareOptions(OptionList& ol) 00074 { 00075 // declareOption(ol, "myoption", &Subsampling2DModule::myoption, 00076 // OptionBase::buildoption, 00077 // "Help text describing this option"); 00078 00079 declareOption(ol, "n_input_images", &Subsampling2DModule::n_input_images, 00080 OptionBase::buildoption, 00081 "Number of input images present at the same time in the" 00082 " input vector"); 00083 00084 declareOption(ol, "input_images_length", 00085 &Subsampling2DModule::input_images_length, 00086 OptionBase::buildoption, 00087 "Length of each of the input images"); 00088 00089 declareOption(ol, "input_images_width", 00090 &Subsampling2DModule::input_images_width, 00091 OptionBase::buildoption, 00092 "Width of each of the input images"); 00093 00094 declareOption(ol, "kernel_length", &Subsampling2DModule::kernel_length, 00095 OptionBase::buildoption, 00096 "Length of the areas to sum" 00097 ); 00098 00099 declareOption(ol, "kernel_width", &Subsampling2DModule::kernel_width, 00100 OptionBase::buildoption, 00101 "Width of the areas to sum" 00102 ); 00103 00104 declareOption(ol, "start_learning_rate", 00105 &Subsampling2DModule::start_learning_rate, 00106 OptionBase::buildoption, 00107 "Starting learning-rate, by which we multiply the gradient" 00108 " step" 00109 ); 00110 00111 declareOption(ol, "decrease_constant", 00112 &Subsampling2DModule::decrease_constant, 00113 OptionBase::buildoption, 00114 "learning_rate = start_learning_rate / (1 +" 00115 " decrease_constant*t),\n" 00116 "where t is the number of updates since the beginning\n" 00117 ); 00118 00119 declareOption(ol, "output_images_length", 00120 &Subsampling2DModule::output_images_length, 00121 OptionBase::learntoption, 00122 "Length of the output images"); 00123 00124 declareOption(ol, "output_images_width", 00125 &Subsampling2DModule::output_images_width, 00126 OptionBase::learntoption, 00127 "Width of the output images"); 00128 00129 declareOption(ol, "scale", &Subsampling2DModule::scale, 00130 OptionBase::learntoption, 00131 "Contains the scale of the output images"); 00132 00133 declareOption(ol, "bias", &Subsampling2DModule::bias, 00134 OptionBase::learntoption, 00135 "Contains the bias of the output images"); 00136 00137 00138 // Now call the parent class' declareOptions 00139 inherited::declareOptions(ol); 00140 00141 // Redeclare some of the parent's options as learntoptions 00142 redeclareOption(ol, "input_size", &Subsampling2DModule::input_size, 00143 OptionBase::learntoption, 00144 "Size of the input, computed from n_input_images,\n" 00145 "input_images_length and input_images_width.\n"); 00146 00147 redeclareOption(ol, "output_size", &Subsampling2DModule::output_size, 00148 OptionBase::learntoption, 00149 "Size of the output, computed from n_output_images,\n" 00150 "output_images_length and output_images_width.\n"); 00151 } 00152 00153 void Subsampling2DModule::build_() 00154 { 00155 MODULE_LOG << "build_() called" << endl; 00156 00157 // Verify the parameters 00158 if( n_input_images < 1 ) 00159 PLERROR("Subsampling2DModule::build_: 'n_input_images' < 1 (%i).\n", 00160 n_input_images); 00161 00162 if( input_images_length < 0 ) 00163 PLERROR("Subsampling2DModule::build_: 'input_images_length'<0 (%i).\n", 00164 input_images_length); 00165 00166 if( input_images_width < 0 ) 00167 PLERROR("Subsampling2DModule::build_: 'input_images_width'<0 (%i).\n", 00168 input_images_width); 00169 00170 if( kernel_length < 0 ) 00171 PLERROR("Subsampling2DModule::build_: 'kernel_length'<0 (%i).\n", 00172 kernel_length); 00173 00174 if( kernel_width < 0 ) 00175 PLERROR("Subsampling2DModule::build_: 'kernel_width'<0 (%i).\n", 00176 kernel_width); 00177 00178 if( input_images_length % kernel_length != 0 ) 00179 PLERROR("Subsampling2DModule::build_: input_images_length (%i)\n" 00180 "should be a multiple of kernel_length (%i).\n", 00181 input_images_length, kernel_length); 00182 00183 if( input_images_width % kernel_width != 0 ) 00184 PLERROR("Subsampling2DModule::build_: input_images_width (%i)\n" 00185 "should be a multiple of kernel_width (%i).\n", 00186 input_images_width, kernel_width); 00187 00188 // Build the learntoptions from the buildoptions 00189 input_images_size = input_images_length * input_images_width; 00190 input_size = n_input_images * input_images_size; 00191 00192 output_images_length = input_images_length / kernel_length; 00193 output_images_width = input_images_width / kernel_width; 00194 output_images_size = output_images_length * output_images_width; 00195 output_size = n_input_images * output_images_size; 00196 00197 kernel_size = kernel_length * kernel_width; 00198 00199 scale.resize(n_input_images); 00200 bias.resize(n_input_images); 00201 00202 input_images.resize(n_input_images); 00203 output_images.resize(n_input_images); 00204 kernel.resize(kernel_length, kernel_width); 00205 input_gradients.resize(n_input_images); 00206 output_gradients.resize(n_input_images); 00207 kernel_gradient.resize(kernel_length, kernel_width); 00208 } 00209 00210 void Subsampling2DModule::build() 00211 { 00212 inherited::build(); 00213 build_(); 00214 } 00215 00216 00217 void Subsampling2DModule::makeDeepCopyFromShallowCopy(CopiesMap& copies) 00218 { 00219 inherited::makeDeepCopyFromShallowCopy(copies); 00220 00221 deepCopyField(scale, copies); 00222 deepCopyField(bias, copies); 00223 deepCopyField(input_images, copies); 00224 deepCopyField(output_images, copies); 00225 deepCopyField(input_gradients, copies); 00226 deepCopyField(output_gradients, copies); 00227 deepCopyField(kernel, copies); 00228 deepCopyField(squared_kernel, copies); 00229 deepCopyField(kernel_gradient, copies); 00230 00231 } 00232 00234 void Subsampling2DModule::fprop(const Vec& input, Vec& output) const 00235 { 00236 // Check size 00237 if( input.size() != input_size ) 00238 PLERROR("Subsampling2DModule::fprop: input.size() should be equal to\n" 00239 "input_size (%i != %i).\n", input.size(), input_size); 00240 output.resize(output_size); 00241 00242 // Make input_images and output_images point to the right places 00243 for( int i=0 ; i<n_input_images ; i++ ) 00244 { 00245 input_images[i] = 00246 input.subVec(i*input_images_size, input_images_size) 00247 .toMat( input_images_length, input_images_width ); 00248 00249 output_images[i] = 00250 output.subVec(i*output_images_size, output_images_size) 00251 .toMat( output_images_length, output_images_width ); 00252 } 00253 00254 // Compute the values of the output_images 00255 for( int i=0 ; i<n_input_images ; i++ ) 00256 { 00257 output_images[i].fill( bias[i] ); 00258 kernel.fill( scale[i] ); 00259 convolve2D( input_images[i], kernel, output_images[i], 00260 kernel_length, kernel_width, true ); 00261 } 00262 } 00263 00264 /* THIS METHOD IS OPTIONAL 00275 void Subsampling2DModule::bpropUpdate(const Vec& input, const Vec& output, 00276 const Vec& output_gradient) 00277 { 00278 } 00279 */ 00280 00282 void Subsampling2DModule::bpropUpdate(const Vec& input, const Vec& output, 00283 Vec& input_gradient, 00284 const Vec& output_gradient, 00285 bool accumulate) 00286 { 00287 // Check size 00288 if( input.size() != input_size ) 00289 PLERROR("Subsampling2DModule::bpropUpdate: input.size() should be\n" 00290 "equal to input_size (%i != %i).\n", input.size(), input_size); 00291 if( output.size() != output_size ) 00292 PLERROR("Subsampling2DModule::bpropUpdate: output.size() should be\n" 00293 "equal to output_size (%i != %i).\n", 00294 output.size(), output_size); 00295 if( output_gradient.size() != output_size ) 00296 PLERROR("Subsampling2DModule::bpropUpdate: output_gradient.size()" 00297 " should be\n" 00298 "equal to output_size (%i != %i).\n", 00299 output_gradient.size(), output_size); 00300 00301 if( accumulate ) 00302 { 00303 PLASSERT_MSG( input_gradient.size() == input_size, 00304 "Cannot resize input_gradient AND accumulate into it" ); 00305 } 00306 else 00307 input_gradient.resize(input_size); 00308 00309 // Since fprop() has just been called, we assume that input_images, 00310 // output_images and gradient are up-to-date 00311 // Make input_gradients and output_gradients point to the right places 00312 for( int i=0 ; i<n_input_images ; i++ ) 00313 { 00314 input_gradients[i] = 00315 input_gradient.subVec(i*input_images_size, input_images_size) 00316 .toMat( input_images_length, input_images_width ); 00317 00318 output_gradients[i] = 00319 output_gradient.subVec(i*output_images_size, output_images_size) 00320 .toMat( output_images_length, output_images_width ); 00321 } 00322 00323 // Do the actual bprop and update 00324 learning_rate = start_learning_rate / (1+decrease_constant*step_number); 00325 for( int i=0 ; i<n_input_images ; i++ ) 00326 { 00327 kernel.fill( scale[i] ); 00328 kernel_gradient.clear(); 00329 convolve2Dbackprop( input_images[i], kernel, 00330 output_gradients[i], 00331 input_gradients[i], kernel_gradient, 00332 kernel_length, kernel_width, accumulate ); 00333 00334 // The scale's gradient is the sum of contributions to kernel_gradient 00335 scale[i] -= learning_rate * sum( kernel_gradient ); 00336 bias[i] -= learning_rate * sum( output_gradients[i] ); 00337 } 00338 step_number++; 00339 } 00340 00343 void Subsampling2DModule::forget() 00344 { 00345 bias.clear(); 00346 00347 if( !random_gen ) 00348 { 00349 PLWARNING( "Subsampling2DModule: cannot forget() without random_gen" ); 00350 return; 00351 } 00352 real scale_factor = 1./(kernel_length*kernel_width); 00353 random_gen->fill_random_uniform( scale, -scale_factor, scale_factor ); 00354 } 00355 00356 /* THIS METHOD IS OPTIONAL 00361 void Subsampling2DModule::finalize() 00362 { 00363 } 00364 */ 00365 00366 /* THIS METHOD IS OPTIONAL 00369 bool Subsampling2DModule::bpropDoesNothing() 00370 { 00371 } 00372 */ 00373 00374 /* THIS METHOD IS OPTIONAL 00384 void Subsampling2DModule::bbpropUpdate(const Vec& input, const Vec& output, 00385 const Vec& output_gradient, 00386 const Vec& output_diag_hessian) 00387 { 00388 } 00389 */ 00390 00395 void Subsampling2DModule::bbpropUpdate(const Vec& input, const Vec& output, 00396 Vec& input_gradient, 00397 const Vec& output_gradient, 00398 Vec& input_diag_hessian, 00399 const Vec& output_diag_hessian, 00400 bool accumulate) 00401 { 00402 // This version forwards the second order information, but does not 00403 // actually use it for the update. 00404 00405 // Check size 00406 if( output_diag_hessian.size() != output_size ) 00407 PLERROR("Subsampling2DModule::bbpropUpdate: output_diag_hessian.size()" 00408 "\n" 00409 "should be equal to output_size (%i != %i).\n", 00410 output_diag_hessian.size(), output_size); 00411 00412 if( accumulate ) 00413 { 00414 PLASSERT_MSG( input_diag_hessian.size() == input_size, 00415 "Cannot resize input_diag_hessian AND accumulate into it" 00416 ); 00417 } 00418 else 00419 input_diag_hessian.resize(input_size); 00420 00421 // Make input_diag_hessians and output_diag_hessians point to the right 00422 // places 00423 for( int i=0 ; i<n_input_images ; i++ ) 00424 { 00425 input_diag_hessians[i] = 00426 input_diag_hessian.subVec(i*input_images_size, input_images_size) 00427 .toMat( input_images_length, input_images_width ); 00428 00429 output_diag_hessians[i] = 00430 output_diag_hessian.subVec(i*output_images_size,output_images_size) 00431 .toMat( output_images_length, output_images_width ); 00432 } 00433 00434 // Propagates to input_diag_hessian 00435 for( int i=0 ; i<n_input_images ; i++ ) 00436 { 00437 kernel.fill( scale[i] ); 00438 squared_kernel.fill( scale[i]*scale[i] ); 00439 backConvolve2D( input_diag_hessians[i], squared_kernel, 00440 output_diag_hessians[i], 00441 kernel_length, kernel_width, accumulate ); 00442 } 00443 00444 // Call bpropUpdate() 00445 bpropUpdate( input, output, input_gradient, output_gradient ); 00446 } 00447 00448 00449 } // end of namespace PLearn 00450 00451 00452 /* 00453 Local Variables: 00454 mode:c++ 00455 c-basic-offset:4 00456 c-file-style:"stroustrup" 00457 c-file-offsets:((innamespace . 0)(inline-open . 0)) 00458 indent-tabs-mode:nil 00459 fill-column:79 00460 End: 00461 */ 00462 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :