PLearn 0.1
OnBagsModule.cc
Go to the documentation of this file.
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 :
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines