PLearn 0.1
|
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 :