PLearn 0.1
MaxSubsampling2DModule.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 // MaxSubsampling2DModule.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 
00040 #define PL_LOG_MODULE_NAME "MaxSubsampling2DModule"
00041 
00042 #include "MaxSubsampling2DModule.h"
00043 #include <plearn/io/pl_log.h>
00044 
00045 namespace PLearn {
00046 using namespace std;
00047 
00048 PLEARN_IMPLEMENT_OBJECT(
00049     MaxSubsampling2DModule,
00050     "Reduce the size of the 2D images by taking the max value of nearby pixels",
00051     "");
00052 
00053 MaxSubsampling2DModule::MaxSubsampling2DModule():
00054     n_input_images(1),
00055     input_images_length(-1),
00056     input_images_width(-1),
00057     kernel_length(-1),
00058     kernel_width(-1),
00059     output_images_length(-1),
00060     output_images_width(-1),
00061     input_images_size(-1),
00062     output_images_size(-1)
00063 {
00064 }
00065 
00066 void MaxSubsampling2DModule::declareOptions(OptionList& ol)
00067 {
00068     declareOption(ol, "n_input_images",
00069                   &MaxSubsampling2DModule::n_input_images,
00070                   OptionBase::buildoption,
00071                   "Number of input images present at the same time in the"
00072                   " input vector");
00073 
00074     declareOption(ol, "input_images_length",
00075                   &MaxSubsampling2DModule::input_images_length,
00076                   OptionBase::buildoption,
00077                   "Length of each of the input images");
00078 
00079     declareOption(ol, "input_images_width",
00080                   &MaxSubsampling2DModule::input_images_width,
00081                   OptionBase::buildoption,
00082                   "Width of each of the input images");
00083 
00084     declareOption(ol, "kernel_length", &MaxSubsampling2DModule::kernel_length,
00085                   OptionBase::buildoption,
00086                   "Length of the areas to maximize over");
00087 
00088     declareOption(ol, "kernel_width", &MaxSubsampling2DModule::kernel_width,
00089                   OptionBase::buildoption,
00090                   "Width of the areas to maximize over");
00091 
00092     declareOption(ol, "output_images_length",
00093                   &MaxSubsampling2DModule::output_images_length,
00094                   OptionBase::learntoption,
00095                   "Length of the output images");
00096 
00097     declareOption(ol, "output_images_width",
00098                   &MaxSubsampling2DModule::output_images_width,
00099                   OptionBase::learntoption,
00100                   "Width of the output images");
00101 
00102     // declareOption(ol, "", &MaxSubsampling2DModule::,
00103     //               OptionBase::buildoption,
00104     //               "");
00105 
00106     // Now call the parent class' declareOptions
00107     inherited::declareOptions(ol);
00108 
00109 
00110     redeclareOption(ol, "input_size", &MaxSubsampling2DModule::input_size,
00111                     OptionBase::learntoption,
00112                     "Size of the input, computed from n_input_images,\n"
00113                     "input_images_length and input_images_width.\n");
00114 
00115     redeclareOption(ol, "output_size", &MaxSubsampling2DModule::output_size,
00116                     OptionBase::learntoption,
00117                     "Size of the output, computed from n_input_images,\n"
00118                     "output_images_length and output_images_width.\n");
00119 
00120 }
00121 
00122 void MaxSubsampling2DModule::build_()
00123 {
00124     MODULE_LOG << "build_() called" << endl;
00125 
00126     // Build the learntoptions from the buildoptions
00127     input_images_size = input_images_length * input_images_width;
00128     input_size = n_input_images * input_images_size;
00129 
00130     PLCHECK( n_input_images > 0 );
00131     PLCHECK( input_images_length > 0 );
00132     PLCHECK( input_images_width > 0 );
00133     PLCHECK( kernel_length > 0 );
00134     PLCHECK( kernel_width > 0 );
00135     PLCHECK_MSG( input_images_length % kernel_length == 0,
00136                  "input_images_length should be a multiple of kernel_length" );
00137     PLCHECK_MSG( input_images_width % kernel_width == 0,
00138                  "input_images_width should be a multiple of kernel_width" );
00139 
00140     output_images_length = input_images_length / kernel_length;
00141     output_images_width = input_images_width / kernel_width;
00142     output_images_size = output_images_length * output_images_width;
00143     output_size = n_input_images * output_images_size;
00144 
00145     // build ports
00146     ports.resize(3);
00147     ports[0] = "input";
00148     ports[1] = "output";
00149     ports[2] = "argmax.state";
00150 
00151     // build port_sizes
00152     port_sizes.resize(nPorts(), 2);
00153     port_sizes.column(0).fill(-1);
00154     port_sizes(0, 1) = input_size;
00155     port_sizes(1, 1) = output_size;
00156     port_sizes(2, 1) = output_size;
00157 }
00158 
00159 // ### Nothing to add here, simply calls build_
00160 void MaxSubsampling2DModule::build()
00161 {
00162     inherited::build();
00163     build_();
00164 }
00165 
00166 
00167 void MaxSubsampling2DModule::makeDeepCopyFromShallowCopy(CopiesMap& copies)
00168 {
00169     inherited::makeDeepCopyFromShallowCopy(copies);
00170 
00171     deepCopyField(ports, copies);
00172 }
00173 
00175 // fprop //
00177 void MaxSubsampling2DModule::fprop(const TVec<Mat*>& ports_value)
00178 {
00179     PLASSERT( ports_value.length() == nPorts() );
00180     // check which ports are input
00181     // (ports_value[i] && !ports_value[i]->isEmpty())
00182     // which ports are output (ports_value[i] && ports_value[i]->isEmpty())
00183     // and which ports are ignored (!ports_value[i]).
00184     // If that combination of (input,output,ignored) is feasible by this class
00185     // then perform the corresponding computation. Otherwise launch the error
00186     // below. See the comment in the header file for more information.
00187 
00188     Mat* input = ports_value[0];
00189     Mat* output = ports_value[1];
00190     Mat* argmax = ports_value[2];
00191 
00192     if( input && !input->isEmpty()
00193         && output && output->isEmpty()
00194         && argmax && argmax->isEmpty() )
00195     {
00196         PLASSERT( input->width() == port_sizes(0,1) );
00197 
00198         int batch_size = input->length();
00199         output->resize(batch_size, port_sizes(1,1));
00200         argmax->resize(batch_size, port_sizes(2,1));
00201 
00202         for( int k=0; k<batch_size; k++ )
00203             for( int l=0; l<n_input_images; l++ )
00204             {
00205                 Mat input_image_kl = (*input)(k)
00206                     .subVec(l*input_images_size, input_images_size)
00207                     .toMat(input_images_length, input_images_width);
00208                 Mat output_image_kl = (*output)(k)
00209                     .subVec(l*output_images_size, output_images_size)
00210                     .toMat(output_images_length, output_images_width);
00211                 Mat argmax_kl = (*argmax)(k)
00212                     .subVec(l*output_images_size, output_images_size)
00213                     .toMat(output_images_length, output_images_width);
00214 
00215                 for( int i=0; i<output_images_length; i++ )
00216                     for( int j=0; j<output_images_width; j++ )
00217                     {
00218                         int argmax_i, argmax_j;
00219                         output_image_kl(i,j) = max(
00220                             input_image_kl.subMat(i*kernel_length,
00221                                                    j*kernel_width,
00222                                                    kernel_length,
00223                                                    kernel_width),
00224                             argmax_i, argmax_j );
00225                         argmax_kl(i,j) = argmax_i*input_images_width+argmax_j;
00226                     }
00227             }
00228     }
00229     else
00230         PLCHECK_MSG( false, "Unknown port configuration" );
00231 }
00232 
00234 // bpropAccUpdate //
00236 void MaxSubsampling2DModule::bpropAccUpdate(const TVec<Mat*>& ports_value,
00237                                             const TVec<Mat*>& ports_gradient)
00238 {
00239     PLASSERT( ports_value.length() == nPorts()
00240               && ports_gradient.length() == nPorts() );
00241     // check which ports are input
00242     // (ports_value[i] && !ports_value[i]->isEmpty())
00243     // which ports are output (ports_value[i] && ports_value[i]->isEmpty())
00244     // and which ports are ignored (!ports_value[i]).
00245     // A similar logic applies to ports_gradients (to know whether gradient
00246     // is coming into the module of coming from the module through a given
00247     // ports_gradient[i]).
00248     // An input port_value should correspond to an outgoing port_gradient,
00249     // an output port_value could either correspond to an incoming
00250     // port_gradient (when that gradient is to be propagated inside and to the
00251     // input ports) or it should be null (no gradient is propagated from that
00252     // output port).
00253 
00254     Mat* input = ports_value[0];
00255 #ifdef BOUNDCHECK
00256     Mat* output = ports_value[1];
00257 #endif
00258     Mat* argmax = ports_value[2];
00259     Mat* input_grad = ports_gradient[0];
00260     Mat* output_grad = ports_gradient[1];
00261 #ifdef BOUNDCHECK
00262     Mat* argmax_grad = ports_gradient[2];
00263 #endif
00264 
00265     // If we want input_grad and we have output_grad
00266     if( input_grad && input_grad->isEmpty()
00267         && output_grad && !output_grad->isEmpty() )
00268     {
00269         PLASSERT( input );
00270         PLASSERT( output );
00271         PLASSERT( argmax );
00272         PLASSERT( !argmax_grad );
00273 
00274         PLASSERT( input->width() == port_sizes(0,1) );
00275         PLASSERT( output->width() == port_sizes(1,1) );
00276         PLASSERT( argmax->width() == port_sizes(2,1) );
00277         PLASSERT( input_grad->width() == port_sizes(0,1) );
00278         PLASSERT( output_grad->width() == port_sizes(1,1) );
00279 
00280         int batch_size = input->length();
00281         PLASSERT( output->length() == batch_size );
00282         PLASSERT( argmax->length() == batch_size );
00283         PLASSERT( output_grad->length() == batch_size );
00284 
00285         input_grad->resize(batch_size, port_sizes(0,1));
00286 
00287         for( int k=0; k<batch_size; k++ )
00288             for( int l=0; l<n_input_images; l++ )
00289             {
00290                 Mat input_grad_image_kl = (*input_grad)(k)
00291                     .subVec(l*input_images_size, input_images_size)
00292                     .toMat(input_images_length, input_images_width);
00293                 Mat output_grad_image_kl = (*output_grad)(k)
00294                     .subVec(l*output_images_size, output_images_size)
00295                     .toMat(output_images_length, output_images_width);
00296                 Mat argmax_kl = (*argmax)(k)
00297                     .subVec(l*output_images_size, output_images_size)
00298                     .toMat(output_images_length, output_images_width);
00299 
00300                 for( int i=0; i<output_images_length; i++ )
00301                     for( int j=0; j<output_images_width; j++ )
00302                     {
00303                         Mat input_grad_zone = input_grad_image_kl
00304                             .subMat(i*kernel_length, j*kernel_width,
00305                                     kernel_length, kernel_width);
00306 
00307                         int argmax_klij = (int) round(argmax_kl(i,j));
00308                         input_grad_zone.data()[argmax_klij] =
00309                             output_grad_image_kl(i,j);
00310                     }
00311             }
00312     }
00313     else
00314         PLERROR("In MaxSubsampling2DModule::bpropAccUpdate - this configuration of ports not implemented for class "
00315             "'%s'", classname().c_str());
00316 }
00317 
00318 
00320 // forget //
00322 void MaxSubsampling2DModule::forget()
00323 {
00324 }
00325 
00327 // finalize //
00329 /* THIS METHOD IS OPTIONAL
00330 void MaxSubsampling2DModule::finalize()
00331 {
00332 }
00333 */
00334 
00336 // bpropDoesNothing //
00338 /* THIS METHOD IS OPTIONAL
00339 // the default implementation returns false
00340 bool MaxSubsampling2DModule::bpropDoesNothing()
00341 {
00342 }
00343 */
00344 
00346 // setLearningRate //
00348 void MaxSubsampling2DModule::setLearningRate(real dynamic_learning_rate)
00349 {
00350     // Do nothing.
00351 }
00352 
00354 // getPorts //
00356 const TVec<string>& MaxSubsampling2DModule::getPorts()
00357 {
00358     return ports;
00359 }
00360 
00362 // getPortSizes //
00364 const TMat<int>& MaxSubsampling2DModule::getPortSizes()
00365 {
00366     return port_sizes;
00367 }
00368 
00369 }
00370 // end of namespace PLearn
00371 
00372 
00373 /*
00374   Local Variables:
00375   mode:c++
00376   c-basic-offset:4
00377   c-file-style:"stroustrup"
00378   c-file-offsets:((innamespace . 0)(inline-open . 0))
00379   indent-tabs-mode:nil
00380   fill-column:79
00381   End:
00382 */
00383 // 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