PLearn 0.1
|
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 :