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