PLearn 0.1
Convolution2DModule.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 // Convolution2DModule.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 "Convolution2DModule"
00041 
00042 #include "Convolution2DModule.h"
00043 #include <plearn/math/convolutions.h>
00044 #include <plearn/math/TMat_maths.h>
00045 #include <plearn/sys/Profiler.h>
00046 #include <plearn/io/pl_log.h>
00047 
00048 namespace PLearn {
00049 using namespace std;
00050 
00051 PLEARN_IMPLEMENT_OBJECT(
00052     Convolution2DModule,
00053     "Apply convolution filters on (possibly multiple) 2D inputs (images)",
00054     "");
00055 
00056 Convolution2DModule::Convolution2DModule() :
00057     n_input_images(1),
00058     input_images_length(-1),
00059     input_images_width(-1),
00060     n_output_images(1),
00061     kernel_length(-1),
00062     kernel_width(-1),
00063     kernel_step1(1),
00064     kernel_step2(1),
00065     start_learning_rate(0.),
00066     decrease_constant(0.),
00067     output_images_length(-1),
00068     output_images_width(-1),
00069     input_images_size(-1),
00070     output_images_size(-1),
00071     kernel_size(-1),
00072     learning_rate(0.),
00073     step_number(0)
00074 {
00075 }
00076 
00077 void Convolution2DModule::declareOptions(OptionList& ol)
00078 {
00079     // declareOption(ol, "myoption", &Convolution2DModule::myoption,
00080     //               OptionBase::buildoption,
00081     //               "Help text describing this option");
00082 
00083     declareOption(ol, "n_input_images", &Convolution2DModule::n_input_images,
00084                   OptionBase::buildoption,
00085                   "Number of input images present at the same time in the"
00086                   " input vector");
00087 
00088     declareOption(ol, "input_images_length",
00089                   &Convolution2DModule::input_images_length,
00090                   OptionBase::buildoption,
00091                   "Length of each of the input images");
00092 
00093     declareOption(ol, "input_images_width",
00094                   &Convolution2DModule::input_images_width,
00095                   OptionBase::buildoption,
00096                   "Width of each of the input images");
00097 
00098     declareOption(ol, "n_output_images", &Convolution2DModule::n_output_images,
00099                   OptionBase::buildoption,
00100                   "Number of output images to put in the output vector");
00101 
00102     declareOption(ol, "kernel_length", &Convolution2DModule::kernel_length,
00103                   OptionBase::buildoption,
00104                   "Length of each filter (or kernel) applied on an input image"
00105                   );
00106 
00107     declareOption(ol, "kernel_width", &Convolution2DModule::kernel_width,
00108                   OptionBase::buildoption,
00109                   "Width of each filter (or kernel) applied on an input image"
00110                   );
00111 
00112     declareOption(ol, "kernel_step1", &Convolution2DModule::kernel_step1,
00113                   OptionBase::buildoption,
00114                   "Horizontal step of the kernels");
00115 
00116     declareOption(ol, "kernel_step2", &Convolution2DModule::kernel_step2,
00117                   OptionBase::buildoption,
00118                   "Vertical step of the kernels");
00119 
00120     declareOption(ol, "connection_matrix",
00121                   &Convolution2DModule::connection_matrix,
00122                   OptionBase::buildoption,
00123                   "Matrix of connections:\n"
00124                   "it has n_input_images rows and n_output_images columns,\n"
00125                   "each output image will only be connected to a subset of"
00126                   " the\n"
00127                   "input images, where a non-zero value is present in this"
00128                   " matrix.\n"
00129                   "If this matrix is not provided, it will be fully"
00130                   " connected.\n"
00131                   );
00132 
00133     declareOption(ol, "start_learning_rate",
00134                   &Convolution2DModule::start_learning_rate,
00135                   OptionBase::buildoption,
00136                   "Starting learning-rate, by which we multiply the gradient"
00137                   " step"
00138                   );
00139 
00140     declareOption(ol, "decrease_constant",
00141                   &Convolution2DModule::decrease_constant,
00142                   OptionBase::buildoption,
00143                   "learning_rate = start_learning_rate / (1 +"
00144                   " decrease_constant*t),\n"
00145                   "where t is the number of updates since the beginning\n"
00146                   );
00147 
00148     declareOption(ol, "output_images_length",
00149                   &Convolution2DModule::output_images_length,
00150                   OptionBase::learntoption,
00151                   "Length of the output images");
00152 
00153     declareOption(ol, "output_images_width",
00154                   &Convolution2DModule::output_images_width,
00155                   OptionBase::learntoption,
00156                   "Width of the output images");
00157 
00158     declareOption(ol, "kernels", &Convolution2DModule::kernels,
00159                   OptionBase::learntoption,
00160                   "Contains the kernels between input and output images");
00161 
00162     declareOption(ol, "bias", &Convolution2DModule::bias,
00163                   OptionBase::learntoption,
00164                   "Contains the bias of the output images");
00165 
00166 
00167     // Now call the parent class' declareOptions
00168     inherited::declareOptions(ol);
00169 
00170     // Redeclare some of the parent's options as learntoptions
00171     redeclareOption(ol, "input_size", &Convolution2DModule::input_size,
00172                     OptionBase::learntoption,
00173                     "Size of the input, computed from n_input_images,\n"
00174                     "n_input_length and n_input_width.\n");
00175 
00176     redeclareOption(ol, "output_size", &Convolution2DModule::output_size,
00177                     OptionBase::learntoption,
00178                     "Size of the output, computed from n_output_images,\n"
00179                     "n_output_length and n_output_width.\n");
00180 }
00181 
00182 void Convolution2DModule::build_()
00183 {
00184     MODULE_LOG << "build_() called" << endl;
00185 
00186     // Verify the parameters
00187     if( n_input_images < 1 )
00188         PLERROR("Convolution2DModule::build_: 'n_input_images' < 1 (%i).\n",
00189                 n_input_images);
00190 
00191     if( input_images_length < 0 )
00192         PLERROR("Convolution2DModule::build_: 'input_images_length'<0 (%i).\n",
00193                 input_images_length);
00194 
00195     if( input_images_width < 0 )
00196         PLERROR("Convolution2DModule::build_: 'input_images_width'<0 (%i).\n",
00197                 input_images_width);
00198 
00199     if( n_output_images < 1 )
00200         PLERROR("Convolution2DModule::build_: 'n_output_images' < 1 (%i).\n",
00201                 n_input_images);
00202 
00203     if( kernel_length < 0 )
00204         PLERROR("Convolution2DModule::build_: 'kernel_length'<0 (%i).\n",
00205                 kernel_length);
00206 
00207     if( kernel_width < 0 )
00208         PLERROR("Convolution2DModule::build_: 'kernel_width'<0 (%i).\n",
00209                 kernel_width);
00210 
00211     if( kernel_step1 < 0 )
00212         PLERROR("Convolution2DModule::build_: 'kernel_step1'<0 (%i).\n",
00213                 kernel_step1);
00214 
00215     if( kernel_step2 < 0 )
00216         PLERROR("Convolution2DModule::build_: 'kernel_step2'<0 (%i).\n",
00217                 kernel_step2);
00218 
00219     if( (input_images_length - kernel_length) % kernel_step1 != 0 )
00220         PLERROR("Convolution2DModule::build_:\n"
00221                 "the difference (input_images_length - kernel_length) (%i)\n"
00222                 "should be a multiple of kernel_step1 (%i).\n",
00223                 (input_images_length - kernel_length), kernel_step1);
00224 
00225     if( (input_images_width - kernel_width) % kernel_step2 != 0 )
00226         PLERROR("Convolution2DModule::build_:\n"
00227                 "the difference (input_images_width - kernel_width) (%i)\n"
00228                 "should be a multiple of kernel_step2 (%i).\n",
00229                 (input_images_width - kernel_width), kernel_step2);
00230 
00231     // Build the learntoptions from the buildoptions
00232     input_images_size = input_images_length * input_images_width;
00233     input_size = n_input_images * input_images_size;
00234 
00235     output_images_length = (input_images_length-kernel_length)/kernel_step1+1;
00236     output_images_width = (input_images_width - kernel_width)/kernel_step2+1;
00237     output_images_size = output_images_length * output_images_width;
00238     output_size = n_output_images * output_images_size;
00239 
00240     kernel_size = kernel_length * kernel_width;
00241 
00242     bias.resize(n_output_images);
00243 
00244     // If connection_matrix was not specified, or inconsistently,
00245     // make it a matrix full of ones.
00246     if( connection_matrix.length() != n_input_images
00247         || connection_matrix.width() != n_output_images )
00248     {
00249         connection_matrix.resize(n_input_images, n_output_images);
00250         connection_matrix.fill(1);
00251     }
00252 
00253     build_kernels();
00254 
00255     input_images.resize(n_input_images);
00256     output_images.resize(n_output_images);
00257     input_gradients.resize(n_input_images);
00258     output_gradients.resize(n_output_images);
00259     input_diag_hessians.resize(n_input_images);
00260     output_diag_hessians.resize(n_output_images);
00261 
00262     // port stuff
00263     ports.resize(2);
00264     ports[0] = "input";
00265     ports[1] = "output";
00266 
00267     port_sizes.resize(nPorts(), 2);
00268     port_sizes.column(0).fill(-1);
00269     port_sizes(0, 1) = input_size;
00270     port_sizes(1, 1) = output_size;
00271 }
00272 
00273 void Convolution2DModule::build_kernels()
00274 {
00275     // If kernels has the right size, for all i and j kernel(i,j) exists iff
00276     // connection_matrix(i,j) !=0, and has the appropriate size, then we don't
00277     // want to forget them.
00278     bool need_rebuild = false;
00279     if( kernels.length() != n_input_images
00280         || kernels.width() != n_output_images )
00281     {
00282         need_rebuild = true;
00283     }
00284     else
00285     {
00286         for( int i=0 ; i<n_input_images ; i++ )
00287             for( int j=0 ; j<n_output_images ; j++ )
00288             {
00289                 if( connection_matrix(i,j) == 0 )
00290                 {
00291                     if( kernels(i,j).size() != 0 )
00292                     {
00293                         need_rebuild = true;
00294                         break;
00295                     }
00296                 }
00297                 else if( kernels(i,j).length() != kernel_length
00298                          || kernels(i,j).width() != kernel_width )
00299                 {
00300                     need_rebuild = true;
00301                     break;
00302                 }
00303             }
00304     }
00305 
00306     if( need_rebuild )
00307         forget();
00308 
00309     kernel_gradient.resize(kernel_length, kernel_width);
00310     kernel_gradients.resize(n_input_images, n_output_images);
00311     squared_kernel.resize(kernel_length, kernel_width);
00312 }
00313 
00314 void Convolution2DModule::build()
00315 {
00316     inherited::build();
00317     build_();
00318 }
00319 
00320 
00321 void Convolution2DModule::makeDeepCopyFromShallowCopy(CopiesMap& copies)
00322 {
00323     inherited::makeDeepCopyFromShallowCopy(copies);
00324 
00325     deepCopyField(connection_matrix, copies);
00326     deepCopyField(kernels, copies);
00327     deepCopyField(bias, copies);
00328     deepCopyField(input_images, copies);
00329     deepCopyField(output_images, copies);
00330     deepCopyField(input_gradients, copies);
00331     deepCopyField(output_gradients, copies);
00332     deepCopyField(input_diag_hessians, copies);
00333     deepCopyField(output_diag_hessians, copies);
00334     deepCopyField(kernel_gradient, copies);
00335     deepCopyField(squared_kernel, copies);
00336 
00337 }
00338 
00340 void Convolution2DModule::fprop(const Vec& input, Vec& output) const
00341 {
00342     // Check size
00343     if( input.size() != input_size )
00344         PLERROR("Convolution2DModule::fprop: input.size() should be equal to\n"
00345                 "input_size (%i != %i).\n", input.size(), input_size);
00346     output.resize(output_size);
00347 
00348     // Make input_images and output_images point to the right places
00349     for( int i=0 ; i<n_input_images ; i++ )
00350         input_images[i] =
00351             input.subVec(i*input_images_size, input_images_size)
00352                 .toMat( input_images_length, input_images_width );
00353 
00354     for( int j=0 ; j<n_output_images ; j++ )
00355         output_images[j] =
00356             output.subVec(j*output_images_size, output_images_size)
00357                 .toMat( output_images_length, output_images_width );
00358 
00359     // Compute the values of the output_images
00360     for( int j=0 ; j<n_output_images ; j++ )
00361     {
00362         output_images[j].fill( bias[j] );
00363         for( int i=0 ; i<n_input_images ; i++ )
00364         {
00365             if( connection_matrix(i,j) != 0 )
00366                 convolve2D( input_images[i], kernels(i,j), output_images[j],
00367                             kernel_step1, kernel_step2, true );
00368         }
00369     }
00370 }
00371 
00372 void Convolution2DModule::fprop(const TVec<Mat*>& ports_value)
00373 {
00374     Profiler::pl_profile_start( "Convolution2DModule::fprop" );
00375     PLASSERT( ports_value.length() == nPorts() );
00376 
00377     Mat* input = ports_value[0];
00378     Mat* output = ports_value[1];
00379 
00380     if( input && !input->isEmpty() && output && output->isEmpty() )
00381     {
00382         PLASSERT( input->width() == port_sizes(0,1) );
00383 
00384         int batch_size = input->length();
00385         output->resize(batch_size, port_sizes(1,1));
00386 
00387         Profiler::pl_profile_start( "convolve2D" );
00388         // TODO: optimize
00389         for( int k=0; k<batch_size; k++ )
00390         {
00391             for( int i=0; i<n_input_images; i++ )
00392                 input_images[i] = (*input)(k)
00393                     .subVec(i*input_images_size, input_images_size)
00394                     .toMat(input_images_length, input_images_width);
00395 
00396             for( int j=0; j<n_output_images; j++ )
00397                 output_images[j] = (*output)(k)
00398                     .subVec(j*output_images_size, output_images_size)
00399                     .toMat(output_images_length, output_images_width);
00400 
00401             for( int j=0; j<n_output_images; j++ )
00402             {
00403                 output_images[j].fill( bias[j] );
00404                 for( int i=0; i<n_input_images; i++ )
00405                     if( connection_matrix(i,j) != 0 )
00406                         convolve2D( input_images[i], kernels(i,j),
00407                                     output_images[j], kernel_step1,
00408                                     kernel_step2, true );
00409             }
00410         }
00411         Profiler::pl_profile_end( "convolve2D" );
00412     }
00413     else if (!input && !output)
00414     {
00415         // Nothing to do
00416     }
00417     else
00418         PLCHECK_MSG( false, "Unknown port configuration" );
00419 
00420     Profiler::pl_profile_end( "Convolution2DModule::fprop" );
00421 }
00422 
00423 /* THIS METHOD IS OPTIONAL
00434 void Convolution2DModule::bpropUpdate(const Vec& input, const Vec& output,
00435                                const Vec& output_gradient)
00436 {
00437 }
00438 */
00439 
00441 void Convolution2DModule::bpropUpdate(const Vec& input, const Vec& output,
00442                                       Vec& input_gradient,
00443                                       const Vec& output_gradient,
00444                                       bool accumulate)
00445 {
00446     // Check size
00447     if( input.size() != input_size )
00448         PLERROR("Convolution2DModule::bpropUpdate: input.size() should be\n"
00449                 "equal to input_size (%i != %i).\n", input.size(), input_size);
00450     if( output.size() != output_size )
00451         PLERROR("Convolution2DModule::bpropUpdate: output.size() should be\n"
00452                 "equal to output_size (%i != %i).\n",
00453                 output.size(), output_size);
00454     if( output_gradient.size() != output_size )
00455         PLERROR("Convolution2DModule::bpropUpdate: output_gradient.size()"
00456                 " should be\n"
00457                 "equal to output_size (%i != %i).\n",
00458                 output_gradient.size(), output_size);
00459 
00460     if( accumulate )
00461     {
00462         PLASSERT_MSG( input_gradient.size() == input_size,
00463                       "Cannot resize input_gradient AND accumulate into it" );
00464     }
00465     else
00466     {
00467         input_gradient.resize(input_size);
00468         input_gradient.clear();
00469     }
00470 
00471     // Since fprop() has just been called, we assume that input_images and
00472     // output_images are up-to-date
00473     // Make input_gradients and output_gradients point to the right places
00474     for( int i=0 ; i<n_input_images ; i++ )
00475         input_gradients[i] =
00476             input_gradient.subVec(i*input_images_size, input_images_size)
00477                 .toMat( input_images_length, input_images_width );
00478 
00479     for( int j=0 ; j<n_output_images ; j++ )
00480         output_gradients[j] =
00481             output_gradient.subVec(j*output_images_size, output_images_size)
00482                 .toMat( output_images_length, output_images_width );
00483 
00484     // Do the actual bprop and update
00485     learning_rate = start_learning_rate / (1+decrease_constant*step_number);
00486     for( int j=0 ; j<n_output_images ; j++ )
00487     {
00488         for( int i=0 ; i<n_input_images ; i++ )
00489             if( connection_matrix(i,j) != 0 )
00490             {
00491                 kernel_gradient.clear();
00492                 convolve2Dbackprop( input_images[i], kernels(i,j),
00493                                     output_gradients[j],
00494                                     input_gradients[i], kernel_gradient,
00495                                     kernel_step1, kernel_step2, true );
00496 
00497                 // kernel(i,j) -= learning_rate * kernel_gradient
00498                 multiplyAcc( kernels(i,j), kernel_gradient, -learning_rate ); // could be more efficiently done within the convolve2Dbackprop
00499             }
00500         bias[j] -= learning_rate * sum( output_gradients[j] );
00501     }
00502 
00503 }
00504 
00505 void Convolution2DModule::bpropAccUpdate(const TVec<Mat*>& ports_value,
00506                                          const TVec<Mat*>& ports_gradient)
00507 {
00508     Profiler::pl_profile_start("Convolution2DModule::bpropAccUpdate");
00509     PLASSERT( ports_value.length() == nPorts()
00510               && ports_gradient.length() == nPorts() );
00511 
00512     Mat* input = ports_value[0];
00513     Mat* output = ports_value[1];
00514     Mat* input_grad = ports_gradient[0];
00515     Mat* output_grad = ports_gradient[1];
00516 
00517     // If we have output_grad and we want to update
00518     if( output_grad && !output_grad->isEmpty()
00519         && (!input_grad || input_grad->isEmpty() ) )
00520     {
00521         // If we have to compute input_grad
00522         bool compute_input_grad = false;
00523         if( input_grad )
00524             compute_input_grad = true;
00525 
00526         PLASSERT( input );
00527         PLASSERT( output );
00528 
00529         PLASSERT( input->width() == port_sizes(0,1) );
00530         PLASSERT( output->width() == port_sizes(1,1) );
00531         PLASSERT( output_grad->width() == port_sizes(1,1) );
00532         if( compute_input_grad )
00533             PLASSERT( input_grad->width() == port_sizes(0,1) );
00534 
00535         int batch_size = input->length();
00536         PLASSERT( output->length() == batch_size );
00537         PLASSERT( output_grad->length() == batch_size );
00538 
00539         learning_rate = start_learning_rate /
00540             (1.+decrease_constant*step_number);
00541         real avg_lr = learning_rate / batch_size;
00542         if( compute_input_grad )
00543             input_grad->resize(batch_size, port_sizes(0,1));
00544 
00545         // clear kernel gradient
00546         for( int i=0; i<n_input_images; i++ )
00547             for( int j=0; j<n_output_images; j++ )
00548                 if( connection_matrix(i,j) != 0 )
00549                 {
00550                     kernel_gradients(i,j).resize(kernel_length, kernel_width);
00551                     kernel_gradients(i,j).clear();
00552                 }
00553 
00554         // TODO: optimize
00555         if( compute_input_grad )
00556             Profiler::pl_profile_start("convolve2Dbackprop");
00557         else
00558             Profiler::pl_profile_start("convolve2Dbackprop (update only)");
00559 
00560         for( int k=0; k<batch_size; k++ )
00561         {
00562             for( int i=0; i<n_input_images; i++ )
00563             {
00564                 input_images[i] = (*input)(k)
00565                     .subVec(i*input_images_size, input_images_size)
00566                     .toMat(input_images_length, input_images_width);
00567 
00568                 if( compute_input_grad )
00569                     input_gradients[i] = (*input_grad)(k)
00570                         .subVec(i*input_images_size, input_images_size)
00571                         .toMat(input_images_length, input_images_width);
00572             }
00573 
00574             for( int j=0; j<n_output_images; j++ )
00575             {
00576                 output_images[j] = (*output)(k)
00577                     .subVec(j*output_images_size, output_images_size)
00578                     .toMat(output_images_length, output_images_width);
00579                 output_gradients[j] = (*output_grad)(k)
00580                     .subVec(j*output_images_size, output_images_size)
00581                     .toMat(output_images_length, output_images_width);
00582             }
00583 
00584             for( int j=0; j<n_output_images; j++ )
00585                 for( int i=0; i<n_input_images; i++ )
00586                     if( connection_matrix(i,j) != 0 )
00587                     {
00588                         if( compute_input_grad )
00589                             convolve2Dbackprop( input_images[i],
00590                                                 kernels(i,j),
00591                                                 output_gradients[j],
00592                                                 input_gradients[i],
00593                                                 kernel_gradients(i,j),
00594                                                 kernel_step1, kernel_step2,
00595                                                 true );
00596                         else
00597                             convolve2Dbackprop( input_images[i],
00598                                                 output_gradients[j],
00599                                                 kernel_gradients(i,j),
00600                                                 kernel_step1, kernel_step2,
00601                                                 true );
00602                     }
00603         }
00604 
00605         if( compute_input_grad )
00606             Profiler::pl_profile_end("convolve2Dbackprop");
00607         else
00608             Profiler::pl_profile_end("convolve2Dbackprop (update only)");
00609 
00610         for( int j=0; j<n_output_images; j++ )
00611         {
00612             for( int i=0; i<n_input_images; i++ )
00613                 if( connection_matrix(i,j) != 0 )
00614                     multiplyAcc(kernels(i,j), kernel_gradients(i,j), -avg_lr);
00615 
00616             bias[j] -= avg_lr * sum( (*output_grad)
00617                 .subMatColumns(j*output_images_size, output_images_size) );
00618         }
00619     }
00620     else if( !input_grad
00621              && output_grad && !output_grad->isEmpty() )
00622     {
00623         PLASSERT( input && !input->isEmpty() );
00624         PLASSERT( output && !output->isEmpty() );
00625     }
00626     else if( !input_grad && !output_grad )
00627     {
00628         PLASSERT( !input || !input->isEmpty() );
00629         PLASSERT( !output || !output->isEmpty() );
00630     }
00631     else
00632         PLCHECK_MSG( false, "Port configuration not implemented" );
00633 
00634     Profiler::pl_profile_end("Convolution2DModule::bpropAccUpdate");
00635 }
00636 
00639 void Convolution2DModule::forget()
00640 {
00641     bias.clear();
00642     if( !random_gen )
00643     {
00644         PLWARNING( "Convolution2DModule: cannot forget() without random_gen" );
00645         return;
00646     }
00647 
00648     real scale_factor = 1./(kernel_length*kernel_width*n_input_images);
00649     kernels.resize( n_input_images, n_output_images );
00650     for( int i=0 ; i<n_input_images ; i++ )
00651         for( int j=0 ; j<n_output_images ; j++ )
00652         {
00653             if( connection_matrix(i,j) == 0 )
00654                 kernels(i,j).resize(0,0);
00655             else
00656             {
00657                 kernels(i,j).resize(kernel_length, kernel_width);
00658                 random_gen->fill_random_uniform( kernels(i,j),
00659                                                  -scale_factor,
00660                                                  scale_factor );
00661             }
00662         }
00663 }
00664 
00665 /* THIS METHOD IS OPTIONAL
00670 void Convolution2DModule::finalize()
00671 {
00672 }
00673 */
00674 
00675 /* THIS METHOD IS OPTIONAL
00678 bool Convolution2DModule::bpropDoesNothing()
00679 {
00680 }
00681 */
00682 
00683 /* THIS METHOD IS OPTIONAL
00693 void Convolution2DModule::bbpropUpdate(const Vec& input, const Vec& output,
00694                                 const Vec& output_gradient,
00695                                 const Vec& output_diag_hessian)
00696 {
00697 }
00698 */
00699 
00704 void Convolution2DModule::bbpropUpdate(const Vec& input, const Vec& output,
00705                                        Vec& input_gradient,
00706                                        const Vec& output_gradient,
00707                                        Vec& input_diag_hessian,
00708                                        const Vec& output_diag_hessian,
00709                                        bool accumulate)
00710 {
00711     // This version forwards the second order information, but does not
00712     // actually use it for the update.
00713 
00714     // Check size
00715     if( output_diag_hessian.size() != output_size )
00716         PLERROR("Convolution2DModule::bbpropUpdate: output_diag_hessian.size()"
00717                 "\n"
00718                 "should be equal to output_size (%i != %i).\n",
00719                 output_diag_hessian.size(), output_size);
00720 
00721     if( accumulate )
00722     {
00723         PLASSERT_MSG( input_diag_hessian.size() == input_size,
00724                       "Cannot resize input_diag_hessian AND accumulate into it"
00725                     );
00726     }
00727     else
00728     {
00729         input_diag_hessian.resize(input_size);
00730         input_diag_hessian.clear();
00731     }
00732 
00733     // Make input_diag_hessians and output_diag_hessians point to the right
00734     // places
00735     for( int i=0 ; i<n_input_images ; i++ )
00736         input_diag_hessians[i] =
00737             input_diag_hessian.subVec(i*input_images_size, input_images_size)
00738                 .toMat( input_images_length, input_images_width );
00739 
00740     for( int j=0 ; j<n_output_images ; j++ )
00741         output_diag_hessians[j] =
00742             output_diag_hessian.subVec(j*output_images_size,output_images_size)
00743                 .toMat( output_images_length, output_images_width );
00744 
00745     // Propagates to input_diag_hessian
00746     for( int j=0 ; j<n_output_images ; j++ )
00747         for( int i=0 ; j<n_input_images ; i++ )
00748             if( connection_matrix(i,j) != 0 )
00749             {
00750                 squared_kernel << kernels(i,j);
00751                 squared_kernel *= kernels(i,j); // term-to-term product
00752 
00753                 backConvolve2D( input_diag_hessians[i], squared_kernel,
00754                                 output_diag_hessians[j],
00755                                 kernel_step1, kernel_step2, true );
00756             }
00757 
00758     // Call bpropUpdate()
00759     bpropUpdate( input, output, input_gradient, output_gradient, accumulate );
00760 }
00761 
00762 
00763 } // end of namespace PLearn
00764 
00765 
00766 /*
00767   Local Variables:
00768   mode:c++
00769   c-basic-offset:4
00770   c-file-style:"stroustrup"
00771   c-file-offsets:((innamespace . 0)(inline-open . 0))
00772   indent-tabs-mode:nil
00773   fill-column:79
00774   End:
00775 */
00776 // 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