PLearn 0.1
|
00001 // -*- C++ -*- 00002 00003 // PLearn (A C++ Machine Learning Library) 00004 // Copyright (C) 1998 Pascal Vincent 00005 // Copyright (C) 1999-2002 Pascal Vincent, Yoshua Bengio, Rejean Ducharme and University of Montreal 00006 // Copyright (C) 2001-2002 Nicolas Chapados, Ichiro Takeuchi, Jean-Sebastien Senecal 00007 // Copyright (C) 2002 Xiangdong Wang, Christian Dorion 00008 00009 // Redistribution and use in source and binary forms, with or without 00010 // modification, are permitted provided that the following conditions are met: 00011 // 00012 // 1. Redistributions of source code must retain the above copyright 00013 // notice, this list of conditions and the following disclaimer. 00014 // 00015 // 2. Redistributions in binary form must reproduce the above copyright 00016 // notice, this list of conditions and the following disclaimer in the 00017 // documentation and/or other materials provided with the distribution. 00018 // 00019 // 3. The name of the authors may not be used to endorse or promote 00020 // products derived from this software without specific prior written 00021 // permission. 00022 // 00023 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 00024 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00025 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 00026 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00027 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 00028 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00029 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00030 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00031 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00032 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 // 00034 // This file is part of the PLearn library. For more information on the PLearn 00035 // library, go to the PLearn Web site at www.plearn.org 00036 00037 00038 /* ******************************************************* 00039 * $Id: UnfoldedFuncVariable.cc 8580 2008-02-26 16:48:40Z tihocan $ 00040 * This file is part of the PLearn library. 00041 ******************************************************* */ 00042 00043 #include "UnfoldedFuncVariable.h" 00044 //#include "PLMPI.h" 00045 //#include "DisplayUtils.h" 00046 00047 namespace PLearn { 00048 using namespace std; 00049 00050 00051 00054 PLEARN_IMPLEMENT_OBJECT( 00055 UnfoldedFuncVariable, 00056 "Computes the output of a Func over all elements on an input matrix.", 00057 "By default the function 'f' is applied over all rows of the input\n" 00058 "provided in 'input_matrix', but it may be applied on columns\n" 00059 "instead using the 'transpose' option.\n" 00060 "A separate propagation path is created (using the Func as a\n" 00061 "template) that maps each input to the corresponding output.\n" 00062 "The parents of this variable include the non-input parents of 'f'."); 00063 00065 // UnfoldedFuncVariable // 00067 UnfoldedFuncVariable::UnfoldedFuncVariable(): 00068 transpose(false) 00069 {} 00070 00071 UnfoldedFuncVariable::UnfoldedFuncVariable( 00072 Var inputmatrix, Func the_f, bool the_transpose, 00073 Var bagsize, bool call_build_): 00074 inherited(VarArray(), 00075 the_transpose ? the_f->outputs[0]->length() 00076 * the_f->outputs[0]->width() 00077 : inputmatrix->length(), 00078 the_transpose ? inputmatrix->width() 00079 : the_f->outputs[0]->length() 00080 * the_f->outputs[0]->width(), 00081 call_build_), 00082 input_matrix(inputmatrix), 00083 bag_size(bagsize), 00084 f(the_f), 00085 transpose(the_transpose) 00086 { 00087 if (call_build_) 00088 build_(); 00089 } 00090 00092 // build // 00094 void UnfoldedFuncVariable::build() 00095 { 00096 inherited::build(); 00097 build_(); 00098 } 00099 00101 // build_ // 00103 void UnfoldedFuncVariable::build_() 00104 { 00105 if (f) { 00106 VarArray f_parents = nonInputParentsOfPath(f->inputs, f->outputs); 00107 varray.resize(f_parents.length() + 2); 00108 varray << (f_parents & input_matrix & bag_size); 00109 00110 if(f->outputs.size()!=1) 00111 PLERROR("In UnfoldedFuncVariable: function must have a single variable output (maybe you can vconcat the vars into a single one prior to calling sumOf, if this is really what you want)"); 00112 f->inputs.setDontBpropHere(true); 00113 int n_unfold = transpose ? input_matrix->width() : input_matrix->length(); 00114 inputs.resize(n_unfold); 00115 outputs.resize(n_unfold); 00116 f_paths.resize(n_unfold); 00117 for (int i=0;i<n_unfold;i++) 00118 { 00119 inputs[i].resize(f->inputs.size()); 00120 for (int j = 0; j < f->inputs.size(); j++) { 00121 inputs[i][j] = Var(f->inputs[j]->length(), f->inputs[j]->width()); 00122 } 00123 outputs[i] = f(inputs[i])[0]; 00124 f_paths[i] = propagationPath(inputs[i],outputs[i]); 00125 } 00126 inherited::build(); // Re-build since varray has changed. 00127 } 00128 00129 if (bag_size) 00130 PLASSERT( bag_size->isScalar() ); 00131 } 00132 00134 // declareOptions // 00136 void UnfoldedFuncVariable::declareOptions(OptionList& ol) 00137 { 00138 declareOption(ol, "f", &UnfoldedFuncVariable::f, OptionBase::buildoption, 00139 " Func that is replicated for each element of the 'bag' taken from the VMat."); 00140 00141 declareOption(ol, "input_matrix", &UnfoldedFuncVariable::input_matrix, OptionBase::buildoption, 00142 "Var containing the data: multiple consecutive rows form one bag."); 00143 00144 declareOption(ol, "bag_size", &UnfoldedFuncVariable::bag_size, 00145 OptionBase::buildoption, 00146 "Optional Var that contains the size of the bag being presented.\n" 00147 "If provided, then only the corresponding number of function values\n" 00148 "will be computed, while the rest of the output data matrix will be\n" 00149 "left untouched."); 00150 00151 declareOption(ol, "transpose", &UnfoldedFuncVariable::transpose, OptionBase::buildoption, 00152 " If set to 1, then instead puts in the columns of the output matrix the values\n" 00153 " of f at the columns of the input matrix."); 00154 00155 inherited::declareOptions(ol); 00156 00157 redeclareOption(ol, "varray", &UnfoldedFuncVariable::varray, 00158 OptionBase::nosave, 00159 "This option is set at build time from other options."); 00160 } 00161 00163 // recomputeSize // 00165 void UnfoldedFuncVariable::recomputeSize(int& l, int& w) const 00166 { 00167 if (f && f->outputs.size() > 0) { 00168 w = f->outputs[0]->length()*f->outputs[0]->width(); 00169 if (transpose) { 00170 l = w; 00171 w = input_matrix->width(); 00172 } else { 00173 l = input_matrix->length(); 00174 } 00175 } else 00176 l = w = 0; 00177 } 00178 00180 // makeDeepCopyFromShallowCopy // 00182 void UnfoldedFuncVariable::makeDeepCopyFromShallowCopy(CopiesMap& copies) 00183 { 00184 inherited::makeDeepCopyFromShallowCopy(copies); 00185 deepCopyField(input_matrix, copies); 00186 deepCopyField(bag_size, copies); 00187 deepCopyField(f, copies); 00188 deepCopyField(inputs, copies); 00189 deepCopyField(outputs, copies); 00190 deepCopyField(f_paths, copies); 00191 } 00192 00194 // fprop // 00196 void UnfoldedFuncVariable::fprop() 00197 { 00198 int n_unfold = bag_size ? int(round(bag_size->value[0])) 00199 : transpose ? input_matrix->width() 00200 : input_matrix->length(); 00201 PLASSERT( !bag_size || is_equal(bag_size->value[0], 00202 round(bag_size->value[0])) ); 00203 for (int i=0;i<n_unfold;i++) { 00204 if (transpose) { 00205 Vec tmp = input_matrix->matValue.column(i).toVecCopy(); // TODO something more efficient 00206 inputs[i] << tmp; 00207 } else { 00208 inputs[i] << input_matrix->matValue(i); 00209 } 00210 f_paths[i].fprop(); 00211 if (transpose) { 00212 matValue.column(i) << outputs[i]->value; 00213 } else { 00214 matValue(i) << outputs[i]->value; 00215 } 00216 } 00217 } 00218 00220 // bprop // 00222 void UnfoldedFuncVariable::bprop() 00223 { 00224 int n_unfold = bag_size ? int(round(bag_size->value[0])) 00225 : transpose ? input_matrix->width() 00226 : input_matrix->length(); 00227 for (int i=0;i<n_unfold;i++) 00228 { 00229 f_paths[i].clearGradient(); 00230 if (transpose) { 00231 Vec tmp = matGradient.column(i).toVecCopy(); // TODO more efficient + check while it compiled without tmp = toVecCopy 00232 outputs[i]->gradient << tmp; 00233 } else { 00234 outputs[i]->gradient << matGradient(i); 00235 } 00236 f_paths[i].bprop(); 00237 } 00238 } 00239 00241 // printInfo // 00243 void UnfoldedFuncVariable::printInfo(bool print_gradient) 00244 { 00245 int n_unfold = bag_size ? int(round(bag_size->value[0])) 00246 : transpose ? input_matrix->width() 00247 : input_matrix->length(); 00248 for (int i=0;i<n_unfold;i++) 00249 f_paths[i].printInfo(print_gradient); 00250 pout << info() << " : " << getName() << "[" << (void*)this << "]" 00251 << "(input_matrix=" << (void*)input_matrix << " "; 00252 for(int i=0; i<n_unfold; i++) 00253 pout << (void*)outputs[i] << " "; 00254 pout << ") = " << value; 00255 if (print_gradient) 00256 pout << " gradient=" << gradient; 00257 pout << endl; 00258 } 00259 00260 } // end of namespace PLearn 00261 00262 00263 /* 00264 Local Variables: 00265 mode:c++ 00266 c-basic-offset:4 00267 c-file-style:"stroustrup" 00268 c-file-offsets:((innamespace . 0)(inline-open . 0)) 00269 indent-tabs-mode:nil 00270 fill-column:79 00271 End: 00272 */ 00273 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :