PLearn 0.1
Subsampling2DModule.cc
Go to the documentation of this file.
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 :
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines