PLearn 0.1
|
00001 // -*- C++ -*- 00002 00003 // SumVarianceOfLinearTransformedBernoullis.cc 00004 // 00005 // Copyright (C) 2009 Pascal Vincent 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 Vincent 00036 00040 #include "SumVarianceOfLinearTransformedBernoullis.h" 00041 00042 namespace PLearn { 00043 using namespace std; 00044 00047 PLEARN_IMPLEMENT_OBJECT( 00048 SumVarianceOfLinearTransformedBernoullis, 00049 "Computes the sum of the variances of the components resulting from a linear transformation of independent bernoullis", 00050 "Let H be a (l,m) matrix of independent bernoullis.\n" 00051 "Let P be a (l,m) matrix containing their corresponding parameters (expectations or prob of 1) \n" 00052 "Let W a (m,d) linear transformation matrix, \n" 00053 "Define Y=HW, Y is a (l,d) matrix of random variables, with Y_ij = <H_i,W_.j> \n" 00054 "i.e. Y_ij is a linear combination of bernoullis in row i of H whose parameters are in row i of P, \n" 00055 "with the combination coefficients being in column j of W \n" 00056 "We have Var[Y_ij] = sum_k Var[H_ik] (W_kj)^2 \n" 00057 " = sum_k P_ik (1-P_ik) (W_kj)^2 \n" 00058 "This binary variable, given input1 P and input2 W, computes:\n" 00059 " out = sum_ij Var[Y_ij] \n" 00060 " = sum_ijk P_ik (1-P_ik) (W_kj)^2 \n" 00061 " = sum_i {sum_k P_ik (1-P_ik) {sum_j (W_kj)^2}} \n" 00062 " = sum_i {sum_k P_ik (1-P_ik) ||W_k.||^2 } \n" 00063 ); 00064 00065 SumVarianceOfLinearTransformedBernoullis::SumVarianceOfLinearTransformedBernoullis() 00066 : inherited(0,0,1,1) 00067 {} 00068 00069 SumVarianceOfLinearTransformedBernoullis::SumVarianceOfLinearTransformedBernoullis(Variable* input1, Variable* input2, 00070 bool call_build_) 00071 : inherited(input1, input2, 1, 1, call_build_) 00072 { 00073 if (call_build_) 00074 build_(); 00075 } 00076 00077 // constructor from input variable and parameters 00078 // SumVarianceOfLinearTransformedBernoullis::SumVarianceOfLinearTransformedBernoullis(Variable* input1, Variable* input2, 00079 // param_type the_parameter, ..., 00080 // bool call_build_) 00081 // ### replace with actual parameters 00082 // : inherited(input1, input2, this_variable_length, this_variable_width, 00083 // call_build_), 00084 // parameter(the_parameter), 00085 // ... 00086 //{ 00087 // if (call_build_) 00088 // build_(); 00089 //} 00090 00091 void SumVarianceOfLinearTransformedBernoullis::recomputeSize(int& l, int& w) const 00092 { 00093 l = 1; 00094 w = 1; 00095 } 00096 00097 void SumVarianceOfLinearTransformedBernoullis::computeWsqnorm() 00098 { 00099 Mat W = input2->matValue; 00100 int m = W.length(); 00101 int d = W.width(); 00102 00103 Wsqnorm.resize(m); 00104 real* pWsqnorm = Wsqnorm.data(); 00105 for(int k=0; k<m; k++) 00106 { 00107 real* Wk = W[k]; 00108 real sqnorm = 0; 00109 for(int j=0; j<d; j++) 00110 { 00111 real Wkj = Wk[j]; 00112 sqnorm += Wkj*Wkj; 00113 } 00114 pWsqnorm[k] = sqnorm; 00115 } 00116 } 00117 00118 // ### computes value from input1 and input2 values 00119 void SumVarianceOfLinearTransformedBernoullis::fprop() 00120 { 00121 Mat P = input1->matValue; 00122 int l = P.length(); 00123 int m = P.width(); 00124 00125 if(m!=input2.length()) 00126 PLERROR("Incompatible sizes: width of P (input1) must equal length of W (input2)"); 00127 00128 computeWsqnorm(); 00129 const real* pWsqnorm = Wsqnorm.data(); 00130 00131 double out = 0; 00132 for(int i=0; i<l; i++) 00133 { 00134 const real* P_i = P[i]; 00135 for(int k=0; k<m; k++) 00136 { 00137 real P_ik = P_i[k]; 00138 out += P_ik*(1-P_ik)*pWsqnorm[k]; 00139 } 00140 } 00141 value[0] = out; 00142 } 00143 00144 // ### computes input1 and input2 gradients from gradient 00145 void SumVarianceOfLinearTransformedBernoullis::bprop() 00146 { 00147 Mat P = input1->matValue; 00148 Mat Pgrad = input1->matGradient; 00149 Mat W = input2->matValue; 00150 Mat Wgrad = input2->matGradient; 00151 int l = P.length(); 00152 int m = W.length(); 00153 int d = W.width(); 00154 00155 real gr = gradient[0]; 00156 00157 computeWsqnorm(); 00158 const real* pWsqnorm = Wsqnorm.data(); 00159 00160 Wsqnormgrad.resize(m); 00161 Wsqnormgrad.fill(0); 00162 real* pWsqnormgrad = Wsqnormgrad.data(); 00163 00164 for(int i=0; i<l; i++) 00165 { 00166 const real* P_i = P[i]; 00167 real* Pgrad_i = Pgrad[i]; 00168 for(int k=0; k<m; k++) 00169 { 00170 real P_ik = P_i[k]; 00171 Pgrad_i[k] += gr*(1-2*P_ik)*pWsqnorm[k]; 00172 pWsqnormgrad[k] += P_ik*(1-P_ik); 00173 } 00174 } 00175 00176 for(int k=0; k<m; k++) 00177 { 00178 real coefk = 2*gr*pWsqnormgrad[k]; 00179 const real* W_k = W[k]; 00180 real* Wgrad_k = Wgrad[k]; 00181 for(int j=0; j<d; j++) 00182 Wgrad_k[j] += coefk*W_k[j]; 00183 } 00184 00185 } 00186 00187 // ### You can implement these methods: 00188 // void SumVarianceOfLinearTransformedBernoullis::bbprop() {} 00189 // void SumVarianceOfLinearTransformedBernoullis::symbolicBprop() {} 00190 // void SumVarianceOfLinearTransformedBernoullis::rfprop() {} 00191 00192 00193 // ### Nothing to add here, simply calls build_ 00194 void SumVarianceOfLinearTransformedBernoullis::build() 00195 { 00196 inherited::build(); 00197 build_(); 00198 } 00199 00200 void SumVarianceOfLinearTransformedBernoullis::makeDeepCopyFromShallowCopy(CopiesMap& copies) 00201 { 00202 inherited::makeDeepCopyFromShallowCopy(copies); 00203 00204 // ### Call deepCopyField on all "pointer-like" fields 00205 // ### that you wish to be deepCopied rather than 00206 // ### shallow-copied. 00207 // ### ex: 00208 // deepCopyField(trainvec, copies); 00209 deepCopyField(Wsqnorm, copies); 00210 deepCopyField(Wsqnormgrad, copies); 00211 00212 // ### If you want to deepCopy a Var field: 00213 // varDeepCopyField(somevariable, copies); 00214 } 00215 00216 void SumVarianceOfLinearTransformedBernoullis::declareOptions(OptionList& ol) 00217 { 00218 // ### Declare all of this object's options here. 00219 // ### For the "flags" of each option, you should typically specify 00220 // ### one of OptionBase::buildoption, OptionBase::learntoption or 00221 // ### OptionBase::tuningoption. If you don't provide one of these three, 00222 // ### this option will be ignored when loading values from a script. 00223 // ### You can also combine flags, for example with OptionBase::nosave: 00224 // ### (OptionBase::buildoption | OptionBase::nosave) 00225 00226 // ### ex: 00227 // declareOption(ol, "myoption", &SumVarianceOfLinearTransformedBernoullis::myoption, 00228 // OptionBase::buildoption, 00229 // "Help text describing this option"); 00230 // ... 00231 00232 // Now call the parent class' declareOptions 00233 inherited::declareOptions(ol); 00234 } 00235 00236 void SumVarianceOfLinearTransformedBernoullis::build_() 00237 { 00238 // ### This method should do the real building of the object, 00239 // ### according to set 'options', in *any* situation. 00240 // ### Typical situations include: 00241 // ### - Initial building of an object from a few user-specified options 00242 // ### - Building of a "reloaded" object: i.e. from the complete set of 00243 // ### all serialised options. 00244 // ### - Updating or "re-building" of an object after a few "tuning" 00245 // ### options have been modified. 00246 // ### You should assume that the parent class' build_() has already been 00247 // ### called. 00248 } 00249 00250 00251 } // end of namespace PLearn 00252 00253 00254 /* 00255 Local Variables: 00256 mode:c++ 00257 c-basic-offset:4 00258 c-file-style:"stroustrup" 00259 c-file-offsets:((innamespace . 0)(inline-open . 0)) 00260 indent-tabs-mode:nil 00261 fill-column:79 00262 End: 00263 */ 00264 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :