PLearn 0.1
|
00001 // -*- C++ -*- 00002 00003 // OnBagsModule.cc 00004 // 00005 // Copyright (C) 2008 Jerome Louradour 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 // Author: Jerome Louradour 00036 00041 #include "OnBagsModule.h" 00042 #include <plearn/var/SumOverBagsVariable.h> 00043 00044 namespace PLearn { 00045 using namespace std; 00046 00047 PLEARN_IMPLEMENT_OBJECT( 00048 OnBagsModule, 00049 "Module that process (variable-length) bags of vectors.\n", 00050 "One output vector is propagated at the end of the bag. Other outputs are MISSING_VALUE.\n" 00051 "The 'bagtarget' contains the bag information at the last position, has follows\n" 00052 " bag info = 1. (01) beginning of bag\n" 00053 " = 0. (00) middle of bag\n" 00054 " = 2. (10) end of bag\n" 00055 " = 3. (11) single-row bag (both beginning and end)\n"); 00056 00057 OnBagsModule::OnBagsModule(): 00058 bagtarget_size(1) 00059 { 00060 } 00061 00062 void OnBagsModule::declareOptions(OptionList& ol) 00063 { 00064 inherited::declareOptions(ol); 00065 00066 declareOption(ol, "bagtarget_size", &OnBagsModule::bagtarget_size, 00067 OptionBase::buildoption, 00068 "Size of the 'bagtarget' port (bag info is the last element)."); 00069 } 00070 00071 void OnBagsModule::build_() 00072 { 00073 PLASSERT( bagtarget_size > 0 ); 00074 PLASSERT( input_size > 0 ); 00075 00076 // The port story... 00077 ports.resize(0); 00078 portname_to_index.clear(); 00079 addPortName("input"); 00080 addPortName("output"); 00081 addPortName("bagtarget"); 00082 00083 port_sizes.resize(nPorts(), 3); 00084 port_sizes.fill(-1); 00085 port_sizes(getPortIndex("input"), 1) = input_size; 00086 port_sizes(getPortIndex("output"), 1) = output_size; 00087 port_sizes(getPortIndex("bagtarget"), 1) = bagtarget_size; 00088 } 00089 00090 void OnBagsModule::build() 00091 { 00092 inherited::build(); 00093 build_(); 00094 } 00095 00096 void OnBagsModule::forget() 00097 { 00098 wait_new_bag = true; 00099 } 00100 00101 void OnBagsModule::makeDeepCopyFromShallowCopy(CopiesMap& copies) 00102 { 00103 inherited::makeDeepCopyFromShallowCopy(copies); 00104 deepCopyField(ports, copies); 00105 } 00106 00107 00109 // fprop // 00111 00112 00113 void OnBagsModule::fprop(const TVec<Mat*>& ports_value) 00114 { 00115 PLASSERT( ports_value.length() == nPorts() ); 00116 00117 Mat* p_inputs = ports_value[getPortIndex("input")]; 00118 Mat* p_bagtargets = ports_value[getPortIndex("bagtarget")]; 00119 Mat* p_outputs = ports_value[getPortIndex("output")]; 00120 00121 if ( p_outputs && p_outputs->isEmpty() ) 00122 { 00123 PLASSERT( p_inputs && !p_inputs->isEmpty() ); 00124 PLASSERT( p_bagtargets && !p_bagtargets->isEmpty() ); 00125 fprop(*p_inputs, *p_bagtargets, *p_outputs); 00126 checkProp(ports_value); 00127 } 00128 else 00129 PLERROR("In OnBagsModule::fprop - Port configuration not implemented."); 00130 } 00131 00132 void OnBagsModule::fprop(const Mat& inputs, const Mat& bagtargets, Mat& outputs) 00133 { 00134 int n_samples = inputs.length(); 00135 outputs.resize( n_samples, output_size ); 00136 //outputs.fill( MISSING_VALUE ); 00137 for (int isample = 0; isample < n_samples; isample++) 00138 { 00139 Vec output; 00140 fprop( inputs(isample), bagtargets(isample), output ); 00141 outputs.row(isample) << output; 00142 } 00143 } 00144 00145 void OnBagsModule::fprop(const Vec& input, const Vec& bagtarget, Vec& output) 00146 { 00147 PLASSERT( input.length() == input_size ); 00148 PLASSERT( bagtarget.length() == bagtarget_size ); 00149 output.resize( output_size ); 00150 output.fill( MISSING_VALUE ); 00151 int bag_info = int(round(bagtarget.lastElement())); 00152 if (bag_info & SumOverBagsVariable::TARGET_COLUMN_FIRST) 00153 { 00154 PLASSERT( wait_new_bag ); 00155 fpropInit( input ); 00156 wait_new_bag = false; 00157 } 00158 else 00159 { 00160 PLASSERT( !wait_new_bag ); 00161 fpropAcc( input ); 00162 } 00163 if (bag_info & SumOverBagsVariable::TARGET_COLUMN_LAST) 00164 { 00165 fpropOutput( output ); 00166 wait_new_bag = true; 00167 } 00168 } 00169 00170 // This function initializes internal statistics 00171 // for the first sample of a bag 00172 void OnBagsModule::fpropInit(const Vec& input) 00173 { 00174 PLERROR("In OnBagsModule::fpropInit(input,output) - not implemented for class %s",classname().c_str()); 00175 } 00176 00177 // This function updates internal statistics given a new bag sample 00178 void OnBagsModule::fpropAcc(const Vec& input) 00179 { 00180 PLERROR("In OnBagsModule::fpropAcc(input,output) - not implemented for class %s",classname().c_str()); 00181 } 00182 00183 // This function fills the output from the internal statistics 00184 // (once all the bag has been seen) 00185 void OnBagsModule::fpropOutput(Vec& output) 00186 { 00187 PLERROR("In OnBagsModule::fpropOutput(input,output) - not implemented for class %s",classname().c_str()); 00188 } 00189 00191 // bpropUpdate // 00193 00194 void OnBagsModule::bpropAccUpdate(const TVec<Mat*>& ports_value, 00195 const TVec<Mat*>& ports_gradient) 00196 { 00197 PLASSERT( input_size > 1 ); 00198 PLASSERT( ports_value.length() == nPorts() ); 00199 PLASSERT( ports_gradient.length() == nPorts() ); 00200 00201 const Mat* p_inputs = ports_value[getPortIndex("input")]; 00202 const Mat* p_bagtargets = ports_value[getPortIndex("bagtarget")]; 00203 const Mat* p_output_grad = ports_gradient[getPortIndex("output")]; 00204 Mat* p_inputs_grad = ports_gradient[getPortIndex("input")]; 00205 00206 if( p_inputs_grad 00207 && p_output_grad && !p_output_grad->isEmpty() ) 00208 { 00209 PLASSERT( p_inputs && !p_inputs->isEmpty()); 00210 PLASSERT( p_bagtargets && !p_bagtargets->isEmpty()); 00211 int n_samples = p_inputs->length(); 00212 PLASSERT( p_output_grad->length() == n_samples ); 00213 PLASSERT( p_output_grad->width() == output_size ); 00214 if( p_inputs_grad->isEmpty() ) 00215 { 00216 p_inputs_grad->resize( n_samples, input_size); 00217 p_inputs_grad->clear(); 00218 } 00219 bpropUpdate( *p_inputs, *p_bagtargets, 00220 *p_inputs_grad, *p_output_grad, true ); 00221 checkProp(ports_gradient); 00222 } 00223 else if( !p_inputs_grad && !p_output_grad ) 00224 return; 00225 else 00226 PLERROR("In OnBagsModule::bpropAccUpdate - Port configuration not implemented."); 00227 00228 } 00229 00230 void OnBagsModule::bpropUpdate( const Mat& inputs, 00231 const Mat& bagtargets, 00232 Mat& input_gradients, 00233 const Mat& output_gradients, 00234 bool accumulate) 00235 { 00236 PLASSERT( inputs.width() == input_size ); 00237 PLASSERT( bagtargets.width() == bagtarget_size ); 00238 PLASSERT( output_gradients.width() == output_size ); 00239 int n_samples = inputs.length(); 00240 PLASSERT( n_samples == bagtargets.length() ); 00241 PLASSERT( n_samples == output_gradients.length() ); 00242 if( accumulate ) 00243 PLASSERT_MSG( input_gradients.width() == input_size && 00244 input_gradients.length() == n_samples, 00245 "Cannot resize input_gradients and accumulate into it." ); 00246 else 00247 { 00248 input_gradients.resize(n_samples, input_size); 00249 input_gradients.fill(0); 00250 } 00251 bool bprop_wait_new_bag = true; 00252 int bag_start; 00253 for (int j = 0; j < n_samples; j++) { 00254 int bag_info = int(round(bagtargets(j).lastElement())); 00255 if (bag_info & SumOverBagsVariable::TARGET_COLUMN_FIRST) 00256 { 00257 PLASSERT( bprop_wait_new_bag ); 00258 bprop_wait_new_bag = false; 00259 bag_start = j; 00260 } 00261 else 00262 PLASSERT( !bprop_wait_new_bag ); 00263 if (bag_info & SumOverBagsVariable::TARGET_COLUMN_LAST) 00264 { 00265 PLASSERT( !is_missing(output_gradients(j,0)) ); 00266 bprop_wait_new_bag = true; 00267 int bag_length = j - bag_start + 1; 00268 Mat baginputs_gradients; 00269 bprop( inputs.subMatRows(bag_start, bag_length), 00270 output_gradients(j), 00271 baginputs_gradients ); 00272 input_gradients.subMatRows(bag_start, bag_length) << baginputs_gradients; 00273 } 00274 else 00275 PLASSERT( is_missing(output_gradients(j,0)) ); 00276 } 00277 00278 if (!bprop_wait_new_bag) 00279 PLERROR("In OnBagsModule::bpropUpdate - entire bags must be given." 00280 "If you use ModuleLearner, you should use the option operate_on_bags = True"); 00281 } 00282 00283 // This function computes the inputs gradients, 00284 // given all inputs from a same bag, 00285 // and the gradient on the (single) output of the bag. 00286 void OnBagsModule::bprop( const Mat& baginputs, 00287 const Vec& bagoutput_gradient, 00288 Mat& baginputs_gradients) 00289 { 00290 PLERROR("In OnBagsModule::bprop() - not implemented for class %s",classname().c_str() ); 00291 } 00292 00293 00295 // name // 00297 TVec<string> OnBagsModule::name() 00298 { 00299 return TVec<string>(1, OnlineLearningModule::name); 00300 } 00301 00303 // addPortName // 00305 void OnBagsModule::addPortName(const string& name) 00306 { 00307 PLASSERT( portname_to_index.find(name) == portname_to_index.end() ); 00308 portname_to_index[name] = ports.length(); 00309 ports.append(name); 00310 } 00311 00313 // getPorts // 00315 const TVec<string>& OnBagsModule::getPorts() 00316 { 00317 return ports; 00318 } 00319 00321 // getPortsSizes // 00323 const TMat<int>& OnBagsModule::getPortSizes() 00324 { 00325 return port_sizes; 00326 } 00327 00329 // getPortIndex // 00331 int OnBagsModule::getPortIndex(const string& port) 00332 { 00333 map<string, int>::const_iterator it = portname_to_index.find(port); 00334 if (it == portname_to_index.end()) 00335 return -1; 00336 else 00337 return it->second; 00338 } 00339 00340 00341 } // end of namespace PLearn 00342 00343 00344 /* 00345 Local Variables: 00346 mode:c++ 00347 c-basic-offset:4 00348 c-file-style:"stroustrup" 00349 c-file-offsets:((innamespace . 0)(inline-open . 0)) 00350 indent-tabs-mode:nil 00351 fill-column:79 00352 End: 00353 */ 00354 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :