PLearn 0.1
RBMMixedConnection.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 // RBMMixedConnection.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 
00041 #include "RBMMixedConnection.h"
00042 #include <plearn/math/TMat_maths.h>
00043 
00044 namespace PLearn {
00045 using namespace std;
00046 
00047 PLEARN_IMPLEMENT_OBJECT(
00048     RBMMixedConnection,
00049     "Stores and learns the parameters between two linear layers of an RBM",
00050     "If a sub_connection is not present, it will be treated as a 0 matrix");
00051 
00053 // RBMMixedConnection //
00055 RBMMixedConnection::RBMMixedConnection()
00056 {}
00057 
00059 // declareOptions //
00061 void RBMMixedConnection::declareOptions(OptionList& ol)
00062 {
00063     declareOption(ol, "sub_connections", &RBMMixedConnection::sub_connections,
00064                   OptionBase::buildoption,
00065                   "Matrix containing the sub-transformations (blocks).");
00066 
00067     declareOption(ol, "up_init_positions",
00068                   &RBMMixedConnection::up_init_positions,
00069                   OptionBase::learntoption,
00070                   "Initial vertical index of the blocks.");
00071 
00072     declareOption(ol, "down_init_positions",
00073                   &RBMMixedConnection::down_init_positions,
00074                   OptionBase::learntoption,
00075                   "Initial horizontal index of the blocks.");
00076 
00077     declareOption(ol, "n_up_blocks", &RBMMixedConnection::n_up_blocks,
00078                   OptionBase::learntoption,
00079                   "Length of the blocks matrix.");
00080 
00081     declareOption(ol, "n_down_blocks", &RBMMixedConnection::n_down_blocks,
00082                   OptionBase::learntoption,
00083                   "Width of the blocks matrix.");
00084 
00085     // Now call the parent class' declareOptions
00086     inherited::declareOptions(ol);
00087 
00088     redeclareOption(ol, "down_size", &RBMMixedConnection::down_size,
00089                     OptionBase::learntoption,
00090                     "It is computed from the sizes of the sub-blocks.");
00091 
00092     redeclareOption(ol, "up_size", &RBMMixedConnection::up_size,
00093                     OptionBase::learntoption,
00094                     "It is computed from the sizes of the sub-blocks.");
00095 
00096     redeclareOption(ol, "initialization_method",
00097                     &RBMMixedConnection::initialization_method,
00098                     OptionBase::nosave,
00099                     "initialization_method is useless here.");
00100 }
00101 
00103 // build_ //
00105 void RBMMixedConnection::build_()
00106 {
00107     up_size = 0;
00108     down_size = 0;
00109 
00110     n_up_blocks = sub_connections.length();
00111     n_down_blocks = sub_connections.width();
00112 
00113     if( n_up_blocks == 0 || n_down_blocks == 0 )
00114         return;
00115 
00116     up_init_positions.resize( n_up_blocks );
00117     up_block_sizes.resize( n_up_blocks );
00118     down_init_positions.resize( n_down_blocks );
00119     down_block_sizes.resize( n_down_blocks );
00120     row_of.resize( 0 );
00121     col_of.resize( 0 );
00122 
00123     // size equality check
00124     for( int i=0 ; i<n_up_blocks ; i++ )
00125     {
00126         up_block_sizes[i] = 0;
00127         for( int j=0 ; j<n_down_blocks ; j++ )
00128         {
00129             if( sub_connections(i,j) )
00130             {
00131                 if( up_block_sizes[i] == 0 ) // first non-null sub_connection
00132                     up_block_sizes[i] = sub_connections(i,j)->up_size;
00133                 else
00134                     PLASSERT( sub_connections(i,j)->up_size ==
00135                             up_block_sizes[i] );
00136             }
00137         }
00138         up_init_positions[i] = up_size;
00139         up_size += up_block_sizes[i];
00140         row_of.append( TVec<int>( up_block_sizes[i], i ) );
00141     }
00142 
00143     for( int j=0 ; j<n_down_blocks ; j++ )
00144     {
00145         down_block_sizes[j] = 0;
00146         for( int i=0 ; i<n_up_blocks ; i++ )
00147         {
00148             if( sub_connections(i,j) )
00149             {
00150                 if( down_block_sizes[j] == 0 ) // first non-null sub_connection
00151                     down_block_sizes[j] = sub_connections(i,j)->down_size;
00152                 else
00153                     PLASSERT( sub_connections(i,j)->down_size ==
00154                             down_block_sizes[j] );
00155             }
00156         }
00157 
00158         down_init_positions[j] = down_size;
00159         down_size += down_block_sizes[j];
00160         col_of.append( TVec<int>( down_block_sizes[j], j ) );
00161     }
00162 
00163     // Assign learning rate and momentum to sub_connections
00164     // If we have a random_gen and they do not, share it with them
00165     for( int i=0 ; i<n_up_blocks ; i++ )
00166         for( int j=0 ; j<n_down_blocks ; j++ )
00167         {
00168             if( sub_connections(i,j) )
00169             {
00170                 if( learning_rate >= 0. )
00171                     sub_connections(i,j)->setLearningRate( learning_rate );
00172 
00173                 if( momentum >= 0. )
00174                     sub_connections(i,j)->setMomentum( momentum );
00175 
00176                 if( random_gen && !(sub_connections(i,j)->random_gen) )
00177                 {
00178                     sub_connections(i,j)->random_gen = random_gen;
00179                     sub_connections(i,j)->forget();
00180                 }
00181             }
00182         }
00183 
00184     // for OnlineLearningModule interface
00185     input_size = down_size;
00186     output_size = up_size;
00187 }
00188 
00190 // build //
00192 void RBMMixedConnection::build()
00193 {
00194     inherited::build();
00195     build_();
00196 }
00197 
00198 
00200 // makeDeepCopyFromShallowCopy //
00202 void RBMMixedConnection::makeDeepCopyFromShallowCopy(CopiesMap& copies)
00203 {
00204     inherited::makeDeepCopyFromShallowCopy(copies);
00205 
00206     deepCopyField(sub_connections,      copies);
00207     deepCopyField(up_init_positions,    copies);
00208     deepCopyField(up_block_sizes,       copies);
00209     deepCopyField(down_init_positions,  copies);
00210     deepCopyField(down_block_sizes,     copies);
00211     deepCopyField(row_of,               copies);
00212     deepCopyField(col_of,               copies);
00213 }
00214 
00215 
00217 // setLearningRate //
00219 void RBMMixedConnection::setLearningRate( real the_learning_rate )
00220 {
00221     inherited::setLearningRate( the_learning_rate );
00222 
00223     for( int i=0 ; i<n_up_blocks ; i++ )
00224         for( int j=0 ; j<n_down_blocks ; j++ )
00225             if( sub_connections(i,j) )
00226                 sub_connections(i,j)->setLearningRate( the_learning_rate );
00227 }
00228 
00230 // setMomentum //
00232 void RBMMixedConnection::setMomentum( real the_momentum )
00233 {
00234     inherited::setMomentum( the_momentum );
00235 
00236     for( int i=0 ; i<n_up_blocks ; i++ )
00237         for( int j=0 ; j<n_down_blocks ; j++ )
00238             if( sub_connections(i,j) )
00239                 sub_connections(i,j)->setMomentum( the_momentum );
00240 }
00241 
00243 // setAsUpInput //
00245 void RBMMixedConnection::setAsUpInput( const Vec& input ) const
00246 {
00247     inherited::setAsUpInput( input );
00248 
00249     for( int i=0 ; i<n_up_blocks ; i++ )
00250     {
00251         Vec sub_input = input.subVec( up_init_positions[i],
00252                                       up_block_sizes[i] );
00253 
00254         for( int j=0 ; j<n_down_blocks ; j++ )
00255             if( sub_connections(i,j) )
00256                 sub_connections(i,j)->setAsUpInput( sub_input );
00257     }
00258 }
00259 
00261 // setAsUpInputs //
00263 void RBMMixedConnection::setAsUpInputs( const Mat& inputs ) const
00264 {
00265     inherited::setAsUpInputs( inputs );
00266 
00267     for( int i=0 ; i<n_up_blocks ; i++ )
00268     {
00269         Mat sub_inputs = inputs.subMatColumns( up_init_positions[i],
00270                                                up_block_sizes[i] );
00271 
00272         for( int j=0 ; j<n_down_blocks ; j++ )
00273             if( sub_connections(i,j) )
00274                 sub_connections(i,j)->setAsUpInputs( sub_inputs );
00275     }
00276 }
00277 
00279 // setAsDownInput //
00281 void RBMMixedConnection::setAsDownInput( const Vec& input ) const
00282 {
00283     inherited::setAsDownInput( input );
00284 
00285     for( int j=0 ; j<n_down_blocks ; j++ )
00286     {
00287         Vec sub_input = input.subVec( down_init_positions[j],
00288                                       down_block_sizes[j] );
00289 
00290         for( int i=0 ; i<n_up_blocks ; i++ )
00291             if( sub_connections(i,j) )
00292                 sub_connections(i,j)->setAsDownInput( sub_input );
00293     }
00294 }
00295 
00297 // setAsDownInputs //
00299 void RBMMixedConnection::setAsDownInputs( const Mat& inputs ) const
00300 {
00301     inherited::setAsDownInputs( inputs );
00302 
00303     for( int j=0 ; j<n_down_blocks ; j++ )
00304     {
00305         Mat sub_inputs = inputs.subMatColumns( down_init_positions[j],
00306                                                down_block_sizes[j] );
00307 
00308         for( int i=0 ; i<n_up_blocks ; i++ )
00309             if( sub_connections(i,j) )
00310                 sub_connections(i,j)->setAsDownInputs( sub_inputs );
00311     }
00312 }
00313 
00314 // Vec version
00315 void RBMMixedConnection::accumulatePosStats( const Vec& down_values,
00316                                              const Vec& up_values )
00317 {
00318     for( int i=0 ; i<n_up_blocks ; i++ )
00319     {
00320         Vec sub_up_values = up_values.subVec( up_init_positions[i],
00321                                               up_block_sizes[i] );
00322 
00323         for( int j=0 ; j<n_down_blocks ; j++ )
00324         {
00325             if( sub_connections(i,j) )
00326             {
00327                 Vec sub_down_values =
00328                     down_values.subVec( down_init_positions[j],
00329                                         sub_connections(i,j)->down_size );
00330 
00331                 sub_connections(i,j)->accumulatePosStats( sub_down_values,
00332                                                           sub_up_values );
00333             }
00334         }
00335     }
00336 
00337     pos_count++;
00338 }
00339 
00340 void RBMMixedConnection::accumulateNegStats( const Vec& down_values,
00341                                              const Vec& up_values )
00342 {
00343     for( int i=0 ; i<n_up_blocks ; i++ )
00344     {
00345         Vec sub_up_values = up_values.subVec( up_init_positions[i],
00346                                               up_block_sizes[i] );
00347 
00348         for( int j=0 ; j<n_down_blocks ; j++ )
00349         {
00350             if( sub_connections(i,j) )
00351             {
00352                 Vec sub_down_values =
00353                     down_values.subVec( down_init_positions[j],
00354                                         sub_connections(i,j)->down_size );
00355 
00356                 sub_connections(i,j)->accumulateNegStats( sub_down_values,
00357                                                           sub_up_values );
00358             }
00359         }
00360     }
00361 
00362     neg_count++;
00363 }
00364 
00365 void RBMMixedConnection::update()
00366 {
00367     for( int i=0 ; i<n_up_blocks ; i++ )
00368         for( int j=0 ; j<n_down_blocks ; j++ )
00369             if( sub_connections(i,j) )
00370                 sub_connections(i,j)->update();
00371 
00372     clearStats();
00373 }
00374 
00375 // Instead of using the statistics, we assume we have only one markov chain
00376 // runned and we update the parameters from the first 4 values of the chain
00377 void RBMMixedConnection::update( const Vec& pos_down_values, // v_0
00378                                  const Vec& pos_up_values,   // h_0
00379                                  const Vec& neg_down_values, // v_1
00380                                  const Vec& neg_up_values )  // h_1
00381 {
00382     for( int i=0 ; i<n_up_blocks ; i++ )
00383     {
00384         int up_begin = up_init_positions[i];
00385         int up_length = up_block_sizes[i];
00386         Vec sub_pos_up_values = pos_up_values.subVec( up_begin, up_length );
00387         Vec sub_neg_up_values = neg_up_values.subVec( up_begin, up_length );
00388         for( int j=0 ; j<n_down_blocks ; j++ )
00389         {
00390             if( sub_connections(i,j) )
00391             {
00392                 int down_begin = down_init_positions[j];
00393                 int down_length = sub_connections(i,j)->down_size;
00394                 Vec sub_pos_down_values = pos_down_values.subVec( down_begin,
00395                                                                   down_length );
00396                 Vec sub_neg_down_values = neg_down_values.subVec( down_begin,
00397                                                                   down_length );
00398 
00399                 sub_connections(i,j)->update( sub_pos_down_values,
00400                                               sub_pos_up_values,
00401                                               sub_neg_down_values,
00402                                               sub_neg_up_values );
00403             }
00404         }
00405     }
00406 }
00407 
00408 // Mat (mini-batch) version
00409 void RBMMixedConnection::update( const Mat& pos_down_values, // v_0
00410                                  const Mat& pos_up_values,   // h_0
00411                                  const Mat& neg_down_values, // v_1
00412                                  const Mat& neg_up_values )  // h_1
00413 {
00414     for( int i=0 ; i<n_up_blocks ; i++ )
00415     {
00416         int up_begin = up_init_positions[i];
00417         int up_length = up_block_sizes[i];
00418         Mat sub_pos_up_values = pos_up_values.subMatColumns( up_begin,
00419                                                              up_length );
00420         Mat sub_neg_up_values = neg_up_values.subMatColumns( up_begin,
00421                                                              up_length );
00422         for( int j=0 ; j<n_down_blocks ; j++ )
00423         {
00424             if( sub_connections(i,j) )
00425             {
00426                 int down_begin = down_init_positions[j];
00427                 int down_length = sub_connections(i,j)->down_size;
00428                 Mat sub_pos_down_values =
00429                     pos_down_values.subMatColumns( down_begin, down_length );
00430                 Mat sub_neg_down_values =
00431                     neg_down_values.subMatColumns( down_begin, down_length );
00432 
00433                 sub_connections(i,j)->update( sub_pos_down_values,
00434                                               sub_pos_up_values,
00435                                               sub_neg_down_values,
00436                                               sub_neg_up_values );
00437             }
00438         }
00439     }
00440 }
00441 
00442 void RBMMixedConnection::clearStats()
00443 {
00444     for( int i=0 ; i<n_up_blocks ; i++ )
00445         for( int j=0 ; j<n_down_blocks ; j++ )
00446             if( sub_connections(i,j) )
00447                 sub_connections(i,j)->clearStats();
00448 
00449     pos_count = 0;
00450     neg_count = 0;
00451 }
00452 
00453 void RBMMixedConnection::computeProduct( int start, int length,
00454                                          const Vec& activations,
00455                                          bool accumulate ) const
00456 {
00457     PLASSERT( activations.length() == length );
00458 
00459     if( !accumulate )
00460         activations.subVec( start, length ).fill( 0. );
00461 
00462     if( going_up )
00463     {
00464         PLASSERT( start+length <= up_size );
00465 
00466         int init_row = row_of[start];
00467         int end_row = row_of[start+length-1];
00468 
00469         if( init_row == end_row )
00470         {
00471             int start_in_row = start - up_init_positions[init_row];
00472 
00473             for( int j=0 ; j<n_down_blocks ; j++ )
00474             {
00475                 if( sub_connections(init_row,j) )
00476                 {
00477                     sub_connections(init_row,j)->computeProduct(
00478                         start_in_row, length, activations, true );
00479                 }
00480             }
00481         }
00482         else
00483         {
00484             // partial computation on init_row
00485             int start_in_init_row = start - up_init_positions[init_row];
00486             int len_in_init_row = up_init_positions[init_row+1]
00487                                     - start_in_init_row;
00488             int cur_pos = 0;
00489 
00490             Vec sub_activations = activations.subVec( cur_pos,
00491                                                       len_in_init_row );
00492             cur_pos += len_in_init_row;
00493             for( int j=0 ; j<n_down_blocks ; j++ )
00494             {
00495                 if( sub_connections(init_row,j) )
00496                 {
00497                     sub_connections(init_row,j)->computeProduct(
00498                         start_in_init_row, len_in_init_row,
00499                         sub_activations, true );
00500                 }
00501             }
00502 
00503             // full computation for init_row < i < end_row
00504             for( int i=init_row+1 ; i<end_row ; i++ )
00505             {
00506                 int up_size_i = up_block_sizes[i];
00507                 sub_activations = activations.subVec( cur_pos, up_size_i );
00508                 cur_pos += up_size_i;
00509                 for( int j=0 ; j<n_down_blocks ; j++ )
00510                 {
00511                     if( sub_connections(i,j) )
00512                     {
00513                         sub_connections(i,j)->computeProduct(
00514                             0, up_size_i, sub_activations, true );
00515                     }
00516                 }
00517 
00518             }
00519 
00520             // partial computation on end_row
00521             int len_in_end_row = start+length - up_init_positions[end_row];
00522             sub_activations = activations.subVec( cur_pos, len_in_end_row );
00523             cur_pos += len_in_end_row;
00524             for( int j=0 ; j<n_down_blocks ; j++ )
00525             {
00526                 if( sub_connections(end_row,j) )
00527                 {
00528                     sub_connections(end_row,j)->computeProduct(
00529                         0, len_in_end_row, sub_activations, true );
00530                 }
00531             }
00532         }
00533     }
00534     else
00535     {
00536         PLASSERT( start+length <= down_size );
00537 
00538         int init_col = col_of[start];
00539         int end_col = col_of[start+length-1];
00540 
00541         if( init_col == end_col )
00542         {
00543             int start_in_col = start - down_init_positions[init_col];
00544 
00545             for( int i=0 ; i<n_up_blocks ; i++ )
00546             {
00547                 if( sub_connections(i,init_col) )
00548                 {
00549                     sub_connections(i,init_col)->computeProduct(
00550                         start_in_col, length, activations, true );
00551                 }
00552             }
00553         }
00554         else
00555         {
00556             // partial computation on init_col
00557             int start_in_init_col = start - down_init_positions[init_col];
00558             int len_in_init_col = down_init_positions[init_col+1]
00559                                     - start_in_init_col;
00560             int cur_pos = 0;
00561 
00562             Vec sub_activations = activations.subVec( cur_pos,
00563                                                       len_in_init_col );
00564             cur_pos += len_in_init_col;
00565             for( int i=0 ; i<n_up_blocks ; i++ )
00566             {
00567                 if( sub_connections(i,init_col) )
00568                 {
00569                     sub_connections(i,init_col)->computeProduct(
00570                         start_in_init_col, len_in_init_col,
00571                         sub_activations, true );
00572                 }
00573             }
00574 
00575             // full computation for init_col < j < end_col
00576             for( int j=init_col+1 ; j<end_col ; j++ )
00577             {
00578                 int down_size_j = down_block_sizes[j];
00579                 sub_activations = activations.subVec( cur_pos, down_size_j );
00580                 cur_pos += down_size_j;
00581                 for( int i=0 ; i<n_up_blocks ; i++ )
00582                 {
00583                     if( sub_connections(i,j) )
00584                     {
00585                         sub_connections(i,j)->computeProduct(
00586                             0, down_size_j, sub_activations, true );
00587                     }
00588                 }
00589 
00590             }
00591 
00592             // partial computation on end_row
00593             int len_in_end_col = start+length - down_init_positions[end_col];
00594             sub_activations = activations.subVec( cur_pos, len_in_end_col );
00595             cur_pos += len_in_end_col;
00596             for( int i=0 ; i<n_up_blocks ; i++ )
00597             {
00598                 if( sub_connections(i,end_col) )
00599                 {
00600                     sub_connections(i,end_col)->computeProduct(
00601                         0, len_in_end_col, sub_activations, true );
00602                 }
00603             }
00604         }
00605     }
00606 }
00607 
00608 // Mat (mini-batch) version
00609 void RBMMixedConnection::computeProducts( int start, int length,
00610                                           Mat& activations,
00611                                           bool accumulate ) const
00612 {
00613     PLASSERT( activations.width() == length );
00614     activations.resize(inputs_mat.length(), length);
00615 
00616     if( !accumulate )
00617         activations.subMatColumns( start, length ).clear();
00618 
00619     if( going_up )
00620     {
00621         PLASSERT( start+length <= up_size );
00622 
00623         int init_row = row_of[start];
00624         int end_row = row_of[start+length-1];
00625 
00626         if( init_row == end_row )
00627         {
00628             int start_in_row = start - up_init_positions[init_row];
00629 
00630             for( int j=0 ; j<n_down_blocks ; j++ )
00631             {
00632                 if( sub_connections(init_row,j) )
00633                 {
00634                     sub_connections(init_row,j)->computeProducts(
00635                         start_in_row, length, activations, true );
00636                 }
00637             }
00638         }
00639         else
00640         {
00641             // partial computation on init_row
00642             int start_in_init_row = start - up_init_positions[init_row];
00643             int len_in_init_row = up_init_positions[init_row+1]
00644                                     - start_in_init_row;
00645             int cur_pos = 0;
00646 
00647             Mat sub_activations = activations.subMatColumns( cur_pos,
00648                                                              len_in_init_row );
00649             cur_pos += len_in_init_row;
00650             for( int j=0 ; j<n_down_blocks ; j++ )
00651             {
00652                 if( sub_connections(init_row,j) )
00653                 {
00654                     sub_connections(init_row,j)->computeProducts(
00655                         start_in_init_row, len_in_init_row,
00656                         sub_activations, true );
00657                 }
00658             }
00659 
00660             // full computation for init_row < i < end_row
00661             for( int i=init_row+1 ; i<end_row ; i++ )
00662             {
00663                 int up_size_i = up_block_sizes[i];
00664                 sub_activations = activations.subMatColumns( cur_pos,
00665                                                              up_size_i );
00666                 cur_pos += up_size_i;
00667                 for( int j=0 ; j<n_down_blocks ; j++ )
00668                 {
00669                     if( sub_connections(i,j) )
00670                     {
00671                         sub_connections(i,j)->computeProducts(
00672                             0, up_size_i, sub_activations, true );
00673                     }
00674                 }
00675 
00676             }
00677 
00678             // partial computation on end_row
00679             int len_in_end_row = start+length - up_init_positions[end_row];
00680             sub_activations = activations.subMatColumns( cur_pos,
00681                                                          len_in_end_row );
00682             cur_pos += len_in_end_row;
00683             for( int j=0 ; j<n_down_blocks ; j++ )
00684             {
00685                 if( sub_connections(end_row,j) )
00686                 {
00687                     sub_connections(end_row,j)->computeProducts(
00688                         0, len_in_end_row, sub_activations, true );
00689                 }
00690             }
00691         }
00692     }
00693     else
00694     {
00695         PLASSERT( start+length <= down_size );
00696 
00697         int init_col = col_of[start];
00698         int end_col = col_of[start+length-1];
00699 
00700         if( init_col == end_col )
00701         {
00702             int start_in_col = start - down_init_positions[init_col];
00703 
00704             for( int i=0 ; i<n_up_blocks ; i++ )
00705             {
00706                 if( sub_connections(i,init_col) )
00707                 {
00708                     sub_connections(i,init_col)->computeProducts(
00709                         start_in_col, length, activations, true );
00710                 }
00711             }
00712         }
00713         else
00714         {
00715             // partial computation on init_col
00716             int start_in_init_col = start - down_init_positions[init_col];
00717             int len_in_init_col = down_init_positions[init_col+1]
00718                                     - start_in_init_col;
00719             int cur_pos = 0;
00720 
00721             Mat sub_activations = activations.subMatColumns( cur_pos,
00722                                                              len_in_init_col );
00723             cur_pos += len_in_init_col;
00724             for( int i=0 ; i<n_up_blocks ; i++ )
00725             {
00726                 if( sub_connections(i,init_col) )
00727                 {
00728                     sub_connections(i,init_col)->computeProducts(
00729                         start_in_init_col, len_in_init_col,
00730                         sub_activations, true );
00731                 }
00732             }
00733 
00734             // full computation for init_col < j < end_col
00735             for( int j=init_col+1 ; j<end_col ; j++ )
00736             {
00737                 int down_size_j = down_block_sizes[j];
00738                 sub_activations = activations.subMatColumns( cur_pos,
00739                                                              down_size_j );
00740                 cur_pos += down_size_j;
00741                 for( int i=0 ; i<n_up_blocks ; i++ )
00742                 {
00743                     if( sub_connections(i,j) )
00744                     {
00745                         sub_connections(i,j)->computeProducts(
00746                             0, down_size_j, sub_activations, true );
00747                     }
00748                 }
00749 
00750             }
00751 
00752             // partial computation on end_row
00753             int len_in_end_col = start+length - down_init_positions[end_col];
00754             sub_activations = activations.subMatColumns( cur_pos,
00755                                                          len_in_end_col );
00756             cur_pos += len_in_end_col;
00757             for( int i=0 ; i<n_up_blocks ; i++ )
00758             {
00759                 if( sub_connections(i,end_col) )
00760                 {
00761                     sub_connections(i,end_col)->computeProducts(
00762                         0, len_in_end_col, sub_activations, true );
00763                 }
00764             }
00765         }
00766     }
00767 }
00768 
00770 void RBMMixedConnection::bpropUpdate(const Vec& input, const Vec& output,
00771                                      Vec& input_gradient,
00772                                      const Vec& output_gradient,
00773                                      bool accumulate)
00774 {
00775     PLASSERT( input.size() == down_size );
00776     PLASSERT( output.size() == up_size );
00777     PLASSERT( output_gradient.size() == up_size );
00778 
00779     if( accumulate )
00780     {
00781         PLASSERT_MSG( input_gradient.size() == down_size,
00782                       "Cannot resize input_gradient AND accumulate into it" );
00783     }
00784     else
00785     {
00786         input_gradient.resize( down_size );
00787         input_gradient.clear();
00788     }
00789 
00790     for( int j=0 ; j<n_down_blocks ; j++ )
00791     {
00792         int init_j = down_init_positions[j];
00793         int down_size_j = down_block_sizes[j];
00794         Vec sub_input = input.subVec( init_j, down_size_j );
00795         Vec sub_input_gradient = input_gradient.subVec( init_j, down_size_j );
00796 
00797         for( int i=0 ; i<n_up_blocks ; i++ )
00798         {
00799             if( sub_connections(i,j) )
00800             {
00801                 int init_i = up_init_positions[i];
00802                 int up_size_i = up_block_sizes[i];
00803                 Vec sub_output = output.subVec( init_i, up_size_i );
00804                 Vec sub_output_gradient = output_gradient.subVec( init_i,
00805                                                                   up_size_i );
00806                 sub_connections(i,j)->bpropUpdate( sub_input, sub_output,
00807                                                    sub_input_gradient,
00808                                                    sub_output_gradient,
00809                                                    true );
00810             }
00811         }
00812     }
00813 }
00814 
00815 void RBMMixedConnection::bpropUpdate(const Mat& inputs, const Mat& outputs,
00816                                      Mat& input_gradients,
00817                                      const Mat& output_gradients,
00818                                      bool accumulate)
00819 {
00820     PLASSERT( inputs.width() == down_size );
00821     PLASSERT( outputs.width() == up_size );
00822     PLASSERT( output_gradients.width() == up_size );
00823 
00824     int batch_size = inputs.length();
00825     PLASSERT( outputs.length() == batch_size );
00826     PLASSERT( output_gradients.length() == batch_size );
00827 
00828     if( accumulate )
00829     {
00830         PLASSERT_MSG( input_gradients.width() == down_size &&
00831                       input_gradients.length() == batch_size,
00832                       "Cannot resize input_gradients AND accumulate into it" );
00833     }
00834     else
00835     {
00836         input_gradients.resize( batch_size, down_size );
00837         input_gradients.clear();
00838     }
00839 
00840     for( int j=0 ; j<n_down_blocks ; j++ )
00841     {
00842         int init_j = down_init_positions[j];
00843         int down_size_j = down_block_sizes[j];
00844         Mat sub_inputs = inputs.subMatColumns( init_j, down_size_j );
00845         Mat sub_input_gradients = input_gradients.subMatColumns( init_j,
00846                                                                  down_size_j );
00847 
00848         for( int i=0 ; i<n_up_blocks ; i++ )
00849         {
00850             if( sub_connections(i,j) )
00851             {
00852                 int init_i = up_init_positions[i];
00853                 int up_size_i = up_block_sizes[i];
00854                 Mat sub_outputs = outputs.subMatColumns( init_i, up_size_i );
00855                 Mat sub_output_gradients =
00856                     output_gradients.subMatColumns( init_i, up_size_i );
00857                 sub_connections(i,j)->bpropUpdate( sub_inputs, sub_outputs,
00858                                                    sub_input_gradients,
00859                                                    sub_output_gradients,
00860                                                    true );
00861             }
00862         }
00863     }
00864 }
00865 
00867 // bpropAccUpdate //
00869 void RBMMixedConnection::bpropAccUpdate(const TVec<Mat*>& ports_value,
00870                                         const TVec<Mat*>& ports_gradient)
00871 {
00872     PLASSERT( ports_value.length() == nPorts()
00873               && ports_gradient.length() == nPorts() );
00874 
00875     Mat* down = ports_value[0];
00876     Mat* up = ports_value[1];
00877     Mat* down_grad = ports_gradient[0];
00878     Mat* up_grad = ports_gradient[1];
00879 
00880     PLASSERT( down && !down->isEmpty() );
00881     PLASSERT( up && !up->isEmpty() );
00882 
00883     int batch_size = down->length();
00884     PLASSERT( up->length() == batch_size );
00885 
00886     // If we have up_grad
00887     if( up_grad && !up_grad->isEmpty() )
00888     {
00889         // down_grad should not be provided
00890         PLASSERT( !down_grad || down_grad->isEmpty() );
00891         PLASSERT( up_grad->length() == batch_size );
00892         PLASSERT( up_grad->width() == up_size );
00893 
00894         // If we want down_grad
00895         bool compute_down_grad = false;
00896         if( down_grad && down_grad->isEmpty() )
00897         {
00898             PLASSERT( down_grad->width() == down_size );
00899             down_grad->resize(batch_size, down_size);
00900             compute_down_grad = true;
00901         }
00902 
00903         for (int j=0; j<n_down_blocks; j++)
00904         {
00905             int init_j = down_init_positions[j];
00906             int down_size_j = down_block_sizes[j];
00907             Mat sub_down = down->subMatColumns(init_j, down_size_j);
00908             Mat sub_down_grad;
00909             Mat* p_sub_down_grad = NULL;
00910             if( compute_down_grad )
00911             {
00912                 sub_down_grad = down_grad->subMatColumns(init_j, down_size_j);
00913                 p_sub_down_grad = &sub_down_grad;
00914             }
00915 
00916             for (int i=0; i<n_up_blocks; i++)
00917             {
00918                 if(sub_connections(i,j))
00919                 {
00920                     int init_i = up_init_positions[i];
00921                     int up_size_i = up_block_sizes[i];
00922                     Mat sub_up = up->subMatColumns(init_i, up_size_i);
00923                     Mat sub_up_grad =
00924                         up_grad->subMatColumns(init_i, up_size_i);
00925 
00926                     TVec<Mat*> sub_ports_value(2);
00927                     sub_ports_value[0] = &sub_down;
00928                     sub_ports_value[1] = &sub_up;
00929                     TVec<Mat*> sub_ports_gradient(2);
00930                     // NOT &sub_down_grad because we may want a NULL pointer
00931                     sub_ports_gradient[0] = p_sub_down_grad;
00932                     sub_ports_gradient[1] = &sub_up_grad;
00933 
00934                     if( compute_down_grad )
00935                         sub_down_grad.resize(0, down_size_j);
00936 
00937                     sub_connections(i,j)->bpropAccUpdate( sub_ports_value,
00938                                                           sub_ports_gradient );
00939                 }
00940             }
00941         }
00942     }
00943     else if( down_grad && !down_grad->isEmpty() )
00944     {
00945         PLASSERT( down_grad->length() == batch_size );
00946         PLASSERT( down_grad->width() == down_size );
00947 
00948         // If we wand up_grad
00949         bool compute_up_grad = false;
00950         if( up_grad && up_grad->isEmpty() )
00951         {
00952             PLASSERT( up_grad->width() == up_size );
00953             up_grad->resize(batch_size, up_size);
00954             compute_up_grad = true;
00955         }
00956 
00957         for (int i=0; i<n_up_blocks; i++)
00958         {
00959             int init_i = up_init_positions[i];
00960             int up_size_i = up_block_sizes[i];
00961             Mat sub_up = up->subMatColumns(init_i, up_size_i);
00962             Mat sub_up_grad;
00963             Mat* p_sub_up_grad = NULL;
00964             if( compute_up_grad )
00965             {
00966                 sub_up_grad = up_grad->subMatColumns(init_i, up_size_i);
00967                 p_sub_up_grad = &sub_up_grad;
00968             }
00969 
00970             for (int j=0; j<n_down_blocks; j++)
00971             {
00972                 int init_j = down_init_positions[j];
00973                 int down_size_j = down_block_sizes[j];
00974                 Mat sub_down = down->subMatColumns(init_j, down_size_j);
00975                 Mat sub_down_grad =
00976                     down_grad->subMatColumns(init_j, down_size_j);
00977 
00978                 TVec<Mat*> sub_ports_value(2);
00979                 sub_ports_value[0] = &sub_down;
00980                 sub_ports_value[1] = &sub_up;
00981                 TVec<Mat*> sub_ports_gradient(2);
00982                 sub_ports_gradient[0] = &sub_down_grad;
00983                 // NOT &sub_up_grad because we may want a NULL pointer
00984                 sub_ports_gradient[1] = p_sub_up_grad;
00985 
00986                 if( compute_up_grad )
00987                     sub_up_grad.resize(0, up_size_i);
00988 
00989                 sub_connections(i,j)->bpropAccUpdate( sub_ports_value,
00990                                                       sub_ports_gradient );
00991             }
00992         }
00993     }
00994     else
00995         PLCHECK_MSG( false,
00996                      "Unknown port configuration" );
00997 
00998 }
00999 
01000 
01003 void RBMMixedConnection::forget()
01004 {
01005     clearStats();
01006 
01007     if( !random_gen )
01008     {
01009         PLWARNING("RBMMixedConnection: cannot forget() without random_gen");
01010         return;
01011     }
01012     for( int i=0 ; i<n_up_blocks ; i++ )
01013         for( int j=0 ; j<n_down_blocks ; j++ )
01014             if( sub_connections(i,j) )
01015             {
01016                 if( !(sub_connections(i,j)->random_gen) )
01017                     sub_connections(i,j)->random_gen = random_gen;
01018                 sub_connections(i,j)->forget();
01019             }
01020 }
01021 
01022 
01023 /* THIS METHOD IS OPTIONAL
01028 void RBMMixedConnection::finalize()
01029 {
01030 }
01031 */
01032 
01034 int RBMMixedConnection::nParameters() const
01035 {
01036     return 0;
01037 }
01038 
01044 Vec RBMMixedConnection::makeParametersPointHere(const Vec& global_parameters)
01045 {
01046     return global_parameters;
01047 }
01048 
01049 
01050 
01051 } // end of namespace PLearn
01052 
01053 
01054 /*
01055   Local Variables:
01056   mode:c++
01057   c-basic-offset:4
01058   c-file-style:"stroustrup"
01059   c-file-offsets:((innamespace . 0)(inline-open . 0))
01060   indent-tabs-mode:nil
01061   fill-column:79
01062   End:
01063 */
01064 // 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