PLearn 0.1
|
00001 // -*- C++ -*- 00002 00003 // RBMConnection.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 #include "RBMConnection.h" 00041 #include <plearn/math/TMat_maths.h> 00042 #include <plearn/base/stringutils.h> 00043 #include <plearn/base/RemoteMethodMap.h> 00044 00045 namespace PLearn { 00046 using namespace std; 00047 00048 PLEARN_IMPLEMENT_ABSTRACT_OBJECT( 00049 RBMConnection, 00050 "Virtual class for the linear transformation between two layers of an RBM", 00051 ""); 00052 00054 // RBMConnection // 00056 RBMConnection::RBMConnection(real the_learning_rate, bool call_build_): 00057 inherited("", call_build_), 00058 learning_rate(the_learning_rate), 00059 momentum(0.), 00060 down_size(-1), 00061 up_size(-1), 00062 going_up(true), 00063 pos_count(0), 00064 neg_count(0) 00065 { 00066 if (call_build_) 00067 build_(); 00068 } 00069 00071 // declareOptions // 00073 void RBMConnection::declareOptions(OptionList& ol) 00074 { 00075 declareOption(ol, "down_size", &RBMConnection::down_size, 00076 OptionBase::buildoption, 00077 "Number of units in down layer."); 00078 00079 declareOption(ol, "up_size", &RBMConnection::up_size, 00080 OptionBase::buildoption, 00081 "Number of units in up layer."); 00082 00083 declareOption(ol, "learning_rate", &RBMConnection::learning_rate, 00084 OptionBase::buildoption, 00085 "The learning rate, used both in update() and bpropUpdate() " 00086 "methods\n"); 00087 00088 declareOption(ol, "momentum", &RBMConnection::momentum, 00089 OptionBase::buildoption, 00090 "The momentum, used both in update() and bpropUpdate() " 00091 "methods\n"); 00092 00093 declareOption(ol, "initialization_method", 00094 &RBMConnection::initialization_method, 00095 OptionBase::buildoption, 00096 "The method used to initialize the weights:\n" 00097 " - \"uniform_linear\" = a uniform law in [-1/d, 1/d]\n" 00098 " - \"uniform_sqrt\" = a uniform law in [-1/sqrt(d)," 00099 " 1/sqrt(d)]\n" 00100 " - \"zero\" = all weights are set to 0,\n" 00101 "where d = max( up_layer_size, down_layer_size ).\n"); 00102 00103 // Now call the parent class' declareOptions 00104 inherited::declareOptions(ol); 00105 00106 redeclareOption(ol, "input_size", &RBMConnection::input_size, 00107 OptionBase::learntoption, 00108 "Equals to down_size"); 00109 00110 redeclareOption(ol, "output_size", &RBMConnection::output_size, 00111 OptionBase::learntoption, 00112 "Equals to up_size"); 00113 } 00114 00115 void RBMConnection::declareMethods(RemoteMethodMap& rmm) 00116 { 00117 rmm.inherited(inherited::_getRemoteMethodMap_()); 00118 00119 declareMethod(rmm, "setAsDownInput", &RBMConnection::setAsDownInput, 00120 (BodyDoc("Sets 'input_vec' to 'input', and 'going_up' to true. \n" 00121 "Note that no data copy is made, so 'input' should not be modified \n" 00122 "afterwards."), 00123 ArgDoc("const Vec& input", "The input vector"))); 00124 declareMethod(rmm, "setAsUpInput", &RBMConnection::setAsUpInput, 00125 (BodyDoc("Sets 'input_vec' to 'input', and 'going_up' to false. \n" 00126 "Note that no data copy is made, so 'input' should not be modified \n" 00127 "afterwards."), 00128 ArgDoc("const Vec& input", "The input vector"))); 00129 } 00130 00132 // build_ // 00134 void RBMConnection::build_() 00135 { 00136 string im = lowerstring( initialization_method ); 00137 if( im == "" || im == "uniform_sqrt" ) 00138 initialization_method = "uniform_sqrt"; 00139 else if( im == "uniform_linear" ) 00140 initialization_method = im; 00141 else if( im == "zero" ) 00142 initialization_method = im; 00143 else 00144 PLERROR( "RBMConnection::build_ - initialization_method\n" 00145 "\"%s\" unknown.\n", initialization_method.c_str() ); 00146 00147 // for the "OnlineLearningModule" interface 00148 if( down_size < 0 ) 00149 down_size = input_size; 00150 else 00151 input_size = down_size; 00152 00153 if( up_size < 0 ) 00154 up_size = output_size; 00155 else 00156 output_size = up_size; 00157 00158 ports.resize(2); 00159 ports[0] = "down"; 00160 ports[1] = "up"; 00161 // NOT weights here, because it only makes sense with an 00162 // RBMMatrixConnection 00163 00164 port_sizes.resize(nPorts(), 2); 00165 port_sizes.column(0).fill(-1); 00166 port_sizes(0, 1) = down_size; 00167 port_sizes(1, 1) = up_size; 00168 } 00169 00171 // build // 00173 void RBMConnection::build() 00174 { 00175 inherited::build(); 00176 build_(); 00177 } 00178 00179 00181 // makeDeepCopyFromShallowCopy // 00183 void RBMConnection::makeDeepCopyFromShallowCopy(CopiesMap& copies) 00184 { 00185 inherited::makeDeepCopyFromShallowCopy(copies); 00186 00187 deepCopyField(input_vec, copies); 00188 deepCopyField(inputs_mat, copies); 00189 } 00190 00192 // setLearningRate // 00194 void RBMConnection::setLearningRate( real the_learning_rate ) 00195 { 00196 learning_rate = the_learning_rate; 00197 } 00198 00200 // setMomentum // 00202 void RBMConnection::setMomentum( real the_momentum ) 00203 { 00204 momentum = the_momentum; 00205 } 00206 00208 // setAsUpInput // 00210 void RBMConnection::setAsUpInput( const Vec& input ) const 00211 { 00212 PLASSERT( input.size() == up_size ); 00213 input_vec = input; 00214 going_up = false; 00215 } 00216 00218 // setAsUpInputs // 00220 void RBMConnection::setAsUpInputs( const Mat& inputs ) const 00221 { 00222 PLASSERT( inputs.width() == up_size ); 00223 inputs_mat = inputs; 00224 going_up = false; 00225 } 00226 00228 // setAsDownInput // 00230 void RBMConnection::setAsDownInput( const Vec& input ) const 00231 { 00232 PLASSERT( input.size() == down_size ); 00233 input_vec = input; 00234 going_up = true; 00235 } 00236 00238 // setAsDownInputs // 00240 void RBMConnection::setAsDownInputs( const Mat& inputs ) const 00241 { 00242 PLASSERT( inputs.width() == down_size ); 00243 inputs_mat = inputs; 00244 going_up = true; 00245 } 00246 00248 // update // 00250 void RBMConnection::update( const Vec& pos_down_values, 00251 const Vec& pos_up_values, 00252 const Vec& neg_down_values, 00253 const Vec& neg_up_values) 00254 { 00255 // Not-so-efficient implementation 00256 accumulatePosStats( pos_down_values, pos_up_values ); 00257 accumulateNegStats( neg_down_values, neg_up_values ); 00258 update(); 00259 } 00260 00261 void RBMConnection::update( const Mat& pos_down_values, 00262 const Mat& pos_up_values, 00263 const Mat& neg_down_values, 00264 const Mat& neg_up_values) 00265 { 00266 // Not-so-efficient implementation. 00267 accumulatePosStats( pos_down_values, pos_up_values ); 00268 accumulateNegStats( neg_down_values, neg_up_values ); 00269 update(); 00270 } 00271 00272 // neg_stats <-- gibbs_chain_statistics_forgetting_factor * neg_stats 00273 // +(1-gibbs_chain_statistics_forgetting_factor) 00274 // * gibbs_neg_up_values'*gibbs_neg_down_values 00275 // delta w = lrate * ( pos_up_values'*pos_down_values 00276 // - ( background_gibbs_update_ratio*neg_stats 00277 // +(1-background_gibbs_update_ratio) 00278 // * cd_neg_up_values'*cd_neg_down_values)) 00279 void RBMConnection::updateCDandGibbs( const Mat& pos_down_values, 00280 const Mat& pos_up_values, 00281 const Mat& cd_neg_down_values, 00282 const Mat& cd_neg_up_values, 00283 const Mat& gibbs_neg_down_values, 00284 const Mat& gibbs_neg_up_values, 00285 real background_gibbs_update_ratio) 00286 { 00287 PLASSERT_MSG(false, "Not implemented by subclass!"); 00288 } 00289 00290 // neg_stats <-- gibbs_chain_statistics_forgetting_factor * neg_stats 00291 // +(1-gibbs_chain_statistics_forgetting_factor) 00292 // * gibbs_neg_up_values'*gibbs_neg_down_values 00293 // delta w = lrate * ( pos_up_values'*pos_down_values - neg_stats ) 00294 void RBMConnection::updateGibbs( const Mat& pos_down_values, 00295 const Mat& pos_up_values, 00296 const Mat& gibbs_neg_down_values, 00297 const Mat& gibbs_neg_up_values) 00298 { 00299 PLASSERT_MSG(false, "Not implemented by subclass!"); 00300 } 00301 00303 // fprop // 00305 void RBMConnection::fprop(const Vec& input, Vec& output) const 00306 { 00307 // propagates the activations. 00308 setAsDownInput( input ); 00309 output.resize( output_size ); 00310 computeProduct( 0, output_size, output ); 00311 } 00312 00313 void RBMConnection::fprop(const Mat& inputs, Mat& outputs) 00314 { 00315 int batch_size = inputs.length(); 00316 // propagates the activations. 00317 setAsDownInputs(inputs); 00318 outputs.resize(batch_size, output_size); 00319 computeProducts(0, output_size, outputs); 00320 } 00321 00322 void RBMConnection::getAllWeights(Mat& rbm_weights) const 00323 { 00324 PLERROR("In RBMConnection::getAllWeights(): not implemented"); 00325 } 00326 00327 void RBMConnection::setAllWeights(const Mat& rbm_weights) 00328 { 00329 PLERROR("In RBMConnection::setAllWeights(): not implemented"); 00330 } 00331 00332 void RBMConnection::petiteCulotteOlivierUpdate( 00333 const Vec& input, const Mat& rbm_weights, 00334 const Vec& output, 00335 Vec& input_gradient, 00336 Mat& rbm_weights_gradient, 00337 const Vec& output_gradient, 00338 bool accumulate) 00339 { 00340 PLERROR("In RBMConnection::bpropUpdate(): not implemented"); 00341 } 00342 00343 00345 // bpropCD // 00347 void RBMConnection::petiteCulotteOlivierCD(Mat& weights_gradient, 00348 bool accumulate) 00349 { 00350 PLERROR("In RBMConnection::petiteCulotteOlivierCD(): not implemented"); 00351 } 00352 00353 void RBMConnection::petiteCulotteOlivierCD( const Vec& pos_down_values, 00354 const Vec& pos_up_values, 00355 const Vec& neg_down_values, 00356 const Vec& neg_up_values, 00357 Mat& weights_gradient, 00358 bool accumulate) 00359 { 00360 PLERROR("In RBMConnection::petiteCulotteOlivierCD(): not implemented"); 00361 } 00362 00364 // getPorts // 00366 const TVec<string>& RBMConnection::getPorts() 00367 { 00368 return ports; 00369 } 00370 00372 // getPortSizes // 00374 const TMat<int>& RBMConnection::getPortSizes() 00375 { 00376 return port_sizes; 00377 } 00378 00379 } // end of namespace PLearn 00380 00381 00382 /* 00383 Local Variables: 00384 mode:c++ 00385 c-basic-offset:4 00386 c-file-style:"stroustrup" 00387 c-file-offsets:((innamespace . 0)(inline-open . 0)) 00388 indent-tabs-mode:nil 00389 fill-column:79 00390 End: 00391 */ 00392 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :