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 and University of Montreal 00006 // 00007 00008 // Redistribution and use in source and binary forms, with or without 00009 // modification, are permitted provided that the following conditions are met: 00010 // 00011 // 1. Redistributions of source code must retain the above copyright 00012 // notice, this list of conditions and the following disclaimer. 00013 // 00014 // 2. Redistributions in binary form must reproduce the above copyright 00015 // notice, this list of conditions and the following disclaimer in the 00016 // documentation and/or other materials provided with the distribution. 00017 // 00018 // 3. The name of the authors may not be used to endorse or promote 00019 // products derived from this software without specific prior written 00020 // permission. 00021 // 00022 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 00023 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00024 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 00025 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00026 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 00027 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00028 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00029 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00030 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00031 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00032 // 00033 // This file is part of the PLearn library. For more information on the PLearn 00034 // library, go to the PLearn Web site at www.plearn.org 00035 00036 00037 00038 00039 /* ******************************************************* 00040 * $Id: Variable.cc 9774 2008-12-11 21:06:26Z nouiz $ 00041 * This file is part of the PLearn library. 00042 ******************************************************* */ 00043 00046 #include "Var.h" 00047 #include "VarArray.h" 00048 #include "Func.h" 00049 00050 #include "VarElementVariable.h" 00051 #include "VarRowVariable.h" 00052 #include "SubMatVariable.h" 00053 #include "SubMatTransposeVariable.h" 00054 #include "SourceVariable.h" 00055 #include "PlusScalarVariable.h" 00056 #include "TimesConstantVariable.h" 00057 #include "Var_operators.h" 00058 00059 //#include "Var_utils.h" 00060 00061 namespace PLearn { 00062 using namespace std; 00063 00064 // To be able to use varDeepCopyField. 00065 // extern void varDeepCopyField(Var& field, CopiesMap& copies); 00066 00069 Var::Var() :PP<Variable>(0) {} 00070 Var::Var(Variable* v) :PP<Variable>(v) {} 00071 Var::Var(Variable* v, const char* name) :PP<Variable>(v) { ptr->setName(name); } 00072 Var::Var(const Var& other) :PP<Variable>(other) {} 00073 Var::Var(const Var& other, const char* name) :PP<Variable>(other) { ptr->setName(name); } 00074 Var::Var(const Var &other, const string &name) : PP<Variable>(other) { ptr->setName(name); } 00075 00076 Var::Var(int the_length, const char* name) 00077 :PP<Variable>(new SourceVariable(the_length,1)) 00078 { ptr->setName(name); } 00079 00080 Var::Var(int the_length, const string &name) 00081 : PP<Variable>(new SourceVariable(the_length, 1)) 00082 { ptr->setName(name); } 00083 00084 Var::Var(int the_length, int the_width) 00085 :PP<Variable>(new SourceVariable(the_length,the_width)) {} 00086 00087 Var::Var(int the_length, int the_width, const char* name) 00088 :PP<Variable>(new SourceVariable(the_length,the_width)) { ptr->setName(name); } 00089 00090 Var::Var(int the_length, int the_width, const string &name) 00091 : PP<Variable>(new SourceVariable(the_length, the_width)) 00092 { ptr->setName(name); } 00093 00094 Var::Var(const Vec& v, bool vertical) 00095 :PP<Variable>(new SourceVariable(v,vertical)) 00096 {} 00097 00098 Var::Var(const Mat& m) 00099 :PP<Variable>(new SourceVariable(m)) 00100 {} 00101 00103 // length // 00105 int Var::length() const 00106 { return (*this)->length(); } 00107 00109 // width // 00111 int Var::width() const 00112 { return (*this)->width(); } 00113 00115 // [] // 00117 Var Var::operator[](int i) const 00118 { 00119 if(width()==1) 00120 return operator()(i,0); 00121 else if(length()==1) 00122 return operator()(0,i); 00123 PLERROR("You shouldnt use operator[](int i) to access a matrix variable, consider using operator() instead"); 00124 return Var(); 00125 } 00126 00127 Var Var::operator[](Var index) const 00128 { 00129 if (!ptr->isVec()) 00130 PLERROR("In Var::operator[](Var index) - You should not use this " 00131 "operator to get the row of a matrix Var, but " 00132 "operator()(Var index)"); 00133 return new VarElementVariable(*this, index); 00134 } 00135 00137 // subMat // 00139 Var Var::subMat(int i, int j, int sublength, int subwidth, bool do_transpose) const 00140 { 00141 if(do_transpose) 00142 return new SubMatTransposeVariable(*this, i, j, sublength, subwidth); 00143 else 00144 return new SubMatVariable(*this, i, j, sublength, subwidth); 00145 } 00146 00147 Var Var::subVec(int start, int len, bool transpose) const 00148 { 00149 if(width()==1) 00150 return subMat(start,0,len,1,transpose); 00151 else if(length()==1) 00152 return subMat(0,start,1,len,transpose); 00153 00154 PLERROR("In Variable::subVec variable is not a vec (single column or single row)"); 00155 return Var(); 00156 } 00157 00158 Var Var::operator()(Var index) const 00159 { return new VarRowVariable(*this,index); } 00160 00161 Var Var::operator()(Var i, Var j) const 00162 { return new VarElementVariable(*this, new PlusScalarVariable(j, new TimesConstantVariable(i,(real)width()))); } 00163 00164 void Var::operator=(real f) 00165 { 00166 if (!isNull()) 00167 (*this)->value.fill(f); 00168 else 00169 PLERROR("Var::operator= called on null Var"); 00170 } 00171 00172 void Var::operator=(const Vec& v) 00173 { 00174 if (!isNull()) 00175 (*this)->value << v; 00176 else 00177 PLERROR("Var::operator= called on null Var"); 00178 } 00179 00180 void Var::operator=(const Mat& m) 00181 { 00182 if (!isNull()) 00183 (*this)->matValue << m; 00184 else 00185 PLERROR("Var::operator= called on null Var"); 00186 } 00187 00188 int Variable::nvars = 0; 00189 00190 Variable::Variable(int thelength, int thewidth, bool call_build_): 00191 inherited(call_build_), 00192 varnum(++nvars), marked(false), varname(""), 00193 allows_partial_update(false), gradient_status(0), 00194 matValue(thelength,thewidth), matGradient(thelength,thewidth), 00195 min_value(-FLT_MAX), max_value(FLT_MAX), diaghessiandata(0), rvaluedata(0), 00196 dont_bprop_here(false) 00197 { 00198 value = matValue.toVec(); 00199 gradient = matGradient.toVec(); 00200 if(value.getStorage()) 00201 valuedata = value.data(); 00202 else 00203 valuedata = 0; 00204 if (gradient.getStorage()) 00205 gradientdata = gradient.data(); 00206 else 00207 gradientdata = 0; 00208 if (call_build_) 00209 build_(); 00210 } 00211 00212 Variable::Variable(const Mat& m, bool call_build_) 00213 :varnum(++nvars), marked(false), varname(""), 00214 allows_partial_update(false), gradient_status(0), 00215 matValue(m), matGradient(m.length(),m.width()), 00216 min_value(-FLT_MAX), max_value(FLT_MAX), diaghessiandata(0), rvaluedata(0), 00217 dont_bprop_here(false) 00218 { 00219 if(!m.isCompact()) 00220 PLERROR("To be able to construct a Var that views the same data as a Mat m, the Mat must be compact (width()==mod()). Maybe you can use m.copy() instead of m?"); 00221 value = matValue.toVec(); 00222 gradient = matGradient.toVec(); 00223 if(value.getStorage()) 00224 valuedata = value.data(); 00225 else 00226 valuedata = 0; 00227 if (gradient.getStorage()) 00228 gradientdata = gradient.data(); 00229 else 00230 gradientdata = 0; 00231 if (call_build_) 00232 build_(); 00233 } 00234 00235 // shallow copy (same as default copy constructor, except varnum is set to ++nvars. 00236 Variable::Variable(const Variable& v) 00237 :varnum(++nvars), marked(false), varname(v.getName()), 00238 allows_partial_update(v.allows_partial_update), gradient_status(v.gradient_status), 00239 value(v.value), gradient(v.gradient), 00240 matValue(v.matValue),matGradient(v.matGradient), 00241 valuedata(v.valuedata), gradientdata(v.gradientdata), 00242 min_value(v.min_value),max_value(v.max_value), 00243 g(v.g), diaghessian(v.diaghessian), diaghessiandata(v.diaghessiandata), 00244 rvaluedata(v.rvaluedata), dont_bprop_here(v.dont_bprop_here) 00245 {} 00246 00247 00249 // declareOptions // 00251 void Variable::declareOptions(OptionList& ol) 00252 { 00253 declareOption(ol, "varname", &Variable::varname, OptionBase::buildoption, 00254 "An (optional) name for the variable\n"); 00255 00256 declareOption(ol, "value", &Variable::matValue, OptionBase::learntoption, 00257 "Current value of the variable\n"); 00258 00259 declareOption(ol, "min_value", &Variable::min_value, OptionBase::buildoption, 00260 "minimum value of the variable\n"); 00261 00262 declareOption(ol, "max_value", &Variable::max_value, OptionBase::buildoption, 00263 "maximum value of the variable\n"); 00264 00265 /* 00266 declareOption(ol, "gradient", &Variable::matGradient, OptionBase::learntoption, 00267 "Current gradient of the variable\n"); 00268 */ 00269 00270 inherited::declareOptions(ol); 00271 } 00272 00274 // declareMethods // 00276 void Variable::declareMethods(RemoteMethodMap& rmm) 00277 { 00278 // Insert a backpointer to remote methods; note that this 00279 // different than for declareOptions() 00280 rmm.inherited(inherited::_getRemoteMethodMap_()); 00281 00282 declareMethod( 00283 rmm, "fillValue", &Variable::fillValue, 00284 (BodyDoc("Fill value with the given constant"), 00285 ArgDoc ("val", "Value to fill with"))); 00286 00287 declareMethod( 00288 rmm, "setValueSubMat", &Variable::setValueSubMat, 00289 (BodyDoc("Replace a sub-matrix of the value with the given data"), 00290 ArgDoc ("submat", "Data to set (as a matrix)"), 00291 ArgDoc ("istart", "Row where 'submat' is inserted"), 00292 ArgDoc ("jstart", "Column where 'submat' is inserted"))); 00293 00294 declareMethod( 00295 rmm, "setMinValue", &Variable::setMinValue, 00296 (BodyDoc("Set box constraint (minimum bound) on this Variable."), 00297 ArgDoc ("val", "Minimum value it can take"))); 00298 00299 declareMethod( 00300 rmm, "fprop", &Variable::fprop, 00301 (BodyDoc("Update value of this Var"))); 00302 00303 } 00304 00306 // build_ // 00308 void Variable::build_() 00309 { 00310 int l_previous = length(); 00311 int w_previous = width(); 00312 int l, w; 00313 recomputeSize(l, w); 00314 if(l==0 || w==0) 00315 { 00316 l = l_previous; 00317 w = w_previous; 00318 } 00319 // we call resize in all cases, even if we already had matValue correctly sized 00320 // the call to resize makes sure that value, valuedata, matGradient, gradient, gradientdata 00321 // are correctly sized and initialized. 00322 resize(l, w); 00323 00324 //if (l && w && (l != l_previous || w != w_previous)) 00325 // resize(l, w); 00326 } 00327 00329 // build // 00331 void Variable::build() 00332 { 00333 inherited::build(); 00334 build_(); 00335 } 00336 00337 00339 // recomputeSize // 00341 void Variable::recomputeSize(int& l, int& w) const 00342 { l = length(); w = width(); } 00343 00345 // resize // 00347 void Variable::resize(int l, int w) 00348 { 00349 value = Vec(); 00350 // Force mod == width so that the call to 'toVec()' below does not crash. 00351 matValue.setMod(w); 00352 matValue.resize(l,w); 00353 value = matValue.toVec(); 00354 if(value.getStorage()) 00355 valuedata = value.data(); 00356 else 00357 valuedata = 0; 00358 00359 gradient = Vec(); 00360 // Same as above. 00361 matGradient.setMod(w); 00362 matGradient.resize(l,w); 00363 gradient = matGradient.toVec(); 00364 if (gradient.getStorage()) 00365 gradientdata = gradient.data(); 00366 else 00367 gradientdata = 0; 00368 } 00369 00371 // sizeprop // 00373 void Variable::sizeprop() 00374 { 00375 int l,w; 00376 recomputeSize(l,w); 00377 resize(l,w); 00378 } 00379 00381 // setParents // 00383 void Variable::setParents(const VarArray& parents) 00384 { PLERROR("In Variable::setParents setParents() function not implemented for %s", classname().c_str()); } 00385 00387 // defineValueLocation // 00389 Mat Variable::defineValueLocation(const Mat& m) 00390 { 00391 if(!m.isCompact()) 00392 PLERROR("In Variable::defineValueLocation, Variables require compact" 00393 " matrices"); 00394 Mat oldm = matValue; 00395 matValue = m; 00396 value = matValue.toVec(); 00397 if(value.getStorage()) 00398 valuedata = value.data(); 00399 else 00400 valuedata = 0; 00401 gradient = Vec(); // Temporarily frees a reference to gradient's storage. 00402 matGradient.setMod(matValue.width()); 00403 matGradient.resize(matValue.length(), matValue.width()); 00404 gradient = matGradient.toVec(); 00405 if (gradient.getStorage()) 00406 gradientdata = gradient.data(); 00407 else 00408 gradientdata = 0; 00409 return oldm; 00410 } 00411 00413 // defineGradientLocation // 00415 Mat Variable::defineGradientLocation(const Mat& m) 00416 { 00417 if(!m.isCompact()) 00418 PLERROR("In Variable::defineGradientLocation, Variables require" 00419 " compact matrices"); 00420 Mat oldm = matGradient; 00421 matGradient = m; 00422 gradient = matGradient.toVec(); 00423 if (gradient.getStorage()) 00424 gradientdata = gradient.data(); 00425 else 00426 gradientdata = 0; 00427 value = Vec(); // Temporarily frees a reference to value's storage. 00428 matValue.setMod(matGradient.width()); 00429 matValue.resize(matGradient.length(), matGradient.width()); 00430 value = matValue.toVec(); 00431 if(value.getStorage()) 00432 valuedata = value.data(); 00433 else 00434 valuedata = 0; 00435 return oldm; 00436 } 00437 00438 /* 00439 void Variable::newwrite(PStream& out) const 00440 { 00441 switch(out.outmode) 00442 { 00443 case PStream::raw_ascii: 00444 case PStream::pretty_ascii: 00445 { 00446 // This is just to strip "Variable" out of the class name (as they all 00447 // end in "Variable") 00448 string cn=info(); 00449 string::size_type len = cn.length(); 00450 if (len >= 9 && cn.substr(len-8,8) == "Variable") 00451 out << cn.substr(0,len-8) << endl; 00452 else 00453 out << cn << endl; 00454 break; 00455 } 00456 default: 00457 inherited::newwrite(out); 00458 } 00459 } 00460 */ 00461 00462 PLEARN_IMPLEMENT_ABSTRACT_OBJECT(Variable, 00463 "The base Variable class", 00464 "" 00465 ); 00466 00467 void Variable::makeDeepCopyFromShallowCopy(CopiesMap& copies) 00468 { 00469 inherited::makeDeepCopyFromShallowCopy(copies); 00470 deepCopyField(value, copies); 00471 deepCopyField(gradient, copies); 00472 deepCopyField(matValue, copies); 00473 deepCopyField(matGradient, copies); 00474 if (value.getStorage()) 00475 valuedata = value.data(); 00476 else 00477 valuedata = 0; 00478 if (gradient.getStorage()) 00479 gradientdata = gradient.data(); 00480 else 00481 gradientdata = 0; 00482 varDeepCopyField(g, copies); 00483 } 00484 00485 void Variable::clearDiagHessian() 00486 { 00487 if(!diaghessian) 00488 resizeDiagHessian(); 00489 diaghessian.clear(); 00490 } 00491 00492 00493 void Variable::fbprop() 00494 { 00495 fprop(); 00496 bprop(); 00497 } 00498 00499 void Variable::fbbprop() 00500 { 00501 fprop(); 00502 bprop(); 00503 bbprop(); 00504 } 00505 00506 void Variable::bbprop() 00507 { PLERROR("bbprop not implemented for this variable (%s)",classname().c_str()); } 00508 00509 void Variable::symbolicBprop() 00510 { PLERROR("symbolicBprop not implemented for this variable (%s)",classname().c_str()); } 00511 00512 void Variable::rfprop() 00513 { PLERROR("rfprop not implmented for this variable (%s)",classname().c_str()); } 00514 00515 void Variable::setName(const string& the_name) 00516 { varname = the_name; } 00517 00518 string Variable::getName() const 00519 { 00520 if (varname.size() == 0) 00521 return "#" + tostring(varnum); 00522 00523 return varname; 00524 } 00525 00526 void Variable::oldread(istream& in) 00527 { PLearn::read(in, value); } 00528 00529 void Variable::write(ostream& out) const 00530 { PLearn::write(out, value); } 00531 00532 00533 Var Variable::subVec(int start, int len, bool transpose) 00534 { 00535 if(isColumnVec()) 00536 return subMat(start,0,len,1,transpose); 00537 else if(isRowVec()) 00538 return subMat(0,start,1,len,transpose); 00539 00540 PLERROR("In Variable::subVec variable is not a vec (single column or single row)"); 00541 return Var(); 00542 } 00543 00544 Var Variable::subMat(int i, int j, int sublength, int subwidth, bool do_transpose) 00545 { 00546 if(do_transpose) 00547 return new SubMatTransposeVariable(this, i, j, sublength, subwidth); 00548 else 00549 return new SubMatVariable(this, i, j, sublength, subwidth); 00550 } 00551 00552 void Variable::fprop_from_all_sources() 00553 { 00554 VarArray all_sources = sources(); 00555 unmarkAncestors(); 00556 VarArray prop_path = propagationPath(all_sources,Var(this)); 00557 prop_path.fprop(); 00558 } 00559 00560 void Variable::printInfos(bool print_gradient) 00561 { 00562 VarArray ancetres = ancestors(); 00563 unmarkAncestors(); 00564 ancetres.printInfo(print_gradient); 00565 } 00566 00567 void Variable::accg(Var vg) 00568 { 00569 if(g || (vg.length()==length() && vg.width()==width())) 00570 g += vg; 00571 else // g does not exist 00572 { 00573 g = Var(length(),width()); 00574 g += vg; 00575 } 00576 } 00577 00578 void Variable::verifyGradient(real step) 00579 { 00580 VarArray inputs = sources(); 00581 unmarkAncestors(); 00582 Func f(inputs,Var(this)); 00583 Vec p(inputs.nelems()); 00584 inputs >> p; 00585 f->verifyGradient(p,step); 00586 } 00587 00588 // set value = value + (step_size*coeff + b) * direction 00589 // with step_size possibly scaled down s.t. box constraints are satisfied 00590 // return true if box constraints have been hit with the update 00591 00592 bool Variable::update(real step_size, Vec direction_vec, real coeff, real b) 00593 { 00594 bool hit = false; 00595 if(allows_partial_update) 00596 PLWARNING("Warning in Variable::update(real,Vec): will update every elements of the Variable"); 00597 real full_coeff = step_size * coeff + b; 00598 if(min_value>-FLT_MAX || max_value<FLT_MAX) 00599 // constrained update 00600 { 00601 real* direction = direction_vec.data(); 00602 for(int i=0; i<nelems(); i++) 00603 { 00604 valuedata[i] += (full_coeff) * direction[i]; 00605 if(valuedata[i]<min_value) 00606 { 00607 valuedata[i]=min_value; 00608 hit = true; 00609 } 00610 else if(valuedata[i]>max_value) 00611 { 00612 valuedata[i]=max_value; 00613 hit = true; 00614 } 00615 } 00616 } 00617 else 00618 // unconstrained update 00619 { 00620 real* direction = direction_vec.data(); 00621 for(int i=0; i<nelems(); i++) 00622 { 00623 valuedata[i] += (full_coeff) * direction[i]; 00624 } 00625 } 00626 return hit; 00627 } 00628 00629 bool Variable::update(Vec step_sizes, Vec direction_vec, real coeff, real b) 00630 { 00631 if(allows_partial_update) 00632 PLWARNING("Warning in Variable::update(Vec,Vec): will update every elements of the Variable"); 00633 bool hit=false; 00634 real* direction = direction_vec.data(); 00635 real* step = step_sizes.data(); 00636 if(min_value>-FLT_MAX || max_value<FLT_MAX) 00637 // constrained update 00638 { 00639 for(int i=0; i<nelems(); i++) 00640 { 00641 valuedata[i] += (step[i] * coeff + b) * direction[i]; 00642 if(valuedata[i]<min_value) 00643 { 00644 valuedata[i]=min_value; 00645 hit = true; 00646 } 00647 else if(valuedata[i]>max_value) 00648 { 00649 valuedata[i]=max_value; 00650 hit = true; 00651 } 00652 } 00653 } 00654 else 00655 // unconstrained update 00656 for(int i=0; i<nelems(); i++) 00657 valuedata[i] += (step[i] * coeff + b) * direction[i]; 00658 return hit; 00659 } 00660 00661 bool Variable::update(real step_size, bool clear) 00662 { 00663 bool hit=false; 00664 if(min_value>-FLT_MAX || max_value<FLT_MAX) 00665 // constrained update 00666 { 00667 if (allows_partial_update && gradient_status!=2) 00668 { 00669 if (gradient_status!=0) 00670 { 00671 for (int r=0;r<rows_to_update.length();r++) 00672 { 00673 int row = rows_to_update[r]; 00674 real* direction = matGradient[row]; 00675 real* params = matValue[row]; 00676 for(int i=0; i<width(); i++) 00677 { 00678 params[i] += step_size*direction[i]; 00679 if(params[i]<min_value) 00680 { 00681 params[i]=min_value; 00682 hit = true; 00683 } 00684 else if(params[i]>max_value) 00685 { 00686 params[i]=max_value; 00687 hit = true; 00688 } 00689 if (clear) 00690 direction[i]=0; 00691 } 00692 } 00693 if (clear) { 00694 rows_to_update.resize(0); 00695 gradient_status=0; 00696 } 00697 } 00698 } 00699 else for (int row=0;row<length();row++) 00700 { 00701 real* direction = matGradient[row]; 00702 real* params = matValue[row]; 00703 for(int i=0; i<width(); i++) 00704 { 00705 params[i] += step_size*direction[i]; 00706 if(params[i]<min_value) 00707 { 00708 params[i]=min_value; 00709 hit = true; 00710 } 00711 else if(params[i]>max_value) 00712 { 00713 params[i]=max_value; 00714 hit = true; 00715 } 00716 if (clear) 00717 direction[i]=0; 00718 } 00719 } 00720 } 00721 else 00722 // unconstrained update 00723 { 00724 if (allows_partial_update && gradient_status!=2) 00725 { 00726 if (gradient_status!=0) 00727 { 00728 for (int r=0;r<rows_to_update.length();r++) 00729 { 00730 int row = rows_to_update[r]; 00731 real* direction = matGradient[row]; 00732 real* params = matValue[row]; 00733 for(int i=0; i<width(); i++) 00734 { 00735 params[i] += step_size*direction[i]; 00736 if (clear) 00737 direction[i] = 0; 00738 } 00739 } 00740 if (clear) { 00741 rows_to_update.resize(0); 00742 gradient_status=0; 00743 } 00744 } 00745 } 00746 else for (int row=0;row<length();row++) 00747 { 00748 real* direction = matGradient[row]; 00749 real* params = matValue[row]; 00750 for(int i=0; i<width(); i++) 00751 { 00752 params[i] += step_size*direction[i]; 00753 if (clear) 00754 direction[i] = 0; 00755 } 00756 } 00757 } 00758 return hit; 00759 } 00760 00762 // updateWithWeightDecay // 00764 void Variable::updateWithWeightDecay(real step_size, real weight_decay, bool L1, bool clear) 00765 { 00766 // we do unconstrained update only here 00767 if (allows_partial_update && gradient_status!=2) 00768 { 00769 if (gradient_status!=0) 00770 { 00771 for (int r=0;r<rows_to_update.length();r++) 00772 { 00773 int row = rows_to_update[r]; 00774 real* direction = matGradient[row]; 00775 real* params = matValue[row]; 00776 if (L1) 00777 { 00778 real delta = fabs(step_size)*weight_decay; 00779 for(int i=0; i<width(); i++) 00780 { 00781 real pi = params[i]; 00782 params[i] += step_size*direction[i]; 00783 if (pi>delta) 00784 params[i] -= delta; 00785 else if (pi<-delta) 00786 params[i] += delta; 00787 else 00788 params[i] = 0; 00789 if (clear) 00790 direction[i] = 0; 00791 } 00792 } 00793 else // L2 00794 for(int i=0; i<width(); i++) 00795 { 00796 params[i] += step_size*(direction[i] + weight_decay*params[i]); 00797 if (clear) 00798 direction[i] = 0; 00799 } 00800 } 00801 if (clear) { 00802 rows_to_update.resize(0); 00803 gradient_status=0; 00804 } 00805 } 00806 } 00807 else 00808 for (int row=0;row<length();row++) 00809 { 00810 real* direction = matGradient[row]; 00811 real* params = matValue[row]; 00812 if (L1) 00813 { 00814 real delta = fabs(step_size)*weight_decay; 00815 for(int i=0; i<width(); i++) 00816 { 00817 real pi = params[i]; 00818 params[i] += step_size*direction[i]; 00819 if (pi>delta) 00820 params[i] -= delta; 00821 else if (pi<-delta) 00822 params[i] += delta; 00823 if (clear) 00824 direction[i] = 0; 00825 } 00826 } 00827 else // L2 00828 for(int i=0; i<width(); i++) 00829 { 00830 params[i] += step_size*(direction[i] + weight_decay*params[i]); 00831 if (clear) 00832 direction[i] = 0; 00833 } 00834 } 00835 } 00836 00837 00839 // updateAndClear // 00841 void Variable::updateAndClear() 00842 { 00843 if (allows_partial_update && gradient_status!=2) 00844 { 00845 if (gradient_status!=0) 00846 { 00847 for (int r=0;r<rows_to_update.length();r++) 00848 { 00849 int row = rows_to_update[r]; 00850 real* direction = matGradient[row]; 00851 real* params = matValue[row]; 00852 for(int i=0; i<width(); i++) 00853 { 00854 real& param_i = params[i]; 00855 param_i += direction[i]; 00856 if (param_i < min_value) 00857 param_i = min_value; 00858 else if (param_i > max_value) 00859 param_i = max_value; 00860 direction[i] = 0; 00861 } 00862 } 00863 rows_to_update.resize(0); 00864 gradient_status=0; 00865 } 00866 } 00867 else 00868 { 00869 for(int i=0; i<nelems(); i++) { 00870 real& value = valuedata[i]; 00871 value += gradientdata[i]; 00872 if (value < min_value) 00873 value = min_value; 00874 else if (value > max_value) 00875 value = max_value; 00876 } 00877 gradient.clear(); 00878 } 00879 } 00880 00881 // set value = value + step_size * gradient 00882 // with step_size possibly scaled down s.t. box constraints are satisfied 00883 // return true if box constraints have been hit with the update 00884 00885 /* 00886 bool Variable::update(real step_size) 00887 { 00888 bool hit=false; 00889 if(min_value>-FLT_MAX || max_value<FLT_MAX) 00890 // constrained update 00891 { 00892 real* direction = gradient.data(); 00893 for(int i=0; i<nelems(); i++) 00894 { 00895 valuedata[i] += step_size*direction[i]; 00896 if(valuedata[i]<min_value) 00897 { 00898 valuedata[i]=min_value; 00899 hit = true; 00900 } 00901 else if(valuedata[i]>max_value) 00902 { 00903 valuedata[i]=max_value; 00904 hit = true; 00905 } 00906 } 00907 } 00908 else 00909 // unconstrained update 00910 { 00911 real* direction = gradient.data(); 00912 for(int i=0; i<nelems(); i++) 00913 valuedata[i] += step_size*direction[i]; 00914 } 00915 00916 return hit; 00917 } 00918 */ 00919 00920 00921 // set value = new_value 00922 // projected down in each direction independently in the 00923 // subspace in which the box constraints are satisfied. 00924 // return true if box constraints have been hit with the update 00925 bool Variable::update(Vec new_value) 00926 { 00927 if(allows_partial_update) 00928 PLWARNING("Warning in Variable::update(Vec): will update every elements of the Variable"); 00929 bool hit=false; 00930 if(min_value>-FLT_MAX || max_value<FLT_MAX) 00931 // constrained update 00932 { 00933 real* new_v = new_value.data(); 00934 for(int i=0; i<nelems(); i++) 00935 { 00936 valuedata[i] = new_v[i]; 00937 if(valuedata[i]<min_value) 00938 { 00939 valuedata[i]=min_value; 00940 hit = true; 00941 } 00942 else if(valuedata[i]>max_value) 00943 { 00944 valuedata[i]=max_value; 00945 hit = true; 00946 } 00947 } 00948 } 00949 else 00950 // unconstrained update 00951 { 00952 real* new_v = new_value.data(); 00953 for(int i=0; i<nelems(); i++) 00954 valuedata[i] = new_v[i]; 00955 } 00956 return hit; 00957 } 00958 00959 // Using the box constraints on the values, return 00960 // the maximum allowable step_size in the given direction 00961 // i.e., argmax_{step_size} {new = value + step_size * direction, new in box} 00962 real Variable::maxUpdate(Vec direction) 00963 { 00964 real max_step_size=FLT_MAX; 00965 if(min_value>-FLT_MAX || max_value<FLT_MAX) 00966 // constrained update 00967 { 00968 real* dir = direction.data(); 00969 for(int i=0; i<nelems(); i++) 00970 { 00971 real v = valuedata[i]; 00972 if (v<min_value || v>max_value) 00973 PLERROR("Variable::maxUpdate:current value %f already out of bounds (%f,%f)!", 00974 v,min_value,max_value); 00975 if (dir[i]>0) // want to increase value: check max_value 00976 { 00977 if (max_value<FLT_MAX) 00978 { 00979 real maxstep = (max_value - v)/dir[i]; 00980 if (maxstep < max_step_size) max_step_size = maxstep; 00981 } 00982 } 00983 else if (dir[i]<0) // want to decrease value: check min_value 00984 { 00985 if (min_value > -FLT_MAX) 00986 { 00987 real maxstep = (min_value - v)/dir[i]; 00988 if (maxstep < max_step_size) max_step_size = maxstep; 00989 } 00990 } 00991 } 00992 } 00993 // else unconstrained 00994 00995 return max_step_size; 00996 } 00997 00998 void Variable::makeSharedValue(real* x, int n) 00999 { 01000 if (n!=nelems()) PLERROR("Variable::makeSharedValue, n(%d) inconsistent with nelems(%d)", 01001 n,nelems()); 01002 real* v=value.data(); 01003 valuedata=x; 01004 if (x!=v) 01005 for (int j=0;j<n;j++) 01006 x[j]=v[j]; 01007 value.storage = new Storage<real>(n,x); 01008 value.offset_ = 0; 01009 matValue.storage = value.storage; 01010 matValue.offset_ = 0; 01011 matValue.mod_ = matValue.width(); 01012 } 01013 01014 void Variable::makeSharedValue(PP<Storage<real> > storage, int offset_) 01015 { 01016 int n=nelems(); 01017 if (storage->length()<offset_+n) 01018 PLERROR("Variable::makeSharedValue, storage(%d) too small(%d+%d)", 01019 storage->length(),offset_,nelems()); 01020 real* v=value.data(); 01021 real* x=valuedata=storage->data+offset_; 01022 if (x!=v) 01023 for (int j=0;j<n;j++) 01024 x[j]=v[j]; 01025 value.storage = storage; 01026 value.offset_ = offset_; 01027 matValue.storage = storage; 01028 matValue.offset_ = offset_; 01029 matValue.mod_ = matValue.width(); 01030 } 01031 01032 void Variable::makeSharedGradient(Vec& v, int offset_) 01033 { 01034 makeSharedGradient(v.storage,v.offset_+offset_); 01035 } 01036 01037 void Variable::makeSharedGradient(PP<Storage<real> > storage, int offset_) 01038 { 01039 int n=nelems(); 01040 if (storage->length()<offset_+n) 01041 PLERROR("Variable::makeSharedGradient, storage(%d) too small(%d+%d)", 01042 storage->length(),offset_,nelems()); 01043 real* v=gradient.data(); 01044 real* x=gradientdata=storage->data+offset_; 01045 if (x!=v) 01046 for (int j=0;j<n;j++) 01047 x[j]=v[j]; 01048 gradient.storage = storage; 01049 gradient.offset_ = offset_; 01050 matGradient.storage = storage; 01051 matGradient.offset_ = offset_; 01052 matGradient.mod_ = matGradient.width(); 01053 } 01054 01055 01056 void Variable::makeSharedGradient(real* x, int n) 01057 { 01058 if (n!=nelems()) PLERROR("Variable::makeSharedGradient, n(%d) inconsistent with nelems(%d)", 01059 n,nelems()); 01060 real* v=gradient.data(); 01061 gradientdata=x; 01062 if (x!=v) 01063 for (int j=0;j<n;j++) 01064 x[j]=v[j]; 01065 gradient.storage = new Storage<real>(n,x); 01066 gradient.offset_ = 0; 01067 matGradient.storage = gradient.storage; 01068 matGradient.offset_ = 0; 01069 matGradient.mod_ = matGradient.width(); 01070 } 01071 01072 void Variable::makeSharedValue(Vec& v, int offset_) 01073 { 01074 makeSharedValue(v.storage,v.offset_+offset_); 01075 } 01076 01077 void Variable::makeSharedRValue(PP<Storage<real> > storage, int offset_) 01078 { 01079 resizeRValue(); 01080 int n=nelems(); 01081 if (storage->length()<offset_+n) 01082 PLERROR("Variable::makeSharedRValue, storage(%d) too small(%d+%d)", 01083 storage->length(),offset_,nelems()); 01084 real* v=rValue.data(); 01085 real* x=rvaluedata=storage->data+offset_; 01086 if (x!=v) 01087 for (int j=0;j<n;j++) 01088 x[j]=v[j]; 01089 rValue.storage = storage; 01090 rValue.offset_ = offset_; 01091 matRValue.storage = storage; 01092 matRValue.offset_ = offset_; 01093 matRValue.mod_ = matRValue.width(); 01094 } 01095 01096 01097 void Variable::makeSharedRValue(real* x, int n) 01098 { 01099 if (n!=nelems()) PLERROR("Variable::makeSharedRValue, n(%d) inconsistent with nelems(%d)", 01100 n,nelems()); 01101 resizeRValue(); 01102 real* v=rValue.data(); 01103 rvaluedata=x; 01104 if (x!=v) 01105 for (int j=0;j<n;j++) 01106 x[j]=v[j]; 01107 rValue.storage = new Storage<real>(n,x); 01108 rValue.offset_ = 0; 01109 matRValue.storage = rValue.storage; 01110 matRValue.offset_ = 0; 01111 matRValue.mod_ = matRValue.width(); 01112 } 01113 01115 // makeSharedRValue // 01117 void Variable::makeSharedRValue(Vec& v, int offset_) 01118 { 01119 makeSharedRValue(v.storage,v.offset_+offset_); 01120 } 01121 01123 // resizeDiagHessian // 01125 void Variable::resizeDiagHessian() 01126 { 01127 matDiagHessian.resize(length(),width()); 01128 diaghessian = matDiagHessian.toVec(); 01129 diaghessiandata = diaghessian.data(); 01130 } 01131 01133 // resizeRValue // 01135 void Variable::resizeRValue() 01136 { 01137 if (!rvaluedata) 01138 { 01139 matRValue.resize(length(),width()); 01140 rValue = matRValue.toVec(); 01141 rvaluedata = rValue.data(); 01142 } 01143 } 01144 01146 // setValueSubMat // 01148 void Variable::setValueSubMat(const Mat& submat, int istart, int jstart) 01149 { 01150 matValue.subMat(istart, jstart, submat.length(), submat.width()) << submat; 01151 } 01152 01153 01154 } // end of namespace PLearn 01155 01156 01157 /* 01158 Local Variables: 01159 mode:c++ 01160 c-basic-offset:4 01161 c-file-style:"stroustrup" 01162 c-file-offsets:((innamespace . 0)(inline-open . 0)) 01163 indent-tabs-mode:nil 01164 fill-column:79 01165 End: 01166 */ 01167 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :